Integrate cluster operations into the Git pipeline
Service Account, kubeconfig, and a job for cluster actions from Git.
To run cluster operations from a Git CI/CD pipeline against a Shturval cluster, you need to:
- create a Service Account in the cluster with the permissions required for your operations;
- obtain a kubeconfig for that Service Account;
- add the kubeconfig to the project repository;
- configure a pipeline job that performs actions in the cluster.
The instructions below show how to create a Namespace from a GitLab pipeline.
Creating a namespace from the GitLab pipeline
Creating a Service Account in a cluster
- In the namespace
defaultof the cluster, create a Service Account with the namename-service-account:
ServiceAccount creation command
kubectl apply -f - <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
name: name-service-account
namespace: default
> EOF
- Create a cluster role with the necessary rights to perform actions
Command with an example of creating a role
kubectl apply -f - <<EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: special-sa-role
rules:
- apiGroups:
- ""
resources:
- "namespaces"
verbs:
- "get"
- "create"
- "list"
> EOF
- Bind the created ClusterRole to the Service Account by creating a ClusterRoleBinding in the cluster.
Command — illustration
kubectl apply -f - <<EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: special-sa-rolebinding
subjects:
kind: ServiceAccount
name: name-service-account
namespace: default
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: special-sa-role
> EOF
- Create a secret
secret-sain the cluster for the Service Account. Specify:
- namespace name
default. - the name of the Service Account created in the first step is
name-service-account; - secret type
kubernetes.io/service-account-token
Command — illustration
kubectl apply -f - <<EOF
apiVersion: v1
kind: Secret
metadata:
name: secret-sa
namespace: default
annotations:
kubernetes.io/service-account.name: name-service-account
type: kubernetes.io/service-account-token
> EOF
- Add the created secret
secret-sato the Service Account.
Command — illustration
kubectl edit sa name-service-account
Service Account Example
apiVersion: v1
kind: ServiceAccount
metadata:
creationTimestamp: "2024-12-11T05:14:47Z"
name: name-service-account
namespace: default
resourceVersion: "586818"
uid: cd32a856-76d9-472d-9345-1fe8a755be3f
secrets:
- name: secret-sa
- Determine the secret index in the Service Account by running:
Command — illustration
kubectl get serviceaccount name-service-account --context username@shturval-clustername --namespace default -o json
Where instead of username@shturval-clustername specify the required cluster context.
Command for obtaining a list of available cluster contexts
kubectl config get-contexts
Example answer
...
"secrets": [
{
"name": "secret-sa"
}
]
In the example, the secret index secret-sa has a value of 0. Use this index when preparing the cluster kubeconfig.
Preparing the cluster kubeconfig
- Create a file
kubeconfig.shwith a script that builds a kubeconfig for the Service Accountname-service-account.
Example kubeconfig.sh
# Set variables
SERVICE_ACCOUNT_NAME=name-service-account
NAMESPACE=default
NEW_CONTEXT=namesa
KUBECONFIG_FILE='kubeconfig-sa'
# Get current context
CONTEXT=$(kubectl config current-context)
# Get secret name from Service Account
SECRET_NAME=$(kubectl get serviceaccount ${SERVICE_ACCOUNT_NAME} --context ${CONTEXT} --namespace ${NAMESPACE} -o jsonpath='{.secrets[0].name}')
# Get access token and decode base64 data
TOKEN_DATA=$(kubectl get secret ${SECRET_NAME} --context ${CONTEXT} --namespace ${NAMESPACE} -o jsonpath='{.data.token}')
TOKEN=$(echo ${TOKEN_DATA} | base64 -d)
# Create kubeconfig file with full copy of current cluster kubeconfig
kubectl config view --raw > ${KUBECONFIG_FILE}.full.tmp
# Switch working context to current
kubectl --kubeconfig ${KUBECONFIG_FILE}.full.tmp config use-context ${CONTEXT}
kubectl --kubeconfig ${KUBECONFIG_FILE}.full.tmp config view --flatten --minify > ${KUBECONFIG_FILE}.tmp
# Rename context to new context
kubectl config --kubeconfig ${KUBECONFIG_FILE}.tmp rename-context ${CONTEXT} ${NEW_CONTEXT}
# Create user token
kubectl config --kubeconfig ${KUBECONFIG_FILE}.tmp set-credentials ${CONTEXT}-token-user --token ${TOKEN}
# Set context to use Service Account token
kubectl config --kubeconfig ${KUBECONFIG_FILE}.tmp set-context ${NEW_CONTEXT} --user ${CONTEXT}-token-user
# Flatten and get kubeconfig for Service Account
kubectl config --kubeconfig ${KUBECONFIG_FILE}.tmp view --flatten --minify > ${KUBECONFIG_FILE}
rm ${KUBECONFIG_FILE}.full.tmp
rm ${KUBECONFIG_FILE}.tmp
Where instead of 0 in .secrets[0].name, specify the index of the secret from the secrets Service Account array obtained in step 5 of the previous section.
- Run the script:
source kubeconfig.sh
As a result, a kubeconfig file named kubeconfig-sa is created for Service Account name-service-account in the current directory.
- Copy the contents of
kubeconfig-sa:
cat kubeconfig-sa
Add a job to the pipeline
In GitLab, add a CI/CD variable to the project repository. Set the key to
KUBECONFIG_fileand the value to the kubeconfig contents from the previous step.Open the CI/CD configuration file (by default,
.gitlab-ci.yml).Add a stage to
stages, for examplecreate_ns, to create a Namespace in the cluster:
stages:
- create_ns
- Add a job with these parameters:
stage— the stage name from the previous step;before_script— write theKUBECONFIG_filevariable tokubeconfig-sa.confand setKUBECONFIG=kubeconfig-sa.conf;script— the command to create the Namespace.
Example job
create_job:
stage: create_ns
before_script:
echo $KUBECONFIG_file> kubeconfig-sa.conf
export KUBECONFIG=kubeconfig-sa.conf
script:
- kubectl create namespace my-namespace
Replace my-namespace with the namespace name you want to create.
- Run the pipeline.
Creating a namespace using the API
- Sign in to the Shturval platform. See API authorization.
- Create a namespace with
curl:
curl -k -s -L --request POST $BACKENDPOINT/api/v1/clusters/{cluster_name}/namespaces?is_system=false
--header "Authorization: Bearer $token"
--data @<(cat <<EOF
{
"name": "namespacename",
"labels": [
{
"key": "example",
"value": "1"
}
]
}
EOF
) | jq -r