services資源+pod詳解

2022-11-29 21:00:12

services資源+pod詳解

一、Service

雖然每個Pod都會分配一個單獨的Pod IP,然而卻存在如下兩問題:

  • Pod IP 會隨著Pod的重建產生變化
  • Pod IP 僅僅是叢集內可見的虛擬IP,外部無法存取

這樣對於存取這個服務帶來了難度。因此,kubernetes設計了Service來解決這個問題。
Service可以看作是一組同類Pod對外的存取介面。藉助Service,應用可以方便地實現服務發現和負載均衡。

操作一:建立叢集內部可存取的Service

# 暴露Service
[root@master ~]# kubectl expose deploy nginx --name=svc-nginx1 --type=ClusterIP --port=80 --target-port=80 -n dev
service/svc-nginx1 exposed

# 檢視service
[root@master ~]# kubectl get svc svc-nginx1 -n dev -o wide
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE     SELECTOR
svc-nginx1   ClusterIP   10.109.179.231   <none>        80/TCP    3m51s   run=nginx

# 這裡產生了一個CLUSTER-IP,這就是service的IP,在Service的生命週期中,這個地址是不會變動的
# 可以通過這個IP存取當前service對應的POD
[root@master ~]# curl 10.109.179.231:80
<!DOCTYPE html><html><head><title>Welcome to nginx!</title></head><body><h1>Welcome to nginx!</h1>
.......</body></html>

操作二:建立叢集外部也可存取的Service

# 上面建立的Service的type型別為ClusterIP,這個ip地址只用叢集內部可存取# 如果需要建立外部也可以存取的Service,需要修改type為NodePort
[root@master ~]# kubectl expose deploy nginx --name=svc-nginx2 --type=NodePort --port=80 --target-port=80 -n dev
service/svc-nginx2 exposed
# 此時檢視,會發現出現了NodePort型別的Service,而且有一對Port(80:31928/TC)
[root@master ~]# kubectl get svc  svc-nginx2  -n dev -o wideNAME          TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE    SELECTOR
svc-nginx2    NodePort    10.100.94.0      <none>        80:31928/TCP   9s     run=nginx
# 接下來就可以通過叢集外的主機存取 節點IP:31928存取服務了# 例如在的電腦主機上通過瀏覽器存取下面的地址http://192.168.100.10:31928/

刪除Service

[root@master ~]# kubectl delete svc svc-nginx-1 -n dev
service "svc-nginx-1" deleted

設定方式
建立一個svc-nginx.yaml,內容如下:

apiVersion: v1
kind: Service
metadata:
  name: svc-nginx
  namespace: dev
spec:
  clusterIP: 10.109.179.231 #固定svc的內網ip
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    run: nginx
  type: ClusterIP

然後就可以執行對應的建立和刪除命令了:
建立:kubectl create -f svc-nginx.yaml
刪除:kubectl delete -f svc-nginx.yaml

二、pod詳解

//pod的資源清單

apiVersion: v1     #必選,版本號,例如v1
kind: Pod         #必選,資源型別,例如 Pod
metadata:         #必選,後設資料
  name: string     #必選,Pod名稱
  namespace: string  #Pod所屬的名稱空間,預設為"default"
  labels:           #自定義標籤列表
    - name: string                 
spec:  #必選,Pod中容器的詳細定義
  containers:  #必選,Pod中容器列表
  - name: string   #必選,容器名稱
    image: string  #必選,容器的映象名稱
    imagePullPolicy: [ Always|Never|IfNotPresent ]  #獲取映象的策略 
    command: [string]   #容器的啟動命令列表,如不指定,使用打包時使用的啟動命令
    args: [string]      #容器的啟動命令參數列
    workingDir: string  #容器的工作目錄
    volumeMounts:       #掛載到容器內部的儲存卷設定
    - name: string      #參照pod定義的共用儲存卷的名稱,需用volumes[]部分定義的的卷名
      mountPath: string #儲存卷在容器內mount的絕對路徑,應少於512字元
      readOnly: boolean #是否為唯讀模式
    ports: #需要暴露的埠庫號列表
    - name: string        #埠的名稱
      containerPort: int  #容器需要監聽的埠號
      hostPort: int       #容器所在主機需要監聽的埠號,預設與Container相同
      protocol: string    #埠協定,支援TCP和UDP,預設TCP
    env:   #容器執行前需設定的環境變數列表
    - name: string  #環境變數名稱
      value: string #環境變數的值
    resources: #資源限制和請求的設定
      limits:  #資源限制的設定
        cpu: string     #Cpu的限制,單位為core數,將用於docker run --cpu-shares引數
        memory: string  #記憶體限制,單位可以為Mib/Gib,將用於docker run --memory引數
      requests: #資源請求的設定
        cpu: string    #Cpu請求,容器啟動的初始可用數量
        memory: string #記憶體請求,容器啟動的初始可用數量
    lifecycle: #生命週期勾點
        postStart: #容器啟動後立即執行此勾點,如果執行失敗,會根據重啟策略進行重啟
        preStop: #容器終止前執行此勾點,無論結果如何,容器都會終止
    livenessProbe:  #對Pod內各容器健康檢查的設定,當探測無響應幾次後將自動重啟該容器
      exec:         #對Pod容器內檢查方式設定為exec方式
        command: [string]  #exec方式需要制定的命令或指令碼
      httpGet:       #對Pod內個容器健康檢查方法設定為HttpGet,需要制定Path、port
        path: string
        port: number
        host: string
        scheme: string
        HttpHeaders:
        - name: string
          value: string
      tcpSocket:     #對Pod內個容器健康檢查方式設定為tcpSocket方式
         port: number
       initialDelaySeconds: 0       #容器啟動完成後首次探測的時間,單位為秒
       timeoutSeconds: 0          #對容器健康檢查探測等待響應的超時時間,單位秒,預設1秒
       periodSeconds: 0           #對容器監控檢查的定期探測時間設定,單位秒,預設10秒一次
       successThreshold: 0
       failureThreshold: 0
       securityContext:
         privileged: false
  restartPolicy: [Always | Never | OnFailure]  #Pod的重啟策略
  nodeName: <string> #設定NodeName表示將該Pod排程到指定到名稱的node節點上
  nodeSelector: obeject #設定NodeSelector表示將該Pod排程到包含這個label的node上
  imagePullSecrets: #Pull映象時使用的secret名稱,以key:secretkey格式指定
  - name: string
  hostNetwork: false   #是否使用主機網路模式,預設為false,如果設定為true,表示使用宿主機網路
  volumes:   #在該pod上定義共用儲存卷列表
  - name: string    #共用儲存卷名稱 (volumes型別有很多種)
    emptyDir: {}       #型別為emtyDir的儲存卷,與Pod同生命週期的一個臨時目錄。為空值
    hostPath: string   #型別為hostPath的儲存卷,表示掛載Pod所在宿主機的目錄
      path: string                #Pod所在宿主機的目錄,將被用於同期中mount的目錄
    secret:          #型別為secret的儲存卷,掛載叢集與定義的secret物件到容器內部
      scretname: string  
      items:     
      - key: string
        path: string
    configMap:         #型別為configMap的儲存卷,掛載預定義的configMap物件到容器內部
      name: string
      items:
      - key: string
        path: string

#小提示:#   在這裡,可通過一個命令來檢視每種資源的可設定項#   kubectl explain 資源型別         檢視某種資源可以設定的一級屬性#   kubectl explain 資源型別.屬性     檢視屬性的子屬性
[root@k8s-master01 ~]# kubectl explain pod
KIND:     Pod
VERSION:  v1
FIELDS:
   apiVersion   <string>
   kind <string>
   metadata     <Object>
   spec <Object>
   status       <Object>

[root@k8s-master01 ~]# kubectl explain pod.metadata
KIND:     Pod
VERSION:  v1
RESOURCE: metadata <Object>
FIELDS:
   annotations  <map[string]string>
   clusterName  <string>
   creationTimestamp    <string>
   deletionGracePeriodSeconds   <integer>
   deletionTimestamp    <string>
   finalizers   <[]string>
   generateName <string>
   generation   <integer>
   labels       <map[string]string>
   managedFields        <[]Object>
   name <string>
   namespace    <string>
   ownerReferences      <[]Object>
   resourceVersion      <string>
   selfLink     <string>
   uid  <string>

在kubernetes中基本所有資源的一級屬性都是一樣的,主要包含5部分:
1、apiVersion 版本,由kubernetes內部定義,版本號必須可以用 kubectl api-versions 查詢到
2、kind 型別,由kubernetes內部定義,版本號必須可以用 kubectl api-resources 查詢到
3、metadata 後設資料,主要是資源標識和說明,常用的有name、namespace、labels等
4、spec描述,這是設定中最重要的一部分,裡面是對各種資源設定的詳細描述
5、status狀態資訊,裡面的內容不需要定義,由kubernetes自動生成

在上面的屬性中,spec是接下來研究的重點,繼續看下它的常見子屬性:
1、containers <[]Object> 容器列表,用於定義容器的詳細資訊
2、nodeName 根據nodeName的值將pod排程到指定的Node節點上
3、nodeSelector <map[]> 根據NodeSelector中定義的資訊選擇將該Pod排程到包含這些label的Node 上
4、hostNetwork 是否使用主機網路模式,預設為false,如果設定為true,表示使用宿主機網路
5、volumes <[]Object> 儲存卷,用於定義Pod上面掛載的儲存資訊
6、restartPolicy 重啟策略,表示Pod在遇到故障的時候的處理策略

//pod設定
本小節主要來研究pod.spec.containers屬性,這也是pod設定中最為關鍵的一項設定。
[root@master01 ~]# kubectl explain pod.spec.containers
KIND: Pod
VERSION: v1
RESOURCE: containers <[ ]Object> # 陣列,代表可以有多個容器
FIELDS:
name # 容器名稱
image # 容器需要的映象地址
imagePullPolicy # 映象拉取策略
command <[ ]string> # 容器的啟動命令列表,如不指定,使用打包時使用的啟動命令
args <[ ]string> # 容器的啟動命令需要的參數列
env <[ ]Object> # 容器環境變數的設定
ports <[ ]Object> # 容器需要暴露的埠號列表
resources # 資源限制和資源請求的設定

//基本設定
建立pod-base.yaml檔案,內容如下

apiVersion: v1
kind: Pod
metadata:
  name: pod-base
  namespace: test
  labels:
    user: user1
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
  - name: busybox
image: busybox:1.30

上面定義了一個比較簡單Pod的設定,裡面有兩個容器:
nginx:用1.17.1版本的nginx映象建立,(nginx是一個輕量級web容器)
busybox:用1.30版本的busybox映象建立,(busybox是一個小巧的linux命令集合)

[root@master ~]# kubectl create -f pod-base.yaml 
pod/pod-base created
[root@master ~]# kubectl get pod -n test
NAME       READY   STATUS              RESTARTS   AGE
pod-base   0/2     ContainerCreating   0          12s


//映象拉取
建立pod-imagepullpolicy.yaml檔案:
apiVersion: v1
kind: Pod
metadata:
  name: pod-imagepullpolicy
  namespace: test
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
    imagePullPolicy: Never
  - name: busybox
image: busybox:1.30

imagePullPolicy,用於設定映象拉取策略,kubernetes支援設定三種拉取策略:

Always:總是從遠端倉庫拉取映象(一直遠端下載)
IfNotPresent:本地有則使用本地映象,本地沒有則從遠端倉庫拉取映象(本地有就本地 本地沒遠端下載)
Never:只使用本地映象,從不去遠端倉庫拉取,本地沒有就報錯 (一直使用本地)

預設值說明:
如果映象tag為具體版本號, 預設策略是:IfNotPresent
如果映象tag為:latest(最終版本) ,預設策略是always
[root@master ~]# kubectl create -f pod-imagepullpolicy.yaml

//啟動命令
在前面的案例中,一直有一個問題沒有解決,就是的busybox容器一直沒有成功執行,那麼到底是什麼原因導致這個容器的故障呢?

原來busybox並不是一個程式,而是類似於一個工具類的集合,kubernetes叢集啟動管理後,它會自動關閉。解決方法就是讓其一直在執行,這就用到了command設定。

建立pod-command.yaml檔案,內容如下:

apiVersion: v1
kind: Pod
metadata:
  name: pod-command1
  namespace: test
spec:
  containers:
  - name: nginx
   image: nginx:1.17.1
   imagePullPolicy: Never
  - name: busybox
image: busybox:1.30
imagePullPolicy: Never
command: ["/bin/sh","-c","touch /tmp/hello.txt;while true;do /bin/echo $(date +%T) >> /tmp/hello.txt; sleep 3; done;"]

command,用於在pod中的容器初始化完畢之後執行一個命令。

稍微解釋下上面命令的意思:

「/bin/sh」,「-c」, 使用sh執行命令

touch /tmp/hello.txt; 建立一個/tmp/hello.txt 檔案

while true;do /bin/echo $(date +%T) >> /tmp/hello.txt; sleep 3; done; 每隔3秒向檔案中寫入當前時間

[root@master ~]# kubectl create -f pod-command.yaml 
pod/pod-command1 created
[root@master ~]# kubectl get pods -n test
pod-command1           2/2     Running             0               2s

進入pod中的busybox容器,檢視檔案內容
補充一個命令: kubectl exec pod名稱 -n 名稱空間 -it -c 容器名稱 /bin/sh 在容器內部執行命令
使用這個命令就可以進入某個容器的內部,然後進行相關操作了
比如,可以檢視txt檔案的內容

[root@master ~]# kubectl exec pod-command1 -n test -it -c busybox /bin/sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
/ # tail -f /tmp/hello.txt
17:22:11
17:22:14
17:22:17
17:22:20
17:22:23
17:22:26

特別說明:
通過上面發現command已經可以完成啟動命令和傳遞引數的功能,為什麼這裡還要提供一個args選項,用於傳遞引數呢?這其實跟docker有點關係,kubernetes中的command、args兩項其實是實現覆蓋Dockerfile中ENTRYPOINT的功能。
1 如果command和args均沒有寫,那麼用Dockerfile的設定。
2 如果command寫了,但args沒有寫,那麼Dockerfile預設的設定會被忽略,執行輸入的command
3 如果command沒寫,但args寫了,那麼Dockerfile中設定的ENTRYPOINT的命令會被執行,使用當前args的引數
4 如果command和args都寫了,那麼Dockerfile的設定被忽略,執行command並追加上args引數

//環境變數
建立pod-env.yaml檔案:
apiVersion: v1
kind: Pod
metadata:
name: pod-env
namespace: test
spec:
containers:

  • name: busybox
    image: busybox:1.30
    imagePullPolicy: Never
    command: ["/bin/sh","-c","while true;do /bin/echo $(date +%T);sleep 60; done;"]
    env:
    • name: "username"
      value: "admin"
    • name: "password"
      value: "redhat"
      env,環境變數,用於在pod中的容器設定環境變數。
      [root@master ~]# kubectl create -f pod-env.yaml
      pod/pod-env created
      pod-env 1/1 Running 0 16s
      [root@master ~]# kubectl exec pod-env -n test -c busybox -it /bin/sh
      kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
      / # echo $username
      admin
      / # echo $password
      redhat
      / #
      這種方式不是很推薦,推薦將這些設定單獨儲存在組態檔中,這種方式將在後面介紹。

//埠設定
本小節來介紹容器的埠設定,也就是containers的ports選項。
首先看下ports支援的子選項:

[root@k8s-master01 ~]# kubectl explain pod.spec.containers.ports
KIND:     Pod
VERSION:  v1
RESOURCE: ports <[ ]Object>
FIELDS:
   name         <string>  # 埠名稱,如果指定,必須保證name在pod中是唯一的		
   containerPort<integer> # 容器要監聽的埠(0<x<65536)
   hostPort     <integer> # 容器要在主機上公開的埠,如果設定,主機上只能執行容器的一個副本(一般省略) 
   hostIP       <string>  # 要將外部埠繫結到的主機IP(一般省略)
   protocol     <string>  # 埠協定。必須是UDP、TCP或SCTP。預設為「TCP」。

接下來,編寫一個測試案例,建立pod-ports.yaml

apiVersion: v1
kind: Pod
metadata:
  name: pod-ports
  namespace: test
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
    imagePullPolicy: Never
    ports:
    - name: nginx-port
      containerPort: 80
      protocol: TCP

[root@master ~]# kubectl create -f pod-ports.yaml 
pod/pod-ports created
[root@master ~]# kubectl get pod -n test
pod-ports              1/1     Running            0                10s
[root@master ~]# kubectl get pod pod-ports -n test -o yaml
......
spec:
  containers:
  - image: nginx:1.17.1
    imagePullPolicy: Never
    name: nginx
    ports:
    - containerPort: 80
      name: nginx-port
      protocol: TCP
存取容器中的程式需要使用的是Podip:containerPort
[root@master ~]# kubectl get pod pod-ports -n test -o wide
NAME        READY   STATUS    RESTARTS   AGE     IP            NODE    NOMINATED NODE   READINESS GATES
pod-ports   1/1     Running   0          3m40s   10.244.1.16   node1   <none>           <none>
[root@master ~]# curl http://10.244.1.16:80

//資源配額
容器中的程式要執行,肯定是要佔用一定資源的,比如cpu和記憶體等,如果不對某個容器的資源做限制,那麼它就可能吃掉大量資源,導致其它容器無法執行。針對這種情況,kubernetes提供了對記憶體和cpu的資源進行配額的機制,這種機制主要通過resources選項實現,他有兩個子選項:

limits:用於限制執行時容器的最大佔用資源,當容器佔用資源超過limits時會被終止,並進行重啟
requests :用於設定容器需要的最小資源,如果環境資源不夠,容器將無法啟動
可以通過上面兩個選項設定資源的上下限。

接下來,編寫一個測試案例,建立pod-resources.yaml

apiVersion: v1
kind: Pod
metadata:
  name: pod-resources
  namespace: test
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
    imagePullPolicy: Never
    resources:       //資源限制
      limits:     //資源限制(上限)
        cpu: "2"     //cpu限制,單位是core數
        memory: "10Gi"   //記憶體限制
      requests:     //請求資源
        cpu: "1"     
        memory: "10Mi"

在這對cpu和memory的單位做一個說明:
cpu:core數,可以為整數或小數
memory: 記憶體大小,可以使用Gi、Mi、G、M等形式
[root@master ~]# kubectl create -f pod-resources.yaml 
pod/pod-resources created
[root@master ~]# kubectl get pods -n test
pod-resources          1/1     Running            0                10s


先停止刪除該pod
[root@master ~]# kubectl delete -f pod-resources.yaml 
pod "pod-resources" deleted

再編輯pod,修改resources.requests.memory的值為10Gi
[root@master ~]# vim pod-resources.yaml

[root@master ~]# kubectl create -f pod-resources.yaml
pod/pod-resources created
[root@master ~]# kubectl get pods -n test
pod-resources          0/1     Pending            0                16s

[root@master ~]# kubectl describe pod pod-resources -n test
Warning  FailedScheduling  87s   default-scheduler  0/3 nodes are available: 1 node(s) had untolerated taint {node-role.kubernetes.io/control-plane: }, 3 Insufficient memory. preemption: 0/3 nodes are available: 1 Preemption is not helpful for scheduling, 2 No preemption victims found for incoming pod.