본문 바로가기
IT일반

Github 웹훅(webhook) php 자동배포하기

by xavi2019 2020. 8. 8.

목표: 소스코드 커밋할 때 커멘트에 [deployment]를 넣을 때만 자동 배포하기

> git commit -m '[deployment] 이 문자열이 있을 때만 배포한다'
> git push

환경 구성 

1. 먼저 SSH Key(Deploy Key)를 생성해야 합니다.
SSH Key는 웹서버에서 생성하도록 합니다.

> sudo mkdir /var/www/.ssh/
> sudo chown www-data:www-data /var/www/.ssh/
> sudo -Hu www-data ssh-keygen -t rsa
> [default dir of /var/www/.ssh/ is fine, no password]
> sudo cat /var/www/.ssh/id_rsa.pub

참고 URL: https://github.com/mboynes/github-deploy

 

 

 

2. Github 에 Deploy Key를 등록합니다.

3. 권한 부여

> sudo visudo

제일 하단에 아래 행 추가

webroot_owner는 웹서버 폴더의 소유자입니다.

 webroot_owner       ALL = (ALL) NOPASSWD: /usr/bin/git


아래 abc를 본인 것으로 대체하고 실행

> git config --global user.email "abc@abc.com"
> git config --global user.name "abc"
> git config --global push.default simple

4. 로그 폴더 / 파일 생성 

deploy.log 파일을 웹서버 루트 폴더 상위에 logs 폴더 생성하고 소유자를 본인의 webroot_owner 로 변경하고

쓰기 권한도 적절히 줍니다. 보통 707

 

5. deploy.php 파일을 웹루트에 생성

 

파일 내용중, 
define( 'REF_REGEX', '#^refs/heads/master$#' ); 의 경우,
최근에 생성한 마스터 브랜치는 main이므로
define( 'REF_REGEX', '#^refs/heads/main$#' );
로 변경해야 합니다.

 

<?php
# Array of the authorized IP addresses who can POST here. You can override this in your config if you so choose.
$authorized_ips = array(
    '207.97.227.253',
    '50.57.128.197',
    '108.171.174.178',
    '50.57.231.61',
    '54.235.183.49',
    '54.235.183.23',
    '54.235.118.251',
    '54.235.120.57',
    '54.235.120.61',
    '54.235.120.62'
);

# Put your deploy config file in the same dir as this file
if ( file_exists( dirname( __FILE__ ) . '/deploy-config.php' ) )
    include_once( 'deploy-config.php' );

# A regex matching the ref of the "push". `git pull` will only run if this matches. Default is the master branch.
if ( !defined( 'REF_REGEX' ) )
    define( 'REF_REGEX', '#^refs/heads/master$#' );

if ( !defined( 'LOG_WRITE' ) )
    define( 'LOG_WRITE', true );

# Log location; make sure it exists
if ( !defined( 'LOG' ) )
    define( 'LOG', '../logs/deploy.log' );

# Where is your repo directory? This script will chdir to it. If %s is present, it gets replaced with the repository name
if ( !defined( 'REPO_DIR' ) )
    define( 'REPO_DIR', dirname( __FILE__ ) . "/" );

# Where is your git binary, and what command would you like to run?
if ( !defined( 'GIT_COMMAND' ) )
    define( 'GIT_COMMAND', 'git pull' );

# Do we want to do IP verification?
if ( !defined( 'VERIFY_IP' ) )
    define( 'VERIFY_IP', true );

# If defined, $_POST gets logged
# define( 'DUMP_POSTDATA', true );

# In your webhook URL to github, you can append ?auth={{ this field }} as a very simple gut-check authentication.
# define( 'AUTH_KEY', 'whatever-you-want' );


if ( is_writable( LOG ) && $handle = fopen( LOG, 'a' ) ) {
    # Sweet taste of victory
    if(LOG_WRITE)
        fwrite( $handle, date( 'Y-m-d H:i:s' ) . "\n==============================\n" );
    else
        @fclose( $handle );
} else {
    @fclose( $handle );
    header( $_SERVER['SERVER_PROTOCOL'] . ' 500 Internal Server Error', true, 500 );
    die( 'Please complete installation' );
}

# Do some authentication
if ( defined( 'AUTH_KEY' ) && ( !isset( $_GET['auth'] ) || AUTH_KEY != $_GET['auth'] ) ) {
    $error = "Auth key doesn't match";
} elseif ( !isset( $_POST['payload'] ) ) {
    $error = '$_POST["payload"] is not set';
} elseif ( VERIFY_IP && !in_array( $_SERVER['REMOTE_ADDR'], $authorized_ips ) ) {
    $error = "{$_SERVER['REMOTE_ADDR']} is not authorized. Authorized IPs are: " . implode( ', ', $authorized_ips );
} else {
    $error = false;
}
if ( false !== $error ) {
    if(LOG_WRITE)
        fwrite( $handle, "*** ALERT ***\nFailed attempt to access deployment script!\n\nMESSAGE: $error\n\n" . print_r( $_SERVER, 1 ) . print_r( $_REQUEST, 1 ) . "\n\n\n" );
    @fclose( $handle );
    header( $_SERVER['SERVER_PROTOCOL'] . ' 401 Unauthorized', true, 401 );
    die( "You don't have permission to access this page." );
}

# We're authorized, let's do this!
if(LOG_WRITE) {
    $content = '';
    if ( defined( 'DUMP_POSTDATA' ) )
        $content .= print_r( $_POST, 1 ) . "\n\n";

    if ( false === fwrite( $handle, $content ) ) {
        echo "Couldn't write to log!\n";
    }
}

$payload = json_decode( $_POST['payload'] );
if ( preg_match( REF_REGEX, $payload->ref ) ) {
    # If we have a commit to master, we can pull on it
    # If commit message has [deployment], pull
    $cnt = count($payload->commits);
    $is_deploy = false;

    for($i=0; $i<$cnt; $i++) {
        if(preg_match('#\[deployment\]#i', $payload->commits[$i]->message)) {
            $is_deploy = true;
            break;
        }
    }

    if($is_deploy === true) {
        $userInfo = posix_getpwuid(fileowner(__FILE__));
        $owner = $userInfo['name'];
        $output = array( 'bash> ' . sprintf(GIT_COMMAND, $owner) );
        chdir( sprintf( REPO_DIR, $payload->repository->name ) );
        exec( sprintf(GIT_COMMAND, $owner) . ' 2>&1', $output );

        if(LOG_WRITE)
            fwrite( $handle, "`$payload->ref` matches, executing:\n" . sprintf(GIT_COMMAND, $owner) . "\n" . implode( "\n", $output ) . "\n" );
    }
} else {
    if(LOG_WRITE)
        fwrite( $handle, "`$payload->ref` doesn't match the ref criteria\n" );
}

if(LOG_WRITE)
    fwrite( $handle, date( 'Y-m-d H:i:s' ) . " Over and out!\n\n\n" );
@fclose( $handle );

?>

6. deploy-config.php를 같은 위치에 생성

 

파일 내용중, 
define( 'REF_REGEX', '#^refs/heads/master$#' ); 의 경우,
최근에 생성한 마스터 브랜치는 main이므로
define( 'REF_REGEX', '#^refs/heads/main$#' );
로 변경해야 합니다.
<?php
# A regex matching the ref of the "push". <code>git pull</code> will only run if this matches. Default is the master branch.
define( 'REF_REGEX', '#^refs/heads/master$#' );

# Write Log File
define('LOG_WRITE', true);

# Log location; make sure it exists
define( 'LOG', '../logs/deploy.log' );

# Where is your repo directory? This script will chdir to it. If %s is present, it gets replaced with the repository name
define( 'REPO_DIR', dirname( __FILE__ ) . "/" );

# If set to true, $_POST gets logged
define( 'DUMP_POSTDATA', false );

# In your webhook URL to github, you can append ?auth={{ this field }} as a very simple gut-check authentication
define( 'AUTH_KEY', 'some_auth_key' );

# Where is your git binary, and what command would you like to run?
define( 'GIT_COMMAND', 'sudo -u %s /usr/bin/git pull' );

# Do we want to do IP verification?
define( 'VERIFY_IP', false );
?>

위 파일의 some_auth_key 를 어려운 암호로 임의로 생성 --> 나중에 github 웹훅에 사용.

 

웹훅 등록

github > 나의 repository > Settings > Webhooks

 

sudo mkdir -p /var/www/git-deploy-log
sudo chown ubuntu: /var/www/git-deploy-log
sudo chmod 707 /var/www/git-deploy-log
touch /var/www/git-deploy-log/deploy_bi.log
chmod 777 /var/www/git-deploy-log/deploy_bi.log

댓글