K8S-網絡模型、POD/RC/SVC YAML 語法官方文檔
-
Kubernetes - Production-Grade Container Orchestration
-
kubernetes/kubernetes: Production-Grade Container Scheduling and Management
-
Posts containing 'yaml' - Stack Overflow
-
how to pass a configuration file thought yaml on kubernetes to create new replication controller - Stack Overflow
-
How to expose a Kubernetes service externally using NodePort - Stack Overflow
-
Yaml templates in Kubernetes - Stack Overflow
-
Kubernetes - Production-Grade Container Orchestration
-
kubernetes/examples at master · kubernetes/kubernetes
-
Kubernetes用戶指南(二)--部署組合型的應用、鏈接應用到網絡中 - 小黑 - 博客頻道 - CSDN.NET
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定義字段列表:
rc能夠經過create命令像建立pod同樣來建立:
$ kubectl create -f ./nginx-rc.yaml
replicationcontrollers/my-nginx
和直接建立pod不同,rc將會替換由於任何緣由而被刪除或者中止運行的Pod,好比說pod依賴的節點掛了。因此咱們推薦使用rc來建立和管理複雜應用,即便你的應用只要使用到一個pod,在配置文件中忽略replicas字段的設置便可。
二、查看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
三、刪除Replication Controller
當你想中止你的應用,刪除你的rc,可使用:
$ kubectl delete rc my-nginx
replicationcontrollers/my-nginx
默認的,這將會刪除全部被這個rc管理的pod,若是pod的數量很大,將會花一些時間來完成整個刪除動做,若是你想使這些pod中止運行,請指定--cascade=false。
若是你在刪除rc以前嘗試刪除pod,rc將會當即啓動新的pod來替換被刪除的pod,就像它承諾要作的同樣。
四、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。
2、鏈接應用到網絡中
一、k8s中鏈接容器的模型
如今,你已經有了組合的、多份副本的應用,你能夠將它鏈接到一個網絡上。在討論k8s聯網的方式以前,有必要和Docker中鏈接網絡的普通方式進行一下比較。
默認狀況下,Docker使用主機私有網絡,因此容器之間能夠互相交互,只要它們在同一臺機器上。
爲了讓Docker容器能夠進行跨節點的交流,必須在主機的IP地址上爲容器分配端口號,以後經過主機IP和端口將信息轉發到容器中。
這樣一來,很明顯地,容器之間必須謹慎地使用和協調端口號的分配,或者動態分配端口號。
在衆多開發者之間協調端口號的分配是十分困難的,會將集羣級別以外的複雜問題暴露給用戶來處理。
在k8s中,假設Pod之間能夠互相交流,不管它們是在哪一個宿主機上。
咱們賦予每一個Pod本身的集羣私有IP,如此一來你就不須要明確地在Pod之間建立鏈接,或者將容器的端口映射到主機的端口中。
這意味着,Pod中的容器能夠在主機上使用任意彼此的端口,並且集羣中的Pods能夠在不使用NAT的方式下鏈接到其餘Pod。
本章將會詳細描述如何經過這樣一個網絡鏈接模型來運行穩定的Services。
二、在集羣上將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同樣,端口仍然能夠發佈到宿主機的接口上,可是由於這個網絡鏈接模型,這個需求就變得不多了。
若是你好奇的話,能夠經過這裏查看咱們是如何作到的:
三、建立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:
$ 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是徹底虛擬的,若是你想知道它是怎麼工做的,請點擊:
四、Pod發現並加入到Service中
k8s提供了兩種基本的方式來發現Service:環境變量和DNS。
環境變量是當即可使用的,DNS則須要kube-dns集羣插件。
五、環境變量
當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
六、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
本節剩下的內容是在假設你擁有一個長時間可使用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
七、使用加密鏈接的Service
到目前爲止,咱們僅僅是在集羣中鏈接了nginx服務,在將服務開放到Internet上以前,你須要確認雙方交流的通道是安全的。
你將會須要如下的東西來確保安全性:
- HTTPS自簽名證書(或者你已經有了一個證書)
- 一個nginx服務配置好了使用這個證書
- 一個加密措施使得證書在Pod之間交流使用
你能夠經過這裏
來得到完整的配置方式,簡要地說,方式以下:
$ 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>
...
八、開放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只能在本身的集羣上訪問到。