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