基本概念
我们都知道一个pod里面可以放若干个容器,容器之间可以共享网络命名空间、文件夹。这时候一个pod里面有两个容器a和b,同时对外提供服务。如果这个两个服务之间需要彼此交互,比如a想要触发b容器的容器,或者b想要获取a容器里的一个变量之类的。我们这时候就可以使用容器共享命名空间的方法。
具体操作
先准备两个程序app1和app2
app1.go
1 2 3 4 5 6 7 8 9 10 11
| package main
import "net/http"
func main() { http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) { writer.Write([]byte("this is app1\n")) }) http.ListenAndServe(":8080", nil) }
|
app2.go
1 2 3 4 5 6 7 8 9 10 11 12 13
| package main
import ( "net/http" )
func main() { http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) { writer.Write([]byte("this is app2\n")) }) http.ListenAndServe(":8081", nil) }
|
然后分别编译丢到服务器上
编写对应的yaml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| apiVersion: apps/v1 kind: Deployment metadata: name: k8splay namespace: default spec: replicas: 1 selector: matchLabels: app: k8splay template: metadata: labels: app: k8splay spec: nodeName: k8s-node1 containers: - name: k8splayapp1 image: alpine:3.12 imagePullPolicy: IfNotPresent command: [ "./app1" ] workingDir: /app volumeMounts: - name: app mountPath: /app ports: - containerPort: 8080 - name: k8splayapp2 image: alpine:3.12 imagePullPolicy: IfNotPresent command: [ "./app2" ] workingDir: /app volumeMounts: - name: app mountPath: /app ports: - containerPort: 8081 volumes: - name: app hostPath: path: /root/k8splay
|
然后直接apply
进入这个容器查看
可以看到 pid为1的进程为 ./app1
,这也没啥好说的
这时候在yaml中加入 shareProcessNamespace: true
,打开共享进程命名空间开关。
此时进入pod查看进程
现在任意一个容器查看 pid为1的进程就不是自己了,而且可以查看到其他容器的进程了。这就是进程命名空间共享。
现在在app1这个容器写入一个文件,在app2容器利用共享进程命名空间可以查看到了,而不需要设置emptydir
总结一下:
- 当启用进程命名空间共享时,容器中的进程对该pod中所有其他容器都可见
- 容器进程PID不再是1
- 容器文件系统 通过
/proc/$pid/root
链接对pod中的其他容器可见
使用信号通知进程
使用命令行操作
使用脚本方式发送信号通知容器1,不通知容器2
重新修改app1.go代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| package main
import ( "fmt" "net/http" "os" "os/signal" "syscall" "time" )
func main() { http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) { writer.Write([]byte("this is app1\n")) }) go func() { for { ch := make(chan os.Signal) signal.Notify(ch, syscall.SIGTERM, syscall.SIGUSR1) c := <-ch fmt.Println("接收到信号:", c) time.Sleep(time.Millisecond * 50) }
}() http.ListenAndServe(":8080", nil) }
|
重新apply 一下
使用代码方式
app1.go
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| package main
import ( "fmt" "net/http" "os" "os/signal" "syscall" "time" )
var counter = 1
func main() { http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) { writer.Write([]byte("this is app1\n")) }) http.HandleFunc("/counter", func(writer http.ResponseWriter, request *http.Request) { writer.Write([]byte(fmt.Sprintf("counter: %d\n", counter))) counter++ }) go func() { for { ch := make(chan os.Signal) signal.Notify(ch, syscall.SIGTERM, syscall.SIGUSR1) c := <-ch switch c { case syscall.SIGUSR1: fmt.Println("counter被重置") counter = 0 } time.Sleep(time.Millisecond * 50) }
}() http.ListenAndServe(":8080", nil) }
|
每次访问/counter ,counter就会加1
app2.go
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| package main
import ( "net/http" "syscall" )
func main() { http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) { writer.Write([]byte("this is app2\n")) }) http.HandleFunc("/rest", func(writer http.ResponseWriter, request *http.Request) { syscall.Kill(-1, syscall.SIGUSR1) }) http.ListenAndServe(":8081", nil) }
|
在app2中访问 /rest,就会发生信号给app1,从而触发counter=0的逻辑
Deploy.yaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| apiVersion: apps/v1 kind: Deployment metadata: name: k8splay namespace: default spec: replicas: 1 selector: matchLabels: app: k8splay template: metadata: labels: app: k8splay spec: nodeName: k8s-node1 shareProcessNamespace: true containers: - name: k8splayapp1 image: byrnedo/alpine-curl imagePullPolicy: IfNotPresent command: [ "./app1" ] workingDir: /app volumeMounts: - name: app mountPath: /app ports: - containerPort: 8080 - name: k8splayapp2 image: byrnedo/alpine-curl imagePullPolicy: IfNotPresent command: [ "./app2" ] workingDir: /app volumeMounts: - name: app mountPath: /app ports: - containerPort: 8081 volumes: - name: app hostPath: path: /root/k8splay
|