471 lines
12 KiB
Bash
471 lines
12 KiB
Bash
#!/usr/bin/env zsh
|
||
|
||
## debuerreotype sequence
|
||
## docker run --cap-add SYS_ADMIN --cap-drop SETFCAP --tmpfs /tmp:dev,exec,suid,noatime ...
|
||
|
||
# bootstrapping a new architecture?
|
||
# ./scripts/debuerreotype-init /tmp/docker-rootfs bullseye now
|
||
# ./scripts/debuerreotype-minimizing-config /tmp/docker-rootfs
|
||
# ./scripts/debuerreotype-debian-sources-list /tmp/docker-rootfs bullseye
|
||
# ./scripts/debuerreotype-tar /tmp/docker-rootfs - | docker import - debian:bullseye-slim
|
||
# alternate:
|
||
# debootstrap --variant=minbase bullseye /tmp/docker-rootfs
|
||
# tar -cC /tmp/docker-rootfs . | docker import - debian:bullseye-slim
|
||
# (or your own favorite set of "debootstrap" commands to create a base image for building this one FROM)
|
||
|
||
##
|
||
|
||
build_docker_dist() {
|
||
fn build_docker_dist
|
||
req=(workdir strapdir os arch size imageformat parted_type)
|
||
ckreq || return 1
|
||
|
||
notice "Building complete docker image(s)"
|
||
|
||
act "obtain apt/dpkg versions."
|
||
apt_version=apt-version
|
||
dpkg_version=dpkg-version
|
||
|
||
act "create and populate the rootfs."
|
||
bootstrap_complete_base-wrapper || { zerr; return 1; }
|
||
blend_preinst || { zerr; return 1; }
|
||
blend_postinst || { zerr; return 1; }
|
||
|
||
notice "import, tag and push them image."
|
||
|
||
docker-init-policy || { zerr; return 1; }
|
||
# docker-hostname || { zerr; return 1; }
|
||
# docker-resolvconf || { zerr; return 1; }
|
||
|
||
act "apt related fixups move to sysconf-docker."
|
||
docker-apt-speedup || { zerr; return 1; }
|
||
docker-apt-autoremove-suggests || { zerr; return 1; }
|
||
docker-apt-clean || { zerr; return 1; }
|
||
docker-apt-gzip-indexes || { zerr; return 1; }
|
||
docker-apt-no-languages || { zerr; return 1; }
|
||
|
||
act "import, tag and push the image."
|
||
docker-import || { zerr; return 1; }
|
||
docker-push || { zerr; return 1; }
|
||
|
||
act "slimify the rootfs."
|
||
docker-purge_slimify_package || { zerr; return 1; }
|
||
docker-slimify || { zerr; return 1; }
|
||
|
||
act "import, tag and push the slim image."
|
||
docker-import --slim || { zerr; return 1; }
|
||
docker-push --slim || { zerr; return 1; }
|
||
clean_strapdir || { zerr; return 1; }
|
||
}
|
||
|
||
|
||
docker-push() {
|
||
fn docker-push
|
||
req=(R strapdir release registry_url registry_user registry_token registry_tag)
|
||
ckreq || return 1
|
||
|
||
notice "beginning the push procedure."
|
||
act "registry login"
|
||
docker login -u ${registry_user} -p ${registry_token} ${registry_url}
|
||
|
||
#${registry_tag} # date, $CI_COMMIT_SHA, $CI_COMMIT_REF_SLUG
|
||
|
||
if [[ -n $1 ]]; then
|
||
case $1 in
|
||
-s|--slim)
|
||
release=${release}-slim
|
||
act "setting release to ${release}."
|
||
shift
|
||
;;
|
||
*)
|
||
echo "Unknown parameter passed: $1"
|
||
exit 1
|
||
;;
|
||
esac
|
||
fi
|
||
|
||
docker tag ${registry_url}/${release}:${registry_tag} ${registry_url}:${release}
|
||
docker push ${registry_url}/${release}
|
||
docker logout ${registry_url}
|
||
}
|
||
|
||
|
||
docker-import() {
|
||
fn docker-import
|
||
req=(R strapdir release apt_version)
|
||
ckreq || return 1
|
||
|
||
notice "tar-ing the \$strapdir before importing for docker."
|
||
act "adding additional excludes for apt versions older than 0.8"
|
||
if dpkg --compare-versions "$apt_version" '>=' '0.8~'; then
|
||
# if APT is new enough to auto-recreate "partial" directories, let it
|
||
# (https://salsa.debian.org/apt-team/apt/commit/1cd1c398d18b78f4aa9d882a5de5385f4538e0be)
|
||
excludes+=(
|
||
'./var/cache/apt/**'
|
||
'./var/lib/apt/lists/**'
|
||
'./var/state/apt/lists/**'
|
||
)
|
||
# (see also the targeted exclusions in "tar-excludes" that these are overriding)
|
||
fi
|
||
|
||
act "calling docker-fixup before tar."
|
||
docker-fixup
|
||
|
||
act "setting arguments for tar."
|
||
tarArgs=(
|
||
--create
|
||
--file "$strapdir"
|
||
--auto-compress
|
||
--directory "$strapdir"
|
||
--exclude-from "${BLENDPATH}/tar-excludes"
|
||
)
|
||
|
||
if [ -z "$includeDev" ]; then
|
||
act "excluding the contents of /dev from the archive."
|
||
excludes+=( './dev/**' )
|
||
fi
|
||
|
||
for exclude in "${excludes[@]}"; do
|
||
tarArgs+=( --exclude "$exclude" )
|
||
done
|
||
|
||
tarArgs+=(
|
||
--numeric-owner
|
||
--transform 's,^./,,'
|
||
--sort name
|
||
.
|
||
)
|
||
|
||
if [[ -n $1 ]]; then
|
||
case $1 in
|
||
-s|--slim)
|
||
release=${release}-slim
|
||
act "setting release to ${release}."
|
||
shift
|
||
;;
|
||
*)
|
||
echo "Unknown parameter passed: $1"
|
||
exit 1
|
||
;;
|
||
esac
|
||
fi
|
||
|
||
act "calling tar."
|
||
tar "${tarArgs[@]}" - | docker import - devuan:${release}
|
||
}
|
||
|
||
|
||
docker-fixup() {
|
||
fn docker-fixup
|
||
req=(R strapdir )
|
||
ckreq || return 1
|
||
|
||
notice "removing redundant log and cache files."
|
||
pushd "$strapdir" || { zerr; return 1; }
|
||
rm -f \
|
||
"./var/log/dpkg.log" \
|
||
"./var/log/bootstrap.log" \
|
||
"./var/log/alternatives.log" \
|
||
"./var/cache/ldconfig/aux-cache"
|
||
|
||
act "removing redundant /run mounts."
|
||
# https://github.com/debuerreotype/debuerreotype/pull/32
|
||
rm -f "./run/mount/utab"
|
||
|
||
# (also remove the directory, but only if it's empty)
|
||
rmdir "./run/mount" 2>/dev/null || :
|
||
|
||
# fix ownership/permissions on / (otherwise "debootstrap" leaves them as-is which causes reproducibility issues)
|
||
chown 0:0 "./"
|
||
chmod 0755 "./"
|
||
popd
|
||
}
|
||
|
||
|
||
docker-slimify() {
|
||
fn docker-slimify
|
||
req=(R strapdir )
|
||
ckreq || return 1
|
||
|
||
notice "Removing files specified in the blends config-docker \$slimExcludes variable and adding the paths to the dpkg config."
|
||
dest=$strapdir/etc/dpkg/dpkg.cfg.d
|
||
dpkgCfgFile="${dest}/docker"
|
||
mkdir -p $(dirname "$dpkgCfgFile")
|
||
|
||
cat > ${dpkgCfgFile} <<-EOF
|
||
# This is the "slim" variant of the Devuan base image.
|
||
# Many files which are normally unnecessary in containers are excluded,
|
||
# and this configuration file keeps them that way.
|
||
EOF
|
||
act "make a record of the directory structure under /usr/share/man."
|
||
extraSpecialDirectories=( "$strapdir"/usr/share/man/man[0-9]/ )
|
||
|
||
act "processing the includes in \$slimIncludes"
|
||
findMatchIncludes=()
|
||
for slimInclude in "${slimIncludes[@]}"; do
|
||
[ "${#findMatchIncludes[@]}" -eq 0 ] || findMatchIncludes+=( '-o' )
|
||
findMatchIncludes+=( -path "$slimInclude" )
|
||
done
|
||
findMatchIncludes=( '(' "${findMatchIncludes[@]}" ')' )
|
||
|
||
act "processing the excludes in \$slimIncludes"
|
||
for slimExclude in "${slimExcludes[@]}"; do
|
||
{
|
||
echo
|
||
echo "# dpkg -S '$slimExclude'"
|
||
if dpkgOutput="$(chroot-script /bin/bash -c " \
|
||
dpkg -S "$slimExclude" 2>&1")"; then
|
||
echo "$dpkgOutput" | sed 's/: .*//g; s/, /\n/g' | sort -u | xargs
|
||
else
|
||
echo "$dpkgOutput"
|
||
fi | fold -w 76 -s | sed 's/^/# /'
|
||
echo "path-exclude $slimExclude"
|
||
} >> "$dpkgCfgFile"
|
||
|
||
notice "remove directories from slimExcludes in two passes."
|
||
if [[ "$slimExclude" == *'/*' ]]; then
|
||
if [ -d "$strapdir/$(dirname "$slimExclude")" ]; then
|
||
# use two passes so that we don't fail trying to remove directories from $slimIncludes
|
||
# this is our best effort at implementing https://sources.debian.net/src/dpkg/stretch/src/filters.c/#L96-L97 in shell
|
||
|
||
act "pass one: delete everything that doesn't match '\$slimIncludes' and isn't a directory or a symlink"
|
||
chroot-script /bin/bash -c " \
|
||
find "$(dirname "$slimExclude")" \
|
||
-depth -mindepth 1 \
|
||
-not \( -type d -o -type l \) \
|
||
-not "${findMatchIncludes[@]}" \
|
||
-exec rm -f '{}' ';'
|
||
"
|
||
|
||
act "pass two: repeatedly delete any dangling symlinks and empty directories until there aren't any"
|
||
# (might have a dangling symlink in a directory which then makes it empty, or a symlink to an empty directory)
|
||
while [ "$(
|
||
chroot-script /bin/bash -c " \
|
||
find "$(dirname "$slimExclude")" \
|
||
-depth -mindepth 1 \( -empty -o -xtype l \) \
|
||
-exec rm -rf '{}' ';' -printf '.' \
|
||
| wc -c "
|
||
)" -gt 0 ]; do true; done
|
||
fi
|
||
else
|
||
chroot-script bash -c "
|
||
rm -f "$slimExclude"
|
||
"
|
||
fi
|
||
done
|
||
|
||
act "appending includes to the dpkg conf."
|
||
{
|
||
echo
|
||
for slimInclude in "${slimIncludes[@]}"; do
|
||
echo "path-include $slimInclude"
|
||
done
|
||
} >> "$dpkgCfgFile"
|
||
|
||
chmod 0644 "$dpkgCfgFile"
|
||
|
||
act "recreate directory structure under /usr/share/man"
|
||
if [ "${#extraSpecialDirectories[@]}" -gt 0 ]; then
|
||
mkdir -p "${extraSpecialDirectories[@]}"
|
||
fi
|
||
}
|
||
|
||
|
||
docker-purge_slimify_package() {
|
||
fn docker-purge_slimify_packages
|
||
req=(strapdir slimify_packages)
|
||
ckreq || return 1
|
||
|
||
cat <<-EOF | sudo tee "$strapdir/purge_slimify_packages" >/dev/null
|
||
#!/bin/sh
|
||
apt-get --yes --force-yes purge ${purge_packages_option} ${slimify_packages} || exit 1
|
||
apt-get --yes --force-yes --purge autoremove || exit 1
|
||
apt-get clean
|
||
EOF
|
||
|
||
chroot-script -d purge_slimify_packages || { zerr; return 1; }
|
||
}
|
||
|
||
|
||
docker-init-policy() {
|
||
fn docker-init-policy
|
||
req=(R strapdir)
|
||
ckreq || return 1
|
||
|
||
dest=$strapdir/usr/sbin
|
||
cat > ${dest}/policy-rc.d.docker <<EOF
|
||
#!/bin/sh
|
||
exit 101 # action forbidden by policy
|
||
EOF
|
||
chmod 0755 "${dest}/policy-rc.d.docker"
|
||
|
||
cat <<-EOF | sudo tee ${strapdir}/init-policy >/dev/null
|
||
#!/bin/sh
|
||
|
||
update-alternatives --quiet --install /usr/sbin/policy-rc.d \
|
||
policy-rc.d /usr/sbin/policy-rc.d.docker 100
|
||
|
||
case "${release}" in
|
||
jessie|ascii)
|
||
dpkg-divert --quiet --local --add /sbin/initctl
|
||
;;
|
||
*)
|
||
dpkg-divert --quiet --local --no-rename --add /sbin/initctl
|
||
;;
|
||
esac
|
||
ln -fs /bin/true /sbin/initctl
|
||
EOF
|
||
chroot-script -d init-policy
|
||
}
|
||
|
||
|
||
docker-apt-speedup() {
|
||
fn docker-apt-speedup
|
||
req=(R strapdir)
|
||
ckreq || return 1
|
||
|
||
dest=$strapdir/etc/dpkg/dpkg.cfg.d
|
||
sudo mkdir -p ${dest}
|
||
|
||
cat <<-EOF | sudo tee ${dest}/docker-apt-speedup" >/dev/null
|
||
force-unsafe-io
|
||
EOF
|
||
chmod 0644 "${dest}/docker-apt-speedup"
|
||
}
|
||
|
||
|
||
docker-apt-autoremove-suggests() {
|
||
fn docker-apt-autoremove-suggests
|
||
req=(R strapdir)
|
||
ckreq || return 1
|
||
|
||
dest=$strapdir/etc/apt/apt.conf.d
|
||
sudo mkdir -p ${dest}
|
||
|
||
cat <<-EOF | sudo tee ${dest}/docker-apt-autoremove-suggests" >/dev/null
|
||
Apt::AutoRemove::SuggestsImportant "false";
|
||
EOF
|
||
chmod 0644 "${dest}/docker-apt-autoremove-suggests"
|
||
}
|
||
|
||
|
||
docker-apt-clean() {
|
||
fn docker-apt-clean
|
||
req=(R strapdir)
|
||
ckreq || return 1
|
||
|
||
dest=$strapdir/etc/apt/apt.conf.d
|
||
sudo mkdir -p ${dest}
|
||
|
||
aptGetClean='"rm -f /var/cache/apt/archives/*.deb /var/cache/apt/archives/partial/*.deb /var/cache/apt/*.bin || true";'
|
||
|
||
cat <<-EOF | sudo tee ${dest}/docker-apt-clean" >/dev/null
|
||
APT::Update::Post-Invoke { $aptGetClean };
|
||
|
||
Dir::Cache::pkgcache "";
|
||
Dir::Cache::srcpkgcache "";
|
||
EOF
|
||
chmod 0644 "${dest}/docker-apt-clean"
|
||
}
|
||
|
||
|
||
docker-apt-gzip-indexes() {
|
||
fn docker-apt-gzip-indexes
|
||
req=(R strapdir)
|
||
ckreq || return 1
|
||
|
||
dest=$strapdir/etc/apt/apt.conf.d
|
||
sudo mkdir -p ${dest}
|
||
|
||
cat <<-EOF | sudo tee ${dest}/docker-apt-gzip-indexes" >/dev/null
|
||
Acquire::GzipIndexes "true";
|
||
EOF
|
||
chmod 0644 "${dest}/docker-apt-gzip-indexes"
|
||
}
|
||
|
||
|
||
docker-apt-no-languages() {
|
||
fn docker-apt-no-languages
|
||
req=(R strapdir)
|
||
ckreq || return 1
|
||
|
||
dest=$strapdir/etc/apt/apt.conf.d
|
||
sudo mkdir -p ${dest}
|
||
|
||
cat <<-EOF | sudo tee ${dest}/docker-apt-no-languages" >/dev/null
|
||
Acquire::Languages "none";
|
||
EOF
|
||
chmod 0644 "${dest}/docker-apt-no-languages"
|
||
}
|
||
|
||
|
||
remove-apt-comments() {
|
||
fn remove-apt-comments
|
||
req=(R strapdir apt_version)
|
||
ckreq || return 1
|
||
|
||
dest=$strapdir/etc/apt/apt.conf.d
|
||
if dpkg --compare-versions "$apt_version" '>=' '0.7.22~'; then
|
||
exit
|
||
fi
|
||
|
||
sed -ri -e 's!^#!//!' "${dest}"
|
||
}
|
||
|
||
|
||
# set in zlibs/sysconf:conf_print_hostname() using $os
|
||
# override in $BLENDPATH/sysconf:conf_print_hosts
|
||
# a container’s hostname defaults to be the container’s ID in
|
||
# Docker unless overriden at build. So this is less important here.
|
||
docker-hostname() {
|
||
fn docker-hostname
|
||
req=(R strapdir hostname)
|
||
ckreq || return 1
|
||
|
||
pushd
|
||
act "setting the hostname."
|
||
echo "${hostname}" > "./etc/hostname"
|
||
chmod 0644 \
|
||
"$strapdir/etc/hostname"
|
||
popd
|
||
}
|
||
|
||
# set in zlibs/sysconf:conf_print_resolvconf()
|
||
# override in $BLENDPATH/sysconf
|
||
docker-resolvconf() {
|
||
fn docker-resolvconf
|
||
req=(R strapdir)
|
||
ckreq || return 1
|
||
|
||
pushd $strapdir
|
||
act "replacing /etc/resolv.conf."
|
||
cat <<-EOF | sudo tee ./etc/resolv.conf" >/dev/null
|
||
# https://1.1.1.1 (privacy-focused, highly-available DNS service)
|
||
nameserver 1.1.1.1
|
||
nameserver 1.0.0.1
|
||
EOF
|
||
chmod 0644 \
|
||
"./etc/resolv.conf"
|
||
popd
|
||
}
|
||
|
||
|
||
# If inside a virtual machine or container environment the
|
||
# /etc/machine-id is usually taken from the container UUID
|
||
#docker-id() {
|
||
# fn docker-id
|
||
# req=(R strapdir epoch)
|
||
# ckreq || return 1
|
||
#
|
||
# pushd $strapdir
|
||
|
||
#act "Initialize the machine ID in /etc/machine-id"
|
||
#echo "$epoch" \
|
||
# | md5sum \
|
||
# | cut -f1 -d' ' \
|
||
# > "./etc/machine-id"
|
||
# chmod 0644 \
|
||
# "./etc/machine-id"
|
||
# popd
|
||
#}
|