Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
lxc template for Debian Wheezy to install on Debian Stretch
#!/bin/bash
#
# lxc: linux Container library
# Authors:
# Daniel Lezcano <daniel.lezcano@free.fr>
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
DEBIANVERSION=wheezy
SUITE=debian-${DEBIANVERSION}
MIRROR=${MIRROR:-http://cdn.debian.net/debian}
configure_debian()
{
rootfs=$1
hostname=$2
fqdn=$3
# squeeze only has /dev/tty and /dev/tty0 by default,
# therefore creating missing device nodes for tty1-4.
for tty in $(seq 1 4); do
if [ ! -e $rootfs/dev/tty$tty ]; then
mknod $rootfs/dev/tty$tty c 4 $tty
fi
done
# configure the inittab
cat <<EOF > $rootfs/etc/inittab
id:2:initdefault:
si::sysinit:/etc/init.d/rcS
l0:0:wait:/etc/init.d/rc 0
l1:1:wait:/etc/init.d/rc 1
l2:2:wait:/etc/init.d/rc 2
l3:3:wait:/etc/init.d/rc 3
l4:4:wait:/etc/init.d/rc 4
l5:5:wait:/etc/init.d/rc 5
l6:6:wait:/etc/init.d/rc 6
# Normally not reached, but fallthrough in case of emergency.
z6:6:respawn:/sbin/sulogin
1:2345:respawn:/sbin/getty 38400 console
c1:12345:respawn:/sbin/getty 38400 tty1 linux
c2:12345:respawn:/sbin/getty 38400 tty2 linux
c3:12345:respawn:/sbin/getty 38400 tty3 linux
c4:12345:respawn:/sbin/getty 38400 tty4 linux
EOF
# disable selinux in debian
mkdir -p $rootfs/selinux
echo 0 > $rootfs/selinux/enforce
# configure the network using the dhcp
cat <<EOF > $rootfs/etc/network/interfaces
auto lo
iface lo inet loopback
auto eth0
iface eth0 inet dhcp
EOF
# set the hostname
cat <<EOF > $rootfs/etc/hostname
$hostname
EOF
# set minimal hosts
cat <<EOF > $rootfs/etc/hosts
127.0.0.1 $fqdn $hostname localhost
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
EOF
# reconfigure some services
LANG="${LANG:-en_US.UTF-8}"
locale="$LANG $(echo $LANG | cut -d. -f2)"
chroot $rootfs echo "locales locales/default_environment_locale select $LANG" | chroot $rootfs sh -c "LANG=C debconf-set-selections"
chroot $rootfs echo "locales locales/default_environment_locale seen true" | chroot $rootfs sh -c "LANG=C debconf-set-selections"
chroot $rootfs echo "locales locales/locales_to_be_generated seen true" | chroot $rootfs sh -c "LANG=C debconf-set-selections"
chroot $rootfs sed -i -e "0,/^[# ]*$locale *$/ s/^[# ]*$locale *$/$locale/" /etc/locale.gen
chroot $rootfs sh -c "LANG=C dpkg-reconfigure locales -f noninteractive"
# remove pointless services in a container
chroot $rootfs /usr/sbin/update-rc.d -f checkroot.sh remove # S
chroot $rootfs /usr/sbin/update-rc.d checkroot.sh stop 09 S .
chroot $rootfs /usr/sbin/update-rc.d -f umountfs remove # 0 6
chroot $rootfs /usr/sbin/update-rc.d umountfs start 09 0 6 .
chroot $rootfs /usr/sbin/update-rc.d -f umountroot remove # 0 6
chroot $rootfs /usr/sbin/update-rc.d umountroot start 10 0 6 .
# The following initscripts don't provide an empty start or stop block.
# To prevent them being enabled on upgrades, we leave a start link on
# runlevel 3.
chroot $rootfs /usr/sbin/update-rc.d -f hwclock.sh remove # S 0 6
chroot $rootfs /usr/sbin/update-rc.d hwclock.sh start 10 3 .
chroot $rootfs /usr/sbin/update-rc.d -f hwclockfirst.sh remove # S
chroot $rootfs /usr/sbin/update-rc.d hwclockfirst start 08 3 .
chroot $rootfs /usr/sbin/update-rc.d -f module-init-tools remove # S
chroot $rootfs /usr/sbin/update-rc.d module-init-tools start 10 3 .
echo "root:root" | chroot $rootfs chpasswd
echo "Root password is 'root', please change !"
return 0
}
cleanup()
{
rm -rf $cache/partial-$SUITE-$arch
rm -rf $cache/rootfs-$SUITE-$arch
}
download_debian()
{
packages=\
ifupdown,\
locales,\
libui-dialog-perl,\
dialog,\
isc-dhcp-client,\
netbase,\
net-tools,\
iproute,\
openssh-server
cache=$1
arch=$2
trap cleanup EXIT SIGHUP SIGINT SIGTERM
# check the mini debian was not already downloaded
mkdir -p "$cache/partial-$SUITE-$arch"
if [ $? -ne 0 ]; then
echo "Failed to create '$cache/partial-$SUITE-$arch' directory"
return 1
fi
# download a mini debian into a cache
echo "Downloading debian minimal ..."
debootstrap --verbose --variant=minbase --arch=$arch \
--include=$packages \
"$DEBIANVERSION" "$cache/partial-$SUITE-$arch" $MIRROR
if [ $? -ne 0 ]; then
echo "Failed to download the rootfs, aborting."
return 1
fi
mv "$1/partial-$SUITE-$arch" "$1/rootfs-$SUITE-$arch"
echo "Download complete."
trap EXIT
trap SIGINT
trap SIGTERM
trap SIGHUP
return 0
}
copy_debian()
{
cache=$1
arch=$2
rootfs=$3
# make a local copy of the minidebian
echo -n "Copying rootfs to $rootfs..."
mkdir -p $rootfs
rsync -a "$cache/rootfs-$SUITE-$arch"/ $rootfs/ || return 1
return 0
}
install_debian()
{
cache="/var/cache/lxc/"$SUITE
rootfs=$1
mkdir -p /var/lock/subsys/
(
flock -x 200
if [ $? -ne 0 ]; then
echo "Cache repository is busy."
return 1
fi
# Code taken from debootstrap
if [ -x /usr/bin/dpkg ] && /usr/bin/dpkg --print-architecture >/dev/null 2>&1; then
arch=`/usr/bin/dpkg --print-architecture`
elif type udpkg >/dev/null 2>&1 && udpkg --print-architecture >/dev/null 2>&1; then
arch=`/usr/bin/udpkg --print-architecture`
else
arch=$(arch)
case $arch in
686) arch="i386";;
x86_64) arch="amd64";;
ppc) arch="powerpc";;
esac
fi
echo "Checking cache download in $cache/rootfs-$SUITE-$arch ... "
if [ ! -e "$cache/rootfs-$SUITE-$arch" ]; then
download_debian $cache $arch
if [ $? -ne 0 ]; then
echo "Failed to download 'debian base'"
return 1
fi
fi
copy_debian $cache $arch $rootfs
if [ $? -ne 0 ]; then
echo "Failed to copy rootfs"
return 1
fi
return 0
) 200>/var/lock/subsys/lxc
return $?
}
copy_configuration()
{
path=$1
rootfs=$2
name=$3
fqdn=$4
ipaddress=$5
cat >> $path/config << EOF
# $path/config
## Container
lxc.utsname = $fqdn
lxc.rootfs = $rootfs
lxc.tty = 4
lxc.pts = 1024
lxc.mount = /var/lib/lxc/$name/fstab
lxc.network.ipv4 = $ipaddress
#lxc.console = /var/log/lxc/$name.console
## Capabilities
lxc.cap.drop = sys_admin
# uncomment the next line to run the container unconfined:
#lxc.aa_profile = unconfined
## Devices
#lxc.cgroup.devices.allow = a
lxc.cgroup.devices.deny = a
# /dev/null
lxc.cgroup.devices.allow = c 1:3 rwm
# /dev/zero
lxc.cgroup.devices.allow = c 1:5 rwm
# /dev/tty[1-4] consoles
lxc.cgroup.devices.allow = c 5:1 rwm
lxc.cgroup.devices.allow = c 5:0 rwm
lxc.cgroup.devices.allow = c 4:0 rwm
lxc.cgroup.devices.allow = c 4:1 rwm
# /dev/{,u}random
lxc.cgroup.devices.allow = c 1:9 rwm
lxc.cgroup.devices.allow = c 1:8 rwm
lxc.cgroup.devices.allow = c 136:* rwm
lxc.cgroup.devices.allow = c 5:2 rwm
# /dev/rtc
lxc.cgroup.devices.allow = c 254:0 rwm
## Limits
#lxc.cgroup.cpu.shares = 1024
#lxc.cgroup.cpuset.cpus = 0
#lxc.cgroup.memory.limit_in_bytes = 256M
#lxc.cgroup.memory.memsw.limit_in_bytes = 1G
## Filesystem
#lxc.mount.entry = proc proc proc nodev,noexec,nosuid 0 0
#lxc.mount.entry = sysfs sys sysfs defaults,ro 0 0
#lxc.mount.entry = /srv/$name srv/$name none defaults,bind 0 0
EOF
if [ -z "$ipaddress" ]; then
sed -i 's/^lxc\.network\.ipv4/#lxc.network.ipv4/g' $path/config
fi
cat <<EOF > $path/fstab
proc proc proc nodev,noexec,nosuid 0 0
sysfs sys sysfs defaults,ro 0 0
tmpfs /var/lib/lxc/$name/rootfs/run/shm tmpfs rw,nosuid,nodev,noexec 0 0
EOF
if [ $? -ne 0 ]; then
echo "Failed to add configuration"
return 1
fi
return 0
}
clean()
{
cache="/var/cache/lxc/debian"
if [ ! -e $cache ]; then
exit 0
fi
# lock, so we won't purge while someone is creating a repository
(
flock -x 200
if [ $? != 0 ]; then
echo "Cache repository is busy."
exit 1
fi
echo -n "Purging the download cache..."
rm --preserve-root --one-file-system -rf $cache && echo "Done." || exit 1
exit 0
) 200>/var/lock/subsys/lxc
}
usage()
{
cat <<EOF
$1 -h|--help -p|--path=<path>|--fqdn=<fully qualified hostname>|--ip=<static ip address> --clean
EOF
return 0
}
options=$(getopt -o hp:n:c -l help,rootfs:,path:,name:,ip:,clean,fqdn: -- "$@")
if [ $? -ne 0 ]; then
usage $(basename $0)
exit 1
fi
eval set -- "$options"
while true
do
case "$1" in
-h|--help) usage $0 && exit 0;;
--rootfs) rootfs=$2; shift 2;;
-p|--path) path=$2; shift 2;;
--fqdn) fqdn=$2; shift 2;;
--ip) ipaddress=$2; shift 2;;
-n|--name) name=$2; shift 2;;
-c|--clean) clean=$2; shift 2;;
--) shift 1; break ;;
*) break ;;
esac
done
if [ ! -z "$clean" -a -z "$path" ]; then
clean || exit 1
exit 0
fi
if [ -z "$fqdn" ]; then
fqdn=$name;
fi
type debootstrap
if [ $? -ne 0 ]; then
echo "'debootstrap' command is missing"
exit 1
fi
if [ -z "$path" ]; then
echo "'path' parameter is required"
exit 1
fi
if [ "$(id -u)" != "0" ]; then
echo "This script should be run as 'root'"
exit 1
fi
install_debian $rootfs
if [ $? -ne 0 ]; then
echo "failed to install debian"
exit 1
fi
configure_debian $rootfs $name $fqdn
if [ $? -ne 0 ]; then
echo "failed to configure debian for a container"
exit 1
fi
copy_configuration $path $rootfs $name $fqdn $ipaddress
if [ $? -ne 0 ]; then
echo "failed write configuration file"
exit 1
fi
if [ ! -z $clean ]; then
clean || exit 1
exit 0
fi
@JohnMertz

This comment has been minimized.

Copy link
Owner Author

commented Oct 4, 2018

LXC as packaged in Stretch (perhaps Jessie as well) specifies the rootfs, rather than inferring it from "$path/rootfs". The template from which this was forked did not understand the "--rootfs=" option, now it does and is tested to work.

FYI. I'm installing Wheezy on a Stretch box to keep alive a piece of software that depends on PHP5 which is no longer packaged. I'd be installing in LXC anyways and the container has no access to the internet, so it is less trouble than compling PHP5 (and several modules) on an updated machine. You probably shouldn't use this template unless you are in a similar situation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.