Skip to content

Instantly share code, notes, and snippets.

@Depado Depado/blog.md Secret
Created Jul 3, 2018

Embed
What would you like to do?

Introduction

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

Simple 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:

https://gist.github.com/aafc3273873fb28f731b9a7f032f36aa

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:

https://gist.github.com/b6aaf659e2cd171d8f8a6a67515a247d

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:

https://gist.github.com/b172a3bc19be7c016abd650caa622c69

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 !

https://gist.github.com/71d10ac0abb7497b4ce1953b3e679d0a

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

Basic 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:

https://gist.github.com/179f2f7dd17d24bf8be59eb264923f55

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:

https://gist.github.com/c69d63e84f0bebadea6ef24d16388558

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.

https://gist.github.com/104e51f2c405d96516395ce6383db00b

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

Setup

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:

https://gist.github.com/5d09198933081bf885357122833fbf8c

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.

new-sa

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:

https://gist.github.com/20d3302bb46be5818020610ea7639761

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:

https://gist.github.com/265918c527a7badab28c24fc33a342a8

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:

https://gist.github.com/59cce055398d9d28f163e5d62f125818

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:

https://gist.github.com/084edc64a34e8c4c275dbfbc27a2d60a

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 !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.