使用 KinD 加速 CI/CD 流水線

現(xiàn)在安裝 Kubernetes 集群已經(jīng)變得越來越簡(jiǎn)單了,出現(xiàn)了很多方案,各種方案都有自己適合的使用場(chǎng)景。雖然我們也可以很快速在云環(huán)境下面啟動(dòng)一個(gè) Kubernetes 集群,但是對(duì)于開發(fā)人員通常更喜歡能夠快速上手的東西,Kubernetes in Docker(KinD)這個(gè)工具就可以通過創(chuàng)建容器來作為 Kubernetes 的節(jié)點(diǎn),只需要在機(jī)器上安裝 Docker 就可以使用,它允許我們?cè)诤芏痰臅r(shí)間內(nèi)就啟動(dòng)一個(gè)多節(jié)點(diǎn)的集群,而不依賴任何其他工具或云服務(wù)商,這就使得它不僅對(duì)本地開發(fā)非常有用,而且對(duì) CI/CD 也很有幫助。
KinD 架構(gòu)
KinD 使用 Docker-in-Docker 的方法來運(yùn)行 Kubernetes 集群,它啟動(dòng)多個(gè) Docker 容器來作為 Kubernetes 的節(jié)點(diǎn)。Docker 容器將 docker.sock 卷掛載到你的節(jié)點(diǎn)上運(yùn)行的 Docker 上,這樣就可以與底層的容器運(yùn)行時(shí)進(jìn)行交互了。

KinD 是使用 kubeadm 工具來啟動(dòng)管理集群,也通過了一致性測(cè)試和 CNCF 的認(rèn)證,當(dāng)然它也會(huì)為你生成訪問集群的 kubeconfig 文件,這樣我們同樣就可以使用 kubectl 來和集群進(jìn)行交互了。其他 Kubernetes 組件,比如 Helm、Istio 也同樣可以在 KinD 集群內(nèi)正常工作。
KinD 有一個(gè)缺點(diǎn)是它不能使用 LoadBalancer 的 Service,所以我們需要使用 NodePort 來對(duì)外暴露服務(wù)。
另外 DinD 也不是一個(gè)非常安全的解決方案,所以除了本地開發(fā)機(jī)和 CI/CD 流水線之外,最好不要在其他環(huán)境使用 KinD 集群,特別是生產(chǎn)環(huán)境中。
安裝
KinD 是一個(gè)簡(jiǎn)單的命令行工具,可以直接下載放置到 PATH 路徑上,然后就可以使用 kind 命令與 KinD 進(jìn)行交互了,當(dāng)然前提是要先安裝上 Docker:
$?sudo?curl?-sL?https://kind.sigs.k8s.io/dl/v0.9.0/kind-linux-amd64?-o?/usr/local/bin/kind
$?sudo?chmod?+x?/usr/local/bin/kind
$?kind?version
kind?v0.9.0?go1.15.2?linux/amd64
安裝完成后你可以使用下面的命令創(chuàng)建你的集群:
$?kind?create?cluster?--wait?10m
該命令會(huì)創(chuàng)建一個(gè)單節(jié)點(diǎn)集群,如果你想定義一個(gè)多節(jié)點(diǎn)集群,你可以使用類似下面的集群配置文件進(jìn)行創(chuàng)建:
#?kind-config.yaml
#?3個(gè)節(jié)點(diǎn)(兩個(gè)node)集群配置
kind:?Cluster
apiVersion:?kind.x-k8s.io/v1alpha4
nodes:
-?role:?control-plane
-?role:?worker
-?role:?worker
然后使用上面的配置文件創(chuàng)建集群:
$?kind?create?cluster?--wait?10m?--config?kind-config.yaml
我們也可以在 nodes 屬性部分指定多個(gè)控制平面角色來創(chuàng)建多控制平面集群。由于 KinD 會(huì)自動(dòng)創(chuàng)建一個(gè) kubeconfig 文件,所以我們可以像使用其他集群一樣使用 kubectl 命令。要想刪除 KinD 集群也很簡(jiǎn)單,直接使用如下所示的命令即可:
$?kind?delete?cluster
測(cè)試
接下來我們來體驗(yàn)一次使用 KinD 的 CI/CD 流水線,這里為了方便我們將使用 GitHub Actions 作為我們的 CI/CD 工具,任何可以訪問 GitHub 的人都可以使用。
我們來構(gòu)建一個(gè)簡(jiǎn)單的 NGINX 應(yīng)用并顯示 "Hello World",我們需要做如下一些工作:
創(chuàng)建應(yīng)用的開發(fā)版本 在 KinD 集群中運(yùn)行一個(gè)組件來測(cè)試 如果測(cè)試成功,我們將鏡像升級(jí)到 release 版本,并推送到 Docker Hub 上去。
首先我們需要一個(gè) GitHub 和 Docker Hub 帳號(hào),然后:
Fork 測(cè)試倉(cāng)庫(kù):https://github.com/cnych/kind-nginx 進(jìn)入代碼倉(cāng)庫(kù),創(chuàng)建兩個(gè) secrets:DOCKER_USER 和 DOCKER_PW,分別表示你的 Docker Hub 的用戶名和密碼。 跳轉(zhuǎn)到 GitHub Actions 并重新執(zhí)行任務(wù),當(dāng)然我們也可以修改倉(cāng)庫(kù)代碼來推送觸發(fā)這個(gè)任務(wù)。

我們可以先查看下 GitHub Actions 的流水線配置文件 build-pipeline.yml:
name:?Docker?Image?CI
on:?[push]
?????#?工作流程中所有?job?和?step?都可使用的環(huán)境變量
env:?#?或者作為環(huán)境變量
??????docker_username:?${{?secrets.DOCKER_USER?}}
??????docker_password:?${{?secrets.DOCKER_PW?}}
jobs:
??build-docker-image:
????runs-on:?ubuntu-latest
????steps:
????-?uses:?actions/checkout@v2
??????with:
????????fetch-depth:?0
????-?name:?Build?the?Docker?image
??????run:?docker?build?-t?$docker_username/nginx:dev?.
????-?name:?Login?to?Docker
??????run:?echo?"$docker_password"?|?docker?login?-u?"$docker_username"?--password-stdin
????-?name:?Push?the?docker?image
??????run:?docker?push?$docker_username/nginx:dev
??kubernetes-component-test:
????runs-on:?ubuntu-latest
????needs:?build-docker-image
????steps:
????-?uses:?actions/checkout@v2
??????with:
????????fetch-depth:?0
????-?name:?Run?KIND?Test
??????run:?sudo?sh?build-test.sh?$docker_username
??
??promote-and-push-docker-image:
????runs-on:?ubuntu-latest
????needs:?kubernetes-component-test
????steps:
????-?uses:?actions/checkout@v2
??????with:
????????fetch-depth:?0
????-?name:?Pull?the?Docker?image
??????run:?docker?pull?$docker_username/nginx:dev
????-?name:?Tag?the?Docker?image
??????run:?docker?tag?$docker_username/nginx:dev?$docker_username/nginx:release
????-?name:?Login?to?Docker
??????run:?echo?"$docker_password"?|?docker?login?-u?"$docker_username"?--password-stdin
????-?name:?Push?the?docker?image
??????run:?docker?push?$docker_username/nginx:release
從上面的流水線文件中可以看到構(gòu)建流水線中有3個(gè)作業(yè):
build-docker-image 作業(yè)會(huì)構(gòu)建開發(fā)版本的 Docker 鏡像,并在構(gòu)建成功后將其推送到 Docker Hub,我們可以在這個(gè)任務(wù)中運(yùn)行單元測(cè)試。 kubernetes-component-test 作業(yè)設(shè)置了一個(gè) KinD 集群,并為應(yīng)用程序運(yùn)行組件進(jìn)行測(cè)試。 promote-and-push-docker-image 作業(yè)拉取開發(fā)版本的鏡像,將其重新標(biāo)記為 release 版本,并將 release 版本推送到 Docker Hub。
我們來看看應(yīng)用的 Dockerfile 文件來了解它的構(gòu)建內(nèi)容:
FROM?nginx
RUN?echo?'Hello?World'?>?/usr/share/nginx/html/index.html
第二步是整個(gè)流水線的關(guān)鍵所在,運(yùn)行一個(gè) buid-test.sh 的 shell 腳本,接下來我們來查看下該腳本的實(shí)現(xiàn):
#!?/bin/bash
docker_username=$1
set?-xe
curl?-sL?https://kind.sigs.k8s.io/dl/v0.9.0/kind-linux-amd64?-o?/usr/local/bin/kind
chmod?755?/usr/local/bin/kind
curl?-sL?https://storage.googleapis.com/kubernetes-release/release/v1.17.4/bin/linux/amd64/kubectl?-o?/usr/local/bin/kubectl
chmod?755?/usr/local/bin/kubectl
curl?-LO?https://get.helm.sh/helm-v3.1.2-linux-amd64.tar.gz
tar?-xzf?helm-v3.1.2-linux-amd64.tar.gz
mv?linux-amd64/helm?/usr/local/bin/
rm?-rf?helm-v3.1.2-linux-amd64.tar.gz
kind?version
kubectl?version?--client=true
helm?version
kind?create?cluster?--wait?10m?--config?kind-config.yaml
kubectl?get?nodes
docker?build?-t?$docker_username/nginx:dev?.
kind?load?docker-image?$docker_username/nginx:dev
kubectl?apply?-f?nginx-deployment.yaml
kubectl?apply?-f?nginx-service.yaml
NODE_IP=$(kubectl?get?node?-o?wide|tail?-1|awk?{'print?$6'})
NODE_PORT=$(kubectl?get?svc?nginx-service?-o?go-template='{{range.spec.ports}}{{if?.nodePort}}{{.nodePort}}{{"\n"}}{{end}}{{end}}')
sleep?60
SUCCESS=$(curl?$NODE_IP:$NODE_PORT)
if?[[?"${SUCCESS}"?!=?"Hello?World"?]];?
then
?kind?-q?delete?cluster
?exit?1;
else
?kind?-q?delete?cluster
?echo?"Component?test?succesful"
fi
上面的 shell 腳本實(shí)現(xiàn)了一系列的功能:
在 CI 服務(wù)器中下載并安裝 kind、kubectl、helm 工具 使用 kind-config.yaml 文件創(chuàng)建了一個(gè)多節(jié)點(diǎn)的集群 使用 docker build命令構(gòu)建 dev 版本的鏡像加載 KinD 集群中的 Docker 鏡像,這樣可以確保鏡像對(duì)所有 KinD 節(jié)點(diǎn)都可用,就不需要從?Docker Hub 中去拉取鏡像了 使用 Deployment 方式部署應(yīng)用,并通過 NodePort 的 Service 暴露服務(wù) 獲取節(jié)點(diǎn) IP 和服務(wù)端口,并運(yùn)行測(cè)試,檢查應(yīng)用程序是否返回"Hello World" 如果測(cè)試成功,則刪除 KinD 集群,打印 "Component test succesful",并返回一個(gè)成功狀態(tài)碼;如果測(cè)試失敗,則刪除 KinD 集群,并返回失敗的狀態(tài)碼。

總結(jié)
當(dāng)我們觸發(fā)流水線管道時(shí),GitHub Actions 會(huì)自動(dòng)運(yùn)行整個(gè)流水線。我們這里就完成了利用 Docker 和 Kubernetes 進(jìn)行持續(xù)集成和部署的無(wú)縫方式,Docker 中的 Kubernetes 不僅簡(jiǎn)化了我們進(jìn)行本地開發(fā)的方式,而且也是 CI/CD 的優(yōu)秀工具。
原文鏈接:https://medium.com/better-programming/accelerate-your-ci-cd-pipelines-with-kubernetes-in-docker-kind-109a67b39c82
K8S進(jìn)階訓(xùn)練營(yíng),點(diǎn)擊下方圖片了解詳情

