K8S知识点记录
文章目錄
- 一.K8s組件
- 整體調用
- 各個組件調用關系
- 二.K8s常用知識點
- 1.Namespace
- 創建namespace
- 查看namespace
- 在namespace中創建資源
- 查看namespace pods
- 2.Pod
- 創建nginx pod,port-forward 實現本地訪問
- 創建一個redis pod,掛載conf文件
- 3.Service
- service是什么?
- Service的類型
- 2.1 ClusterIp
- 2.2 NodePort類型
- 2.3 LoadBalancer
- service的三種端口
- kubectl expose
- 集群內訪問 Service
- 4.Ingress
- Ingress Controoler
- 高可靠部署架構
- 有哪些部署方案 ?
- 方案一:Deployment + LB
- 方案二:Daemonset + HostNetwork + LB
- 方案三:Deployment + LB 直通 Pod
- 5.Deployment
- Deployment 通過 ReplicaSet 來管理 Pod
- 查看副本詳細信息:
- rollout history
- StatefulSet 無狀態服務
- 6 kube-dns發現服務
- 7.k8s Endpoints
- 8.externalTrafficPolicy
- 9.Kube-proxy
- iptables
- ipvs
- 10. hpa
- 三.配置存儲 configmap secret
- pod env
- secret
- 2.secret使用
- 配置熱更新之reloader
- 四.安全認證
- secret 創建tls
- 創建https的負載均衡
- k8s
- PersistentVolume、PersistentVolumeClaim和StorageClass的概念關系
- pv pvc
- StorageClass
- k8s監控
- 探針
- scale 彈性伸縮命令
- 彈性伸縮 監控
- Internet到k8s的流量
- k8s 的一些命令
- 9-4 ReplicationController 與 deployment 關系
- port-forward
- K8S反向代理ip
- LoadBalancer
- nodeport(節點端口)的外部流量策略
- k8s 好用的工具🔧
- kubens命名空間切換工具
- k9s
- k8s 發布模式
- 藍綠發布:兩套環境交替升級,舊版本保留一定時間便于回滾。
- 灰度發布:根據比例將老版本升級,例如80%用戶訪問是老版本,20%用戶訪問是新版本。
- 滾動發布:按批次停止老版本實例,啟動新版本實例。
一.K8s組件
整體調用
各個組件調用關系
二.K8s常用知識點
1.Namespace
Namespace用于對k8s中資源對象的分組。namespace之間沒有嵌套或層級關系。一個資源對象只能屬于一個namespace。不同組之間的對象是隔離的,互相不可見。
常見的pods, services, replication controllers和deployments等都是屬于某一個namespace的(默認是default),而node, persistentVolumes等則不屬于任何namespace。
Namespace 適合用于隔離不同用戶創建的資源。
注意:namespace無法保證網絡的隔離性,比如說service可以跨namespace訪問。
默認來說Kubernetes具有如下3個namespace:
- default: k8s默認的namespace,如果操作如果不指明namespace,默認會操作名為default的namespace。
- kube-system: k8s系統自己運行所需的資源對象所在的namespace。
- kube-public: k8s自動創建的namespace,對所有用戶可見。適合放置集群范圍都可見的服務。
創建namespace
#test.yaml:kind: Namespace apiVersion: v1 metadata:name: test labels:name: test ╰─? kubectl apply -f test.yaml --validate=false 1 ? namespace/test created查看namespace
kubectl get namespace在namespace中創建資源
Pod YAML文件
apiVersion: v1 kind: Pod metadata:name: mypodnamespace: testlabels:name: mypod spec:containers:- name: mypodimage: nginx ╰─? kubectl apply -f nginx-pod.yaml 1 ? pod/mypod created查看namespace pods
╰─? kubectl get pods --namespace=test NAME READY STATUS RESTARTS AGE mypod 1/1 Running 0 5m4s```2.Pod
k8s 創建的pod會被分配到不同的 Node 上
一般是使用deployment 來創建 與管理 pod
創建nginx pod,port-forward 實現本地訪問
-
創建nginx pod
k create -f nginx-pod.yamlnginx-pod.yaml
apiVersion: v1 kind: Pod metadata:name: nginxlabels:name: nginx spec:containers:- name: nginximage: nginximagePullPolicy: IfNotPresentports:- containerPort: 80 -
查看pod狀態
-
進入pod容器中查看nginx
k exec -it nginx /bin/bash -
本地端口映射
k port-forward nginx 8080:80
創建一個redis pod,掛載conf文件
redis.conf
3.Service
service是什么?
在說明Service是什么之前先了解下Service的使用場景:
當客戶端想要訪問K8S集群中的pod時,需要知道pod的ip以及端口,那K8S中如何在不知道pod的地址信息的情況下進行pod服務的快速連接?
若某一node上的pod發生故障,K8S最大的特點就是能夠給感知和重啟該pod,但是pod重啟后ip會發生變化,那么客戶端如何感知并保持對pod的訪問?
如果多個pod組合在一起形成pod組,如何在被訪問時達到負載均衡的效果?
針對上面三種需求,K8S提出了Service的概念,意在解決上述三個問題和場景,下面倆看看Service的定義:
Kubernetes Service是為了管理具有相同功能的一組Pod而定義的一種對象,Service具體的作用和場景如下:
-
通過Pod的Label Selector訪問Pod組。
-
Service的IP保持不變(Headless Servcie除外,下面會單獨講),保證了訪問接口的穩定性,屏蔽了Pod的IP地址變化帶來的影響,進而實現解耦合。雖然這樣,還是建議使用ServiceName進行訪問。
-
Service通過kube-proxy借助iptables/ipvs提供負載均衡的能力,實現反向代理,將請求轉發到合適的Pod上。
Service可以看作是一組提供相同服務的Pod對外的訪問接口。借助Service,應用可以方便地實現服務發現和負載均衡。
Service的類型
在Serive定義時,我們需要指定spec.type字段,這個字段擁有四個選項:
- ClusterIP。默認值。給這個Service分配一個Cluster IP,它是Kubernetes系統自動分配的虛擬IP,因此只能在集群內部訪問。
- NodePort。將Service通過指定的Node上的端口暴露給外部。通過此方法,訪問任意一個NodeIP:nodePort都將路由到ClusterIP,從而成功獲得該服務。
- LoadBalancer。在 NodePort 的基礎上,借助 cloud provider 創建一個外部的負載均衡器,并將請求轉發到 :NodePort。此模式只能在云服務器(AWS等)上使用。
- ExternalName。將服務通過 DNS CNAME 記錄方式轉發到指定的域名(通過 spec.externlName 設定)。需要 kube-dns 版本在 1.7 以上。
2.1 ClusterIp
ClusterIP主要在每個node節點使用iptables,將發向ClusterIP對應端口的數據,轉發到kube-proxy中。然后kube-proxy自己內部實現有負載均衡的方法,并可以查詢到這個service下對應pod的地址和端口,進而把數據轉發給對應的pod的地址和端口。
2.2 NodePort類型
在定義Service時指定spec.type=NodePort,并指定spec.ports.nodePort的值,Kubernetes就會在集群中的每一個Node上打開你定義的這個端口,這樣,就能夠從外部通過任意一個NodeIP:nodePort訪問到這個Service了。
NodePort的原理在于在 Node上開了一個端口,將向該端口的流量導入到 kube-proxy,然后由 kube-proxy進一步到給對應的 pod。
這種類型的service工作流程為:
Client----->NodeIP:NodePort----->ClusterIP:ServicePort----->PodIP:ContainerPort
https://www.jianshu.com/p/72e0d3033ab8
下面是一個簡單的例子:
apiVersion: v1 kind: Service metadata:name: nginx-servicelabels:run: nginx spec:selector:app: nginxports:- port: 80nodePort: 30001targetPort: 5003type: NodePort假如有3個app: nginx Pod運行在3個不同的Node中,那么此時客戶端訪問任意一個Node的30001端口都能訪問到這個nginx服務。
NodeIP: 30001=> ClusterIP:80 => PodIP:5003
2.3 LoadBalancer
LoadBalancer和NodePort其實是同一種方式。區別在于LoadBalancer比NodePort多了一步,就是可以調用Cloud provider去創建LB來向節點導流。
使用云提供商的負載均衡器向外部暴露服務。 外部負載均衡器可以將流量路由到自動創建的 NodePort 服務和 ClusterIP 服務上。
service的三種端口
port
service暴露在cluster ip上的端口,:port 是提供給集群內部客戶訪問service的入口。
nodePort
nodePort是k8s提供給集群外部客戶訪問service入口的一種方式,:nodePort 是提供給集群外部客戶訪問service的入口。
targetPort
targetPort是pod上的端口,從port和nodePort上到來的數據最終經過kube-proxy流入到后端pod的targetPort上進入容器。
port、nodePort總結
總的來說,port和nodePort都是service的端口,前者暴露給集群內客戶訪問服務,后者暴露給集群外客戶訪問服務。從這兩個端口到來的數據都需要經過反向代理kube-proxy流入后端pod的targetPod,從而到達pod上的容器內。
kubectl expose
將資源暴露為新的Kubernetes Service。
指定deployment、service、replica set、replication controller或pod ,并使用該資源的選擇器作為指定端口上新服務的選擇器。deployment 或 replica set只有當其選擇器可轉換為service支持的選擇器時,即當選擇器僅包含matchLabels組件時才會作為暴露新的Service。
為RC的nginx創建service,并通過Service的80端口轉發至容器的8000端口上。
kubectl expose rc nginx --port=80 --target-port=8000集群內訪問 Service
在集群里面,其他 pod 要怎么訪問到我們所創建的這個 service 呢?有三種方式:
首先我們可以通過 service 的虛擬 IP 去訪問,比如說剛創建的 my-service 這個服務,通過 kubectl get svc 或者 kubectl discribe service 都可以看到它的虛擬 IP 地址是 172.29.3.27,端口是 80,然后就可以通過這個虛擬 IP 及端口在 pod 里面直接訪問到這個 service 的地址。
第二種方式直接訪問服務名,依靠 DNS 解析,就是同一個 namespace 里 pod 可以直接通過 service 的名字去訪問到剛才所聲明的這個 service。不同的 namespace 里面,我們可以通過 service 名字加“.”,然后加 service 所在的哪個 namespace 去訪問這個 service,例如我們直接用 curl 去訪問,就是 my-service:80 就可以訪問到這個 service。
第三種是通過環境變量訪問,在同一個 namespace 里的 pod 啟動時,K8s 會把 service 的一些 IP 地址、端口,以及一些簡單的配置,通過環境變量的方式放到 K8s 的 pod 里面。在 K8s pod 的容器啟動之后,通過讀取系統的環境變量比讀取到 namespace 里面其他 service 配置的一個地址,或者是它的端口號等等。比如在集群的某一個 pod 里面,可以直接通過 curl $ 取到一個環境變量的值,比如取到 MY_SERVICE_SERVICE_HOST 就是它的一個 IP 地址,MY_SERVICE 就是剛才我們聲明的 MY_SERVICE,SERVICE_PORT 就是它的端口號,這樣也可以請求到集群里面的 MY_SERVICE 這個 service。
4.Ingress
Ingress 包含兩大組件:Ingress Controller 和 Ingress。
Ingress 簡單的理解就是你原來需要改 Nginx 配置,然后配置各種域名對應哪個 Service,現在把這個動作抽象出來,變成一個 Ingress 對象,你可以用 yaml 創建,每次不要去改 Nginx 了,直接改 yaml 然后創建/更新就行了;
Ingress Controoler
Ingress Controoler 通過與 Kubernetes API 交互,動態的去感知集群中 Ingress 規則變化,并按照規則模板生成一段 Nginx 配置,再寫到 Nginx Pod 里,最后 reload 一下,工作流程如下圖:
當然在實際應用中,最新版本 Kubernetes 已經將 Nginx 與 Ingress Controller 合并為一個組件,所以 Nginx 無需單獨部署,只需要部署 Ingress Controller 即可
(注意:寫入 nginx.conf 的不是service的地址,而是service backend 的 pod 的地址,避免在 service 在增加一層負載均衡轉發)
https://www.jianshu.com/p/3574ecda6417
部署ingress及使用
高可靠部署架構
在Kubernetes集群中,Ingress作為集群流量接入層,Ingress的高可靠性顯得尤為重要
當您成功創建一個ACK集群后,默認情況下,集群內部已經部署了一套擁有2個Pod副本的Nginx Ingress Controller服務,其前端掛載在一個公網SLB實例上。
https://help.aliyun.com/document_detail/151524.html
高可靠性首先要解決的就是單點故障問題,一般常用的是采用多副本部署的方式,我們在Kubernetes集群中部署高可靠Ingress接入層同樣采用多節點部署架構,同時由于Ingress作為集群流量接入口,建議采用獨占Ingress節點的方式,以避免業務應用與Ingress服務發生資源爭搶。
如上述部署架構圖,由多個獨占Ingress實例組成統一接入層承載集群入口流量,同時可依據后端業務流量水平擴縮容Ingress節點。當然如果您前期的集群規模并不大,也可以采用將Ingress服務與業務應用混部的方式,但建議進行資源限制和隔離。
我們可以通過修改deployment(nginx-ingress-controller)的副本數來實現高可用,但是由于ingress承載著整個集群流量的接入,所以生產環境中,建議把ingress通過DaemonSet的方式部署集群中,而且該節點打上污點不允許業務pod進行調度,以避免業務應用與Ingress服務發生資源爭搶。然后通過SLB把ingress節點主機添為后端服務器,進行流量轉發。
Ingress高可用
有哪些部署方案 ?
Nginx Ingress on TKE 部署最佳實踐
方案一:Deployment + LB
在 TKE 上部署 Nginx Ingress 最簡單的方式就是將 Nginx Ingress Controller 以 Deployment 的方式部署,并且為其創建 LoadBalancer 類型的 Service(可以是自動創建 CLB 也可以是綁定已有 CLB),這樣就可以讓 CLB 接收外部流量,然后轉發到 Nginx Ingress 內部:
前 TKE 上 LoadBalancer 類型的 Service 默認實現是基于 NodePort,CLB 會綁定各節點的 NodePort 作為后端 rs,將流量轉發到節點的 NodePort,然后節點上再通過 Iptables 或 IPVS 將請求路由到 Service 對應的后端 Pod,這里的 Pod 就是 Nginx Ingress Controller 的 Pod。后續如果有節點的增刪,CLB 也會自動更新節點 NodePort 的綁定。
方案二:Daemonset + HostNetwork + LB
方案一雖然簡單,但是流量會經過一層 NodePort,會多一層轉發。這種方式有一些缺點:
轉發路徑較長,流量到了 NodePort 還會再經過 Kubernetes 內部負載均衡,通過 Iptables 或 IPVS 轉發到 Nginx,會增加一點網絡耗時。
經過 NodePort 必然發生 SNAT,如果流量過于集中容易導致源端口耗盡或者 conntrack 插入沖突導致丟包,引發部分流量異常。
每個節點的 NodePort 也充當一個負載均衡器,CLB 如果綁定大量節點的 NodePort,負載均衡的狀態就分散在每個節點上,容易導致全局負載不均。
CLB 會對 NodePort 進行健康探測,探測包最終會被轉發到 Nginx Ingress 的 Pod,如果 CLB 綁定的節點多,Nginx Ingress 的 Pod 少,會導致探測包對 Nginx Ingress 造成較大的壓力。
我們可以讓 Nginx Ingress 使用 hostNetwork,CLB 直接綁節點 IP + 端口(80,443), 這樣就不用走 NodePort;由于使用 hostNetwork,Nginx Ingress 的 pod 就不能被調度到同一節點避免端口監聽沖突。通常做法是提前規劃好,選取部分節點作為邊緣節點,專門用于部署 Nginx Ingress,為這些節點打上 label,然后 Nginx Ingress 以 DaemonSet 方式部署在這些節點上。下面是架構圖:
方案三:Deployment + LB 直通 Pod
方案二雖然相比方案一有一些優勢,但同時也引入了手動維護 CLB 和 Nginx Ingress 節點的運維成本,需要提前規劃好 Nginx Ingress 的節點,增刪 Nginx Ingress 節點時需要手動在 CLB 控制臺綁定和解綁節點,也無法支持自動擴縮容。如果你的網絡模式是 VPC-CNI,那么所有的 Pod 都使用的彈性網卡,彈性網卡的 Pod 是支持 CLB 直接綁 Pod 的,可以繞過 NodePort,并且不用手動管理 CLB,支持自動擴縮容:
5.Deployment
在 k8s 中編排應用可以更好地做彈性擴容,負載均衡。既然要均衡,一個 Pod 肯定不能均衡,自然要部署多個 Pod
docker-compose 可以簡單地通過 docker-compose scale 來擴容,現在用k8s擴容
在k8s中管理 Pod 的稱作 Controller,我們可以使用 Deployment 這種 Controller 來為 Pod 進行擴容,當然它還可以滾動升級,回滾,金絲雀等等關于部署的事情
Deployment同樣為Kubernetes的一個核心內容,主要職責同樣是為了保證pod的數量和健康,90%的功能與Replication Controller完全一樣,可以看做新一代的Replication Controller。但是,它又具備了Replication Controller之外的新特性:
Replication Controller全部功能:Deployment繼承了上面描述的Replication Controller全部功能。
-
事件和狀態查看:可以查看Deployment的升級詳細進度和狀態。
-
回滾:當升級pod鏡像或者相關參數的時候發現問題,可以使用回滾操作回滾到上一個穩定的版本或者指定的版本。
-
版本記錄: 每一次對Deployment的操作,都能保存下來,給予后續可能的回滾使用。
-
暫停和啟動:對于每一次升級,都能夠隨時暫停和啟動。
-
多種升級方案:Recreate:刪除所有已存在的pod,重新創建新的; - RollingUpdate:滾動升級,逐步替換的策略,同時滾動升級時,支持更多的附加參數,例如設置最大不可用pod數量,最小升級間隔時間等等。
我們編寫一個 Deployment 的資源配置文件
- spec.template: 指定要部署的 Pod
- spec.replicas: 指定要部署的個數
- spec.selector: 定位需要管理的 Pod
kubectl get deplouyment命令可以查看 httpd-ken 的狀態,輸出顯示一個副本正常運行。
kubectl describe deployment 了解更詳細的信息
創建了一個 ReplicaSet qa-ibaboss-elk-redis-6446fd4484,
Events 是 Deployment 的日志,記錄了 ReplicaSet 的啟動過程。
Deployment 通過 ReplicaSet 來管理 Pod
接著我們將注意力切換到 qa-ibaboss-elk-redis-6446fd4484,執行
╰─? kubectl get replicaset NAME DESIRED CURRENT READY AGE qa-ibaboss-elk-redis-6446fd4484 1 1 1 23m查看副本詳細信息:
kubectl describe replicaset
Controlled By 指明此 ReplicaSet 是由 Deployment httpd-ken 創建。
Events 記錄了兩個副本 Pod 的創建。
rollout history
k rollout history deployment deploymentName回到上一個版本
k rollout undo deployment deploymentNameStatefulSet 無狀態服務
6 kube-dns發現服務
kube-dns可以解決Service的發現問題,k8s將Service的名稱當做域名注冊到kube-dns中,通過Service的名稱就可以訪問其提供的服務。
● 在k8s集群中,服務是運行在Pod中的,Pod的發現和副本間負載均衡是我們面臨的問題。
● 通過Service可以解決這兩個問題,但訪問Service也需要對應的IP,因此又引入了Service發現的問題。
● 得益于kube-dns插件,我們可以通過域名來訪問集群內的Service,解決了Service發現的問題。
● 為了讓Pod中的容器可以使用kube-dns來解析域名,k8s會修改容器的/etc/resolv.conf配置。
部分 DNS 查詢延遲的問題
經過搜索發現這是一個普遍問題。
根本原因是內核conntrack模塊的bug。
https://tencentcloudcontainerteam.github.io/2018/10/26/DNS-5-seconds-delay/
7.k8s Endpoints
endpoint 是k8s集群中一個資源對象,存儲在etcd里面,用來記錄一個service對應的所有pod的訪問地址。
簡述: endpoints: 實際上servce服務后端的pod端點集合
k8s集群中創建一個名為test的service,就h會生成一個同名的endpoint 對象,endpoint對象就是關聯pod的ip 地址和端口 (使用kubectl describe svc mongodb -n namespace-name, 查看當前的service 下面有一個pod 的)
注意的點:
如果在應用程序中直接使用存儲應用的ip 地址,考慮如果后期的ip變化了,我們要手動修改應用的配置。
當然使用configmap也可以解決我說的上述問題,只需要將端點存儲在Configmap里面,并將其作為環境變量用于代碼中讀取,但是如果端點發生變化,我們可能要重新所有的應用的容器
我們需要能夠在k8s里面像使用同一個命名空間下面的服務那種直接使用service name 名稱,我們可以使用k8s的靜態服務來解決,如果后期需要將有狀態服務添加到k8s里面,則代碼不需要任何修改。
8.externalTrafficPolicy
把集群外部的服務引入到集群內部來,在集群內部直接使用。沒有任何類型代理被創建,這只有 kubernetes 1.7 或更高版本的 kube-dns 才支持【當我們的集群服務需要訪問k8s之外的集群時,可以選擇這種類型,然后把外部服務的IP及端口寫入到k8s服務中來,k8s的代理將會幫助我們訪問到外部的集群服務】
1 什么是external-traffic-policy
在k8s的Service對象(申明一條訪問通道)中,有一個“externalTrafficPolicy”字段可以設置。有2個值可以設置:Cluster或者Local。
1)Cluster表示:流量可以轉發到其他節點上的Pod。
2)Local表示:流量只發給本機的Pod。
externalTrafficPolicy=Local
為了解決這個問題, k8s 提供了一個功能,通過設置 externalTrafficPolicy=Local 可以保留源IP地址
- client sends packet to node2:nodePort, which doesn’t have any endpoints
客戶端發送tcp包到 node2:nodePort, 但是 node2 并沒有 這個pod - packet is dropped
tcp包被丟棄 - client sends packet to node1:nodePort, which does have endpoints
客戶端發送數據包到 node1:nodePort, node1有pod - node1 routes packet to endpoint with the correct source IP
node1 把包路由到對應的pod,那么pod 就可以拿到正確的客戶端源IP地址
缺點是負載均衡可能不是很好,因為一旦容器實例分布在多個節點上,它只轉發給本機,不跨節點轉發流量。當然,少了一次轉發,性能會相對好一丟丟。
注:這種模式下的Service類型只能為外部流量,即:LoadBalancer 或者 NodePort 兩種,否則會報錯。
同時,由于本機不會跨節點轉發報文,所以要想所有節點上的容器有負載均衡,就需要上一級的Loadbalancer來做了。
9.Kube-proxy
Kube-proxy 是 kubernetes 工作節點上的一個網絡代理組件,運行在每個節點上。
Kube-proxy維護節點上的網絡規則,實現了Kubernetes Service 概念的一部分 。它的作用是使發往 Service 的流量(通過ClusterIP和端口)負載均衡到正確的后端Pod。
kube-proxy負責為Service提供cluster內部的服務發現和負載均衡,它運行在每個Node計算節點上,負責Pod網絡代理, 它會定時從etcd服務獲取到service信息來做相應的策略,維護網絡規則和四層負載均衡工作。在K8s集群中微服務的負載均衡是由Kube-proxy實現的,它是K8s集群內部的負載均衡器,也是一個分布式代理服務器,在K8s的每個節點上都有一個,這一設計體現了它的伸縮性優勢,需要訪問服務的節點越多,提供負載均衡能力的Kube-proxy就越多,高可用節點也隨之增多。
service是一組pod的服務抽象,相當于一組pod的LB,負責將請求分發給對應的pod。service會為這個LB提供一個IP,一般稱為cluster IP。kube-proxy的作用主要是負責service的實現,具體來說,就是實現了內部從pod到service和外部的從node port向service的訪問。
代理模式
目前 Kube-proxy 支持4中代理模式:
userspace
iptables
ipvs
kernelspace
其中 kernelspace 專用于windows,userspace 是早期版本的實現,本文我們不作過多闡述。
iptables
iptables是一種Linux內核功能,旨在成為一種高效的防火墻,具有足夠的靈活性來處理各種常見的數據包操作和過濾需求。它允許將靈活的規則序列附加到內核的數據包處理管道中的各種鉤子上。
在iptables模式下,kube-proxy將規則附加到“ NAT預路由”鉤子上,以實現其NAT和負載均衡功能。這種方法很簡單,使用成熟的內核功能,并且可以與通過iptables實現網絡策略的組件“完美配合”。
默認的策略是,kube-proxy 在 iptables 模式下隨機選擇一個后端。
如果 kube-proxy 在 iptables 模式下運行,并且所選的第一個 Pod 沒有響應, 則連接失敗。 這與用戶空間模式不同:在這種情況下,kube-proxy 將檢測到與第一個 Pod 的連接已失敗, 并會自動使用其他后端 Pod 重試。
但是,kube-proxy對iptables規則進行編程的方式是一種O(n)復雜度的算法,其中n與集群大小(或更確切地說,服務的數量和每個服務背后的后端Pod的數量)成比例地增長)。
所以綜合上面的例子,對于ipable方式的k8s集群內cluster-ip類型的service總結為:
- 流量從pod network namespace中走到host netwok namespace的docker0中。
- 在host netwok namespace的PREROUTING chain中會經過一系列target。
- 在這些target里根據iptable內核隨機模塊來實現匹配endpoint target,隨機比率為均勻分配,實現均勻的負載均衡。
- 在endpoint target里實現了DNAT,也就是將目標地址cluster ip轉化為實際的pod的ip。
- cluster ip是虛擬ip,不會和任何device綁定。
- 負載均衡為內核實現,使用均勻負載均衡,不可以有自定義的負載均衡算法。
- 需要host開啟路由轉發功能(net.ipv4.ip_forward = 1)。
- 數據包在host netwok namespace中經過轉換以及DNAT之后,由host network namespace的路由表來決定下一跳地址。
ipvs
IPVS是專門用于負載均衡的Linux內核功能。在IPVS模式下,kube-proxy可以對IPVS負載均衡器進行編程,而不是使用iptables。這非常有效,它還使用了成熟的內核功能,并且IPVS旨在均衡許多服務的負載。它具有優化的API和優化的查找例程,而不是一系列順序規則。 結果是IPVS模式下kube-proxy的連接處理的計算復雜度為O(1)。換句話說,在大多數情況下,其連接處理性能將保持恒定,而與集群大小無關。
與 iptables 模式下的 kube-proxy 相比,IPVS 模式下的 kube-proxy 重定向通信的延遲要短,并且在同步代理規則時具有更好的性能。 與其他代理模式相比,IPVS 模式還支持更高的網絡流量吞吐量。
k logs -n kube-system kube-proxy-worker-tm4nm10. hpa
最佳實踐
為了實現 K8s 集群中資源的有效調度和充分利用, K8s 采用requests和limits兩種限制類型來對資源進行容器粒度的分配。每一個容器都可以獨立地設定相應的requests和limits。這 2 個參數是通過每個容器 containerSpec 的 resources 字段進行設置的。一般來說,在調度的時候requests比較重要,在運行時limits比較重要。
resources: requests: cpu: 50mmemory: 50Milimits: cpu: 100mmemory: 100Mirequests定義了對應容器需要的最小資源量。這句話的含義是,舉例來講,比如對于一個 Spring Boot 業務容器,這里的requests必須是容器鏡像中 JVM 虛擬機需要占用的最少資源。如果這里把 pod 的內存requests指定為 10Mi ,顯然是不合理的,JVM 實際占用的內存 Xms 超出了 K8s 分配給 pod 的內存,導致 pod 內存溢出,從而 K8s 不斷重啟 pod 。
limits定義了這個容器最大可以消耗的資源上限,防止過量消耗資源導致資源短缺甚至宕機。特別的,設置為 0 表示對使用的資源不做限制。值得一提的是,當設置limits而沒有設置requests時,Kubernetes 默認令requests等于limits。
進一步可以把requests和limits描述的資源分為 2 類:可壓縮資源(例如 CPU )和不可壓縮資源(例如內存)。合理地設置limits參數對于不可壓縮資源來講尤為重要。
前面我們已經知道requests參數會最終的 K8s 調度結果起到直接的顯而易見的影響。借助于 Linux 內核 Cgroup 機制,limits參數實際上是被 K8s 用來約束分配給進程的資源。對于內存參數而言,實際上就是告訴 Linux 內核什么時候相關容器進程可以為了清理空間而被殺死( oom-kill )。
總結一下:
- 對于 CPU,如果 pod 中服務使用 CPU 超過設置的limits,pod 不會被 kill 掉但會被限制。如果沒有設置 limits ,pod 可以使用全部空閑的 CPU 資源。
- 對于內存,當一個 pod 使用內存超過了設置的limits,pod 中 container 的進程會被 kernel 因 OOM kill 掉。當 container 因為 OOM 被 kill 掉時,系統傾向于在其原所在的機器上重啟該 container 或本機或其他重新創建一個 pod。
- 0 <= requests <=Node Allocatable, requests <= limits <= Infinity
https://kubesphere.io/zh/blogs/deep-dive-into-the-k8s-request-and-limit/
三.配置存儲 configmap secret
pod env
apiVersion: v1 kind: Pod metadata:name: envar-demolabels:purpose: demonstrate-envars spec:containers:- name: envar-demo-containerimage: gcr.io/google-samples/node-hello:1.0env:- name: DEMO_GREETINGvalue: "Hello from the environment"secret
Secret介紹
k8s secrets用于存儲和管理一些敏感數據,比如密碼,token,密鑰等敏感信息。它把 Pod 想要訪問的加密數據存放到 Etcd 中。然后用戶就可以通過在 Pod 的容器里掛載 Volume 的方式或者環境變量的方式訪問到這些 Secret 里保存的信息了。
Secret有三種類型
-
Opaque:base64 編碼格式的 Secret,用來存儲密碼、密鑰等;但數據也可以通過base64 –decode解碼得到原始數據,所有加密性很弱。
#secret.yamlapiVersion: v1 kind: Secret metadata: name: mysecret type: Opaque data: user: YWRtaW4= pass: MWYyZDFlMmU2N2Rm注:通過yaml創建Opaque類型的Secret值需要base64編碼
kubectl create -f secret.yaml
-
Service Account:用來訪問Kubernetes API,由Kubernetes自動創建,并且會自動掛載到Pod的 /run/secrets/kubernetes.io/serviceaccount 目錄中。
-
kubernetes.io/dockerconfigjson : 用來存儲私有docker registry的認證信息。
用來創建用戶docker registry認證的Secret,直接使用kubectl create命令創建即可,如下:
kubectl create secret docker-registry myregistry --docker-server=DOCKER_SERVER --docker-username=DOCKER_USER --docker-password=DOCKER_PASSWORD --docker-email=DOCKER_EMAIL
imagePullSecrets 使用docker registry的認證信息
2.secret使用
方式一:通過Volume掛載的方式
#test-projected-volume.yamlapiVersion: v1 kind: Pod metadata:name: test-projected-volume spec:containers:- name: test-secret-volumeimage: busyboxargs:- sleep- "86400"volumeMounts:- name: mysql-credmountPath: "/projected-volume"readOnly: truevolumes:- name: mysql-credprojected:sources:- secret:name: user- secret:name: pass當 Pod 變成 Running 狀態之后,我們再驗證一下這些 Secret 對象是不是已經在容器里了:
$ kubectl exec -it test-projected-volume -- /bin/sh $ ls /projected-volume/ user pass $ cat /projected-volume/user admin $ cat /projected-volume/pass 1f2d1e2e67df配置熱更新之reloader
Configmap或Secret使用有兩種方式,一種是env系統變量賦值,一種是volume掛載賦值,env寫入系統的configmap是不會熱更新的,而volume寫入的方式支持熱更新!
對于env環境的,必須要滾動更新pod才能生效,也就是刪除老的pod,重新使用鏡像拉起新pod加載環境變量才能生效。
對于volume的方式,雖然內容變了,但是需要我們的應用直接監控configmap的變動,或者一直去更新環境變量才能在這種情況下達到熱更新的目的。
應用不支持熱更新,可以在業務容器中啟動一個sidercar容器,監控configmap的變動,更新配置文件,或者也滾動更新pod達到更新配置的效果。
Reloader 可以觀察 ConfigMap 和 Secret 中的變化,并通過相關的 deploymentconfiggs、 deploymentconfiggs、 deploymonset 和 statefulset 對 Pods 進行滾動升級。
通過對比配置sha
https://juejin.cn/post/6897882769624727559
當 Reloader 檢測到 ConfigMap 發生變化的時候,會使用 SHA1 計算 ConfigMap 的哈希值(使用 SHA1 是因為它高效且不易發生沖突),計算完哈希值之后,Reloader 獲取所有的 Deployments,Daemonsets,Statefulsets 和 Rollouts 列表,并查找其 anotations 中是否配置了 Reloader 相關的注解,比如配置了如下 annotations :
metadata:annotations:reloader.stakater.com/auto: "true"接著 Reloader 會查找配置了 Reloader 相關 annotations 的 Deployments,Daemonsets,Statefulsets 中一個特殊的環境變量。
如果找到這個環境變量,則獲取其值并將其與前面計算的新 ConfigMap 哈希值進行比較,如果環境變量中的舊值與新哈希值不同,則 Reloader 會更新環境變量。
如果環境變量不存在,那么它會從 ConfigMap 創建一個具有最新哈希值的新環境變量并更新相關的deployment,daemonset或者statefulset。
k8s 檢測到這個環境變量發生變化,則會觸發 pod 關聯的 deployment,daemonset或者statefulset 的滾動升級。
四.安全認證
secret 創建tls
創建https的負載均衡
apiVersion: v1 kind: Service metadata:annotations:service.beta.kubernetes.io/alibaba-cloud-loadbalancer-cert-id: 1858386724757...service.beta.kubernetes.io/alibaba-cloud-loadbalancer-protocol-port: 'https:443'service.beta.kubernetes.io/alibaba-cloud-loadbalancer-spec: slb.s1.smallname: ps-svcnamespace: prod spec:ports:- port: 443protocol: TCPtargetPort: 8091selector:app: ps-devtype: LoadBalancer需要通過service的annotation指定規格 service.beta.kubernetes.io/alibaba-cloud-loadbalancer-spec: "slb.s1.small"
并且很多k8s service 的annotation不可用,
比如指定使用已創建的負載均衡(推薦)service.beta.kubernetes.io/alicloud-loadbalancer-id:lb-xxxx
k8s
PersistentVolume、PersistentVolumeClaim和StorageClass的概念關系
pv pvc
如果要求Pod重新調度后仍然能使用之前讀寫過的數據,就只能使用網絡存儲了,網絡存儲種類非常多且有不同的使用方法,通常一個云服務提供商至少有塊存儲、文件存儲、對象存儲三種,如華為云的EVS、SFS和OBS。
Kubernetes解決這個問題的方式是抽象了PV(PersistentVolume)和PVC(PersistentVolumeClaim)來解耦這個問題,從而讓使用者不用關心具體的基礎設施,當需要存儲資源的時候,只要像CPU和內存一樣,聲明要多少即可。
-
PV:PV描述的是持久化存儲卷,主要定義的是一個持久化存儲在宿主機上的目錄,比如一個NFS的掛載目錄。
-
PVC:PVC描述的是Pod所希望使用的持久化存儲的屬性,比如,Volume存儲的大小、可讀寫權限等等。
Kubernetes管理員設置好網絡存儲的類型,提供對應的PV描述符配置到Kubernetes,使用者需要存儲的時候只需要創建PVC,然后在Pod中使用Volume關聯PVC,即可讓Pod使用到存儲資源,它們之間的關系如下圖所示。
$ kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pv-example 10Gi RWX Retain Bound default/pvc-example 50s可以看到狀態也變成了Bound,CLAIM是default/pvc-example,表示這個PV綁定了default命名空間下的pvc-example這個PVC。
這里一個比較有意思的地方是CLAIM是default/pvc-example,為什么要顯示default呢,這是因為PV是集群級別的資源,并不屬于某個命名空間,而PVC是命名空間級別的資源,PV可以與任何命名空間的PVC資源綁定。
StorageClass
上節說的PV和PVC方法雖然能實現屏蔽底層存儲,但是PV創建比較復雜(可以看到PV中csi字段的配置很麻煩),通常都是由集群管理員管理,這非常不方便。
Kubernetes解決這個問題的方法是提供動態配置PV的方法,可以自動創PV。管理員可以部署PV配置器(provisioner),然后定義對應的StorageClass,這樣開發者在創建PVC的時候就可以選擇需要創建存儲的類型,PVC會把StorageClass傳遞給PV provisioner,由provisioner自動創建PV。
如CCE就提供csi-disk、csi-nas、csi-obs等StorageClass,在聲明PVC時加上StorageClassName,就可以自動創建PV,并自動創建底層的存儲資源。
使用StorageClass,不僅創建了PVC,而且創建了PV,并且將二者綁定了。
定義了StorageClass后,就可以減少創建并維護PV的工作,PV變成了自動創建,作為使用者,只需要在聲明PVC時指定StorageClassName即可,這就大大減少工作量。
k8s監控
探針
https://kubernetes.io/zh/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/
scale 彈性伸縮命令
http://docs.kubernetes.org.cn/664.html
k scale rc celery-controller --replicas=2- 動態彈性伸縮
彈性伸縮 監控
go-zero 給出的例子
apiVersion: apps/v1 kind: Deployment metadata:name: go-zero-demo02namespace: testlabels:app: go-zero-demo02 spec:replicas: 1revisionHistoryLimit: 5selector:matchLabels:app: go-zero-demo02template:metadata:labels:app: go-zero-demo02spec:containers:- name: go-zero-demo02image: registry.cn-shanghai.aliyuncs.com/russell-cloud/devlop-docker:latestlifecycle:preStop:exec:command: ["sh","-c","sleep 5"]ports:- containerPort: 8888readinessProbe:tcpSocket:port: 8888initialDelaySeconds: 5periodSeconds: 10livenessProbe:tcpSocket:port: 8888initialDelaySeconds: 15periodSeconds: 20resources:requests:cpu: 500mmemory: 512Milimits:cpu: 1000mmemory: 1024MivolumeMounts:- name: timezonemountPath: /etc/localtimevolumes:- name: timezonehostPath:path: /usr/share/zoneinfo/Asia/Shanghai---apiVersion: v1 kind: Service metadata:name: go-zero-demo02-svcnamespace: test spec:ports:- port: 8888selector:app: go-zero-demo02--- apiVersion: autoscaling/v2beta1 kind: HorizontalPodAutoscaler metadata:name: go-zero-demo02-hpa-cnamespace: testlabels:app: go-zero-demo02-hpa-c spec:scaleTargetRef:apiVersion: apps/v1kind: Deploymentname: go-zero-demo02minReplicas: 3maxReplicas: 10metrics:- type: Resourceresource:name: cputargetAverageUtilization: 80--- apiVersion: autoscaling/v2beta1 kind: HorizontalPodAutoscaler metadata:name: go-zero-demo02-hpa-mnamespace: testlabels:app: go-zero-demo02-hpa-m spec:scaleTargetRef:apiVersion: apps/v1kind: Deploymentname: go-zero-demo02minReplicas: 3maxReplicas: 10metrics:- type: Resourceresource:name: memorytargetAverageUtilization: 80Internet到k8s的流量
https://blog.csdn.net/weixin_43746433/article/details/114290213
k8s 的一些命令
k config get-contexts 查看當前上下文以及對應使用的名稱空間
k config view 查看配置信息
k cluster-info 集群信息
9-4 ReplicationController 與 deployment 關系
Replication Controller為Kubernetes的一個核心內容,應用托管到Kubernetes之后,需要保證應用能夠持續的運行,Replication Controller就是這個保證的key,主要的功能如下:
- 確保pod數量:它會確保Kubernetes中有指定數量的Pod在運行。如果少于指定數量的pod,Replication Controller會創建新的,反之則會刪除掉多余的以保證Pod數量不變。
- 確保pod健康:當pod不健康,運行出錯或者無法提供服務時,Replication Controller也會殺死不健康的pod,重新創建新的。
- 彈性伸縮 :在業務高峰或者低峰期的時候,可以通過Replication Controller動態的調整pod的數量來提高資源的利用率。同時,配置相應的監控功能(Hroizontal Pod Autoscaler),會定時自動從監控平臺獲取Replication Controller關聯pod的整體資源使用情況,做到自動伸縮。
- 滾動升級:滾動升級為一種平滑的升級方式,通過逐步替換的策略,保證整體系統的穩定,在初始化升級的時候就可以及時發現和解決問題,避免問題不斷擴大。
port-forward
這是一種通過 kubectl port-forward 指令來實現數據轉發的方法。kubectl port-forward 命令可以為 Pod 設置端口轉發,通過在本機指定監聽端口,訪問這些端口的請求將會被轉發到 Pod 的容器中對應的端口上。
首先,我們來看下 Kubernetes Port Forward 這種方式的工作機制:
使用 Kubectl 創建 Port Forward 后,Kubectl 會主動監聽指定的本地端口。
當向 Local-Port 建立端口連接并向該端口發送數據時,數據流向會經過以下步驟:
1].數據發往 Kubctl 監聽的 Local-Port。
2].Kubectl 通過 SPDY 協議將數據發送給 ApiServer。
3].ApiServer 與目標節點的 Kubelet 建立連接,并通過 SPDY 協議將數據發送到目標 Pod 的端口上。
4].目標節點的 Kubelet 收到數據后,通過 PIPE(STDIN、STDOUT)與 Socat 通信。
5].Socat 將 STDIN 的數據發送給 Pod 內部指定的容器端口,并將返回的數據寫入到 STDOUT。
6].STDOUT 的數據由 Kubelet 接收并按照相反的路徑發送回去。
注:SPDY 協議將來可能會被替換為 HTTP/2。
-
查看pod
kubectl get pod -
kubectl port-forward 端口映射
kubectl port-forward dev-db-5959f58bd7-88zlm 5432:5432 --address=0.0.0.0 -
啟動Django 本地環境
DJANGO_SETTINGS_MODULE=project_name.settings_local python3 ./manage.py runserver
K8S反向代理ip
externalName Service是k8s中一個特殊的service類型,它不需要指定selector去選擇哪些pods實例提供服務,而是使用DNS CNAME機制把自己CNAME到你指定的另外一個域名上,你可以提供集群內的名字,比如mysql.db.svc這樣的建立在db命名空間內的mysql服務,也可以指定http://mysql.example.com這樣的外部真實域名
CNAME是很有用的一個功能,在不同的域名之間搭建橋梁達到明一個域名暗另一個域名,比如github就通過CNAME機制來達到為用戶提供私有域名站點的功能,云服務商也都是使用CNAME為用戶提供各種各樣的服務。作為明域名的所有者,我可以用A云來提供服務,哪天我口味變了,我換成B云提供服務,對我的用戶的來說沒有任何感知。
這么好的功能,k8s當然要加以利用,那就是externalName Service。從External這個名字看,把外部服務引入集群的意味相當濃烈吧,我提供給pod一個mysql.db.svc這樣一個數據庫服務,至于真實的數據庫是運行在同一個集群內,還是在集群外部,pod不在意也不需要關心,反正能用就成。這就是extenalName的主要用途。
how to set reverse proxy with ingress
項目中 使用yaml文件經過脫敏 后如下
apiVersion: v1 kind: Service metadata:name: service_name spec:externalName: "127.0.0.1"ports:- port: 80protocol: TCPtargetPort: 8433type: ExternalName---apiVersion: extensions/v1beta1 kind: Ingress metadata:name: service_nameannotations:kubernetes.io/ingress.class: "nginx"cert-manager.io/cluster-issuer: "letsencrypt-prod"nginx.ingress.kubernetes.io/upstream-vhost: "127.0.0.1" spec:tls:- hosts:- xxx.域名.netsecretName: service_name-oss-tlsrules:- host: xxx.域名.nethttp:paths:- backend:serviceName: service_nameservicePort: 80path: /這樣可以通過xxx.域名.net 的域名訪問 通過 xxx.域名.net (舉例)訪問127.0 .0.1:8433
LoadBalancer
LoadBalancer 只能在service上定義。這是公有云提供的負載均衡器,如AWS、Azure、CloudStack、GCE等。
kind: Service apiVersion: v1 metadata:name: influxdb spec:type: LoadBalancerports:- port: 8086selector:name: influxdb查看服務:
$ kubectl get svc influxdb NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE influxdb 10.97.121.42 10.13.242.236 8086:30051/TCP 39s內部可以使用ClusterIP加端口來訪問服務,如19.97.121.42:8086。
外部可以用以下兩種方式訪問該服務:
使用任一節點的IP加30051端口訪問該服務
使用EXTERNAL-IP來訪問,這是一個VIP,是云供應商提供的負載均衡器IP,如10.13.242.236:8086。
案例, 設置service 為LoadBalancer類型,公網訪問
k get svc -o wide -n dev NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR scheduler LoadBalancer 172.22.5.138 8.131.97.41 80:31293/TCP 2m31s app=scheduler訪問 http://8.131.97.41/ 成功
nodeport(節點端口)的外部流量策略
k8s 好用的工具🔧
kubens命名空間切換工具
激活之后 直接可以操作 而不用每次都帶--namespace
k9s
github 1w+ star, 本地操作k8s神器
缺點網速不好會很難受
https://github.com/derailed/k9s
k8s 發布模式
藍綠發布:兩套環境交替升級,舊版本保留一定時間便于回滾。
項目邏輯上分為AB組(冗余),在項目系統時,首先把A組從負載均衡中摘除,進行新版本的部署。B組仍然繼續提供服務。
當A組升級完畢,負載均衡重新接入A組,再把B組從負載列表中摘除,進行新版本的部署。A組重新提供服務。
灰度發布:根據比例將老版本升級,例如80%用戶訪問是老版本,20%用戶訪問是新版本。
滾動發布:按批次停止老版本實例,啟動新版本實例。
三種方式均可以做到平滑式升級,在升級過程中服務仍然保持服務的連續性,升級對外界是無感知的。
那生產上選擇哪種部署方法最合適呢?這取決于哪種方法最適合你的業務和技術需求。
如果你們運維自動化能力儲備不夠,肯定是越簡單越好,建議藍綠發布,如果業務對用戶依賴很強,建議灰度發布。如果是K8S平臺,滾動更新是現成的方案,建議先直接使用。
總結
- 上一篇: python生僻字如何转码_Python
- 下一篇: 在线代理浏览国外网站_知道这些在线PS网