资料
背景
资源和对象
Kubernetes 中的所有内容都被抽象为“资源”,如 Pod、Service、Node 等都是资源。“对象”就是“资源”的实例,是持久化的实体。如某个具体的 Pod、某个具体的 Node。Kubernetes 使用这些实体去表示整个集群的状态。
对象的创建、删除、修改都是通过 “Kubernetes API”,也就是 “Api Server” 组件提供的 API 接口,这些是 RESTful 风格的 Api,与 k8s 的“万物皆对象”理念相符。命令行工具 “kubectl”,实际上也是调用 kubernetes api。
K8s 中的资源类别有很多种,kubectl 可以通过配置文件来创建这些 “对象”,配置文件更像是描述对象“属性”的文件,配置文件格式可以是 “JSON” 或 “YAML”,常用 “YAML”。
ps: 本文不会刻意说 “对象” 这一词,对于某个具体的 Pod、Node,有时候可能也说成是 “资源”,这其实也是合理的,对象是资源的实例,所以对象也是资源,不必要钻牛角尖,理解意思即可。
对象规约(Spec)和状态(Status)
对象是用来完成一些任务的,是持久的,是有目的性的,因此 kubernetes 创建一个对象后,将持续地工作以确保对象存在。当然,kubernetes 并不只是维持对象的存在这么简单,kubernetes 还管理着对象的方方面面。每个Kubernetes对象包含两个嵌套的对象字段,它们负责管理对象的配置,他们分别是 “spec” 和 “status” 。
- “spec” 是 “规约”、“规格” 的意思,spec 是必需的,它描述了对象的期望状态(Desired State)—— 希望对象所具有的特征。当创建 Kubernetes 对象时,必须提供对象的规约,用来描述该对象的期望状态,以及关于对象的一些基本信息(例如名称)。以 Pod 为例,如下是一个简单的创建 Pod 的 yaml 文件模板:
apiVersion: v1 kind: Pod metadata: name: myapp-pod labels: app: myapp spec: containers: - name: myapp-container image: busybox command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 3600']
上面的模板描述了一个对象,对象的类型是 “Pod”,对象名为 “myapp-pod”,包含一个 “app: myapp” 标签。“spec” 指定了该 Pod 对象的特征——对象包含一个名为 “myapp-container” 的容器,容器根据 “busybox” 镜像生成,容器运行的命令是 “ ['sh', '-c', 'echo Hello Kubernetes! && sleep 3600'] ”。
除 “spec” 字段外,在创建一个Pod及Pod的控制器对象时,还要像上面模板所示一样,还要有这三个字段:
“apiVersion”——“创建该对象所使用的 Kubernetes API 的版本”;
“kind”——“想要创建的对象的类型”;
“metadata”——“帮助识别对象唯一性的数据,包括一个 name 字符串、UID 和可选的 namespace。”
- status 描述了对象的 实际状态(Actual State) ,它是由 Kubernetes 系统提供和更新的。在任何时刻,Kubernetes 控制面一直努力地管理着对象的实际状态以与期望状态相匹配。
对象的常用属性
name和uid
k8s 中每个对象都有 uid ,uid 是 k8s 自动为对象生成的,可以唯一标识该对象的字符串。uid 是用于给 k8s 本身管理对象的标识,对人类来说其可读性太差,因此对象还具有另一个属性 —— 可读性相对更好的,有一定意义的 “名称” 。在创建对象时可以给对象指定名称。不属于同一类别的对象可以有相同的名称,而同一种类型的对象,想要赋予相同的名称,则需要用到 namespace。
NameSpace
很多地方都有 namespace 的概念,如 Linux 中的 namespace 、C++ 中的 namespace 等等。 C++ 用 namespace 来解决命名冲突(两个不同的 namespace 可以存在同名的类),k8s 中 的 namespace 也有这样的作用——不同的 namespace 中可以存在同名的资源对象(即使这些对象是相同的类型)。然而,k8s 中的 namespace,更多的是为了提高资源的管理效率。
在 k8s 中, namespace (命名空间) 也称为虚拟集群。namespace 用来在逻辑上对资源进行分组(是的,namespace 用来给资源分组,namespace 本身也是资源...)。怎样个分组法?譬如,一个 k8s 集群上部署两个应用——一个是商城,叫 sMall;另一个是视频类应用,叫 iQipa。那么可以创建两个 namespace,然后给前者所有资源分配名为 “sMall” 的 namespace,后者分配 “iQipa”,这样,两个不同的项目各自管理自己的资源,互不干扰。
可以用 “kubectl get” 命令罗列在集群中存在的某一类资源的对象,例如想要获取 “sMall” 的所有 pod,可以输入命令:
kubectl get pods --namespace=sMall
对应的,如果想要获取 iQipa 的 service,则输入命令
kubectl get services --namespace=iQipa
k8s 集群搭建好后,会创建一个名为 "default" 的 namespace,当没有为资源明确指定 namespace 时,会默认分配该 namespace。kubernetes 的组件,分配的是名为 “kube-system” 的 namespace。
命名空间为名称提供了一个范围。对象的名称需要在命名空间内是唯一的,但不能跨命名空间。命名空间不能相互嵌套,每个 Kubernetes 对象只能在一个命名空间中。大多数 kubernetes 资源的对象(例如 Pod、Service、副本控制器等)都位于某些命名空间中。但是命名空间资源本身并不在命名空间中。而且底层资源,例如 nodes 和持久化卷不属于任何命名空间。可以使用命令查看哪些资源在 namespace 中,哪些不在:
# 列出在命名空间中的资源
kubectl api-resources --namespaced=true
# 列出不在命名空间中的资源
kubectl api-resources --namespaced=false
更多资料:
label和selector
label (标签)是附加到 Kubernetes 对象(比如 Pods)上的键值对,用于区分对象(比如Pod、Service)。 label 旨在用于指定对用户有意义且相关的对象的标识属性,但不直接对核心系统有语义含义。 label 可以用于组织和选择对象的子集。label 可以在创建时附加到对象,随后可以随时添加和修改。可以像 namespace 一样,使用 label 来获取某类对象,但 label 可以与 selector 一起配合使用,用表达式对条件加以限制,实现更精确、更灵活的资源查找。
label 与 selector 配合,可以实现对象的“关联”,“Pod 控制器” 与 Pod 是相关联的 —— “Pod 控制器”依赖于 Pod,可以给 Pod 设置 label,然后给“控制器”设置对应的 selector,这就实现了对象的关联。
每个对象都可以定义一组键/值标签。每个键对于给定对象必须是唯一的。如:
"metadata": {
"labels": {
"app1" : "iQipa",
"app2" : "sMall"
}
}
更多资料:
对象信息的获取
“Kubectl” 这个命令行工具提供了与 k8s 交互的接口,可以通过 kubectl 来创建、更改、查看、删除对象,这里只稍微讲解下对象信息的获取,其它放到 Kubectl 有关的文章中再介绍。要查看当前 k8s 集群中存在的某一类资源,可以使用 kubectl 的 “get” 选项:
kubectl get <resource_type> --namespace=<namespace>
参数说明:
-
<resource_type> 就是资源的类别,可以是 pod、node 或其它所有类别的名称。这里可以输入资源的单数形式、复数形式,比如 “pod” 还可以写成 “pods”;对于稍微长一点的资源名,还可以使用缩写,比如 “service”,可以输入其缩写 “svc”。
-
<namespace> <namespace>后面的 “=” 可有可无。namespace 是对象所在的 namespace,namespace 可以看做是对象的分组的组名,下文会简单介绍。k8s 集群初始化后会创建名为 “default” 的 namespace,在创建对象时如果没有指定 namespace,默认使用这个 namespace。如果在使用 “kubectl get” 时不指定 “--namespace”这个参数,获取的是 “default” namespace 下的对象。 另外 “--namespace” 可以简写成 “-n”,如果想获取所有 namespace 下的对象,则可以写成 “--all-namespaces”。
几个示例:
- 查看集群中存在的所有 namespace
kubectl get namespace
- 查看当前集群下所有存在的 node ( node 不在 namespace 中)
kubectl get node
- 查看当前存在的所有 pod
kubectl get pods --all-namespaces
- 查看“kube-system”下所有的service
kubectl get svc -n kube-system
“get” 选项只是罗列出资源对象而已,如果想要查看对象的具体信息,需要用 “describe”
kubectl describe <resource_type> <object_name> --namespace=<namespace>
参数说明:
-
<resource_type> 跟上面一样,可以写单复数形式、简写。<namespace> 也是一样的,可以写成 “-n”,但有一点需要注意,不能写成 “--all-namespaces”,因为如果不同 namespace 有两个同名同类别的对象,那么就出现歧义了,“--all-namespaces” 对 “kubectl describe” 是没有意义的,所以不要这样写。
-
<object_name> 就是对象的名称,也就是 “kubectl get” 命令显示的结果。
示例:
- 获取名为 “kube-apiserver”,namespace 为 “kube-system” 的 pod 的信息
kubectl describe pod kube-apiserver -n kube-system
- 获取名为 “hello” 的 node 的信息
kubectl describe node hello
小 Tips: 可以用 “kubectl explain” 来查看某类资源的作用,如 “kubectl explain pod”,不过显示的信息都是一两句话带过。。不然我也懒得写这篇。。(;′⌒`)
更多资料:
资源种类
接下来开始正式介绍 k8s 的各种资源。
Pod
Pod 是最小的可部署的 Kubernetes 对象模型。Pod 表示集群上正在运行的进程。一个 Pod 由一个或多个容器组成,Pod 中容器共享存储和网络,在同一台 Docker 主机上运行。在 kubernetes 中,若要运行一个容器,则必须先创建 pod,让容器在 pod 中运行,可以把 Pod 看成是容器的运行环境。
Docker 是 Kubernetes Pod 中最常用的容器运行时,但 Pod 也能支持其他的容器运行时,如 rtk。
Kubernetes 集群中的 Pod 可被用于以下两个主要用途:
-
运行单个容器的 Pod。”每个 Pod 一个容器”模型是最常见的 Kubernetes 用例;在这种情况下,可以将 Pod 看作单个容器的包装器,并且 Kubernetes 直接管理 Pod,而不是容器。
-
运行多个协同工作的容器的 Pod。 Pod 可能封装由多个紧密耦合且需要共享资源的共处容器组成的应用程序。 这些位于同一位置的容器可能形成单个内聚的服务单元——一个容器将文件从共享卷提供给公众,而另一个单独的“挂斗”容器则刷新或更新这些文件。 Pod 将这些容器和存储资源打包为一个可管理的实体。
上面讲对象的“规约”时已经提及 Pod 的模板文件,这里不再赘述。
Pod是容器的运行环境,而我们的应用程序是部署在容器里的,对于k8s的初学者,可以先把Pod简单地看作为应用的运行容器,把Pod看作是应用在k8s上部署的最小单位。可以简单粗暴的说“Pod就是用来部署应用的,Pod就是用来装应用的。”
Pod是不能被外网直接访问的,所以不要想着只要把应用部署到Pod就可以直接用,要想在外网访问Pod需要用到service,下文会介绍。
更多资料:
Controller(控制器)
当 Pod 被创建出来,Pod 会被调度到集群中的节点上运行,Pod 会在该节点上一直保持运行状态,直到进程终止、Pod 对象被删除、Pod 因节点资源不足而被驱逐或者节点失效为止。Pod 并不会自愈,当节点失效,或者调度 Pod 的这一操作失败了,Pod 就该被删除。如此,单单用 Pod 来部署应用,是不稳定不安全的。
Kubernetes 使用更高级的资源对象 “控制器” 来实现对Pod的管理。控制器可以为您创建和管理多个 Pod,管理副本和上线,并在集群范围内提供自修复能力。 例如,如果一个节点失败,控制器可以在不同的节点上调度一样的替身来自动替换 Pod。
先引入“副本”的概念——一个Pod可以被复制成多份,每一份可被称之为一个“副本”,这些“副本”除了一些描述性的信息(Pod的名字、uid等)不一样以外,其它信息都是一样的,譬如Pod内部的容器、容器数量、容器里面运行的应用等的这些信息都是一样的,这些副本提供同样的功能。Pod 的“控制器”通常包含一个名为 “replicas” 的属性。“replicas”属性则指定了特定Pod的副本的数量,当当前集群中该Pod的数量与该属性指定的值不一致时,k8s会采取一些策略去使得当前状态满足配置的要求。
k8s的一些Pod“控制器”可以提供Pod的“滚动更新”功能,如果你的应用升级了,譬如原来应用是v1版本,现在的版本是v2,那么可以通过仅仅一条命令或一份配置文件,让k8s来自动地滚动更新应用。k8s会删除一个v1的Pod,然后新建一个v2的Pod……这样反复交替操作,直至所有v1Pod被v2Pod代替,这样就实现了不停机的应用滚动更新。k8s会保存应用的更新记录,在需要“回滚降级”时,同样可以通过仅仅一条命令或者一个配置文件实现。
因此,虽然可以直接使用 Pod,可以直接创建Pod,但在 Kubernetes 中,更为常见的是使用控制器创建和管理 Pod。在部署应用时,“控制器” 是比简单的 Pod 更好的选择。
下面开始介绍 Pod 的各种控制器,注意,这些控制器也是 k8s 中的资源,也可以创建对象。
ReplicationController
ReplicationController 简写 “RC” 或 “RCS”。译作“副本控制器”,“Replication” 就是“复制”、“副本”的意思。ReplicationController 确保在任何时候都有特定数量的 pod 副本处于运行状态。 换句话说,ReplicationController 确保一个 pod 或一组同类的 pod 总是可用的。
当 pods 数量过多时,ReplicationController 会终止多余的 pods。当 pods 数量太少时,ReplicationController 将会启动新的 pods。 与手动创建的 pod 不同,由 ReplicationController 创建的 pods 在失败、被删除或被终止时会被自动替换。
下面给出一份生成 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
来看下配置文件,该文件描述了一个资源对象,它有4个字段,分别是 “apiVersion”、“kind”、“metadata”、“spec”。上面讲对象与“规约”时讲过,创建一个 Pod 及 Pod控制器 对象时,这四个字段是必不可少的。kind 说明这是一个 “ReplicationController” 类型的对象,metadata 说明对象名称是 “nginx”。spec 指定了这个对象的特征,关注 spec 这个字段:
-
template
在 spec 中 template 这个字段是必需的,其实这就是一个 Pod 的模板,只不过这个模板是嵌套进来的,不需要 kind 和 apiVersion 字段。再来看下这是怎样一个 Pod —— metadata 部分描述了 Pod 的名称 “nginx”,还为这个 Pod 分配了名为 “app: nginx” 的标签。spec 指定了该 Pod 由 “nginx” 镜像构建而成,容器开启了“80”端口。 -
replicas
replica就是“复制品”、“副本”的意思,“replicas: 3”就是开启三个 Pod 副本,并维护这些副本,当 Pod 出错了,就把 Pod 删掉然后创建一个新的 Pod,使得 Pod 的数量始终维持在3个,这充分提高了部署的应用的高可用性。当然,在 k8s 运行过程中某个瞬间,ReplicationController 管理的 Pod 由于种种原因,可能比设置的 replicas 的数量多,也可能少,但 ReplicationController 会采取合适的策略尽量维持 Pod 的数量。 -
selector
通过指定 ReplicationController 的 selector 和 Pod 的 “app: nginx” 标签,可以实现 ReplicationController 和 Pod 的绑定关系,ReplicationController 就是仅仅管理这些附带 “app: nginx” 标签的 Pod 而不干涉其它的 Pod。不是由 ReplicationController 本身创建的,但包含 “app: nginx” 的 Pod,也由其管理。
更多资料:
ReplicaSet
ReplicaSet 简写 “RS”,是 “Replication Controller” 的升级版。和 “ReplicationController” 一样用于确保任何给定时间指定的Pod副本数量,并提供声明式更新等功能。
RC与RS唯一区别就是lable selectore支持不同,RS支持新的基于集合的标签,RC仅支持基于等式的标签。
Deployment
Deployment是一个更高层次的API对象,他管理ReplicaSets和Pod,并提供声明式更新等功能。
官方建议使用Deployment管理ReplicaSets,而不是直接使用ReplicaSets,这就意味着可能永远不需要直接操作ReplicaSet对象。
StatefulSet
StatefulSet适合持久性的应用程序,有唯一的网络标识符(IP),持久存储,有序的部署、扩展、删除和滚动更新。
DaemonSet
Daemon 一词应该不陌生的,Daemon 进程(守护进程)、Demon 程序(守护程序)。顾名思义,DaemonSet 一般是用来部署一些特殊应用的,譬如日志应用等有“守护”意义的应用。
DaemonSet确保所有(或一些)节点运行同一个Pod(当然这里不是指“同一个”,而是和副本一样的概念,当然不可能多个节点运行“同一个”Pod,它又不是量子态)。当节点加入kubernetes集群中,Pod会被调度到该节点上运行,当节点从集群中移除时,DaemonSet的Pod会被删除。删除DaemonSet会清理它所有创建的Pod。
Job
一次性任务,运行完成后Pod销毁,不再重新启动新容器。
CronJob
CronJob 是在 Job 基础上加上了定时功能。
HorizontalPodAutoscaling
更多资料:
------------------------以上都是 Pod 的 Controller---------------------
Service
“Service” 简写 “svc”。如上文提到的,Pod不能直接提供给外网访问,而是应该使用service。Service就是把Pod暴露出来提供服务,Service才是真正的“服务”,它的中文名就叫“服务”。o( ̄︶ ̄)o
按照百度上找到的更专业的的说法,可以说Service是一个应用服务的抽象,定义了Pod逻辑集合和访问这个Pod集合的策略。Service代理Pod集合,对外表现为一个访问入口,访问该入口的请求将经过负载均衡,转发到后端Pod中的容器。
Pod只是运行应用的容器,只是简单地提供某种“功能”,不能称之为“服务”。而service不一样,service是对Pod访问方式的抽象,service利用Pod的“功能”,利用“Pod”的能动性,通过路由转发和负载均衡,对外提供真正意义上的“服务”。
k8s使用service还有一个原因。一般而言,k8s每创建一个新的Pod,它的ip地址都是不一样的(当然,你可以设置固定ip,但这样并不妥当,程序员都喜欢“解耦”,而这么做显然是与该理念背道而驰了),如果一个Pod因为某些问题挂了,k8s创建了一个新的Pod,这时ip地址不一样了,那它还怎么提供功能?这时,Service意义就出来了,一个Service与特定的一个或者一组Pod挂钩,即使Pod挂掉了,k8s又创建了新的特定的Pod,Service仍然与这个新的Pod挂钩,这样,Pod的ip不一样了,哪怕端口也不一样了,仍然能通过Service来获取Pod所提供的服务。
Service是如何保持这种与特定Pod绑定的关系的呢?那就是“Label”和“Label Selector”,可以给Pod分配特定的Label,然后配置Service,通过“Lable Selector”选择具有这些特定“Label”的Pod来接受请求、提供服务。
默认情况下,在创建service对象的时候,如果不指定service的访问方式,service被配置为ClusterIp模式,在该模式下,只有集群内部的网络才能访问到该service,要想真正的实现外网访问service,需要把service访问方式配置为NodePort或其它。
更多资料:
以下内容待更…………
Volume
数据卷,共享Pod中容器使用的数据。用来放持久化的数据,比如数据库数据。
Secret
用来存放一些隐秘的数据,见不得人的数据,比如证书、token、密码等,可以像 Volume 一样被一个 Pod 引用(挂载)。
ConfigMap
用来放配置,与 Secret 是类似的,只是ConfigMap放的是明文的数据,Secret 是密文存放。
Ingress
Ingress 可以提供外网访问 Service 的能力。可以把某个请求地址映射、路由到特定的 service。ingress 需要配合 ingress controller 一起使用才能发挥作用,ingress只是相当于路由规则的集合而已,真正实现路由功能的,是 Ingress Controller,ingress controller 和其它 k8s 组件一样,也是在Pod中运行。
更多资料:
ThirdPartyResource
ServiceAccount
访问Service的Account