kubernetes - day08

August 29, 2020

POD 和容器一樣,應該只運行一個應用,這樣才有輕量化的感覺。舉例來說,前端和後端應該要在各自的 POD 上,這樣的優勢有很多,像是被調度到不同節點上運行,提高資源使用上的效率。然而,Kubernetes 的伸縮功能,可針對每個獨立的 POD 進行,這樣提高了靈活性。但是,實際上有些系統設計需要在一個 POD 中運行多個容器,而這些的設計想必又會有一套原則去實踐,如下:

管理 POD 容器

apiVersion: v1
kind: Pod
metadata:
  name: pod-demo
  namespace: default
  labels:
    app: myapp
    tier: frontend
spec:
  containers:
  - name: myapp # 容器名稱
    image: nginx:1.18 # image
  - name: busybox
    image: busybox:latest
    command: ["bin/sh", "-c", "sleep 3600"]

以上面的 POD 資源清單來看,containers 是被用來定義容器清單。在 POD 中必定要有一個容器,因此該字段必須是要定義的。然而容器的環境設置還有許多參數可設定,可用以下方式去查看,會列出關於 containers 的相關字段。

$ kubectl explain pods.spec.containers
KIND:     Pod
VERSION:  v1

RESOURCE: containers <[]Object>
...

Image 取得策略

上面 yamlcontainers 中有定義 image 字段,用來獲取定義的 image。我們都知道 POD 是用來運行容器,想必節點上必須要有 CRI,這邊以 Docker 為例,其獲取 image 過程如下圖。

來自"TechBridge技術共筆部落格"

運作大致是,運行容器時,容器的引擎會於本地尋找所定義的 image 檔案,當不存在時會從 Registry 下載到本地端。而在 Kubernetes 中可讓用戶自定義關於容器 image 的取得策略,其字段為 imagePullPolicy,其可有以下值做設定,詳細可參考官網

可嘗試使用上面的 yaml 建立 POD,用 -o yaml 觀察 imagePullPolicy 是否預設為 IfNotPresent,當 image 帶有 latest 標籤時始以 Always 作為預設。而 imagePullPolicy 設置如下

apiVersion: v1
kind: Pod
metadata:
  name: pod-demo
  namespace: default
  labels:
    app: myapp
    tier: frontend
spec:
  containers:
  - name: myapp
    image: nginx:1.18
    imagePullPolicy: Always
  - name: busybox
    image: busybox:latest
    command: ["/bin/sh", "-c", "sleep 3600"]

Port 映射

Docker 網路設計中,每個容器的網路需要透過 NAT 機制將其暴露到網路中才能被其他節點上的容器訪問。但在 Kubernetes 中,每個 PODIP 位址都在同一個網路上,而這樣的設計讓其它節點的 POD 客戶端可直接訪問,因此 Port 的定義可為集群的客戶端提供一個快速連接 POD 的可訪問 Port 途徑。

yaml 配置如下

apiVersion: v1
kind: Pod
metadata:
  name: pod-ports-demo
  namespace: default
  labels:
    app: myapp
    tier: frontend
spec:
  containers:
  - name: myapp
    image: nginx:1.18
    imagePullPolicy: Always
    ports: # 從這邊開始
    - name: http # 可被 Service 資源調用
      containerPort: 80 # 在 POD 對象的 IP 地址上映射的容器 Port
      protocol: TCP
  - name: busybox
    image: busybox:latest
    command: ["/bin/sh", "-c", "sleep 3600"]

上述的設定無法讓集群外部的使用者進行訪問,解決此方式是將節點的 IPPort 將其映射至集群外部,可使用 hostPorthostIP 將其資訊應設至主機上,叫好的方式是使用 Service 資源。

環境變數

容器是一種隔離技術,對於應用程式其環境配置相當麻煩,因此環境變數這個概念,使得該概念可在容器啟用時傳遞一個可配置的訊息。在 POD 中的容器環境變數傳遞方法有以下

下面為 env 使用範例

# 官方範例
apiVersion: v1
kind: Pod
metadata:
  name: envar-demo
  labels:
    purpose: demonstrate-envars
spec:
  containers:
  - name: envar-demo-container
    image: gcr.io/google-samples/node-hello:1.0
    env:
    - name: DEMO_GREETING
      value: "Hello from the environment"
    - name: DEMO_FAREWELL
      value: "Such a sweet sorrow"

當上述 yaml 成功啟動時,透過 exec 去驗證,是否以環境變數傳遞。

$ kubectl exec envar-demo -- printenv
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=envar-demo
DEMO_GREETING=Hello from the environment # this
DEMO_FAREWELL=Such a sweet sorrow # this
KUBERNETES_SERVICE_PORT=443
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_PORT=tcp://10.8.0.1:443
KUBERNETES_PORT_443_TCP=tcp://10.8.0.1:443
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_PORT_443_TCP_ADDR=10.8.0.1
KUBERNETES_SERVICE_HOST=10.8.0.1
NPM_CONFIG_LOGLEVEL=info
NODE_VERSION=4.4.2
HOME=/root

共享節點網路

簡單來說就是把主機的網路掛到 POD 中,使用 hostNetwork 字段即可實現。如下圖所示

我們定義以下 yaml 驗證。

apiVersion: v1
kind: Pod
metadata:
  name: pod-host-net-demo
  namespace: default
  labels:
    app: myapp
    tier: frontend
spec:
  containers:
  - name: myapp
    image: nginx:1.18
    imagePullPolicy: Always
    ports:
    - name: http
      containerPort: 80
      protocol: TCP
  - name: busybox
    image: busybox:latest
    command: ["/bin/sh", "-c", "sleep 3600"]
  hostNetwork: True

IP 可以看出來它變成節點 IP

$ kubectl get pods -o wide
NAME                READY   STATUS    RESTARTS   AGE     IP                NODE     NOMINATED NODE   READINESS GATES
pod-host-net-demo   2/2     Running   0          116s    192.168.134.135   node02   <none>           <none>

POD 容器安全

POD 中可以設置容器的權限和訪問控制。在 POD 等級使用 $ kubectl explain pods.spec.securityContext 查看,至於容器則是 $ kubectl explain pods.spec.containers.securityContext 。詳細可參考官方資源

總結

今天描述了 POD 資源清單定義容器的一些應用,上面資源清單可使用 kubectl apply -f 方式去部署 POD,同時在熟練前面幾個章節介紹的指令去觀察 POD,像是 describeget-o wide 等。