Published on

Deploying a Spring Boot Airline Application to AKS with ArgoCD

Authors

The Application

Let's start with a simple Spring Boot application for airline operations. Our sample application will handle basic flight information:

@RestController
@RequestMapping("/api/flights")
public class FlightController {
    
    @GetMapping
    public List<Flight> getFlights() {
        // Return flight list
    }
    
    @PostMapping
    public Flight createFlight(@RequestBody Flight flight) {
        // Create new flight
    }
}

@Entity
public class Flight {
    @Id
    private String flightNumber;
    private String origin;
    private String destination;
    private LocalDateTime departureTime;
    private LocalDateTime arrivalTime;
    // getters, setters
}

Project Structure

Our GitOps repository structure:

airline-gitops/
├── base/
│   ├── deployment.yaml
│   ├── service.yaml
│   ├── configmap.yaml
│   ├── secret.yaml
│   └── kustomization.yaml
└── overlays/
    ├── dev/
    │   └── kustomization.yaml
    └── prod/
        └── kustomization.yaml

Kubernetes Manifests

Base Deployment (deployment.yaml)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: airline-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: airline-app
  template:
    metadata:
      labels:
        app: airline-app
    spec:
      containers:
      - name: airline-app
        image: acr.azurecr.io/airline-app:latest
        ports:
        - containerPort: 8080
        resources:
          requests:
            memory: "512Mi"
            cpu: "500m"
          limits:
            memory: "1Gi"
            cpu: "1"
        env:
        - name: SPRING_PROFILES_ACTIVE
          valueFrom:
            configMapKeyRef:
              name: airline-config
              key: spring.profiles.active
        - name: DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: airline-secrets
              key: db-password

Service (service.yaml)

apiVersion: v1
kind: Service
metadata:
  name: airline-app
spec:
  type: ClusterIP
  ports:
  - port: 80
    targetPort: 8080
  selector:
    app: airline-app

ConfigMap (configmap.yaml)

apiVersion: v1
kind: ConfigMap
metadata:
  name: airline-config
data:
  spring.profiles.active: "prod"
  application.properties: |
    server.port=8080
    management.endpoints.web.exposure.include=health,metrics

ArgoCD Application Configuration (airline-app.yaml):

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: airline-app
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/your-org/airline-gitops.git
    targetRevision: HEAD
    path: overlays/prod
  destination:
    server: https://kubernetes.default.svc
    namespace: airline-prod
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
    - CreateNamespace=true

Container Image Build Pipeline (azure-pipelines.yml):

trigger:
  - main

variables:
  imageRepository: 'airline-app'
  containerRegistry: 'your-acr.azurecr.io'
  dockerfilePath: 'Dockerfile'
  tag: '$(Build.BuildId)'

stages:
- stage: Build
  jobs:
  - job: Build
    pool:
      vmImage: 'ubuntu-latest'
    steps:
    - task: Docker@2
      inputs:
        containerRegistry: 'ACR'
        repository: $(imageRepository)
        command: 'buildAndPush'
        Dockerfile: $(dockerfilePath)
        tags: |
          $(tag)
          latest

Pod Disruption Budget

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: airline-app-pdb
spec:
  minAvailable: 1
  selector:
    matchLabels:
      app: airline-app

Horizontal Pod Autoscaler

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: airline-app-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: airline-app
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 80