Docker那点事儿

Docker是一种Container技术,运行在OS特别是Linux之上。虽然支持多种OS,但大多情况下,Linux是应用最广泛的宿主OS。

核心组件有Client,Docker Daemon,Image,Registry和Container。

Docker

Container

Container是Docker的核心。一种运行在OS上可移植的计算单元,体量远远小于VM,不需要VM的Hypervisor,不需要VM的OS。借助于宿主OS比如Linux的一些特性,模拟出来的隔离计算环境。以Linux为例,利用Linux Kernel Namespace来进行计算资源等的隔离,比如PID,Network,Mount,User等。借助于Kernel cgroup,来控制资源的大小。

一个container的创建需要一个image,还需要一个runtime。最有名的image registry为hub.docker.com和quay.io,在那里可发现各种软件发行版本的image。Docker的runtime为runc。

应用程序和依赖被打包封装为Docker image,借助于Docker runtime部署,形成了一个container。应用程序不会再以war包rpm包等形式呈现给开发和运维。

Image

image是分层的,每一层对应着Dockerfile中的一行指令,用”docker history image_name”来查看所有分层。image的所有层在host中保存,是只读的,可被多个container共享。不同层的image如果有相同路径,那么上层的会覆盖下层的。

Image层之上为container层,只有这一层是可读写的。添加文件时,直接将文件添加到container层。读取文件时,由上而下一次读取。修改文件时,先找到该文件,拷贝到container层,再在container层修改。删除文件,先找到该文件,再在container层记录此文件已经被删除。所有这些特性就是著名的COW,copy on write。COW是由所谓的storage driver来实现的,比如AUFS,Device Mapper等。Linux发行版本会有不同的driver,Docker安装时会选择宿主OS默认的driver,比如Ubuntu是AUFS,CentOS是Device Mapper。

共享Kernel

Linux操作系统由内核Kernel空间和用户空间组成。内核空间对应着bootfs文件系统,Linux刚启动时会加载 bootfs,之后 bootfs 会被卸载掉。用户空间的文件系统是 rootfs,包含我们熟悉的 /dev, /proc, /bin 等目录。对于Docker image来说,底层直接用 Host 的 kernel,自己只需要提供 rootfs 就行了。

所有所有container共享一个宿主的Kernel。会出现这种情况,构建base image比如CentOS7.6的Kernel版本有可能和实际运行的宿主机上的Kernel版本不同。

Dockerfile

Dockerfile有几个命令比较相似,现在列出来加以区分。

CMD – container启动后执行的命令,会被docker run 之后的命令替换
RUN – 构建image时运行的命令,常用来安装软件包
ENTRYPOINT – 用来设置启动应用程序或者服务,不会被docker run后的命令替换

网络

Docker有几种网络类型: none, host, bridge, overlay。

none

通过docker run –network=none指定none网络。none网络就是没有任何网络,对应的container是封闭的。

host

host网络通过docker run –network=host指定。对应的container和host共享网络栈,在container可看到host所有网卡。

bridge

Docker安装时默认安装的Linux bridge为docker0,docker run不指定network时所有container会挂到docker0。用以下命令可查看docker0的网段。

docker network inspect bridge

bridge上的container能访问外网,是通过NAT实现的。在host上查看iptables:iptables -t nat -S,可看到相关配置。如果docker0收到外出包,则MASQUERADE将包的源地址改为host地址。可通过以下命令来查看验证。

ip r #查看路由,看由哪个网卡发包出去,这里假设是eth2
ping www.bing.com #在container内ping
tcpdump -i docker0 -n icmp #将会看到内网IP
tcpdump -i eth2 -n icmp #将会看到内网IP变成了eth2的地址

外部访问container可通过端口映射,由docker-proxy的进程来完成。docker run -d -p 80:80 nginx。Port:Port, 前一个为host的端口,后一个为container的端口。

user-defined network

bridge – 可以创建和docker0相似的网络。docker network create –driver bridge –subnet 172.11.11.0/24 –gateway=172.11.11.1 new_bridge

两个bridge上的不同网络之间原则上可以通信,需要打开ip forwarding (sysctl net.ipv4.ip_forward)。但是仍然跨bridge打不通,原因是iptables Drop了两个bridge之间的通信。但container可添加一块网卡,指向别的网络。docker network connect new_bridge container_ID

overlay – 跨主机网络。
建立网络。docker network create -d overlay my_overlay_net,运行后会在集群(可用docker-machine搭建)上每一个host会看到此网络。
绑定网络到container。docker run –network=my_overlay_net 指定刚创建的网络。查看此container后会发现有两个网口,eth0 和 eth1,eth0连接my_overlay_net。
container和外网的通信。eth1连接刚docker network create时创建的Linux bridge网络docker_gwbridge,所有overlay容器通过docker_gwbridge打通外网。注意my_overlay_net和docker_gwbridge两个网络有不同的网段,可以这样查看,docker network inspect docker_gwbridge (docker0)。
container之间的通信。Docker 会为每个 overlay 网络创建一个独立的 network namespace,每个namespace中会有一个linux bridge br0,br0通过vxlan设备和不同host建立vxlan tunnel。container之间借助于此vxlan tunnel进行通信。
不同overlay之间的通信。不同overlay网络内容器不能互通,但可通过docker network connect my_overlay_net container_ID打通。

macvlan – 跨主机网络。
macvlan 本身是Linux Kernel 模块,其功能是允许在同一个物理网卡上配置多个 MAC 地址,即多个 interface,每个 interface 可以配置自己的 IP。macvlan 的最大优点是性能极好,相比其他实现,macvlan 不需要创建 Linux bridge,而是直接通过以太 interface 连接到物理网络。macvlan是一种underlay网络。

flannel等第三方跨主机网络。flannel 是 CoreOS 开发的容器网络解决方案。flannel 为每个 host 分配一个 subnet,容器从此 subnet 中分配 IP,这些 IP 可以在 host 间路由,容器间无需 NAT 和 port mapping 就可以跨主机通信。每个 subnet 都是从一个更大的 IP 池中划分的,flannel 会在每个主机上运行一个叫 flanneld 的 agent,其职责就是从池子中分配 subnet。为了在各个主机间共享信息,flannel 用 etcd(与 consul 类似的 key-value 分布式数据库)存放网络配置、已分配的 subnet、host 的 IP 等信息。(此段参考自CloudMan)

存储

监控

集群

标签:

发表评论

电子邮件地址不会被公开。