什麼是Kubernetes部署?
在此文章中,我們將探索Kubernetes(K8s),結合DigitalOcean Kubernetes叢集與Buddy自動化運維繫統部署以達到以下列出的目標:
- 使用一個K8s示例應用透過Buddy流水線操作構建Docker映象並推送至Docker Hub註冊中心
- 透過K8s示例應用設定兩個Hello World演示部署於K8s叢集之中以便測試負載均衡器
- 為K8s示例應用安裝Ingress NGINX控制器於K8s叢集之中
- 使用Cert-Manager新增域名SSL證書
K8s優勢
K8s可以將其描述為一個容器編排平臺,它可以在雲端或遠端機器上擴充套件和執行您的應用程式。為了更容易理解,您可以把它想象成一個容器管理器,它會自動處理您必須手動執行的操作。
以下是使用K8s的一些優勢:
- 自愈能力 – 透過自動排程程式,K8s能夠在出現錯誤或超時的情況下用新容器替換容器。
- 滾動(Rollouts)與回滾(Rollbacks) – 除了自我修復能力外,K8s還實現了新部署滾動,類似於藍綠色部署,大大減少了停機機會。
- 負載分配和自動發現 – 在K8s上執行的解耦應用程式能夠在本地叢集網路上進行通訊,從而減少公開應用程式地址所需的工作量。除此之外,K8s還有多個負載分配點。這意味著,您可以將負載從入口層和服務層分配到Pod。
- 橫向與縱向擴充套件 – K8s允許我們根據場景進行橫縱擴充套件。您可以執行同一應用程式的500多個容器,並且仍然幾乎毫不費力地管理分配給每個容器的資源。說明K8s為您的應用程式提供彈性伸縮!
- 交付速率 – 釋出應用程式的速度對當今每個團隊都至關重要。過去,釋出必須由許多團隊成員在預定維護期間完成,期間會出現很多中斷和停機時間。
即使沒有持續部署,K8s也能夠在幾乎沒有停機時間的情況下促進和管理各種規模的釋出。
K8s構架
K8s本身由幾個元件組成。但我們不會在本文中介紹所有內容,主要關注於容器,我們還將使用Docker。
K8s上的容器以稱為Pod的組合執行。Pod中的容器共享相同的網路、儲存和地址。這說明訪問pod的地址實際上意味著訪問pod中的容器之一:
雖然您確實不需要流水線來讓應用程式在雲服務上執行,但由於SDK,在更大範圍內,團隊會發現依賴本地機子部署效率非常低。
K8s部署工作原理
流水線可以被認為是將服務或應用程式從A點移動到B點的一種方式。在CI/CD方面,我們可以將其分為三種型別:
- 持續整合 – 透過GitHub等版本控制平臺對程式碼進行測試和版本控制。這就是Buddy的用武之地,它提供了更簡單、更高效的流水線配置方式。
- 持續交付 – 有助於將應用程式從版本控制平臺部署到雲服務或其他供應商特定的服務。交付流水線需要批准才能部署到特定環境,例如生產環境或面向客戶的環境。
- 持續部署 – 無需人為干預、批准或輸入,即可輕鬆自動部署到雲端。
微服務模式引入了一種新的軟體實現方式。將此視為一種移動模式,涉及多個移動部件,所有部件都統一起來以呈現單個應用程式。
無論有沒有DevOps工作人員,您的團隊都不必擔心與運維相關的問題,比如弄清楚三個應用程式元件的交付。最重要的是保持對產品的聚焦。
K8s自動化陷阱
技術棧
過去,部署堆疊主要基於Shell指令碼構建。對於以前沒有堆疊經驗的團隊成員來說,這通常很複雜。現在,幾乎每個平臺都提供 YAML。作為一種宣告式和更透明的語言,YAML的學習曲線相當容易。然而,不幸的是,有些平臺仍然需要YAML上對shell的解決方案。
Buddy憑藉著其直觀的GUI和流水線宣告式YAML配置解決了這些問題。
安全性
安全性是任何流水線的關鍵組成部分。關鍵的安全問題之一是處理金鑰和敏感資訊。在大多數情況下,金鑰或敏感資訊在進行加密後作為環境變數新增到平臺上,然後在構建過程中進行轉譯和解密。在定義這些作業的過程中,很容易透過列印金鑰或對公共Docker映象進行版本控制來洩露這些細節資訊。同時還建議避免在第三方服務上使用不受限制的API金鑰。
Buddy如何處理安全問題
- 只需按一下按鈕即可自動加密和手動加密。
- 儲存倉通用的操作變數建議和預設環境變數
模糊的平臺與工具關聯
平臺關聯肯定是最大的挑戰之一。不同的團隊以不同的方式處理此問題:從開箱即用的特定於平臺YAML模組到指令碼連線。建議採用模組化方法代替指令碼化流水線,通常涉及幾個步驟:從獲取SDK到授權,再到實際部署。這通常會導致相當複雜、容易出錯且體積龐大的流水線。
Buddy提供與各大商家的各種整合,以及具有宣告性流水線操作模式豐富的buddy.yml
指令碼。
K8s部署如何工作? 示例流水線
本文的K8s示例應用可以在這個GitHub Repo中下載原始碼!
構建與推送Docker映象
首先建立一個名為hello的Buddy專案,並選擇Buddy自帶的Git託管作為程式碼儲存倉:
- 如果您還沒有Buddy帳號可在此免費建立一個
下載GitHub儲存倉中的原始碼並推送至剛剛建立的專案儲存倉:
然後在Buddy中新增DigitalOcean整合,以方便持續整合所要使用的DigitalOcean Kubernetes叢集:
流水線中新增操作
在hello專案中建立一條流水線:
接下來,我們將在流水線上新增第一個操作,即Docker構建映象,為將所構建的映象推送至Docker Hub而做準備:
選擇儲存倉上的Dockerfile
檔案並提交完成新增Docker構建映象操作:
新增第二個操作:推送Docker映象
推送Docker映象的作用是可將上一個操作構建好的映象推送至目標Docker註冊中心,也就是Docker映象儲存倉,例如:Docker Hub、Amazon ECR、Google GCR以及私有的映象註冊中心等等不一。
如果您是第一次接觸Docker映象構建,推薦使用Docker Hub,目前只需要在Docker官方網站上免費註冊一個帳戶即可使用。
填寫好相關要推送的映象資訊完成新增推送Docker映象
此時,您應該看到如下圖有兩個操作新增於流水線之中:
執行流水線
點選以上藍色“執行”按鈕開始執行流水線:
獲取Docker映象資訊
執行完成之後,我們就可以在Docker Hub帳戶中看到已有相關映象資訊顯示:
自動化部署K8s叢集
部署第一個Hello World
在hello專案儲存倉中新增第一個Hello World YAML檔案hello-kubernetes-first.yaml
,同時在檔案中新增以下程式碼:
apiVersion: v1
kind: Service
metadata:
name: hello-kubernetes-first
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 8080
selector:
app: hello-kubernetes-first
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-kubernetes-first
spec:
replicas: 3
selector:
matchLabels:
app: hello-kubernetes-first
template:
metadata:
labels:
app: hello-kubernetes-first
spec:
containers:
- name: hello-kubernetes
image: paulbouwer/hello-kubernetes:1.10
ports:
- containerPort: 8080
env:
- name: MESSAGE
value: 這是第一個Hello World部署!
此配置定義了部署(Deployment
)和服務(Service
)。 部署包含aulbouwer/hello-kubernetes:1.7
映象的三個副本(replicas
)和一個名為MESSAGE
的環境變數(您將在訪問應用程式時看到此資訊)。這裡的服務(Service
)定義為在80
埠顯露(expose
)叢集內的部署(Deployment
)。
在流水線中新增K8s提交部署操作:
新增hello-kubernetes-first.yaml
檔案,這個檔案將在流水線執行時提交部署至K8s叢集中:
部署第二個Hello World
根據以上相同的新增步驟再新增一個hello-kubernetes-second.yaml
檔案作為第二個Hello World演示,並在檔案中新增以下程式碼:
apiVersion: v1
kind: Service
metadata:
name: hello-kubernetes-second
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 8080
selector:
app: hello-kubernetes-second
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-kubernetes-second
spec:
replicas: 3
selector:
matchLabels:
app: hello-kubernetes-second
template:
metadata:
labels:
app: hello-kubernetes-second
spec:
containers:
- name: hello-kubernetes
image: paulbouwer/hello-kubernetes:1.10
ports:
- containerPort: 8080
env:
- name: MESSAGE
value: 這是第二個Hello World部署!
此時我們就可以在流水線中看到如下圖所示的流水線資訊:
如上圖在流水線上點選藍色“執行”按鈕,將會看到如下圖所示的構建Docker映象、推送Docker映象以及提交兩個Hello World YAML配置檔案至K8s叢集的流水線執行資訊:
在命令列介面上執行以下命令:(建立DigitalOcean Kubernetes叢集時會提示您如何配置您的電腦與其連線)
kubectl get service
執行以上程式碼後會顯示以下資訊
hello-kubernetes-first和hello-kubernetes-second都已列出,說明已經建立成功Kubernetes。
您已經使用Buddy自動化運維建立了hello-kubernetes應用程式的兩個部署。每個在部署規範中都有不同的資訊顯示,以便在測試期間區分。 下一步,我們將安裝Nginx Ingress Controller:
安裝Nginx Ingress
我們將使用Helm安裝Nginx Ingress 控制器
Nginx Ingress控制器 由一個Pod和一個Service組成。Pod執行控制器,控制器不斷輪詢叢集API伺服器上的/ingresses
端點以獲取可用Ingress資源的更新。該服務的型別為LoadBalancer
。因為您將其部署到DigitalOcean Kubernetes叢集,叢集將自動建立一個DigitalOcean負載均衡器,所有外部流量將透過該負載均衡器流向控制器。然後控制器會將流量路由到適當的服務,如Ingress資源中定義的那樣。
只有LoadBalancer
服務知道自動建立的負載均衡IP地址。某些應用程式(例如:ExternalDNS)需要知道其IP地址,但只能讀取Ingress的配置。透過在helm install
安裝期間將controller.publishService.enabled
引數設定為true
,可以將控制器配置為在每個Ingress上釋出IP地址。建議啟用此設定以支援可能依賴於負載均衡器IP地址的應用程式。
要安裝 K8s Nginx Ingress 控制器,我們首先需要透過執行以下命令將其儲存庫新增到Helm:
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
更新系統,讓Helm知道所包含的內容:
helm repo update
最後,執行以下命令安裝Nginx Ingress:
helm install nginx-ingress ingress-nginx/ingress-nginx --set controller.publishService.enabled=true
此命令從穩定chart儲存倉安裝Nginx Ingress,將Helm版本命名為nginx-ingress
,並將publishService
引數設定為true
。
執行後,您將看到類似以下的輸出:
Helm已將其在Kubernetes中建立的資源記錄為chart安裝的一部分。
執行此命令以檢視負載均衡器是否可用:
kubectl --namespace default get services -o wide -w nginx-ingress-ingress-nginx-controller
該命令在預設名稱空間中獲取Nginx Ingress服務並輸出其資訊,但該命令不會立即退出。使用-w
引數,它會在發生更改時監測並重新整理輸出資訊。
我們已經安裝了由Kubernetes社群維護的Nginx Ingress。它將HTTP和HTTPS流量從負載均衡器路由到Ingress資源中適配後端服務。 下一步,我們將顯露(expose)公開hello-kubernetes
應用程式部署。
使用Ingress顯露公開應用程式
在公開應用程式之前,我們需要準備兩個域名並指向負載均衡器IP,我們將使用以下兩個域名作為演示:
- 1.m2jd.com
- 2.m2jd.com
首先,透過以上已在Buddy建立的hello專案儲存倉中再建立一個名為hello-kubernetes-ingress.yaml的檔案,並新增以下程式碼部署兩個示例域名以便在瀏覽器中測試:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: hello-kubernetes-ingress
annotations:
kubernetes.io/ingress.class: nginx
spec:
rules:
- host: "1.m2jd.com"
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: hello-kubernetes-first
port:
number: 80
- host: "2.m2jd.com"
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: hello-kubernetes-second
port:
number: 80
我們使用名稱hello-kubernetes-ingress定義Ingress資源。然後指定兩個主機規則,以便將1.m2jd.com域名轉向路由到hello-kubernetes-first服務,並將2.m2jd.com域名轉向路由到第二個部署hello-kubernetes-second的服務。
接下來,新增hello-kubernetes-ingress.yaml檔案到流水線操作提交Kubernetes部署之中並執行流水線。我們就可看到如下圖的hello-kubernetes-ingress部署到K8s叢集的Buddy流水線執行記錄:
現在我們可以在瀏覽器中開啟域名1.m2jd.com即可看到如下顯示:
在瀏覽器中開啟域名2.m2jd.com即可看到如下顯示:
用Cert-Manager加強Ingress安全
為了保護Ingress資源,我們將安裝Cert-Manager,為生產運營建立ClusterIssuer
,並修改Ingress的配置以使用TLS證書。安裝和配置後,應用程式將在HTTPS之下執行。
ClusterIssuers
是Kubernetes中的Cert-Manager資源,它為整個叢集提供TLS證書。ClusterIssuer
是一種特定型別的發行者。
在透過Helm將Cert-Manager安裝到您的叢集之前,您將為它建立一個名稱空間:
kubectl create namespace cert-manager
這時,您需要將Jetstack Helm儲存倉新增到託管Cert-Manager圖譜(chart)的Helm。 為此,執行以下命令:
helm repo add jetstack https://charts.jetstack.io
Helm將顯示以下輸出資訊:
更新Helm圖譜快取:
helm repo update
更新命令執行將顯示以下輸出資訊:
最後,透過執行以下命令將Cert-Manager安裝到cert-manager名稱空間中:
helm install cert-manager jetstack/cert-manager --namespace cert-manager --version v1.10.1 --set installCRDs=true
在此命令中,我們也將installCRDs
引數設定為true
,以便在Helm安裝期間安裝cert-managerCustomResourceDefinition
配置清單。在寫本文時,v1.10.1是最新版本。您可以參考ArtifactHub查詢最新版本號。
除了在命令列介面上執行Helm命令,您也可以在Buddy流水線上新增Helm CLI操作並執行流水線:
輸出資訊將顯示如下:
我們現在建立一個由Let's Encrypt頒發的證書,並將其配置儲存在名為production_issuer.yaml
的檔案中。在hello專案儲存倉中建立並開啟此檔案並新增以下程式碼:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
# Email address used for ACME registration
email: 請在此輸入您的電子郵件地址
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
# Name of a secret used to store the ACME account private key
name: letsencrypt-prod-private-key
# Add a single challenge solver, HTTP01 using nginx
solvers:
- http01:
ingress:
class: nginx
接下來,同樣在流水線中新增production_issuer.yaml檔案到流水線操作提交Kubernetes部署之中並執行流水線:
在hello-kubernetes-ingress.yaml檔案中新增第7行與9-13行的程式碼:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: hello-kubernetes-ingress
annotations:
kubernetes.io/ingress.class: nginx
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
tls:
- hosts:
- 1.m2jd.com
- 2.m2jd.com
secretName: hello-kubernetes-tls
rules:
- host: "1.m2jd.com"
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: hello-kubernetes-first
port:
number: 80
- host: "2.m2jd.com"
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: hello-kubernetes-second
port:
number: 80
提交檔案後Buddy將自動為您執行流水線,此時您的域名已支援SSL證書,恭喜!
在實際操作中,請將域名換成您自己的域名,而不是照搬1.m2jd.com與2.m2jd.com,那樣將不會正常執行!
K8s部署最佳化
Kubernetes是一個基於容器的平臺,用於部署、擴充套件和執行應用程式。Buddy讓您可以透過一系列專用的K8s操作來自動化您的Kubernetes交付工作流。
每次更改應用程式程式碼或Kubernetes配置時,您都有兩個選項來更新叢集:kubectl apply
或 kubectl set image
。
在這種情況下,您的工作流程通常如下所示:
- 編輯程式碼或配置.yaml
- 將其推送至您的Git儲存倉
- 構建新的Docker映象
- 推送至Docker映象
- 登入至您的K8s叢集
- 執行
kubectl apply
或kubectl set image
如果您經常使用 kubectl apply
或 kubectl set image
,這個就是更好的解決方案!
如何自動執行K8s pod或任務
如果你經常在容器中執行任務,比如:
- 新版本部署時資料庫遷移
- 備份
- 批次處理作業,例如:為新版本的應用程式建立目錄結構。
您可以使用pods或任務,第一種型別使用任務啟動單個pod;第二個啟動系列pod,直到指定數量的pod以成功狀態結束。
用於執行K8s pods或任務的流水線配置
假設您在K8s叢集上有一個應用程式,儲存倉包含如下內容:
- 您的應用程式原始碼
- 一個Dockerfile檔案,其中包含有關建立應用程式映象的說明。
- 資料庫遷移指令碼
- 一個Dockerfile檔案,其中包含有關建立將在部署期間執行遷移的映象說明(資料庫遷移執行器)。
在這種情況下,您可以配置一個流水線:
A. 構建應用程式並遷移映象(第一個操作)
B. 推送至Docker Hub(第二個操作)
C. 觸發資料庫遷移 使用先前構建的映象(第三個操作)。您可以使用YAML檔案定義映象、命令和部署:
進行推送後,流水線將自動構建並將映象推送到儲存倉並執行遷移指令碼,是不是很酷?
作業操作將等到命令執行完畢,如果退出狀態不同於0,則操作將被標記為“失敗”。
D. 最後一個操作是使用提交Kubernetes部署或Kubernetes設定映象來更新K8s應用程式中的映象。新增操作後,整個流水線將如下所示:
一切就緒後,再次推送,即可看到Buddy自動執行整個工作流程。
希望您有所收穫,非常感謝您花時間閱讀本文!