[Lxc-users] lxc-clone
Daniel Lezcano
daniel.lezcano at free.fr
Tue Apr 5 11:29:31 UTC 2011
On 03/30/2011 06:29 PM, Serge E. Hallyn wrote:
> I've replaced most of my previous use of kvm and cloud instances for bug
> investigations with lxc instances. To emulate my older workflows, I've
> created lxc-clone. My diff against the current natty lxc package is
> attached. I've written up how I use this at s3hh.wordpress.com. Briefly,
> I have a single pristine container, with LVM rootfs, for each of lucid,
> maverick, and natty. When I want a container, I
>
> lxc-clone -o natty -n n1 -s
> lxc-start -n n1
>
> which takes about 5 seconds altogether. Ruin n1 however I like, and
>
> lxc-destroy -l -n n1
>
> when done.
>
> It needs fleshing out, but it's at the point where it does exactly what
> I need. The next thing I'm likely to add will be btrfs snapshotting,
> not sure when.
>
> Daniel, is this something you'd consider adding? I assume that if so,
> then there are changes you'd like to make to the interface :)
Hi Serge,
yes, it is an interesting feature, thanks for the patch.
I think more configuration tweaking will be needed but this patch looks
good for me.
> === modified file 'configure.ac'
> --- configure.ac 2011-03-10 07:25:34 +0000
> +++ configure.ac 2011-03-30 15:36:58 +0000
> @@ -156,6 +156,7 @@
> src/lxc/lxc-setuid
> src/lxc/lxc-version
> src/lxc/lxc-create
> + src/lxc/lxc-clone
> src/lxc/lxc-destroy
>
> ])
>
> === modified file 'lxc.spec'
It should be lxc.spec.in
> --- lxc.spec 2011-03-10 07:25:34 +0000
> +++ lxc.spec 2011-03-30 15:36:58 +0000
> @@ -78,6 +78,7 @@
> %{_bindir}/*
> %attr(4111,root,root) %{_bindir}/lxc-attach
> %attr(4111,root,root) %{_bindir}/lxc-create
> +%attr(4111,root,root) %{_bindir}/lxc-clone
> %attr(4111,root,root) %{_bindir}/lxc-start
> %attr(4111,root,root) %{_bindir}/lxc-netstat
> %attr(4111,root,root) %{_bindir}/lxc-unshare
>
> === modified file 'src/lxc/Makefile.am'
> --- src/lxc/Makefile.am 2011-03-10 07:25:34 +0000
> +++ src/lxc/Makefile.am 2011-03-30 15:36:58 +0000
> @@ -72,6 +72,7 @@
> lxc-setuid \
> lxc-version \
> lxc-create \
> + lxc-clone \
> lxc-destroy
>
> bin_PROGRAMS = \
>
> === modified file 'src/lxc/Makefile.in'
Makefile.in is generated. I suppose it is the diff command which
integrated the configure and Makefile.in in the diff result.
> === added file 'src/lxc/lxc-clone.in'
> --- src/lxc/lxc-clone.in 1970-01-01 00:00:00 +0000
> +++ src/lxc/lxc-clone.in 2011-03-30 15:36:58 +0000
> @@ -0,0 +1,206 @@
> +#!/bin/bash
> +
> +#
> +# lxc: linux Container library
> +
> +# Authors:
> +# Serge Hallyn<serge.hallyn at ubuntu.com>
> +# Daniel Lezcano<daniel.lezcano at 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
> +
> +usage() {
> + echo "usage: lxc-clone -o<orig> -n<new> [-s] [-h] [-L fssize] [-v vgname]"
> +}
> +
> +help() {
> + usage
> + echo
> + echo "creates a lxc system object."
> + echo
> + echo "Options:"
> + echo "orig : name of the original container"
> + echo "new : name of the new container"
> + echo "-s : make the new rootfs a snapshot of the original"
> + echo "fssize : size if creating a new fs. By default, 2G"
> + echo "vgname : lvm volume group name, lxc by default"
> +}
> +
> +shortoptions='ho:n:sL:v:'
> +longoptions='help,orig:,name:,snapshot,fssize,vgname'
> +lxc_path=/var/lib/lxc
> +bindir=/usr/bin
> +snapshot=no
> +lxc_size=2G
> +lxc_vg=lxc
> +
> +getopt=$(getopt -o $shortoptions --longoptions $longoptions -- "$@")
> +if [ $? != 0 ]; then
> + usage
> + exit 1;
> +fi
> +
> +eval set -- "$getopt"
> +
> +while true; do
> + case "$1" in
> + -h|--help)
> + help
> + exit 1
> + ;;
> + -s|--snapshot)
> + shift
> + snapshot=yes
> + ;;
> + -o|--orig)
> + shift
> + lxc_orig=$1
> + shift
> + ;;
> + -L|--fssize)
> + shift
> + lxc_size=$1
> + shift
> + ;;
> + -v|--vgname)
> + shift
> + lxc_vg=$1
> + shift
> + ;;
> + -n|--new)
> + shift
> + lxc_new=$1
> + shift
> + ;;
> + --)
> + shift
> + break;;
> + *)
> + echo $1
> + usage
> + exit 1
> + ;;
> + esac
> +done
> +
> +if [ -z "$lxc_path" ]; then
> + echo "no configuration path defined !"
> + exit 1
> +fi
> +
> +if [ ! -r $lxc_path ]; then
> + echo "configuration path '$lxc_path' not found"
> + exit 1
> +fi
> +
> +if [ -z "$lxc_orig" ]; then
> + echo "no original container name specified"
> + usage
> + exit 1
> +fi
> +
> +if [ -z "$lxc_new" ]; then
> + echo "no new container name specified"
> + usage
> + exit 1
> +fi
> +
> +if [ "$(id -u)" != "0" ]; then
> + echo "This command has to be run as root"
> + exit 1
> +fi
> +
> +if [ ! -r $lxc_path ]; then
> + echo "no configuration path defined !"
> + exit 1
> +fi
> +
> +if [ ! -d "$lxc_path/$lxc_orig" ]; then
> + echo "'$lxc_orig' does not exist"
> + exit 1
> +fi
> +
> +if [ -d "$lxc_path/$lxc_new" ]; then
> + echo "'$lxc_new' already exists"
> + exit 1
> +fi
> +
> +trap "${bindir}/lxc-destroy -n $lxc_new; echo aborted; exit 1" SIGHUP SIGINT SIGTERM
> +
> +mkdir -p $lxc_path/$lxc_new
> +
> +echo "Tweaking configuration"
> +cp $lxc_path/$lxc_orig/config $lxc_path/$lxc_new/config
> +sed -i '/lxc.utsname/d' $lxc_path/$lxc_new/config
> +echo "lxc.utsname = $hostname">> $lxc_path/$lxc_new/config
We should not assume lxc.utsname is in the configuration file in order
to not write a hostname in all the cases.
The user may want to let the container to setup itself the hostname.
> +
> +sed -i '/lxc.mount/d' $lxc_path/$lxc_new/config
> +echo "lxc.mount = $lxc_path/$lxc_new/fstab">> $lxc_path/$lxc_new/config
> +
> +cp $lxc_path/$lxc_orig/fstab $lxc_path/$lxc_new/fstab
> +sed -i "s@$lxc_path/$lxc_orig@$lxc_path/$lxc_new@" $lxc_path/$lxc_new/fstab
Same comment.
> +echo "Copying rootfs..."
> +rootfs=$lxc_path/$lxc_new/rootfs
> +# First figure out if the old is a device. For now we only support
> +# lvm devices.
> +mounted=0
> +sed -i '/lxc.rootfs/d' $lxc_path/$lxc_new/config
> +oldroot=`grep lxc.rootfs $lxc_path/$lxc_orig/config | awk -F= '{ print $2 '}`
> +if [ -b $oldroot ]; then
> + # this is a device. If we don't want to snapshot, then mkfs, mount
> + # and rsync. Trivial but not yet implemented
> + if [ $snapshot == "no" ]; then
> + echo "non-snapshot and non-lvm clone of block device not yet implemented"
> + exit 1
> + fi
> + lvdisplay $oldroot> /dev/null 2>&1
> + if [ $? -ne 0 ]; then
> + echo "non-snapshot and non-lvm clone of block device not yet implemented"
> + exit 1
> + fi
> + # ok, create a snapshot of the lvm device
> + lvcreate -s -L $lxc_size -n $lxc_new /dev/$lxc_vg/$lxc_orig || exit 1
> + echo "lxc.rootfs = /dev/$lxc_vg/$lxc_new">> $lxc_path/$lxc_new/config
> + # and mount it so we can tweak it
> + mkdir -p $lxc_path/$lxc_new/rootfs
> + mount /dev/$lxc_vg/$lxc_new $rootfs || { echo "failed to mount new rootfs"; exit 1; }
> + mounted=1
> +else
> + cp -a $lxc_path/$lxc_orig/rootfs $lxc_path/$lxc_new/rootfs || return 1
> + echo "lxc.rootfs = $rootfs">> $lxc_path/$lxc_new/config
> +fi
> +
> +echo "Updating rootfs..."
> +hostname=$lxc_new
> +
> +# so you can 'ssh $hostname.' or 'ssh $hostname.local'
> +sed -i "s/send host-name.*$/send host-name $hostname/" $rootfs/etc/dhcp/dhclient.conf
> +
> +# set the hostname
> +cat<<EOF> $rootfs/etc/hostname
> +$hostname
> +EOF
> +# set minimal hosts
> +cat<<EOF> $rootfs/etc/hosts
> +127.0.0.1 localhost $hostname
> +EOF
> +
> +# if this was a block device, then umount it now
> +if [ $mounted -eq 1 ]; then
> + umount $rootfs
> +fi
> +
> +echo "'$lxc_new' created"
>
> === modified file 'src/lxc/lxc-destroy.in'
> --- src/lxc/lxc-destroy.in 2010-01-10 10:40:21 +0000
> +++ src/lxc/lxc-destroy.in 2011-03-29 23:00:34 +0000
> @@ -26,7 +26,8 @@
> #
>
> usage() {
> - echo "usage: $0 -n<name>"
> + echo "usage: $0 -n<name> [-l]"
> + echo " if -l is specified, attempt to lvremove the rootfs device"
> }
>
> if [ "$(id -u)" != "0" ]; then
> @@ -34,9 +35,9 @@
> exit 1
> fi
>
> -shortoptions='n:'
> -longoptions='name:'
> -lxc_path=@LXCPATH@
> +shortoptions='n:l'
> +longoptions='name:,lvm'
> +lxc_path=/var/lib/lxc
>
> getopt=$(getopt -o $shortoptions --longoptions $longoptions -- "$@")
> if [ $? != 0 ]; then
> @@ -46,6 +47,8 @@
>
> eval set -- "$getopt"
>
> +lvremove=0
> +
> while true; do
> case "$1" in
> -n|--name)
> @@ -53,6 +56,10 @@
> lxc_name=$1
> shift
> ;;
> + -l|--lvm)
> + shift
> + lvremove=1
> + ;;
> --)
> shift
> break;;
> @@ -75,5 +82,13 @@
> exit 1
> fi
>
> +if [ $lvremove -eq 1 ]; then
> + rootdev=`grep lxc.rootfs $lxc_path/$lxc_name/config | awk -F= '{ print $2 '}`
> + # only makes sense if it is a blockdev or a symlink to one
> + if [ -b $rootdev -o -h $rootdev ]; then
> + lvremove $rootdev
> + fi
> +fi
> +
> # recursively remove the container to remove old container configuration
> rm -rf --preserve-root $lxc_path/$lxc_name
More information about the lxc-users
mailing list