日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
讀讀Pause容器源碼

本文轉(zhuǎn)載自微信公眾號(hào)「董澤潤(rùn)的技術(shù)筆記」,作者董澤潤(rùn)。轉(zhuǎn)載本文請(qǐng)聯(lián)系董澤潤(rùn)的技術(shù)筆記公眾號(hào)。

創(chuàng)新互聯(lián)專業(yè)為企業(yè)提供鐵山網(wǎng)站建設(shè)、鐵山做網(wǎng)站、鐵山網(wǎng)站設(shè)計(jì)、鐵山網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁設(shè)計(jì)與制作、鐵山企業(yè)網(wǎng)站模板建站服務(wù),十載鐵山做網(wǎng)站經(jīng)驗(yàn),不只是建網(wǎng)站,更提供有價(jià)值的思路和整體網(wǎng)絡(luò)服務(wù)。

都知道 k8s 的調(diào)度最小單位是 POD, 并且每個(gè) POD 都有一個(gè)所謂的 Infra 容器 Pause, 負(fù)責(zé)初始化相關(guān) namespace, 先于 POD 內(nèi)其它容器起動(dòng)。那么到底什么是 Pause 容器呢?長(zhǎng)什么樣?有什么作用?

分析源碼

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

 
 
 
 
  1. #include  
  2. #include  
  3. #include  
  4. #include  
  5. #include  
  6. #include  
  7. #include  
  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. 注冊(cè)各種信號(hào)處理函數(shù),主要處理兩類信息:退出信號(hào)和 child 信號(hào)。收到 SIGINT 或是 SIGTERM 后,直接退出。收到 SIGCHLD 信號(hào),調(diào)用 waitpid, 回收退出進(jìn)程
  2. 主進(jìn)程 for 循環(huán)調(diào)用 pause() 函數(shù),使進(jìn)程進(jìn)入休眠狀態(tài),直到被終止或是收到信號(hào)

可疑的 waitpid

還是 c 的基礎(chǔ)不夠扎實(shí),一直以為 waitpid 是父進(jìn)程等待回收退出的子進(jìn)程,但是真的這樣嘛?

 
 
 
 
  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  

在 mac 上查看 man 手冊(cè),wait for process termination 也確實(shí)這么寫的。登到 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 

對(duì)于 linux man 手冊(cè),就變成了 wait for process to change state 等待進(jìn)程的狀態(tài)變更!!!

 
 
 
 
  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). 

并且還很貼心的提供了測(cè)試代碼

 
 
 
 
  1. #include  
  2. #include  
  3. #include  
  4. #include  
  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.    } 

子進(jìn)程一直處于 pause 狀態(tài),而父進(jìn)程則調(diào)用 waitpid 等待子進(jìn)程狀態(tài)變更。讓我們開啟一個(gè) session 運(yùn)行代碼,另外一個(gè) session 發(fā)送信號(hào)

 
 
 
 
  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 

通過向子進(jìn)程發(fā)送信號(hào) STOP CONT 來控制進(jìn)程。

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

共享哪些 NS

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

使用 minikube 搭建環(huán)境,先看一下 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 開始有參數(shù) shareProcessNamespace 用來控制是否 POD 內(nèi)共享 PID namespace, 1.18 之后默認(rèn)是 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 內(nèi)所有進(jìn)程,并且只有 pause 容器是 init 1 進(jìn)程。

 
 
 
 
  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 

測(cè)試給 nginx master 發(fā)送 HUP 信號(hào),子進(jìn)程重啟。

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

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

進(jìn)程對(duì) pod 中的其他容器可見。這包括 /proc 中可見的所有信息,例如作為參數(shù)或環(huán)境變量傳遞的密碼。這些僅受常規(guī) Unix 權(quán)限的保護(hù)。

容器文件系統(tǒng)通過 /proc/$pid/root 鏈接對(duì) pod 中的其他容器可見。這使調(diào)試更加容易,但也意味著文件系統(tǒng)安全性只受文件系統(tǒng)權(quán)限的保護(hù)。

在宿主機(jī)查看 nginx, sh 的進(jìn)程 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. 這里僅限于測(cè)試案例。

殺掉 Pause 容器

測(cè)試一下殺掉 Pause 容器的話,k8s 是如何處理 POD. 使用 minikube 搭建環(huán)境,先看一下 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 

啟動(dòng)后,查看 pause 進(jìn)程 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 檢測(cè)到 pause 容器狀態(tài)異常,就會(huì)重啟該 POD, 其實(shí)也不難理解,無論是否共享 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/,


本文題目:讀讀Pause容器源碼
文章URL:http://m.5511xx.com/article/cdpihpg.html