NestJS 프로젝트를 진행하면서 docker와 github action을 사용하여 CI(Continuous Integration)와 CD(Continuous Deployment) 작업을 진행하게 되어 작업한 내용을 정리하고자 한다.
프로젝트 경로에 Dockerfile을 추가해주자.
FROM node:16.15.1
RUN mkdir -p /app
WORKDIR /app
COPY package*.json /app/
RUN npm install
COPY . /app/
EXPOSE 3000
CMD ["npm", "run", "start:dev"]
데이터베이스는 mysql을 사용하였다.
mysql:5.7 이미지를 사용하였으며 웹과 함께 사용하기 위해 docker compose로 묶어주었다.
version: '3'
services:
db:
image: mysql:5.7
container_name: mysql
env_file: ./.env
volumes:
- ./database/data:/var/lib/mysql
ports:
- 3307:3306
environment:
MYSQL_ROOT_PASSWORD: mysql_password
MYSQL_DATABASE: database_name
networks:
- server
web:
image: ci-cd-prac
container_name: web_server
env_file: ./.env
restart: always
ports:
- 3333:3000
depends_on:
- db
networks:
- server
networks:
server:
master 브랜치에 해당 이벤트가 발생하면 도커허브에 로그인하여 변경사항이 반영된 이미지를 생성해 올리도록 작업을 설정해주었다.
여기서 사용하는 변수들은 repository secret 변수에 등록해주어야 사용이 가능하다! (CD 뒷 부분에 방법을 작성해두었다.)
name: Docker Image CI
on:
push:
pull_request_target:
branches: [master]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Login to DockerHub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}
- name: Build and push
uses: docker/build-push-action@v2
with:
context: .
push: true
tags: ${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKER_IMAGE_NAME }}:latest
AMI는 인스턴스를 시작하는 최초의 운영체제를 의미하는데, ubuntu server 20.04 버전 으로 설정해주었다.
.pem
파일 형식으로 키 페어를 생성해준다. (ssh 연결에 사용되니 잘 저장해두자!)
네트워크나 다른 설정은 기본 값으로 두고 진행하였다.
인스턴스를 생성한 뒤에는 인스턴스 상세 화면에서 보안 그룹을 확인할 수 있다.
보안 그룹을 클릭하여 인바운드 규칙을 추가해주자!
기본으로 ssh 연결을 위해 22 포트가 설정되어 있는데 필요한 포트를 추가적으로 열어줘야 접근이 가능하다.
인스턴스를 중지했다가 다시 시작하면 IP가 계속 바뀌기 때문에 고정적인 IP 사용을 위해 탄력적 IP (Elastic) IP를 설정해주자.
IP 할당 후 생성된 IP로 들어가 앞서 생성한 인스턴스를 연결해주면 된다.
(인스턴스를 더이상 사용하지 않아 중지할 때에는 IP도 함께 릴리즈해야 한다는 것을 잊지 말자!!)
EC2로 인스턴스에 ssh를 사용하여 접속해보자.
생성한 인스턴스의 Connect 탭으로 들어가 SSH Client 부분에서 자신의 환경에 맞는 명령어를 확인할 수 있으니 그대로 진행하면 된다!
접속한 서버에 docker를 설치해주자.
$ sudo apt-get update
$ sudo apt-get install apt-transport-https ca-certificates curl gnupg lsb-release
$ sudo mkdir -p /etc/apt/keyrings
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
$ echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu / $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
$ sudo apt-get update
$ sudo apt-get install docker-ce docker-ce-cli containerd.io
이후 docker 명령을 입력하면 docker 명령어들이 나오는데 그렇게 나오면 docker가 잘 설치된 것이다.
이제 Gthub actions 설정을 해주자.
name: build and deploy
on:
push:
branches: [master]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Login to DockerHub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}
- name: Build and push
uses: docker/build-push-action@v2
with:
context: .
push: true
tags: ${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKER_IMAGE_NAME }}:latest
deploy:
needs: build
runs-on: ubuntu-latest
steps:
- name: ssh connect & production
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.HOST }}
username: ${{ secrets.USERNAME }}
password: ${{ secrets.PASSWORD }}
port: ${{ secrets.PORT }}
script: |
cd project_dir
docker system prune -a --volumes -f
docker compose pull -q
docker compose up --force-recreate --build -d --quiet-pull 2>log.out
cat log.out
master 브랜치에 push 이벤트가 발생했을 때 해당 작업을 수행하도록 워크플로우를 작성해준다.
ssh 배포에 https://github.com/appleboy/ssh-action 를 활용하는데 private key나 password를 사용해 ssh 접속이 가능하다. 나는 password를 사용해 접속하는 방법을 선택했기 때문에 비밀번호를 생성해준 뒤 repository의 secret 변수로 등록해줘야한다.
ssh로 접속해서 아래의 명령을 통해 password 설정이 가능하다.
$ sudo passwd <username>
password를 사용한 접속을 허용하기 위해 sshd_config 파일에 PasswordAuthentication 을 yes로 변경해준다.
$ sudo vi /etc/ssh/sshd_config
이후 restart해주면 적용이 된다!
$ service ssh restart
yml에서 사용한 secret 변수들을 설정해주자!
repository의 settings-security-secrets-actions 탭에 들어가서 변수를 추가할 수 있다.
윗 단계까지 진행하고 push를 하면
err: Got permission denied while trying to connect to the Docker daemon socket
과 같은 에러가 발생할 수 있다.
이는 docker group에 해당 유저가 없어서 생기는 에러인데 docker group에 추가만 해주면 바로 해결된다!
$ sudo groupadd docker
$ sudo usermod -aG docker $USER
$ newgrp docker
참고
https://docs.docker.com/engine/install/ubuntu/
https://github.com/appleboy/ssh-action
https://velog.io/@combi_jihoon/Docker-AWS-EC2-%EB%9D%84%EC%9A%B0%EA%B8%B0
https://goodgid.github.io/Github-Action-CI-CD-AWS-EC2/
https://seulcode.tistory.com/557