Gitlab-CI 구성 & .gitlab-ci.yml 예제
CI/CD 도입
Gitlab을 설치하는 방법은 전에 다뤘다. 이번에는 CI/CD 도구를 도입했다. 예전에 일했던 프로젝트에서는 주로 jenkins를 사용했는데, 이번에는 Gitlab-CI를 써보기로 했다. Git 초심자가 대부분인 우리 프로젝트 특성상, Gitlab과 연계가 긴밀한 Gitlab-CI를 선택하는 편이 Git 보급에 유리할 듯 싶었다. Gitlab-CI과 jenkins의 비교는 하기 링크를 참조했다. 물론 애시당초 jenkins와 Gitlab-CI는 같은 선상에서 비교할만한 도구도 아니긴 하다.
Gitlab-CI versus jenkins
Gitlab-CI 구성
올라운드플레이어님의 이 글에 설명이 잘 되어 있다. 그냥 따라하기만 하면 된다. 너무 좋아서 뽀뽀해주고 싶을 정도. Gitlab-CI 공식 문서도 충실하다. 하지만 gitlab-runner가 어떤 작업을 수행할지 설정해줘야 한다. 이건 .gitlab-ci.yml 에 기입해줘야 한다.
.gitlab-ci.yml 구성
이제 내가 원하는 작업을 gitlab-runner가 수행하도록 .gitlab-ci.yml를 짜보자. 이 또한 그리 어렵지 않다. script: 아래의 한 줄은 gitlab-runner register에서 7번째로 설정하는 Please enter the executor에 입력한 executor에서의 명령어 한 번씩이다. 예를 들어 shell을 executor로 선택하고 하기 스크립트로 .gitlab-ci.yml을 구성하면,
script:
- echo hello
- dir
아래와 같은 결과가 나온다.
hello # echo hello의 결과
c:\blah\blah\blah # dir의 결과
예제: 단순 배포
이제 소스코드를 copy & paste 하는 단순 작업 수행 .gitlab-ci.yml을 구성해보자. only 는 git의 어느 branch의 변화에 반응하느냐를 기술한 것이다.
예를 들어
only:
- master
는 master 브랜치에 커밋이나 변경 사항이 있을 때만 동작한다.
배포 target 서버에 gitlab-runner를 register한 후, 하기 .gitlab-ci.yml 예시를 돌려보자. master 브랜치와 develop 브랜치에 push가 들어오면, 각각 하기의 script를 실행한다. Windows 환경에서 shell을 executor로 하여 xcopy 명령어를 활용하였다.
# master 브랜치에 push가 들어올 때 동작하는 job
deploy-to-production-server:
only:
- master
script:
- xcopy . D:\운영서버의\코드들어갈_위치\ /h /k /y /e /r /d
# develop 브랜치에 push가 들어올 때 동작하는 job
deploy-to-develop-server:
only:
- develop
script:
- xcopy . D:\개발서버의\코드들어갈_위치\ /h /k /y /e /r /d
허접하지만 단순 배포를 위해서는 잘 돌아간다. Anyway, It works! 하지만 개발서버와 운영서버를 따로 구축해놓은 경우에는 조금 복잡해진다. 또한 운영 중인 서비스가 많을 경우, 서비스마다 gitlab-runner를 register하기도 어렵다.
예제: Shared Runners를 활용한 원격 배포
위 단순 배포 예제의 문제점을 해결하려면 Shared Runners로 원격 서버의 디스크를 마운트하여 배포하면 된다. 단순 배포 예제에서처럼 하나의 프로젝트에 하나의 gitlab-runner를 등록하는 경우를 Specific Runners라고 하는데, Shared Runners와 Specific Runners의 차이점은 공식 문서에 잘 나와있다. 특별히 복잡한 스크립트를 실행하여 특별 관리가 필요한 프로젝트가 아니라면 Shared Runners를 사용하는게 편하다. Shared Runners의 설정 방법은 여기를 참고하면 된다. 아래 .gitlab-ci.yml은 Windows 환경에서 shell을 executor로 돌린다.
deploy to production:
stage: deploy # 따로 설정해두지 않으면 기본값인 test로 박힌다
environment: # 서버별로 따로 설정해두는 편이 나중에 롤백하기 편하다
name: production server
only:
- master
script:
- echo 'deploy to production server'
- 'net use o: \\서버IP\소스코드_경로 서버접속PW /user:서버접속ID' # 배포할 원격 서버의 경로를 o드라이브로 잡는다
- 'xcopy . o:\ /h /k /y /e /r /d' # 배포
after_script: # script실행시 에러가 발생해도 이 after_script 구문은 반드시 실행한다
- 'net use /delete o:' # 원격 드라이브의 연결을 해제
deploy to develop:
stage: deploy
only:
- develop
- branches # 가끔 급히 branch를 push해서 개발서버에 배포해야 할 때도 있다
except:
- master # master 브랜치와는 확실히 분리해준다. 예시를 위해 추가한 구문이니 빼도 상관없다
environment:
name: develop server
script:
- echo 'deploy to develop server'
- 'net use o: \\서버IP\소스코드_경로 서버접속PW /user:서버접속ID'
- 'xcopy . o:\ /h /k /y /e /r /d'
after_script:
- 'net use /delete o:'
예제: stages와 cache 적용
위 예제에서는 1번의 배포를 할 때 1개의 job을 실행했다. 이번 예제에서는 stage와 cache를 추가했다.
- stages를 등록하면 여러 개의 job을 순차적으로 실행할 수 있다.
- cache를 설정하면 과거에 수행한 job에서 만든 캐시를 사용할 수 있다. 따라서 npm install처럼 인터넷에서 라이브러리 등을 매번 다운받아야 하는 지점에 사용하면 배포 시간을 단축할 수 있다. 자세한 내용은 공식 문서 참조.
# deploy -> foreign_survey_build 순서로 job이 실행된다
# deploy 먼저 실행하는 이유는, npm install과 build에 시간이 많이 걸리기 때문이다
stages:
- deploy
- foreign_survey_build
# 모든 job이 끝날 때마다 after_script를 실행한다
after_script:
- 'net use /delete o:'
# 모든 job의 이름은 unique 해야 한다
deploy-to-dev:
stage: deploy # deploy 차례(stage)에 실행되는 job이다
environment:
name: development server
only:
- develop
- branches
except:
- master
script:
- echo 'deploy to develop server'
- 'net use o: \\서버IP\소스코드_경로 서버접속PW /user:서버접속ID'
- 'xcopy . o:\ /h /k /y /e /r /d /exclude:.\gitlab-ci-copy-exclude-list.txt'
deploy-to-prod:
stage: deploy # stage: deploy인 job이 2개가 있는데, 이럴 경우에 두 job은 병렬로 실행된다
environment:
name: production server
only:
- master
script:
- echo 'deploy to production server'
- 'net use o: \\서버IP\소스코드_경로 서버접속PW /user:서버접속ID'
- 'xcopy . o:\ /h /k /y /e /r /d /exclude:.\gitlab-ci-copy-exclude-list.txt'
foreign-survey-build-to-dev:
stage: foreign_survey_build
only:
- develop
- branches
except:
- master
environment:
name: development server
script:
- echo 'foreign_survey is being builded to develop server'
- cd foreign_survey\client # 일부 모듈만 npm을 사용하여 이렇게 구성했다
- call npm install # cache가 있고 package.json이 변경되지 않았으면, cache로 저장된 파일(압축 저장되어 있음)을 사용한다.
- call npm run build
- 'net use o: \\서버IP\소스코드_경로 서버접속PW /user:서버접속ID'
- 'xcopy dist\. o:\foreign_survey\client\dist\ /h /k /y /e /r'
cache:
key: ${CI_COMMIT_REF_SLUG} # 이 브랜치(master)에서 만들어둔 cache를 사용한다
paths:
- foreign_survey/client/node_modules/ # cache할 디렉토리를 정의한다
foreign-survey-build-to-prod:
stage: foreign_survey_build
environment:
name: production server
only:
- master
script:
- echo 'foreign_survey is being builded to production server'
- cd foreign_survey\client
- call npm install
- call npm run build
- 'net use o: \\서버IP\소스코드_경로 서버접속PW /user:서버접속ID'
- 'xcopy dist\. o:\foreign_survey\client\dist\ /h /k /y /e /r'
cache: # cache는 job을 실행하면서 존재 여부를 check하고, script를 다 실행한 이후에 다시 한 번 cache한다.
key: ${CI_COMMIT_REF_SLUG}
paths:
- foreign_survey/client/node_modules/
위 예제에서는 branch를 기준으로 cache를 저장한다. 하지만 하나의 상위 프로젝트 안에 여러 개의 하위 Node 프로젝트가 들어 있고, 각각의 stage에서 build를 하는 경우에는 branch만을 기준으로는 cache를 저장해봐야 소용없다. 아래처럼 설정하면 stage & branch 별로 cache를 저장할 수 있다.
# ...
cache:
key: "$CI_JOB_STAGE-$CI_COMMIT_REF_SLUG"
# ...
동일 branch 내에서 cache를 공유하는 방법에 대한 자세한 내용은 여기를 참조하시라.
배포 지옥에서 해방되길 간절히 바랍니다!
끝!
Leave a comment