Guest post originally published on Arctiq’s blog by Daniyal Javed, DevOps Engineer and Consultant at Arctiq
Last year I posted a demo of using GitLab CI and ArgoCD with Anthos Config Management. It’s been a popular video on our YouTube Channel.
But, every comment has been asking for the configuration files 😄
Unfortunately, I can’t make the repos public so I will use this blog to go over the configuration.
CI Workflow
The architecture for this workflow separates CI and CD into two different streams and repositories. When a developer checks in code against the source repository, a GitLab CI job is triggered. This can be achieved using only
and except
specs in GitLab CI.
An example of building the app where the image is built with the commit SHA everytime there is a merge request against the dev
branch.
build_image:
stage: build_image
image:
name: gcr.io/kaniko-project/executor:debug
entrypoint: [""]
script:
- export GOOGLE_APPLICATION_CREDENTIALS=/kaniko/kaniko-secret.json
- echo $GOOGLE_APPLICATION_CREDENTIALS_BASE64 | base64 -d > $GOOGLE_APPLICATION_CREDENTIALS
- /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --destination gcr.io/$GOOGLE_PROJECT_ID/springstore:$CI_COMMIT_SHORT_SHA
only:
refs:
- merge_request
variables:
- $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "dev"
except:
variables:
- $CI_MERGE_REQUEST_SOURCE_BRANCH_NAME == "dev"
- $CI_MERGE_REQUEST_SOURCE_BRANCH_NAME == "qa"
- $CI_MERGE_REQUEST_SOURCE_BRANCH_NAME == "master"
Update tags
Once the image is pushed to the registry (in my case its GCR), our GitLab workflow needs to know the updated image tag. The image tag is stored as an environment variable in GitLab CI. Using GitLab’s API, this variable can be updated.
stage_image_tag:
stage: Stage Image Tag
script:
- curl --request PUT --header "PRIVATE-TOKEN:${GITLAB_API_TOKEN}" "https://gitlab.com/api/v4/projects/${CI_PROJECT_ID}/variables/IMAGE_ID" --form "value=${CI_COMMIT_SHORT_SHA}"
only:
refs:
- merge_request
variables:
- $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "dev"
except:
variables:
- $CI_MERGE_REQUEST_SOURCE_BRANCH_NAME == "dev"
- $CI_MERGE_REQUEST_SOURCE_BRANCH_NAME == "qa"
- $CI_MERGE_REQUEST_SOURCE_BRANCH_NAME == "master"
CD Workflow
Once the image is updated in GitLab CI environment variables, the image is updated and committed to the Anthos Config Management repository. This ACM repository is hooked to Anthos clusters to automatically deploy configurations from Git. I am using envsubst
to achieve this. Other tools can also be used.
Deployment to Dev
deploy_dev:
stage: deploy_dev
environment:
name: dev
image: daniyalj/alpine-envsub:v1
before_script:
- git config --global user.email "gitlab@gitlab.com"
- git config --global user.name "Mr GitLab"
- mkdir -p ~/.ssh
- echo "$GIT_SSH_PRIV_KEY" > ~/.ssh/id_rsa
- chmod 400 ~/.ssh/id_rsa
- ssh-keyscan gitlab.com >> ~/.ssh/known_hosts
script:
- git clone -b ${ENV_BRANCH} git@gitlab.com:daniyalj/${ENV_GIT_REPO}.git
- cd ${ENV_GIT_REPO}
- git checkout -b ${CI_ENVIRONMENT_NAME}-${CI_PIPELINE_ID}
- envsubst < pipeline-staging/spring-store.yaml > config-management/namespaces/argocd/spring-store-app-${CI_ENVIRONMENT_NAME}.yaml
- git add . && git commit -m "deploy ${CI_ENVIRONMENT_NAME}-${CI_PIPELINE_ID}" && git push -o merge_request.label="Deploy" -o merge_request.create -o merge_request.target=${ENV_BRANCH} --force origin ${CI_ENVIRONMENT_NAME}-${CI_PIPELINE_ID}
only:
- dev
The ArgoCD application within ACM looks like this:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: spring-store-dev
annotations:
configmanagement.gke.io/cluster-selector: selector-env-dev
spec:
destination:
namespace: spring-store
server: https://kubernetes.default.svc
project: default
source:
chart: spring-store
helm:
parameters:
- name: imageTag
value: "bab2517a"
- name: hostname
value: springstore.dev.anthos.daniyalj.team.arctiq.ca
repoURL: https://spring-store.storage.googleapis.com/charts
targetRevision: "4.0.0"
syncPolicy:
automated:
selfHeal: true
Where the image tag is replaced with commit short SHA. Once this change is commited to ACM, ArgoCD will detect the change, synchronize the application and deploy to the dev cluster which is specified with configmanagement.gke.io/cluster-selector: selector-env-dev
in ACM.
At this point, the application can be verified in dev. Once, happy with the change, the merge request can be merged to master which will trigger the production deployment.
Deployment to Prod
deploy_dev:
stage: deploy_prod
environment:
name: dev
image: daniyalj/alpine-envsub:v1
before_script:
- git config --global user.email "gitlab@gitlab.com"
- git config --global user.name "Mr GitLab"
- mkdir -p ~/.ssh
- echo "$GIT_SSH_PRIV_KEY" > ~/.ssh/id_rsa
- chmod 400 ~/.ssh/id_rsa
- ssh-keyscan gitlab.com >> ~/.ssh/known_hosts
script:
- git clone -b ${ENV_BRANCH} git@gitlab.com:daniyalj/${ENV_GIT_REPO}.git
- cd ${ENV_GIT_REPO}
- git checkout -b ${CI_ENVIRONMENT_NAME}-${CI_PIPELINE_ID}
- envsubst < pipeline-staging/spring-store.yaml > config-management/namespaces/argocd/spring-store-app-${CI_ENVIRONMENT_NAME}.yaml
- git add . && git commit -m "deploy ${CI_ENVIRONMENT_NAME}-${CI_PIPELINE_ID}" && git push -o merge_request.label="Deploy" -o merge_request.create -o merge_request.target=${ENV_BRANCH} --force origin ${CI_ENVIRONMENT_NAME}-${CI_PIPELINE_ID}
only:
- master
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: spring-store-prod
annotations:
configmanagement.gke.io/cluster-selector: selector-env-prod
spec:
destination:
namespace: spring-store
server: https://kubernetes.default.svc
project: default
source:
chart: spring-store
helm:
parameters:
- name: imageTag
value: "bab2517a"
- name: hostname
value: springstore.prod.anthos.daniyalj.team.arctiq.ca
repoURL: https://spring-store.storage.googleapis.com/charts
targetRevision: "4.0.0"
syncPolicy:
automated:
selfHeal: true
And as dev, once this change is detected, ACM updates ArgoCD and ArgoCD deploys the new instance in prod.
Hope this blog summarizes the workflow covered in the video. If you want to discuss this topic further please feel free to reach out, we would love to hear from you.