1. 程式人生 > >使用YAML建立一個 Kubernetes Depolyment

使用YAML建立一個 Kubernetes Depolyment

在之前的文章中,我們已經提到過如何使用Kubernetes去建立資源。到目前為止,我們一直僅僅通過命令列去執行,但是這裡有一個更加簡單有效的方式去建立資源:通過使用YAML建立一個配置檔案。在這篇文章,我們將會關注YAML的工作方式以及如何使用YAML建立一個Kubernetes Pod,然後使用Kubernetes建立一個Depolyment。當然您如果是新手可以先了解Kubernetes上執行你的第一個容器

YAML 基礎

如果你正在做的事與很多軟體領域相關,那麼將很難不涉及到YAML,特別是Kubernetes,SDN,和OpenStack。YAML,它代表著另一種標誌語言,或者YAML不是標誌語言(取決於你問誰)而是特定配置型別基於人類可讀的文字格式的資訊,例如,在本文中,我們將會分開說說明YAML定義建立Pod和使用Kubernetes建立一個Depolyment。

使用YAML用於k8s的定義將給你一些好處,包括:

  • 便捷性:你將不再需要新增大量的引數到命令列中執行命令
  • 可維護性:YAML檔案可以通過源頭控制,可以跟蹤每次的操作
  • 靈活性:通過YAML你將可以建立比命令列更加複雜的結構

YAML是一個JSON的超集,意味著任何有效JSON檔案也都是一個有效的YAML檔案。所以一方面,如果你知道JSON,你只是要去寫自己的YAML(而不是閱讀別人的)也就可以了。另一方面,不太可能,不幸的是,儘管你嘗試去網上找到例子,但是他們通常都不是JSON,所以我們可能需要去習慣它。不過,有JSON的情況下可能會更方便,這樣你將會很開心你懂得JSON。

幸運的是,YAML只有兩種結構型別你需要知道:

  • Lists
  • Maps

那就是說,將有可能存在lists的maps和maps的lists,等等,但是,你只要掌握了這兩種結構也就可以了。這並不是說你不能做更加複雜的事,但是通常,這些也就夠了。

YAML Maps

我們先開始看YAML maps。Maps讓你將鍵值組合,你就可以更加方便的去設定配置資訊。例如,你可能有以下這樣一個配置資訊:

---
apiVersion: v1
kind:Pod

第一行是分隔符,並且是可選的,除非你試圖在單個檔案中定義多個結構。從這裡你可以看到,我們有兩個值,V1和Pod,對應他們的鍵是apiVersion和kind。

這種比較簡單,當然你也可以將之轉換為json格式,如下:

{"apiVersion":"v1","kind":"Pod"}

注意,在我們的YAML版本中,引號是可選的,處理器可以知道你正在檢視基於格式化的字串。

你也可以指定一個複雜的結構,建立一個key其對應的值不是字串而是一個maps如下所示:

---
apiVersion: v1
kind:Podmetadata:  name: rss-site  labels:    app: web

這種情況下,我們有metadata這個key對應的值中又有兩個key分別為name和labels。labels 這個key的值又是一個map。你可以根據場景進行多層巢狀。

YAML處理器可以根據行縮排來知道內容之間的關聯。在這個例子中我用了兩個空格使之可讀,但是空格的數量不重要,但是至少要求一個,並且所有縮排都保持一致的空格數。例如,name和labels是相同縮排級別,因此YAML處理器知道他們屬於同一map;它知道app是lables的值因為app的縮排更大。

注意:在YAML檔案中絕對不要使用tab鍵

因此,如果我們將上述內容翻譯成JSON,它看起來結果如下所示:

{"apiVersion":"v1","kind":"Pod","metadata":{"name":"rss-site","labels":{"app":"web"}}}

現在讓我們來看看lists。

YAML lists

YAML lists 簡直是一個序列的物件,例如:

args
  - sleep
  -"1000"- message
  -"Bring back Firefly!"

正如你可以看到,你可以有任何數量的項在列表中,項的定義以破折號(-)開頭,並且與父元素之間存在縮排。在JSON格式中,它將表示如下:

{"args":["sleep","1000","message","Bring back Firefly!"]}

當然,list的子項也可以是maps,maps的子項也可以是list如下所示:

---
apiVersion: v1
kind:Pod
metadata:
  name: rss-site
  labels:
    app: web
spec:  containers:- name: front-end      image: nginx      ports:- containerPort:80- name: rss-reader      image:nickchase/rss-php-nginx:v1
      ports:- containerPort:88

正如你所看到的,我們有一個叫container的list物件,每個子項都由name、image、ports組成,每個ports都由一個key為containerPort map組成

如下所示,是上述內容的JSON格式:

{"apiVersion":"v1","kind":"Pod","metadata":{"name":"rss-site","labels":{"app":"web"}},"spec":{"containers":[{"name":"front-end","image":"nginx","ports":[{"containerPort":"80"}]},{"name":"rss-reader","image":"nickchase/rss-php-nginx:v1","ports":[{"containerPort":"88"}]}]}}

正如你所看到的,我們寫的內容開始變的複雜,甚至我們還沒有進入任何特別複雜!難怪YAML代替JSON如此之快。

現在然我們複習一下,我們有:

  • maps,鍵值對
  • lists,單獨的項
  • maps的maps
  • maps的lists
  • lists的lists
  • lists的maps

基本上,無論你想要什麼樣結構,你都可以通過這兩個結構去組合實現。

使用YAML建立Pod

所以現在我們已經有了基礎知識,讓我們將他們用起來。我們將使用YAML建立一個Pod然後建立Deployment。

如果你還沒有搭建起叢集和kubectl,那麼在你繼續下去之前需要閱讀之前關於如何搭建kubernets叢集的文章,等搭建完成了我們再繼續下去。
回來了?好的!讓我們開始建立一個Pod。

建立Pod檔案

在之前的例子中,我們通過YAML描述了一個簡單的Pod檔案內容:


apiVersion: v1
kind: Pod
metadata:
name: rss-site
labels:
app: web
spec:
containers:
– name: front-end
image: nginx
ports:
– containerPort: 80
– name: rss-reader
image: nickchase/rss-php-nginx:v1
ports:
– containerPort: 88

讓我們分開來解析這些內容,先從apiVersion 這個關鍵字開始;這裡它的值是v1.(當我們要建立Depolyment的時候,這個值將會指定一個不一樣的值,因為Depolyment沒有v1版本。)

接下來,我們指定我們要建立的是一個Pod;根據我們想要得到的結果,我們將會指定Pod而不是Deployment,Job,Services等等。

最後我們將指定組成pod的實際物件。spec屬性包括一些containers,storage,volumes,或者其他Kubernetes需要知道的引數,以及諸如是否在容器失敗時重新啟動容器的屬性。你可以在特定Kubernetes API找到完整的Kubernetes Pod的屬性,讓我們進一步來看一個典型的容器的定義:


spec:
containers:
– name: front-end
image: nginx
ports:
– containerPort: 80
– name: rss-reader

在這個例子中,這是一個簡單的最小定義:一個名字(front-end),基於nginx的映象,以及容器 將會監聽的一個埠(80)。在這些當中,只有名字是非常需要的,但是通常如果你想做更多的事情,你需要更多的定義。

你也可以指定一個更加複雜的屬性,例如在容器啟動時執行的命令,應使用的引數,工作目錄,或每次例項化時是否拉取映像的新副本。 您還可以指定更深入的資訊,例如容器的退出日誌的位置。

以下有一些容器可以設定的屬性:

  • name
  • image
  • command
  • args
  • workingDir
  • ports
  • env
  • resources
  • volumeMounts
  • livenessProbe
  • readinessProbe
  • livecycle
  • terminationMessagePath
  • imagePullPolicy
  • securityContext
  • stdin
  • stdinOnce
  • tty

現在讓我繼續真正的去建立Pod。

使用YAML檔案建立Pod
第一步,建立一個文字檔案,叫做pod.yaml,然後新增我們之前定義的內容,如下所示:


apiVersion: v1
kind: Pod
metadata:
name: rss-site
labels:
app: web
spec:
containers:
– name: front-end
image: nginx
ports:
– containerPort: 80
– name: rss-reader
image: nickchase/rss-php-nginx:v1
ports:
– containerPort: 88

儲存這個檔案,讓Kubernetes去執行內容所描述的動作:

> kubectl create -f pod.yaml
pod "rss-site" created

正如你所見,k8s 引用了你給pod的命名。如果你想看pods列表可以通過以下方式:

> kubectl get pods
NAME READY STATUS RESTARTS AGE
rss-site 0/2 ContainerCreating 0 6s

如果你更早的檢視的話,你可以看到它仍然處於created的狀態,大概幾秒之後,你就可以看到容器處於running狀態:

> kubectl get pods
NAME       READY     STATUS    RESTARTS   AGE
rss-site   2/2Running014s

至此,你可以測試以下Pod(正如我們之前文章做的),但是最後我們要建立一個Deployment,因此我們先刪除這個pod以免發生名字衝突:

> kubectl delete pod rss-site
pod "rss-site" deleted

pod建立故障定位

有時候,事情並不會如我們所想的發展下去。可能你會遇到一個網路問題,或者在YAML檔案用錯了內容。你可能會看到以下類似以下的錯誤:

> kubectl get pods
NAME       READY     STATUS         RESTARTS   AGE
rss-site   1/2ErrImagePull09s

在這個情況下,我們可以看到我們其中一個容器啟動正常,但是另一個出現了問題。我們可以用以下方式去檢視pod的詳細資訊並定位這個問題:

> kubectl describe pod rss-site
Name:           rss-site
Namespace:defaultNode:10.0.10.7/10.0.10.7StartTime:Sun,08Jan201708:36:47+0000Labels:         app=web
Status:Pending
IP:10.200.18.2Controllers:<none>Containers:
  front-end:Container ID:               docker://a42edaa6dfbfdf161f3df5bc6af05e740b97fd9ac3d35317a6dcda77b0310759Image:                      nginx
    Image ID:                   docker://sha256:01f818af747d88b4ebca7cdabd0c581e406e0e790be72678d257735fad84a15fPort:80/TCP
    State:RunningStarted:Sun,08Jan201708:36:49+0000Ready:TrueRestartCount:0EnvironmentVariables:<none>
  rss-reader:Container ID:Image:                      nickchase/rss-php-nginx
    Image ID:Port:88/TCP
    State:WaitingReason:ErrImagePullReady:FalseRestartCount:0EnvironmentVariables:<none>Conditions:TypeStatusInitializedTrueReadyFalsePodScheduledTrueNo volumes.QoSTier:BestEffortEvents:FirstSeenLastSeenCountFromSubobjectPathTypeReasonMessage------------------------------------------------------------45s45s1{default-scheduler }NormalScheduledSuccessfully assigned rss-site to 10.0.10.744s44s1{kubelet 10.0.10.7}     spec.containers{front-end}NormalPulling                 pulling image "nginx"45s43s2{kubelet 10.0.10.7}WarningMissingClusterDNS       kubelet does not have ClusterDNS IP configured and cannot create Podusing"ClusterFirst" policy.Falling back to DNSDefault policy.43s43s1{kubelet 10.0.10.7}     spec.containers{front-end}NormalPulledSuccessfully pulled image "nginx"43s43s1{kubelet 10.0.10.7}     spec.containers{front-end}NormalCreatedCreated container with docker id a42edaa6dfbf
  43s43s1{kubelet 10.0.10.7}     spec.containers{front-end}NormalStartedStarted container with docker id a42edaa6dfbf
43s29s2{kubelet 10.0.10.7}     spec.containers{rss-reader}NormalPulling                 pulling image "nickchase/rss-php-nginx"42s26s2{kubelet 10.0.10.7}     spec.containers{rss-reader}WarningFailedFailed to pull image "nickchase/rss-php-nginx":Tag latest not found in repository docker.io/nickchase/rss-php-nginx42s26s2{kubelet 10.0.10.7}WarningFailedSyncError syncing pod, skipping: failed to "StartContainer"for"rss-reader"withErrImagePull:"Tag latest not found in repository docker.io/nickchase/rss-php-nginx"41s12s2{kubelet 10.0.10.7}     spec.containers{rss-reader}NormalBackOffBack-off pulling image "nickchase/rss-php-nginx"41s12s2{kubelet 10.0.10.7}WarningFailedSyncError syncing pod, skipping: failed to "StartContainer"for"rss-reader"withImagePullBackOff:"Back-off pulling image \"nickchase/rss-php-nginx\""

正如你所見,這裡有很多資訊,但是最有用的資訊在Events中,詳細的顯示出了曾經出現的警告和錯誤資訊。從這裡我們可以很快的看出,我忘記將:有v1 標籤的映象,所以它用了最新的映象,但是它不存在。

為了解決這個問題,我先刪了這個Pod,然後修復YAML檔案,重新啟動。我修復了之後Kubernetes 將能夠從映象庫中到到,之後也就能夠安裝下去了。

現在我們已經成功運行了一個Pod,接下讓讓我們同樣的執行Deployment。

使用YAML檔案建立Deployment
最後,我們將要進行真正的建立Depolyment。在那之前,我們必須瞭解它實際上是在做什麼。

k8s,記住和管理基於容器的資源。在這個Deployment的例子中,你正在建立一組要管理的資源。例如,在之前的例子中,我們給Pod建立了一個例項,我們將建立一個Deployment去讓Kubernetes管理一組Pod的副本,也就是副本集,保證一定數量的副本一直可用。因此我們可以這樣定義一個Deployment:


apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: rss-site
spec:
replicas: 2

這裡我們指定了apiVersion為extensions/v1beta1,記住,Deployments並不像Pods是v1,我們這裡想要的是Deployments。接下來我們指定名字,我們也可以指定我們想要的元資料,但是我們現在儘量保持簡單。

最後,我們進入配置spec項,我們之前在其中指定我們想要在Pod中做的事;同樣的我們也需要在其中指定Deployment中做的事。我們將開始,在這種情況下,通過說我們部署的任何Pod,我們總是想有2個副本。 當然,你可以設定這個數字,你還可以設定屬性,如定義受此Deployment影響的Pod的選擇器,或者一個Pod在沒有任何錯誤變成準備的情況下必須達到的最小秒數。

你可以在Kubernetes v1beta1 API參考中找到一個完整的Depolyment可指定的引數列表。

因此目前我們想要建立兩個副本,我們需要知道我們做的是什麼