
언젠가 CI/CD 구축을 해야지...하다가 계속 하지 않고 코드의 변경 사항이 생길 때 마다 docker-compose build로 이미지를 빌드하고 하나하나 docker tag ~~ 이런식으로 태그 지정하고, docker push하고 ssh 서버에서 docker pull 까지 반복 작업을 하려니 너무 번거로워서 하루 날 잡고 CI/CD 구축을 하기로 하였다.
이미 두번 정도 시도를 했다가 실패했기 때문에 이번에는 꼭 끝내보자 하고 끝장을 봤다.
master 브랜치 제외,
개발 브랜치: cebu.citymart.kr_dev
배포 브랜치: cebu.citymart.kr
개발 브랜치는 gajapos Organization의 Gajapos 레포지토리의 cebu.citymart.kr_dev 브랜치이다. 기본적으로 코드 통합은 개인 레포지토리에서 Pull Request 를 통한 merge로 cebu.citymart.kr_dev 브랜치로 통합되고, 문제가 없는 경우 cebu.citymart.kr 브랜치로 통합된다.
cebu.citymart.kr 브랜치로의 푸시를 성공하면 자동으로 SSH 서버로 푸시된 코드를 배포하기로 한다.


ci-cd.yml로 입력한다.
저장소의 Settings 탭으로 이동한다.
왼쪽 사이드바에서 Secrets and variables > Actions를 선택한다.
New repository secret 버튼을 클릭하여 다음 secrets를 추가합니다:
DOCKERHUB_USERNAME: Docker Hub 사용자 이름DOCKERHUB_TOKEN: Docker Hub 액세스 토큰AWS_HOST: AWS EC2 인스턴스의 공개 IP 또는 도메인AWS_USERNAME: EC2 인스턴스 접속 사용자 이름 (예: ubuntu)AWS_PRIVATE_KEY: EC2 인스턴스 접속용 SSH 개인 키등 나머지 기타 변수들 추가.
# workflow name
name: CI/CD Pipeline
# workflow를 발생시킬 event
on:
push:
branches:
- cebu.citymart.kr # cebu.citymart.kr 브랜치에 push가 발생할 때 실행
# 실행할 작업들을 정의
jobs:
build-and-deploy:
runs-on: ubuntu-latest # Ubuntu 최신 버전에서 작업 실행
steps:
# 저장소의 코드를 체크아웃
- name: Checkout code
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_TOKEN }}
# Spring Docker 이미지 빌드, 푸시
- name: Build and push Spring image
uses: docker/build-push-action@v2
with:
context: ./gazapos_db
push: ${{ github.event_name == 'push' && github.ref == 'refs/heads/cebu.citymart.kr' || github.event.inputs.deploy == 'true' }}
tags: sungnij/gazapos-spring:latest
# React를 위한 환경 변수 파일을 생성 (.env 파일)
- name: Create .env file
run: |
echo "REACT_APP_ENVIRONMENT=${{ secrets.REACT_APP_ENVIRONMENT }}" > ./pos4phill-web/.env
echo "REACT_APP_JEPETTO_PROD_API_URL=${{ secrets.REACT_APP_JEPETTO_PROD_API_URL }}" >> ./pos4phill-web/.env
echo "REACT_APP_JEPETTO_DEV_API_URL=${{ secrets.REACT_APP_JEPETTO_DEV_API_URL }}" >> ./pos4phill-web/.env
echo "REACT_APP_SPRING_PROD_API_URL=${{ secrets.REACT_APP_SPRING_PROD_API_URL }}" >> ./pos4phill-web/.env
echo "REACT_APP_SPRING_DEV_API_URL=${{ secrets.REACT_APP_SPRING_DEV_API_URL }}" >> ./pos4phill-web/.env
# React 애플리케이션의 Docker 이미지 빌드, 푸시
- name: Build and push React image
uses: docker/build-push-action@v2
with:
context: ./pos4phill-web
push: ${{ github.event_name == 'push' && github.ref == 'refs/heads/cebu.citymart.kr' || github.event.inputs.deploy == 'true' }}
tags: sungnij/gazapos-react:latest
# Nginx의 Docker 이미지 빌드, 푸시
- name: Build and push Nginx image
uses: docker/build-push-action@v2
with:
context: ./nginx
push: ${{ github.event_name == 'push' && github.ref == 'refs/heads/cebu.citymart.kr' || github.event.inputs.deploy == 'true' }}
tags: sungnij/gazapos-nginx:latest
# Jepetto 설정 파일을 업데이트
- name: Update jepetto.properties
run: |
sed -i '/^BASE64_ENCODED_KEY=/d' ./gazapos/tomcat/conf/jepetto.properties
sed -i '/^CITYMART_BOT_TOKEN=/d' ./gazapos/tomcat/conf/jepetto.properties
sed -i '/^CITYMART_CHAT_ID=/d' ./gazapos/tomcat/conf/jepetto.properties
echo "BASE64_ENCODED_KEY=${{ secrets.BASE64_ENCODED_KEY }}" >> ./gazapos/tomcat/conf/jepetto.properties
echo "CITYMART_BOT_TOKEN=${{ secrets.CITYMART_BOT_TOKEN }}" >> ./gazapos/tomcat/conf/jepetto.properties
echo "CITYMART_CHAT_ID=${{ secrets.CITYMART_CHAT_ID }}" >> ./gazapos/tomcat/conf/jepetto.properties
# Jepetto Docker 이미지 빌드, 푸시
- name: Build and push Jepetto image
uses: docker/build-push-action@v2
with:
context: .
file: ./gazapos/Dockerfile
push: ${{ github.event_name == 'push' && github.ref == 'refs/heads/cebu.citymart.kr' || github.event.inputs.deploy == 'true' }}
tags: sungnij/gazapos-jepetto:latest
# AWS EC2 인스턴스에 SSH로 접속하여 배포 작업 수행
- name: Deploy to AWS EC2
if: github.event_name == 'push' && github.ref == 'refs/heads/cebu.citymart.kr' || github.event.inputs.deploy == 'true'
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.AWS_HOST }}
username: ${{ secrets.AWS_USERNAME }}
key: ${{ secrets.AWS_PRIVATE_KEY }}
script: |
# Git 저장소 안전 디렉토리 설정
git config --global --add safe.directory /home/***/Gajapos
# 현재 사용자를 docker 그룹에 추가
sudo usermod -aG docker $USER
# docker 그룹 권한 즉시 적용
newgrp docker
# 프로젝트 디렉토리로 이동
cd ~/Gajapos
# 최신 코드 pull
git pull origin cebu.citymart.kr
# 기존 Docker 컨테이너, 네트워크 정리
docker-compose down --remove-orphans
docker rm -f $(docker ps -aq)
docker network prune -f
# 최신 Docker 이미지 pull
docker pull sungnij/gazapos-react:latest
docker pull sungnij/gazapos-spring:latest
docker pull sungnij/gazapos-jepetto:latest
docker pull sungnij/gazapos-nginx:latest
docker pull certbot/certbot
# Docker Compose를 사용하여 서비스 시작
docker-compose up -d
docker image를 build 하고 tag를 지정 후 docker-compose pull 했을 때 ssh 서버에서 최신화된 이미지를 pull 하지 못하는 문제가 있었다. 그래서 workflow는 success 했음에도 불구하고 변경된 코드가 반영이 안되었다.
확인 결과 docker-compose pull 에서 제대로 최신화된 이미지를 가져오지 못하는것을 알게 되었고 docker-compose 를 사용하지 않고 직접 이미지를 모두 지정해서 docker pull 하도록 변경하였다.
docker pull sungnij/gazapos-react:latest
docker pull sungnij/gazapos-spring:latest
docker pull sungnij/gazapos-jepetto:latest
docker pull sungnij/gazapos-nginx:latest
docker pull certbot/certbot
