When the infrastructure is done and all resources are in place we need to create a CI/CD pipeline to allow our code to be deployed. We choose GitLab’s CI/CD pipeline to deploy new code to production.
We will test, build, push image to Google Container Registry and deploy a simple Go app to Google Kubernetes Engine. The app can be found in repo but feel free to use directly your docker image, it’ s straight forward 🙂
Some remarks on .gitlab-ci.yml file, skipping the basics:
Stages
We manage deploys in 4 stages, 4 + 1 because one is a bit fatty
stages:
- test
- build
- cannary
- deploy
Test
test:
stage: test
image: node:latest
cache:
paths:
- node_modules/
script:
- npm install
- npm test
The stage pulls the latest node image and perform npm install
and npm test
and it keeps node_modules/
cached for further runs
Build
build-push:
stage: build
image: docker:latest
services:
- docker:dind
before_script:
# Login to Google Cloud Registry
- base64 -d $GCP_SA_KEY | docker login -u _json_key --password-stdin https://gcr.io
script:
- docker build -t gcr.io/project-292212/api:$CI_COMMIT_TITLE -t gcr.io/project-292212/api:latest .
- docker push gcr.io/project-292212/api:$CI_COMMIT_TITLE
- docker push gcr.io/project-292212/api:latest
# only:
# - tags
Before building docker image we need to authenticate in GCR to have where to push new images. We use a service-account.json key for authentication step, which need a cluster admin and storage write permissions
$GCP_SA_KEY
is the serice-account.json encoded in base64 variable defined in GitLab -> Settings -> CI/CD -> Variables. To encode the json in base64
base64 project-292212-69fc45252989.json > project-292212-69fc45252989-base64.json
$CI_COMMIT_TITLE
is a gitlab environment variable containing the commit title. A full list of predefined vars here
Optionally, we can define when this stage will be triggered.
Cannary
deploy:
stage: cannary
image: google/cloud-sdk
services:
- docker:dind
before_script:
# Login to Google Cloud
- gcloud auth activate-service-account project@project-292212.iam.gserviceaccount.com --key-file=$GOOGLE_CLOUD_ACCOUNT
- gcloud config set project project-292212
- gcloud config set compute/zone europe-west4
- gcloud container clusters get-credentials project-292212-gke-cluster-2ab5 --zone europe-west4 --project project-292212
- kubectl config current-context
script:
# Make gcloud available
- source /root/.bashrc
- sed -e "s|GIT_VERSION|$CI_COMMIT_TITLE|g" cannary.yml | kubectl apply -f -
Auto deploy to a cannary stage in Google Kubernetes Engine. In deployment.yaml
is a simple Kubernetes Deploy which takes the latest app version from Google Cloud Registry and apply to GKE. For this, we need the google/cloud-sdk
image, which includes kubectl (
thanks to this StackOverflow answer),
and we need to configure cluster access to kubectl in before_script:
job. We added a simple variable to our cannary.yml Deploy and apply it through kubectl
Deploy
Last step is the same but we added when: manual
to manually promote deploy to production, if the cannary looks good.
Some useful resources:
Connection between GitLab and Kubernetes Cluster can be made through GitLab’s Cluster Management
Configure Gitlab CI with Google Container Registry article is the inspiration for the build-push
stage
GitLab repo: https://gitlab.com/aaadipop/gcr-gke-deploy-pipeline