k8s中幾個基本概念的理解,pod,service,deployment,ingress的使用場景
k8s 總體概覽
前言
學習 k8s 之前首先對 k8s 中具體的組件做個簡單的了解。
Pod
Pod 是 k8s 中集群部署應用和服務的最小單元,一個 pod 中可以部署多個容器。
Pod 的設計理念是支援多個容器在一個 Pod 中共享網路地址和文件系統,可以通過進程間通訊和文件共享這種簡單高效的方式組合完成服務。Pod 對多容器的支援是 K8 最基礎的設計理念。
副本控制器(Replication Controller,RC)
RC 是 k8s 集群中最早的保證 Pod 高可用的 API 對象。它的作用就是保證集群中有指定數目的 pod 運行。
當前運行的 pod 數目少於指定的數目,RC 就會啟動新的 pod 副本,保證運行 pod 數量等於指定數目。
當前運行的 pod 數目大於指定的數目,RC 就會殺死多餘的 pod 副本。
副本集(Replica Set,RS)
RS 是新一代 RC,提供同樣的高可用能力,區別主要在於 RS 後來居上,能支援更多種類的匹配模式。副本集對象一般不單獨使用,而是作為 Deployment 的理想狀態參數使用。
部署(Deployment)
Deployment 提供了一種對 Pod 和 ReplicaSet 的管理方式,每一個 Deployment 都對應集群中的一次部署,是非常常見的 Kubernetes 對象。
Deployment 是一個比 RS 應用模式更廣的 API 對象,可以用來創建一個新的服務,更新一個新的服務,也可以用來滾動升級一個服務。
滾動升級一個服務,滾動升級一個服務,實際是創建一個新的 RS,然後逐漸將新 RS 中副本數增加到理想狀態,將舊 RS 中的副本數減小到 0 的複合操作;這樣一個複合操作用一個 RS 是不太好描述的,所以用一個更通用的 Deployment 來描述。
服務(Service)
RC、RS 和 Deployment 只是保證了支撐服務的微服務 Pod 的數量。但是沒有解決如何訪問這些服務的問題。
一個 Pod 只是一個運行服務的實例,隨時可能在節點上停止,然後再新的節點上用一個新的 IP 啟動一個新的 Pod,因此不能使用確定的 IP 和埠號提供服務。這對於業務來說,就不能根據 Pod 的 IP 作為業務調度。kubernetes 就引入了 Service 的概 念,它為 Pod 提供一個入口,主要通過 Labels 標籤來選擇後端Pod,這時候不論後端 Pod 的 IP 地址如何變更,只要 Pod 的 Labels 標籤沒變,那麼 業務通過 service 調度就不會存在問題。
同時 service 對綁定的 Pod 提供了負載均衡的功能,我們業務直接使用 service 即可。
當聲明Service的時候,會自動生成一個cluster IP,這個IP是虛擬IP。我們就可以通過這個IP來訪問後端的Pod,當然,如果集群配置了DNS服務,比如現在 的CoreDNS,那麼也可以通過Service的名字來訪問,它會通過DNS自動解析Service的IP地址。
Service 對外暴露服務的方式
1、ClusterIP (默認) :在集群的內部 IP 上公開 Service 。這種類型使得 Service 只能從集群內訪問,一般這種類型的 Service 上層會掛一個 Ingress,通過 Ingress 暴露服務;
2、NodePort:在每個選定 Node 的相同埠上公開 Service,使用 <NodeIP>:<NodePort>
即可從集群外部訪問 Service;
3、LoadBalancer:使用雲廠商的 K8S 集群,即可使用這種方式的暴露 Service,自建的服務一般不支援。使用 LoadBalancer ,會生成一個 IP 地址,通過這個即可訪問 Service, 通知這個 IP 也是高可用的;
4、ExternalName: 通過返回帶有該名稱的 CNAME 記錄,使用任意名稱(由 spec 中的externalName指定)公開 Service。不使用代理。這種類型需要kube-dns的v1.7或更高版本。
什麼是 CNAME:這種記錄允許您將多個名字映射到同一台電腦。
例如:當您擁有多個域名需要指向同一伺服器IP,此時您就可以將一個域名做A記錄指向伺服器IP,然後將其他的域名做別名(即CNAME)到A記錄的域名上;那麼當您的伺服器IP地址變更時,您就可以不必對一個一個域名做更改指向了,只需要更改A記錄的那個域名到伺服器新IP上,其他做別名(即CNAME)的那些域名的指向將自動更改到新的IP地址上(以上操作均需要在DNS處執行)。
ingress
Ingress 是反向代理規則,用來規定 HTTP/S 請求應該被轉發到哪個 Service 上,比如根據請求中不同的 Host 和 url 路徑讓請求落到不同的 Service 上。
Ingress Controller
就是一個反向代理程式,它負責解析 Ingress 的反向代理規則,如果 Ingress 有增刪改的變動,所有的 Ingress Controller
都會及時更新自己相應的轉發規則,當 Ingress Controller
收到請求後就會根據這些規則將請求轉發到對應的 Service。
Kubernetes 並沒有自帶 Ingress Controller
,它只是一種標準,具體實現有多種,需要自己單獨安裝,常用的是 Nginx Ingress Controller
和 Traefik Ingress Controller
。
一個集群中可以有多個 Ingress Controller
, 在Ingress 中可以指定使用哪一個 Ingress Controller
。
Ingress Controller
是部署在集群中的,怎麼讓 Ingress Controller
本身能夠被外面訪問到呢?
1、Ingress Controller 用 Deployment 方式部署,給它添加一個 Service,類型為 LoadBalancer,這樣會自動生成一個 IP 地址,通過這個 IP 就能訪問到了,並且一般這個 IP 是高可用的(前提是集群支援 LoadBalancer,通常雲服務提供商才支援,自建集群一般沒有);
2、使用 hostPort;
-
1、
Ingress Controller
用 DaemonSet 方式部署,使用集群內部的某個或某些節點作為邊緣節點,給 node 添加 label 來標識,使用 nodeSelector 綁定到邊緣節點,保證每個邊緣節點啟動一個Ingress Controller
實例,用 hostPort 直接在這些邊緣節點宿主機暴露埠,然後我們可以訪問邊緣節點中Ingress Controller
暴露的埠,這樣外部就可以訪問到Ingress Controller
了; -
2、使用非親緣性策略,使需要部署
Ingress Controller
的節點,每個節點都有一個Ingress Controller
部署,然後用 hostPort 直接在這些邊緣節點宿主機暴露埠,我們就能通過這些節點的 IP 和 hostPort來訪問Ingress Controller
了。
不過使用 hostPort 這種方式,我們還需要再上面部署一層負載均衡。
什麼是 hostPort
這是一種直接定義 Pod 網路的方式。
hostPort 是直接將容器的埠與所調度的節點上的埠路由,這樣用戶就可以通過宿主機的 IP 加上來訪問 Pod 了,比如:
apiVersion: v1
kind: Pod
metadata:
name: influxdb
spec:
containers:
- name: influxdb
image: influxdb
ports:
- containerPort: 8086
hostPort: 8086
節點(Node)
k8s 中通過將容器放入到節點 Node 上運行的 Pod 中來執行工作負載。 k8s 中的計算能力就是由 node 提供。
節點可以是物理機也可以是虛擬機,取決於集群的配置,通常 k8s 集群中,有越多的 node 節點,意味著有更強的計算能力。
命名空間(Namespace)
命名空間為 Kubernetes 集群提供虛擬的隔離作用,Kubernetes 集群初始有兩個命名空間,分別是默認命名空間 default 和系統命名空間 kube-system,除此以外,管理員可以可以創建新的命名空間滿足需要。
名字空間適用於存在很多跨多個團隊或項目的用戶的場景。對於只有幾到幾十個用戶的集群,根本不需要創建或考慮名字空間。
k8s 中的部署過程
這裡用一個簡單的栗子來看下,看下 k8s 中應用的部署過程。
1、創建命名空間
$ kubectl create namespace study-k8s
2、使用 deployment 部署 pod
$ cat go-web.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: go-web
name: go-web
namespace: study-k8s
spec:
replicas: 5
selector:
matchLabels:
app: go-web
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: go-web
spec:
containers:
- image: liz2019/test-docker-go-hub
name: go-app-container
resources: {}
status: {}
運行
$ kubectl apply -f go-web.yaml -n study-k8s
$ kubectl get pods -n study-k8s
NAME READY STATUS RESTARTS AGE
go-web-59f7dc559c-g2hjg 1/1 Running 0 5h21m
go-web-59f7dc559c-g6p8k 1/1 Running 0 5h21m
go-web-59f7dc559c-l4fgm 1/1 Running 0 5h21m
go-web-59f7dc559c-lqvpj 1/1 Running 0 5h21m
go-web-59f7dc559c-rrdjp 1/1 Running 0 5h21m
$ kubectl describe deployment nginx-deploy -n study-k8s
Name: go-web
Namespace: study-k8s
CreationTimestamp: Wed, 07 Sep 2022 15:33:58 +0800
Labels: app=go-web
Annotations: deployment.kubernetes.io/revision: 1
Selector: app=go-web
Replicas: 5 desired | 5 updated | 5 total | 5 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=go-web
Containers:
go-app-container:
Image: liz2019/test-docker-go-hub
Port: <none>
Host Port: <none>
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: go-web-59f7dc559c (5/5 replicas created)
Events: <none>
Deployment 為 Pod 和 Replica Set
提供聲明式更新。所以可以看到創建的 Deployment 裡面就同時也創建好了 Replica Set
。
3、為服務創建 service
上面我們創建了一組 Pod ,接下來,我們藉助於 service 來實現對這些 Pod 的訪問。
$ cat go-web-svc.yaml
apiVersion: v1
kind: Service
metadata:
name: go-web-svc
labels:
run: go-web-svc
spec:
selector:
app: go-web
ports:
- protocol: TCP
port: 8000
targetPort: 8000
name: go-web-http
運行
$ kubectl apply -f go-web-svc.yaml -n study-k8s
$ kubectl get svc -n study-k8s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
go-web-svc ClusterIP 10.233.9.188 <none> 8000/TCP 37s
$ kubectl describe svc go-web-svc -n study-k8s
Name: go-web-svc
Namespace: study-k8s
Labels: run=go-web-svc
Annotations: <none>
Selector: app=go-web
Type: ClusterIP
IP: 10.233.9.188
Port: go-web-http 8000/TCP
TargetPort: 8000/TCP
Endpoints: 10.233.111.104:8000,10.233.111.105:8000,10.233.111.106:8000 + 2 more...
Session Affinity: None
Events: <none>
可以看到 service 已經創建完成。
4、配置 ingress 的轉發策略
service 已經創建成功了,接下來我們使用 ingress
$ cat go-web-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: go-web-ingress
annotations:
kubernetes.io/ingress.class: nginx
spec:
rules:
- host: www.go-web.com
http:
paths:
- path: /index
pathType: Prefix
backend:
service:
name: go-web-svc
port:
number: 8000
部署 ingress
$ kubectl apply -f go-web-ingress.yaml -n study-k8s
$ kubectl get ingress -n study-k8s
NAME CLASS HOSTS ADDRESS PORTS AGE
go-web-ingress <none> www.go-web.com 11.11.111.113 80 107s
通過 ingress 訪問
$ curl '11.11.111.113:80/index' \
--header 'Host: www.go-web.com'
<h1>hello world</h1><div>你好</div>%
也可以在本地添加 host,通過域名訪問
$ sudo vi /etc/hosts
// 根據ingress部署的iP
11.11.111.113 www.liz-test.com
總結
1、Pod 是 k8s 中集群部署應用和服務的最小單元;
2、RC 是 k8s 集群中最早的保證 Pod 高可用的 API 對象。它的作用就是保證集群中有指定數目的 pod 運行;
3、RS 是新一代 RC,提供同樣的高可用能力,是目前主要使用的對象;
4、Deployment 提供了一種對 Pod 和 ReplicaSet 的管理方式,RS 的使用都是結合 Deployment 來完成的。
5、一般使用 Deployment 來滾動升級一個服務,滾動升級一個服務,實際是創建一個新的 RS,然後逐漸將新 RS 中副本數增加到理想狀態,將舊 RS 中的副本數減小到 0 的複合操作;這樣一個複合操作用一個 RS 是不太好描述的,所以用一個更通用的 Deployment 來描述。
6、RC、RS 和 Deployment 只是保證了支撐服務的微服務 Pod 的數量。但是沒有解決如何訪問這些服務的問題。一個 Pod 只是一個運行服務的實例,隨時可能在節點上停止,然後再新的節點上用一個新的 IP 啟動一個新的 Pod,因此不能使用確定的 IP 和埠號提供服務。這對於業務來說,就不能根據 Pod 的 IP 作為業務調度。kubernetes 就引入了 Service 的概 念,它為 Pod 提供一個入口,主要通過 Labels 標籤來選擇後端Pod,這時候不論後端 Pod 的 IP 地址如何變更,只要 Pod 的 Labels 標籤沒變,那麼 業務通過 service 調度就不會存在問題。
7、Service 是後端真實服務的抽象,一個 Service 可以代表多個相同的後端服務;
8、Ingress 是反向代理規則,用來規定 HTTP/S 請求應該被轉發到哪個 Service 上,比如根據請求中不同的 Host 和 url 路徑讓請求落到不同的 Service 上;
參考
【Kubernetes 的設計理念】//jimmysong.io/kubernetes-handbook/concepts/concepts.html
【Kubernetes中文文檔】//docs.kubernetes.org.cn/
【通俗理解Kubernetes中Service、Ingress與Ingress Controller的作用與關係】//cloud.tencent.com/developer/article/1167282
【CNAME記錄】//zh.m.wikipedia.org/zh-hans/CNAME記錄
【CNAME】//baike.baidu.com/item/CNAME/9845877
【k8s中幾個基本概念的理解】//boilingfrog.github.io/2022/09/11/k8s總體概覽/