什麼是 Kubernetes – 實際應用

上一篇文章中我們介紹了 Kubernetes 解決了什麼樣的問題以及他的基本原理。在這一篇,我們要來使用 minikube 來建立一個模擬的 Kubernetes 環境,並且我們也會用到 kubectl 這個工具,這是一個專屬於 Kubernetes 的 command line tools,使用者主要透過這個去和 Cluster 溝通!我們會運行簡單的程式碼,建立 Docker 映像檔並透過 Kubernetes 部署,簡單的看看到底該如何使用 Kubernetes,以及他到底怎麼運作的!

安裝 minikube

第一步當然就是來到我們的安裝啦!安裝非常簡單,我們直接到 minikube 的官方網站就可以找到 Installation 了!因為我的電腦是 Mac,所以以下我就用 Mac 的指令來進行安裝。

$ brew install minikube

這樣就完成安裝啦!是不是很簡單!

執行 minikube

安裝完 minikube 後,我們就可以跑這一行指令執行 minikube!

執行之後,我們應該會看到類似以下的畫面!我們可以發現,在 minikube 建立 Cluster 之前,他會先檢查 Docker 的版本以及是否運行正常,顯示 Kubernetes 跟 Docker 是密不可分的!所以我們絕對要先了解 Docker 才能真的了解 Kubernetes。我們也可以看到在最後一行,kubectl 同時也被 minikube 建置好了!

另外,我們也可以試著跑跑看以下指令

$ minikube status       # 列出 minikube 狀態
$ minikube dashboard    # 提供 UI 介面查看 Cluster 資訊
$ minikube stop         # 停止 minikube
$ minikube ip           # 查看 minikube 的對外接口

還記得 kubectl 嗎?我們也可以用 kubectl 來查看我們 Cluster 的資訊

$ kubectl get all

開始部署

接下來,我們要來準備我們的應用程式。在這個例子中,我們會利用 Python Dash 來建立一個互動式的儀表板。我們會先從最最最簡單的 local 應用開始,接著進一步利用 Docker 來容器化我們的應用程式,最後利用 Kubernetes 來部署我們的應用程式。

為什麼要這樣勒?幹嘛不直接講要怎麼在 Kubernetes 上部署就好了?因為我認為透過這樣的步驟,我們才可以真的理解 Kubernetes 是什麼時候需要被用到,以及他為什麼會被發明出來!

本地端

假設今天你因為學校作業需求,或是突然想學習要怎麼用 Python 來建立一個可以和使用者互動的儀表板。那麼大概率你不需要 Docker 甚至是 Kubernetes 這類工具,因為你做出來的東西基本上就是個人需求而已。所以基本上你只要在自己的電腦上把需要的套件安裝一下,然後寫出一段可以運行的程式碼跑一下就行了!這就是我們接下來要做的!如果覺得不想在自己電腦上安裝一些有的沒的,可以利用 virtualenv,但這章為求方便,我們就直接裝在本機上吧~

首先,我們先來安裝這兩個套件

pip3 install dash pandas

dash 就是 python 的互動式儀表板,而 pandas 則是一個被廣泛使用的資料處理工具。

安裝完成後,我們來寫一個 app.py 程式碼:

from dash import Dash, html, dcc, callback, Output, Input
import plotly.express as px
import pandas as pd

df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/gapminder_unfiltered.csv')

app = Dash(__name__)

app.layout = html.Div([
    html.H1(children='Title of Dash App', style={'textAlign':'center'}),
    dcc.Dropdown(df.country.unique(), 'Canada', id='dropdown-selection'),
    dcc.Graph(id='graph-content')
])

@callback(
    Output('graph-content', 'figure'),
    Input('dropdown-selection', 'value')
)
def update_graph(value):
    dff = df[df.country==value]
    return px.line(dff, x='year', y='pop')

if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0')

接著,我們可以直接執行這段程式碼

python3 app.py

我們會看到類似以下輸出

Dash is running on http://0.0.0.0:8050/

 * Serving Flask app 'app'
 * Debug mode: on

接著把這個連結 http://0.0.0.0:8050/ 複製貼上到你最喜歡用的瀏覽器,我們就可以看到這樣的結果啦!

容器化

誒結果你有一個朋友發現你寫出來的儀表板很棒很漂亮想要借你的成品參考一下。因為是你的好朋友,你二話不說直接傳給他你的 app.py 叫他自己在他電腦上跑就好了,但是他後來跑過來跟你說誒他的電腦跑不動你的程式碼。你們研究了一下發現,啊原來在他電腦上,dash 跟 pandas 的套件版本跟你電腦上的版本不一樣,而且他電腦是用某個非常獨一無二的作業系統,運行指令的方式完全不同。你想了想要怎麼解決,想起來你在科技讀蟲這個一級棒的部落格上學到 Docker 這個技能。沒錯!我們接下來就是要將我們的成品容器化,解決你的朋友沒辦法在他的電腦上運行的這個問題!

首先,我們要建立一個 /app 的檔案夾,並將 app.py 放進這個檔案夾。接著,我們要建立一個 requirements.txt,裡面放我們需要安裝的套件。

dash
pandas

接著,我們要來寫一個 Dockerfile

FROM python:3

WORKDIR /usr/src/app

COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

CMD [ "python3", "app.py" ]

做好這些後,我們就可以來建立一個映像檔

docker build -t app .

接著就可以在 container 裡面執行我們的程式啦!

docker run -h localhost -p 8050:8050 app

執行完成後我們會看到這樣的輸出

Dash is running on http://0.0.0.0:8050/

 * Serving Flask app 'app'
 * Debug mode: on

一樣,將那個連結 http://0.0.0.0:8050/ 複製到瀏覽器上就可以看到儀表板啦!

k8s 部署

殊不知你做的儀表板實在是太出色了!出色到有一家公司願意購買你的產品!但是問題來了,到了市場層面後,每天可能會有幾千幾萬人在網路上訪問你的產品,你要確保你的產品可以全年無休 24 小時的都在工作。而且萬一真的出錯當機的話,產品可以馬上替換掉當機的服務,讓正常產品立刻上限供客戶使用。另外,因為使用人數眾多,你可能還要提供網路分流、錯誤匯報、產品自動更新等等的服務。沒錯!這就是 Kubernetes 上場的時間啦!接下來,我們就會將我們的產品部署在之前下載好的 minikube 上。

首先,我們要來建立一個 demo.yaml 的文件

apiVersion: v1
kind: Service
metadata:
  name: dash-app-service
spec:
  selector:
    app: dash-app
  type: NodePort
  ports:
    - protocol: TCP
      port: 3000
      nodePort: 30390
      targetPort: 8050
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: dash-app
spec:
  selector:
    matchLabels:
      app: dash-app
  replicas: 3
  template:
    metadata:
      labels:
        app: dash-app
    spec:
      containers:
        - name: dash-app-container
          image: app:latest
          imagePullPolicy: Never
          ports:
            - containerPort: 8050

接著,我們要運行這行指令並重新建立映像檔,讓我們的 minikube 可以看到這個映像檔

eval $(minikube -p minikube docker-env)
docker build -t app .

接著,利用 kubectl 運行我們的配置檔

kubectl create -f demo.yaml

我們可以利用這行指令查看部署完後的情況

kubectl get all

接著,我們要輸入這行指令來查看 minikube 給我們的連結

minikube service dash-app-service --url

接著將連結複製到瀏覽器上就可以看到產品啦!

理解 demo.yaml

讓我們來深入了解一下我們在 demo.yaml 做了什麼吧!首先先要說明一下,這個設置檔可以是任意名字,不一定要叫做 demo.yaml,只要他是 YAML 文件就可以了!我們可以看到基本上 demo.yaml 這個檔案基本上分成兩個部分,第一部分是和 Service 有關的設置,第二部分則是和 Deployment 有關,我們先來講講 Service。

還記得在前一章我們說常用的 Service 有兩種,NodePort 和 LoadBalancer,這邊因為我們的產品比較簡單,我們選擇使用 NodePort。在這裡面我們有兩個設置可以講講,selectorports

  • selector:顧名思義就是要決定這個 service 是要服務哪一些 pods。這邊我們就是選擇 label 叫做 dash-app 的一群 pods,這個 label 會在 deployment 的配置中設定。
  • ports:在 ports 中我們設置了三個 ports,第一個是 port,這是決定我們的 pod 要指到 service 上的哪個接口。第二個是 targetPort,這是我們 pod 上的對外接口,這個接口會在 deployment 的配置中設定。第三個是 NodePort,這個決定 pod 要指到 node 上的哪個接口,在這裡並不重要,因此可以移除。

接著我們來講講 Deployment。這邊我認為有兩個設置可以講講,replicascontainers

  • replicas:這個配置決定了我們會在 Cluster 中建立多少個 Pod。Kubernetes 會隨時檢測 Pod 的數量,如果低於這個數字就會自動新增,高於的話就會減少。這有什麼用呢?這其實非常重要!因為如果我們正在運行的產品(也就是某個 Pod)當機的話,Kubernetes 就會自動偵測到,並且立即運行替代品,確保我們的產品可以全年無休 24 小時都在運行!
  • containers:這裡就決定了我們要如何建立我們的容器啦!比如說容器的名字,要用哪個映像檔(這裡當然是我們剛剛建立的 app),還有應該使用哪個接口接收服務。

這幾個就是比較重要的配置啦,其他沒有提到的我認為不用我解釋大家那麼聰明一定都可以看得懂!

好啦講到這邊我們就講完啦。是不是覺得 Docker 真的是博大精深!我也覺得發明 Docker 跟 Kubernetes 的人真的都是天才!這篇我們從本地端,到產品容器化,到最後利用 Kubernetes 部署產品,希望大家可以透過這個流程更加理解前因後果,而不是知道有這個工具卻不知道我們為什麼要用他。希望這篇文章有幫助到你啦!