Skip to content

Instantly share code, notes, and snippets.

@nelsnelson
Created March 17, 2014 15:54
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nelsnelson/9601966 to your computer and use it in GitHub Desktop.
Save nelsnelson/9601966 to your computer and use it in GitHub Desktop.
Template for LXC intended to provide a minimal rootfs and ran as a daemon
#!/bin/bash
#
# lxc: linux Container library
# Authors:
# Daniel Lezcano <daniel.lezcano@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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
# Detect use under userns (unsupported)
for arg in "$@"; do
[ "$arg" = "--" ] && break
if [ "$arg" = "--mapped-uid" -o "$arg" = "--mapped-gid" ]; then
echo "This template can't be used for unprivileged containers." 1>&2
echo "You may want to try the \"download\" template instead." 1>&2
exit 1
fi
done
# Make sure the usual locations are in PATH
export PATH=$PATH:/usr/sbin:/usr/bin:/sbin:/bin
install_minimal()
{
rootfs=$1
tree="\
$rootfs/var/run/minimal \
$rootfs/var/empty/minimal \
$rootfs/var/lib/empty/minimal \
$rootfs/etc/init.d \
$rootfs/etc/rc.d \
$rootfs/etc/sysconfig/network-scripts \
$rootfs/dev/shm \
$rootfs/run/shm \
$rootfs/proc \
$rootfs/sys \
$rootfs/bin \
$rootfs/sbin \
$rootfs/usr \
$rootfs/tmp \
$rootfs/home \
$rootfs/root \
$rootfs/lib \
$rootfs/lib64"
mkdir -p $tree
if [ $? -ne 0 ]; then
return 1
fi
return 0
}
configure_minimal()
{
rootfs=$1
cat <<EOF > $rootfs/etc/passwd
root:x:0:0:root:/root:/bin/bash
EOF
cat <<EOF > $rootfs/etc/group
root:x:0:root
EOF
return 0
}
copy_configuration()
{
path=$1
rootfs=$2
name=$3
grep -q "^lxc.rootfs" $path/config 2>/dev/null || echo "lxc.rootfs = $rootfs" >> $path/config
cat <<EOF >> $path/config
lxc.utsname = $name
lxc.pts = 1024
lxc.kmsg = 0
lxc.cap.drop = sys_module mac_admin mac_override sys_time
# When using LXC with apparmor, uncomment the next line to run unconfined:
#lxc.aa_profile = unconfined
lxc.mount.entry = /dev dev none ro,bind 0 0
lxc.mount.entry = /lib lib none ro,bind 0 0
lxc.mount.entry = /bin bin none ro,bind 0 0
lxc.mount.entry = /usr usr none ro,bind 0 0
lxc.mount.entry = /sbin sbin none ro,bind 0 0
lxc.mount.entry = /usr/share/lxc/templates/lxc-minimal sbin/init none ro,bind 0 0
lxc.mount.entry = proc proc proc nodev,noexec,nosuid 0 0
lxc.mount.entry = sysfs sys sysfs ro 0 0
lxc.mount.entry = /etc/init.d etc/init.d none ro,bind 0 0
EOF
# Oracle Linux and Fedora need the following two bind mounted
if [ -d /etc/sysconfig/network-scripts ]; then
cat <<EOF >> $path/config
lxc.mount.entry = /etc/sysconfig/network-scripts etc/sysconfig/network-scripts none ro,bind 0 0
EOF
fi
if [ -d /etc/rc.d ]; then
cat <<EOF >> $path/config
lxc.mount.entry = /etc/rc.d etc/rc.d none ro,bind 0 0
EOF
fi
# if no .ipv4 section in config, then have the container run dhcp
grep -q "^lxc.network.ipv4" $path/config || touch $rootfs/run-dhcp
if [ "$(uname -m)" = "x86_64" ]; then
cat <<EOF >> $path/config
lxc.mount.entry = /lib64 lib64 none ro,bind 0 0
EOF
fi
}
usage()
{
cat <<EOF
$1 -h|--help -p|--path=<path> [--rootfs=<path>]
EOF
return 0
}
check_for_cmd()
{
cmd_path=`type $1`
if [ $? -ne 0 ]; then
echo "The command '$1' $cmd_path is not accessible on the system"
exit 1
fi
# we use cut instead of awk because awk is alternatives symlink on ubuntu
# and /etc/alternatives isn't bind mounted
cmd_path=`echo $cmd_path |cut -d ' ' -f 3`
}
options=$(getopt -o hp:n:S: -l help,rootfs:,path:,name: -- "$@")
if [ $? -ne 0 ]; then
usage $(basename $0)
exit 1
fi
eval set -- "$options"
while true
do
case "$1" in
-h|--help) usage $0 && exit 0;;
-p|--path) path=$2; shift 2;;
--rootfs) rootfs=$2; shift 2;;
-n|--name) name=$2; shift 2;;
--) shift 1; break ;;
*) break ;;
esac
done
if [ "$(id -u)" != "0" ]; then
echo "This script should be run as 'root'"
exit 1
fi
cat << 'EOF' > /tmp/boringd
#! /usr/bin/env bash
/usr/bin/daemon -- watch ls /tmp
EOF
chmod +x /tmp/boringd
if [ $0 = "/sbin/init" ]; then
PATH="$PATH:/bin:/sbin:/usr/sbin"
check_for_cmd /usr/lib/lxc/lxc-init
check_for_cmd /tmp/boringd
daemon_path=$cmd_path
echo "init'ing with ${daemon_path}"
exec /usr/lib/lxc/lxc-init -- $daemon_path
exit 1
fi
if [ -z "$path" ]; then
echo "'path' parameter is required"
exit 1
fi
# detect rootfs
config="$path/config"
if [ -z "$rootfs" ]; then
if grep -q '^lxc.rootfs' $config 2>/dev/null ; then
rootfs=$(awk -F= '/^lxc.rootfs =/{ print $2 }' $config)
else
rootfs=$path/rootfs
fi
fi
install_minimal $rootfs
if [ $? -ne 0 ]; then
echo "failed to install minimal's rootfs"
exit 1
fi
configure_minimal $rootfs
if [ $? -ne 0 ]; then
echo "failed to configure minimal template"
exit 1
fi
copy_configuration $path $rootfs $name
if [ $? -ne 0 ]; then
echo "failed to write configuration file"
exit 1
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment