Kubernetes学习笔记(3)-Service与数据存储
Service
介绍
在Kubernetes中,Pod是应用程序的载体,我们可以通过Pod的ip来访问应用程序。但是Pod的ip地址不是固定的,这也就意味着不方便直接采用Pod的Ip对服务进行访问。
为了解决这个问题,Kubernetes提供了Service这种类型的Resource。Service会对提供同一个服务的多个Pod进行聚合,并且提供一个统一的入口地址。通过访问Service的入口地址就能访问到后面的Pod服务。
事实上,Service在很多情况下只是一个概念,真正起作用的其实是kube-proxy服务进程。每个Node节点上都运行着一个kube-proxy服务进程。当创建Service的时候,Kubernetes通过Api-Server向etcd写入创建的Service的信息,而kube-proxy会基于监听的机制来发现这种Service的变动,之后它会将最新的Service信息转换成对应的访问规则。
下面是Service的资源清单描述:
1 |
|
其中type表示Service的类型,可选值有:
ClusterIP
:默认类型。这种Service只能在集群内部,通过Kubernetes系统自动分配的虚拟IP访问NodePort
:将Service通过指定的Node上的端口暴露给外部,通过此方法,就可以在集群外部访问服务LoadBalancer
:使用外接负载均衡器完成到服务的负载分发,注意此模式需要外部云环境支持ExternalName
: 把集群外部的服务引入集群内部,直接使用
ClusterIP
一个ClusterIP类型的Service,对应配置文件示例如下,其中直接指定type为ClusterIP,并通过Label Selector来决定代理Pod的范围。
1 |
|
Service配置文件中的Selector描述可以对应到一系列Pod,在Kubernetes中用Endpoint来描述这种对应关系。Endpoint是Kubernetes中的一个资源对象,存储在etcd中,用来记录一个Service对应的所有Pod的访问地址。这也就是说,Service和Pod之间的联系是通过Endpoints来实现的,一个Service由一组Pod组成,这些Pod通过Endpoints暴露出来。
默认情况下,对于Service的访问会转发到后面真实的Pod上,转发策略默认使用kube-proxy的策略,例如随机,轮询等。不过Kubernetes中也提供了基于客户端地址的会话保持模式,可以通过设置spec.sessionAffinity:ClientIP
来开启。在这种模式下,来自同一个客户端发起的所有请求都会转发到固定的一个Pod上。
当然在某些场景中,开发人员可能不想使用Service提供的负载均衡功能,而希望自己来控制负载均衡策略。针对这种情况,Kubernetes提供了HeadLiness
Service,这类Service不会分配Cluster
IP,如果想要访问Service,只能通过Service的域名进行查询。要创建一个HeadLiness
Service,只需要在配置文件中指定spec.type
为ClusterIP,同时指定spec.clusterIP
为None即可。
NodePort
ClusterIP类型的Service只能在集群内部访问,如果希望将Service暴露给集群外部使用,则需要NodePort类型的Service。NodePort的工作原理实际上就是将service的端口映射到Node的一个端口上,然后就可以通过NodeIp:NodePort
来访问Service了。
一个NodePort的配置文件示例:
1 |
|
LoadBalancer
LoadBalancer和NodePort很相似,目的都是向外部暴露一个端口,区别在于LoadBalancer会在集群的外部再来做一个负载均衡设备,而这个设备需要外部环境支持。外部服务发送到这个设备上的请求,会被设备负载之后转发到集群中。
ExternalName
ExternalName类型的Service用于引入集群外部的服务,它通过externalName
属性指定外部一个服务的地址,然后在集群内部访问此service就可以访问到外部的服务了。
数据存储
介绍
在Kubernetes中,容器的生命周期可能很短,会被频繁地创建和销毁。容器在被销毁时,保存在其中的数据也会被清除。Kubernetes引入Volume的概念来持久化保存容器中的数据。
Volume
是Pod中能够被多个容器访问的共享目录,它被定义在Pod上(在Pod的配置文件中声明),然后被一个Pod里的多个容器挂载到具体的文件目录下。Kubernetes通过Volume实现同一个Pod中不同容器之间的数据共享以及数据的持久化存储。Volume的生命容器不与Pod中单个容器的生命周期相关,当容器终止或者重启时,Volume中的数据也不会丢失。
kubernetes的Volume支持多种类型,比较常见的有下面几个:
- 简单存储:EmptyDir、HostPath、NFS
- 高级存储:PV、PVC
- 配置存储:ConfigMap、Secret
基本存储
EmptyDir
EmptyDir是最基础的Volume类型,一个EmptyDir就是Host上的一个空目录。EmptyDir是在Pod被分配到Node时创建的,它的初始内容为空,并且无须指定宿主机上对应的目录文件,因为Kubernetes会自动分配一个目录,当Pod销毁时, EmptyDir中的数据也会被永久删除。 EmptyDir用途如下:
- 临时空间,例如用于某些应用程序运行时所需的临时目录,且无须永久保留
- 一个容器需要从另一个容器中获取数据的目录(多容器共享目录)
例如下面的配置文件,在Pod.spec.volumes
中声明了Volume,然后在Container的详细配置中进行对应挂载。
1 |
|
HostPath
EmptyDir中数据不会被持久化,它会随着Pod的结束而销毁,如果想简单的将数据持久化到主机中,可以选择HostPath。HostPath就是将Node主机中一个实际目录挂载到Pod中,以供容器使用,这样设计可以保证即使Pod销毁,数据依旧可以存在于Node主机上。
HostPath的使用方式与EmptyDir基本相同,只需要在声明的时候指定相关配置即可,后续Container可以用来挂载。
1 |
|
其中type的可选值如下:
DirectoryOrCreate
:目录存在就使用,不存在就先创建后使用Directory
:目录必须存在FileOrCreate
:文件存在就使用,不存在就先创建后使用File
:文件必须存在Socket
:unix套接字必须存在CharDevice
:字符设备必须存在BlockDevice
:块设备必须存在
NFS
HostPath可以解决数据持久化的问题,但是一旦Node节点故障了,或者Pod转移到了别的节点,就又会出现问题。此时需要准备单独的网络存储系统,比较常用的有NFS、CIFS。在Volume中也可以直接配置NFS相关的存储系统。
1 |
|
高级存储
Kubernetes支持的存储系统有很多,每种存储系统可能有互不相同的配置,学习成本较高。而为了能够屏蔽底层存储实现的细节,方便用户使用, Kubernetes引入PV和PVC两种资源对象。
PV(Persistent Volume)
指持久化卷,是对底层的共享存储的一种抽象。一般情况下PV由Kubernetes管理员进行创建和配置,它与底层具体的共享存储技术有关,并通过插件完成与共享存储的对接。
PVC(Persistent Volume Claim)
指持久卷声明,是用户对于存储需求的一种声明。换句话说,PVC其实就是用户向Kubernetes系统发出的一种资源需求申请。
PV和PVC是一一对应的,整个使用过程通常会经过下面一些阶段:
资源供应:首先由管理员手动创建底层存储和PV
资源绑定:用户创建PVC,Kubernetes负责根据PVC的声明去寻找PV,并进行绑定。
- 一旦找到,就将该PV与用户定义的PVC进行绑定,用户的应用就可以使用这个PVC了PV一旦绑定到某个PVC上,就会被这个PVC独占,不能再与其他PVC进行绑定了
- 如果找不到,PVC则会无限期处于Pending状态,直到等到系统管理员创建了一个符合其要求的PV
资源使用:用户可在Pod中像Volume一样使用PVC,将PVC挂载到容器内的某个路径进行使用。
资源释放:用户删除PVC来释放PV。当存储资源使用完毕后,用户可以删除PVC,与该PVC绑定的PV将会被标记为“已释放”,但还不能立刻与其他PVC进行绑定。通过之前PVC写入的数据可能还被留在存储设备上,只有在清除之后该PV才能再次使用。
资源回收:Kubernetes根据PV设置的回收策略进行资源的回收。对于PV,管理员可以设定回收策略,用于设置与之绑定的PVC释放资源之后如何处理遗留数据的问题。只有PV的存储空间完成回收,才能供新的PVC绑定和使用。
配置存储
ConfigMap
ConfigMap是一种比较特殊的存储卷,它的主要作用是存储配置信息。
ConfigMap也属于一种Resource,例如可以通过如下配置文件创建一个ConfigMap:
1 |
|
注意这里的
|
竖线。在yaml中竖线表示保留文本块中的换行符,因此这里的含义是向data.info
传递了username:admin\npassword:123456
。
创建之后可以通过describe命令查看详情:
1 |
|
创建好了之后,就可以像正常使用Volume的步骤一样,使用ConfigMap。例如现在我们创建一个Pod,在其中挂载ConfigMap,对应的配置文件如下:
1 |
|
通过进入这个Pod,我们可以发现,ConfigMap对应目录到目录/configmap/config
,并且在该目录下有两个文件info, myConfig
,并且这两个文件的内容对应就是yaml配置文件中的值。
1 |
|
实际上ConfigMap的核心就在于配置文件中的data
字段。在data字段中允许我们以键值对的形式传入内容,并且每个键值对最终会对应到目录下的一个文件,其中Key是文件名称,Value是文件中的内容。并且如果我们更新ConfigMap的内容,Pod中的值也会动态更新。
Secret
Secret与ConfigMap非常类似,它可以完成自动解码,主要用于存储敏感信息,例如密码、秘钥、证书等等。