【Kubernetes】Pod 之 多容器

3,322 阅读5分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第7天,点击查看活动详情

一、前言

为什么在一个pod上运行多个容器,而不是在一个容器上运行多个进程呢?

  1. 容器的设计原则就是一个容器运行一个进程(由父进程产生子进程的除外)
  2. 容器中有多个进程,根据日志进行系统排错变困难,难以管理不同进程的生命周期
  3. 一个应用程序使用多个容器可以实现进一步的解耦

多容器Pod的特征

运行在一个pod节点上的多个容器,它们共享的资源有:

  • 相同的Linux命名空间(相同IP地址和端口空间,容器间互相访问)
  • 相同 IPC名称空间
  • 可以使用相同的共享卷

使用场景:应用由一个主进程和一个/多个辅助进程组成。



二、Pod容器间的通信

通信主要3种方式:

  • Pod 共享 Volume
  • 进程间通信(IPC
  • 容器间网络通信

(1)Pod 共享 Volume

常见用法: 一个容器写日志或其它数据文件到共享目录中,其它容器从这个共享目录中读取数据。

Pod 中运行的多个容器可以共享 Pod 级别的存储卷 Volume,可以使用 emptyDir 类型的存储卷作为 Pod 内部的空目录,用于 Pod 中运行的多个容器间的数据共享。

举个例子:

一个pod包含两个容器:

  • tomcat容器,用于向app-logs volume中写入日志文件
  • busybox容器用于从app-logs volume中读取日志文件并打印
  1. 创建tomcat-busybox.yaml

tomcat容器在启动后会向/usr/local/tomcat/logs目录下写日志文件,而busybox容器就可以读取其中的日志文件

apiVersion: v1
kind: Pod
metadata:
  name: tomcat-busybox-pod
spec:
  containers:
    - name: tomcat
    image: tomcat
      ports:
        - containerPort: 8080
      volumeMounts:
        - name: app-logs
          mountPath: /usr/local/tomcat/logs # 将共享卷 app-logs 挂载到 tomcat 容器内的 /usr/local/tomcat/logs 目录下
    - name: busybox
      image: busybox
      command: ["sh", "-c", "tail -f /logs/catalina*.log"]
      volumeMounts:
        - name: app-logs
          mountPath: /logs # 将共享卷 app-logs 挂载到 busybox 容器内的 /logs 目录下
  volumes:
    - name: app-logs
      emptyDir: {}
  1. 执行创建
$ kubectl create -f tomcat-busybox.yaml
pod/tomcat-busybox-pod created

# 这里的 2/2 表示两个容器都启动成功了
$ kubectl get pods
NAME                 READY   STATUS    RESTARTS   AGE
tomcat-busybox-pod   2/2     Running   0          50s
  1. 查看创建过程
# 查看详细的创建过程(包括 Volumes 和 Events),可以看到两个容器依次被创建了起来
$ kubectl describe pod tomcat-busybox-pod
  1. 查看busybox日志

busybox容器的启动命令tail -f /logs/catalina*.log 通过kubelet logs命令查看busybox容器的输出内容 busybox容器打印的是日志文件 /usr/local/tomact/logs/catalina..log 中的内容

$ kubectl logs tomcat-busybox-pod -c busybox
......
26-Sep-2019 09:56:26.653 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/usr/local/tomcat/webapps/docs]
26-Sep-2019 09:56:26.687 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/usr/local/tomcat/webapps/docs] has finished in [34] ms
26-Sep-2019 09:56:26.691 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["http-nio-8080"]
26-Sep-2019 09:56:26.702 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["ajp-nio-8009"]
26-Sep-2019 09:56:26.705 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in 822 ms
  1. 查看tomcat容器日志信息
$ kubectl exec -it tomcat-busybox-pod -c tomcat -- ls /usr/local/tomcat/logs
catalina.2019-09-26.log      localhost_access_log.2019-09-26.txt
host-manager.2019-09-26.log  manager.2019-09-26.log
localhost.2019-09-26.log

$ kubectl exec -it tomcat-busybox-pod -c tomcat -- tail /usr/local/tomcat/logs/catalina.2019-09-26.log
......
26-Sep-2019 09:56:26.653 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/usr/local/tomcat/webapps/docs]
26-Sep-2019 09:56:26.687 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/usr/local/tomcat/webapps/docs] has finished in [34] ms
26-Sep-2019 09:56:26.691 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["http-nio-8080"]
26-Sep-2019 09:56:26.702 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["ajp-nio-8009"]
26-Sep-2019 09:56:26.705 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in 822 ms
  1. 删除 podkubectl delete pod xxx

(2)进程间通信(IPC

一个 Pod 中的多个容器之间共享相同的 IPC 命名空间,所以它们互相之间可以使用标准进程间通信,比如:SystemV 信号系统或 POSIX 共享内存。

举个例子:

在一个pod中运行两个容器:

  • 生产者producer
  • 消费者consumer

这两个容器都使用相同的镜像ipc

  1. producer容器创建了一个标准的Linux消费队列,写一些随机的消息,最后写一个特殊的退出消息
  2. consumer容器打开相同的消费队列来读取消息,直到接收到退出消息。
  1. 创建yaml配置文件
apiVersion: v1
kind: Pod
metadata:
  name: ipc-test
spec:
  containers:
    - name: producer
      image: registry-vpc.cn-hangzhou.aliyuncs.com/chenshi-kubernetes/ipc:latest
      command: ["./ipc", "-producer"]
    - name: consumer
      image: registry-vpc.cn-hangzhou.aliyuncs.com/chenshi-kubernetes/ipc:latest
      command: ["./ipc", "-consumer"]
  restartPolicy: Never
  1. 执行创建:kubectl create -f ipc-pod.yaml

  2. 查看每个容器的日志

$ kubectl logs ipc-test -c producer
......
Produced: 9a
Produced: 21
Produced: c8
Produced: a
Produced: 76

$ kubectl logs ipc-test -c consumer
......
Consumed: 9a
Consumed: 21
Consumed: c8
Consumed: a
Consumed: 76
Consumed: done

(3)容器间网络通信

pod中的多个容器都可以通过localhost进行互相访问,因为它们都使用相同的网络名称空间。

举个例子:

pod中创建两个容器:

  • nginx容器作为反向代理
  • webapp容器运行一个简单的服务

配置nginx文件通过 http 80端口访问请求会被转发到本地的 5000 端口上

  1. nginx.conf配置文件写入
user nginx;
worker_processes 1;

error_log /var/log/nginx/error.log warn;
pid       /var/run/nginx.pid;

events {
worker_connections 1024;
}

http {
include      /etc/nginx/mime.types;
default_type application/octet-stream;

sendfile          on;
keepalive_timeout 65;

upstream webapp {
server 127.0.0.1:5000;
}

server {
listen 80;

location / {
proxy_pass     http://webapp;
proxy_redirect off;
}
}
}
  1. 使用nginx.conf配置文件创建一个 nginx-confConfigMap
$ kubectl create configmap nginx-conf --from-file=/home/shiyanlou/nginx.conf
configmap/nginx-conf created
  1. 创建pod文件

开放 nginx容器的 80 端口,webapp容器的5000端口没有开放的,不能被pod外部访问

apiVersion: v1
kind: Pod
metadata:
  name: nginx-webapp-pod
  labels:
    app: http-service
spec:
  containers:
    - name: webapp
      image: registry-vpc.cn-hangzhou.aliyuncs.com/chenshi-kubernetes/webapp:latest
    - name: nginx
      image: nginx:alpine
      ports:
        - containerPort: 80
      volumeMounts:
        - name: nginx-proxy-config
          mountPath: /etc/nginx/nginx.conf
          subPath: nginx.conf
  volumes:
    - name: nginx-proxy-config
      configMap:
        name: nginx-conf
  1. 执行创建pod资源对象
$ kubectl create -f nginx-webapp.yaml
pod/nginx-webapp-pod created
  1. 使用NodePort服务暴露nginx-webapp-pod Pod
$ kubectl expose pod nginx-webapp-pod --type=NodePort --port=80
service/nginx-webapp-pod exposed
  1. 查看 nginx-webapp-pod所在的Node节点,并且查看nginx-webapp-pod服务开放的NodePort
$ kubectl get pod nginx-webapp-pod -o wide
NAME               READY   STATUS    RESTARTS   AGE    IP           NODE          NOMINATED NODE   READINESS GATES
nginx-webapp-pod   2/2     Running   0          7m7s   10.244.2.4   kube-node-1   <none>           <none>

$ kubectl describe service nginx-webapp-pod
...
NodePort:                 <unset>  30889/TCP
...
  1. 通过curl访问 Node IP + NodePort地址
$ curl 10.192.0.3:30889
Hello world!