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
/ #
這種方式不是很推薦,推薦將這些配置單獨存儲在配置文件中,這種方式將在後面介紹。
- name: “username”
//端口配置
本小節來介紹容器的端口設置,也就是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.