# Kubernetes 進階
> [name=翁維甫]
> [time=Thur, Sep 22, 2020 4:00 PM]
---
# Agenda
* Deployment
* Service
* StatefulSet
* DaemonSet
* ConfigMap
* Secret
* Volumes
* Resource Quotas
* CronJob
---
## Deployment
* Deployment 為 pod 和 replicaset 提供了一個宣告式的設定與更新方式,應用場景:
* 定義 Deployment 來創建 Pod 和 ReplicaSet
* 滾動更新及回溯應用
* 擴充和縮編
* 暫停和繼續佈署
---
###

---
### 建立 Deployment
編輯文件檔
```linux=
vim deployment.yaml
```
```yaml=
# 該元件的版本號
apiVersion: apps/v1
# 該元件是什麼屬性
kind: Deployment
metadata:
# deployment name
name: nginx-deployment
# deployment 標籤
labels:
app: nginx
spec:
# 同時建立 3 個 nginx 的 pod
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
# 設定給 pod 的 label 資訊
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
```
---
以文件檔佈署
```linux=
kubectl apply -f deployment.yaml --record
```

查詢佈署相關資訊
```linux=
kubectl get all
```

---
檢視細節
```linux=
kubectl describe deployment nginx-deployment
```

---
### 更新 Deployment
更新 nginx 版本
```linux=
kubectl set image deployment nginx-deployment nginx=nginx:1.9.1 --record
```

檢視 replicaset 的狀態
```linux=
kubectl get rs
```

---
檢視更新後細節
```linux=
kubectl describe deployment nginx-deployment
```

---
更新錯誤的版本
```linux=
kubectl set image deployment nginx-deployment nginx=nginx:1.99 --record
```

檢視 replicaset 的狀態
```linux=
kubectl get rs
```

---
### Deployment 版本回溯
查詢下過的指令
```linux=
kubectl rollout history deployment nginx-deployment
```

檢視 rollout hsitory 的細節
```linux=
kubectl rollout history deployment nginx-deployment --revision=3
```

---
發現版本錯誤,故可退回前一版,也就是 revision=2
```linux=
kubectl rollout undo deployment nginx-deployment --to-revision=2
```

檢視 replicaset 的狀態
```linux=
kubectl get rs
```

---
### Deployment 擴充
將 pod 增加到 5
```linux=
kubectl scale deployment nginx-deployment --replicas=5
```

查詢狀態
```linux=
kubectl get all
```

---
### 自動擴充
```linux=
kubectl autoscale deployment nginx-deployment --min=3 --max=10 --cpu-percent=80
```

查詢設定狀況
```linux=
kubectl get hpa
```

---
### 暫停 Deployment
暫停 rollout
```linux=
kubectl rollout pause deployment nginx-deployment
```

恢復 rollout
```linux=
kubectl rollout resume deploy nginx-deployment
```

---
### Deployment 狀態
* Deployment 的生命週期有三種狀態:
* Progressing
* Complete
* Fail to progress
---
#### Progressing
* Kubernetes 將執行過下列任務其中之一的 Deployment 標記為 Progressing
* 正在建立新的 ReplicaSet
* 正在擴充一個已經有的 ReplicaSet
* 正在縮編一個已經有的 ReplicaSet
* 新的 Pod 狀態變成 ready or available
---
#### Complete
* Kubernetes 將包括以下特性的 Deployment 標記為 Complete
* 所有與該 Deployment 相關的 ReplicaSet 都已經更新到指定版本
* 所有相關的 Pod 的狀態都是 available
* 沒有舊版本的 Pod 還在執行中
---
#### Fail to progress
* Deployment 執行到一半發生問題或是卡住而無法完成任務,以下因素:
* Readiness probe 診斷失敗
* 映像檔拉取發生錯誤
* 權限不足
* 集群資源不足
* 超過資源限制範圍
* 應用程式本身造成的錯誤
---
#### Fail to progress 預設時間修改
* progressDeadlineSeconds 預設時間為 600 秒
* 修改指令,範例修改為 60 秒
```linux=
kubectl patch deployments nginx-deployment -p '{ "spec": { "progressDeadlineSeconds": 60 }}'
```
---
## Service
* Kubernetes Service 是個抽象化的概念,主要定義了邏輯上的一群 Pod 以及如何存取他們的規則
---
### Service Types
* ClusterIP
* 內部 Client 端存取用
* NodePort
* 外部 Client 端存取用,可指定一個或多個 NodePort 節點的 IP
* LoadBalancer
* 外部 Client 端存取用,同時也建立了負載平衡的機制來分散流量
* ExternalName
* 內部 Client 端使用的 DNS 別名
* 主要用途為把 Service 導向指定的 DNS name
---
### NodePort
建立 Service
```linux=
vim service.yaml
```
```yaml=
kind: Service
apiVersion: v1
metadata:
name: nginx-service
spec:
# 將 type 設定為 NodePort
type: NodePort
# 選擇帶有 "app=nginx" 的 pod
selector:
app: nginx
# Service 實際對外服務的設定
ports:
# 若不指定,預設為 TCP
- protocol: TCP
port: 80
# 若不指定,預設與 port 相同
targetPort: 9123
# 指定 NodePort number(.spec.ports[*].nodePort)
# 也可不指定(30000~32767)
nodePort: 30077
```
---
以文件檔建立
```linux=
kubectl apply -f service.yaml
```

檢查狀態
```linux=
kubectl get svc
```

---
### Load Balancer
* 目前僅有在 public cloud or OpenStack 上才有支援
* MetalLB
---
### Headless Service
* Service 需要將 spec.clusterIP 設置成 None
* 不會分配 ClusterIP,而是將 Endpoints 返回
---
## StatefulSet
* 可當成有狀態的 Deployment ,有固定的識別資訊,應用場景:
* 需要穩定且唯一的網路識別
* 需要穩定持久儲存
* 有順序性的佈署和擴充
* 有順序性的滾動更新
---
### 如何分辨 StatefulSet 產生的 Pod ?
* Pod 會有自己獨一無二的 hostname,命名規則為 $ (statefulset name)-$ (ordinal index)
* 透過 Headless Service 來維持 Pod domain name 是固定指到 Pod IP , domain name 格式為 $ (service name).$ (namespace).svc.cluster.local
---
### 建立 StatefulSet
編輯文件檔
```linux=
vim statefulset.yaml
```
```yaml=
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
ports:
- port: 80
name: web
# clusterIP 設置為 None
clusterIP: None
selector:
app: nginx
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
serviceName: "nginx"
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx-headless
image: nginx:1.7.9
ports:
- containerPort: 80
name: web
```
---
以文件檔佈署
```linux=
kubectl apply -f statefulset.yaml --record
```

查詢服務
```linux=
kubectl get pods -o wide | grep web
```

---
查詢 K8S DNS 的 IP
```linux=
kubectl get svc -n kube-system | grep dns
```

測試 Service 域名是否解析出兩個 Pod IP
```linux=
nslookup nginx.default.svc.cluster.local 10.96.0.10
```

---
測試 Pod 域名是否解析出對應的 Pod IP
```linux=
nslookup web-0.nginx.default.svc.cluster.local 10.96.0.10
```

```linux=
nslookup web-1.nginx.default.svc.cluster.local 10.96.0.10
```

---
## DaemonSet
---
## Volumes
* Volumes 可以當成是 Kubernetes Cluster 中用來儲存資料的地方
* 能將 Container 的資料儲存下來,也可以透過掛載( mounting )的方式,供許多個 Pods 同時存取
* 常用的 Volume 類型:
* emptyDir
* hostPath
* Cloud Storage
* NFS( Network FileSystem )
---
### emptyDir
* 當 Pod 建立後,該 Volume 也會一併被建立,並賦予讀寫的權限,其生命週期與 Pod 一致,當 Pod 中的容器掛掉時,emptyDir Volume 中的內容不會被清除,容器重啟後數據依然可見,只有當 Pod 被刪除,emptyDir Volume 中的內容才會被清除,適合存放不重要的資料
---

---
#### Demo emptyDir
編輯文件檔
```linux=
vim emptydir.yaml
```
```yaml=
apiVersion: v1
kind: Pod
metadata:
name: emptydir-pod
spec:
# 定義 emptyDir 名稱
volumes:
- name: my-emptydir-vol
emptyDir: {}
containers:
- name: busybox-1
image: busybox:latest
command:
- "sleep"
- "3600"
# 將 my-emptydir-vol Mount 到容器中
volumeMounts:
- name: my-emptydir-vol
# 容器中目錄
mountPath: /data-1
- name: busybox-2
image: busybox:latest
command:
- "sleep"
- "3600"
# 將 my-emptydir-vol Mount 到容器中
volumeMounts:
- name: my-emptydir-vol
mountPath: /data-2
```
---
以文件檔建立
```linux=
kubectl apply -f emptydir.yaml --record
```

查詢服務
```linux=
kubectl get pods
```

---
確認一下 Volume
```linux=
kubectl describe pod
```



此部分只截取 Volume 相關部分
---
進入容器 busybox-1
```linux=
kubectl exec -it emptydir-pod -c busybox-1 sh
```

在 data-1 資料夾中建立一個文件
```linux=
cd /data-1
echo "5566" > 5566.txt
```

---
進入容器 busybox-2
```linux=
kubectl exec -it emptydir-pod -c busybox-2 sh
```

確認是否可以查看剛剛在 busybox-1 建立的文件
```linux=
cat /data-2/5566.txt
```

---
* emptyDir Volume 會存放在 Node 節點,會有一個臨時目錄
查詢 Pod 所在的 Node
```linux=
kubectl get pods -o yaml | grep nodename
```
查詢 Pod 的 uid
```linux=
kubectl get pods -o yaml | grep uid
```
查看剛剛建立的文件
```linux=
cat /var/lib/kubelet/pods/$(uid)/volumes/kubernetes.io~empty-dir/my-emptydir-vol/5566.txt
```
---
{"metaMigratedAt":"2023-06-15T13:51:04.290Z","metaMigratedFrom":"YAML","title":"Kubernetes 進階","breaks":true,"contributors":"[{\"id\":\"f7df1304-fff3-4f97-80d7-e2ae0a04d33f\",\"add\":9463,\"del\":464},{\"id\":\"4f5c5dc0-df78-40b6-8b4c-d0c83c7416cb\",\"add\":1,\"del\":1}]"}