---
# System prepended metadata

title: K8S入門hands on
tags: [BruceYang, Docker/K8S]

---

# K8S入門hands on
</br>

# 目錄
> [TOC]

---

# 事前說明
## Container Orchestriation容器編排
- 編排應用程式與後端容器(資料庫、SNS、其它後端服務)的依賴關係。
- 根據負載，設定應用程式的擴縮。
- 常見容器編排工具：
  - Docker Swarm
  - Kubernetes
  - MESOS（Apache）

---

# 一、Kubernetes組成架構
## 1. Nodes(Minions)節點
- 安裝Kubernetes的虛擬主機，可以是一台AWS EC2、GCP Compute Engine等。
- 如果應用程式僅部屬單一Node節點，則該Node若出現故障，會導致應用程式無法運行。

## 2. Cluster 叢集
- 由多個Node組成的叢集，彼此協助負載流量。
- 若單一Node出現故障，仍可以從其他Node訪問應用程式。
- 一個Cluster叢集包含下列2種類型的Node節點：
 ![Kubernetes主叢節點](https://hackmd.io/_uploads/BklKqplFR.png)
  - **Master節點：**
    - **說明：** 包含所有子節點的配置訊息，並負責子節點上容器的實際編排。
    - **API Server：** K8S的前端服務，用戶、CMD都透過API Server與K8S進行通信、交互。
    - **etcd：** 以Key-Value、分佈式的形式儲存用於管理集群的所有數據。
    - **Controller：** 在節點、容器、端點出現故障時，負責進行通知、響應，必且做出創建新容器的決定。
    - **Scheduler：** 負責節點間的調度、分配工作或容器、查找新創建的容器並將其分配給節點。
  - **Worker節點：**
    - **說明：** 負責託管、運行容器的節點（但Kubernetes不會直接在Worker節點上部屬容器）。
    - **kubelet：** 確保容器按預期在節點上運行。
    - **kube-proxy：** 與其他節點進行通信、節點網路設定。
    - **Container Runtime：** 接收Master節點API Server的請求動作，並根據請求運行容器。

## 3. Pod
- 運行應用程式的最小單位，且Pod也是Kubernetes運作的最小單位。
- 通常Pod數量會對應應用程式數量（含多個容器Container），不會在同一Pod擴展應用程式數量。
- **Kubernetes 擴展（說明 Node、Cluster、Pod 間的關係）：**
  ![Kubernetes添加POD、NODE](https://hackmd.io/_uploads/B1vkfAeKR.png)
  - 若應用程式的使用者增加，會先直接在同一Node中添加一個運行應用程式的Pod2（1 個 Node 運行 2 個 Pod）。
  - 若應用程式的使用者再度增加，且Node節點沒有足夠容量再添加Pod，則會擴展Cluster集群的Node2節點（2 個 Node 運行 3 個 Pod）。
- **Docker v.s Kubernetes Pod：**
  - 若純Docker環境的應用程式有一個Web容器+資料庫容器，擴展時必須先添加多組Web容器+資料庫容器的應用程式，並且設置多個容器共用網路、映射共同目錄、多容器監控等作業。
  - Kubernetes環境則可以透過Pod打包應用程式（Web容器+資料庫容器），來管理多容器應用程式。

---

# 二、CentOS作業系統部屬 K8S 測試環境
## **1. 說明**
- **Docker Engine：** Kubernetes是一個容器編排的應用程式，因此必須有Docker Engine來啟動、管理容器。
- **kubectl：** 用於Kubernetes集群的部署和管理應用程式的Kubernetes指令集。
- **minikube：** 於本地主機啟動、部屬單節點的Kubernetes叢集。

## **2. 安裝、部屬**
- **Docker Engine：**
  [Docker官方網站說明](https://docs.docker.com/engine/install/)。
- **kubectl：**
  [Kubernetes官方網站說明](https://kubernetes.io/docs/tasks/tools/)。
- **minikube：**
  [Kubernetes官方網站說明](https://minikube.sigs.k8s.io/docs/start/?arch=%2Flinux%2Fx86-64%2Fstable%2Fbinary+download)
  - 啟動minikube時，不得使用root管理員，因此必須創建minikube使用者並給予權限。
    ![minikube1](https://hackmd.io/_uploads/r1XGdlWFA.jpg)
    ```
    sudo useradd -m minikubeuser
    sudo passwd minikubeuser
    sudo usermod -aG docker minikubeuser
    ```
    ```
    su - minikubeuser
    ```
    ```
    minikube start --driver=docker
    ```
    ![minikube2](https://hackmd.io/_uploads/SyPdOgWK0.jpg)

## **3. kubectl常用指令**
  - `kubectl run 鏡像名稱`：命令在集群的Pod部屬容器。
  - `kubectl cluster info`：用於查看集群訊息。
  - `kubectl get nodes`：列出所有節點。

## **4. 實作範例**
  :::info
  :::spoiler **Pod實作**
  </br>

  **1.創建Pod並從Docker Hub Repository下載Nginx鏡像**
  ```
  kubectl run nginx --image nginx
  ```
  ![pod1](https://hackmd.io/_uploads/SJUUc0ltR.jpg)
  </br>

  **2.查看Pods列表**
  ```
  kubectl get pods
  ```
  ![pod2](https://hackmd.io/_uploads/BkRPqCgFR.jpg)
  </br>

  **3.查看該Pod的詳細資訊**
  ```
  kubectl describe pod pod名稱
  ```
  ![pod3](https://hackmd.io/_uploads/H14lR3EYC.jpg)
  - Pod本身之IP地址、Port端口
  - Pod所在Node節點之IP地址
  - 啟動的容器、鏡像訊息
  - 創建Pod之流程事件
  </br>

  **4.查看Pod本身之IP地址、端口**
  ```
  kubectl get pods -o wide
  ```
  ![pod4](https://hackmd.io/_uploads/ry_meaNY0.jpg)
  </br>
  :::

---

# 三、Kubernetes的YAML文件(Pod)
## **1. YAML說明**
使用YAML文件來創建Object對象如:Pod、Replica副本、Deployment部屬、Service服務。

## **2. YAML文件內容**
- **apiVersion**
  - 創建對象時，指定的Kubernetes API版本。　
  - 範例：
    | Kind | Version |
    | -------- | -------- |
    | Pod | v1 |
    | Service | v1 |
    | ReplicaSet | apps/v1 |
    | Deployment | apps/v1 |
- **kind**
  - 對象的類型，如：Pod、Replica、Deployment、Service（下方3. 實作範例包含4種類型的yaml範例文件）。
- **metadata**
  - 對象的元數據，如：name名稱、labels標籤（包含app、type）等。
- **spec**
  - 對象的詳細資訊，如：啟動的容器名稱、鏡像名稱等。

## **3. 實作範例**
:::info
:::spoiler **使用Pod的YAML文件創建Pod**
**1. 撰寫pod-definition.yml文件**
```
apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    app: myapp
    tier: front-end
spec:
  containers:
  - name: nginx
    image: nginx
##第2個容器
##- name: busybox
##  image: busybox
```
![yaml1](https://hackmd.io/_uploads/By9w0pNFA.jpg)
</br>

**2. 執行YAML文件來創建Pod**
```
kubectl create -f pod-definition.yml
```
![yaml2](https://hackmd.io/_uploads/BJQOCa4F0.jpg)
</br>

**3. 查看Pod列表**
```
kubectl get pods
```
![yaml3](https://hackmd.io/_uploads/r1idRTVKA.jpg)
</br>

**4. 查看Pod詳細資料**
```
kubectl describe pod myapp-pod
```
![yaml4](https://hackmd.io/_uploads/SkEFApEFC.jpg)
</br>
:::

---

# 四、Kubernetes的YAML文件(Replication)
## **1. Replication Controller（舊技術）說明**
由Kubernetes Master節點中的Replication Controller元件決定是否增加新Pod、容器（可跨節點執行），並確保指定數量的Pod始終在運行（不論數量大小）。

:::info
:::spoiler **使用Replication Controller的YAML文件創建Pod**
**1. 撰寫rc-definition.yml文件**
```
apiVersion: v1
kind: ReplicationController
metadata:
  name: nginx-rc
  labels:
      app: myapp
      tier: front-end
spec:
  template: ##replica的啟動範本（參照啟動Pod之yaml文件）

    metadata:
      name: nginx
      labels:
        app: myapp
        type: front-end
    spec:
      containers:
      - name: nginx
        image: nginx
  
  replicas: 3 ##replica副本數量
```
![replication1](https://hackmd.io/_uploads/BJjEJDvK0.jpg)
</br>

**2. 執行YAML文件來創建Replication**
```
kubectl create -f rc-definition.yml
```
![replication2](https://hackmd.io/_uploads/B1BBkvPYC.jpg)
</br>

**3. 查看Replication列表**
```
kubectl get replicationcontroller
```
![replication3](https://hackmd.io/_uploads/rJK01vvKC.jpg)
</br>

**4. 查看Pod列表**
```
kubectl get pods
```
![replication4](https://hackmd.io/_uploads/HysGxDDKR.jpg)
</br>
:::

## 2. Replica Set（新技術）
相較於Replication Controller，Replica Set可以透過標籤（selector-matchLabels）的方式，篩選並監控帶有該標籤內容的Pod，若有任一Pod出現問題，Replica Set便會生成新Pod。
:::info
:::spoiler **使用Replica Set的YAML文件創建Pod**
**1. 撰寫replicaset-definition.yml文件**
```
apiVersion: apps/v1 ##版本必須撰寫成『apps/版本號』　
kind: ReplicaSet
metadata:
  name: nginx-replicaset
  labels:
      app: myapp
      tier: front-end
spec:
  template: ##replica的啟動範本（參照啟動Pod之yaml文件）

    metadata:
      name: nginx
      labels:
        app: myapp
        type: front-end
    spec:
      containers:
      - name: nginx
        image: nginx 
  
  replicas: 3 ##replica副本數量
  selector: ##非必要撰寫，replica副本標籤
    matchLabels:
      type: front-end
```
![replicaset1](https://hackmd.io/_uploads/B1-C3PwFR.jpg)
</br>

**2. 執行YAML文件來創建ReplicaSet**
```
kubectl create -f replicaset-definition.yml
```
![replicaset2](https://hackmd.io/_uploads/r1YJ6vPtA.jpg)
</br>

**3. 查看ReplicaSet列表**
```
kubectl get replicaset
```
![replicaset3](https://hackmd.io/_uploads/rk_46vvtA.jpg)
</br>

**4. 查看Pod列表**
```
kubectl get pods
```
![replicaset5](https://hackmd.io/_uploads/HyXO6wPtC.jpg)
</br>
  
**5. 將Replication副本添加為6個Pod**
- **方法1**
  ```
  修改replicaset-definition.yml的[replicas項目為6]
  ```
  ![replicaset6](https://hackmd.io/_uploads/S1lyAdPKR.jpg)
  ```
  kubectl replace -f replicaset-definition.yml
  ```
  ![replicaset7](https://hackmd.io/_uploads/SJ-ApuvtA.jpg)

- **方法2**
  ```
  kubectl scale --replicas=6 -f replicaset-definition.yml
  ```
  ![replicaset8](https://hackmd.io/_uploads/Bym6puvtR.jpg)
:::

---

# 五、Kubernetes的YAML文件(Deployment)
## 1. Deployment說明
![Deployment](https://hackmd.io/_uploads/S1Jkq5lcA.png)
Deployment在Kubernetes中是更高層級的對象類型(Object Kind)，負責為Replication Controller/ReplicaSet部屬的Pod，執行版本上的滾動升級、暫停更新、恢復更新等操作。

## 2. 實作範例
:::info
:::spoiler **使用Deployment的YAML文件創建Pod**
**1. 撰寫deployment-definition.yml文件**
```
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
      app: myapp
      type: front-end
spec:
  template:
    metadata:
      name: nginx
      labels:
          app: myapp
          type: front-end
    spec:
      containers:
      - name: nginx
        image: nginx

  replicas: 3
  selector:
    matchLabels:
      type: front-end
```
</br>

**2. 執行YAML文件**
```
kubectl create -f deployment-definition.yml
```
![deployment1](https://hackmd.io/_uploads/S17gGox90.jpg)
</br>

**3. 查看Deployment列表**
```
kubectl get deployment
```
![deployment2](https://hackmd.io/_uploads/Hyn7zsx9C.jpg)
</br>

**4. 查看Replicaset列表**
```
kubectl get replicaset
```
![deployment3](https://hackmd.io/_uploads/SJiDzix9C.jpg)
</br>
  
**5. 查看Pod列表**
```
kubectl get pods
```
![deployment4](https://hackmd.io/_uploads/SkAnzox9C.jpg)
:::

## 3. Update & Rollback
- **執行Rollout的策略**
  - **Rolling Update策略(Default)**
    逐步Update，而不影響應用程式的運行。
    ![rollout](https://hackmd.io/_uploads/rJ3fV3WqA.png)

  - **Recreate策略**
    全部一起Update，會導致應用程式暫停運行。
    ![rollout2](https://hackmd.io/_uploads/HJ8Nv2W9A.png)

- **常用指令**
  :::info
  :::spoiler **修改Deployment鏡像並套用至Deployment**
  - **方法1**
    手動修改YAML文件後，套用至Deployment。
    ```
    kubectl apply -f deployment-definition.yml
    ```
    ![deployment5](https://hackmd.io/_uploads/HJaKih-5R.jpg)
    ![deployment6](https://hackmd.io/_uploads/H1n5s3b9R.jpg)

  - **方法2**
    直接修改Deploymnet的YAML文件並套用至Deployment。
    ```
    kubectl set image deployment/deployment名稱 container容器名稱=鏡像名稱
    ```
    ![deployment7](https://hackmd.io/_uploads/ry7hahb9R.jpg)
  :::

  :::info
  :::spoiler **執行Rollout(Rolling Update)**
  ```
  kubectl rollout status deployment/deployment名稱
  ```
  ![deployment5](https://hackmd.io/_uploads/rk10CoW9R.jpg)
  :::

  :::info
  :::spoiler **查看Rollout(Rolling Update)修訂歷史紀錄**
  ```
  kubectl rollout history deployment/deployment名稱
  ```
  ![deployment6](https://hackmd.io/_uploads/Hy1P13Z5R.jpg)

