--- title: 'Kubernetes intro' disqus: hackmd --- # Kubernetes [TOC] Kubernetes Deployment Introduction === Kubernetes gitbook: https://feisky.gitbooks.io/kubernetes/content/ > 須先從 `基础入门`、`核心原理`、`资源对象`、`部署配置`、`访问控制`、`服务治理`、`Istio`中取得必要資訊,再進行練習較佳。 部署工具服務簡述 === 1. Ingress Controller 外部http流量控制器,可實現初步JWT檢測、特定header自動導流,使用Nginx-Ingress 2. Cert-Manager 根據服務所需domain位置,自動簽署TLS/SSL(https)憑證中心 3. Rancher 提供節點流量與節點健康度檢測,並提供Grafana(監測服務)、fleet gitops (deployment 文件上版)、金絲雀上版、A/B Test、Jaeger鏈型追蹤gRPC log、Kiali 服務網格可檢視性儀表板。 4. Istio 一種服務網格,有彈性又簡單的方式將應用程式網路功能自動化。 5. EFK (Elastic / Fluentd / Kibana) 資料採集系統,並搭配Big Query可在外部系統根據時間、容器、節點名稱,篩選出相關log 或 sql log 6. Consul 微服務註冊中心 上版服務簡述 === 1. k8s不同於以往code based的方式進行上版,是以docker image 來當作上版的內容。 而k8s架構不同於以往容器化框架,是多容器、多服務與多節點間的整題服務架構,而上版內容已不是只有單純 “推code => 上版” 的單一化處理方式,目前除了單一上版外,已衍生出漸進式上版,A/B不同版本上版等,developer必須與infra(SRE)人員進行協作。 2. 開發者開發完程式碼後,推版至git,接著會進行新版本的自動化測試,測試無誤後,會將新的code打包成一個image,並推上ACR(azure container registry) 3. infra(SRE)人員會與開發者討論,當前是需要以什麼方式上版 ; 如這段code有可能會導致服務loading很重,因此會需要漸進式地上版,以觀察服務是否正常運行、機器loading是否過大。因此選擇漸進式部署(v1 90%,V2 10% -> V1 50%, V2 50% -> V1 10%, V2 90%)。 ## k8s-deployment layout ```gherkin= ├── cert-manager //-> 部署 自動tls簽證服務 │ ├── cert-manager.yaml //-> 部署 nginx-ingress 的 cert-manager設定 │ ├── cert-manager-istio.yaml //-> 部署 istio 的 ingressgateway 的 cert-manager 設定 │ └── namespace.yaml //-> 部署 cert-manager 的namespace ├── consul //-> 部署 微服務 註冊中心 │ └── ingress.yaml //-> 部署 微服務 註冊中心 consul 的 ingress ├── efk //-> ( elastic / fluentd / kibana ) │ ├── deployment.yaml //-> 部署 log 採集服務 的 deployment (elastic / kibana) │ ├── fluentd-configmap.yaml //-> 部署 log 採集服務 的 configmap (fluentd) │ └── fluentd.yaml //-> 部署 log 採集服務 的 deployment (fluentd) ├── istio │ ├── certificate.yaml //-> 部署 網格服務的tls簽證 │ └── gateway.yaml ├── pma | └── ingress.yaml //-> 部署 pma 服務 的 ingress | | -----------------------以下為 gitops部署文件----------------------------- └── services //-> fleet 的 gitops 服務 會持續 watch 設定的分支 並且自動 apply 下列的部署文件 ├── namespace.yaml //-> 部署 ap服務相關 namespace ├── pod-rbac.yaml //-> 部署 ap服務相關 namespace 的使用權限 ├── api │ └── member //-> 部署所有api服務的deployment / service │ ├── service.yaml //-> 部署 api/member 的 service │ ├── deployment.yaml //-> 部署 api/member 的 deployment | ├── deployment-v2.yaml //-> 部署 api/member 的 v2 deployment │ ├── destination-rule.yaml //-> 部署 api/member 的 v2 istio destination-rule │ └── virtual-service.yaml //-> 部署 api/member 的 v2 istio virtual-service └── svc └── member //-> 部署所有svc服務的deployment / service ├── service.yaml //-> 部署 svc/member 的 service ├── deployment.yaml //-> 部署 svc/member 的 deployment ├── deployment-v2.yaml //-> 部署 svc/member 的 v2 deployment ├── destination-rule.yaml //-> 部署 svc/member 的 v2 istio destination-rule └── virtual-service.yaml //-> 部署 svc/member 的 v2 istio virtual-service ``` > 若其他服務的 ["ingress.yaml", "deployment.yaml"] 不在 k8s-deployment/ 中,則是以[Helm](https://helm.sh/zh/) 或網路文件作部署(如:MariaDB / pma / efk / redis ... ) k8s 基礎部署步驟 --- 1. 以 Azure 部署一個 k8s service 2. 待 k8s service 部署完成後,透過下列圖示步驟來連上 k8s service 1. ![step1](https://static.stors.club/upload/2021524/527a80c744a4d0366a0f474caa4c7a08.png "RUNOOB") ----------------------------- 2. ![step2](https://static.stors.club/upload/2021524/28be10ce7a0a28d50a9997fe59d06fbc.png "RUNOOB") 3. 以上圖為例,取得兩個相對應的token後,在本地terminal輸入,來連上k8s。 ```gherkin= az account set --subscription bde24ffc-88bd-42ba-bf8d-64b56d13c59b az aks get-credentials --resource-group rg-18platform-v2-dev --name sg-18platform-v2-dev ``` > 以後會泛用 `kubectl` 與 `kubectl -n`,推薦寫入 alias 以節省輸入時間。 4. 輸入以下指令測試是否連上k8s服務。 ```gherkin= kubectl get deployments --all-namespaces=true ``` 5. 在 /k8s-deployment 資料夾中,首先需要先部署AP所需要的namespace與rbac權限,因此執行以下指令。 ```gherkin= kubectl apply -f namespace.yaml #部署namespace kubectl apply -f pod-rbac.yaml #部署rbac權限 ``` 6. 安裝 [Helm](https://helm.sh/zh/) k8s Nginx-Ingress (LoadBalancer)部署步驟 --- 1. 部署 [Nginx-Ingress](https://docs.microsoft.com/zh-tw/azure/aks/ingress-basic) ```gherkin= kubectl create namespace ingress-basic #建立 ingress controller 專屬 namespace helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx #添加 ingress-nginx 的源 helm install nginx-ingress ingress-nginx/ingress-nginx \ --namespace ingress-basic \ --set controller.replicaCount=2 \ --set controller.nodeSelector."beta\.kubernetes\.io/os"=linux \ --set defaultBackend.nodeSelector."beta\.kubernetes\.io/os"=linux \ --set controller.admissionWebhooks.patch.nodeSelector."beta\.kubernetes\.io/os"=linux # 使用 helm 安裝 ingress-nginx # helm install 自己取的套件名稱(nginx-ingress) 來源庫(ingress-nginx/ingress-nginx) \ # -n namespace ``` 2. 輸入以下指令可得到 namespace = ingress-basic 的所有 service,並以拿到的 External IP:80 來進行連線測試。 ```gherkin= kubectl --namespace ingress-basic get services -o wide NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE nginx-ingress-ingress-nginx-controller LoadBalancer 10.0.76.32 52.229.186.90 80:31168/TCP,443:30939/TCP 14d app.kubernetes.io/compo ``` k8s cert-manager (自動簽署TLS)部署步驟 --- 1. 部署 cert-manager ```gherkin= kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.3.1/cert-manager.crds.yaml #先部署 cert-manager 的 kubernetes crd 權限 kubectl create namespace cert-manager #創建 cert-manager 命名空間 helm repo add jetstack https://charts.jetstack.io helm repo update helm install \ cert-manager jetstack/cert-manager \ --namespace cert-manager \ --create-namespace \ --version v1.3.1 ``` 2. 驗證部署 ```gherkin= kubectl get pods --namespace cert-manager NAME READY STATUS RESTARTS AGE cert-manager-7998c69865-nqn5z 1/1 Running 0 3d7h cert-manager-cainjector-7b744d56fb-cwfbj 1/1 Running 0 3d7h cert-manager-webhook-7d6d4c78bc-tnhwf 1/1 Running 0 3d7h ``` k8s Istio Service Mesh 部署步驟 --- > Rancher 內部的 Apps & Marketplace 也可以自動部署 istio,但有不少問題,因此還是需要透過官網來部署較佳 1. 本地安裝 [Istio](https://istio.io/latest/zh/docs/setup/getting-started/#download) 2. 安裝完後,請執行下列步驟安裝istio ```gherkin= istioctl install #在k8s上安裝istio kubectl -n istio-system get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE istio-ingressgateway LoadBalancer 10.0.226.135 13.70.21.229 15021:32337/TCP,80:31615/TCP,443:31916/TCP 19h istiod ClusterIP 10.0.119.103 <none> 15010/TCP,15012/TCP,443/TCP,15014/TCP 19h ``` 2. `istio-ingressgateway` 的對外 ip (LoadBalancer) 即是之後ap服務要對外的ip,因為 nginx-ingress 對於智能路由(設定特定的設定(特定header、特定uri prefix)來 routing 到特定版本號的 ap pod) 的支援尚不是很明朗,而 istio 這部分已經做得非常完整,之後只要設定 Deployment, Service, VirtualService, DestinationRule 就可以根據特定設定來跑 A/B Test, Rolling update 等 3. 因此,先前部署的 nginx-ingress 將會被拿來當作是工具的入口 (Rancher/Consul/phpmyadmin等),而 ap 服務主要是走 istio 的 ingressgateway。 4. 透過以下指令部署 jaeger / kaili ```gherkin= kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.10/samples/addons/jaeger.yaml #部署jaeger kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.10/samples/addons/kiali.yaml #部署kaili #等待部署完畢後 istioctl dashboard jaeger #port-forwarding jaeger對外 istioctl dashboard kaili #port-forwarding kaili對外 ``` k8s Rancher (Dashboard, ClusterManager, GitOps, Grafana, Prometheus) 部署步驟 --- 1. 透過以下指令部署 Rancher (Dashboard 、 ClusterManager) ```gherkin= kubectl create namespace cattle-system helm repo add rancher-latest https://releases.rancher.com/server-charts/latest helm install rancher rancher-latest/rancher \ --namespace cattle-system \ --set hostname=YOURDOMAIN \ --set ingress.tls.source=letsEncrypt \ --set letsEncrypt.email=YOUREMAIL kubectl -n cattle-system rollout status deploy/rancher ``` 2. 接著,進入 上述填寫的https domain 即可進入 Rancher。 3. 因為k8s 只要第一步驟的 token 外流,即非常危險(可對 Cluster 做任何操作),因此,此步驟可以開放 kubectl 給特定人員,減少外流風險。 4. 進入 Rancher 後,點擊左上角切換至 `Apps & Marketplace` ,選擇部署 `Monitoring` ,稍待片刻後點擊左上角,切換至 `Monitoring` 即可點擊進入 `Alertmanager` (告警服務)、 `Grafana`(監控服務)。 k8s efk (log 採集)部署步驟 --- 1. 首先部署 [ECK Operator](https://makeoptim.com/kubernetes/logging-high-availability#%E9%83%A8%E7%BD%B2-fluentd) ,安裝成功後,會自動創建一個 namespace = elastic-system 以及一個 operator 的 Pod。 ```gherkin= kubectl apply -f https://download.elastic.co/downloads/eck/1.3.0/all-in-one.yaml ``` 2. 在 /k8s-deployment/efk 資料夾中,部署 Elastic / Kibana (deployment.yaml) 以及 Fluentd 的 Configmap (fluentd-configmap.yaml) 以及 ServiceAccount / ClusterRoleBinding / DaemonSet (fluentd.yaml) 。 ```gherkin= kubectl apply -f deployment.yaml kubectl apply -f fluentd-configmap.yaml kubectl apply -f fluentd.yaml ``` 3. 輸入以下指令可得到 namespace = elastic-system 的所有 service。其中,`elastic-es-http` 為 elastic 提供api來搜集數據的 IP ,需要與 `fluentd.yaml` 中的 `FLUENT_ELASTICSEARCH_HOST` 有所對應。得到以下結果後,即可取得 `kibana-kb-http` 的 External IP:5601 來進行連線測試。 ```gherkin= kubectl --namespace elastic-system get services -o wide NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR elastic-es-default ClusterIP None <none> 9200/TCP 10d common.k8s.elastic.co/type=elasticsearch,elasticsearch.k8s.elastic.co/cluster-name=elastic,elasticsearch.k8s.elastic.co/statefulset-name=elastic-es-default elastic-es-http LoadBalancer 10.0.97.27 52.184.14.39 9200:31117/TCP 10d common.k8s.elastic.co/type=elasticsearch,elasticsearch.k8s.elastic.co/cluster-name=elastic elastic-es-transport ClusterIP None <none> 9300/TCP 10d common.k8s.elastic.co/type=elasticsearch,elasticsearch.k8s.elastic.co/cluster-name=elastic elastic-webhook-server ClusterIP 10.0.94.71 <none> 443/TCP 10d control-plane=elastic-operator kibana-kb-http LoadBalancer 10.0.28.137 13.70.56.230 5601:31215/TCP 10d common.k8s.elastic.co/type=kibana,kibana.k8s.elastic.co/name=kibana ``` 3. 透過 `kibana-kb-http` EXTERNAL-IP:5601 就可以訪問 Kibana 囉。 ```gherkin= kubectl apply -f cert-manager.yaml ``` 4. 另外,此處需要另外找尋設定外掛 Azure 儲存空間的設定(PV),不然 elastic 的所搜集的 log 很快就會佔滿 node 的空間,以及需要進去 elastic 設定資料的 lifecycle (資料儲存多久自我清除)。 k8s consul (服務註冊中心)部署步驟 --- 1. 透過 helm 部署 [consul](https://github.com/hashicorp/consul-helm) ```gherkin= helm repo add hashicorp https://helm.releases.hashicorp.com helm install -n consul consul hashicorp/consul --set global.name=consul ``` 2. 透過 /k8s-deployment/consul/ingress.yaml 部署 consul ui 的 Ingress,部署完成後稍待5至10秒,等待 cert-manager 簽名,即可透過 Nginx-ingress 所設定的 consul.XXXX.XXX 訪問 consul ui ```gherkin= kubectl apply -f ingress.yaml kubectl -n consul describe ingress Name: consul-ingress Namespace: consul Address: 52.229.186.90 Default backend: default-http-backend:80 (<none>) TLS: tls-secret-consul terminates consul.18plm.com Rules: Host Path Backends ---- ---- -------- consul.18plm.com / consul-ui:80 (10.244.0.79:8500,10.244.1.74:8500,10.244.2.52:8500) Annotations: kubernetes.io/ingress.class: nginx cert-manager.io/cluster-issuer: letsencrypt field.cattle.io/publicEndpoints: [{"addresses":["52.229.186.90"],"port":443,"protocol":"HTTPS","serviceName":"18xl-backend:consul-ui","ingressName":"18xl-backend:18xl-backend-consul-ingress","hostname":"consul.18plm.com","path":"/","allNodes":false}] ingress.kubernetes.io/ssl-redirect: true kubectl.kubernetes.io/last-applied-configuration: {"apiVersion":"networking.k8s.io/v1","kind":"Ingress","metadata":{"annotations":{"cert-manager.io/cluster-issuer":"letsencrypt","ingress.kubernetes.io/ssl-redirect":"true","kubernetes.io/ingress.class":"nginx"},"name":"18xl-backend-consul-ingress","namespace":"18xl-backend"},"spec":{"rules":[{"host":"consul.18plm.com","http":{"paths":[{"backend":{"service":{"name":"consul-ui","port":{"number":80}}},"path":"/","pathType":"Prefix"}]}}],"tls":[{"hosts":["consul.18plm.com"],"secretName":"tls-secret-consul"}]}} Events: <none> ``` 4. 但這樣所有人都能訪問該網址,因此要在 ingress.yaml 中 `annotations` 的部分添加 ingress 白名單 ```gherkin= metadata: name: consul-ingress namespace: consul annotations: kubernetes.io/ingress.class: nginx cert-manager.io/cluster-issuer: letsencrypt ingress.kubernetes.io/ssl-redirect: "true" nginx.ingress.kubernetes.io/whitelist-source-range: '192.168.8.0/24' # 访问白名单 ``` k8s redis 部署步驟 --- 1. 透過 helm 部署 [redis](https://github.com/bitnami/charts/tree/master/bitnami/redis) ```gherkin= helm repo add bitnami https://charts.bitnami.com/bitnami helm install redis --set auth.password=18tgcity,master.service.type=LoadBalancer bitnami/redis ``` 2. 待部署完畢,執行下列指令取得 redis-master svc 的對外 IP。 ```gherkin= kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE redis-headless ClusterIP None <none> 6379/TCP 21s redis-master LoadBalancer 10.0.125.149 13.70.35.126 6379:31185/TCP 21s redis-replicas ClusterIP 10.0.12.190 <none> 6379/TCP 21s ``` k8s mariadb 部署步驟 --- 1. 透過 helm 部署 [mariadb](https://github.com/bitnami/charts/tree/master/bitnami/mariadb) ```gherkin= helm install mariadb bitnami/mariadb --set auth.rootPassword=ROOTPASSWORD,auth.database=18xl bitnami/mariadb ``` k8s phpmyadmin 部署步驟 --- 1. 透過 helm 部署 [phpmyadmin](https://bitnami.com/stack/phpmyadmin/helm) ```gherkin= helm repo add bitnami https://charts.bitnami.com/bitnami helm install phpmyadmin bitnami/phpmyadmin ``` 2. 透過 helm update 來更新 mariadb host ```gherkin= helm upgrade phpmyadmin bitnami/phpmyadmin --set db.host=mariadb.default.svc.cluster.local ``` 3. 至 /k8s-deployment/pma/ 中 執行 ```gherkin= kubectl apply -f ingress.yaml ``` 4. 即可從 /k8s-deployment/pma/ingress.yaml 所設定的 domain 位置訪問 phpmyadmin k8s GitOps --- 1. k8s 不同於以往 code based 的方式進行上版,是以 docker image 來作為 ap 的啟動內容。 2. 而k8s架構不同於以往容器化框架,是多容器、多服務與多節點間的整體服務架構,而上版內容已不是只有單純 `推code => 上版` 的單一化處理方式,目前除了單一上版外,已衍生出漸進式上版,A/B不同版本上版等,developer必須與infra(SRE)人員進行協作。 ```gherkin= [RD線] git push -> github/gitlab... -> CI(各項目自動化測試) -> 編譯程式碼/打包成 docker image -> Azure ACR [DevOps線] 與RD討論上版內容 -> 修改 k8s-deployment/services 內的 .yaml 配置 -> git push -> fleet gitOps 自動化部屬 ``` 3. 開發RD 開發完程式碼後,推版至git,接著會進行新版本的自動化測試,測試無誤後,會將新的code打包成一個image,並推上ACR(azure container registry) 4. infra(SRE)人員會與開發者討論,當前是需要以什麼方式上版,並修改 k8s-deployment/services 內的 .yaml 配置,修改完後一樣透過git上版的方式,把設置推上去 git,讓 fleet 去自動偵測並自動部署。 >上版方式可能有 >1. 金絲雀上版(Canary Update) > ex: 新版code有可能會導致服務loading很重,因此會需要漸進式地上版,以觀察服務是否正常運行、機器loading是否過大 >(v1 90%, V2 10%) -> (V1 50%, V2 50%) -> (V1 10%, V2 90%) >2. 藍紅上版 (A/B Test) >3. 灰度上版 (request 帶特定 header 才能被 routing 至相對應的 `測試版本` or `新版本`) k8s GitOps 工具 Fleet --- 1. 部署 Rancher 就會自動幫你部署了 fleet ,但一樣有些小問題,因此推薦透過 helm 移除後重新安裝 ```gherkin= helm -n fleet-system uninstall fleet-crd helm -n fleet-system uninstall fleet #移除後,再透過指令進行安裝 helm -n fleet-system install --create-namespace --wait fleet-crd https://github.com/rancher/fleet/releases/download/v0.3.3/fleet-crd-0.3.3.tgz helm -n fleet-system install --create-namespace --wait fleet https://github.com/rancher/fleet/releases/download/v0.3.3/fleet-0.3.3.tgz kubectl -n fleet-system get po #驗證一下 pod 是否 ready NAME READY STATUS RESTARTS AGE fleet-agent-d59db746-9778t 1/1 Running 0 3h24m fleet-controller-79554fcbf5-zdxwc 1/1 Running 0 3h24m gitjob-568c57cfb9-dmp6p 1/1 Running 0 3h24m ``` 2. 點擊 Rancher 左上角 切換至 Continuous Delivery (CD) 3. 點擊 Continuous Delivery 右邊的下拉式選單至 fleet-local (確認左側 Clusters 數量必須為 1) 4. 點擊 Git Repos -> Create 5. 填寫 Name / Repository URL / Watch Branch Name 以及 Authentication (推薦 http) > Username 填寫 github 帳號 > Password 產生方式:點擊[Github Profile](https://github.com/settings/profile) -> Developer settings -> Personal access tokens 6. Path 填寫 k8s-deployment/services 7. 點擊建立後,靜待 Git Repos 的 State 變化