2019년도에 회사 내에서 GITLAB 을 이용하여 배포 자동화 작업을 하면서 작성했던 내용입니다. 설치형 GitLab 기준으로 작성한 내용이며 gitlab-runner 사용에 대한 내용은 포함되어 있지 않습니다.

Apache 내에서 특정 Document Root 를 바라보고 있을 때 rsync 를 이용하여 웹 서비스를 배포하는 내용을 담고 있습니다. 다른 방식으로 배포하는 것을 참고하려면 이 글과는 맞지 않으니 다른 글을 참고하세요.

 

배포 전략

rsync 를 통해 운영 서버에 업로드하며 롤링 배포를 심볼릭 링크를 이용하여 기존 버전을 교체하는 방식으로 진행할 것이다.

  1. 저장소에서 TAG Push 를 통해 배포를 한다.
  2. CI/CD 파이프라인 내에서 rsync 를 통해 업로드를 한다.
    1. CI/CD Variables 를 이용하여 Runner 에서 SSH 비밀키와 config 를 설정을 먼저 진행한다.
    2. 배포 서버에 미리 만들어놓은 releases 폴더 안에 Push 했던 TAG 이름으로 디렉토리를 만든다.
    3. 해당 디렉토리에 rsync 를 이용하여 파일 및 디렉토리를 모두 배포한다.
  3. releases 폴더와 같은 depth 에 최근에 배포한 TAG 이름의 디렉토리를 current 라는 이름으로 심볼릭 링크를 만들거나 대체한다.
  4. releases 폴더 내부에서 TAG 이름 디렉토리를 내림차순으로 정렬한 후 5개만 남겨두고 나머지는 삭제한다.

 

RUNNER 구성

GITLAB CI/CD 를 이용하기 위해서는 각 프로젝트에 미리 RUNNER 를 구성해주어야 한다.

GITLAB 관리자 영역 페이지에 들어간 후 'RUNNER' 메뉴에서 현재 작동되고 있는 RUNNER 로 들어간 후 프로젝트별로 검색을 해서 RUNNER 활성화를 시켜주면 된다.

 

목적지 서버 계정 생성

실서버에서 배포 담당으로 역할을 맡을 계정을 생성한다. 예를 들면, git 이라던지의 이름으로 계정을 생성한다.

mkdir, git 과 같은 기본적인 명령어는 사용할 수 있도록 권한을 미리 체크한다.

 

SSH KEY 할당

RUNNER 에서 ssh, rsync 를 이용하여 배포하려는 서버에 접속하려는 경우에 필요하다.

비밀키, 공개키 생성

GITLAB 에서는 비밀키로, 접근하려는 서버에서는 ~/.ssh/authorized_keys 에 공개키를 추가해서 진행할 것이다.

우선은 키를 생성해야 한다.

Key 생성

$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/user/karsei/.ssh/id_rsa):
/home/user/karsei/.ssh/id_rsa already exists.
Overwrite (y/n)? y
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/user/karsei/.ssh/id_rsa.
Your public key has been saved in /home/user/karsei/.ssh/id_rsa.pub.
The key fingerprint is:
c8:9d:62:57:5d:5e:d7:c8:84:0c:f2:1d:bd:91:69:18 karsei@somehost
The key's randomart image is:
+--[ RSA 2048]----+
|        . .oEBo++|
|         o o++O.o|
|          o o..o |
|     . o o    .  |
|      = S        |
|     . o         |
|                 |
|                 |
|                 |
+-----------------+

공개키 등록

배포하려는 서버에서는 SSH 공개키 접속으로 RUNNER 가 접근할 수 있도록 공개키를 등록해주어야 한다.

$ cat id_rsa.pub >> authorized_keys

공개키 권한 설정

권한이 너무 많이 열려있으면 SSH 접속 시 아예 인증방식을 무시하거나 안된다고 오류가 나타나므로 반드시 권한 설정을 해주어야 한다.

$ chmod 700 .ssh
$ chmod 600 .ssh/authorized_keys
$ chmod 600 .ssh/id_rsa

비밀키 등록

RUNNER 에서 비밀키를 CI/CD 파이프라인에서 사용할 수 있도록 Variables 에 등록한다.

저장소나 그룹의 Setting > CI/CD > Variables 로 들어가면 등록할 수 있다.

ssh config 로 사용할 변수와 비밀키를 담은 변수 하나씩을 만들어주었다.

ssh config 같은 경우는 RUNNER 에서 SSH 접속을 할 때 위의 Public Key 를 생성할 때 같이 생성된 Private Key 를 이용해서 접근해야 하므로 따로 config 설정을 통해 해당 Private Key 를 이용하도록 설정해주어야 한다.

Private Key 내부 내용을 복사하여 클라이언트에 따로 파일로 만든 후 해당 파일을 이용하는 방식으로 진행한다.

 

참고로 .gitlab-ci.yml 파일에서 $로 변수를 사용할 수 있다.

  • known host 를 암묵적으로 yes 로 취급할 것이므로 StrictHostKeyChecking 을 no 로 맞춘다.
Host 123.123.123.123
StrictHostKeyChecking no
IdentityFile ~/.ssh/prod

예를 들면 위와 같은 내용을 SSH_CONFIG 라는 변수키를 만들고 CI/CD 파이프라인에서 아래처럼 배포 스크립트에서 이용할 수 있도록 하였다.

# SSH 설정
.set_ssh: &set_ssh |
    echo "Set SSH"
    mkdir -p ~/.ssh
    chmod 700 ~/.ssh
    touch ~/.ssh/id_rsa
    echo "$SSH_PRIVATE_KEY_PROD" > ~/.ssh/prod
    chmod 400 ~/.ssh/prod
    echo "$SSH_CONFIG" > ~/.ssh/config

 

방화벽 허용

배포를 할 때에는 ssh와 rsync 를 이용할 것이기 때문에 22번 포트를 미리 열어주어야 한다.

 

배포 폴더 생성

releases 라는 폴더를 만들고 해당 폴더 내에 태그별로 디렉토리를 생성하여 배포한 후 releases 폴더와 같은 depth 에서 current 라는 심볼릭 링크를 만들어서 교체를 진행할 것이다.

아래처럼 구성하여 배포할 것이기 때문에 배포할 메인 경로에 미리 releases 폴더를 만들어 둔다.

$ ll
lrwxr-xr-x  1 karsei  staff    17B  2 18 13:05 current -> ./releases/v1.1.2
drwxr-xr-x  6 karsei  staff   192B  2 18 13:05 releases

$ ll releases
drwxr-xr-x  2 karsei  staff    64B  2 18 13:05 v1.0.0
drwxr-xr-x  2 karsei  staff    64B  2 18 13:05 v1.1.0
drwxr-xr-x  2 karsei  staff    64B  2 18 13:05 v1.1.1
drwxr-xr-x  2 karsei  staff    64B  2 18 13:05 v1.1.2

 

rsync 예외 파일 생성

GIT 에서 예외를 지정하는 .gitignore 처럼 rsync 도 예외를 지정하는 .rsyncignore 라는 파일로 관리할 수 있다.

rsync 로 배포할 때 README.md 또는 .gitignore 같은 것들은 배포하지 않아도 되므로 예외로 추가할 수 있다.

 

.gitlab-ci.yml 작성

https://docs.gitlab.com/ee/ci/yaml/README.html에 어떻게 작성하면 되는지 나와 있다. 예시로 작성된 yml 파일을 참고해도 좋다.

SSH 설정

공개키, 비밀키 방식으로 진행할 것이기 때문에 SSH 설정을 진행하기 위해 위에서도 언급했지만 아래와 같이 템플릿을 제작한다.

# SSH 설정
.set_ssh: &set_ssh |
    echo "Set SSH"
    mkdir -p ~/.ssh
    chmod 700 ~/.ssh
    touch ~/.ssh/id_rsa
    echo "$SSH_PRIVATE_KEY_PROD" > ~/.ssh/prod
    chmod 400 ~/.ssh/prod
    echo "$SSH_CONFIG" > ~/.ssh/config

 

기존 버전 삭제

계속 배포를 하다보면 기존 버전들이 계속 쌓일 것이므로 기존 버전들을 삭제하는 작업이 필요하다.

아래와 같이 버전들이 많을 경우 시간순으로 정렬하고 tail 을 통해 삭제할 수 있다.

  • ls -t : 파일을 수정한 시간 기준으로 정렬하여 출력한다.
  • tail -n N : 원하는 N개 만큼의 라인을 출력한다.
  • tail -n +N : N번째를 포함한 이후의 라인을 출력한다.
$ ls -t
v1.2.1 v1.2.0 v1.1.4 v1.1.3 v1.1.2 v1.1.1 v1.1.0 v1.0.0

$ ls -t | tail -n +6
v1.1.1
v1.1.0
v1.0.0

템플릿을 만들어준다.

# 기존 배포 버전 삭제
.gc_script: &gc_script |
    ssh -T "$USER"@"$SERVER" cd "$APP_PATH/releases && ls -t | tail -n +6 && ls -t | tail -n +6 | xargs rm -rf";

 

rsync 배포

  • rsync
    • a : 아카이브 모드로 실행 (-rlptgoD 옵션과 동일. 모든 디렉토리 및 파일 복사하되 소유자, 그룹, 권한, 심볼릭, 장치까지 유지)
    • r : 재귀적으로 디렉토리까지 복사
    • t : 타임스탬프 보존
    • l : 심볼릭 링크 보존
    • p : permission 보존
    • i : 변경사항 출력
  • ln
    • f : 동일한 링크 파일이 있을 경우 기존 파일을 지우고 다시 생성
    • s : 심볼릭 링크 생성
    • n : 대상 파일이 심볼릭 링크면 기존 심볼릭 링크의 정보로 연결
# RSYNC 배포
.deploy_script: &deploy_script
    script:
        # ssh 설정
        - *set_ssh

        # 배포 및 로컬 파일과 비교
        - rsync -artlp --ignore-existing --exclude-from='.rsyncignore' ./ "$USER"@"$SERVER":"$RSYNC_TO_PATH"
        - compare=`rsync -artlpi --dry-run --ignore-existing --exclude-from='.rsyncignore' ./ "$USER"@"$SERVER":"$RSYNC_TO_PATH"`;
        - if [ "$compare" == "" ]; then true; else echo $compare; false; fi;

        # 심볼릭 연결
        - ssh -T "$USER"@"$SERVER" ln -fsn "$SYMBOLIC_TARGET_PATH" "$SYMBOLIC_LINK_PATH"

        # 기존 버전 정리
        - *gc_script

 

stage 작성

배포 서버의 유저와 호스트를 variables 로 작성 후 위의 템플릿을 실행하도록 해준다.

# 서버 배포
deploy_prod:
    stage: deploy_prod
    variables:
        USER: git
        SERVER: 123.123.123.123

        APP_PATH: /www/someapp.some.com
        SYMBOLIC_LINK_PATH: /www/someapp.some.com

    <<: *deploy_script

    only:
        refs:
            - /release\/v(\d+).(\d+).((\d+)|(\d+).(\d+))$/