Engineering Note

[Server] GCP 인스턴스 만들고 배포하기 + githubaction(무료 크레딧 사용) 본문

Server

[Server] GCP 인스턴스 만들고 배포하기 + githubaction(무료 크레딧 사용)

Software Engineer Kim 2025. 12. 21. 20:50

 

GCP는 3개월간 무료크레딧을 주고 비용이 나가지 않기 때문에 선택했다.

 

1. 인스턴스 만들기

 

무료 크레딧 조건에 맞게 인스턴스를 생성해준다.

 

2. 운영체제 선택

운영체제도 자신에게 맞는 운영체제를 선택한다. 나는 ubuntu가 가장 익숙해 ubuntu를 선택했다.

 

 

 

3. SSH 키 생성과 GCP SSH 연결

3-1 SSH 키 생성

ssh-keygen -t rsa -f ~/.ssh/gcp-key -C "GCP계정메일주소"

 

  • -t rsa: RSA 암호화 방식을 사용합니다.
  • -f ~/.ssh/gcp-key: 키 파일의 이름을 gcp-key로 지정하고 .ssh 폴더에 저장합니다. (이름은 자유롭게 변경 가능합니다.)
  • -C "메일주소": 주석(Comment)입니다. 보통 GCP 로그인 이메일을 넣으면 관리가 편합니다.

 

 

이렇게 하면 지정한 경로에 2개의 파일이 생겼을 것이다.

  • gcp-key: 비밀키 (Private Key) - 절대 남에게 보여주면 안 됩니다. 내 컴퓨터에 보관하세요.
  • gcp-key.pub: 공개키 (Public Key) - GCP 콘솔에 등록할 파일입니다.
    • 공개키 확인하기 : cat ~/.ssh/gcp-key.pub

 

3-2 SSH 공개키 GCP에 등록하기

 

GCP Settings에서 Metadata에서 SSH Keys를 등록한다.

 

 

3-3. 로컬에서 GCP SSH로 접속하기

ssh -i ~/.ssh/gcp-key [사용자이름]@[인스턴스_외부_IP]

 

github repo> Settings > Secrets & Variables, Actions

 

여기서 위 이미지 처럼 Repository scretes에서 New repository secret 키를 등록해준다.

  • SERVER_HOST : GCP VM IP
  • SERVER_KEY : SSH private key(public key가 아니라 private key를 등록한다.)
  • SERVER_USER : 사용자 이름(ex. ubuntu)

 

 

work-flow.yml

name: Deploy on PR Merge

on:
  pull_request:
    types: [ closed ]
    branches: [ dev ]

jobs:
  deploy:
    runs-on: ubuntu-latest
    # PR이 merge되었을 때만 실행
    if: github.event.pull_request.merged == true

    steps:
      - name: Checkout merged code
        uses: actions/checkout@v3
        with:
          ref: ${{ github.event.pull_request.merge_commit_sha }}

      - name: Set up JDK 17
        uses: actions/setup-java@v3
        with:
          java-version: '17'
          distribution: 'temurin'

      - name: Build with Maven
        run: mvn clean package -DskipTests

      - name: Verify build output
        run: |
          echo "JAR file created:"
          ls -la target/shop-0.0.1-SNAPSHOT.jar
          du -h target/shop-0.0.1-SNAPSHOT.jar

      - name: Copy deployment files to server
        uses: appleboy/scp-action@v0.1.4
        with:
          host: ${{ secrets.SERVER_HOST }}
          username: ${{ secrets.SERVER_USER }}
          key: ${{ secrets.SERVER_KEY }}
          source: "target/shop-0.0.1-SNAPSHOT.jar,docker-compose.yml,Dockerfile,nginx/,src/main/resources/application-prod.yml"
          target: "/home/${{ secrets.SERVER_USER }}/shop-app/"
          strip_components: 0

      - name: Deploy with Docker Compose
        uses: appleboy/ssh-action@v0.1.5
        with:
          host: ${{ secrets.SERVER_HOST }}
          username: ${{ secrets.SERVER_USER }}
          key: ${{ secrets.SERVER_KEY }}
          script: |
            cd /home/${{ secrets.SERVER_USER }}/shop-app/
            
            echo "=== PR #${{ github.event.pull_request.number }} merged by ${{ github.event.pull_request.user.login }} ==="
            echo "=== Deploying to dev environment ==="
            
            echo "=== Stopping existing containers ==="
            docker-compose down || true
            
            echo "=== Mkdir image directory ==="
            mkdir -p /home/${{ secrets.SERVER_USER }}/shop-app/uploads/item
            
            echo "=== Removing old images ==="
            docker image prune -f
            
            echo "=== Starting new deployment ==="
            docker-compose up -d --build
            
            echo "=== Waiting for services to start ==="
            sleep 30
            
            echo "=== Checking container status ==="
            docker-compose ps
            
            echo "=== Checking application health ==="
            for i in {1..10}; do
              if curl -f http://localhost/actuator/health; then
                echo "✅ Application is healthy!"
                break
              else
                echo "Attempt $i: Application not ready yet, waiting 10 seconds..."
                sleep 10
              fi
            done
            
            echo "=== Recent application logs ==="
            docker-compose logs --tail=50 app

      - name: Notify deployment result
        if: always()
        run: |
          if [ ${{ job.status }} == 'success' ]; then
            echo "✅ Deployment successful for PR #${{ github.event.pull_request.number }}"
          else
            echo "❌ Deployment failed for PR #${{ github.event.pull_request.number }}"
          fi

'Server' 카테고리의 다른 글

[Server] 데이터베이스 커넥션풀  (0) 2025.12.27
[Server] Redis 자료구조  (1) 2025.12.27
[Spring] OncePerRequestFilter  (0) 2025.12.21
[Server] Access Token과 Refresh Token을 사용하는 이유  (0) 2025.12.19
[JPA] em.flush();  (0) 2025.12.15
Comments