프로젝트에서 redis와 mysql을 같이 사용하는 상황이라 jar, redis, mysql을 하나의 도커 이미지로 만들어서 gcp에 올리기로 하였다.
1. Dockerfile
# Base image
FROM openjdk:21-jdk-slim
# Build arguments
ARG JAR_FILE=build/libs/*.jar
# Copy the application JAR
COPY ${JAR_FILE} app.jar
# Expose the application port
EXPOSE 8080
# Run the application
ENTRYPOINT ["java", "-jar", "/app.jar"]
2. docker-compose.yml
version: '3.8'
services:
app:
build:
context: .
dockerfile: Dockerfile
image: ${DOCKER_USERNAME}/app:latest
ports:
- "8080:8080"
environment:
SPRING_PROFILES_ACTIVE: ${SPRING_PROFILES_ACTIVE}
DB_URL: ${DB_URL}
DB_USER: ${DB_USER}
DB_PASSWORD: ${DB_PASSWORD}
REDIS_PASSWORD: ${REDIS_PASSWORD}
env_file:
- .env
depends_on:
mysql:
condition: service_healthy
redis:
condition: service_healthy
volumes:
- /home:/data
restart: always
mysql:
image: mysql:8.0
container_name: mysql
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
MYSQL_DATABASE: ${MYSQL_DATABASE}
env_file:
- .env
volumes:
- mysql-data:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-p${DB_PASSWORD}"]
interval: 10s
timeout: 5s
retries: 3
restart: always
redis:
image: redis:6.2-alpine
container_name: redis
ports:
- "6379:6379"
environment:
REDIS_PASSWORD: ${REDIS_PASSWORD}
command: ["redis-server", "--requirepass", "${REDIS_PASSWORD}"]
env_file:
- .env
healthcheck:
test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"]
interval: 10s
timeout: 5s
retries: 3
restart: always
volumes:
mysql-data:
docker-compose.yml을 이용해 mysql, redis, app.jar을 한번에 이미지로 만들어 줄 수 있도록 하였다.
이때 gcp에서 env 파일의 위치를 보고 참조할 수 있도록 volumes: - mysql-data:/var/lib/mysql를 이용해 위치를 표시해주었다.
3. git actioins
name: Deploy to Compute Engine
on:
push:
branches:
- main
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Log in to Docker Hub
run: echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin
- name: Set up JDK
uses: actions/setup-java@v3
with:
java-version: '21'
distribution: 'temurin'
- name: Add execute permission to Gradle Wrapper
run: chmod +x ./gradlew
- name: Build project without running tests
run: ./gradlew build -x test
- name: Install Docker
run: |
sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
sudo apt-get update
sudo apt-get install -y docker-ce
- name: Install standalone Docker Compose
run: |
sudo curl -L "https://github.com/docker/compose/releases/download/v2.20.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
- name: Verify Docker Compose installation
run: docker-compose --version
- name: Generate .env file
run: |
cat <<EOF > .env
DOCKER_USERNAME=${{ secrets.DOCKER_USERNAME }}
SPRING_PROFILES_ACTIVE=prod
DB_URL=jdbc:mysql://mysql:3306/${{ secrets.MYSQL_DATABASE }}
DB_USER=root
DB_PASSWORD=${{ secrets.DB_PASSWORD }}
MYSQL_DATABASE=${{ secrets.MYSQL_DATABASE }}
REDIS_PASSWORD=${{ secrets.REDIS_PASSWORD }}
JWT_EXPIRATION=${{ secrets.JWT_EXPIRATION }}
JWT_SECRET=${{ secrets.JWT_SECRET }}
YOUTUBE_KEY=${{ secrets.YOUTUBE_KEY }}
EOF
shell: bash
- name: Build and push Docker images
run: |
docker-compose -f ${{ github.workspace }}/docker-compose.yml build
docker-compose -f ${{ github.workspace }}/docker-compose.yml push
- name: Authenticate to GCP
uses: google-github-actions/auth@v1
with:
credentials_json: ${{ secrets.GCP_SA_KEY }}
- name: Set up GCP configuration
run: |
gcloud config set project ${{ secrets.GCP_PROJECT_ID }}
gcloud config set compute/zone ${{ secrets.GCP_ZONE }}
- name: Copy configuration files to VM
run: |
# Copy docker-compose.yml
gcloud compute scp ${{ github.workspace }}/docker-compose.yml ${{ secrets.VM_NAME }}:/tmp/docker-compose.yml --zone ${{ secrets.GCP_ZONE }}
# Copy .env file
gcloud compute scp .env ${{ secrets.VM_NAME }}:/tmp/.env --zone ${{ secrets.GCP_ZONE }}
- name: Move configuration files to appropriate directory
run: |
gcloud compute ssh ${{ secrets.VM_NAME }} --zone ${{ secrets.GCP_ZONE }} --command "
sudo mv /tmp/docker-compose.yml /home/${{ secrets.VM_USER }}/docker-compose.yml &&
sudo mv /tmp/.env /home/${{ secrets.VM_USER }}/.env &&
sudo chown $USER:$USER /home/${{ secrets.VM_USER }}/docker-compose.yml &&
sudo chown $USER:$USER /home/${{ secrets.VM_USER }}/.env
"
- name: Pull Docker images and start services on VM
run: |
gcloud compute ssh ${{ secrets.VM_NAME }} --zone ${{ secrets.GCP_ZONE }} --command "
cd /home/${{ secrets.VM_USER }} &&
sudo docker login -u '${{ secrets.DOCKER_USERNAME }}' -p '${{ secrets.DOCKER_PASSWORD }}' &&
sudo docker-compose --env-file .env -f docker-compose.yml pull &&
sudo docker-compose --env-file .env -f docker-compose.yml up -d
".
git actioins 코드에서 ${{ secrets.VM_NAME }}와 같이 secrets.~ 인 값은 github에 있는 Secrets기능을 사용해 보안상 중요한 코드들을 숨겨둔 것이다.
https://every-word.tistory.com/16
git-secret 사용하기
배포를 진행하기 위해 환경변수, .env 파일처럼 보안상 중요한 코드를 숨기는 방법을 찾아보았다. git-secret를 등록할 레포지토리에서 Settings -> Secrets and variables -> Actions로 이동한다 Repository secre
every-word.tistory.com
에 git secret를 사용하는 방법을 정리해 놨다.
git actioins 코드를 설명하면 다음과 같다.
1. 워크플로우 이름 및 트리거 조건
name: Deploy to Compute Engine
on:
push:
branches:
- main
- 워크플로우 이름: Deploy to Compute Engine
- 트리거: main 브랜치에 코드가 푸시될 때 실행됩니다.
2. 작업(Job): build-and-deploy
jobs:
build-and-deploy:
runs-on: ubuntu-latest
- 실행 환경: ubuntu-latest (최신 우분투 OS 사용)
(1) 코드 체크아웃
steps:
- name: Checkout code
uses: actions/checkout@v3
- GitHub 저장소의 코드를 가져옵니다.
(2) Docker Hub 로그인
- name: Log in to Docker Hub
run: echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin
- Docker 이미지를 빌드하고 푸시하기 위해 Docker Hub에 로그인합니다.
- secrets 사용: GitHub Secrets에서 보안 정보를 읽어옵니다
(3) Java 환경 설정
- name: Set up JDK
uses: actions/setup-java@v3
with:
java-version: '21'
distribution: 'temurin'
- Java 21 버전을 설치하고 Gradle 빌드를 준비합니다.
(4) Gradle 빌드 준비 및 실행
- name: Add execute permission to Gradle Wrapper
run: chmod +x ./gradlew
- name: Build project without running tests
run: ./gradlew build -x test
- Gradle Wrapper에 실행 권한을 부여하고, 테스트를 제외한 빌드를 실행합니다.
(5) Docker 및 Docker Compose 설치
- name: Install Docker
run: |
sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
sudo apt-get update
sudo apt-get install -y docker-ce
- name: Install standalone Docker Compose
run: |
sudo curl -L "https://github.com/docker/compose/releases/download/v2.20.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
- name: Verify Docker Compose installation
run: docker-compose --version
- Docker: 애플리케이션 컨테이너 이미지를 빌드 및 배포하기 위해 설치.
- Docker Compose: 여러 컨테이너 서비스를 정의하고 실행하기 위해 사용.
- 설치 후, Docker Compose가 제대로 설치되었는지 확인.
(6) 환경 변수 파일(.env) 생성
- name: Generate .env file
run: |
cat <<EOF > .env
DOCKER_USERNAME=${{ secrets.DOCKER_USERNAME }}
SPRING_PROFILES_ACTIVE=prod
DB_URL=jdbc:mysql://mysql:3306/${{ secrets.MYSQL_DATABASE }}
DB_USER=root
DB_PASSWORD=${{ secrets.DB_PASSWORD }}
MYSQL_DATABASE=${{ secrets.MYSQL_DATABASE }}
REDIS_PASSWORD=${{ secrets.REDIS_PASSWORD }}
JWT_EXPIRATION=${{ secrets.JWT_EXPIRATION }}
JWT_SECRET=${{ secrets.JWT_SECRET }}
YOUTUBE_KEY=${{ secrets.YOUTUBE_KEY }}
EOF
shell: bash
- 배포 과정에서 필요한 민감한 정보를 포함한 .env 파일을 생성.
- GitHub Secrets에서 읽은 값을 활용.
(7) Docker 이미지 빌드 및 푸시
- name: Build and push Docker images
run: |
docker-compose -f ${{ github.workspace }}/docker-compose.yml build
docker-compose -f ${{ github.workspace }}/docker-compose.yml push
- docker-compose.yml 파일을 기반으로 이미지를 빌드한 뒤, Docker Hub에 푸시.
(8) Google Cloud Platform(GCP) 인증
- name: Authenticate to GCP
uses: google-github-actions/auth@v1
with:
credentials_json: ${{ secrets.GCP_SA_KEY }}
- name: Set up GCP configuration
run: |
gcloud config set project ${{ secrets.GCP_PROJECT_ID }}
gcloud config set compute/zone ${{ secrets.GCP_ZONE }}
- GCP 인증: GitHub Secrets에서 서비스 계정 키(JSON)를 읽어 인증.
- 구성 설정: GCP 프로젝트 및 리전을 설정.
(9) GCE로 파일 복사
- name: Copy configuration files to VM
run: |
# Copy docker-compose.yml
gcloud compute scp ${{ github.workspace }}/docker-compose.yml ${{ secrets.VM_NAME }}:/tmp/docker-compose.yml --zone ${{ secrets.GCP_ZONE }}
# Copy .env file
gcloud compute scp .env ${{ secrets.VM_NAME }}:/tmp/.env --zone ${{ secrets.GCP_ZONE }}
- name: Move configuration files to appropriate directory
run: |
gcloud compute ssh ${{ secrets.VM_NAME }} --zone ${{ secrets.GCP_ZONE }} --command "
sudo mv /tmp/docker-compose.yml /home/${{ secrets.VM_USER }}/docker-compose.yml &&
sudo mv /tmp/.env /home/${{ secrets.VM_USER }}/.env &&
sudo chown $USER:$USER /home/${{ secrets.VM_USER }}/docker-compose.yml &&
sudo chown $USER:$USER /home/${{ secrets.VM_USER }}/.env
"
- gcloud compute scp 명령을 사용해 구성 파일을 GCE 가상머신(VM)으로 복사.
(10) VM에서 Docker 컨테이너 실행
- name: Pull Docker images and start services on VM
run: |
gcloud compute ssh ${{ secrets.VM_NAME }} --zone ${{ secrets.GCP_ZONE }} --command "
cd /home/${{ secrets.VM_USER }} &&
sudo docker login -u '${{ secrets.DOCKER_USERNAME }}' -p '${{ secrets.DOCKER_PASSWORD }}' &&
sudo docker-compose --env-file .env -f docker-compose.yml pull &&
sudo docker-compose --env-file .env -f docker-compose.yml up -d
"
- VM에 접속한 후, Docker 이미지를 가져와 컨테이너 서비스를 시작합니다.
- .env 파일을 읽어 Docker Compose를 실행합니다.
'프로젝트' 카테고리의 다른 글
| 꾸똑(구독을 똑똑하게) - 에필로그 (1) | 2024.12.25 |
|---|---|
| music place 프로젝트 소개 (0) | 2024.12.01 |
| GCP docker 컨테이너에 있는 MySQL 접속하기 (0) | 2024.12.01 |
| 스프링 시큐리티 인증(ajaxAuthenticationFilter, jwt, oauth2) (0) | 2024.09.20 |
| [기록] Music Place - DB 설계 (0) | 2024.04.04 |