k8s 中 pod 是如何做到網絡共享的

前言

在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容器:

image-20230523143629109

另外, 因爲我們開啓了shareProcessNamespace共享進程空間, 因此我們可以進入容器查看當前運行的所有進程:

image-20230523143922784

也可以清楚的看到pause進程, 與當前容器在同一個進程命名空間中.

(另外, 這裏可以看到我們exec進入的sh進程, 其父進程PID是0, 與容器掛載目錄中說的也對上了嘛. exec的原理是將進程強行加入已有的命名空間中)

pause容器

pause需要具有如下特點:

  1. 體積小 (方便快速拉取鏡像)
  2. 不佔用資源(否則每個pod啓動一個, 用戶資源都被喫光了)
  3. 穩定 (一旦掛了, 接入此容器命名空間的關聯容器都會被波及, 所以此容器不能掛)

那麼, pause到底做了什麼呢? 在github可以看到鏡像構建的源碼. 其主要運行的源碼在這裏.

簡單說, pause容器什麼也沒幹. 進程在啓動後, 不停的調用pause函數進入睡眠, 從而使得容器能夠持續運行而又不消耗系統資源. 同時越是簡單的就越是穩定. 而這個容器的大小也不過742KB.


至此, pod網絡共享的謎團算是大致解開了. 雖然沒有特別深入, 但對於理解pod也有一定的幫助.

原文地址: https://hujingnb.com/archives/900

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章