Building a Multi-Language Microservice Project with Kubernetes, ArgoCD, and DevSecOps

Introduction

This blog post walks through my implementation of a multi-language microservice project (Java, Python, Go) deployed on Kubernetes, automated with ArgoCD (GitOps), and secured via DevSecOps practices (Trivy scanning, GitHub Actions CI/CD).

πŸ”— Project Repository

GitHub - multi-lang-devops-project

🌐Demo Endpoints


Technical Implementation

1. Microservices in Three Languages

β˜• Java Service (Spring Boot)

  • REST API with Spring Web

  • Actuator for health checks (/health)

  • Maven build system

  • Multi-stage Docker build for optimized image

🐍 Python Service (Flask)

  • Lightweight Flask REST API

  • Pytest for unit testing

  • requirements.txt dependency management

  • Alpine-based Docker image for minimal footprint

πŸš€ Go Service (Native HTTP)

  • Standard library HTTP server

  • Minimal dependencies (go.mod)

  • Single-binary deployment

  • Scratch-based Docker image (~5MB)


2. Kubernetes Deployment

All services are deployed using Kubernetes manifests with:

  • Deployments (replicas, resource limits)

  • Services (ClusterIP for internal communication)

  • Health checks (liveness & readiness probes)

Example Deployment (Java Service)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: java-service
spec:
  replicas: 2
  template:
    spec:
      containers:
      - name: java-service
        image: lookatravi/java-service:latest
        ports:
        - containerPort: 8080
        livenessProbe:
          httpGet:
            path: /api/java/health
            port: 8080

Manifest Structure

k8s-manifest-all/
β”œβ”€β”€ all-services.yaml  # Combined manifests
β”œβ”€β”€ java-deployment.yaml
β”œβ”€β”€ python-service.yaml
└── go-service.yaml

3. Local Development Access with Port-Forwarding

For easy local testing, I use a Bash script to automate kubectl port-forward:

port-forward.sh

#!/bin/bash

# Stop all port-forwards on script exit
trap "echo 'Stopping port-forwarding...'; kill 0" SIGINT SIGTERM EXIT

# Forward Java service (8080 β†’ 80)
nohup kubectl port-forward svc/java-service 8080:80 > java.log 2>&1 &
echo "Java: http://localhost:8080"

# Forward Python service (5001 β†’ 80)  
nohup kubectl port-forward svc/python-service 5001:80 > python.log 2>&1 &
echo "Python: http://localhost:5001"

# Forward Go service (5002 β†’ 80)
nohup kubectl port-forward svc/go-service 5002:80 > go.log 2>&1 &
echo "Go: http://localhost:5002"

wait  # Keep running until Ctrl+C

Features

βœ… Graceful shutdown (kills all forwards on exit)
βœ… Log separation (per-service logs in java.log, python.log, go.log)
βœ… Consistent ports (matches production endpoints)

Usage

chmod +x port-forward.sh
./port-forward.sh
# Access:
# - Java: localhost:8080
# - Python: localhost:5001  
# - Go: localhost:5002

4. ArgoCD (GitOps Deployment)

Deployed on AWS EC2, ArgoCD syncs Kubernetes manifests automatically:

Installation

helm install argocd argo/argo-cd --namespace argocd

Application Configuration

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: multi-lang-app
spec:
  source:
    repoURL: https://github.com/lookatravi/multi-lang-devops-project
    path: k8s-manifest-all
  destination:
    server: https://kubernetes.default.svc
  syncPolicy:
    automated:  # Auto-sync on Git changes
      prune: true
      selfHeal: true

Benefits

βœ” Automated deployments (Git as single source of truth)
βœ” Rollback capability (via Git history)
βœ” Visual UI for monitoring status


5. CI/CD Pipeline (GitHub Actions + DevSecOps)

Pipeline Stages

  1. Build & Test (Java, Python, Go)

  2. Dockerize & Push (to DockerHub)

  3. Security Scan (Trivy for vulnerabilities)

  4. Update K8s Manifests (GitOps trigger)

Key Workflow Features

- name: Trivy Scan (Java)
  run: |
    trivy image --severity CRITICAL,HIGH \
      --exit-code 1 \
      ${{ env.DOCKER_USERNAME }}/java-service:${{ github.run_id }}

- name: Update K8s Manifests
  run: |
    sed -i "s|image: lookatravi/java-service:.*|image: lookatravi/java-service:${{ github.run_id }}|" k8s-manifest-all/all-services.yaml
    git commit -am "CI: Update image tags"
    git push

Security Checks

πŸ”’ Trivy scans for CVEs in containers
πŸ”’ GitHub CodeQL integration for SARIF reports
πŸ”’ Fail pipeline on critical vulnerabilities

SARIF reports Sample


πŸ“Š Architecture Overview


πŸ“ Lessons Learned

βœ… Consistency is key – Standardizing APIs (/health, /api) across languages improves maintainability.
βœ… Go containers are tiny – Scratch images are ~5MB vs Java (~200MB).
βœ… Trivy + ArgoCD = Strong Security – Catching vulnerabilities before deployment is crucial.
βœ… Port-forwarding script saves time – No more manual kubectl commands!


Kubernetes Pods Running

kubectl get deployments
kubectl get svc
kubectl get pods

ArgoCD UI Sync Status

GitHub Actions Pipeline Passed

Live Endpoints Working

API: http://IP/localhost:8080/api/java

Health: http://IP/localhost:8080/api/java/health

API: http://IP/localhost:5001/api/python

Health: http://IP/localhost:5001/api/python/health

API: http://IP/localhost:5002/api/go

Health: http://IP/localhost:5002/api/go/health


πŸ”š Conclusion

This project demonstrates how to manage polyglot microservices with:
βœ” Kubernetes (unified deployment)
βœ” ArgoCD (GitOps automation)
βœ” DevSecOps (Trivy, GitHub Actions)
βœ” Bash automation (port-forwarding, logging)

Check out the full code:
πŸ‘‰ GitHub - multi-lang-devops-project

Questions? Let me know in the comments! πŸš€

0
Subscribe to my newsletter

Read articles from Ravichandran Sundaramurthy directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Ravichandran Sundaramurthy
Ravichandran Sundaramurthy