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,以便更好地掌控和定制这部分功能。