Kubernetes for Java & Python Developers

Kubernetes for Java & Python Developers | TK Tips

Kubernetes for Java & Python Developers

Master Pods, Deployments, Services & CI/CD pipelines with real project examples tailored for Java Spring Boot and Python Django/FastAPI applications.

Java/Spring Boot
Python/Django/FastAPI
Kubernetes

Core Kubernetes Concepts

Pods

The smallest deployable units in Kubernetes. For Java/Python apps, a pod typically contains your application container and sidecars for logging, monitoring, or service mesh.

Developer Tip: Don’t put multiple app containers in one pod unless they’re tightly coupled.

Deployments

Manages the lifecycle of pods. Handles rolling updates, rollbacks, and scaling. Essential for zero-downtime deployments of your Java/Python applications.

Java Tip: Set proper memory limits for JVM apps. Python Tip: Use Gunicorn/Uvicorn workers appropriately.

Services

Abstract way to expose your application. Load balances traffic to pods. Types: ClusterIP (internal), NodePort, LoadBalancer, and Ingress for HTTP routing.

Real-world: Use Ingress for web apps, ClusterIP for microservices communication.

Pod vs Deployment: Quick Comparison

Pod YAML (Basic) k8s-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: java-app-pod
spec:
  containers:
  - name: spring-boot-app
    image: myapp:1.0
    ports:
    - containerPort: 8080
    resources:
      requests:
        memory: "512Mi"
        cpu: "250m"
      limits:
        memory: "1Gi"
        cpu: "500m"
Deployment YAML (Production) deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: java-app-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: java-app
  template:
    metadata:
      labels:
        app: java-app
    spec:
      containers:
      - name: spring-boot-app
        image: myapp:1.0
        ports:
        - containerPort: 8080
        livenessProbe:
          httpGet:
            path: /actuator/health
            port: 8080
        readinessProbe:
          httpGet:
            path: /actuator/health/readiness
            port: 8080

Java vs Python in Kubernetes

Key Differences & Best Practices

Java/Spring Boot
# Dockerfile for Spring Boot
FROM openjdk:17-jdk-slim
WORKDIR /app
COPY target/*.jar app.jar

# JVM Memory Configuration
ENV JAVA_OPTS="-Xmx512m -Xms256m"
ENV SPRING_PROFILES_ACTIVE="k8s"

# Health Checks (Spring Actuator)
HEALTHCHECK --interval=30s --timeout=3s \
  CMD curl -f http://localhost:8080/actuator/health || exit 1

EXPOSE 8080
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]

Best Practices:

  • Set JVM memory limits in Dockerfile & K8s
  • Use Spring Actuator for health checks
  • Enable graceful shutdown
  • Use ConfigMaps for application.properties
Python/FastAPI
# Dockerfile for FastAPI
FROM python:3.11-slim
WORKDIR /app

# Install dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Copy application
COPY . .

# Gunicorn configuration
ENV WORKERS=4
ENV PORT=8000

# Health check endpoint
HEALTHCHECK --interval=30s --timeout=3s \
  CMD curl -f http://localhost:8000/health || exit 1

EXPOSE 8000
CMD ["gunicorn", "main:app", \
     "--workers", "4", \
     "--worker-class", "uvicorn.workers.UvicornWorker", \
     "--bind", "0.0.0.0:8000"]

Best Practices:

  • Use Gunicorn with Uvicorn workers for async
  • Set appropriate worker counts based on CPU
  • Implement /health endpoint
  • Use environment variables for configuration

Memory Management

Java: Set -Xmx and -Xms flags. Monitor heap usage with JMX or Micrometer.

Python: Watch for memory leaks. Use workers appropriately. Consider using PyPy for CPU-bound tasks.

Health Checks

Java: Spring Boot Actuator provides /health, /readiness, /liveness endpoints out of the box.

Python: Implement custom health endpoints or use FastAPI’s health check extensions.

Configuration

Both: Use ConfigMaps and Secrets. Never hardcode configurations. Use environment-specific profiles.

Production Deployments

Complete Deployment Example

Java Spring Boot Deployment with ConfigMap spring-deployment.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: spring-app-config
data:
  application.properties: |
    server.port=8080
    spring.datasource.url=${DB_URL}
    logging.level.root=INFO
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: spring-boot-deployment
spec:
  replicas: 3
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  selector:
    matchLabels:
      app: spring-boot-app
  template:
    metadata:
      labels:
        app: spring-boot-app
    spec:
      containers:
      - name: spring-app
        image: myregistry/spring-app:1.2.0
        ports:
        - containerPort: 8080
        env:
        - name: DB_URL
          valueFrom:
            secretKeyRef:
              name: db-secret
              key: url
        - name: JAVA_OPTS
          value: "-Xmx512m -Xms256m -XX:+UseG1GC"
        volumeMounts:
        - name: config-volume
          mountPath: /app/config
        livenessProbe:
          httpGet:
            path: /actuator/health/liveness
            port: 8080
          initialDelaySeconds: 60
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /actuator/health/readiness
            port: 8080
          initialDelaySeconds: 30
          periodSeconds: 5
        resources:
          requests:
            memory: "512Mi"
            cpu: "250m"
          limits:
            memory: "1Gi"
            cpu: "500m"
      volumes:
      - name: config-volume
        configMap:
          name: spring-app-config

Rolling Update Strategy

Before Update

v1.0 v1.0 v1.0
β†’

During Update

v1.0 v1.1 v1.0
β†’

After Update

v1.1 v1.1 v1.1

Commands for Deployment Management

# Deploy application
kubectl apply -f spring-deployment.yaml

# Check rollout status
kubectl rollout status deployment/spring-boot-deployment

# View deployment history
kubectl rollout history deployment/spring-boot-deployment

# Rollback to previous version
kubectl rollout undo deployment/spring-boot-deployment

# Scale deployment
kubectl scale deployment spring-boot-deployment --replicas=5

# Update image version
kubectl set image deployment/spring-boot-deployment \
  spring-app=myregistry/spring-app:1.3.0

Services & Networking

Service Types Comparison

ClusterIP

Use Case: Internal communication between microservices

Java Example: Spring Boot service calling another Spring Boot service

Python Example: FastAPI service calling a Django REST API

kind: Service
apiVersion: v1
metadata:
  name: internal-service
spec:
  type: ClusterIP
  selector:
    app: my-app
  ports:
  - port: 8080
    targetPort: 8080

NodePort

Use Case: Development/testing, exposing to external traffic directly

Port Range: 30000-32767

Not Recommended for production web applications

kind: Service
apiVersion: v1
metadata:
  name: nodeport-service
spec:
  type: NodePort
  selector:
    app: my-app
  ports:
  - port: 80
    targetPort: 8080
    nodePort: 30007

LoadBalancer

Use Case: Cloud providers (AWS, GCP, Azure)

Creates: External load balancer

Cost: Additional cloud costs

kind: Service
apiVersion: v1
metadata:
  name: loadbalancer-service
spec:
  type: LoadBalancer
  selector:
    app: my-app
  ports:
  - port: 80
    targetPort: 8080

Ingress

Use Case: Production web applications (HTTP/HTTPS)

Features: SSL termination, path-based routing, virtual hosts

Requires: Ingress Controller (nginx, traefik)

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: app-ingress
spec:
  rules:
  - host: app.tktips.org
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: spring-app-service
            port:
              number: 8080

Complete Example: Spring Boot with Ingress

Full Stack: Deployment + Service + Ingress full-stack.yaml
# Spring Boot Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: spring-boot-api
spec:
  replicas: 3
  selector:
    matchLabels:
      app: spring-api
  template:
    metadata:
      labels:
        app: spring-api
    spec:
      containers:
      - name: api
        image: myapp/api:2.1.0
        ports:
        - containerPort: 8080
        env:
        - name: SPRING_PROFILES_ACTIVE
          value: "production"
---
# Service
apiVersion: v1
kind: Service
metadata:
  name: spring-api-service
spec:
  selector:
    app: spring-api
  ports:
  - port: 80
    targetPort: 8080
---
# Ingress (NGINX)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: api-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
  tls:
  - hosts:
    - api.tktips.org
    secretName: api-tls-secret
  rules:
  - host: api.tktips.org
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: spring-api-service
            port:
              number: 80

CI/CD Pipeline for Kubernetes

Modern CI/CD Pipeline for Java & Python Apps

1. Code Commit

Developer pushes code to Git repository (GitHub/GitLab)

2. Build & Test

Java: Maven/Gradle build + unit tests
Python: pip install + pytest

3. Build Image

Create Docker image
Tag with commit SHA
Push to registry

4. Security Scan

Scan for vulnerabilities
Check dependencies
Image signing

5. Deploy to K8s

Update deployment
Canary/Rolling update
Health checks

6. Monitor & Verify

Monitor metrics
Automated rollback if needed
Performance verification

GitHub Actions Example

Java CI/CD Pipeline .github/workflows/java-k8s.yml
name: Java CI/CD to Kubernetes

on:
  push:
    branches: [ main ]

jobs:
  build-test:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    
    - 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: Run tests
      run: mvn test
      
    - name: Build Docker image
      run: |
        docker build -t myregistry/java-app:${{ github.sha }} .
        docker push myregistry/java-app:${{ github.sha }}
        
  deploy:
    needs: build-test
    runs-on: ubuntu-latest
    steps:
    - name: Deploy to Kubernetes
      run: |
        # Update deployment with new image
        kubectl set image deployment/java-app \
          java-app=myregistry/java-app:${{ github.sha }}
        kubectl rollout status deployment/java-app
        
    - name: Run integration tests
      run: |
        # Test the deployed application
        ./scripts/integration-test.sh
Python CI/CD Pipeline .github/workflows/python-k8s.yml
name: Python CI/CD to Kubernetes

on:
  push:
    branches: [ main ]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    
    - name: Set up Python
      uses: actions/setup-python@v4
      with:
        python-version: '3.11'
        
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install -r requirements.txt
        
    - name: Run tests
      run: |
        pytest --cov=app tests/
        
  build-deploy:
    needs: test
    runs-on: ubuntu-latest
    steps:
    - name: Build Docker image
      run: |
        docker build -t myregistry/python-app:${{ github.sha }} .
        docker push myregistry/python-app:${{ github.sha }}
        
    - name: Configure kubectl
      uses: azure/setup-kubectl@v3
      with:
        version: 'latest'
        
    - name: Deploy to Kubernetes
      run: |
        # Use kustomize for environment-specific configs
        kustomize build k8s/overlays/prod | \
          kubectl apply -f -
        kubectl rollout status deployment/python-app
        
    - name: Health check
      run: |
        # Wait for service to be healthy
        ./scripts/health-check.sh

GitOps with ArgoCD/Flux

Recommended for production: Use GitOps tools to sync your Kubernetes manifests automatically.

# ArgoCD Application Manifest
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: java-app
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/yourrepo/k8s-manifests
    targetRevision: HEAD
    path: apps/java-app/overlays/prod
  destination:
    server: https://kubernetes.default.svc
    namespace: production
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
    - CreateNamespace=true

Real Project Examples

E-commerce Microservices (Java)

Stack: Spring Boot + MySQL + Redis + Kafka

K8s Components:

  • Deployments for each service
  • ConfigMaps for application properties
  • Secrets for database credentials
  • Ingress for API gateway
  • Horizontal Pod Autoscaler
  • StatefulSets for MySQL and Kafka
Project Structure:
k8s/
β”œβ”€β”€ base/
β”‚   β”œβ”€β”€ deployment.yaml
β”‚   β”œβ”€β”€ service.yaml
β”‚   └── hpa.yaml
β”œβ”€β”€ overlays/
β”‚   β”œβ”€β”€ dev/
β”‚   └── prod/
└── databases/
    β”œβ”€β”€ mysql-statefulset.yaml
    └── redis-deployment.yaml

Data Processing Pipeline (Python)

Stack: FastAPI + Celery + PostgreSQL + RabbitMQ

K8s Components:

  • Deployments for API and workers
  • Jobs for batch processing
  • CronJobs for scheduled tasks
  • PersistentVolumeClaims for data
  • Network Policies for security
  • Service Mesh for observability
Worker Deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
  name: celery-worker
spec:
  replicas: 5
  template:
    spec:
      containers:
      - name: worker
        image: python-worker:latest
        command: ["celery", "-A", "tasks", "worker"]
        resources:
          requests:
            cpu: "200m"
            memory: "256Mi"

Hybrid Java-Python Application

Scenario: Java backend + Python ML service

Architecture:

  • Spring Boot REST API (Java)
  • FastAPI ML service (Python)
  • Shared Redis cache
  • Unified monitoring with Prometheus
  • Centralized logging with Loki
Service Communication:
# Java calls Python service
String mlUrl = "http://ml-service/predict";
ResponseEntity response = 
    restTemplate.postForEntity(mlUrl, data, String.class);

# Python service definition
apiVersion: v1
kind: Service
metadata:
  name: ml-service
spec:
  selector:
    app: ml-api
  ports:
  - port: 8000
    targetPort: 8000

Deployment Strategies in Practice

Blue-Green Deployment

Use when: Zero downtime critical

Java/Python: Perfect for both

Implementation: Two identical environments, switch traffic at load balancer

Canary Release

Use when: Testing with real users

Implementation: Gradually route traffic to new version

# Using Istio for traffic splitting
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
spec:
  hosts:
  - myapp.tktips.org
  http:
  - route:
    - destination:
        host: myapp
        subset: v1
      weight: 90
    - destination:
        host: myapp
        subset: v2
      weight: 10

Rolling Update

Use when: Default for most apps

K8s Native: Built into Deployments

Configuration: maxSurge and maxUnavailable

Quick Tips & Best Practices

πŸ’‘ Resource Limits

Always set memory and CPU limits for Java apps. JVM needs to know its limits for garbage collection tuning.

🐍 Python Workers

For Python web apps, set worker count based on available CPU: workers = 2 * CPU cores + 1

πŸ”§ Health Checks

Implement proper liveness and readiness probes. Spring Boot Actuator and FastAPI health endpoints make this easy.

πŸ“¦ Multi-Stage Builds

Use multi-stage Docker builds to keep image sizes small. Critical for fast deployments.

πŸ” Secrets Management

Never store secrets in configmaps. Use Kubernetes Secrets or external secret managers like HashiCorp Vault.

πŸ“Š Monitoring

Java: Use Micrometer with Prometheus. Python: Use Prometheus client library. Both integrate seamlessly with K8s.

πŸ”„ Graceful Shutdown

Handle SIGTERM signals properly. Spring Boot and FastAPI both support graceful shutdown out of the box.

πŸš€ Startup Probes

Use startup probes for apps with long initialization (like Spring Boot with large context).

Common Issues & Solutions

Java: OOM Killed

Problem: Container killed due to memory limit

Solution: Set -Xmx lower than container memory limit (leave room for overhead)

JAVA_OPTS="-Xmx512m" # for 1Gi container limit

Python: High CPU Usage

Problem: Gunicorn workers using too much CPU

Solution: Tune worker count and threads

workers = (2 * cpu_cores) + 1

Both: Slow Startup

Problem: Pods taking too long to start

Solution: Use startup probes and consider readiness gates

Essential kubectl Commands

Most Used Commands for Developers
# Get pods with wide output
kubectl get pods -o wide

# Watch pods in real-time
kubectl get pods --watch

# Describe a specific pod
kubectl describe pod <pod-name>

# Get logs from a pod
kubectl logs <pod-name> -f  # follow logs

# Execute command in pod
kubectl exec -it <pod-name> -- /bin/bash

# Port forward to local machine
kubectl port-forward pod/<pod-name> 8080:8080

# Get all resources in namespace
kubectl get all -n <namespace>

# Check events for troubleshooting
kubectl get events --sort-by=.metadata.creationTimestamp

# Apply configuration
kubectl apply -f deployment.yaml

# Rollback deployment
kubectl rollout undo deployment/<deployment-name>

Ready to Deploy Your Java/Python Apps on Kubernetes?

Start with our step-by-step tutorials and example projects.