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

讀讀 Pause 容器源碼

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

[[397735]]

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

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

分析源碼

廢話不多,直接上源碼,來(lái)自官方 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. 注冊(cè)各種信號(hào)處理函數(shù),主要處理兩類(lèi)信息:退出信號(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 <sys/wait.h> 

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

子進(jìn)程一直處于 pause 狀態(tài),而父進(jìn)程則調(diào)用 waitpid 等待子進(jìn)程狀態(tài)變更。讓我們開(kā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 

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

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

共享哪些 NS

一般提起 POD 就知道,同一個(gè) POD 內(nèi)的容器如果互相訪問(wèn),只需調(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 開(kāi)始有參數(shù) shareProcessNamespace 用來(lái)控制是否 POD 內(nèi)共享 PID namespace, 1.18 之后默認(rèn)是 false 的,如果有需求需要填寫(xiě)該字段。

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

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

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

在宿主機(jī)查看 nginx, sh 的進(jìn)程 id, 通過(guò) /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í)也不難理解,無(wú)論是否共享 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/,

 

責(zé)任編輯:武曉燕 來(lái)源: 董澤潤(rùn)的技術(shù)筆記
相關(guān)推薦

2023-09-21 07:24:52

2023-06-14 08:49:22

PodKubernetes

2017-03-06 17:02:21

戴爾

2020-02-27 21:24:31

JavaAIOBIO

2017-01-16 11:56:21

戴爾

2023-09-22 08:39:00

sleep函數(shù)語(yǔ)言

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

微型容器鏡像微服務(wù)

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容器安全

2022-09-13 09:09:37

容器容器云容器化

2015-05-05 14:16:22

容器技術(shù)CoreOSGoogle

2022-07-18 11:13:07

容器安全Docker

2013-02-26 09:53:19

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 国产一区精品 | 午夜精品在线观看 | 欧美亚洲另类在线 | 欧美精品1区2区3区 免费黄篇 | 国产精品久久久久久中文字 | 一区二区福利视频 | 久久综合久久久 | 亚洲日本欧美日韩高观看 | 秋霞影院一区二区 | 欧美日韩中 | 欧美成人一区二区三区片免费 | 瑟瑟视频在线看 | 91精品国产91久久久久久最新 | 草草草草视频 | www.com久久久 | 高清国产午夜精品久久久久久 | 天天想天天干 | 青娱乐av| 日韩一区不卡 | 欧美一级www片免费观看 | 久久精品国产亚洲 | 日一区二区 | 久久久久久免费看 | 人人九九精 | 99久久精品免费 | 亚洲一区二区精品视频 | 一级毛片视频在线观看 | www.五月天婷婷.com | 另类在线 | 亚洲综合日韩精品欧美综合区 | 久久男人 | 久久免费看 | 亚洲视频中文字幕 | 亚洲精品成人免费 | 久久精品二区亚洲w码 | 日韩欧美专区 | 欧美中文字幕一区二区 | 宅女噜噜66国产精品观看免费 | 日韩精品一区二区三区免费视频 | 亚洲欧美日韩一区 | 黄色一级电影免费观看 |