Kubernetes架構圖php
上圖能夠看到以下組件,使用特別的圖標表示Service和Label:html
Pod 是Kubernetes的基本操做單元,也是應用運行的載體。整個Kubernetes系統都是圍繞着Pod展開的,好比如何部署運行Pod、如何保證Pod的數量、如何訪問Pod等。另外,Pod是一個或多個機關容器的集合,提供了一種容器的組合的模型。前端
Pod(上圖綠色方框)安排在節點上,包含一組容器和卷。同一個Pod裏的容器共享同一個網絡命名空間,可使用localhost互相通訊。Pod是短暫的,不是持續性實體。node
Pods提供兩種共享資源:網絡和存儲。
網絡:
每一個Pod被分配一個獨立的IP地址,Pod中的每一個容器共享網絡命名空間,包括IP地址和網絡端口。
Pod內的容器可使用localhost相互通訊。
當Pod中的容器與Pod 外部通訊時,他們必須協調如何使用共享網絡資源(如端口)。
存儲:
Pod能夠指定一組共享存儲volumes。
Pod中的全部容器均可以訪問共享volumes,容許這些容器共享數據。
volumes 還用於Pod中的數據持久化,以防其中一個容器須要從新啓動而丟失數據。mysql
建立 kubectl create -f xxx.yamlnginx
查詢 kubectl get pod yourPodName kubectl describe pod yourPodNamegit
刪除 kubectl delete pod yourPodNamegithub
更新 kubectl replace /path/to/yourNewYaml.yamlweb
在Docker中,容器是最小的處理單元,增刪改查的對象是容器,容器是一種虛擬化技術,容器之間是隔離的,隔離是基於Linux Namespace實現的。而在Kubernetes中,Pod包含一個或者多個相關的容器,Pod能夠認爲是容器的一種延伸擴展,一個Pod也是一個隔離體,而Pod內部包含的一組容器又是共享的(包括PID、Network、IPC、UTS)。除此以外,Pod中的容器能夠訪問共同的數據捲來實現文件系統的共享。redis
Controller能夠建立和管理多個Pod,提供副本管理、滾動升級和集羣級別的自愈能力。若是一個Node故障,Controller就能自動將該節點上的Pod調度到其餘健康的Node上。
在kubernetes中,鏡像的下載策略爲:
Always:每次都下載最新的鏡像
Never:只使用本地鏡像,從不下載
IfNotPresent:只有當本地沒有的時候才下載鏡像
Pod被分配到Node以後會根據鏡像下載策略進行鏡像下載,能夠根據自身集羣的特色來決定採用何種下載策略。不管何種策略,都要確保Node上有正確的鏡像可用。
經過yaml文件,能夠在Pod中設置:
啓動命令,如:spec-->containers-->command;
環境變量,如:spec-->containers-->env-->name/value;
端口橋接,如:spec-->containers-->ports-->containerPort/protocol/hostIP/hostPort(使用hostPort時須要注意端口衝突的問題,不過Kubernetes在調度Pod的時候會檢查宿主機端口是否衝突,好比當兩個Pod均要求綁定宿主機的80端口,Kubernetes將會將這兩個Pod分別調度到不一樣的機器上);
Host網絡,一些特殊場景下,容器必需要以host方式進行網絡設置(如接收物理機網絡纔可以接收到的組播流),在Pod中也支持host網絡的設置,如:spec-->hostNetwork=true;
數據持久化,如:spec-->containers-->volumeMounts-->mountPath;
重啓策略,當Pod中的容器終止退出後,重啓容器的策略。這裏的所謂Pod的重啓,實際上的作法是容器的重建,以前容器中的數據將會丟失,若是須要持久化數據,那麼須要使用數據捲進行持久化設置。Pod支持三種重啓策略:Always(默認策略,當容器終止退出後,老是重啓容器)、OnFailure(當容器終止且異常退出時,重啓)、Never(從不重啓);
Pod被分配到一個Node上以後,就不會離開這個Node,直到被刪除。當某個Pod失敗,首先會被Kubernetes清理掉,以後ReplicationController將會在其它機器上(或本機)重建Pod,重建以後Pod的ID發生了變化,那將會是一個新的Pod。因此,Kubernetes中Pod的遷移,實際指的是在新Node上重建Pod。
Replication Controller確保任意時間都有指定數量的Pod「副本」在運行。若是爲某個Pod建立了Replication Controller而且指定3個副本,它會建立3個Pod,而且持續監控它們。若是某個Pod不響應,那麼Replication Controller會替換它。
當建立Replication Controller時,須要指定兩個東西:
使用過程:
apiVersion: v1
kind: ReplicationController
metadata: #設置rc的元數據
name: frontend
labels:
name: frontend
spec:
replicas: 3 #設置Pod的具體數量
selector: #經過selector來匹配相應的Pod的label
name: frontend
template: #設置Pod的模板
metadata:
labels:
name: frontend
spec:
containers:
- name: frontend
image: kubeguide/guestbook-php-frontend:latest
imagePullPolicy: IfNotPresent #鏡像拉取策略,分爲Always,Never,IfNotPresent,默認是Always
env :
- name : GET_HOSTS_FROM
value : env
ports:
- containerPort: 80
yaml字段的含義:
spec.replicas:副本數量3
spec.selector:RC經過spec.selector來篩選要控制的Pod
spec.template:這裏寫Pod的定義(但不須要apiVersion和kind)
spec.template.metadata.labels:Pod的label,能夠看到這個label與spec.selector相同
這個文件的意思:
定義一個RC對象,它的名字是frontend(metadata.name:frontend),保證有3個Pod運行(spec.replicas:3),Pod的鏡像是kubeguide/guestbook-php-frontend:latest(spec.template.spec.containers.image:kubeguide/guestbook-php-frontend:latest)
關鍵在於spec.selector與spec.template.metadata.labels,這兩個字段必須相同,不然下一步建立RC會失敗。(也能夠不寫spec.selector,這樣默認與spec.template.metadata.labels相同)
RC的經常使用操做命令:
經過kubectl建立RC
# kubectl create -f rc.yaml
查看RC具體信息
# kubectl describe rc frontend
經過RC修改Pod副本數量(須要修改yaml文件的spec.replicas字段到目標值,而後替換舊的yaml文件)
# kubectl replace -f rc.yaml 或 # kubect edit replicationcontroller frontend
對RC使用滾動升級,來發布新功能或修復BUG
# kubectl rolling-update frontend --image=kubeguide/guestbook-php-frontend:latest
當Pod中只有一個容器時,經過–image參數指定新的Tag完成滾動升級,但若是有多個容器或其餘字段修改時,須要指定yaml文件
# kubectl rolling-update frontend -f FILE.yaml
若是在升級過程當中出現問題(如發現配置錯誤、長時間無響應),可使用CTRL+C退出,再進行回滾
# kubectl rolling-update frontend --image=kubeguide/guestbook-php-frontend:latest --rollback
但若是升級完成後出現問題(好比新版本程序出core),此命令就無能爲力了。咱們須要使用一樣方法,利用原來的鏡像,「升級」爲舊版本。
k8s是一個高速發展的項目,在新的版本中,官方推薦使用Replica Set和Deployment來代替RC。那麼它們優點在哪裏,咱們來看一看:
RC只支持基於等式的selector(env=dev或environment!=qa),但Replica Set還支持新的,基於集合的selector(version in (v1.0, v2.0)或env notin (dev, qa)),這對複雜的運維管理很方便。
使用Deployment升級Pod,只須要定義Pod的最終狀態,k8s會爲你執行必要的操做,雖然可以使用命令# kubectl rolling-update
完成升級,但它是在客戶端與服務端屢次交互控制RC完成的,因此REST API中並無rolling-update的接口,這爲定製本身的管理系統帶來了一些麻煩。
Deployment擁有更加靈活強大的升級、回滾功能。
目前,Replica Set與RC的區別只是支持的selector不一樣,後續確定會加入更多功能。Deployment使用了Replica Set,它是更高一層的概念。除非用戶須要自定義升級功能或根本不須要升級Pod,在通常狀況下,咱們推薦使用Deployment而不直接使用Replica Set。
Deployment的一些基礎命令。
$ kubectl describe deployments #查詢詳細信息,獲取升級進度
$ kubectl rollout pause deployment/nginx-deployment2 #暫停升級
$ kubectl rollout resume deployment/nginx-deployment2 #繼續升級
$ kubectl rollout undo deployment/nginx-deployment2 #升級回滾
$ kubectl scale deployment nginx-deployment --replicas 10 #彈性伸縮Pod數量
使用子命令create,建立Deployment
# kubectl create -f deployment.yaml --record
注意–record參數,使用此參數將記錄後續建立對象的操做,方便管理與問題追溯
使用子命令edit,編輯spec.replicas/spec.template.spec.container.image字段,完成deployment的擴縮容與滾動升級(這要比子命令rolling-update速度快不少)
# kubectl edit deployment hello-deployment
使用rollout history命令,查看Deployment的歷史信息
# kubectl rollout history deployment hello-deployment
上面提到RC在rolling-update升級成功後不能直接回滾,而使用Deployment卻能夠回滾到上一版本,但要加上–revision參數,指定版本號
# kubectl rollout history deployment hello-deployment --revision=2
使用rollout undo回滾到上一版本
# kubectl rollout undo deployment hello-deployment
使用–to-revision能夠回滾到指定版本
# kubectl rollout undo deployment hello-deployment --to-revision=2
在Docker中,容器中的數據是臨時的,當容器被銷燬時,其中的數據將會丟失。若是須要持久化數據,須要使用Docker數據卷掛載宿主機上的文件或者目錄到容器中。Docker中有docker Volume的概念,Docker的Volume只是磁盤中的一個目錄,生命週期不受管理。固然Docker如今也提供Volume將數據持久化存儲,但支持功能比較少(例如,對於Docker 1.7,每一個容器只容許掛載一個Volume,而且不能將參數傳遞給Volume)。
在Kubernetes中,當Pod重建的時候,數據也會丟失,Kubernetes也是經過數據卷掛載來提供Pod數據的持久化的。Kubernetes數據卷是對Docker數據卷的擴展,Kubernetes數據卷是Pod級別的,能夠用來實現Pod中容器的文件共享。Kubernetes Volume具備明確的生命週期 - 與pod相同。所以,Volume的生命週期比Pod中運行的任何容器要持久,在容器從新啓動時能夠保留數據,固然,當Pod被刪除不存在時,Volume也將消失。注意,Kubernetes支持許多類型的Volume,Pod能夠同時使用任意類型/數量的Volume。
要使用Volume,pod須要指定Volume的類型和內容(spec.volumes字段),和映射到容器的位置(spec.containers.volumeMounts字段)。
容器中的進程能夠看到Docker image和volumes組成的文件系統。Docker image處於文件系統架構的root,任何volume都映射在鏡像的特定路徑上。Volume不能映射到其餘volume上,或者硬連接到其餘volume。容器中的每一個容器必須堵路地指定他們要映射的volume。
Kubernetes支持Volume類型有:
emptyDir
使用emptyDir,當Pod分配到Node上時,將會建立emptyDir,而且只要Node上的Pod一直運行,Volume就會一直存。當Pod(無論任何緣由)從Node上被刪除時,emptyDir也同時會刪除,存儲的數據也將永久刪除。注:刪除容器不影響emptyDir。
從名稱就能夠看出,它的初始內容爲空。同一個pod中全部容器能夠讀和寫emptyDir中的相同文件。
emptyDir的用途:
示例:
apiVersion: v1
kind: Pod
metadata:
name: test-pd
spec:
containers:
- image: gcr.io/google_containers/test-webserver
name: test-container
volumeMounts:
- mountPath: /cache
name: cache-volume
volumes:
- name: cache-volume
emptyDir: {}
hostPath
hostPath容許掛載Node上的文件系統到Pod裏面去。若是Pod須要使用Node上的文件,可使用hostPath。
hostPath一般應用於:
使用此類型的Volume時需注意:
在不一樣Node上具備相同配置的Pod可能會由於宿主機上的目錄和文件不用而致使對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 #宿主機路徑
gcePersistentDisk
gcePersistentDisk能夠掛載GCE上的永久磁盤到容器,須要Kubernetes運行在GCE的VM中。與emptyDir不一樣,Pod刪除時,gcePersistentDisk被刪除,但Persistent Disk 的內容任然存在。這就意味着gcePersistentDisk可以容許咱們提早對數據進行處理,並且這些數據能夠在Pod之間「切換」。
提示:使用gcePersistentDisk,必須用gcloud或使用GCE API或UI 建立PD
建立PD
使用GCE PD與pod以前,須要建立它
gcloud compute disks create --size=500GB --zone=us-central1-a my-data-disk
示例
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
# This GCE PD must already exist.
gcePersistentDisk:
pdName: my-data-disk
fsType: ext4
awsElasticBlockStore
awsElasticBlockStore能夠掛載AWS上的EBS盤到容器,須要Kubernetes運行在AWS的EC2上。與emptyDir Pod被刪除狀況不一樣,Volume僅被卸載,內容將被保留。這就意味着awsElasticBlockStore可以容許咱們提早對數據進行處理,並且這些數據能夠在Pod之間「切換」。
提示:必須使用aws ec2 create-volumeAWS API 建立EBS Volume,而後才能使用。
建立EBS Volume
在使用EBS Volume與pod以前,須要建立它。
aws ec2 create-volume --availability-zone eu-west-1a --size 10 --volume-type gp2
AWS EBS配置示例
apiVersion: v1 kind: Pod metadata: name: test-ebs spec: containers: - image: gcr.io/google_containers/test-webserver name: test-container volumeMounts: - mountPath: /test-ebs name: test-volume volumes: - name: test-volume # This AWS EBS volume must already exist. awsElasticBlockStore: volumeID: <volume-id> fsType: ext4
NFS
NFS 是Network File System的縮寫,即網絡文件系統。Kubernetes中經過簡單地配置就能夠掛載NFS到Pod中,而NFS中的數據是能夠永久保存的,同時NFS支持同時寫操做。Pod被刪除時,Volume被卸載,內容被保留。這就意味着NFS可以容許咱們提早對數據進行處理,並且這些數據能夠在Pod之間相互傳遞。
iSCSI
iscsi容許將現有的iscsi磁盤掛載到咱們的pod中,和emptyDir不一樣的是,刪除Pod時會被刪除,但Volume只是被卸載,內容被保留,這就意味着iscsi可以容許咱們提早對數據進行處理,並且這些數據能夠在Pod之間「切換」。
flocker
Flocker是一個開源的容器集羣數據卷管理器。它提供各類存儲後端支持的數據卷的管理和編排。
glusterfs
glusterfs,容許將Glusterfs(一個開源網絡文件系統)Volume安裝到pod中。不一樣於emptyDir,Pod被刪除時,Volume只是被卸載,內容被保留。味着glusterfs可以容許咱們提早對數據進行處理,並且這些數據能夠在Pod之間「切換」。
RBD
RBD容許Rados Block Device格式的磁盤掛載到Pod中,一樣的,當pod被刪除的時候,rbd也僅僅是被卸載,內容保留,rbd可以容許咱們提早對數據進行處理,並且這些數據能夠在Pod之間「切換」。
cephfs
cephfs Volume能夠將已經存在的CephFS Volume掛載到pod中,與emptyDir特色不一樣,pod被刪除的時,cephfs僅被被卸載,內容保留。cephfs可以容許咱們提早對數據進行處理,並且這些數據能夠在Pod之間「切換」。
提示:可使用本身的Ceph服務器運行導出,而後在使用cephfs。
gitRepo
gitRepo volume將git代碼下拉到指定的容器路徑中。
示例:
apiVersion: v1
kind: Pod
metadata:
name: server
spec:
containers:
- image: nginx
name: nginx
volumeMounts:
- mountPath: /mypath
name: git-volume
volumes:
- name: git-volume
gitRepo:
repository: "git@somewhere:me/my-git-repository.git"
revision: "22f1d8406d464b0c0874075539c1f2e96c253775"
secret
secret volume用於將敏感信息(如密碼)傳遞給pod。能夠將secrets存儲在Kubernetes API中,使用的時候以文件的形式掛載到pod中,而不用鏈接api。 secret volume由tmpfs(RAM支持的文件系統)支持。
persistentVolumeClaim
persistentVolumeClaim用來掛載持久化磁盤的。PersistentVolumes是用戶在不知道特定雲環境的細節的狀況下,實現持久化存儲(如GCE PersistentDisk或iSCSI卷)的一種方式。
downwardAPI
經過環境變量的方式告訴容器Pod的信息
projected
Projected volume將多個Volume源映射到同一個目錄
目前,能夠支持如下類型的卷源:
全部卷源都要求與pod在同一命名空間中。
示例
apiVersion: v1
kind: Pod
metadata:
name: volume-test
spec:
containers:
- name: container-test
image: busybox
volumeMounts:
- name: all-in-one
mountPath: "/projected-volume"
readOnly: true
volumes:
- name: all-in-one
projected:
sources:
- secret:
name: mysecret
items:
- key: username
path: my-group/my-username
- downwardAPI:
items:
- path: "labels"
fieldRef:
fieldPath: metadata.labels
- path: "cpu_limit"
resourceFieldRef:
containerName: container-test
resource: limits.cpu
- configMap:
name: myconfigmap
items:
- key: config
path: my-group/my-config
apiVersion: v1
kind: Pod
metadata:
name: volume-test
spec:
containers:
- name: container-test
image: busybox
volumeMounts:
- name: all-in-one
mountPath: "/projected-volume"
readOnly: true
volumes:
- name: all-in-one
projected:
sources:
- secret:
name: mysecret
items:
- key: username
path: my-group/my-username
- secret:
name: mysecret2
items:
- key: password
path: my-group/my-password
mode: 511
FlexVolume
alpha功能
AzureFileVolume
AzureFileVolume用於將Microsoft Azure文件卷(SMB 2.1和3.0)掛載到Pod中。
AzureDiskVolume
Azure是微軟提供的公有云服務,若是使用Azure上面的虛擬機來做爲Kubernetes集羣使用時,那麼能夠經過AzureDisk這種類型的卷插件來掛載Azure提供的數據磁盤。
vsphereVolume
須要條件:配置了vSphere Cloud Provider的Kubernetes。
vsphereVolume用於將vSphere VMDK Volume掛載到Pod中。卸載卷後,內容將被保留。它同時支持VMFS和VSAN數據存儲。
重要提示:使用POD以前,必須使用如下方法建立VMDK。
建立一個VMDK卷
vmkfstools -c 2G /vmfs/volumes/DatastoreName/volumes/myDisk.vmdk
shell vmware-vdiskmanager -c -t 0 -s 40GB -a lsilogic myDisk.vmdk
示例
apiVersion: v1
kind: Pod
metadata:
name: test-vmdk
spec:
containers:
- image: gcr.io/google_containers/test-webserver
name: test-container
volumeMounts:
- mountPath: /test-vmdk
name: test-volume
volumes:
- name: test-volume
# This VMDK volume must already exist.
vsphereVolume:
volumePath: "[DatastoreName] volumes/myDisk"
fsType: ext4
Quobyte
在kubernetes中使用Quobyte存儲,須要提早部署Quobyte軟件,要求必須是1.3以及更高版本,而且在kubernetes管理的節點上面部署Quobyte客戶端。
PortworxVolume
Portworx能把你的服務器容量進行蓄積(pool),將你的服務器或者雲實例變成一個聚合的高可用的計算和存儲節點。
PortworxVolume能夠經過Kubernetes動態建立,也能夠在Kubernetes pod中預先配置和引用。示例:
apiVersion: v1 kind: Pod metadata: name: test-portworx-volume-pod spec: containers: - image: gcr.io/google_containers/test-webserver name: test-container volumeMounts: - mountPath: /mnt name: pxvol volumes: - name: pxvol # This Portworx volume must already exist. portworxVolume: volumeID: "pxvol" fsType: "<fs-type>"
ScaleIO
ScaleIO是一種基於軟件的存儲平臺(虛擬SAN),可使用現有硬件來建立可擴展共享塊網絡存儲的集羣。ScaleIO卷插件容許部署的pod訪問現有的ScaleIO卷(或者能夠爲持久卷聲明動態配置新卷,請參閱 Scaleio Persistent Volumes)。
示例:
apiVersion: v1
kind: Pod
metadata:
name: pod-0
spec:
containers:
- image: gcr.io/google_containers/test-webserver
name: pod-0
volumeMounts:
- mountPath: /test-pd
name: vol-0
volumes:
- name: vol-0
scaleIO:
gateway: https://localhost:443/api
system: scaleio
volumeName: vol-0
secretRef:
name: sio-secret
fsType: xfs
StorageOS
StorageOS是一家英國的初創公司,給無狀態容器提供簡單的自動塊存儲、狀態來運行數據庫和其餘須要企業級存儲功能,但避免隨之而來的複雜性、剛性以及成本。
核心:是StorageOS向容器提供塊存儲,可經過文件系統訪問。
StorageOS容器須要64位Linux,沒有額外的依賴關係,提供免費開發許可證。
安裝說明,請參閱StorageOS文檔
apiVersion: v1
kind: Pod
metadata:
labels:
name: redis
role: master
name: test-storageos-redis
spec:
containers:
- name: master
image: kubernetes/redis:v1
env:
- name: MASTER
value: "true"
ports:
- containerPort: 6379
volumeMounts:
- mountPath: /redis-master-data
name: redis-data
volumes:
- name: redis-data
storageos:
# The `redis-vol01` volume must already exist within StorageOS in the `default` namespace.
volumeName: redis-vol01
fsType: ext4
有關動態配置和持久卷聲明的更多信息,請參閱StorageOS示例。
Local
目前處於 Kubernetes 1.7中的 alpha 級別。
Local 是Kubernetes集羣中每一個節點的本地存儲(如磁盤,分區或目錄),在Kubernetes1.7中kubelet能夠支持對kube-reserved和system-reserved指定本地存儲資源。
經過上面的這個新特性能夠看出來,Local Storage同HostPath的區別在於對Pod的調度上,使用Local Storage能夠由Kubernetes自動的對Pod進行調度,而是用HostPath只能人工手動調度Pod,由於Kubernetes已經知道了每一個節點上kube-reserved和system-reserved設置的本地存儲限制。
示例:
apiVersion: v1
kind: PersistentVolume
metadata:
name: example-pv
annotations:
"volume.alpha.kubernetes.io/node-affinity": '{
"requiredDuringSchedulingIgnoredDuringExecution": {
"nodeSelectorTerms": [
{ "matchExpressions": [
{ "key": "kubernetes.io/hostname",
"operator": "In",
"values": ["example-node"]
}
]}
]}
}'
spec:
capacity:
storage: 100Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Delete
storageClassName: local-storage
local:
path: /mnt/disks/ssd1
請注意,本地PersistentVolume須要手動清理和刪除。
有關local卷類型的詳細信息,請參閱 Local Persistent Storage user guide
Using subPath
有時,能夠在一個pod中,將同一個卷共享,使其有多個用處。volumeMounts.subPath特性能夠用來指定卷中的一個子目錄,而不是直接使用卷的根目錄。
如下是使用單個共享卷的LAMP堆棧(Linux Apache Mysql PHP)的pod的示例。HTML內容映射到其html文件夾,數據庫將存儲在mysql文件夾中:
apiVersion: v1
kind: Pod
metadata:
name: my-lamp-site
spec:
containers:
- name: mysql
image: mysql
volumeMounts:
- mountPath: /var/lib/mysql
name: site-data
subPath: mysql
- name: php
image: php
volumeMounts:
- mountPath: /var/www/html
name: site-data
subPath: html
volumes:
- name: site-data
persistentVolumeClaim:
claimName: my-lamp-site-data
Resources
emptyDir Volume的存儲介質(Disk,SSD等)取決於kubelet根目錄(如/var/lib/kubelet)所處文件系統的存儲介質。不限制emptyDir或hostPath Volume使用的空間大小,不對容器或Pod的資源隔離。
Service是定義一系列Pod以及訪問這些Pod的策略的一層抽象。由於Service是抽象的,因此在圖表裏一般看不到它們的存在。
Service經過Label找到Pod組。當你在Service的yaml文件中定義了該Service的selector中的label爲app:my-web,那麼這個Service會將Pod-->metadata-->labeks中label爲app:my-web的Pod做爲分發請求的後端。當Pod發生變化時(增長、減小、重建等),Service會及時更新。這樣一來,Service就能夠做爲Pod的訪問入口,起到代理服務器的做用,而對於訪問者來講,經過Service進行訪問,無需直接感知Pod。
Service的目標是提供一種橋樑, 它會爲訪問者提供一個固定訪問地址,用於在訪問時重定向到相應的後端,這使得非 Kubernetes原生應用程序,在無須爲Kubemces編寫特定代碼的前提下,輕鬆訪問後端。
須要注意的是,Kubernetes分配給Service的固定IP是一個虛擬IP,並非一個真實的IP,在外部是沒法尋址的。真實的系統實現上,Kubernetes是經過Kube-proxy組件來實現的虛擬IP路由及轉發。因此在以前集羣部署的環節上,咱們在每一個Node上均部署了Proxy這個組件,從而實現了Kubernetes層級的虛擬轉發網絡。有一個特別類型的Kubernetes Service,稱爲'LoadBalancer',做爲外部負載均衡器使用,在必定數量的Pod之間均衡流量。好比,對於負載均衡Web流量頗有用。
如今,假定有2個後臺Pod,而且定義後臺Service的名稱爲‘backend-service’,lable選擇器爲(tier=backend, app=myapp)。backend-service 的Service會完成以下兩件重要的事情:
Service代理外部服務
Service不只能夠代理Pod,還能夠代理任意其餘後端,好比運行在Kubernetes外部Mysql、Oracle等。這是經過定義兩個同名的service和endPoints來實現的。示例以下:
redis-service.yaml
apiVersion: v1
kind: Service
metadata:
name: redis-service
spec:
ports:
- port: 6379
targetPort: 6379
protocol: TCP
redis-endpoints.yaml
apiVersion: v1
kind: Endpoints
metadata:
name: redis-service
subsets:
- addresses:
- ip: 10.0.251.145
ports:
- port: 6379
protocol: TCP
基於文件建立完Service和Endpoints以後,在Kubernetes的Service中便可查詢到自定義的Endpoints。
[root@k8s-master demon]# kubectl describe service redis-service Name: redis-service Namespace: default Labels: <none> Selector: <none> Type: ClusterIP IP: 10.254.52.88 Port: <unset> 6379/TCP Endpoints: 10.0.251.145:6379 Session Affinity: None No events. [root@k8s-master demon]# etcdctl get /skydns/sky/default/redis-service {"host":"10.254.52.88","priority":10,"weight":10,"ttl":30,"targetstrip":0}
Service內部負載均衡
當Service的Endpoints包含多個IP的時候,及服務代理存在多個後端,將進行請求的負載均衡。默認的負載均衡策略是輪訓或者隨機(有kube-proxy的模式決定)。同時,Service上經過設置Service-->spec-->sessionAffinity=ClientIP,來實現基於源IP地址的會話保持。
發佈Service
Service的虛擬IP是由Kubernetes虛擬出來的內部網絡,外部是沒法尋址到的。可是有些服務又須要被外部訪問到,例如web前段。這時候就須要加一層網絡轉發,即外網到內網的轉發。Kubernetes提供了NodePort、LoadBalancer、Ingress三種方式。
servicede 自發性機制
Kubernetes中有一個很重要的服務自發現特性。一旦一個service被建立,該service的service IP和service port等信息均可以被注入到pod中供它們使用。Kubernetes主要支持兩種service發現 機制:環境變量和DNS。
環境變量方式
Kubernetes建立Pod時會自動添加全部可用的service環境變量到該Pod中,若有須要.這些環境變量就被注入Pod內的容器裏。須要注意的是,環境變量的注入只發送在Pod建立時,且不會被自動更新。這個特色暗含了service和訪問該service的Pod的建立時間的前後順序,即任何想要訪問service的pod都須要在service已經存在後建立,不然與service相關的環境變量就沒法注入該Pod的容器中,這樣先建立的容器就沒法發現後建立的service。
DNS方式
Kubernetes集羣如今支持增長一個可選的組件——DNS服務器。這個DNS服務器使用Kubernetes的watchAPI,不間斷的監測新的service的建立併爲每一個service新建一個DNS記錄。若是DNS在整個集羣範圍內均可用,那麼全部的Pod都可以自動解析service的域名。
多個service如何避免地址和端口衝突
此處設計思想是,Kubernetes經過爲每一個service分配一個惟一的ClusterIP,因此當使用ClusterIP:port的組合訪問一個service的時候,無論port是什麼,這個組合是必定不會發生重複的。另外一方面,kube-proxy爲每一個service真正打開的是一個絕對不會重複的隨機端口,用戶在service描述文件中指定的訪問端口會被映射到這個隨機端口上。這就是爲何用戶能夠在建立service時隨意指定訪問端口。
service目前存在的不足
Kubernetes使用iptables和kube-proxy解析service的人口地址,在中小規模的集羣中運行良好,可是當service的數量超過必定規模時,仍然有一些小問題。首當其衝的即是service環境變量氾濫,以及service與使用service的pod二者建立時間前後的制約關係。目前來看,不少使用者在使用Kubernetes時每每會開發一套本身的Router組件來替代service,以便更好地掌控和定製這部分功能。