Terraform Without Tears: How I Turned an LLM Into a DevOps Teammate That Writes Dockerfiles, K8s Manifests and CI/CD Pipelines

Terraform Without Tears: How I Turned an LLM Into a DevOps Teammate That Writes Dockerfiles, K8s Manifests and CI/CD Pipelines

Infrastructure work is 20% architecture and 80% remembering the exact syntax of volumeMounts vs volumeDevices, whether it's depends_on or dependsOn, and why the pod is in CrashLoopBackOff again. An LLM won't replace your judgment, but it absolutely kills the syntax archaeology. Below is a working collection of DevOps prompts — Docker, Kubernetes, CI/CD, Terraform — each with a real example and the routine it removes. Treat every output as a draft: validate with docker build, kubectl apply --dry-run=server, terraform validate and tflint before it touches prod.

1. Hardened multi-stage Dockerfile from a project tree

Drops the guesswork of picking a base image, ordering layers, and creating a non-root user.

Prompt:

You are a senior DevOps engineer. Given this project tree and package.json,
write a multi-stage Dockerfile for Node 20: builder stage with dev deps,
runtime stage on node:20-alpine, non-root user `app` (uid 10001),
HEALTHCHECK hitting /health, and explicit ENV NODE_ENV=production.
Explain each layer and why it's ordered that way.

Example output excerpt:

FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:20-alpine AS runtime
RUN addgroup -g 10001 app && adduser -u 10001 -G app -D app
WORKDIR /app
COPY --from=builder --chown=app:app /app/dist ./dist
COPY --from=builder --chown=app:app /app/node_modules ./node_modules
USER app
HEALTHCHECK CMD wget -qO- http://localhost:3000/health || exit 1
CMD ["node", "dist/main.js"]

Removes: 20 minutes of hunting for the right adduser flags on Alpine.

2. Image diet audit

Prompt:

Here is my Dockerfile and `docker history` output. Identify the 3 biggest
size contributors, propose concrete replacements (distroless, alpine,
multi-stage, .dockerignore entries), and estimate savings per layer.

Pairs with docker history --no-trunc myimage:latest. Removes: blind docker-slim experiments.

3. Kubernetes Deployment + Service + HPA bundle

Prompt:

Generate a Kubernetes 1.30 manifest set for a stateless API:
Deployment (3 replicas, requests cpu 100m/mem 128Mi, limits cpu 500m/mem 512Mi),
Service ClusterIP, HPA on cpu 70%. Use apps/v1 and autoscaling/v2.
Add readinessProbe on /ready and livenessProbe on /live.

Always run kubectl apply --dry-run=server -f app.yaml. Removes: copy-pasting from old repos with deprecated extensions/v1beta1.

4. CrashLoopBackOff triage

Prompt:

Pod is in CrashLoopBackOff. Here are `kubectl describe pod` and `kubectl logs --previous`.
Rank the 5 most likely causes, map each to a diagnostic command,
and tell me the fastest one to run first.

Removes: 40 minutes of scrolling Stack Overflow at 2 a.m.

5. Terraform module skeleton

Prompt:

Write a reusable Terraform module for an S3 bucket with versioning,
server-side encryption (AES256), and public access block.
Files: main.tf, variables.tf, outputs.tf, versions.tf pinning aws >= 5.0.
Add a README with a usage example.

Validate with terraform init && terraform validate && tflint. Removes: boilerplate from scratch each time.

6. Terraform plan review

Prompt:

Here is `terraform plan` output. Flag every destructive change (destroy/replace),
explain why the resource is being replaced, and propose a safer alternative
(create_before_destroy, lifecycle ignore_changes) where appropriate.

Removes: the classic "why is my RDS instance being recreated?" heart attack.

7. GitHub Actions pipeline with cache and matrix

Prompt:

Write a GitHub Actions workflow for a Node app: lint, test, build Docker image,
push to GHCR on main only. Use actions/checkout@v4, setup-node@v4 with
npm cache, docker/build-push-action@v6 with buildx cache (type=gha).
Add a matrix over Node 20 and 22.

Removes: reinventing cache keys for the tenth time.

8. Pipeline failure decoder

Prompt:

CI failed. Here are the logs (last 100 lines) and the workflow YAML.
Identify the failing step, root cause, and give me a minimal diff to fix it.

Removes: log spelunking when the error is buried under 300 lines of npm noise.

9. Secrets hygiene check

Prompt:

Review this workflow and Dockerfile for secret leakage: hardcoded tokens,
secrets echoed in logs, secrets passed as build ARGs (visible in image history).
Propose the fix using GitHub OIDC or env vars at runtime.

Removes: the post-incident scramble after a token lands in a public image layer.

10. Helm values diff

Prompt:

Compare these two values.yaml files for the same chart. List every changed key,
the resulting Kubernetes object it affects, and whether the change is rolling-safe.

Removes: eyeballing 400-line YAML diffs before a release.

11. Compose for local dev parity

Prompt:

Write docker-compose.yml matching our prod stack: app, postgres:16, redis:7,
with healthchecks and depends_on conditions so app waits for db readiness.
Use named volumes and .env for secrets.

Removes: "works on my machine" drift.

12. Terraform state and drift explainer

Prompt:

Explain this `terraform plan` drift output in plain English for a junior dev.
What changed outside Terraform, and what's the safest remediation path?

Removes: the weekly "someone clicked in the AWS console" meeting.

Takeaways

An LLM is a syntax accelerator, not an approver. The pattern that works: paste real context (logs, plans, trees), ask for a diff plus rationale, then gate everything through the real validators — docker build, kubectl --dry-run=server, terraform validate, tflint, actionlint. That keeps the 80% of mechanical work off your plate while you keep the 20% that actually needs a human brain. Start with prompt #4 next time a pod dies — you'll feel the difference immediately.

← All posts

Comments