前面我們的kubernets集群已經(jīng)搭建成功了,現(xiàn)在我們就可以在集群里面來跑我們的應(yīng)用了。要在集群里面運行我們自己的應(yīng)用,首先我們需要知道幾個概念。
第一個當(dāng)然就是應(yīng)用的鏡像,因為我們在集群中運行的是容器,所以我們首先需要將我們的應(yīng)用打包成鏡像,前面的文章已經(jīng)學(xué)習(xí)過如何將應(yīng)用打包成鏡像,這里不再贅述。
鏡像準(zhǔn)備好了,k8s集群也準(zhǔn)備好了,其實我們就可以把我們的應(yīng)用部署到集群中了。但是鏡像到集群中運行這個過程是如何完成的呢?必然有一個地方可以來描述我們的應(yīng)用,然后把這份描述告訴k8s集群,然后集群按照這個描述來部署應(yīng)用。
在之前Docker環(huán)境下面我們直接通過命令docker run來運行我們的應(yīng)用,在k8s環(huán)境下我們同樣也可以用類似kubectl run這樣的命令來運行我們的應(yīng)用,但是在k8s中卻不推薦使用命令行的方式,而是希望使用我們稱為資源清單的東西來描述應(yīng)用,資源清單可以用YAML或者JSON文件來編寫,一般來說YAML文件更方便閱讀和理解,所以我們使用YAML文件來進(jìn)行描述。
通過一個資源清單文件來定義好一個應(yīng)用后,我們就可以通過kubectl工具來直接運行它:
kubectl create -f xxx.yaml
我們知道kubectl是直接操作APIServer的,所以就相當(dāng)于把我們的清單提交給了APIServer,然后集群獲取到清單描述的應(yīng)用信息后存儲到etcd數(shù)據(jù)庫中,然后kube-scheduler組件發(fā)現(xiàn)這個時候有一個Pod還沒有綁定到節(jié)點上,就會對這個Pod進(jìn)行一系列的調(diào)度,把它調(diào)度到一個最合適的節(jié)點上,然后把這個節(jié)點和Pod綁定到一起(信息再寫回etcd),然后節(jié)點上的kubelet組件這個時候watch到有一個Pod被分配過來了,就去把這個Pod的信息垃取下來,然后根據(jù)描述通過容器運行時把容器創(chuàng)建出來,最后當(dāng)然同樣把Pod狀態(tài)再寫回道etcd中去,這樣就完成了一整個的創(chuàng)建流程。
第一個容器化應(yīng)用
apiVersion: apps/v1 # 新版本的deployment都使用這個apiVersion
kind: Deployment # API對象類型,也就是資源對象類型
metadata: # 資源對象的元信息
name: nginx-deploy # deployment的名稱
namespace: default # 如果不寫的話就默認(rèn)是default命名空間的
labels: # 標(biāo)識或過濾
chapter: first-app
spec:
selector: # required,必須填寫的。當(dāng)資源對象類型是Deployment時
matchLabels: # Lable selector,匹配標(biāo)簽(labels),下面一行就是要匹配的值,即匹配的就是 "app:nginx"標(biāo)簽
app: nginx # Pod的標(biāo)簽 "此處是第11行"
replicas: 2 # Pod副本數(shù)
template: # Pod 模版
metadata: # Pod的元信息
labels: # Pod的Label標(biāo)簽
app: nginx # 此處和"第11行必須是一致的"
spec:
containers: # Pod下面有多個容器
- name: nginx # 容器名稱
image: nginx:1.7.9 #使用的鏡像名稱
ports: # 容器暴露的端口
- containerPort: 80
- containerPort: 443
Deployment 這個
資源對象就是用來定義多副本應(yīng)用的對象,而且還支持對每個副本進(jìn)行滾動更新,上面我們的資源清單中的描述中有一個屬性 replicas: 2,所以最后生成兩個副本的 Pod。
而這個 Deployment 定義的副本 Pod 具體是什么樣的,是通過下面的Pod 模板來定義的,就是template 下面的定義,這個模板中定義了我們的 Pod 中只有一個名為 nginx 的容器,容器使用的鏡像是 nginx:1.7.9(spec.containers[0].image),并且這個容器監(jiān)聽的端口是 80(spec.containers[0].ports[0].containerPort),另外我們還為 Pod 添加了一個app: nginx這樣的 Label 標(biāo)簽,這里需要非常注意的是上面的 selector.matchLabels 區(qū)域就是來表示我們的 Deployment 來管理哪些 Pod 的,所以這個地方需要和 Pod 模板中的 Label 標(biāo)簽保持一致,這個 Label 標(biāo)簽之前我們也提到過是非常重要的。
另外我們也可以發(fā)現(xiàn)每個 API 對象都有一個 Metadata 的字段,用來表示該對象的元數(shù)據(jù)的,比如定義 name、namespace 等,比如上面 Deployment 和 Pod 模板中都有這個字段,至于為什么 Pod 模板中沒有 name 這個元信息呢,這是因為 Deployment 這個控制器會自動在他自己的 name 基礎(chǔ)上生成 Pod 名,不過 Deployment 下面定義的 Label 標(biāo)簽就沒有 Pod 中定義的 Label 標(biāo)簽?zāi)敲粗匾?,只是起到一個對該對象標(biāo)識和過濾的作用。比如我們在查詢對象的時候可以帶上標(biāo)簽來進(jìn)行過濾。
然后直接用 kubectl 命令來創(chuàng)建這個應(yīng)用:
[root@master my_kubernets_yaml]# kubectl create -f nginx-deployment.yaml # 創(chuàng)建應(yīng)用
deployment.apps/nginx-deploy created
[root@master my_kubernets_yaml]# kubectl get pods #查看Pod
NAME READY STATUS RESTARTS AGE
nginx-deploy-7cb4fc6c56-8ljb7 1/1 Running 0 84s
nginx-deploy-7cb4fc6c56-9fnjs 1/1 Running 0 84s
[root@master my_kubernets_yaml]# kubectl get pods -l app=nginx # 或者加個標(biāo)簽過濾
NAME READY STATUS RESTARTS AGE
nginx-deploy-7cb4fc6c56-8ljb7 1/1 Running 0 33m
nginx-deploy-7cb4fc6c56-9fnjs 1/1 Running 0 33m
[root@master my_kubernets_yaml]# kubectl get deployment #查看deployment
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deploy 2/2 2 2 8m17s
[root@master my_kubernets_yaml]# kubectl get deployment -l chapter=first-app # 或者加個標(biāo)簽過濾
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deploy 2/2 2 2 29m
我們可以看到會在集群中生成兩個 Pod 出來。而整個資源清單文件對應(yīng)到 Kubernetes 中就是一個 API Object(API 對象),我們按照這些對象的要求填充上對應(yīng)的屬性后,提交給 Kubernetes 集群,就可以為我們創(chuàng)建出對應(yīng)的資源對象,比如
我們這里定義的是一個 Deployment 類型的 API 對象,我們按照這個 API 對象的要求填充了一些屬性,就會為我們創(chuàng)建出對應(yīng)的資源對象。
查看某個pod的具體信息
kubectl describe pod "pod名稱"
[root@node02 ~]# kubectl describe pod nginx-deploy-7cb4fc6c56-8ljb7
Name: nginx-deploy-7cb4fc6c56-8ljb7
Namespace: default
Priority: 0
Node: node01/172.17.122.151
Start Time: Wed, 15 Jan 2020 17:21:49 +0800
Labels: app=nginx
pod-template-hash=7cb4fc6c56
Annotations: <none>
Status: Running
IP: 10.244.1.3
IPs:
IP: 10.244.1.3
Controlled By: ReplicaSet/nginx-deploy-7cb4fc6c56
Containers:
nginx:
Container ID: docker://951e1e4dcab3b990a68f6225ad63f1aa0b4f105a0e10639aeca127d9243f25e5
Image: nginx:1.7.9
Image ID: docker-pullable://nginx@sha256:e3456c851a152494c3e4ff5fcc26f240206abac0c9d794affb40e0714846c451
Ports: 80/TCP, 443/TCP
Host Ports: 0/TCP, 0/TCP
State: Running
Started: Wed, 15 Jan 2020 17:22:43 +0800
Ready: True
Restart Count: 0
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-557h9 (ro)
Conditions:
Type Status
Initialized True
Ready True
ContainersReady True
PodScheduled True
Volumes:
default-token-557h9:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-557h9
Optional: false
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s
node.kubernetes.io/unreachable:NoExecute for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled <unknown> default-scheduler Successfully assigned default/nginx-deploy-7cb4fc6c56-8ljb7 to node01
Normal Pulling 41m kubelet, node01 Pulling image "nginx:1.7.9"
Normal Pulled 40m kubelet, node01 Successfully pulled image "nginx:1.7.9"
Normal Created 40m kubelet, node01 Created container nginx
Normal Started 40m kubelet, node01 Started container nginx
如果鏡像升級了,這時我們需要重新運行應(yīng)用,此時只需要改動下image即可。
apiVersion: apps/v1 # 新版本的deployment都使用這個apiVersion
kind: Deployment # API對象類型,也就是資源對象類型
metadata: # 資源對象的元信息
name: nginx-deploy
namespace: default # 如果不寫的話就默認(rèn)是default命名空間的
labels: # 標(biāo)識或過濾
chapter: first-app
spec:
selector: # required,必須填寫的。當(dāng)資源對象類型是Deployment時
matchLabels: # Lable selector,匹配標(biāo)簽(labels)等于 app:nginx
app: nginx # Pod的標(biāo)簽
replicas: 4 # Pod副本數(shù)
template: # Pod 模版
metadata: # Pod的元信息
labels: # Pod的Label標(biāo)簽
app: nginx # 此處和11行必須是一致的
spec:
containers: # Pod下面有多個容器
- name: nginx # 容器名稱
image: nginx:latest ############## "使用的鏡像名稱,鏡像升級,修改鏡像名稱"
ports: # 容器暴露的端口
- containerPort: 80
- containerPort: 443
然后使用kubectl apply xxx.yaml來更新應(yīng)用(滾動更新)即可。
如果要刪除deployment的話則使用kubectl delete -f xxx.yaml
關(guān)于YAML的字段說明與使用
上面我們了解了 YAML 文件的基本語法,現(xiàn)在至少可以保證我們的編寫的 YAML 文件語法是合法的,那么要怎么編寫符合 Kubernetes API 對象的資源清單呢?比如我們怎么知道 Pod、Deployment 這些資源對象有哪些功能、有哪些字段呢?
一些簡單的資源對象我們可能可以憑借記憶寫出對應(yīng)的資源清單,但是 Kubernetes 發(fā)展也非???,版本迭代也很快,每個版本中資源對象可能又有很多變化,那么有沒有一種辦法可以讓我們做到有的放矢呢?
實際上是有的,最簡單的方法就是查找 Kubernetes API 文檔,比如我們現(xiàn)在使用的是 v1.16.2 版本的集群,可以通過地址 https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.16/ 查找到對應(yīng)的 API 文檔,在這個文檔中我們可以找到所有資源對象的一些字段。
比如我們要了解創(chuàng)建一個 Deployment 資源對象需要哪些字段,我們可以打開上面的 API 文檔頁面,在左側(cè)側(cè)邊欄找到 Deployment v1 apps,點擊下面的 Write Operations,然后點擊 Create,然后我們查找到創(chuàng)建 Deployment 需要提交的 Body 參數(shù)。
每個字段具體什么含義以及每個字段下面是否還有其他字段都可以這樣去追溯。
但是如果平時我們編寫資源清單的時候都這樣去查找文檔勢必會效率低下,Kubernetes 也考慮到了這點,我們可以直接通過 kubectl 命令行工具來獲取這些字段信息,同樣的,比如我們要獲取 Deployment 的字段信息,我們可以通過 kubectl explain 命令來了解:
kubectl explain 資源對象類型,如下:
[root@master ~]# kubectl explain Deployment
KIND: Deployment
VERSION: apps/v1
DESCRIPTION:
Deployment enables declarative updates for Pods and ReplicaSets.
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
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
metadata <Object>
Standard object metadata.
spec <Object>
Specification of the desired behavior of the Deployment.
status <Object>
Most recently observed status of the Deployment.
如上,我們可以查看到相關(guān)字段的說明,如果要繼續(xù)深入往下查看呢?則
[root@master ~]# kubectl explain Deployment.spec
KIND: Deployment
VERSION: apps/v1
RESOURCE: spec <Object>
DESCRIPTION:
Specification of the desired behavior of the Deployment.
DeploymentSpec is the specification of the desired behavior of the
Deployment.
FIELDS:
minReadySeconds <integer>
Minimum number of seconds for which a newly created pod should be ready
without any of its container crashing, for it to be considered available.
Defaults to 0 (pod will be considered available as soon as it is ready)
paused <boolean>
Indicates that the deployment is paused.
progressDeadlineSeconds <integer>
The maximum time in seconds for a deployment to make progress before it is
considered to be failed. The deployment controller will continue to process
failed deployments and a condition with a ProgressDeadlineExceeded reason
will be surfaced in the deployment status. Note that progress will not be
estimated during the time a deployment is paused. Defaults to 600s.
replicas <integer>
Number of desired pods. This is a pointer to distinguish between explicit
zero and not specified. Defaults to 1.
revisionHistoryLimit <integer>
The number of old ReplicaSets to retain to allow rollback. This is a
pointer to distinguish between explicit zero and not specified. Defaults to
10.
selector <Object> -required- # "可以看到此處是一個必須存在的,當(dāng)然前提是kind值為Deployment"
Label selector for pods. Existing ReplicaSets whose pods are selected by
this will be the ones affected by this deployment. It must match the pod
template's labels.
strategy <Object>
The deployment strategy to use to replace existing pods with new ones.
template <Object> -required-
Template describes the pods that will be created.
如果一個字段顯示的是required,這就證明該字段是必填的,也就是我們在創(chuàng)建這個資源對象的時候必須聲明這個字段,每個字段的類型也都完全為我們進(jìn)行了說明,所以有了 kubectl explain這個命令我們就完全可以寫出一個不熟悉的資源對象的清單說明了,這個命令我們也是必須要記住的,會在以后的工作中為我們提供很大的幫助。