[lxc-devel] [PATCH] Add lxc-cross-debian to create debian containers for non native architectures.

Laurent Vivier Laurent at Vivier.EU
Wed Dec 25 23:12:11 UTC 2013


Le 25/12/2013 21:47, Stéphane Graber a écrit :
> On Wed, Dec 25, 2013 at 09:38:57PM +0100, Laurent Vivier wrote:
>> 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 ]
>>
> Why not do it the same way we do in lxc-ubuntu?
>
> In lxc-ubuntu, foreign architecture containers are completely
> transparent, basically if qemu-debootstrap is on the system, it'll be
> called automatically and then some tweaks are done to setup multi-arch
> post-install and install the few bits that don't work properly under
> qemu-user-static (netlink mostly).
Because my goal is to have a real install I can use on the real machine. 
I don't want to put inconsistent binaries in it.
Moreover, I'm before all a qemu developer, so I prefer to correct qemu 
instead of using some tweaks to use qemu with linux containers.

> I personaly would much rather the feature be added to lxc-debian than
> have another template for that which would mostly create some extra
> confusion (I already don't like the two Ubuntu templates for that reason
> though those are at least entirely different in the way they work and so
> vaguely make sense).
>
>> 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
>>
>> _______________________________________________
>> lxc-devel mailing list
>> lxc-devel at lists.linuxcontainers.org
>> http://lists.linuxcontainers.org/listinfo/lxc-devel



More information about the lxc-devel mailing list