理解docker,主要從namesapce,cgroups,聯合文件,運行時(runC),網絡幾個方面。接下來咱們會花一些時間,分別介紹。git
namesapce主要是隔離做用,cgroups主要是資源限制,聯合文件主要用於鏡像分層存儲和管理,runC是運行時,遵循了oci接口,通常來講基於libcontainer。網絡主要是docker單機網絡和多主機通訊模式。github
咱們在使用docker run建立Docker容器時,能夠用--net選項指定容器的網絡模式,Docker有如下4種網絡模式:docker
下面分別介紹一下Docker的各個網絡模式。ubuntu
1)none:不爲容器配置任何網絡功能。
在該模式下,須要以--net=none參數啓動容器:segmentfault
$ docker run --net=none -ti ubuntu:latest ip addr show 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default 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 inet6 ::1/128 scope host valid_lft forever preferred_lft forever
能夠看到Docker容器僅有一lo環回接口,用戶使用--net=none啓動容器以後,仍然能夠手動爲容器配置網絡。安全
2)container:與另外一個運行中的容器共享Network Namespace,共享相同的網絡視圖。
舉個例子,首先以默認網絡配置(bridge模式)啓動一個容器,設置hostname爲dockerNet,dns爲8.8.4.4。bash
$ docker run -h dockerNet --dns 8.8.4.4 -tid ubuntu:latest bash d25864df1a3bbdd40613552197bd1a965acaf7f3dcb2673d50c875d4a303a67f $ docker exec -ti d25864df1a3b bash root@dockerNet:/# ip addr show 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default 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 inet6 ::1/128 scope host valid_lft forever preferred_lft forever 1739: eth0: <BROADCAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link/ether 02:42:ac:11:00:01 brd ff:ff:ff:ff:ff:ff inet 172.17.0.1/16 scope global eth0 valid_lft forever preferred_lft forever inet6 fe80::42:acff:fe11:1/64 scope link valid_lft forever preferred_lft forever root@dockerNet:/# cat /etc/resolv.conf nameserver 8.8.4.4 root@dockerNet:/# exit exit
而後以--net=container:d25864df1a3b方式啓動另外一個容器:網絡
$ docker run --net=container:d25864df1a3b -ti ubuntu:latest bash root@dockerNet:/# ip addr show 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default 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 inet6 ::1/128 scope host valid_lft forever preferred_lft forever 1739: eth0: <BROADCAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link/ether 02:42:ac:11:00:01 brd ff:ff:ff:ff:ff:ff inet 172.17.0.1/16 scope global eth0 valid_lft forever preferred_lft forever inet6 fe80::42:acff:fe11:1/64 scope link valid_lft forever preferred_lft forever root@dockerNet:/# cat /etc/resolv.conf nameserver 8.8.4.4
能夠看到,使用--net=container:d25864df1a3b參數啓動的容器,其IP地址、DNS、hostname都繼承了容器d25864df1a3b。實質上兩個容器是共享同一個Network Namespace的,天然網絡配置也是徹底相同。oop
3)host:與主機共享Root Network Namespace,容器有完整的權限能夠操縱主機的協議棧、路由表和防火牆等,因此被認爲是不安全的。
相應的,host模式啓動時須要指定--net=host參數。舉個例子:google
$ docker run -ti --net=host ubuntu:latest bash root@darcy-HP:/# ip addr show 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default 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 inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast state DOWN group default qlen 1000 link/ether 2c:41:38:9e:e4:d5 brd ff:ff:ff:ff:ff:ff 3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 link/ether 00:1b:21:cc:ee:6d brd ff:ff:ff:ff:ff:ff inet 10.110.52.38/22 brd 10.110.55.255 scope global eth1 valid_lft forever preferred_lft forever inet6 fe80::21b:21ff:fecc:ee6d/64 scope link valid_lft forever preferred_lft forever 1642: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link/ether 22:f2:f3:18:62:5d brd ff:ff:ff:ff:ff:ff inet 172.17.42.1/16 scope global docker0 valid_lft forever preferred_lft forever inet6 fe80::348e:71ff:fe44:2d41/64 scope link valid_lft forever preferred_lft forever
host模式下,容器能夠操縱主機的網絡配置,這是危險的,除非萬不得已,應該儘量避免使用host模式。
4)bridge:Docker設計的NAT網絡模型。
Docker daemon啓動時會在主機建立一個Linux網橋(默認爲docker0,可經過-b參數手動指定)。容器啓動時,Docker會建立一對veth pair(虛擬網絡接口)設備,veth設備的特色是成對存在,從一端進入的數據會同時出如今另外一端。Docker會將一端掛載到docker0網橋上,另外一端放入容器的Network Namespace內,從而實現容器與主機通訊的目的。bridge模式下的網絡拓撲圖以下圖所示。
在橋接模式下,Docker容器與Internet的通訊,以及不一樣容器之間的通訊,都是經過iptables規則控制的。
總之,Docker網絡的初始化動做包括:建立docker0網橋、爲docker0網橋新建子網及路由、建立相應的iptables規則等。
docker在跨主機通訊方面一直比較弱。目前主要有容器網絡模型(CNM)和容器網絡接口(CNI),下面咱們分別介紹。固然k8s和docker之間通訊採納的是CNI。
CNM是一個被 Docker 提出的規範。如今已經被Cisco Contiv, Kuryr, Open Virtual Networking (OVN), Project Calico, VMware 和 Weave 這些公司和項目所採納。
Libnetwork是CNM的原生實現。它爲Docker daemon和網絡驅動程序之間提供了接口。網絡控制器負責將驅動和一個網絡進行對接。每一個驅動程序負責管理它所擁有的網絡以及爲該網絡提供的各類服務,例如IPAM等等。由多個驅動支撐的多個網絡能夠同時並存。網絡驅動能夠按提供方被劃分爲原生驅動(libnetwork內置的或Docker支持的)或者遠程驅動 (第三方插件)。原生驅動包括 none, bridge, overlay 以及 MACvlan。驅動也能夠被按照適用範圍被劃分爲本地(單主機)的和全局的 (多主機)。
『Network Sandbox』– 一個容器內部的網絡棧。
『Endpoint』– 一個一般成對出現的網絡接口。一端在網絡容器內,另外一端在網絡內。 一個Endpoints能夠加入一個網絡。一個容器能夠有多個endpoints。
『Network』– 一個endpoints的集合。該集合內的全部endpoints能夠互聯互通。
最後,CNM還支持標籤(labels)。Lable是以key-value對定義的元數據。用戶能夠經過定義label這樣的元數據來自定義libnetwork和驅動的行爲。
接着咱們看下通常使用libnetwork的方法,具體的步驟通常是下面這樣的:
(1)獲取一個NetworkController對象用於進行下面的操做。獲取對象的時候指定Driver。
(2)經過NetworkController對象的NewNetwork()創建一個網絡。這裏最簡單的理解就是如今咱們有了一個bridge了。
(3)經過網絡的CreateEndpoint()在這個網絡上創建Endpoint。這裏最簡單的理解就是每創建一個Endpoint,咱們上面創建的bridge上就會多出一個VIF口等着虛擬機或者Sandbox連上來。假設這裏使用的是veth,則veth的一頭目前接在了bridge中,另外一頭還暴露在外面。
(4) 調用上面創建的Endpoint的Join方法,提供容器信息,因而libnetwork的代碼就會創建一個Sandbox對象(通常這裏的Sandbox就是容器的namespace,因此不會重複創建),而後將第三步創建的veth的一頭接入到這個Sandbox中,也就是將其放到Sandbox的namespace中。
(5)當Sandbox的生命週期結束時,調用Endpoint的Leave方法使其從這個Network中解綁。簡單的說就是將veth從Sandbox的namespace中拿出來回到物理機上。
(6)若是一個Endpoint無用了,則能夠調用Delete方法刪除。
(7)若是一個Network無用了,則能夠調用Delete方法刪除。
CNI(Conteinre Network Interface) 是 google 和 CoreOS 主導制定的容器網絡標準,它 自己並非實現或者代碼,能夠理解成一個協議。這個標準是在 rkt 網絡提議 的基礎上發展起來的,綜合考慮了靈活性、擴展性、ip 分配、多網卡等因素。
這個協議鏈接了兩個組件:容器管理系統和網絡插件。它們之間經過 JSON 格式的文件進行通訊,實現容器的網絡功能。具體的事情都是插件來實現的,包括:建立容器網絡空間(network namespace)、把網絡接口(interface)放到對應的網絡空間、給網絡接口分配 IP 等等。
CNI自己實現了一些基本的插件(https://github.com/containern..., 好比bridge、ipvlan、macvlan、loopback、vlan等網絡接口管理插件,還有dhcp、host-local等IP管理插件,而且主流的container網絡解決方案都有對應CNI的支持能力,好比Flannel、Calico、Weave、Contiv、SR-IOV、Amazon ECS CNI Plugins等。
具體Flannel的分析能夠閱讀我以前的文章(k8s與網絡--Flannel解讀)。