Kubernetes用户指南(二)--部署组合型的应用、连接应用到网络中
生活随笔
收集整理的這篇文章主要介紹了
Kubernetes用户指南(二)--部署组合型的应用、连接应用到网络中
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
一、部署組合型的應用
1、使用配置文件啟動replicas集合
k8s通過Replication Controller來創建和管理各個不同的重復容器集合(實際上是重復的pods)。
Replication Controller會確保pod的數量在運行的時候會一直保持在一個特殊的數字,即replicas的設置。 這個功能類似于Google GCE的實例組管理和AWS的彈性伸縮。
在快速開始中,通過kubectl run以下的YAML文件創建了一個rc運行著nginx:
apiVersion:?v1
kind:?ReplicationController
metadata:
? name:?my-nginx
spec:
? replicas:?2
? template:
? ? metadata:
? ? ? labels:
? ? ? ? app:?nginx
? ? spec:
? ? ? containers:
? ? ? -?name:?nginx
? ? ? ? image:?nginx
? ? ? ? ports:
? ? ? ? -?containerPort:?80
和定義一個pod的YAML文件相比,不同的只是kind的值為ReplicationController,replicas的值需要制定,pod的相關定義在template中,pod的名字不需要顯式地指定,因為它們會在rc中創建并賦予名字,點擊查看完整的rc定義字段列表:
replication controller API object
rc可以通過create命令像創建pod一樣來創建:
$?kubectl?create?-f?./nginx-rc.yaml
replicationcontrollers/my-nginx
和直接創建pod不一樣,rc將會替換因為任何原因而被刪除或者停止運行的Pod,比如說pod依賴的節點掛了。所以我們推薦使用rc來創建和管理復雜應用,即使你的應用只要使用到一個pod,在配置文件中忽略replicas字段的設置即可。
2、查看Replication Controller的狀態
可以通過get命令來查看你創建的rc:
$?kubectl?get?rc
CONTROLLER? ?CONTAINER(S)? ?IMAGE(S)? ?SELECTOR? ? REPLICAS
my-nginx? ? ?nginx? ? ? ? ? nginx? ? ? app=nginx? ?2
這個狀態表示,你創建的rc將會確保你一直有兩個nginx的副本。
也可以和直接創pPod一樣查看創建的Pod狀態信息:
$?kubectl?get?pods
NAME? ? ? ? ? ? ?READY? ? ?STATUS? ? RESTARTS? ?AGE
my-nginx-065jq? ?1/1? ? ? ?Running? ?0? ? ? ? ? 51s
my-nginx-buaiq? ?1/1? ? ? ?Running? ?0? ? ? ? ? 51s
3、刪除Replication Controller
當你想停止你的應用,刪除你的rc,可以使用:
$?kubectl?delete?rc?my-nginx
replicationcontrollers/my-nginx
默認的,這將會刪除所有被這個rc管理的pod,如果pod的數量很大,將會花一些時間來完成整個刪除動作,如果你想使這些pod停止運行,請指定--cascade=false。 如果你在刪除rc之前嘗試刪除pod,rc將會立即啟動新的pod來替換被刪除的pod,就像它承諾要做的一樣。
4、Labels
k8s使用用戶自定義的key-value鍵值對來區分和標識資源集合(就像rc、pod等資源),這種鍵值對稱為label。 在上面的例子中,定義pod的template字段包含了一個簡單定義的label,key的值為app,value的值為nginx。所有被創建的pod都會卸載這個label,可以通過-L參數來查看:
$?kubectl?get?rc?my-nginx?-L?app
CONTROLLER? ?CONTAINER(S)? ?IMAGE(S)? ?SELECTOR? ? REPLICAS? ?APP
my-nginx? ? ?nginx? ? ? ? ? nginx? ? ? app=nginx? ?2? ? ? ? ? nginx
默認情況下,pod的label會復制到rc的label,同樣地,k8s中的所有資源都支持攜帶label。
更重要的是,pod的label會被用來創建一個selector,用來匹配過濾攜帶這些label的pods。 你可以通過kubectl get請求這樣一個字段來查看template的格式化輸出:
$?kubectl?get?rc?my-nginx?-o?template?--template="{{.spec.selector}}" map[app:nginx] 你也可以直接指定selector,比如你想在pod template中指明那些不想選中的label,但是你應該確保selector將會匹配這些從pod template中創建的pod的label,并且它將不會匹配其他rc創建的pod。
確保后者最簡單的方法是為rc創建一個唯一的label值,然后在pod template的label和selector中都指定這個label。
二、連接應用到網絡中
1、k8s中連接容器的模型
現在,你已經有了組合的、多份副本的應用,你可以將它連接到一個網絡上。在討論k8s聯網的方式之前,有必要和Docker中連接網絡的普通方式進行一下比較。
默認情況下,Docker使用主機私有網絡,所以容器之間可以互相交互,只要它們在同一臺機器上。 為了讓Docker容器可以進行跨節點的交流,必須在主機的IP地址上為容器分配端口號,之后通過主機IP和端口將信息轉發到容器中。 這樣一來,很明顯地,容器之間必須謹慎地使用和協調端口號的分配,或者動態分配端口號。
在眾多開發者之間協調端口號的分配是十分困難的,會將集群級別之外的復雜問題暴露給用戶來處理。
在k8s中,假設Pod之間可以互相交流,無論它們是在哪個宿主機上。 我們賦予每個Pod自己的集群私有IP,如此一來你就不需要明確地在Pod之間創建連接,或者將容器的端口映射到主機的端口中。 這意味著,Pod中的容器可以在主機上使用任意彼此的端口,而且集群中的Pods可以在不使用NAT的方式下連接到其他Pod。
本章將會詳細描述如何通過這樣一個網絡連接模型來運行穩定的Services。
本指南使用一個簡單的nginx服務來驗證以上的概念,在Jenkins CI application有對相同概念的更加詳細的說明。
2、在集群上將Pod連接到網絡
我們之前做過這個例子,但是讓我們以網絡連接的角度來重新做一次。 創建一個nginx Pod,注意,這個Pod有一個容器端口的說明:
$?cat?nginxrc.yaml
apiVersion:?v1
kind:?ReplicationController
metadata:
? name:?my-nginx
spec:
? replicas:?2
? template:
? ? metadata:
? ? ? labels:
? ? ? ? app:?nginx
? ? spec:
? ? ? containers:
? ? ? -?name:?nginx
? ? ? ? image:?nginx
? ? ? ? ports:
? ? ? ? -?containerPort:?80
這使它可以進入集群上的任意節點,檢查節點上運行的Pod:
$?kubectl?create?-f?./nginxrc.yaml
$?kubectl?get?pods?-l?app=nginx?-o?wide
my-nginx-6isf4? ?1/1? ? ? ?Running? ?0? ? ? ? ? 2h? ? ? ? e2e-test-beeps-minion-93ly
my-nginx-t26zt? ?1/1? ? ? ?Running? ?0? ? ? ? ? 2h? ? ? ? e2e-test-beeps-minion-93ly
檢查你的Pod的IPs:
$?kubectl?get?pods?-l?app=nginx?-o?json?|?grep?podIP
? ? ? ? ? ? ? ? "podIP":?"10.245.0.15", ? ? ? ? ? ? ? ? "podIP":?"10.245.0.14",
這時,你應該能夠通過ssh登錄任意節點然后使用curl來連接任一IP(如果節點之間沒有處于同一個子網段,無法使用私有IP進行連接的話,就只能在對應節點上使用對應的IP進行連接測試)。 注意,容器并不是真的在節點上使用80端口,也沒有任何的NAT規則來路由流量到Pod中。 這意味著你可以在同樣的節點上使用同樣的containerPort來運行多個nginx Pod,并且可以在集群上的任何Pod或者節點通過這個IP來連接它們。 和Docker一樣,端口仍然可以發布到宿主機的接口上,但是因為這個網絡連接模型,這個需求就變得很少了。
如果你好奇的話,可以通過這里查看我們是如何做到的: how we achieve this
3、創建Service
現在,在集群上我們有了一個運行著niginx并且有分配IP地址空間的的Pod。 理論上,你可以直接和這些Pod進行交互,但是當節點掛掉之后會發生什么? 這些Pod會跟著節點掛掉,然后RC會在另外一個健康的節點上重新創建新的Pod來代替,而這些Pod分配的IP地址都會發生變化,對于Service類型的服務來說這是一個難題。
k8s上的Service是抽象的,其定義了一組運行在集群之上的Pod的邏輯集合,這些Pod是重復的,復制出來的,所以提供相同的功能。 當Service被創建,會被分配一個唯一的IP地址(也稱為集群IP)。這個地址和Service的生命周期相關聯,并且當Service是運行的時候,這個IP不會發生改變。 Pods進行配置來和這個Service進行交互,之后Service將會自動做負載均衡到Service中的Pod。
你可以通過以下的YAML文件來為你的兩個nginx容器副本創建一個Service:
$?cat?nginxsvc.yaml
apiVersion:?v1
kind:?Service
metadata:
? name:?nginxsvc
? labels:
? ? app:?nginx
spec:
? ports:
? -?port:?80
? ? protocol:?TCP
? selector: app:?nginx
這個YAML定義創建創建一個Service,帶有Label為app=nginx的Pod都將會開放80端口,并將其關聯到一個抽象的Service端口。 (targetPort字段是指容器內開放的端口Service通過這個端口連接Pod,port字段是指抽象Service的端口,nodePort為節點上暴露的端口號,不指定的話為隨機。) 點擊這里查看完整的Service字段列表:
service API object?
現在查看你創建的Service:
$?kubectl?get?svc
NAME? ? ? ? ?CLUSTER_IP? ? ? ?EXTERNAL_IP? ? ? ?PORT(S)? ? ? ? ? ? ? ? SELECTOR? ? ?AGE
kubernetes? ?10.179.240.1? ? ?<none>? ? ? ? ? ? 443/TCP? ? ? ? ? ? ? ? <none>? ? ? ?8d nginxsvc? ? ?10.179.252.126? ?122.222.183.144? ?80/TCP,81/TCP,82/TCP? ?run=nginx2? ?11m
和之前提到的一樣,Service是以一組Pod為基礎的。 這些Pod通過endpoints字段開放出來。 Service的selector將會不斷地進行Pod的Label匹配,結果將會通知一個Endpoints Object,這里創建的也叫做nginxsvc。 當Pod掛掉之后,將會自動從Endpoints中移除,當有新的Pod被Service的selector匹配到之后將會自動加入這個Endpoints。 你可以查看這個Endpoint,注意,這些IP和第一步中創建Pods的時候是一樣的:
$?kubectl?describe?svc?nginxsvc
Name:? ? ? ? ? ?nginxsvc
Namespace:? ? ? default
Labels:? ? ? ? ?app=nginx
Selector:? ? ? ?app=nginx
Type:? ? ? ? ? ?ClusterIP
IP:? ? ? ? ?10.0.116.146
Port:? ? ? ? ? ?<unnamed>? ?80/TCP
Endpoints:? ? ? 10.245.0.14:80,10.245.0.15:80
Session?Affinity:? ?None
No?events.
$?kubectl?get?ep
NAME? ? ? ? ?ENDPOINTS nginxsvc? ? ?10.245.0.14:80,10.245.0.15:80
你現在應該可以通過10.0.116.146:80這個IP從集群上的任何一個節點使用curl命令來連接到nginx的Service。 注意,Service的IP是完全虛擬的,如果你想知道它是怎么工作的,請點擊: service proxy
4、Pod發現并加入到Service中
k8s提供了兩種基本的方式來發現Service:環境變量和DNS。 環境變量是立即可以使用的,DNS則需要kube-dns集群插件。
5、環境變量
當Pod運行在一個節點上,kubelet將會為每個激活的Service添加一系列的環境變量。 為你的nginx Pod檢查一下環境: $?kubectl?exec?my-nginx-6isf4?--?printenv?|?grep?SERVICE
KUBERNETES_SERVICE_HOST=10.0.0.1 KUBERNETES_SERVICE_PORT=443
注意,這里沒有顯示和Service相關的東西,因為這個Pod是在Service之前創建的,這種做法另外一個缺點是, Scheduler可能會將兩個Pod都在同一個機器上啟動,這樣一來,當節點掛掉之后整個Service也會掛掉。 ? ?? 這里正確的做法是殺死兩個Pod,等待RC重新啟動新的Pod來代替。 這樣一來,Service就在那些副本之前存在,并將環境變量設置到所有的Pod中。 正確的環境變量應為:
$?kubectl?scale?rc?my-nginx?--replicas=0;?kubectl?scale?rc?my-nginx?--replicas=2;
$?kubectl?get?pods?-l?app=nginx?-o?wide
NAME? ? ? ? ? ? ?READY? ?STATUS? ? ?RESTARTS? ?AGE? ?NODE
my-nginx-5j8ok? ?1/1? ? ?Running? ? 0? ? ? ? ?2m? ? node1
my-nginx-90vaf? ?1/1? ? ?Running? ?0? ? ? ? ? 2m? ? node2
$?kubectl?exec?my-nginx-5j8ok?--?printenv?|?grep?SERVICE
KUBERNETES_SERVICE_PORT=443
NGINXSVC_SERVICE_HOST=10.0.116.146
KUBERNETES_SERVICE_HOST=10.0.0.1
NGINXSVC_SERVICE_PORT=80
6、DNS
k8s提供了一個DNS集群服務插件,使用skydns來自動分配DNS給其他的Service。如果你的集群上有運行的話,你可以查看它的狀態:
$?kubectl?get?services?kube-dns?--namespace=kube-system
NAME? ? ? ?CLUSTER_IP? ? ? EXTERNAL_IP? ?PORT(S)? ? ? ? ?SELECTOR? ? ? ? ? ?AGE
kube-dns? ?10.179.240.10? ?<none>? ? ? ? 53/UDP,53/TCP? ?k8s-app=kube-dns? ?8d
如果集群上沒有運行,那么你可以啟用它:enable it
本節剩下的內容是在假設你擁有一個長時間可以使用IP的Service(nginxsvc)并且DNS域名已經通過dns服務(DNS集群服務插件)分配給這個IP的前提下。 所以你可以在集群上的任一節點中使用標準的請求方法來連接Service,現在來創建另外一個Pod進行測試:
$?cat?curlpod.yaml
apiVersion:?v1
kind:?Pod
metadata:
? name:?curlpod
spec:
? containers:
? -?image:?radial/busyboxplus:curl
? ? command:
? ? ? -?sleep
? ? ? -?"3600"
? ? imagePullPolicy:?IfNotPresent
? ? name:?curlcontainer
? restartPolicy:?Always
執行查找nginx Service:
$?kubectl?create?-f?./curlpod.yaml
default/curlpod
$?kubectl?get?pods?curlpod
NAME? ? ? READY? ? ?STATUS? ? RESTARTS? ?AGE
curlpod? ?1/1? ? ? ?Running? ?0? ? ? ? ? 18s
$?kubectl?exec?curlpod?--?nslookup?nginxsvc
Server:? ? 10.0.0.10
Address?1:?10.0.0.10
Name:? ? ? nginxsvc
Address?1:?10.0.116.146
7、使用加密連接的Service
到目前為止,我們僅僅是在集群中連接了nginx服務,在將服務開放到Internet上之前,你需要確認雙方交流的通道是安全的。 你將會需要以下的東西來確保安全性:
你可以通過這里 nginx https example 來獲得完整的配置方式,簡要地說,方式如下:
$?make?keys?secret?KEY=/tmp/nginx.key?CERT=/tmp/nginx.crt?SECRET=/tmp/secret.json
$?kubectl?create?-f?/tmp/secret.json
secrets/nginxsecret
$?kubectl?get?secrets
NAME? ? ? ? ? ? ? ? ? TYPE? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? DATA
default-token-il9rc? ?kubernetes.io/service-account-token? ?1
nginxsecret? ? ? ? ? ?Opaque? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 2
現在修改你的nginx副本來啟動一個使用這個證書的HTTPS服務和Service,并且都開放80和443端口:
$?cat?nginx-app.yaml
apiVersion:?v1
kind:?Service
metadata:
? name:?nginxsvc
? labels:
? ? app:?nginx
spec:
? type:?NodePort
? ports:
? -?port:?8080
? ? targetPort:?80
? ? protocol:?TCP
? ? name:?http
? -?port:?443
? ? protocol:?TCP
? ? name:?https
? selector:
? ? app:?nginx
---
apiVersion:?v1
kind:?ReplicationController
metadata:
? name:?my-nginx
spec:
? replicas:?1
? template:
? ? metadata:
? ? ? labels:
? ? ? ? app:?nginx
? ? spec:
? ? ? volumes:
? ? ? -?name:?secret-volume
? ? ? ? secret:
? ? ? ? ? secretName:?nginxsecret
? ? ? containers:
? ? ? -?name:?nginxhttps
? ? ? ? image:?bprashanth/nginxhttps:1.0
? ? ? ? ports:
? ? ? ? -?containerPort:?443
? ? ? ? -?containerPort:?80
? ? ? ? volumeMounts:
? ? ? ? -?mountPath:?/etc/nginx/ssl
? ? ? ? ? name:?secret-volume
nginx-app中值得注意的點有:
$?kubectl?delete?rc,svc?-l?app=nginx;?kubectl?create?-f?./nginx-app.yaml
replicationcontrollers/my-nginx
services/nginxsvc
services/nginxsvc replicationcontrollers/my-nginx 此時,你可以在任意節點上訪問nginx服務
$?kubectl?get?pods?-o?json?|?grep?-i?podip
? ? "podIP":?"10.1.0.80",
node?$?curl?-k?https://10.1.0.80
... <h1>Welcome?to?nginx!</h1>
注意在最后一步中,我們是如何使用-k這個參數的,因為我們不知道任何有關nginx服務運行的Pod的證書生成時刻,所以我們要告訴curl忽略別名不匹配。 通過創建一個Service,在Pod發現Service的時候我們將證書中使用的別名和真實地DNS域名關聯起來,讓我們通過一個Pod來測試(這里會重用這個證書,Pod連接Service只需要nginx.crt):
$?cat?curlpod.yaml
vapiVersion:?v1
kind:?ReplicationController
metadata:
? name:?curlrc
spec:
? replicas:?1
? template:
? ? metadata:
? ? ? labels:
? ? ? ? app:?curlpod
? ? spec:
? ? ? volumes:
? ? ? -?name:?secret-volume
? ? ? ? secret:
? ? ? ? ? secretName:?nginxsecret
? ? ? containers:
? ? ? -?name:?curlpod
? ? ? ? command:
? ? ? ? -?sh
? ? ? ? -?-c
? ? ? ? -?while?true;?do?sleep?1;?done
? ? ? ? image:?radial/busyboxplus:curl
? ? ? ? volumeMounts:
? ? ? ? -?mountPath:?/etc/nginx/ssl
? ? ? ? ? name:?secret-volume
$?kubectl?create?-f?./curlpod.yaml
$?kubectl?get?pods
NAME? ? ? ? ? ? ?READY? ? ?STATUS? ? RESTARTS? ?AGE
curlpod? ? ? ? ? 1/1? ? ? ?Running? ?0? ? ? ? ? 2m
my-nginx-7006w? ?1/1? ? ? ?Running? ?0? ? ? ? ? 24m
$?kubectl?exec?curlpod?--?curl?https://nginxsvc?--cacert?/etc/nginx/ssl/nginx.crt
...
<title>Welcome?to?nginx!</title>
...
8、開放Service
在你的應用中可能需要將其開放到一個外部的IP中。 k8s提供了兩種方式:NodePorts和LoadBalancers。 在上面的最后一部分中,我們已經通過NodePorts方式創建了Service,所以如果你有公網IP,你的nginx https副本就可以在Internet上開放了。
$?kubectl?get?svc?nginxsvc?-o?json?|?grep?-i?nodeport?-C?5
? ? ? ? ? ? {
? ? ? ? ? ? ? ? "name":?"http",
? ? ? ? ? ? ? ? "protocol":?"TCP",
? ? ? ? ? ? ? ? "port":?80,
? ? ? ? ? ? ? ? "targetPort":?80,
? ? ? ? ? ? ? ? "nodePort":?32188
? ? ? ? ? ? },
? ? ? ? ? ? {
? ? ? ? ? ? ? ? "name":?"https",
? ? ? ? ? ? ? ? "protocol":?"TCP",
? ? ? ? ? ? ? ? "port":?443,
? ? ? ? ? ? ? ? "targetPort":?443,
? ? ? ? ? ? ? ? "nodePort":?30645
? ? ? ? ? ? }
?
$?kubectl?get?nodes?-o?json?|?grep?ExternalIP?-C?2
? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? "type":?"ExternalIP",
? ? ? ? ? ? ? ? ? ? ? ? "address":?"104.197.63.17"
? ? ? ? ? ? ? ? ? ? }
--
? ? ? ? ? ? ? ? ? ? },
? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? "type":?"ExternalIP",
? ? ? ? ? ? ? ? ? ? ? ? "address":?"104.154.89.170"
? ? ? ? ? ? ? ? ? ? }
$?curl?https://104.197.63.17:30645?-k
...
<h1>Welcome?to?nginx!</h1>
現在,我們將通過負載均衡器重新創建一個Service,只需要將nginx-app.yaml文件中的type字段從NodePort改為LoadBalancer即可:
$?kubectl?delete?rc,?svc?-l?app=nginx
$?kubectl?create?-f?./nginx-app.yaml
$?kubectl?get?svc?nginxsvc
NAME? ? ? CLUSTER_IP? ? ? ?EXTERNAL_IP? ? ? ?PORT(S)? ? ? ? ? ? ? ? SELECTOR? ? ?AGE
nginxsvc? 10.179.252.126? ?162.222.184.144? ?80/TCP,81/TCP,82/TCP? ?run=nginx2? ?13m
$?curl?https://162.22.184.144?-k
...
<title>Welcome?to?nginx!</title>
EXTERNAL_IP這列的IP即是可以在公網上訪問的IP,CLUSTER_IP只能在自己的集群上訪問到。
1、使用配置文件啟動replicas集合
k8s通過Replication Controller來創建和管理各個不同的重復容器集合(實際上是重復的pods)。
Replication Controller會確保pod的數量在運行的時候會一直保持在一個特殊的數字,即replicas的設置。 這個功能類似于Google GCE的實例組管理和AWS的彈性伸縮。
在快速開始中,通過kubectl run以下的YAML文件創建了一個rc運行著nginx:
apiVersion:?v1
kind:?ReplicationController
metadata:
? name:?my-nginx
spec:
? replicas:?2
? template:
? ? metadata:
? ? ? labels:
? ? ? ? app:?nginx
? ? spec:
? ? ? containers:
? ? ? -?name:?nginx
? ? ? ? image:?nginx
? ? ? ? ports:
? ? ? ? -?containerPort:?80
和定義一個pod的YAML文件相比,不同的只是kind的值為ReplicationController,replicas的值需要制定,pod的相關定義在template中,pod的名字不需要顯式地指定,因為它們會在rc中創建并賦予名字,點擊查看完整的rc定義字段列表:
replication controller API object
rc可以通過create命令像創建pod一樣來創建:
$?kubectl?create?-f?./nginx-rc.yaml
replicationcontrollers/my-nginx
和直接創建pod不一樣,rc將會替換因為任何原因而被刪除或者停止運行的Pod,比如說pod依賴的節點掛了。所以我們推薦使用rc來創建和管理復雜應用,即使你的應用只要使用到一個pod,在配置文件中忽略replicas字段的設置即可。
2、查看Replication Controller的狀態
可以通過get命令來查看你創建的rc:
$?kubectl?get?rc
CONTROLLER? ?CONTAINER(S)? ?IMAGE(S)? ?SELECTOR? ? REPLICAS
my-nginx? ? ?nginx? ? ? ? ? nginx? ? ? app=nginx? ?2
這個狀態表示,你創建的rc將會確保你一直有兩個nginx的副本。
也可以和直接創pPod一樣查看創建的Pod狀態信息:
$?kubectl?get?pods
NAME? ? ? ? ? ? ?READY? ? ?STATUS? ? RESTARTS? ?AGE
my-nginx-065jq? ?1/1? ? ? ?Running? ?0? ? ? ? ? 51s
my-nginx-buaiq? ?1/1? ? ? ?Running? ?0? ? ? ? ? 51s
3、刪除Replication Controller
當你想停止你的應用,刪除你的rc,可以使用:
$?kubectl?delete?rc?my-nginx
replicationcontrollers/my-nginx
默認的,這將會刪除所有被這個rc管理的pod,如果pod的數量很大,將會花一些時間來完成整個刪除動作,如果你想使這些pod停止運行,請指定--cascade=false。 如果你在刪除rc之前嘗試刪除pod,rc將會立即啟動新的pod來替換被刪除的pod,就像它承諾要做的一樣。
4、Labels
k8s使用用戶自定義的key-value鍵值對來區分和標識資源集合(就像rc、pod等資源),這種鍵值對稱為label。 在上面的例子中,定義pod的template字段包含了一個簡單定義的label,key的值為app,value的值為nginx。所有被創建的pod都會卸載這個label,可以通過-L參數來查看:
$?kubectl?get?rc?my-nginx?-L?app
CONTROLLER? ?CONTAINER(S)? ?IMAGE(S)? ?SELECTOR? ? REPLICAS? ?APP
my-nginx? ? ?nginx? ? ? ? ? nginx? ? ? app=nginx? ?2? ? ? ? ? nginx
默認情況下,pod的label會復制到rc的label,同樣地,k8s中的所有資源都支持攜帶label。
更重要的是,pod的label會被用來創建一個selector,用來匹配過濾攜帶這些label的pods。 你可以通過kubectl get請求這樣一個字段來查看template的格式化輸出:
$?kubectl?get?rc?my-nginx?-o?template?--template="{{.spec.selector}}" map[app:nginx] 你也可以直接指定selector,比如你想在pod template中指明那些不想選中的label,但是你應該確保selector將會匹配這些從pod template中創建的pod的label,并且它將不會匹配其他rc創建的pod。
確保后者最簡單的方法是為rc創建一個唯一的label值,然后在pod template的label和selector中都指定這個label。
二、連接應用到網絡中
1、k8s中連接容器的模型
現在,你已經有了組合的、多份副本的應用,你可以將它連接到一個網絡上。在討論k8s聯網的方式之前,有必要和Docker中連接網絡的普通方式進行一下比較。
默認情況下,Docker使用主機私有網絡,所以容器之間可以互相交互,只要它們在同一臺機器上。 為了讓Docker容器可以進行跨節點的交流,必須在主機的IP地址上為容器分配端口號,之后通過主機IP和端口將信息轉發到容器中。 這樣一來,很明顯地,容器之間必須謹慎地使用和協調端口號的分配,或者動態分配端口號。
在眾多開發者之間協調端口號的分配是十分困難的,會將集群級別之外的復雜問題暴露給用戶來處理。
在k8s中,假設Pod之間可以互相交流,無論它們是在哪個宿主機上。 我們賦予每個Pod自己的集群私有IP,如此一來你就不需要明確地在Pod之間創建連接,或者將容器的端口映射到主機的端口中。 這意味著,Pod中的容器可以在主機上使用任意彼此的端口,而且集群中的Pods可以在不使用NAT的方式下連接到其他Pod。
本章將會詳細描述如何通過這樣一個網絡連接模型來運行穩定的Services。
本指南使用一個簡單的nginx服務來驗證以上的概念,在Jenkins CI application有對相同概念的更加詳細的說明。
2、在集群上將Pod連接到網絡
我們之前做過這個例子,但是讓我們以網絡連接的角度來重新做一次。 創建一個nginx Pod,注意,這個Pod有一個容器端口的說明:
$?cat?nginxrc.yaml
apiVersion:?v1
kind:?ReplicationController
metadata:
? name:?my-nginx
spec:
? replicas:?2
? template:
? ? metadata:
? ? ? labels:
? ? ? ? app:?nginx
? ? spec:
? ? ? containers:
? ? ? -?name:?nginx
? ? ? ? image:?nginx
? ? ? ? ports:
? ? ? ? -?containerPort:?80
這使它可以進入集群上的任意節點,檢查節點上運行的Pod:
$?kubectl?create?-f?./nginxrc.yaml
$?kubectl?get?pods?-l?app=nginx?-o?wide
my-nginx-6isf4? ?1/1? ? ? ?Running? ?0? ? ? ? ? 2h? ? ? ? e2e-test-beeps-minion-93ly
my-nginx-t26zt? ?1/1? ? ? ?Running? ?0? ? ? ? ? 2h? ? ? ? e2e-test-beeps-minion-93ly
檢查你的Pod的IPs:
$?kubectl?get?pods?-l?app=nginx?-o?json?|?grep?podIP
? ? ? ? ? ? ? ? "podIP":?"10.245.0.15", ? ? ? ? ? ? ? ? "podIP":?"10.245.0.14",
這時,你應該能夠通過ssh登錄任意節點然后使用curl來連接任一IP(如果節點之間沒有處于同一個子網段,無法使用私有IP進行連接的話,就只能在對應節點上使用對應的IP進行連接測試)。 注意,容器并不是真的在節點上使用80端口,也沒有任何的NAT規則來路由流量到Pod中。 這意味著你可以在同樣的節點上使用同樣的containerPort來運行多個nginx Pod,并且可以在集群上的任何Pod或者節點通過這個IP來連接它們。 和Docker一樣,端口仍然可以發布到宿主機的接口上,但是因為這個網絡連接模型,這個需求就變得很少了。
如果你好奇的話,可以通過這里查看我們是如何做到的: how we achieve this
3、創建Service
現在,在集群上我們有了一個運行著niginx并且有分配IP地址空間的的Pod。 理論上,你可以直接和這些Pod進行交互,但是當節點掛掉之后會發生什么? 這些Pod會跟著節點掛掉,然后RC會在另外一個健康的節點上重新創建新的Pod來代替,而這些Pod分配的IP地址都會發生變化,對于Service類型的服務來說這是一個難題。
k8s上的Service是抽象的,其定義了一組運行在集群之上的Pod的邏輯集合,這些Pod是重復的,復制出來的,所以提供相同的功能。 當Service被創建,會被分配一個唯一的IP地址(也稱為集群IP)。這個地址和Service的生命周期相關聯,并且當Service是運行的時候,這個IP不會發生改變。 Pods進行配置來和這個Service進行交互,之后Service將會自動做負載均衡到Service中的Pod。
你可以通過以下的YAML文件來為你的兩個nginx容器副本創建一個Service:
$?cat?nginxsvc.yaml
apiVersion:?v1
kind:?Service
metadata:
? name:?nginxsvc
? labels:
? ? app:?nginx
spec:
? ports:
? -?port:?80
? ? protocol:?TCP
? selector: app:?nginx
這個YAML定義創建創建一個Service,帶有Label為app=nginx的Pod都將會開放80端口,并將其關聯到一個抽象的Service端口。 (targetPort字段是指容器內開放的端口Service通過這個端口連接Pod,port字段是指抽象Service的端口,nodePort為節點上暴露的端口號,不指定的話為隨機。) 點擊這里查看完整的Service字段列表:
service API object?
現在查看你創建的Service:
$?kubectl?get?svc
NAME? ? ? ? ?CLUSTER_IP? ? ? ?EXTERNAL_IP? ? ? ?PORT(S)? ? ? ? ? ? ? ? SELECTOR? ? ?AGE
kubernetes? ?10.179.240.1? ? ?<none>? ? ? ? ? ? 443/TCP? ? ? ? ? ? ? ? <none>? ? ? ?8d nginxsvc? ? ?10.179.252.126? ?122.222.183.144? ?80/TCP,81/TCP,82/TCP? ?run=nginx2? ?11m
和之前提到的一樣,Service是以一組Pod為基礎的。 這些Pod通過endpoints字段開放出來。 Service的selector將會不斷地進行Pod的Label匹配,結果將會通知一個Endpoints Object,這里創建的也叫做nginxsvc。 當Pod掛掉之后,將會自動從Endpoints中移除,當有新的Pod被Service的selector匹配到之后將會自動加入這個Endpoints。 你可以查看這個Endpoint,注意,這些IP和第一步中創建Pods的時候是一樣的:
$?kubectl?describe?svc?nginxsvc
Name:? ? ? ? ? ?nginxsvc
Namespace:? ? ? default
Labels:? ? ? ? ?app=nginx
Selector:? ? ? ?app=nginx
Type:? ? ? ? ? ?ClusterIP
IP:? ? ? ? ?10.0.116.146
Port:? ? ? ? ? ?<unnamed>? ?80/TCP
Endpoints:? ? ? 10.245.0.14:80,10.245.0.15:80
Session?Affinity:? ?None
No?events.
$?kubectl?get?ep
NAME? ? ? ? ?ENDPOINTS nginxsvc? ? ?10.245.0.14:80,10.245.0.15:80
你現在應該可以通過10.0.116.146:80這個IP從集群上的任何一個節點使用curl命令來連接到nginx的Service。 注意,Service的IP是完全虛擬的,如果你想知道它是怎么工作的,請點擊: service proxy
4、Pod發現并加入到Service中
k8s提供了兩種基本的方式來發現Service:環境變量和DNS。 環境變量是立即可以使用的,DNS則需要kube-dns集群插件。
5、環境變量
當Pod運行在一個節點上,kubelet將會為每個激活的Service添加一系列的環境變量。 為你的nginx Pod檢查一下環境: $?kubectl?exec?my-nginx-6isf4?--?printenv?|?grep?SERVICE
KUBERNETES_SERVICE_HOST=10.0.0.1 KUBERNETES_SERVICE_PORT=443
注意,這里沒有顯示和Service相關的東西,因為這個Pod是在Service之前創建的,這種做法另外一個缺點是, Scheduler可能會將兩個Pod都在同一個機器上啟動,這樣一來,當節點掛掉之后整個Service也會掛掉。 ? ?? 這里正確的做法是殺死兩個Pod,等待RC重新啟動新的Pod來代替。 這樣一來,Service就在那些副本之前存在,并將環境變量設置到所有的Pod中。 正確的環境變量應為:
$?kubectl?scale?rc?my-nginx?--replicas=0;?kubectl?scale?rc?my-nginx?--replicas=2;
$?kubectl?get?pods?-l?app=nginx?-o?wide
NAME? ? ? ? ? ? ?READY? ?STATUS? ? ?RESTARTS? ?AGE? ?NODE
my-nginx-5j8ok? ?1/1? ? ?Running? ? 0? ? ? ? ?2m? ? node1
my-nginx-90vaf? ?1/1? ? ?Running? ?0? ? ? ? ? 2m? ? node2
$?kubectl?exec?my-nginx-5j8ok?--?printenv?|?grep?SERVICE
KUBERNETES_SERVICE_PORT=443
NGINXSVC_SERVICE_HOST=10.0.116.146
KUBERNETES_SERVICE_HOST=10.0.0.1
NGINXSVC_SERVICE_PORT=80
6、DNS
k8s提供了一個DNS集群服務插件,使用skydns來自動分配DNS給其他的Service。如果你的集群上有運行的話,你可以查看它的狀態:
$?kubectl?get?services?kube-dns?--namespace=kube-system
NAME? ? ? ?CLUSTER_IP? ? ? EXTERNAL_IP? ?PORT(S)? ? ? ? ?SELECTOR? ? ? ? ? ?AGE
kube-dns? ?10.179.240.10? ?<none>? ? ? ? 53/UDP,53/TCP? ?k8s-app=kube-dns? ?8d
如果集群上沒有運行,那么你可以啟用它:enable it
本節剩下的內容是在假設你擁有一個長時間可以使用IP的Service(nginxsvc)并且DNS域名已經通過dns服務(DNS集群服務插件)分配給這個IP的前提下。 所以你可以在集群上的任一節點中使用標準的請求方法來連接Service,現在來創建另外一個Pod進行測試:
$?cat?curlpod.yaml
apiVersion:?v1
kind:?Pod
metadata:
? name:?curlpod
spec:
? containers:
? -?image:?radial/busyboxplus:curl
? ? command:
? ? ? -?sleep
? ? ? -?"3600"
? ? imagePullPolicy:?IfNotPresent
? ? name:?curlcontainer
? restartPolicy:?Always
執行查找nginx Service:
$?kubectl?create?-f?./curlpod.yaml
default/curlpod
$?kubectl?get?pods?curlpod
NAME? ? ? READY? ? ?STATUS? ? RESTARTS? ?AGE
curlpod? ?1/1? ? ? ?Running? ?0? ? ? ? ? 18s
$?kubectl?exec?curlpod?--?nslookup?nginxsvc
Server:? ? 10.0.0.10
Address?1:?10.0.0.10
Name:? ? ? nginxsvc
Address?1:?10.0.116.146
7、使用加密連接的Service
到目前為止,我們僅僅是在集群中連接了nginx服務,在將服務開放到Internet上之前,你需要確認雙方交流的通道是安全的。 你將會需要以下的東西來確保安全性:
- HTTPS自簽名證書(或者你已經有了一個證書)
- 一個nginx服務配置好了使用這個證書
- 一個加密措施使得證書在Pod之間交流使用
你可以通過這里 nginx https example 來獲得完整的配置方式,簡要地說,方式如下:
$?make?keys?secret?KEY=/tmp/nginx.key?CERT=/tmp/nginx.crt?SECRET=/tmp/secret.json
$?kubectl?create?-f?/tmp/secret.json
secrets/nginxsecret
$?kubectl?get?secrets
NAME? ? ? ? ? ? ? ? ? TYPE? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? DATA
default-token-il9rc? ?kubernetes.io/service-account-token? ?1
nginxsecret? ? ? ? ? ?Opaque? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 2
現在修改你的nginx副本來啟動一個使用這個證書的HTTPS服務和Service,并且都開放80和443端口:
$?cat?nginx-app.yaml
apiVersion:?v1
kind:?Service
metadata:
? name:?nginxsvc
? labels:
? ? app:?nginx
spec:
? type:?NodePort
? ports:
? -?port:?8080
? ? targetPort:?80
? ? protocol:?TCP
? ? name:?http
? -?port:?443
? ? protocol:?TCP
? ? name:?https
? selector:
? ? app:?nginx
---
apiVersion:?v1
kind:?ReplicationController
metadata:
? name:?my-nginx
spec:
? replicas:?1
? template:
? ? metadata:
? ? ? labels:
? ? ? ? app:?nginx
? ? spec:
? ? ? volumes:
? ? ? -?name:?secret-volume
? ? ? ? secret:
? ? ? ? ? secretName:?nginxsecret
? ? ? containers:
? ? ? -?name:?nginxhttps
? ? ? ? image:?bprashanth/nginxhttps:1.0
? ? ? ? ports:
? ? ? ? -?containerPort:?443
? ? ? ? -?containerPort:?80
? ? ? ? volumeMounts:
? ? ? ? -?mountPath:?/etc/nginx/ssl
? ? ? ? ? name:?secret-volume
nginx-app中值得注意的點有:
- 其包括了RC和SVC的定義在同一個文件中
- nginx服務的HTTP通過80端口,HTTPS通過443端口
- 每個容器都通過掛載在/etc/nginx/ssl卷中的keys來連接。這步是在nginx服務啟動之前完成的
$?kubectl?delete?rc,svc?-l?app=nginx;?kubectl?create?-f?./nginx-app.yaml
replicationcontrollers/my-nginx
services/nginxsvc
services/nginxsvc replicationcontrollers/my-nginx 此時,你可以在任意節點上訪問nginx服務
$?kubectl?get?pods?-o?json?|?grep?-i?podip
? ? "podIP":?"10.1.0.80",
node?$?curl?-k?https://10.1.0.80
... <h1>Welcome?to?nginx!</h1>
注意在最后一步中,我們是如何使用-k這個參數的,因為我們不知道任何有關nginx服務運行的Pod的證書生成時刻,所以我們要告訴curl忽略別名不匹配。 通過創建一個Service,在Pod發現Service的時候我們將證書中使用的別名和真實地DNS域名關聯起來,讓我們通過一個Pod來測試(這里會重用這個證書,Pod連接Service只需要nginx.crt):
$?cat?curlpod.yaml
vapiVersion:?v1
kind:?ReplicationController
metadata:
? name:?curlrc
spec:
? replicas:?1
? template:
? ? metadata:
? ? ? labels:
? ? ? ? app:?curlpod
? ? spec:
? ? ? volumes:
? ? ? -?name:?secret-volume
? ? ? ? secret:
? ? ? ? ? secretName:?nginxsecret
? ? ? containers:
? ? ? -?name:?curlpod
? ? ? ? command:
? ? ? ? -?sh
? ? ? ? -?-c
? ? ? ? -?while?true;?do?sleep?1;?done
? ? ? ? image:?radial/busyboxplus:curl
? ? ? ? volumeMounts:
? ? ? ? -?mountPath:?/etc/nginx/ssl
? ? ? ? ? name:?secret-volume
$?kubectl?create?-f?./curlpod.yaml
$?kubectl?get?pods
NAME? ? ? ? ? ? ?READY? ? ?STATUS? ? RESTARTS? ?AGE
curlpod? ? ? ? ? 1/1? ? ? ?Running? ?0? ? ? ? ? 2m
my-nginx-7006w? ?1/1? ? ? ?Running? ?0? ? ? ? ? 24m
$?kubectl?exec?curlpod?--?curl?https://nginxsvc?--cacert?/etc/nginx/ssl/nginx.crt
...
<title>Welcome?to?nginx!</title>
...
8、開放Service
在你的應用中可能需要將其開放到一個外部的IP中。 k8s提供了兩種方式:NodePorts和LoadBalancers。 在上面的最后一部分中,我們已經通過NodePorts方式創建了Service,所以如果你有公網IP,你的nginx https副本就可以在Internet上開放了。
$?kubectl?get?svc?nginxsvc?-o?json?|?grep?-i?nodeport?-C?5
? ? ? ? ? ? {
? ? ? ? ? ? ? ? "name":?"http",
? ? ? ? ? ? ? ? "protocol":?"TCP",
? ? ? ? ? ? ? ? "port":?80,
? ? ? ? ? ? ? ? "targetPort":?80,
? ? ? ? ? ? ? ? "nodePort":?32188
? ? ? ? ? ? },
? ? ? ? ? ? {
? ? ? ? ? ? ? ? "name":?"https",
? ? ? ? ? ? ? ? "protocol":?"TCP",
? ? ? ? ? ? ? ? "port":?443,
? ? ? ? ? ? ? ? "targetPort":?443,
? ? ? ? ? ? ? ? "nodePort":?30645
? ? ? ? ? ? }
?
$?kubectl?get?nodes?-o?json?|?grep?ExternalIP?-C?2
? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? "type":?"ExternalIP",
? ? ? ? ? ? ? ? ? ? ? ? "address":?"104.197.63.17"
? ? ? ? ? ? ? ? ? ? }
--
? ? ? ? ? ? ? ? ? ? },
? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? "type":?"ExternalIP",
? ? ? ? ? ? ? ? ? ? ? ? "address":?"104.154.89.170"
? ? ? ? ? ? ? ? ? ? }
$?curl?https://104.197.63.17:30645?-k
...
<h1>Welcome?to?nginx!</h1>
現在,我們將通過負載均衡器重新創建一個Service,只需要將nginx-app.yaml文件中的type字段從NodePort改為LoadBalancer即可:
$?kubectl?delete?rc,?svc?-l?app=nginx
$?kubectl?create?-f?./nginx-app.yaml
$?kubectl?get?svc?nginxsvc
NAME? ? ? CLUSTER_IP? ? ? ?EXTERNAL_IP? ? ? ?PORT(S)? ? ? ? ? ? ? ? SELECTOR? ? ?AGE
nginxsvc? 10.179.252.126? ?162.222.184.144? ?80/TCP,81/TCP,82/TCP? ?run=nginx2? ?13m
$?curl?https://162.22.184.144?-k
...
<title>Welcome?to?nginx!</title>
EXTERNAL_IP這列的IP即是可以在公網上訪問的IP,CLUSTER_IP只能在自己的集群上訪問到。
轉載于:https://www.cnblogs.com/jchubby/p/5449369.html
總結
以上是生活随笔為你收集整理的Kubernetes用户指南(二)--部署组合型的应用、连接应用到网络中的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: seo技巧-2015/10/05
- 下一篇: 我只是不甘心-------Day51