독학/[etc] 개발 관련 내용 정리
[배포🌎] AWS EC2, GitHub Action, Docker compose를 이용한 CI/CD 자동화 (2)
최연재
2025. 5. 18. 23:13
시작하기 앞서 해당 글에서 이어지는 내용입니다.
3. 필요한 프로그램을 ec2 환경 내에서 설치하기
3.1 인바운드/아웃바운드 규칙 설정
- 인바운드 규칙 편집 : 상황에 따라서 편집
- 아웃바운드 규칙 편집 :
3.2. 필요한 프로그램 설치
- Git 설치하기
$ sudo apt update
$ sudo apt install git -y
- Docker 설치하기
$ sudo apt install docker.io -y
$ sudo systemctl start docker
$ sudo systemctl enable docker
- Docker-compose 설치하기
$ sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
$ sudo chmod +x /usr/local/bin/docker-compose
- Java 설치하기
$ sudo apt install openjdk-17-jdk -y
- redis 설치하기
$ sudo apt update
$ sudo apt install redis-server -y
$ sudo systemctl enable redis
$ sudo systemctl start redis
$ sudo systemctl status redis
4. Docker Hub에서 레포지토리 생성하기
5. GitHub Repository Secrets 에 필요한 값 설정하기
- 각각의 값에 대한 설명은 아래와 같습니다.
- APPLICATION_PROPERTIES : Spring Boot 프로젝트 내 applicatioproperties 또는 application.yml 파일 내용
- APPLICATION_TEST_PROPERTIES : 테스트용 applicatioproperties 또는 application.yml 파일 내용
- DOCKERHUB_PASSWORD : 본인의 docker hub 비밀번호
- DOCKERHUB_REPOSITORY : 위에서 생성한 리포지토리 이름
- DOCKERHUB_USERNAME : 본인의 docker hub 아이디
- HOST : 배포 서버 도메인
- JWT_EXPIRATION_ACCESS : Access 토큰의 만료 시간
- JWT_EXPIRATION_REFRESH : Refresh 토큰의 만료 시간
- POSTGRES_DB : 사용할 PostgreSQL 데이터베이스 이름
- JWT_SECRET_KEY : JWT 서명을 위한 비밀 키
- SPRING_DATASOURCE_PASSWORD : DB 비밀번호
- SPRING_DATASOURCE_URL : DB 연결 URL
- SPRING_DATASOURCE_USERNAME : DB 사용자 이름
- SSH_PRIVATE_KEY : 배포용 SSH 프라이빗 키 (AWS 인스턴스 만들면서 다운받은 .pem키)
- SSH_USERNAME : 배포 서버의 SSH 접속용 사용자 이름 (여기에는 ubuntu)
6. 프로젝트 루트 위치에 DockerFile 작성
FROM openjdk:17-jdk-slim-buster
COPY build/libs/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "/app.jar"]
7. 프로젝트 루트 위치에 docker-compose.yml 작성
services:
app:
container_name: spring-boot-app
image: ${DOCKER_IMAGE}
ports:
- "8080:8080"
restart: always
environment:
SPRING_DATASOURCE_URL: ${SPRING_DATASOURCE_URL}
SPRING_DATASOURCE_USERNAME: ${SPRING_DATASOURCE_USERNAME}
SPRING_DATASOURCE_PASSWORD: ${SPRING_DATASOURCE_PASSWORD}
JWT_SECRET_KEY: ${JWT_SECRET_KEY}
JWT_EXPIRATION_ACCESS: ${JWT_EXPIRATION_ACCESS}
JWT_EXPIRATION_REFRESH: ${JWT_EXPIRATION_REFRESH}
SPRING_REDIS_HOST: redis
SPRING_REDIS_PORT: 6379
depends_on:
- postgres
- redis
postgres:
image: postgres:latest
container_name: postgres-db
environment:
POSTGRES_USER: ${SPRING_DATASOURCE_USERNAME}
POSTGRES_PASSWORD: ${SPRING_DATASOURCE_PASSWORD}
POSTGRES_DB: ${POSTGRES_DB}
ports:
- "5432:5432"
volumes:
- ./init_postgres.sql:/docker-entrypoint-initdb.d/init_postgres.sql # SQL 파일 마운트
restart: always
redis:
image: redis:latest
container_name: redis
ports:
- "6379:6379"
restart: always
8. GitHub Action 시작하기
8.1 리포지토리 옵션 중 Actions 클릭
8.2 스크립트 작성
name: Java CI with Gradle
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
# Gradle wrapper에 실행 권한 부여
- name: Give Gradle wrapper execute permissions
run: chmod +x ./gradlew
- name: Setup Gradle
uses: gradle/actions/setup-gradle@ # v4.0.0
### application.properties (main) 생성
- name: Generate application.properties (main)
run: |
mkdir -p src/main/resources
echo "${{ secrets.APPLICATION_PROPERTIES }}" > src/main/resources/application.properties
### application.properties (test) 생성
- name: Generate application.properties (test)
run: |
mkdir -p src/test/resources
echo "${{ secrets.APPLICATION_TEST_PROPERTIES }}" > src/test/resources/application.properties
### Gradle Build (테스트 제외)
- name: Build with Gradle Wrapper
run: ./gradlew build -x test
### Docker 로그인
- name: Docker login
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}
### Docker 이미지 빌드 및 푸시
- name: Build and push Docker image
run: |
docker build -t ${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKERHUB_REPOSITORY }}:${{ github.sha }} -f ./Dockerfile .
docker push ${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKERHUB_REPOSITORY }}:${{ github.sha }}
### EC2 배포
- name: Deploy to EC2
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.HOST }}
username: ${{ secrets.SSH_USERNAME }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
echo "Starting deployment..."
cd ~/howWeather-backend
echo "Pulling latest changes from main branch..."
git fetch --all
git reset --hard origin/main
echo "Pulling latest Docker image..."
docker pull ${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKERHUB_REPOSITORY }}:${{ github.sha }}
echo "Setting environment variables..."
cat > .env <<EOL
SPRING_DATASOURCE_URL=${{ secrets.SPRING_DATASOURCE_URL }}
SPRING_DATASOURCE_USERNAME=${{ secrets.SPRING_DATASOURCE_USERNAME }}
SPRING_DATASOURCE_PASSWORD=${{ secrets.SPRING_DATASOURCE_PASSWORD }}
DOCKERHUB_USERNAME=${{ secrets.DOCKERHUB_USERNAME }}
DOCKERHUB_REPOSITORY=${{ secrets.DOCKERHUB_REPOSITORY }}
GITHUB_SHA=${{ github.sha }}
DOCKER_IMAGE=${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKERHUB_REPOSITORY }}:${{ github.sha }}
JWT_SECRET_KEY=${{ secrets.JWT_SECRET_KEY }}
JWT_EXPIRATION_ACCESS=${{ secrets.JWT_EXPIRATION_ACCESS }}
JWT_EXPIRATION_REFRESH=${{ secrets.JWT_EXPIRATION_REFRESH }}
DOCKER_IMAGE=${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKERHUB_REPOSITORY }}:${{ github.sha }}
OPENWEATHER_API_KEY=${{ secrets.WEATHER_SERVICE_KEY }}
EOL
echo "Stopping spring-boot-app container..."
docker-compose --env-file .env stop app || true
echo "Removing spring-boot-app container..."
docker-compose --env-file .env rm -f app || true
echo "Recreating spring-boot-app service with docker-compose..."
docker-compose --env-file .env up -d --no-deps --build app
echo "Checking Docker containers..."
docker-compose ps
echo "Deployment completed successfully!"
dependency-submission:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
- name: Generate and submit dependency graph
uses: gradle/actions/dependency-submission@ # v4.0.0
9. 성공 여부 확인
- 퍼블릭 IP 주소로 접근이 잘 되는지 확인
- docker-compose logs 명령어로 에러 발생하는지 확인