Best practices

Pin image tags

In order to keep your builds reproducible, even if you haven't touched them for a year it's best to pin the stage image tags as narrowly as possible (or at least major and minor to avoid adopting breaking changes). This will ensure you're not wasting a day figuring out why your build is suddenly broken, when it turns out it's the latest image tag of one of the used images is actually a different image now.

DON'T:

stages:
  build:
    image: golang
stages:
  build:
    image: golang:latest

DO:

stages:
  build:
    image: golang:1.11.2-alpine3.8

Use commands instead of build scripts

One of the strengths of Estafette‘s manifest is that you can immediately see which commands have been issued and can try those on your own machine. This particularly comes in handy when your build breaks. If the actual commands are hidden in a build script you have to navigate from repository to repository to find which commands are actually executed and it means more work to fix things in that case.

DON'T:

stages:
  build:
    image: microsoft/dotnet:2.1-sdk
    commands:
    - build-script.sh

DO:

stages:
    image: microsoft/dotnet:2.1-sdk
    commands:
    - dotnet build --configuration Release /p:Version=${ESTAFETTE_BUILD_VERSION} --no-restore

Share as little as possible between applications

Although it's tempting to build your own fat builder images to run your steps (particularly to improve speed), before you know it a dozen applications rely on this particular image. When you by accident break the image all the builds using it can no longer build. Or you remove an installed depedency because your particular build no longer use it, turns out a bunch of other applications actually do use it.

DON'T:

stages:
  build:
    image: myrepo/myown-cloud-sdk
    commands:
    - ...

DO:

stages:
    image: google/cloud-sdk:223.0.0-alpine
    commands:
    - apk add gettext
    - gcloud commands install kubectl
    - ...

Avoid using Estafette's dev or beta tags

Estafette dogfoods it's own components, pushing new versions to the dev tag first. Once it's confirmed to be functional it gets promoted to beta, then to stable. Because the dev tag of any extension can be broken at any time avoid using it and use the stable tag instead.

DON'T:

stages:
  build:
    image: extensions/docker:dev

DO:

stages:
  build:
    image: extensions/docker:stable

Avoid using Estafette's builder dev track

Estafette dogfoods it's own components, pushing new versions to the dev track first. Once it's confirmed to be functional it gets promoted to beta, then to stable. Because the dev track of the builder itself can be broken at any time avoid using it and use the stable track instead.

DON'T:

builder:
  track: dev

DO:

builder:
  track: stable

Or drop the builder section alltogether, it defaults to the stable track.

Use pipeline restricted secrets instead of global secrets

In Estafette you can create global secrets which can be decrypted by any pipeline and restricted secrets which can only be used in a single pipeline. In your .estafette.yaml manifest it's best to only use pipeline restricted secrets.

You can distinguish between the two types by the number of dots in the estafette.secret(...) envelope. A global secret use one dot to separate the nonce from the encrypted value; a restricted secret has two dots separating the nonce, the encrypted value and the pipeline regex.

DON'T:

env:
  MY_GLOBAL_SECRET: estafette.secret(deFTz5Bdjg6SUe29.oPIkXbze5G9PNEWS2-ZnArl8BCqHnx4MdTdxHg37th9u)

Global secrets were originally the only type of secret, but now they should only be used in Estafette's centrally stored credentials, which can then be reused by any pipeline using trusted images that get those credentials injected.

DO:

env:
  MY_PIPELINE_RESTRICTED_SECRET: estafette.secret(7pB-Znp16my5l-Gz.l--UakUaK5N8KYFt-sVNUaOY5uobSpWabJNVXYDEyDWT.hO6JcRARdtB-PY577NJeUrKMVOx-sjg617wTd8IkAh-PvIm9exuATeDeFiYaEr9eQtfreBQ=)

When replacing a global secret with a restricted secret make sure to rotate the encrypted value itself - i.e. database password, api key, etc - in order to prevent anyone from using the former global secret to gain access to the protected system. The restricted secret can be generated in the pipeline's secrets tab.