---
# System prepended metadata

title: k8s 基礎
tags: [k8s]

---

---
title: 'k8s 基礎'
disqus: hackmd
---

[TOC]

<style>
#doc {
    min-width: 1200px;
    margin-left: 200px;
}
</style>


# K8s Node 定義

![](https://i.imgur.com/fSRwpI4.png)

:::info
Ｍaster Node是由etcd、kube-controller-manager、kube-apiserver、kubescheduler構成
:::

**Etcd**
* 用來存放 Kubernetes Cluster 的資料作為備份，當 Master 因為某些原因而故障時，我們可以透過 etcd 幫我們還原 Kubernetes 的狀態

**kube-controller-manager**
* 負責管理並運行 Kubernetes controller 的組件，簡單來說 controller 就是 Kubernetes 裡一個個負責監視 Cluster 狀態的 Process
* 這些 Process 會在 Cluster 與預期狀態（desire state）不符時嘗試更新現有狀態（current state）
* controller-manager 的監控與嘗試更新也都需要透過訪問 kube-apiserver 達成
    * controller 包含以下四種：
        * Node controller
            * 當節點有問題時負責通知與回應
        * Replication controller
		    * 用來管理 Pod 的數量及狀態，並可確保有指定數量的 Pod 正在運行
	    * Endpoints controller
		    * 用來結合 Pod 和 Service 的物件
	    * Service Account & Token controllers
		    * 建立預設的帳號、為新的 namespace 建立新的 API 存取 token
		    
**kube-apiserver**
* 管理整個 Kubernetes 所需 API 的接口（Endpoint）
* 負責 Node 之間的溝通橋樑，每個 Node 彼此不能直接溝通，必須要透過 apiserver 轉介
* 負責 Kubernetes 中的請求的身份認證與授權


**Kubescheduler**
* 整個 K8S 的 Pods 調度員，scheduler 會監視新建立但還沒有被指定要跑在哪個 Node 上的 Pod，並根據每個 Node 上面資源規定、硬體限制等條件去協調出一個最適合放置的 Node 讓該 Pod 跑


:::info
WorkerNode是由kubelet、kube-Proxy、Container Runtime構成
:::

**Kubelet**
* kubelet相當於 node agent，用於管理該 Node 上的所有 pods以及與 master node 即時溝通。

**kube-Proxy**
* kube-proxy則是會將目前該 Node 上所有 Pods 的資訊傳給 iptables，讓 iptables 即時獲得在該 Node 上所有 Pod 的最新狀態。

**Container Runtime**
* 該 Node 真正負責容器執行的程式，以 Docker 容器為例其對應的 Container Runtime 就是 Docker Engine。


---

# K8s Object 定義

![](https://i.imgur.com/GMXXC3g.png)

:::info
Basic
:::

* Pod
    * Pod是k8s中可以被創造或是發布的最小的單位，一個 Pod 在k8s世界中就相當於一個application。Pod有以下特點：
        1. 每個 Pod 都有屬於自己的 yaml 檔
		2. 一個Pod裡面可以包含一個或多個Docker Container ( 或者是其他 Container)
		3. 在同一個Pod裡面的Containers，可以用Local Port互相溝通
		
* Service
    * k8s服務是一個abstraction，它定義了一組邏輯Pod和一個訪問它們的策略 - 有時稱為micro-service。負責不同Pod之間的溝通。

* Volume
    * k8s服務中的Volume與Docker的Volume是類似的概念，他們都是為了在虛擬化系統中，因該設計的pod或是container生命週期是短暫的，為了要保存資料的永久性和完整性所做的方法，也就是保存資料用的，也可以用作共享資料，無論是在不同的pod或是container之間，但是k8s的Volume不同於Docker的是，它會有明確的生命週期，且能在產生pod時加入屬於Volume不同的參數，像是要掛載的檔案系統類型等等（如：NFS），簡言之它具有更大的彈性，另外它可在container切換時保持存在，以達到交換資料的目的。
		
* Namespace
    * 所謂的Namespace，是劃分不同使用者能使用多少資源的方法（resource quota），舉例來說：CPU或是memory分配的多寡，在少量的使用者場景中（幾個或幾十個），這樣的功能是不需要的，此外，若是分配不同資源，並不需要使用不同的Namespace，只要在同個Namespace下定義不同的label即可。在管理k8s系統中的情況，最常使用到的是kube-system這個Namespace。


:::info
Abstraction
:::

* ReplicaSet
    * 複製集，是基於Replication Controller的改良版，本質差異是在selector的支援多寡，在現在的使用情境下，我們不會直接操作到ReplicaSet，每個不同的Deployment會有他們自己的ReplicaSet，並會自動調配，除非我們有對於複製集有特殊設定需求，不然一般直接套用Deployment的預設即可，ReplicaSet顧名思義是讓同個Pod有多個分身在同時運行，舉例來說：這樣的好處是在更新的時候不會讓使用者斷線
		
* Deployment
    * 部署，Deployment Controller提供Pods和ReplicaSets可定義的更新，k8s下的Deployment有許多feature可以使用，如：create、update、roll back、pause、resume等，針對Deployment的替代方案可以使用kubectl rolling update這個指令。
		
* StatefulSet
    * StatefulSet管理一組Pod的部署（Deployment）和擴展（scaling），並提供有關這些Pod的排序和唯一性的保證。
    * 與部署（Deployment）類似的是，StatefulSet管理基於相同容器規範的Pod。與部署（Deployment）不同的是，StatefulSet為其Pod保持標籤（label）。
    * 這些Pod是根據相同的規範創建的，但不可互換：每個Pod都有一個永久性的標籤（label），它可以在任何重新安排時保留。
		
* DaemonSet
    * DaemonSet能確保部份或所有node運行Pod的副本持續運行。
    * 刪除DaemonSet將清除它創建的Pod。
		
* Job
    * Job創建一個或多個pod，並確保指定數量的Pod工作完成後終止。
    * 刪除Job將清除它創建的Pod。
    * Job還可以用於並行運行多個Pod。
---

# Tool

```bash=
-- 查看 主服務狀態
kubectl get componentstatuses

-- 查看 現有Namespace
kubectl get namespace

-- 查看 pod/service/rc 較多資訊
kubectl get all -o wide


```

---

# Pod

yaml 建立 pod, 並指定特定label的node
k8s-web-pod-node-selector.yaml
```yaml=
apiVersion: v1
kind: Pod # 定義類型
metadata:
  name: k8s-net-pod # 資源名稱
  labels: # 該pod 的label
    app: k8s-net-pod
spec: # 資源狀態
  containers: # 單一Container的設定，可以單一Pod設定多個Container
    - name: web # 該Container在該Pod的名稱
      image: test_project/v1 # docker image 名稱
      imagePullPolicy: IfNotPresent # 預設為 Always (每次都重遠端拉取Image)，通過設定 IfNotPresent或Never来使用local Image
      ports:
        - containerPort: 80
      livenessProbe: # 設定healthCheck
        httpGet:
          path: /host/CheckHealth # healthCheck API Path
          port: 80 # healthCheck API Port
        initialDelaySeconds: 15 # 服務啟動後 幾秒後做healthCheck      default=0 min=0
        periodSeconds: 15       # 每隔幾秒Check一次                  default=10 min=1
        timeoutSeconds: 30      # timeout時間                       default=1 min=1
        successThreshold: 1     # 呼叫幾次成功後 會更改狀態回success    default=1 min=1
        failureThreshold: 3     # 呼叫幾次失敗後 會更改狀態回failure    default=1 min=1
  nodeSelector:
    SpecifyNode: node_test1 # 指定部屬到含有 label SpecifyNode=node_test1 的 node中
```




---

# Service

功能: 在Node 與 Pod 之間的橋樑, 幫忙轉接IP

```bash=
-- 當Node建立好後, 建立expose service
kubectl expose pod/k8s-net-pod --name=k8s-net-service --port=80 --type=NodePort

-- 查看目前 service 所有資訊
kubectl -ojson get service k8s-net-service
```

更新Service 的nodeport 的方式
```bash=
1. 編輯service
kubectl edit service k8s-net-service
=> 直接修改完後, ESC :wq 退出

2. 更新yaml檔後 重新apply
kubectl apply service -f k8s-web-service-demo.yaml

3. 更新yaml檔後 重新 replace
kubectl replace service -f k8s-web-service-demo.yaml

    **若沒有yaml檔 可匯出當前Service的yaml檔設定 進行修改
    **kubectl get service k8s-net-service -o yaml > k8s-web-service-demo.yaml

    ** apply 與 replace差異
    apply => 若有現有service 則 更新, 若無 則創建
    replace => 刪除現有service 重新創建

    apply 可更新部分設定, 故不需完整的yaml檔
    replace 則需完整的yaml檔, 因需要重新創建
    
4. Patch更新
kubectl patch service k8s-net-service --type='json' -p='[{"op": "replace", "path": "/spec/ports/0/nodePort", "value":31500}]'
```


yaml檔 建立 service
k8s-web-service.yaml
```yaml=
apiVersion: v1
kind: Service
metadata:
  name: k8s-net-service
spec:
  selector:
    app: k8s-net-pod
  ports:
  - protocol: TCP
    port: 80
    targetPort:
    nodePort: 31000
  type: NodePort
```


# ReplicationController
功能: 
1. 用來管理Pod的數量以及狀態的controller
2. 在Replication Controller設定檔中可以指定同時有多少個相同的Pods運行在Kubernetes Cluster上
3. 當某一Pod發生crash, failed，而終止運行時，Replication Controller會幫我們自動偵測，並且自動創建一個新的Pod，確保Pod運行的數量與設定檔的指定的數量相同
4. 當機器重新開啟時，之前在機器上運行的 Replication Controller 會自動被建立，確保pod隨時都在運行


```bash=
# 建立 ReplicationController
kubectl apply -f k8s-web-rc.yaml

# 自動擴展 pod數量
kubectl scale --replicas=4 -f k8s-web-rc.yaml

# 刪除RC時 其所指定label的pod 也會一併被刪除
kubectl describe rc my-replication-controller

# 刪除RC時 保留pods
kubectl describe rc my-replication-controller --cascade=false
```

yaml檔 建立 ReplicationController
k8s-web-rc.yaml
```yaml=
apiVersion: v1
kind: ReplicationController
metadata:
  name: my-replication-controller
spec:
  replicas: 3 # 欲創建pods 的數量
  selector:
    app: k8s-net-pod
  template:
    metadata:
      labels: # 創建pods 的 label
        app: k8s-net-pod
    spec:
      containers:
      - name: web
        image: test_project/v1
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
```


# Deployment
功能:
1. 部署一個應用服務(application)
2. 協助 applications 升級到某個特定版本
3. 服務升級過程中做到無停機服務遷移(zero downtime deployment)
4. 可以Rollback到先前版本

:::info
會自動創建Replica Sets (為 ReplicationController 的進化版，提供更彈性的selector設定)
:::

```bash=
# 建立 deployent
kubectl apply -f k8s-web-deployment.yaml

# 查看 deployment 較多資訊
kubectl get deploy -o wide

# 更新 Image版本
kubectl set image deploy/my-deployment web=test_project/v2  --record

# 查看 deployment滾動更新 紀錄
kubectl rollout history deploy my-deployment

# 回滾 deployment至上一個版本
kubectl rollout undo deploy my-deployment

# 回滾 deployment至某指定版本
kubectl rollout undo deploy my-deployment --to-revision=4
```

yaml檔 建立 Deployment
k8s-web-deployment.yaml
```yaml=
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: k8s-net-pod
  template:
    metadata:
      labels:
        app: k8s-net-pod
    spec:
      containers:
      - name: web
        image: test_project/v2
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
        livenessProbe:
          httpGet:
            path: /host/CheckHealth
            port: 80
      nodeSelector:
        SpecifyNode: node_test1
```

# Lable
功能:
1. 每個物件可以同時擁有許多個labels(multiple labels)
2. 可以透過 Selector，幫我們縮小要尋找的物件
3. 目前 API 提供不再只是一個 key對應一個value(Equality-based requirement)的關係，我們也可以使用 matchExpressions 來設定更有彈性的Labels

```bash=
# 新增 label 至 指定pod中
kubectl label pods k8s-net-pod env=production
```
###### tags: `k8s`
