Post

[Gitlab CI/CD 1] CI 적용하고 CD는 비동기 처리하기


인턴십에서 개발에 참여한 프로젝트의 배포 자동화 업무를 담당하게 되었다. 처음에는 기존에 회사에서 사용하고 있던 방식으로 배포했는데, 이 방식이 온프레미스 서버에 수동으로 배포하는 작업이었다. 이를 위해서 애플리케이션을 로컬에서 빌드하고, 빌드한 이미지를 서버에 보낸 후 서버에 접속해서 run하는 절차를 거쳐야 했다.

불필요하게 반복적인 작업을 자주하는 것도 불편했고, 특히 빌드하는 시간동안 유의미한 작업을 할 수가 없어서 Gitlab을 이용한 CI/CD 배포 자동화에 도전하게 되었다. 적용해보고 - 피드백 받고 - 개선하는 일련의 과정을 기록해두려고 한다!


gitlab-ci.yml

(빌드 부분만 가져왔다.)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
build:
  image: docker:20.10.16
  stage: build
  services:
    - docker:20.10.16-dind
  variables:
    IMAGE_TAG: $CI_REGISTRY_IMAGE:image-$CI_COMMIT_BRANCH
  before_script:
    - cp ${QA_ENV_FILE} .env.qa
  script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD
    - docker build -t $IMAGE_TAG -f Dockerfile.qa .
    - docker push $IMAGE_TAG
  only:
    - qa
  except:
    - develop
  • docker build가 Dockerfile.qa를 이용해서 이미지를 빌드하는데, Dockerfile.qa는 .env.qa를 필요로 한다. Gitlab > Settings > CI/CD > Variables에서 설정이 필요하다.
  • before_script에서 .env.qa를 만들도록 하고 script에서 빌드할 때 이것을 이용하도록 했다. 도움이 되었던 스택오버플로우의 글을 첨부한다.

How do I add a .env file in gitlab ci during deployment stage?


Variables

  • Gitlab (적용할 프로젝트 선택) > Settings > CI/CD > Variables에 위치한다.
  • job script에서 사용할 변수들을 저장할 수 있고, 8000개까지 정의할 수 있다.
  • 단일 변수를 지정할 때는 Type을 Variable(default)로 지정해도 되는데, 현재 프로젝트처럼 .env 파일을 정의한 경우에는 Type을 File로 변경하는 것을 잊지 말자. (이 부분을 놓치면 이후에 변수나 파일이 정의되지 않았다, 찾을 수 없다는 오류와 함께 잡이 종료한다.)
  • Flag를 Expand variable reference로 지정해서 script 내에서 $로 참조할 수 있다.

Untitled


IMAGE_TAG

  • 위와 같이 스크립트를 설정하고 job을 수행하면, docker push $IMAGE_TAG로 인해 Deploy > Container Registry에 이미지가 push 된다.
  • ✅ 이미지의 이름에 경로가 포함되어 있으므로, 회사 내부 온프레미스 서버에 스크립트를 작성하여 이 경로를 통해 이미지를 pull 받아서 실행할 수 있도록 한다!

Untitled


Predefined CI/CD variables refernece

이미지 이름에서 앞부분 REPOSITORY는 경로를 의미하고, TAG는 gitlab-ci 스크립트에서 IMAGE_TAG로 설정한 부분이다.

  • $CI_REGISTRY_IMAGE : image가 저장된 registry의 경로
  • $CI_COMMIT_REF_SLUG : 현재 커밋 sha
  • $CI_COMMIT_BRANCH : 커밋이 발생한 브랜치

Gitlab 공식 문서의 Predefined CI/CD variables reference를 참고하여 적절히 설정하자!


only, except

배포 목적이라서 push 할 때마다 빌드할 필요는 없다. push할 때마다 build를 하면 container registry에 지나치게 이미지가 많아진다. qa 브랜치에 머지될 때만 파이프라인이 동작하도록 설정한다.

  • only를 이용하면 설정한 조건에서만 동작, except를 이용하면 설정한 조건 외에서 항상 동작한다.

deploy token

gitlab-ci를 통해 이미지를 빌드하면 Container Registry에 이미지가 저장된다. 사내 온프레미스 서버에서 Gitlab 서버에 접근하여 이미지를 Pull 받기 위해서는, 먼저 로그인이 필요하다. 이를 위해 Deploy Token을 발급한다.


deploy_qa.sh

내가 직접 짠 스크립트이지만, 아무래도 회사에 있는 코드이기 때문에 주석만 남기려고 한다.

1
2
3
4
5
6
7
8
9
# config

# gitlab access

# docker pull image

# docker stop old container

# docker run new container
  • image-qa 태그의 웹 이미지를 만들면 container registry에서 충돌이 날 것 같지만, 업데이트 하며 새로 Published 하기 때문에 문제 없다.
  • 현재 배포 버전에 문제가 생기면 예전 이미지로 롤백 시키고 작업을 해야하기 때문에, 가장 최신 버전의 이미지가 아닌 이전 버전의 이미지도 저장할 필요가 있다. 이를 old 태그를 붙여서 관리했다.


crontab

1
30 17 * * * /home/mint/@@@/web/deploy_qa.sh >> /home/mint/@@@/web/logs/deploy_qa.log 2>&1
1
2
3
4
$ docker images
REPOSITORY               TAG                IMAGE ID       CREATED         SIZE
@@@@@@-web               staging-current    a0740f41@@@@   18 hours ago    698MB
@@@@@@-web               staging-old        94486940@@@@   19 hours ago    698MB
1
2
3
$ docker ps
CONTAINER ID   IMAGE                              COMMAND                   CREATED             STATUS                   PORTS                                       NAMES
f3eefb3b5130   @@@@@@-web:staging-current         "docker-entrypoint.s…"    About an hour ago   Up About an hour         0.0.0.0:80->3000/tcp, :::80->3000/tcp       safety-web


피드백

여기까지 작업을 마치고 주간회의 시간에 일련의 처리 과정을 발표했다. 받은 피드백은 다음과 같다.

  • 빌드 부분을 자세히 설명하길래 gitlab-ci.yml 파일을 봤는데, 실행에 필요한 환경 변수까지 빌드 단계에서 주입하는 것은 지양해야 한다. 현재는 Dockerfile 자체가 .env의 모든 내용을 이용하도록 설계되어 있는데, 변수를 분리해라.
  • Gitlab은 CI/CD 도구인데, 현재는 CI까지만 Gitlab의 도움을 받는다. 서버에서 크론탭으로 스크립트를 실행 시킬 필요없이, 내부 서버에 접속해서 스크립트를 실행하는 것까지 Gitlab의 도움을 받아서 해결할 수 있다. 여기까지 시도해보는 것은 어떤지?



This post is licensed under CC BY 4.0 by the author.