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

Laurent Vivier Laurent at Vivier.EU
Thu Dec 26 10:17:25 UTC 2013


Le 26/12/2013 00:12, Laurent Vivier a écrit :
> 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.

OK, I think I missed the point. What you want is I merge lxc-debian and 
my lxc-cross-debian to manage the both cases in the same script. I 
didn't do that because I don't want to break the original script, but if 
you think it is better, I can try...

>
>> 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