Merge pull request #578 from mslacken/podmanBuild

Dockerfile for warewulf host container
This commit is contained in:
Christian Goll
2023-02-03 11:53:08 +01:00
committed by GitHub
11 changed files with 524 additions and 7 deletions

93
Dockerfile Normal file
View File

@@ -0,0 +1,93 @@
FROM opensuse/tumbleweed:latest as builder
RUN zypper -n install --no-recommends git go1.18 libgpgme-devel &&\
zypper -n install -t pattern devel_basis
# now build the warewulf
COPY . /warewulf-src
RUN cd /warewulf-src &&\
make contclean &&\
make genconfig \
PREFIX=/usr \
BINDIRa=/usr/bin \
SYSCONFDIR=/etc \
DATADIR=/usr/share \
LOCALSTATEDIR=/var/lib \
SHAREDSTATEDIR=/var/lib \
MANDIR=/usr/share/man \
INFODIR=/usr/share/info \
DOCDIR=/usr/share/doc \
SRVDIR=/var/lib \
TFTPDIR=/srv/tftpboot \
SYSTEMDDIR=/usr/lib/systemd/system \
BASHCOMPDIR=/etc/warewulf/bash_completion.d/ \
FIREWALLDDIR=/usr/lib/firewalld/services \
WWCLIENTDIR=/warewulf &&\
make lint &&\
make &&\
make install
# now all again but just the bare install for running the stuff
FROM opensuse/tumbleweed:latest
LABEL Description="Warewulf Base Container"
LABEL maintainer="Christian Goll <cgoll@suse.com>"
COPY --from=builder /usr/bin/wwctl /usr/bin/wwctl
COPY --from=builder /var/lib/warewulf /var/lib/warewulf
COPY --from=builder /usr/share/warewulf /usr/share/warewulf
COPY --from=builder /usr/lib/systemd/system/warewulfd.service /container-scripts/warewulfd.service
COPY --from=builder /etc/warewulf /etc/warewulf
COPY --from=builder /warewulf-src/container-scripts /container-scripts
RUN zypper -n install \
cpio \
gzip \
pigz \
rsync \
openssh-clients \
less \
dhcp-server \
iproute2 \
vim \
yq \
tftp \
systemd \
&& \
zypper clean -a && \
systemctl enable dhcpd && \
systemctl enable tftp.socket &&\
export DHCPDCONF=/etc/sysconfig/dhcpd; test -e $DHCPDCONF && \
sed -i 's/^DHCPD_INTERFACE=""/DHCPD_INTERFACE="ANY"/' $DHCPDCONF && \
sed -i 's/^DHCPD_RUN_CHROOTED="yes"/DHCPD_RUN_CHROOTED="no"/' $DHCPDCONF && \
WW4CONF=/etc/warewulf/warewulf.conf; test -e $WW4CONF && \
yq e '.ipaddr |= "EMPTY"' -i $WW4CONF && \
yq e '.netmask |= "EMPTY"' -i $WW4CONF && \
yq e '.network |= "EMPTY"' -i $WW4CONF && \
yq e '.dhcp.["range start"] |= "EMPTY"' -i $WW4CONF && \
yq e '.dhcp.["range end"] |= "EMPTY"' -i $WW4CONF && \
yq e '.nfs.enabled |= false' -i $WW4CONF && \
mkdir -p /container && \
cp -vr container-scripts/label-* \
container-scripts/wwctl \
container-scripts/warewulf.service \
container-scripts/warewulf-container-manage.sh \
container-scripts/config-warewulf \
/container &&\
mkdir -p /usr/share/bash_completion/completions/ &&\
cp /etc/warewulf/bash_completion.d/warewulf /usr/share/bash_completion/completions/warewulf &&\
mv -v container-scripts/ww4-config.service /etc/systemd/system/ &&\
mv -v container-scripts/warewulfd.service /etc/systemd/system/ &&\
systemctl enable ww4-config &&\
systemctl enable warewulfd
CMD [ "/usr/sbin/init" ]
EXPOSE 67/udp 68/udp 69/udp 80 9873
LABEL INSTALL="/usr/bin/docker run --env IMAGE=IMAGE --rm --privileged -v /:/host IMAGE /bin/bash /container/label-install"
LABEL UNINSTALL="/usr/bin/docker run --rm --privileged -v /:/host IMAGE /bin/bash /container/label-uninstall"
LABEL PURGE="/usr/bin/docker run -ti --rm --privileged -v /:/host IMAGE /bin/bash /container/label-purge"
LABEL RUN="/usr/bin/docker run -d --replace --name \${NAME} --privileged --net=host -v /:/host -v /etc/warewulf:/etc/warewulf -v /var/lib/warewulf/:/var/lib/warewulf/ -e NAME=\${NAME} -e IMAGE=\${IMAGE} \${IMAGE}"

View File

@@ -1,4 +1,4 @@
.PHONY: all
.PHONY: all clean contclean
-include Defaults.mk
@@ -53,7 +53,7 @@ else
endif
# OS-Specific Service Locations
VARLIST += TFTPDIR FIREWALLDDIR SYSTEMDDIR
VARLIST += TFTPDIR FIREWALLDDIR SYSTEMDDIR BASHCOMPDIR
SYSTEMDDIR ?= /usr/lib/systemd/system
BASHCOMPDIR ?= /etc/bash_completion.d
FIREWALLDDIR ?= /usr/lib/firewalld/services
@@ -257,10 +257,9 @@ warewulfconf: config_defaults
./config_defaults
dist: vendor config
rm -rf .dist/$(WAREWULF)-$(VERSION)
rm -rf .dist/$(WAREWULF)-$(VERSION) $(WAREWULF)-$(VERSION).tar.gz
mkdir -p .dist/$(WAREWULF)-$(VERSION)
cp -rap * .dist/$(WAREWULF)-$(VERSION)/
find .dist/$(WAREWULF)-$(VERSION)/ -type f -name '*~' -delete
rsync -a --exclude=".*" --exclude "*~" * .dist/$(WAREWULF)-$(VERSION)/
cd .dist; tar -czf ../$(WAREWULF)-$(VERSION).tar.gz $(WAREWULF)-$(VERSION)
rm -rf .dist
@@ -292,7 +291,7 @@ wwapic: ## Build the sample wwapi client.
wwapird: ## Build the rest api server (revese proxy to the grpc api server).
go build -o ./wwapird internal/app/api/wwapird/wwapird.go
clean:
contclean:
rm -f wwclient
rm -f wwctl
rm -rf .dist
@@ -301,7 +300,6 @@ clean:
rm -rf bash_completion.d
rm -f man_page
rm -rf man_pages
rm -rf vendor
rm -f warewulf.spec
rm -f config
rm -f Defaults.mk
@@ -311,6 +309,9 @@ clean:
rm -f print_defaults
rm -f etc/wwapi{c,d,rd}.conf
clean: contclean
rm -rf vendor
install: files install_wwclient
debinstall: files debfiles

View File

@@ -0,0 +1,61 @@
# Warewulf on SUSE/openSUSE/ALP
This is the warewulf container including `tftp` and `dhcpd` services. It also shares the install run labels with the upstream container, but this container uses the rpm package of warewulf and not the upstream source.
The containers used for deployment, the overlays and compressed images are stored not in the warewulf container but under `var/lib/warewulf` on the host. Also the configuration directory `/etc/warewulf`is created on the host.
`dhpd` and `tftp` require systemd running also in the container. To provide these services the container must also run in the same network as the host and the container must also run in privileged mode.
Additionally the `warewulf-container-manage.sh` script is included to manage the container via podman and the `wwctl` command to manage the warewulf itself.
# Install the warewulf container
## Prepare the host system
It is heavlily advised that the host has a static ipv4 address. To configure this on ALP
you can use `nmcli` with the following command:
```
nmcli connection modify "$(nmcli -t device | awk -F: '/ethernet/{print$4;exit}')" \
ipv4.method manual \
ipv4.addresses 192.168.1.250/24 \
ipv4.gateway 192.168.1.1\
ipv4.dns 182.168.1.1
```
In order to run the warewulf container, you can just use the the '''runlable install''' on the container available in the registry.
```
# podman container runlabel install registry.opensuse.org/suse/alp/workloads/tumbleweed_containerfiles/suse/alp/workloads/warewlf:latest
```
This will create the directories `/var/lib/warewulf` and `/etc/warewulf` on the host system and populate it with necesarry configuraiton files, if this files are not present on the host.
On the first install the actual ip network settings are used as base values for the dynamic
network configuration in `warewulf.conf`.
## Create the container
The warewulf service is started with the command
```
# podman container runlabel run registry.opensuse.org/suse/alp/workloads/tumbleweed_containerfiles/suse/alp/workloads/warewlf:latest
```
Now the cluster can be managed with the `wwctl` command.
## Remove the Container
The container itself can be remove with the '''label uninstall''' which will remove the container and its scripts from the host.
```
# podman container runlabel uninstall registry.opensuse.org/suse/alp/workloads/tumbleweed_containerfiles/suse/alp/workloads/warewlf:latest
```
This step *doesn't* remove the configuration of warewulf under `/etc/warewulf` and the containers with the overlays under `/var/lib/warewulf`. You can use the purge label to remove these directories.
## Purge warewulf
All components of warewulf including `/etc/warewulf` and `/var/lib/warewulf` can be removed the the '''label purge''' which can be called with
```
# podman container runlabel purge registry.opensuse.org/suse/alp/workloads/tumbleweed_containerfiles/suse/alp/workloads/warewlf:latest
```
Please note that the '''label purge''' inherits the label '''label uninstall'''.
## More Info
* [Warewulf](https://github.com/hpcng/warewulf)

View File

@@ -0,0 +1,75 @@
#!/bin/sh
# Helper functions
# Get the mask form prefix
cdr2mask()
{
# Number of args to shift, 255..255, first non-255 byte, zeroes
set -- $(( 5 - ($1 / 8) )) 255 255 255 255 $(( (255 << (8 - ($1 % 8))) & 255 )) 0 0 0
[ $1 -gt 1 ] && shift $1 || shift
echo ${1-0}.${2-0}.${3-0}.${4-0}
}
# Get the ip4 address of the netork
network_address() {
declare address prefix_length
IFS=/ read address prefix_length <<< "$1"
declare -a octets
IFS=. read -a octets <<< "$address"
declare mask
mask=$( printf "%08x" $(( (1 << 32) - (1 << (32 - prefix_length)) )) )
declare -i i
for i in {0..3}; do octets[$i]=$(( octets[i] & 16#${mask:2*i:2} )); done
echo $( IFS=.; echo "${octets[*]}" )
}
echo "-- WW4 CONFIGURAION $* --"
# Make sure that a ip address was defined for out network so that
# we can configure dhcpd correctly
IP4CIDR=`ip addr | awk '/scope global/ {print $2;exit}'`
IP4=${IP4CIDR%/*}
IP4PREFIX=${IP4CIDR#*/}
IP4MASK=$(cdr2mask $IP4PREFIX)
IP4NET=$(network_address "$IP4/$IP4PREFIX")
if [ "$IP4PREFIX" -gt 25 ] ; then
echo "ERROR: warewulf does at least a /25 network for dynamic addresses"
exit 1
fi
DYNSIZE=100
DYNSTART=${IP4#*.*.*.}
DYNPRE=${IP4%.*}
DYNEND=$(( $DYNSTART + $DYNSIZE ))
if [ $DYNEND -gt 254 ] ; then
DYNEND=$(( $IPNET + 2 + $DYNSIZE ))
DYNSTART=$(( $IPNET + 2 ))
fi
DYNSTART="${DYNPRE}.${DYNSTART}"
DYNEND="${DYNPRE}.${DYNEND}"
WW4CONF=/etc/warewulf/warewulf.conf
if [ -e $WW4CONF ] ; then
test -n $IP4 && sed -i 's/^ipaddr: EMPTY/ipaddr: '$IP4'/' $WW4CONF
test -n $IP4MASK && sed -i 's/^netmask: EMPTY/netmask: '$IP4MASK'/' $WW4CONF
test -n $IP4NET && sed -i 's/^network: EMPTY/network: '$IP4NET'/' $WW4CONF
test -n $DYNSTART && sed -i 's/^ range start: EMPTY/ range start: '$DYNSTART'/' $WW4CONF
test -n $DYNEND && sed -i 's/^ range end: EMPTY/ range end: '$DYNEND'/' $WW4CONF
cat << EOF
ipaddr: $IP4
netmask: $IP4MASK
network: $IP4NET
range start: $DYNSTART
range end: $DYNEND
EOF
fi
# configure the services of the host by building the host overlay
echo "-- Running wwctl --"
# enable tftp if systemd is running
test -e /run/systemd/system && wwctl configure tftp
test -e /run/systemd/system && wwctl configure ssh
wwctl overlay build

82
container-scripts/label-install Executable file
View File

@@ -0,0 +1,82 @@
#!/bin/sh -eu
# This is the install script for warewulf when run in a privileged
# container.
cd /
PATH="/usr/bin:/usr/sbin"
CONTAINER=warewulf
BINSCRIPT=${CONTAINER}-container-manage.sh
WWCTL=wwctl
OVERLAYDIR=/var/lib/warewulf/overlays
CHROOTDIR=/var/lib/warewulf/chroots
CONTAINERDIR=/var/lib/warewulf/container
WAREWULFCONF=/etc/warewulf
BASHCOMPLETION=/usr/share/bash_completion/completions/w*
AUTHKEYDIR=/root/.ssh
echo "LABEL INSTALL"
# ensure all scripts will be present on the host
copy_to_usr_local_bin() {
SCRIPT=$1
BASEDIR=`dirname $SCRIPT`
mkdir -p $BASEDIR
if [ ! -e /host/usr/local/bin/${SCRIPT} ]; then
echo "copy /container/${SCRIPT} in /host/usr/local/bin/"
rsync -u /container/${SCRIPT} /host/usr/local/bin/${SCRIPT}
chmod 755 /host/usr/local/bin/${SCRIPT}
else
echo "/host/usr/local/bin/${SCRIPT} already exist, will not update it"
fi
}
copy_to_etc() {
CONF=$1
BASEDIR=`dirname $CONF`
mkdir -p $BASEDIR
if [ ! -e /host/etc/${CONF} ]; then
echo "copy /container/${CONF} in /host/etc/"
rsync -u /container/${CONF} /host/etc/${CONF}
else
echo "/host/etc/${CONF} already exist, will not update it"
fi
}
sync_dir() {
DIR=$1
test -e /host/${DIR} || mkdir -pv /host/${DIR}
test -e /host/${DIR} && (rsync -au --ignore-existing ${DIR} `dirname /host/${DIR}`; echo "updating $DIR")
}
# For podman, cp a systemd unit for starting on boot
if [ ! -e /host/etc/systemd/system/${CONTAINER}.service ]; then
mkdir -p /host/etc/systemd/system/
rsync -u /container/${CONTAINER}.service /host/etc/systemd/system/${CONTAINER}.service
else
echo "/host/etc/systemd/system/${CONTAINER}.service already exist"
fi
# create the dirs
mkdir -p /host/etc/warewulf
mkdir -p /host/var/lib/warewulf
copy_to_usr_local_bin ${WWCTL}
copy_to_usr_local_bin ${BINSCRIPT}
# now sync hosts and overlays
sync_dir $OVERLAYDIR
sync_dir $CHROOTDIR
sync_dir $WAREWULFCONF
# bash completion
if [ ! -e /host/etc/bash_completion.d/warewulf ] ; then
mkdir -p /host/etc/bash_completion.d
cp $BASHCOMPLETION /host/etc/bash_completion.d/
fi
# containerdir
mkdir -p /host/$CONTAINERDIR
# authorized keys
mkdir -p /root/.ssh/
echo "Copy authorized keys to container"
test -e /host/${AUTHKEYDIR}/*pub && cp -v /host/${AUTHKEYDIR}/*pub ${AUTHKEYDIR} || echo "no public keys found"

34
container-scripts/label-purge Executable file
View File

@@ -0,0 +1,34 @@
#!/bin/bash
OVERLAYDIR=/var/lib/warewulf/overlays
CHROOTDIR=/var/lib/warewulf/chroots
OCIDIR=/var/lib/warewulf/oci
CONTAINERDIR=/var/lib/warewulf/container
WAREWULFCONF=/etc/warewulf
BASEDIR=/var/lib/warewulf
cat >&2 << EOF
WARNING:
Purging all warewulf configurations, containers aka node images and overlays
Wating for 10s, press any key to abort
EOF
count=0
while true ; do
if read -t 0; then # Input ready
read -n 1 char
echo "Aborting purge"
exit 0
else # No input
echo -n '.'
sleep 1
count=$(( $count + 1))
if [ $count -eq 10 ] ; then
echo
break
fi
fi
done
echo "PURGING"
/container/label-uninstall
rm -rv /host/$WAREWULFCONF /host/$OVERLAYDIR /host/$CHROOTDIR /host/$CONTAINERDIR /host/$OCIDIR
rmdir /host/$BASEDIR

View File

@@ -0,0 +1,20 @@
#!/bin/sh -eu
# This is the uninstall script for grafana when run in a privileged
# container.
CONTAINER=warewulf
cd /
PATH="/usr/bin:/usr/sbin"
if [ ! -d /host/etc ] || [ ! -d /host/usr/local/bin ]; then
echo "${CONTAINER}-uninstall: host file system is not mounted at /host"
exit 1
fi
# removing installed files
echo "LABEL UNINSTALL: Removing all files"
rm -vf /host/usr/local/bin/wwctl
rm -vf /host/usr/local/bin/warewulf-container-manage.sh
rm -vf /host/etc/systemd/system/${CONTAINER}.service
rm -vf /host/usr/share/bash_completion/completions/wwctl

View File

@@ -0,0 +1,108 @@
#!/bin/bash
# quick script to manage the container
CONTAINER_NAME=warewulf
create_container() {
podman create \
--name ${CONTAINER_NAME} \
--tls-verify=false \
--network host \
${IMAGE}
}
run_container() {
podman run \
--name ${CONTAINER_NAME} \
--rm -ti \
--network host \
--entrypoint bash \
${IMAGE}
}
if [ -z "$1" ]; then
echo "
First ARG is mandatory:
$0 [create|start|stop|rm|rmcache|run|bash|logs|install|uninstall]
CONTAINER_NAME: '${CONTAINER_NAME}'
DEPLOYMENT:
create
Pull the image and create the container automatically
install
install needed files on the host to manage '${CONTAINER_NAME}' container
(in /usr/local/bin and /etc)
start
Start the container '${CONTAINER_NAME}'
REMOVAL:
uninstall
uninstall all needed files on the host to manage '${CONTAINER_NAME}' container
stop
stop the container '${CONTAINER_NAME}'
rm
delete the container '${CONTAINER_NAME}'
rmcache
remove the container image in cache ${IMAGE}
DEBUG:
run
podman run container '${CONTAINER_NAME}'
bash
go with /bin/bash command inside '${CONTAINER_NAME}'
logs
see log of container '${CONTAINER_NAME}'
"
exit 1
fi
###########
# MAIN
###########
set -euxo pipefail
case $1 in
start)
podman start ${CONTAINER_NAME}
podman ps | grep ${CONTAINER_NAME}
;;
stop)
podman stop ${CONTAINER_NAME}
podman ps | grep ${CONTAINER_NAME}
;;
rm)
set +e
podman stop ${CONTAINER_NAME}
podman rm ${CONTAINER_NAME}
;;
create)
create_container
;;
run)
run_container
;;
rmcache)
podman rmi ${IMAGE}
;;
logs)
podman logs ${CONTAINER_NAME}
;;
bash)
set +e
podman exec -ti ${CONTAINER_NAME} $@
;;
install)
podman run --env IMAGE=${IMAGE} --rm --privileged -v /:/host ${IMAGE} /bin/bash /container/label-install
;;
uninstall)
podman run --env IMAGE=${IMAGE} --rm --privileged -v /:/host ${IMAGE} /bin/bash /container/label-uninstall
;;
esac

View File

@@ -0,0 +1,25 @@
[Unit]
Description=warewulf daemon container
Documentation=https://build.opensuse.org/package/show/SUSE:ALP:Workloads/warewulf-container
After=network-online.target
After=local-fs.target
Wants=network-online.target
StartLimitIntervalSec=40
StartLimitBurst=5
[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=always
RestartSec=1s
TimeoutStopSec=70
#Environment=WAREWULF_IMAGE_PATH=registry.opensuse.org/suse/alp/workloads/tumbleweed_containerfiles/suse/alp/workloads/warewulf:latest
Environment=WAREWULF_IMAGE_PATH=warewulf:latest
ExecStartPre=-/usr/bin/podman container runlabel --name warewulf install ${WAREWULF_IMAGE_PATH}
ExecStart=/usr/bin/podman container runlabel --name warewulf run ${WAREWULF_IMAGE_PATH}
ExecStop=/usr/bin/podman container stop warewulf
ExecStopPost=/usr/bin/podman container rm warewulf
Type=notify
NotifyAccess=all
[Install]
WantedBy=multi-user.target

View File

@@ -0,0 +1,12 @@
[Unit]
Description=Warewulf container configuration
After=local-fs.target
Before=warewulfd.service
Before=dhcpd
[Service]
Type=oneshot
ExecStart=/container/config-warewulf
[Install]
WantedBy=multi-user.target

6
container-scripts/wwctl Executable file
View File

@@ -0,0 +1,6 @@
#!/bin/bash
set -euxo pipefail
# Run the domain
podman exec -ti ${CONTAINER_NAME} wwctl $@