k8s常見管理


一、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 中的 imagePullPolicyAlways
  • 省略 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/ 開頭的標簽。如需要使用該標簽前綴作為節點隔離的目的,需要:

例如: 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被調度到特定的節點上。

主要有以下幾個優點:

  1. 語法更具表現力(不僅僅支持“與(AND)"完全匹配)
  2. 可以指明規則是“soft/preference”而不是強制要求,所以如果不滿足調度條件,pods依然可以被調度。
  3. 可以將規則限制在運行在一個節點上的pods(或其他拓撲域),而不僅僅是節點本身,這將允許pods是否可以調度到同一個節點。

目前支持兩種類型的node affinity,

requiredDuringSchedulingIgnoredDuringExecution (強制)
preferredDuringSchedulingIgnoredDuringExecution (非強制)

某種意義上,前者指定了要將pod調度到節點上必須滿足的規則(像nodeSelector,但使用了更具表現力的語法),而后者試圖調度到特定的節點但不能保證一定會調度到該節點。

其中,“IgnoredDuringExecution”表示如果在pod運行時節點的標簽發生改變導致無法滿足pods創建時使用的調度規則,pod會繼續在該節點上運行,這點與nodeSelector相似。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM