一、定義和分類
1,定義
k8s 中內建了很多控制器(controller ),這些相當於一個狀態機,用來控制 Pod 的具體狀態和行爲。
2,類型
ReplicationController、ReplicaSet、DaemonSet、StatefulSet、Job/CronJob和Horizontal Pod Autoscaling
二、資源控制器的定義和示例
1,ReplicationController 和 ReplicaSet
ReplicationController(RC)用來確保容器應用的副本數始終保持在用戶定義的副本數,即如果有容器異常退出,會自動創建新的Pod來替代,而如果異常多出來的容器也會被自動回收。
在新版本的k8s中建議使用ReplicaSet(RS)來取代RC,RS與RC沒有本質的不同,只是名字不一樣,並且RS支持集合式的selector,即通過標籤(labels)來管理多個Pod。
RS示例:(rs.yaml)
apiVersion: extensions/v1beta1 kind: ReplicaSet #類型爲RS metadata: name: rs-1 #RS的名稱 spec: replicas: 3 #Pod的副本數 selector: #選擇器 matchLabels: tier: frontend #需要匹配的Pod標籤 template: #定義Pod metadata: labels: tier: frontend #當前Pod的標籤 spec: containers: - name: nginx-container image: hub.xcc.com/my/mynginx:v1 ports: - containerPort: 80
執行如下命令:
kubectl create -f rs.yaml #獲取rs kubectl get rs #列出指定標籤 kubectl get pod --show-labels -l tier=frontend #修改標籤爲frontend1 kubectl label pod rs-1-abc tier=frontend1 --overwrite=true #查看pod kubectl get pod --show-labels #刪除控制器rs-1 kubectl delete rs rs-1 kubectl get pod --show-labels
2,Deployment
Deployment爲Pod和RS提供了一個聲明式定義方法,用來替換以前的RC來方便的管理應用。
Deployment示例:(deployment.yaml)
apiVersion: extensions/v1beta1 kind: Deployment metadata: name: deployment-1 #名稱 spec: replicas: 3 #Pod副本 template: metadata: labels: app: nginx-app #Pod標籤 spec: containers: - name: nginx-container image: hub.xcc.com/my/mynginx:v1 ports: - containerPort: 80
創建查看命令
#創建並保存記錄 kubectl apply -f demployment.yaml --record #查看Deployment kubectl get deployment #查看rs kubectl get rs #查看Pod 顯示標籤 kubectl get pod --show-labels
擴容
# 將Pod的期望副本數擴容到5個 kubectl scale deployment deployment-1 --replicas 5 kubectl get pod --show-labels
滾動更新
[root@master01 ~]# kubectl set image deployment/deployment-1 nginx-container=hub.xcc.com/library/mynginx:v2 deployment.extensions/deployment-1 image updated # 查看 deployment,發現沒什麼變化 [root@master01 ~]# kubectl get deployment NAME READY UP-TO-DATE AVAILABLE AGE deployment-1 5/5 5 5 24m # 查看 rs,出現了一個新的rs,pod數量維持在5個,並且原先的rs的pod數量變爲0了 # deployment-1-6fd64dcb5 就是deployment升級後新創建的rs,並且Pod裏的容器使用的是新的鏡像 [root@master01 ~]# kubectl get rs NAME DESIRED CURRENT READY AGE deployment-1-6fd64dcb5 5 5 5 22s deployment-1-7796b9c74d 0 0 0 22m
#查看更新狀態 [root@master01 ~]# kubectl rollout status deployment/deployment-1 deployment "deployment-1" successfully rolled out
#查看升級記錄 [root@k8s-master01 ~]# kubectl rollout history deployment/deployment-1 deployment.extensions/deployment-1 REVISION CHANGE-CAUSE 1 kubectl apply --filename=demployment.yaml --record=true 2 kubectl apply --filename=demployment.yaml --record=true
#查看單個revision 的詳細信息 kubectl rollout history deployment/deployment-1 --revision=2
清理 Policy
設置 Deployment 中的 .spec.revisionHistoryLimit 項來指定保留多少舊的 ReplicaSet。 餘下的將在後臺被當作垃圾收集。默認的,所有的 revision 歷史就都會被保留。
注意: 將該值設置爲0,將導致所有的 Deployment 歷史記錄都會被清除,該 Deployment 就無法再回退了。
回滾更新
#回退到上一個版本 kubectl rollout undo deployment/deployment-1 #回退到指定版本 首先查看版本記錄 kubectl rollout history deployment/deployment-1 #再回退到指定版本爲2 kubectl rollout undo deployment/deployment-1 --to-revision=2
更新策略
Deployment 可以保證在升級時只有一定數量的 Pod 是 down 的。默認的,它會確保至少有比期望的Pod數量少一個是up狀態(最多一個不可用)。
Deployment 同時也可以確保只創建出超過期望數量的一定數量的 Pod。默認的,它會確保最多比期望的Pod數量多一個的 Pod 是 up 的(最多1個 surge )。
在未來的 Kuberentes 版本中,將從1-1變成25%-25%。
Rollover(多個rollout並行)
假如您創建了一個有5個 niginx:1.7.9 replica 的 Deployment,但是當還只有3個 nginx:1.7.9 的 replica 創建出來的時候您就開始更新含有5個 nginx:1.9.1 replica 的 Deployment。在這種情況下,Deployment 會立即殺掉已創建的3個 nginx:1.7.9 的 Pod,並開始創建 nginx:1.9.1 的 Pod。它不會等到所有的5個 nginx:1.7.9 的 Pod 都創建完成後纔開始改變航道。
3,DaemonSet
DaemonSet確保全部(或者一些)node 上運行一個 Pod 的副本。當有新的 node 加入集羣時,會自動爲他們添加一個這樣的 Pod。當有集羣移除時,這些 Pod 也會被回收。刪除 DaemonSet 將會刪除它所創建的所有 Pod。
使用場景
- 運行集羣存儲 daemon,例如在每個 node 上運行 glusterd、ceph。
- 在每個 node 上運行日期收集 daemon,例如 fluentd、logstash。
- 在每個 node 上運行監控 daemon,例如 Prometheus node Exporter、collectd、Datadog 代理或New Relic 代理。
DaemonSet 示例:(daemonset.yaml
)
apiVersion: extensions/v1beta1 kind: DaemonSet metadata: name: daemonset-1 #名稱 labels: app: daemonset-app #daemonSet標籤 spec: selector: matchLabels: name: daemonset-label #選擇指定的Pod template: metadata: labels: name: daemonset-label #定義Pod的標籤 spec: containers: - name: nginx-container image: hub.xcc.com/my/mynginx:v1 ports: - containerPort: 80
執行命令
kubectl create -f daemonset.yaml #查看daemonSet kubectl get ds #查看Pod標籤 kubectl get pod --show-labels #查看Pod運行的節點 kubectl get pod -o wide
DaemonSet 確保了集羣中每一個節點都會運行一個 Pod(master 節點沒有運行是因爲污點
的設置)。就算我們刪除某個節點的 Pod,DaemonSet 也會馬上爲這個節點重新創建一個 Pod。當然此時如果有新的節點加入到集羣中,那麼 DaemonSet 也會爲這個新節點自動創建一個這樣的 Pod。
4,Job
Job 負責批處理任務,即僅執行一次的任務,它能夠確保批處理任務的一個或多個 Pod 運行成功。意思就是,運行一個 Job 來創建 Pod,讓裏面的容器成功運行了指定的次數,才認爲這個 Job 是成功的,那麼這個 Job 纔算執行完成。
特殊說明
- spec.template 格式同 Pod
- restartPolicy 策略僅支持 Never 或 OnFailure。
- 單個 Pod 時,默認 Pod 成功運行後 Job 即結束。
- .spec.completions 標誌 Job 結束需要成功運行的 Pod 個數,默認爲 1。
- .spec.parallelism 標誌並行運行的 Pod 個數,默認爲 1。
- spec.activeDeadlineSeconds 標誌失敗的重試最大時間,超過這個時間不會繼續重試。
Job示例:(job.yaml)
apiVersion: batch/v1 kind: Job metadata: name: job-1 #job名稱 spec: template: metadata: name: job-app spec: containers: - name: busybox-container image: hub.xcc.com/my/mybusybox:v1 command: ['sh', '-c', 'echo hello world'] restartPolicy: Never
執行命令
kubectl create -f job.yaml kubectl get job kubectl get pod #查看日誌 kubectl log job-1-abcd1
5,CronJob
CronJob 管理基於時間的 Job,即:
- 在給定的時間點運行一次
- 週期性的在給定時間點運行
- 其本質就是在特定的時間循環創建 Job 來執行任務
- 其表達式爲:分、時、日、月、周
常用場景:
- 在給定的時間點調度 Job 運行
- 創建週期性的運行的 Job,例如:數據庫備份,發送郵件。
CronJob 的示例:(cronjob.yaml)
apiVersion: batch/v1beta1 kind: CronJob metadata: name: cronjob-1 spec: schedule: "*/1 * * * *" #spec.schedule:調度,必須字段,指定任務運行週期,格式爲分、時、日、月、周。 jobTemplate: #spec.jobTemplate:Job 模板,必須字段,指定需要運行的任務,格式同 Job。 spec: template: metadata: name: cronjob-app spec: containers: - name: busybox-container image: hub.xcc.com/my-xcc/my-busybox:v1 command: ['sh', '-c', 'date && echo hello world'] restartPolicy: Never #spec.startingDeadlineSeconds:啓動 Job 的期限(秒級別),該字段是可選的,如果因爲任何原因而錯過了被調度的時間,那麼錯過指定時間的 Job 將被認爲的失敗的。默認無期限。
執行命令
kubectl apply -f cronjob.yaml kubectl get cj #查看job,每分鐘執行一個job kubectl get job kubectl get pod #查看pod日誌 kubectl log cronjob-1-15123460-acdf6
6,StatefulSet
StatefulSet 爲 Pod 提供唯一的標識,它可以保證部署和 scale 的順序。StatefulSet 是爲了解決有狀態服努的問題,對應 Deployment 和 ReplicaSet 是爲無狀態服務而設計。
StatefulSet 有以下特點:
- 穩定的持久化存儲,即 Pod 重新調度後還是能訪問到相同的持久化數據,基於PVC來實現。
- 穩定的網絡標誌,即 Pod 重新調度後,其 PodName 和 HostName 不變,基於 Headless Service(即沒有Cluster IP的 Service)來實現。
- 有序部署,有序擴展。即 Pod 是有順序的,在部署或擴展的時候要依據定義的順序依次進行(即從 0 到 N-1,在下一個 Pod 運行之前,之前所有的 Pod 必須都是 Running 和 Ready 狀態),基於 init containers 來實現。
- 有序收縮,有序刪除(即從 N- 1 到 0)。
7,HPA(Horizontal Pod Autoscaling)
應用的資源使用率通常都有高峯和低谷的時候,如何削峯埋谷,提高集羣的整體資源利用率,讓 service 中的 Pod 個數自動調整暱?這就有賴於 Horizontal Pod Autoscaling 了,顧名思義,使 Pod 水平自動縮放。
三、Service
1,定義
k8s 定義了這樣一種抽象:一個 Pod 的邏輯分組,一種可以訪問它們的策略 —— 通常稱爲微服務。 這一組 Pod 能夠被 Service 訪問到,通常是通過 Label Selector 實現的。Service是k8s中的一個重要概念,主要是提供負載均衡和服務自動發現。
2,Service的類型
-
ClusterIp:默認類型,自動分配一個僅 Cluster 內部可以訪問的虛擬 IP。普通Service:通過爲Kubernetes的Service分配一個集羣內部可訪問的
固定虛擬IP
(Cluster IP);Headless Service:DNS會將headless service的後端直接解析爲podIP列表。 -
NodePort:在 ClusterIP 基礎上爲 Service 在每臺機器上綁定一個端口,這樣就可以通過 : NodePort 來訪問該服務。
-
LoadBalancer:在 NodePort 的基礎上,藉助 cloud provider 創建一個外部負載均衡器,並將請求轉發到: NodePort 。
- ExternalName:把集羣外部的服務引入到集羣內部來,在集羣內部直接使用。沒有任何類型代理被創建,這隻有 kubernetes 1.7 或更高版本的 kube-dns 才支持
3,Service的創建
一個 Service 在 k8s 中是一個 Rest 對象,和 Pod 類似。 像所有的 Rest 對象一樣, Service 定義可以基於 POST 方式,請求 apiserver 創建新的實例。 例如,假定有一組 Pod,它們對外暴露了 9376 端口,同時還被打上 "app=MyApp" 標籤。
apiVersion: v1 kind: Service metadata: name: my-service spec: selector: app: MyApp ports: - protocol: TCP port: 80 targetPort: 9376 #將請求代理到使用 TCP 端口 9376,並且具有標籤 "app=MyApp" 的 Pod 上
a)ClusterIP類型
clusterIP 主要在每個 node 節點使用 iptables 或 ipvs,將發向 clusterIP 對應端口的數據,轉發到 kube-proxy 中。然後 kube-proxy 自己內部實現有負載均衡的方法,並可以查詢到這個 service 下對應 pod 的地址和端口,進而把數據轉發給對應的 pod 的地址和端口。
主要需要以下幾個組件的協同工作:
- apiserver:用戶通過 kubectl 命令向 apiserver 發送創建 service 的命令,apiserver 接收到請求後將數據存儲 到 etcd 中。
- kube-proxy:k8s 的每個節點中都有一個叫做 kube-porxy 的進程,這個進程負責感知 service,pod 的變化,並將變化的信息寫入本地的 iptables 或 ipvs 規則中。
- iptables 或 ipvs:使用 NAT 等技術將 virtual IP 的流量轉至 endpoints 中。
創建Deployment(cluster-deployment.yaml)
apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment namespace: default spec: replicas: 3 selector: matchLabels: app: nginx-app template: metadata: labels: app: nginx-app spec: containers: - name: nginx-container image: hub.xcc.com/my-xcc/my-nginx:v1 imagePullPolicy: IfNotPresent ports: - name: http containerPort: 80
創建一個 Service(cluster-svc.yaml)
apiVersion: v1 kind: Service metadata: name: cluster-svc namespace: default spec: type: ClusterIP selector: app: nginx-app ports: - name: http port: 80 targetPort: 80
執行命令
#先創建deployment kubectl apply -f cluster-deployment.yaml kubectl get deployment #查看pod及其對應的ip kubectl get pod -o wide #創建svc kubectl apply -f cluster-svc.yaml kubectl get svc # 查看 ipvs規則。可以看見 svc 所在的 ip 地址代理的是上面的三個 pod 的 ip ipvsadm -Ln
b)NodePort類型
如果設置 type 的值爲 "NodePort",Kubernetes master 將從給定的配置範圍內(默認:30000-32767)分配端口,每個 Node 將從該端口(每個 Node 上的同一端口)代理到 Service。該端口將通過 Service 的 spec.ports[*].nodePort 字段被指定。
創建NodePort資源(nodeport-svc.yaml
)
apiVersion: v1 kind: Service metadata: name: nodeport-svc namespace: default spec: type: NodePort selector: app: nginx-app ports: - name: http port: 80 targetPort: 80 # 綁定到宿主機的31234端口,如果不指定,將隨機分配30000-32767 nodePort: 31234
執行命令
kubectl apply -f nodeport-svc.yaml kubectl get svc # 查看 ipvs 規則 ipvsadm -Ln
c)LoadBalancer 類型
使用支持外部負載均衡器的雲提供商的服務,設置 type 的值爲 "LoadBalancer",將爲 Service 提供負載均衡器。 負載均衡器是異步創建的,關於被提供的負載均衡器的信息將會通過 Service 的 status.loadBalancer 字段被髮布出去。
示例:(loadbalancer-svc.yaml)
kind: Service apiVersion: v1 metadata: name: loadbalancer-svc spec: selector: app: nginx-App ports: - protocol: TCP port: 80 targetPort: 9376 nodePort: 30061 clusterIP: 10.0.124.225 loadBalancerIP: 79.41.36.129 type: LoadBalancer status: loadBalancer: ingress: - ip: 124.145.67.177
來自外部負載均衡器的流量將直接打到 backend Pod 上,不過實際它們是如何工作的,這要依賴於雲提供商。 在這些情況下,將根據用戶設置的 loadBalancerIP 來創建負載均衡器。 某些雲提供商允許設置 loadBalancerIP。如果沒有設置 loadBalancerIP,將會給負載均衡器指派一個臨時 IP。 如果設置了 loadBalancerIP,但云提供商並不支持這種特性,那麼設置的 loadBalancerIP 值將會被忽略掉。
d)ExternalName 類型
這種類型的 Service 通過返回 CNAME 和它的值,可以將服務映射到 externalName 字段的內容,例如 www.xcc.com。ExternalName Service 是 Service 的特例,它沒有 selector,也沒有定義任何的端口和Endpoint。相反的,對於運行在集羣外部的服務,它通過返回該外部服務的別名這種方式來提供服務。
示例:(externelname-svc.yaml)
apiVersion: v1 kind: Service metadata: name: externalname-svc namespace: default spec: type: ExternalName externalName: www.xcc.com
當查詢主機 externalname-svc.defalut.svc.cluster.local(svc-name.namespace.svc.cluster.local)時,集羣的 DNS 服務將返回一個值 www.xcc.com 的 CNAME 記錄。訪問這個服務的工作方式和其他的相 同,唯一不同的是重定向發生在 DNS 層,而且不會進行代理或轉發。
執行命令
[root@master01 ~]# kubectl apply -f externelname-svc.yaml service/externalname-svc created [root@master01 ~]# kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE externalname-svc ExternalName <none> www.xixihaha.com <none> 4s kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 10d [root@master01 ~]# dig -t A externalname-svc.default.svc.cluster.local. @10.244.0.7 ; <<>> DiG 9.11.4-P2-RedHat-9.11.4-9.P2.el7 <<>> -t A externalname-svc.default.svc.cluster.local. @10.244.0.7 ...... ;; ANSWER SECTION: externalname-svc.default.svc.cluster.local. 30 IN CNAME www.xcc.com. ......
e)Headless Service
一種特殊的 ClusterIP SVC 類型。有時不需要或不想要負載均衡,以及單獨的 Service IP。 遇到這種情況,可以通過指定 Cluster IP 的值爲 "None" 來創建 Headless Service(spec.clusterIP: "None")。這個選項允許開發人員自由尋找他們自己的方式,從而降低與 Kubernetes 系統的耦合性。 應用仍然可以使用一種自注冊的模式和適配器,對其它需要發現機制的系統能夠很容易地基於這個 API 來構建。對這類 Service 並不會分配 Cluster IP,kube-proxy 不會處理它們,而且平臺也不會爲它們進行負載均衡和路由。 DNS 如何實現自動配置,依賴於 Service 是否定義了 selector。
示例:(headless-svc.yaml
)
apiVersion: v1 kind: Service metadata: name: headless-svc namespace: default spec: selector: app: nginx-app clusterIP: "None" ports: - port: 80 targetPort: 80
執行命令
[root@master01 ~]# kubectl apply -f headless-svc.yaml service/headless-svc created # 查看 svc。可以看見 headless-svc 的 IP 是空的 [root@master01 ~]# kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE headless-svc ClusterIP None <none> 80/TCP 5s kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 10d # 查看 k8s 組件所在 IP 地址 [root@k8s-master01 ~]# kubectl get pod -n kube-system -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES coredns-5c98db65d4-4vjp4 1/1 Running 3 20h 10.244.0.7 master01 <none> <none> coredns-5c98db65d4-d2kxh 1/1 Running 4 20h 10.244.0.6 master01 <none> <none> ...... # 使用 dig 命令查看 svc 解析到的ip地址。yum install -y bind-utils 安裝 dig 命令 [root@k8s-master01 ~]# dig -t A headless-svc.default.svc.cluster.local. @10.244.0.6 ; <<>> DiG 9.11.4-P2-RedHat-9.11.4-9.P2.el7 <<>> -t A headless-svc.default.svc.cluster.local. @10.244.0.14 ...... ;; ANSWER SECTION: headless-svc.default.svc.cluster.local. 30 IN A 10.244.2.57 headless-svc.default.svc.cluster.local. 30 IN A 10.244.1.47 headless-svc.default.svc.cluster.local. 30 IN A 10.244.1.46
使用 dig 命令從 codedns 組件查看到了 headless-svc 所解析到的 IP 地址。有三個 10.244.2.57
、10.244.1.47
和 10.244.1.46
。
如果你現在創建一個不使用 spec.clusterIP: "None"
的 svc,使用 codedns 查看,會發現只解析到了一個 IP 上。