天天看點

Gitlab-ci and Helm CI/CD Kubernetes叢集實踐大綱

大綱

  • 基礎準備工作
    • Kubernetes cluster
    • Helm
    • Helm repository(Optional)
    • Nginx-Ingress-Conroller
    • Docker Registry
    • Gitlab-ce Service
    • DNS
    • Demo Service
    • Helm Charts

對于想要在Gitlab上實施CICD到kubernetes的朋友,可能需要了解一下gitlab、k8s、helm、nginx-ingress相關技術 的概念和知識。

Kubernetes Cluster(已有k8s叢集的可以跳過本節)

對于K8s叢集的安裝部署,本篇文章使用的是GKE,當然你也可以選擇其它公有雲提供的k8s的産品。例如AWS的EKS, Microsoft的AKS。另外國内的有Alibaba的 容器服務kubernetes版,國内的公有雲現在貌似基本都有k8s 服務,包括專業做CDN的某牛雲。說明kubernetes早已成為容器編排領域的事實标準。

建立叢集
gcloud beta container --project "hi42-top" clusters create "demo-k8s" --zone "us-east1-b" --no-enable-basic-auth --cluster-version "1.12.6-gke.10" --machine-type "g1-small" --image-type "COS" --disk-type "pd-standard" --disk-size "30" --num-nodes "2" --enable-cloud-logging --enable-cloud-monitoring --no-enable-ip-alias --network "hi42-vpc" --subnetwork "hi42-east" --addons HorizontalPodAutoscaling --enable-autoupgrade --enable-autorepair      
驗證叢集部署

檢視剛剛建立的 k8s cluster

$ gcloud container clusters list
NAME      LOCATION    MASTER_VERSION  MASTER_IP      MACHINE_TYPE  NODE_VERSION   NUM_NODES  STATUS
demo-k8s  us-east1-b  1.12.6-gke.10   35.196.230.33  g1-small      1.12.6-gke.10  2          RUNNING      

安裝kubectl command 根據你用戶端選擇合适的

kubectl發行版

使用gcloud自帶指令,自動配置本地的kubectl用戶端

$ gcloud container clusters get-credentials demo-k8s      

Tips: 這一步gcloud用戶端會下載下傳kubeconfig,把内容導入并合并到kubeconfig預設檔案 ~/.kube/config

确認下目前使用的叢集配置是我們剛剛建立的叢集

$ kubectl config current-context
gke_hi42-top_us-east1-b_demo-k8s      

Notes:預設config檔案裡可能會有很多叢集配置。如果目前顯示的不是我們想要的叢集,可以使用

kubectl config

進行設定,切換到正确的叢集配置。

部署個demo程式驗證一下

$ kubectl run hello-server --image gcr.io/google-samples/hello-app:1.0 --port 8080      

建立一個類型為LoadBalance的Service,目的是将剛剛建立的服務暴露到叢集外部,可外部通路。

kubectl apply -f - <<EOF
kind: Service
apiVersion: v1
metadata:
  name: hello-server
  namespace: default
  labels:
    run: hello-server
  annotations:
    cloud.google.com/load-balancer-type: "Internal"
spec:
  selector:
    run: hello-server
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8080
  type: LoadBalancer
EOF      

Notes:cloud.google.com/load-balancer-type: “Internal” 表示内網LB

Tips:在k8s叢集内部暴露服務到外部,我們有多種選擇:Nodeport、LoadBalancer、Ingress。

檢視剛剛建立的Service 資源

$ kubectl get svc
NAME           TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
hello-server   LoadBalancer   10.19.254.53   10.11.0.18    80:30105/TCP   7m
kubernetes     ClusterIP      10.19.240.1    <none>        443/TCP        38m      

名為hello-server 的 svc已經就緒,外部IP是

10.11.0.8

,下面使用curl通路該服務。

$ curl 10.11.0.18
Hello, world!
Version: 1.0.0
Hostname: hello-server-5cdf4854df-lf76k      

Notes: 我的網絡已經和gcp 建立了隧道,是以兩地内網是互通的,可以直接通路VPC内部IP。當然沒有 條件的話,你也可以選擇ssh登陸gcp上的k8s Node節點上,直接通路該IP。

Gitlab CE Setup (1)

Gitlab這一節隻介紹一些安裝配置方法,因為gitlab配置項目涉及的細節有點多。

Gitlab 安裝

見Gitlab-安裝文檔:

https://about.gitlab.com/install/#centos-7
Gitlab 正常配置
  • https
  • 自動備份
  • LDAP
Gitlab runner 配置

Gitlab Runner 是根據.gitlab-ci.yaml檔案定義的job來跑pipeline的。并且根據注冊的runner的執行者不同, 可選擇在shell、docker、kubernetes等環境中運作job指令内容。 見:

runner executor
  • 安裝gitlab runner
參考官方runner 安裝文檔
  • 注冊runner到gitlab server

添加shell runner(當然也可以選擇docker executor)

參考runner 注冊文檔

Warning

:另外我們需要在該runner上安裝

Docker-ce
配置Runner使用kubectl & helm

*Warning: 這裡我直接使用runner所在主機以shell executor跑pipeline,是以這裡直接将kubeconfig 放到了系統上。完整檔案位置在gitlab-runner使用者的家目錄:/home/gitlab-runner/.kube/config *

擷取kubeconfig檔案: >參考

kubernetes cheatsheet
$ kubectl config view --flatten=true > /tmp/demo-k8s.kubeconfig      

将該檔案demo-k8s.kubeconfig拷貝到runner家目錄 /home/gitlab-runner/.kube/config

Notes: 注意config是檔案名,不是目錄

驗證kubectl與叢集連接配接是否正常:

gitlab-runner@gitlab-slave:~$ kubectl cluster-info
Kubernetes master is running at https://35.196.230.33
Heapster is running at https://35.196.230.33/api/v1/namespaces/kube-system/services/heapster/proxy
KubeDNS is running at https://35.196.230.33/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
Metrics-server is running at https://35.196.230.33/api/v1/namespaces/kube-system/services/https:metrics-server:/proxy
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
gitlab-runner@gitlab-slave:~$ kubectl get po
NAME                            READY   STATUS    RESTARTS   AGE
hello-server-5cdf4854df-lf76k   1/1     Running   0          130m      

下一步便是安裝在runner主機上安裝helm。

Helm Setup

給Helm 來個簡短的介紹? Helm是kubernetes裡面的包管理工具。把它想象成Linux中的yum、apt。它将 一個服務部署所需要的k8s資源(deployment、secret、configmap、service、ingress…)都打包在一個 Chart中,另外Chart可單獨存儲在本地。也可以存儲到遠端git倉庫中,或搭建個WebServer可供http下載下傳chart 就行。 Helm 分為client端 和 server端,Server 端(Tiller)部署在k8s叢集中,根據helm用戶端送出 的chart解析成相應k8s資源的yaml檔案,在k8s上建立對應類型的資源。

安裝helm

Warning:helm client不是安裝在本機,而且安裝在gitlab-runner所在主機上。

下載下傳 helm用戶端

curl https://raw.githubusercontent.com/helm/helm/master/scripts/get | bash      

HELM init with tiller (RBAC)

$ kubectl apply -f - <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
  name: tiller
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: tiller
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
  - kind: ServiceAccount
    name: tiller
    namespace: kube-system
EOF      

初始化并安裝helm tiller

$ helm init --service-account tiller --history-max 200
...
Happy Helming!      

看到以上輸出,表示tiller已經正确部署到kube-system下。有興趣的可以檢視下pod在kube-system namespace下。

Ingress-controller setup

安裝ingress controller
helm install --name=nginx-ingress-intranet --namespace=ingress-controller \
--set controller.ingressClass=nginx-ingress-intranet \
--set controller.service.annotations."cloud\.google\.com/load-balancer-type"=Internal \
--set rbac.create=true \
stable/nginx-ingress      
驗證 ingress controller
kubectl get svc -n ingress-controller
NAME                                     TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
nginx-ingress-intranet-controller        LoadBalancer   10.19.246.51    10.11.0.19    80:31604/TCP,443:30083/TCP   39m
nginx-ingress-intranet-default-backend   ClusterIP      10.19.253.220   <none>        80/TCP                       39m      

從上面可以看出已經成功建立lb,注意這裡的外部IP是VPC内網IP。我們curl一下:

$ curl 10.11.0.19
default backend - 404      

由于叢集裡面現在還沒有Ingress資源被建立。是以預設将請求轉發到default-backend這個服務,當然, 你也可以根據自己需要修改default-backend服務鏡像,定制404頁面。

建立 SSL Secret

如果你有證書的話,可以以這種方式建立Secret資源,供後面的Ingress資源使用。

$ kubectl create secret tls demo-hi42-top --key demo.hi42.top.key --cert fullchain.cer
secret "demo-hi42-top" created      

DNS 配置

配置DNS泛域名解析

上一節我們建立了Ingress controller,現在需要将某域名系統下的所有服務配置指向該IP

*.demo.hi42.top  A 10.11.0.19      

Docker hub (Optional private docker reg)

這裡選擇了docker hub,省去了搭建私有倉庫的步驟。當然也可以選擇gcp的 container registry。 需要提供2個變量給後面gitlab-ci使用,docker login 使用者名和密碼。

Demo code

用go寫了簡單的web server。兩個二哈,兩個貓咪。 代碼:見

minions

Helm Charts 準備

建立 monions chart
$ mkdir charts && cd charts/ && helm create minions      

目前項目根目錄charts/minions,簡單起見,我們隻對檔案内容做了一點點修改(包含修改readiness url), 另外我們在pipeline裡面deploy job時會定義。進行動态 set。

Gitlab project settings

Project開啟CI/CD,并設定環境變量。添加2變量:

  • CI_REGISTRY_PASSWORD
  • CI_REGISTRY_USER
添加gitlab-runner 到docker使用者組

由于我們直接使用gitlab runner shell作為executor,是以需要将gitlab-runner使用者加到docker 組中。在gitlab-runner 主機上執行。

$ usermod -aG docker gitlab-runner      

Gitlab-PIPELINE 示例

.gitlab-ci.yml 完整内容
stages:
  - build
  - test
  - release
  - deploy
variables:
  # CI_DEBUG_TRACE: "true"
  DOCKER_DRIVER: overlay2
  # application domain name
  QA_DOMAIN_NAME: minions.demo.hi42.top
  PROD_DOMAIN_NAME: minions.hi42.top
  CHART_PATH: ./charts/minions
  INGRESS_CLASS_NAME: nginx-ingress-intranet
  CI_REGISTRY: docker.io
  CONTAINER_PROJECT: hanyifeng/minions
  CONTAINER_IMAGE: $CI_REGISTRY/$CONTAINER_PROJECT
  CONTAINER_TAG: $CI_COMMIT_SHORT_SHA
  # variables 好像不支援這樣嵌套指派。。。Ref:https://docs.gitlab.com/ee/ci/variables/where_variables_can_be_used.html#gitlab-runner-internal-variable-expansion-mechanism
  # CONTAINER_BUILT_IMAGE: "$CONTAINER_IMAGE:$CONTAINER_TAG"
  # CONTAINER_RELEASE_IMAGE: "$CONTAINER_IMAGE:latest"
  # Kubernetes config
  STAGE_NAMESPACE: qa
  PROD_NAMESPACE: production
  STAGE_RELEASE_NAME: minions-qa
  PROD_RELEASE_NAME: minions-product
before_script:
  - echo "Hello Minions"
build:
  stage: build
  script:
    - docker login -u ${CI_REGISTRY_USER} -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
    - echo "Building image..."
    - docker build --pull -t $CONTAINER_IMAGE:$CONTAINER_TAG .
    - echo "Pushing to ${CI_REGISTRY}..."
    - docker push $CONTAINER_IMAGE:$CONTAINER_TAG
  tags:
    - shell
test1:
  stage: test
  script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
    - echo "do unit test"
    - docker pull $CONTAINER_IMAGE:$CONTAINER_TAG
  tags:
    - shell
release-image:
  stage: release
  script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
    - docker pull $CONTAINER_IMAGE:$CONTAINER_TAG
    - docker tag $CONTAINER_IMAGE:$CONTAINER_TAG $CONTAINER_IMAGE:latest
    - docker push $CONTAINER_IMAGE:latest
  tags:
    - shell
deploy_qa:
  stage: deploy
  script:
    - helm upgrade --install
      --set image.repository=$CONTAINER_IMAGE
      --set image.tag=$CONTAINER_TAG
      --set image.pullPolicy=Always
      --set ingress.enabled=true
      --set ingress.annotations."kubernetes\.io/ingress\.class"=$INGRESS_CLASS_NAME
      --set ingress.hosts[0]=$QA_DOMAIN_NAME
      --set ingress.enabled=true --set ingress.tls[0].hosts[0]=$QA_DOMAIN_NAME
      --set ingress.tls[0].secretName=demo-hi42-top
      --set service.port="8080"
      --wait
      --namespace=$STAGE_NAMESPACE
      $STAGE_RELEASE_NAME $CHART_PATH
  environment:
    name: staging
    url: $QA_DOMAIN_NAME
  tags:
    - shell      

Warning:由于這裡加了ssl,是以需要引用證書,我們之前建立的secret是在default namespace裡, 是以需要重新在qa環境下建立一個secret證書。

$ kubectl create secret tls demo-hi42-top --key demo.hi42.top.key --cert fullchain.cer -n qa      
驗證部署狀态

可以在gitlab pipeline上,找到最新的建構,并檢視部署狀态。這裡以一個GIF進行示範。

傻二哈測試

可以嘗試修改main.go,将dog.gif,改為cat.gif,重新送出代碼到git倉庫。之後部署成功後,你将看到兩隻可愛的小貓咪。。。

Done。

總結

跟之前在使用的Jenkins相比,gitlab-ci和代碼管理結合的更完美。但是有些地方還是挺坑的,可能是對gitlab-ci 比較陌生。慢慢的熟悉之後再來發表評論。

其實不管是使用jenkins或者gitlab ci,又或者其他工具也好。原理基本上都差不多,就是使用定義方式上有些不同而已。 後面就是根據項目繼續完善優化pipeline。如資料庫遷移job,pr review等。

繼續閱讀