opsi Docker Compose files

Docker Compose files to spin up an instance of opsi open source device management system. This specifically launches a so-called opsi Config Server. In opsi lingo Config Server is the central hub that includes among other components an opsi Depot Server. See also opsi 4.3 English docs section "opsi Server" for reference.

How to run

Add a COMPOSE_ENV file and save its location as a shell variable along with the location where this repo lives, here for example /opt/containers/opsi plus all other variables. At env/fqdn_context.env.example you'll find an example environment file.

When everything's ready start opsi with Docker Compose, otherwise head down to Initial setup first.

Environment

Make sure the upstream github.com/opsi-org/opsi-docker repository is checked out locally. We're going with example dir /opt/git/github.com/opsi-org/opsi-docker/branch/main. We're also assuming that this repo exists at /opt/containers/opsi.

export UPSTREAM_REPO_DIR='/opt/git/github.com/opsi-org/opsi-docker/branch/main'
export UPSTREAM_COMPOSE_FILE="${UPSTREAM_REPO_DIR%/}"'/opsi-server/docker-compose.yml'
export UPSTREAM_ENV_FILE="${UPSTREAM_REPO_DIR%/}"'/opsi-server/opsi-server.env'
export CONTEXT='ux_vilnius'
export COMPOSE_PROJECT_NAME='opsi-'"${CONTEXT}"
export COMPOSE_ENV=<add accordingly>
export COMPOSE_OVERRIDE='/opt/containers/opsi/compose.override.yaml'

In opsi's Git repo check out newest commit:

git -C "${UPSTREAM_REPO_DIR:?}" reset --hard origin/main
git -C "${UPSTREAM_REPO_DIR:?}" checkout main
git -C "${UPSTREAM_REPO_DIR:?}" pull

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 images from Docker Hub verbatim.

docker compose \
    --project-name "${COMPOSE_PROJECT_NAME}" \
    --file "${UPSTREAM_COMPOSE_FILE}" \
    --file "${COMPOSE_OVERRIDE}" \
    --env-file "${UPSTREAM_ENV_FILE}" \
    --env-file "${COMPOSE_ENV}" \
    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 or your private registry of choice. 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 where copy-docker.sh allows the following workflow:

images="$(docker compose --project-name "${COMPOSE_PROJECT_NAME}" --file "${UPSTREAM_COMPOSE_FILE}" --file "${COMPOSE_OVERRIDE}" --env-file "${UPSTREAM_ENV_FILE}" --env-file "${COMPOSE_ENV}" config | grep -Pi -- 'image:' | awk '{print $2}' | sort | uniq)"
while IFS= read -u 10 -r image; do
    copy-docker "${image}" fully.qualified.domain.name
done 10<<<"${images}"

This will for example copy over:

# docker image ls -a

REPOSITORY                 TAG       IMAGE ID       CREATED        SIZE
grafana/grafana            latest    0a7de979b313   2 weeks ago    723MB
redis/redis-stack-server   latest    1ebedd176a23   7 weeks ago    513MB
uibmz/opsi-server          4.3       f07683f1828b   2 months ago   996MB
mariadb                    10.7      895b6c8829c3   2 years ago    396MB

Start

docker \
    --context 'fully.qualified.domain.name' \
    compose \
    --project-name "${COMPOSE_PROJECT_NAME}" \
    --file "${UPSTREAM_COMPOSE_FILE}" \
    --file "${COMPOSE_OVERRIDE}" \
    --env-file "${UPSTREAM_ENV_FILE}" \
    --env-file "${COMPOSE_ENV}" \
    up --detach

Clean up

docker --context 'fully.qualified.domain.name' system prune -af
docker system prune -af

Initial setup

We're assuming you run Docker Compose workloads with ZFS-based bind mounts. ZFS management, creating a zpool and setting adequate properties for its datasets is out of scope of this document.

Datasets

Create ZFS datasets and set permissions as needed.

  • Parent dateset

    export "$(grep -Pi -- '^CONTEXT=' "${COMPOSE_ENV}" | xargs --max-lines 1)"
    zfs create -o canmount=off zpool/data/opt
    zfs create -o mountpoint=/opt/docker-data zpool/data/opt/docker-data
    
  • Container-specific datasets

    zfs create -p 'zpool/data/opt/docker-data/opsi-'"${CONTEXT}"'/grafana/data'
    zfs create -p 'zpool/data/opt/docker-data/opsi-'"${CONTEXT}"'/mysql/data'
    zfs create -p 'zpool/data/opt/docker-data/opsi-'"${CONTEXT}"'/opsi/data'
    zfs create -p 'zpool/data/opt/docker-data/opsi-'"${CONTEXT}"'/redis/data'
    

    All four opsi components, that it Grafana, MySQL, opsi and Redis have one subdirectory for their data volume. None of them require a config volume or other mounts.

  • Create subdirs

    mkdir -p '/opt/docker-data/opsi-'"${CONTEXT}"'/opsi/'{'.ssh','config','data','projects'}
    
  • Change ownership

    chown -R 472:472 'zpool/data/opt/docker-data/opsi-'"${CONTEXT}"'/grafana/data'
    

    Here you'll want to accommodate the Grafana container. Per its upstream Dockerfile retrieved from Dockerfile in the github.com/grafana/grafana repository in August 2025 all Grafana images that end up at Docker Hub are built with the directive:

    USER "$GF_UID"
    

    Where "$GF_UID" is populated with ARG GF_UID="472".

Additional files

With preparations out of the way opsi does not require any additional files present on your Docker host's filesystem, as bind mounts or via other means.

Head back up to How to run.

Development

Conventional commits

This project uses Conventional Commits for its commit messages.

Commit types

Commit types besides fix and feat are:

  • refactor: Keeping functionality while streamlining or otherwise improving function flow
  • docs: Documentation for project or components

Commit scopes

The following scopes are known for this project. A Conventional Commits commit message may optionally use one of the following scopes or none:

  • mysql: A change to how the mysql service component works
  • redis: A change to how the redis service component works
  • grafana: A change to how the grafana service component works
  • opsi_server: A change to how the opsi_server service component works
  • build: Build-related changes such as Dockerfile fixes and features.
  • mount: Volume or bind mount-related changes.
  • net: Networking, IP addressing, routing changes
  • meta: Affects the project's repo layout, file names etc.
Description
Docker Compose setup of an opsi software distribution and management system instance
Readme MIT 31 KiB