CI with GCP Cloud Build – evaluation

Cloud Build on of the services available on Google Cloud Platform. Evaluation happened January 2021 and I believe that is still improving. This post is supposed to be part of the bigger series with a unified structure.

Overview:

  • Even though Cloud Build labels itself as CI/CD tool it lacks the CD features (e.g. deployment strategies, manual approval stages etc.) – nobody prevents you from developing those
  • Run in GCP or has some support for local execution as well
  • Build using wiring Docker containers together. Executed on single VM, you can upscale VM to high cpu machines up to 32cpu. 

Continous Integration features:

Pricing:

Summary:

Purely CI system with capability to build (~ Cloud Build). No triggers for time based related things. So either Event based (commit, tag, …) or manual trigger. Probably could be emulated via Cloud Function to trigger to simulate Time Based Trigger. Has ability to run locally which is nice. Scales up to 32cpu machines. Prices based on build time (clock time). Doesn’t offer Approval stages, security model based on IAM and seems that you cannot grant permission on particular configuration/build. Doesn’t have concept of pipeline – but rather set of tasks steps(stages). Definition lives in Git – so LTS branches should be buildable. To have full end-2-end deployment, you need a CD system. This system manages just “build artefact”. 

Kubernetes Helm features I would wish to know from day one

Kubernetes Helm is a package manager for Kubernetes deployments. It is one of the possible tools for deployment management on Kubernetes platform. You can imagine it as an RPM in Linux world with package management on top of it like an apt-get utility.

Helm release management, ability to install or rollback to a previous revision, is one of the strongest selling points of Helm and together with strong community support makes it an exciting option. Especially the number of prepared packages is amazing and make it extremely easy to bootstrap a tech stack on the kubernetes cluster. But this article is not supposed to be a comparison between the kubernetes tools but instead describing an experience I’ve made while working with it and finding the limitations which for some else might be quite ok but having an ability to use the tool in those scenarios might be an additional benefit.
Helm is written in GO lang with the usage of GO templates which brings some limitation to the tool. Helm works on the level of string literals, and you need to take care of quotation, indentation etc. to form a valid kubernetes deployment manifest. This is a strong design decision from the creators of the Helm, and it is good to be aware of it. Secondly, Helm merges two responsibilities: To render a template and to provide kubernetes manifest. Though you can nest templates or create a template hierarchy, the rendered result must be a Kubernetes manifest which somehow limits possible use cases for the tool. Having the ability to render any template would extend tool capabilities as quite often the kubernetes deployment descriptors contain some configuration where you would appreciate type validation or possibility to render it separately. At the time of writing this article, the Helm version 2.11 didn’t allow that. To achieve this, you can combine Helm with other tools like Jsonnet and tie those together.
While combining different tools, I found following Helm advanced features quite useful which greatly simplified and provide some structure to the resulting Helm template. Following list enumerates those which I found quite useful.

Template nesting (named templates)
Sub-templates can be structured in helper files starting with an underscore, e.g. `_configuration.tpl` as files starting with underscore doesn’t need to contain valid kubernetes manifest.

{{- define "template.to.include" -}}
The content of the template
{{- end -}}

To use the sub-template, you can use

{{ include "template.to.include" .  -}}

Where “.” passes the actual context. When there are problems with the context trick with $ will solve the issue.

To include a file all you need is specify a path

{{ $.Files.Get "application.conf" -}}

Embedding file as configuration

{{ (.Files.Glob "application.conf").AsConfig  }}

it generates key-value automatically which is great when declaring a configMap

To provide a reasonable error message and make some config values mandatory, use required function

{{ required "Error message if value not specified" .Values.component.port }}

Accessing a key from value file which contains a dot e.g. application.conf

{{- index .Values.configuration "application.conf" }}

IF statements combining multiple values

{{- if or (.Values.boolean1) (.Values.boolean2) (.Values.boolean3) }}

Wrapping reference to value into braces solves the issue.

I hope that you found tips useful and if you have any suggestions leave the comment below or you can reach me for further questions on twitter.