# 5/16 Backend Study (K8s) --- ## Who am i ? PHP FullStack -> Data Science -> Cloud computing --- ## 什麼是容器 ? ![](https://i.imgur.com/hhF7e9R.png) --- ### Docker #### Before Docker => VMs VM : 以作業系統為核心,將一個應用程式所需的執行環境打包起來,建立一個獨立環境,方便在不同的硬體中移動。 虛擬機器是在系統層上虛擬化,透過 Hypervisor 在目標的機器上提供可以執行一個或多個虛擬機器的平台。而這些虛擬機器可以執行完整的作業系統。簡單來說,Hypervisor就是一個可以讓你在作業系統(Host OS)上面再裝一個作業系統(Guest OS),然後讓兩個作業系統彼此不會打架的平台。 --- ![](https://i.imgur.com/4Zbe0VC.png) --- #### After Docker Docker: 以應用程式為核心,主要是想改善 VM 需要裝 Guest OS 造成系統負擔重的問題。 容器是在作業系統層上虛擬化,透過 Container Manager 直接將一個應用程式所需的程式碼、函式庫打包,建立資源控管機制隔離各個容器,並分配 Host OS 上的系統資源。透過容器,應用程式不需要再另外安裝作業系統(Guest OS)也可以執行。 --- ![](https://i.imgur.com/aBMVUrD.png) --- #### 容器跟虛擬機的比較 | 特性 | 容器 | 虛擬機 | | -------- | -------- | -------- | | 啟動 | 秒 | 分鐘 | | 硬碟佔用 | 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 架構 ![](https://i.imgur.com/sFvWnHG.png) --- ### 四大元件 --- #### 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 ![](https://i.imgur.com/oRqc9aG.png) --- #### 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 ``` ![](https://i.imgur.com/0V3FTRJ.png) --- ### 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 ![](https://i.imgur.com/PbzX7LG.png =350x) --- ## 其他Deployment應用 --- ### Blue/Green Deployments on Kubernetes ![](https://i.imgur.com/OkvX74M.png) --- 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}]"}
    504 views