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
  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

🔐 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

Convert to keystore.p12 for Spring Boot:

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

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

🐳 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"]
  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
  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

✅ 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.

Leave a Reply