CI/CD with Drone, Kubernetes and Helm — Part 2

leboncoin tech
leboncoin tech Blog
6 min readJul 19, 2018

By Paul Lhussiez (Lab Backend Developer)

This is the second part of the article series. In the first part we saw how to start a Kubernetes cluster, how to deploy Tiller and use Helm with it, and we deployed a Drone instance. We also enabled HTTPS using cert-manager for our Drone instance.

In this article we’ll see how to create a quality pipeline for a go project, how to build and push a docker image to Google Cloud Registry from our CI according to the different event that can be handled by Drone.

Go Project

TL;DR: You can find the code and the various files here.

We’re going to work on a dummy go project. So just create a new repository in your VCS, clone it and create a new file named main.go in it:

This example is a simple server that listens on 127.0.0.1:8080 and has a single route: /health, a health-check route, which will always respond 200 OK with a small JSON message.

Tooling and Docker

As mentioned in a previous article, we’re going to use dep to handle our dependencies, and we’re going to have a multi-stage Dockerfile.

So first, let’s install dep and initialize it in our repository:

We now have two more files in our repository: Gopkg.lock and Gopkg.toml. We also have a vendor/ directory. Great, now our dependencies are fixed. Let's create the Dockerfile:

We are also going to prevent Docker from copying the whole vendor/ directory by creating a .dockerignore at the root of our repository. And voilà. We're now ready to build our Docker image !

There we go, we now have a small docker image containing our go program, and everything need to be deployed to a Kubernetes cluster.

Drone Pipeline

As stated in the previous article of the series, Drone works the same way as Travis, which is: You create a .drone.yml file at the root of your repository:

This is the most basic pipeline you can create while you’re using dep. The first step is, using the golang:latest Docker image, display the go version, install dep and then install the dependencies. The second step of the pipeline is simply to build and check if our project builds.

Linter

In this section we’re going to see two linters. The first one is gometalinter, it has been around for a long time now and is really stable. The second one is golangci-lint which is more recent but has some amazing performance compared to gometalinter. So pick your weapon, no need to use both of them !

gometalinter

Simply put, gometalinter is a tool that has a whole bunch of linters vendored, and that can run them concurrently and report any errors found by them. The full list of linters can be found here.

So let’s add a step to our pipeline:

We need to disable gotype since it has some issues with aliasing and vendoring and other stuff like that.

golangci-lint

So basically golangci-lint is quite the same as gometalinter, except it’s way faster. You can check out the comparison between golangci-lint and gometalinter.

To add this linter to your pipeline, you can simply add this step to your pipeline.

If you prefer, you can directly vendor golangci-lint in your repository to save a network call.

Opinion

Although I love gometalinter, since I found golangci-lint I can’t really think of a single reason to go back to it. The output is better, the run time is way faster which is nice when you want your pipeline to complete quickly. So I’d personally go with golangci-lint and ditch gometalinter.

Pushing to GCR

Now things are getting serious. In this section we are going to start using Drone secrets. So you need to make sure that you installed the drone CLI, and that you configured it correctly. You can check if that worked properly by running:

Google Container Registry is a private Docker registry which we’re going to use to host our tagged Docker images for our future deployments. As it’s private, we’re going to need to authenticate and we can achieve this by creating what’s called a service account. This service account won’t be inside our k8s cluster though, and will be used to grant some authorization to our CI when it will use it.

So let’s head to the IAM Console and create a new service account. Name it as you like and select the “Storage Admin” role, check the box to generate a new JSON key and hit “Save”. You’ll be offered to download the JSON key, download and save it on your computer.

Latest

We’re going to use our first Drone plugin, namely the Google Container Registry plugin. There’s some explanation on this page on how to use this plugin, and it’s written that this plugin is actually an extension of the Docker plugin.

So let’s add this step to our .drone.yml file:

Obviously you need to replace the project-id with your own project ID. Here's what Drone understands at this step:

If a commit is pushed on the master branch, then build the Docker image, tag it with latest and the git sha1 commit, and push it to GCR using the credentials defined in the google_credentials secret.

We’re missing something here. The google_credentials secret is yet to be created. So in your terminal, we'll use the drone CLI to create a new secret for our repository, and we'll limit this secret to be used only by the plugins/gcr image:

Here we’re adding a secret to our repository (Depado/dummy), with the name google_credentials and we're limiting the use of this secret to the plugins/gcr image.

Now we’re going to commit our .drone.yml file and test it. If everything went fine, you should see your Docker image with the latest tag in GCR !

Release

So now we can push our Docker image with the latest tag to our Google Cloud Registry. What about we also push the image when we tag a release on our Github ? Drone can handle that, in case of the tag event, here's the additional step we're going to add to our .drone.yml file:

Now only when we’re going to tag a release will this step be triggered. Not only will it build the image just like the gcr step, but it will also add the ${DRONE_TAG##v} tag. That simply means that Drone will replace this value with the tag it detected and strip away the v if there's any. This means that you can tag your release v1.0.1 and the tag will be 1.0.1

Summary

At this point, your .drone.yml should look somewhat like that:

Our Drone is now able to check if our code passes all the linters, checks if the project compiles, build the Docker image using our Dockerfile and push it to GCR according to the various events Drone can read.

In the next part we’ll see how to create a Helm Chart for our application. We already saw how to use a pre-made Chart, we will see how we can automate the helm upgrade process !

--

--