侧边栏壁纸
  • 累计撰写 51 篇文章
  • 累计创建 23 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

K8s Pod 和 Service 4

zhanjie.me
2020-11-11 / 0 评论 / 0 点赞 / 1 阅读 / 0 字

4.1 多容器 Pod 简介

为什么要在一个 Pod 上运行多个容器,而不是一个容器上运行多个进程呢?这是因为容器的设计原则就是一个容器运行一个进程(由父进程产生子进程的除外)。如果一个容器中有多个进程,首先当出现进程问题时要根据日志进行系统排错将会非常困难,其次会比较难管理不同进程的生命周期,最后一个应用程序使用多个容器可以实现进一步的解耦、使系统管理更加简单化。

在一个 Pod 上运行多容器,一个进程对应一个容器,在一定程度上是实现了进程的部分隔离,但是由于又是运行在同一个 Pod 中,Pod 为这些容器提供了几乎相同的环境,使得容器间可以共享需要的数据资源,所以可以理解为 Pod 是容器更高级的一个抽象概念。

多容器 Pod 的特征

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

  • 相同的 Linux 命名空间:也就是相同的 IP 地址和端口空间,容器应用间相互访问只需要通过 localhost 进行通信即可,但是需要注意的是:同一 Pod 中的容器进程不能绑定到相同的端口号,否则会导致端口冲突
  • 相同的 IPC 名称空间
  • 可以使用相同的共享卷

正是这些共享的资源保证了多容器之间强耦合,可以彼此紧密联系完成强相关的功能。

使用场景

由于 Kubernetes 集群理论上可以创建无数个 Pod,所以我们并不需要将所有的组件都运行在一个 Pod 中,官方推荐的依然是尽量一个 Pod 运行一个容器,这个会更加方便管理,如果在必要的情况下,一个 Pod 中可以运行紧密相关的组件或进程,也就是多个容器。

在 Pod 中运行多容器的常用场景是:应用由一个主进程和一个/多个辅助进程组成。


4.2 Pod 中容器间的通信

这里主要包含 3 种方式:Pod 容器共享 Volume、进程间通信(IPC)、以及容器间网络通信。

Pod 容器共享 Volume

Pod 中运行的多个容器可以共享 Pod 级别的存储卷 Volume,可以使用 emptyDir 类型的存储卷作为 Pod 内部的空目录,用于 Pod 中运行的多个容器间的数据共享。当 Pod 被分配到 Node 上时,存储卷 Volume 最先被创建,并且存储卷的存在时间与 Pod 存活时间相同。

对于多容器 Pod 共享 Volume 的常见用法是:一个容器写日志或其它数据文件到共享目录中,其它容器从这个共享目录中读取数据。比如我们创建一个 Pod 包含两个容器,其中 tomcat 容器用于向 “app-logs” Volume 中写入日志文件,而 busybox 容器用于从 “app-logs” Volume 中读取日志文件并打印。

新建 tomcat-busybox.yaml 文件并向其中写入如下内容:

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: {}

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

执行创建:

$ 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          44s

查看详细的创建过程(包括 Volumes 和 Events),可以看到两个容器依次被创建了起来:

$ kubectl describe pod tomcat-busybox-pod
...
Events:
  Type    Reason     Age   From                   Message
  ----    ------     ----  ----                   -------
  Normal  Scheduled  2m4s  default-scheduler      Successfully assigned user-test/tomcat-busybox-pod to kubesphere03
  Normal  Pulling    2m3s  kubelet, kubesphere03  Pulling image "tomcat"
  Normal  Pulled     88s   kubelet, kubesphere03  Successfully pulled image "tomcat"
  Normal  Created    88s   kubelet, kubesphere03  Created container tomcat
  Normal  Started    88s   kubelet, kubesphere03  Started container tomcat
  Normal  Pulling    88s   kubelet, kubesphere03  Pulling image "busybox"
  Normal  Pulled     83s   kubelet, kubesphere03  Successfully pulled image "busybox"
  Normal  Created    83s   kubelet, kubesphere03  Created container busybox
  Normal  Started    83s   kubelet, kubesphere03  Started container busybox

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

$ kubectl logs tomcat-busybox-pod -c busybox
11-Nov-2020 14:24:24.536 INFO [main] org.apache.catalina.core.AprLifecycleListener.lifecycleEvent Loaded Apache Tomcat Native library [1.2.25] using APR version [1.6.5].
11-Nov-2020 14:24:24.536 INFO [main] org.apache.catalina.core.AprLifecycleListener.lifecycleEvent APR capabilities: IPv6 [true], sendfile [true], accept filters [false], random [true].
11-Nov-2020 14:24:24.536 INFO [main] org.apache.catalina.core.AprLifecycleListener.lifecycleEvent APR/OpenSSL configuration: useAprConnector [false], useOpenSSL [true]
11-Nov-2020 14:24:24.539 INFO [main] org.apache.catalina.core.AprLifecycleListener.initializeSSL OpenSSL successfully initialized [OpenSSL 1.1.1d  10 Sep 2019]
11-Nov-2020 14:24:24.947 INFO [main] org.apache.coyote.AbstractProtocol.init Initializing ProtocolHandler ["http-nio-8080"]
11-Nov-2020 14:24:24.975 INFO [main] org.apache.catalina.startup.Catalina.load Server initialization in [706] milliseconds
11-Nov-2020 14:24:25.058 INFO [main] org.apache.catalina.core.StandardService.startInternal Starting service [Catalina]
11-Nov-2020 14:24:25.058 INFO [main] org.apache.catalina.core.StandardEngine.startInternal Starting Servlet engine: [Apache Tomcat/9.0.39]
11-Nov-2020 14:24:25.068 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["http-nio-8080"]
11-Nov-2020 14:24:25.083 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in [107] milliseconds

现在进入 tomcat 容器中查看日志信息是否相同:

$ kubectl exec -it tomcat-busybox-pod -c tomcat -- ls /usr/local/tomcat/logs
catalina.2020-11-11.log      localhost_access_log.2020-11-11.txt
host-manager.2020-11-11.log  manager.2020-11-11.log
localhost.2020-11-11.log

$ kubectl exec -it tomcat-busybox-pod -c tomcat -- tail /usr/local/tomcat/logs/catalina.2020-11-11.log
11-Nov-2020 14:24:24.536 INFO [main] org.apache.catalina.core.AprLifecycleListener.lifecycleEvent Loaded Apache Tomcat Native library [1.2.25] using APR version [1.6.5].
11-Nov-2020 14:24:24.536 INFO [main] org.apache.catalina.core.AprLifecycleListener.lifecycleEvent APR capabilities: IPv6 [true], sendfile [true], accept filters [false], random [true].
11-Nov-2020 14:24:24.536 INFO [main] org.apache.catalina.core.AprLifecycleListener.lifecycleEvent APR/OpenSSL configuration: useAprConnector [false], useOpenSSL [true]
11-Nov-2020 14:24:24.539 INFO [main] org.apache.catalina.core.AprLifecycleListener.initializeSSL OpenSSL successfully initialized [OpenSSL 1.1.1d  10 Sep 2019]
11-Nov-2020 14:24:24.947 INFO [main] org.apache.coyote.AbstractProtocol.init Initializing ProtocolHandler ["http-nio-8080"]
11-Nov-2020 14:24:24.975 INFO [main] org.apache.catalina.startup.Catalina.load Server initialization in [706] milliseconds
11-Nov-2020 14:24:25.058 INFO [main] org.apache.catalina.core.StandardService.startInternal Starting service [Catalina]
11-Nov-2020 14:24:25.058 INFO [main] org.apache.catalina.core.StandardEngine.startInternal Starting Servlet engine: [Apache Tomcat/9.0.39]
11-Nov-2020 14:24:25.068 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["http-nio-8080"]
11-Nov-2020 14:24:25.083 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in [107] milliseconds

这就表明 Pod 中的两个容器确实共享了一个 Volume。


4.3 进程间通信(IPC)

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

比如,在一个 Pod 中运行两个容器,分别命名为生产者 producer 和消费者 consumer,这两个容器都使用的相同的镜像 ipc,producer 容器创建了一个标准的 Linux 消费队列,写一些随机的消息,最后写一个特殊的退出消息,consumer 容器打开相同的消费队列来读取消息,直到接收到退出消息。将重启策略设置为 “Never”,当这两个容器终止后该 Pod 就会停止。

新建 ipc-pod.yaml 文件,并向其中写入如下内容:

apiVersion: v1
kind: Pod
metadata:
  name: ipc-test
spec:
  containers:
    - name: producer
      image: ipc:latest
      command: ["./ipc", "-producer"]
    - name: consumer
      image: ipc:latest
      command: ["./ipc", "-consumer"]
  restartPolicy: Never

执行创建资源对象,查看每个容器的日志,可以发现 consumer 容器接收了所有来自 producer 容器的消息,包括退出消息:

$ 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

4.4 容器间网络通信

Pod 中的多个容器都可以通过 localhost 进行互相访问,因为它们使用相同的网络名称空间。下面的例子我们将展示容器间的网络通信。

我们在 Pod 中创建两个容器,一个 Nginx 容器作为反向代理,另一个 Webapp 容器运行一个简单的服务、当访问服务时会显示 “Hello world!”。

配置 Nginx 文件通过 HTTP 80 端口访问的请求会被转发到本地的 5000 端口上,新建 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;
}
}
}

使用上面创建的 nginx.conf 配置文件创建一个名为 nginx-conf 的 ConfigMap:

$ kubectl create configmap nginx-conf --from-file=/root/learning/nginx.conf
configmap/nginx-conf created

接下来创建 Pod YAML 文件,只开放 nginx 容器的 80 端口,webapp 容器的 5000 端口是没有开放的、所以不能被 Pod 外部访问,新建 nginx-webapp.yaml 文件,并向其中写入如下内容:

apiVersion: v1
kind: Pod
metadata:
  name: nginx-webapp-pod
  labels:
    app: http-service
spec:
  containers:
    - name: webapp
      image: 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

执行创建 Pod 资源对象:

$ kubectl create -f nginx-webapp.yaml
pod/nginx-webapp-pod created

使用 NodePort 服务暴露 nginx-webapp-pod Pod:

$ kubectl expose pod nginx-webapp-pod --type=NodePort --port=80
service/nginx-webapp-pod exposed

查看 nginx-webapp-pod 所在的 Node 节点,并且查看 nginx-webapp-pod 服务开放的 NodePort:

$ kubectl get pod nginx-webapp-pod -o wide
$ curl 192.168.0.31:30886
Hello world!
0

评论区