容器化之路Docker網路核心知識小結,理清楚了嗎?
- 2021 年 10 月 18 日
- 筆記
- docker, Docker Swarm, flannel, iptables, k8s, Kubernetes, 網路
Docker網路是容器化中最難理解的一點也是整個容器化中最容易出問題又難以排查的地方,加上使用Kubernets後大部分人即使是專業運維如果沒有紮實的網路知識也很難定位容器網路問題,因此這裡就容器網路單獨拿出來理一理。
先了解一下Docker的一點基礎架構知識,Docker 技術架構圖:
Docker是不能直接在 Windows 平台上運行的,只支援 linux 系統,因為Docker 依賴 linux kernel 三項最基本的技術。
- Namespaces 充當隔離的第一級,是對 Docker 容器進行隔離,讓容器擁有獨立的 hostname,ip,pid,同時確保一個容器中運行一個進程而且不能看到或影響容器外的其它進程 。
- Cgroups 是容器對使用的宿主機資源進行核算並限制的關鍵功能,比如 CPU, 記憶體, 磁碟等。
- Union FS 主要是對鏡像也就是 image 這一塊作支援,採用 copy-on-write 技術,讓大家可以共用某一層,對於某些差異層的話就可以在差異的記憶體存儲,
- Libcontainer 是一個庫,是對上面這三項技術做一個封裝。
- Docker engine 用來控制容器 container 的運行,以及鏡像文件的拉取。
Docker的工作原理:每個容器都在自己的命名空間中運行,但使用與所有其他容器完全相同的內核。發生隔離是因為內核知道分配給進程的命名空間,並且在API調用期間確保進程只能訪問其自己的命名空間中的資源。
Docker部署關鍵配置
daemon.json文件
指定私有倉庫地址insecure-registries,否則拉取鏡像出現問題:
1 { 2 "data-root": "/docker/data", 3 "exec-opts": ["native.cgroupdriver=cgroupfs"], 4 "registry-mirrors": [ 5 "//docker.mirrors.ustc.edu.cn", 6 "//hub-mirror.c.163.com" 7 ], 8 "hosts": ["tcp://0.0.0.0:2375", "unix:///var/run/docker.sock"], 9 "insecure-registries": ["192.168.0.23:5000"], 10 "max-concurrent-downloads": 10, 11 "live-restore": false, 12 "log-driver": "json-file", 13 "log-level": "warn", 14 "log-opts": { 15 "max-size": "50m", 16 "max-file": "1" 17 }, 18 "storage-driver": "overlay2" 19 }
1.指定data-root 配置容器數據地址,在伺服器中單獨規劃磁碟空間,避免佔用系統空間
2.指定hosts,放開2375對外介面
3.Docker使用storage driver(存儲驅動程式)來管理image和container的數據,要使用overlayfs
,要確保系統的內核版本大於等於3.18,overlay
要比aufs和device mapper快一點,OverlayFS僅有兩層,鏡像中的每一層對應/var/lib/docker/overlay
中的一個文件夾,文件夾以該層的UUID命名。然後使用硬連接將下面層的文件引用到上層。這在一定程度上節省了磁碟空間。
4.指定文件驅動native.cgroupdriver=cgroupfs控制的資源主要包括CPU、記憶體、block I/O、網路頻寬等,也可以指定為systemd,這裡要注意的是後續布署k8s時要與k8s設置的文件驅動操持一致,否時會報錯:
failed to create kubelet: misconfiguration: kubelet cgroup driver: “cgroupfs” is different from docker cgroup driver: “systemd”
需要修改kubelet.service Environment中添加–cgroup-driver=cgroupfs或systemd
docker.service文件
[Unit] Description=Docker Application Container Engine Documentation=http://docs.docker.io [Service] Environment="PATH=/docker/bin:/bin:/sbin:/usr/bin:/usr/sbin" ExecStart=/docker/bin/dockerd ExecStartPost=/sbin/iptables -I FORWARD -s 0.0.0.0/0 -j ACCEPT ExecReload=/bin/kill -s HUP $MAINPID Restart=always RestartSec=5 LimitNOFILE=infinity LimitNPROC=infinity LimitCORE=infinity TimeoutStartSec=0 Delegate=yes KillMode=process [Install] WantedBy=multi-user.target
docker 從 1.13 版本開始,將`iptables` 的`filter` 表的`FORWARD` 鏈的默認策略設置為`DROP`,從而導致 ping 其它 Node 上的 Pod IP 失敗,因此必須在 `filter` 表的`FORWARD` 鏈增加一條默認允許規則 `iptables -I FORWARD -s 0.0.0.0/0 -j ACCEPT`
通過了解以上docker基礎框架後排查網路問題思路會更清晰。
Docker容器的網路模型
Docker容器網路的原始模型主要有三種:Bridge(橋接)、Host(主機)及Container(容器)
Docker默認使用Bridge+NAT的通訊模型,Bridge模型藉助於虛擬網橋設備為容器建立網路連接,Docker守護進程首次啟動時,它會在當前節點上創建一個名為docker0的橋設備,並默認配置其使用172.17.0.0/16網路,此主機上啟動的Docker容器會連接到這個虛擬網橋上。
容器與外部網路間的通訊
為了解決容器訪問外部網路,docker引入NAT,通過iptables規則控制,網橋 docker0 通過 iptables 中的配置與宿主機器上的網卡相連,所有符合條件的請求都會通過 iptables 轉發到 docker0 並由網橋分發給對應的機器。創建MASQUERADE規則:
查看nat表
# iptables -t nat -S
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
數據包流程
這條規則將所有從容器發出的、目的地址為Host外部網路的包的IP都修改成Host的IP,並由Host發送出去。
外部網路訪問容器
Docker容器是通過dnat映射或docker-proxy服務對外提供訪問,如指定埠映射:docker run -p 9001:9000。
使用docker run -p時,docker實際是在iptables做了DNAT規則,實現埠轉發功能,為容器分配一個 IP 地址,同時向 iptables 中追加一條新的規則。
可以使用iptables -t nat -vnL查看。
-A PREROUTING -m addrtype –dst-type LOCAL -j DOCKER
-A DOCKER ! -i docker0 -p tcp -m tcp –dport 9001 -j DNAT –to-destination 172.17.0.2:9000
外部訪問外部伺服器訪問10.3.20.87:9001
匹配到DNAT規則,訪問到容器-A PREROUTING -m addrtype –dst-type LOCAL -j DOCKER
-A DOCKER ! -i docker0 -p tcp -m tcp –dport 9001 -j DNAT –to-destination 172.17.0.2:9000
本機訪問127.0.0.1:9001 沒有匹配到任何iptable,走docker-proxy
另外容器要訪問外部網路需要宿主機進行轉發,要在宿主機中打開轉發設置:
#sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 1
為0說明沒有開啟,需要手動打開。
#docker network lsNETWORK ID NAME DRIVER7fca4eb8c647 bridge bridge9f904ee27bf5 none nullcf03ee007fb4 host host
docker network create -d macvlan \–subnet=172.16.86.0/24 \–gateway=172.16.86.1 \-o parent=eth0 pub_net
Docker跨主機容器間網路通訊
具體的介紹可參考 之前的文章 Kubernetes集群部署關鍵知識總結 地址 //www.cnblogs.com/zhangs1986/p/10749721.html
注意:flannel 使用 vxlan 技術為各節點創建一個可以互通的 Pod 網路,使用的埠為 UDP 8472,需要開放該埠。
本文所用到Docker版本為19.03.15
Kubernetes 1.20 版本開始將棄用 Docker
kubelet目前推薦方式是直連containerd。
被去掉的部分是刪除 dockershim(Dockershim 作用
:把外部收到的請求轉化成 Docker Daemon
能聽懂的請求,讓 Docker Daemon 執行創建、刪除等容器操作。)
可以用Containerd 或 Podman 替換。