728x90

⚠️ 문제

  • 프로젝트를 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의 모든 프로세스를 중단했는데도 이미 기존 프로세스는 돌아가고 있는 걸로 나오는 거였다…..
 

Not in sync? · Issue #4556 · Unitech/pm2

What's going wrong? "Current process list running is not in sync with saved list. npm differs. Type 'pm2 save' to synchronize." It does not start over at boot and sometimes gi...

github.com

  • 이미 많은 사람들이 해당 문제 때문에 고통을 겪고 있었고 dump 파일이 덮어씌워지면서 충돌을 일으킨 것 같다.
  • 대부분의 해결방법이 “pm2를 업데이트해라.” 였고 해당 방법대로는 해결이 안됐고 결국 pm2를 삭제하고 다시 깔면 해당 문제가 해결이 됐었다.

 

  • 프로젝트를 배포할 때마다,, 이 과정을 반복하기에는 무리라는 판단에,, 한이음에서 제공해주는 GitLab에서 파이프라인을 가동시켜서 배포를 자동화 하기로 했다..!!
  • 마침 GitLab을 이용한 CI/CD 핸즈온 수업이 있었고 해당 수업을 들으며 기본적으로 웹서버에 어떻게 깃랩 러너를 구축할 수 있는지를 배워왔다. 
  • 관련 레퍼런스
 

4. GitLab Runner 설치 및 구성 - Setup CI/CD System with GitLab

4. GitLab Runner 설치 및 구성 GitLab이 설치된 머신과 다른 별도의 머신에 Docker Engine과 Docker Compose를 설치합니다. Docker Compose를 사용하여 Runner를 설치하고 GitLab에 등록합니다. GitLab Runner 설치 GitLab Run

workshop.infograb.io

  • 여기 링크에 나와있는대로 우리 프로젝트의 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 에서 무한으로 로딩 되는 현상 발생
 

GitLab Checking pipeline status - running forever

I've enabled the option - Settings/General/Merge Requests/Merge Checks - Pipelines must succeed. Since then every merge requests automatically starts execution of the pipeline which is actually wha...

stackoverflow.com

 

기존 배포 방식은 개발 리포지토리에서 따로 release-x.x.x 명의 브랜치를 분기해서 배포를 진행했었다.

그런데 Github 리포지토리에서 Gitlab 리포지토리로 자동 푸쉬하는 중에 위의 무한 로딩 문제가 발생해서 중간에 한번 리포지토리를 삭제하고 다시 Github의 모든 커밋을 Gitlab으로 재 싱크하는 과정을 거쳤다.

→ 개발 리포지토리에서 문제가 발생했을 때, 배포 상황에도 문제가 발생할 수 있다는 생각에 배포 리포지토리로 따로 분리하기로 결정했다.

  • 기존
    • 개발 리포지토리 1
    • 브랜치 분기로 배포 버전 관리
  • 변경
    • 개발 리포지토리 1, 배포 리포지토리 1
    • 배포 리포지토리에서 업데이트 사항 로그 남기고 커밋과 태그로 관리

 

 

Try3

 

Use Docker to build Docker images | GitLab

Documentation for GitLab Community Edition, GitLab Enterprise Edition, Omnibus GitLab, and GitLab Runner.

docs.gitlab.com

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

 

 

 

dial tcp: lookup docker on x.x.x.x:53: no such host error runner inside docker on armhf (#4794) · Issues · GitLab.org / gitlab

Summary When running gitlab-runner inside docker on an armhf platform the following error is thrown when trying to run docker login:...

gitlab.com

알고 보니, 도커 데몬 권한때문에 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

 

 


🔗 참고

 

 


💡 깨달은 점

🥸 나중에 또 삽질하지 않기 위해 적어두는,, 깃랩 파이프라인 적용 방법 정리

  1. Gitlab Repository ‘Settings’ > ‘CI/CD’ > ‘Runners’ 에서 url과 토큰값을 확인한다.
  2. 웹 서버에 [GITLAB으로 CI/CD 시스템 구축] 이거대로 배포하려는 웹 서버에 러너를 설치한다.
  3. 러너가 설치된 디렉토리 내의📄 config.toml 파일을 관리자 권한으로 실행한 뒤 privileged 옵션을 true 로 수정해준다.
  4. 프로젝트 리포지토리에 .gitlab-ci.yml 이름의 yaml 파일을 생성해준다. → 생성이 완료되면 자동으로 파이프라인이 돌아간다.
    • yaml 문법에 유의하기!
    • 문법 오류가 있을 시, 태그가 달린다. → 파이프라인 job에서 확인 가능!
728x90