Github 액션으로 Laravel 배포 자동화 (멀티 브런치)

배경

기존 gitlab 러너를 이용해서 배포 자동화 처리를 하다가, 최근 사내 프로젝트들 관리를 github 로 전체 옮기면서 action 으로 배포 자동화를 처리하게 되었음

가정

  • Linux (ubuntu) / git 사용
  • Dev branch와 Production brnach 분리되어있음
    • 각 각 브런치별로 다른 서버를 바라봄
    • 물론 branch가 하나라면 더 쉬움 =)
  • 각 branch에 커밋 push 이벤트가 트리거 되었을때 스크립트가 실행되도록 할것

작업

1. 배포 스크립트 제작

Laravel 어플리케이션의 루트 디렉토리에 .scripts 라는 폴더를 생성하고, deploy.sh 라는 파일을 만들어 실제 배포에 관련된 로직을 작성한다 (이 글에서는 pull 을 이용하겠다)

#!/bin/bash
set -e

echo "Deployment started ..."

# Enter maintenance mode or return true
# if already is in maintenance mode
(php artisan down) || true

ENV_FILE="$(dirname "${BASH_SOURCE[0]}")/../.env"

APP_ENV=$(grep -oP "(?<=APP_ENV=).*" "$ENV_FILE")

echo "starting pulling in $APP_ENV"

# Pull the latest version of the app
if [ "$APP_ENV" = "development" ]; then
    git pull origin dev
elif [ "$APP_ENV" = "production" ]; then
    git pull origin production
fi

echo "Pulling done"


# Install composer dependencies
composer install --no-dev --no-interaction --prefer-dist --optimize-autoloader

# Clear the old cache
php artisan clear-compiled

# Recreate cache
php artisan optimize

# Run database migrations
php artisan migrate --force

# Exit maintenance mode
php artisan up

echo "Deployment finished!"

쉘스크립트에서 .env 의 APP_ENV 에 따라 다른 브런치로 부터 소스를 pulling 하게끔 만든다.

워크플로우 만들기

우선 Laravel 어플리케이션의 루트 디렉토리에 .github/workflows 라는 폴더를 만들자.

그리고 deploy.yml 이라는 파일을 생성한다

name: deploy

on:
  push:
    branches:
      - dev
      - production

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2

      - name: Deploy to server (Dev)
        if: github.ref == 'refs/heads/dev'
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.HOST }}
          username: ${{ secrets.USERNAME }}
          port: ${{ secrets.PORT }}
          key: ${{ secrets.SSHKEY }}
          script: "cd {프로젝트 경로} && ./.scripts/deploy.sh"

      - name: Deploy to server (Production)
        if: github.ref == 'refs/heads/production'
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.PRD_HOST }}
          username: ${{ secrets.PRD_USERNAME }}
          port: ${{ secrets.PRD_PORT }}
          key: ${{ secrets.PRD_SSHKEY }}
          script: "cd {프로젝트 경로} && ./.scripts/deploy.sh"

이것도 역시 deploy.sh 처럼 바라보고 있는 branch에 따라 다른 deploy.yml 이 적용되도록 설정한다. 나는 dev, production 두개 서버와 두개 브런치를 사용하므로 위와 같이 작성했다.

생성된 deploy.sh , deploy.yml 을 각 브런치에 커밋

$ git add deploy.sh deploy.yml 
$ git commit -m "Deployment automation"

각 브런치에 생성된 파일 푸시

$ git checkout -b dev // dev branch 없을 경우
$ git checkout -b production // production branch 없을 경우
$ git push -u origin dev // dev 서버에서
$ git push -u origin production // production 서버에서

SSH 키 설정

이제 서버와 github 간 연결 설정을 해야한다. 서버에서 먼저 새로운 SSH 키 쌍을 생성하자

$ ssh-keygen -t rsa -b 4096 -C "email@example.com"

파일 이름과 암호를 입력하라는 메시지가 나타나면 그냥 확인을 누르자 (기본값). 그럼 홈 디렉토리 .ssh/ 폴더 내에 공개키와 비공개키 2개의 ssh 키가 생성된다.

다음 명령을 이용해서 ssh 개인 키를 ssh-agent에 추가하자

$ eval "$(ssh-agent -s)"
$ ssh-add ~/.ssh/id_rsa

그런 다음, 다음 명령을 사용해서 공개 키를 서버 파일에 추가하자

$ cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys

SSH 키를 Github 에 복사

서버에 접근하기 위해 서버에서 발행한 ssh 키를 github에 등록해줘야한다. 프로젝트 Setting 으로 이동하여 Secrets and variables 내의 ‘Actions’ 를 클릭한다.

그런 다음 키를 추가하자. branch 가 나눠져있을 경우 키도 역시 분리되어야한다.

또한, 위에 deploy.yml 에서 정한 키 값과 동일해야한다. (PRD_HOST, PRD_PORT …)

  • 입력 예시 (PRD_ 도 다른 서버 ssh 접근을 위한 키일뿐 개념은 동일하다)
    • HOST : 서버 IP 주소
    • PORT : 서버 shh 포트 주소 (기본 22)
    • SSHKEY : 서버에서 생성한 개인키
    • USERNAME : 서버 ssh 접근 계정(whoami 로 알 수 있다)

SSHKEY는 각 서버(개발서버,운영서버)에서 다음 명령어를 입력하여 복사할 수 있다.

$ cat ~/.ssh/id_rsa

이렇게 dev, production 을 분리해서 등록해주자. (필자는 PRD_ 가 프로덕션 용이다)

Github 서버 액세스 허용

프로젝트 Setting 에 Deploy keys 로 이동한 다음, 배포키를 추가한다.

Title 은 알기 쉬운 이름으로 등록하면 된다. (개발 / 운영 두개의 서버로 나눠져있을 경우, 당연히 배포키도 두개를 생성해야한다)

Key는 각각의 서버에서 공개키를 가져와서 복사한다.

$ cat ~/.ssh/id_rsa.pub

쓰기 액세스 허용은 선택하지말고, 추가 버튼을 클릭해서 완료하자.

그런 다음, 서버에서 git remote origin을 ssh 로 등록해준다

git remote set-url origin git@github.com:USERNAME/REPOSITORY.git
git fetch

그런 다음, github 액션이 접근해서 deploy.sh 를 실행할 수 있도록 실행 권한을 부여한다.

sudo chmod +x ./REPOSITORY/.scripts/deploy.sh

끝!

이제 dev branch 나 production branch 에 커밋이 push 되면 github 액션이 트리거 / github가 ssh 로 서버 접근 / deploy.sh 이 실행되면서 저장소에 있는 소스를 pulling 할 것이다~~