/ circleci

Microservices in Golang - Part 9 - Deployments with CircleCI

Sponsor me on Patreon to support more content like this.

In this part of the series, we're going to briefly look at setting up continuous integration with one of our services, using CircleCI.

CircleCI is a fantastic tool, and has a very usable free-tier. It's a SaaS, so unlike Jenkins, it's fully managed. I also just find the configuration and set-up very straight forward. CircleCI also utilises Docker images, so you can be really creative with how you manage your builds.

Ensuring you've signed-up and created account. First let's create a new project in CircleCI. Down the left-hand menu, click 'add project'. If you've connected your github account to your CircleCI account, you should see your microservice's git repo appear in the list. Click on 'follow project'. You will then see a page asking what operating system and language you'd like to use. Ensure Linux and Go are selected. And hit start building.

This will create some default confugration, but we need to add our own into that repo before our builds can start working correctly.

So in our service (I'm going to use our consignment-service for this), create a new directory in the root mkdir .circleci and in that directory, create a new file touch .circleci/config.yml. Now let's start adding our build configuration.

version: 2
jobs:
  build:
    working_directory: /app
    docker:
      # Here we select the Docker images we wish to use
      # in order to build our service.
      # We're using a container I made, which configurs the Google Cloud SDK
      # Kubernetes, and a few other utils. This is open-source, and you can find
      # the repo here https://github.com/EwanValentine/gcloud-docker-kubernetes 
      #
      # Then we're using the docker image itself, so that we can build docker containers.
      - image: ewanvalentine/gcdeploy:latest
        environment:
          GCLOUD_PROJECT_NAME: shippy-freight
          GCLOUD_CLUSTER_NAME: shippy-freight-cluster
          CLOUDSDK_COMPUTE_ZONE: europe-west2-a

          # This is a google service key, which allows us to authenticate
          # our build process with our cluster. 
          # You need to generate a service key, such as the one we generated
          # in part 7. You can copy the contents of this and encode it using base64.
          # Then add the base64 string into your environment variables, in the settings
          # of this build project. To find this, click on the spanner icon in your build.
          # Then click on environment variables, click add variable, with the name GCLOUD_SERVICE_KEY
          # then paste the base64 string of your service key into the value and save that.
          GOOGLE_APPLICATION_CREDENTIALS: ${HOME}/gcloud-service-key.json

      - image: docker:17.05.0-ce-git
        environment:
          DOCKER_TAG_PREFIX: "eu.gcr.io/$GCLOUD_PROJECT_NAME/shippy-consignment-service"
          DOCKER_TAG: "$DOCKER_TAG_PREFIX:$CIRCLE_SHA1"
    steps:
      - checkout
      - setup_remote_docker
      - run:
          name: Install dependencies
          
          # Fetches the base64 encoded service key content, decodes it into a file again.
          # Then sets the gcloud project name from the environment variables we set above.
          # Then we set the cluster name, the compute region/zone, then fetch the credentials.
          command: |
            echo $GCLOUD_SERVICE_KEY | base64 --decode -i > ${HOME}/gcloud-service-key.json && \
              gcloud auth activate-service-account --key-file ${HOME}/gcloud-service-key.json && \
              gcloud config set project $GCLOUD_PROJECT_NAME && \
              gcloud --quiet config set container/cluster $GCLOUD_CLUSTER_NAME && \
              gcloud config set compute/zone ${CLOUDSDK_COMPUTE_ZONE} && \
              gcloud --quiet container clusters get-credentials $GCLOUD_CLUSTER_NAME
      - deploy:
          name: Push application Docker image
          command: |
            make deploy

There's something we need to do in order to make this work, I've touched on this a little in the comments, but it's an important step, so I'd like to re-iterate this part.

We need our google cloud service key, such as the one we created in part 7, and we need to encode this into base64 and store it as an environment variable within our build project settings.

So locate your Google Cloud service key, and run $ cat <keyname>.json | base64, now copy that string. Head over to your project in CircleCI, click on the cog in the top right, then select the environments variables on the left column. Now create a new variable, named GCLOUD_SERVICE_KEY, and paste in your base64 string as the value, now save that.

What this does, is it keeps any secure information within circleci and keeps the repository free of any sensitive data. It keeps these access keys within the control of your ops team, and not just anyone who can access the repo.

Now in our build config, the contents of that variable are decoded into a file, which is then used to authenticate against our cluster.

...
echo $GCLOUD_SERVICE_KEY | base64 --decode -i > ${HOME}/gcloud-service-key.json && \
              gcloud auth activate-service-account --key-file ${HOME}/gcloud-service-key.json
...

There we have it, pretty simple. We have CI for one of our services. For a production service, you'll probably want to run your tests first, before your deploy step. Take a look at the docs and check out some of the cool stuff you can do with circle. Because circle uses Docker containers, you can even add a database container, so that you can run integration tests, too. Be creative, make the most of these features!

If you are finding this series useful, and you use an ad-blocker (who can blame you). Please consider chucking me a couple of quid for my time and effort. Cheers! https://monzo.me/ewanvalentine

Or, sponsor me on Patreon to support more content like this.