⚠️ 문제
- 프로젝트를 ec2에 배포 할 때, 변경 사항이 생길 때마다 리포지토리 pull을 받고
pm2
를 다시 돌리고 하는 작업을 반복했다. - 이 과정에서 pm2의 모든 프로세스를 kill 하고 다시 restart 하는 일을 반복했는데, restart를 할 때면 계속 같은 문제에 직면했다…😭
"Current process list running is not in sync with saved list. npm differs. Type 'pm2 save' to synchronize."
- 이 에러가 떴는데, 기존에 돌아가던 pm2의 모든 프로세스를 중단했는데도 이미 기존 프로세스는 돌아가고 있는 걸로 나오는 거였다…..
- 이미 많은 사람들이 해당 문제 때문에 고통을 겪고 있었고
dump
파일이 덮어씌워지면서 충돌을 일으킨 것 같다. - 대부분의 해결방법이 “pm2를 업데이트해라.” 였고 해당 방법대로는 해결이 안됐고 결국 pm2를 삭제하고 다시 깔면 해당 문제가 해결이 됐었다.
- 프로젝트를 배포할 때마다,, 이 과정을 반복하기에는 무리라는 판단에,, 한이음에서 제공해주는 GitLab에서 파이프라인을 가동시켜서 배포를 자동화 하기로 했다..!!
- 마침 GitLab을 이용한 CI/CD 핸즈온 수업이 있었고 해당 수업을 들으며 기본적으로 웹서버에 어떻게 깃랩 러너를 구축할 수 있는지를 배워왔다.
- 관련 레퍼런스
- 여기 링크에 나와있는대로 우리 프로젝트의 aws 인스턴스에 도커 기반의 깃랩 러너를 설치했다.
🏃 시도
Try 1
stages:
- server_build
- client_build
image: node:latest
server_build:
stage: server_build
script:
- cd /builds/22_HF077/gongants_untact_study_room-deploy/server/
- npm run install:clean
- npm i apidoc -g
- npm install --force && apidoc -i . -o public
- npm run start
client_build:
stage: client_build
script:
- cd /builds/22_HF077/gongants_untact_study_room-deploy/client/
- npm run install:clean
- npm install --force
- npm run start
yml
파일 스크립트를 프로젝트package.json
처럼 프로젝트 실행 스크립트를 넣고 실행했다.- job은 server_build (사실상 빌드 → 배포 합쳐진 단계)와 client_build (사실상 빌드 → 배포 합쳐진 단계)로 구성했다.
⚠️ 문제
- npm으로 서버를 돌리다보니 job이 영원히 안끝난다.
물론 엄청 당연한 결과..
Try 2
stages:
- build
image: node:latest
build:
stage: build
script:
- cd /builds/22_HF077/gongants_untact_study_room-deploy/client/
- npm run deploy:install
- cd /builds/22_HF077/gongants_untact_study_room-deploy/server/
- npm i apidoc -g
- npm run deploy:install
- npm run dev
서버 빌드와 클라이언트 빌드를 하나로 합쳤다.
package.json
의 script:dev
"dev": "concurrently \"npm run start\" \"npm run frontend\"",
여기서 concurrently
는 클라이언트와 서버를 모두 구동시켜주는 모듈이다.
서버는 구동 성공! but 클라이언트는 구동 실패..!
[nodemon] starting `node index.js`
...
[1] npm run frontend exited with code 1
...
Try 2.5
- 무한 “Checking pipline status” 문제
- gitlab ci/cd 에서 무한으로 로딩 되는 현상 발생
기존 배포 방식은 개발 리포지토리에서 따로 release-x.x.x
명의 브랜치를 분기해서 배포를 진행했었다.
그런데 Github 리포지토리에서 Gitlab 리포지토리로 자동 푸쉬하는 중에 위의 무한 로딩 문제가 발생해서 중간에 한번 리포지토리를 삭제하고 다시 Github의 모든 커밋을 Gitlab으로 재 싱크하는 과정을 거쳤다.
→ 개발 리포지토리에서 문제가 발생했을 때, 배포 상황에도 문제가 발생할 수 있다는 생각에 배포 리포지토리로 따로 분리하기로 결정했다.
- 기존
- 개발 리포지토리 1
- 브랜치 분기로 배포 버전 관리
- 변경
- 개발 리포지토리 1, 배포 리포지토리 1
- 배포 리포지토리에서 업데이트 사항 로그 남기고 커밋과 태그로 관리
Try3
Gitlab 도큐먼트에서 도커 러너 위에서 도커를 또 띄워서 돌릴 수 있는 방법을 발견했다.
- 도커 러너 내부에 또 다른 도커를 띄우고 클라이언트와 서버 컨테이너 두 개를 돌리는 방법을 시도했다.
클라이언트 디렉토리와 서버 디렉토리에 각각 도커 파일을 생성해주었고 로컬 환경에서 제대로 돌아가는 걸 확인했다.
📄 client/Dockerfile
From node:16.16.0
WORKDIR /usr/app
COPY package*.json ./
RUN npm run deploy:install
COPY . .
EXPOSE 3000
CMD ["npm", "run", "deploy:production"]
📄 server/Dockerfile
From node:16.16.0
WORKDIR /usr/app
COPY package*.json ./
RUN npm run deploy:install
COPY . .
EXPOSE 4000
CMD ["npm", "run", "deploy:production"]
처음에는 러너에서 직접 도커를 돌리려면 Gitlab 러너안에 도커를 설치해줘야하는 줄 알고 도커 러너에 대화형 셸로 들어간 뒤, 도커를 설치해줬다.
- 리눅스에 도커 설치 하기
$ docker-compose exec gitlab-runner bash # 러너에 대화형 셸으로 들어가기
$ apt update
$ apt-get install -y ca-certificates curl software-properties-common apt-transport-https gnupg lsb-release
$ mkdir -p /etc/apt/keyrings
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
$ echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
$ apt update
$ apt install docker-ce docker-ce-cli containerd.io
$ apt-get install docker-ce=5:20.10.17~3-0~ubuntu-focal docker-ce-cli=5:20.10.17~3-0~ubuntu-focal containerd.io
$ docker version # 도커 설치 확인
⚠️ sudo 명령어 붙이면 오류가 발생한다!
→ 이 방법으로 러너에서 도커를 돌리는 것 까지는 됐는데, dind 방식으로 Gitlab 파이프라인을 돌리는 건 안됐다.
yaml 파일을 조금 수정해줬다.
📄 .gitlab-ci.yml
image: docker:git
services:
- docker:latest
stages:
- build
build:
stage: build
script:
- cd ./server
- docker build . -t gongants-docker/gongants-deploy:latest
- docker run -p 4000:4000 -d gongants-docker/gongants-deploy:latest
이번에도 job은 실패했고 이런 에러가 떴다.
$ docker build . -t gongants-docker/gongants-deploy:latest
error during connect: Post "http://docker:2375/v1.24/...&version=1": dial tcp: lookup docker on 172.31.0.2:53: no such host
알고 보니, 도커 데몬 권한때문에 privileged = true
로 옵션을 수정해줘야했다.
...
privileged = true
volumes = ["/cache","/var/run/docker.sock:/var/run/docker.sock"]
...
📄 config.toml
[[runners]]
name = "docker-in-docker"
url = [url]
token = [token]
executor = "docker"
[runners.custom_build_dir]
[runners.cache]
[runners.cache.s3]
[runners.cache.gcs]
[runners.cache.azure]
[runners.docker]
tls_verify = false
image = "alpine:latest"
privileged = true # (default)false -> true
disable_entrypoint_overwrite = false
oom_kill_disable = false
disable_cache = false
volumes = ["/cache","/var/run/docker.sock:/var/run/docker.sock"]
shm_size = 0
config.toml
파일에서 'privileged’ 옵션을 ‘true’로 바꿔줬다.
💡 config.toml
파일을 수정하려면 sudo 권한으로 실행해야한다.
이렇게 바꿔주니까 파이프라인의 job이 성공적으로 수행되었다!!
But,, 😭😭
$ ubuntu@ip-%%:~/gitlab-runner/config$ docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3e5a5be73311 gongants-docker/gongants-deploy:latest "docker-entrypoint.s…" 10 seconds ago Exited (1) 7 seconds ago gongantsdeploy
c0b364fbc3ba gitlab/gitlab-runner:latest "/usr/bin/dumb-init …" 34 minutes ago Up 34 minutes gitlab-runner
요로코롬 컨테이너가 시작과 동시에 꺼지는 걸 발견했고 컨테이너의 로그를 찍어봤다.
$ docker logs 3e5a5be73311
> gong_ants@2.0.0 deploy:production
> node index.js
/usr/app/node_modules/passport-oauth2/lib/strategy.js:87
if (!options.clientID) { throw new TypeError('OAuth2Strategy requires a clientID option'); }
^
TypeError: OAuth2Strategy requires a clientID option
at Strategy.OAuth2Strategy (/usr/app/node_modules/passport-oauth2/lib/strategy.js:87:34)
at new Strategy (/usr/app/node_modules/passport-google-oauth20/lib/strategy.js:52:18)
at Object.<anonymous> (/usr/app/index.js:170:3)
at Module._compile (node:internal/modules/cjs/loader:1105:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1159:10)
at Module.load (node:internal/modules/cjs/loader:981:32)
at Function.Module._load (node:internal/modules/cjs/loader:822:12)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)
at node:internal/main/run_main_module:17:47
오잉..? 🧐 googleLogin 의 clientID를 읽어오지 못하는 거였다
기존에 파이프라인에서 npm이나 pm2로 클라이언트, 서버를 돌릴 때는 Gitlab 리포지토리의 Settings
> CI/CD
> Variables
에 프로젝트 .env
파일에 있는 모든 환경변수를 넣어줘서 키 파일을 적용시킬 수 있었는데, 지금 방식은 도커 러너 내부에서 도커를 또 돌리는 방식이어서 환경변수를 또다시 설정해줘야했다.
이렇게 client/.env
의 파일과 server/.env
파일을 각각의 환경변수로 분리해서 통째로 value로 저장했다.
키 파일을 프로젝트 디렉토리 내에 직접 만들어주는 방식으로 해당 에러를 해결할 수 있었다.
$ echo "$ENV_SERVER" > ./.env
$ echo "$ENV_CLIENT" > ./.env
✨ 해결
- 최종 파일
📄 .gitlab-ci.yml
image: docker:git
services:
- docker:latest
stages:
- server-build
- server-deploy
- client-build
- client-deploy
server-build:
stage: server-build
script:
- docker system prune -af
- cd ./server/
- echo "$ENV_SERVER" > ./.env
- docker container ls -a
- docker container rm -f gongants-server
- docker build . -t gongants-docker/gongants-server:latest
server-deploy:
stage: server-deploy
script:
- docker run -d -p 4000:4000 --name gongants-server --restart always gongants-docker/gongants-server:latest
- docker container ls -a
client-build:
stage: client-build
script:
- cd ./client/
- echo "$ENV_CLIENT" > ./.env
- docker container ls -a
- docker container rm -f gongants-client
- docker build . -t gongants-docker/gongants-client:latest
client-deploy:
stage: client-deploy
script:
- docker run -d -p 3000:3000 --name gongants-client --restart always gongants-docker/gongants-client:latest
- docker container ls -a
- docker:git 간단한 리눅스 배포판에서 실행되는 git 컨테이너
- -d: 데몬모드, 백그라운드로 실행
- -p: 호스트와 컨테이너 포트 연결
- --name: 컨테이너 이름 설정(빌드 단계에서 컨테이너를 삭제할 때 동일한 컨테이너를 삭제해야하므로 필요하다)
- --restart: 컨테이너 종료 시, 재시작 정책 설정
✨ Success!
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
090d0a5c83da gongants-docker/gongants-client:latest "docker-entrypoint.s…" About an hour ago Up About an hour 0.0.0.0:3000->3000/tcp, :::3000->3000/tcp gongants-client
8e77518f8182 gongants-docker/gongants-server:latest "docker-entrypoint.s…" About an hour ago Up About an hour 0.0.0.0:4000->4000/tcp, :::4000->4000/tcp gongants-server
c0b364fbc3ba gitlab/gitlab-runner:latest "/usr/bin/dumb-init …" 13 days ago Up 9 days gitlab-runner
🔗 참고
- GITLAB으로 CI/CD 시스템 구축
- (https://workshop.infograb.io/setup-gitlab/)
- [Docker] Ubuntu에 Docker 설치하기
- (https://dongle94.github.io/docker/docker-ubuntu-install/)
- Gitlab Runner 관련 : [Gitlab] CI/CD Pipeline 사용하기
- (https://sg-choi.tistory.com/552)
- Gitlab 환경변수 관련 : Gitlab CI 작성하기
- (https://playit.tistory.com/4)
- 도커 파일 작성 : [node.js] 도커(docker) 기반으로 배포하기
- (https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=pjt3591oo&logNo=222010156379)
- [Gitlab-CI/CD] window에서 Gitlab CI/CD를 docker로 배포하는 방법
- (https://otrodevym.tistory.com/entry/CICD-window에서-Gitlab-CICD를-docker로-배포하는-방법?category=975426)
- Gitlab 환경 변수로 키파일 생성하기 : Lab 2: GitLab CI/CD environment variables
- (https://clouddocs.f5.com/training/community/nginx/html/class2/module1/lab/lab2.html)
- [Docker] Docker 데몬 시작 시 마다 container 함께 시작시키기
- (https://blog.leocat.kr/notes/2019/11/20/docker-restart-container-whenever-start-docker-desktop)
- 도커(Docker) : 포트 포워딩 설정(포트 맵핑)하기
- (https://tttsss77.tistory.com/155)
💡 깨달은 점
🥸 나중에 또 삽질하지 않기 위해 적어두는,, 깃랩 파이프라인 적용 방법 정리
- Gitlab Repository ‘Settings’ > ‘CI/CD’ > ‘Runners’ 에서 url과 토큰값을 확인한다.
- 웹 서버에 [GITLAB으로 CI/CD 시스템 구축] 이거대로 배포하려는 웹 서버에 러너를 설치한다.
- 러너가 설치된 디렉토리 내의
📄 config.toml
파일을 관리자 권한으로 실행한 뒤privileged
옵션을true
로 수정해준다. - 프로젝트 리포지토리에
.gitlab-ci.yml
이름의 yaml 파일을 생성해준다. → 생성이 완료되면 자동으로 파이프라인이 돌아간다.- yaml 문법에 유의하기!
- 문법 오류가 있을 시, 태그가 달린다. → 파이프라인 job에서 확인 가능!
'🎨 Project' 카테고리의 다른 글
[BE/Node.js] AWS S3에 log 저장하기 (0) | 2022.10.04 |
---|---|
[BE/Git] Git push 파일 용량 초과 문제 해결하기 (2) | 2022.09.06 |
[BE/Node.js] apidoc으로 api document 만들기 (0) | 2022.09.02 |
[BE/Node.js] bcrypto를 이용한 비밀번호 암호화 (0) | 2022.09.02 |