Skip to content
⭐ If you like Dalec, please give it a star on GitHub!
Targets

Targets

DALEC is designed to support building artifacts for a number of different systems. DALEC refers to these in the spec as “targets”. When executing a build with Docker these targets can be specified with the --target=<target> flag.

Available Targets

DALEC includes a number of built-in targets that you can either use in your spec.

  • azlinux3 - Azure Linux 3
  • azlinux4 - Azure Linux 4 (beta status)
  • bullseye - Debian 11 (Bullseye) (v0.11)
  • bookworm - Debian 12 (Bookworm) (v0.11)
  • trixie - Debian 13 (Trixie) (v0.next)
  • bionic - Ubuntu 18.04 (Bionic) (v0.11)
  • focal - Ubuntu 20.04 (focal) (v0.11)
  • jammy - Ubuntu 22.04 (jammy) (v0.9)
  • noble - Ubuntu 24.04 (noble) (v0.11)
  • windowscross - Cross compile from Ubuntu Jammy to Windows
  • almalinux9 - AlmaLinux 9 (v0.13)
  • almalinux8 - AlmaLinux 8 (v0.13)
  • rockylinux8 - Rocky Linux 8 (v0.13)
  • rockylinux9 - Rocky Linux 9 (v0.13)

When specifying a “target” to docker build --target=<target> DALEC treats <target> as a route (much like an HTTP path) and each of the above mentioned targets have subroutes you can specify as well, e.g. jammy/deb to have DALEC build and output just the deb package. What subroutes are available depend on the underlying target implementation.

To print a list of available build targets:

docker buildx build --call targets --build-arg BUILDKIT_SYNTAX=ghcr.io/project-dalec/dalec/frontend:latest - <<< "null"
DALEC targets list output
TARGET                           DESCRIPTION
almalinux8/container (default)   Builds a container image for AlmaLinux 8
almalinux8/container/depsonly    Builds a container image with only the runtime dependencies installed.
almalinux8/rpm                   Builds an rpm and src.rpm.
almalinux8/rpm/debug/buildroot   Outputs an rpm buildroot suitable for passing to rpmbuild.
almalinux8/rpm/debug/sources     Outputs all the sources specified in the spec file in the format given to rpmbuild.
almalinux8/rpm/debug/spec        Outputs the generated RPM spec file
almalinux8/worker                Builds the base worker image responsible for building the rpm
almalinux9/container (default)   Builds a container image for AlmaLinux 9
almalinux9/container/depsonly    Builds a container image with only the runtime dependencies installed.
almalinux9/rpm                   Builds an rpm and src.rpm.
almalinux9/rpm/debug/buildroot   Outputs an rpm buildroot suitable for passing to rpmbuild.
almalinux9/rpm/debug/sources     Outputs all the sources specified in the spec file in the format given to rpmbuild.
almalinux9/rpm/debug/spec        Outputs the generated RPM spec file
almalinux9/worker                Builds the base worker image responsible for building the rpm
azlinux3/container (default)     Builds a container image for Azure Linux 3
azlinux3/container/depsonly      Builds a container image with only the runtime dependencies installed.
azlinux3/rpm                     Builds an rpm and src.rpm.
azlinux3/rpm/debug/buildroot     Outputs an rpm buildroot suitable for passing to rpmbuild.
azlinux3/rpm/debug/sources       Outputs all the sources specified in the spec file in the format given to rpmbuild.
azlinux3/rpm/debug/spec          Outputs the generated RPM spec file
azlinux3/testing/sysext          Builds a systemd system extension image.
azlinux3/worker                  Builds the base worker image responsible for building the rpm
azlinux4/container (default)     Builds a container image for Azure Linux 4
azlinux4/container/depsonly      Builds a container image with only the runtime dependencies installed.
azlinux4/rpm                     Builds an rpm and src.rpm.
azlinux4/rpm/debug/buildroot     Outputs an rpm buildroot suitable for passing to rpmbuild.
azlinux4/rpm/debug/sources       Outputs all the sources specified in the spec file in the format given to rpmbuild.
azlinux4/rpm/debug/spec          Outputs the generated RPM spec file
azlinux4/testing/sysext          Builds a systemd system extension image.
azlinux4/worker                  Builds the base worker image responsible for building the rpm
bionic/container                 Builds a container image.
bionic/deb (default)             Builds a deb package.
bionic/dsc                       Builds a Debian source package.
bionic/testing/container         Builds a container image for testing purposes only.
bionic/worker                    Builds the worker image.
bookworm/container               Builds a container image.
bookworm/deb (default)           Builds a deb package.
bookworm/dsc                     Builds a Debian source package.
bookworm/testing/container       Builds a container image for testing purposes only.
bookworm/worker                  Builds the worker image.
bullseye/container               Builds a container image.
bullseye/deb (default)           Builds a deb package.
bullseye/dsc                     Builds a Debian source package.
bullseye/testing/container       Builds a container image for testing purposes only.
bullseye/worker                  Builds the worker image.
debug/cargohome                  Outputs all the Cargo dependencies for the spec
debug/gomods                     Outputs all the gomodule dependencies for the spec
debug/patched-sources            Outputs all patched sources from a dalec spec file.
debug/pip                        Outputs all the pip dependencies for the spec
debug/resolve                    Outputs the resolved dalec spec file with build args applied.
debug/sources                    Outputs all sources from a dalec spec file.
flatcar/testing/sysext (default) Build a Flatcar-compatible systemd sysext (.raw)
flatcar/worker                   Builds the worker image used to assemble Flatcar sysext images.
focal/container                  Builds a container image.
focal/deb (default)              Builds a deb package.
focal/dsc                        Builds a Debian source package.
focal/testing/container          Builds a container image for testing purposes only.
focal/worker                     Builds the worker image.
jammy/container                  Builds a container image.
jammy/deb (default)              Builds a deb package.
jammy/dsc                        Builds a Debian source package.
jammy/testing/container          Builds a container image for testing purposes only.
jammy/worker                     Builds the worker image.
noble/container                  Builds a container image.
noble/deb (default)              Builds a deb package.
noble/dsc                        Builds a Debian source package.
noble/testing/container          Builds a container image for testing purposes only.
noble/testing/sysext             Builds a systemd system extension image.
noble/worker                     Builds the worker image.
resolute/container               Builds a container image.
resolute/deb (default)           Builds a deb package.
resolute/dsc                     Builds a Debian source package.
resolute/testing/container       Builds a container image for testing purposes only.
resolute/testing/sysext          Builds a systemd system extension image.
resolute/worker                  Builds the worker image.
rockylinux8/container (default)  Builds a container image for RockyLinux 8
rockylinux8/container/depsonly   Builds a container image with only the runtime dependencies installed.
rockylinux8/rpm                  Builds an rpm and src.rpm.
rockylinux8/rpm/debug/buildroot  Outputs an rpm buildroot suitable for passing to rpmbuild.
rockylinux8/rpm/debug/sources    Outputs all the sources specified in the spec file in the format given to rpmbuild.
rockylinux8/rpm/debug/spec       Outputs the generated RPM spec file
rockylinux8/worker               Builds the base worker image responsible for building the rpm
rockylinux9/container (default)  Builds a container image for RockyLinux 9
rockylinux9/container/depsonly   Builds a container image with only the runtime dependencies installed.
rockylinux9/rpm                  Builds an rpm and src.rpm.
rockylinux9/rpm/debug/buildroot  Outputs an rpm buildroot suitable for passing to rpmbuild.
rockylinux9/rpm/debug/sources    Outputs all the sources specified in the spec file in the format given to rpmbuild.
rockylinux9/rpm/debug/spec       Outputs the generated RPM spec file
rockylinux9/worker               Builds the base worker image responsible for building the rpm
trixie/container                 Builds a container image.
trixie/deb (default)             Builds a deb package.
trixie/dsc                       Builds a Debian source package.
trixie/testing/container         Builds a container image for testing purposes only.
trixie/testing/sysext            Builds a systemd system extension image.
trixie/worker                    Builds the worker image.
windowscross/container (default) Builds binaries and installs them into a Windows base image
windowscross/worker              Builds the base worker image responsible for building the package
windowscross/zip                 Builds binaries combined into a zip file
The above command is passing in a “null” value as the build spec and telling buildkit to use the latest dalec version. This output can change depending on version or spec you provide.

To check the targets available for a specific spec you can just add --call targets to your normal docker build command:

docker buildx build --call targets -f ./path/to/spec .

If the --target=<val> flag is set, the list of targets will be filtered based on <val>.

Likewise if the spec file contains items in the targets section then the list of available targets will be filtered to just the targets in the spec.

Dependencies

Many components, such as package dependencies and base images, are specific to a distro or a subset of distros. The dalec spec allows you to move these distro specific things into a target.

Instead of specifying a package dependency at the root of the spec, you can specify it under a target. This allows you to include different packages for different targets.

Please note that dependencies under a target will override dependencies at the root level.
targets:
  azlinux3:
    dependencies:
      build:
        - golang

Extensibility

Dalec can’t feasibly support every Linux distribution. Instead, it gives you the flexibility to specify a custom builder image for any target, directing the build process to that specified image.

This method allows for the use of a single spec file for all targets, employing one #syntax= directive to build the package for any specified target. It also permits the replacement of the default targets with custom builder configurations.

targets:
  azlinux3:
    frontend:
      image: docker.io/my/custom:azlinux3

Advanced Customization

Worker images

In some cases you may need to have additional things installed in the worker image that are not typically available in the base image. As an example, a package dependency may not be available in the default package repositories.

You can have Dalec output an image with the target’s worker image with <target>/worker> build target, e.g. --target=azlinux3/worker. You can then add any customizations and feed that back in via source policies or named build contexts.

Source Policies

docker buildx build has experimental support for providing a source policy which updates the base image ref used to create the worker image. This method will update any and all references to the matched image used for any part of the build. It also requires knowing the image(s) that are used ahead of time and creating the right set of match rules and potentially having to update this in the future if the worker image refs in Dalec change.

A finer grained approach is to use named build contexts.

Named Build Contexts

docker buildx build has a flag called --build-context (doc) which allows you to provide additional build contexts apart from the main build context in the form of <name>=<ref>. See the prior linked documentation for what can go into <ref>.

In the azlinux3 target, Dalec looks for a named context called either

  1. The actual base image used internally for azlinux3 i. --build-context mcr.microsoft.com/azurelinux/base/core:3.0=<new ref>
  2. A build context named dalec-azlinux3-worker i. --build-context dalec-azlinux3-worker=<new ref>

If 1 is provided, then 2 is ignored.

Target Defined Artifacts

There are some situations where you may want to have multiple builds and for those different targets they may require different binaries to exist that are not globally applicable to all of the builds. For example, windowscross may require specific artifacts (binaries, docs, config files, etc.) that are not relevant to azlinux3, and vice versa.

To address this you can define artifacts per target. Target-defined artifacts will override global (spec-defined) artifacts if there is a conflict. However, if a target does not define an artifact, it will inherit artifacts from the global spec.

Here is an example:

targets:
  windowscross:
    artifacts:
      binaries:
        bin/windows-cross.exe:
          subpath: ""
          mode: 0o755
  azlinux3:
    artifacts:
      binaries:
        bin/linux-binary:
          subpath: ""
          permissions: 0o755

For more details on how Artifacts are structured and configured, see the Artifacts documentation.

Target defined package metadata

conflicts, replaces, and provides can be defined at the target level in addition to the global spec level. This allows you to define package metadata that is specific to a target. If a target defines one of these fields, the target value replaces the global value for that field.

targets:
  azlinux3:
    conflicts:
      foo:
      bar:
    replaces:
      foo:
    provides:
      qux:

Special considerations

Windows

When using the windowscross target you will need to make sure that binaries use the .exe extension.

build:
  steps:
    - command: |
        go build -o _output/bin/dalec_example.exe

You can use the built-in TARGETOS build-arg to determine if the build is targeting Windows or not. Alternatively you can use the built-in DALEC_TARGET build-arg to determine the target being built.

build:
  env:
    TARGETOS: ${TARGETOS}
  steps:
    - command: |
        if [ "$TARGETOS" = "windows" ]; then
          go build -o _output/bin/dalec_example.exe
        else
          go build -o _output/bin/dalec_example
        fi
build:
  env:
    DALEC_TARGET: ${DALEC_TARGET}
  steps:
    - command: |
        if [ "$DALEC_TARGET" = "windowscross" ]; then
          go build -o _output/bin/dalec_example.exe
        else
          go build -o _output/bin/dalec_example
        fi

Since windowscross is intended for cross-compilation, the environment has the following env vars set by default:

  • GOOS=windows - ensures that by default go build produces a Windows binary

This can be overridden in your spec by either setting them in the env section or in the actual build step script, which may be necessary if you need to build tooling or other things first.

build:
  env:
    GOOS: linux
  steps:
    - command: |
        go build -o _output/bin/dalec_example
build:
  steps:
    - command: |
        GOOS=linux go build -o _output/bin/dalec_example

Azure Linux 4

The azlinux4 target produces packages and containers for Azure Linux 4. Azure Linux 4 is currently in beta, and not yet supported for production use. Its base image and package repositories will move to new locations when it reaches general availability.

Tips

Overriding default debian rules

Debian-based distros currently use dpkg-buildpackage to produce the deb package. This brings a lot of functionality with it, sometimes perhaps too much. dpkg-buildpackage, under the covers, is driven by a rules at debian/rules. Dalec generates this file for the rules it needs to inject to make the build behave per the dalec spec.

Some of the rules followed by dpkg-buildpackage, most in fact, are implicit and not actually in debian/rules explicitly. You can override some of these rules from within the build, though not all. See the debian rules file docs for details on these rules and how to override them.

Example override from a dalec spec:

build:
  steps:
    - command: |
        # If the debian directory doesn't exist, then there is nothing to do
        [ -d debian ] || exit 0

        # Add a makefile rule to override how dpkg-shlibdeps is executed
        echo "override_dh_shlibdeps:" >> debian/rules
        # Ignore errors from dh_shlibdeps
        echo "	dh_shlibdeps --dpkg-shlibdeps-params=--ignore-missing-info" >> debian/rules

Note that at the point your build steps are run some of the rules have already been applied. This is considered a “break glass” way to work around issues when building on Debian-based distributions. Overriding some rules, such as dh_install, will also interfere with dalec functionality.

In the future dalec may stop using dpkg-buildpackage and these rules would not be applicable anymore.