워크플로우 개요
- 이 GitHub Actions 워크플로우는 Java, Spring Boot, Ubuntu, Docker를 사용하여 CI/CD(Continuous Integration/Continuous Deployment)를 자동화하는 설정이다.
- 이 워크플로우는 develop-be 브랜치에 push 또는 pull request 이벤트가 발생할 때 실행된다.
- 두 개의 작업(Job) build, deploy 로 구성되어 있다.
- Docker를 사용하기 때문에 Docker 이미지를 빌드하는 단계에서 Dockerfile이 필요하다.
Dockerfile 준비하기
Dockerfile은 애플리케이션의 실행 환경을 코드로 정의하여, 어디서나 동일한 환경에서 애플리케이션을 실행할 수 있도록 한다. Dockerfile을 사용하여 Docker 이미지를 빌드한다.
FROM openjdk:17-alpine
ARG JAR_FILE=build/libs/*.jar
COPY ${JAR_FILE} app.jar
ENV TZ=Asia/Seoul
ENTRYPOINT ["java","-jar","/app.jar","-Duser.timezone=Asia/Seoul"]
# -Duser.timezone=Asia/Seoul 옵션: 기본 타임존을 Asia/Seoul로 강제 설정
- Dockerfile은 애플리케이션을 컨테이너화하는 데 필요한 명령어들을 포함하고 있다.
- 여기에는 베이스 이미지를 설정하고, 필요한 종속성을 설치하고, 애플리케이션 코드를 추가하고, 실행 명령을 정의하는 내용이 포함된다
워크플로우 구성
# deploy.yml
name: CI/CD with Gradle, Docker, AWS
# develop-be 브랜치에 push 또는 PR 이벤트가 발생하면 워크플로우가 실행된다.
on:
push:
branches: [ "develop-be" ]
pull_request:
branches: [ "develop-be" ]
# 해당 Workflow의 Job 목록
jobs:
build:
# 이 작업이 실행되는 환경을 정의: 최신 Ubuntu 환경
runs-on: ubuntu-latest
# 리포지토리에 대한 읽기 권한을 부여한다.
permissions:
contents: read
# build Job 내의 step 목록
steps:
### CI
# 레포지토리 체크아웃하여 레포지토리에 접근할 수 있게 한다.
- name: Checkout Repository
uses: actions/checkout@v4
# JDK 버전 17 설정 (temurin 배포판 사용)
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
# Gradle 캐싱 설정으로 의존성 다운로드 시간을 줄인다.
- name: Gradle Caching
uses: actions/cache@v3
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('backend/pomoro-do/**/*.gradle*', 'backend/pomoro-do/**/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-
# Gradle 래퍼 스크립트에 실행 권한 부여
- name: Grant Execute Permission For Gradlew
run: chmod +x backend/pomoro-do/gradlew
# 테스트를 제외한 Gradle 빌드 수행 (CI 단계)
- name: Build with Gradle
run: cd backend/pomoro-do && ./gradlew build -x test
### CD
# Docker Hub에 로그인 (보안) (CD 단계 준비)
- name: Log in to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
# SpringBoot 어플리케이션의 Docker 이미지를 빌드하고 Docker Hub에 푸시 (CD 단계 준비)
- name: Build and Push Docker Image for SpringBoot
run: |
cd backend/pomoro-do
set -e # 명령 실패 시 스크립트 종료
# 현재 디렉토리에 있는 Dockerfile을 사용하여 Docker 이미지를 빌드
docker build -t ${{ secrets.DOCKER_USERNAME }}/pomorodo:latest .
# Docker Hub에 이미지 푸시
docker push ${{ secrets.DOCKER_USERNAME }}/pomorodo:latest
deploy:
# 이 작업은 build 작업이 성공적으로 완료된 후에만 실행다.
needs: build
runs-on: ubuntu-latest
steps:
# SSH를 통해 원격 서버에서 명령을 실행하여 Docker 컨테이너 배포
- name: Docker Run
uses: appleboy/ssh-action@v0.1.8
with:
host: ${{ secrets.SSH_HOST }} # 원격 서버의 호스트명
username: ${{ secrets.SSH_USERNAME }} # 원격 서버의 사용자명
key: ${{ secrets.SSH_PRIVATE_KEY }} # 원격 서버의 비밀 키
port: 22 # SSH 포트
sync: false
use_insecure_cipher: false
timeout: 30s
command_timeout: 10m
debug: true # 디버그 모드 활성화
script: |
docker stop pomorodo-server || true # 실행 중인 pomorodo-server 컨테이너 중지
docker rm pomorodo-server || true # 기존 컨테이너 삭제
docker rmi ${{ secrets.DOCKER_USERNAME }}/pomorodo:latest || true # 기존 이미지 삭제
docker pull ${{ secrets.DOCKER_USERNAME }}/pomorodo:latest # 최신 이미지 다운로드
docker run -d -p 8080:8080 --name pomorodo-server -e DB_URL=${{ secrets.DB_URL }} -e DB_USERNAME=${{ secrets.DB_USERNAME }} -e DB_PASSWORD=${{ secrets.DB_PASSWORD }} ${{ secrets.DOCKER_USERNAME }}/pomorodo:latest
CI (Continuous Integration)
CI 단계에서는 코드의 변경사항이 빌드되고 테스트된다.
여기서는 주로 코드가 정상적으로 동작하는지 확인하는 작업이 이루어진다. 여기서 코드를 빌드하여 문제가 없는지 확인한다.
워크플로우 설정
워크플로우 이름을 정의한다.
name: CI/CD with Gradle, Docker, AWS
- name: CI/CD with Gradle, Docker, AWS - 워크플로우의 이름이다.
이벤트 트리거
develop-be 브랜치에 push되거나 pull request가 생성될 때 워크플로우가 실행된다.
on:
push:
branches: [ "develop-be" ]
pull_request:
branches: [ "develop-be" ]
- on: - 워크플로우를 트리거하는 이벤트를 정의한다.
- push: branches: - 해당 브랜치로 푸시 이벤트가 발생하면 워크플로우가 실행한다.
- pull_request: branches: - 해당 브랜치를 대상으로 한 풀 리퀘스트 이벤트가 발생하면 워크플로우가 실행한다.
Job 1: build
기본 설정
이 작업은 최신 Ubuntu 환경에서 실행된다. 리포지토리에 대한 읽기 권한을 부여한다.
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
- runs-on: ubuntu-latest - 최신 버전의 Ubuntu 가상 머신에서 작업이 실행한다.
- permissions: contents: read - 저장소 내용에 대한 읽기 권한을 부여한다.
Steps (단계)
1. 레포지토리 체크아웃 (Checkout Repository)
레포지토리의 코드를 체크아웃하여 접근할 수 있게 한다.
- name: Checkout Repository
uses: actions/checkout@v4
- actions/checkout 액션을 사용하여 저장소를 러너에 클론한다.
2. JDK 17 설정 (Set up JDK 17)
JDK 17을 설정한다.
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
- actions/setup-java 액션을 사용하여 JDK 17 (Temurin 배포판)을 설치한다.
3. Gradle 캐싱 (Gradle Caching)
Gradle 캐싱을 설정하여 빌드 시간을 줄인다.
- name: Gradle Caching
uses: actions/cache@v3
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('backend/pomoro-do/**/*.gradle*', 'backend/pomoro-do/**/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-
- actions/cache 액션을 사용하여 Gradle 종속성을 캐싱하여 빌드 속도를 높인다.
- path - 캐싱할 디렉토리를 지정한다.
- key - OS 및 Gradle 파일의 해시를 기반으로 한 고유한 캐시 키를 정의한다.
- restore-keys - 기본 키가 없을 때 사용할 대체 키를 정의한다.
4. Gradlew 실행 권한 부여 (Grant Execute Permission For Gradlew)
Gradle 래퍼 스크립트에 실행 권한을 부여한다.
- name: Grant Execute Permission For Gradlew
run: chmod +x backend/pomoro-do/gradlew
5. Gradle로 빌드 (Build with Gradle)
- name: Build with Gradle
run: cd backend/pomoro-do && ./gradlew build -x test
- Gradle 빌드 명령을 실행하여 테스트를 제외한 빌드를 수행한다.
CD (Continuous Deployment)
CD 단계에서는 빌드된 애플리케이션을 실제 환경에 배포한다.
6. Docker Hub에 로그인 (Log in to Docker Hub)
Docker Hub에 로그인한다.
- name: Log in to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- docker/login-action 액션을 사용하여 Docker Hub에 로그인한다.
- GitHub Secrets에 저장된 자격 증명 사용한다.
7. SpringBoot용 Docker 이미지 빌드 및 푸시 (Build and Push Docker Image for SpringBoot)
- name: Build and Push Docker Image for SpringBoot
run: |
cd backend/pomoro-do
set -e
docker build -t ${{ secrets.DOCKER_USERNAME }}/pomorodo:latest .
docker push ${{ secrets.DOCKER_USERNAME }}/pomorodo:latest
- 이 단계에서는 backend/pomoro-do 디렉토리에 있는 Dockerfile을 사용하여 Spring Boot 애플리케이션의 Docker 이미지를 빌드한다.
- 빌드된 Docker 이미지를 Docker Hub에 푸시한다.
Job 2: deploy
기본 설정
deploy:
needs: build
runs-on: ubuntu-latest
- needs: build - 이 작업은 build 작업이 성공적으로 완료된 후에만 실행된다.
- 최신 Ubuntu 환경에서 실행다.
Steps (단계)
1. Docker 실행 (Docker Run)
SSH를 통해 원격 서버에 접속하여 Docker 컨테이너를 배포한다.
기존 컨테이너와 이미지를 중지하고 삭제한 후, 최신 이미지를 다운로드하여 새로운 컨테이너를 실행한다.
- 이 단계에서는 Docker Hub에서 최신 이미지를 풀(pull) 한 후, 컨테이너를 실행한다.
- 이 이미지도 Dockerfile을 통해 빌드된 것이므로, 이전 단계에서 만든 Dockerfile이 중요하다.
- name: Docker Run
uses: appleboy/ssh-action@v0.1.8
with:
host: ${{ secrets.SSH_HOST }}
username: ${{ secrets.SSH_USERNAME }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
port: 22
sync: false
use_insecure_cipher: false
timeout: 30s
command_timeout: 10m
debug: true
script: |
docker stop pomorodo-server || true
docker rm pomorodo-server || true
docker rmi ${{ secrets.DOCKER_USERNAME }}/pomorodo:latest || true
docker pull ${{ secrets.DOCKER_USERNAME }}/pomorodo:latest
docker run -d -p 8080:8080 --name pomorodo-server -e DB_URL=${{ secrets.DB_URL }} -e DB_USERNAME=${{ secrets.DB_USERNAME }} -e DB_PASSWORD=${{ secrets.DB_PASSWORD }} ${{ secrets.DOCKER_USERNAME }}/pomorodo:latest
- appleboy/ssh-action 액션을 사용하여 SSH를 통해 원격 서버에서 명령을 실행한다.
- 실행 중인 pomorodo-server 컨테이너를 중지하고 삭제한다.
- 기존 Docker 이미지를 삭제한다.
- Docker Hub에서 최신 이미지를 다운로드한다.
- 환경 변수를 설정하고 새로운 Docker 컨테이너를 실행다.
CI/CD
CI는 코드의 품질을 보장하고 빌드 과정을 자동화하며,
CD는 빌드된 애플리케이션을 실제 운영 환경에 배포하는 과정을 자동화한다.
- CI (지속적 통합): 코드 체크아웃, JDK 설정, Gradle 캐싱, Gradle 빌드
- CD (지속적 배포): Docker Hub 로그인, Docker 이미지 빌드 및 푸시, Docker 컨테이너 배포
이 워크플로우는 코드가 develop-be 브랜치에 푸시되거나 PR이 생성될 때 자동으로 빌드와 배포 과정을 수행하여, 최신 버전의 애플리케이션이 원격 서버에 배포되도록 설정되어 있다.
docker-compose 사용하기
docker-compose.yml 파일은 Docker Compose를 사용하여 여러 컨테이너 서비스를 정의하고 설정할 수 있는 구성 파일이다.
docker-compose.yml
# docker-compose.yml
# Docker Compose 파일의 버전을 지정
version: '3.8'
services:
app:
build:
context: ./backend/pomoro-do
dockerfile: Dockerfile
image: ${DOCKER_USERNAME}/pomorodo:latest
ports:
- "8080:8080"
environment:
DB_URL: ${DB_URL}
DB_USERNAME: ${DB_USERNAME}
DB_PASSWORD: ${DB_PASSWORD}
S3_ACCESS_KEY: ${S3_ACCESS_KEY}
S3_SECRET_KEY: ${S3_SECRET_KEY}
REGION: ${REGION}
BUCKET_NAME: ${BUCKET_NAME}
JWT_ACCESS_SECRET: ${JWT_ACCESS_SECRET}
JWT_REFRESH_SECRET: ${JWT_REFRESH_SECRET}
버전
version: '3.8'
- version: Docker Compose 파일의 버전을 지정합니다. 여기서는 버전 3.8을 사용합니다. 이는 Docker Compose의 여러 기능을 사용할 수 있게 합니다.
서비스 정의
services:
app:
- services: 여러 컨테이너 서비스를 정의할 수 있는 섹션입니다.
- app: 서비스의 이름입니다. 여기서는 app이라는 이름을 사용하여 Spring Boot 애플리케이션을 정의하고 있습니다.
빌드 설정
build:
context: ./backend/pomoro-do
dockerfile: Dockerfile
- build: Docker 이미지를 빌드하는 설정을 정의합니다.
- context: Docker 빌드 컨텍스트를 지정합니다. ./backend/pomoro-do 디렉토리를 기준으로 빌드가 수행됩니다. 이 디렉토리에는 Dockerfile과 소스 코드가 있어야 합니다.
- dockerfile: 사용할 Dockerfile을 지정합니다. 기본적으로 context 내의 Dockerfile을 사용합니다.
이미지 설정
image: "${DOCKER_USERNAME}/pomorodo:latest"
- image: 빌드된 Docker 이미지를 태그할 이름을 지정합니다. 여기서는 환경 변수 ${DOCKER_USERNAME}를 사용하여 Docker Hub의 사용자 이름과 pomorodo:latest 이미지를 결합하여 이름을 설정합니다. 예를 들어, 사용자 이름이 exampleuser인 경우 exampleuser/pomorodo:latest로 태그됩니다.
포트 설정
image: "${DOCKER_USERNAME}/pomorodo:latest"
- ports: 호스트와 컨테이너 간의 포트 매핑을 설정합니다.
- "8080:8080": 호스트의 포트 8080을 컨테이너의 포트 8080에 매핑합니다. 이렇게 하면 호스트의 8080 포트로 접근할 때 컨테이너의 8080 포트로 요청이 전달됩니다.
환경 변수 설정
environment:
DB_URL: "${DB_URL}"
DB_USERNAME: "${DB_USERNAME}"
DB_PASSWORD: "${DB_PASSWORD}"
- environment: 컨테이너에서 사용할 환경 변수를 설정합니다. 환경 변수는 주로 애플리케이션의 설정 값을 지정하는 데 사용됩니다.
- DB_URL: 데이터베이스 URL을 지정합니다.
- DB_USERNAME: 데이터베이스 사용자 이름을 지정합니다.
- DB_PASSWORD: 데이터베이스 비밀번호를 지정합니다.
요약
이 docker-compose.yml 파일은 Spring Boot 애플리케이션을 정의하고, Docker 이미지를 빌드하고, 환경 변수를 설정하며, 포트 매핑을 통해 컨테이너가 호스트의 특정 포트에서 접근 가능하도록 합니다. 이를 통해 애플리케이션을 손쉽게 배포하고 관리할 수 있습니다. 각 구성 요소는 다음과 같은 역할을 합니다:
- version: Docker Compose 파일의 버전 지정
- services: 여러 컨테이너 서비스를 정의
- app: 서비스 이름
- build: Docker 이미지를 빌드하는 설정
- image: 빌드된 이미지의 태그 이름
- ports: 호스트와 컨테이너 간의 포트 매핑
- environment: 컨테이너 내에서 사용할 환경 변수 설정
deploy.yml
# deploy.yml
name: CI/CD with Gradle, Docker, AWS
# develop-be 브랜치에 push 또는 PR 이벤트가 발생하면 워크플로우가 실행된다.
on:
push:
branches: [ "develop-be" ]
pull_request:
branches: [ "develop-be" ]
# 해당 Workflow의 Job 목록
jobs:
build:
# 이 작업이 실행되는 환경을 정의: 최신 Ubuntu 환경
runs-on: ubuntu-latest
# 리포지토리에 대한 읽기 권한을 부여한다.
permissions:
contents: read
# build Job 내의 step 목록
steps:
### CI
# 레포지토리 체크아웃하여 레포지토리에 접근할 수 있게 한다.
- name: Checkout Repository
uses: actions/checkout@v4
# JDK 버전 17 설정 (temurin 배포판 사용)
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
# Gradle 캐싱 설정으로 의존성 다운로드 시간을 줄인다.
- name: Gradle Caching
uses: actions/cache@v3
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('backend/pomoro-do/**/*.gradle*', 'backend/pomoro-do/**/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-
# Gradle 래퍼 스크립트에 실행 권한 부여
- name: Grant Execute Permission For Gradlew
run: chmod +x backend/pomoro-do/gradlew
# 테스트를 제외한 Gradle 빌드 수행 (CI 단계)
- name: Build with Gradle
run: cd backend/pomoro-do && ./gradlew build -x test
### CD
# Docker Hub에 로그인 (보안) (CD 단계 준비)
- name: Log in to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
# SpringBoot 어플리케이션의 Docker 이미지를 빌드하고 Docker Hub에 푸시 (CD 단계 준비)
- name: Build and Push Docker Image for SpringBoot
run: |
cd backend/pomoro-do
set -e # 명령 실패 시 스크립트 종료
# 현재 디렉토리에 있는 Dockerfile을 사용하여 Docker 이미지를 빌드
docker-compose build
# Docker Hub에 이미지 푸시
docker-compose push
deploy:
# 이 작업은 build 작업이 성공적으로 완료된 후에만 실행다.
needs: build
runs-on: ubuntu-latest
steps:
# SSH를 통해 원격 서버에서 명령을 실행하여 Docker 컨테이너 배포
- name: Docker Run
uses: appleboy/ssh-action@v0.1.8
with:
host: ${{ secrets.SSH_HOST }} # 원격 서버의 호스트명
username: ${{ secrets.SSH_USERNAME }} # 원격 서버의 사용자명
key: ${{ secrets.SSH_PRIVATE_KEY }} # 원격 서버의 비밀 키
port: 22 # SSH 포트
sync: false
use_insecure_cipher: false
timeout: 30s
command_timeout: 10m
debug: true # 디버그 모드 활성화
script: |
cd /path/to/deploy
docker-compose down # 기존 컨테이너 중지 및 제거
docker-compose pull # 최신 이미지 가져오기
docker-compose up -d # Docker Compose를 사용해 컨테이너 시작
'내맘대로 개발 일기 > 뽀모로 Do!' 카테고리의 다른 글
[인프라 구축] Let’s Encrypt, SSL/TLS 인증서 발급하기 (0) | 2024.06.16 |
---|---|
[인프라 구축] Ubuntu 현재 시스템의 시간대를 한국 시간으로 변경하기 (0) | 2024.06.15 |
[CICD 구축] GitHub Actions 시작하기 (0) | 2024.06.12 |
[인프라 구축] Nginx 설치하기 (1) | 2024.06.09 |
[인프라 구축] Amazon Lightsail에 가비아 도메인 연결하기 (0) | 2024.06.08 |