Kubernetes pod調度約束[親和性 污點] 生命階段 排障手段

調度約束

Kubernetes 是通過 List-Watch 的機制進行每個組件的協作,保持數據同步的,每個組件之間的設計實現了解耦。

用戶是通過 kubectl 根據配置文件,向 APIServer 發送命令,在 Node 節點上面建立 Pod 和 Container。


APIServer 經過 API 調用,權限控制,調用資源和存儲資源的過程,實際上還沒有真正開始部署應用。這里?? ?需要 Controller Manager、Scheduler 和 kubelet 的協助才能完成整個部署過程。

在 Kubernetes 中,所有部署的信息都會寫到 etcd 中保存。實際上 etcd 在存儲部署信息的時候,會發送 Create 事件給 APIServer,而 APIServer 會通過監聽(Watch)etcd 發過來的事件。其他組件也會監聽(Watch)APIServer 發出來的事件。

K8S是通過 List-Watch 機制實現每個組件的協作
controller-manager、scheduler、kubelet 通過 List-Watch 機制監聽 apiserver 發出的事件,apiserver 通過 List-Watch 機制監聽 etcd 發出的事件?

Pod 是 Kubernetes 的基礎單元,Pod 啟動典型創建過程如下
(1)這里有三個 List-Watch,分別是 Controller Manager(運行在 Master),Scheduler(運行在 Master),kubelet(運行在 Node)。 他們在進程已啟動就會監聽(Watch)APIServer 發出來的事件。

(2)用戶通過 kubectl 或其他 API 客戶端提交請求給 APIServer 來建立一個 Pod 對象副本。

(3)APIServer 嘗試著將 Pod 對象的相關元信息存入 etcd 中,待寫入操作執行完成,APIServer 即會返回確認信息至客戶端。

(4)當 etcd 接受創建 Pod 信息以后,會發送一個 Create 事件給 APIServer。

(5)由于 Controller Manager 一直在監聽(Watch,通過https的6443端口)APIServer 中的事件。此時 APIServer 接受到了 Create 事件,又會發送給 Controller Manager。

(6)Controller Manager 在接到 Create 事件以后,調用其中的 Replication Controller 來保證 Node 上面需要創建的副本數量。一旦副本數量少于 RC 中定義的數量,RC 會自動創建副本。總之它是保證副本數量的 Controller(PS:擴容縮容的擔當)。

(7)在 Controller Manager 創建 Pod 副本以后,APIServer 會在 etcd 中記錄這個 Pod 的詳細信息。例如 Pod 的副本數,Container 的內容是什么。

(8)同樣的 etcd 會將創建 Pod 的信息通過事件發送給 APIServer。

(9)由于 Scheduler 在監聽(Watch)APIServer,并且它在系統中起到了“承上啟下”的作用,“承上”是指它負責接收創建的 Pod 事件,為其安排 Node;“啟下”是指安置工作完成后,Node 上的 kubelet 進程會接管后繼工作,負責 Pod 生命周期中的“下半生”。 換句話說,Scheduler 的作用是將待調度的 Pod 按照調度算法和策略綁定到集群中 Node 上。

(10)Scheduler 調度完畢以后會更新 Pod 的信息,此時的信息更加豐富了。除了知道 Pod 的副本數量,副本內容。還知道部署到哪個 Node 上面了。并將上面的 Pod 信息更新至 API Server,由 APIServer 更新至 etcd 中,保存起來。

(11)etcd 將更新成功的事件發送給 APIServer,APIServer 也開始反映此 Pod 對象的調度結果。

(12)kubelet 是在 Node 上面運行的進程,它也通過 List-Watch 的方式監聽(Watch,通過https的6443端口)APIServer 發送的 Pod 更新的事件。kubelet 會嘗試在當前節點上調用 Docker 啟動容器,并將 Pod 以及容器的結果狀態回送至 APIServer。

(13)APIServer 將 Pod 狀態信息存入 etcd 中。在 etcd 確認寫入操作成功完成后,APIServer將確認信息發送至相關的 kubelet,事件將通過它被接受。

#注意:在創建 Pod 的工作就已經完成了后,為什么 kubelet 還要一直監聽呢?原因很簡單,假設這個時候 kubectl 發命令,要擴充 Pod 副本數量,那么上面的流程又會觸發一遍,kubelet 會根據最新的 Pod 的部署情況調整 Node 的資源。又或者 Pod 副本數量沒有發生變化,但是其中的鏡像文件升級了,kubelet 也會自動獲取最新的鏡像文件并且加載。

調度過程

Scheduler 是 kubernetes 的調度器,主要的任務是把定義的 pod 分配到集群的節點上。其主要考慮的問題如下:
●公平:如何保證每個節點都能被分配資源
●資源高效利用:集群所有資源最大化被使用
●效率:調度的性能要好,能夠盡快地對大批量的 pod 完成調度工作
●靈活:允許用戶根據自己的需求控制調度的邏輯

Sheduler 是作為單獨的程序運行的,啟動之后會一直監聽 APIServer,獲取 spec.nodeName 為空的 pod,對每個 pod 都會創建一個 binding,表明該 pod 應該放到哪個節點上。

調度分為幾個部分:首先是過濾掉不滿足條件的節點,這個過程稱為預算策略(predicate);然后對通過的節點按照優先級排序,這個是優選策略(priorities);最后從中選擇優先級最高的節點。如果中間任何一步驟有錯誤,就直接返回錯誤。

Predicate 有一系列的常見的算法可以使用:(預選)
●PodFitsResources:節點上剩余的資源是否大于 pod 請求的資源。
●PodFitsHost:如果 pod 指定了 NodeName,檢查節點名稱是否和 NodeName 匹配。
●PodFitsHostPorts:節點上已經使用的 port 是否和 pod 申請的 port 沖突。
●PodSelectorMatches:過濾掉和 pod 指定的 label 不匹配的節點。
●NoDiskConflict:已經 mount 的 volume 和 pod 指定的 volume 不沖突,除非它們都是只讀。

如果在 predicate 過程中沒有合適的節點,pod 會一直在 pending 狀態,不斷重試調度,直到有節點滿足條件。 經過這個步驟,如果有多個節點滿足條件,就繼續 priorities 過程:按照優先級大小對節點排序。

優先級由一系列鍵值對組成,鍵是該優先級項的名稱,值是它的權重(該項的重要性)。有一系列的常見的優先級選項包括:(優選)
●LeastRequestedPriority:通過計算CPU和Memory的使用率來決定權重,使用率越低權重越高。也就是說,這個優先級指標傾向于資源使用比例更低的節點。
●BalancedResourceAllocation:節點上 CPU 和 Memory 使用率越接近,權重越高。這個一般和上面的一起使用,不單獨使用。比如 node01 的 CPU 和 Memory 使用率 20:60,node02 的 CPU 和 Memory 使用率 50:50,雖然 node01 的總使用率比 node02 低,但 node02 的 CPU 和 Memory 使用率更接近,從而調度時會優選 node02。
●ImageLocalityPriority:傾向于已經有要使用鏡像的節點,鏡像總大小值越大,權重越高。

通過算法對所有的優先級項目和權重進行計算,得出最終的結果。

scheduler 的調度策略

預選策略/預算策略

通過調度算法過濾掉不滿足條件的Node節點,如果沒有滿足條件的Node節點,Pod會處于Pending狀態,直到有符合條件的Node節點出現
PodFitsResources、PodFitsHost、PodFitsHostPorts、PodSelectorMatches、NoDiskConflict

優選策略

根據優先級選項為滿足預選策略條件的Node節點進行優先級權重排序,最終選擇優先級最高的Node節點來調度Pod
LeastRequestedPriority、BalancedResourceAllocation、ImageLocalityPriority

指定調度節點

Pod 調度到指定的 Node節點

  1. 使用 nodeName 字段指定 Node節點名稱
  2. 使用 nodeSelector 指定 Node節點的標簽
  3. 使用 節點/Pod 親和性
  4. 使用 污點+容忍?

●pod.spec.nodeName (節點名)將 Pod 直接調度到指定的 Node 節點上,會跳過 Scheduler 的調度策略,該匹配規則是強制匹配

vim myapp.yamlapiVersion: apps/v1 ?
kind: Deployment ?
metadata:name: myapp
spec:replicas: 3selector:matchLabels:app: myapptemplate:metadata:labels:app: myappspec:nodeName: node01 #這里指定節點名containers:- name: myappimage: nginxports:- containerPort: 80
kubectl apply -f myapp.yaml
kubectl get pods -o wideNAME ? ? ? ? ? ? ? ? ? ? READY ? STATUS ? ?RESTARTS ? AGE ? IP ? ? ? ? ? ?NODE ? ? NOMINATED NODE ? READINESS GATES
myapp-6bc58d7775-6wlpp ? 1/1 ? ? Running ? 0 ? ? ? ? ?14s ? 10.244.1.25 ? node01 ? <none> ? ? ? ? ? <none>
myapp-6bc58d7775-szcvp ? 1/1 ? ? Running ? 0 ? ? ? ? ?14s ? 10.244.1.26 ? node01 ? <none> ? ? ? ? ? <none>
myapp-6bc58d7775-vnxlp ? 1/1 ? ? Running ? 0 ? ? ? ? ?14s ? 10.244.1.24 ? node01 ? <none> ? ? ? ? ? <none>

//查看詳細事件(發現未經過 scheduler 調度分配)

kubectl describe pod myapp-6bc58d7775-6wlpp......Type ? ?Reason ? Age ? From ? ? ? ? ? ? Message---- ? ?------ ? ---- ?---- ? ? ? ? ? ? -------Normal ?Pulled ? 95s ? kubelet, node01 ?Container image "nginx" already present on machineNormal ?Created ?99s ? kubelet, node01 ?Created container nginxNormal ?Started ?99s ? kubelet, node01 ?Started container nginx

●pod.spec.nodeSelector:通過 kubernetes 的 label-selector 機制選擇節點(根據標簽),由調度器調度策略匹配 label,然后調度 Pod 到目標節點,該匹配規則屬于強制約束

//獲取標簽幫助

kubectl label --helpUsage:kubectl label [--overwrite] (-f FILENAME | TYPE NAME) KEY_1=VAL_1 ... KEY_N=VAL_N [--resource-version=version] [options]

//需要獲取 node 上的 NAME 名稱

kubectl get nodeNAME ? ? STATUS ? ROLES ? ?AGE ? VERSION
master ? Ready ? ?master ? 30h ? v1.20.11
node01 ? Ready ? ?<none> ? 30h ? v1.20.11
node02 ? Ready ? ?<none> ? 30h ? v1.20.11

//給對應的 node 設置標簽分別為 mylabel=a 和 mylabel=b

kubectl label nodes node01 mylabel=akubectl label nodes node02 mylabel=b

//查看標簽

kubectl get nodes --show-labelsNAME ? ? STATUS ? ROLES ? ?AGE ? VERSION ? LABELS
master ? Ready ? ?master ? 30h ? v1.20.11 ? beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=master,kubernetes.io/os=linux,node-role.kubernetes.io/master=
node01 ? Ready ? ?<none> ? 30h ? v1.20.11 ? beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,mylabel=a,kubernetes.io/arch=amd64,kubernetes.io/hostname=node01,kubernetes.io/os=linux
node02 ? Ready ? ?<none> ? 30h ? v1.20.11 ? beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,mylabel=b,kubernetes.io/arch=amd64,kubernetes.io/hostname=node02,kubernetes.io/os=linux

//修改成 nodeSelector 調度方式

vim myapp1.yamlapiVersion: apps/v1
kind: Deployment ?
metadata:name: myapp1
spec:replicas: 3selector:matchLabels:app: myapp1template:metadata:labels:app: myapp1spec:nodeSelector: #這里指定節點標簽mylabel: acontainers:- name: myapp1image: nginxports:- containerPort: 80
kubectl apply -f myapp1.yaml

查看pods,都根據指定的節點擁有的標簽分配到了node1上?

kubectl get pods -o wideNAME ? ? ? ? ? ? ? ? ? ? READY ? STATUS ? ?RESTARTS ? AGE ? IP ? ? ? ? ? ?NODE ? ? NOMINATED NODE ? READINESS GATES
myapp1-58cff4d75-52xm5 ? 1/1 ? ? Running ? 0 ? ? ? ? ?24s ? 10.244.1.29 ? node01 ? <none> ? ? ? ? ? <none>
myapp1-58cff4d75-f747q ? 1/1 ? ? Running ? 0 ? ? ? ? ?24s ? 10.244.1.27 ? node01 ? <none> ? ? ? ? ? <none>
myapp1-58cff4d75-kn8gk ? 1/1 ? ? Running ? 0 ? ? ? ? ?24s ? 10.244.1.28 ? node01 ? <none> ? ? ? ? ? <none>

//查看詳細事件(通過事件可以發現要先經過 scheduler 調度分配)

kubectl describe pod myapp1-58cff4d75-52xm5Events:Type ? ?Reason ? ? Age ? From ? ? ? ? ? ? ? Message---- ? ?------ ? ? ---- ?---- ? ? ? ? ? ? ? -------Normal ?Scheduled ?57s ? default-scheduler ?Successfully assigned default/myapp1-58cff4d75-52xm5 to node01Normal ?Pulled ? ? 57s ? kubelet, node01 ? ?Container image "nginx" already present on machineNormal ?Created ? ?56s ? kubelet, node01 ? ?Created container myapp1Normal ?Started ? ?56s ? kubelet, node01 ? ?Started container myapp1



//修改一個 label 的值,需要加上 --overwrite 參數

kubectl label nodes node02 mylabel=a --overwrite

//刪除一個 label,只需在命令行最后指定 label 的 key 名并與一個減號相連即可:

kubectl label nodes node02 mylabel-

//指定標簽查詢 node 節點

kubectl get node -l mylabel=a

標簽的管理操作

???添加標簽

kubectl label <資源類型> <資源名稱> ?標簽key=標簽value

更改標簽
kubectl label <資源類型> <資源名稱> ?標簽key=標簽value --overwrite

去除標簽
kubectl label <資源類型> <資源名稱> ?標簽key-

查看pod具有的標簽

kubectl get <資源類型> <資源名稱> --show-labels

查看具有特定標簽的pod
kubectl get <資源類型> -l 標簽key[=標簽value]


親和性

一個新創建的pod,想要被調度到指定的節點,或是與另一個pod存在于相同的拓撲域中,即為親和性

https://kubernetes.io/zh/docs/concepts/scheduling-eviction/assign-pod-node/

節點親和性的策略
pod.spec.nodeAffinity

  • preferredDuringSchedulingIgnoredDuringExecution:軟策略
  • requiredDuringSchedulingIgnoredDuringExecution:硬策略

Pod 親和性
pod.spec.affinity.podAffinity/podAntiAffinity

  • preferredDuringSchedulingIgnoredDuringExecution:軟策略
  • requiredDuringSchedulingIgnoredDuringExecution:硬策略

硬策略(required....)

強制性的滿足指定條件,如果沒有滿足條件的Node節點,Pod會處于Pending狀態,直到有符合條件的Node節點出現

軟策略(preferred....)

非強制性的,會優先選擇滿足條件的Node節點調度,即使沒有滿足條件的Node節點,Pod依然會完成調度

可以把自己理解成一個Pod,當你報名來學云計算,如果你更傾向去zhangsan老師帶的班級,把不同老師帶的班級當作一個node的話,這個就是節點親和性。如果你是必須要去zhangsan老師帶的班級,這就是硬策略;而你說你想去并且最好能去zhangsan老師帶的班級,這就是軟策略。
如果你有一個很好的朋友叫lisi,你傾向和lisi同學在同一個班級,這個就是Pod親和性。如果你一定要去lisi同學在的班級,這就是硬策略;而你說你想去并且最好能去lisi同學在的班級,這就是軟策略。軟策略是不去也可以,硬策略則是不去就不行。

親和性

節點親和性(nodeAffinity)

匹配指定的Node節點標簽,將要部署的Pod調度到滿足條件的Node節點上

Pod親和性(podAffinity)

匹配指定的Pod標簽,將要部署的Pod調度到與指定Pod所在的Node節點處于 同一個拓撲域 的Node節點上

Pod反親和性(podAntiAffinity)

匹配指定的Pod標簽,將要部署的Pod調度到與指定Pod所在的Node節點處于 不同的拓撲域 的Node節點上

如何判斷是否在同一個拓撲域?

看拓撲域key(topologyKey),如果有其它Node節點擁有與指定Pod所在的Node節點相同的 拓撲域key的標簽key和value,那么它們就在同一個拓撲域 (下文會演示實例)

鍵值運算關系
●In:label 的值在某個列表中
●NotIn:label 的值不在某個列表中
●Gt:label 的值大于某個值
●Lt:label 的值小于某個值
●Exists:某個 label 存在
●DoesNotExist:某個 label 不存在

kubectl get nodes --show-labels
NAME ? ? STATUS ? ROLES ? ?AGE ? VERSION ? LABELS
master ? Ready ? ?master ? 11d ? v1.20.11 ? beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=master,kubernetes.io/os=linux,node-role.kubernetes.io/master=
node01 ? Ready ? ?<none> ? 11d ? v1.20.11 ? beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=node01,kubernetes.io/os=linux
node02 ? Ready ? ?<none> ? 11d ? v1.20.11 ? beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=node02,kubernetes.io/os=linux

節點親和性?

//requiredDuringSchedulingIgnoredDuringExecution:硬策略?

mkdir /opt/affinity
cd /opt/affinity
vim pod1.yamlapiVersion: v1
kind: Pod
metadata:name: affinitylabels:app: node-affinity-pod
spec:containers:- name: with-node-affinityimage: nginxaffinity:         #親和性nodeAffinity:   #節點親和性requiredDuringSchedulingIgnoredDuringExecution:  #硬策略nodeSelectorTerms:- matchExpressions:#- key: kubernetes.io/hostname ? ?#指定node的標簽(這里是key)- key: mylabel        #指定mylabel:a(node1擁有的標簽)operator: NotIn ? ? #設置Pod安裝到kubernetes.io/hostname的標簽值不在values列表中的node上values: #這里是key里的值 - a#- node02

設置了節點親和 硬策略。指定了node1 上自定義的標簽 mylabel:a 代表要去node1.?

kubectl apply -f pod1.yaml
kubectl get pods -o wideNAME ? ? ? READY ? STATUS ? ?RESTARTS ? AGE ? IP ? ? ? ? ? ?NODE ? ? NOMINATED NODE ? READINESS GATES
affinity ? 1/1 ? ? Running ? 0 ? ? ? ? ?13s ? 10.244.1.30 ? node01 ? <none> ? ? ? ? ? <none>
kubectl delete pod --all && kubectl apply -f pod1.yaml && kubectl get pods -o wide

如果硬策略不滿足條件,Pod 狀態一直會處于 Pending 狀態。

preferredDuringSchedulingIgnoredDuringExecution:軟策略

vim pod2.yaml
apiVersion: v1
kind: Pod
metadata:name: affinitylabels:app: node-affinity-pod
spec:containers:- name: with-node-affinityimage: nginxaffinity:nodeAffinity:preferredDuringSchedulingIgnoredDuringExecution:- weight: 1 ? #如果有多個軟策略選項的話,權重越大,優先級越高preference:matchExpressions:- key: kubernetes.io/hostnameoperator: Invalues:- node03

這里軟策略指定分配到node03,但是沒有這個節點!于是被分配到node1或是2上。?

kubectl apply -f pod2.yaml
kubectl get pods -o wideNAME ? ? ? READY ? STATUS ? ?RESTARTS ? AGE ? IP ? ? ? ? ? ?NODE ? ? NOMINATED NODE ? READINESS GATES
affinity ? 1/1 ? ? Running ? 0 ? ? ? ? ?5s ? ?10.244.2.35 ? node02 ? <none> ? ? ? ? ? <none>

//把values:的值改成node01,則會優先在node01上創建Pod

kubectl delete pod --all && kubectl apply -f pod2.yaml && kubectl get pods -o wide

//如果把硬策略和軟策略合在一起使用,則要先滿足硬策略之后才會滿足軟策略
//示例:

apiVersion: v1
kind: Pod
metadata:name: affinitylabels:app: node-affinity-pod
spec:containers:- name: with-node-affinityimage: nginxaffinity:nodeAffinity:requiredDuringSchedulingIgnoredDuringExecution: ? #先滿足硬策略,排除有kubernetes.io/hostname=node02標簽的節點nodeSelectorTerms:- matchExpressions:- key: kubernetes.io/hostnameoperator: NotInvalues:- node02preferredDuringSchedulingIgnoredDuringExecution: ?#再滿足軟策略,優先選擇有mylabel=a標簽的節點(node1)- weight: 1preference:matchExpressions:- key: mylabeloperator: Invalues:- a

由于優先滿足硬策略,排除node2。然后滿足軟策略,選擇自定義標簽mylabel=a的節點。于是選擇了node1。?

Pod親和性與反親和性

調度策略?? ??? ??? ?匹配標簽?? ?操作符?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?拓撲域支持?? ??? ?調度目標
nodeAffinity?? ??? ?主機?? ??? ?In, NotIn, Exists,DoesNotExist, Gt, Lt?? ??? ?否?? ??? ??? ??? ?指定主機
podAffinity?? ??? ??? ?Pod?? ??? ??? ?In, NotIn, Exists,DoesNotExist?? ??? ??? ??? ?是?? ??? ??? ??? ?Pod與指定Pod同一拓撲域
podAntiAffinity?? ??? ?Pod?? ??? ??? ?In, NotIn, Exists,DoesNotExist?? ??? ??? ??? ?是?? ??? ??? ??? ?Pod與指定Pod不在同一拓撲域

將兩個節點自定義標簽mylabel都設置為a(若拓撲域選擇mylabel則兩節點同一拓撲域)

將兩個節點自定義標簽difftop一個a一個b(若拓撲域選擇difftop則兩節點處于不同拓撲域)

kubectl label nodes node1 mylabel=a
kubectl label nodes node2 mylabel=akubectl label nodes node1 difftop=a
kubectl label nodes node2 difftop=b

//創建一個標簽為 app=myapp01 的 Pod(作為pod2的親和項)

vim pod3.yamlapiVersion: v1
kind: Pod
metadata:name: myapp01labels:app: myapp01
spec:containers:- name: with-node-affinityimage: nginx
kubectl apply -f pod3.yaml
kubectl get pods --show-labels -o wideNAME ? ? ?READY ? STATUS ? ?RESTARTS ? AGE ? IP ? ? ? ? ? NODE ? ? NOMINATED NODE ? READINESS GATES ? LABELS
myapp01 ? 1/1 ? ? Running ? 0 ? ? ? ? ?37s ? 10.244.2.3 ? node01 ? <none> ? ? ? ? ? <none> ? ? ? ? ? ?app=myapp01

//使用 Pod 親和性調度,創建多個 Pod 資源

vim pod4.yamlkind: Deployment
metadata:name: myapp02
spec:replicas: 3selector:matchLabels:app: myapp02template:metadata:labels:app: myapp02spec:containers:- name: myapp02image: nginxports:- containerPort: 80affinity:podAffinity: #節點親和requiredDuringSchedulingIgnoredDuringExecution: #硬需求- labelSelector: #標簽選擇器,指定需要親和的pod標簽matchExpressions:- key: app #指定需要親和的pod標簽的keyoperator: Invalues:- myapp01 #指定需要親和的pod標簽key的值topologyKey: mylabel #指定拓撲域mylabel (兩個節點相同)這里指定了mylabel標簽作為拓撲域,由于node1,node2都設置了mylabel=a,值相同都為a,所以處于同一拓撲域,會在node1,或是node2,生成pod。拓撲域用于劃定pod生成的節點范圍。

topologyKey 是節點標簽的鍵。如果兩個節點使用此鍵標記并且具有相同的標簽值,則調度器會將這兩個節點視為處于同一拓撲域中。 調度器試圖在每個拓撲域中放置數量均衡的 Pod。
#如果?mylabel 對應的值不一樣就是不同的拓撲域。比如 Pod1 在?mylabel =a?的 Node 上Pod2 在?mylabel =b?的 Node 上Pod3 在?mylabel =a?的 Node 上,則 Pod2Pod1、Pod3 不在同一個拓撲域,而Pod1 和 Pod3在同一個拓撲域。

kubectl apply -f pod4.yaml

由于這里設置兩個node擁有的標簽 mylabel =?a 值一致,所以這兩個node在同一個拓撲域。

  1. 老的pod生成在的node2具有標簽mylabel=a
  2. 由于配置了新pod親和拓撲域為mylabel
  3. 于是新的pod 選擇同樣值為a的mylabel? ?的節點(node1或是node2,都有同樣的值,都在同一個拓撲域),在這個兩個節點上平均創建新pod
kubectl get pods --show-labels -o wideNAME                       READY   STATUS    RESTARTS   AGE     IP            NODE    NOMINATED NODE   READINESS GATES   LABELS
myapp01                    1/1     Running   0          10m     10.244.2.35   node2   <none>           <none>            app=myapp01
myapp02-76975f4869-cdtcn   1/1     Running   0          4m16s   10.244.2.36   node2   <none>           <none>            app=myapp02,pod-template-hash=76975f4869
myapp02-76975f4869-qdpjj   1/1     Running   0          4m16s   10.244.2.37   node2   <none>           <none>            app=myapp02,pod-template-hash=76975f4869
myapp02-76975f4869-xs7fj   1/1     Running   0          4m16s   10.244.1.36   node1   <none>           <none>            app=myapp02,pod-template-hash=76975f4869
myapp02-95d4fc876-jbb2h    1/1     Running   0          74s     10.244.1.38   node1   <none>           <none>            app=myapp02,pod-template-hash=95d4fc876
myapp02-95d4fc876-l75bx    1/1     Running   0          74s     10.244.2.38   node2   <none>           <none>            app=myapp02,pod-template-hash=95d4fc876
myapp02-95d4fc876-sqfl5    1/1     Running   0          74s     10.244.1.37   node1   <none>           <none>            app=myapp02,pod-template-hash=95d4fc876

?

更改拓撲域為difftop (兩個節點不同)

vim pod4.yamlapiVersion: v1
kind: Pod
metadata:name: myapp02labels:app: myapp02
spec:containers:- name: myapp02image: nginxaffinity:podAffinity:requiredDuringSchedulingIgnoredDuringExecution:- labelSelector:matchExpressions:- key: appoperator: Invalues:- myapp01topologyKey: difftop #?指定拓撲域difftop (兩個節點不同)
#?kubectl delete -f pod4.yaml #刪除剛剛的kubectl apply -f pod4.yaml #創建更改過的

由于這里設置兩個node擁有的標簽 difftop =?a (node1)difftop =?b(node2) 值不一致,所以這兩個node不在同一個拓撲域。

  1. 老的pod生成在的node1具有標簽difftop =?a
  2. 由于配置了新pod親和拓撲域為difftop
  3. 于是新的pod 選擇同樣值為a的difftop 的節點(只有node1是difftop=a,不與node2在同一個拓撲域),在node1上創建新pod

kubectl get pods --show-labels -o wideNAME                      READY   STATUS    RESTARTS   AGE    IP            NODE    NOMINATED NODE   READINESS GATES   LABELS
myapp01                   1/1     Running   0          2m2s   10.244.1.42   node1   <none>           <none>            app=myapp01
myapp02-c559f76f5-5hhlk   1/1     Running   0          43s    10.244.1.45   node1   <none>           <none>            app=myapp02,pod-template-hash=c559f76f5
myapp02-c559f76f5-79lf4   1/1     Running   0          43s    10.244.1.43   node1   <none>           <none>            app=myapp02,pod-template-hash=c559f76f5
myapp02-c559f76f5-fttk7   1/1     Running   0          43s    10.244.1.44   node1   <none>           <none>            app=myapp02,pod-template-hash=c559f76f5

//使用 Pod 反親和性調度
示例1:

vim pod5.yamlapiVersion: v1
kind: Pod
metadata:name: myapp10labels:app: myapp10
spec:containers:- name: myapp10image: nginxaffinity:podAntiAffinity:  #反親和preferredDuringSchedulingIgnoredDuringExecution:  #軟限制- weight: 100podAffinityTerm:
#          namespaces:  #若指定pod的命名空間
#          - defaultlabelSelector:matchExpressions:- key: appoperator: Invalues:- myapp01#topologyKey: kubernetes.io/hostname #根據主機名topologyKey: difftop  #根據自定義標簽difftop中兩個node值分別為a,b 兩個節點在不同的拓撲域

指定舊的pod(app?myapp01,目前位于node1,difftop=a) ,

由于設置了反親和,

新的pod會生成在與舊pod不同的 拓撲域上(node2,difftop=b)。

kubectl apply -f pod5.yaml
kubectl get pods --show-labels -o wideNAME ? ? ?READY ? STATUS ? ?RESTARTS ? AGE ? IP ? ? ? ? ? NODE ? ? NOMINATED NODE ? READINESS GATES ? LABELS
myapp01 ? 1/1 ? ? Running ? 0 ? ? ? ? ?44m ? 10.244.1.3 ? node01 ? <none> ? ? ? ? ? <none> ? ? ? ? ? ?app=myapp01
myapp10 ? 1/1 ? ? Running ? 0 ? ? ? ? ?75s ? 10.244.2.4 ? node02 ? <none> ? ? ? ? ? <none> ? ? ? ? ? ?app=myapp03


示例2:若硬限制反親和(必須,不像軟限制一樣盡量),并且沒有除了指定拓撲域以外的任何其他拓撲域的節點,會直接pending等待資源

vim pod6.yamlapiVersion: v1
kind: Pod
metadata:name: myapp20labels:app: myapp20
spec:containers:- name: myapp20image: nginxaffinity:podAntiAffinity:requiredDuringSchedulingIgnoredDuringExecution:- labelSelector:matchExpressions:- key: appoperator: Invalues:- myapp01topologyKey: mylabel

指定舊的pod(myapp01,位于node1,mylabel=a

由于設置了反親和,需要找到拓撲域mylabel值不為a的節點創建pod(但是node1,node2兩個節點的mylabel都是a,處于同一個拓撲域。此時沒有其他的拓撲域

并且設置了硬限制,此時沒有資源于是直接進入pending等待資源。(如果是軟限制則滿足不了就將就一下,盡量選一個能滿足的,硬限制就只能滿足)

kubectl get pod --show-labels -owideNAME ? ? ? ? ?READY ? STATUS ? ?RESTARTS ? AGE ? ? IP ? ? ? ? ? ?NODE ? ? NOMINATED NODE ? READINESS GATES ? LABELS
myapp01 ? ? ? 1/1 ? ? Running ? 0 ? ? ? ? ?43s ? ? 10.244.1.68 ? node01 ? <none> ? ? ? ? ? <none> ? ? ? ? ? ?app=myapp01
myapp20 ? ? ? 0/1 ? ? Pending ? 0 ? ? ? ? ?4s ? ? ?<none> ? ? ? ?<none> ? <none> ? ? ? ? ? <none> ? ? ? ? ? ?app=myapp03

此時將node2的mylabel改為b(與node1的mylabel=a區分開,使得成為兩個不同的拓撲域)?

kubectl label nodes node02 mylabel=b --overwrite

這樣反親和就能在 不是處于myapp01的拓撲域(mylabel=a【node1節點】)的其他拓撲域(mylabel=b【node2節點】)上生成pod

kubectl get pod --show-labels -o wideNAME ? ? ? ? ?READY ? STATUS ? ?RESTARTS ? AGE ? ? IP ? ? ? ? ? ?NODE ? ? NOMINATED NODE ? READINESS GATES ? LABELS
myapp01 ? ? ? 1/1 ? ? Running ? 0 ? ? ? ? ?7m40s ? 10.244.1.68 ? node01 ? <none> ? ? ? ? ? <none> ? ? ? ? ? ?app=myapp01
myapp21 ? ? ? 1/1 ? ? Running ? 0 ? ? ? ? ?7m1s ? ?10.244.2.65 ? node02 ? <none> ? ? ? ? ? <none> ? ? ? ? ? ?app=myapp03

污點(Taint) 和 容忍(Tolerations)

污點(Taint)?

節點親和性,是Pod的一種屬性(偏好或硬性要求),它使Pod被吸引到一類特定的節點。Taint 則相反,它使節點能夠排斥一類特定的 Pod。
Taint 和 Toleration 相互配合,可以用來避免 Pod 被分配到不合適的節點上。每個節點上都可以應用一個或多個 taint ,這表示對于那些不能容忍這些 taint 的 Pod,是不會被該節點接受的。如果將 toleration 應用于 Pod 上,則表示這些 Pod 可以(但不一定)被調度到具有匹配 taint 的節點上。

使用 kubectl taint 命令可以給某個 Node 節點設置污點,Node 被設置上污點之后就和 Pod 之間存在了一種相斥的關系,可以讓 Node 拒絕 Pod 的調度執行,甚至將 Node 已經存在的 Pod 驅逐出去。

污點的組成格式如下:

key=value:effectsuch like:
mycheck=xue:NoSchedule
tadcx=sino:PreferNoSchedule

每個污點有一個 key 和 value 作為污點的標簽,其中 value 可以為空,effect 描述污點的作用。?

當前 taint effect 支持如下三個選項

  • NoSchedule:表示 k8s 將不會將 Pod 調度到具有該污點的 Node 上
  • PreferNoSchedule:表示 k8s 將盡量避免將 Pod 調度到具有該污點的 Node 上
  • NoExecute:表示 k8s 將不會將 Pod 調度到具有該污點的 Node 上,同時會將 Node 上已經存在的 Pod 驅逐出去

master 就是因為有 NoSchedule 污點,k8s 才不會將 Pod 調度到 master 節點上

kubectl get nodesNAME ? ? STATUS ? ROLES ? ?AGE ? VERSION
master ? Ready ? ?master ? 11d ? v1.20.11
node01 ? Ready ? ?<none> ? 11d ? v1.20.11
node02 ? Ready ? ?<none> ? 11d ? v1.20.11
kubectl describe node master
......
Taints: ? ? ? ? ? ? node-role.kubernetes.io/master:NoSchedule

#設置污點

kubectl taint node node01 key1=value1:NoSchedule#鍵值隨意取名,效果注意即可。
node01將不會被調度在其上面生成pod完整命令
kubectl taint node <node名稱>  key=value:effectNoSchedule(一定不會被調度)PreferNoSchedule(盡量不被調度) NoExecute(不會被調度,并驅逐節點上的Pod)

?#節點說明中,查找 Taints 字段

kubectl describe node [node-name]
kubectl describe nodes  <node名稱>  | grep Taints

#去除污點 末尾添上 -

kubectl taint node node01 key1:NoSchedule-
kubectl taint node <node名稱>  key[=value:effect]-

NoExecute選項還會額外驅逐已經存在的pod

kubectl get pods -o wideNAME ? ? ?READY ? STATUS ? ?RESTARTS ? AGE ? ? IP ? ? ? ? ? NODE ? ? NOMINATED NODE ? READINESS GATES
myapp01 ? 1/1 ? ? Running ? 0 ? ? ? ? ?4h28m ? 10.244.2.3 ? node02 ? <none> ? ? ? ? ? <none>
myapp02 ? 1/1 ? ? Running ? 0 ? ? ? ? ?4h13m ? 10.244.2.4 ? node02 ? <none> ? ? ? ? ? <none>
myapp03 ? 1/1 ? ? Running ? 0 ? ? ? ? ?3h45m ? 10.244.1.4 ? node01 ? <none> ? ? ? ? ? <none>
kubectl taint node node02 check=mycheck:NoExecute#鍵值隨意取名,效果注意即可。

//查看 Pod 狀態,會發現 node02 上的 Pod 已經被全部驅逐

注:如果是 Deployment 或者 StatefulSet 資源類型,為了維持副本數量則會在別的 Node 上再創建新的 Pod。

? ? ? ?如果是直接創建的pod沒有創建deploy等控制器,則寄了就是寄了。

kubectl get pods -o wideNAME ? ? ?READY ? STATUS ? ?RESTARTS ? AGE ? ? IP ? ? ? ? ? NODE ? ? NOMINATED NODE ? READINESS GATES
myapp03 ? 1/1 ? ? Running ? 0 ? ? ? ? ?3h48m ? 10.244.1.4 ? node01 ? <none> ? ? ? ? ? <none>

容忍(Tolerations)

設置了污點的 Node 將根據 taint 的 effect:NoSchedule、PreferNoSchedule、NoExecute 和 Pod 之間產生互斥的關系,Pod 將在一定程度上不會被調度到 Node 上。但我們可以在 Pod 上設置容忍(Tolerations),意思是設置了容忍的 Pod 將可以容忍污點的存在,可以被調度到存在污點的 Node 上

設置node1的污點?NoExecute

kubectl taint node node01 check=mycheck:NoExecute#鍵值隨意取名,效果注意即可。

pod配置文件,此時還設置容忍?

vim pod3.yamlapiVersion: v1
kind: Pod
metadata:name: myapp01labels:app: myapp01
spec:containers:- name: with-node-affinityimage: nginx
kubectl apply -f pod3.yaml

//在兩個 Node 上都設置了污點后,此時 Pod 將無法創建成功

kubectl get pods -o wideNAME ? ? ?READY ? STATUS ? ?RESTARTS ? AGE ? IP ? ? ? NODE ? ? NOMINATED NODE ? READINESS GATES
myapp01 ? 0/1 ? ? Pending ? 0 ? ? ? ? ?17s ? <none> ? <none> ? <none> ? ? ? ? ? <none>

?更改pod配置文件,添加容忍?

vim pod3.yamlapiVersion: v1
kind: Pod
metadata:name: myapp01labels:app: myapp01
spec:containers:- name: with-node-affinityimage: soscscs/myapp:v1tolerations: #容忍- key: "check" #與污點的鍵值相對應 exist操作符時可以不寫operator: "Equal" #Equal(等于,精確打擊)或 Exists(存在,范圍打擊) value: "mycheck" #與污點的鍵值相對應  可以不寫effect: "NoExecute"  #NoSchedule|PreferNoSchedule|NoExecute 與上面指定污點的效果相對應 exist操作符時可以不寫tolerationSeconds: 3600 #容忍期限 超過時間就不忍了 可以不寫其中的 key、vaule、effect 都要與 Node 上設置的 taint 保持一致
operator 的值為 Exists 將會忽略 value 值,即存在即可
tolerationSeconds 用于描述當 Pod 需要被驅逐時可以在 Node 上繼續保留運行的時間
kubectl apply -f pod3.yaml

//在設置了容忍之后,Pod 創建成功

kubectl get pods -o wideNAME ? ? ?READY ? STATUS ? ?RESTARTS ? AGE ? IP ? ? ? ? ? NODE ? ? NOMINATED NODE ? READINESS GATES
myapp01 ? 1/1 ? ? Running ? 0 ? ? ? ? ?10m ? 10.244.1.5 ? node01 ? <none> ? ? ? ? ? <none>

其它注意事項
(1)當不指定 key 值時,表示容忍所有的污點 key

? tolerations:- operator: "Exists"
容忍所有污點,無論key與類型

?(2)當不指定 effect 值時,表示容忍所有的污點作用

? tolerations:- key: "mykey"operator: "Exists"
容忍所有包含mykey這個鍵的污點,無論類型

(3)有多個 Master 存在時,防止資源浪費,可以如下設置(設置盡量不調度模式,在master上也能調度pod。不太建議,master本來就很忙)

kubectl taint node [Master-Name] node-role.kubernetes.io/master=:PreferNoSchedule

(4)如果某個 Node 更新升級系統組件,為了防止業務長時間中斷,可以先在該 Node 設置 NoExecute 污點,把該 Node 上的 Pod 都驅逐出去?

kubectl taint node node01 check=mycheck:NoExecute

//此時如果別的 Node 資源不夠用,可臨時給 Master 設置 PreferNoSchedule 污點,讓 Pod 可在 Master 上臨時創建

kubectl taint node master node-role.kubernetes.io/master=:PreferNoSchedule

//待所有 Node 的更新操作都完成后,再去除污點

kubectl taint node node01 check=mycheck:NoExecute-
kubectl taint node master node-role.kubernetes.io/master=:NoSchedule

cordon 和 drain 用于節點維護時 不可調度與驅逐pod

這兩條命令專門用于做節點維護 (就是上面第四個升級的進階版。相比上面的手動設置污點驅逐,不用擔心pod已經設置了容忍)

cordon (設置不可調度)

##對節點執行維護操作:

kubectl get nodes

cordon?將 Node 標記為不可調度的狀態,這樣就不會讓新創建的 Pod 在此 Node 上運行

kubectl cordon 	<node名稱>
#該node將會變為SchedulingDisabled狀態

恢復?

kubectl uncordon  <node名稱>

drain(設置不可調度與驅逐 drain = cordon + NoSchedule)

kubectl drain 可以讓 Node 節點開始釋放所有 pod,并且不接收新的 pod 進程。drain 本意排水,意思是將出問題的 Node 下的 Pod 轉移到其它 Node 下運行

kubectl drain  <node名稱>  --ignore-daemonsets --delete-emptydir-data --force--ignore-daemonsets:無視 DaemonSet 管理下的 Pod。
DaemonSet是所有pod上都會創建的pod,多數情況為守護進程,類似網絡插件flannel。忽略,以免驅逐了守護進程導致故障
--delete-emptydir-data:如果有 mount local volume 的 pod,會強制殺掉該 pod。
--force:強制釋放不是控制器管理的 Pod。

注:執行 drain 命令,會自動做了兩件事情:

  1. 設定此 node 為不可調度狀態(cordon)
  2. evict(驅逐)了 Pod

恢復

kubectl uncordon 將 Node 標記為可調度的狀態

kubectl uncordon <NODE_NAME>


Pod啟動階段(相位 phase)【重中之重】

Pod 創建完之后,一直到持久運行起來,中間有很多步驟,也就有很多出錯的可能,因此會有很多不同的狀態。


一般來說,pod 這個過程包含以下幾個步驟

  1. 通過 scheduler 根據調度算法選擇一臺在最適合的 Node節點運行 Pod
  2. 拉取鏡像
  3. 掛載 存儲卷 等
  4. 創建并運行容器
  5. 根據容器的探針探測結果設置 Pod 狀態

phase 的可能狀態有 【pod生命周期五大狀態】【重中之重】

  • Pending表示APIServer創建了Pod資源對象并已經存入了etcd中,但是它并未被調度完成到node節點
    • 還沒有調度到某臺node上,或者仍然處于從倉庫下載鏡像的過程中,或者掛載存儲卷失敗。
  • RunningPod已經被調度到某節點之上,并且Pod中所有容器都已經被kubelet創建。至少有一個容器正在運行,或者正處于啟動或者重啟狀態(也就是說Running狀態下的Pod不一定能被正常訪問)。
  • Succeeded:有些pod不是長久運行的,比如job、cronjob,一段時間后Pod中的所有容器都被成功終止,并且不會再重啟。需要反饋任務執行的結果。(Completed)
  • FailedPod中的所有容器都已終止了,并且至少有一個容器異常退出。也就是說,容器以非0狀態退出或者被系統終止,比如 command 寫的有問題。(Error)
  • UnknownMaster節點的 controller-manager無法讀取 Pod 狀態,通常是Pod 所在的 Node 出了問題或失聯,從而導致 Pod 的狀態為 Unknow

Pod遵循預定義的生命周期,起始于Pending階段,如果至少其中有一個主要容器正常啟動,則進入Running階段,之后取決于Pod中是否有容器以失敗狀態結束而進入Succeeded或者Failed階段。

如何刪除 Unknown 狀態的 Pod ?

  • 從集群中刪除有問題的 Node(pod管不了就直接干node)。使用公有云時,kube-controller-manager 會在 VM 刪除后自動刪除對應的 Node。 而在物理機部署的集群中,需要管理員手動刪除 Node(kubectl delete node <node_name>)。
  • 被動等待 Node 恢復正常,Kubelet 會重新跟 kube-apiserver 通信確認這些 Pod 的期待狀態,進而再決定刪除或者繼續運行這些 Pod。
  • 主動刪除 Pod,通過執行 kubectl delete pod <pod_name> --grace-period=0 --force 強制刪除 Pod(不建議這種kill -9方式!容易丟失數據或崩潰)。但是這里需要注意的是,除非明確知道 Pod 的確處于停止狀態(比如 Node 所在 VM 或物理機已經關機),否則不建議使用該方法。特別是 StatefulSet 管理的 Pod,強制刪除容易導致腦裂或者數據丟失等問題。

K8S 中的排障手段?

//查看Pod事件

kubectl get pods
查看Pod運行狀態kubectl describe <資源類型|pods> <資源名稱>
查看資源的詳細信息和事件

//查看Pod日志(Failed狀態下)

kubectl logs <pod名稱> [-c <容器名>] [-p]
查看容器的進程日志 -c指定容器 -p查看容器重啟前日志

//進入Pod(狀態為running,但是服務沒有提供)

方法1
kubectl exec -it <pod名稱> [-c <容器名>] sh|bash
進入Pod容器,查看容器內部相關狀態信息方法2
kubectl debug -it <pod名稱> --image=<臨時容器的鏡像名> ?--target=<目標容器>
在Pod中創建臨時容器進入目標容器進行調試(因為一般鏡像為了極簡都會去掉常用命令)方法3
在Pod容器的宿主機使用nsenter轉換網絡等命名空間,直接在宿主機進入目標容器的命名空間進行調試

//查看集群信息

kubectl get nodes
查看Node節點的運行狀態kubectl get cs
查看Master組件的狀態

//發現集群狀態正常

kubectl cluster-info
查看集群信息

//查看kubelet日志發現

journalctl -xefu kubeletjournalctl -u kubelet -f
跟蹤查看Kubelet進程日志

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/36817.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/36817.shtml
英文地址,請注明出處:http://en.pswp.cn/news/36817.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

springcloud3 hystrix實現服務降級,熔斷,限流以及案例配置

一 hystrix的作用 1.1 降級&#xff0c;熔斷&#xff0c;限流 1.服務降級&#xff1a; A方案出現問題&#xff0c;切換到兜底方案B&#xff1b; 2.服務熔斷&#xff1a;觸發規則&#xff0c;出現斷電限閘&#xff0c;服務降級 3.服務限流&#xff1a;限制請求數量。 二 案例…

ES6學習-Symbol

Symbol 數據類型Symbol&#xff0c;表示獨一無二的值。 對象的屬性名可有兩種類型&#xff0c;一種是原來的字符串&#xff0c;另一種是新增的 Symbol 類型 可以保證不與其他屬性名產生沖突。 let s1 Symbol() let s2 Symbol() console.log(s1, s2, s1 s2)//Symbol() Sy…

liunx exercise

云計算作業 Linux DAY1 1、創建alan1用戶&#xff0c;并使用root用戶切換用戶至alan1用戶。&#xff08;兩種方式切換【加-與不加-】&#xff0c;并總結其效果&#xff09; [rootlocalhost ~]# useradd alan1 [rootlocalhost ~]# su alan1 [alan1localhost root]$ pwd /roo…

FPGA學習——驅動WS2812光源并進行動態顯示

文章目錄 一、WS2812手冊分析1.1 WS2812燈源特性及概述1.2 手冊重點內容分析1.2.1 產品概述1.2.2 碼型及24bit數據設計 二、系統設計2.1 模塊設計2.2 模塊分析2.2.1 驅動模塊2.2.1 數據控制模塊 三、IP核設置及項目源碼3.1 MIF文件設計3.2 ROM IP核調用3.3 FIFO IP核調用3.4 項…

源碼斷點分析Spring的占位符(Placeholder)是怎么工作的

項目中經常需要使用到占位符來滿足多環境不同配置信息的需求&#xff0c;比如&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <beans xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xmlns"http://www.springframe…

InnoDB文件物理結構解析7 - FIL_PAGE_SDI

在數據庫系統中&#xff0c;通常包含數據字典(data dictionary)用于記錄數據庫對象的元數據(表&#xff0c;分區&#xff0c;觸發器&#xff0c;存儲過程&#xff0c;函數的定義)&#xff0c;我們可以通過information_schema(i_s)數據庫下的視圖(view)或者SHOW語句來訪問數據字…

【愛書不愛輸的程序猿】CPOLAR+HFS,低成本搭建NAS

歡迎來到愛書不愛輸的程序猿的博客, 本博客致力于知識分享&#xff0c;與更多的人進行學習交流 通過HFS低成本搭建NAS&#xff0c;并內網穿透實現公網訪問 - cpolar 極點云 前言1.下載安裝cpolar1.1 設置HFS訪客1.2 虛擬文件系統 2. 使用cpolar建立一條內網穿透數據隧道2.1 保留…

(三) 搞定SOME/IP通信之CommonAPI庫

本章主要介紹在SOME/IP通信過程中的另外一個IPC通信利劍,CommonAPI庫,文章將從如下幾個角度讓讀者了解什么是CommonAPI, 以及庫在實際工作中的作用 SOME/IP通信之CommonAPI CommonAPI庫是什么CommonAPI庫的編譯寫個Demo實戰一下CommonAPI庫是什么 CommonAPI是GENIVI組織開發…

推出 Elasticsearch 查詢語言 (ES|QL)

作者&#xff1a;Costin Leau 我很高興地宣布&#xff0c;經過大約一年的開發&#xff0c;Elasticsearch 查詢語言 (ES|QL) 已準備好與世界共享&#xff0c;并已登陸 Elasticsearch 存儲庫。 ES|QL 是 Elasticsearch 原生的強大聲明性語言&#xff0c;專為可組合性、表現力和速…

Django-配置郵箱功能(一):使用django自帶的發送郵件功能

一、獲取郵箱授權碼 以QQ郵箱為例子&#xff1a; 1、進入到設置&#xff0c;找到賬戶 2、開啟POP3等服務&#xff0c;點擊管理服務 3、進入管理服務&#xff0c;生成授權碼 4、按照要求發送短信就可以了 5、將授權碼復制保存&#xff0c;離開界面就看不到了 二、django項目中…

2023上半年京東手機行業品牌銷售排行榜(京東數據平臺)

后疫情時代&#xff0c;不少行業都迎來消費復蘇&#xff0c;我國智能手機市場在今年上半年也實現溫和的復蘇&#xff0c;手機市場的出貨量回暖。 根據鯨參謀平臺的數據顯示&#xff0c;2023年上半年&#xff0c;京東平臺上手機的銷量為2830萬&#xff0c;環比增長約4%&#xf…

劍指 Offer ! 61. 撲克牌中的順子

參考資料&#xff1a;力扣K神的講解 劍指 Offer 61. 撲克牌中的順子 簡單 351 相關企業 從若干副撲克牌中隨機抽 5 張牌&#xff0c;判斷是不是一個順子&#xff0c;即這5張牌是不是連續的。2&#xff5e;10為數字本身&#xff0c;A為1&#xff0c;J為11&#xff0c;Q為12&…

引入三階失真的非線性放大器的模擬輸出及使用中值濾波器去除峰值研究(Matlab代碼實現)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;歡迎來到本博客????&#x1f4a5;&#x1f4a5; &#x1f3c6;博主優勢&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客內容盡量做到思維縝密&#xff0c;邏輯清晰&#xff0c;為了方便讀者。 ??座右銘&a…

【C/C++】STL queue 非線程安全接口,危險!

STL 中的 queue 是非線程安全的&#xff0c;一個組合操作&#xff1a;front(); pop() 先讀取隊首元素然后刪除隊首元素&#xff0c;若是有多個線程執行這個組合操作的話&#xff0c;可能會發生執行序列交替執行&#xff0c;導致一些意想不到的行為。因此需要重新設計線程安全的…

JVM 內存結構

1、方法區&#xff08;線程共享&#xff09; 存儲靜態變量(靜態方法、變量、代碼塊)、常量池、類信息 2、堆信息&#xff08;線程共享&#xff09; 存儲實例對象&#xff0c;例如 new 出來的對象信息 A a1 new A() 3、虛擬機棧&#xff08;線程隔離&#xff09; 每個線程的都有…

三、MySql表的操作

文章目錄 一、創建表&#xff08;一&#xff09;語法&#xff1a;&#xff08;二&#xff09;說明&#xff1a; 二、創建表案例&#xff08;一&#xff09;代碼&#xff1a;&#xff08;二&#xff09;說明&#xff1a; 三、查看表結構&#xff08;一&#xff09;語法&#xff…

docker相關命令總結(停止、重啟、重加載配置文件)

常用命令 # 配置 Docker 守護進程的行為和參數 vi /etc/docker/daemon.json# 停止docker服務 sudo systemctl stop docker# 啟動 Docker 服務&#xff1a; sudo systemctl start docker# 重新加載systemd守護程序的配置文件&#xff0c;不會重啟服務&#xff08;配置文件&…

Go語言template模板語法

Go語言模板語法 文章目錄 <center> Go語言模板語法連接前后端的符號: {{}}注釋管道(pipeline)變量條件判斷range 關鍵字with 關鍵字比較函數自定義函數嵌套模板模板繼承 連接前后端的符號: {{}} 模板語法都包含在{{}}之中,其中{{.}}中的.表示當前對象.在傳入一個結構體對…

sql-libs靶場-----0x00、環境準備

文章目錄 一、PhPstudy下載、安裝二、Sqli-libs下載、搭建三、啟用Sqli-libs phpstudy地址&#xff1a;https://www.xp.cn/ sqli-libs地址&#xff1a;https://github.com/Audi-1/sqli-labs 一、PhPstudy下載、安裝 1、下載–解壓–安裝&#xff0c;安裝完成如下圖 2、更換php…

【學習筆記】[AGC021F] Trinity

有點難&#x1f605; 考慮加入每一列&#xff0c;發現我們只關心當前還未確定的行的數目 有點難算&#x1f605; 設 d p i , j dp_{i,j} dpi,j?表示有 i i i列&#xff0c;其中 j j j行未確定的方案數。欽定每一列至少有一個黑色格子。 d p i , j j ( j 1 ) 2 d p i ? 1…