一、kubectl 命令補全
安裝bash自動補全工具
yum install -y bash-completion
source /usr/share/bash-completion/bash_completion
bash 終端
source <(kubectl completion bash) # 在 bash 中設置當前 shell 的自動補全,要先安裝 bash-completion 包。
echo "source <(kubectl completion bash)" >> ~/.bashrc # 在您的 bash shell 中永久的添加自動補全
zsh 終端
source <(kubectl completion zsh) # setup autocomplete in zsh into the current shell
echo "[[ $commands[kubectl] ]] && source <(kubectl completion zsh)" >> ~/.zshrc # add autocomplete permanently to your zsh shell
設置別名,減短命令
vim ~/.bashrc
# 添加下面兩行
alias k=kubectl
complete -F __start_kubectl k
二、更新鏡像
Kubernetes中,默認的鏡像抓取策略是 IfNotPresent
,使用此策略,kubelet在發現本機有鏡像的情況下,不會向鏡像倉庫抓取鏡像。如果您期望每次啟動 Pod 時,都強制從鏡像倉庫抓取鏡像,可以嘗試如下方式:
- 設置 container 中的
imagePullPolicy
為Always
- 省略
imagePullPolicy
字段,並使用:latest
tag 的鏡像 - 省略
imagePullPolicy
字段和鏡像的 tag - 激活
AlwaysPullImages
管理控制器
imagePullPolicy
字段和 image tag
的可能取值將影響到 kubelet 如何抓取鏡像:
imagePullPolicy:
IfNotPresent 僅在節點上沒有該鏡像時,從鏡像倉庫抓取imagePullPolicy:
Always 每次啟動 Pod 時,從鏡像倉庫抓取imagePullPolicy
未填寫,鏡像 tag 為:latest
或者未填寫,則同Always
每次啟動 Pod 時,從鏡像倉庫抓取imagePullPolicy
未填寫,鏡像 tag 已填寫但不是:latest
,則同IfNotPresent
僅在節點上沒有該鏡像時,從鏡像倉庫抓取imagePullPolicy:
Never,Kubernetes 假設本地存在該鏡像,並且不會嘗試從鏡像倉庫抓取鏡像
重要
在生產環境部署時,您應該避免使用 :latest tag,如果這樣做,您將無法追蹤當前正在使用的鏡像版本,也無法正確地執行回滾動作 |
---|
如果要 100% 確保所有的容器都使用了同樣的鏡像版本,可以嘗試使用鏡像的 digest,例如 sha256:45b23dee08af5e43a7fea6c4cf9c25ccf269ee113168c19722f87876677c5cb2。 Digest 唯一地標識了容器鏡像的版本,並且永遠不會改變。 |
容器引擎的鏡像緩存機制使得 imagePullPolicy: Always 仍然是高效的。在 Docker 中,如果鏡像已經存在,抓取嘗試非常快速,先檢查鏡像所有的 layer 是否有更新,如果該鏡像在鏡像倉庫中所有 layer 的 digest 與本地所有 layer 的 digest 相同,則不會再下載鏡像。 |
三、管理容器的計算資源
您可以為 Pod 中的每一個容器指定其所需要的內存(RAM)大小和 CPU 數量。如果這些信息被指定了,Kubernetes 調度器可以更好的決定將 Pod 調度到哪一個節點。對於容器來說,其所需要的資源也將依據其指定的數值得到保證
1、CPU 的計量
在 Kubernetes 中,1 個 CPU 代表:
- 1 AWS vCPU
- 1 GCP Core
- 1 Azure vCore
- 1 IBM vCPU
- 物理機上 Intel 超線程 CPU 的 1 個超線程(Hyperthread)
Kubernetes 中,0.5 代表請求半個 CPU 資源。表達式 0.1 等價於 表達式 100m,在 API Server 中,表達式 0.1 將被轉換成 100m,精度低於 1m 的請求是不受支持的。 CPU 的計量代表的是絕對值,而非相對值,例如,您請求了 0.1 個 CPU,無論您的節點是 單核、雙核、48核,您得到的 CPU 資源都是 0.1 核。
2、內存的計量
內存的計量單位是 byte 字節。您可以使用一個整數來表達內存的大小,也可以使用后綴來表示(E、P、T、G、M、K)。您也可以使用 2 的冪數來表示內存大小,其后綴為(Ei、Pi、Ti、Gi、Mi、Ki)。例如,下面的幾個表達方式所表示的內存大小大致相等:
128974848, 129e6, 129M, 123Mi
Kubernetes 中,可以為容器指定計算資源的請求數量 request
和限制數量 limit
。盡管資源的請求/限制數量只能在容器上指定,我們仍然經常討論容器組的資源請求/限制數量。容器組對某一個類型的資源請求/限制數量是該容器組中所有工作容器對該資源請求/限制數量的求和。
3、帶有資源請求的容器組是如何調度的
調度程序將確保:對於每一種資源類型,已調度的 Pod 對該資源的請求之和小於該節點最大可供使用資源數量。
如果資源請求之和大於Node節點資源,則調度程序不會將該 Pod 分配到該節點。Kubernetes 這樣做可以避免在日常的流量高峰時段,節點上出現資源短缺的情況。
4、帶有資源限制的容器組是如何運行的
Kubelet 啟動容器組的容器時,將 CPU、內存的最大使用限制作為參數傳遞給容器引擎。
以 Docker 容器引擎為例:
- 容器的 cpu 請求將轉換成 docker 要求的格式,並以
--cpu-shares
標志傳遞到docker run
命令 - 容器的 cpu 限制將也將轉換成 millicore 表達式並乘以 100。結果數字是每 100ms 的周期內,該容器可以使用的 CPU 份額
- 容器的內存限制將轉換成一個整數,並使用
--memory
標志傳遞到docker run
命令
如下情況可能會發生:
- 如果某個容器超出了其內存限制,它可能將被終止。如果 restartPolicy 為 Always 或 OnFailure,kubelet 將重啟該容器
- 如果某個容器超出了其內存申請(仍低於其內存限制),當節點超出內存使用時,該容器仍然存在從節點驅逐的可能性
- 短時間內容器有可能能夠超出其 CPU 使用限制運行。kubernetes 並不會終止這些超出 CPU 使用限制的容器
apiVersion: v1
kind: Pod
metadata:
name: frontend
spec:
containers:
- name: db
image: mysql
env:
- name: MYSQL_ROOT_PASSWORD
value: "password"
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
- name: wp
image: wordpress
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
排查問題
容器可能因為資源不足而被終止。要檢查容器是否由於達到資源限制而被殺死,請在有問題的Pod上調用kubectl describe pod PodName
kubectl describe pod simmemleak-hra99
Name: simmemleak-hra99
Namespace: default
Image(s): saadali/simmemleak
Node: kubernetes-node-tf0f/10.240.216.66
...
Containers:
simmemleak:
Image: saadali/simmemleak
Limits:
cpu: 100m
memory: 50Mi
State: Running
Started: Tue, 07 Jul 2015 12:54:41 -0700
Last Termination State: Terminated
Exit Code: 1
Started: Fri, 07 Jul 2015 12:54:30 -0700
Finished: Fri, 07 Jul 2015 12:54:33 -0700
Ready: False
Restart Count: 5
...
Events:
FirstSeen LastSeen Count From SubobjectPath Reason Message
主要觀察
Last Termination State: Terminated
Restart Count: 5
可以通過 kubectl get pod
加上 -o go-template=...
選項來以取先前pod終止的狀態
kubectl get pod -o go-template='{{range.status.containerStatuses}}{{"Container Name: "}}{{.name}}{{"\r\nLastState: "}}{{.lastState}}{{end}}' simmemleak-hra99
Container Name: simmemleak
LastState: map[terminated:map[exitCode:137 reason:OOM Killed startedAt:2015-07-07T20:58:43Z finishedAt:2015-07-07T20:58:43Z containerID:docker://0e4095bba1feccdfe7ef9fb6ebffe972b4b14285d5acdec6f0d3ae8a22fad8b2]]
你可以看到 reason:OOM Killed
, 因為超過內存限制所以被 OOM
四、將pod調度到指定node節點
您可以限定 Pod 只能在特定的節點上運行,或者優先選擇在特定的節點上運行。
- 確保某些 Pod 被分配到具有固態硬盤的節點
- 將相互通信頻繁的兩個 Pod 分配到同一個高可用區的節點
Kubernetes 一共提供了四種方法,可以將 Pod 調度到指定的節點上,這些方法從簡便到復雜的順序如下:
- 指定節點 nodeName
- 節點選擇器 nodeSelector Kubernetes 推薦用法
- Node isolation/restriction
- Affinity and anti-affinity
1、指定節點 nodeName
nodeName 是四種方法中最簡單的一個,但是因為它的局限性,也是使用最少的。nodeName 是 Pod Spec 當中的一個字段。如果該字段非空,調度程序直接將其指派到 nodeName 對應的節點上運行。
通過 nodeName 限定 Pod 所運行的節點有如下局限性:
- 如果 nodeName 對應的節點不存在,Pod 將不能運行
- 如果 nodeName 對應的節點沒有足夠的資源,Pod 將運行失敗,可能的原因有:OutOfmemory /OutOfcpu
- 集群中的 nodeName 通常是變化的(新的集群中可能沒有該 nodeName 的節點,指定的 nodeName 的節點可能從集群中移除)
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: tomcat-deploy
spec:
replicas: 1
template:
metadata:
labels:
app: tomcat-app
spec:
nodeName: k8s.node1 # 指定調度節點為k8s.node1
containers:
- name: tomcat
image: tomcat:8.0
ports:
- containerPort: 8080
2、節點選擇器 nodeSelector
nodeSelector 是 PodSpec 中的一個字段。指定了一組名值對。節點的 labels 中必須包含 Pod 的 nodeSelector 中所有的名值對,該節點才可以運行此 Pod。最普遍的用法中, nodeSelector 只包含一個鍵值對。
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: tomcat-deploy
spec:
replicas: 1
template:
metadata:
labels:
app: tomcat-app
spec:
nodeSelector:
cloudnil.com/role: dev #指定調度節點為帶有label標記為:cloudnil.com/role=dev的node節點
containers:
- name: tomcat
image: tomcat:8.0
ports:
- containerPort: 8080
3、Node isolation/restriction (限制/隔離)
向節點對象添加標簽后,可以將 Pod 指定到特定(一個或一組)的節點,以便確保某些 Pod 只在具備某些隔離性、安全性或符合管理規定的節點上運行
如果將標簽用於這個目的,推薦選擇那些不會被 kubelet 修改的標簽。這樣做可以避免節點非法使用其 kubelet credential 來設置節點自己的標簽,進一步影響到調度器將工作負載調度到該節點上。
NodeRestriction
管理插件可以阻止 kubelet 設置或者修改節點上以 node-restriction.kubernetes.io/
開頭的標簽。如需要使用該標簽前綴作為節點隔離的目的,需要:
-
確保 kubenetes 已經啟用了 Node authorizer 和 NodeRestriction admission plugin
-
添加帶
node-restriction.kubernetes.io/
前綴的標簽到節點對象,並將這些標簽作為 Pod 中的節點選擇器。
例如:
example.com.node-restriction.kubernetes.io/fips=true
或者example.com.node-restriction.kubernetes.io/pci-dss=true
4、Affinity and anti-affinity (親和性和反親和性)
Node affinity概念上與nodeSelector相似,通過選擇標簽的方式,可以限制pod被調度到特定的節點上。
主要有以下幾個優點:
- 語法更具表現力(不僅僅支持“與(AND)"完全匹配)
- 可以指明規則是“soft/preference”而不是強制要求,所以如果不滿足調度條件,pods依然可以被調度。
- 可以將規則限制在運行在一個節點上的pods(或其他拓撲域),而不僅僅是節點本身,這將允許pods是否可以調度到同一個節點。
目前支持兩種類型的node affinity,
requiredDuringSchedulingIgnoredDuringExecution (強制)
preferredDuringSchedulingIgnoredDuringExecution (非強制)
某種意義上,前者指定了要將pod調度到節點上必須滿足的規則(像nodeSelector,但使用了更具表現力的語法),而后者試圖調度到特定的節點但不能保證一定會調度到該節點。
其中,“IgnoredDuringExecution”表示如果在pod運行時節點的標簽發生改變導致無法滿足pods創建時使用的調度規則,pod會繼續在該節點上運行,這點與nodeSelector相似。