Build & CI Infrastructure
The CI/CD workflow
.github/workflows/test-and-deploy.yml,
- pulls the Docker image that defines the CI execution environment,
- imports pinned CI dependencies through the reusable
pinsworkflow job, - invokes the shared Docker build scripts within that environment, and
- executes its job steps inside a container instantiated from that image.
Docker Image
A Docker image is build from Dockerfile.
# Build a docker image from the Dockerfile in the current directory
# and tag the resulting image as <image-name>:<image-tag>
docker build \
-t <image-name>:<image-tag> .
# Push the tagged image to the configured container registry.
# The image name must include the registry prefix unless Docker Hub is implied.
docker push <image-name>:<image-tag>Publishing Docker Images to a Registry
To make a Docker image pullable by CI/CD, it must be published to a container registry. Docker Desktop’s My Hub is only a UI for your Docker Hub account, and it does not authenticate you to any other registry — each registry requires its own explicit
docker login. Images without a registry prefix (e.g.,myapp:1.0) are pushed to Docker Hub.Recommended image naming scheme
To ensure consistent builds and predictable CI behavior,
- use fully qualified image names with the following structure:
<image-name> = <registry>/<org-or-user>/<repo>-ciwhere:
<registry>is the container registry host, for example,
docker.io(default Docker Hub Registry),ghcr.io(GitHub Container Registry),registry.gitlab.com(GitLab Container Registry),<aws-account>.dkr.ecr.<region>.amazonaws.com(Amazon ECR),<region>-docker.pkg.dev(Google Artifact Registry),registry.example.com(Private/self‑hosted registries),<org-or-user>is the GitHub namespace,<repo>-ciis the repository name with a-cisuffix to distinguish CI images from runtime images.- decide whether the CI image uses a hardened base. The tag naming should reflect that choice:
<image-tag> = <project-version>-<base>-<revision>(non-hardened base)<image-tag> = <project-version>-hardened-<base>-<revision>(hardened base) examples:0.1.0-debian13-3,0.1.0-hardened-debian13-3
Example Image:
rdned/nbdev_fhemb-ci:0.1.0-hardened-debian13-3
where docker.io is implicit, i.e., this Docker image is published to Docker Hub.
Hardened base image reference
The current CI image uses Docker Hardened Images Python Debian 13 dev base. To verify the exact base metadata locally, run:
docker pull dhi.io/python:3.11-debian13-dev docker image inspect dhi.io/python:3.11-debian13-dev --format '{{index .Config.Labels "com.docker.dhi.definition"}} {{index .Config.Labels "com.docker.dhi.variant"}} {{index .Config.Labels "com.docker.dhi.version"}}'Expected definition pattern:
image/python/debian-13/3.11-dev.
Images for other than Docker Hub registries must use fully qualified names and require explicit authentication, for example:
echo "$GHCR_PAT" | docker login ghcr.io -u <github-username> --password-stdinCI dependency pins
External CI dependencies are pinned explicitly in .github/workflows/reusable-pins.yml:
FHEMB_TAG — version/tag of the external
fhembwheel. It is equal tov<fhemb_version>.CI_UTILS_COMMIT — pinned commit of external CI helper scripts.
NBDEV_FHEMB_IMAGE — pinned Docker image tag used to run CI build/test jobs. It coincides with the
<image-tag>.
To bump external dependencies, update only .github/workflows/reusable-pins.yml and open a PR.
Docker build scripts
All Docker-related scripts now live under the docker/ directory:
docker/
ci-prepare.sh
configure-ssh.sh
install-fhemb.sh
setup-env.sh
test-and-build.sh
The Dockerfile expects these paths, so keep all build scripts inside this directory.
Any modification of the
Dockerfileor any of the docker build scripts requires rebuilding docker image and publishing it.