前言
在k8s中, pod是編排的最小單位, 在同一個pod中, 容器之間能夠共享hostname
network
等內容.
共享network
, 簡單說就是同一個pod中的容器, 可以通過訪問localhost
互相訪問, 且端口占用會衝突.
在之前的介紹中提到過, 容器的隔離是通過namespace
技術實現的, 網絡隔離自然也是通過Network Namespace
實現. 每個network namespace
中都有自己的一套網絡資源, 比如: IP地址, 路由表, 網卡等.
那麼網絡共享的原理, 自然也就是將多個容器加入到同一個network namespace
中咯.
令多個容器共用一套network namespace
, 在docker
中可以這樣做:
# 方式一: 創建一個network, 然後所有容器都使用這個網絡
docker network create mynetwork
docker run --name container1 --network=mynetwork nginx
docker run --name container2 --network=mynetwork nginx
# 方式二: 啓動一個容器, 然後將新的容器加入到已有容器的網絡中
docker run --name container1 nginx
docker run --name container2 --network container:container1 nginx
而k8s則是容器的管理者, 它又是怎麼選擇的呢?
k8s 的網絡共享
在k8s
中, 選擇了第二種方式來共享網絡, 不止是網絡, 包括volume
也是這樣. 這樣設計可能是爲了更大的靈活性吧. 具體原因沒有細究.
但是, 如果說我們在啓動容器的時候, 要將其加入到已有容器的網絡中, pod中的容器就必須有一個是先啓動的, 這樣後續的容器才能加入. 那麼問題來了, pod中哪個容器能夠最先啓動呢? 難道我們在定義pod時還需要定義容器的啓動順序嗎? 顯然不是這樣的.
那麼k8s
是如何解決容器啓動順序的問題呢? 處理方式也十分簡單粗暴, 在所有容器啓動之前, 先啓動一個默認的容器, 後續所有容器就可以都加入此容器的命名空間中了. 這個預先啓動的容器什麼都不做, 只是爲了後續容器加入.
pause容器查看
口說無憑, 我們啓動一個pod來看一下:
apiVersion: v1
kind: Pod
metadata:
name: test
namespace: hj
spec:
shareProcessNamespace: true
restartPolicy: Never
containers:
- name: nginx
image: nginx
- name: busybox
image: busybox
command: ["/bin/sh"]
args: ["-c", "sleep infinity"]
此時查看運行中的容器列表, 那麼你就能夠看到pause
容器:
另外, 因爲我們開啓了shareProcessNamespace
共享進程空間, 因此我們可以進入容器查看當前運行的所有進程:
也可以清楚的看到pause
進程, 與當前容器在同一個進程命名空間中.
(另外, 這裏可以看到我們exec
進入的sh
進程, 其父進程PID是0, 與容器掛載目錄中說的也對上了嘛. exec的原理是將進程強行加入已有的命名空間中)
pause容器
pause
需要具有如下特點:
- 體積小 (方便快速拉取鏡像)
- 不佔用資源(否則每個pod啓動一個, 用戶資源都被喫光了)
- 穩定 (一旦掛了, 接入此容器命名空間的關聯容器都會被波及, 所以此容器不能掛)
那麼, pause
到底做了什麼呢? 在github可以看到鏡像構建的源碼. 其主要運行的源碼在這裏.
簡單說, pause
容器什麼也沒幹. 進程在啓動後, 不停的調用pause
函數進入睡眠, 從而使得容器能夠持續運行而又不消耗系統資源. 同時越是簡單的就越是穩定. 而這個容器的大小也不過742KB.
至此, pod網絡共享的謎團算是大致解開了. 雖然沒有特別深入, 但對於理解pod也有一定的幫助.