[lxc-devel] [PATCH] Add lxc-cross-debian to create debian containers for non native architectures.
Laurent Vivier
laurent at vivier.eu
Wed Dec 25 20:38:57 UTC 2013
These containers will use the binfmt kernel module and
an interpreter to execute binaries inside the container.
To use it :
1- configure correctly binfmt on your system to load the
interpreter.
2- provide the path to the interpreter to the lxc template.
The interpreter must be statically linked.
3- provide the architecture to install (armhf, mips, m68k, sparc, ...)
4- provide the suite to install (stable, lenny, etch, ...)
For instance, if you want to use qemu as an interpreter, check this:
If you want to create an m68k containers on your x86_64 system,
you can use a script to do all the work :
git clone git at gitorious.org:qemu-m68k/qemu-m68k.git
cd qemu-m68k
scripts/debian-create-lxc.sh m68k
You can change "m68k", but m68k is the one really tested...
[TIPS: want to create a raspberry-pi container ?
scripts/debian-create-lxc.sh raspberrypi ]
Signed-off-by: Laurent Vivier <laurent at vivier.eu>
---
configure.ac | 1 +
templates/Makefile.am | 3 +-
templates/lxc-cross-debian.in | 360 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 363 insertions(+), 1 deletion(-)
create mode 100755 templates/lxc-cross-debian.in
diff --git a/configure.ac b/configure.ac
index 4c5f002..feb1771 100644
--- a/configure.ac
+++ b/configure.ac
@@ -583,6 +583,7 @@ AC_CONFIG_FILES([
templates/lxc-archlinux
templates/lxc-alpine
templates/lxc-plamo
+ templates/lxc-cross-debian
src/Makefile
src/lxc/Makefile
diff --git a/templates/Makefile.am b/templates/Makefile.am
index abdca6f..33939b4 100644
--- a/templates/Makefile.am
+++ b/templates/Makefile.am
@@ -15,4 +15,5 @@ templates_SCRIPTS = \
lxc-archlinux \
lxc-alpine \
lxc-cirros \
- lxc-plamo
+ lxc-plamo \
+ lxc-cross-debian
diff --git a/templates/lxc-cross-debian.in b/templates/lxc-cross-debian.in
new file mode 100755
index 0000000..a12caa1
--- /dev/null
+++ b/templates/lxc-cross-debian.in
@@ -0,0 +1,360 @@
+#!/bin/bash
+#
+# Some parts from lxc-debian, Daniel Lezcano <daniel.lezcano at free.fr>
+#
+# Copy this script to /usr/share/lxc/templates
+#
+# and use it with
+# lxc-create -t cross-debian -n xxxx -- --arch xxx --interpreter-path /a/b/c/qemu-xxx
+#
+
+SUITE=${SUITE:-stable}
+MIRROR=${MIRROR:-http://ftp.debian.org/debian}
+
+find_interpreter() {
+ given_interpreter=$(basename "$1")
+
+ if [ ! -d /proc/sys/fs/binfmt_misc/ ] ; then
+ return 1
+ fi
+ for file in /proc/sys/fs/binfmt_misc/* ; do
+ if [ "$file" = "/proc/sys/fs/binfmt_misc/register" -o \
+ "$file" = "/proc/sys/fs/binfmt_misc/status" ] ; then
+ continue
+ fi
+ interpreter_path=$(sed -n "/^interpreter/s/interpreter \([^[:space:]]*\)/\1/p" "$file")
+ interpreter=$(basename $interpreter_path)
+
+ if [ "$given_interpreter" = "$interpreter" ] ; then
+ echo "$interpreter_path"
+ return 0
+ fi
+ done
+ return 1
+}
+
+download_debian()
+{
+ cache="$1"
+ arch="$2"
+
+ if [ ! -d "$cache/archives-$SUITE-$arch" ]; then
+ if ! mkdir -p "$cache/archives-$SUITE-$arch" ; then
+ echo "Failed to create '$cache/archives-$SUITE-$arch' directory"
+ return 1
+ fi
+ fi
+
+ echo "Downloading debian $SUITE $arch..."
+ if ! debootstrap --download-only \
+ --no-check-gpg \
+ --arch=$arch \
+ --include="locales" \
+ ${SUITE} "$cache/archives-$SUITE-$arch" \
+ ${MIRROR} ; then
+ echo "ERROR: failed to download to $cache/archives-$SUITE-$arch" 1>&2
+ exit 1
+ fi
+ echo "Download complete."
+ trap EXIT
+ trap SIGINT
+ trap SIGTERM
+ trap SIGHUP
+
+ return 0
+}
+
+copy_debian()
+{
+ cache=$1
+ arch=$2
+ rootfs=$3
+
+ echo -n "Copying rootfs to $rootfs..."
+ mkdir -p $rootfs
+ rsync -Ha "$cache/archives-$SUITE-$arch"/ $rootfs/ || return 1
+ echo "Copy complete."
+ return 0
+}
+
+install_debian()
+{
+ cache="@LOCALSTATEDIR@/cache/lxc/debian"
+ rootfs="$1"
+ arch="$2"
+
+ mkdir -p @LOCALSTATEDIR@/lock/subsys/
+ (
+ if ! flock -x 200 ; then
+ echo "Cache repository is busy."
+ return 1
+ fi
+
+ if ! download_debian $cache $arch ; then
+ echo "Failed to download 'debian base'"
+ return 1
+ fi
+
+ if ! copy_debian $cache $arch $rootfs ; then
+ echo "Failed to copy rootfs"
+ return 1
+ fi
+
+ return 0
+
+ ) 200>@LOCALSTATEDIR@/lock/subsys/lxc-cross-debian
+
+ return $?
+}
+
+create_root() {
+
+ rootfs="$1"
+ hostname="$2"
+ interpreter="$3"
+ arch="$4"
+ interpreter_path="$5"
+ include="$6"
+
+ if ! install_debian "$rootfs" "$arch" ; then
+ echo "ERROR: failed to update cache" 1>&2
+ exit 1
+ fi
+
+ if [ "${include}" = "" ] ; then
+ include="locales"
+ else
+ include="locales,${include}"
+ fi
+
+ # Debian bootstrap
+
+ if ! debootstrap --no-check-gpg --foreign \
+ --arch=$arch \
+ --include="${include}" \
+ ${SUITE} "$rootfs" \
+ ${MIRROR} ; then
+ echo "ERROR: failed to debootstrap to $rootfs" 1>&2
+ exit 1
+ fi
+
+ # adding interpreter binary
+
+ if ! cp "$interpreter" "$rootfs/$interpreter_path" ; then
+ echo "ERROR: failed to copy $interpreter to $rootfs/$interpreter_path" 1>&2
+ exit 1
+ fi
+
+ # debian bootstrap second stage
+
+ chroot "$rootfs" debootstrap/debootstrap --second-stage
+}
+
+configure_debian() {
+
+ rootfs="$1"
+ hostname="$2"
+ debian_sign="$3"
+
+ # set timezone
+
+ cat /etc/timezone > "$rootfs/etc/timezone"
+ chroot $rootfs dpkg-reconfigure -fnoninteractive tzdata
+
+ # configuration
+
+ cat >> "$rootfs/etc/fstab" <<!EOF
+# <file system> <mount point> <type> <options> <dump> <pass>
+devpts /dev/pts devpts nodev,noexec,nosuid 0 1
+!EOF
+
+ echo "$hostname" > "$rootfs/etc/hostname"
+ echo "c:2345:respawn:/sbin/getty 38400 console" >> "$rootfs/etc/inittab"
+
+ cat >> "$rootfs/etc/network/interfaces" <<!EOF
+auto eth0
+iface eth0 inet dhcp
+!EOF
+
+ cat > "$rootfs/etc/apt/sources.list" <<!EOF
+deb ${MIRROR} ${SUITE} main contrib non-free
+#deb-src ${MIRROR} ${SUITE} main contrib non-free
+!EOF
+
+ if [ "$debian_sign" != "" ]
+ then
+ HOME=/root chroot "$rootfs" gpg --keyserver pgpkeys.mit.edu --recv-key ${debian_sign}
+ HOME=/root chroot "$rootfs" gpg -a --export ${debian_sign} | chroot "$rootfs" apt-key add -
+ fi
+
+ chroot "$rootfs" apt-get update
+
+ if [ -z "$LANG" ]; then
+ echo "en_US.UTF-8 UTF-8" > "$rootfs/etc/locale.gen"
+ chroot $rootfs locale-gen
+ chroot $rootfs update-locale LANG=en_US.UTF-8
+ else
+ echo "$LANG $(echo $LANG | cut -d. -f2)" > "$rootfs/etc/locale.gen"
+ chroot $rootfs locale-gen
+ chroot $rootfs update-locale LANG=$LANG
+ fi
+
+ # remove pointless services in a container
+
+ if [ -x "$rootfs/usr/sbin/update-rc.d" ] ; then
+ chroot $rootfs /usr/sbin/update-rc.d -f checkroot.sh remove
+ chroot $rootfs /usr/sbin/update-rc.d -f umountfs remove
+ chroot $rootfs /usr/sbin/update-rc.d -f hwclock.sh remove
+ chroot $rootfs /usr/sbin/update-rc.d -f hwclockfirst.sh remove
+ chroot $rootfs /usr/sbin/update-rc.d -f module-init-tools remove
+ fi
+
+ echo "root:root" | chroot $rootfs chpasswd
+ echo "Root password is 'root', please change !"
+}
+
+get_rootfs() {
+ config="$1/config"
+ rootfs=$(sed -n "s/^lxc.rootfs[[:space:]]*=[[:space:]]*\(.*\)/\1/p" $config)
+ if [ "$rootfs" = "" ]
+ then
+ echo "$path/rootfs"
+ else
+ echo "$rootfs"
+ fi
+}
+
+create_lxc() {
+ path="$1"
+ rootfs="$2"
+ hostname="$3"
+
+ grep -q "^lxc.rootfs" $path/config 2>/dev/null || echo "lxc.rootfs = $rootfs" >> "$path/config"
+ cat >> "$path/config" <<!EOF
+lxc.utsname = $hostname
+
+lxc.pts=1023
+lxc.tty=12
+
+lxc.cgroup.devices.deny = a
+lxc.cgroup.devices.allow = c 136:* rwm # pts
+lxc.cgroup.devices.allow = c 254:0 rwm # rtc
+lxc.cgroup.devices.allow = c 5:* rwm
+lxc.cgroup.devices.allow = c 4:* rwm # ttyXX
+lxc.cgroup.devices.allow = c 1:* rwm
+lxc.cgroup.devices.allow = b 7:* rwm # loop
+lxc.cgroup.devices.allow = b 1:* rwm # ram
+
+lxc.mount.entry=proc proc proc nodev,noexec,nosuid 0 0
+lxc.mount.entry=sysfs sys sysfs defaults 0 0
+
+!EOF
+ if [ $? -ne 0 ] ; then
+ echo "ERROR: failed to create LXC configuration" 1>&2
+ exit 1
+ fi
+}
+
+usage()
+{
+ cat <<!EOF
+Usage: $1 --path PATH --name NAME --arch ARCH --interpreter-path QEMU
+ [--mirror MIRROR][--suite SUITE]
+
+ --path is configuration path
+ --name is container name
+ --arch is debian architecture
+ --interpreter-path is path to the interpreter to copy to rootfs
+ --mirror is URL of debian mirror to use
+ --suite is debian suite to install
+ --include is the list of package to add to debootstrap
+!EOF
+}
+
+options=$(getopt -o hp:n:I:a:s:m:k:i: -l help,rootfs:,path:,name:,interpreter-path:,arch:,suite:,mirror:,deb-sign:,include: -- "$@")
+if [ $? -ne 0 ]; then
+ usage $(basename $0)
+ exit 1
+fi
+eval set -- "$options"
+
+while true ; do
+ case "$1" in
+ -p|--path)
+ shift
+ path="$1"
+ ;;
+ --rootfs)
+ shift
+ rootfs="$1"
+ ;;
+ -n|--name)
+ shift
+ name="$1"
+ ;;
+ -a|--arch)
+ shift
+ arch="$1"
+ ;;
+ -I|--interpreter-path)
+ shift
+ interpreter="$1"
+ ;;
+ -s|--suite)
+ shift
+ SUITE="$1"
+ ;;
+ -m|--mirror)
+ shift
+ MIRROR="$1"
+ ;;
+ -i|--include)
+ shift
+ include="$1"
+ ;;
+ -k|--deb-sign)
+ shift
+ debian_sign="$1"
+ ;;
+ -h|--help)
+ usage
+ exit 1
+ ;;
+ *)
+ break
+ ;;
+ esac
+ shift
+done
+
+if [ "$path" = "" -o "$name" = "" -o "$arch" = "" -o "$interpreter" = "" ] ; then
+ echo "ERROR: missing parameter" 1>&2
+ usage
+ exit 1
+fi
+
+if ! type debootstrap ; then
+ echo "ERROR: 'debootstrap' command is missing" 1>&2
+ exit 1
+fi
+
+if ! file -b "${interpreter}" |grep -q "statically linked" ; then
+ echo "ERROR: '${interpreter}' must be statically linked" 1>&2
+ exit 1
+fi
+
+interpreter_path=$(find_interpreter "$interpreter")
+if [ $? -ne 0 ] ; then
+ echo "ERROR: no binfmt interpreter using $(basename $interpreter)" 1>&2
+ exit 1
+fi
+
+if [ "$rootfs" = "" ] ; then
+ rootfs=$(get_rootfs $path)
+fi
+
+create_root "$rootfs" "$name" "$interpreter" "$arch" "$interpreter_path" "$include"
+
+configure_debian "$rootfs" "$name" "$debian_sign"
+
+create_lxc "$path" "$rootfs" "$name"
--
1.8.3.2
More information about the lxc-devel
mailing list