Kubernetes pod裏一個特殊的容器:pause-amd64

你們在使用Docker容器或者Kubernetes時,遇到過這個容器麼?gcr.io/google_containers/pause-amd64node

docker ps的命令返回的結果:git

[root@k8s-minion1 kubernetes]# docker ps |grep pause
c3026adee957        gcr.io/google_containers/pause-amd64:3.0           "/pause"                 22 minutes ago      Up 22 minutes                           k8s_POD.d8dbe16c_redis-master-343230949-04glm_default_ce3f60a9-095d-11e7-914b-0a77ecd65f3e_66c108d5
202df18d636e        gcr.io/google_containers/pause-amd64:3.0           "/pause"                 24 hours ago        Up 24 hours                             k8s_POD.d8dbe16c_kube-proxy-js0z0_kube-system_2866cfc2-0891-11e7-914b-0a77ecd65f3e_c8e1a667
072d3414d33a        gcr.io/google_containers/pause-amd64:3.0           "/pause"                 24 hours ago        Up 24 hours                             k8s_POD.d8dbe16c_kube-flannel-ds-tsps5_default_2866e3fb-0891-11e7-914b-0a77ecd65f3e_be4b719e
[root@k8s-minion1 kubernetes]#

Kubernetes的官網解釋:github

it's part of the infrastructure. This container is started first in all Pods to setup the network for the Pod.redis

意思是:pause-amd64是Kubernetes基礎設施的一部分,Kubernetes管理的全部pod裏,pause-amd64容器是第一個啓動的,用於實現Kubernetes集羣裏pod之間的網絡通信。docker

對這個特殊容器感興趣的朋友,能夠閱讀其源代碼: https://github.com/kubernetes/kubernetes/tree/master/build/pauseshell

咱們查看這個pause-amd64鏡像的dockerfile,發現實現很簡單,基於一個空白鏡像開始:網絡

FROM scratch
ARG ARCH
ADD bin/pause-${ARCH} /pause
ENTRYPOINT ["/pause"]

ARG指令用於指定在執行docker build命令時傳遞進去的參數。ide

這個pause container是用C語言寫的:函數

https://www.ianlewis.org/en/almighty-pause-container工具

在運行的Kubernetes node上運行docker ps,能發現這些pause container:

pause container做爲pod裏其餘全部container的parent container,主要有兩個職責:

  1. 是pod裏其餘容器共享Linux namespace的基礎
  2. 扮演PID 1的角色,負責處理殭屍進程

這兩點我會逐一細說。在Linux裏,當父進程fork一個新進程時,子進程會從父進程繼承namespace。目前Linux實現了六種類型的namespace,每個namespace是包裝了一些全局系統資源的抽象集合,這一抽象集合使得在進程的命名空間中能夠看到全局系統資源。命名空間的一個整體目標是支持輕量級虛擬化工具container的實現,container機制自己對外提供一組進程,這組進程本身會認爲它們就是系統惟一存在的進程。

在Linux裏,父進程fork的子進程會繼承父進程的命名空間。與這種行爲相反的一個系統命令就是unshare:

再來聊聊pause容器如何處理殭屍進程的。

Pause容器內其實就運行了一個很是簡單的進程,其邏輯能夠從前面提到的Pause github倉庫上找到:

static void sigdown(int signo) {
  psignal(signo, "Shutting down, got signal");
  exit(0);
}

static void sigreap(int signo) {
  while (waitpid(-1, NULL, WNOHANG) > 0);
}

int main() {
  if (getpid() != 1)
    /* Not an error because pause sees use outside of infra containers. */
    fprintf(stderr, "Warning: pause should be the first process\n");

  if (sigaction(SIGINT, &(struct sigaction){.sa_handler = sigdown}, NULL) < 0)
    return 1;
  if (sigaction(SIGTERM, &(struct sigaction){.sa_handler = sigdown}, NULL) < 0)
    return 2;
  if (sigaction(SIGCHLD, &(struct sigaction){.sa_handler = sigreap,
                                             .sa_flags = SA_NOCLDSTOP},
                NULL) < 0)
    return 3;

  for (;;)
    pause();
  fprintf(stderr, "Error: infinite loop terminated\n");
  return 42;
}

這個c語言實現的進程,核心代碼就28行:

其中第24行裏一個無限循環for(;;), 至此你們能看出來pause容器名稱的由來了吧?

這個無限循環裏執行的是一個系統調用pause,

所以pause容器大部分時間都在沉睡,等待有信號將其喚醒。

接收什麼信號呢?

一旦收到SIGCHLD信號,pause進程就執行註冊的sigreap函數。

看下SIGCHLD信號的幫助:

SIGCHLD,在一個進程正常終止或者中止時,將SIGCHLD信號發送給其父進程,按系統默認將忽略此信號,若是父進程但願被告知其子系統的這種狀態,則應捕捉此信號。

pause進程註冊的信號處理函數sigreap裏,調用另外一個系統調用waitpid來得到子進程終止的緣由。

但願這篇文章對你們理解Kubernetes裏的pause容器有所幫助。感謝閱讀。

要獲取更多Jerry的原創文章,請關注公衆號"汪子熙":

相關文章
相關標籤/搜索