이번 프로젝트에 Docker와 GitHub Action을 사용하여 CI/CD를 구현 해 보았다.
CI/CD는 Continuous Integration(CI) 및 Continuous Delivery(CD)의 약어 이다.
1.Continuous Integration(CI)
CI는 개발자들이 자주 자신의 코드 변경사항을 Git과 같은 중앙 저장소에 통합하는 프로세스를 말한다.각 통합은 자동화된 빌드 및 테스트를 통해 검증되므로,문제점을 조기에 발견하고 수정할 수 있게 된다.
이는 버그를 빠르게 찾아 해결하고,품질을 높이는 데 도움을 준다.
2.Continuous Delivery(CD)
CD는 CI의 자연스러운 연장선상에 있어, 소프트웨어 변경사항을 안전하고 신속하게 프로덕션 환경에 배포하는 프로세스를 의미한다.Continuous Deployment와 헷갈리기 쉬운,Deployment는 자동화된 배포를 의미하고,Delivery는 수동 배포를 포함할 수 있다.
Continuous Delivery (CD) 와 Continuous Deployment (CD) 차이
- Continuous Delivery (CD)
CI의 프로세스에 이어서,코드 변경사항을 프로덕션과 같은 환경에 배포 준비 상태로 만드는 것을 말한다.
그러나 실제로 프로덕션에 자동으로 배포하는 것은 아니다. 마지막 단계는 수동으로 수행될 수 있다.
즉,필요할때 실제 프로덕션 배포를 클릭 한 번 이나 명령어 한 줄로 할 수 있다.- Continuous Deployment (CD)
Continuous Delivery의 확장 개념으로, 코드 변경사항을 자동으로 프로덕션 환경에 배포하는 것을 말한다. 이 경우,수동 단계 없이 코드가 자동으로 프로덕션에 배포 된다.
따라서 CI/CD라는 용어는 전체적으로 Continuous Intergration 및 Continuous Delivery 또는 Continuous Deployment를 포괄하는 개념으로 사용된다.
이번에 구현한 CI/CD의 CD는 'Continuous Deployment (CD)'에 해당한다.
main 브랜치에 해당 이벤트가 발생하면 Docker에 로그인하여 변경사항이 반영된 이미지를 생성해 Docker Hub에 Push 해주도록 설정해 주었다.
여기서 사용하는 변수들은 Repository secret 변수에 등록해주어야 사용이 가능하다.
name: CI/CD with Node.js and Docker
on:
push:
branches:
- main # 원하는 브랜치로 변경 가능
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Set up Node.js
uses: actions/setup-node@v2
with:
token: ${{ secrets.GH_DOTCOM_TOKEN }}
node-version: '18' # 사용할 Node.js 버전을 선택합니다
- name: Cache yarn dependencies
uses: actions/cache@v2
with:
path: .yarn/cache
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Install dependencies
run: yarn install --immutable --immutable-cache --check-cache
- name: Build Node.js app
run: yarn run build
- name: Build Docker image
run: docker buildx build .
- name: Log in to Docker Hub
run: docker login -u ${{ secrets.DOCKERHUB_USERNAME }} -p ${{ 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 to production server
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.HOST }}
username: ${{ secrets.USERNAME }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
password: ${{ secrets.PASSWORD }}
port: ${{ secrets.PORT }}
script: |
cd project_dir
docker-compose down
docker-compose pull
docker-compose up --force-recreate --build -d
builld 작업
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Set up Node.js
uses: actions/setup-node@v2
with:
token: ${{ secrets.GH_DOTCOM_TOKEN }}
node-version: '18' # 사용할 Node.js 버전을 선택합니다
- name: Cache yarn dependencies
uses: actions/cache@v2
with:
path: .yarn/cache
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Install dependencies
run: yarn install --immutable --immutable-cache --check-cache
- name: Build Node.js app
run: yarn run build
- name: Build Docker image
run: docker buildx build .
- name: Log in to Docker Hub
run: docker login -u ${{ secrets.DOCKERHUB_USERNAME }} -p ${{ 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 작업
deploy:
needs: build
runs-on: ubuntu-latest
steps:
- name: SSH connect to production server
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.HOST }}
username: ${{ secrets.USERNAME }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
password: ${{ secrets.PASSWORD }}
port: ${{ secrets.PORT }}
script: |
cd project_dir
docker-compose down
docker-compose pull
docker-compose up --force-recreate --build -d
- ${{ secrets.HOST }}:배포 대상 서버의 호스트명 또는 IP 주소.
ex) example.com 또는 192.168.1.100- ${{ secrets.USERNAME }}:SSH 접속을 위한 사용자 이름.
ex)root, ubuntu, deployer 등.- ${{ secrets.SSH_PRIVATE_KEY }}:SSH접속을 위한 개인 키.해당 키는 대상 서버에 등록된 공개 키와 쌍을 이룬다.GitHub secrets에는 개인 키의 전체 내용을 입력해야 한다.
- ${{ secrets.PASSWORD }}:일부 SSH 접속 방식에서 사용자 암호를 요구할 수 있다. 하지만 대부분의 경우,키 기반 인증을 사용하여 패스워드 없이 접속 한다. 이 경우 해당 값은 필요 없을 수 있다.
- ${{ secrets.PORT }}: SSH 서버가 리스닝하고 있는 포트 번호.기본적으로 SSH는 22번 포트를 사용한다. 하지만 보안 상의 이유나 기타 다른 이유로 변경된 경우 해당 포트 번호를 입력한다.
yml에서 사용한 secret 변수 설정
Repository의 Settings ->security ->secrets -> actions 탭에 들어가 New repository secret 눌러 변수를 추가 할 수 있다.