# 5/16 Backend Study (K8s)
---
## Who am i ?
PHP FullStack -> Data Science -> Cloud computing
---
## 什麼是容器 ?

---
###  Docker
#### Before Docker => VMs
VM : 以作業系統為核心,將一個應用程式所需的執行環境打包起來,建立一個獨立環境,方便在不同的硬體中移動。
虛擬機器是在系統層上虛擬化,透過 Hypervisor 在目標的機器上提供可以執行一個或多個虛擬機器的平台。而這些虛擬機器可以執行完整的作業系統。簡單來說,Hypervisor就是一個可以讓你在作業系統(Host OS)上面再裝一個作業系統(Guest OS),然後讓兩個作業系統彼此不會打架的平台。
---

---
#### After Docker
Docker: 以應用程式為核心,主要是想改善 VM 需要裝 Guest OS 造成系統負擔重的問題。
容器是在作業系統層上虛擬化,透過 Container Manager 直接將一個應用程式所需的程式碼、函式庫打包,建立資源控管機制隔離各個容器,並分配 Host OS 上的系統資源。透過容器,應用程式不需要再另外安裝作業系統(Guest OS)也可以執行。
---

---
#### 容器跟虛擬機的比較
| 特性 | 容器 | 虛擬機 |
| -------- | -------- | -------- |
| 啟動     | 秒     | 分鐘     |
| 硬碟佔用     | MB     | GB     |
| 性能     | 接近原生     | 較弱     |
| 系統支援量     | 單機支援上千個     | 幾十個     |
---
#### 用簡單的script就可以啟動service
```bash=
docker pull username/simple_node_app
docker run -d -p 8080:8080 --name test_app username/simple_node_app
```
---
### 情況 1: 小明公司的 api server 發現不堪負荷,需要平行去擴展 Server,直觀的話需要怎麼做呢?
Ans: 把所有 Service 一個一個進去伺服器建立系統並且上線 api server。
---
### 那如果今天有 1000 個一樣的 Service 需要部署呢 ?
### 那如果今天有 1000 個一樣的 Service 需要更新呢 ?
---
## Kubernetes
---
常簡稱為 K8s, 是用於自動部署、擴充和管理「容器化(containerized)應用程式」的開源系統。該系統由Google設計並捐贈給 Cloud Native Computing Foundation(今屬Linux基金會)來使用。
---
### 目錄
* 架構
* 元件
* 新增 K8s cluster
* 新增一個 Pod
* 新增 Service
* 一次部署多個 Pod
---
### Kubernetes 架構

---
### 四大元件
---
#### Pod
Kubernetes 運作的最小單位,一個 Pod 對應到一個應用服務(Application) ,舉例來說一個 Pod 可能會對應到一個 API Server。
* 每個 Pod 都有一個身分證,也就是屬於這個 Pod 的 yaml 檔
* 一個 Pod 裡面可以有一個或是多個 Container,但一般情況一個 Pod 最好只有一個 Container
* 同一個 Pod 中的 Containers 共享相同資源及網路,彼此透過 local port number 溝通
---
#### Worker Node
Kubernetes 運作的最小硬體單位,一個 Worker Node(簡稱 Node)對應到一台機器,可以是實體機如你的筆電、或是虛擬機如 AWS 上的一台 EC2 或 GCP 上的一台 Computer Engine。
每個 Node 中都有三個組件:kubelet、kube-proxy、Container Runtime。
---
#### Master Node
Kubernetes 運作的指揮中心,可以簡化看成一個特化的 Node 負責管理所有其他 Node。一個 Master Node(簡稱 Master)中有四個組件:kube-apiserver、etcd、kube-scheduler、kube-controller-manager。
---
#### Cluster
Kubernetes 中多個 Node 與 Master 的集合。基本上可以想成在同一個環境裡所有 Node 集合在一起的單位。
---
### 新增 K8s cluster
在現實層面可能是很多台 server 串接再一起形成 Cluster,但是今天方便示範就會以 Minikube 來跑單一機器下的 Single Cluster。
* Minikube: 一個 Google 發佈的輕量級工具,讓開發者可以輕鬆體驗一個的 Kubernetes Cluster。Minikube 會在本機端建立 Virtual Machine,並在其中運行一個 Single-Node 的 Kubernetes Cluster
---
```bash=
brew install minikube
```
```bash=
minikube start //啟動minikube虛擬機
minikube dashboard //開啟網頁監控視窗
kubectl version
kubectl get nodes
minikube stop //停止minikube(不玩了)
```
---
### Pod
---
**Image from**: paulbouwer/hello-kubernetes:1.8

---
#### YAML 檢查工具
https://www.bejson.com/validators/yaml/
---
#### 撰寫一個 Pod yaml
```yaml=
//hello-kubernetes.yaml
apiVersion: v1
kind: Pod
metadata:
    name: hello-kubernetes
    labels:
        app: hello-kubernetes-app
spec:
    containers:
    - name: hello-kubernetes
      image: paulbouwer/hello-kubernetes:1.8
      ports:
        - containerPort: 8080
```
---
```bash=
kubectl create -f hello-kubernetes.yaml
kubectl get pods
```
```
NAME                                READY   STATUS    RESTARTS   AGE
hello-kubernetes                    1/1     Running   0          4s
```
---
建立好我們的 Pod 之後,打開瀏覽器的 localhost:8080 我們會發現怎麼什麼都看不到。這是因為在 Pod 中所指定的 port,跟我們 local 端的 port 是不相通的。因此,我們必須還要透過 kubectl port-forward,把我們兩端的 port 做 mapping。
---
#### 利用 port-foward 進入 pod
```bash=
kubectl port-foward hello-kubernetes 8080:8080
```

---
### Service
---
還記得上面提到我們在連線到一個 Pod 的服務資源時,會使用到 port-forward 的指令。但如果我們有多個 Pods 想要同時被連線時,我們就可以用到 Service 這個元件。簡單來說,Service 就是 Kubernetes 中用來定義「一群 Pod 要如何被連線及存取」的元件。
---
#### 撰寫 Service.yaml
```yaml=
apiVersion: v1
kind: Service
metadata:
   name: my-service
spec:
   selector:
     app: hello-kubernetes-app
   type: NodePort
   ports:
     - protocol: TCP
       port: 3001
       targetPort: 8080
       nodePort: 30390
```
---
```bash=
kubectl create -f service.yaml
kubectl get service
```
```
NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE
kubernetes   ClusterIP   10.96.0.1      <none>        443/TCP          4h38m
my-service   NodePort    10.102.55.93   <none>        3001:30390/TCP   6s
```
---
#### 存取 Service
此時只要打開瀏覽器,輸入 http://ip:nodePort 即可看到畫面。
如果想要直接進去 minikube 存取到 Service,則只要輸入
```bash=
minikube ip
minikube ssh
curl <cluster-ip>:<port>
```
---
```
<!DOCTYPE html>
<html>
<head>
    <title>Hello Kubernetes!</title>
    <link rel="stylesheet" type="text/css" href="/css/main.css">
    <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Ubuntu:300" >
</head>
<body>
  <div class="main">
    <img src="/images/kubernetes.png"/>
    <div class="content">
      <div id="message">
  Hello world!
</div>
<div id="info">
  <table>
    <tr>
      <th>pod:</th>
      <td>hello-kubernetes-f8dd54444-px4rc</td>
    </tr>
    <tr>
      <th>node:</th>
      <td>Linux (4.19.107)</td>
    </tr>
  </table>
</div>
    </div>
  </div>
</body>
</html>
```
---
或是
```bash=
kubectl port-forward service/my-service 7080:3001
```
---
### Deployment
---
今天當我們同時要把一個 Pod 做橫向擴展,也就是複製多個相同的 Pod 在 Cluster 中同時提供服務,並監控如果有 Pod 當機我們就要重新把它啟動時,如果我們要一個 Pod 一個 Pod 透過指令建立並監控是很花時間的。因此,我們可以透過 Deployment 這個特殊元件幫我們達成上述的要求。
---
#### 撰寫 deployment.yaml
```yaml=
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-kubernetes
spec:
  replicas: 3
  selector:
    matchLabels:
      app: hello-kubernetes
  template:
    metadata:
      labels:
        app: hello-kubernetes
    spec:
      containers:
      - name: hello-kubernetes
        image: paulbouwer/hello-kubernetes:1.8
        ports:
        - containerPort: 8080
```
---
```bash=
kubectl get deployment
kubectl get pods
```
```
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
hello-kubernetes   3/3     8            8           77m
```
```
NAME                                READY   STATUS    RESTARTS   AGE
hello-kubernetes-66c94b4c7c-26dxp   1/1     Running   0          73m
hello-kubernetes-66c94b4c7c-9mmq2   1/1     Running   0          73m
hello-kubernetes-66c94b4c7c-b59m8   1/1     Running   0          75m
```
---
### Scale up
---
可以先輸入
```
kubectl get rs
```
```
NAME                          DESIRED   CURRENT   READY   AGE
hello-kubernetes-66c94b4c7c   3         3         3       5s
```
---
看目前有幾個 replicas,若今天要擴展成8個,則只需要輸入
```
kubectl scale deployment/hello-kubernetes --replicas=8
```
---
即可擴展成功
```
NAME                          DESIRED   CURRENT   READY   AGE
hello-kubernetes-66c94b4c7c   8         8         8       2m43s
```
---
### Rollout/Rollback
---
#### Zero Downtime Rollout
---
當我們要更新我們的 Pod 時,Kubernetes 並不會直接砍掉我們所有的 Pod,而是會建立新的 Pod,等新的 Pod 開始正常運行後,再來取代舊的 Pod。
---
舉例來說,假設我們現在想要更新我們 Pod 對外的 Port,我們可以先透過指令
```bash=
kubectl edit deployment hello-kubernetes
```
---
把 Port 8080 改成 8081 後儲存。這時候就可以透過
```bash=
kubectl get pods
```
觀看 Pods 狀態。
```
NAME                                READY   STATUS        RESTARTS   AGE
hello-kubernetes                    1/1     Running       0          13h
hello-kubernetes-66c94b4c7c-bxc68   0/1     Terminating   0          30m
hello-kubernetes-f8dd54444-bmnkp    1/1     Running       0          5s
hello-kubernetes-f8dd54444-px4rc    1/1     Running       0          7s
hello-kubernetes-f8dd54444-tczgm    1/1     Running       0          8s
```
---
#### Rollback version
---
這時候可以透過
```bash=
kubectl rollout history deployment hello-kubernetes
```
觀看目前Deployment的版本
```
deployment.extensions/hello-kubernetes
REVISION  CHANGE-CAUSE
1         <none>
2         <none>
```
---
也可以將目前的版本用
```bash=
kubectl rollout undo deploy hello-kubernetes
```
讓我們的 Pod 都恢復成版本 1。甚至之後如果版本變的較多後,我們也可以指定要 Rollback 到的版本
```bash=
kubectl rollout undo deploy hello-kubernetes --to-revision=2
```
---
### More
---
#### Reverse proxy: Ingress

---
## 其他Deployment應用
---
### Blue/Green Deployments on Kubernetes

---
DEMO
---
## Reference
1. https://zh.wikipedia.org/wiki/Kubernetes
2. http://samchu.logdown.com/posts/2473458-blue-green-deployments-on-kubernetes
3. https://medium.com/unorthodox-paranoid/docker-tutorial-101-c3808b899ac6
4. https://kubernetes.io/
5. https://github.com/paulbouwer/hello-kubernetes
6. https://www.bejson.com/validators/yaml/
             
            {"metaMigratedAt":"2023-06-15T08:16:16.235Z","metaMigratedFrom":"Content","title":"5/16 Backend Study (K8s)","breaks":true,"contributors":"[{\"id\":\"79ae42f5-7271-4ddc-bfc4-f012d7063029\",\"add\":9708,\"del\":1206}]"}