Introduction
In many delivery workflows, a full redeploy is unnecessary. A rollout restart is sufficient to force Pods to be recreated (for example after updating ConfigMaps, Secrets, or re-pulling an image with the same tag). This article describes how to trigger:
kubectl rollout restart deployment/<name>
from GitLab CI against Kubernetes (including k3s), using a minimal and secure setup.
Kubernetes-side requirements
To allow a CI job to operate on the cluster, you need:
- ServiceAccount – identity used by the CI job
- Role (RBAC) – permissions (minimal scope)
- RoleBinding – attaches the Role to the ServiceAccount
- Token – credential used by the CI job
A rollout restart is implemented as a PATCH to the Deployment (spec.template.metadata.annotations), so the essential permission is:
verbs: ["patch"]
get is recommended; list is optional.
Kubernetes setup using YAML (recommended)
Create a single manifest with all required resources.
Full manifest
apiVersion: v1
kind: ServiceAccount
metadata:
name: gitlab-deploy
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: gitlab-deploy-role
rules:
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "patch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: gitlab-deploy-binding
subjects:
- kind: ServiceAccount
name: gitlab-deploy
roleRef:
kind: Role
name: gitlab-deploy-role
apiGroup: rbac.authorization.k8s.io
---
# Non-expiring token for CI/CD
apiVersion: v1
kind: Secret
metadata:
name: gitlab-deploy-token
annotations:
kubernetes.io/service-account.name: gitlab-deploy
type: kubernetes.io/service-account-token
Creating a non-expiring token (recommended for CI/CD)
Modern Kubernetes does not automatically create long-lived tokens. Instead, you explicitly create one via a Secret (as shown above).
Apply configuration
kubectl apply -f gitlab-deploy.yaml -n some-namespace
Retrieve the token
kubectl get secret gitlab-deploy-token -n some-namespace -o jsonpath="{.data.token}" | base64 -d
This token:
- does not expire
- is stable for CI/CD usage
- is tied to the ServiceAccount lifecycle
This is the recommended approach for GitLab CI pipelines.
Kubernetes setup using CLI (alternative)
kubectl create serviceaccount gitlab-deploy -n some-namespace
kubectl create role gitlab-deploy-role \
--verb=get,patch \
--resource=deployments \
-n some-namespace
kubectl create rolebinding gitlab-deploy-binding \
--role=gitlab-deploy-role \
--serviceaccount=some-namespace:gitlab-deploy \
-n some-namespace
Temporary token (not recommended for CI)
kubectl create token gitlab-deploy -n some-namespace
This token:
- expires (default ~1 hour)
- is suitable only for testing
Obtaining GitLab environment variables
You need three variables in GitLab:
KUBE_TOKEN_DEVKUBE_API_URLKUBE_CA_PEM
Add them under Settings → CI/CD → Variables.
1. KUBE_TOKEN_DEV
For non-expiring token:
kubectl get secret gitlab-deploy-token -n some-namespace -o jsonpath="{.data.token}" | base64 -d
Copy and store as KUBE_TOKEN_DEV.
2. KUBE_API_URL
kubectl config view --minify -o jsonpath="{.clusters[0].cluster.server}"
Store output as KUBE_API_URL.
3. KUBE_CA_PEM
kubectl config view --raw -o jsonpath="{.clusters[0].cluster.certificate-authority-data}" | base64 -d
Store full certificate as KUBE_CA_PEM.
For k3s:
sudo cat /etc/rancher/k3s/k3s.yaml
GitLab CI configuration
.gitlab-ci.yml
deploy_dev:
stage: deploy
image: ubuntu:22.04
before_script:
- apt-get update && apt-get install -y curl
- curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
- install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
script:
- echo "$KUBE_CA_PEM" > ca.crt
- kubectl config set-cluster k3s --server=$KUBE_API_URL --certificate-authority=ca.crt
- kubectl config set-credentials gitlab --token=$KUBE_TOKEN_DEV
- kubectl config set-context gitlab --cluster=k3s --user=gitlab --namespace=some-namespace
- kubectl config use-context gitlab
- kubectl rollout restart deployment/pod-deployment
rules:
- if: '$CI_COMMIT_BRANCH == "develop"'
when: always
- when: never
Explanation of the pipeline
- Installs
kubectl - Configures cluster endpoint and TLS
- Authenticates using ServiceAccount token
- Sets context with namespace
- Executes rollout restart
- Runs only on selected branch
Troubleshooting
RoleBinding error: cannot change roleRef
Fix:
kubectl delete rolebinding gitlab-deploy-binding -n some-namespace
kubectl apply -f gitlab-deploy.yaml
Forbidden errors
Check permissions:
kubectl auth can-i patch deployment \
--as=system:serviceaccount:some-namespace:gitlab-deploy \
-n some-namespace
Token expired
Cause:
- Using
kubectl create token
Fix:
- Use Secret-based non-expiring token
Missing annotation warning
Safe to ignore when switching from create to apply.
API connection issues
Verify:
kubectl config view --minify
Top comments (0)