0%

docker 技术原理

docker 技术原理

目的:

  • 资源隔离: 隔离各个服务使用的资源
  • 打包环境: 减小部署的难度,一次打包,多次使用
  • 资源控制: 控制各个服务的资源,防止相互影响

使用的主要技术有:

  1. linux namespce 资源隔离
  2. overlayfs 文件系统
  3. cgroup 资源控制
  4. linux bridge,veth,vxlan. 网络虚拟化(overlay)

1. linux namespace

资源的隔离:

c++ namespace , namespace 之间隔离函数的命名空间

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
#include <vector>

namespace myns {
template<typename T>
class vector {
public:
vector() {
std::cout<<"my vector"<<std::endl;
}
};
};

int main() {
std::vector<int> v1;
myns::vector<int> v2;
}

linux namespace :

system api:

  • clone()

  • setns()

  • unshare()

      #define _GNU_SOURCE
      #include <sched.h>
    
      int clone(int (*fn)(void *), void *child_stack,
          int flags, void *arg, ...
          /* pid_t *ptid, void *newtls, pid_t *ctid */ );
flag namespace 效果
CLONE_NEWNS mount namespace 挂载的文件系统互不可见
CLONE_NEWIPC ipc namespace ipc 队列互不可见
CLONE_NEWUTS 主机名uts namespace 主机名互互不相同
CLONE_NEWPID pid namespace 进程互不可见
CLONE_NEWNET network namespace 网络隔离
CLONE_NEWUSER user namespce 用户隔离
CLONE_NEWCGROUP cgroup namespace 资源控制隔离

2. overlayfs

分层文件系统

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
cd /tmp
mkdir lower upper workdir overlay
sudo mount -t overlay -o lowerdir=/tmp/lower,upper=/tmp/upper,workdir=/tmp/workdir none /tmp/overlay


# 创建一个文件
echo "Hello world" >> /tmp/lower/hello.txt


# 在 overlayfs 中查看文件
ls /tmp/overlay

# 在 overylayfs 中修改文件
echo "append write " >> /tmp/overlay/hello.txt

# 再次查看 lower 中的文件, 没有变化
cat /tmp/lower/hello.txt
hello world


# 查看 upper 中的文件
cat /tmp/upper/hello.txt
hello world
append write



# 在 overlay 中创建文件
echo "world world " >> /tmp/overlay/world.txt

# 查看 lower,没有变化
ls /tmp/lower


# 查看 upper, 发现有 world 文件
ls /tmp/upper
world

3. cgroup (control grop) 控制组

cgroup 挂载为文件系统

查看 cgroup 挂载
mount -l |grep cgroup

ls /sys/fs/cgroup/

blkio 块设备io cpu cpu 使用率、调度 cpuacct cpu 目前使用率 cpuset cpu绑核 devices 限制使用的设备 freezer 恢复或者挂起 cgroup 中的人物 hugetlb 透明大页 memory 内存限制 net_cls 标记流量 net_prio 设置网络优先级

cgroup 中的概念:

task: 系统进程
control group: 控制组
hierarchy: 层级
subsystem: 子系统

1
2
3
4
5
6
7
8
9
10
11
12
mkdir -p /sys/fs/cgroup/cpu/mytask
echo $$ > /sys/fs/cgroup/cpu/mytask/tasks
cat /sys/fs/cgroup/cpu/mytask/cpu.cfs_period_us
100000

# 设置 CPU 使用率 20%
echo 20000 > /sys/fs/cgroup/cpu/mytask/cpu.cfs_period_us

# 运行死循环
while true; do ; done;

# 打开另一个终端 top 查看 cpu 使用率

4. linux 虚拟网络设备

两个 namespace 之间的网络是隔离的。

4.1 veth pair 设备

veth 设备能够连接两端,就想 linux pipe 一样,向一头 veth 写数据,另一端可以读取数据

1
2
3
4
5
6
    10.10.0.1         10.10.0.2
+--------+ +----------+
| | veth1 veth2 |
| ns1 |<--------------->| ns2 |
| | | |
+--------+ +----------+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
ip netns add ns1
ip netns add ns2

ip link add veth1 type veth peer name veth2

ip link set veth1 netns ns1
ip link set veth2 netns ns2

ip netns exec ns1 ip addr add 10.10.0.1/24 dev veth1
ip netns exec ns2 ip addr add 10.10.0.2/24 dev veth2

ip netns exec ns1 ip link set veth1 up
ip netns exec ns2 ip link set veth2 up


# 测试
ip netns exec ns1 ping 10.10.0.2

4.2 网桥设备(交换机)

1
2
3
4
5
6
7
8
9
10
11
12
13
+-----------+              +-------------+
| ns1 | | ns2 |
| | | |
| veth0 | | veth2 |
+------+----+ +---+---------+
+----+ +------------+
| |
| |
veth1++-----+-+veth3
|bridge |
| br0 | ==> switcher
+--------+

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
ip netns add ns1
ip netns add ns2

ip link add veth0 type veth peer name veth1
ip link add veth2 type veth peer name veth3
ip link add br0 type bridge

ip link set veth0 netns ns1
ip link set veth2 netns ns2

ip link set veth1 master br0
ip link set veth3 master br0

ip addr add 10.20.0.1/24 dev br0
ip netns exec ns1 ip addr add 10.20.0.2/24 dev veth0
ip netns exec ns2 ip addr add 10.20.0.3/24 dev veth2

ip link set br0 up
ip link set veth1 up
ip link set veth3 up
ip netns exec ns1 ip link set veth0 up
ip netns exec ns2 ip link set veth2 up

# 添加路由
ip netns exec ns1 ip route add default via 10.20.0.1 dev veth0
ip netns exec ns2 ip route add default via 10.20.0.1 dev veth2

# 测试
ip netns exec ns1 ping 10.20.0.3

4.3 vxlan 网络

传统的 vlan 网络 vid 支持支持 12 位 2^12=4096,仅支持 4096 个网络,而 vxlan 网络的 vid 支持 24 位,可以支持 1600 万以上的网络。

vxlan 将 IP 层的数据包封装为带有 vxlan 头部的 UDP 数据包,再次发送出去.

vxlan 其实是工作在第三层(udp) 的第二层协议(ip),因为 vxlan 模拟了 ip 层的数据

1
2
3
4
5
6
7
8
9
10
11
# 四层网络协议栈
+------------------+
| application |
+------------------+
| tcp/udp |
+------------------+
| ip |
+------------------+
| 数据链路层 |
| |
+------------------+

5. docker 使用

5.1 docker 打包应用

编写 Dockerfile 文件,然后在 Dockerfile 所在目录使用 docker build . -t mytag, 注意打包的时候有个点,表示打包的上下文路径。这里的上下文路径表示的是docker打包时会将这个上下文路径里面的所有内容都发送给dockerd,之后再由 Dockerfile 中的指令操作这些文件,生成 docker 镜像。

1
2
3
4
5
6
7
8
9
10
FROM busybox
COPY . /bin/

...

ENV HELLO="hello"
VOLUME /mnt/data

...

常见的 Dockerfile 指令有:

指令 功能
FROM 引入基础镜像
ADD 添加文件,可以自动解压,修改权限等,较为复杂,不建议使用
COPY 拷贝文件,保持文件权限
ENV 指定环境变量
| VOLUME | VOLUME

表示这个dir是卷,如果运行时没有指定挂载的目录,会使用匿名卷 | | RUN | 打包时执行命令 | | CMD | 运行时的命令 | | ENTRYPOINT | 运行时的入口点位置 |

ENTRYPOINTCMD 格式 :

执行命令有两种形式,一种是使用 exec 模式,跟到参数是一个参数列表;另一种使用 shell 方式,直接跟命令字符串。

exec 格式:

1
2
CMD ['ls', '-l']
ENTRYPOINT ['ls', '-l']

shell 格式, shell 格式会转换为 /bin/sh -c "command ...",执行可以读取环境变量,exec格式无法默认无法读取环境变量 , 需要使用 sh, 比如 ['/bin/sh', '-c', 'command']

1
2
CMD ls -l
ENTRYPINT ls -l

CMDENTRYPOINT 添加参数

test.sh

1
2
#!/bin/sh
echo $@

默认向 test.sh 传入 ls 的参数,如果手动指定,则运行手动指定的

1
2
ENTRYPINT ["./test.sh"]
CMD ["ls"]

5.2 常见的 docker 命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
docker ps -a # 查看所有的 docker 容器
docker images # 查看所有的 docker 镜像

docker ps -aq # 查看所有的 docker 容器,只包含 docker id

docker inspect <container id> # docker 检查容器运行情况

docker inspect <container id> |grep -i pid # 可以看到容器的 pid

docker run -d <image name> [command] # 后台运行 docker 容器,可以添加命令

docker run -it --rm <image name> /bin/[sh|bash] # 交互式打开容器,使用容器内部的 sh 或者
bash,使用完成自动删除(--rm)

docker exec -it <container id> /bin/[sh|bash] # 打开已经运行的容器内部的 sh 或者 bash

docker stop <container id> # 停止容器
docker start <container id> # 启动容器

docker rm <container id> # 删除容器
docker rmi <image name> # 删除镜像

reference

man clone man namespace

docker 使用的最佳实践

TODO: docker 精简镜像 https://mp.weixin.qq.com/s/S1Ib08SpQbf1SCbCutUoqQ

阅读资料

docker namespace 上 docker namespace 下 docker aufs docker cgroup docker devicemapper k8s/docker 排障 linux namespace api docker control group docker namespace docker 与 git overlayfs 实现 简单的 docker https://itnext.io/breaking-down-containers-part-1-namespaces-9668b86d003d bocker

docker 网络转发过程 https://www.jianshu.com/p/91002d316185

https://unix.stackexchange.com/questions/465669/what-is-the-nsfs-filesystem