# Upstream repo We use the [official Zabbix Docker GitHub repo](https://github.com/zabbix/zabbix-docker) for Docker Compose deployment, we add a few local changes. Create dir ``` mkdir -p '/opt/git/github.com/zabbix/zabbix-docker/branches/latest' ``` Pull repo ``` git -C '/opt/git/github.com/zabbix/zabbix-docker/branches/latest' clone 'https://github.com/zabbix/zabbix-docker' . ``` # Docker Compose ## Base setup When everything's ready start Zabbix with Docker Compose, otherwise head down to [Initial setup](#initial-setup) or [Upgrade an existing repo](#upgrade-an-existing-repo) first. Define variables assuming the official Zabbix Docker repo lives at `/opt/git/github.com/zabbix/zabbix-docker/branches/latest`: ``` export UPSTREAM_REPO_DIR='/opt/git/github.com/zabbix/zabbix-docker/branches/latest' export UPSTREAM_REPO_TAG='6.4.4' export UPSTREAM_COMPOSE_FILE="${UPSTREAM_REPO_DIR%/}"'/docker-compose_v3_alpine_pgsql_latest.yaml' export COMPOSE_CTX='bi_colombo' export COMPOSE_PROJECT_NAME='zabbixserver-'"${COMPOSE_CTX}" export COMPOSE_ENV_FILE= ``` ## Context On your deployment machine create the necessary Docker context to connect to and control the Docker daemon on whatever target host you'll be using, for example: ``` docker context create fully.qualified.domain.name --docker 'host=ssh://root@fully.qualified.domain.name' ``` ## Pull Pull newest image versions: ``` docker compose --project-name "${COMPOSE_PROJECT_NAME}" --file "${UPSTREAM_COMPOSE_FILE}" --env-file "${COMPOSE_ENV_FILE}" pull ``` ## Copy to target Copy images to target Docker host, that is assuming you deploy to a machine that itself has no network route to reach Docker Hub. Copying in its simplest form involves a local `docker save` and a remote `docker load`. Consider the helper mini-project [quico.space/Quico/copy-docker](https://quico.space/Quico/copy-docker) where [copy-docker.sh](https://quico.space/Quico/copy-docker/src/branch/main/copy-docker.sh) allows the following workflow: ``` source "${COMPOSE_ENV_FILE}" while IFS= read -r image; do copy-docker.sh "${image}" fully.qualified.domain.name done < <(grep -Pi -- '^[^#]*image:' "${UPSTREAM_COMPOSE_FILE}" | awk '{print $2}') ``` This first `grep`s a list of images and their tags from Zabbix' official Docker Compose file: ``` # grep -Pi -- '^[^#]*image:' "${UPSTREAM_COMPOSE_FILE}" | awk '{print $2}' zabbix/zabbix-server-pgsql:alpine-6.4-latest zabbix/zabbix-web-nginx-pgsql:alpine-6.4-latest postgres:14-alpine busybox ``` It then pushes each image to your remote host where the image is needed. Note that `busybox` implies `busybox:latest` by convention. ## Start Run Zabbix like so ``` docker --context 'fully.qualified.domain.name' compose --project-name "${COMPOSE_PROJECT_NAME}" --file "${UPSTREAM_COMPOSE_FILE}" --env-file "${COMPOSE_ENV_FILE}" up --detach ``` ## Additional files - [common-settings.yml](common-settings.yml) This file will be auto-created as part of the patch. Use it as an example in case patching fails - [env/fqdn_context.env.example](env/fqdn_context.env.example) An example env file with all currently used variables after `docker-compose_v3_alpine_pgsql_latest.yaml` is patched - Directory tree underneath [build-context](build-context) ``` build-context/ └── docker-data ├── postgres │   └── config │   ├── cert │   │   ├── ZBX_PGSQL_TLS_CA_CERT_FILE │   │   ├── ZBX_PGSQL_TLS_CERT_FILE │   │   └── ZBX_PGSQL_TLS_KEY_FILE │   └── docker-entrypoint-initdb.d │   └── init-user-db.sh ├── zabbixserver │   └── config │   └── cert │   ├── ZBX_SERVER_TLS_CA_CERT_FILE │   ├── ZBX_SERVER_TLS_CERT_FILE │   └── ZBX_SERVER_TLS_KEY_FILE └── zabbixwebnginx └── config └── cert ├── dhparam.pem ├── ZBX_WEBNGINX_TLS_CERT_FULLCHAIN_FILE └── ZBX_WEBNGINX_TLS_KEY_FILE ``` Example data you're going to want to physically place on your deployment machine. SSL certs and keys are blank files each of which has the exact same name used in env file `fqdn_context.env.example`. In [postgres/config/docker-entrypoint-initdb.d](build-context/docker-data/postgres/config/docker-entrypoint-initdb.d) a PostgreSQL initialization script - when this container is run on a completely empty data directory - will create an additional read-only user `ZBX_DB_USERNAME_RO` with password `ZBX_DB_USERNAME_PW`. The example's intended to grant a Grafana daemon direct PostgreSQL database read access. # Upgrade an existing repo Check [Initial setup](#initial-setup) below for first time steps. On consecutive upgrades proceed as follows. ## Revert unpushed local changes Return repo state to exactly the upstream repo's original branch state throwing away the commits you added. ``` git -C '/opt/git/github.com/zabbix/zabbix-docker/branches/latest' reset --hard origin ``` Switch to `trunk` branch, get newest commits from upstream ``` git -C '/opt/git/github.com/zabbix/zabbix-docker/branches/latest' checkout trunk git -C '/opt/git/github.com/zabbix/zabbix-docker/branches/latest' pull ``` Pick and checkout new tag ``` pushd '/opt/git/github.com/zabbix/zabbix-docker/branches/latest' while IFS= read -r; do commitDate=$(grep -Pio '^.+?(?=[[:space:]])' <<< "${REPLY}"); commitDate=$(date --date='@'"${commitDate}" +%F-%H%M%S); tagRef="$(cut -d $'\t' -f2 <<< "${REPLY}")"; tagName="$(grep -Pio '(?<=refs/tags/)[^\r\n\f]+' <<<"${tagRef}")"; commitHash="$(git rev-list -n 1 "${tagRef}")"; echo "${commitDate} ${commitHash} ${tagName}"; done < <(git for-each-ref --sort=v:refname --format='%(*creatordate:raw)%00%(creatordate:raw)%00%(refname)' refs/tags | awk -F"\0" 'BEGIN {ORS=""} $1 == "" {print $2} $1 != "" {print $1} {print "\t"$3"\n"}') # Output goes like: ... 2023-03-07-191829 9f2e726e554b23595489eb66c8e11e5d114b573f 6.4.0 2023-04-03-105513 9f16f6d773a2a46f1595c86077899d1e040db283 6.4.1 2023-04-25-133446 0fa87156974e799e04bf99e5300bad6830d754ab 6.4.2 2023-05-30-151931 d7b0eab80723a2c562a13ee866c4cd384af96d3b 6.4.3 2023-06-27-133008 482e21c7803c2878e522aba0325bf04533efa61a 6.4.4 ... git -C '/opt/git/github.com/zabbix/zabbix-docker/branches/latest' checkout 'tags/x.y.z' ``` Lastly [apply patch](#apply-patch). If patch does not apply cleanly read on in the next section [Create new patch](#create-new-patch) to find out how to fix your patch. # Create new patch ## Add your changes as commits Get `zabbix-docker` repo into a state with which you're happy then ``` git -C '/opt/git/github.com/zabbix/zabbix-docker/branches/latest' format-patch 7665739620ba6d99090838d502ab76d2f5a47e96^..a17380598ca66153ddc2a42eb618d906d4f582e6 --stdout > '/opt/containers/zabbixserver/zabbix-docker.patch' ``` Where the first commit hash is our first commit and the other commit hash is our last commit. Note the caret (`^`) right after the first commit hash. ## Investigation You may have to try and find out how a known good base commit differs from a newer one in case the newer one does no longer cleanly accept the patch. Get commit hashes from both affected tags, e.g. ``` pushd '/opt/git/github.com/zabbix/zabbix-docker/branches/latest' while IFS= read -r; do commitDate=$(grep -Pio '^.+?(?=[[:space:]])' <<< "${REPLY}"); commitDate=$(date --date='@'"${commitDate}" +%F-%H%M%S); tagRef="$(cut -d $'\t' -f2 <<< "${REPLY}")"; tagName="$(grep -Pio '(?<=refs/tags/)[^\r\n\f]+' <<<"${tagRef}")"; commitHash="$(git rev-list -n 1 "${tagRef}")"; echo "${commitDate} ${commitHash} ${tagName}"; done < <(git for-each-ref --sort=v:refname --format='%(*creatordate:raw)%00%(creatordate:raw)%00%(refname)' refs/tags | awk -F"\0" 'BEGIN {ORS=""} $1 == "" {print $2} $1 != "" {print $1} {print "\t"$3"\n"}') # Output goes like: ... 2023-03-07-191829 9f2e726e554b23595489eb66c8e11e5d114b573f 6.4.0 2023-04-03-105513 9f16f6d773a2a46f1595c86077899d1e040db283 6.4.1 2023-04-25-133446 0fa87156974e799e04bf99e5300bad6830d754ab 6.4.2 2023-05-30-151931 d7b0eab80723a2c562a13ee866c4cd384af96d3b 6.4.3 2023-06-27-133008 482e21c7803c2878e522aba0325bf04533efa61a 6.4.4 ... ``` Diff them ``` git -C '/opt/git/github.com/zabbix/zabbix-docker/branches/latest' diff d7b0eab80723a2c562a13ee866c4cd384af96d3b 482e21c7803c2878e522aba0325bf04533efa61a 'docker-compose_v3_alpine_pgsql_latest.yaml' ``` Output will be empty in case no difference exists in `docker-compose_v3_alpine_pgsql_latest.yaml` between both commit hashes. Commit your updated patch file into _this_ repo. With a new working patch in hand head back up to [Upgrade an existing repo](#upgrade-an-existing-repo). # Initial setup ## Prep Get desired tag e.g. from version-sorted tags list ``` pushd '/opt/git/github.com/zabbix/zabbix-docker/branches/latest' while IFS= read -r; do commitDate=$(grep -Pio '^.+?(?=[[:space:]])' <<< "${REPLY}"); commitDate=$(date --date='@'"${commitDate}" +%F-%H%M%S); tagRef="$(cut -d $'\t' -f2 <<< "${REPLY}")"; tagName="$(grep -Pio '(?<=refs/tags/)[^\r\n\f]+' <<<"${tagRef}")"; commitHash="$(git rev-list -n 1 "${tagRef}")"; echo "${commitDate} ${commitHash} ${tagName}"; done < <(git for-each-ref --sort=v:refname --format='%(*creatordate:raw)%00%(creatordate:raw)%00%(refname)' refs/tags | awk -F"\0" 'BEGIN {ORS=""} $1 == "" {print $2} $1 != "" {print $1} {print "\t"$3"\n"}') # Output goes like: ... 2023-03-07-191829 9f2e726e554b23595489eb66c8e11e5d114b573f 6.4.0 2023-04-03-105513 9f16f6d773a2a46f1595c86077899d1e040db283 6.4.1 2023-04-25-133446 0fa87156974e799e04bf99e5300bad6830d754ab 6.4.2 2023-05-30-151931 d7b0eab80723a2c562a13ee866c4cd384af96d3b 6.4.3 2023-06-27-133008 482e21c7803c2878e522aba0325bf04533efa61a 6.4.4 ... ``` Switch to desired tag ``` git -C '/opt/git/github.com/zabbix/zabbix-docker/branches/latest' checkout 'tags/6.4.4' ``` ## Apply patch Identify yourself to the local `zabbix-docker` repo. Obviously substitute your own name. An e-mail address is optional here. You don't want to contribute upstream, you just want to locally apply a patch file. ``` git -C '/opt/git/github.com/zabbix/zabbix-docker/branches/latest' config user.name "hygienic-books" git -C '/opt/git/github.com/zabbix/zabbix-docker/branches/latest' config user.email "" ``` Apply `zabbix-docker.patch` to Docker Compose file. We use Zabbix' `docker-compose_v3_alpine_pgsql_latest.yaml` Compose file. Assuming this repo lives at `/opt/containers/zabbixserver`: ``` git -C '/opt/git/github.com/zabbix/zabbix-docker/branches/latest' am '/opt/containers/zabbixserver/zabbix-docker.patch' # Output will be: Applying: refactor(compose): Remove trailing whitespace Applying: refactor(compose): 4 leading spaces Applying: refactor(compose): Indent comments Applying: refactor(zabbix-server): Set correct libs paths Applying: refactor(zabbix-server): Set TLS cert file names Applying: feat(zabbix-server): Replace env files with variables ... ``` And now back up to [Docker Compose](#docker-compose).