K8s中的多容器Pod和Pod内容器间通信


容器(Container)常被用来解决比如微服务的单个问题,但在实际场景中,问题的解决往往需要多容器方案。本文会讨论将多个容器整合进单个Kubernetes Pod 中,以及Pod中的容器之间是如何通信的。

Kubernetes Pod 是什么?

首先我们来探讨下什么是Pod。Pod是Kubernetes中最小的可部署和管理单元。换句话讲,如果需要在Kubernetes中运行单个容器,那么你就得为这个容器创建一个Pod。同时,一个Pod可以包含多个容器,这些容器往往是紧耦合的。怎么样个紧耦合法呢?试着想象这么一个场景,一个Pod中的多个容器代表需要运行在同一个服务器上的多个进程。这种类比是合理的,因为在许多方面,Pod就类似于一台服务器。比如,通过localhost每个容器可以访问它所在Pod中的其它容器。

为什么Kubernetes将Pod而不是单个容器作为最小可部署单元呢?

尽管直接部署单个容器也许会更容易,但增加Pod这个新的抽象层会带来新的好处。容器是一个真实存在的实体,它代表一个具体的东西。这个“东西”可以是一个Docker容器,也可以是一个rkt容器。每种“东西”都有不同的用途。为了管理容器,Kubernetes需要更多的信息,比如重启策略(restart policy),它定义了当容器终止了时怎样重启容器;还有活性检测(liveness probe),它定义了如何从应用视角去检测容器中的进程是否活着,比如Web服务器进程是否能响应HTTP请求。

 

为了避免在容器这个已有的实体上增加这些新的属性,Kubernetes架构师们决定使用一个新的实体,那就是Pod。它逻辑地包含一个或多个容器。

为什么Kubernetes允许Pod中存在一个或多个容器?

Pod中的容器们运行在一个逻辑“主机”上。他们使用同一个网络命名空间(network namespace,换句话讲,就是同样的IP地址和端口空间),以及同样的IPC(inter-process communication,进程间通信)命名空间,他们还使用共享卷(shared volume)。这些特征使得Pod内的容器能互相高效地通信。同时,Pod使得你可以将多个紧耦合的应用容器当做一个实体来管理。

 

那么,如果一个应用需要在同一台服务器上运行多个容器,为什么不把所有东西放在一个容器里面呢?好吧,首先,这会违反“一个容器一个进程”规范。这个规范很重要,因为当一个容器中有多个进程时,调试会变得非常困难,因为不同进程的日志会混在一起,而且很难去管理这些进程的生命周期。其次,为一个应用使用多个容器会更简单、更直接、能解耦软件依赖。而且,更细粒度的容器可以在团队间复用。

多容器Pod的用例

多容器Pod的主要目的是为了支持同时存在的(co-located)及同时被管理的(co-managed)帮助进程(helper process)。帮助进程有几种通用场景:

 

  • 边车容器(sidecarcontainer):比如日志或数据变化监视器等。一个团队创建日志监视器(log watcher)后,它可以被各种应用使用。另一个边车容器的例子是文件或数据加载器,它负责为主容器产生数据。

  • 代理(Proxy)、桥(bridge)和适配器(adapter):它们将主容器连接到外部世界。比如,Apache HTTP 服务器或nginx 会读取静态文件。它们还能被用作主容器中的web应用的反向代理(reverseproxy)。

     

当你在Pod中运行多层应用(比如WordPress)时,推荐的方式是为每层使用单独的Pod。最简单的理由是这样你就可以独立地扩展每层,并将他们分布在不同节点上。

Pod 中容器间的通信

在Pod中运行多个容器,使得它们之间的通信非常直接。他们自己的通信有几种方法。

通过共享卷通信 

在Kubernetes中,Pod中的容器可以将共享卷当做一种简单和高效的共享数据方式。在大多数场景中,使用主机上的一个目录,并在多个容器间共享,是一种高效的方式。 

 

Kubernetes volume(卷)使得在容器重启后数据能被保存下来。卷具有和Pod一样的生命周期。这意味着,只要Pod存在,卷就存在。如果Pod被删除了,即使一模一样的Pod被创建出来,原来Pod的共享卷也会被销毁,一个新的共享卷会被创建出来。 

进程间通信(Inter-processCommunication,IPC)

Pod中的容器共享同一个IPC命名空间,这意味着它们可以使用标准的进程间通信方式来互相通信,比如SystemV信号量和POSIX共享内存。

 

容器间的网络通信

Pod中的容器可以通过“localhost”来互相通信,因为他们使用同一个网络命名空间。而且,对容器来说,hostname就是Pod的名称。因为Pod中的所有容器共享同一个IP地址和端口空间,你需要为每个需要接收连接的容器分配不同的端口。也就是说,Pod中的应用需要自己协调端口的使用。

 

在下面的例子中,我们会创建一个多容器Pod,其中一个容器中运行Nginx,它作为另一个容器中运行的web应用的反向代理。

(1)步骤1,为nginx配置文件创建一个ConfigMap。从80端口进来的HTTP请求会被转发到localhost上的5000端口。

(2)步骤2:创建一个两容器Pod,一个容器运行nginx,另一个容器运行简单的web应用。注意我们只为Pod定义了80端口。端口5000不能被从Pod外部访问到。

 查看pod中的端口空间,能看到有80 和 5000端口。

 

(3)步骤3:将Pod暴露为一个 NodePort服务

 (4)步骤4:确认服务

现在,就可以使用浏览器或者curl工具来访问这个web应用了。

nginx容器的80端口上收到的HTTP请求会被转发到web应用容器的5000端口。

 

posted @ 2019-12-08 22:12  莫孟林  阅读(16272)  评论(0编辑  收藏  举报