Permalink
Cannot retrieve contributors at this time
Fetching contributors…
| #!/bin/bash | |
| # | |
| # Creates a ubuntu based container | |
| # | |
| # This script is based on the lxc-ubuntu example script that ships with lxc. | |
| # | |
| # Copyright (C) 2010 Nigel McNie | |
| # Modified for Ubuntu 2010 phbaer | |
| # Modified some more 2011 David Schoen | |
| # | |
| ################################################################################ | |
| # change log | |
| ################################################################################ | |
| # 2011-08-02 - 2011-08-03 | |
| # - simplified argument parsing and usage/help messages for future refactoring | |
| # - adjusted all variables to not be UPPER case to ensure no risk of ENV variable overlap | |
| # - consolidated config variable initialisation | |
| # - added defaults so that just running './lxc-ubuntu' is sufficient | |
| # - set a default root password to 'lxc' | |
| # - add --arch, --mirror, --device and --yes cli args | |
| # - broke backwards compatibility a little, run with: './lxc-ubuntu ... --device auto' to preserve old behavior | |
| ################################################################################ | |
| # ubuntu custom configuration files | |
| ################################################################################ | |
| # Disable selinux in the container | |
| write_ubuntu_selinux() { | |
| mkdir -p $rootfs/selinux | |
| echo 0 > $rootfs/selinux/enforce | |
| } | |
| # Write out a custom fstab | |
| write_ubuntu_fstab() { | |
| cat <<EOF > $rootfs/etc/fstab | |
| tmpfs /dev/shm tmpfs defaults 0 0 | |
| EOF | |
| } | |
| # Write out network config (dhcp) | |
| write_ubuntu_network() { | |
| cat <<EOF > $rootfs/etc/network/interfaces | |
| auto lo | |
| iface lo inet loopback | |
| EOF | |
| if [ -z "$static_ip4" ] ; then | |
| ## no static address set: enable DHCP | |
| cat <<EOF > $rootfs/etc/network/interfaces | |
| auto eth0 | |
| iface eth0 inet dhcp | |
| EOF | |
| cat <<EOF >> $rootfs/etc/dhcp/dhclient.conf | |
| send host-name "$utsname"; | |
| EOF | |
| else | |
| ## fixed address | |
| cat <<EOF >> $rootfs/etc/network/interfaces | |
| auto eth0 | |
| iface eth0 inet static | |
| address $address | |
| netmask $netmask | |
| gateway $gateway | |
| EOF | |
| ## resolver config | |
| if [ -n "$nameserver" ] ; then | |
| cat <<EOF >> $rootfs/etc/resolv.conf | |
| nameserver $nameserver | |
| EOF | |
| fi | |
| fi | |
| } | |
| # Set the hostname for the container | |
| write_ubuntu_hostname() { | |
| cat <<EOF > $rootfs/etc/hostname | |
| $utsname | |
| EOF | |
| cat <<EOF > $rootfs/etc/hosts | |
| 127.0.0.1 $utsname localhost | |
| # The following lines are desirable for IPv6 capable hosts | |
| ::1 localhost ip6-localhost ip6-loopback | |
| fe00::0 ip6-localnet | |
| ff00::0 ip6-mcastprefix | |
| ff02::1 ip6-allnodes | |
| ff02::2 ip6-allrouters | |
| ff02::3 ip6-allhosts | |
| EOF | |
| } | |
| # Writes a custom ssh config that allows root logins | |
| write_ubuntu_sshd_config() { | |
| cat <<EOF > $rootfs/etc/ssh/sshd_config | |
| Port 22 | |
| Protocol 2 | |
| HostKey /etc/ssh/ssh_host_rsa_key | |
| HostKey /etc/ssh/ssh_host_dsa_key | |
| UsePrivilegeSeparation yes | |
| KeyRegenerationInterval 3600 | |
| ServerKeyBits 768 | |
| SyslogFacility AUTH | |
| LogLevel INFO | |
| LoginGraceTime 120 | |
| PermitRootLogin yes | |
| StrictModes yes | |
| RSAAuthentication yes | |
| PubkeyAuthentication yes | |
| IgnoreRhosts yes | |
| RhostsRSAAuthentication no | |
| HostbasedAuthentication no | |
| PermitEmptyPasswords yes | |
| ChallengeResponseAuthentication no | |
| EOF | |
| } | |
| # Autoconfigures packages in the container so no debconf questions are asked | |
| # when it's made | |
| reconfigure_ubuntu_packages() { | |
| default_environment_locale=$(debconf-show locales | grep default_environment_locale | cut -f 2 -d :) | |
| locales_to_be_generated=$(debconf-show locales | grep locales_to_be_generated | cut -f 2 -d :) | |
| tzdata_area=$(debconf-show tzdata | grep Areas | cut -f 2 -d :) | |
| tzdata_zone=$(debconf-show tzdata | grep Zones/${tzdata_area:1} | cut -f 2 -d :) | |
| cat <<EOF | chroot $rootfs sh | |
| #!/bin/sh | |
| apt-get install --force-yes -y language-pack-en | |
| update-locale LANG="en_GB.UTF-8" LANGUAGE="en_GB.UTF-8" LC_ALL="en_GB.UTF-8" | |
| EOF | |
| } | |
| # set root's password to 'lxc' | |
| reset_root_password() { | |
| sed -i 's%^root:.*%root:$6$EEGUnn6e$DkpHEGpLyyFW/QePxZjsTvix9E7c8YPdH6RF4BYx8yagQMySPYkmjKMPLyrE7ZpNxUh0huqMCfSLcIct7/puH/:15248:0:99999:7:::%' $rootfs/etc/shadow | |
| } | |
| # create root's SSH authorized_keys file | |
| write_root_authkey() { | |
| mkdir -p $rootfs/root/.ssh | |
| local f=$rootfs/root/.ssh/authorized_keys | |
| cp "$1" "$f" | |
| chmod 644 "$f" | |
| chown root:root "$f" | |
| } | |
| disable_upstart_mounts() { | |
| cat <<EOF > $rootfs/lib/init/fstab | |
| # | |
| # These are the filesystems that are always mounted on boot, you can | |
| # override any of these by copying the appropriate line from this file into | |
| # /etc/fstab and tweaking it as you see fit. See fstab(5). | |
| # | |
| # <file system> <mount point> <type> <options> <dump> <pass> | |
| /dev/root / rootfs defaults 0 1 | |
| #none /proc proc nodev,noexec,nosuid 0 0 | |
| none /proc/sys/fs/binfmt_misc binfmt_misc nodev,noexec,nosuid,optional 0 0 | |
| #none /sys sysfs nodev,noexec,nosuid 0 0 | |
| none /sys/fs/fuse/connections fusectl optional 0 0 | |
| none /sys/kernel/debug debugfs optional 0 0 | |
| none /sys/kernel/security securityfs optional 0 0 | |
| none /spu spufs gid=spu,optional 0 0 | |
| #none /dev devtmpfs,tmpfs mode=0755 0 0 | |
| none /dev/pts devpts noexec,nosuid,gid=tty,mode=0620 0 0 | |
| none /dev/shm tmpfs nosuid,nodev 0 0 | |
| none /tmp none defaults 0 0 | |
| none /var/run tmpfs mode=0755,nosuid,showthrough 0 0 | |
| none /var/lock tmpfs nodev,noexec,nosuid,showthrough 0 0 | |
| none /lib/init/rw tmpfs mode=0755,nosuid,optional 0 0 | |
| EOF | |
| } | |
| modify_upstart_sysinit() { | |
| sed -i 's/start on filesystem and net-device-up IFACE=lo/start on filesystem #and net-device-up IFACE=lo/' $rootfs/etc/init/rc-sysinit.conf | |
| } | |
| write_upstart_lxc() { | |
| cat <<EOF > $rootfs/etc/init/lxc.conf | |
| # LXC – Fix init sequence to have LXC containers boot with upstart | |
| # description “Fix LXC container” | |
| start on startup | |
| task | |
| pre-start script | |
| mount -t proc proc /proc | |
| mount -t devpts devpts /dev/pts | |
| mount -t sysfs sys /sys | |
| mount -t tmpfs varrun /var/run | |
| mount -t tmpfs varlock /var/lock | |
| mkdir -p /var/run/network | |
| touch /var/run/utmp | |
| chmod 664 /var/run/utmp | |
| chown root.utmp /var/run/utmp | |
| if [ "$(find /etc/network/ -name upstart -type f)" ]; then | |
| chmod -x /etc/network/*/upstart || true | |
| fi | |
| end script | |
| script | |
| start networking | |
| initctl emit filesystem --no-wait | |
| initctl emit local-filesystems --no-wait | |
| initctl emit virtual-filesystems --no-wait | |
| init 2 | |
| end script | |
| EOF | |
| mkdir -p $rootfs/var/run/network | |
| touch $rootfs/var/run/network/ifstate | |
| mkdir -p $rootfs/var/run/sshd | |
| } | |
| # Disables services a container doesn't need | |
| disable_ubuntu_services() { | |
| 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 | |
| } | |
| ################################################################################ | |
| # lxc configuration files | |
| ################################################################################ | |
| write_lxc_configuration() { | |
| cat <<EOF > $conffile | |
| lxc.utsname = $utsname | |
| lxc.tty = 6 | |
| lxc.pts = 1024 | |
| lxc.network.type = veth | |
| lxc.network.flags = up | |
| lxc.network.link = $bridge | |
| lxc.network.name = eth0 | |
| lxc.network.mtu = $mtu | |
| lxc.rootfs = $rootfs | |
| #lxc.mount = $tmpmntfile | |
| lxc.cgroup.devices.deny = a | |
| # /dev/null and zero | |
| lxc.cgroup.devices.allow = c 1:3 rwm | |
| lxc.cgroup.devices.allow = c 1:5 rwm | |
| # 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 | |
| # rtc | |
| lxc.cgroup.devices.allow = c 254:0 rwm | |
| EOF | |
| } | |
| write_lxc_mounts() { | |
| tmpmntfile=$(mktemp lxc.XXXXXXXXXX) | |
| if [ ! -z "$mntfile" ]; then | |
| cp $mntfile $tmpmntfile | |
| fi | |
| } | |
| collect_information() { | |
| [[ $interactive = yes ]] || return | |
| # choose a hostname, default is the container name | |
| echo -n "What hostname do you wish for this container ? [$utsname] " | |
| read _utsname_ | |
| if [ ! -z "$_utsname_" ]; then | |
| utsname=$_utsname_ | |
| fi | |
| echo -n "Specify the location for an extra fstab file [(none)] " | |
| read _mntfile_ | |
| if [ ! -z "$_mntfile_" ]; then | |
| mntfile=$_mntfile_ | |
| fi | |
| echo "Choose the architecture for the container (choices as for deboostrap, e.g.: amd64, i386" | |
| echo -n "Choice ? [$arch] " | |
| read _arch_ | |
| if [ ! -z "$_arch_" ]; then | |
| arch=$_arch_ | |
| fi | |
| # choose a mirror | |
| echo -n "Specify the ubuntu mirror to use to download the rootfs [$debmirror] " | |
| read _debmirror_ | |
| if [ ! -z "$_debmirror_" ]; then | |
| debmirror=$_debmirror_ | |
| fi | |
| } | |
| install_ubuntu() | |
| { | |
| case $arch in | |
| amd64|i386) ;; | |
| *) echo "Unsupported architecture $arch!"; exit 1;; | |
| esac | |
| # download a mini ubuntu into a cache | |
| echo "Downloading ubuntu minimal ..." | |
| debootstrap --verbose --variant=minbase --arch=$arch \ | |
| --include ifupdown,locales,netbase,net-tools,iproute,openssh-server,isc-dhcp-client,gpgv,adduser,apt-utils,vim,openssh-blacklist,openssh-blacklist-extra,console-setup,sudo,iputils-ping,aptitude,ubuntu-minimal \ | |
| $release $rootfs $debmirror | |
| resULT=$? | |
| if [ "$resULT" != "0" ]; then | |
| echo "Failed to download the rootfs, aborting." | |
| exit 1 | |
| fi | |
| } | |
| run_pre_create_hook() { | |
| # source a hook that's run before the container is created | |
| # sourced so it has access to our variables, like $utsname | |
| test -x /etc/lxc-ubuntu/host-pre-create && . /etc/lxc-ubuntu/host-pre-create | |
| } | |
| run_post_create_hooks() { | |
| # source host and guest hooks for after the container is created | |
| test -x /etc/lxc-ubuntu/host-post-create && . /etc/lxc-ubuntu/host-post-create | |
| if [ -x /etc/lxc-ubuntu/guest-post-create ]; then | |
| cp /etc/lxc-ubuntu/guest-post-create $rootfs/guest-post-create | |
| chroot $rootfs /bin/bash /guest-post-create | |
| chroot $rootfs /bin/rm /guest-post-create | |
| fi | |
| } | |
| create() { | |
| collect_information | |
| write_lxc_mounts | |
| write_lxc_configuration | |
| /usr/bin/lxc-create -n $utsname -f $conffile | |
| res=$? | |
| # remove the configuration files | |
| rm -f $conffile | |
| rm -f $tmpmntfile | |
| if [ "$res" != "0" ]; then | |
| echo "Failed to create '$utsname'" | |
| exit 1 | |
| fi | |
| mkdir -p $rootfs | |
| if [[ ! -z $device ]]; then | |
| if ! mount "$device" "$rootfs"; then | |
| echo "Failed to mount $device" | |
| lxc-destroy -n "$utsname" | |
| exit 1 | |
| fi | |
| fi | |
| install_ubuntu | |
| write_ubuntu_hostname | |
| write_ubuntu_fstab | |
| write_ubuntu_network | |
| write_ubuntu_selinux | |
| reconfigure_ubuntu_packages | |
| disable_ubuntu_services | |
| run_pre_create_hook | |
| run_post_create_hooks | |
| disable_upstart_mounts | |
| modify_upstart_sysinit | |
| write_upstart_lxc | |
| if [ -z "$root_authkey" ] ; then | |
| write_ubuntu_sshd_config | |
| reset_root_password | |
| else | |
| write_root_authkey "$root_authkey" | |
| fi | |
| echo "Done." | |
| echo -e "\nYou can run your container with the 'lxc-start -n $utsname'\n" | |
| if [ -z "$root_authkey" ] ; then | |
| echo -e "\nYou can login to your container over SSH as root with password 'lxc'\n" | |
| else | |
| echo -e "\nYou can login to your container over SSH as root with the authkey you have provided\n" | |
| fi | |
| } | |
| destroy() { | |
| echo -n "This will PERMANENTLY DESTROY the container $utsname. Are you sure? [y/N] ? " | |
| read reply | |
| if [ "$reply" != "y" ]; then | |
| echo "Abort." | |
| exit | |
| fi | |
| halt=$(which lxc-halt-container) | |
| if lxc-info -n $utsname | grep RUNNING > /dev/null; then | |
| if [ -n "$halt" ]; then | |
| lxc-halt-container -n $utsname | |
| else | |
| lxc-stop -n $utsname | |
| fi | |
| fi | |
| sleep .5 | |
| rm -rf $rootfs | |
| /usr/bin/lxc-destroy -n $utsname | |
| RETVAL=$? | |
| if [ ! $RETVAL -eq 0 ]; then | |
| echo "Failed to destroy '$utsname'" | |
| return $RETVAL | |
| fi | |
| return 0 | |
| } | |
| usage() { | |
| echo "Usage: $0 [command] [options]" | |
| echo | |
| echo "Example: $0 create -n ubuntu" | |
| echo | |
| echo "This script is a helper to create ubuntu system containers." | |
| echo | |
| echo "The script will create the container configuration file following" | |
| echo "the information submitted interactively with 'lxc-ubuntu create'" | |
| echo "or as options outlined below." | |
| echo | |
| echo "Command: default is 'create'" | |
| echo " create: Create a new lxc" | |
| echo " destroy: Destroy an existing lxc" | |
| echo | |
| echo "Options:" | |
| echo " -n|--name <name>: name of lxc, default is 'ubuntu'" | |
| echo " -h|-help|--help: display this helpful message" | |
| echo " --mirror <deb mirror>: defaults to http://archive.ubuntu.com/ubuntu" | |
| echo " --arch <i386|amd64>: dpkg arch type" | |
| echo " --release <hardy|intrepid|jaunty|karmic|lucid|oneiric> : debian release" | |
| echo " --root-authkey <file>: use publickey-based authentication for root, no password authetication for root" | |
| echo " -y|--yes: assume defaults are correct for all questions, do not ask interactive questions" | |
| echo " --device </dev/foo>: specify some device to mount as the rootfs of the lxc, 'auto' will use /dev/vg0/lxc-<name>" | |
| echo " --bridge IFNAME" | |
| echo " --static-ip4 IPADDR NETMASK GATEWAY DNSSERVER" | |
| echo | |
| echo "Have fun :)" | |
| } | |
| # Main program | |
| if [ "$(id -u)" != "0" ]; then | |
| echo "This script should be run as 'root'" | |
| exit 1 | |
| fi | |
| bridge=br0 | |
| static_ip4="" | |
| # parse cli args | |
| while true; do | |
| [[ -z $1 ]] && break | |
| case "$1" in | |
| -h|-help|--help) | |
| usage | |
| exit 0 | |
| ;; | |
| -n|--name) | |
| utsname="$2" | |
| shift # remove name from remaining arguments | |
| ;; | |
| create|destroy) | |
| command="$1" | |
| ;; | |
| --mirror) | |
| debmirror="$2" | |
| shift | |
| ;; | |
| --release) | |
| release="$2" | |
| shift | |
| ;; | |
| --arch) | |
| arch="$2" | |
| shift | |
| ;; | |
| --device) | |
| device="$2" | |
| shift | |
| ;; | |
| --root-authkey) | |
| root_authkey="$2" | |
| shift | |
| ;; | |
| --bridge) | |
| bridge="$2" | |
| shift | |
| ;; | |
| --static-ip4) | |
| if [ $# -lt 5 ] ; then usage; exit; fi | |
| address="$2" | |
| shift | |
| netmask="$2" | |
| shift | |
| gateway="$2" | |
| shift | |
| nameserver="$2" | |
| shift | |
| static_ip4=yes | |
| ;; | |
| -y|--yes) | |
| interactive=no | |
| ;; | |
| *) | |
| echo "ERROR: Unknown argument $1" | |
| echo | |
| usage | |
| exit 1 | |
| ;; | |
| esac | |
| shift | |
| done | |
| utsname="${utsname:-ubuntu}" # default lxc name of "ubuntu" | |
| command="${command:-create}" # default command is to "create" | |
| interactive="${interactive:-yes}" | |
| mntfile= | |
| tmpmntfile= | |
| mtu="1500" | |
| debmirror="${debmirror:-http://archive.ubuntu.com/ubuntu}" | |
| fqdn=$(hostname --fqdn) | |
| conffile="/var/lib/lxc/$utsname.conf" | |
| rootfs="/var/lib/lxc/$utsname/rootfs" | |
| arch="${arch:-$(dpkg --print-architecture)}" | |
| release="${release:-$(lsb_release -s -c)}" | |
| device="${device:-}" | |
| [[ $device = auto ]] && device="/dev/vg0/lxc-$utsname" | |
| $command | |
| # vim: et sw=4 ts=4 |