CI/CD(Continuous Integration/Continuous Deployment)는 지속적인 통합과 배포를 가능하게 하는데, 전 이벤트 기반 아키텍처로 구성된 자바 스프링 부트 프로젝트를 베포 자동화 하기 위해서 Producer, Consumer 서버 두개를 베포하는것을 했습니다.
.
├── .github
│ └── workflows
│ ├── ci.yml # CI: 빌드 및 테스트용 워크플로우 파일
│ └── cd.yml # CD: 배포용 워크플로우 파일
├── producer
│ ├── src
│ ├── build.gradle
│ └── Dockerfile
├── consumer
│ ├── src
│ ├── build.gradle
│ └── Dockerfile
├── settings.gradle
└── README.md
개요
이 글에서는 GitHub Actions를 활용해 Gradle 기반의 Producer와 Consumer 프로젝트를 빌드하고, Docker Hub에 이미지를 업로드하며, AWS EC2 서버에 배포하는 CI/CD 환경을 구축하는 과정을 다룹니다. 특히, 워크플로우 작성과 민감한 정보 처리를 중심으로 설명합니다.
1. CI/CD 환경 개요
CI/CD(Continuous Integration/Continuous Deployment)는 지속적인 통합과 배포를 가능하게 하며, 다음과 같은 장점을 제공합니다:
- 코드 품질 개선: 푸시마다 자동으로 빌드와 테스트 수행.
- 배포 자동화: 배포 과정을 자동화해 실수를 방지하고 시간을 절약.
아키텍처 개요
- GitHub Actions로 코드가 푸시되거나 PR(Pull Request)이 생성되면 워크플로우 시작.
- 프로젝트를 빌드 후 Docker 이미지를 생성.
- Docker Hub에 이미지를 푸시.
- AWS EC2 서버로 SSH 연결을 통해 컨테이너 실행.
2. CI/CD 구성
2-1. 사전 준비
- Docker Hub 계정 생성 및 이미지 저장소(repository) 생성
- Docker Hub에서 <이름>/producer, <이름>/consumer 같은 이미지를 저장할 저장소 생성.
- GitHub Secrets 설정
- GitHub 레포지토리의 Settings > Secrets and variables > Actions에서 아래 정보를 등록:
- DOCKER_USERNAME: Docker Hub 사용자 이름.
- DOCKER_PASSWORD: Docker Hub 비밀번호.
- EC2_HOST, EC2_USERNAME, EC2_KEY: EC2 접속 정보.
- 기타 필요한 환경 변수: SPRING_DATASOURCE_URL, REDIS_PASSWORD 등.
- GitHub 레포지토리의 Settings > Secrets and variables > Actions에서 아래 정보를 등록:
2-2. 워크플로우 파일 작성
워크플로우 파일 위치
GitHub Actions에서 워크플로우는 반드시 .github/workflows/ 디렉토리에 YAML 형식으로 저장해야 합니다. 이는 GitHub가 워크플로우 파일을 자동으로 탐지하고 실행하기 위한 표준 위치입니다.
CI 파일: 코드 빌드
ci-workflow.yml 파일은 Producer와 Consumer 프로젝트를 각각 빌드합니다.
name: CI for Producer and Consumer
on:
push:
branches:
- 'main'
- 'develop'
pull_request:
branches:
- 'main'
- 'develop'
permissions:
contents: read
jobs:
build-producer:
name: Build Producer
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: ☕️ Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
- name: 🐘 Build Producer with Gradle
run: |
chmod +x ./gradlew
./gradlew :producer:clean :producer:build -x test --stacktrace
build-consumer:
name: Build Consumer
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: ☕️ Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
- name: 🐘 Build Consumer with Gradle
run: |
chmod +x ./gradlew
./gradlew :consumer:clean :consumer:build -x test --stacktrace
설명:
- on: push와 pull_request 이벤트로 워크플로우가 실행.
- jobs:
- build-producer: Producer 프로젝트를 빌드.
- build-consumer: Consumer 프로젝트를 빌드.
CD 파일: 빌드 및 배포
cd-workflow.yml 파일은 Docker 이미지를 생성하고 Docker Hub에 푸시한 뒤, AWS EC2에 배포합니다.
name: CD with Gradle and Docker for Producer and Consumer
on:
push:
branches:
- 'main'
- 'develop'
pull_request:
branches:
- 'main'
- 'develop'
permissions:
contents: read
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: ☕️ Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
- name: Grant execute permission for Gradlew
run: chmod +x ./gradlew
- name: 🐘 Build Producer with Gradle
run: ./gradlew :producer:clean :producer:build -x test --stacktrace
- name: 🐘 Build Consumer with Gradle
run: ./gradlew :consumer:clean :consumer:build -x test --stacktrace
- name: 💣 Build and Push Docker Images
run: |
docker login -u <DOCKER_USERNAME> -p <DOCKER_PASSWORD>
docker build -f ./producer/Dockerfile -t <DOCKER_USERNAME>/producer:latest ./producer
docker build -f ./consumer/Dockerfile -t <DOCKER_USERNAME>/consumer:latest ./consumer
docker push <DOCKER_USERNAME>/producer:latest
docker push <DOCKER_USERNAME>/consumer:latest
- name: 🚀 Deploy without Docker Compose
uses: appleboy/ssh-action@master
with:
host: <EC2_HOST>
username: <EC2_USERNAME>
key: ${{ secrets.EC2_KEY }}
port: 22
script: |
echo "Stopping and removing existing containers"
sudo docker stop producer || true
sudo docker rm producer || true
sudo docker stop consumer || true
sudo docker rm consumer || true
echo "Pulling and running the latest images"
sudo docker pull <DOCKER_USERNAME>/producer:latest
sudo docker run -d --name producer -p 8080:8080 <DOCKER_USERNAME>/producer:latest
sudo docker pull <DOCKER_USERNAME>/consumer:latest
sudo docker run -d --name consumer -p 8081:8081 <DOCKER_USERNAME>/consumer:latest
echo "Cleaning up unused Docker images"
sudo docker image prune -f
설명:
- Docker Build & Push: Producer와 Consumer 이미지를 Docker Hub에 업로드.
- AWS EC2 배포:
- 기존 컨테이너를 중지하고 삭제.
- Docker Hub에서 최신 이미지를 Pull 후 실행.
- 미사용 이미지를 삭제하여 공간 절약.
3. 결과 확인
배포가 완료되면 AWS EC2에서 다음 명령어로 컨테이너 상태를 확인할 수 있습니다:
sudo docker ps
4. 주의 사항
- Secrets 관리: 모든 민감 정보는 GitHub Secrets에 저장.
- Docker 이미지 태깅: latest 외에도 버전 태그를 사용하면 더욱 안정적인 배포 관리 가능.
- EC2 설정: EC2에 Docker가 설치되어 있어야 하며, 필요한 포트가 열려 있어야 합니다.
반응형
'Server > 🐳 Docker' 카테고리의 다른 글
[Docker] Docker Hub 이용해서 CD 환경 구축 시 최신 이미지 미적용 문제 해결하기 (0) | 2025.01.24 |
---|
댓글