部署Dotnet Core应用到Kubernetes(二)
前一篇文章,概念性地介紹了K8s的一些基礎組件,如Pod、部署和服務。這篇文章,我打算寫寫如何使用YAML清單定義和配置這些資源。
?
實際上,在K8s集群中創建對象有幾種方式 - 命令,或聲明。兩種方式區別不大。
不過實際應用中,一旦開始真正部署應用,最終都會走到YAML配置文件方式。這種方式也叫配置清單。每個資源類型的清單,例如部署、服務、入口,他們的格式會略有不同,盡管他們之間存在著共性。
這篇文章,我就著重寫寫如何使用YAML清單定義和配置這些資源。當然,涉及內容太多,我們還是面向實際應用,寫寫通用的,和最有針對性的配置格式,而不詳細解釋所有的配置選項和排列。
Pod和部署的配置清單
前文我們說過,Pod是K8s最小的可部署單元。我們部署Pod,不是部署單個容器,而是部署包含一個或多個容器的Pod。這個概念一定要清楚。
K8s中部署獨立的Pod是可以的。但在實際應用中,最常見的做法是將Pod部署成為“部署資源”的一部分。
所以,通常我們的做法,是在部署清單中定義Pod資源,而不是創建一個Pod,然后創建一個部署來管理他們。換句話說,我們是創建了一個知道如何為我們創建Pod的部署。
我們先來看一個相對基礎的部署清單:
apiVersion:?apps/v1 kind:?Deployment metadata:name:?nginx-deploymentlabels:app:?nginx spec:replicas:?3strategy:?type:?RollingUpdaterollingUpdate:maxUnavailable:?1maxSurge:?1maxUnavailable:?1selector:matchLabels:app:?nginxtemplate:metadata:labels:app:?nginxspec:containers:-?name:?nginximage:?nginx:1.19.3ports:-?containerPort:?80YAML對空格敏感,所以寫的時候一定要注意縮進。
1. apiVersion、kind、metadata
這是K8s配置清單的開頭,每個清單都會有這三個項。
?
apiVersion:?apps/v1apiVersion用來指示K8s API的版本。K8s有很多個API版本。以下命令可以查詢已經安裝的全部版本。
%?kubectl?api-versionsK8s的每個版本都包含了不同的API資源版本。
大多數情況下,配置應用時不需要太多關注這個版本號,對應好就成。
?
kind:?Deployment定義清單的類型。前面說了,各種資源都有不同的配置清單。本例中是部署。
?
metadata:name:?nginx-deploymentlabels:app:?nginx元數據提供了諸如資源名稱以及附加到資源上的標簽等細節。
需要注意一下:標簽是與資源相關的鍵值對,后面我們會用到。本例中,我們只有一個標簽app,值是nginx。
2. spec
這是K8s清單中的規范資源部分,這部分才是實際指定類型的資源定義,在本例中,是部署(kind: Deployment)的配置。
?
??replicas:?3strategy:?type:?RollingUpdaterollingUpdate:maxUnavailable:?1maxSurge:?1maxUnavailable:?1副本和策略,定義了部署應該創建多少個Pod實例,以及創建他們應該使用的方法。本例中,我們希望K8s同時運行三個Pod,并且部署新版本時使用滾動更新。
在策略中,我們設置maxUnavilable為1,這是更新策略的一個額外設置,表示我們希望在發布部署新版本時,在需要用新版本替換舊版本的Pod過程中,或者開始新Pod之前,每次只刪除一個舊Pod。
maxSurge和maxUnavailable也是額外設置。maxSurge控制滾動更新時一次應該添加多少額外的容器,而maxUnavilable則定義了一個容器要運行多少秒后才可被認為是可用的。
?
??selector:matchLabels:app:?nginxselector部分定義這個部署管理哪些Pod。這里面涉及到元數據和選擇器的相互配合,我們后面會說到。
?
??template:metadata:labels:app:?nginxspec:containers:-?name:?nginximage:?nginx:1.19.3ports:-?containerPort:?80部署的spec節的最后一個部分是模板。這是一個清單內的清單,里面也同樣有metadata和spec。這里的內容實際是一個Pod的定義配置清單。
因此,這整個部署清單定義了兩種類型的資源:Pod,和用于管理Pod擴展和生命周期的部署。
上面這個Pod模板,定義了一個叫nginx的容器,是由nginx 1.19.3鏡像構建的。這里containerPort定義了容器內公開的端口。默認80,可不寫。不過我自己覺得,寫出來是一個好習慣。
?
如果我們想在Pod中部署兩個容器,則需要在containers下添加另一個:
template:metadata:labels:app:?nginxspec:containers:-?name:?nginximage:?nginx:1.19.3ports:-?containerPort:?80-?name:?nginx1image:?nginx:1.19.3ports:-?containerPort:?8080例子中,我們添加的第二個容器,名稱叫nginx1,也是nginx 1.19.3鏡像,端口在8080。
?
上面就是部署清單的基本內容。這部分內容很多,需要了可以查K8s相關的部分。
前面說了,K8s清單不同類型的規范會稍有不同,但他們的共同之處也很多,比如元數據和選擇器。所以學通了一個,其它基本上也就通了。
標簽和選擇器的配合
標簽是K8s中最廣泛使用的一個概念,是與對象關聯的一個鍵值對。每個對象都可以有幾個不同的標簽,但每個鍵只能定義一次。
看前邊的例子:
metadata:name:?nginx-deploymentlabels:app:?nginx有一個鍵名叫app,值是nginx。
同樣,在spec的template中:
spec:template:metadata:labels:app:?nginx這里,我們向Pod添加了同樣的鍵值對。
在需要的情況下,我們還可以添加其它的標簽,例如:
metadata:labels:app:?nginxenvironment:?stagingsystem:?frontend這兩個標簽的用處,可以自己去查。
標簽在命令行管理的時候非常有用。例如下面的命令:
kubectl?get?pods?-l?environment=staging,system=frontend可以查出所有具有staging和frontend標簽的Pod。
標簽在這里,主要是提供附加信息。所以,實際中可以加上各種合適的標簽。同樣,在選擇器定義時,也可以通過這些標簽來區分不同的資源。例如:
selector:matchLabels:app:?nginx這里面,選擇器定義了所選資源的條件。滿足條件的資源,才會被匹配。例如,上面這個選擇器將匹配所有具有app標簽且值為nginx的Pod。
同樣,對應上面的命令行,選擇器可以寫為:
selector:matchLabels:environment:?stagingsystem:?frontend這兒要注意:這個匹配的全條件的,條件之間是與的關系。當然,還有一些資源可以支持更多的匹配表達式,例如:In、NotIn、Exists或DoesNotExist。
?
除了部署外,服務也使用相同的機制來定義它將數據傳遞給哪個Pod。
服務的配置清單
在前文中說過,服務可以看作集群內的負載均衡,負責隔離并轉發向Pod發出的請求。
我們來看一個清單的例子:
apiVersion:?v1 kind:?Service metadata:name:?my-shop-backendlabels:?app:?my-shopsystem:?backend spec:type:?ClusterIPselector:app:?my-shopsystem:?backendports:-?port:?80targetPort:?8080protocol:?TCP1. apiVersion、kind、metadata
跟前邊一樣,先定義清單的資源類型,這回是服務,以及所需的API版本。元數據為服務指定了一個名稱,并加了兩個標簽用來記錄和提供信息。
2. spec
首先,需要定義服務類型。根據K8s的版本,這兒有4種選擇:
ClusterIP,默認值,定義服務只能從內部訪問;
NodePort,在每個節點自動生成的端口上公開服務;
loadbalance,在連接AWS、Azure等云服務時,提供負載均衡;
ExternalName,這個有點特殊,它不做代理或轉發,而只提供內部的DNS服務。
實際應用中,通常就用默認的ClusterIP,把服務作為內部負載均衡器,并使用入口將外部請求轉發到服務的結構就OK了。
下一個是選擇器,這個配置具體控制負載均衡的實現配置。如前一節所寫的,選擇器將選擇所有具有所需標簽的Pod,在本例中是app:my-shop和system:backend。服務將把所有傳入的請求路由到這些服務??聪旅娴牟糠?#xff1a;
spec:selector:app:?my-shopsystem:?backend最后,是清單中的端口配置。例子中定義了服務將被公開的端口80以及要使用的協議,本例中是TCP。targetPort是Pod上的端口,表示請求將會被傳發到8080。這一段單摘出來如下:
spec:ports:-?port:?80targetPort:?8080protocol:?TCP這個部分因為涉及到網絡,所以配置可以很復雜。必要時,可以參考K8s的文檔。
?
在應用中,通常需要向外部公開某種HTTP服務。部署部分處理應用程序Pod的管理,服務提供多個Pod內部的負載均衡,而入口將應用暴露給外部。
入口的配置清單
前文中說過,入口充當內部K8s服務的外部負載均衡或反向代理。下面的例子展示了如何公開內部服務到外網:
apiVersion:?extensions/v1beta1 kind:?Ingress metadata:name:?my-shop-backend-ingresslabels:?app:?my-shopsystem:?backendannotations:nginx.ingress.kubernetes.io/rewrite-target:?/ spec:rules:-?http:host:?api.my-shop.compaths:-?path:?/my-shopbackend:serviceName:?my-shop-backendservicePort:?801. apiVersion、kind、metadata
同樣,入口清單也包含API版本、類型和元數據。不同的是,入口的元數據還包含入口的名稱以及關聯對象的標簽。
此外,還多了一個注釋標簽annotations。注釋標簽的工作原理與前面提到的標簽很相似,也都是鍵值對。不同的是注釋標簽不能用來選擇對象。
本例中,我們添加了注釋nginx.ingress.kubernetes.io/rewrite-target,值為/。這個注釋用到了Nginx入口控制器的一個特殊鍵值,用來告訴控制器重寫傳入請求的匹配路徑為“/”。
例如,在以下路徑收到一個請求:
/my-shop/orders/123入口控制器將重寫到:
/orders/123?
另外,為了使用入口,集群中需要部署一個入口控制器。每個入口控制器會有不同的特性,都需要不同的注釋來配置。因此,入口配置清單可能會根據不同的作用而有所不同。
2. spec
入口清單的spec部分包含配置由集群的入口控制器管理的反向代理所需要的全部規則。如果你用過Nginx、IIS或其它類似的反代,那應該會容易理解,規則很相似,都是定義了一組傳入請求的規則,以決定將他們路由到什么路徑。
入口清單可以定義多種規則,但一定要記著可部署單元的概念。我們應該為部署到K8s的每個應用配置單一入口,而不是跨應用去配置入口,盡管這樣做技術上支持。
看上面例子的spec段:
spec:rules:-?http:host:?api.my-shop.compaths:-?path:?/my-shopbackend:serviceName:?my-shop-backendservicePort:?80通常我會習慣用主機來區分不同的應用,像例子中的api.my-shop.com。當然,您也可以通過匹配路徑來定義,例如/my-shop。而這個會根據元數據中的重寫定義注釋被重寫。
除了匹配傳入的路徑和主機外,清單中還需要定義請求轉發的內部服務和端口。本例中,我們用了同樣的80端口去路由到上一節中定義的后端服務中。
?
上面這個例子是最常見的一個入口清單定義,只將傳入的請求與單個服務匹配。
有時候,可能會幾種不同類型的Pod組成一個服務“微單元”。這種情況下,也可能會有幾個K8s服務,并且基于路徑將幾個服務路由到單一入口內,這時候可以這樣配置:
spec:rules:-?http:paths:-?path:?/ordersbackend:serviceName:?my-shop-orders-serviceservicePort:?80-?http:paths:-?path:?/historybackend:serviceName:?my-shop-order-history-backendservicePort:?80?
在K8s配置時,入口中可以加入很多配置。這部分如果有問題,可以去翻K8s文檔。
如果只是需要將應用部署到K8s,那上邊的內容基本夠用了。唯一要注意的是集群中用了哪個入口控制器。
總結一下
這篇文章是這個系列的第二篇。
這篇文章介紹了我們必須要知道的K8s的主要資源:Pod、部署、服務、入口的YAML基本配置,并列出了一些最重要的配置值。
K8s這個東西,做為一個大的分布式架構,肯定是比較復雜的。但實際應用中,不是每個內容都需要理解和應用。
做多了,就是套路。
蹚過了,就是經驗。
(未完待續)
喜歡就來個三連,讓更多人因你而受益
總結
以上是生活随笔為你收集整理的部署Dotnet Core应用到Kubernetes(二)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 持续交付二:为什么需要多个环境
- 下一篇: Winform 进度条弹窗和任务控制