kubernetes之多容器pod以及通讯

系列目录html

容器常常是为了解决单一的,窄范围的问题,好比说微服务.然而现实中,一些复杂问题的完成每每须要多个容器.这里咱们讨论一下如何把多个容器放在同一个pod里以及容器间的通讯linux

什么是pod

pod是kubernetes里的一个基本概念,可能咱们从一开始接触kubernetes的时候就开始接触pod,并被灌输pod是kubernetes里最小的不可分割的工做单元,这里再从多容器的角度对其进行一些基本阐释.nginx

简言之,pod是kubernetes能够部署和管理的最小单元,换言之也就是说若是你想要运行一个容器,你先要为这个容器建立一个pod.同时,一个pod也能够包含多个容器,之因此多个容器包含在一个pod里,前面讲到过的初始容器为普通应用容器准备环境是一种使用场景,每每因为业务上的紧密耦合,一组容器也须要放在同一个pod里.web

须要注意的是,以上场景都非必须把不一样的容器放在同一个pod里,可是这样每每更便于管理,甚至后面会讲到的,紧密耦合的业务容器放置在同一个容器里通讯效率更高.具体怎么使用还要看实际状况,综合权衡.docker

kubernetes为何使用pod做为最小单元,而不是container

直接部署一个容器看起来更简单,可是这里也有更好的缘由为何在容器基础上抽象一层.容器是一个存在的实体,并指向一个具体的事物.这个具体的事物多是一个docker容器,但也多是一个rtk容器,或者一个Virtlet管理的虚拟机.它们有不一样的要求.api

更深层的缘由是为了管理容器,kubernetes须要更多的信息,好比重启策略,它定义了容器终止后要采起的策略;或者是一个可用性探针,从应用程序的角度去探测是否一个进程还存活着.浏览器

基于这些缘由,kubernetes架构师决定使用一个新的实体,也就是pod,而不是重载容器的信息添加更多属性,用来在逻辑上包装一个或者多个容器的管理所须要的信息bash

kubernetes为何容许一个pod里有多个容器

pod里的容器运行在一个逻辑上的"主机"上,它们使用相同的网络名称空间(也就是说,同一pod里的容器使用相同的ip和相同的端口段区间)和相同的IPC名称空间.它们也能够共享存储卷.这些特性使它们能够更有效的通讯.而且pod可使你把紧密耦合的应用容器做为一个单元来管理.服务器

所以一个应用若是须要多个运行在同一主机上的容器时,为何为把它们放在同一个容器里呢?首先,这样何故违反了一个容器只负责一个应用的原则.这点很是重要,若是咱们把多个应用放在同一个容器里,这将使解决问题变得很是麻烦由于它们的日志记录混合在了一块儿,而且它们的生命周期也很难管理.所以一个应用使用多个容器将更简单,更透明,而且使应用依赖解偶.而且粒度更小的容器更便于不一样的开发团队共享和复用.网络

这里说到为了解偶把应用分别放在不一样容器里,前面咱们也强调为了便于管理管紧耦合的应用把它们的容器放在同一个pod里.一会强调耦合,一个强调解偶看似矛盾,实际上广泛存在,高内聚低耦合是咱们的追求,然而一个应用的业务逻辑模块不可能彻底完独立不存在耦合,这就须要咱们从实际上来考量,作出决策.

多容器pod的使用场景举例

  • Sidecar containers "帮助"主容器,好比日志文件监视器.一个日志监视器构建完成之后,能够由不一样的应用来使用.另外一个示例是sidecar 容器为主容器加载文件和运行须要的数据

  • 代理,桥接和适配器 使主容器与外部世界联通.好比Apache http服务器或者nginx可承载静态文件.也能够作为一个web的反向代理服务器.

你可使用一个pod来承载一个多层应用(好比wordpress),可是更建议使用不一样的pod来承载不一样的层,因这这样你能够为每个层单独扩容而且把它们分布到集群的不一样节点上.

同一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就会读取它并响应给用户.

image

你能够经过把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

image

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

容器的依赖关系和启动顺序

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

同一pod的容器间网络通讯

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

同一个pod暴露多个容器

一般pod里的容器监听不一样的端口,想要被外部访问都须要暴露出去.你能够经过在一个服务里暴露多个端口或者使用不一样的服务来暴露不一样的端口来实现

相关文章
相关标签/搜索