Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Elbe Docker container #407

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions contrib/container/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
apt_keys/*.asc
apt_keys/*.gpg
elbe.tar.gz
result
Dockerfile_tmp
sources.list
84 changes: 84 additions & 0 deletions contrib/container/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
FROM debian:bookworm

ARG USER="dev"

USER root

ENV DEBIAN_FRONTEND noninteractive

COPY sources.list /etc/apt/sources.list

RUN apt update

# install build tools, QEMU and Python
RUN apt -y install \
openssh-server debootstrap reprepro python3 python3-pip python3-venv \
binfmt-support qemu-user-static locales git apt python3-cherrypy3 sudo \
python3-gpg python3-lxml python3-mako python3-passlib python3-pycdlib \
python3-debian python3-suds python3-libvirt swig cpio patchelf \
python3-beaker python3-spyne python3-sqlalchemy python3-parted \
tmux dosfstools e2fsprogs xfsprogs file lsof vim

RUN dpkg --add-architecture arm64
RUN apt update

RUN apt -y install libc6:arm64

# setup locale
RUN echo "en_US.UTF-8 UTF-8" > /etc/locale.gen && locale-gen
ENV LANG en_US.UTF-8
ENV LANGUAGE en_US:en
ENV LC_ALL en_US.UTF-8

##### create user #####

ARG HOST_USER=1000
ARG HOST_GROUP=1000

# Create build user mathching outside UID and GID to avoid ownership issues
# and allow user to use sudo
RUN addgroup --gid $HOST_GROUP $USER && \
useradd -rm -d /home/$USER -s /bin/bash -g $USER -G sudo -u $HOST_USER $USER && \
echo "$USER ALL=(ALL:ALL) NOPASSWD:ALL" >> /etc/sudoers && \
mkdir -p /home/$USER/.ssh && \
chown -R $USER:$USER /home/$USER

# Prepare the elbe setup
RUN mkdir -p /var/cache/elbe
COPY source.xml /var/cache/elbe/
RUN mkdir -p /var/cache/elbe/installer
RUN mkdir -p /var/cache/elbe/devel

RUN mkdir -p /etc/ssh
RUN echo 'PermitRootLogin yes' >> /etc/ssh/sshd_config

# reduce container size
# RUN sudo apt clean -y

# copy repository keys
RUN mkdir -p /etc/apt/trusted.gpg.d/
COPY apt_keys/* /etc/apt/trusted.gpg.d/

# Copy bashrc
COPY bashrc /home/$USER/.bashrc
RUN chown $USER:$USER /home/$USER/.bashrc && chmod +x /home/$USER/.bashrc
COPY bashrc /root/.bashrc
RUN chown root:root /root/.bashrc && chmod +x /root/.bashrc

RUN chown $USER:$USER /var/cache/elbe

# copy scripts
COPY scripts/* /scripts/
RUN chmod +x /scripts/*

# Get elbe
ADD elbe.tar.gz /var/cache/elbe/devel

RUN mkdir -p /build/results/images

WORKDIR /var/cache/elbe
USER $USER

RUN PATH=$PATH:/var/cache/elbe/devel PYTHONPATH=$PYTHONPATH:/var/cache/elbe/devel elbe db init

CMD "bash"
41 changes: 41 additions & 0 deletions contrib/container/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Elbe Docker container

This container allows to use elbe without a initvm.

Building for foreign CPU architectures is supported if the host is able to load the binfmt_misc kernel module.

## Build the container

- First get the Debian, Ubuntu and Elbe apt repository signing keys by running: `contrib/container/apt_keys/get_keys.sh`.
- Then build the container by running `contrib/container/build_container.sh`.
This script expects that you have cloned the git repository, i.e. that the elbe sources can be found at `../../`

## Use the container

Run `contrib/container/run_container.sh` to start the container.

This script read-only bind-mounts the example images to `/images` in the container.
The `.bashrc` is used to mount and writeable overlay at `/tmp/images`.

The `initvm` commands are not supported in the container, but you can use `build_image` instead:
```bash
Usage: build_image
[ -c | --build-sdk ]
[ -r | --result-path ]
-i | --image path/to/image/xml
```

You can find this and other scripts available in the container at `contrib/container/scripts`.

## More information

- The elbe Docker container _simulates_ and elbe initvm. Please be aware that this means the kernel of the host OS is used and may have an impact on the build result, e.g. with respect to used filesystem drivers.
- Since elbe is not modified, the _initvm_ command will not work since no libvirt or QEMU VM is available.
- The container uses [qemu and bimfmt](https://wiki.debian.org/QemuUserEmulation) to allow building images for foreign architectures, which is the same mechanism as used by the elbe initvm. To use this, the kernel module *binfmt_misc* needs to be loaded. This is done in the *run_container.sh* script, but the module must be available and the user needs sudo rights.
- The container needs to be a _privileged_ container, for _binfmt_ but also for different _mount_ operations needed during the image build.
- The container also needs to bind-mount _dev_ form the host environment, else new devices created by _losetup_ will not show up, and the build will fail.

## Known issues

- Elbe initvm and related commands doesn't work.
- Building ISO images doesn't work
19 changes: 19 additions & 0 deletions contrib/container/apt_keys/get_keys.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/bin/bash

# Extract the apt keys form the docker containers.
CONTAINERS="ubuntu:24.04 ubuntu:22.04 debian:bookworm"

# extract the apt repo keys form the given containers
for CONTAINER in $CONTAINERS; do
docker run -it --rm -v ${PWD}:/keys $CONTAINER \
bash -c "cp /etc/apt/trusted.gpg.d/* /keys"
done

# dearmor all armored keys
for KEY in $(find . -name "*.asc"); do
gpg --dearmor $KEY
done

# add elbe key
cp ../elbe.asc .
gpg --dearmor elbe.asc
10 changes: 10 additions & 0 deletions contrib/container/bashrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export PATH=/scripts:$PATH:/var/cache/elbe/devel
export PYTHONPATH=$PYTHONPATH:/var/cache/elbe/devel

# Register binfmt
register_binfmt

# Start elbe service
start_elbe_service

echo "Welcome to the elbe container"
23 changes: 23 additions & 0 deletions contrib/container/build_container.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/bin/bash

SCRIPT_DIR=$( dirname "${BASH_SOURCE[0]}")
echo "SCRIPT: $SCRIPT_DIR"
cd $SCRIPT_DIR

cd ../../
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use pushd and popd below. Or a subshell.

tar --exclude='contrib' -zcvf contrib/container/elbe.tar.gz .
cd contrib/container

if [ $# -ne 0 ]; then
distro=$1
else
distro="debian:bookworm"
fi

rm -f Dockerfile_tmp
sed "s/debian:bookworm/${distro}/g" Dockerfile > Dockerfile_tmp
cp "sources_${distro}.list" sources.list

docker build \
-f Dockerfile_tmp \
-t elbe_container:testing .
46 changes: 46 additions & 0 deletions contrib/container/elbe.asc
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----

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
lffHf8U7HFvRg+zm
=3i/P
-----END PGP PUBLIC KEY BLOCK-----
25 changes: 25 additions & 0 deletions contrib/container/run_container.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#!/bin/bash

lsmod | grep binfmt_misc
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check will also fail if binfmt_misc is builtin.

Instead check for "binfmt_misc" in /proc/filesystems/.
Or unconditionally call modprobe. It will helpfully do nothing if it's builtin.

if [ $? -ne 0 ]; then
echo "Trying to load binfmt kernel module for cross-builds ..."
sudo modprobe binfmt_misc
fi

echo "PWD: $PWD"
mkdir -p result
RESULT=$(realpath ./result)
echo "RESULT DIR: $RESULT"

SCRIPT_DIR=$(realpath "${BASH_SOURCE[0]}")
echo "SCRIPT: $SCRIPT_DIR"
IMAGES=$(realpath ../../examples)
echo "IMAGES: $IMAGES"

docker run --rm -it \
-v ${HOME}/.ssh:/home/dev/.ssh:ro \
-v ${IMAGES}:/images:ro \
-v ${RESULT}:/build/results/images:rw \
-v /dev:/dev \
--privileged \
elbe_container:testing
102 changes: 102 additions & 0 deletions contrib/container/scripts/build_image
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
#!/bin/bash

set +e
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This disables "abort on error", intentional?
If so, it needs an explanation.


sdk=0
image=""
result="/build/results/images"

usage(){
>&2 cat << EOF
Usage: build_image
[ -c | --build-sdk ]
[ -r | --result-path ]
-i | --image path/to/image/xml
EOF
exit 1
}

args=$(getopt -a -o c,h,r:,i: --long build-sdk,help,result-path:,image: -- "$@")
if [[ $? -gt 0 ]]; then
usage
fi

eval set -- "${args}"
while [ : ]; do
case "$1" in
-c | --build-sdk)
sdk=1
shift
;;
-r | --result-path)
result=$2
shift 2
;;
-i | --image)
image=$2
shift 2
;;
-h | --help)
usage
;;
--)
shift
break
;;
?)
echo "Unsupported option: $1"
shift
;;
esac
done

echo "Build SDK: $sdk"
echo "IMAGE: $image"

if [ ! -f $image ]; then
echo "Image $image doesn't exist!"
exit 1
fi

# stop on error during build preparation
set -e

IMAGE=$(realpath $image)
IMAGE_NAME=$(basename $IMAGE)
RESULT_FOLDER="${result}/${IMAGE_NAME}"
PROJECT="${RESULT_FOLDER}/elbe.prj"
PRE_XML="${RESULT_FOLDER}/${IMAGE_NAME}.gz"

mkdir -p $RESULT_FOLDER

PROJECT_ID=$(elbe control create_project)
echo $PROJECT_ID > ${PROJECT}
elbe preprocess --output=${PRE_XML} $IMAGE
rm -f "${RESULT_FOLDER}/${IMAGE_NAME}" || true
gzip -dk ${PRE_XML}
elbe control set_xml ${PROJECT_ID} ${PRE_XML}
elbe control build ${PROJECT_ID}

# ignore build errors and complete script
set +e

elbe control wait_busy ${PROJECT_ID}
if [ $sdk -eq 1 ]; then
elbe control build_sdk ${PROJECT_ID}
elbe control wait_busy ${PROJECT_ID}
fi
elbe control get_files --output ${RESULT_FOLDER} ${PROJECT_ID}
elbe control del_project ${PROJECT_ID}

echo "The build result was written to ${RESULT_FOLDER}."

set +e
ERROR=$(cat "${RESULT_FOLDER}/log.txt" | grep "\[ERROR\]")
if [ $? -eq 0 ]; then
echo "ERROR: Build failed, see log.txt!"
cat "${RESULT_FOLDER}/log.txt" | grep "\[ERROR\]"
exit 1
else
echo "SUCCESS: Build was successful!"
exit 0
fi
Loading