DEV Community

Cover image for Deploying a Kubernetes application with ArgoCD and Gitlab CI
Chabane R. for Onepoint x Stack Labs

Posted on • Edited on

Deploying a Kubernetes application with ArgoCD and Gitlab CI

Hello there !

In the part 4, we deployed the Scaleway Infrastructure with GitLab and Terraform.

In this last part, we will deploy a simple application using ArgoCD and Gitlab.

Alt Text

Plan

  • Building and publishing our Docker image using Gitlab and Google Cloud Build.
  • Configuring and deploying our Docker image to Kubernetes using Gitlab and ArgoCD.

Docker image

As mentioned in the part 2, we need to build the docker image after each git tag. Once the new docker image is published we edit the Kubernetes manifests using Kustomize and an env repo pipeline is triggered from the app-repo pipeline.

That mechanism is described in the demo-app repo pipeline:

.gitlab-ci.yaml
stages: - publish publish docker image: stage: publish image: name: eu.gcr.io/${GCP_PROJECT_ID}/tools script: - eval $(ssh-agent -s) - echo "$GITLAB_SSH_KEY" | tr -d '\r' | ssh-add - - mkdir -p ~/.ssh - chmod 700 ~/.ssh - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config' - ssh -T git@gitlab.com - git config --global user.name "${GITLAB_USER_NAME}" - git config --global user.email "${GITLAB_USER_EMAIL}" - git config --global push.followTags true - IMAGE_TAG=$CI_COMMIT_TAG-$CI_COMMIT_SHORT_SHA - cd src - gcloud config set project ${GCP_PROJECT_ID} - gcloud builds submit . --tag=eu.gcr.io/${GCP_PROJECT_ID}/demo:$IMAGE_TAG --project ${GCP_PROJECT_ID} --gcs-log-dir=gs://${GCP_PROJECT_ID}_cloudbuild/logs - git clone "git@gitlab.com:stack-labs/internal/sandbox/chabanerefes/meetup/demo-env.git" - cd demo-env/envs/dev - kustomize edit set image eu.gcr.io/${GCP_PROJECT_ID}/demo:$IMAGE_TAG - cd ../.. - git add . - 'git commit -m "ci: update image to $IMAGE_TAG"' - git tag -a -m "New release available - $CI_COMMIT_TAG" $CI_COMMIT_TAG - git push -o ci.skip tags: - k8s-dev-runner only: refs: - tags changes: - src/**/* 
Enter fullscreen mode Exit fullscreen mode

Share the specific runner k8s-dev-runner created previously with this project. You will need Maintainer permission in Gitlab.

Now you can run the Gitlab pipeline with the following Gitlab CI/CD Variables:

GCP_PROJECT_ID=$GCP_PROJECT_ID 
Enter fullscreen mode Exit fullscreen mode

Deployment

In the demo-env repo we have our Kubernetes manifests. Each time the docker image version is edited and a git tag is created, the Gitlab pipeline is executed.

The following files describe the Kubernetes manifests to deploy:

base/demo-deployment.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: demo labels: app: demo spec: selector: matchLabels: app: demo template: metadata: labels: app: demo spec: containers: - image: eu.gcr.io/<GCP_PROJECT_ID>/demo:v0.1.0 name: demo ports: - containerPort: 8080 
Enter fullscreen mode Exit fullscreen mode

base/demo-svc.yaml
apiVersion: v1 kind: Service metadata: name: demo spec: ports: - port: 80 targetPort: 8080 selector: app: demo 
Enter fullscreen mode Exit fullscreen mode

base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization # Adds namespace to all resources. namespace: app-dev resources: - demo-deployment.yaml - demo-svc.yaml 
Enter fullscreen mode Exit fullscreen mode

envs/dev/kustomization.yaml
namespace: app-dev apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - ../../base 
Enter fullscreen mode Exit fullscreen mode

The ArgoCD application is also defined in a yaml file:

envs/dev/application.yaml
apiVersion: argoproj.io/v1alpha1 kind: Application metadata: name: app-demo-dev namespace: argocd spec: project: demo-dev source: repoURL: <GIT_REPOSITORY_URL> targetRevision: HEAD path: envs/dev destination: server: <SW_KAPSULE_CLUSTER_URL> namespace: app-dev syncPolicy: automated: prune: true 
Enter fullscreen mode Exit fullscreen mode

In the gitlab pipeline we have two stages init and deploy.

  • The first stage adds Kapsule cluster in ArgoCD and initializes the dev environment in Kubernetes.
  • The second stage creates and configures the application in ArgoCD.
  • I added a third stage for manual sync on ArgoCD.

envs/dev/application.yaml
stages: - init - deploy - sync # Get Scaleway credentials from Vault before_script: - export VAULT_TOKEN="$(gcloud secrets versions access latest --secret=vault-token --project ${GCP_PROJECT_ID})" - export SCW_SECRET_KEY="$(vault kv get -field=key scaleway/project/${SW_PROJECT_NAME}/credentials/secret)" - export AROGOCD_TOKEN="$(gcloud secrets versions access latest --secret=argocd-token --project ${GCP_PROJECT_ID})" init sw k8s project ๐Ÿ”ฌ: stage: init when: manual image: name: eu.gcr.io/${GCP_PROJECT_ID}/tools script: # Connect to GCP GKE DevOps Cluster - gcloud container clusters get-credentials gke-cluster-devops --zone europe-west1-b --project ${GCP_PROJECT_ID} # Connect to scaleway - scw init secret-key=$SCW_SECRET_KEY # Get kubeconfig from sw kapsule cluster - scw k8s kubeconfig get $(scw k8s cluster list | grep kapsule-cluster-dev-demo | awk '{ print $1 }') region=fr-par > kapsule_config # Register kapsule cluster on Argocd - export KUBECONFIG=~/.kube/config:$(pwd)/kapsule_config - argocd cluster add admin@kapsuleclusterdevdemo --name kapsule-cluster-dev-demo --kubeconfig kapsule_config --auth-token=${AROGOCD_TOKEN} --server ${ARGOCD_ADDR} --grpc-web # Create namespace on kapsule cluster - kubectl config use-context admin@kapsuleclusterdevdemo - kubectl create namespace app-dev || echo 'namespace app-dev already exists' # To access GCR service, create the json key file and associate it with the service account - gcloud iam service-accounts keys create sw-gcr-auth-ro.json --iam-account=sw-gcr-auth-ro@${GCP_PROJECT_ID}.iam.gserviceaccount.com - export GCR_SECRET_NAME=gcp-gcr-auth-ro - | kubectl create secret docker-registry $GCR_SECRET_NAME -n app-dev \ --docker-server=https://eu.gcr.io \ --docker-username=_json_key \ --docker-email=ci@<MY_COMPANY>.com \ --docker-password="$(cat sw-gcr-auth-ro.json)" || echo 'secret $GCR_SECRET_NAME already exists' - | kubectl patch serviceaccount default -n app-dev \ -p "{\"imagePullSecrets\": [{\"name\": \"$GCR_SECRET_NAME\"}]}" tags: - k8s-dev-runner only: - master deploy sw k8s project ๐Ÿš€: stage: deploy when: manual image: name: eu.gcr.io/${GCP_PROJECT_ID}/tools script: # Connect to scaleway - scw init secret-key=$SCW_SECRET_KEY # Get sw kapsule cluster url - export SW_KAPSULE_CLUSTER_URL=$(scw k8s cluster get $(scw k8s cluster list | grep kapsule-cluster-dev-demo | awk '{ print $1 }') | grep ClusterURL | awk '{ print $2 }' | tr -d '\r') - cd envs/dev - sed -i "s,<SW_KAPSULE_CLUSTER_URL>,$SW_KAPSULE_CLUSTER_URL,g;s,<GIT_REPOSITORY_URL>,$CI_PROJECT_URL.git,g" application.yaml # Connecto to gcp gke devops cluster - gcloud container clusters get-credentials gke-cluster-devops --zone europe-west1-b --project ${GCP_PROJECT_ID} # Create ArgoCD project - argocd proj create demo-dev -d $SW_KAPSULE_CLUSTER_URL,app-dev -s $CI_PROJECT_URL.git --auth-token=${AROGOCD_TOKEN} --server ${ARGOCD_ADDR} --grpc-web # Create ArgoCD application - kubectl apply -n argocd -f application.yaml tags: - k8s-dev-runner only: - master sync dev ๐Ÿ”จ: stage: sync when: manual image: name: eu.gcr.io/${GCP_PROJECT_ID}/tools script: - argocd app sync app-demo-dev tags: - k8s-dev-runner only: - master 
Enter fullscreen mode Exit fullscreen mode

Share the specific runner k8s-dev-runner created previously with this project. You will need Maintainer permission in Gitlab.

Now you can run the Gitlab pipeline with the following Gitlab CI/CD Variables:

GCP_PROJECT_ID=$GCP_PROJECT_ID SW_PROJECT_NAME=$SW_PROJECT_NAME ARGOCD_ADDR=$ARGOCD_ADDR VAULT_ADDR=$VAULT_ADDR ENV=dev 
Enter fullscreen mode Exit fullscreen mode

That's it!

Final Words

The source code is available on Gitlab.

The demonstration is also available (but in ๐Ÿ‡ซ๐Ÿ‡ท) on Youtube at 32:12.

If you have any questions or feedback, please feel free to leave a comment.

Otherwise, I hope I have helped you answer some of the hard questions about building a multi-cloud between an European cloud and an American cloud leader.

By the way, do not hesitate to share with peers ๐Ÿ˜Š

Thanks for reading!

Top comments (0)