Skip to content

Repository files navigation

Docker and Kubernetes Deployment Tutorial

This repository teaches Kubernetes deployment in three steps:

  1. Deploy one Docker image as a simple web application.
  2. Deploy a multi-image application stack: n8n plus PostgreSQL.
  3. Use one AI agent skill to apply the same workflow to any application repository.

The deployment path

flowchart LR
    A[Application source] --> B[Dockerfile]
    B --> C[Docker image]
    C --> D[Registry or local cluster]
    D --> E[Kubernetes Deployment]
    E --> F[Pod]
    F --> G[Service]
    G --> H[User]
Loading

Prerequisites

Install Docker, kubectl, and a Kubernetes cluster. Minikube is a simple local choice:

minikube start
kubectl cluster-info
kubectl get nodes

Part 1: Deploy one application image

The demo application is a static NGINX site in app/. It listens on port 8080; Kubernetes checks / for readiness and liveness.

File Purpose
Dockerfile Packages the site into a non-root NGINX container.
app/ The application HTML.
k8s/namespace.yaml Creates the isolated kubernetes-demo namespace.
k8s/deployment.yaml Runs two replicas, probes /, and defines resources.
k8s/service.yaml Exposes matching Pods internally on port 80.

Build and run with Docker

docker build -t kubernetes-demo:1.0.0 .
docker run --rm -p 8080:8080 kubernetes-demo:1.0.0

In another terminal:

curl --fail http://localhost:8080/

The container image must be accessible to the cluster. For Minikube, load the local image:

minikube image load kubernetes-demo:1.0.0

For a remote cluster, push a pinned tag to your registry:

docker tag kubernetes-demo:1.0.0 YOUR_REGISTRY_USERNAME/YOUR_IMAGE_NAME:1.0.0
docker push YOUR_REGISTRY_USERNAME/YOUR_IMAGE_NAME:1.0.0

Deploy and access it

Validate first, then apply only the demo manifests and wait for the rollout:

kubectl apply --dry-run=client -f k8s/
kubectl apply -f k8s/
kubectl -n kubernetes-demo rollout status deployment/kubernetes-demo
kubectl -n kubernetes-demo get deployments,pods,services
kubectl -n kubernetes-demo port-forward service/kubernetes-demo 8080:80

Open http://localhost:8080. The ClusterIP Service is internal by design; port forwarding is the most reliable local access method. In cloud Kubernetes, use a LoadBalancer Service or Ingress when public access is required.

Observe Kubernetes features

kubectl -n kubernetes-demo scale deployment/kubernetes-demo --replicas=3
kubectl -n kubernetes-demo get pods
kubectl -n kubernetes-demo delete pod POD_NAME
kubectl -n kubernetes-demo get pods --watch
kubectl -n kubernetes-demo set image deployment/kubernetes-demo \
  kubernetes-demo=YOUR_REGISTRY_USERNAME/YOUR_IMAGE_NAME:1.0.1
kubectl -n kubernetes-demo rollout status deployment/kubernetes-demo
kubectl -n kubernetes-demo rollout undo deployment/kubernetes-demo

Scaling changes the desired number of Pods. Deleting a Pod demonstrates self-healing: the Deployment creates a replacement. A pinned image update creates a rolling update; rollout undo reverts it.

Part 2: Deploy a multi-image n8n application

n8n.yaml is a real multi-workload example. It contains these images:

Image Kubernetes workload Purpose
n8nio/n8n:2.35.0 Deployment n8n editor, workflows, webhooks, and API.
postgres:16-alpine StatefulSet Persistent database for n8n.
postgres:16-alpine n8n init container Waits for PostgreSQL before n8n starts.

This is not a multi-container Pod: n8n and PostgreSQL run in separate Pods because they have independent lifecycles and storage. The Services give each workload stable DNS:

flowchart LR
    U[Browser or webhook] --> I[Traefik Ingress]
    I --> S[n8n Service]
    S --> N[n8n Pod]
    N --> P[PostgreSQL Service]
    P --> DB[PostgreSQL StatefulSet and PVC]
    C[cert-manager] --> T[n8n TLS Secret]
    T --> I
Loading

Required cluster prerequisites

The n8n example is intentionally closer to production and requires pre-existing cluster services:

kubectl get ingressclass traefik
kubectl get clusterissuer letsencrypt-prod
kubectl get storageclass longhorn

It also requires a DNS record for n8n.nstsdc.org to reach Traefik and a n8n-secrets Secret containing postgres-password and a persistent encryption-key. Do not commit Secret values. Create them locally and apply them directly:

kubectl apply -f namespace.yaml
kubectl -n n8n create secret generic n8n-secrets \
  --from-literal=postgres-password='CHOOSE_A_STRONG_PASSWORD' \
  --from-literal=encryption-key="$(openssl rand -hex 32)" \
  --dry-run=client -o yaml | kubectl apply -f -

Keep the original encryption key securely backed up. Changing it prevents n8n from decrypting existing credentials.

Deploy and verify n8n

kubectl apply --dry-run=client -f namespace.yaml
kubectl apply --dry-run=client -f n8n.yaml
kubectl apply -f namespace.yaml
kubectl apply -f n8n.yaml
kubectl -n n8n rollout status statefulset/postgres --timeout=10m
kubectl -n n8n rollout status deployment/n8n --timeout=10m
kubectl -n n8n wait --for=condition=Ready certificate/n8n-tls --timeout=10m
kubectl -n n8n get pods,svc,pvc,ingress,certificate
curl --fail --location https://n8n.nstsdc.org/healthz

The n8n manifest shows additional Kubernetes concerns that a single app does not need: StatefulSets, PVCs, an init container, Secrets, TLS, and Ingress.

Part 3: Deploy any application with an AI agent

The single reusable skill is .github/skills/kubernetes-deployment/SKILL.md. It follows:

flowchart LR
    U[User request] --> A[AI deployment skill]
    A --> B[Inspect repository]
    B --> C{Image supplied?}
    C -- No --> D[Dockerize and build]
    C -- Yes --> E[Use existing image]
    D --> F[Generate or validate YAML]
    E --> F
    F --> G[Dry run and deploy]
    G --> H[Verify rollout and endpoint]
    H --> I{Healthy?}
    I -- No --> J[Inspect logs and events]
    J --> G
    I -- Yes --> K[Report status]
Loading

Use it with a bounded prompt:

Use the kubernetes-deployment skill. Inspect this repository, Dockerize it if necessary, and deploy it to my current Kubernetes cluster. Use the kubernetes-demo namespace, validate manifests first, wait for rollout, and verify the health endpoint. Do not modify other namespaces.

If an image already exists, the agent should skip Docker build work:

Use the kubernetes-deployment skill. Deploy image YOUR_REGISTRY_USERNAME/YOUR_IMAGE_NAME:1.0.0 to my current Kubernetes cluster. Use the kubernetes-demo namespace and verify the service endpoint.

The skill detects the runtime, port, commands, environment variables, Docker configuration, image accessibility, and existing Kubernetes assets. It validates YAML before applying, checks rollout health, and inspects events and logs before changing failed resources.

Never give an agent kubeconfig contents, passwords, tokens, private keys, registry credentials, or Kubernetes Secret values. Confirm the context, namespace, image, and every state-changing command.

Troubleshooting

kubectl config current-context
kubectl -n kubernetes-demo get pods,svc
kubectl -n kubernetes-demo describe pod POD_NAME
kubectl -n kubernetes-demo logs POD_NAME
kubectl -n kubernetes-demo logs POD_NAME --previous
kubectl -n kubernetes-demo get events --sort-by=.metadata.creationTimestamp
Symptom What to inspect
ImagePullBackOff or ErrImagePull Image name, pinned tag, registry access, or Minikube image loading.
CrashLoopBackOff Container logs, production command, required environment variables, and bind address.
Pending Pod events, resource requests, storage, and node capacity.
Service is unreachable Service selector, Pod labels, targetPort, container port, and endpoint readiness.
n8n certificate not ready DNS, Traefik, letsencrypt-prod, and cert-manager events.

Cleanup

kubectl delete -f k8s/namespace.yaml

This removes only the kubernetes-demo namespace. Do not delete the n8n namespace or its PVCs unless you explicitly intend to remove the n8n deployment and persistent data.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages