前言
本文試圖將Kubernetes的基礎(chǔ)相關(guān)知識描述清楚,讓一個從來沒有Kubernetes實踐的開發(fā)人員,能夠非常容易地理解Kubernetes是什么,能夠做哪些事情,以及使用它能帶來的好處是什么。
Kubernetes是什么
Kubernetes是一個開源的容器編排引擎,它支持自動化部署、大規(guī)模可伸縮、應(yīng)用容器化管理。我們在完成一個應(yīng)用程序的開發(fā)時,需要冗余部署該應(yīng)用的多個實例,同時需要支持對應(yīng)用的請求進(jìn)行負(fù)載均衡,在Kubernetes中,我們可以把這個應(yīng)用的多個實例分別啟動一個容器,每個容器里面運(yùn)行一個應(yīng)用實例,然后通過內(nèi)置的負(fù)載均衡策略,實現(xiàn)對這一組應(yīng)用實例的管理、發(fā)現(xiàn)、訪問,而這些細(xì)節(jié)都不需要應(yīng)用開發(fā)和運(yùn)維人員去進(jìn)行復(fù)雜的手工配置和處理。Kubernetes是Google基于內(nèi)部Borg開源的容器編排引擎,關(guān)于Borg的設(shè)計,可以查看對應(yīng)的論文《Large-scale cluster management at Google with Borg》。這里,我們先說一說Borg系統(tǒng),它是Google內(nèi)部的集群管理系統(tǒng),使用它能夠獲得如下好處:
在一個分布式系統(tǒng)中進(jìn)行資源管理是非常復(fù)雜的,構(gòu)建于Borg系統(tǒng)之上的其他系統(tǒng),無需關(guān)心這些資源管理的復(fù)雜細(xì)節(jié)
在大型分布式系統(tǒng)中處理異常也是非常困難的,Borg也屏蔽了運(yùn)行于其上系統(tǒng)對失敗或異常情況的處理,用戶可以將精力集中在開發(fā)自己的應(yīng)用系統(tǒng)上
支持高可靠性、高可用性
Borg支持不同Workload,并且都能夠非常高效地運(yùn)行
從應(yīng)用的視角來看,Google內(nèi)部的很多系統(tǒng)都構(gòu)建于Borg之上:應(yīng)用框架,如MapReduce、FlumeJava、MillWheel、Pregel;存儲系統(tǒng),如GFS、CFS、Bigtable、Megastore。從用戶的視角來看, 運(yùn)行在Borg集群之上的Workload主要分為兩類:一類是long-running服務(wù),這類服務(wù)一旦運(yùn)行就不應(yīng)該終止,比如Gmail、Google Docs、Google Search;另一類是批量作業(yè),這類批量作業(yè)可能運(yùn)行幾秒到幾天不等,比如MapReduce作業(yè)。下面看一下,Borg系統(tǒng)的架構(gòu),如下圖所示(來自Borg的論文):

Borg集群從邏輯上看是一個主從架構(gòu)風(fēng)格的系統(tǒng),主要由BorgMaster和Borglet兩個核心組件組成。其中,BorgMaster是Borg集群的中央控制器,它由一個BorgMaster進(jìn)程和一個Scheduler組成,BorgMaster進(jìn)程負(fù)責(zé)處理客戶端RPC調(diào)用請求,管理整個集群中所有對象的狀態(tài)機(jī),Scheduler負(fù)責(zé)調(diào)度Job到指定的節(jié)點(diǎn)上運(yùn)行;Borglet會作為Borg Agent在每個節(jié)點(diǎn)上運(yùn)行,負(fù)責(zé)管理啟動任務(wù)、終止任務(wù)、任務(wù)失敗重啟等等,管理本地節(jié)點(diǎn)上的資源,同時將Borglet所在節(jié)點(diǎn)的狀態(tài)報告給BorgMaster。
主要特性
自動化部署
應(yīng)用部署到容器中,Kubernetes能夠根據(jù)應(yīng)用程序的計算資源需求和其它一些限制條件,自動地將運(yùn)行應(yīng)用程序的容器調(diào)度到集群中指定的Node上,在這個過程中并不會影響應(yīng)用程序的可用性。
系統(tǒng)自愈
當(dāng)Kubernetes集群中某些容器失敗時,會重新啟動它們。當(dāng)某些Node掛掉后,Kubernetes會自動重新調(diào)度這些Node上的容器到其他可用的Node上。如果某些容器沒有滿足用戶定義的健康檢查條件,這些容器會被判定為無法正常工作的,集群會自動Kill掉這些容器,在這個過程中直到容器被重新啟動或重新調(diào)度,直到可用以后才會對調(diào)用的客戶端可見。
水平擴(kuò)展
在Kubernetes中,通過一個命令就可以實現(xiàn)應(yīng)用程序的水平擴(kuò)展,實現(xiàn)這個功能的是HPA(Horizontal Pod Autoscaler)對象。HPA是通過Kubernetes API Resource和Controller的方式實現(xiàn)的,其中Resource決定了Controller的行為,而Controller周期性地調(diào)整Replication Controller或Deployment中的副本數(shù),使得觀察到的平均CPU使用情況與用戶定義的能夠匹配。
服務(wù)發(fā)現(xiàn)和負(fù)載均衡
Kubernetes內(nèi)置實現(xiàn)了服務(wù)發(fā)現(xiàn)的功能,他會給每個容器指派一個IP地址,給一組容器指派一個DNS名稱,通過這個就可以實現(xiàn)服務(wù)的負(fù)載均衡功能。
自動更新和回滾
當(dāng)我們開發(fā)的應(yīng)用程序發(fā)生變更,Kubernetes可以實現(xiàn)滾動更新,同時監(jiān)控應(yīng)用的狀態(tài),確保不會在同一時刻殺掉所有的實例,造成應(yīng)用在一段時間范圍內(nèi)不可用。如果某些時候應(yīng)用更新出錯,Kubernetes能夠自動地將應(yīng)用恢復(fù)到原來正確的狀態(tài)。
密鑰和配置管理
Kubernetes提供了一種機(jī)制(ConfigMap),能夠使我們的配置數(shù)據(jù)與應(yīng)用對應(yīng)的Docker鏡像解耦合,如果配置需要變更,不需要重新構(gòu)建Docker鏡像,這為應(yīng)用開發(fā)部署提供很大的靈活性。同時,對于應(yīng)用所依賴的一些敏感信息,如用戶名和密碼、令牌、密鑰等信息,Kubernetes也通過Secret對象實現(xiàn)了將這些敏感配置信息與應(yīng)用的解耦合,這對應(yīng)用的快速開發(fā)和交付提供了便利,在一定程上提供了也安全保障。
存儲掛載
Kubernetes可以支持掛載不同類型存儲系統(tǒng),比如本地存儲、公有云存儲(如AWS、GCP)、網(wǎng)絡(luò)存儲系統(tǒng)(如NFS、iSCSI、Gluster、Ceph、Cinder、Flocker)等,我們可以進(jìn)行靈活的選擇。
批量作業(yè)執(zhí)行
Kubernetes也支持批量作業(yè)的處理、監(jiān)控、恢復(fù)。作業(yè)提交以后,直到作業(yè)運(yùn)行完成即退出。如果運(yùn)行失敗,Kubernetes能夠使失敗的作業(yè)自動重新運(yùn)行,直到作業(yè)運(yùn)行成功為止。
總體架構(gòu)
首先給出一個概念:Kubernetes Control Plane,翻譯過來就是“Kubernetes控制平面”,它表示Kubernetes為了實現(xiàn)最終的目標(biāo)而構(gòu)建的一組集群范圍內(nèi)的進(jìn)程,這組進(jìn)程相互協(xié)調(diào),保證整個集群系統(tǒng)達(dá)到用戶所期望的目標(biāo)狀態(tài),比如,容器失敗自動調(diào)度并重啟,應(yīng)用服務(wù)的擴(kuò)容縮容,等等。Kubernetes Control Plane管理了Kubernetes集群中的所有Kubernetes對象及其狀態(tài),這些對象包括Pod、Service、Volume、Namespace、ReplicaSet、Deployment、StatefulSet、DaemonSet、Job等等。Kubernetes集群的總體架構(gòu),如下圖所示:

Kubernetes Control Plane主要包含兩部分,一部分是Kubernetes集群Master上一組關(guān)鍵進(jìn)程,另一個部分是在每個工作的Node節(jié)點(diǎn)上的一組關(guān)鍵進(jìn)程,下面我們分別詳細(xì)說明:
Kubernetes Master
Kubernetes Master主要由kube-apiserver、kube-controller-manager和kube-scheduler三個進(jìn)程組成,它們運(yùn)行在集群中一個單獨(dú)的節(jié)點(diǎn)上,具體說明如下:kube-apiserver進(jìn)程:想要操作Kubernetes集群中的任何對象,都需要經(jīng)過kube-apiserver,它封裝了對Kubernetes對象的所有操作,以REST接口方式提供給想要與Kubernetes交互的任何客戶端。經(jīng)過kube-apiserver的所有對Kubernetes對象的修改操作都將持久化到etcd存儲中。kube-controller-manager進(jìn)程:負(fù)責(zé)運(yùn)行各種Controller,這些Controller主要包括:
Node Controller
Replication Controller
Endpoints Controller
Service Account
Token Controller
kube-scheduler進(jìn)程:負(fù)責(zé)Kubernetes集群內(nèi)部的資源調(diào)度,主要負(fù)責(zé)監(jiān)視Kubernetes集群內(nèi)部已創(chuàng)建但沒有被調(diào)度到某個Node上的Pod,然后將該P(yáng)od調(diào)度到一個選定的Node上面運(yùn)行。
Kubernetes Node
Kubernetes集群中,每個工作的Node節(jié)點(diǎn)上主要運(yùn)行如下兩個進(jìn)程:kubelet進(jìn)程:kubelet負(fù)責(zé)監(jiān)視指派到它所在Node上的Pod,還負(fù)責(zé)處理如下工作:
為Pod掛載Volume
下載Pod擁有的Secret
運(yùn)行屬于Pod的容器
周期性地檢查Pod中的容器是否存活
向Master報告當(dāng)前Node上Pod的狀態(tài)信息
向Master報告當(dāng)前Node的狀態(tài)信息
kube-proxy進(jìn)程:在Kubernetes集群中,每個Node上面都有一個該網(wǎng)絡(luò)代理進(jìn)程,它主要負(fù)責(zé)為Pod對象提供代理:定期從etcd存儲中獲取所有的Service對象,并根據(jù)Service信息創(chuàng)建代理。當(dāng)某個Client要訪問一個Pod時,請求會經(jīng)過該Node上的代理進(jìn)程進(jìn)行請求轉(zhuǎn)發(fā)。
基本概念
Node
Node是Kubernetes集群的工作節(jié)點(diǎn),它可以是物理機(jī),也可以是虛擬機(jī)。我們創(chuàng)建的Pod,都運(yùn)行在Kubernetes集群中的每個Node節(jié)點(diǎn)上。而且,在每個Node上還會存在一個運(yùn)行容器的daemon進(jìn)程,比如Docker daemon進(jìn)程,它負(fù)責(zé)管理Docker容器的運(yùn)行。Node在Kubernetes集群中也是一種資源,內(nèi)部會創(chuàng)建該資源,定義Node示例如下所示:
{
"kind": "Node",
"apiVersion": "v1",
"metadata": {
"name": "10.240.79.157",
"labels": {
"name": "my-first-k8s-node"
}
}
}
Namespace
在一個Kubernetes集群中,可以使用Namespace創(chuàng)建多個“虛擬集群”,這些Namespace之間可以完全隔離,也可以通過某種方式,使一個Namespace中的Service可以訪問到其他Namespace中的Service。查看當(dāng)前Kubernetes集群中的Namespace列表,執(zhí)行如下命令:
kubectl get namespaces
默認(rèn)情況下,會有兩個系統(tǒng)自動創(chuàng)建好的Namespace:
default:Kubernetes集群中沒有Namespace的對象都會放到該默認(rèn)Namespace中
kube-system:Kubernetes集群自動創(chuàng)建的Namespace
創(chuàng)建一個名稱為myns的Namespace,配置內(nèi)容如下所示:
apiVersion: v1
kind: Namespace
metadata:
name: myns
Pod
在Kubernetes集群中,Pod是創(chuàng)建、部署和調(diào)度的基本單位。一個Pod代表著集群中運(yùn)行的一個進(jìn)程,它內(nèi)部封裝了一個或多個應(yīng)用的容器。在同一個Pod內(nèi)部,多個容器共享存儲、網(wǎng)絡(luò)IP,以及管理容器如何運(yùn)行的策略選項。Docker是Kubernetes中最常用的容器運(yùn)行時。在Kubrenetes集群中,Pod有兩種使用方式,如下所示:
一個Pod中運(yùn)行一個容器
這種模式是最常見的用法,可以把Pod想象成是單個容器的封裝,Kubernetes直接管理的是Pod,而不是Pod內(nèi)部的容器。
一個Pod中同時運(yùn)行多個容器
一個Pod中也可以同時運(yùn)行幾個容器,這些容器之間需要緊密協(xié)作,并共享資源。這些在同一個Pod中的容器可以互相協(xié)作,邏輯上代表一個Service對象。每個Pod都是應(yīng)用的一個實例,如果我們想要運(yùn)行多個實例,就應(yīng)該運(yùn)行多個Pod。同一個Pod中的容器,會自動的分配到同一個Node上。每個Pod都會被分配一個唯一的IP地址,該P(yáng)od中的所有容器共享網(wǎng)絡(luò)空間,包括IP地址和端口。Pod內(nèi)部的容器可以使用localhost互相通信。Pod中的容器與外界通信時,必須分配共享網(wǎng)絡(luò)資源(例如,使用宿主機(jī)的端口映射)。我們可以為一個Pod指定多個共享的Volume,它內(nèi)部的所有容器都可以訪問共享的Volume。Volume也可以用來持久化Pod中的存儲資源,以防容器重啟后文件丟失。我們可以使用Kubernetes中抽象的Controller來創(chuàng)建和管理多個Pod,提供副本管理、滾動升級和集群級別的自愈能力。當(dāng)Pod被創(chuàng)建后,都會被Kuberentes調(diào)度到集群的Node上,直到Pod的進(jìn)程終止而被移除掉。
Service
Kubernetes Service從邏輯上定義了一個Pod的集合以及如何訪問這些Pod的策略,有時也被稱作是微服務(wù),它與Pod、ReplicaSet等Kubernetes對象之間的關(guān)系,描述如下圖所示:

上圖中,Client請求Service,Service通過Label Selector,將請求轉(zhuǎn)發(fā)到對應(yīng)的一組Pod上。同時,ReplicaSet會基于Label Selector來監(jiān)控Service對應(yīng)的Pod的數(shù)量是否滿足用戶設(shè)置的預(yù)期個數(shù),最終保證Pod的數(shù)量和replica的值一致。在Kubernetes集群中,每個Node都會運(yùn)行一個kube-proxy,它主要負(fù)責(zé)為Service實現(xiàn)一種虛擬IP的代理,這種代理有兩種模式:
userspace模式
這種模式是在Kubernetes v1.0版本加入的,工作在4層(傳輸層:TCPUDP over IP),稱為userspace模式,如下圖所示:

iptables模式
這種模式是在Kubernetes v1.1版本新增的,它工作在七層(應(yīng)用層:HTTP),稱為iptables,如下圖所示:

Service定義了4種服務(wù)類型,以滿足使用不同的方式去訪問一個Service,這4種類型包括:ClusterIP、NodePort、LoadBalancer、ExternalName。
ClusterIP是默認(rèn)使用的類型,它表示在使用Kubernetes集群內(nèi)部的IP地址,使用這種方式我們只能在該集群中訪問Service。
NodePort類型,會在Node節(jié)點(diǎn)上暴露一個靜態(tài)的IP地址和端口,使得外部通過NodeIP:NodePort的方式就能訪問到該Service。
LoadBalancer類型,通過使用Cloud提供商提供的負(fù)載均衡IP地址,將Service暴露出去。
ExternalName類型,會使用一個外部的域名來將Service暴露出去(Kubernetes v1.7及以上版本的kube-dns支持該種類型)。
我們可以定義一個Service,對應(yīng)的配置內(nèi)容,如下所示:
kind: Service
apiVersion: v1
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- name: http
protocol: TCP
port: 80
targetPort: 9376
- name: https
protocol: TCP
port: 443
targetPort: 9377
clusterIP: 10.0.171.239
loadBalancerIP: 78.11.24.19
type: LoadBalancer
status:
loadBalancer:
ingress:
- ip: 146.148.47.155
定義的該服務(wù)是一個多端口服務(wù),同時為該服務(wù)設(shè)置了一個負(fù)載均衡的IP(78.11.24.19),所有訪問該服務(wù)的應(yīng)用,通過該負(fù)載均衡IP地址都可以訪問到該Service對應(yīng)的Pod集合中的容器服務(wù)(應(yīng)用服務(wù))。
ReplicationController/ReplicaSet
在Kubernetes集群中,ReplicationController能夠確保在任意時刻,指定數(shù)量的Pod副本正在運(yùn)行。如果Pod副本的數(shù)量過多,則ReplicationController會Kill掉部分使其數(shù)量與預(yù)期保持一致,如果Pod數(shù)量過少,則會自動創(chuàng)建新的Pod副本以與預(yù)期數(shù)量相同。下面是一個ReplicationController的配置示例,如下所示:
apiVersion: v1
kind: ReplicationController
metadata:
name: nginx
spec:
replicas: 3
selector:
app: nginx
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
ReplicaSet是ReplicationController的下一代實現(xiàn),它們之間沒有本質(zhì)的區(qū)別,除了ReplicaSet支持在selector中通過集合的方式進(jìn)行配置。在新版本的Kubernetes中支持并建議使用ReplicaSet,而且我們應(yīng)該盡量使用Deployment來管理一個ReplicaSet。下面定義一個ReplicaSet,對應(yīng)的配置示例如下所示:
apiVersion: extensions/v1beta1
kind: ReplicaSet
metadata:
name: frontend
labels:
app: guestbook
tier: frontend
spec:
replicas: 3.
selector:
matchLabels:
tier: frontend
matchExpressions:
- {key: tier, operator: In, values: [frontend]}
template:
metadata:
labels:
app: guestbook
tier: frontend
spec:
containers:
- name: php-redis
image: gcr.io/google_samples/gb-frontend:v3
resources:
requests:
cpu: 100m
memory: 100Mi
env:
- name: GET_HOSTS_FROM
value: dns
ports:
- containerPort: 80
Volume
默認(rèn)情況下容器的數(shù)據(jù)都是非持久化的,在容器銷毀以后數(shù)據(jù)也會丟失,所以Docker提供了Volume機(jī)制來實現(xiàn)數(shù)據(jù)的持久化存儲。同樣,Kubernetes提供了更強(qiáng)大的Volume機(jī)制和豐富的插件,實現(xiàn)了容器數(shù)據(jù)的持久化,以及在容器之間共享數(shù)據(jù)。Kubernetes Volume具有顯式的生命周期,它與Pod的生命周期是相同的,所以只要Pod還處于運(yùn)行狀態(tài),則該P(yáng)od內(nèi)部的所有容器都能夠訪問該Volume,即使該P(yáng)od中的某個容器失敗,數(shù)據(jù)也不會丟失。Kubernetes支持多種類型的Volume,如下所示:
emptyDir
hostPath
gcePersistentDisk
awsElasticBlockStore
nfs
iscsi
fc (fibre channel)
flocker
glusterfs
rbd
cephfs
gitRepo
secret
persistentVolumeClaim
downwardAPI
projected
azureFileVolume
azureDisk
vsphereVolume
Quobyte
PortworxVolume
ScaleIO
StorageOS
local
上面各種類型的說明和示例,可以參考官方文檔。Volume是與Pod有關(guān)的,所以這里我們給出一個Pod定義的配置示例,使用了hostPath類型的Volume,如下所示:
apiVersion: v1
kind: Pod
metadata:
name: test-pd
spec:
containers:
- image: gcr.io/google_containers/test-webserver
name: test-container
volumeMounts:
- mountPath: /test-pd
name: test-volume
volumes:
- name: test-volume
hostPath:
# directory location on host
path: /data
上面定義中,指定了Pod中容器使用的Node節(jié)點(diǎn)上的data存儲路徑。
Deployment
Deployment提供了聲明式的方法,對Pod和ReplicaSet進(jìn)行更新,我們只需要在Deployment對象中設(shè)置好預(yù)期的狀態(tài),然后Deployment就能夠控制將實際的狀態(tài)保持與預(yù)期狀態(tài)一致。使用Deployment的典型場景,有如下幾個:
創(chuàng)建ReplicaSet,進(jìn)而通過ReplicaSet啟動Pod,Deployment會檢查啟動狀態(tài)是否成功
滾動升級或回滾應(yīng)用
應(yīng)用擴(kuò)容或縮容
暫停(比如修改Pod模板)及恢復(fù)Deployment的運(yùn)行
根據(jù)Deployment的運(yùn)行狀態(tài),可以判斷對應(yīng)的應(yīng)用是否hang住
清除掉不再使用的ReplicaSet
定義一個Deployment,示例如下所示:
apiVersion: apps/v1beta1 # for versions before 1.6.0 use extensions/v1beta1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 3
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
上述配置創(chuàng)建一個ReplicaSet,進(jìn)而啟動3個Nginx Pod。
DaemonSet
DaemonSet能夠保證Kubernetes集群中某些Node,或者全部Node上都運(yùn)行一個Pod副本,當(dāng)集群中某個Node被移除時,該Node上的Pod副本也會被清理掉。刪除一個DaemonSet,也會把對應(yīng)的Pod都刪除掉。通常,DaemonSet會被用于如下場景(在Kubernetes集群中每個Node上):
運(yùn)行一個存儲Daemon,如glusterd、ceph等
運(yùn)行一個日志收集Daemon,如fluentd、logstash等
運(yùn)行一個監(jiān)控Daemon,如collectd、gmond等
定義一個DaemonSet,示例如下所示:
apiVersion: apps/v1beta1
kind: DaemonSet
metadata:
name: fluentd
spec:
template:
metadata:
labels:
app: logging
id: fluentd
name: fluentd
spec:
containers:
- name: fluentd-es
image: gcr.io/google_containers/fluentd-elasticsearch:1.3
env:
- name: FLUENTD_ARGS
value: -qq
volumeMounts:
- name: containers
mountPath: /var/lib/docker/containers
- name: varlog
mountPath: /varlog
volumes:
- hostPath:
path: /var/lib/docker/containers
name: containers
- hostPath:
path: /var/log
name: varlog
上面例子,創(chuàng)建了一個基于fluentd的日志收集DaemonSet。
StatefulSet
StatefulSet是Kubernetes v1.5版本新增的,在v1.5之前的版本叫做PetSet(使用v1.4版本可以使用,具體可以查看官方文檔,這里不再累述),是為了解決有狀態(tài)服務(wù)的問題(對應(yīng)無狀態(tài)服務(wù)的Kubernetes對象:Deployment和ReplicaSet),其應(yīng)用場景包括:
穩(wěn)定的持久化存儲,即Pod重新調(diào)度后還是能訪問到相同的持久化數(shù)據(jù),基于PVC來實現(xiàn)
穩(wěn)定的網(wǎng)絡(luò)標(biāo)志,即Pod重新調(diào)度后其PodName和HostName不變,基于Headless Service(即沒有Cluster IP的Service)來實現(xiàn)
有序部署,有序擴(kuò)展,即Pod是有順序的,在部署或者擴(kuò)展的時候要依據(jù)定義的順序依次進(jìn)行,基于init containers來實現(xiàn)
有序縮容,有序刪除
為了說明StatefulSet,我們先定義一個名稱為nginx的Headless Service,如下所示:
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
ports:
- port: 80
name: web
clusterIP: None
selector:
app: nginx
再定義一個名稱為web的StatefulSet,定義了要在3個獨(dú)立的Pod中分別創(chuàng)建3個nginx容器,示例如下所示:
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
name: web
spec:
serviceName: "nginx"
replicas: 3
template:
metadata:
labels:
app: nginx
spec:
terminationGracePeriodSeconds: 10
containers:
- name: nginx
image: gcr.io/google_containers/nginx-slim:0.8
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www
annotations:
volume.beta.kubernetes.io/storage-class: anything
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 1Gi
上面示例,在Service中引用了名稱為web的StatefulSet,該Service對應(yīng)的存儲信息是有狀態(tài)的,通過StatefulSet能夠保證Service中的Pod失敗也不會丟失存儲的數(shù)據(jù),它通過PersistentVolume來提供穩(wěn)定存儲的。
ConfigMap
應(yīng)用程序會從配置文件、命令行參數(shù)或環(huán)境變量中讀取配置信息,如果將這些配置信息直接寫在Docker鏡像中,會非常不靈活,每次修改配置信息都要重新創(chuàng)建一個Docker鏡像。ConfigMap的出現(xiàn),能夠使配置信息與Docker鏡像解耦,更加方便和靈活。在定義一個Pod的時候,可以使用ConfigMap對象中的配置數(shù)據(jù),有很多種方式,如下所示:
從一個ConfigMap中讀取鍵值對配置數(shù)據(jù)
從多個ConfigMap中讀取鍵值對配置數(shù)據(jù)
從一個ConfigMap中讀取全部的鍵值對配置數(shù)據(jù)
將一個ConfigMap中的配置數(shù)據(jù)加入到一個Volume中
下面給出其中2種使用方式:
定義一個環(huán)境變量,該變量值映射到一個ConfigMap對象中的配置值
創(chuàng)建一個名稱為special-config的ConfigMap對象,執(zhí)行如下命令:
kubectl create configmap special-config --from-literal=special.how=very
在上述ConfigMap對象special-config中創(chuàng)建了一個鍵special.how,它對應(yīng)的值為very。然后,我們定義一個Pod,將ConfigMap中的鍵special.how對應(yīng)的值,賦值給環(huán)境變量SPECIAL_LEVEL_KEY,Pod定義文件內(nèi)容,如下所示:
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
image: gcr.io/google_containers/busybox
command: [ "/bin/sh", "-c", "env" ]
env:
# Define the environment variable
- name: SPECIAL_LEVEL_KEY
valueFrom:
configMapKeyRef:
# The ConfigMap containing the value you want to assign to SPECIAL_LEVEL_KEY
name: special-config
# Specify the key associated with the value
key: special.how
restartPolicy: Never
這時,Pod創(chuàng)建以后,就可以獲取到對應(yīng)的環(huán)境變量的值:SPECIAL_LEVEL_KEY=very。
創(chuàng)建多個ConfigMap對象,Pod從多個ConfigMap對象中讀取到對應(yīng)的配置值
首先,創(chuàng)建第一個ConfigMap對象special-config,該對象定義了配置數(shù)據(jù)special.how=very,如下所示:
apiVersion: v1
kind: ConfigMap
metadata:
name: special-config
namespace: default
data:
special.how: very
然后,創(chuàng)建第二個ConfigMap對象env-config,該對象定義了配置數(shù)據(jù)log_level=INFO,如下所示:
apiVersion: v1
kind: ConfigMap
metadata:
name: env-config
namespace: default
data:
log_level: INFO
最后,就可以在Pod中定義環(huán)境變量,如下所示:
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
image: gcr.io/google_containers/busybox
command: [ "/bin/sh", "-c", "env" ]
env:
- name: SPECIAL_LEVEL_KEY
valueFrom:
configMapKeyRef:
name: special-config
key: special.how
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: env-config
key: special.type
restartPolicy: Never
在Pod創(chuàng)建后,可以分別從special-config、env-config中讀取環(huán)境變量的值:SPECIAL_LEVEL_KEY=very、LOG_LEVEL=INFO。
Secret
Secret對象用來保存一些敏感信息,比如密碼、OAuth令牌、ssh秘鑰等,雖然這些敏感信息可以放到Pod定義中,或者Docker鏡像中,但是放到Secret對象中更加安全和靈活。使用Secret對象時,可以在Pod中引用創(chuàng)建的Secret對象,主要有如下兩種方式:
掛載到一個或多個容器的Volume中的文件里面
當(dāng)為一個Pod拉取鏡像時,被kubectl使用
可以通過將Secret掛載到Volume中,或者以環(huán)境變量的形式導(dǎo)出,來被一個Pod中的容器使用。下面是一個示例,在一個Pod中的Volume上掛載一個Secret,如下所示:
{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"name": "mypod",
"namespace": "myns"
},
"spec": {
"containers": [{
"name": "mypod",
"image": "redis",
"volumeMounts": [{
"name": "foo",
"mountPath": "/etc/foo",
"readOnly": true
}]
}],
"volumes": [{
"name": "foo",
"secret": {
"secretName": "mysecret"
}
}]
}
}
通過導(dǎo)出環(huán)境變量,使用Secret,示例如下所示:
apiVersion: v1
kind: Pod
metadata:
name: secret-env-pod
spec:
containers:
- name: mycontainer
image: redis
env:
- name: SECRET_USERNAME
valueFrom:
secretKeyRef:
name: mysecret
key: username
- name: SECRET_PASSWORD
valueFrom:
secretKeyRef:
name: mysecret
key: password
restartPolicy: Never
其它有關(guān)Secret的更詳細(xì)信息,可以參考官網(wǎng)文檔。
Job
一個Job會創(chuàng)建一個或多個Pod,并確保指定數(shù)目的Pod能夠運(yùn)行成功。Job會跟蹤每個Pod的運(yùn)行,直到其運(yùn)行成功,如果該Job跟蹤的多個Pod都運(yùn)行成功,則該Job就變?yōu)橥瓿蔂顟B(tài)。刪除一個Job,該Job創(chuàng)建的Pod都會被清理掉。定義一個Job,示例如下所示:
apiVersion: batch/v1
kind: Job
metadata:
name: pi
spec:
template:
metadata:
name: pi
spec:
containers:
- name: pi
image: perl
command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
restartPolicy: Never
CronJob
Crontab用來管理定時Job,主要使用場景如下:
在一個給定的時間點(diǎn),調(diào)度Job運(yùn)行
創(chuàng)建一個周期性運(yùn)行的Job,例如數(shù)據(jù)庫備份、發(fā)送郵件等等
定義一個CronJob,示例配置內(nèi)容如下所示:
apiVersion: batch/v2alpha1
kind: CronJob
metadata:
name: hello
spec:
schedule: "*/1 * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: hello
image: busybox
args:
- /bin/sh
- -c
- date; echo Hello from the Kubernetes cluster
restartPolicy: OnFailure
上面CronJob運(yùn)行,會定時執(zhí)行一個Bash命令行輸出字符串“Hello from the Kubernetes cluster”。
Ingress
通常情況下,Service和Pod僅可在集群內(nèi)部網(wǎng)絡(luò)中通過IP地址訪問。所有到達(dá)Edge router的流量或被丟棄或被轉(zhuǎn)發(fā)到其它地方。一個Ingress是一組規(guī)則的集合,這些規(guī)則允許外部請求(公網(wǎng)訪問)直接連接到Kubernetes集群內(nèi)部的Service,如下圖所示:

我們可以配置Ingress,為它提供外部(公網(wǎng))可訪問給定Service的規(guī)則,如Service URL、負(fù)載均衡、SSL、基于名稱的虛擬主機(jī)等。用戶想要基于POST方式請求Ingress資源,需要通過訪問Kubernetes API Server來操作Ingress資源。Ingress Controller是一個daemon進(jìn)程,它是通過Kubernetes Pod來進(jìn)行部署的。它負(fù)責(zé)實現(xiàn)Ingress,通常使用負(fù)載均衡器,還可以配置Edge router和其他前端(frontends),以高可用(HA)的方式來處理請求。為了能夠使Ingress工作,Kubernetes集群中必須要有個一個Ingress Controller在運(yùn)行,不同于kube-controller-manager所管理的Controller,我們必須要選擇一個適合我們Kubernetes集群的Ingress Controller實現(xiàn),如果沒有合適的就需要開發(fā)實現(xiàn)一個。定義一個Ingress,示例如下所示:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: test-ingress
spec:
rules:
- http:
paths:
- path: /testpath
backend:
serviceName: test
servicePort: 80
上面rules配置了Ingress的規(guī)則列表,目前只支持HTTP規(guī)則,該示例使用了HTTP的paths規(guī)則,所請求URL能夠匹配上paths指定的testpath,都會被轉(zhuǎn)發(fā)到backend指定的Service上。Ingress有如下5種類型:
單Service Ingress
簡單扇出(fanout)
基于名稱的虛擬主機(jī)
TLS
負(fù)載均衡
想要熟悉上面5種類型的Ingress,可以查閱官方文檔,這里不再詳述。
Horizontal Pod Autoscaler
應(yīng)用運(yùn)行在容器中,它所依賴的資源的使用率通常并不均衡,資源使用量有時可能達(dá)到峰值,有時使用的又很少,為了提高Kubernetes集群的整體資源利用率,我們需要Service中的Pod的個數(shù)能夠根據(jù)實際資源使用量來自動調(diào)整。這時我們就可以使用HPA(Horizontal Pod Autoscaling),它和Pod、Deployment等都是Kubernetes API資源,能實現(xiàn)Kubernetes集群內(nèi)Service中Pod的水平伸縮。HPA的工作原理,如下圖所示:

通過下面命令,可以對HPA進(jìn)行各種操作(創(chuàng)建HPA、列出所有HPA、獲取HPA詳細(xì)描述信息、刪除HPA):
kubectl create hpa
kubectl get hpa
kubectl describe hpa
kubectl delete hpa
另外,還可以通過kubectl autoscale 命令來創(chuàng)建HPA,例如,執(zhí)行如下命令:
kubectl autoscale rc foo --min=2 --max=5 --cpu-percent=80
上面示例的命令,要為名稱為foo的ReplicationController創(chuàng)建一個HPA對象,使得目標(biāo)CPU利率用為80%,并且副本的數(shù)量保持在2到5之間。
kubectl CLI
kubectl是一個命令行接口,通過它可以執(zhí)行命令與Kubernetes集群交互。kubectl命令的語法格式,如下所示:
kubectl [command] [TYPE] [NAME] [flags]
上面命令說明中:command:需要在一種或多種資源上執(zhí)行的操作,比如:create、get、describe、delete等等,更詳細(xì)可以參考官網(wǎng)文檔。TYPE:指定資源類型,大小寫敏感,當(dāng)前支持如下這些類型的資源:
certificatesigningrequests、clusters、clusterrolebindings、clusterroles、componentstatuses、configmaps、cronjobs、daemonsets、deployments、endpoints、events、horizontalpodautoscalers、ingresses、jobs、limitranges、namespaces、networkpolicies、nodes、persistentvolumeclaims、persistentvolumes、poddisruptionbudget、pods、podsecuritypolicies、podtemplates、replicasets、replicationcontrollers、resourcequotas、rolebindings、roles、secrets、serviceaccounts、services、statefulsets、storageclasses、thirdpartyresources。NAME:指定資源的名稱,大小寫敏感。flags:可選,指定選項標(biāo)志,比如:-s或-server表示Kubernetes API Server的IP地址和端口。如果想要了解上述命令的詳細(xì)用法說明,可以執(zhí)行幫助命令:
kubectl help
另外,還可以通過官方文檔,根據(jù)使用的Kubernetes的不同版本,來參考如下鏈接獲取幫助:
https://kubernetes.io/docs/user-guide/kubectl/v1.7/
https://kubernetes.io/docs/user-guide/kubectl/v1.6/
https://kubernetes.io/docs/user-guide/kubectl/v1.5/
下面,舉個常用的命令行操作,需要通過YAML文件定義一個Service(詳見上文“基本概念”中給出的Service示例),創(chuàng)建一個Service,執(zhí)行如下命令:
kubectl create -f ./my-k8s-service.yaml
定義任何Kubernetes對象,都是通過YAML文件去配置,使用類似上述命令進(jìn)行創(chuàng)建。如果想要查看創(chuàng)建Kubernetes對象的結(jié)果,比如查看創(chuàng)建Service對象的結(jié)果,可通過如下命令查看:
kubectl get services
這樣,就能看到當(dāng)前創(chuàng)建的Service對象的狀態(tài)。
原文鏈接:https://www.toutiao.com/a6832665997808239115/?log_from=e6bb6845d722b_1638616404297