
네이버 부스트캠프 웹 모바일 8기를 진행하면서 팀 프로젝트를 수행했을 때, 각 기능 개발이 완료되고 버전마다 배포를 해야하거나, 변경된 기능을 실 서버에 적용해야 할 때마다 직접 Ubuntu 서버 콘솔을 열어 Object Storage로 push한 docker Image를 pull 해야하는 번거롭고 불편한 단점이 있었다.
이때문에 여러 과정을 통한 개선점을 이루었는데 해당 과정을 차례대로 적어 정리해보려 한다.
Ubuntu환경에서 Linux 명령어를 통한 sh파일에서 crontab을 활용해 주기적으로 업데이틑 하는 방법이 있었다.
이러한 방법은 일정 시간마다 자동적으로 github에 업로드된 dev branch의 코드를 pull해와 서버를 재시작하는 방법으로 업데이트를 할 수 있었다.
crontab -e
---> 이 명령어를 통해 ubuntu 환경에서 crontab 설정할 수 있다.
0 12 * * * /path/to/git_pull.sh
---> 매일 12시마다 path 경로에 있는 github code를 pull 하는 코드를 담은 shell script 파일 실행하도록 설정.
git_pull.sh 파일 코드
cd /path/to/your/repository
---> git pull을 위해 서버가 실행되는 OS내 서버 프로젝트 디렉토리로 이동
git pull origin(remote로 설정한 이름) main
---> 해당 프로젝트 디렉토리에서 git pull 실행. ( git fetch 도 가능 )
그러나, 위 방법은 서버 코드가 변경되지 않아도 정해진 시간마다 불필요하게 github로부터 코드를 pull한다는 것과 이러한 과정에서 매번 서버의 실행이 중단되었다 재실행이 되는 크나큰 단점이 있었다.
이러한 단점을 해결하기 위해서 Docker와 github action을 CI/CD의 도구로 선택하게 되었다.

Docker는 가상 컨테이너를 관리하는 프레임워크라고 할 수 있다.
Docker를 이용해 가상 컨테이너를 생성하고 해당 컨테이너에서 내가 원하는 작업을 할 수 있다.
이러한 특징이 어떤 점이 CI/CD를 더 효율적으로 작업하게 할 수 있을까?
바로 "독립된 환경" 이다.
가상 컨테이너는 서로 모두 독립적으로 작동한다.
( 하나의 컨테이너가 종료되어도 다른 컨테이너에 영향을 미치지 않는다 )
Crontab에서 언급한 단점중 하나는, 무중단 배포가 어렵다는 것이었다.
그러나 이 Docker를 이용하면 기존 실행하는 서버 컨테이너와 별개의 컨테이너를 하나 생성하고 해당 컨테이너에 변경된 서버를 적용한 후 서버의 접근을 해당 컨테이너로 변경한다면 사용자는 서버의 중단없이 어느 순간부터 변경된 서버를 이용할 수 있다는 것이다.



다른 장점으로는 변경되지 않았을 때는 가져오지 않는다는 것이다.
Crontab의 경우에는 선택의 여지가 없이 일정시간마다 github dir을 pull해와야 했지만, docker의 경우에는 github action을 이용해 trigger가 발생할 때에만 업데이트를 진행할 수 있다.
Github Action은 Github 작업 브랜치가 변경되어 이를 트리거로 자동 CI/CD를 진행하려 할 때 사용하기 좋은 기능이다.
프로젝트 디렉토리의 workflow.yml 파일 설정을 통해서 타겟 브랜치가 변경되었을 때 이를 트리거로 여러 작업을 진행할 수 있다.
나의 경우에는 Ncloud의 Object Storage에 Docker Image 파일을 업로드한 후, ssh로 WAS에 접속하여 docker pull을 이용해 업데이트를 진행했다.
이러한 과정에서 마주했던 난감한 상황도 물론 있었다.
서버를 업데이트하면서 Docker 컨테이너를 새로 생성하는 경우 해당 컨테이너에는 typrORM config와 같은 DB설정이나 Object Storage config 정보가 없다.
이를 전달하기 위해서 docker container로 직접 값을 입력하는 것은 자동화가 절대 아니기에 고민에 빠졌었다.
해결방법은 Github Secret Key였다.
Github Secret Key로 미리 등록해둔 config 정보들을 github workflow에서 template literal 방식으로 호출함으로써 해당 정보를 은닉하면서 새로 생성하는 컨테이너에 안정적으로 설정을 적용할 수 있었다.

name: auto deploy
on:
push:
branches:
- develop/be
jobs:
push_to_registry:
name: Push to ncp container registry
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to NCP Container Registry
uses: docker/login-action@v2
with:
registry: ${{ secrets.NCP_CONTAINER_REGISTRY }}
username: ${{ secrets.NCP_ACCESS_KEY }}
password: ${{ secrets.NCP_SECRET_KEY }}
- name: Create config file
run: |
echo "export const awsConfig = ${OBJECT_STORAGE_CONFIG}" > ./be/objectStorage.config.ts
env:
OBJECT_STORAGE_CONFIG: ${{ secrets.OBJECT_STORAGE_CONFIG }}
- name: Create TypeORM config
run: |
mkdir -p ./be/src/configs
echo "import { TypeOrmModuleOptions } from '@nestjs/typeorm';" > ./be/src/configs/typeorm.config.ts
echo "export const typeORMConfig: TypeOrmModuleOptions = ${TYPEORM_CONFIG}" >> ./be/src/configs/typeorm.config.ts
env:
TYPEORM_CONFIG: ${{ secrets.TYPEORM_CONFIG }}
- name: build and push
uses: docker/build-push-action@v3
with:
context: ./be
file: ./be/Dockerfile
push: true
tags: ${{ secrets.NCP_CONTAINER_REGISTRY }}/nibobnebob:latest
cache-from: type=registry,ref=${{ secrets.NCP_CONTAINER_REGISTRY }}/nibobnebob:latest
cache-to: type=inline