DEV Community

giveitatry
giveitatry

Posted on

Restarting a Kubernetes Deployment from GitLab CI

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>
Enter fullscreen mode Exit fullscreen mode

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:

  1. ServiceAccount – identity used by the CI job
  2. Role (RBAC) – permissions (minimal scope)
  3. RoleBinding – attaches the Role to the ServiceAccount
  4. 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"]
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Retrieve the token

kubectl get secret gitlab-deploy-token -n some-namespace -o jsonpath="{.data.token}" | base64 -d
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Temporary token (not recommended for CI)

kubectl create token gitlab-deploy -n some-namespace
Enter fullscreen mode Exit fullscreen mode

This token:

  • expires (default ~1 hour)
  • is suitable only for testing

Obtaining GitLab environment variables

You need three variables in GitLab:

  • KUBE_TOKEN_DEV
  • KUBE_API_URL
  • KUBE_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
Enter fullscreen mode Exit fullscreen mode

Copy and store as KUBE_TOKEN_DEV.


2. KUBE_API_URL

kubectl config view --minify -o jsonpath="{.clusters[0].cluster.server}"
Enter fullscreen mode Exit fullscreen mode

Store output as KUBE_API_URL.


3. KUBE_CA_PEM

kubectl config view --raw -o jsonpath="{.clusters[0].cluster.certificate-authority-data}" | base64 -d
Enter fullscreen mode Exit fullscreen mode

Store full certificate as KUBE_CA_PEM.

For k3s:

sudo cat /etc/rancher/k3s/k3s.yaml
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Explanation of the pipeline

  1. Installs kubectl
  2. Configures cluster endpoint and TLS
  3. Authenticates using ServiceAccount token
  4. Sets context with namespace
  5. Executes rollout restart
  6. 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
Enter fullscreen mode Exit fullscreen mode

Forbidden errors

Check permissions:

kubectl auth can-i patch deployment \
  --as=system:serviceaccount:some-namespace:gitlab-deploy \
  -n some-namespace
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Top comments (0)