成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

讀讀 Pause 容器源碼

開發 開發工具
都知道 k8s 的調度最小單位是 POD, 并且每個 POD 都有一個所謂的 Infra 容器 Pause, 負責初始化相關 namespace, 先于 POD 內其它容器起動。那么到底什么是 Pause 容器呢?長什么樣?有什么作用?

[[397735]]

本文轉載自微信公眾號「董澤潤的技術筆記」,作者董澤潤。轉載本文請聯系董澤潤的技術筆記公眾號。

都知道 k8s 的調度最小單位是 POD, 并且每個 POD 都有一個所謂的 Infra 容器 Pause, 負責初始化相關 namespace, 先于 POD 內其它容器起動。那么到底什么是 Pause 容器呢?長什么樣?有什么作用?

分析源碼

廢話不多,直接上源碼,來自官方 pause.c[1]

  1. #include <signal.h> 
  2. #include <stdio.h> 
  3. #include <stdlib.h> 
  4. #include <string.h> 
  5. #include <sys/types.h> 
  6. #include <sys/wait.h> 
  7. #include <unistd.h> 
  8.  
  9. #define STRINGIFY(x) #x 
  10. #define VERSION_STRING(x) STRINGIFY(x) 
  11.  
  12. #ifndef VERSION 
  13. #define VERSION HEAD 
  14. #endif 
  15.  
  16. static void sigdown(int signo) { 
  17.   psignal(signo, "Shutting down, got signal"); 
  18.   exit(0); 
  19.  
  20. static void sigreap(int signo) { 
  21.   while (waitpid(-1, NULL, WNOHANG) > 0) 
  22.     ; 
  23.  
  24. int main(int argc, char **argv) { 
  25.   int i; 
  26.   for (i = 1; i < argc; ++i) { 
  27.     if (!strcasecmp(argv[i], "-v")) { 
  28.       printf("pause.c %s\n", VERSION_STRING(VERSION)); 
  29.       return 0; 
  30.     } 
  31.   } 
  32.  
  33.   if (getpid() != 1) 
  34.     /* Not an error because pause sees use outside of infra containers. */ 
  35.     fprintf(stderr, "Warning: pause should be the first process\n"); 
  36.  
  37.   if (sigaction(SIGINT, &(struct sigaction){.sa_handler = sigdown}, NULL) < 0) 
  38.     return 1; 
  39.   if (sigaction(SIGTERM, &(struct sigaction){.sa_handler = sigdown}, NULL) < 0) 
  40.     return 2; 
  41.   if (sigaction(SIGCHLD, &(struct sigaction){.sa_handler = sigreap, 
  42.                                              .sa_flags = SA_NOCLDSTOP}, 
  43.                 NULL) < 0) 
  44.     return 3; 
  45.  
  46.   for (;;) 
  47.     pause(); 
  48.   fprintf(stderr, "Error: infinite loop terminated\n"); 
  49.   return 42; 

可以看到 Pause 容器做如下兩件事情:

  1. 注冊各種信號處理函數,主要處理兩類信息:退出信號和 child 信號。收到 SIGINT 或是 SIGTERM 后,直接退出。收到 SIGCHLD 信號,調用 waitpid, 回收退出進程
  2. 主進程 for 循環調用 pause() 函數,使進程進入休眠狀態,直到被終止或是收到信號

可疑的 waitpid

還是 c 的基礎不夠扎實,一直以為 waitpid 是父進程等待回收退出的子進程,但是真的這樣嘛?

  1. zerun.dong$ man waitpid 
  2. WAIT(2)                     BSD System Calls Manual                    WAIT(2) 
  3.  
  4. NAME 
  5.      wait, wait3, wait4, waitpid -- wait for process termination 
  6.  
  7. SYNOPSIS 
  8.      #include <sys/wait.h> 

在 mac 上查看 man 手冊,wait for process termination 也確實這么寫的。登到 ubuntu 18.04 查看一下

  1. :~# man waitpid 
  2. WAIT(2)                                                      Linux Programmer's Manual                                                      WAIT(2) 
  3.  
  4. NAME 
  5.        wait, waitpid, waitid - wait for process to change state 

對于 linux man 手冊,就變成了 wait for process to change state 等待進程的狀態變更!!!

  1. All of these system calls are used to wait for state changes in a child of the calling process, and obtain information about the child whose 
  2. state has changed.  A state change is considered to be: the child terminated; the child was stopped by a signal; or the child was resumed by 
  3. a  signal.   In the case of a terminated child, performing a wait allows the system to release the resources associated with the child; if a 
  4. wait is not performed, then the terminated child remains in a "zombie" state (see NOTES below). 

并且還很貼心的提供了測試代碼

  1. #include <sys/wait.h> 
  2. #include <stdlib.h> 
  3. #include <unistd.h> 
  4. #include <stdio.h> 
  5.  
  6. int main(int argc, char *argv[]) 
  7.    pid_t cpid, w; 
  8.    int wstatus; 
  9.  
  10.    cpid = fork(); 
  11.    if (cpid == -1) { 
  12.        perror("fork"); 
  13.        exit(EXIT_FAILURE); 
  14.    } 
  15.  
  16.    if (cpid == 0) {            /* Code executed by child */ 
  17.        printf("Child PID is %ld\n", (long) getpid()); 
  18.        if (argc == 1) 
  19.            pause();                    /* Wait for signals */ 
  20.        _exit(atoi(argv[1])); 
  21.  
  22.    } else {                    /* Code executed by parent */ 
  23.        do { 
  24.            w = waitpid(cpid, &wstatus, WUNTRACED | WCONTINUED); 
  25.            if (w == -1) { 
  26.                perror("waitpid"); 
  27.                exit(EXIT_FAILURE); 
  28.            } 
  29.  
  30.            if (WIFEXITED(wstatus)) { 
  31.                printf("exited, status=%d\n", WEXITSTATUS(wstatus)); 
  32.            } else if (WIFSIGNALED(wstatus)) { 
  33.                printf("killed by signal %d\n", WTERMSIG(wstatus)); 
  34.            } else if (WIFSTOPPED(wstatus)) { 
  35.                printf("stopped by signal %d\n", WSTOPSIG(wstatus)); 
  36.            } else if (WIFCONTINUED(wstatus)) { 
  37.                printf("continued\n"); 
  38.            } 
  39.        } while (!WIFEXITED(wstatus) && !WIFSIGNALED(wstatus)); 
  40.        exit(EXIT_SUCCESS); 
  41.    } 

子進程一直處于 pause 狀態,而父進程則調用 waitpid 等待子進程狀態變更。讓我們開啟一個 session 運行代碼,另外一個 session 發送信號

  1. ~$ ./a.out 
  2. Child PID is 70718 
  3. stopped by signal 19 
  4.  
  5. continued 
  6. stopped by signal 19 
  7. continued 
  8. ^C 
  9. ~# ps aux | grep a.out 
  10. zerun.d+   70717  0.0  0.0   4512   744 pts/0    S+   06:48   0:00 ./a.out 
  11. zerun.d+   70718  0.0  0.0   4512    72 pts/0    S+   06:48   0:00 ./a.out 
  12. root       71155  0.0  0.0  16152  1060 pts/1    S+   06:49   0:00 grep --color=auto a.out 
  13. ~# 
  14. ~# kill -STOP 70718 
  15. ~# 
  16. ~# ps aux | grep a.out 
  17. zerun.d+   70717  0.0  0.0   4512   744 pts/0    S+   06:48   0:00 ./a.out 
  18. zerun.d+   70718  0.0  0.0   4512    72 pts/0    T+   06:48   0:00 ./a.out 
  19. root       71173  0.0  0.0  16152  1060 pts/1    S+   06:49   0:00 grep --color=auto a.out 
  20. ~# 
  21. ~# kill -CONT 70718 
  22. ~# 
  23. ~# ps aux | grep a.out 
  24. zerun.d+   70717  0.0  0.0   4512   744 pts/0    S+   06:48   0:00 ./a.out 
  25. zerun.d+   70718  0.0  0.0   4512    72 pts/0    S+   06:48   0:00 ./a.out 
  26. root       71296  0.0  0.0  16152  1056 pts/1    R+   06:49   0:00 grep --color=auto a.out 

通過向子進程發送信號 STOP CONT 來控制進程。

看來不同操作系統,同名 c 函數行為是不太一樣的。大驚小怪,就是菜:(

共享哪些 NS

一般提起 POD 就知道,同一個 POD 內的容器如果互相訪問,只需調用 localhost 即可。如果把 k8s 集群想象成分布式操作系統,那么 POD 就是進程組的概念,一定要共享某些東西的,那么默認共享哪些 namespace 呢?

使用 minikube 搭建環境,先看一下 POD 定義文件

  1. apiVersion: v1 
  2. kind: Pod 
  3. metadata: 
  4.   name: nginx 
  5. spec: 
  6.   shareProcessNamespace: true 
  7.   containers: 
  8.   - name: nginx 
  9.     image: nginx 
  10.   - name: shell 
  11.     image: busybox 
  12.     securityContext: 
  13.       capabilities: 
  14.         add
  15.         - SYS_PTRACE 
  16.     stdin: true 
  17.     tty: true 

從 1.17 開始有參數 shareProcessNamespace 用來控制是否 POD 內共享 PID namespace, 1.18 之后默認是 false 的,如果有需求需要填寫該字段。

  1. ~$ kubectl attach -it nginx -c shell 
  2. If you don't see a command prompt, try pressing enter. 
  3. / # ps aux 
  4. PID   USER     TIME  COMMAND 
  5.     1 root      0:00 /pause 
  6.     8 root      0:00 nginx: master process nginx -g daemon off
  7.    41 101       0:00 nginx: worker process 
  8.    42 root      0:00 sh 
  9.    49 root      0:00 ps aux 

attach 到 shell 容器中,可以看到該 POD 內所有進程,并且只有 pause 容器是 init 1 進程。

  1. / # kill -HUP 8 
  2. / # ps aux 
  3. PID   USER     TIME  COMMAND 
  4.     1 root      0:00 /pause 
  5.     8 root      0:00 nginx: master process nginx -g daemon off
  6.    42 root      0:00 sh 
  7.    50 101       0:00 nginx: worker process 
  8.    51 root      0:00 ps aux 

測試給 nginx master 發送 HUP 信號,子進程重啟。

如果不共享 PID ns, 那么每個容器內的進程 pid 都是 init 1 進程。共享 PID ns 有什么影響呢?參考這篇文章[2]

容器進程不再具有 PID 1。在沒有 PID 1 的情況下,一些容器鏡像拒絕啟動(例如,使用 systemd 的容器),或者拒絕執行 kill -HUP 1 之類的命令來通知容器進程。在具有共享進程命名空間的 pod 中,kill -HUP 1 將通知 pod 沙箱(在上面的例子中是 /pause)。

進程對 pod 中的其他容器可見。這包括 /proc 中可見的所有信息,例如作為參數或環境變量傳遞的密碼。這些僅受常規 Unix 權限的保護。

容器文件系統通過 /proc/$pid/root 鏈接對 pod 中的其他容器可見。這使調試更加容易,但也意味著文件系統安全性只受文件系統權限的保護。

在宿主機查看 nginx, sh 的進程 id, 通過 /proc/pid/ns 查看 namespace id

  1. ~# ls -l /proc/140756/ns 
  2. total 0 
  3. lrwxrwxrwx 1 root root 0 May  6 09:08 cgroup -> 'cgroup:[4026531835]' 
  4. lrwxrwxrwx 1 root root 0 May  6 09:08 ipc -> 'ipc:[4026532497]' 
  5. lrwxrwxrwx 1 root root 0 May  6 09:08 mnt -> 'mnt:[4026532561]' 
  6. lrwxrwxrwx 1 root root 0 May  6 09:08 net -> 'net:[4026532500]' 
  7. lrwxrwxrwx 1 root root 0 May  6 09:08 pid -> 'pid:[4026532498]' 
  8. lrwxrwxrwx 1 root root 0 May  6 09:08 pid_for_children -> 'pid:[4026532498]' 
  9. lrwxrwxrwx 1 root root 0 May  6 09:08 user -> 'user:[4026531837]' 
  10. lrwxrwxrwx 1 root root 0 May  6 09:08 uts -> 'uts:[4026532562]' 
  11. ~# ls -l /proc/140879/ns 
  12. total 0 
  13. lrwxrwxrwx 1 root root 0 May  6 09:08 cgroup -> 'cgroup:[4026531835]' 
  14. lrwxrwxrwx 1 root root 0 May  6 09:08 ipc -> 'ipc:[4026532497]' 
  15. lrwxrwxrwx 1 root root 0 May  6 09:08 mnt -> 'mnt:[4026532563]' 
  16. lrwxrwxrwx 1 root root 0 May  6 09:08 net -> 'net:[4026532500]' 
  17. lrwxrwxrwx 1 root root 0 May  6 09:08 pid -> 'pid:[4026532498]' 
  18. lrwxrwxrwx 1 root root 0 May  6 09:08 pid_for_children -> 'pid:[4026532498]' 
  19. lrwxrwxrwx 1 root root 0 May  6 09:08 user -> 'user:[4026531837]' 
  20. lrwxrwxrwx 1 root root 0 May  6 09:08 uts -> 'uts:[4026532564]' 

可以看到這里共享了 cgroup, ipc, net, pid, user. 這里僅限于測試案例。

殺掉 Pause 容器

測試一下殺掉 Pause 容器的話,k8s 是如何處理 POD. 使用 minikube 搭建環境,先看一下 POD 定義文件

  1. apiVersion: v1 
  2. kind: Pod 
  3. metadata: 
  4.   name: nginx 
  5. spec: 
  6.   shareProcessNamespace: false 
  7.   containers: 
  8.   - name: nginx 
  9.     image: nginx 
  10.   - name: shell 
  11.     image: busybox 
  12.     securityContext: 
  13.       capabilities: 
  14.         add
  15.         - SYS_PTRACE 
  16.     stdin: true 
  17.     tty: true 

啟動后,查看 pause 進程 id, 然后殺掉

  1. ~$ kubectl describe pod nginx 
  2. ...... 
  3. Events: 
  4.   Type    Reason          Age                   From     Message 
  5.   ----    ------          ----                  ----     ------- 
  6.   Normal  SandboxChanged  3m1s (x2 over 155m)   kubelet  Pod sandbox changed, it will be killed and re-created. 
  7.   Normal  Killing         3m1s (x2 over 155m)   kubelet  Stopping container nginx 
  8.   Normal  Killing         3m1s (x2 over 155m)   kubelet  Stopping container shell 
  9.   Normal  Pulling         2m31s (x3 over 156m)  kubelet  Pulling image "nginx" 
  10.   Normal  Pulling         2m28s (x3 over 156m)  kubelet  Pulling image "busybox" 
  11.   Normal  Created         2m28s (x3 over 156m)  kubelet  Created container nginx 
  12.   Normal  Started         2m28s (x3 over 156m)  kubelet  Started container nginx 
  13.   Normal  Pulled          2m28s                 kubelet  Successfully pulled image "nginx" in 2.796081224s 
  14.   Normal  Created         2m25s (x3 over 156m)  kubelet  Created container shell 
  15.   Normal  Started         2m25s (x3 over 156m)  kubelet  Started container shell 
  16.   Normal  Pulled          2m25s                 kubelet  Successfully pulled image "busybox" in 2.856292466s 

k8s 檢測到 pause 容器狀態異常,就會重啟該 POD, 其實也不難理解,無論是否共享 PID namespace, infra 容器退出了,POD 必然要重啟,畢竟生命周期是與 infra 容器一致的。

參考資料

[1]pause.c: https://github.com/kubernetes/kubernetes/blob/master/build/pause/linux/pause.c,

[2]share proceess namespace: https://kubernetes.io/zh/docs/tasks/configure-pod-container/share-process-namespace/,

 

責任編輯:武曉燕 來源: 董澤潤的技術筆記
相關推薦

2023-09-21 07:24:52

2023-06-14 08:49:22

PodKubernetes

2020-02-27 21:24:31

JavaAIOBIO

2017-03-06 17:02:21

戴爾

2017-01-16 11:56:21

戴爾

2023-09-22 08:39:00

sleep函數語言

2025-03-14 10:37:24

SpringSpring IOC容器

2025-05-21 10:09:09

Spring 5.xIOC編程

2020-05-09 14:58:35

Intel PAUSMySQL性能

2011-07-13 15:07:48

STLC++

2011-07-13 14:49:31

STLC++

2022-09-06 10:18:39

微型容器鏡像微服務

2024-03-20 10:46:00

云原生容器

2015-03-31 18:26:43

陌陌社交

2024-10-15 09:10:41

Docker容器iOS

2022-07-25 14:24:53

Docker容器安全

2015-05-05 14:16:22

容器技術CoreOSGoogle

2022-07-18 11:13:07

容器安全Docker

2022-09-13 09:09:37

容器容器云容器化

2013-02-26 09:53:19

點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 91久久久久久久 | 国产精品久久久久久久久久久免费看 | 国产精品久久午夜夜伦鲁鲁 | 奇米四色影视 | 男人av网| 日本精品视频 | 欧美最猛黑人 | 精品乱子伦一区二区三区 | 国产精品精品视频一区二区三区 | 国产精品成人国产乱一区 | 一本一道久久a久久精品蜜桃 | 欧美韩一区二区三区 | av中文网 | 成人免费视频网站在线看 | 成人三级网址 | 精品无码久久久久久国产 | 黄色一级电影在线观看 | 亚洲成人av在线 | 亚洲中午字幕 | 97免费在线观看视频 | 欧美多人在线 | 神马福利| 国产剧情一区 | 久久精品久久精品久久精品 | 亚洲精品久久久久久一区二区 | 999www视频免费观看 | 91在线视频网址 | 特级做a爰片毛片免费看108 | 国产特一级黄色片 | 国产精品久久精品 | 国产99久久精品一区二区300 | 福利视频一区二区 | 欧美一区二区三区四区视频 | 91在线播| 青青草在线播放 | 99九九久久| 国产高清一区二区 | 国产久视频 | 日韩中文字幕 | 中文字幕在线看第二 | 亚洲国产成人精品女人久久久 |