kubernetes中不同pod之间的通讯详解

avatar 2021年5月18日18:14:14 评论 4,002 次浏览

pod是kubernetes的最小单元,我们所有的服务都是以pod为参考,在kubernetes中运行的,本章主要是针对pod之间的通信,pod里的容器之间又是如何通信的:

同一pod内的容器共识存储卷

你可以使用一个共享的存储卷来简单高效的地在容器间共享数据.大多数情况下,使用一个共享目录在同一pod里的不同容器间共享数据就够了.
一个标准的同一pod内容器共享存储卷的用例是一个容器往共享存储卷里写入数据,其它的则从共享目录里读取数据

apiVersion: v1
kind: Pod
metadata:
  name: mc1
spec:
  volumes:
  - name: html
    emptyDir: {}
  containers:
  - name: 1st
    image: nginx
    volumeMounts:
    - name: html
      mountPath: /usr/share/nginx/html
  - name: 2nd
    image: debian
    volumeMounts:
    - name: html
      mountPath: /html
    command: ["/bin/sh", "-c"]
    args:
      - while true; do
          date >> /html/index.html;
          sleep 1;
        done

这个示例里我们定义了一个存储卷叫作html,它是emptyDir类型的.当一个pod在一个节点上创建的时候,它就被分配,只要pod一直运行在这个节点上它就一直存在(emptyDir生命周期和pod相同).就像它的名字所暗示的一样,它是一个空的目录,第一个容器运行了一个nginx server并且把它挂载到/usr/share/nginx/html,第二个容器使用了一个Debian镜像并把emptyDir挂载到/html.每一秒钟,第二个容器就会把当前日期写入到index.html里,它位于共享存储卷里.当用户发起一个http请求,nginx就会读取它并响应给用户.

你可以通过把nginx的端口暴露出去然后通过浏览器查看或者查看共享目录里的文件来检测以上是否有效果

kubectl exec mc1 -c 1st -- /bin/cat /usr/share/nginx/html/index.html
 ...
 Fri Aug 25 18:36:06 UTC 2017
 
 $ kubectl exec mc1 -c 2nd -- /bin/cat /html/index.html
 ...
 Fri Aug 25 18:36:06 UTC 2017
 Fri Aug 25 18:36:07 UTC 2017

进程间通信(IPC)

同一个pod里的容器共享IPC名称空间,这就意味着他们可以通过进程间通信的手段来进行通信,比如使用SystemV semaphores或者POSIX共享内存
以下示例中,我们定义一个包含了两个容器的pod.它们使用相同的docker镜像,第一个容器是一个生产者,创建一个标准的linux消息队列,写一些随机的消息,然后写一个特殊的退出消息.第二个容器是一个消费者,打开同一个消息队列来读取数据直到读到退出消息,我们把重启策略设置为Never,这样当两个pod都中止的时候pod就会停止.

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

然后通过kubectl create来创建pod,用下面命令来查看状态

$ kubectl get pods --show-all -w
NAME      READY     STATUS              RESTARTS  AGE
mc2       0/2       Pending             0         0s
mc2       0/2       ContainerCreating   0         0s
mc2       0/2       Completed           0         29

这时候你可以检测每一个容器的日志来检测第二个队列是否消费了第一个队列生产的所有消息包括退出消息

$ kubectl logs mc2 -c producer
...
Produced: f4
Produced: 1d
Produced: 9e
Produced: 27
$ kubectl logs mc2 -c consumer
...
Consumed: f4
Consumed: 1d
Consumed: 9e
Consumed: 27
Consumed: done

这里面存在一个问题,就是生产者所在容器要早于消费者所在容器,我们必须处理容器的启动顺序问题

容器的依赖关系和启动顺序
当前,同一个pod里的所有容器都是并行启动并且没有办法确定哪一个容器必须早于哪一个容器启动.就上面的IPC示例,我们不能总保证第一个容器早于第二个容器启动.这时候就需要使用到初始容器(init container)来保证启动顺序,关于初始容器,可以查看官方文档,本系列也对其进行了翻译,以便查看.

同一pod的容器间网络通信
同一pod下的容器使用相同的网络名称空间,这就意味着他们可以通过'localhost'来进行通信,它们共享同一个Ip和相同的端口空间

同一个pod暴露多个容器
通常pod里的容器监听不同的端口,想要被外部访问都需要暴露出去.你可以通过在一个服务里暴露多个端口或者使用不同的服务来暴露不同的端口来实现

各个Pod之间的通讯,即Pod1至Pod2:overlay network

Flannel是CoreOS团队针对k8s设计的一个网络规划服务,简单来说,他的功能是让集群的不同节点创建的Docker容器都具有全集群唯一的虚拟Ip地址。而且他还能在这些Ip地址之间建立一个覆盖网络(Overlay network),通过这个覆盖网络,将数据包原封不动地传递到目标容器。

Flannel方案 整体方案

ETCD与Flannel关系:存储管理Flannel可分配的IP地址段资源;监控ECTD中每个Pod的实际地址,并在内存中建立维护Pod节点路由表

1》Pod1与Pod2不在同一台主机,Pod的地址是与docker0在同一个网段的,但docker0网段与宿主机网卡是两个完全不同的ip网段,并且不同Node之间的通讯只能通过宿主机的物理网卡进行。将Pod的ip和所在Node的ip关联起来,通过这个关联可以让Pod互相访问。

2》Pod1与Pod2在同一台主机,由docker0网桥直接转发请求值Pod2,不需要经过Flannel

示例一、Pod1与Pod2不在同一台主机,跨节点通讯 过程

其实不管flannel或者calico网络环境,大致都是一样的,区别是fannle和calico的区别,其他的不受影响。

avatar

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: