kubectl接口風格
kubectl是一種RESTful風格的api,它把各種操作對象都一率當成資源來管理,並且可通過標準的http請求方法來處理,如: GET, PUT, DELETE, POST
資源:對象
資源實例化之後就是一個對象,類型於py的 類, 如k8s資源: service, pod, deployment
- workload: 運行應用程序對外提供的服務,如Pod,
工作負載型資源: ReplicaSet, Deployment, StatefulSet, DaemonSet, Job, Cronjob…
-
服務發現及服務均衡: Service, Ingress
-
配置與存儲: Volume(存儲卷), CSI (容器存儲接口), PV, PVC
屬性 說明 configMap 當配置中心使用 Secret 與configMap一致,但這個工具用於保存敏感資源 DownwardAPI 將外部環境信息輸出給容器 -------> 做爲容器編排系統之上的應用程序,運行時需要用到存儲,尤其是有狀態的持久化存儲的應用程序,其必然會用到Volume,以及幾乎爲了能夠配置容器化應用也必然會用到的configMap與Secret
-
集羣級資源
資源名稱 說明 名稱空間 不指定默認就是defalut 如 pod Node 節點自身也是資源 Role 角色,應該屬於名稱空間namespace中的一種 ClusterRole 集羣角色 RoleBinging 角色綁定 CluseterRoleBinding 集羣角色綁定 -
元數據型資源
屬性 說明 HPA 水平pod的自主控制器,能自動調整其它資源的元數據信息 如replicas PodTemplate pod模板,用於讓控制器創建pod使用的模板 LimitRange pod資源限制, 在啓動容器之前名稱空間中設定, 如 cpu|內存
資源配置清單
查看清單詳細狀態:
~]# kubectl get pods myapp-64758bffd4-4kp5z -o yaml
-
apiVersion
- 查看屬於哪一個對象的版本或api組
- apiVersion給定值一般格式爲
group/version
,如果不帶group,那就表示爲核心組之一,如apiVersion: v1
- 查看api版本有哪些:
~]# kubectl api-versions
- 三個級別: bata(開發), stable(穩定), alpha(測試)
-
kind
- 資源類別,指定資源對象時使用 如:
kind: Pod
, workload, 服務發現及均衡
- 資源類別,指定資源對象時使用 如:
-
metadata
指定元數據, 嵌套字段 如
{xx:[{'xx':xx},{'yy':yy}]}
屬性 說明 labels 標籤,每一種類型的資源都會有各自對應的標籤, 當標籤改變時會通知api server name 容器名稱,name必須唯一 namespace K8s概念的名稱空間 如default, 通過 ~]# kubectl get ns
查看名稱空間ownerReferences 屬於哪個的資源 selfLink /api/GROUP/VERSION/namespaces/NAMESPACE/TYPE/NAME
如: /api/v1/namespaces/default/pods/myapp-64758bffd4-4kp5zuid 唯一標識,每個pod都不會相同 -
spec規格:
定義創建對象時應當具備什麼樣的特性以及規範,如容器數量,容器鏡像,容忍度, spec是資源對象中最重要的一個字段,使用該字段可以定義我們所期望的資源應當具體什麼樣的特性以及規範,而後靠控制器來確保它的特性能夠被滿足。
- required: 必須要的字段 , 如pod資源類型 container是必要字段
-
status:
用於顯示當前容器的當前狀態, 本字段由kubernetes集羣維護, 副本個數,rollout,版本
-
資源清單參數:
~]# kubectl explain pods
屬性 說明 <string> 字符串 <[]string> 字符串列表 <object> 能嵌套兩級字段 <[]object> 對象列表,可以同時出現的多個列表 <map> 鍵值組成的映射, 另外格式的json數組 k:v
創建資源方法
- apiserver僅接收JSON格式的資源定義。
- yaml格式提供配置清單,apiserver可自動將其轉爲json格式, 而後在提交之後在執行
yaml清單優勢
- 無需在檢查pod是否存在, 可直接使用yaml刪除
- 複用效果
- 創建比命令行更加快捷
kubectl create -f xx.yaml
- 裸pod無需刪除控制器,可自定義屬性 存活性探測,就續狀態探測,生命週期探測, 初始化時配置, 容器資源限定,資源最低需求
清單用法
命令 | 清單 |
---|---|
kubectl run | 命令式資源清單 |
kubectl create | 配置清單 |
yaml | 聲明式資源清單 |
創建第一個yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-demo
namespace: default
labels:
app: firstapp
title: demo
# spec <Object>
spec:
# containers <[]Object>
containers: # 一個容器一個組
- name: nginxs
image: nginx
- name: nginx2
image: nginx
# labels用法
# labels:
# app: firstapp
# title: demo
# labels: {app:firstapp, title, demo}
# command的用法
# command: ['/bin/sh', 'nginx','-s', 'daemon off']
# command:
# - "/bin/sh"
# - "-c"
# - "sleep 5"
# 兩個容器運行在同一個pod中, 如果A有目錄而B沒有,需要使用存儲卷
創建: kubectl create -f first.yaml
刪除: kubectl delete -f first.yaml
pod資源管理
通過Pod運行容器,但Pod與容器並不是對應關係,Pod可以理解爲容器的有一層外殼,Pod在容器之外增加了一層抽象封裝,這個抽象封裝叫Pod,而且在一個Pod內部可以有多個容器,而且這些容器本身將共享同一個網絡名稱空間,
在Pod中會存在一個基礎架構的容器,當我們來使用原始方式去部署k8s的時候,它用到的基礎架構容器的對應的鏡像叫pause,它創建以後一直處於暫停狀態,我們甚至都看不見這麼一個容器; 而後,任意一個Pod中的pause容器會爲加入到此Pod中的其它容器來提供網絡名稱空間,提供存儲卷的定義等功能;比如我們要定義存儲卷, 那就意味着存儲卷也屬於該Pod或得Pod這個pause基礎架構容器的,其它任何加入到此Pod的容器都將共享底層基礎Pod的Pid、Mount、User、Ipc、Uts、Network等主要空間, 通過這種方式組織出來的多個容器,就像是運行在一個宿主機上的多個進程, 每一個容器就是一個進程 ,而進程與進程之間也就可以通過lo接口來進行通信了;
pod網絡
Kubernetes之上存在三種類型的網絡,分別的node網絡這個纔是能與外連網絡通信的接口,第二個是service網絡,service網絡僅能出現在iptables或ipvs規則當中用於路由和調度請求流量,第三種網絡是Pod網絡,就相當於我們機房裏面的Kubernetes內部網絡,每一個Pod都處於這個網絡當中,Pod的IP地址都是在這個網絡動態分配的IP地址,因此各個Pod無論在跑在哪個node上,是可以直接通信的,Pod和Pod之間可以使用彼此的地址,互相之間通信,但是Pod是動態的,隨之有可能被Pod控制器所重建,因此IP地址會發生變化的,那這個時候Pod和Pod之間直接使用IP地址進行通信就不是一種理想的狀態的,我們因爲讓他藉助於service地址通信;
因此,在k8s之上運行應用程序,它就有一個特點,我們必須在Pod前增加一個抽象層(service),哪怕只有一個Pod我們也應該增加一個service前端,固定Service地址用於客戶端能訪問到這個應用程序, 而Service對象它表現在所有節點上的iptabels或ipvs規則,所以客戶端在訪問Pod的時候需要先到Service然後在後代或調度給Pod;
pod控制
只要建構在k8s 之上的Pod都應該由於控制器來管理, 而且這個Pod一般不會由我們手動去創建,這種Pod叫做自助式Pod,它有一個特點,就是這個Pod一刪除,它就不會被重建了,節點一宕機,在個Pod就沒了,所以我們使用Pod雖然很多,但是絕對不會以手動的方式創建獨立運行的Pod,而應該使用Pod控制器來創建Pod;
Pod控制器也是一類標準的Kubernetes資源,控制器有多種,不同的控制器有不同的功能和任務,控制器也是整個Kubernetes最核心的組成部分,整個集羣的大腦,因爲它主要通過和解循環,loop來完成確保用戶所定義的每一個對象,它的當前狀態和用戶的期望值一致,如果不一致那麼控制器就會通過一系列的邏輯操作來進行修復,所以說控制器裏面包含的任務就像運維裏面的發佈、變更、故障處理等功能;
所以從某種意義上來講,控制器就是運維,因此有了Kubernetes之後我們運維工程師的日常任務,基本上就不需要再去人爲的接入和管理了,至少對於現在的無狀態應用來講,已經做到了,你只需要管理Kubernetes集羣自身是否運行正常就可以了;
Pod外部訪問
我們怎麼能把集羣外部的流量在必要時接入到集羣內部的Pod呢?
-
使用service的nodeport類型,它會在集羣節點上的每一個node節點打開一個端口,而後你訪問,集羣中的任何一個節點的地址和端口都可以訪問到Pod,它首先會DNAT到service,然後service再調度給Pod
-
使用service的hostPort類型,我們在定義Pod時候,使用hostPort的方式來將容器的端口映射到Node的端口,那這樣的話這個容器跑在哪個節點,我們就可以使用哪個節點的地址和端口就行訪問了,與nodeport的不同之處在於,hostPort僅在運行容器的節點打開端口,所以說它並不經由service;
-
使用hostNetwork,讓Pod可以直接使用它所在主機的網絡名稱空間,因此,Pod的地址也就是主機的地址,Pod監聽的端口也就是主機的端口,那這個時候直接訪問Pod所在的node的地址和端口即可訪問,那麼很顯然,Pod就不那麼隱蔽了;
-
ingress: k8s的核心目標就是去運行Pod, 而圍繞在Pod之外,我們還有很多類型的資源,比如我們的Service, 像ipvs或iptables的規則都是四層會話,如果我們的服務是https,四層是不能卸載https會話的,那麼所有的https證都都得安裝在pod中,那就比較麻煩了,所以這裏又有一個七層調度Ingress服務,類似於一個nginx或haproxy的組件
總結
- 當使用第一種方式nodeport類型時, 訪問邏輯是最通透最直接的,訪問任何一個節點都能到達, 但有一個缺陷就在於,我們創建的任何服務都要在所有節點上增加一個iptables或ipvs規則, 所以說如果服務使用同一個端口,都會導至端口衝突,所以nodeport只能是隨機映射, 端口範圍: 30000-32676;
- 所以說在這個時侯就不得不在K8s集羣之外的前端,在人爲的建立一個負載均衡器,用戶訪問這個LB將請求負載到後端的每一個物理節點所映射的端口, 那麼一旦這個LB宕機了,對應的服務也就沒了;
- 在必要的時候,我們還需要keepalived來給他做高可用,那這就背離了Kubernetes的使用初衷,因爲還需要在Kubernetes集羣之外再加一個不受Kubernetes管理的層,層層轉發性能不是特別的好,更何況我們的Kubernetes集羣外的負載均衡器也無法按需創建
labels 標籤
當pod數量過多時使用標籤可以有效的將pod進行分組,控制器也需要使用標籤來管控對應的pod資源,標籤其實就是附加在pod之上的一個鍵值對,每一個標籤都可以被標籤選擇器進行匹配度檢查從而完成資源挑選, 一個資源可擁有多個標籤,標籤也可以同時添加到多個資源上, 標籤可以在pod創建之前指定, 也可以在創建之後用命令來管理(增\刪\改),
實際當中通過不同緯度標籤的標籤來管理pod,也可通過分層 如application=nginx
指定應用程序爲nginx, 使用標籤時,一般會使用幾種類型如: 應用程序版本 release (stable: 穩定版, bata:研發版 , alpha: 測試版), 環境標籤(dev, test(qa), prodect), 使用功能 ( 存儲, 應用程序, 分區標籤 )
資源標籤
# 格式: key=value
# 標籤中的鍵的名稱通暢是由鍵前綴和鍵名組成的,其格式可以如KEY_NAME/KEY_PREFIX_NAME;
key: 字母、數字、下劃線_、 橫線-、點. 、5種類型開頭,鍵名至多能使用63個字符,且只能以字母或數字開頭
# 鍵前綴必須爲DNS子域名格式,且不能超過253個字符,省略鍵前綴時,鍵將被視爲用戶的私有數據,不過由於Kuberetes系統組成,或第三方組件自動爲用戶資源添加的鍵必須使用前綴而"kubernetes/"前綴預留給kubernetes的核心組件使用;
value: 不能超過63個字符,可以爲空, 只能以字母或數字開頭及結尾,且中間僅使用了字母、數字、連接符號(-)、下劃線或點號(.)等字符的數據;
標籤選擇器
- 等值關係
- =, ==: # key=value的值
```bash
~]# kubectl get pods -l release=stable # 等值關係判斷
~]# kubectl get pods -l release=stable,app=firstapp --show-labels
NAME READY STATUS RESTARTS AGE LABELS
pod-demo 1/1 Running 0 28h app=firstapp,release=stable,title=demo
```
- !=: # key中不存在的值,取反
```bash
# 取pods中不帶stable的, 但 app=firstapp的資源
~]# kubectl get pods -l release!=stable,app=firstapp --show-labels
```
- 集合關係
- KEY in (value1, value2…) # key 存在於列表中值
```bash
# 取出 run這個key中存在myapp與myapp2的values資源對象
~]# kubectl get pods -l "run in (myapp, myapp2)" --show-labels
```
- KEY notin (value1, value2,…) # key 不具有的值
```bash
# 取出 run這個key中存在myapp與myapp2的values資源對象
~]# kubectl get pods -l "run notin (myapp)" --show-labels
```
- 內嵌字段
kubernetes的諸多資源對象必須以標籤選擇器的方式關聯到Pod資源對象,例如Service、Deployment和ReplicaSet類型的資源等,他們在spec字段中嵌套使用嵌套的selector字段通過matchLabels來指定標籤選擇器,有的甚至還支持使用matchExpressions來構造複雜的標籤選擇器機制;
標籤選擇器 | 說明 |
---|---|
matchLabels | 直接給定鍵值來進行選擇 |
matchExpressions | 基於給定的表達式來定義使用的標籤選擇器 {key:“KEY”, operator: “操作符”, values:[VAL1,VAL2]}, # values:[val1, val2] 與 operator進行對比 |
選擇器操作符 | 說明 |
---|---|
IN, NotIn | values: 其值必須爲非空列表 |
Exists, NotExists | values: 必須爲空列表 |
- 邏輯
# 許多資源支持內嵌字段定義其使用的標籤選擇器
# service 只支持 matchLabels
# deployment,replicas 兩種都支持
使用標籤選擇器還能使用一下邏輯
同時指定多個選擇器之間的邏輯關係爲與操作;
使用"空值"的標籤選擇器意味着每個資源對象都將被選中;
"空的"標籤選擇器將無法選出任何資源;
查看\顯示標籤
查看labels
~]# kubectl get pods --show-labels
pod-demo 1/1 Running 0 26h app=firstapp,title=demo
# -L: 用於指定顯示,指定資源對象類別下的所有資源對應的標籤的值
~]# kubectl get pods -L app
NAME READY STATUS RESTARTS AGE APP
client-f44986c9-6mnvd 1/1 Running 0 5d21h
pod-demo 1/1 Running 0 27h firstapp
# -l 只顯示有這個標籤的資源
~]# kubectl get pods -l app --show-labels
NAME READY STATUS RESTARTS AGE LABELS
pod-demo 1/1 Running 0 28h app=firstapp,title=demo
# 過濾兩種條件同時存在的pod
~]# kubectl get pods -l app,release --show-labels
打標籤
~]# kubectl get pods --show-labels
NAME READY STATUS RESTARTS AGE LABELS
pod-demo 1/1 Running 0 28h app=firstapp,title=demo
# 添加標籤選擇器
~]# kubectl label pods pod-demo release=base
pod/pod-demo labeled
~]# kubectl get pods --show-labels
NAME READY STATUS RESTARTS AGE LABELS
pod-demo 1/1 Running 0 28h app=firstapp,release=base,title=demo
# 修改已存在的標籤, 需要加上 --overwrite不加,會提示已存在的錯誤
~]# kubectl label pods pod-demo release=stable --overwrite
pod/pod-demo labeled
~]# kubectl get pods --show-labels
NAME READY STATUS RESTARTS AGE LABELS
pod-demo 1/1 Running 0 28h app=firstapp,release=stable,title=demo
# 刪除labels
]# kubectl label pods pod-demo -n qa release-
spec.nodeSelector
nodeSelector <map[string]string>
:節點標籤選擇器, 限定pod運行在哪種類型的節點標籤上
demo
-
查看節點
~]# kubectl get nodes --show-labels NAME STATUS ROLES AGE VERSION LABELS master Ready master 6d4h v1.16.3 kubernetes.io/hostname=master node1 Ready <none> 6d4h v1.16.3 kubernetes.io/hostname=node1 node2 Ready <none> 6d4h v1.16.3 kubernetes.io/hostname=node2
-
創建yaml
]# cat node.yaml apiVersion: v1 kind: Pod metadata: name: pod-node # craete -f 時pod的名稱 namespace: default # 名稱空間default labels: run: node # 完成之後的label標籤 spec: containers: - name: cnode image: nginx:1.16.1 # 指定容器版本 默認imagePullPolicy就是IfNot imagePullPolicy: IfNotPresent ports: # 暴露端口號 - name: http containerPort: 80 - name: https containerPort: 443 nodeSelector: # 限定pod運行在node2這個節點上 kubernetes.io/hostname: node2
-
創建
]# kubectl create -f node.yaml pod/pod-node created
-
查看創建的pod
]# kubectl describe pods pod-node Name: pod-node Namespace: default Priority: 0 Node: node2/192.168.9.32 Start Time: Wed, 04 Dec 2019 14:45:02 +0800 Labels: run=node Annotations: <none> Status: Running IP: 10.244.2.26 IPs: IP: 10.244.2.26 Containers: cnode: Container ID: docker://xx Image: nginx:1.16.1 Ports: 80/TCP, 443/TCP Host Ports: 0/TCP, 0/TCP State: Running Started: Wed, 04 Dec 2019 14:45:27 +0800 Ready: True Node-Selectors: kubernetes.io/hostname=node2 Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 29s default-scheduler Successfully assigned default/pod-node to node2 Normal Pulling 28s kubelet, node2 Pulling image "nginx:1.16.1" Normal Pulled 4s kubelet, node2 Successfully pulled image "nginx:1.16.1" Normal Created 4s kubelet, node2 Created container cnode Normal Started 4s kubelet, node2 Started container cnode ]# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE pod-node 1/1 Running 0 4m48s 10.244.2.26 node2
spec.nodeName
直接限定死運行在指定的節點之上
metadata.annotaions
資源註解,與lable不同的地方在於,它不能用於挑選資源對象,僅用於爲對象提供“元數據”。 鍵值不受字符限制,如:前綴/組:value
apiVersion: v1
kind: Pod
metadata:
name: mypod-nginx
namespace: default
labels:
k8s.com/mypod: qa
spec:
containers:
- name: mypod-nginx
image: nginx
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
- name: https
containerPort: 443
nodeSelector:
kubernetes.io/hostname: slave2
pod生命週期
所謂Pod生命週期指的是,Pod從創建,退出結束終止之間經歷的階段;
**第一階段:**在啓動Pod主容器時, 可能需要先給它做一下環境初始化;
-
比如: nginx在啓動前需要先做一些文件操作, 那麼在運行一個Nginx主容器之前,需要先啓動一個容器, 然後創建一個目錄並創建一個文件或掛載文件, 都完成之後才能啓動主容器, 這個階段過程我們稱之爲初始化階段, 然後初始化容器就會退出, 但這個過程不是必須的, 而如果以後在創建Pod時有這種場景就可以使用, 這種術語叫: init container;
-
且需要注意的是初始化容器也可能會存在多個, 比如多個容器都只幹一件事,c1創建目錄, c2創建訪問文件, 只有兩個容器都完成初始化工作, 主容器纔會啓動, 否則主容器是無法啓動的, 並且需要注意的是如果初始化容器有多個,那麼它們必須是串行, 不能並行
-
]# kubectl explain pods.spec.initContainers
第二階段,主容器的運行階段,分爲三個階段,
-
第一個主容器剛啓動之後;
-
第二是主容器正常運行;
-
第三是主容器結束之前,post start hook這個時候是你的容器剛剛啓動完成,它是一個鉤子,這個時候你可以觸發你的定義的鉤子命令,來幫你在這個容器中做一些啓動後的設置,那麼pre start hook就是結束之前做的操作,而這個兩個主要是用於觸發一些命令來執行的,讓用戶可以自定義操作的;
]# kubectl explain pods.spec.containers.lifecycle
從pod被創建開始,一個容器實際上來說只運行一個進程, 這個進程稱爲主進程,一個pod可以運行多個容器,但一般只運行一個容器,容器在創建之前,有多個初始化容器(init container)用來進行初始化環境,init container執行完,它就退出了,接下來是主容器(main container)開始啓動,主容器啓動時也要初始化主容器裏面的環境,在主容器剛啓動時,用戶可以手動嵌入一個操作叫 post start (啓動後程序),啓動執行完之後就會退出,在主容器結束前,也可以做一個收尾操作 pre stop (結束前),用來在主容器結束前做一個清理。
- 初始化容器完成初始化
- 主容器啓動後可以做啓動前鉤子也可以在結束後做結束前鉤子,還可以在運行過程中做容器探測(liveness probe、readiness probe);
- 在post start後,先做存活狀態檢測,再做就緒性檢測;
- 程序操作完之後 執行一個pre stop(結束前)程序做結束前主容器的最後清理。
創建pod流程
- 當用戶創建pod時請求會提交給apiserver, apiserver會將創建請求的目標狀態保存到etcd;
- 接着請求scheduler進行調度(必須參與,挑選節點),將調度結果保存到etcd狀態信息當中;
- 目標節點上的kubelet通過apiserver當中的狀態位拿到用戶提交的創建清單;
- 最後根據清單在當前節點上創建並運行這個Pod;
- 如果創建成功或失敗,kubelet會將將狀態結束返回給apiserver,再把結果存到etcd中
Pod的狀態
Pod生命週期中的重要行爲: 初始化容器、容器探測、生命週期鉤子(啓動前、啓動後)
狀態 | 說明 |
---|---|
Pending | 掛起,調度尚未完成 |
Running | 運行中 |
Failed | 容器運行失敗 |
Successed | 成功 |
Unknown | 未知狀態 |
容器探測
健康檢查分三個層次: 1.執行自定義命令; 2.直接向tcp端口發請求; 3.向http發get請求.
狀態 | 說明 |
---|---|
liveness probe | 存活狀態探測,用於判定主容器是否處於運行狀態 |
readiness probe | 就緒性探測: 用於判定容器中的主進程是否準備就緒以及能否對外提供服務 |
pod刪除
在提交刪除pod時,程序不會直接kill刪除,而是會往pod 內中的每一個容器發送終止信號,讓pod中的容器正常終止,其會有一個平滑期比如2分鐘,之後就會直接強行進行終止刪除
spec.restartPolicy
重啓策略, 一旦pod被調度到某一節點, 只要節點在pod就不會被重新調度到別的節點, 容器只會重啓,除非pod被刪除,節點故障等問題pod纔會被重新調度,否則它就一直會存在於被調度的節目之上
選項 | 說明 |
---|---|
Always | 一旦pod中的容器掛了, 總是重啓 |
OnFailure | 只是其狀態爲錯誤時,纔會重啓,第一次立即,第二次會延時, 第三次及以上失敗次數都是上一次的倍數 |
Never | 從不重啓 |
Default to Always | 默認就是總是重啓 |
探針類型
3種類型如果針對 liveness probe就是存活性探 針, 針對readiness probe就是就緒性探針
類型 | 說明 |
---|---|
ExecAction | 用戶自定義命令, 需要是容器中存在的命令 |
TCPSocketAction | 向tcp端口連接請求 |
HttpGetAction | 向http發get請求 |
containers.livenessProbe
位置: spec.containers.livenessProbe
存活性探針, 定義探針只需要定義其中的一種即可,exec, httpGet, tcpsocket
選項 | 說明 |
---|---|
failureThreshold | 探測幾次失敗纔算是失敗,默認爲3 |
periodSeconds | 每次探測的時長是多少秒纔算是失敗, 默認10s |
timeoutSeconds | 每次探測之後的時長, 默認1秒 |
initialDelaySeconds | 默認是容器一啓動就開始探測,但是此時容器可能還沒啓動完,此時探測肯定是失敗的, 所以initialDelaySeconds表示容器啓動多長時間後纔開始探測 |
exec | 執行用戶自定義的命令,命令必須是容器中存在的命令 command: 運行命令探測是否成功, 判斷狀態碼 |
ExecAction
]# cat liveness_exec.yaml
apiVersion: v1
kind: Pod
metadata:
name: liveness-exec
namespace: default
spec:
containers:
- name: liveness-exec
image: ikubernetes/myapp:v1
imagePullPolicy: IfNotPresent
# 執行命令, 創建he.html文件, 睡眠2秒之後刪除
command: ['/bin/sh', '-c', 'touch /tmp/he.html; sleep 20; rm -f /tmp/he.html; sleep 60']
ports:
- name: http
containerPort: 80
livenessProbe:
exec: # 自定義命令探測
# 存活性探測, 如果狀態不爲0那就說明該文件不存在
command: ['test', '-e', '/tmp/he.html']
# 初始化三秒之後在進行探測
initialDelaySeconds: 3
# 3秒鐘探測一次
periodSeconds: 3
# 失敗3次就說明該容器的確是有問題
failureThreshold: 3
nodeSelector:
kubernetes.io/hostname: node2
Command:
/bin/sh
-c
touch /tmp/he.html; sleep 20; rm -f /tmp/he.html; sleep 60
State: Running # 重啓之後又恢復正常
Last State: Terminated # 上一次的狀態是失敗的
Reason: Error
Exit Code: 137
Restart Count: 1 # 重啓一次
Liveness: exec [test -e /tmp/he.html] delay=3s timeout=1s period=3s #success=1 #failure=3
HttpGetAction
]# cat liveness_html.yaml
apiVersion: v1
kind: Pod
metadata:
name: liveness-html
namespace: default
spec:
containers:
- name: liveness-html
image: ikubernetes/myapp:v1
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
livenessProbe:
httpGet:
port: http # 如果暴露的端口有別名那就可以直接使用別名
# 訪問的路徑
path: /index.html
# 啓動後延遲3秒在進行探測
initialDelaySeconds: 3
# 3秒鐘探測一次
periodSeconds: 3
failureThreshold: 3
nodeSelector:
kubernetes.io/hostname: node2
# 檢查狀態, 如果刪除容器中的 index.html文件, 如果探測訪問不了那麼就會直接重啓容器
~]# kubectl describe pods liveness-html
Name: liveness-html
Node: node2/192.168.9.32
Containers:
liveness-html:
Image: ikubernetes/myapp:v1
Port: 80/TCP
Host Port: 0/TCP
State: Running
Started: Thu, 05 Dec 2019 13:44:17 +0800
Last State: Terminated
Reason: Completed
Exit Code: 0
Started: Thu, 05 Dec 2019 13:42:09 +0800
Finished: Thu, 05 Dec 2019 13:44:17 +0800
Restart Count: 1
Liveness: http-get http://:http/index.html delay=3s timeout=1s period=3s #success=1 #failure=3
containers.readinessProbe
位置:spec.containers.readinessProbe
就緒性探針, 參數與存活性探針一樣
service通過lables選擇器關連至各pod資源, 當新建的pod符合service的lables選擇器的選擇條件, 那麼pod將會立即做爲service的後端對象pod之一, 當用戶有新請求時將會被隨機調度至新的pod中, 而新容器在啓動之時啓動是需要時間的(當容器在啓動時,需要經過很多步驟,比如tomcat, 啓動jvm展開war,啓動tomcat, 啓動過程不止一秒鐘) 而就緒在開始之前就會直接顯示成功,所以當新請求過來時必定會出現錯誤, 因此如果不做就緒性探測新容器創建的就緒準備,轉發新請求都將會失敗, 解決辦法: 創建之後需要先做就緒性探測
HttpGetAction
]# cat readline.yaml
apiVersion: v1
kind: Pod
metadata:
name: readline-exec
namespace: default
spec:
containers:
- name: readline-exec
image: ikubernetes/myapp:v1
ports:
- name: http
containerPort: 80
readinessProbe:
httpGet:
port: http
path: /index.html
initialDelaySeconds: 3
periodSeconds: 3
]# kubectl get pods
NAME READY STATUS RESTARTS AGE
readline-exec 1/1 Running 0 4s
# 如果 index.html無法訪問 , 那麼pod不會被刪除, 而容器會進入非就緒狀態,轉發請求將會失敗
]# kubectl describe pods readline-exec
Ready: False
Restart Count: 0
Readiness: http-get http://:http/index.html delay=3s timeout=1s period=3s #success=1 #failure=3
Environment: <none>
]# kubectl get pods # pods 控制器 也會一直存在, 當容器服務正常它又會重新進入就緒狀態
readline-exec 0/1 Running 0 2m42s
lifecycle
位置: spec.containers.lifecycle
生命週期探針, 鉤子(啓動後,終止前探測)
- postStart: 啓動後
- preStop: 終止前, 對應的pod在終止之前執行的命令 ,命令執行完之後纔會被刪除
資源需求及資源限制
CPU屬於可壓縮(compressible)型資源,即資源額度可按需收縮,而內存則是不可壓縮型資源,對其執行收縮操作可能會導致某種程度的問題,所以我們需要資源進行一定的限制;
CPU的計量方式:一個核心相當於1000個微核心,即1=1000m,0.5=500m;
內存的計量方式:默認單位爲字節,也可以使用E、P、T、G、M和K後綴單位,或Ei、Ei、Pi、Ti、Gi、Mi和Ki形式的單位爲後綴;
Pod服務質量類別
根據Pod對象的requests和limits屬性,Kubernetes把Pod對象歸類到BesteFFort、Buaranteed三個服務質量類別,可以使用describe查看QoS Class屬性;
- Guaranteed:每個容器都爲CPU資源設置了具有相同值的requests和limits屬性,以及每個容器都爲內存資源社會了具有相同值的requests和limits屬性的pod資源會自動歸類爲此類別,這類Pod資源具有最高優先級;
- Burstable:至少有一個容器設置了CPU或者內存資源的requests屬性,但不滿足Guaranteed類別要求的Pod資源自動歸屬此類,他們具有中等優先級;
- BestEffort:未爲任何一個容器設置requests或limits屬性的Pod資源自動歸屬此類別,他們的優先級爲最低級別;
spec.containers <[]object>
-
name\image
- name <string> -required- # 必須要的參數 image <string> # 指定鏡像, 可以是頂級倉庫|私有|其它,需要是有效鏡像
-
imagePullPolicy: 鏡像獲取策略, 一旦創建就不能被修改
策略|選項 說明 Always 不管有沒有,總是去register中下載 never 從不下載,如果本地有就用,沒有就等待,需要手動下載 ifNotPresent 如果本地存在就直接使用,不存在就下載, 如果標籤是always那麼總是去register上下載, 如果指定了版本,那麼標籤就是 ifNotPresent -
**ports <[]Object>: **暴露端口
定義端口容器內要暴露的端口, 每一個端口可以有名稱,端口號,協議,暴露的端口僅僅提供額外信息, ports一般需要指定的子參數,如下
參數 說明 containerPort <integer> -required- 只需要指定容器端口 hostIP <string> 使用 0.0.0.0 所有端口 name <string> 常使用 IANA_SVC_NAME格式 protocol 指定協議 TCP|UDP 默認TCP -
args\command
參數 說明 args 傳遞給程序的參數 在args中 $(VAR_NAME)命令引用 command 要運行的程序, 所給定的代碼是不會運行在shell中的, 如果想要以sh運行需要手動指定, 如果沒有指定命令,那就會先運行容器中的entrypoint的命令 屬性描述
描述 Docker 字段名稱 Kubernetes 字段名稱 容器運行的命令 Entrypoint command 傳遞給命令的參數集合 Cmd args 如果要覆蓋默認的 Entrypoint 與 Cmd,需要遵循如下規則:
- 如果在容器配置中沒有設置
command
或者args
,那麼將使用Docker鏡像自帶的命令及其入參。 - 如果在容器配置中只設置了
command
但是沒有設置args
,那麼容器啓動時只會執行該 命令,Docker鏡像中自帶的命令及其入參會被忽略。 - 如果在容器配置中只設置了
args
,那麼Docker鏡像中自帶的命令會使用該新入參作爲 其執行時的入參。 - 如果在容器配置中同時設置了
command
與args
,那麼Docker鏡像中自帶的命令及 其入參會被忽略。容器啓動時只會執行配置中設置的命令,並使用配置中設置的入參作爲 命令的入參。
下表涵蓋了各類設置場景:
鏡像 Entrypoint 鏡像 Cmd 容器 command 容器 args 運行的命令 [/ep-1]
[foo bar]
[ep-1 foo bar]
[/ep-1]
[foo bar]
[/ep-2]
[ep-2]
[/ep-1]
[foo bar]
[zoo boo]
[ep-1 zoo boo]
[/ep-1]
[foo bar]
[/ep-2]
[zoo boo]
[ep-2 zoo boo]
- 如果在容器配置中沒有設置
容器日誌-logs
~]# kubectl logs 容器名稱, # 檢查容器的日誌, 如果pod有多個容器需要 -c指定容器名稱
# 如 先使用 kubectl describe deployments 查看容器名稱
~]# kubectl logs -c 容器名稱
時設置了command
與 args
,那麼Docker鏡像中自帶的命令及 其入參會被忽略。容器啓動時只會執行配置中設置的命令,並使用配置中設置的入參作爲 命令的入參。
下表涵蓋了各類設置場景:
鏡像 Entrypoint | 鏡像 Cmd | 容器 command | 容器 args | 運行的命令 |
---|---|---|---|---|
[/ep-1] |
[foo bar] |
[ep-1 foo bar] |
||
[/ep-1] |
[foo bar] |
[/ep-2] |
[ep-2] |
|
[/ep-1] |
[foo bar] |
[zoo boo] |
[ep-1 zoo boo] |
|
[/ep-1] |
[foo bar] |
[/ep-2] |
[zoo boo] |
[ep-2 zoo boo] |
容器日誌-logs
~]# kubectl logs 容器名稱, # 檢查容器的日誌, 如果pod有多個容器需要 -c指定容器名稱
# 如 先使用 kubectl describe deployments 查看容器名稱
~]# kubectl logs -c 容器名稱