Skip to content

Instantly share code, notes, and snippets.

@ChrisWeiss
Created March 10, 2017 22:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ChrisWeiss/228f00622b606880574b18bcd98f6c21 to your computer and use it in GitHub Desktop.
Save ChrisWeiss/228f00622b606880574b18bcd98f6c21 to your computer and use it in GitHub Desktop.
Creating containers by hand (the hard way)
# List the contents of the current directory
root@host:/# ls
bin dev home lib lost+found mnt proc run srv tmp vagrant vmlinuz
boot etc initrd.img lib64 media opt root sbin sys usr var
# Bind mount 'dev' and 'proc' filesystems from the host
root@host:/# TARGET="/var/some-chroot"
root@host:/# mkdir -p ${TARGET}/{dev,proc,bin,lib,lib64}
root@host:/# mount --bind /dev ${TARGET}/dev
root@host:/# mount --bind /proc ${TARGET}/proc
# Determine libraries needed by the 'sh' shell
root@host:/# ldd /bin/sh
linux-vdso.so.1 => (0x00007fff6e3bb000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f056052b000)
/lib64/ld-linux-x86-64.so.2 (0x00007f0560b10000)
# Copy files
root@host:/# cp -afL /lib/x86_64-linux-gnu/libc.so.6 ${TARGET}/lib/
root@host:/# cp -afL /lib64/ld-linux-x86-64.so.2 ${TARGET}/lib64/
root@host:/# cp -aL /bin/sh ${TARGET}/bin/
# Create and enter the chroot
root@host:/# chroot ${TARGET} /bin/sh
root@container:/# ls
/bin/sh: 1: ls: not found
# Run the Docker image; download the image if it isn’t already in the cache
$ docker run -it --rm -p 8080:80 nginx:1.10.1
Unable to find image 'nginx:1.10.1' locally
1.10.1: Pulling from library/nginx
...
4b2a7c26975a2c235c6b670a7ba9821b5222a3cbdd9c5b575f203abb08890c58
# Check the status of the image (output abbreviated)
$ docker ps --format 'table{{.ID}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}'
CONTAINER ID IMAGE STATUS PORTS
4b2a7c26975a nginx:1.10.1 Up 4 minutes 443/tcp, 0.0.0.0:8080->80/tcp
# Get the IP address of the ethernet interface on the host
# ip -4 addr show dev enp0s3 | grep inet
inet 10.0.2.15/24 brd 10.0.2.255 scope global enp0s3
# Use the 'download' template to get a list of all available images
# lxc-create -t download -n my-cn-01
...
# Enter the desired image details from the listing
Distribution: centos
Release: 7
Architecture: amd64
...
You just created a CentOS container (release=7, arch=amd64, variant=default)
# Start the container
# lxc-start -n my-cn-01 -d
# lxc-info -n my-cn-01
Name: my-cn-01
State: RUNNING
PID: 3825
IP: 10.0.3.15
CPU use: 0.57 seconds
BlkIO use: 6.63 MiB
Memory use: 28.18 MiB
KMem use: 0 bytes
Link: vethATHHIC
TX bytes: 1.42 KiB
RX bytes: 1.53 KiB
Total bytes: 2.95 KiB
# lxc-attach -n my-cn-01
bash-4.2# pwd
/
bash-4.2# ls
bin dev home lib64 mnt proc run selinux sys usr
boot etc lib media opt root sbin srv tmp var
bash-4.2# uname -a
Linux my-cn-01 4.4.0-38-generic #57-Ubuntu SMP Tue Sep 6 15:42:33 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
# Get the OS release of the host
root@host:/# cat /etc/os-release | grep PRETTY_NAME
PRETTY_NAME="Ubuntu 16.04.1 LTS"
# Create a new container and network namespace, using Debian stable as the rootfs
root@host:/# export TARGET="/var/some-chroot"
root@host:/# debootstrap stable ${TARGET} http://httpredir.debian.org/debian/
root@host:/# ip netns add netns1
root@host:/# unshare --mount --uts --ipc --net=/var/run/netns/netns1 --pid --fork sh
root@container:/# chroot ${TARGET} /bin/sh
root@container:/# mount -t proc none /proc
# You're now inside the container ...
root@container:/# cat /etc/os-release | grep PRETTY_NAME
PRETTY_NAME="Debian GNU/Linux 8 (jessie)"
root@container:/# ps
PID TTY TIME CMD
1 ? 00:00:00 sh
...
# ... but without networking, yet
root@container:/# ping localhost
connect: Network is unreachable
# In a separate process, configure the new network namespace
root@host:/# ip link add veth0 type veth peer name veth1
root@host:/# ip link set veth1 netns netns1
root@host:/# ip addr add 172.16.99.1/24 dev veth0
root@host:/# ip link set veth0 up
root@host:/# ip netns exec netns1 ip addr add 172.16.99.100/24 dev veth1
root@host:/# ip netns exec netns1 ip link set lo up
root@host:/# ip netns exec netns1 ip link set veth1 up
root@host:/# ip netns exec netns1 ip route add default via 172.16.99.1
# We now have local networking, but no access to the internet
root@container:/# ip route
default via 172.16.99.1 dev veth1
172.16.99.0/24 dev veth1 proto kernel scope link src 172.16.99.100
root@container:/# ping 172.16.99.100
PING 172.16.99.100 (172.16.99.100) 56(84) bytes of data.
64 bytes from 172.16.99.100: icmp_seq=1 ttl=64 time=0.019 ms
64 bytes from 172.16.99.100: icmp_seq=2 ttl=64 time=0.029 ms
^C
root@container:/# ping google.com
^C
# Configure the host to forward traffic from the container
root@host:/# echo 1 > /proc/sys/net/ipv4/ip_forward
root@host:/# iptables -P FORWARD DROP
root@host:/# iptables -F FORWARD
root@host:/# iptables -t nat -F
root@host:/# iptables -t nat -A POSTROUTING -s 172.16.99.100/24 -o enp0s3 -j MASQUERADE
root@host:/# iptables -A FORWARD -i enp0s3 -o veth0 -j ACCEPT
root@host:/# iptables -A FORWARD -o enp0s3 -i veth0 -j ACCEPT
root@container:/# ping google.com
PING google.com (216.58.195.238) 56(84) bytes of data.
64 bytes from sfo03s06-in-f238.1e100.net (216.58.195.238): icmp_seq=1 ttl=61 time=20.7 ms
64 bytes from sfo03s06-in-f238.1e100.net (216.58.195.238): icmp_seq=2 ttl=61 time=19.9 ms
^C
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment