tutorial

Uptime monitoring for k3d

k3d runs k3s Kubernetes clusters inside Docker containers, making it the go-to tool for local development and CI pipeline clusters. Because k3d clusters are ...

k3d runs k3s Kubernetes clusters inside Docker containers, making it the go-to tool for local development and CI pipeline clusters. Because k3d clusters are often short-lived, teams rarely bother with monitoring them — and that is exactly when something breaks at the worst time: a CI run that silently fails because the cluster stopped responding, or a staging environment that looks healthy but cannot schedule pods.

This tutorial covers uptime monitoring for k3d clusters using Vigilmon. We will walk through:

  • Exposing the Kubernetes API server for external health checks
  • Monitoring workloads running inside a k3d cluster
  • Port-forwarding based monitoring for local development
  • Webhook alerts for DOWN/UP events

Prerequisites

  • k3d installed and a cluster running (k3d cluster create mycluster)
  • kubectl configured to target the cluster
  • A free account at vigilmon.online

Part 1: Expose the Kubernetes API health endpoint

The Kubernetes API server exposes a /healthz endpoint that returns ok when the control plane is healthy. In k3d, the API server is accessible from the host machine on a mapped port.

Find the API server port

k3d cluster list
# NAME        SERVERS   AGENTS   LOADBALANCER
# mycluster   1/1       2/2      true

kubectl cluster-info
# Kubernetes control plane is running at https://0.0.0.0:6443

The port is configured when you create the cluster. If you used the default settings, the API server maps to a random host port. To use a fixed port:

k3d cluster create mycluster \
  --api-port 6443 \
  --port "8080:80@loadbalancer" \
  --port "8443:443@loadbalancer"

Test the health endpoint

curl -k https://localhost:6443/healthz
# ok

The -k flag skips certificate verification for the self-signed k3d certificate. For monitoring purposes, you will want to either:

  1. Use a Vigilmon monitor configured to skip TLS verification, or
  2. Expose the API through an ingress with a valid certificate.

Part 2: Set up HTTP monitoring in Vigilmon

Monitor the Kubernetes API server

For a k3d cluster exposed on a public IP (staging, preview environment, or CI runner with an inbound rule):

  1. Log in to vigilmon.online and click Add Monitor.
  2. Choose HTTP(S) monitor.
  3. Enter: https://your-server-ip:6443/healthz
  4. Set interval to 1 minute.
  5. Add a keyword check: must contain ok.
  6. Toggle Skip TLS verification if using a self-signed certificate.
  7. Add your alert channel.
  8. Click Save.

Monitor workloads through the k3d load balancer

k3d includes a built-in load balancer (powered by Nginx) that routes traffic from host ports to cluster services. If your application exposes a health check, monitor it directly:

  1. Add another HTTP(S) monitor.
  2. Enter: http://your-server-ip:8080/health
  3. Set interval to 1 minute.
  4. Add a keyword check matching your application's health response.
  5. Click Save.

This catches the most common k3d failure modes: the cluster is running but your application pod crashed, or a misconfigured ingress rule stopped routing traffic.


Part 3: Add a lightweight health endpoint to your cluster

If your application does not expose a /health endpoint, deploy a simple health probe inside the cluster:

# k3d-health-probe.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: health-probe
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: health-probe
  template:
    metadata:
      labels:
        app: health-probe
    spec:
      containers:
        - name: probe
          image: nginx:alpine
          ports:
            - containerPort: 80
          readinessProbe:
            httpGet:
              path: /
              port: 80
            initialDelaySeconds: 5
            periodSeconds: 10
---
apiVersion: v1
kind: Service
metadata:
  name: health-probe
  namespace: default
spec:
  selector:
    app: health-probe
  ports:
    - port: 80
      targetPort: 80
  type: ClusterIP
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: health-probe-ingress
  namespace: default
  annotations:
    kubernetes.io/ingress.class: traefik
spec:
  rules:
    - http:
        paths:
          - path: /probe
            pathType: Prefix
            backend:
              service:
                name: health-probe
                port:
                  number: 80

Apply it:

kubectl apply -f k3d-health-probe.yaml

Then add a Vigilmon monitor for http://your-server-ip:8080/probe.


Part 4: CI pipeline monitoring with port forwarding

For ephemeral k3d clusters in CI pipelines, use a port-forward sidecar to expose the health endpoint during the test run:

# .github/workflows/integration-test.yml
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Install k3d
        run: curl -s https://raw.githubusercontent.com/k3d-io/k3d/main/install.sh | bash

      - name: Create cluster
        run: |
          k3d cluster create testcluster \
            --api-port 6443 \
            --port "8080:80@loadbalancer" \
            --wait

      - name: Wait for cluster ready
        run: |
          kubectl wait --for=condition=ready nodes --all --timeout=60s

      - name: Verify API health
        run: |
          curl -k https://localhost:6443/healthz
          # Returns "ok" if cluster is healthy

      - name: Deploy application
        run: kubectl apply -f k8s/

      - name: Run tests
        run: npm test

      - name: Delete cluster
        if: always()
        run: k3d cluster delete testcluster

For longer-running environments where you want Vigilmon to alert on CI runner failures, deploy a persistent health endpoint using the probe approach from Part 3.


Part 5: Monitor node and cluster status

k3d clusters can lose nodes when Docker containers are stopped or when the host runs out of memory. Add a node-health endpoint:

# Create a simple node checker as a CronJob
cat <<EOF | kubectl apply -f -
apiVersion: batch/v1
kind: CronJob
metadata:
  name: node-health-reporter
spec:
  schedule: "*/1 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          serviceAccountName: default
          containers:
            - name: reporter
              image: bitnami/kubectl:latest
              command:
                - sh
                - -c
                - |
                  READY=$(kubectl get nodes --no-headers | grep -c ' Ready')
                  TOTAL=$(kubectl get nodes --no-headers | wc -l)
                  echo "Nodes ready: $READY/$TOTAL"
                  if [ "$READY" != "$TOTAL" ]; then exit 1; fi
          restartPolicy: Never
EOF

Part 6: Webhook alerts

Configure Vigilmon to deliver alerts to your team when a k3d environment goes down:

// webhook-receiver.ts
import express from 'express';

const app = express();
app.use(express.json());

app.post('/webhook/vigilmon', (req, res) => {
  const { monitor_name, status, url, checked_at, response_code } = req.body;

  if (status === 'down') {
    console.error('[K3D] Cluster monitor DOWN', {
      monitor: monitor_name,
      url,
      code: response_code,
      at: checked_at,
    });

    // Notify dev team — someone's local-dev or CI cluster is down
    notifySlack({
      channel: '#dev-infra',
      text: `k3d cluster down: ${monitor_name} (${url})`,
    });
  } else if (status === 'up') {
    console.info('[K3D] Cluster monitor recovered', { monitor: monitor_name });
  }

  res.sendStatus(204);
});

app.listen(3001);

Vigilmon sends this payload on state transitions:

{
  "monitor_id": "mon_abc123",
  "monitor_name": "k3d Staging API",
  "status": "down",
  "url": "https://staging.example.com:6443/healthz",
  "checked_at": "2026-06-30T08:01:00Z",
  "response_code": 0,
  "response_time_ms": 5000
}

A response_code of 0 indicates a connection timeout — the API server is unreachable, not returning an error. This is the most common k3d failure mode when Docker runs out of memory.


Part 7: Multiple environments

If you run multiple k3d environments (dev, staging, feature branches), add a monitor per environment:

| Environment | Monitor URL | Name | |-------------|-------------|------| | Dev | https://dev.example.com:6443/healthz | k3d Dev Cluster | | Staging | https://staging.example.com:6443/healthz | k3d Staging Cluster | | Feature | http://feature.example.com:8080/health | k3d Feature App |

Tag them with k3d in Vigilmon for a consolidated cluster health dashboard.


Summary

Your k3d clusters now have three layers of monitoring:

  1. API server /healthz — polled every 60 seconds, confirms the Kubernetes control plane is healthy.
  2. Application health endpoint — a separate monitor through the k3d load balancer catches pod-level failures independent of the control plane.
  3. Webhook alerts — DOWN events reach your dev team channel within 60 seconds so nobody wastes time debugging a cluster that is silently offline.

Vigilmon handles check scheduling, multi-region polling, alert routing, and uptime history.


Monitor your k3d clusters free at vigilmon.online

#k3d #kubernetes #devops #monitoring #docker

Monitor your app with Vigilmon

Free plan — 5 monitors, no credit card required. Up and running in 60 seconds.

Start free →