Kubernetes 系列(七):Pod、容器之间通讯方式
pod内部容器之间
在Pod中运行多个容器,使得它们之间的通信非常直接。他们自己的通信有几种方法。
通过共享卷通信
在Kubernetes中,Pod中的容器可以将共享卷当做一种简单和高效的共享数据方式。在大多数场景中,使用主机上的一个目录,并在多个容器间共享,是一种高效的方式,比如日志处理。
我现在有一个应用,需要不断地把日志文件输出到容器的 /var/log 目录中。这时,我就可以把一个 Pod 里的 Volume 挂载到应用容器的 /var/log 目录上。
然后,我在这个 Pod 里同时运行一个 sidecar 容器,它也声明挂载同一个 Volume 到自己的 /var/log 目录上。这样,接下来 sidecar 容器就只需要做一件事儿,那就是不断地从自己的 /var/log 目录里读取日志文件,转发到 MongoDB 或者 Elasticsearch 中存储起来。这样,一个最基本的日志收集工作就完成了。
Kubernetes volume(卷)使得在容器重启后数据能被保存下来。卷具有和Pod一样的生命周期。这意味着,只要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就会读取它并响应给用户.
你可以通过把nginx的端口暴露出去然后通过浏览器查看或者查看共享目录里的文件来检测以上是否有效果。
进程间通信(Inter-processCommunication,IPC)
Pod中的容器共享同一个IPC命名空间,这意味着它们可以使用标准的进程间通信方式来互相通信,比如SystemV信号量和POSIX共享内存。
容器间的网络通信
pod内部容器是共享一个网络命名空间的,所以Pod中的容器可以通过“localhost”来互相通信,pod中的容器
而且,对容器来说,hostname就是Pod的名称。因为Pod中的所有容器共享同一个IP地址和端口空间,你需要为每个需要接收连接的容器分配不同的端口。也就是说,Pod中的应用需要自己协调端口的使用。
k8s在启动容器的时候会先启动一个pause容器,这个容器就是实现这个功能的。
在下面的例子中,我们会创建一个多容器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端口。
外网访问pod中的容器
两种方法:
一、手动创建service文件
1.创建nginx.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment spec: selector: matchLabels: app: nginx replicas: 2 template: metadata: labels: app: nginx 就是说哪些Pod被Service池化是根据Label标签来的,此行nginx字样,后面我们创建Service会用到 spec: containers: - name: nginx image: nginx ports: - containerPort: 80(容器内部开放的端口)
2.创建Deployment
kubectl create -f nginx.yaml
3.创建nginx-svc.yml
注意:需要指定type类型NodePort,并且nodePort指定一个外部访问的port(范围:30000-32767)
selector选择之前Label标签为nginx的Pod作为Service池化的对象,最后说的是把Service的8080端口映射到Pod的80端口。
apiVersion: v1 kind: Service metadata: name: nginx-svc spec: type: NodePort #必须 selector: app: nginx ports: - protocol: TCP
nodePort:37844 #service暴露在cluster ip上的端口,通过<cluster ip>:port访问服务,通过此端口集群内的服务可以相互访问 port: 8080 #Pod的外部访问端口,port和nodePort的数据通过这个端口进入到Pod内部,Pod里面的containers的端口映射到这个端口,提供服务 targetPort: 80 #Node节点的端口,<nodeIP>:nodePort 是提供给集群外部客户访问service的入口
4.创建service
kubectl apply -f nginx-svc.yml
5.查看该Service
kubectl get nginx-svc
6.查看该Service的描述信息
kuectl desribe service nginx-svc
最后总结:
集群内部:集群内部客户端访问service的入口,即clusterIP:port
。
外网:外部流量通过访问nodeIP:nodePort单个pod。
二、手动创建service文件
使用kube expose命令
转发K8S后端服务的四种方式
ClusterIP
此类型会提供一个集群内部的虚拟IP(与Pod不在同一网段),以供集群内部的pod之间通信使用。ClusterIP也是Kubernetes service的默认类型。
为了实现图上的功能主要需要以下几个组件的协同工作:
apiserver:在创建service时,apiserver接收到请求以后将数据存储到etcd中。
kube-proxy:k8s的每个节点中都有该进程,负责实现service功能,这个进程负责感知service,pod的变化,并将变化的信息写入本地的iptables中。
iptables:使用NAT等技术将virtualIP的流量转至endpoint中。
NodePort
NodePort模式除了使用cluster ip外,也将service的port映射到每个node的一个指定内部port上,映射的每个node的内部port都一样。
为每个节点暴露一个端口,通过nodeip + nodeport可以访问这个服务,同时服务依然会有cluster类型的ip+port。内部通过clusterip方式访问,外部通过nodeport方式访问。
loadbalance
LoadBalancer在NodePort基础上,K8S可以请求底层云平台创建一个负载均衡器,将每个Node作为后端,进行服务分发。该模式需要底层云平台(例如GCE)支持。
Ingress
Ingress,是一种HTTP方式的路由转发机制,由Ingress Controller和HTTP代理服务器组合而成。Ingress Controller实时监控Kubernetes API,实时更新HTTP代理服务器的转发规则。HTTP代理服务器有GCE Load-Balancer、HaProxy、Nginx等开源方案。
详细说明请见http://blog.csdn.net/liyingke112/article/details/77066814
service的三种端口
port
port是暴露在cluster ip上的端口,port提供了集群内部客户端访问service的入口,即clusterIP:port
。
mysql容器暴露了3306端口(参考DockerFile),集群内其他容器通过33306端口访问mysql服务,但是外部流量不能访问mysql服务,因为mysql服务没有配置NodePort。对应的service.yaml如下:
nodePort
nodePort提供了集群外部客户端访问service的一种方式,:nodePort提供了集群外部客户端访问service的端口,即nodeIP:nodePort
提供了外部流量访问k8s集群中service的入口。
比如外部用户要访问k8s集群中的一个Web应用,那么我们可以配置对应service的type=NodePort
,nodePort=30001
。其他用户就可以通过浏览器http://node:30001
访问到该web服务。
而数据库等服务可能不需要被外界访问,只需被内部服务访问即可,那么我们就不必设置service的NodePort。
targetPort
targetPort是pod上的端口,从port/nodePort上来的数据,经过kube-proxy流入到后端pod的targetPort上,最后进入容器。
containerPort
containerPort是在pod控制器中定义的、pod中的容器需要暴露的端口。
port、nodePort总结
总的来说,port和nodePort都是service的端口,前者暴露给集群内客户访问服务,后者暴露给集群外客户访问服务。从这两个端口到来的数据都需要经过反向代理kube-proxy流入后端pod的targetPod,从而到达pod上的容器内。
pod 与 pod 容器之间