새로운 프로젝트에 앞서서 배포를 진행하기에 Github Actions + Docker를 통해 배포를 진행해보려고 한다.
순서는 다음과 같다.
1. Docker-compose.yml 작성
- 서비스에 필요한 인프라 이미지 작성
- ex) postgis, memcached 작성 서비스할 Dockerfile에 관련된 설정 작성
- ※주의 사항 host는 Docker compose 파일에서 정의한 서비스 이름으로 사용
- application.yml의 각 인프라의 url 호스트명은 docker 컨테이너 명으로 설정
- 기술적 의사결정
- Docker network 사용
- Docker network 사용하여 관리 및 유지보수를 용이하게 함
version: "3"
services:
postgresql:
image: postgis/postgis:16-3.4
restart: always
container_name: postgres
ports:
- "5432:5432"
environment:
POSTGRES_USER: ${DB_USER}
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_DB: ${DB_NAME}
volumes:
- ./data/postgres/:/var/lib/postgresql/data
networks:
- app-network
memcached:
image: memcached:1.6.25
container_name: memcached
ports:
- "11211:11211"
command: memcached -m 64 -o modern -v
networks:
- app-network
app:
build:
context: .
dockerfile: Dockerfile
ports:
- "8080:8080"
restart: always
depends_on:
- postgresql
- memcached
networks:
- app-network
environment:
- SPRING_PROFILES_ACTIVE=prod
- DATABASE_HOST=postgresql
- MEMCACHED_HOST=memcached
- MEMCACHED_PORT=11211
networks:
app-network:
driver: bridge
2. Dockerfile 작성
- docker를 통해 이미지 생성 및 빌드
- openjdk + jar 파일을 빌드할 코드 작성
# 런타임 스테이지
FROM openjdk:21-jdk-slim
RUN mkdir /app
# EC2 인스턴스에 이미 존재하는 JAR 파일을 이미지에 복사
COPY service-back.jar /app/service-back.jar
# 컨테이너 실행 시 JAR 파일 실행
ENTRYPOINT ["java", "-jar", "/app/service-back.jar"]
3. github Actions gradle.yml 작성
- GithubActions를 통해 배포를 진행할 workflow 작성 (git 프로젝트 리포지토리 -> Actions -> new workflow)
- CI/CD 코드작성
- CI
- CI부분 github Action은 git vm을 통해 빌드 및 테스트 진행
- github artifact를 사용하여 파일 업로드
트러블 슈팅
- artifact 사용시 저장할 이름명과 Path명이 같으면 안됨
name: Upload build artifact
uses: actions/upload-artifact@v2
with:
name: service-back
path: build/libs/service-back-0.0.1-SNAPSHOT.jar
- Github Actions 빌드 테스트 할때 postgis jdbc connection 문제
- github Actions는 자체적으로 github vm에서 build 및 테스트를 진행
- 따라서 서비스 resources 파일에 있는 application-test.yml을 통해 테스트 즉 로컬 환경의 테스트와 같다
- application-prod.yml과 다르게 postgis, memcached 호스트를 로컬로 변경하여 문제 해결
- CD
- CI과정에서 업로드한 파일들을 scp와 ssh로 EC2 인스턴스에 전송
- 인스턴스에서 Docker-compose.yml 빌드를 통해 서버 빌드 및 업데이트
# 워크 플로우 이름
name: Java CI with Gradle
# 워크 플로우가 언제 실행 될지를 정한다.
on:
pull_request:
types:
- closed
branches:
- dev
# 워크 플로우가 깃 레포에 대한 권한을 읽기 만 가능하게 설정한다.
@@ -15,40 +18,81 @@ permissions:
# 워크플로우에서 할 작업 정의한다.
jobs:
# 작업 환경 = 우분투 최신 버전
build:
runs-on: ubuntu-latest
if: (github.event_name == 'pull_request' && github.event.pull_request.merged == true)
services:
postgres:
image: postgis/postgis:16-3.4
env:
POSTGRES_PASSWORD: ${{ secrets.DB_PASSWORD }}
POSTGRES_DB: ${{ secrets.DB_NAME }}
POSTGRES_USER: ${{ secrets.DB_USER }}
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
memcached:
image: memcached:1.6.25
ports:
- 11211:11211
# 깃허브에서 제공하는 checkout 엑션 사용
steps:
- uses: actions/checkout@v4
# JDK 21 설정한당
# temurin = Adoptium에서 제공하는 JDK
- name: Set up JDK 21
uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'temurin'
# gradle wrapper 파일에 실행 권한을 부여
# gradle wrapper = 개발자가 특정 버전의 Gradle을 미리 설치하지 않고도 Gradle 빌드를 실행할 수 있게 해주는 편리한 도구
- name: Grant execute permission for gradlew
run: chmod +x gradlew
# 데이터베이스 서비스 준비 대기
- name: Wait for Postgres to become ready
run: |
until docker exec $(docker ps -q -f "ancestor=postgis/postgis:16-3.4") pg_isready -h localhost -p 5432 -U postgres; do
echo "Waiting for Postgres to become ready..."
sleep 5
done
echo "Postgres is ready."
# Gradle 빌드 엑션을 이용해서 프로젝트 빌드
- name: Build with Gradle
uses: gradle/gradle-build-action@v2
with:
gradle-version: '8.4'
arguments: build test
# 빌드해서 생긴 JAR 파일을 깃허브 아티팩트로 업로드!!
- name: Upload build artifact
uses: actions/upload-artifact@v2
with:
name: service-back
path: build/libs/service-0.0.1-SNAPSHOT.jar
- name: Upload Dockerfile
uses: actions/upload-artifact@v2
with:
name: service-dockerfile
path: Dockerfile
- name: Upload docker-compose
uses: actions/upload-artifact@v2
with:
name: service-docker-compose
path: docker/docker-compose.yml
# 배포 **
deploy:
@@ -57,21 +101,40 @@ jobs:
# 위의 빌드작업한 JAR 파일 = 아티팩트를 다운로드
steps:
- name: Download build artifact
uses: actions/download-artifact@v2
with:
name: service-back
path: build/libs/
- name: Download Dockerfile
uses: actions/download-artifact@v2
with:
name: service-dockerfile
path: ./
- name: Download docker-compose
uses: actions/download-artifact@v2
with:
name: service-docker-compose
path: docker/
- name: Deploy to EC2 and Build/Run Docker Containers
run: |
echo "${{ secrets.SSH_PEM_KEY }}" > ssh_key.pem
chmod 600 ssh_key.pem
scp -i ssh_key.pem -o StrictHostKeyChecking=no build/libs/service-0.0.1-SNAPSHOT.jar ${{ secrets.USER }}@${{ secrets.HOST }}:/home/${{ secrets.USER }}/service-back.jar
ssh -i ssh_key.pem -o StrictHostKeyChecking=no ${{ secrets.USER }}@${{ secrets.HOST }} "pgrep java | xargs kill -9; nohup java -jar /home/${{ secrets.USER }}/service-back.jar > app.log 2>&1 &"
scp -i ssh_key.pem -o StrictHostKeyChecking=no Dockerfile ${{ secrets.USER }}@${{ secrets.HOST }}:/home/${{ secrets.USER }}/Dockerfile
scp -i ssh_key.pem -o StrictHostKeyChecking=no docker/docker-compose.yml ${{ secrets.USER }}@${{ secrets.HOST }}:/home/${{ secrets.USER }}/docker-compose.yml
ssh -i ssh_key.pem -o StrictHostKeyChecking=no ${{ secrets.USER }}@${{ secrets.HOST }} << EOF
cd /home/${{ secrets.USER }}
docker compose build
docker compose up -d
EOF
4. EC2 배포할 서버의 인프라 구성
- Docker 다운로드(Docker-compose 포함)
- 이슈사항
EC2 Docker 다운로드(공식문서 참고)
https://docs.docker.com/engine/install/ubuntu/#install-using-the-repository
궁금한것
docker compose 빌드는 변경사항이 생긴다. 이렇게 되면 버전이 업데이트 될수록 Docker 이미지 관리는 어떻게 할것인가?
'배운내용 정리' 카테고리의 다른 글
Github Actions + Docker compose 버전관리 + nginx (0) | 2024.04.20 |
---|---|
Nginx + Certbot을 통한 Https 및 TimeZone 적용 (0) | 2024.04.15 |
JDBC (0) | 2023.11.13 |
Spring IoC와 DI (0) | 2023.11.10 |
Spring MVC (0) | 2023.11.09 |