# Kubernetes Workloads

> Read [`../../references/kubernetes.md`](../../references/kubernetes.md) before changing a workload. It supplies the kubectl-only boundary, identity contract, naming defaults, and mutation loop.

- Skill: `zeabur/kubernetes-workloads` (Agent Skill)
- Install (CLI): `npx skillmds@latest add zeabur/kubernetes-workloads`
- Raw SKILL.md: https://api.skillmd.com/api/skills/zeabur/kubernetes-workloads/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- Author: zeabur (https://skillmd.com/u/zeabur)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/zeabur/kubernetes-workloads

---


Read [`../../references/kubernetes.md`](../../references/kubernetes.md) before changing a workload. It supplies the kubectl-only boundary, identity contract, naming defaults, and mutation loop.

## Inputs and inventory

Require the target cluster context, environment ID, service ID, and requested outcome. Also require the container name for a multi-container pod. For a new workload, require image, port, and the project/user IDs to inject. For a command replacement, distinguish an argv from a shell command.

Inventory the candidate first:

```sh
kubectl -n "$NS" get deploy,sts -l "zeabur_service_id=$ZEABUR_SERVICE_ID"
kubectl -n "$NS" get pods -l "zeabur_service_id=$ZEABUR_SERVICE_ID" \
  -o custom-columns=NAME:.metadata.name,READY:.status.containerStatuses[*].ready,IMAGE:.spec.containers[*].image
```

Select exactly one controller. Preserve its existing selector and Service relationship. A new standalone workload uses a stable selector containing only `app.kubernetes.io/name: service-<service-id>`; put the Zeabur identity labels on both the Deployment and pod template.

Complete this step only when the controller, container, and current rollout revision are known.

## Deployments, image, command, and variables

For an existing Deployment, make narrow imperative changes:

```sh
kubectl -n "$NS" set image deployment/$WORKLOAD "$CONTAINER=$IMAGE"
kubectl -n "$NS" set env deployment/$WORKLOAD \
  ZEABUR=1 \
  ZEABUR_PROJECT_ID="$ZEABUR_PROJECT_ID" \
  ZEABUR_SERVICE_ID="$ZEABUR_SERVICE_ID" \
  ZEABUR_ENVIRONMENT_ID="$ZEABUR_ENVIRONMENT_ID" \
  ZEABUR_USER_ID="$ZEABUR_USER_ID" \
  ZEABUR_REGION="$ZEABUR_REGION"
```

Add user environment values with `kubectl set env`; source secret values from a Secret through a small server-side-apply fragment rather than placing a secret literal on the command line. Reconcile a removed environment variable explicitly with `kubectl set env deployment/$WORKLOAD KEY-`.

Replace a command with a minimal fragment that names the existing container. Use `command` and `args` as argv. Wrap an intentional shell program as `command: ["/bin/sh", "-c"]` and one `args` element; do not split it on whitespace.

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: <workload>
  namespace: environment-<environment-id>
spec:
  template:
    spec:
      containers:
        - name: <container>
          command: ["/bin/sh", "-c"]
          args: ["exec ./start-server --port $PORT"]
```

Apply the fragment through the shared field manager. A `command` or `args` update produces a new ReplicaSet; wait for that rollout before reporting success.

## Resources and replicas

Use Kubernetes quantities, not decimal approximations: CPU `250m`, memory `512Mi`, ephemeral storage `1Gi`. Requests reserve scheduling capacity; limits cap execution. Keep each requested resource in the same update so the scheduler sees a coherent pod shape.

```sh
kubectl -n "$NS" set resources deployment/$WORKLOAD --containers="$CONTAINER" \
  --requests=cpu=250m,memory=256Mi,ephemeral-storage=512Mi \
  --limits=cpu=500m,memory=512Mi,ephemeral-storage=1Gi
kubectl -n "$NS" scale deployment/$WORKLOAD --replicas=3
```

Before increasing replicas, inspect every mounted PVC. A `ReadWriteOnce` claim can make multi-replica scheduling fail unless the storage driver supports the chosen topology. State this conflict instead of claiming a successful scale from the desired replica count alone.

## Health checks

Match the backend's baseline health semantics: use a startup probe to tolerate initialization and a readiness probe to gate traffic. It uses the same HTTP or TCP handler for both:

```yaml
startupProbe:
  httpGet: {path: /healthz, port: 8080}
  failureThreshold: 36
  periodSeconds: 5
  successThreshold: 1
readinessProbe:
  httpGet: {path: /healthz, port: 8080}
  failureThreshold: 3
  periodSeconds: 10
  successThreshold: 1
```

For TCP, replace `httpGet` with `tcpSocket: {port: 8080}`. Add a liveness probe only when the requested behavior is to restart a process that becomes unhealthy after startup; startup and readiness alone prevent premature routing without adding a restart loop. Verify the probe path and port from the container, then verify Ready endpoints after rollout.

## Scheduled restart

A scheduled restart is a Kubernetes CronJob that patches the target Deployment; it must not call a Zeabur HTTP endpoint. First create a namespaced ServiceAccount, Role, and RoleBinding granting `get`, `list`, and `patch` only on `deployments` in `$NS`. Use a cluster-approved image containing a `kubectl` version compatible with the API server.

The CronJob has these safe lifecycle settings:

```yaml
spec:
  schedule: "0 3 * * *"
  timeZone: "Etc/UTC"
  concurrencyPolicy: Forbid
  successfulJobsHistoryLimit: 1
  failedJobsHistoryLimit: 1
  jobTemplate:
    spec:
      backoffLimit: 0
      ttlSecondsAfterFinished: 300
      activeDeadlineSeconds: 1800
      template:
        spec:
          serviceAccountName: restart-<service-id>
          restartPolicy: Never
          containers:
            - name: restart
              image: <approved-kubectl-image>
              command: ["kubectl"]
              args: ["-n", "environment-<environment-id>", "rollout", "restart", "deployment/<workload>"]
```

Apply its RBAC and CronJob together. Verify the schedule, service account, and `kubectl auth can-i patch deployments --as=system:serviceaccount:$NS:<service-account> -n "$NS"`. Removing the CronJob disables automatic restarts; it does not restart the service.

## Completion

After every workload mutation:

```sh
kubectl -n "$NS" rollout status deployment/$WORKLOAD --timeout=5m
kubectl -n "$NS" get deployment/$WORKLOAD
kubectl -n "$NS" get pods -l "zeabur_service_id=$ZEABUR_SERVICE_ID"
kubectl -n "$NS" get endpointslice -l "kubernetes.io/service-name=$SERVICE_NAME"
```

Report the controller, new revision, desired/available replicas, image digest or image reference, changed probe/resource/command fields, and any unsatisfied prerequisite. The operation is complete only when the requested state is present and every expected replica is Available and Ready.

