---
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. 
-----------------------------
2. 
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 變化