5.2 KiB
| name | description | author | version | date |
|---|---|---|---|---|
| drone-k8s-auto-deploy | Set up Drone CI pipelines that build Docker images and auto-deploy to Kubernetes. Use when: (1) setting up CI/CD for a project running on a k8s cluster with Drone, (2) need to trigger a k8s deployment update from a Drone pipeline step, (3) want to avoid manual kubectl rollout restart after image push. Covers pipeline type selection, k8s API patching via service account token, and build-number tagging. | Claude Code | 1.0.0 | 2026-02-06 |
Drone CI Kubernetes Auto-Deploy
Problem
After pushing a new Docker image from Drone CI, the Kubernetes deployment still runs
the old image. Manual kubectl rollout restart is needed, breaking the automated
pipeline.
Context / Trigger Conditions
- Drone CI is running on a Kubernetes cluster (not as a standalone Docker host)
- The deployment uses a specific image tag (not
:latestwithimagePullPolicy: Always) - You want push-to-main to automatically build, push, and deploy
- The Drone service account has RBAC permissions to patch deployments (e.g. cluster-admin)
Solution
1. Use type: kubernetes pipeline
When Drone runs on k8s, pipeline steps execute as pods with access to the cluster API via mounted service account tokens.
kind: pipeline
type: kubernetes # NOT 'docker'
name: my-app
2. Tag images with build number
Use ${DRONE_BUILD_NUMBER} for unique, incrementing tags. Push both :latest and
the build number for flexibility.
- name: docker
image: plugins/docker
settings:
repo: myregistry/myapp
tags:
- latest
- "${DRONE_BUILD_NUMBER}"
username:
from_secret: docker_username
password:
from_secret: docker_password
3. Patch the deployment via k8s API
Use curl to PATCH the deployment's container image to the new tag. The service
account token is auto-mounted at /var/run/secrets/kubernetes.io/serviceaccount/token.
- name: deploy
image: alpine
commands:
- apk add --no-cache curl
- |
curl -sfk -X PATCH \
"https://<K8S_API_HOST>:6443/apis/apps/v1/namespaces/<NAMESPACE>/deployments/<DEPLOYMENT>" \
-H "Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" \
-H "Content-Type: application/strategic-merge-patch+json" \
-d '{"spec":{"template":{"spec":{"containers":[{"name":"<CONTAINER_NAME>","image":"myregistry/myapp:'"${DRONE_BUILD_NUMBER}"'"}]}}}}'
This is the API equivalent of kubectl set image deployment/<name> <container>=<image>:<tag>.
4. Required Drone secrets
Configure these in the Drone UI for the repository:
docker_username— Docker Hub usernamedocker_password— Docker Hub access token (PAT works)
No kubectl credentials needed — the pipeline uses the Drone pod's service account.
Verification
# Check Drone build passed
# In the Drone UI, verify all 3 steps (build, docker, deploy) are green
# Verify deployment updated
kubectl -n <namespace> get deployment <name> -o jsonpath='{.spec.template.spec.containers[0].image}'
# Should show: myregistry/myapp:<build-number>
# Verify pod is running new image
kubectl -n <namespace> get pods -o jsonpath='{.items[*].status.containerStatuses[*].image}'
Example
Full .drone.yml for a Node.js app deployed to k8s:
kind: pipeline
type: kubernetes
name: my-app
concurrency:
limit: 1
trigger:
branch:
- main
event:
- push
steps:
- name: build
image: node:18-alpine
commands:
- npm ci
- npm run build
- name: docker
image: plugins/docker
settings:
repo: myuser/myapp
tags:
- latest
- "${DRONE_BUILD_NUMBER}"
username:
from_secret: docker_username
password:
from_secret: docker_password
- name: deploy
image: alpine
commands:
- apk add --no-cache curl
- |
curl -sfk -X PATCH \
"https://10.0.20.100:6443/apis/apps/v1/namespaces/myapp/deployments/myapp" \
-H "Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" \
-H "Content-Type: application/strategic-merge-patch+json" \
-d '{"spec":{"template":{"spec":{"containers":[{"name":"myapp","image":"myuser/myapp:'"${DRONE_BUILD_NUMBER}"'"}]}}}}'
Notes
- The k8s API host (
10.0.20.100:6443) is cluster-specific — find it withkubectl cluster-info - The
-kflag on curl skips TLS verification for the k8s API (common for internal clusters with self-signed certs) - The
-sfflags make curl fail silently on HTTP errors and return non-zero exit code, which fails the pipeline step - The container
namein the PATCH must match the container name in the deployment spec - RBAC: The Drone service account needs permissions to PATCH deployments in the target namespace
- See also:
kubernetes-latest-tag-image-pullfor why build-number tags are preferred over:latest