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.
Setting up the build environment with 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:
-
Install the packages for
newuidmap
andnewgidmap
. -
Make sure that
newuidmap
andnewgidmap
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 togitlab-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 (min65536
).
Make sure there are no conflicts with other ranges, if any. Changing files may require a reboot. See
man subuid
andman 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 thegitlab-runner
user has read and write access. -
The
sysctl -ne kernel.unprivileged_userns_clone
command should NOT return0
, otherwise runecho 'kernel.unprivileged_userns_clone = 1' | sudo tee -a /etc/sysctl.conf && sudo sysctl -p
. -
The
sysctl -n user.max_user_namespaces
command should return15000
or more, otherwise runecho 'user.max_user_namespaces = 15000' | sudo tee -a /etc/sysctl.conf && sudo sysctl -p
. -
(For Ubuntu 23.10 and later) set values
kernel.apparmor_restrict_unprivileged_unconfined
andkernel.apparmor_restrict_unprivileged_userns
to0
with the command:{ echo "kernel.apparmor_restrict_unprivileged_userns = 0" && echo "kernel.apparmor_restrict_unprivileged_unconfined = 0";} | sudo tee -a /etc/sysctl.d/20-apparmor-donotrestrict.conf && sudo sysctl -p /etc/sysctl.d/20-apparmor-donotrestrict.conf
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"
Installing Argo CD Image Updater
Install Argo CD Image Updater with the “continuous deployment of OCI Helm chart type application” patch:
kubectl apply -n argocd -f https://raw.githubusercontent.com/werf/3p-argocd-image-updater/master/manifests/install.yaml
Configure the project
Configuring Argo CD Application
- Apply the following Application CRD to the target cluster to deploy a bundle from the container registry:
kubectl create -f - <<EOF
---
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
annotations:
argocd-image-updater.argoproj.io/chart-version: ~ 1.0
argocd-image-updater.argoproj.io/pull-secret: pullsecret:myproject-production/myproject-regcred
name: myproject
namespace: argocd
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
destination:
namespace: myproject-production
server: https://kubernetes.default.svc
project: default
source:
chart: myproject
repoURL: registry.mycompany.org/myproject
targetRevision: 1.0.0
syncPolicy:
automated:
prune: true
selfHeal: true
EOF
The value of argocd-image-updater.argoproj.io/chart-version="~ 1.0"
means that the operator must automatically deploy the chart updated to the latest patch version in the SEMVER
range 1.0.*
.
- Create a pull secret to access the project container registry:
kubectl create -f - <<EOF
---
apiVersion: v1
kind: Secret
metadata:
name: myproject-regcred
namespace: myproject-production
type: kubernetes.io/dockerconfigjson
data:
.dockerconfigjson: BASE64_DOCKER_CONFIG_JSON
EOF
Configuring the GitLab project
-
Create and save the access token for cleaning up the no longer needed images in the container registry; use 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 and set the
main
/master
branch as the Target branch.
Configuring CI/CD of the project
This is what the repository that uses werf for building and deploying might look like:
stages:
- release
- 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>"]
Build and publish release:
stage: release
script:
- werf bundle publish --tag "1.0.${CI_PIPELINE_ID}"
only:
- main
except:
- schedules
Cleanup registry:
stage: cleanup
script:
- werf cr login $WERF_REPO
- werf cleanup
only:
- schedules
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 the instructions.