1.查看節點的日志信息:journalctl -u kubelet -n 1000
2.查看對應deployment的pod數量,並對其進行設置:kubectl get deployments & kubectl scale deployment nginx-deployment --replicas
3.node節點加入k8s集群:kubeadm join --token 1f627e.a37793601a406d7e 10.0.1.22:6443 --discovery-token-ca-cert-hash sha256:e12a8e1d1be7d308dad31bebdb2684d9d4ba7e5ae290f4fd1f855089b1abe71a
4.K8S給node設置污點策略:
kubectl taint nodes node1 key=value:NoSchedule --新的不能容忍的pod不能再調度過來,但是老的運行在node上不受影響
kubectl taint nodes node1 key=value:NoExecute --新的不能容忍的pod不能調度過來,老的pod也會被驅逐
kubectl taint nodes node1 key=value:PreferNoSchedule --pod會嘗試將pod分配到該節點
5.K8S如何給節點去除對應的污點:kubectl taint nodes master key:NoExecute-
6.重啟kubelet:systemctl restart kubelet.service
7.設置kubelet開機自啟動:systemctl enable kubelet.service
8.查看k8s存在的命名空間:kubectl get namespaces
9.查看命名空間里的服務:kubectl get services --namespace=logging
10.查看系統中所運行的容器:kubectl get po -n kube-system -o wide
11.查看對應的錯誤日志:kubectl describe pod XXX -n kube-system
12.K8S的pod調度策略:
可以參考鏈接詳細學習:https://www.qikqiak.com/post/kubernetes-affinity-scheduler/
nodeSelector調度:強制調度pod到某個節點上
親和性和反親和性調度:
nodeAffinity(節點親和性)、podAffinity(pod 親和性) 以及 podAntiAffinity(pod 反親和性)
親和性調度可以分成軟策略和硬策略兩種方式:
- 軟策略就是如果你沒有滿足調度要求的節點的話,pod 就會忽略這條規則,繼續完成調度過程,說白了就是滿足條件最好了,沒有的話也無所謂了的策略
- 硬策略就比較強硬了,如果沒有滿足條件的節點的話,就不斷重試直到滿足條件為止,簡單說就是你必須滿足我的要求,不然我就不干的策略。
對於親和性和反親和性都有這兩種規則可以設置: preferredDuringSchedulingIgnoredDuringExecution和requiredDuringSchedulingIgnoredDuringExecution,前面的就是軟策略,后面的就是硬策略。
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution: # 硬策略
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: NotIn
values:
- node03
preferredDuringSchedulingIgnoredDuringExecution: # 軟策略
- weight: 1
preference:
matchExpressions:
- key: com
operator: In
values:
- youdianzhishi
nodeSelectorTerms屬性類型
- In:label 的值在某個列表中
- NotIn:label 的值不在某個列表中
- Gt:label 的值大於某個值
- Lt:label 的值小於某個值
- Exists:某個 label 存在
- DoesNotExist:某個 label 不存在
如果nodeSelectorTerms下面有多個選項的話,滿足任何一個條件就可以了;如果matchExpressions有多個選項的話,則必須同時滿足這些條件才能正常調度 POD。
13.k8s pod erro exit code 137 :該錯誤碼表示node節點的內存不足
14.開啟代理協議端口:kubectl proxy --address='192.168.30.30' --port=8888 --accept-hosts='^*$' &
15.K8s中yaml的資源類型(kind字段)
工作負載型資源對象(workload):POD,ReplicaSet,Deployment,StatefulSet,DaemonSet,Job,Cronjob ...
服務發現及均衡資源對象:Service,Ingress ...
配置與存儲資源對象:Volume(存儲卷),CSI(容器存儲接口,可以擴展各種各樣的第三方存儲卷),ConfigMap,Secret,DownwardAPI
集群級資源:Namespace,Node,Role,ClusterRole,RoleBinding,ClusterRoleBinding
元數據型資源:HPA,PodTemplate,LimitRange
16.K8S中存儲卷volume的類型
一.本地存儲
1,EmptyDir
如果在此目錄中創建刪除文件,都將對容器中的/data目錄有影響,如果刪除Pod,文件將全部刪除,即使是在宿主機上創建的文件也是如此,在宿主機上刪除容器則k8s會再自動創建一個容器,此時文件仍然存在。
2.HostDir
在宿主機上指定一個目錄,掛載到Pod的容器中,其實跟上面的寫法不盡相同,這里只截取不同的部分,當pod刪除時,本地仍然保留文件
二.網絡數據卷(NFS)
1.NFS
如何加入NFS文件系統
# 安裝nfs服務
[root@nfs01 ~]# yum install nfs-utils rpcbind
# 創建nfs掛載目錄
[root@nfs01 ~]# mkdir /data/volums/data01/ -p
# 啟動服務
[root@nfs01 ~]# systemctl start rpcbind
[root@nfs01 ~]# systemctl enable rpcbind
[root@nfs01 ~]# systemctl start nfs-server
[root@nfs01 ~]# systemctl enable nfs-server
# 配置nfs服務
[root@nfs01 ~]# cat /etc/exports
/data/volums/data01 *(async,insecure,no_root_squash,no_subtree_check,rw)
# 查看nfs狀態
[root@nfs01 ~]# showmount -e 192.168.17.195
Export list for 192.168.17.195:
/data/volums/data01 192.168.17.0/24
注意:對應的節點需要安裝客戶端:yum install nfs-utils
采用nfc存儲的yaml樣例
spec:
containers:
- name: web
image: nginx
imagePullPolicy: Never #如果已經有鏡像,就不需要再拉取鏡像
ports:
- name: web
containerPort: 80
hostPort: 80 #將容器的80端口映射到宿主機的80端口
volumeMounts:
- name : nfs #指定名稱必須與下面一致
mountPath: "/usr/share/nginx/html" #容器內的掛載點
volumes:
- name: nfs #指定名稱必須與上面一致
nfs: #nfs存儲
server: 192.168.30.32 #nfs服務器ip或是域名
path: "/nfs-data" #nfs服務器共享的目錄
在/test目錄中創建index.html文件后,這個文件也將在容器中生效,當Pod刪除時,文件不受影響,實現了數據持久化。
三. Persistent Volume(PV)和Persistent Volume Claim(PVC)
其實這兩種數據卷也屬於網絡數據卷,單拎出來是因為我覺得這個比前面的數據卷要酷多了,有種大數據,雲平台的意思,當用戶要使用數據存儲的時候他是否還需要知道是什么類型的數據存儲,答案是不需要,用戶只想要安全可靠的數據存儲,而且實現起來很簡單,管理員建立一個存儲平台,用戶按自己的需求消費就可以了
PersistentVolume (PV) 是外部存儲系統中的一塊存儲空間,由管理員創建和維護。與 Volume 一樣,PV 具有持久性,生命周期獨立於 Pod。
PersistentVolumeClaim (PVC) 是對 PV 的申請 (Claim)。PVC 通常由普通用戶創建和維護。需要為 Pod 分配存儲資源時,用戶可以創建一個 PVC,指明存儲資源的容量大小和訪問模式(比如只讀)等信息,Kubernetes 會查找並提供滿足條件的 PV。
靜態Pvc的示例
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: efk-pvc
namespace: kube-system #注意pvc所在的命名空間和所引用的pod需要在同一個
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 2Gi
storageClassName: efk-nfs
pod如何引用pvc
volumeMounts:
- name: elasticsearch-logging
mountPath: /data
env:
- name: "NAMESPACE"
valueFrom:
fieldRef:
fieldPath: metadata.namespace
volumes:
- name: elasticsearch-logging
persistentVolumeClaim:
claimName: efk-pvc
具體創建和使用參考:
https://blog.51cto.com/forall/2135152
動態pvc的使用
創建和使用參考鏈接:https://blog.51cto.com/goome/2423200
過程中遇到的問題
nfs-client-provisioner這個pod一直報錯error retrieving resource lock default/fuseim.pri-ifs: Unauthorized
最后參考鏈接
https://github.com/kubernetes-incubator/external-storage/issues/953
把下面這段替換rbac.yaml文件就行,大概的原因是rbac分配給nfs-client的權限不夠
kind: ClusterRoleapiVersion: rbac.authorization.k8s.io/v1metadata:
name: efs-provisioner-runnerrules:
- apiGroups: [""]
resources: ["persistentvolumes"]
verbs: ["get", "list", "watch", "create", "delete"]
- apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get", "list", "watch", "update"]
- apiGroups: ["storage.k8s.io"]
resources: ["storageclasses"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["events"]
verbs: ["list", "watch", "create", "update", "patch"]
- apiGroups: [""]
resources: ["endpoints"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
不再需要再創建pod前先申請pvc然后再掛載進pod,可以通過在部署pod的yaml文件中采用StatefulSet
statefulset,可以翻譯成有狀態的設定.
和deployment的對比
deployment部署創建的pod是無狀態的,重新調度pod,pod名字hostname,啟動pod順序刪除pod順序都是隨機的.deployment使用的是共享存儲,所有pod共用一個存儲卷.
statefulset部署創建的pod是有狀態的,重新調度pod,pod名字hostname保持固定不變,啟動pod順序刪除pod順序都可以根據定義的順序有序執行操作,有序的動態更新,statefulset使用的存儲,不是共用一個存儲卷,一個pod對應一個存儲卷(pv).pod重新創建調度掛載的存儲卷保持不變.
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: statefulset-testspec:
serviceName: headless-svc
replicas: 3
selector:
matchLabels:
app: headless-pod
template:
metadata:
labels:
app: headless-pod
spec:
containers:
- image: httpd
name: myhttpd
ports:
- containerPort: 80
name: httpd
volumeMounts:
- mountPath: /mnt
name: test
volumeClaimTemplates:
- metadata:
name: test
annotations:
volume.beta.kubernetes.io/storage-class: managed-nfs-storage
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 100Mi
accessModes
用於定義資源的訪問方式,受限於存儲底層的支持,訪問方式包括以下幾種:
ReadWriteOnce – 被單個節點mount為讀寫rw模式
ReadOnlyMany – 被多個節點mount為只讀ro模式
ReadWriteMany – 被多個節點mount為讀寫rw模式
17.K8S進入pod中:kubectl exec -ti curl-6bf6db5c4f-hm96f -n default -- /bin/sh
18.K8S的service介紹
service是一個抽象概念,定義了一個服務的多個pod邏輯合集和訪問pod的策略,一般把service稱為微服務
服務類型
ClusterIP:
分配一個內部集群IP地址,只能在集群內部訪問(同Namespace內的Pod),默認ServiceType。
Service對象在Cluster IP range池中分配到的IP只能在內部訪問,如果服務作為一個應用程序內部的層次,還是很合適的。如果這個Service作為前端服務,准備為集群外的客戶提供業務,我們就需要給這個服務提供公共IP了。
NodePort:
分配一個內部集群IP地址,並在每個節點上啟用一個端口來暴露服務,可以在集群外部訪問。
訪問地址:<NodeIP>:<NodePort>
LoadBalancer:
分配一個內部集群IP地址,並在每個節點上啟用一個端口來暴露服務。
除此之外,Kubernetes會請求底層雲平台上的負載均衡器,將每個Node([NodeIP]:[NodePort])作為后端添加進去。
service的類型
ClusterIP 默認模式,只能在集群內部訪問
NodePort 在每個節點上都監聽一個同樣的端口號(30000-32767),ClusterIP和路由規則會自動創建。集群外部可以訪問<NodeIP>:<NodePort>聯系到集群內部服務,可以配合外部負載均衡使用(我現在公司用的就是這個模式配合阿里雲的SLB)
LoadBalancer 要配合支持公有雲負載均衡使用比如GCE、AWS。其實也是NodePort,只不過會把<NodeIP>:<NodePort>自動添加到公有雲的負載均衡當中
ExternalName 創建一個dns別名指到service name上,主要是防止service name發生變化,要配合dns插件使用,用戶可以指定一個任意的名字,作為該service被解析的CNAME,這種類型的servcie不用指定clusterIP,因此kube-proxy不會管理這類service,這類service需要使用1.7版本以上的kubedns。比如用戶想創建一個service,但要讓所有容器訪問該service的請求都引導到用戶自己定義的外部域名服務,就可以通過這個方式實現。可以說這個是最自由的一個方式:你希望服務被如何解析,服務就能被如何解析。你甚至可以給多個service配置同一個externalName。
---
kind: Service
apiVersion: v1
metadata:
name: mysql-5-7-01-service
spec:
type: ExternalName
externalName: ai-production-mysql-bot.cfyipcsxzevb.rds.cn-northwest-1.amazonaws.com.cn
---
通過上面創建的servicename去訪問對應的aws上的mysql服務
集群中容器訪問集群外部服務
DNS
Service type:ExternalName
在Docker環境中,由於Docker Engine自帶 DNS Server,我們使用容器名來訪問其它容器,因為容器是不穩定的,當容器宕掉,再重新啟動相同鏡像的容器,IP地址會改變,所以我們不使用IP訪問其它容器;同樣的,在Kubernetes集群中,由於我們使用 kube-DNS,我們常用Service名稱來訪問某個服務,Service資源對象能保證其背后的容器副本始終是最新的IP。
因此,我們可以利用這個特性,對Service名稱和外部服務地址做一個映射,使之訪問Service名稱既是訪問外部服務。例如下面的例子是將 svc1 和 xxx.xxx.xxx.xxx 做了對等關系。
kind: Service
apiVersion: v1
metadata:
name: svc1
namespace: default
spec:
type: ExternalName
externalName: somedomain.org
設置 Service 的 EndPoint
在Kubernetes集群中,同一個微服務的不同副本會對集群內或集群外(取決於服務對外暴露類型)暴露統一的服務名稱,一個服務背后是多個 EndPoint,EndPoint解決映射到某個容器的問題,在 EndPoint 中不僅可以指定集群內容器的IP,還可以指定集群外的IP,我們可以利用這個特性使用集群外部的服務。
EndPoint 方式的缺點是只能指定IP,不能使用網址,比如網址,比如RDS的地址,這種情況下只能使用ExternalName來解決。
apiVersion: v1
kind: Service
metadata:
name: mysql-production
spec:
ports:
- port: 3306
---
kind: Endpoints
apiVersion: v1
metadata:
name: mysql-production
namespace: default
subsets:
- addresses:
- ip: 192.168.1.25
ports:
- port: 3306
總結
本文介紹了集群內部訪問外部服務的兩種方法,ExternalName 類型的服務適用於外部服務使用域名的方式,缺點是不能指定端口;而EndPoint的方式適合於外部服務是IP的情況,但是可以指定端口。根據需要使用吧!
19. K8S中pod的內存和cpu設置
下面是如何給一個pod分配cpu和內存
在Kubernetes系統上,l個單位的CPU相當於虛擬機上的l顆虛擬CPU(vCPU)或物理機上的一個超線程(Hyperthread,或稱為一個邏輯CPU),它支持分數計量方式,一個核心(1core)相當於1000個微核心(millicores),因此500m相當於是0.5個核心
apiVersion: v1
kind: Pod
metadata:
name: memory-demo
spec:
containers:
- name: memory-demo-ctr
image: vish/stress
resources:
limits:
memory: "200Mi"
requests:
memory: "100Mi"
args:
- -mem-total
- 150Mi
- -mem-alloc-size
- 10Mi
- -mem-alloc-sleep
- 1s
超出容器的內存限制報錯
NAME READY STATUS RESTARTS AGE
memory-demo-2 0/1 OOMKilled 1 24s
配置超出節點能力范圍的內存申請,pod會一直處於pending狀態
kubectl get pod memory-demo-3 --namespace=mem-example
NAME READY STATUS RESTARTS AGE
memory-demo-3 0/1 Pending 0 25s
查看具體報錯信息如下
Events:
... Reason Message
------ -------
... FailedScheduling No nodes are available that match all of the following predicates:: Insufficient memory (3).
如果不配置內存限制
如果不給容器配置內存限制,那下面的任意一種情況可能會出現:
容器使用內存資源沒有上限,容器可以使用當前節點上所有可用的內存資源。
容器所運行的命名空間有默認內存限制,容器會自動繼承默認的限制。
內存申請和限制的原因
通過配置容器的內存申請和限制,你可以更加有效充分的使用集群里內存資源。配置較少的內存申請, 可以讓Pod跟任意被調度。設置超過內存申請的限制,可以達到以下效果:
Pod可以在負載高峰時更加充分利用內存。
可以將Pod的內存使用限制在比較合理的范圍。
20. 強制刪除pod: kubectl delete po <your-pod-name> -n <name-space> --force --grace-period=0
21. K8S的鏡像拉取策略
Always 總是拉取鏡像
IfNotPresent 本地有則使用本地鏡像,不拉取
Never 只使用本地鏡像,從不拉取,即使本地沒有
如果省略imagePullPolicy 鏡像tag為 :latest 策略為always ,否則 策略為 IfNotPresent
22. Pod健康檢測機制
對於Pod的健康狀態檢測,kubernetes提供了兩類探針(Probe)來執行對Pod的健康狀態檢測:
- LivenessProbe探針:
用於判斷容器是否存活,即Pod是否為running狀態,如果LivenessProbe探針探測到容器不健康,則kubelet將kill掉容器,並根據容器的重啟策略是否重啟,如果一個容器不包含LivenessProbe探針,則Kubelet認為容器的LivenessProbe探針的返回值永遠成功。 - ReadinessProbe探針:
用於判斷容器是否啟動完成,即容器的Ready是否為True,可以接收請求,如果ReadinessProbe探測失敗,則容器的Ready將為False,控制器將此Pod的Endpoint從對應的service的Endpoint列表中移除,從此不再將任何請求調度此Pod上,直到下次探測成功。
每類探針都支持三種探測方法:
- exec:通過執行命令來檢查服務是否正常,針對復雜檢測或無HTTP接口的服務,命令返回值為0則表示容器健康。
- httpGet:通過發送http請求檢查服務是否正常,返回200-399狀態碼則表明容器健康。
- tcpSocket:通過容器的IP和Port執行TCP檢查,如果能夠建立TCP連接,則表明容器健康。
探針探測的結果有以下三者之一:
- Success:Container通過了檢查。
- Failure:Container未通過檢查。
- Unknown:未能執行檢查,因此不采取任何措施。