Dockerfiles/Containerfiles for images used in Ansible execution environments?

Several of the execution-environment.yml examples I’ve seen (e.g. awx-ee or community-ee-base use base images hosted on quay.io (e.g. quay.io/fedora/fedora:latest).

I’ve not been able to actually find/see the source Dockerfile / Containerfile for these images. Are they available?

If not, can somebody please at least roughly describe what’s in them? In view of certain supply chain issues I’d like to be able to demonstrate how to become self-sufficient in terms of the execution environments I use. :slight_smile:

1 Like

Hey Jan-Piet,

from my understanding there are no Container Files available, since the images are build with Fedoras build system “Fedora Koji” and are built using Kickstart files.

This GitHub Repository explains the process a bit: docker-brew-fedora

The build assets, like the kickstart files are publicly available, for instance: Fedora-Container-Minimal-Base-38-20240402.0 | Build Info | koji

But this is just my understanding of it. Maybe somebody here has ties to the Fedora Project, knows more or can point you in the right direction? I can imagine @gwmngilfen could be of help :slight_smile:

2 Likes

The awx-ee Containerfile existed in a hand-crafted fashion once-upon-a-time. It has since been removed in favor of ansible-builder v3. You’re supposed to use ansible-builder and the execution-environment.yml to generate a Containerfile and build context.

Personally, the ansible-builder still lacks some customization capabilities for generating the Containerfile, so I still hand craft one. However, I do use ansible-builder to create a base Containerfile to start with.

Mine looks like this for .e.g. It allows me to build against dev/prod pipelines, and let the CI define the version of the awx.awx collection to be added to requirements. It’s also using an entitled ubi-9 build. It still depends on the context/_build/* directory created by ansible-builder though.

ARG EE_BASE_IMAGE="quay.privatedomain.local/dev-ansible-ci/ubi9/ubi:latest"
ARG LIFECYCLE=dev
ARG PYCMD="/usr/bin/python3"
ARG PKGMGR_PRESERVE_CACHE=""
ARG ANSIBLE_GALAXY_CLI_COLLECTION_OPTS="-U"
ARG ANSIBLE_GALAXY_CLI_ROLE_OPTS=""
ARG ANSIBLE_INSTALL_REFS="ansible-core==2.14.9 ansible-runner"
ARG PKGMGR="/usr/bin/dnf"
ARG AWX_VERSION="23.8.1"

# Base build stage
FROM $EE_BASE_IMAGE as base
USER root
ARG EE_BASE_IMAGE
ARG PYCMD
ARG PKGMGR_PRESERVE_CACHE
ARG LIFECYCLE
ARG ANSIBLE_GALAXY_CLI_COLLECTION_OPTS
ARG ANSIBLE_GALAXY_CLI_ROLE_OPTS
ARG ANSIBLE_INSTALL_REFS
ARG PKGMGR

RUN mkdir -p /etc/ansible
COPY _build/configs/ansible_${LIFECYCLE}.cfg /etc/ansible/ansible.cfg
COPY _build/configs/pip.conf /etc/pip.conf
RUN dnf install -y ansible dnf-utils && dnf clean all && rm -rf /var/cache/{yum,dnf}
RUN dnf config-manager --enable rhocp-4.12-for-rhel-rpms --enable ocp-tools-4.12-for-rhel-8-x86_64-rpms && dnf clean all && rm -rf /var/cache/{yum,dnf}
ENV PIP_NO_CACHE_DIR=off
RUN $PYCMD -m ensurepip
RUN $PYCMD -m pip install --no-cache-dir $ANSIBLE_INSTALL_REFS
COPY _build/scripts/ /output/scripts/
COPY _build/scripts/entrypoint /opt/builder/bin/entrypoint
RUN $PYCMD -m pip install -U pip

# Galaxy build stage
FROM base as galaxy
ARG EE_BASE_IMAGE
ARG PYCMD
ARG PKGMGR_PRESERVE_CACHE
ARG ANSIBLE_GALAXY_CLI_COLLECTION_OPTS
ARG ANSIBLE_GALAXY_CLI_ROLE_OPTS
ARG ANSIBLE_INSTALL_REFS
ARG PKGMGR
ARG AWX_VERSION

RUN /output/scripts/check_galaxy
COPY _build /build
WORKDIR /build

RUN echo "  - name: awx.awx" >> requirements.yml && echo "    version: ${AWX_VERSION}" >> requirements.yml
RUN ansible-galaxy role install $ANSIBLE_GALAXY_CLI_ROLE_OPTS -r requirements.yml --roles-path "/usr/share/ansible/roles"
RUN ANSIBLE_GALAXY_DISABLE_GPG_VERIFY=1 ansible-galaxy collection install $ANSIBLE_GALAXY_CLI_COLLECTION_OPTS -r requirements.yml --collections-path "/usr/share/ansible/collections"

# Builder build stage
FROM base as builder
WORKDIR /build
ARG EE_BASE_IMAGE
ARG PYCMD
ARG PKGMGR_PRESERVE_CACHE
ARG ANSIBLE_GALAXY_CLI_COLLECTION_OPTS
ARG ANSIBLE_GALAXY_CLI_ROLE_OPTS
ARG ANSIBLE_INSTALL_REFS
ARG PKGMGR

RUN $PYCMD -m pip install --no-cache-dir bindep pyyaml requirements-parser

COPY --from=galaxy /usr/share/ansible /usr/share/ansible

COPY _build/requirements.txt requirements.txt
COPY _build/bindep.txt bindep.txt
RUN $PYCMD /output/scripts/introspect.py introspect --sanitize --user-pip=requirements.txt --user-bindep=bindep.txt --write-bindep=/tmp/src/bindep.txt --write-pip=/tmp/src/requirements.txt
RUN /output/scripts/assemble
RUN $PYCMD -m pip install ansible-builder
RUN ansible-builder introspect --sanitize --user-pip=requirements.txt --user-bindep=bindep.txt --write-bindep=/tmp/src/bindep.txt --write-pip=/tmp/src/requirements.txt /usr/share/ansible
RUN /output/scripts/assemble

# Final build stage
FROM base as final
ARG EE_BASE_IMAGE
ARG PYCMD
ARG PKGMGR_PRESERVE_CACHE
ARG ANSIBLE_GALAXY_CLI_COLLECTION_OPTS
ARG ANSIBLE_GALAXY_CLI_ROLE_OPTS
ARG ANSIBLE_INSTALL_REFS
ARG PKGMGR

RUN /output/scripts/check_ansible $PYCMD

COPY --from=galaxy /usr/share/ansible /usr/share/ansible

COPY --from=builder /output/ /output/
RUN /output/scripts/install-from-bindep && rm -rf /output/wheels
RUN chmod ug+rw /etc/passwd
RUN mkdir -p /runner && chgrp 0 /runner && chmod -R ug+rwx /runner
WORKDIR /runner
RUN $PYCMD -m pip install --no-cache-dir 'dumb-init==1.2.5'
COPY --from=quay.io/ansible/receptor:latest /usr/bin/receptor /usr/bin/receptor
RUN mkdir -p /var/run/receptor
RUN git lfs install --system
RUN rm -rf /output
LABEL ansible-execution-environment=true
USER 1000
ENTRYPOINT ["/opt/builder/bin/entrypoint", "dumb-init"]
CMD ["bash"]

@jpmens I totally misread that you wanted to view the Dockerfile for the base image used in EE’s, such as the fedora or the centos one. Going to leave my other comment intact just in case anyone else comes looking here for the AWX-EE Containerfile specifically.

1 Like

@Denney-tech indeed, but thanks – interesting nevertheless.

So a large portion of the Ansible world relies on execution environments (possibly self-built) using container images assembled and built opaquely, i.e. without actually knowing what goes into them respectively what they contain? I find that quite amazing, and actually slightly scary.

Of course we typically trust our software vendors, and rightly so, but if I really want to begin building my base image I have to start from scratch.

3 Likes

The good thing about ansible-builder 3 is that you can use arbitrary base images - as long as they use the right distro. (Earlier versions of ansible-builder required very specially crafted base images.)

I think it’s planned in principle to support other base images, but so far there are only ideas (Design principles for expanded distro support · Issue #553 · ansible/ansible-builder · GitHub, Pluggable abstraction of base image interactions and support scripts · Issue #637 · ansible/ansible-builder · GitHub), but no concrete plans / implementations. (I did have a PoC PR to make it work with other package managers, but that was just a hack and won’t get merged. And has quite a few conflicts now anyway.)

Having support for other distro images and package managers would make it a lot easier to create EEs you can fully trust. (Assuming you can fully trust all the packages and collections you are installing in them, of course :slight_smile: )

3 Likes

@felixfontein a pity your “hack” won’t be merged; it looks quite straightforward to me, at least at first glance.

Thanks all for your feedback – much appreciated!

I wouldn’t say that. You can look at the packages in Quay, and you can podman run -it quay.io/fedora/fedora:latest cat /root/original-ks.cfg to see how the scratch image was installed.

# Generated by pykickstart v3.48
#version=DEVEL
# Use text mode install
text
# Keyboard layouts
keyboard 'us'
# Network information
network  --bootproto=dhcp --device=link --activate
# Reboot after installation
reboot
repo --name="koji-override-0" --baseurl=https://kojipkgs.fedoraproject.org/compose/39/latest-Fedora-39/compose/Everything/x86_64/os/
repo --name="koji-override-1" --baseurl=https://kojipkgs.fedoraproject.org/compose/updates/f39-updates/compose/Everything/x86_64/os/
# Root password
rootpw --iscrypted --lock locked
timesource --ntp-disable
# System timezone
timezone Etc/UTC --utc
# Use network installation
url --url="https://kojipkgs.fedoraproject.org/compose/39/latest-Fedora-39/compose/Everything/x86_64/os/"
# System bootloader configuration
bootloader --disabled
autopart --type=plain --nohome --noboot --noswap
# Clear the Master Boot Record
zerombr
# Partition clearing information
clearpart --all

%post --logfile=/root/anaconda-post.log --erroronfail
set -eux

# Set install langs macro so that new rpms that get installed will
# only install langs that we limit it to.
LANG="en_US"
echo "%_install_langs $LANG" > /etc/rpm/macros.image-language-conf

# https://bugzilla.redhat.com/show_bug.cgi?id=1727489
echo 'LANG="C.UTF-8"' >  /etc/locale.conf

# https://bugzilla.redhat.com/show_bug.cgi?id=1400682
echo "Import RPM GPG key"
releasever=$(rpm --eval '%{?fedora}')

# When building ELN containers, we don't have the %{fedora} macro
if [ -z $releasever ]; then
  releasever=eln
fi

rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-$releasever-primary

echo "# fstab intentionally empty for containers" > /etc/fstab

# Remove machine-id on pre generated images
rm -f /etc/machine-id
touch /etc/machine-id

echo "# resolv placeholder" > /etc/resolv.conf
chmod 644 /etc/resolv.conf
%end

%post --logfile=/root/anaconda-post.log --erroronfail
# remove some extraneous files
rm -rf /var/cache/dnf/*
rm -rf /tmp/*

# https://pagure.io/atomic-wg/issue/308
printf "tsflags=nodocs\n" >>/etc/dnf/dnf.conf


# https://bugzilla.redhat.com/show_bug.cgi?id=1343138
# Fix /run/lock breakage since it's not tmpfs in docker
# This unmounts /run (tmpfs) and then recreates the files
# in the /run directory on the root filesystem of the container
#
# We ignore the return code of the systemd-tmpfiles command because
# at this point we have already removed the /etc/machine-id and all
# tmpfiles lines with %m in them will fail and cause a bad return
# code. Example failure:
#   [/usr/lib/tmpfiles.d/systemd.conf:26] Failed to replace specifiers: /run/log/journal/%m
#
umount /run
rm -f /run/nologin # https://pagure.io/atomic-wg/issue/316

# Final pruning
rm -rfv /var/cache/* /var/log/* /tmp/*

%end

%post --nochroot --logfile=/mnt/sysimage/root/anaconda-post-nochroot.log --erroronfail
set -eux

# See: https://bugzilla.redhat.com/show_bug.cgi?id=1051816
# NOTE: run this in nochroot because "find" does not exist in chroot
KEEPLANG=en_US
for dir in locale i18n; do
    find /mnt/sysimage/usr/share/${dir} -mindepth  1 -maxdepth 1 -type d -not \( -name "${KEEPLANG}" -o -name POSIX \) -exec rm -rfv {} +
done

%end

%packages --excludedocs --nocore --inst-langs=en --exclude-weakdeps
bash
coreutils
dnf
dnf-yum
fedora-release-container
glibc-minimal-langpack
rootfiles
rpm
sudo
tar
util-linux-core
vim-minimal
-dosfstools
-e2fsprogs
-fuse-libs
-glibc-langpack-en
-gnupg2-smime
-grubby
-kernel
-langpacks-en
-langpacks-en_GB
-libss
-pinentry
-shared-mime-info
-sssd-client
-trousers
-util-linux
-xkeyboard-config

%end

1 Like