1. 程式人生 > >Cloud in Action:Practice Docker and its Networking

Cloud in Action:Practice Docker and its Networking

docker lxc namespace

Cloud in Action: Practice Docker and its Networking on Ubuntu

薛國鋒 [email protected]

VM, LXC, Docker and Libcontainer

VMs and LXC (Linux Containers) differ on quite a few dimensions, but primarily LXC is a OS-level virtualization technology that allows creation and running of multiple isolated Linux virtual environments on a single control host, whereas with VMs, the hardware is being virtualized to run multiple OS instances. LXC sits on top of a physical server and its host OS, and each container shares the host OS kernel. The shared components are read-only and each container is able to be written to through a unique mount, which makes containers exceptionally “light”. Containers’ speed, agility and portability make them an important tool for DevOps.

技術分享圖片

Docker is a significant improvement and extension of LXC’s capabilities, and acts as a portable container engine, packaging the application and all its dependencies in a virtual container that can run on any Linux server, and making containers more protable and flexible to use. Using Docker containers, you can deploy, replicate, move, and back up a workload even more quickly and easily than you can do so using virtual machines. Basically, Docker brings cloudlike flexibility to any infrastructure capable of running containers.

技術分享圖片

Docker/LXC takes advantage of several features of the Linux kernel to deliver its functionality:

Namespace is to wrap a particular global system resource in an abstraction that makes it appear to the process within the namespace that they have their own isolated instance of the global resource. Currently there are 6 namespaces implemented in the Linux Kern

el: Mount, UTS, IPC, Network, PID and User.

Cgroups allow allocating resources to user-defined groups of processes running on the system. A cgroup limits an application to a specific set of resources.

UnionFS, Union file systems operate by creating layers, making them very lightweight and fast to privide the building blocks for containers.


LXC was used before Docker 1.10 as one execution driver, and offered a userspace interface for the Linux kernel containment features, which is very specific to Linux. Libcontainer is an abstraction layer being an attempt to standarize the way apps are packed up, delivered, and run in isolation, and support a wider range of isolation technologies, and could transform Docker into a cross-platform technology including Windows. Now Libcontainer is the default Docker execution environment.

技術分享圖片

It deserves mentioning that Windows server can’t run Linux containers in Docker format but only Windows containers, because Linux containers require the Linux APIs from the host kernel and Windows Server Containers require the Windows APIs of a host Windows kernel; however, the process of managing Linux and Windows containers are strictly identical.

技術分享圖片


Here is the quick summary: Container - Virtual Machine; Docker - Hypervisor (Xen,KVM); Kubernetes - OpenStack.


Practice Namespace

// Create a child process with the different namespace on UTS

gset@ubuntu:~$ gedit hello.c

#define _GNU_SOURCE

#include <sys/types.h>

#include <sys/wait.h>

#include <stdio.h>

#include <sched.h>

#include <signal.h>

#include <unistd.h>

#define STACK_SIZE (1024 * 1024)

static char child_stack[STACK_SIZE];

char * const child_args[] = { "/bin/bash", NULL};

int child_main1(void* args)

{

printf("Running in the child process!\n");

sethostname("XGF", 12);

execv(child_args[0], child_args);

return 1;

}

int main() {

printf("Get started in the main process: \n");

int child_pid1 = clone(child_main1, child_stack+STACK_SIZE,CLONE_NEWUTS | SIGCHLD, NULL);

waitpid(child_pid1, NULL, 0); // CLONE_NEWUTScreate a new UTS Namespace

printf("The main process exits\n");

return 0;

}

gset@ubuntu:~$ gcc hello.c -o hello.out

gset@ubuntu:~$

gset@ubuntu:~$ hostname

ubuntu

gset@ubuntu:~$ sudo ./hello.out

Get started in the main process:

Running in the child process!

root@XGF:~# hostname

XGF

root@XGF:~# exit

exit

The main process exits

gset@ubuntu:~$ hostname

ubuntu

// Create a network namespace - xgf, and connect it to Host with a pair of veth interfaces


技術分享圖片


gset@ubuntu:~$ sudo ip netns add xgf // create a network namespace - xgf

gset@ubuntu:~$ sudo ip link add veth-a type veth peer name veth-b // create a pair of veth interfaces: veth-a, veth-b

gset@ubuntu:~$ sudo ip link set veth-b netns xgf // move veth-b to the network namespace - xgf

gset@ubuntu:~$ sudo ip link set dev veth-a up

gset@ubuntu:~$ sudo ip addr add 10.110.0.1/24 dev veth-a

gset@ubuntu:~$ sudo ip netns exec xgf ip link set dev veth-b up // execute commands in the network namespace - xgf

gset@ubuntu:~$ sudo ip netns exec xgf ip addr add 10.110.0.2/24 dev veth-b

gset@ubuntu:~$ sudo ip netns exec xgf ip link set dev lo up

gset@ubuntu:~$ ip link/addr/route

gset@ubuntu:~$ sudo ip netns exec xgf ip link/addr/route

gset@ubuntu:~$ sudo ip netns list

gset@ubuntu:~$ ping 10.110.0.1

PING 10.110.0.1 (10.110.0.1) 56(84) bytes of data.

64 bytes from 10.110.0.1: icmp_seq=1 ttl=64 time=0.032 ms

gset@ubuntu:~$ ping 10.110.0.2

PING 10.110.0.2 (10.110.0.2) 56(84) bytes of data.

64 bytes from 10.110.0.2: icmp_seq=1 ttl=64 time=0.038 ms

gset@ubuntu:~$ sudo ip netns exec xgf ping 10.110.0.1

PING 10.110.0.1 (10.110.0.1) 56(84) bytes of data.

64 bytes from 10.110.0.1: icmp_seq=1 ttl=64 time=0.093 ms

gset@ubuntu:~$ sudo ip netns exec xgf ping 10.110.0.2

PING 10.110.0.2 (10.110.0.2) 56(84) bytes of data.

64 bytes from 10.110.0.2: icmp_seq=1 ttl=64 time=0.075 ms

gset@ubuntu:~$ ifconfig

veth-a Link encap:Ethernet HWaddr d6:8e:09:5a:ed:4a

inet addr:10.110.0.1 Bcast:0.0.0.0 Mask:255.255.255.0

inet6 addr: fe80::d48e:9ff:fe5a:ed4a/64 Scope:Link

UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1

RX packets:25 errors:0 dropped:0 overruns:0 frame:0

TX packets:48 errors:0 dropped:0 overruns:0 carrier:0

collisions:0 txqueuelen:1000

RX bytes:1818 (1.8 KB) TX bytes:5455 (5.4 KB)

gset@ubuntu:~$ sudo ip netns exec xgf bash // enter into the network namespace - xgf

root@ubuntu:~# ifconfig

veth-b Link encap:Ethernet HWaddr 1a:ed:45:0f:1b:36

inet addr:10.110.0.2 Bcast:0.0.0.0 Mask:255.255.255.0

inet6 addr: fe80::18ed:45ff:fe0f:1b36/64 Scope:Link

UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1

RX packets:47 errors:0 dropped:0 overruns:0 frame:0

TX packets:24 errors:0 dropped:0 overruns:0 carrier:0

collisions:0 txqueuelen:1000

RX bytes:5368 (5.3 KB) TX bytes:1748 (1.7 KB)

root@ubuntu:~# ip route

10.110.0.0/24 dev veth-b proto kernel scope link src 10.110.0.2

root@ubuntu:~# ping 10.110.0.1

PING 10.110.0.1 (10.110.0.1) 56(84) bytes of data.

64 bytes from 10.110.0.1: icmp_seq=1 ttl=64 time=0.039 ms

root@ubuntu:~# ping 10.110.0.2

PING 10.110.0.2 (10.110.0.2) 56(84) bytes of data.

64 bytes from 10.110.0.2: icmp_seq=1 ttl=64 time=0.024 ms

gset@ubuntu:~$ sudo ip link del veth-a ( or veth-b ) // delete veth intefaces

gset@ubuntu:~$ sudo ip netns del xgf // delete the network namespace – xgf

Docker Installation

https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-on-ubuntu-16-04

The Docker installation package available in the official Ubuntu 16.04 repository may not be the latest version. To get the latest and greatest version, install Docker from the official Docker repository:

gset@ubuntu:~$ uname –rso

gset@ubuntu:~$ cat /etc/lsb-release

gset@ubuntu:~$ sudo apt-get install curl

gset@ubuntu:~$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add –

// add the GPG key for the official Docker repository to the system

gset@ubuntu:~$ sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" // add the Docker repository to APT sources

gset@ubuntu:~$ sudo apt-get update

gset@ubuntu:~$ apt-cache policy docker-ce

gset@ubuntu:~$ sudo apt-get install -y docker-ce

gset@ubuntu:~$ sudo systemctl status docker

gset@ubuntu:~$ sudo docker run hello-world

Running the docker command requires root privileges and we have to prefix the command with sudo. It can also be run by a user in the docker group, which is automatically created during the installation of Docker. If you attempt to run the docker command without prefixing it with sudo or without being in the docker group, you need finish the following confiurations:

sudo usermod -aG docker ${USER} // add the current username to the docker group:

su - ${USER} // apply the new group membership

id -nG // confirm the membership of docker group

gset@ubuntu:~$ docker version

gset@ubuntu:~$ docker info


技術分享圖片

Use Case 1: Create a web server with port mapping


技術分享圖片

// Download the Ubuntu 14.04 image from Docker Hub

gset@ubuntu:~$ docker pull ubuntu:14.04

gset@ubuntu:~$ docker images

REPOSITORY TAG IMAGE ID CREATED SIZE

ubuntu 14.04 d6ed29ffda6b 8 days ago 221MB

// Create the xgfwebserver container with the docker image ubuntu 14.04

// Map the host port - 8000 to the xgfwebserver port - 80

gset@ubuntu:~$ docker run -it -p 8000:80 --name xgfwebserver ubuntu:14.04

// Install python-pip and Flask, and run the web service on the 80 port

root@62b4975b2a8d:/#

root@62b4975b2a8d:/# ip addr

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000

link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

inet 127.0.0.1/8 scope host lo

valid_lft forever preferred_lft forever

7: eth0@if8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default

link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff

inet 172.17.0.2/16 scope global eth0

valid_lft forever preferred_lft forever

root@62b4975b2a8d:/# sudo apt-get update

root@62b4975b2a8d:/# sudo apt-get install python-pip

root@62b4975b2a8d:/# sudo pip install Flask

root@62b4975b2a8d:/# vi hello.py

from flask import Flask

app = Flask(__name__)

@app.route('/')

def hello_world():

return 'Hello World, this is Richard Xue \r\n'

if __name__ == '__main__':

app.run(host='0.0.0.0',port=80)

root@62b4975b2a8d:/# python hello.py

* Running on http://0.0.0.0:80/ (Press CTRL+C to quit)

10.0.0.129 - - [26/Nov/2017 20:29:26] "GET / HTTP/1.1" 200 -

10.0.0.1 - - [26/Nov/2017 20:29:27] "GET / HTTP/1.1" 200 -

10.0.0.137 - - [26/Nov/2017 20:29:32] "GET / HTTP/1.1" 200 –

root@62b4975b2a8d:/# ps -ef

UID PID PPID C STIME TTY TIME CMD

root 1 0 0 23:29 pts/0 00:00:00 /bin/bash

root 15 1 0 23:29 pts/0 00:00:00 ps -ef

// Check the web service in the host

gset@ubuntu:~$ curl 10.0.0.137:8000

Hello World, this is Richard Xue

gset@ubuntu:~$ docker ps

CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

62b4975b2a8d ubuntu:14.04 "/bin/bash" 6 minutes ago Up 6 minutes 0.0.0.0:8000->80/tcp xgfwebserver

gset@ubuntu:~$ docker stop xgfwebserver

gset@ubuntu:~$ docker restart xgfwebserver

gset@ubuntu:~$ docker start xgfwebserver

gset@ubuntu:~$ docker attach xgfwebserver

gset@ubuntu:~$ docker exec -it 62b4975b2a8d /bin/bash

gset@ubuntu:~$ docker exec -it 62b4975b2a8d python hello.py

Use Case 2: Share the data between Host and containers

// Create the xgf directory in the host and share with its containers

gset@ubuntu:~$ mkdir xgf

gset@ubuntu:~$ cd xgf

gset@ubuntu:~/xgf$ gedit hello1.py

from flask import Flask

app = Flask(__name__)

@app.route('/',methods=['GET'])

def root_get():

return 'GET - This is Richard Xue\r\n'

@app.route('/hello/<id>')

def hello_world(id):

return 'Hello World: {}\r\n'.format(id)

@app.route('/add/<int:id>')

def add(id):

return 'Sum: %d\r\n' %id

if __name__ == '__main__':

app.run(host='0.0.0.0',port=80)

// Create ‘xgf’ in the container and map ‘/home/gset/xgf’ in the host to the ‘/xgf’ of container

gset@ubuntu:~$ docker run -it -v /home/gset/xgf:/xgf -p 8080:80 --name xgfwebserver2 flaskweb

// If ready-only

gset@ubuntu:~$ docker run -it -v /home/gset/xgf:/xgf:ro -p 8080:80 --name xgfwebserver2 flaskweb

root@770058c45a94:/# python ./xgf/hello1.py

* Running on http://0.0.0.0:80/ (Press CTRL+C to quit)

10.0.0.129 - - [26/Nov/2017 21:23:59] "GET / HTTP/1.1" 200 –

10.0.0.137 - - [26/Nov/2017 21:49:32] "GET / HTTP/1.1" 200 -

10.0.0.137 - - [26/Nov/2017 21:49:38] "GET /hello/10 HTTP/1.1" 200 -

10.0.0.137 - - [26/Nov/2017 21:49:55] "GET /add/100 HTTP/1.1" 200 -

// Check the web service in the host

gset@ubuntu:~$ curl 10.0.0.137:8080

GET - This is Richard Xue

gset@ubuntu:~$ curl 10.0.0.137:8080/hello/10

Hello World: 10

gset@ubuntu:~$ curl 10.0.0.137:8080/add/100

Sum: 100

// Create ‘/xgf’ in ‘data-provider’, and share data between two the containers of ‘data-provider’ and ‘data consumer’

gset@ubuntu:~$ docker run -ti -v /xgf --name "data-provider" ubuntu:14.04

gset@ubuntu:~$ docker run -ti --volumes-from "data-provider" --name "data-consumer" ubuntu:14.04

gset@ubuntu:~$ docker ps

CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

b3275e7357f4 ubuntu:14.04 "/bin/bash" 2 minutes ago Up 2 minutes data-consumer

ed8643c1f926 ubuntu:14.04 "/bin/bash" 3 minutes ago Up 3 minutes data-provider

Use Case 3: Create images

gset@ubuntu:~$ docker ps

CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

62b4975b2a8d ubuntu:14.04 "/bin/bash" 6 minutes ago Up 6 minutes 0.0.0.0:8000->80/tcp xgfwebserver

// Create a new image with the running or stoped container

gset@ubuntu:~$ docker commit -m "flask web server" -a "Richard Xue" 62b4975b2a8d flaskweb

sha256:5589ca92a091801dd8e35bcc1238a92a10b977dd32eb99b98422680fc0806203

gset@ubuntu:~$ docker inspect flaskweb

gset@ubuntu:~$ docker images

REPOSITORY TAG IMAGE ID CREATED SIZE

flaskweb latest 5589ca92a091 6 seconds ago 394MB

ubuntu 14.04 d6ed29ffda6b 8 days ago 221MB

// Create a new image with the docker file

gset@ubuntu:~$ cd xgf

gset@ubuntu:~/xgf$ gedit dockerfile

FROM flaskweb

CMD python hello.py

gset@ubuntu:~/xgf$ docker build -t flaskweb:0.0.1 .

gset@ubuntu:~$ docker images

REPOSITORY TAG IMAGE ID CREATED SIZE

flaskweb 0.0.1 d3855d7f874b 50 seconds ago 394MB

flaskweb latest 4532c3c18668 2 minutes ago 394MB

ubuntu 14.04 d6ed29ffda6b 9 days ago 221MB

// Create a container with the new image: flaskweb:0.0.1

gset@ubuntu:~$ docker run -it -p 8001:80 --name xgfwebserver3 flaskweb:0.0.1

* Running on http://0.0.0.0:80/ (Press CTRL+C to quit)

10.0.0.137 - - [26/Nov/2017 22:31:48] "GET / HTTP/1.1" 200 -

10.0.0.137 - - [26/Nov/2017 22:31:57] "GET / HTTP/1.1" 200 –

// Check the web service in the host

gset@ubuntu:~$ curl 10.0.0.137:8001

Hello World, this is Richard Xue

gset@ubuntu:~$ docker rmi dc63ece8d22e // delete the image - dc63ece8d22e

gset@ubuntu:~$ docker rm -f 0d020af8693a // delete the running container - 0d020af8693a


Use Case 4: Connect containers in different hosts with VxLAN


技術分享圖片

// Configuration in Host 1

gset@ubuntu:~$ docker start xgfwebserver

gset@ubuntu:~$ sudo ls -la /var/run/netns

gset@ubuntu:~$ sudo ip link add vxlan0 type vxlan id 42 dstport 4789 remote 10.0.0.139 local 10.0.0.137

gset@ubuntu:~$ ifconfig –a

gset@ubuntu:~$ sudo docker inspect --format '{{.State.Pid}}' xgfwebserver

2748

gset@ubuntu: ~$ sudo ln -s /proc/2748/ns/net /var/run/netns/xgfwebserver

gset@ubuntu: ~$ sudo ip netns list

gset@ubuntu:~$ sudo ip netns exec xgfwebserver ip link

gset@ubuntu:~$ sudo ip link set vxlan0 netns xgfwebserver

gset@ubuntu:~$ sudo ip netns exec xgfwebserver ip link set dev vxlan0 up

gset@ubuntu:~$ sudo ip netns exec xgfwebserver ip addr add 10.110.0.1/24 dev vxlan0

gset@ubuntu:~$ docker attach xgfwebserver

root@62b4975b2a8d:/# ifconfig

vxlan0 Link encap:Ethernet HWaddr 06:a5:2d:28:03:b8

inet addr:10.110.0.1 Bcast:0.0.0.0 Mask:255.255.255.0

UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1

RX packets:0 errors:0 dropped:0 overruns:0 frame:0

TX packets:0 errors:0 dropped:0 overruns:0 carrier:0

collisions:0 txqueuelen:1000

RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)

root@62b4975b2a8d:/#

root@62b4975b2a8d:/# ping 10.110.0.1

PING 10.110.0.1 (10.110.0.1) 56(84) bytes of data.

root@62b4975b2a8d:/# ping 10.110.0.2

PING 10.110.0.2 (10.110.0.2) 56(84) bytes of data.

64 bytes from 10.110.0.2: icmp_seq=1 ttl=64 time=0.840 ms

root@62b4975b2a8d:/#

root@62b4975b2a8d:/# python hello.py

* Running on http://0.0.0.0:80/ (Press CTRL+C to quit)

10.110.0.2 - - [27/Nov/2017 02:17:30] "GET / HTTP/1.1" 200 -

10.110.0.2 - - [27/Nov/2017 02:17:41] "GET / HTTP/1.1" 200 -

root@62b4975b2a8d:/# route

Kernel IP routing table

Destination Gateway Genmask Flags Metric Ref Use Iface

default 172.17.0.1 0.0.0.0 UG 0 0 0 eth0

10.110.0.0 * 255.255.255.0 U 0 0 0 vxlan0

172.17.0.0 * 255.255.0.0 U 0 0 0 eth0

root@62b4975b2a8d:/# ip route

default via 172.17.0.1 dev eth0

10.110.0.0/24 dev vxlan0 proto kernel scope link src 10.110.0.1

172.17.0.0/16 dev eth0 proto kernel scope link src 172.17.0.2

// Configuration in Host 2

gset@ubuntu:~$ docker start xgfwebserver

gset@ubuntu:~$ sudo ls -la /var/run/netns

gset@ubuntu:~$ sudo ip link add vxlan0 type vxlan id 42 dstport 4789 remote 10.0.0.137 local 10.0.0.139

gset@ubuntu:~$ ifconfig -a

gset@ubuntu:~$ sudo docker inspect --format '{{.State.Pid}}' xgfwebserver

2751

gset@ubuntu: ~$ sudo ln -s /proc/2751/ns/net /var/run/netns/xgfwebserver

gset@ubuntu: ~$ sudo ip netns list

gset@ubuntu:~$ sudo ip netns exec xgfwebserver ip link

gset@ubuntu:~$ sudo ip link set vxlan0 netns xgfwebserver

gset@ubuntu:~$ sudo ip netns exec xgfwebserver ip link set dev vxlan0 up

gset@ubuntu:~$ sudo ip netns exec xgfwebserver ip addr add 10.110.0.2/24 dev vxlan0

gset@ubuntu:~$ docker attach xgfwebserver

root@62b4975b2a8d:/# ifconfig

vxlan0 Link encap:Ethernet HWaddr 96:66:72:e7:1e:42

inet addr:10.110.0.2 Bcast:0.0.0.0 Mask:255.255.255.0

UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1

RX packets:0 errors:0 dropped:0 overruns:0 frame:0

TX packets:0 errors:0 dropped:0 overruns:0 carrier:0

collisions:0 txqueuelen:1000

RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)

root@62b4975b2a8d:/#

root@62b4975b2a8d:/# ping 10.110.0.1

PING 10.110.0.1 (10.110.0.1) 56(84) bytes of data.

64 bytes from 10.110.0.1: icmp_seq=1 ttl=64 time=0.301 ms

root@62b4975b2a8d:/# ping 10.110.0.2

PING 10.110.0.2 (10.110.0.2) 56(84) bytes of data.

64 bytes from 10.110.0.2: icmp_seq=1 ttl=64 time=0.029 ms

root@62b4975b2a8d:/#

root@62b4975b2a8d:/# apt-get install curl

root@62b4975b2a8d:/# curl 10.110.0.1:80

root@62b4975b2a8d:/#

root@62b4975b2a8d:/#

root@62b4975b2a8d:/# ip route

default via 172.17.0.1 dev eth0

10.110.0.0/24 dev vxlan0 proto kernel scope link src 10.110.0.2

172.17.0.0/16 dev eth0 proto kernel scope link src 172.17.0.2






Cloud in Action:Practice Docker and its Networking