DEV Community

ivan chiou
ivan chiou

Posted on

CI/CD pipeline using GitHub Actions to deploy to Google Cloud Platform (GCP)

๐Ÿš€ Why CI/CD?

CI/CD automates every stage of your software delivery process:

  • CI (Continuous Integration): Automatically builds and tests your code on each commit.
  • CD (Continuous Deployment): Automatically deploys your application to the production environment after passing tests.

Together, CI/CD reduces errors, improves productivity, and ensures reliable releasesโ€”critical in agile and DevOps workflows.


๐Ÿ—๏ธ Project Overview

Youโ€™ll learn how to:

  • Use GitHub Actions to automate Maven build and GCP deployment.
  • Securely manage SSH keys and secrets.
  • Use Docker for containerization (optional).
  • Deploy to a GCP Compute Engine VM running Ubuntu.

๐Ÿ”ง Prerequisites

Before you begin:

  • GCP project with Compute Engine VM set up (Ubuntu OS, Java installed).
  • GitHub repository for your Spring Boot project.
  • Domain name (e.g., from No-IP) and optional SSL certificate via Letโ€™s Encrypt.
  • SSH key pair added to your GitHub and GCP metadata.
  • Application setup (e.g., application.properties, MySQL, Redis, etc.) already running on the VM.

๐Ÿ“ GitHub Repository Setup

Image description

  1. Add Secrets to GitHub: Navigate to Settings โ†’ Secrets and Variables โ†’ Actions, and add:
    • GCP_SSH_PRIVATE_KEY: Your private SSH key (no passphrase).
    • GCP_VM_IP: Your VMโ€™s external IP.
    • GCP_VM_USER: The SSH username (usually your GCP email-based user).
    • KEYSTORE_BASE64: Base64 encoded keystore.p12 SSL cert file.

To create KEYSTORE_BASE64:

   base64 cert/keystore.p12 > keystore_base64.txt
Enter fullscreen mode Exit fullscreen mode
  1. Public Key in GCP VM: Upload your public SSH key (gcp_ssh_key.pub) using GCPโ€™s OS Login or manually via ~/.ssh/authorized_keys.

๐Ÿ“œ GitHub Actions Workflow File (.github/workflows/deploy.yml)

name: Deploy Java App to GCP VM

on:
  push:
    branches: [main]

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

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

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

      - name: Set up SSH
        run: |
          mkdir -p ~/.ssh
          echo "${{ secrets.GCP_SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
          chmod 600 ~/.ssh/id_rsa
          ssh-keyscan -H ${{ secrets.GCP_VM_IP }} >> ~/.ssh/known_hosts

      - name: Deploy JAR to GCP VM
        run: |
          scp -i ~/.ssh/id_rsa target/*.jar ${{ secrets.GCP_VM_USER }}@${{ secrets.GCP_VM_IP }}:/home/${{ secrets.GCP_VM_USER }}/app.jar
          ssh -i ~/.ssh/id_rsa ${{ secrets.GCP_VM_USER }}@${{ secrets.GCP_VM_IP }} << 'EOF'
            sudo pkill -f "java -jar" || true
            nohup java -jar /home/${{ secrets.GCP_VM_USER }}/app.jar --spring.config.location=/home/${{ secrets.GCP_VM_USER }}/application.properties > app.log 2>&1 &
          EOF
Enter fullscreen mode Exit fullscreen mode

๐Ÿ” SSL and Secrets Management

Use Letโ€™s Encrypt to generate a free SSL certificate:

sudo apt install certbot
sudo certbot certonly --standalone -d your-domain.ddns.net
Enter fullscreen mode Exit fullscreen mode

Convert to keystore.p12 for Spring Boot:

openssl pkcs12 -export -in fullchain.pem -inkey privkey.pem -out keystore.p12 -name mysslkey -password pass:yourpassword
Enter fullscreen mode Exit fullscreen mode

Encode and add it to GitHub as KEYSTORE_BASE64, then restore it in your workflow:

- name: Restore keystore.p12
  run: |
    mkdir -p src/main/resources/cert
    echo "${{ secrets.KEYSTORE_BASE64 }}" | base64 --decode > src/main/resources/cert/keystore.p12
Enter fullscreen mode Exit fullscreen mode

๐Ÿณ Bonus: Dockerizing Your Java App

To containerize your app:

  1. Create a Dockerfile:
FROM openjdk:17-slim
COPY target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
Enter fullscreen mode Exit fullscreen mode
  1. Add Docker build/push to your GitHub Actions:
- name: Build Docker Image
  run: docker build -t youruser/demo-spring-app .

- name: Push to Docker Hub
  run: |
    echo "${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}" | docker login -u "${{ secrets.DOCKER_HUB_USERNAME }}" --password-stdin
    docker push youruser/demo-spring-app
Enter fullscreen mode Exit fullscreen mode
  1. Pull and run the container on GCP VM:
docker pull youruser/demo-spring-app
docker run -d --name demo -p 8080:8080 youruser/demo-spring-app
Enter fullscreen mode Exit fullscreen mode

โœ… CI/CD Flow Summary

  1. Developer pushes code to GitHub main branch.
  2. GitHub Actions:
    • Builds the project using Maven.
    • Deploys .jar or Docker image to GCP VM.
  3. App runs on VM, accessible via your domain and secured with SSL.

๐ŸŽฏ Conclusion

Setting up a CI/CD pipeline with GitHub Actions and GCP Compute Engine offers a powerful, scalable, and fully automated deployment workflow for your Java apps. By leveraging GitHubโ€™s native integration with Secrets and Actions, plus the flexibility of GCP, you can deploy with confidence and consistency.

Top comments (0)