1. 程式人生 > 實用技巧 >Kubernetes進階實戰讀書筆記:管理Pod資源物件(資源物件和容器)

Kubernetes進階實戰讀書筆記:管理Pod資源物件(資源物件和容器)

一、容器與pod資源物件

絕大對數場景中都應該於一個容器中僅執行一個程序、它將日誌資訊直接輸出至容器的標準輸出、支援使用者直接使用命令(kubectl logs)獲取、這也是Docker及Kubernetes使用容器的標準方式

需要特別強調的是:一個pod物件中的多個容器必須運行於同一工作節點之上


1、Sidercar pattern(邊車模型或跨都模型)

容器中的日誌使用agent收集至日誌伺服器中時,可以將agent執行為輔助應用容器、為主應用容器中的database server啟動本地快取

2、Ambassador pattern(大使模型)

一主多從模型的遠端redis應用時,可在當前pod容器中為redis服務建立一個Ambassador container

主應用容器中的程序直接通過localhost介面訪問Ambassador container即可。即便是redis主從叢集架構發生變動時,也僅需要將Ambassador container、加以修改即可,主應用容器無需對此做任何反應

3、adapter pattern(介面卡模型)

將主應用容器中的內容進行標準輸出

1、日誌資料或指標資料的輸出

2、某應用滾動升級後的版本不相容舊版本時,其報告資訊的格式也存在不相容的可能性,使用adapter pattern有助於避免那些呼叫此報告資料的應用發生錯誤


kubernetes系統的pod資源物件用於執行單個容器化應用、此應用成為pod物件的主容器,同時pod也容納多個容器、不過額外的容器一般工作為sidecar模型,用於輔助主容器完成工作職能

二、映象及獲取策略

1、定義一個容器的基礎框架

name:CONTAINER_NAME
images:IMAGE_FILE_NAME

2、映象及獲取策略

1、資源清單

apiVersion: v1
kind: Pod
metadata:
  name: private-image-test-1
spec:
  containers:
    - name: uses-private-image
      image: $PRIVATE_IMAGE_NAME
      imagePullPolicy: Always
      command: [ "echo", "SUCCESS" ]

2、官方手冊

[root@master ~]# kubectl explain pod.spec.containers.imagePullPolicy
KIND:     Pod
VERSION:  v1

FIELD:    imagePullPolicy <string>

DESCRIPTION:
     Image pull policy. One of Always, Never, IfNotPresent. Defaults to Always
     if :latest tag is specified, or IfNotPresent otherwise. Cannot be updated.
     More info:
     https://kubernetes.io/docs/concepts/containers/images#updating-images

首先將於本地查詢指定的映象檔案,不存在的映象則需要從指定的映象倉庫下載至本地

1、imagePullPolicy: 網路資源較為緊張時可以 禁止從倉庫中獲取映象檔案

2、always: 映象標籤為 "latest" 或映象不存在是 總是從指定的倉庫中獲取映象

3、ifNotPresent: 僅當本地映象缺失時才從目標倉庫下載映象 預設策略

4、Never: 禁止從倉庫下載映象,即使用本地映象

三、暴露埠

[root@master ~]# kubectl explain pods.spec.containers.ports
RESOURCE: ports <[]Object>

DESCRIPTION:
     List of ports to expose from the container. Exposing a port here gives the
     system additional information about the network connections a container
     uses, but is primarily informational. Not specifying a port here DOES NOT
     prevent that port from being exposed. Any port which is listening on the
     default "0.0.0.0" address inside a container will be accessible from the
     network. Cannot be updated.

    ContainerPort represents a network port in a single container.

FIELDS:
   hostIP	<string>  #主機埠要繫結的主機IP
     #預設為0.0.0.0,即主機之上所有可用的ip地址
     What host IP to bind the external port to.
     
     #考慮到託管的pod物件時由排程器排程執行的,工作節點的IP地址難以明確指定,因此此欄位通常使用預設值

   hostPort	<integer>  #主機埠
     #它將接受到的請求通過NAT機制轉發至由containersport欄位指定的容器埠
     Number of port to expose on the host. If specified, this must be a valid
     port number, 0 < x < 65536. If HostNetwork is specified, this must match
     ContainerPort. Most containers do not need this.

   name	<string>  #當前埠的名稱,
     #必須符合IANA_SVC_BANE規範且在當前pod內必須唯一的;此埠可被service資源呼叫
     If specified, this must be an IANA_SVC_NAME and unique within the pod. Each
     named port in a pod must have a unique name. Name for the port that can be
     referred to by services.

   protocol	<string>  #埠相關的協議,其值金可為TCP或UDP,預設TCP
     Protocol for port. Must be UDP or TCP. Defaults to "TCP".

   containerPort	<integer> -required-  #必須欄位
     #指定在pod物件的ip地址上暴露的容器埠
     Number of port to expose on the pod's IP address. This must be a valid port 
     number, 0 < x < 65536. #有效範圍為:(0,65536)  #應該總是指定容器應用正常監聽著的埠

通過其所在的工作節點的IP地址和埠將其暴露到叢集外部

需要注意的是:hostPort與nodePort物件暴露埠的方式不同,nodePort是通過所有節點暴露容器服務的、而hostPort則是經由pod物件所在節點的IP地址來進行

四、自定義執行的容器化應用

1、args

[root@master ~]# kubectl explain pods.spec.containers.args
FIELD: args <[]string>

DESCRIPTION:
     '''
     自定義args,也是向容器中的應用程式傳遞配置資訊的常用方式之一,對於非原生的應用程式
     這幾乎也是最簡單的配置方式,領一個常用方式是使用環境變數
     '''
     Arguments to the entrypoint. The docker image's CMD is used if this is not
     provided. Variable references $(VAR_NAME) are expanded using the container's
     environment. If a variable cannot be resolved, the reference in the input
     string will be unchanged. The $(VAR_NAME) syntax can be escaped with a
     double $$, ie: $$(VAR_NAME). Escaped references will never be expanded,
     regardless of whether the variable exists or not. Cannot be updated. More
     info:
     http://kubernetes.io/docs/user-guide/containers#containers-and-commands

2、command

[root@master ~]# kubectl explain pods.spec.containers.command
FIELD: command <[]string>

'''
容器的command欄位能夠指定不同獎項預設執行的應用程式、同時使用args欄位進行引數傳遞,他們將覆蓋映象中的預設定義
只定義args欄位:將作為引數傳遞給映象中預設指定執行的應用程式
只定義了command欄位:會覆蓋映象中定義的程式及引數、並以無引數方式執行用用程式
     
 '''

DESCRIPTION:
     Entrypoint array. Not executed within a shell. The docker image's
     ENTRYPOINT is used if this is not provided. Variable references $(VAR_NAME)
     are expanded using the container's environment. If a variable cannot be
     resolved, the reference in the input string will be unchanged. The
     $(VAR_NAME) syntax can be escaped with a double $$, ie: $$(VAR_NAME).
     Escaped references will never be expanded, regardless of whether the
     variable exists or not. Cannot be updated. More info:
     http://kubernetes.io/docs/user-guide/containers#containers-and-commands

3、模板檔案

apiVersion: v1
kind: Pod
metadata:
  name: command-demo
  labels:
    purpose: demonstrate-command
spec:
  containers:
  - name: command-demo-container
    image: debian
    command: ["printenv"]
    args: ["HOSTNAME", "KUBERNETES_PORT"]
  restartPolicy: OnFailur

五、環境變數

1、解決了什麼問題

1、非容器化的傳統管理方式中、複雜應用的配置資訊多數由配置檔案進行制定、使用者可藉助與簡單的文字編輯器完成配置管理

2、然而對容器隔離出的環境中的應用程式、使用者就不得不穿透容器邊界在容器內進行配置編輯並進行過載、這種方式複雜且低效

3、於是、由環境變數在容器啟動時傳遞配置資訊就成為一種受青睞的方式

這種方式依賴於應用程式支援通過環境變數進行配置的能力、否則、使用者在製作Dorker映象時需要通過enrypoint指令碼完成環境變數到程式配置檔案的同步

2、官方手冊

[root@master ~]# kubectl explain pods.spec.containers.env
RESOURCE: env <[]Object>

DESCRIPTION:
     List of environment variables to set in the container. Cannot be updated.

    EnvVar represents an environment variable present in a Container.

FIELDS:
   name	<string> -required-   #環境變數的名稱,必選欄位
     Name of the environment variable. Must be a C_IDENTIFIER.

   value	<string>      #傳遞環境變數的值,通過$(VAR_NAME)引用、預設值為空
     Variable references $(VAR_NAME) are expanded using the previous defined
     environment variables in the container and any service environment
     variables. If a variable cannot be resolved, the reference in the input
     string will be unchanged. The $(VAR_NAME) syntax can be escaped with a
     double $$, ie: $$(VAR_NAME). Escaped references will never be expanded,
     regardless of whether the variable exists or not. Defaults to "".

   valueFrom	<Object>
     Source for the environment variable's value. Cannot be used if value is not
     empty.

1、REDIS_HOST:定義了filebeat手機的日誌資訊要發往的redis主機地址,

2、LOG_LEVEL:則定義了filebeat的日誌級別

這些環境變數可直接注入容器的shell環境中,無論他們是否真正被用到,使用printenv一類的命令都能在容器中獲取所有環境變數的列表

3、生產用例

[root@master chapter5]# cat filebeat-ds.yaml 
.....
spec:
  selector:
.....
    spec:
      containers:
      - name: filebeat
        image: ikubernetes/filebeat:5.6.5-alpine
        env:
        - name: REDIS_HOST
          value: db.ikubernetes.io:6379
        - name: LOG_LEVEL
          value: info

六、共享節點的網路名稱空間

也有一些特殊的pod物件需要運行於所在節點的名稱空間中,執行系統級的管理任務、例如檢視和操作節點的網路資源甚至是網路裝置等

kube-apiserver
kube-controller-manager
kube-scheduler
kube-proxy
kube-flannel

1、pod物件網路名稱空間

2、官方手冊

spec.hostNetwork的屬性為true即可建立共享節點網路名稱空間的pod物件

[root@master ~]# kubectl explain pod.spec.hostNetwork
KIND:     Pod
VERSION:  v1

FIELD:    hostNetwork <boolean>

DESCRIPTION:
     Host networking requested for this pod. Use the host's network namespace.
     If this option is set, the ports that will be used must be specified.
     Default to false.

3、測試用例

1、資源清單

[root@master pod]# cat pod-use-hostnetwrk.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: pod-user-hostnetwork
spec:
  containers:
    - name: myapp
      image: ikubernetes/myapp:v1
  hostNetwork: true

2、建立驗證

[root@master pod]# kubectl apply -f pod-use-hostnetwrk.yaml 
pod "pod-user-hostnetwork" created
[root@master pod]# kubectl apply -f pod-use-hostnetwrk.yaml 
pod "pod-user-hostnetwork" configured
[root@master pod]# kubectl exec -it pod-use-hostnetwork --sh
/ #ifconfig
root@master pod]# ifconfig
eth0      Link encap:Ethernet  HWaddr 52:54:00:52:4A:B1  
          inet addr:192.168.118.19  Bcast:192.168.118.255  Mask:255.255.255.0
          inet6 addr: fe80::5054:ff:fe52:4ab1/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:4792773 errors:0 dropped:10180 overruns:0 frame:0
          TX packets:2124456 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:3485493892 (3.2 GiB)  TX bytes:282501368 (269.4 MiB)

3、檢視pod-use-hostnetwork執行的結點

[root@master pod]# kubectl get all -o wide
pod/pod-use-hostnetwork 1/1 Running 0 2m29s 192.168.118.19 node1 <none> <none>

通過向node1結點發起請求來驗證

[root@node1 ~]# hostname
node1
[root@node1 ~]# curl node1
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>

另外,在pod物件中時還可以分別使用spec.hostPID和spec.hostIPC來共享工作節點的PID和IPC名稱空間

七、設定pod物件的安全上下文

1、設定pod物件安全上文常用屬性

Pod物件的安全上下文用於設定Pod或容器的許可權和訪問控制功能、其支援設定的常用屬性包括一下幾個方面

  • 基於使用者ID和組ID控制訪問物件時的許可權
  • 以特權或非特權的方式執行
  • 通過Linux Capabilities為其提供部分特權
  • 基於Seccomp過濾進行的系統呼叫
  • 基於seLinux的安全標籤
  • 是否能夠進行許可權升級

2、測試用例

pod物件的安全上下文定在pod.spec.securityContext欄位中 而容器的安全上下文則定義在欄位pod.spec.containers.securityContext中、且二者可巢狀使用的欄位還有所不同

1、配置清單

[root@master chapter4]# cat pod-with-seccontext.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: pod-with-securitycontext
spec:
  containers:
  - name: busybox
    image: busybox
    command: ["/bin/sh","-c","sleep 86400"]
    securityContext:
      runAsNonRoot: true
      runAsUser: 1000
      runAsGroup: 1000
      allowPrivilegeEscalation: false

2、執行驗證

[root@master chapter4]# kubectl apply -f pod-with-seccontext.yaml 
pod/pod-with-securitycontext created
[root@master chapter4]# kubectl exec pod-with-securitycontext -- ps aux
PID   USER     TIME  COMMAND
    1 1000      0:00 sleep 86400
    6 1000      0:00 ps aux