架構(gòu)大佬教你學(xué),Kubernetes的主要特性、基本概念與總體架構(gòu)

前言

本文試圖將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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容