Prepare the infrastructure

Requirements

  • GitLab;

  • Linux host to install the GitLab Runner, featuring:

    • Bash;

    • Git version 2.18.0 or above;

    • GPG.

Installing the GitLab Runner

Follow official instructions to install the GitLab Runner on your dedicated host.

Installing Buildah

Follow these steps on the GitLab Runner host to install Buildah:

  • Install the Buildah package following the official instructions but avoid configuring it. If there are no ready-made Buildah packages for your distribution, refer to the following guidelines:
Installing Buildah manually
  • Install the packages for newuidmap and newgidmap.

  • Make sure that newuidmap and newgidmap have the proper permissions:

    sudo setcap cap_setuid+ep /usr/bin/newuidmap
    sudo setcap cap_setgid+ep /usr/bin/newgidmap
    sudo chmod u-s,g-s /usr/bin/newuidmap /usr/bin/newgidmap
    
  • Install the package that provides the /etc/subuid and /etc/subgid files.

  • Make sure that the /etc/subuid and /etc/subgid files have a line similar to gitlab-runner:1000000:65536, where

    • gitlab-runner — name of the GitLab Runner user;

    • 1000000 — the first subUID/subGID in the range to be allocated;

    • 65536 — subUIDs/subGIDs range size (min 65536).

    Make sure there are no conflicts with other ranges, if any. Changing files may require a reboot. See man subuid and man subgid for details.

  • (Linux 5.12 and below) Install the package that provides the fuse-overlayfs utility.

  • Make sure that the /home/gitlab-runner/.local/share/containers path is created and the gitlab-runner user has read and write access.

  • The sysctl -ne kernel.unprivileged_userns_clone command should NOT return 0, otherwise run echo 'kernel.unprivileged_userns_clone = 1' | sudo tee -a /etc/sysctl.conf && sudo sysctl -p.

  • The sysctl -n user.max_user_namespaces command should return 15000 or more, otherwise run echo 'user.max_user_namespaces = 15000' | sudo tee -a /etc/sysctl.conf && sudo sysctl -p.

Installing werf

To install werf on the GitLab Runner host, run the following command:

curl -sSL https://werf.io/install.sh | bash -s -- --ci

Registering the GitLab Runner

Follow official instructions to register GitLab Runner in GitLab: set Shell as the executor. Once the registration is complete, you may want to perform additional GitLab Runner configuration.

Configuring the container registry

Enable garbage collection for your container registry.

Preparing the system for cross-platform building (optional)

This step only needed to build images for platforms other than host platform running werf.

Register emulators on your system using qemu-user-static:

docker run --restart=always --name=qemu-user-static -d --privileged --entrypoint=/bin/sh multiarch/qemu-user-static -c "/register --reset -p yes && tail -f /dev/null"

Configure the project

Configuring the GitLab project

  • Create and save the access token to clean up the no longer needed images from the container registry with the following parameters:

    • Token name: werf-images-cleanup;

    • Role: developer;

    • Scopes: api.

  • Add the following variables to the project variables:

    • Access token to clean up the no longer needed images:
      • Key: WERF_IMAGES_CLEANUP_PASSWORD;

      • Value: <"werf-images-cleanup" access token you saved earlier>;

      • Protect variable: yes;

      • Mask variable: yes.

  • Add a scheduled nightly task to clean up the no longer needed images in the container registry by setting the main/master branch as the Target branch.

Configuring CI/CD of the project

This is how the repository that uses werf for build and deploy might look:

.helm
app
.gitlab-ci.yml
werf.yaml
stages:
  - prod
  - cleanup

variables:
  WERF_BUILDAH_MODE: auto

default:
  before_script:
    - source "$(~/bin/trdl use werf 2 stable)"
    - source "$(werf ci-env gitlab --as-file)"
  tags: ["<GitLab Runner tag>"]

prod:
  stage: prod
  script:
    - werf converge
  environment:
    name: prod
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_PIPELINE_SOURCE != "schedule"
      when: manual

images:cleanup:
  stage: cleanup
  script:
    - werf cr login -u nobody -p "${WERF_IMAGES_CLEANUP_PASSWORD:?}" "${WERF_REPO:?}"
    - werf cleanup
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_PIPELINE_SOURCE == "schedule"

apiVersion: apps/v1
kind: Deployment
metadata:
  name: app
spec:
  selector:
    matchLabels:
      app: app
  template:
    metadata:
      labels:
        app: app
    spec:
      containers:
      - name: app
        image: {{ .Values.werf.image.app }}

apiVersion: v1
kind: Service
metadata:
  name: app
spec:
  selector:
    app: app
  ports:
  - name: app
    port: 80

FROM node

WORKDIR /app
COPY . .
RUN npm ci

CMD ["node", "server.js"]

{
  "name": "app",
  "version": "1.0.0",
  "lockfileVersion": 2,
  "requires": true,
  "packages": {
    "": {
      "name": "app",
      "version": "1.0.0"
    }
  }
}

{
  "name": "app",
  "version": "1.0.0",
  "main": "server.js",
  "scripts": {
    "start": "node server.js"
  }
}

const http = require('http');

const hostname = '127.0.0.1';
const port = 80;

const server = http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');
  res.end('Hello World');
});

server.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});

configVersion: 1
project: myproject
---
image: app
dockerfile: Dockerfile
context: ./app

Extras:

  • Add authorization options for werf cleanup in the container registry by following instructions.