services資源+pod詳解

  • 2022 年 11 月 29 日
  • 筆記

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訪問服務了# 例如在的電腦主機上通過瀏覽器訪問下面的地址//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 //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.