GCP VM 준비

가장 저렴한 E2-micro(vCPU 2, 1GB 메모리)를 사용하고 Ubuntu 24.04 LTS를 사용합니다 vm생성후 ssh 접속을 통해 동작을 확인합니다

vm 인스턴스에서 초기 준비를 합니다. docker, docker-compose, docker rootless를 설치합니다

sudo apt update && sudo apt upgrade -y

sudo sh -eux <<EOF
# Install newuidmap & newgidmap binaries
apt-get install -y uidmap
EOF
dockerd-rootless-setuptool.sh install


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

또한 ssh 연결 종료후 서버 동작 유지를 위해 linger를 활성화 합니다 sudo loginctl enable-linger $(whoami)

GCP 방화벽 설정

VPC 네트워크 > 방화벽 > 방화벽 규칙 만들기 메뉴를 통해서 위에서 생성한 인스턴스에 대해 TCP 포트 8000을 허용합니다

GCP IAM 설정

gcloud compute ssh 를 사용하여 외부에서 인스턴스 제어를 위해 필요합니다 IAM 및 관리자 > 서비스계정 메뉴로 이동후 상단의 +서비스 계정 만들기 메뉴를 클릭합니다 서비스 계정 이름 입력 후 아래 3개 역할을 추가합니다

  • 서비스 계정 사용자(Service Account User)
  • Compute 인스턴스 관리자(Compute Instance Admin)
  • Compute OS 로그인 (Compute OS Login)

Docker 작성

Dockerfile.backend 백엔드는 코틀린/스프링부트 조합입니다

FROM gradle:8.5.0-jdk17 AS build
WORKDIR /home/gradle/src

COPY build.gradle.kts settings.gradle.kts gradlew ./
COPY gradle ./gradle

RUN chmod +x ./gradlew
RUN ./gradlew dependencies --no-daemon

COPY src ./src

RUN ./gradlew bootJar -x test

FROM openjdk:17.0.1-jdk-slim
WORKDIR /app
COPY --from=build /home/gradle/src/build/libs/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]

Dockerfile.frontend 프론트는 리액트로 구성되어 있습니다

FROM node:18-alpine AS build
WORKDIR /app/frontend
COPY frontend/package.json frontend/package-lock.json ./
RUN npm install
COPY frontend/ ./
RUN npm run build

FROM nginx:stable-alpine
COPY --from=build /app/frontend/dist /usr/share/nginx/html
COPY nginx.default.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

GCP vm에서 사용할 docker-compose.yml 입니다

services:
  backend:
    image: your-docker-hub/backend:1.0
    container_name: backend
    restart: always
    ports:
      - "8080:8080"
    networks:
      - custom-net

  frontend:
    image: your-docker-hub/frontend:1.0
    container_name: frontend
    restart: always
    ports:
      - "8000:80"
    depends_on:
      - backend
    networks:
      - custom-net

networks:
  custom-net:
    driver: bridge

Github actions 워크플로우 작성

buildx 를 사용해서 backend, frontend 이미지를 빌드하고 dockerhub에 업로드합니다 이후 gcloud를 사용하여 gcp vm에 저장소를 최신화 하고 docker-compose 를 사용하여 최신상태 서버로 재시작합니다

name: CI/CD Pipeline to GCP VM

on:
  push:
    branches:
      - main

jobs:
  # 첫 번째 Job: Docker 이미지 빌드 및 푸시
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Log in to Docker Hub
        uses: docker/login-action@v3
        with:
          username: $
          password: $

      - name: Build and push Backend image
        run: |
          export DOCKER_USER=$
          export VERSION=1.0
          docker buildx build \
            --platform linux/amd64 \
            -t $DOCKER_USER/backend:$VERSION \
            -f Dockerfile.backend \
            --push .

      - name: Build and push Frontend image
        run: |
          export DOCKER_USER=$
          export VERSION=1.0
          docker buildx build \
            --platform linux/amd64 \
            -t $DOCKER_USER/frontend:$VERSION \
            -f Dockerfile.frontend \
            --push .

  # 두 번째 Job: GCP VM에 배포
  deploy:
    needs: build # 'build' Job이 성공해야만 이 Job이 실행됨
    runs-on: ubuntu-latest
    steps:
      - name: Authenticate to Google Cloud
        uses: google-github-actions/auth@v2
        with:
          credentials_json: $

      - name: Deploy to GCP VM via gcloud
        run: |
          gcloud compute ssh $@$ \
            --project=$ \
            --zone us-central1-c \
            --command="cd ~/workspace && git pull --rebase && docker-compose pull && docker-compose up -d"

해야할일

  • 고정 IP 주소 또는 도메인 연결
  • Nginx 리버스 프록시 구성
  • HTTPS/SSL 적용