Beispielarbeiten · Software & Web-Apps
Cloud und DevOps: Helm-Chart, Rolling Update, Terraform und CI-Pipeline
Eine kleine App mit Docker-Image, Helm-Chart und CI-Datei, ausgerollt auf einem lokalen Kubernetes-Cluster. Das Update lief unter Last ohne Fehler, der Rollback ebenfalls. Dazu ein Terraform-Modul, geprüft gegen einen AWS-Nachbau.
Musterarbeit (Demo), kein Kundenauftrag. Gebaut als Probeaufgabe mit erfundenen Beispieldaten; die Prüfzahlen unten stammen aus dem automatischen Prüflauf und sind nicht geschönt.
Was gebaut wurde
- Helm-Chart mit Deployment, Service, ConfigMap und Autoscaler, Proben und Grenzen gesetzt
- Rolling Update und Rollback unter Last, gemessen an den Antworten während des Updates
- Terraform: Formatierung, Validierung, Plan und Anwendung mit Gegenlesen, danach ohne Abweichung
- Gegenproben: falscher Port, fehlende Readiness-Probe und ein zu offenes Terraform-Modul werden erkannt
devops-dateien.zip herunterladen
Alles lief lokal: ein Cluster mit einem Knoten, kein Produktivbetrieb. Kein echtes AWS-, Azure- oder GCP-Konto, Terraform nur gegen einen Nachbau; Kosten, Limits und echte Rechte sagt das nicht. Autoscaling nicht gemessen. Ohne Ingress, TLS, Secrets-Verwaltung, GitOps und Monitoring. Die CI-Datei ist mit actionlint geprüft, aber nicht auf GitHub gelaufen.
Wie geprüft wurde
Automatischer Prüflauf vom 01.11.2026, aus dem Protokoll (Testdaten erfunden, Zahlen gemessen):
- 18/18 erfuellt: CI-Schritt Unit-Tests laeuft gruen (4 Tests)
- actionlint: CI-Datei (test->build->deploy) ohne Meldung
- Gegenprobe CI: unbekannter Job 'bild' und Kontext 'sha_kurz' erkannt
- Docker-Images 1.0.0 und 2.0.0 gebaut (nicht-root, Version per Build-Arg)
Grenzen
Was diese Probe nicht abdeckt, steht hier, damit niemand mehr erwartet:
- Alles lokal: ein kind-Cluster mit einem Knoten (Docker Desktop, 4 GB RAM) - kein Mehrknoten-Betrieb, keine echte Hochverfuegbarkeit, kein Produktivbetrieb, keine Lastspitzen; Rolling Update mit 2 …
- keine echten AWS-/Azure-/GCP-Konten: AWS nur gegen den Nachbau moto (S3, IAM) - Terraform-Plan/Apply dort sagt nichts ueber Kontolimits, Service-Control-Policies, Kosten, Regionen oder echte …
- HPA nur als Manifest ausgerollt und vom API-Server angenommen; Autoscaling nicht gemessen (kein metrics-server installiert)
- kein Ingress/TLS/cert-manager, kein Service Mesh, kein Secrets-Management (Vault, Sealed Secrets, External Secrets), kein GitOps (Argo CD/Flux), kein Prometheus/Grafana/Logging-Stack
- CI-Datei nur statisch mit actionlint geprueft - nicht auf GitHub ausgefuehrt (kein Repository/Runner des Kunden); Container-Registry (ECR/GHCR/Docker Hub) und Zugangsdaten des Kunden nicht verwendet
- hadolint und tflint nicht installiert (hadolint veroeffentlicht keine Pruefsumme); Terraform-Provider wird beim ersten Lauf von registry.terraform.io geladen (kostenlos, ohne Konto) …
- Plan-Pruefung auf offene Policies ist eine eigene Regel (Platzhalter in Action/Resource, fehlender Public-Access-Block), kein Ersatz fuer tfsec/Checkov/OPA
Die CI-Pipeline
name: ci
on:
push:
branches: [main]
pull_request:
permissions:
contents: read
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Unit-Tests
working-directory: app
run: python -m unittest -v
build:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Image bauen
run: docker build --build-arg VERSION=${{ github.sha }} -t probeapp:${{ github.sha }} app
- name: Chart pruefen
run: |
curl -fsSL https://get.helm.sh/helm-v3.16.0-linux-amd64.tar.gz | tar xz
./linux-amd64/helm lint chart
deploy:
needs: build
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
environment: production
concurrency: deploy-production
steps:
- uses: actions/checkout@v4
- name: Ausrollen
env:
KUBECONFIG_DATA: ${{ secrets.KUBECONFIG_DATA }}
run: |
echo "$KUBECONFIG_DATA" | base64 -d > "$RUNNER_TEMP/kubeconfig"
helm upgrade --install probeapp chart --kubeconfig "$RUNNER_TEMP/kubeconfig" --set image.tag=${{ github.sha }} --atomic --timeout 5m
Das Terraform-Modul
terraform {
required_version = ">= 1.5"
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 5.0"
}
}
}
variable "endpoint" {
description = "Nur fuer die lokale Probe (moto); gegen echtes AWS leer lassen"
type = string
default = ""
}
variable "bucket_name" {
type = string
default = "gltools-probe-daten"
}
provider "aws" {
region = "eu-central-1"
access_key = var.endpoint == "" ? null : "test"
secret_key = var.endpoint == "" ? null : "test"
skip_credentials_validation = var.endpoint != ""
skip_requesting_account_id = var.endpoint != ""
skip_metadata_api_check = var.endpoint != ""
s3_use_path_style = var.endpoint != ""
dynamic "endpoints" {
for_each = var.endpoint == "" ? [] : [var.endpoint]
content {
s3 = endpoints.value
iam = endpoints.value
sts = endpoints.value
}
}
}
resource "aws_s3_bucket" "daten" {
bucket = var.bucket_name
}
resource "aws_s3_bucket_versioning" "daten" {
bucket = aws_s3_bucket.daten.id
versioning_configuration {
status = "Enabled"
}
}
resource "aws_s3_bucket_server_side_encryption_configuration" "daten" {
bucket = aws_s3_bucket.daten.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
}
}
}
resource "aws_s3_bucket_public_access_block" "daten" {
bucket = aws_s3_bucket.daten.id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
# Least Privilege: nur lesen/schreiben/auflisten in genau diesem Bucket
data "aws_iam_policy_document" "app" {
statement {
sid = "ObjekteLesenSchreiben"
actions = ["s3:GetObject", "s3:PutObject"]
resources = ["${aws_s3_bucket.daten.arn}/*"]
}
statement {
sid = "BucketAuflisten"
actions = ["s3:ListBucket"]
resources = [aws_s3_bucket.daten.arn]
}
}
resource "aws_iam_policy" "app" {
name = "gltools-probe-app"
policy = data.aws_iam_policy_document.app.json
}
output "bucket" {
value = aws_s3_bucket.daten.id
}
output "policy_arn" {
value = aws_iam_policy.app.arn
}
So etwas für deinen Betrieb?
Beschreib kurz, was du brauchst. Du bekommst einen Festpreis, bevor ich anfange; ohne dein Ja passiert nichts.