一、Kubernetes中的排程流程
1,介紹
Scheduler 是 k8s 中的排程器,主要的任務是把定義的 Pod 分配到叢集的節點上。Scheduler 是作為一個單獨的程式執行的,啟動之後會一直監聽 apiserver。聽起來很簡單,但有很多要考慮的問題:
- 公平:如何保證每個節點都能被分配資源。
- 資源利用率高:叢集所有資源最大化被使用。
- 效率:排程的效能要好,能夠儘快的對大批量的 Pod 完成排程工作。
- 靈活:允許使用者根據自己的需求控制排程邏輯。
排程過程分為幾個部分:
2,親和性
親和性策略,可以設定 Pod 在建立時更傾向建立在哪個節點上。其有兩個維度可設定:
- 節點親和性:設定節點的相關資訊,在建立 Pod 的時候與節點資訊進行匹配。
- Pod 親和性:設定 Pod 的相關資訊,在建立 Pod 的時候與已存在的 Pod 資訊進行匹配。
不管是節點親和性還是 Pod 親和性,其設定策略中都有 軟策略
和 硬策略
兩種方案。
- 軟策略(preferredDuringSchedulingIgnoredDuringExecution):Pod 傾向於建立在某個節點上,如果條件不符合,可以建立在其它節點上。
- 硬策略(requiredDuringSchedulingIgnoredDuringExecution):Pod 必須被建立某個節點上,如果條件不符合,那麼 Pod 會一直處於 pending 狀態。
a)節點親和性
軟策略示例
apiVersion: v1 kind: Pod metadata: name: node-pre-pod spec: containers: - name: nginx-container image: hub.xcc.com/my-xcc/my-nginx:v1 ports: - containerPort: 80 affinity: nodeAffinity: #親和性 preferredDuringSchedulingIgnoredDuringExecution: #軟策略 - weight: 1 #權重值 preference: matchExpressions: #匹配表示式 - key: kubernetes.io/hostname #節點標籤名 operator: In #操作運算關係符 values: #標籤值 - worker01
硬策略示例
apiVersion: v1 kind: Pod metadata: name: node-req-pod spec: containers: - name: nginx-container image: hub.xcc.com/my-xcc/my-nginx:v1 ports: - containerPort: 80 affinity: nodeAffinity: #節點親和性 requiredDuringSchedulingIgnoredDuringExecution: #硬策略 nodeSelectorTerms: - matchExpressions: - key: kubernetes.io/hostname operator: NotIn values: -worker01
兩個策略組合。這樣的Pod會先匹配符合硬策略的節點,然後在匹配符合軟策略的節點。
apiVersion: v1 kind: Pod metadata: name: node-pod spec: containers: - name: nginx-container image: hub.xcc.com/my-xcc/my-nginx:v1 ports: - containerPort: 80 affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: kubernetes.io/hostname operator: NotIn values: - worker01 preferredDuringSchedulingIgnoredDuringExecution: - weight: 1 preference: matchExpressions: - key: kubernetes.io/hostname operator: In values: - worker02
b)Pod親和性
- podAffinity:Pod 與指定的 Pod 在同一拓撲域。
- podAntiAffinity:Pod 與指定的 Pod 不在同一拓撲域。
拓撲域:使用 topologyKey
屬性(下方示例中有)定義的值,通俗來講就是節點的標籤。
示例
apiVersion: v1 kind: Pod metadata: name: pod-aff-pod spec: containers: - name: nginx-container image: hub.xcc.com/my-xcc/my-nginx:v1 ports: - containerPort: 80 affinity: podAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: pod-name operator: In values: - nginx-pod topologyKey: kubernetes.io/hostname podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 1 podAffinityTerm: labelSelector: matchExpressions: - key: pod-name operator: In valuses: - nginx-pod topologyKey: kubernetes.io/hostname
排程策略 | 匹配標籤 | 操作符 | 拓撲域支援 | 排程目標 |
---|---|---|---|---|
nodeAffinity | 主機 | In、NotIn、Exists、DoesNotExist、Gt、Lt | 否 | 指定主機 |
podAffinity | Pod | In、NotIn、Exists、DoesNotExist | 是 | Pod 與指定 Pod 在同一拓撲域 |
podAnitAffinity | Pod | In、NotIn、Exists、DoesNotExist | 是 | Pod 與指定 Pod 不在同一拓撲域 |
3,汙點和容忍
汙點(taint)和容忍(toleration)相互相互配合,可以用來避免 Pod 被分配到不適合的節點上。每個節點可以有0個或者多個 taint,這表示對於那些不能容忍這些 taint 的 Pod,是不會被建立在這些節點上的。如果將 toleration 應用於 Pod 上,則表示這些 Pod 可以被排程到具有匹配 taint 的節點上。
通俗來講,就是節點上可以設定汙點(taint),如果建立 Pod 時不設定 Pod 的容忍(toleration)的話,那麼該 Pod 就不可能被建立在有汙點的節點上。master 節點預設有一個汙點,這也就是為什麼前面我們建立的 Pod 一直沒有被建立在 master 節點上的原因。
kubectl get node kubectl describe node master01 ...... Taints: node-role.kubernetes.io/master:NoSchedule ......
a)汙點
key=value:effect
-
key=value:每一個汙點都有一個 key 和 value 作為 汙點的標籤,其中 value 可以為空,即 key:effect。我們上面列出的 master 預設汙點就是這種格式。
-
effect:描述汙點的作用,支援以下三種選項:
- NoSchedule:k8s 不會將 Pod 排程到具有該汙點的 Node 上。
- PreferNoSchedule:k8s 儘量避免將 Pod 排程到具有該汙點的 Node 上。
- NoExecute:k8s 不會將 Pod 排程到具有該汙點的 Node 上,同時會將 Node 上已存在的 Pod 驅逐出去。
注意:上面描述的前提是所有 Pod 是沒有設定容忍的。
設定、去除汙點
# 設定汙點 kubectl taint nodes node01 check=test:NoSchedule # 去除汙點,只需要在最後加一個 '-' kubectl taint nodes node01 check=test:NoSchedule- # 檢視某個node的汙點,其結果中的 Taints 欄位便是汙點 kubectl describe node node01
設定多master防止資源浪費
kubectl taint nodes <node-name> node-role.kubernetes.io/master=:PreferNoSchedule
b)容忍
設定了汙點的 node 將根據汙點的作用(effect)與 Pod 之間產生互斥的關係。但是我們可以在建立 Pod 時為 Pod 設定容忍,意味著 Pod 在建立時可以容忍汙點的存在,可以被排程到存在汙點的 node 上。
spec: tolerations: - effect: "NoSchedule" key: "key" operator: "Exists" tolerationSeconds: 3600 value: "value"
-
key、value、effect:需要與 node 上的汙點標籤資訊一致。
-
operator:表示 key 與 value 的關係。
- Exists:忽略 value 的值,只要 key 匹配上即可。
- Equal:預設為 Equal。
-
tolerationSeconds:如果 effect 的值為 Noexecute,那麼 tolerationSeconds 表示 Pod 在被驅逐之前還可以保留執行的時間。
#當不指定 key 時,表示容忍所有的汙點 key spec: tolerations: - operator: "Exists" #當不指定 effect 時,表示容忍所有的汙點作用 spec: tolerations: - key: "key" operator: "Exists"
4,指定排程節點
如果你想要指定 Pod 被排程到具體的 node 上,那麼你可以這樣做
kind: Pod spec: nodeName: node01 #將 Pod 直接排程到指定的 node 節點上,會跳過 Scheduler 的排程策略,是強制匹配 # 或者 spec: nodeSelector: #通過 k8s 的 label-selector 機制選擇節點,由排程器策略匹配 label,而後排程 Pod 到目標節點上,該匹配規則屬於強制約束。 kubernetes.io/hostname: node01
二、Kubernetes中的認證、鑑權和准入控制
1,機制說明
Kubernetes作為一個分散式叢集的管理工具,保證叢集的安全性是一個重要的任務。API Server是叢集內部各元件通訊的中介,也是外部控制的入口。所以Kubernetes的安全機制基本就是圍繞保護API Server來設計的。Kubernetes使用了認證(Authetication)、鑑權(Authorization)、准入控制(Admission Control)三步來保證API Server的安全。
2,認證(Authentication)
-
HTTP Token 認證:通過一個 Token 來識別合法使用者
-
HTTP Base 認證:通過 使用者名稱+密碼 的方式認證(base64加密)
-
最嚴格的 HTTPS 證書認證:基於 CA 根證書籤名的客戶端身份認證方式
a)HTTPS 證書認證:
b)需要認證的節點
- Kubenetes 元件對 API Server 的訪問:kubectl、Controller Manager、Scheduler、kubelet、kube-proxy
- Kubernetes 管理的 Pod 對容器的訪問:Pod(dashborad 也是以 Pod 形式執行)
- Controller Manager、Scheduler 與 API Server 在同一臺機器,所以直接使用 API Server 的非安全埠訪問, --insecure-bind-address=127.0.0.1
- kubectl、kubelet、kube-proxy 訪問 API Server 就都需要證書進行 HTTPS 雙向認證
- 手動簽發:通過 k8s 叢集的跟 ca 進行簽發 HTTPS 證書
- 自動簽發:kubelet 首次訪問 API Server 時,使用 token 做認證,通過後,Controller Manager 會為kubelet 生成一個證書,以後的訪問都是用證書做認證了
c)kubeconfig
d)ServiceAccount
e)Secret 與 SA 的關係
- token是使用 API Server 私鑰簽名的 JWT。用於訪問API Server時,Server端認證
- ca.crt,根證書。用於Client端驗證API Server傳送的證書
- namespace, 標識這個service-account-token的作用域名空間
kubectl get secret --all-namespaces
kubectl describe secret default-token-5gm9r --namespace=kube-system
3,授權(Authorization)
上面認證過程,只是確認通訊的雙方都確認了對方是可信的,可以相互通訊。而鑑權是確定請求方有哪些資源的許可權。API Server 目前支援以下幾種授權策略 (通過 API Server 的啟動引數 “--authorization-mode” 設定)。
- AlwaysDeny:表示拒絕所有的請求,一般用於測試
- AlwaysAllow:允許接收所有請求,如果叢集不需要授權流程,則可以採用該策略
- ABAC(Attribute-Based Access Control):基於屬性的訪問控制,表示使用使用者配置的授權規則對使用者請求進行匹配和控制
- Webbook:通過呼叫外部 REST 服務對使用者進行授權
- RBAC(Role-Based Access Control):基於角色的訪問控制,現行預設規則
4,RBAC授權模式
- 對叢集中的資源和非資源均擁有完整的覆蓋
- 整個 RBAC 完全由幾個 API 物件完成,同其它 API 物件一樣,可以用 kubectl 或 API 進行操作
- 可以在執行時進行調整,無需重啟 API Server
a)RBAC 的 API 資源物件說明
b)Role和ClusterRole
kind: Role apiVersion: rbac.authorization.k8s.io/v1beta1 metadata: namespace: default name: pod-reader rules: - apiGroups: [""] # "" indicates the core API group resources: ["pods"] verbs: ["get", "watch", "list"]
ClusterRole 具有與 Role 相同的許可權角色控制能力,不同的是 ClusterRole 是叢集級別的,ClusterRole 可以用於:
- 叢集級別的資源控制( 例如 node 訪問許可權 )
- 非資源型 endpoints( 例如 /healthz 訪問 )
- 所有名稱空間資源控制(例如 pods )
kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1beta1 metadata: # "namespace" omitted since ClusterRoles are not namespaced name: secret-reader rules: - apiGroups: [""] resources: ["secrets"] verbs: ["get", "watch", "list"]
c)RoleBinding和ClusterRoleBinding
kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1beta1 metadata: name: read-pods namespace: default subjects: - kind: User name: jane apiGroup: rbac.authorization.k8s.io roleRef: kind: Role name: pod-reader apiGroup: rbac.authorization.k8s.io
kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1beta1 metadata: name: read-secrets namespace: development # 只能訪問 development 空間中的 secrets(因為 RoleBinding 定義在 development 名稱空間) subjects: - kind: User name: dave apiGroup: rbac.authorization.k8s.io roleRef: kind: ClusterRole # RoleBinding 引用了一個 ClusterRole name: secret-reader #這個 ClusterRole 具有整個叢集內對 secrets 的訪問許可權 apiGroup: rbac.authorization.k8s.io
使用 ClusterRoleBinding 可以對整個叢集中的所有名稱空間資源許可權進行授權;以下 ClusterRoleBinding 樣例展示了授權 manager 組內所有使用者在全部名稱空間中對 secrets 進行訪問 。
#允許在manger的Group組中的每個人都可以去讀取任意namespace下的secrets kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1beta1 metadata: name: read-secrets-global subjects: - kind: Group name: manager apiGroup: rbac.authorization.k8s.io roleRef: kind: ClusterRole name: secret-reader #餘ClusterRole對應 apiGroup: rbac.authorization.k8s.io
d)Resources
Kubernetes 叢集內一些資源一般以其名稱字串來表示,這些字串一般會在 API 的 URL 地址中出現;同時某些資源也會包含子資源,例如 logs 資源就屬於 pods 的子資源,API 中 URL 樣例如下
GET /api/v1/namespaces/{namespace}/pods/{name}/log
kind: Role apiVersion: rbac.authorization.k8s.io/v1beta1 metadata: namespace: default name: pod-and-pod-logs-reader rules: - apiGroups: [""] resources: ["pods/log"] verbs: ["get", "list"]
5,實踐(建立使用者管理dev空間)
{ "CN": "devuser", #定義使用者 "hosts": [ ], "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "CN", "ST": "BeiJing", "L": "BeiJing", "O": "k8s", #定義Group組 "OU": "System" } ] }
下載證書工具
wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64 mv cfssl_linux-amd64 /usr/local/bin/cfssl wget https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64 mv cfssljson_linux-amd64 /usr/local/bin/cfssljson wget https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64 mv cfssl-certinfo_linux-amd64 /usr/local/bin/cfssl-certinfo
#建立使用定義的json檔案 cfssl gencert -ca=ca.crt -ca-key=ca.key -profile=kubernetes /root/devuser-csr.json | cfssljson -bare devuser
設定叢集引數
export KUBE_APISERVER="https://172.20.0.113:6443" kubectl config set-cluster kubernetes \ --certificate-authority=/etc/kubernetes/ssl/ca.pem \ --embed-certs=true \ --server=${KUBE_APISERVER} \ --kubeconfig=devuser.kubeconfig
kubectl config set-credentials devuser \ --client-certificate=/etc/kubernetes/ssl/devuser.pem \ --client-key=/etc/kubernetes/ssl/devuser-key.pem \ --embed-certs=true \ --kubeconfig=devuser.kubeconfig
設定上下文引數
kubectl config set-context kubernetes \ --cluster=kubernetes \ --user=devuser \ --namespace=dev \ --kubeconfig=devuser.kubeconfig
設定預設上下文
kubectl config use-context kubernetes --kubeconfig=devuser.kubeconfig cp -f ./devuser.kubeconfig /root/.kube/config
建立rolebinding繫結
# 在名為”dev”的名字空間中將admin ClusterRole授予使用者”devuser”
kubectl create rolebinding devuser-admin-binding --clusterrole=admin --user=devuser -- namespace=dev
6,准入控制(Admission Control)
官方文件上有一份針對不同版本的准入控制器推薦列表,其中最新的 1.14 的推薦列表是:
NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,Mutat ingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota
- NamespaceLifecycle: 防止在不存在的 namespace 上建立物件,防止刪除系統預置 namespace,刪除
- namespace 時,連帶刪除它的所有資源物件。
- LimitRanger:確保請求的資源不會超過資源所在 Namespace 的 LimitRange 的限制。
- ServiceAccount: 實現了自動化新增 ServiceAccount。
- ResourceQuota:確保請求的資源不會超過資源的 ResourceQuota 限制。