build-tools

module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 23, 2019 License: MIT

README

build-tools

A set of highly opinionated tools for creating and building components/services into docker images and deploying them to Kubernetes clusters.

By following the conventions set by the tools, building and deploying applications is made simpler.

The only hard requirement is to provide a Dockerfile which describes how to build and run your application.

The configuration needed is done by environment variables (most likely for CI/CD) and yaml files (for local use).

Available commands

build

push

deploy

Conventions

  • Dockerfile must be present in the root of the project directory (TODO Override name of file). The Dockerfile will be used to build the project into a runnable docker image.
  • The name of the directory will be used as the name of the docker image (TODO Override by ENV)
  • The current commit id will be used as docker tag
  • Kubernetes descriptor files must be located in the k8s folder under the root

Take a look at the build-tools-example repository (TODO link) to try it out.

Using in CI/CD pipelines

Example usage

After installing (TODO link) the tools, clone the build-tools-example repository (TODO link), cd into it and execute the build command.

$ build
Using CI none

no Docker registry found

Since we we haven't setup a.buildtools.yaml (TODO LINK in doc) file, nothing has been configured, and to be able to build a docker image we must specify where we (potentially) want to push it later. In other words, setting the tags of the created image. Luckily we can use environment variables as well, let's try:

$ DOCKERHUB_REPOSITORY=sparetimecoders build
Using CI none

Using registry Dockerhub

Login Succeeded
Using build variables commit 7c76db502b4a70df5480d6ff438ae10e374b420e on branch master

As we can see, the build command identified that we are using Dockerhub, and extracted the commit id and branch information from the local git repository. Notice that the name of the current directory is used as the image name. After the successful build the image is tagged with the commit id and branch.

Successfully tagged sparetimecoders/buildtools-examples:7c76db502b4a70df5480d6ff438ae10e374b420e
Successfully tagged sparetimecoders/buildtools-examples:master
Successfully tagged sparetimecoders/buildtools-examples:latest

Now that we have a docker image, let's publish it to the docker repository (this of course requires write access to the repository).

$ DOCKERHUB_REPOSITORY=sparetimecoders DOCKERHUB_PASSWORD=<PASSWORD> DOCKERHUB_USERNAME=<USERNAME> push
...
Pushing tag 'sparetimecoders/buildtools-examples:7c76db502b4a70df5480d6ff438ae10e374b420e'
...

TODO Link to more environment variables and stuff

Basic setup

  • Clone this repository
  • Add BUILD_TOOLS_PATH=<PATH TO THIS REPOSITORY> to your shell environment, typically in .bash_profile or something similar

Setup script

Script to be used for scaffolding a component/service. Handles repository, build-pipeline and basic files-scaffolding.

${BUILD_TOOLS_PATH}/service-setup --stack <stack> <name>

See Build project structure below

Common build scripts

Scripts to be used for building and deploying our services (typically when running in a CI/CD environment). They can also be used for local builds/deploy.

${BUILD_TOOLS_PATH}/build
${BUILD_TOOLS_PATH}/push

Build project structure

Configuration and setup is done in .buildtools files. Those files must be present in the project folder or upwards in the dicectory structure. This lets you create a common .buildtools file to be used for a set of projects. Example:

$ pwd
~/source/
$ tree
.
├── customer1
│   ├── project1
│   └── project2
└── customer2
    └── project1

Here we can choose to put a .buildtools file in the different customer directories since they (most likely) have different deployment configuration.

$ cat customer1/.buildtools
CI=azure
VCS=azure
REGISTRY=dockerhub
ORGANIZATION=com.organization
DOCKERHUB_REPOSITORY=repository
DOCKERHUB_USERNAME=user
DOCKERHUB_PASSWORD=$(lpass show devenv/docker.com --password)
AZURE_USER=user
AZURE_TOKEN=token
AZURE_ORG=organization
AZURE_PROJECT=project
PIPELINE_VARIABLES=(
["DOCKERHUB_REPOSITORY"]="repository"
["DOCKERHUB_USERNAME"]="user"
["DOCKERHUB_PASSWORD"]="secret:$(lpass show devenv/docker.com --password)"
["BUILDTOOLS_CONTENT"]="$(lpass show devenv/organization/team/buildtools --notes | base64 -w0)"
["KUBECONFIG_CONTENT"]="$(lpass show devenv/organization/team/kubeconfig --notes | base64 -w0)"
)
valid_environments=(
    ["local"]="--context docker-for-desktop --namespace default"
    ["staging"]="--context docker-for-desktop --namespace staging"
    ["prod"]="--context docker-for-desktop --namespace prod"
)

This defines three environments (local,staging,prod) all which are to be deployed to a local Kubernetes cluster but in different namespaces.

$ cat customer2/.buildtools
valid_environments=(
    ["local"]="--context docker-for-desktop --namespace local"
    ["prod"]="--context kube-cluster-prod --namespace prod"
)

Context and namespaces must be provided/created/configured elsewhere.

Configuration for service-setup

The service-setup script need to know where to scaffold things (i.e. which VCS, CI and container registry to use and how to connect to them). The environment variables CI, VCS and REGISTRY are used to define this. Depending on the values of those variables, other variables are required as well. See each section below for the required variables. Values from the associative array PIPELINE_VARIABLES will be created as pipeline-variables in the CI-system. If the value is prepended vith secret: the variable will be a secret (if the CI-system supports that).

Azure Devops

If CI and/or VCS is set to azure the following variables are required:

Variable Value
AZURE_USER Azure username
AZURE_TOKEN Azure Personal Access Token
AZURE_ORG The organization name in Azure
AZURE_PROJECT The project name in Azure where repository and build-pipeline will be created
Buildkite

If CI is set to buildkite the following variables are required:

Variable Value
BUILDKITE_TOKEN Buildkite Access Token
BUILDKITE_ORG The organization name in Buildkite where the build-pipeline will be created
GitlabCI

If CI or VCS is set to gitlab the following variables are required:

Variable Value
GITLAB_TOKEN Gitlab Access Token
GITLAB_GROUP The group name in Gitlab where project will be created
Configuration using environment variables

The .buildtools file can be created by defining an environment variable in the build pipeline named BUILDTOOLS_CONTENT. The value should be a base64-encoded string. On MacOS the value can be created and copied to the clipboard using the following snippet:

cat - <<EOF | base64 -w0 | pbcopy
valid_environments=(
    ["local"]="--context docker-for-desktop --namespace local"
    ["prod"]="--context kube-cluster-prod --namespace prod"
)
EOF

The Kubernetes contexts to deploy to are configured by setting the KUBECONFIG_CONTENT variable. The value should be a base64-encoded string containing the Kubernetes config for the clusters you want to be able to deploy to. On MacOS the value can be created and copied to the clipboard using the following snippet:

cat ~/.kube/config.d/prod-cluster.yaml | base64 -w0 | pbcopy

The scripts assume that the project follow the directory layout described below.

Project structure

The project folder must be a Git repository, with a least one commit.

There must be a k8s directory in the root of your project file. This directory contains all the yaml files used to describe the Kubernetes deployment tasks needed to run this service. Environment specific files can be handled in two different ways depending on personal preference. They can either be located in sub-directories, for example k8s/local for local setup.

$ cd projecct
$ tree
.
└── k8s
    ├── deploy.yaml
    ├── local
    │   ├── ingress.yaml
    │   └── setup.sh
    └── prod
        └── ingress.yaml

Or they can be defined using a -<environment> suffix, i.e. ingress-prod.yaml

$ cd projecct
$ tree
.
└── k8s
    ├── deploy.yaml
    ├── ingress-local.yaml
    ├── ingress-prod.yaml
    └── setup-local.sh

Running in a CI/CD environment

The tools recognize which CI/CD environment they are executed in based on which environment variables are present.

Variable CI/CD environment
VSTS_PROCESS_LOOKUP_ID Azure Devops
BUILDKITE_COMMIT Buildkite
GITLAB_CI GitlabCI

Support for different Docker container registries

The container registry to use when running docker:push is also defined by environment variables.

Variable Container registry Example value
DOCKERHUB_REPOSITORY Docker Hub bitnami (resulting in bitnami/<image>
ECR_URL AWS ECR 12345678.dkr.ecr.eu-west-1.amazonaws.com
CI_REGISTRY_IMAGE Gitlab Registry registry.gitlab.com/sparetimecoders/build-tools
QUAY_REPOSITORY Quay.io quay.io/bitnami

Other environment variables that need to be defined (either automatically by the CI/CD environment or manually in the build pipeline) for each of the container registries are defined below.

Docker Hub
Variable Description
DOCKERHUB_USERNAME Username
DOCKERHUB_PASSWORD Password
AWS ECR
Variable Description
ECR_REGION Optionally specified region, will use eu-west-1 as default value
Gitlab Registry
Variable Description
CI_BUILD_TOKEN The build-token set by GitlabCI
CI_REGISTRY The URL to the registry set by GitlabCI
Quay.io
Variable Description
QUAY_USERNAME Username
QUAY_PASSWORD Password

Example Azure Devops pipeline (azure-pipelines.yml)

resources:
  containers:
  - container: build-tools
    image: registry.gitlab.com/sparetimecoders/build-tools:master

jobs:
- job: build_and_deploy
  pool:
    vmImage: 'Ubuntu 16.04'
  container: build-tools
  steps:
  - script: |
      build
      push
    name: build
    env:
      DOCKERHUB_PASSWORD: $(DOCKERHUB_PASSWORD)
      QUAY_PASSWORD: $(QUAY_PASSWORD)
  - script: deploy staging
    name: deploy_staging
    condition: succeeded()

Example Buildkite pipeline (.buildkite/pipeline.yml)

steps:
  - command: |-
      build
      push
    label: build

  - wait

  - command: |-
      ${BUILD_TOOLS_PATH}/deploy staging
    label: Deploy to staging
    branches: "master"

  - block: ":rocket: Release PROD"
    branches: "master"

  - command: |-
      ${BUILD_TOOLS_PATH}/deploy prod
    label: Deploy PROD
    branches: "master"

Example GitlabCI pipeline (.gitlab-ci.yaml)

stages:
  - build
  - deploy-staging
  - deploy-prod

variables:
  DOCKER_HOST: tcp://docker:2375/

image: registry.gitlab.com/sparetimecoders/build-tools:master

build:
  stage: build
  services:
    - docker:dind
  script:
  - build
  - push

deploy-to-staging:
  stage: deploy-staging
  when: on_success
  script:
    - echo Deploy to staging.
    - deploy staging
  environment:
    name: staging

deploy-to-prod:
  stage: deploy-prod
  when: on_success
  script:
    - echo Deploy to PROD.
    - deploy prod
  environment:
    name: prod
  only:
    - master

Developing

Generate test mocks

mockgen -package=mocks -destination=pkg/config/mocks/MockRepositoriesService.go gitlab.com/sparetimecoders/build-tools/pkg/config RepositoriesService

Directories

Path Synopsis
cmd
pkg
ci
config/scaffold/vcs/mocks
Package mocks is a generated GoMock package.
Package mocks is a generated GoMock package.
tar
vcs

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL