
Kubernetes,简称K8s,是用8代替名字中间的8个字符“ubernete”而成的缩写。它是一个全新的基于容器技术的分布式架构领先方案,是一个完备的分布式系统支撑平台。
Kubernetes具有完备的集群管理能力,包括多层次的安全防护和准入机制、多租户应用支撑能力、透明的服务注册和服务发现机制、内建的智能负载均衡器、强大的故障发现和自我修复能力、服务滚动升级和在线扩容能力、可扩展的资源自动调度机制,以及多粒度的资源配额管理能力。同时,Kubernetes提供了完善的管理工具,这些工具涵盖了包括开发、部署测试、运维监控在内的各个环节。
1.2、使用Kubernets的理由 使用Kubernetes的理由很多,最重要的理由是,IT行业从来都是由新技术驱动的。
当前,Docker这门容器化技术已经被很多公司采用,从单机走向集群已成为必然,云计算的蓬勃发展正在加速这一进程。Kubernetes作为当前被业界广泛认可和看好的基于Docker的大规模容器化分布式系统解决方案,得到了以谷歌为首的IT巨头们的大力宣传和持续推进。
使用Kubernetes能得到的好处:
- 可以“轻装上阵”地开发复杂系统。
- 可以全面拥抱微服务架构。
- 可以随时随地将系统整体“搬迁”到公有云上。
- Kubernetes内在的服务d性扩容机制可以让我们轻松应对突发流量。
- Kubernetes系统架构超强的横向扩容能力可以让我们的竞争力大大提升。
Kubernetes中的大部分概念如Node、Pod、Replication Controller、 Service等都可以被看作一种资源对象,几乎所有资源对象都可以通过 Kubernetes提供的kubectl工具(或者API编程调用)执行增、删、改、查等 *** 作并将其保存在etcd中持久化存储。从这个角度来看,Kubernetes 其实是一个高度自动化的资源控制系统,它通过跟踪对比etcd库里保存 的“资源期望状态”与当前环境中的“实际资源状态”的差异来实现自动控制和自动纠错的高级功能。
1.3.1、Master Kubernetes里的Master指的是集群控制节点,在每个Kubernetes集群里都需要有一个Master来负责整个集群的管理和控制,基本上 Kubernetes的所有控制命令都发给它,它负责具体的执行过程,我们后面执行的所有命令基本都是在Master上运行的。
1.3.2、Node 除了Master,Kubernetes集群中的其他机器被称为Node,在较早的版本中也被称为Minion。Node是Kubernetes集群中的工作负载节点,每个 Node都会被Master分配一些工作负载(Docker容器)。
关于Node有两个重要命令 kubectl get nodes和kubectl describe node [nodeName],分别用于查看集群的Node信息和指定Node的详细情况。
Pod是Kubernetes最重要的基本概念,每个Pod都有一个特殊的被称为“根容器”的Pause容器。Pause容器对应的镜像属于Kubernetes平台的一部分,除了Pause容器,每个Pod还包含一个或多个紧密相关的用户业务容器。
Pod 的共享上下文包括一组 Linux 名字空间、控制组(cgroup)和可能一些其他的隔离方面,即用来隔离 Docker 容器的技术。就 Docker 概念的术语而言,Pod 类似于共享名字空间和文件系统卷的一组 Docker 容器。
Kubernetes 集群中的 Pod 主要有两种用法:
-
运行单个容器的 Pod。"每个 Pod 一个容器"模型是最常见的 Kubernetes 用例;在这种情况下,可以将 Pod 看作单个容器的包装器,并且 Kubernetes 直接管理 Pod,而不是容器。
-
运行多个协同工作的容器的 Pod。 Pod 可能封装由多个紧密耦合且需要共享资源的共处容器组成的应用程序。这些位于同一位置的容器可能形成单个内聚的服务单元 —— 一个容器将文件从共享卷提供给公众,而另一个单独的“边车”(sidecar)容器则刷新或更新这些文件。 Pod 将这些容器和存储资源打包为一个可管理的实体。
Label(标签)是Kubernetes系统中另外一个核心概念。一个Label是 一个key=value的键值对,其中key与value由用户自己指定。Label可以被附加到各种资源对象上,例如Node、Pod、Service、RC等。
给某个资源对象定义一个Label, 就相当于给它打了一个标签,随后可以通过Label Selector(标签选择器)查询和筛选拥有某些Label的资源对象,Kubernetes通过这种方式实现了类似SQL的简单又通用的对象查询机制。
使用Label可以给对象创建多组标签,Label和Label Selector 共同构成了Kubernetes系统中核心的应用模型,使得被管理对象能够被精细地分组管理,同时实现了整个集群的高可用性。
RC是Kubernetes系统中的核心概念之一,简单来说,它其实定义了一个期望的场景,即声明某种Pod的副本数量在任意时刻都符合某个预期值,所以RC的定义包括如下几个部分。
- Pod期待的副本数量。
- 用于筛选目标Pod的Label Selector。
- 当Pod的副本数量小于预期数量时,用于创建新Pod的Pod模板 (template)。
在我们定义了一个RC并将其提交到Kubernetes集群中后,Master上 的Controller Manager组件就得到通知,定期巡检系统中当前存活的目标 Pod,并确保目标Pod实例的数量刚好等于此RC的期望值,如果有过多的Pod副本在运行,系统就会停掉一些Pod,否则系统会再自动创建一些 Pod。
Deployment相对于RC的一个最大升级是我们可以随时知道当前 Pod“部署”的进度。实际上由于一个Pod的创建、调度、绑定节点及在目标Node上启动对应的容器这一完整过程需要一定的时间,所以我们期待系统启动N个Pod副本的目标状态,实际上是一个连续变化的“部署过程”导致的最终状态。
Horizontal Pod Autoscaling(Pod横向自动扩容,HPA),也属于一种Kubernetes资源对象。通过追踪分析指定RC控制的所有目标Pod的负载变化情况,来确定是否需要有针对性地调整目标Pod的副本数量,这是HPA的实现原理。当前,HPA有以下两种方式作为Pod负载的度量指标。
- CPUUtilizationPercentage。
- 应用程序自定义的度量指标,比如服务在每秒内的相应请求数(TPS或QPS)。
Pod的管理对象RC、Deployment、DaemonSet 和Job都面向无状态的服务。但现实中有很多服务是有状态的。StatefulSet从本质上来说,可以看作 Deployment/RC的一个特殊变种,它有如下特性。
- StatefulSet里的每个Pod都有稳定、唯一的网络标识,可以用来发现集群内的其他成员。假设StatefulSet的名称为kafka,那么第1个Pod 叫kafka-0,第2个叫kafka-1,以此类推。
- StatefulSet控制的Pod副本的启停顺序是受控的, *** 作第n个Pod 时,前n-1个Pod已经是运行且准备好的状态。
- StatefulSet里的Pod采用稳定的持久化存储卷,通过PV或PVC来实现,删除Pod时默认不会删除与StatefulSet相关的存储卷(为了保证数据的安全)。
Service服务也是Kubernetes里的核心资源对象之一,Kubernetes里的ßßß每个Service其实就是我们经常提起的微服务架构中的一个微服务,之前 讲解Pod、RC等资源对象其实都是为讲解Kubernetes Service做铺垫的。
Kubernetes的Service定义了一个服务的访问 入口地址,前端的应用(Pod)通过这个入口地址访问其背后的一组由 Pod副本组成的集群实例,Service与其后端Pod副本集群之间则是通过 Label Selector来实现无缝对接的。RC的作用实际上是保证Service的服务 能力和服务质量始终符合预期标准。
批处理任务通常并行(或者串行)启动多个计算进程去处理一批工作项(work item),在处理完成后,整个批处理任务结束。
1.3.11、Volume Volume(存储卷)是Pod中能够被多个容器访问的共享目录。 Kubernetes的Volume概念、用途和目的与Docker的Volume比较类似,但两者不能等价。首先,Kubernetes中的Volume被定义在Pod上,然后被一个Pod里的多个容器挂载到具体的文件目录下;其次,Kubernetes中的 Volume与Pod的生命周期相同,但与容器的生命周期不相关,当容器终止或者重启时,Volume中的数据也不会丢失。最后,Kubernetes支持多种类型的Volume,例如GlusterFS、Ceph等先进的分布式文件系统。
1.3.12、Persistent Volume Persistent Volume(PV)可以被理解成Kubernetes集群中的某个网络存储对应的一块存储,它与Volume类似,但有以下区别。
- PV只能是网络存储,不属于任何Node,但可以在每个Node上访问。
- PV并不是被定义在Pod上的,而是独立于Pod之外定义的。
- PV目前支持的类型与Volume不同。
Namespace(命名空间)是Kubernetes系统中的另一个非常重要的概 念,Namespace在很多情况下用于实现多租户的资源隔离。Namespace 通过将集群内部的资源对象“分配”到不同的Namespace中,形成逻辑上分组的不同项目、小组或用户组,便于不同的分组在共享使用整个集群的资源的同时还能被分别管理。
Annotation(注解)与Label类似,也使用key/value键值对的形式进行定义。不同的是Label具有严格的命名规则,它定义的是Kubernetes对象的元数据(metadata),并且用于Label Selector。
1.3.15、ConfigMap Kubernetes ConfigMap是分布式系统中最为简单(使用方法简单,但背后实现比较复杂)且对应用无侵入的配置中心。
1.4、基本命令 二、Kubernetes安装 三、深入掌握Pod 3.1、基本概念 在使用Docker时,可以使用docker run命令创建并启动一个容器。 而在Kubernetes系统中对长时间运行容器的要求是:其主程序需要一直在前台执行。如果我们创建的Docker镜像的启动命令是后台执行程序,则在kubelet创建包含这个容器的Pod之后运行完该命令,即认为Pod 执行结束,将立刻销毁该Pod。
Pod 遵循一个预定义的生命周期,起始于 Pending阶段,如果至少其中有一个主要容器正常启动,则进入 Running,之后取决于 Pod 中是否有容器以 失败状态结束而进入 Succeeded 或者 Failed 阶段。
3.2、举一个例子[root@k8s-master daemon]# cat mysql-rc.yaml
apiVersion: v1
kind: ReplicationController
metadata:
name: mysql
spec:
replicas: 1
selector:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql
ports:
- containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
value: "123456"
[root@k8s-master daemon]# kubectl create -f mysql-rc.yaml
replicationcontroller/mysql created
[root@k8s-master daemon]# kubectl get pod
NAME READY STATUS RESTARTS AGE
mysql-488kh 0/1 ContainerCreating 0 13s
3.3、静态Pod
静态Pod是由kubelet进行管理的仅存在于特定Node上的Pod。它们不能通过API Server进行管理,无法与ReplicationController、Deployment 或者DaemonSet进行关联,并且kubelet无法对它们进行健康检查。静态 Pod总是由kubelet创建的,并且总在kubelet所在的Node上运行。
静态 Pod 通常绑定到某个节点上的 kubelet。 其主要用途是运行自托管的控制面。 在自托管场景中,使用 kubelet 来管理各个独立的 控制面组件。
3.4、共享Volume 同一个Pod中的多个容器能够共享Pod级别的存储卷Volume。Volume可以被定义为各种类型,多个容器各自进行挂载 *** 作,将一个 Volume挂载为容器内部需要的目录。
ConfigMap供容器使用的典型用法如下。
- 生成为容器内的环境变量。
- 设置容器启动命令的启动参数(需设置为环境变量)。
- 以V olume的形式挂载为容器内部的文件或目录。
ConfigMap以一个或多个key:value的形式保存在Kubernetes系统中供应用使用,既可以用于表示一个变量的值(例如apploglevel=info),也可以用于表示一个完整配置文件的内容(例如server.xml=…)。可以通过YAML配置文件或者直接使用kubectl create configmap命令行的方式来创建ConfigMap。
[root@k8s-master daemon]# cat cm-appvars.yaml apiVersion: v1 kind: ConfigMap metadata: name: cm-appvars data: apploglevel: info appdatadir: /var/data [root@k8s-master daemon]# kubectl create -f cm-appvars.yaml configmap/cm-appvars created [root@k8s-master daemon]# kubectl get configmap NAME DATA AGE cm-appvars 2 26s kube-root-ca.crt 1 4d18h [root@k8s-master daemon]# kubectl describe configmap cm-appvars Name: cm-appvars Namespace: default Labels:3.6、在容器中获取Pod的配置信息 3.6.1、环境变量方式:将Pod信息注入为环境变量Annotations: Data ==== appdatadir: ---- /var/data apploglevel: ---- info BinaryData ==== Events: [root@k8s-master daemon]# kubectl get configmap cm-appvars -o yaml apiVersion: v1 data: appdatadir: /var/data apploglevel: info kind: ConfigMap metadata: creationTimestamp: "2021-12-13T01:00:38Z" name: cm-appvars namespace: default resourceVersion: "539281" uid: 5a633cd0-b6f0-4afe-8746-1bae0e03137f
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
...
env:
- name: MY_POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- metadata.name:Pod的名称,当Pod通过RC生成时,其名称是 RC随机产生的唯一名称。
- status.podIP:Pod的IP地址,之所以叫作status.podIP而非 metadata.IP,是因为Pod的IP属于状态数据,而非元数据。
- metadata.namespace:Pod所在的Namespace。
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod-container-vars
spec:
containers:
- name: test-container
...
env:
- name: MY_CPU_REQUEST
valueFrom:
resourceFieldRef:
containerName: test-container
resource: limits.cpu
- requests.cpu:容器的CPU请求值。
- limits.cpu:容器的CPU限制值。
- requests.memory:容器的内存请求值。
- imits.memory:容器的内存限制值。
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod-volume
spec:
containers:
- name: test-container
...
volumeMounts:
- name: podinfo
mountPath: /etc
readOnly: false
volume:
- name: podinfo
downwardAPI:
items:
- path: "labels"
fieldRef:
fieldPath: metadata.labels
3.7、Pod生命周期和重启策略
3.7.1、生命周期
Pod的重启策略包括Always、OnFailure和Never,默认值为Always。
- Always:当容器失效时,由kubelet自动重启该容器。
- OnFailure:当容器终止运行且退出码不为0时,由kubelet自动重启该容器。
- Never:不论容器运行状态如何,kubelet都不会重启该容器。
Pod的重启策略与控制方式息息相关,当前可用于管理Pod的控制器包括ReplicationController、Job、DaemonSet及直接通过kubelet管理(静态Pod)。每种控制器对Pod的重启策略要求如下。
- RC和DaemonSet:必须设置为Always,需要保证该容器持续运行。
- Job:OnFailure或Never,确保容器执行完成后不再重启。
- kubelet:在Pod失效时自动重启它,不论将RestartPolicy设置为什么值,也不会对Pod进行健康检查。
- **LivenessProbe探针:**用于判断容器是否存活(Running状态),如果LivenessProbe探针探测到容器不健康,则kubelet将杀掉该容器,并根据容器的重启策略做相应的处理。如果一个容器不包含 LivenessProbe探针,那么kubelet认为该容器的LivenessProbe探针返回的值永远是Success。
- **ReadinessProbe探针:**用于判断容器服务是否可用(Ready状态),达到Ready状态的Pod才可以接收请求。对于被Service管理的 Pod,Service与Pod Endpoint的关联关系也将基于Pod是否Ready进行设置。如果在运行过程中Ready状态变为False,则系统自动将其从Service 的后端Endpoint列表中隔离出去,后续再把恢复到Ready状态的Pod加回后端Endpoint列表。这样就能保证客户端在访问Service时不会被转发到 服务不可用的Pod实例上。
LivenessProbe和ReadinessProbe均可配置以下三种实现方式。
-
ExecAction:在容器内部执行一个命令,如果该命令的返回码为0,则表明容器健康。
... spec: containers: - name: liveness ... livenessProbe: exec: command: - cat - /tmp/health inizialDelaySeconds: 30 timeoutSeconds: 1 -
TCPSocketAction:通过容器的IP地址和端口号执行TCP检查,如果能够建立TCP连接,则表明容器健康。
... spec: containers: - name: nginx image: nginx ports: - containerPort: 80 livenessProbe: tcpSocket: port: 80 inizialDelaySeconds: 30 timeoutSeconds: 1 -
HTTPGetAction:通过容器的IP地址、端口号及路径调用 HTTP Get方法,如果响应的状态码大于等于200且小于400,则认为容器健康。
... spec: containers: - name: nginx image: nginx ports: - containerPort: 80 livenessProbe: httpGet: path: /_status/healthz port: 80 inizialDelaySeconds: 30 timeoutSeconds: 1
在Kubernetes平台上,我们很少会直接创建一个Pod,在大多数情况下会通过RC、Deployment、DaemonSet、Job等控制器完成对一组Pod副本的创建、调度及全生命周期的自动控制任务。
3.9.1、Deployment或RC:全自动调度 Deployment或RC的主要功能之一就是自动部署一个容器应用的多份副本,以及持续监控副本的数量,在集群内始终维持用户指定的副本数量。它们各自最终运行在哪个节点上,完全由Master的Scheduler经过一系列算法计算得出,用户无法干预调度过程和结果。
3.9.2、NodeSelector:定向调度 在实际情况下,也可能需要将Pod调度到指定的一些Node上,可以通过Node的标签(Label)和Pod 的nodeSelector属性相匹配,来达到上述目的。
3.9.3、NodeAffinity:Node亲和性调度 NodeAffinity意为Node亲和性的调度策略,是用于替换NodeSelector的全新调度策略。目前有两种节点亲和性表达。
- RequiredDuringSchedulingIgnoredDuringExecution:必须满足指 定的规则才可以调度Pod到Node上(功能与nodeSelector很像,但是使用的是不同的语法),相当于硬限制。
- PreferredDuringSchedulingIgnoredDuringExecution:强调优先满足指定规则,调度器会尝试调度Pod到Node上,但并不强求,相当于软限制。多个优先级规则还可以设置权重(weight)值,以定义执行的先后顺序。
根据在节点上正在运行的 Pod的标签而不是节点的标签进行判断和调度,要求对节点和Pod两个条件进行匹配。这种规则可以描述为:如果在具有标签X的Node上运行了一个或者多个符合条件Y的Pod,那么Pod应该(如果是互斥的情况,那么就变成拒绝)运行在这个Node上。
3.9.5、Taints和Tolerations(污点和容忍) Taint需要和Toleration配合使用,让Pod避开那些不合适的Node。在 Node上设置一个或多个Taint之后,除非Pod明确声明能够容忍这些污点,否则无法在这些Node上运行。Toleration是Pod的属性,让Pod能够 (注意,只是能够,而非必须)运行在标注了Taint的Node上。
3.9.6、Pod Priority Preemption:Pod优先级调度 当集群的可用资源不足时,在用户提交新的Pod创建请求后,Kubernetes会尝试释放目标节点上低优先级的Pod,以腾出空间(资源)安置高优先级的 Pod,这种调度方式被称为“抢占式调度”。我们可以通过以下几个维度来定义:
- Priority,优先级;
- QoS,服务质量等级;
- 系统定义的其他度量指标。
用于管理在集群中每个Node上仅运行一份Pod的副本实例。这种用法适合有这种需求的应用。
- 在每个Node上都运行一个GlusterFS存储或者Ceph存储的 Daemon进程。
- 在每个Node上都运行一个日志采集程序,例如Fluentd或者 Logstach。
- 在每个Node上都运行一个性能监控程序,采集该Node的运行性能数据,例如Prometheus Node Exporter、collectd、New Relic agent或者Ganglia gmond等。
批处理任务通常并行(或者串行)启动多个计算进程去处理一批工作项(work item),处理完成后,整个批处理任务结束。
3.9.9、Cronjob:定时任务 类似Linux Cron的定时任务Cron Job。
3.9.10、自定义调度器 如果Kubernetes调度器的众多特性还无法满足我们的独特调度需求,则还可以用自己开发的调度器进行调度。
3.10、Init化容器 Init 容器是一种特殊容器,在 Pod 内的应用容器启动之前运行。Init 容器可以包括一些应用镜像中不存在的实用工具和安装脚本。
下面的例子定义了一个具有 2 个 Init 容器的简单 Pod。 第一个等待 myservice 启动, 第二个等待 mydb 启动。 一旦这两个 Init容器都启动完成,Pod 将启动 spec 节中的应用容器。
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
spec:
containers:
- name: myapp-container
image: busybox:1.28
command: ['sh', '-c', 'echo The app is running! && sleep 3600']
initContainers:
- name: init-myservice
image: busybox:1.28
command: ['sh', '-c', "until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done"]
- name: init-mydb
image: busybox:1.28
command: ['sh', '-c', "until nslookup mydb.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for mydb; sleep 2; done"]
3.11、Pod的升级和回滚
如果Pod是通过Deployment创建的,则用户可以在运行时修改 Deployment的Pod定义(spec.template)或镜像名称,并应用到 Deployment对象上,系统即可完成Deployment的自动更新 *** 作。如果在更新过程中发生了错误,则还可以通过回滚 *** 作恢复Pod的版本。
3.12、Pod的扩缩容 Kubernetes对Pod的扩缩容 *** 作提供了手动和自动两种模式,手动模 式通过执行kubectl scale命令或通过RESTful API对一个Deployment/RC进行Pod副本数量的设置,即可一键完成。自动模式则需要用户根据某个性能指标或者自定义业务指标,并指定Pod副本数量的范围,系统将自动在这个范围内根据性能指标的变化进行调整。
四、深入掌握Service 4.1、基本概念 创建和销毁 Kubernetes Pod 以匹配集群状态。 Pod 是非永久性资源,它可以动态创建和销毁 Pod。每个 Pod 都有自己的 IP 地址,但是在 Deployment 中,在同一时刻运行的 Pod 集合可能与稍后运行该应用程序的 Pod 集合不同。这导致了一个问题:如果一组 Pod(称为“后端”)为集群内的其他 Pod(称为“前端”)提供功能,那么前端如何找出并跟踪要连接的 IP 地址,以便前端可以使用提供工作负载的后端部分?
Kubernetes Service 定义了这样一种抽象:逻辑上的一组 Pod,一种可以访问它们的策略 —— 通常称为微服务。
4.2、举一个例子 例如,假定有一组 Pod,它们对外暴露了 9376 端口,同时还被打上 app=MyApp 标签:
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- protocol: TCP
port: 80
targetPort: 9376
上述配置创建一个名称为 “my-service” 的 Service 对象,它会将请求代理到使用 TCP 端口 9376,并且具有标签 "app=MyApp" 的 Pod 上。
Kubernetes 为该服务分配一个 IP 地址(有时称为 “集群IP”),该 IP 地址由服务代理使用。 (请参见下面的 VIP 和 Service 代理)。服务选择算符的控制器不断扫描与其选择器匹配的Pod,然后将所有更新发布到也称为 “my-service” 的 Endpoint 对象。
4.3、Service的基本用法 4.3.1、多端口ServiceapiVersion: v1
kind: Service
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
4.3.2、外部服务Service
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
ports:
- name: tcp
protocol: TCP
port: 80
targetPort: 80
创建一个不带标签选择器的Service,即无选择后端的Pod,系统不会自动创建Endpoint,因此需要手动创建一个和该Service同名的Endpoint,用于指向实际的后端访问地址。
apiVersion: v1 kind: Endpoints metadata: name: my-service subsets: - addresses: - IP: 1.2.3.4 ports: - port: 804.4、Headless Service
在某些应用场景中,开发人员希望自己控制负载均衡的策略,不使用Service提供的默认负载均衡的功能,或者应用程序希望知道属于同组服务的其他实例。Kubernetes提供了Headless Service来实现这种功能,即不为Service设置ClusterIP(入口IP地址),仅通过Label Selector将后端的Pod列表返回给调用的客户端。
4.5、集群外访问Pod和Service 4.5.1、将容器应用的端口号映射到物理机-
设置容器级别的hostPort,将应用端口映射到物理机
apiVersion: v1 kind: Pod metadata: name: webapp labels: app: webapp spec: containers: - name: webapp image: tomcat ports: - containerPort: 8080 hostPort: 8081
-
设置Pod级别hostNetwork=true,将该Pod中所有容器的端口映射到物理机
apiVersion: v1 kind: Pod metadata: name: webapp labels: app: webapp spec: hostNetwork: true containers: - name: webapp image: tomcat imagePullPolicy: Never ports: - containerPort: 8080
apiVersion: v1 kind: Service metadata: name: webapp spec: type: NodePort ports: - protocol: TCP port: 80 targetPort: 9376 nodePort: 80804.6、DNS服务搭建和配置指南
作为服务发现机制的基本功能,在集群内需要能够通过服务名对服务进行访问,这就需要一个集群范围内的DNS服务来完成从服务名到 ClusterIP的解析。
Kubernetes集群的DNS服务由CoreDNS 提供。CoreDNS是CNCF基金会的一个项目,是用Go语言实现的高性 能、插件式、易扩展的DNS服务端。
Ingress资源对象,用于将不同URL的访问请求转发到后端不同的Service,以实现HTTP层的业务路由机制。Kubernetes使用了一个Ingress策略定义和一个具体的Ingress Controller,两者结合并实现了一个完整的Ingress负载均衡器。
五、核心组件运行机制 5.1、Kubernetes API Server Kubernetes API Server的核心功能是提供Kubernetes各类资源对象(如Pod、RC、Service等)的增、删、改、查及Watch等HTTP Rest接口,成为集群内各个功能模块之间数据交互和通信的中心枢纽,是整个系统的数据总线和数据中心。除此之外,它还有以下一些功能特性。
- 是集群管理的API入口。
- 是资源配额控制的入口。
- 提供了完备的集群安全机制。
Kubernetes API Server作为集群的核心,负责集群各功能模块之间的通信。集群内的各个功能模块通过API Server将信息存入etcd,当需要获取和 *** 作这些数据时,则通过API Server提供的 REST接口(用GET、LIST或W A TCH方法)来实现,从而实现各模块之间的信息交互。
在Kubernetes集群中,每个Controller通过API Server提供的(List-Watch)接口实时监控集群中特定资源的状态变化,当发生各种故障导致某资源对象的状态发生变化时,Controller会尝试将其状态调整为期望的状态。Controller Manager是 Kubernetes中各种 *** 作系统的管理者,是集群内部的管理控制中心,也是Kubernetes自动化功能的核心。
Controller Manager内部包含Replication Controller、 Node Controller、ResourceQuota Controller、Namespace Controller、 ServiceAccount Controller、Token Controller、Service Controller及 Endpoint Controller这8种Controller,每种Controller都负责一种特定资源的控制流程,而Controller Manager正是这些Controller的核心管理者。
核心作用是确保在任何时候集群中某个RC关联的Pod副本数量都保持预设值。
5.2.2、Node Controller 通过API Server实时获取Node的相关信息,实现管理和监控集群中的各个Node的相关控制功能。
5.2.3、ResourceQuota Controller 确保了指定的资源对象在任何时候都不会超量占用系统物理资源。
5.2.4、Namespace Controller 定时通过API Server读取这些Namespace的信息。
5.2.5、Service Controller和Endpoint Controller Service Controller监听Service 的变化,Endpoints Controller就是负责生成和维护所有Endpoints对象的控制器。
5.2.6、ServiceAccount Controller和Token Controller ServiceAccount Controller与Token Controller是与安全相关的两个控制器,并且与Service Account、Token密切相关。
5.3、Scheduler Kubernetes Scheduler的作用是将待调度的Pod(API新创建的Pod、Controller Manager为补足副本而创建的Pod等)按照特定的调 度算法和调度策略绑定(Binding)到集群中某个合适的Node上,并将 绑定信息写入etcd中。在整个调度过程中涉及三个对象,分别是待调度 Pod列表、可用Node列表,以及调度算法和策略。简单地说,就是通过调度算法调度为待调度Pod列表中的每个Pod从Node列表中选择一个最适合的Node。
5.4、kubelet 在Kubernetes集群中,在每个Node上都会启动一个 kubelet服务进程。该进程用于处理Master下发到本节点的任务,管理 Pod及Pod中的容器。每个kubelet进程都会在API Server上注册节点自身的信息,定期向Master汇报节点资源的使用情况,并通过cAdvisor监控容器和节点资源。
5.5、kube-proxy 在Kubernetes集群的每个Node上都会运行一个kube-proxy服务进 程,我们可以把这个进程看作Service的透明代理兼负载均衡器,其核心功能是将到某个Service的访问请求转发到后端的多个Pod实例上。
Kubernetes通过一系列机制来实现集群的安全控制,其中包括API Server的认证授权、准入控制机制及保护敏感信息的Secret机制等。集群的安全性必须考虑如下几个目标。
- 保证容器与其所在宿主机的隔离。
- 限制容器给基础设施或其他容器带来的干扰。
- 最小权限原则—合理限制所有组件的权限,确保组件只执行它被授权的行为,通过限制单个组件的能力来限制它的权限范围。
- 明确组件间边界的划分。
- 划分普通用户和管理员的角色。
- 在必要时允许将管理员权限赋给普通用户。
- 允许拥有Secret数据(Keys、Certs、Passwords)的应用在集群中运行。
Kubernetes网络模型设计的一个基础原则是:每个Pod都拥有一个独立的IP地址,并假定所有Pod都在一个可以直接连通的、扁平的网络空间中。所以不管它们是否运行在同一个Node(宿主机)中,都要求它们可以直接通过对方的IP进行访问。设计这个原则的原因是,用户不需要额外考虑如何建立Pod之间的连接,也不需要考虑如何将容器端口映射到主机端口等问题。
7.2、Docker网络基础 Docker使用到的与 Linux网络有关的主要技术有:网络命名空间 (Network Namespace)、Veth设备对、网桥、ipatables和路由。
标准的Docker支持以下4类网络模式。
- host模式:使用–net=host指定。
- container模式:使用–net=container:NAME_or_ID指定。
- none模式:使用–net=none指定。
- bridge模式:使用–net=bridge指定,为默认设置。
在Kubernetes管理模式下通常只会使用bridge模式。
7.3、Kubernetes网络实现 7.3.1、容器到容器的通信 同一个Pod内的容器(Pod内的容器是不会跨宿主机的)共享同一个网络命名空间,共享同一个Linux协议栈。所以对于网络的各类 *** 作,就和它们在同一台机器上一样,它们甚至可以用localhost地址访问彼此的端口。
7.3.2、Pod之间的通信- 同一个Node内Pod之间的通信
可以直接采用对方Pod的IP地址通信。
- 不同Node上Pod之间的通信
要想支持不同Node上Pod之间的通信,就要满足两个条件:(1)在整个Kubernetes集群中对Pod的IP分配进行规划,不能有冲突;(2)找到一种办法,将Pod的IP和所在Node的IP关联起来,通过这个关联让Pod可以互相访问。
7.4、Pod和Service网络 在Kubernetes的网络模型中,每台主机上的docker0网桥都是可以被 路由到的。也就是说,在部署了一个Pod时,在同一个集群内,各主机都可以访问其他主机上的Pod IP,并不需要在主机上做端口映射。综上所述,我们可以在网络层将Kubernetes的节点看作一个路由器。为了支持Kubernetes网络模型,我们采取了直接路由的方式来实现,在每个Node上都配置相应的静态路由项。
这意味着,每一个新部署的容器都将使用这个Node(docker0的网桥IP)作为它的默认网关。而这些Node(类似路由器)都有其他 docker0的路由信息,这样它们就能够相互连通了。
7.5、CNI网络模型 CNI提供了一种应用容器的插件化网络解决方案,定义对容器网络进行 *** 作和配置的规范,通过插件的形式对CNI接口进行实现。CNI是由rkt Networking Proposal发展而来的,试图提供一种普适的容器网络解决方案。
在CNI模型中只涉及两个概念:容器和网络。
- **容器(Container)*是拥有独立Linux网络命名空间的环境, 例如使用Docker或rkt创建的容器。关键之处是容器需要拥有自己的 Linux网络命名空间,这是加入网络的必要条件。
- **网络(Network)*表示可以互连的一组实体,这些实体拥有各自独立、唯一的IP地址,可以是容器、物理机或者其他网络设备(比如路由器)等。
Network Policy机制用于实现细粒度的容器间网络访问隔离策略,主要功能是对Pod间的网络通信进行限制和准入控制。
Kubernetes引入了一个新的资源对象 NetworkPolicy,供用户设置Pod间网络访问的策略,设置方式为将Pod的Label作为查询条件,设置允许访问或禁止访问的客户端Pod列表。目前查询条件可以作用于Pod和Namespace级别。
八、共享存储原理 Kubernetes对于有状态的容器应用或者对数据需要持久化的应用,不仅需要将容器内的目录挂载到宿主机的目录或者emptyDir临时存储卷,而且需要更加可靠的存储来保存应用产生的重要数据,以便容器应用在重建之后仍然可以使用之前的数据。
8.1、PersistentVolume(PV) PV作为存储资源,主要包括存储能力、访问模式、存储类型、回收策略、后端存储类型等关键信息的设置。下面的例子声明的PV具有如下属性:5GiB存储空间,访问模式为ReadWriteOnce,存储类型为 slow(要求在系统中已存在名为slow的StorageClass),回收策略为 Recycle,并且后端存储类型为nfs(设置了NFS Server的IP地址和路径):
apiVersion: v1 kind: PersistentVolume mwtadata: name: pv1 spec: capatcity: storage: 5Gi accessModes: - ReadWriteonce persistentVolumeReclaimPolicy: Recycle storageClassName: slow nfs: path: /tmp server: 172.17.0.2
某个PV在生命周期中可能处于以下4个阶段(Phaes)之一。
- Available:可用状态,还未与某个PVC绑定。
- Bound:已与某个PVC绑定。
- Released:绑定的PVC已经删除,资源已释放,但没有被集群回收。
- Failed:自动资源回收失败。
PVC作为用户对存储资源的需求申请,主要包括存储空间请求、访问模式、PV选择条件和存储类别等信息的设置。下例声明的PVC具有如下属性:申请8GiB存储空间,访问模式为ReadWriteOnce,PV 选择条件为包含标签“release=stable”并且包含条件为“environment In [dev]”的标签,存储类别为“slow”(要求在系统中已存在名为slow的 StorageClass)
apiVersion: v1
kind: PersistentVolumeClaim
mwtadata:
name: myclaim
spec:
accessModes:
- ReadWriteonce
resources:
requests:
storage: 5Gi
storageClassName: slow
selector:
matchLabels:
release: "stable"
matchexpressions:
- {key: environment, operator: In, values: [dev]}
8.3、PV与PVC关系
可以将PV看作可用的存储资源,PVC则是对存储资源的需求,PV和PVC的相互关系遵循如图的生命周期。
StorageClass作为对存储资源的抽象定义,对用户设置的PVC申请屏蔽后端存储的细节,一方面减少了用户对于存储资源细节的关注,另一方面减轻了管理员手工管理PV的工作,由系统自动完成PV的创建和绑定,实现了动态的资源供应。
StorageClass的定义主要包括名称、后端存储的提供者 (provisioner)和后端存储的相关参数配置。StorageClass一旦被创建出来,则将无法修改。如需更改,则只能删除原StorageClass的定义重建。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)