1、 k8s核心資源之Pod
1.1 什麼是Pod?
官方文件:https://kubernetes.io/docs/concepts/workloads/pods/
Pod是Kubernetes中的最小排程單元,k8s是通過定義一個Pod的資源,然後在Pod裡面執行容器,容器需要指定一個映象,這樣就可以用來執行具體的服務。一個Pod封裝一個容器(也可以封裝多個容器),Pod裡的容器共享儲存、網路等。也就是說,應該把整個pod看作虛擬機器,然後每個容器相當於執行在虛擬機器的程序。
Pod是需要排程到k8s叢集的工作節點來執行的,具體排程到哪個節點,是根據scheduler排程器實現的。
白話解釋:
可以把pod看成是一個“豌豆莢”,裡面有很多“豆子”(容器)。一個豌豆莢裡的豆子,它們吸收著共同的營養成分、肥料、水分等,Pod和容器的關係也是一樣,Pod裡面的容器共享pod的網路、儲存等。
pod相當於一個邏輯主機--比方說我們想要部署一個tomcat應用,如果不用容器,我們可能會部署到物理機、虛擬機器或者雲主機上,那麼出現k8s之後,我們就可以定義一個pod資源,在pod裡定義一個把tomcat容器,所以pod充當的是一個邏輯主機的角色。
1.2 Pod如何管理多個容器?
Pod中可以同時執行多個容器。同一個Pod中的容器會自動的分配到同一個 node 上。同一個Pod中的容器共享資源、網路環境,它們總是被同時排程,在一個Pod中同時執行多個容器是一種比較高階的用法,只有當你的容器需要緊密配合協作的時候才考慮用這種模式。例如,你有一個容器作為web伺服器執行,需要用到共享的volume,有另一個“sidecar”容器來從遠端獲取資源更新這些檔案。
一些Pod有init容器和應用容器。 在應用程式容器啟動之前,執行初始化容器。
1.3 Pod網路
Pod是有IP地址的,每個pod都被分配唯一的IP地址(IP地址是靠網路外掛calico、flannel、weave等分配的),POD中的容器共享網路名稱空間,包括IP地址和網路埠。 Pod內部的容器可以使用localhost相互通訊。 Pod中的容器也可以通過網路外掛calico與其他節點的Pod通訊。
1.4 Pod儲存
建立Pod的時候可以指定掛載的儲存卷。 POD中的所有容器都可以訪問共享卷,允許這些容器共享資料。 Pod只要掛載持久化資料卷,Pod重啟之後資料還是會存在的。
1.5 Pod工作方式
在K8s中,所有的資源都可以使用一個yaml檔案來建立,建立Pod也可以使用yaml配置檔案。或者使用kubectl run在命令列建立Pod(不常用)。
1.5.1 自主式Pod
① 所謂的自主式Pod,就是直接定義一個Pod資源,如下:yaml檔案內容編寫在後面會有講解
[root@xianchaomaster1 ~]# vim pod-tomcat.yaml
apiVersion: v1
kind: Pod
metadata:
name: tomcat-test
namespace: default
labels:
app: tomcat
spec:
containers:
- name: tomcat-java
ports:
- containerPort: 8080
image: hxu/tomcat-8.5-jre8:v1
imagePullPolicy: IfNotPresent
② 上傳映象到node節點,步驟省略
③ 更新資源清單檔案yaml檔案建立pod
[root@k8s-master1 kubenetes-han]# kubectl apply -f pod-tomcat.yaml
pod/tomcat-test created
檢視pod
[root@k8s-master1 kubenetes-han]# kubectl get pod
tomcat-test 1/1 Running 0 5s
但是自主式Pod是存在一個問題的,假如我們不小心刪除了pod:
[root@k8s-master1 kubenetes-han]# kubectl delete pods tomcat-test
pod "tomcat-test" deleted
檢視pod是否還在
kubectl get pods -l app=tomcat
結果是空,說明pod已經被刪除了
通過上面可以看到,如果直接定義一個Pod資源,那Pod被刪除,就徹底被刪除了,不會再建立一個新的Pod,這在生產環境還是具有非常大風險的,所以今後我們接觸的Pod,都是控制器管理的。
1.5.2 控制器管理的Pod
常見的管理Pod的控制器:Replicaset、Deployment、Job、CronJob、Daemonset、Statefulset。
控制器管理的Pod可以確保Pod始終維持在指定的副本數執行。
如,通過Deployment管理Pod
① 更新資源清單檔案
#更新資源清單檔案
[root@k8s-master1 kubenetes-han]# kubectl apply -f nginx-deploy.yaml
#檢視Deployment
[root@k8s-master1 kubenetes-han]# kubectl get deploy -l app=nginx-deploy
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-test 2/2 2 2 8d
[root@k8s-master1 kubenetes-han]# kubectl get rs -l app=nginx
NAME DESIRED CURRENT READY AGE
nginx-test-57f9f5b6d7 2 2 2 8d
#檢視pod
[root@k8s-master1 kubenetes-han]# kubectl get pods -o wide -l app=nginx
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-test-57f9f5b6d7-dqm8h 1/1 Running 0 8d 10.244.1.17 k8s-node1 <none> <none>
nginx-test-57f9f5b6d7-fxsw5 1/1 Running 0 8d 10.244.1.16 k8s-node1 <none> <none>
#刪除nginx-test-57f9f5b6d7-dqm8h這個pod
[root@k8s-master1 kubenetes-han]# kubectl delete pods nginx-test-57f9f5b6d7-dqm8h
pod "nginx-test-57f9f5b6d7-dqm8h" deleted
[root@k8s-master1 kubenetes-han]# kubectl get pods -o wide -l app=nginx
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-test-57f9f5b6d7-8zt7x 1/1 Running 0 16s 10.244.1.19 k8s-node1 <none> <none>
nginx-test-57f9f5b6d7-fxsw5 1/1 Running 0 8d 10.244.1.16 k8s-node1 <none> <none>
#發現重新建立一個新的pod是nginx-test-57f9f5b6d7-8zt7x
通過上面可以發現通過deployment管理的pod,可以確保pod始終維持在指定副本數量
1.6 建立Pod流程
Pod是Kubernetes中最基本的部署排程單元,可以包含container,邏輯上表示某種應用的一個例項。例如一個web站點應用由前端、後端及資料庫構建而成,這三個元件將執行在各自的容器中,那麼我們可以建立包含三個container的pod
建立pod的詳細流程:
第一步:
客戶端提交建立Pod的請求,可以通過呼叫API Server的Rest API介面,也可以通過kubectl命令列工具。如kubectl apply -f filename.yaml(資源清單檔案)
第二步:
apiserver接收到pod建立請求後,會將yaml中的屬性資訊(metadata)寫入etcd。
第三步:
apiserver觸發watch機制準備建立pod,資訊轉發給排程器scheduler,排程器使用排程演算法選擇node,排程器將node資訊給apiserver,apiserver將繫結的node資訊寫入etcd
排程器用一組規則過濾掉不符合要求的主機。比如Pod指定了所需要的資源量,那麼可用資源比Pod需要的資源量少的主機會被過濾掉。
scheduler 檢視 k8s api ,類似於通知機制。
首先判斷:pod.spec.Node == null?
若為null,表示這個Pod請求是新來的,需要建立;因此先進行排程計算,找到最“閒”的node。
然後將資訊在etcd資料庫中更新分配結果:pod.spec.Node = nodeA (設定一個具體的節點)
ps:同樣上述操作的各種資訊也要寫到etcd資料庫中中
第四步:
apiserver又通過watch機制,呼叫kubelet,指定pod資訊,呼叫Docker API建立並啟動pod內的容器。
第五步:
建立完成之後反饋給kubelet, kubelet又將pod的狀態資訊給apiserver,
apiserver又將pod的狀態資訊寫入etcd。
2、如何編寫資源清單YAML檔案?
示例:
# vim pod-tomcat.yaml
apiVersion: v1 #api版本
kind: Pod #建立的資源
metadata:
name: tomcat-test #Pod的名字
namespace: default #Pod所在的名稱空間
labels:
app: tomcat #Pod具有的標籤
spec:
containers:
- name: tomcat-java #Pod裡容器的名字
ports:
- containerPort: 8080 #容器暴露的埠
image: hxu/tomcat-8.5-jre8:v1 #容器使用的映象
imagePullPolicy: IfNotPresent #映象拉取策略
#更新資源清單檔案
# kubectl apply -f pod-tomcat.yaml
# Pod資源清單編寫技巧
通過kubectl explain 檢視定義Pod資源包含哪些欄位。
# kubectl explain pod
KIND: Pod
VERSION: v1
DESCRIPTION:
Pod is a collection of containers that can run on a host. This resource is
created by clients and scheduled onto hosts.
[Pod是可以在主機上執行的容器的集合。此資源是由客戶端建立並安排到主機上。]
FIELDS:
apiVersion <string>
APIVersion defines the versioned schema of this representation of an
object. Servers should convert recognized schemas to the latest internal
value, and may reject unrecognized values. More info:
https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
[APIVersion定義了物件,代表了一個版本。]
kind <string>
Kind is a string value representing the REST resource this object
represents. Servers may infer this from the endpoint the client submits
requests to. Cannot be updated. In CamelCase. More info:
https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
[Kind是字串型別的值,代表了要建立的資源。伺服器可以從客戶端提交的請求推斷出這個資源。]
metadata <Object>
Standard object's metadata. More info:
https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
[metadata是物件,定義元資料屬性資訊的]
spec <Object>
Specification of the desired behavior of the pod. More info:
https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status
[spec制定了定義Pod的規格,裡面包含容器的資訊]
status <Object>
Most recently observed status of the pod. This data may not be up to date.
Populated by the system. Read-only. More info:
https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status
[status表示狀態,這個不可以修改,定義pod的時候也不需要定義這個欄位]
#檢視pod.metadata欄位如何定義
# kubectl explain pod.metadata
KIND: Pod
VERSION: v1
RESOURCE: metadata <Object>
# metadata是物件<Object>,下面可以有多個欄位
DESCRIPTION:
Standard object's metadata. More info:
https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
ObjectMeta is metadata that all persisted resources must have, which
includes all objects users must create.
FIELDS:
annotations <map[string]string>
Annotations is an unstructured key value map stored with a resource that
may be set by external tools to store and retrieve arbitrary metadata. They
are not queryable and should be preserved when modifying objects. More
info: http://kubernetes.io/docs/user-guide/annotations
# annotations是註解,map型別表示對應的值是key-value鍵值對,<string,string>表示 key和value都是String型別的
"metadata": {
"annotations": {
"key1" : "value1",
"key2" : "value2"
}
}
用Annotation來記錄的資訊包括:
build資訊、release資訊、Docker映象資訊等,例如時間戳、release id號、映象hash值、docker registry地址等;
日誌庫、監控庫、分析庫等資源庫的地址資訊;
程式除錯工具資訊,例如工具名稱、版本號等;
團隊的聯絡資訊,例如電話號碼、負責人名稱、網址等。
clusterName <string>
The name of the cluster which the object belongs to. This is used to
distinguish resources with same name and namespace in different clusters.
This field is not set anywhere right now and apiserver is going to ignore
it if set in create or update request.
#物件所屬群集的名稱。這是用來區分不同叢集中具有相同名稱和名稱空間的資源。此欄位現在未設定在任何位置,apiserver將忽略它,如果設定了就使用設定的值
creationTimestamp <string>
deletionGracePeriodSeconds <integer>
deletionTimestamp <string>
finalizers <[]string>
generateName <string>
generation <integer>
labels <map[string]string> #建立的資源具有的標籤
Map of string keys and values that can be used to organize and categorize
(scope and select) objects. May match selectors of replication controllers
and services. More info: http://kubernetes.io/docs/user-guide/labels
#labels是標籤,labels是map型別,map型別表示對應的值是key-value鍵值對,<string,string>表示 key和value都是String型別的
managedFields <[]Object>
name <string> #建立的資源的名字
namespace <string> #建立的資源所屬的名稱空間
Namespace defines the space within which each name must be unique. An empty
namespace is equivalent to the "default" namespace, but "default" is the
canonical representation. Not all objects are required to be scoped to a
namespace - the value of this field for those objects will be empty.
Must be a DNS_LABEL. Cannot be updated. More info:
http://kubernetes.io/docs/user-guide/namespaces
# namespaces劃分了一個空間,在同一個namesace下的資源名字是唯一的,預設的名稱空間是default。
ownerReferences <[]Object>
resourceVersion <string>
selfLink <string>
uid <string>****
檢視pod.spec欄位如何定義
# kubectl explain pod.spec
KIND: Pod
VERSION: v1
RESOURCE: spec <Object>
DESCRIPTION:
Specification of the desired behavior of the pod. More info:
https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status
PodSpec is a description of a pod.
#Pod的spec欄位是用來描述Pod的
FIELDS:
activeDeadlineSeconds <integer>
#表示Pod可以執行的最長時間,達到設定的值後,Pod會自動停止。
affinity <Object>
#定義親和性的
automountServiceAccountToken <boolean>
containers <[]Object> -required-
#containers是物件列表,用來定義容器的,是必須欄位。物件列表 表示下面有很多物件,物件列表下面的內容用 - 連線。
dnsConfig <Object>
dnsPolicy <string>
enableServiceLinks <boolean>
ephemeralContainers <[]Object>
hostAliases <[]Object>
hostIPC <boolean>
hostNetwork <boolean>
hostPID <boolean>
hostname <string>
imagePullSecrets <[]Object>
initContainers <[]Object>
nodeName <string>
nodeSelector <map[string]string>
overhead <map[string]string>
preemptionPolicy <string>
priority <integer>
priorityClassName <string>
readinessGates <[]Object>
restartPolicy <string>
runtimeClassName <string>
schedulerName <string>
securityContext <Object>
serviceAccount <string>
serviceAccountName <string>
setHostnameAsFQDN <boolean>
shareProcessNamespace <boolean>
subdomain <string>
terminationGracePeriodSeconds <integer>
tolerations <[]Object>
topologySpreadConstraints <[]Object>
volumes <[]Object>
檢視pod.spec.containers欄位如何定義
# kubectl explain pod.spec.containers
KIND: Pod
VERSION: v1
RESOURCE: containers <[]Object>
DESCRIPTION:
List of containers belonging to the pod. Containers cannot currently be
added or removed. There must be at least one container in a Pod. Cannot be
updated.
A single application container that you want to run within a pod.
#container是定義在pod裡面的,一個pod至少要有一個容器。
FIELDS:
args <[]string>
command <[]string>
env <[]Object>
envFrom <[]Object>
image <string>
#image是用來指定容器需要的映象的
imagePullPolicy <string>
#映象拉取策略,pod是要排程到node節點的,那pod啟動需要映象,可以根據這個欄位設定映象拉取策略,支援如下三種:
Always:不管本地是否存在映象,都要重新拉取映象
Never: 從不拉取映象
IfNotPresent:如果本地存在,使用本地的映象,本地不存在,從官方拉取映象
lifecycle <Object>
livenessProbe <Object>
name <string> -required-
#name是必須欄位,用來指定容器名字的
ports <[]Object>
#port是埠,屬於物件列表
readinessProbe <Object>
resources <Object>
securityContext <Object>
startupProbe <Object>
stdin <boolean>
stdinOnce <boolean>
terminationMessagePath <string>
terminationMessagePolicy <string>
tty <boolean>
volumeDevices <[]Object>
volumeMounts <[]Object>
workingDir <string>
檢視pod.spec.container.ports欄位如何定義
# kubectl explain pod.spec.containers.ports
KIND: Pod
VERSION: v1
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:
containerPort <integer> -required-
Number of port to expose on the pod's IP address. This must be a valid port
number, 0 < x < 65536.
#containerPort是必須欄位, pod中的容器需要暴露的埠。
hostIP <string>
What host IP to bind the external port to.
#將容器中的服務暴露到宿主機的埠上時,可以指定繫結的宿主機 IP。
hostPort <integer>
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>
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>
Protocol for port. Must be UDP, TCP, or SCTP. Defaults to "TCP".
通過資源清單檔案建立第一個Pod(如上文的1.5.1章節)
#檢視pod日誌
kubectl logs pod-first
#檢視pod裡指定容器的日誌
kubectl logs pod-first -c tomcat-first
#進入到剛才建立的pod,剛才建立的pod名字是web
kubectl exec -it pod-first -- /bin/bash
#假如pod裡有多個容器,進入到pod裡的指定容器,按如下命令:
kubectl exec -it pod-first -c tomcat-first -- /bin/bash
我們上面建立的pod是一個自主式pod,也就是通過pod建立一個應用程式,如果pod出現故障停掉,那麼我們通過pod部署的應用也就會停掉,不安全, 還有一種控制器管理的pod,通過控制器建立pod,可以對pod的生命週期做管理,可以定義pod的副本數,如果有一個pod意外停掉,那麼會自動起來一個pod替代之前的pod,之後會講解pod的控制器
通過kubectl run建立Pod
kubectl run tomcat --image=hxu/tomcat-8.5-jre8:v1 --image-pull-policy='IfNotPresent' --port=8080