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 容器之間
