Kubernetes 是一个可移植、可扩展的开源平台,用于管理容器化的工作负载和服务,可促进声明式配置和自动化。 Kubernetes 拥有一个庞大且快速增长的生态,其服务、支持和工具的使用范围相当广泛。
Kubernetes 的目标是让部署容器化的应用简单并且高效(powerful),Kubernetes 提供了应用部署,规划,更新,维护的一种机制。
Kubernetes 这个名字源于希腊语,意为“舵手”或“飞行员”。K8s 这个缩写是因为 K 和 s 之间有 8 个字符的关系。 Google 在 2014 年开源了 Kubernetes 项目。 Kubernetes 建立在 Google 大规模运行生产工作负载十几年经验的基础上, 结合了社区中最优秀的想法和实践。
利用 OpenStask / VMware 等虚拟化技术,将一台目标机器虚拟化为多个虚拟机器,按照需求将应用部署到不同的虚拟机中,对虚拟机进行动态的水平扩容等管理操作。
相对传统部署自动化、资源隔离的能力提升了,带来的问题是虚拟化的逻辑过重,导致效率不高,且耗费资源较多。
自我修复:Kubernetes 可以监控容器的运行状态,自动重启或替换失败的容器,并根据需要重新调度 Pod,从而确保应用的高可用性。
弹性伸缩:Kubernetes 支持根据流量负载或其他指标,自动伸缩(增加或减少)Pod 的数量,从而有效地利用资源,满足业务需求。
自动部署和回滚:Kubernetes 通过控制器(如 Deployment)实现应用的自动部署和更新。它还支持回滚功能,可以快速恢复到之前的版本,确保在出现问题时能够迅速解决。
服务发现和负载均衡:Kubernetes 提供内置的服务发现机制,使得应用之间可以通过服务名称互相通信。Kubernetes 还提供负载均衡功能,自动将流量分配到多个 Pod 上,确保高效的资源使用和应用的高可用性。
机密和配置管理:Kubernetes 支持将敏感数据(如密码、密钥)通过 Secrets 进行管理,并可以将配置信息通过 ConfigMap 进行管理,确保应用配置的安全性和灵活性。
存储编排:Kubernetes 支持通过 Persistent Volumes 和 Persistent Volume Claims 实现持久化存储的管理和调度,适应各种存储系统(如本地存储、云存储、网络存储)。
批处理:Kubernetes 支持批处理任务,通过 Job 和 CronJob 对批处理任务进行管理,可以调度一次性或定时的任务执行,适用于数据处理和定时任务。
由于API Server是Kubernetes集群数据的唯一访问入口,因此安全性与高性能成为API Server设计和实现的两大核心目标。通过采用HTTPS安全传输通道与CA签名数字证书强制双向认证的方式,API Server的安全性得以保障。此外,为了更细粒度地控制用户或应用对Kubernetes资源对象的访问权限,Kubernetes启用了RBAC访问控制策略。
API Server拥有大量高性能的底层代码。在API Server源码中使用协程+队列这种轻量级的高性能并发代码,使得单进程的API Server具备超强的多核处理能力,从而以很快的速度并发处理大量的请求。
普通List接口结合异步Watch接口,不但完美解决了Kubernetes中各种资源对象的高性能同步问题,也极大提升了Kubernetes集群实时响应各种事件的灵敏度。
采用了高性能的etcd数据库而非传统的关系数据库,不仅解决了数据的可靠性问题,也极大提升了API Server数据访问层的性能。在常见的公有云环境中,一个3节点的etcd集群在轻负载环境中处理一个请求的时间可以少于1ms,在重负载环境中可以每秒处理超过30000个请求。
API 服务器是 Kubernetes 控制平面的组件, 该组件负责公开了 Kubernetes API,负责处理接受请求的工作。 API 服务器是 Kubernetes 控制平面的前端。
kube-controller-manager 是控制平面的组件, 负责运行控制器进程。
从逻辑上讲, 每个控制器都是一个单独的进程, 但是为了降低复杂性,它们都被编译到同一个可执行文件,并在同一个进程中运行。
这些控制器包括:
嵌入了特定于云平台的控制逻辑。 云控制器管理器(Cloud Controller Manager)允许你将你的集群连接到云提供商的 API 之上, 并将与该云平台交互的组件同与你的集群交互的组件分离开来。
cloud-controller-manager 仅运行特定于云平台的控制器。 因此如果你在自己的环境中运行 Kubernetes,或者在本地计算机中运行学习环境, 所部署的集群不需要有云控制器管理器。
与 kube-controller-manager 类似,cloud-controller-manager 将若干逻辑上独立的控制回路组合到同一个可执行文件中, 供你以同一进程的方式运行。 你可以对其执行水平扩容(运行不止一个副本)以提升性能或者增强容错能力。
scheduler 负责资源的调度,按照预定的调度策略将 Pod 调度到相应的机器上;
一致且高度可用的键值存储,用作 Kubernetes 的所有集群数据的后台数据库。
如果你的 Kubernetes 集群使用 etcd 作为其后台数据库, 请确保你针对这些数据有一份 备份计划。
你可以在官方文档中找到有关 etcd 的深入知识。
早期数据存放在内存,现在已经是持久化存储的了。
kubelet 负责维护容器的生命周期,同时也负责 Volume(CVI)和网络(CNI)的管理;
kube-proxy 负责为 Service 提供 cluster 内部的服务发现和负载均衡;
Container runtime 负责镜像管理以及 Pod 和容器的真正运行(CRI);
Nginx
Apache
优点:对客户端透明,无依赖关系,可以高效实现扩容、迁移
缺点:不能存储数据,需要额外的数据服务支撑
MySQL
Redis
优点:可以独立存储数据,实现数据管理
缺点:集群环境下需要实现主从、数据同步、备份、水平扩容复杂
“spec” 是 “规约”、“规格” 的意思,spec 是必需的,它描述了对象的期望状态(Desired State)—— 希望对象所具有的特征。当创建 Kubernetes 对象时,必须提供对象的规约,用来描述该对象的期望状态,以及关于对象的一些基本信息(例如名称)。
表示对象的实际状态,该属性由 k8s 自己维护,k8s 会通过一系列的控制器对对应对象进行管理,让对象尽可能的让实际状态与期望状态重合。
Kubernetes 中的所有内容都被抽象为“资源”,如 Pod、Service、Node 等都是资源。“对象”就是“资源”的实例,是持久化的实体。如某个具体的 Pod、某个具体的 Node。Kubernetes 使用这些实体去表示整个集群的状态。
对象的创建、删除、修改都是通过 “Kubernetes API”,也就是 “Api Server” 组件提供的 API 接口,这些是 RESTful 风格的 Api,与 k8s 的“万物皆对象”理念相符。命令行工具 “kubectl”,实际上也是调用 kubernetes api。
K8s 中的资源类别有很多种,kubectl 可以通过配置文件来创建这些 “对象”,配置文件更像是描述对象“属性”的文件,配置文件格式可以是 “JSON” 或 “YAML”,常用 “YAML”。
Pod 自动扩容:可以根据 CPU 使用率或自定义指标(metrics)自动对 Pod 进行扩/缩容。
Pod Template 是关于 Pod 的定义,但是被包含在其他的 Kubernetes 对象中(例如 Deployment、StatefulSet、DaemonSet 等控制器)。控制器通过 Pod Template 信息来创建 Pod。
可以对集群内 Request 和 Limits 的配置做一个全局的统一的限制,相当于批量设置了某一个范围内(某个命名空间)的 Pod 的资源使用限制。
Kubernetes 支持多个虚拟集群,它们底层依赖于同一个物理集群,这些虚拟集群被称为命名空间。
作用是用于实现多团队/环境的资源隔离。
命名空间 namespace 是 k8s 集群级别的资源,可以给不同的用户、租户、环境或项目创建对应的命名空间。
不像其他的资源(如 Pod 和 Namespace),Node 本质上不是Kubernetes 来创建的,Kubernetes 只是管理 Node 上的资源。虽然可以通过 Manifest 创建一个Node对象(如下 json 所示),但 Kubernetes 也只是去检查是否真的是有这么一个 Node,如果检查失败,也不会往上调度 Pod。
ClusterRole 是一组权限的集合,但与 Role 不同的是,ClusterRole 可以在包括所有 Namespace 和集群级别的资源或非资源类型进行鉴权。
ClusterRoleBinding:将 Subject 绑定到 ClusterRole,ClusterRoleBinding 将使规则在所有命名空间中生效。
Pod(容器组)是 Kubernetes 中最小的可部署单元。一个 Pod(容器组)包含了一个应用程序容器(某些情况下是多个容器)、存储资源、一个唯一的网络 IP 地址、以及一些确定容器该如何运行的选项。Pod 容器组代表了 Kubernetes 中一个独立的应用程序运行实例,该实例可能由单个容器或者几个紧耦合在一起的容器组成。
Docker 是 Kubernetes Pod 中使用最广泛的容器引擎;Kubernetes Pod 同时也支持其他类型的容器引擎。
Kubernetes 集群中的 Pod 存在如下两种使用途径: 一个 Pod 中只运行一个容器。"one-container-per-pod" 是 Kubernetes 中最常见的使用方式。此时,您可以认为 Pod 容器组是该容器的 wrapper,Kubernetes 通过 Pod 管理容器,而不是直接管理容器。 一个 Pod 中运行多个需要互相协作的容器。您可以将多个紧密耦合、共享资源且始终在一起运行的容器编排在同一个 Pod 中,可能的情况有:
先引入“副本”的概念——一个 Pod 可以被复制成多份,每一份可被称之为一个“副本”,这些“副本”除了一些描述性的信息(Pod 的名字、uid 等)不一样以外,其它信息都是一样的,譬如 Pod 内部的容器、容器数量、容器里面运行的应用等的这些信息都是一样的,这些副本提供同样的功能。
Pod 的“控制器”通常包含一个名为 “replicas” 的属性。“replicas”属性则指定了特定 Pod 的副本的数量,当当前集群中该 Pod 的数量与该属性指定的值不一致时,k8s 会采取一些策略去使得当前状态满足配置的要求。
当 Pod 被创建出来,Pod 会被调度到集群中的节点上运行,Pod 会在该节点上一直保持运行状态,直到进程终止、Pod 对象被删除、Pod 因节点资源不足而被驱逐或者节点失效为止。Pod 并不会自愈,当节点失效,或者调度 Pod 的这一操作失败了,Pod 就该被删除。如此,单单用 Pod 来部署应用,是不稳定不安全的。
Kubernetes 使用更高级的资源对象 “控制器” 来实现对Pod的管理。控制器可以为您创建和管理多个 Pod,管理副本和上线,并在集群范围内提供自修复能力。 例如,如果一个节点失败,控制器可以在不同的节点上调度一样的替身来自动替换 Pod。
Replication Controller 简称 RC,RC 是 Kubernetes 系统中的核心概念之一,简单来说,RC 可以保证在任意时间运行 Pod 的副本数量,能够保证 Pod 总是可用的。如果实际 Pod 数量比指定的多那就结束掉多余的,如果实际数量比指定的少就新启动一些Pod,当 Pod 失败、被删除或者挂掉后,RC 都会去自动创建新的 Pod 来保证副本数量,所以即使只有一个 Pod,我们也应该使用 RC 来管理我们的 Pod。可以说,通过 ReplicationController,Kubernetes 实现了 Pod 的高可用性。
- ReplicaSet(RS) > RC (ReplicationController )主要的作用就是用来确保容器应用的副本数始终保持在用户定义的副本数 。即如果有容器异常退出,会自动创建新的 Pod 来替代;而如果异常多出来的容器也会自动回收(已经成为过去时),在 v1.11 版本废弃。 > Kubernetes 官方建议使用 RS(ReplicaSet ) 替代 RC (ReplicationController ) 进行部署,RS 跟 RC 没有本质的不同,只是名字不一样,并且 RS 支持集合式的 selector。 - Label 和 Selector > label (标签)是附加到 Kubernetes 对象(比如 Pods)上的键值对,用于区分对象(比如Pod、Service)。 label 旨在用于指定对用户有意义且相关的对象的标识属性,但不直接对核心系统有语义含义。 label 可以用于组织和选择对象的子集。label 可以在创建时附加到对象,随后可以随时添加和修改。可以像 namespace 一样,使用 label 来获取某类对象,但 label 可以与 selector 一起配合使用,用表达式对条件加以限制,实现更精确、更灵活的资源查找。 > label 与 selector 配合,可以实现对象的“关联”,“Pod 控制器” 与 Pod 是相关联的 —— “Pod 控制器”依赖于 Pod,可以给 Pod 设置 label,然后给“控制器”设置对应的 selector,这就实现了对象的关联。 - Deployment - 创建 Replica Set / Pod - 滚动升级/回滚 - 平滑扩容和缩容 - 暂停与恢复 Deployment > Deployment 为 Pod 和 Replica Set 提供声明式更新。 > 只需要在 Deployment 中描述你想要的目标状态是什么,Deployment controller 就会帮你将 Pod 和 Replica Set 的实际状态改变到你的目标状态。你可以定义一个全新的 Deployment,也可以创建一个新的替换旧的 Deployment。
StatefulSet 中每个 Pod 的 DNS 格式为 statefulSetName-{0..N-1}.serviceName.namespace.svc.cluster.local serviceName 为 Headless Service 的名字 0..N-1 为 Pod 所在的序号,从 0 开始到 N-1 statefulSetName 为 StatefulSet 的名字 namespace 为服务所在的 namespace,Headless Servic 和 StatefulSet 必须在相同的 namespace .cluster.local 为 Cluster Domain
主要特点
即 Pod 重新调度后还是能访问到相同的持久化数据,基于 PVC 来实现
稳定的网络标志,即 Pod 重新调度后其 PodName 和 HostName 不变,基于 Headless Service(即没有 Cluster IP 的 Service)来实现
有序部署,有序扩展,即 Pod 是有顺序的,在部署或者扩展的时候要依据定义的顺序依次依次进行(即从 0到 N-1,在下一个Pod 运行之前所有之前的 Pod 必须都是 Running 和 Ready 状态),基于 init containers 来实现
有序收缩,有序删除(即从 N-1 到 0)
组成
用于定义网络标志(DNS domain)
Domain Name Server:域名服务 将域名与 ip 绑定映射关系
服务名 => 访问路径(域名) => ip
用于创建 PersistentVolumes
注意事项
DaemonSet 保证在每个 Node 上都运行一个容器副本,常用来部署一些集群的日志、监控或者其他系统管理应用。典型的应用包括:
一次性任务,运行完成后Pod销毁,不再重新启动新容器。
CronJob 是在 Job 基础上加上了定时功能。
“Service” 简写 “svc”。Pod 不能直接提供给外网访问,而是应该使用 service。Service 就是把 Pod 暴露出来提供服务,Service 才是真正的“服务”,它的中文名就叫“服务”。
可以说 Service 是一个应用服务的抽象,定义了 Pod 逻辑集合和访问这个 Pod 集合的策略。Service 代理 Pod 集合,对外表现为一个访问入口,访问该入口的请求将经过负载均衡,转发到后端 Pod 中的容器。
Ingress 可以提供外网访问 Service 的能力。可以把某个请求地址映射、路由到特定的 service。
ingress 需要配合 ingress controller 一起使用才能发挥作用,ingress 只是相当于路由规则的集合而已,真正实现路由功能的,是 Ingress Controller,ingress controller 和其它 k8s 组件一样,也是在 Pod 中运行。
数据卷,共享 Pod 中容器使用的数据。用来放持久化的数据,比如数据库数据。
Container Storage Interface 是由来自 Kubernetes、Mesos、Docker 等社区成员联合制定的一个行业标准接口规范,旨在将任意存储系统暴露给容器化应用程序。
CSI 规范定义了存储提供商实现 CSI 兼容的 Volume Plugin 的最小操作集和部署建议。CSI 规范的主要焦点是声明 Volume Plugin 必须实现的接口。
用来放配置,与 Secret 是类似的,只是 ConfigMap 放的是明文的数据,Secret 是密文存放。
Secret 解决了密码、token、密钥等敏感数据的配置问题,而不需要把这些敏感数据暴露到镜像或者 Pod Spec 中。Secret 可以以 Volume 或者环境变量的方式使用。
downwardAPI 这个模式和其他模式不一样的地方在于它不是为了存放容器的数据也不是用来进行容器和宿主机的数据交换的,而是让 pod 里的容器能够直接获取到这个 pod 对象本身的一些信息。
downwardAPI 提供了两种方式用于将 pod 的信息注入到容器内部:
环境变量:用于单个变量,可以将 pod 信息和容器信息直接注入容器内部
volume 挂载:将 pod 信息生成为文件,直接挂载到容器内部中去
Role 是一组权限的集合,例如 Role 可以包含列出 Pod 权限及列出 Deployment 权限,Role 用于给某个 Namespace 中的资源进行鉴权。
RoleBinding :将 Subject 绑定到 Role,RoleBinding 使规则在命名空间内生效。
参数名 | 类型 | 字段说明 |
---|---|---|
apiVersion | String | K8S APl 的版本,可以用 kubectl api versions 命令查询 |
kind | String | yam 文件定义的资源类型和角色 |
metadata | Object | 元数据对象,下面是它的属性 |
metadata.name | String | 元数据对象的名字,比如 pod 的名字 |
metadata.namespace | String | 元数据对象的命名空间 |
Spec | Object | 详细定义对象 |
spec.containers[] | list | 定义 Spec 对象的容器列表 |
spec.containers[].name | String | 为列表中的某个容器定义名称 |
spec.containers[].image | String | 为列表中的某个容器定义需要的镜像名称 |
spec.containers[].imagePullPolicy | string | 定义镜像拉取策略,有 Always、Never、IfNotPresent 三个值可选 - Always(默认):意思是每次都尝试重新拉取镜像 - Never:表示仅适用本地镜像 - IfNotPresent:如果本地有镜像就使用本地镜像,没有就拉取在线镜像。 |
spec.containers[].command[] | list | 指定容器启动命令,因为是数组可以指定多个,不指定则使用镜像打包时使用的启动命令。 |
spec.containers[].args[] | list | 指定容器启动命令参数,因为是数组可以指定多个。 |
spec.containers[].workingDir | string | 指定容器的工作目录 |
spec.containers[].volumeMounts[] | list | 指定容器内部的存储卷配置 |
spec.containers[].volumeMounts[].name | string | 指定可以被容器挂载的存储卷的名称 |
spec.containers[].volumeMounts[].mountPath | string | 指定可以被容器挂载的存储卷的路径 |
spec.containers[].volumeMounts[].readOnly | string | 设置存储卷路径的读写模式,ture 或者 false,默认是读写模式 |
spec.containers[].ports[] | list | 指定容器需要用到的端口列表 |
spec.containers[].ports[].name | string | 指定端口的名称 |
spec.containers[].ports[].containerPort | string | 指定容器需要监听的端口号 |
spec.containers[].ports[].hostPort | string | 指定容器所在主机需要监听的端口号,默认跟上面 containerPort 相同,注意设置了 hostPort 同一台主机无法启动该容器的相同副本(因为主机的端口号不能相同,这样会冲突) |
spec.containers[].ports[].protocol | string | 指定端口协议,支持 TCP 和 UDP,默认值为 TCP |
spec.containers[].env[] | list | 指定容器运行前需设置的环境变量列表 |
spec.containers[].env[].name | string | 指定环境变量名称 |
spec.containers[].env[].value | string | 指定环境变量值 |
spec.containers[].resources | Object | 指定资源限制和资源请求的值(这里开始就是设置容器的资源上限) |
spec.containers[].resources.limits | Object | 指定设置容器运行时资源的运行上限 |
spec.containers[].resources.limits.cpu | string | 指定 CPU 的限制,单位为 Core 数,将用于 docker run –cpu-shares 参数 |
spec.containers[].resources.limits.memory | string | 指定 mem 内存的限制,单位为 MIB、GiB |
spec.containers[].resources.requests | Object | 指定容器启动和调度时的限制设置 |
spec.containers[].resources.requests.cpu | string | CPU请求,单位为core数,容器启动时初始化可用数量 |
spec.containers[].resources.requests.memory | string | 内存请求,单位为MIB、GiB,容器启动的初始化可用数量 |
spec.restartPolicy | string | 定义 pod 的重启策略,可选值为 Always、OnFailure、Never,默认值为 Always。 - Always:pod 一旦终止运行,则无论容器是如何终止的,kubelet 服务都将重启它。 - OnFailure:只有 pod 以非零退出码终止时,kubelet 才会重启该容器。如果容器正常结束(退出码为0),则 kubectl 将不会重启它。 - Never:Pod 终止后,kubelet 将退出码报告给 master,不会重启该 pod |
spec.nodeSelector | Object | 定义 Node 的 label 过滤标签,以 key:value 格式指定 |
spec.imagePullSecrets | Object | 定义 pull 镜像时使用 secret 名称,以 name:secretkey 格式指定 |
spec.hostNetwork | Boolean | 定义是否使用主机网络模式,默认值为 false。设置 true 表示使用宿主机网络,不使用 docker 网桥,同时设置了 true将无法在同一台宿主机上启动第二个副本 |
......
命令行工具 (kubectl) Kubernetes 提供 kubectl 是使用 Kubernetes API 与 Kubernetes 集群的控制面进行通信的命令行工具。
bashscp /etc/kubernetes/admin.conf root@k8s-node1:/etc/kubernetes
bashecho "export KUBECONFIG=/etc/kubernetes/admin.conf" >> ~/.bash_profile
source ~/.bash_profile
bash$ kubectl create -f ./my-manifest.yaml # 创建资源
$ kubectl create -f ./my1.yaml -f ./my2.yaml # 使用多个文件创建资源
$ kubectl create -f ./dir # 使用目录下的所有清单文件来创建资源
$ kubectl create -f https://git.io/vPieo # 使用 url 来创建资源
$ kubectl run nginx --image=nginx # 启动一个 nginx 实例
$ kubectl explain pods,svc # 获取 pod 和 svc 的文档
# 从 stdin 输入中创建多个 YAML 对象
$ cat <<EOF | kubectl create -f -
apiVersion: v1
kind: Pod
metadata:
name: busybox-sleep
spec:
containers:
- name: busybox
image: busybox
args:
- sleep
- "1000000"
---
apiVersion: v1
kind: Pod
metadata:
name: busybox-sleep-less
spec:
containers:
- name: busybox
image: busybox
args:
- sleep
- "1000"
EOF
# 创建包含几个 key 的 Secret
$ cat <<EOF | kubectl create -f -
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
password: $(echo "s33msi4" | base64)
username: $(echo "jane" | base64)
EOF
bash# Get commands with basic output
$ kubectl get services # 列出所有 namespace 中的所有 service
$ kubectl get pods --all-namespaces # 列出所有 namespace 中的所有 pod
$ kubectl get pods -o wide # 列出所有 pod 并显示详细信息
$ kubectl get deployment my-dep # 列出指定 deployment
$ kubectl get pods --include-uninitialized # 列出该 namespace 中的所有 pod 包括未初始化的
# 使用详细输出来描述命令
$ kubectl describe nodes my-node
$ kubectl describe pods my-pod
$ kubectl get services --sort-by=.metadata.name # List Services Sorted by Name
# 根据重启次数排序列出 pod
$ kubectl get pods --sort-by='.status.containerStatuses[0].restartCount'
# 获取所有具有 app=cassandra 的 pod 中的 version 标签
$ kubectl get pods --selector=app=cassandra rc -o \
jsonpath='{.items[*].metadata.labels.version}'
# 获取所有节点的 ExternalIP
$ kubectl get nodes -o jsonpath='{.items[*].status.addresses[?(@.type=="ExternalIP")].address}'
# 列出属于某个 PC 的 Pod 的名字
# “jq”命令用于转换复杂的 jsonpath,参考 https://stedolan.github.io/jq/
$ sel=${$(kubectl get rc my-rc --output=json | jq -j '.spec.selector | to_entries | .[] | "\(.key)=\(.value),"')%?}
$ echo $(kubectl get pods --selector=$sel --output=jsonpath={.items..metadata.name})
# 查看哪些节点已就绪
$ JSONPATH='{range .items[*]}{@.metadata.name}:{range @.status.conditions[*]}{@.type}={@.status};{end}{end}' \
&& kubectl get nodes -o jsonpath="$JSONPATH" | grep "Ready=True"
# 列出当前 Pod 中使用的 Secret
$ kubectl get pods -o json | jq '.items[].spec.containers[].env[]?.valueFrom.secretKeyRef.name' | grep -v null | sort | uniq
bash$ kubectl rolling-update frontend-v1 -f frontend-v2.json # 滚动更新 pod frontend-v1
$ kubectl rolling-update frontend-v1 frontend-v2 --image=image:v2 # 更新资源名称并更新镜像
$ kubectl rolling-update frontend --image=image:v2 # 更新 frontend pod 中的镜像
$ kubectl rolling-update frontend-v1 frontend-v2 --rollback # 退出已存在的进行中的滚动更新
$ cat pod.json | kubectl replace -f - # 基于 stdin 输入的 JSON 替换 pod
# 强制替换,删除后重新创建资源。会导致服务中断。
$ kubectl replace --force -f ./pod.json
# 为 nginx RC 创建服务,启用本地 80 端口连接到容器上的 8000 端口
$ kubectl expose rc nginx --port=80 --target-port=8000
# 更新单容器 pod 的镜像版本(tag)到 v4
$ kubectl get pod mypod -o yaml | sed 's/\(image: myimage\):.*$/\1:v4/' | kubectl replace -f -
$ kubectl label pods my-pod new-label=awesome # 添加标签
$ kubectl annotate pods my-pod icon-url=http://goo.gl/XXBTWq # 添加注解
$ kubectl autoscale deployment foo --min=2 --max=10 # 自动扩展 deployment “foo”
bash$ kubectl patch node k8s-node-1 -p '{"spec":{"unschedulable":true}}' # 部分更新节点
# 更新容器镜像; spec.containers[*].name 是必须的,因为这是合并的关键字
$ kubectl patch pod valid-pod -p '{"spec":{"containers":[{"name":"kubernetes-serve-hostname","image":"new image"}]}}'
# 使用具有位置数组的 json 补丁更新容器镜像
$ kubectl patch pod valid-pod --type='json' -p='[{"op": "replace", "path": "/spec/containers/0/image", "value":"new image"}]'
# 使用具有位置数组的 json 补丁禁用 deployment 的 livenessProbe
$ kubectl patch deployment valid-deployment --type json -p='[{"op": "remove", "path": "/spec/template/spec/containers/0/livenessProbe"}]'
bash$ kubectl edit svc/docker-registry # 编辑名为 docker-registry 的 service
$ KUBE_EDITOR="nano" kubectl edit svc/docker-registry # 使用其它编辑器
bash$ kubectl scale --replicas=3 rs/foo # Scale a replicaset named 'foo' to 3
$ kubectl scale --replicas=3 -f foo.yaml # Scale a resource specified in "foo.yaml" to 3
$ kubectl scale --current-replicas=2 --replicas=3 deployment/mysql # If the deployment named mysql's current size is 2, scale mysql to 3
$ kubectl scale --replicas=5 rc/foo rc/bar rc/baz # Scale multiple replication controllers
bash$ kubectl delete -f ./pod.json # 删除 pod.json 文件中定义的类型和名称的 pod
$ kubectl delete pod,service baz foo # 删除名为“baz”的 pod 和名为“foo”的 service
$ kubectl delete pods,services -l name=myLabel # 删除具有 name=myLabel 标签的 pod 和 serivce
$ kubectl delete pods,services -l name=myLabel --include-uninitialized # 删除具有 name=myLabel 标签的 pod 和 service,包括尚未初始化的
$ kubectl -n my-ns delete po,svc --all # 删除 my-ns namespace 下的所有 pod 和 serivce,包括尚未初始化的
bash$ kubectl logs my-pod # dump 输出 pod 的日志(stdout)
$ kubectl logs my-pod -c my-container # dump 输出 pod 中容器的日志(stdout,pod 中有多个容器的情况下使用)
$ kubectl logs -f my-pod # 流式输出 pod 的日志(stdout)
$ kubectl logs -f my-pod -c my-container # 流式输出 pod 中容器的日志(stdout,pod 中有多个容器的情况下使用)
$ kubectl run -i --tty busybox --image=busybox -- sh # 交互式 shell 的方式运行 pod
$ kubectl attach my-pod -i # 连接到运行中的容器
$ kubectl port-forward my-pod 5000:6000 # 转发 pod 中的 6000 端口到本地的 5000 端口
$ kubectl exec my-pod -- ls / # 在已存在的容器中执行命令(只有一个容器的情况下)
$ kubectl exec my-pod -c my-container -- ls / # 在已存在的容器中执行命令(pod 中有多个容器的情况下)
$ kubectl top pod POD_NAME --containers # 显示指定 pod 和容器的指标度量
bash$ kubectl cordon my-node # 标记 my-node 不可调度
$ kubectl drain my-node # 清空 my-node 以待维护
$ kubectl uncordon my-node # 标记 my-node 可调度
$ kubectl top node my-node # 显示 my-node 的指标度量
$ kubectl cluster-info # 显示 master 和服务的地址
$ kubectl cluster-info dump # 将当前集群状态输出到 stdout
$ kubectl cluster-info dump --output-directory=/path/to/cluster-state # 将当前集群状态输出到 /path/to/cluster-state
# 如果该键和影响的污点(taint)已存在,则使用指定的值替换
$ kubectl taint nodes foo dedicated=special-user:NoSchedule
资源类型 | 缩写别名 |
---|---|
clusters | |
componentstatuses | cs |
configmaps | cm |
daemonsets | ds |
deployments | deploy |
endpoints | ep |
event | ev |
horizontalpodautoscalers | hpa |
ingresses | ing |
jobs | |
limitranges | limits |
namespaces | ns |
networkpolicies | |
nodes | no |
statefulsets | |
persistentvolumeclaims | pvc |
persistentvolumes | pv |
pods | po |
podsecuritypolicies | psp |
podtemplates | |
replicasets | rs |
replicationcontrollers | rc |
resourcequotas | quota |
cronjob | |
secrets | |
serviceaccount | sa |
services | svc |
storageclasses | |
thirdpartyresources |
-o json
-o name
-o wide
-o yaml
REST API 是 Kubernetes 系统的重要部分,组件之间的所有操作和通信均由 API Server 处理的 REST AP I调用,大多数情况下, API 定义和实现都符合标准的 HTTP REST 格式,可以通过 kubectl 命令管理工具或其他命令行工具来执行。
nginx-demo.yaml
:bashapiVersion: v1
kind: Pod # 指定要创建的资源类型是 Pod
metadata:
name: nginx-demo # Pod 的名称
labels:
type: app # 标签键,标识该 Pod 的类型为应用
version: 1.0.0 # 标签值,表示该 Pod 的版本
namespace: 'default' # Pod 所属的命名空间,'default' 表示使用默认命名空间
spec:
containers:
- name: nginx # 容器的名称
image: nginx:1.7.9 # 容器使用的镜像,nginx:1.7.9 表示 Nginx 的版本 1.7.9
imagePullPolicy: IfNotPresent # 拉取镜像的策略,如果本地已有镜像,则不会重新拉取
command:
- nginx # 容器启动时执行的命令,指定启动 Nginx
- -g
- 'daemon off;' # 额外的命令参数,指定 Nginx 在前台模式下运行
workingDir: /usr/share/nginx/html # 容器的工作目录,Nginx 将在这个目录下查找文件
ports:
- name: http # 端口的名称
containerPort: 80 # 容器内部暴露的端口,80 是 HTTP 的默认端口
protocol: TCP # 使用的网络协议,HTTP 通常使用 TCP 协议
env:
- name: JVM_OPTS # 环境变量的名称
value: '-Xms128m -Xmx128' # 环境变量的值,用于 JVM 配置最小和最大内存
resources:
requests: # 资源请求,指定容器需要的最小资源
cpu: 100m # 请求的 CPU 量,100m 表示 0.1 个 CPU
memory: 128Mi # 请求的内存量,128Mi 表示 128 兆字节
limits: # 资源限制,指定容器可以使用的最大资源
cpu: 200m # 限制的 CPU 量,200m 表示 0.2 个 CPU
memory: 256Mi # 限制的内存量,256Mi 表示 256 兆字节
restartPolicy: OnFailure # 容器的重启策略,当容器失败时,Kubernetes 将尝试重新启动容器
使用kubectl create -f nginx-demo.yaml
创建pod
bash[root@k8s-master pods]# kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-demo 1/1 Running 0 45s
bash[root@k8s-master pods]# kubectl get po -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-demo 1/1 Running 0 2m24s 10.244.36.88 k8s-node1 <none> <none>
kubectl describe po nginx-demo
命令查看详细信息k8s 1.16 版本新增的探针,用于判断应用程序是否已经启动了。
当配置了 startupProbe 后,会先禁用其他探针,直到 startupProbe 成功后,其他探针才会继续。
作用:由于有时候不能准确预估应用一定是多长时间启动成功,因此配置另外两种方式不方便配置初始化时长来检测,而配置了 statupProbe 后,只有在应用启动成功了,才会执行另外两种探针,可以更加方便的结合使用另外两种探针使用。
yamlstartupProbe:
httpGet:
path: /api/startup
port: 80
用于探测容器中的应用是否运行,如果探测失败,kubelet 会根据配置的重启策略进行重启,若没有配置,默认就认为容器启动成功,不会执行重启策略。
yamllivenessProbe:
failureThreshold: 5
httpGet:
path: /health
port: 8080
scheme: HTTP
initialDelaySeconds: 60
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 5
用于探测容器内的程序是否健康,它的返回值如果返回 success,那么就认为该容器已经完全启动,并且该容器是可以接收外部流量的。
yamlreadinessProbe:
failureThreshold: 3 # 错误次数
httpGet:
path: /ready
port: 8181
scheme: HTTP
periodSeconds: 10 # 间隔时间
successThreshold: 1
timeoutSeconds: 1
在容器内部执行一个命令,如果返回值为 0,则任务容器时健康的。
yamllivenessProbe:
exec:
command:
- cat
- /health
通过 tcp 连接监测容器内端口是否开放,如果开放则证明该容器健康
yamllivenessProbe:
tcpSocket:
port: 80
生产环境用的较多的方式,发送 HTTP 请求到容器内的应用程序,如果接口返回的状态码在 200~400 之间,则认为容器健康。
yamllivenessProbe:
failureThreshold: 5
httpGet:
path: /health
port: 8080
scheme: HTTP
httpHeaders:
- name: xxx
value: xxx
bashinitialDelaySeconds: 60 # 初始化时间
timeoutSeconds: 2 # 超时时间
periodSeconds: 5 # 监测间隔时间
successThreshold: 1 # 检查 1 次成功就表示成功
failureThreshold: 2 # 监测失败 2 次就表示失败
bash[root@k8s-master pods]# kubectl get po -n kube-system
NAME READY STATUS RESTARTS AGE
calico-kube-controllers-64cc74d646-b7zgf 1/1 Running 5 (82m ago) 17d
calico-node-lnmv6 1/1 Running 7 (82m ago) 17d
calico-node-rd2xc 1/1 Running 5 (82m ago) 17d
calico-node-sjzg8 1/1 Running 6 (82m ago) 17d
coredns-6d8c4cb4d-6qj6t 1/1 Running 5 (82m ago) 17d
coredns-6d8c4cb4d-7z5mx 1/1 Running 5 (82m ago) 17d
etcd-k8s-master 1/1 Running 7 (82m ago) 17d
kube-apiserver-k8s-master 1/1 Running 7 (82m ago) 17d
kube-controller-manager-k8s-master 1/1 Running 7 (82m ago) 17d
kube-proxy-45cmx 1/1 Running 6 (82m ago) 17d
kube-proxy-mh4vz 1/1 Running 7 (82m ago) 17d
kube-proxy-zvdwz 1/1 Running 7 (82m ago) 17d
kube-scheduler-k8s-master 1/1 Running 7 (82m ago) 17d
[root@k8s-master pods]# kubectl edit deployment -n kube-system coredns
无法直接去修改pod
bash[root@k8s-master pods]# kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-demo 1/1 Running 0 25m
[root@k8s-master pods]# kubectl edit po nginx-demo
bashstartupProbe:
httpGet:
path: /api/path # 探针发送 HTTP GET 请求的路径。这个路径是容器内的服务端点,用于检查容器是否准备好接收请求。
port: 80 # 探针发送 HTTP GET 请求的端口号。这个端口号必须与容器内部服务的端口一致。
initialDelaySeconds: 10 # 在容器启动后,探针开始执行之前的等待时间(以秒为单位)。在此延迟之后,探针开始对容器进行检查。
periodSeconds: 10 # 探针的执行频率(以秒为单位)。指定每隔多长时间对容器执行一次检查。
failureThreshold: 3 # 探针失败的阈值。当探针连续失败达到此阈值时,Kubernetes 将认为容器启动失败并重启容器。
successThreshold: 1 # 探针成功的阈值。当探针连续成功达到此阈值时,Kubernetes 将认为容器启动成功,不再进行启动检查。
由于/api/path接口不存在, 因此使用kubectl describe po nginx-demo
会显示 Warning Unhealthy 7s (x3 over 27s) kubelet Startup probe failed: HTTP probe failed with statuscode: 404
tcp
exec
set paste
)前两次由于没有那个文件, LivenessProbe检测到所以失败, 而后面执行
kubectl cp
将文件拷贝进去, 因此LivenessProbe探针再次检测时检测到, pod又启动成功
kubectl cp
后探针检测到, 状态恢复正常yamllifecycle:
postStart: # 容创建完成后执行的动作,不能保证该操作一定在容器的 command 之前执行,一般不使用
exec: # 可以是 exec / httpGet / tcpSocket
command:
- sh
- -c
- 'mkdir /data'
preStop: # 在容器停止前执行的动作
httpGet: # 发送一个 http 请求
path: /
port: 80
exec: # 执行一个命令
command:
- sh
- -c
- sleep 9
变为删除中的状态后,会给 pod 一个宽限期,让 pod 去执行一些清理或销毁操作。
yaml# 作用于 pod 中的所有容器
terminationGracePeriodSeconds: 30
containers:
- xxx
配置参数:
如果应用销毁操作耗时需要比较长,可以在 preStop 按照如下方式进行配置
yamlpreStop:
exec:
command:
- sh
- -c
- 'sleep 20; kill pgrep java'
在各类资源的 metadata.labels 中进行配置
kubectl label po <资源名称> app=hello
kubectl label po <资源名称> app=hello2 --overwrite
selector 按照 label 单值查找节点
kubectl get po -A -l app=hello
查看所有节点的 labels
kubectl get po --show-labels
在各对象的配置 spec.selector 或其他可以写 selector 的属性中编写
匹配单个值,查找 app=hello 的 pod
kubectl get po -A -l app=hello
匹配多个值
kubectl get po -A -l 'k8s-app in (metrics-server, kubernetes-dashboard)'
或者
查找 version!=1 and app=nginx 的 pod 信息
kubectl get po -l version!=1,app=nginx
不等值 + 语句
kubectl get po -A -l version!=1,'app in (busybox, nginx)'
创建一个 deployment
kubectl create deploy nginx-deploy --image=nginx:1.7.9
或执行
kubectl create -f xxx.yaml --record
--record 会在 annotation 中记录当前命令创建或升级了资源,后续可以查看做过哪些变动操作。
查看部署信息
kubectl get deployments
查看 rs
kubectl get rs
查看 pod 以及展示标签,可以看到是关联的那个 rs
kubectl get pods --show-labels
yamlapiVersion: apps/v1 # 定义 API 版本,使用 apps/v1 表示这是一个 Deployment 对象
kind: Deployment # 定义资源类型,这里是一个 Deployment
metadata:
labels:
app: nginx-deploy # 标签,给 Deployment 对象打标签,方便识别和管理
name: nginx-deploy # Deployment 的名称
namespace: default # 指定 Deployment 所在的命名空间,默认是 default
spec:
replicas: 1 # 副本数量,定义了运行的 Pod 副本数量
revisionHistoryLimit: 10 # 记录的历史版本数量,超出这个限制的版本会被删除
selector:
matchLabels:
app: nginx-deploy # 匹配 Pod 的标签,用于确定哪些 Pod 属于这个 Deployment
strategy: # 定义更新策略
rollingUpdate: # 使用滚动更新策略,在更新过程中逐步替换 Pod
maxSurge: 25% # 定义在更新时允许创建的最大额外 Pod 数量,可以是绝对值或百分比
maxUnavailable: 25% # 更新时允许最大不可用的 Pod 数量,可以是绝对值或百分比
type: RollingUpdate # 设置更新类型为滚动更新
template: # Pod 模板,定义 Deployment 中的 Pod 规格
metadata:
labels:
app: nginx-deploy # Pod 的标签,用于与 selector 匹配
spec: # Pod 规格
containers:
- image: nginx:1.7.9 # 容器使用的镜像,这里是 nginx 1.7.9 版本
imagePullPolicy: IfNotPresent # 镜像拉取策略,只有当本地没有镜像时才拉取
name: nginx # 容器的名称
restartPolicy: Always # 容器重启策略,表示容器退出时始终重启
terminationGracePeriodSeconds: 30 # 容器终止的宽限时间,确保在 30 秒内优雅终止 Pod
只有修改了 deployment 配置文件中的 template 中的属性后,才会触发更新操作
kubectl set image deployment/nginx-deployment nginx=nginx:1.9.1
或者通过 kubectl edit deployment/nginx-deployment
进行修改
查看滚动更新的过程
kubectl rollout status deploy <deployment_name>
查看部署描述,最后展示发生的事件列表也可以看到滚动更新过程
kubectl describe deploy <deployment_name>
通过 kubectl get deployments
获取部署信息,UP-TO-DATE
表示已经有多少副本达到了配置中要求的数目
通过 kubectl get rs
可以看到增加了一个新的 rs
通过 kubectl get pods
可以看到所有 pod 关联的 rs 变成了新的
bash[root@k8s-master deployments]# kubectl set image deployment/nginx-deploy nginx=nginx:1.7.9
deployment.apps/nginx-deploy image updated
[root@k8s-master deployments]# kubectl describe deploy
Name: nginx-deploy
Namespace: default
CreationTimestamp: Fri, 06 Sep 2024 19:24:09 +0800
Labels: app=nginx-deploy
teest=123
Annotations: deployment.kubernetes.io/revision: 3
Selector: app=nginx-deploy
Replicas: 3 desired | 3 updated | 3 total | 3 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=nginx-deploy
Containers:
nginx:
Image: nginx:1.7.9
Port: <none>
Host Port: <none>
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: nginx-deploy-78d8bf4fd7 (3/3 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 3m46s deployment-controller Scaled up replica set nginx-deploy-754898b577 to 1
Normal ScalingReplicaSet 3m25s deployment-controller Scaled down replica set nginx-deploy-78d8bf4fd7 to 2
Normal ScalingReplicaSet 3m25s deployment-controller Scaled up replica set nginx-deploy-754898b577 to 2
Normal ScalingReplicaSet 3m2s deployment-controller Scaled up replica set nginx-deploy-754898b577 to 3
Normal ScalingReplicaSet 3m2s deployment-controller Scaled down replica set nginx-deploy-78d8bf4fd7 to 1
Normal ScalingReplicaSet 3m deployment-controller Scaled down replica set nginx-deploy-78d8bf4fd7 to 0
Normal ScalingReplicaSet 29s (x2 over 23m) deployment-controller Scaled up replica set nginx-deploy-78d8bf4fd7 to 1
Normal ScalingReplicaSet 26s deployment-controller Scaled down replica set nginx-deploy-754898b577 to 2
Normal ScalingReplicaSet 24s (x2 over 5m15s) deployment-controller Scaled up replica set nginx-deploy-78d8bf4fd7 to 3
Normal ScalingReplicaSet 22s (x3 over 26s) deployment-controller (combined from similar events): Scaled down replica set nginx-deploy-754898b577 to 0
假设当前有 5 个 nginx:1.7.9 版本,你想将版本更新为 1.9.1,当更新成功第三个以后,你马上又将期望更新的版本改为 1.9.2,那么此时会立马删除之前的三个,并且立马开启更新 1.9.2 的任务
有时候你可能想回退一个Deployment,例如,当Deployment不稳定时,比如一直crash looping。
默认情况下,kubernetes会在系统中保存前两次的Deployment的rollout历史记录,以便你可以随时会退(你可以修改revision history limit来更改保存的revision数)。
更新 deployment 时参数不小心写错,如 nginx:1.9.1 写成了 nginx:1.91
kubectl set image deployment/nginx-deploy nginx=nginx:1.91
监控滚动升级状态,由于镜像名称错误,下载镜像失败,因此更新过程会卡住
kubectl rollout status deployments nginx-deploy
结束监听后,获取 rs 信息,我们可以看到新增的 rs 副本数是 2 个
kubectl get rs
--record
参数后可加描述信息, 说明修改原因
为了修复这个问题,我们需要找到需要回退的 revision 进行回退
通过 kubectl rollout history deployment/nginx-deploy
可以获取 revison 的列表
通过 kubectl rollout history deployment/nginx-deploy --revision=2
可以查看详细信息
确认要回退的版本后,可以通过 kubectl rollout undo deployment/nginx-deploy
可以回退到上一个版本
也可以回退到指定的 revision
kubectl rollout undo deployment/nginx-deploy --to-revision=2
kubectl get deployment
和 kubectl describe deployment
可以看到,我们的版本已经回退到对应的 revison 上了.spec.revisonHistoryLimit
来指定 deployment 保留多少 revison,如果设置为 0,则不允许 deployment 回退了。通过 kube scale 命令可以进行自动扩容/缩容,以及通过 kube edit 编辑 replcas 也可以实现扩容/缩容
扩容与缩容只是直接创建副本数,没有更新 pod template 因此不会创建新的 rs
由于每次对 pod template 中的信息发生修改后,都会触发更新 deployment 操作,那么此时如果频繁修改信息,就会产生多次更新,而实际上只需要执行最后一次更新即可,当出现此类情况时我们就可以暂停 deployment 的 rollout
通过 kubectl rollout pause deployment <name>
就可以实现暂停,直到你下次恢复后才会继续进行滚动更新
尝试对容器进行修改,然后查看是否发生更新操作了
kubectl set image deploy <name> nginx=nginx:1.17.9
kubectl get po
通过以上操作可以看到实际并没有发生修改,此时我们再次进行修改一些属性,如限制 nginx 容器的最大cpu为 0.2 核,最大内存为 128M,最小内存为 64M,最小 cpu 为 0.1 核
kubectl set resources deploy <deploy_name> -c <container_name> --limits=cpu=200m,memory=128Mi --requests=cpu100m,memory=64Mi
通过格式化输出 kubectl get deploy <name> -oyaml
,可以看到配置确实发生了修改,再通过 kubectl get po
可以看到 pod 没有被更新
那么此时我们再恢复 rollout,通过命令 kubectl rollout deploy <name>
恢复后,我们再次查看 rs 和 po 信息,我们可以看到就开始进行滚动更新操作了
kubectl get rs
kubectl get po
示例:
yamlapiVersion: apps/v1 # deployment api 版本
kind: Deployment # 资源类型为 deployment
metadata: # 元信息
labels: # 标签
app: nginx-deploy # 具体的 key: value 配置形式
name: nginx-deploy # deployment 的名字
namespace: default # 所在的命名空间
spec:
replicas: 1 # 期望副本数
revisionHistoryLimit: 10 # 进行滚动更新后,保留的历史版本数
selector: # 选择器,用于找到匹配的 RS
matchLabels: # 按照标签匹配
app: nginx-deploy # 匹配的标签key/value
strategy: # 更新策略
rollingUpdate: # 滚动更新配置
maxSurge: 25% # 进行滚动更新时,更新的个数最多可以超过期望副本数的个数/比例
maxUnavailable: 25% # 进行滚动更新时,最大不可用比例更新比例,表示在所有副本数中,最多可以有多少个不更新成功
type: RollingUpdate # 更新类型,采用滚动更新
template: # pod 模板
metadata: # pod 的元信息
labels: # pod 的标签
app: nginx-deploy
spec: # pod 期望信息
containers: # pod 的容器
- image: nginx:1.7.9 # 镜像
imagePullPolicy: IfNotPresent # 拉取策略
name: nginx # 容器名称
restartPolicy: Always # 重启策略
terminationGracePeriodSeconds: 30 # 删除操作最多宽限多长时间
bashkubectl create -f web.yaml
# 查看 service 和 statefulset => sts
kubectl get service nginx
kubectl get statefulset web
# 查看 PVC 信息
kubectl get pvc
# 查看创建的 pod,这些 pod 是有序的
kubectl get pods -l app=nginx
# 查看这些 pod 的 dns
# 运行一个 pod,基础镜像为 busybox 工具包,利用里面的 nslookup 可以看到 dns 信息
kubectl run -i --tty --image busybox dns-test --restart=Never --rm /bin/sh
nslookup web-0.nginx
bash# 扩容
$ kubectl scale statefulset web --replicas=5
# 缩容
$ kubectl patch statefulset web -p '{"spec":{"replicas":3}}'
镜像更新(目前还不支持直接更新 image,需要 patch 来间接实现)
bashkubectl patch sts web --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"nginx:1.9.1"}]'
StatefulSet 也可以采用滚动更新策略,同样是修改 pod template 属性后会触发更新,但是由于 pod 是有序的,在 StatefulSet 中更新时是基于 pod 的顺序倒序更新的
利用滚动更新中的 partition 属性,可以实现简易的灰度发布的效果
例如我们有 5 个 pod,如果当前 partition 设置为 3,那么此时滚动更新时,只会更新那些 序号 >= 3 的 pod
利用该机制,我们可以通过控制 partition 的值,来决定只更新其中一部分 pod,确认没有问题后再主键增大更新的 pod 数量,最终实现全部 pod 更新
只有在 pod 被删除时会进行更新操作
StatefulSet
和 Headless Service
kubectl delete statefulset web
kubectl deelte sts web --cascade=false
kubectl delete service nginx
$ kubectl delete pvc www-web-0 www-web-1
yaml---
apiVersion: v1
kind: Service
metadata:
name: nginx # Service 的名称
labels:
app: nginx # Service 的标签,用于选择器匹配
spec:
ports:
- port: 80 # Service 暴露的端口
name: web # 端口的名称,可以用于识别
clusterIP: None # 将 clusterIP 设置为 None,使其成为无头服务(Headless Service)
selector:
app: nginx # 选择器,用于匹配具有 "app: nginx" 标签的 Pod
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web # StatefulSet 的名称
spec:
serviceName: "nginx" # 使用的无头服务名称,用于稳定的网络身份
replicas: 2 # StatefulSet 中期望的 Pod 数量
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx # 由 StatefulSet 创建的 Pod 的标签
spec:
containers:
- name: nginx # Pod 中容器的名称
image: nginx:1.7.9 # 容器使用的 Docker 镜像
ports:
- containerPort: 80 # 容器暴露的端口
name: web # 容器端口的名称
volumeMounts:
- name: www # 挂载到容器中的卷的名称
mountPath: /usr/share/nginx/html # 卷在容器内的挂载路径
volumeClaimTemplates:
- metadata:
name: www # PersistentVolumeClaim (PVC) 的名称
annotations:
volume.alpha.kubernetes.io/storage-class: anything # 注释,用于指定存储类
spec:
accessModes: [ "ReadWriteOnce" ] # PVC 的访问模式,可以被单个节点读写
resources:
requests:
storage: 1Gi # 卷的存储请求
yamlapiVersion: apps/v1 # 指定 DaemonSet 资源的 API 版本。
kind: DaemonSet # 表示这是一个 DaemonSet,确保集群中的每个节点上都运行一个副本。
metadata:
name: fluentd # DaemonSet 的名称,这里是 "fluentd"。
spec:
template: # 模板定义了 DaemonSet 管理的 Pod 的规格。
metadata:
labels: # 标签用于标识和选择 Kubernetes 中的对象。
app: logging # 标识应用程序的标签。
id: fluentd # 标识应用实例或类型的标签(Fluentd)。
name: fluentd # DaemonSet 管理的 Pod 的名称。
spec:
containers: # 定义 Pod 内运行的容器。
- name: fluentd-es # 容器实例的名称。
image: agilestacks/fluentd-elasticsearch:v1.3.0 # 从 Docker Hub 拉取的容器镜像(支持 Elasticsearch 的 Fluentd)。
env:
- name: FLUENTD_ARGS # 传递给容器的环境变量。
value: -qq # Fluentd 参数,用于安静模式,减少不必要的日志输出。
volumeMounts: # 指定从主机系统挂载到容器中的目录。
- name: containers # 要挂载到容器内的卷的名称。
mountPath: /var/lib/docker/containers # 容器内的路径,用于挂载主机卷。
- name: varlog # 另一个卷挂载。
mountPath: /varlog # 容器内的路径,用于挂载主机日志。
volumes: # 定义要挂载到 Pod 的主机目录。
- hostPath:
path: /var/lib/docker/containers # 主机目录,用于 Docker 容器数据。
name: containers # 用于在 volumeMounts 中引用的卷名称。
- hostPath:
path: /var/log # 主机目录,用于系统日志。
name: varlog # 用于在 volumeMounts 中引用的卷名称。
DaemonSet 会忽略 Node 的 unschedulable 状态,有两种方式来指定 Pod 只运行在指定的
Node 节点上:
先为 Node 打上标签
kubectl label nodes k8s-node1 svc_type=microsvc
yamlspec:
template:
spec:
nodeSelector:
svc_type: microsvc
nodeAffinity 目前支持两种:requiredDuringSchedulingIgnoredDuringExecution 和 preferredDuringSchedulingIgnoredDuringExecution,分别代表必须满足条件和优选条件。
比如下面的例子代表调度到包含标签 wolfcode.cn/framework-name 并且值为 spring 或 springboot 的 Node 上,并且优选还带有标签 another-node-label-key=another-node-label-value 的Node。
yamlapiVersion: v1
kind: Pod
metadata:
name: with-node-affinity
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: wolfcode.cn/framework-name
operator: In
values:
- spring
- springboot
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: another-node-label-key
operator: In
values:
- another-node-label-value
containers:
- name: with-node-affinity
image: pauseyyf/pause
podAffinity 基于 Pod 的标签来选择 Node,仅调度到满足条件Pod 所在的 Node 上,支持 podAffinity 和 podAntiAffinity。这个功能比较绕,以下面的例子为例: 如果一个 “Node 所在空间中包含至少一个带有 auth=oauth2 标签且运行中的 Pod”,那么可以调度到该 Node 不调度到 “包含至少一个带有 auth=jwt 标签且运行中 Pod”的 Node 上
yamlapiVersion: v1
kind: Pod
metadata:
name: with-pod-affinity
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: auth
operator: In
values:
- oauth2
topologyKey: failure-domain.beta.kubernetes.io/zone
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: auth
operator: In
values:
- jwt
topologyKey: kubernetes.io/hostname
containers:
- name: with-pod-affinity
image: pauseyyf/pause
不建议使用 RollingUpdate,建议使用 OnDelete 模式,这样避免频繁更新 ds
通过观察 pod 的 cpu、内存使用率或自定义 metrics 指标进行自动的扩容或缩容 pod 的数量。
通常用于 Deployment,不适用于无法扩/缩容的对象,如 DaemonSet
控制管理器每隔30s(可以通过–horizontal-pod-autoscaler-sync-period修改)查询metrics的资源使用情况
下载 metrics-server 组件配置文件
wget https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml -O metrics-server-components.yaml
修改镜像地址为国内的地址
sed -i 's/k8s.gcr.io\/metrics-server/registry.cn-hangzhou.aliyuncs.com\/google_containers/g' metrics-server-components.yaml
修改容器的 tls 配置,不验证 tls,在 containers 的 args 参数中增加 --kubelet-insecure-tls 参数
安装组件
kubectl apply -f metrics-server-components.yaml
查看 pod 状态
kubectl get pods --all-namespaces | grep metrics
实现 cpu 或内存的监控,首先有个前提条件是该对象必须配置了 resources.requests.cpu 或 resources.requests.memory 才可以,可以配置当 cpu/memory 达到上述配置的百分比后进行扩容或缩容
创建一个 HPA:
测试:找到对应服务的 service,编写循环测试脚本提升内存与 cpu 负载
while true; do wget -q -O- http://<ip:port> > /dev/null ; done
可以通过多台机器执行上述命令,增加负载,当超过负载后可以查看 pods 的扩容情况 kubectl get pods
查看 pods 资源使用情况
kubectl top pods
扩容测试完成后,再关闭循环执行的指令,让 cpu 占用率降下来,然后过 5 分钟后查看自动缩容情况
负责东西流量(同层级/内部服务网络通信)的通信
yamlapiVersion: v1
kind: Service
metadata:
name: nginx-svc
labels:
app: nginx-svc
spec:
ports:
- name: http # service 端口配置的名称
protocol: TCP # 端口绑定的协议,支持 TCP、UDP、SCTP,默认为 TCP
port: 80 # service 自己的端口
targetPort: 9527 # 目标 pod 的端口
- name: https
port: 443
protocol: TCP
targetPort: 443
selector: # 选中当前 service 匹配哪些 pod,对哪些 pod 的东西流量进行代理
app: nginx
创建 service kubectl create -f nginx-svc.yaml
查看 service 信息,通过 service 的 cluster ip 进行访问
kubectl get svc
查看 pod 信息,通过 pod 的 ip 进行访问
kubectl get po -owide
创建其他 pod 通过 service name 进行访问(推荐)
kubectl exec -it busybox -- sh
curl http://nginx-svc
默认在当前 namespace 中访问,如果需要跨 namespace 访问 pod,则在 service name 后面加上 . 即可
curl http://nginx-svc.default
yamlapiVersion: v1
kind: Endpoints
metadata:
labels:
app: wolfcode-svc-external # 与 service 一致
name: wolfcode-svc-external # 与 service 一致
namespace: default # 与 service 一致
subsets:
- addresses:
- ip: <target ip> # 目标 ip 地址
ports: # 与 service 一致
- name: http
port: 80
protocol: TCP
yamlapiVersion: v1
kind: Service
metadata:
labels:
app: wolfcode-external-domain
name: wolfcode-external-domain
spec:
type: ExternalName
externalName: www.wolfcode.cn
只能在集群内部使用,不配置类型的话默认就是 ClusterIP
返回定义的 CNAME 别名,可以配置为域名
会在所有安装了 kube-proxy 的节点都绑定一个端口,此端口可以代理至对应的 Pod,集群外部可以使用任意节点 ip + NodePort 的端口号访问到集群中对应 Pod 中的服务。
类型设置为 NodePort 后,可以在 ports 配置中增加 nodePort 配置指定端口,需要在下方的端口范围内,如果不指定会随机指定端口
端口范围:30000~32767
端口范围配置在 /usr/lib/systemd/system/kube-apiserver.service 文件中
使用云服务商(阿里云、腾讯云等)提供的负载均衡器服务
Ingress 大家可以理解为也是一种 LB 的抽象,它的实现也是支持 nginx、haproxy 等负载均衡服务的
传统
k8s
官方图
https://kubernetes.github.io/ingress-nginx/deploy/#using-helm
添加仓库
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
查看仓库列表
helm repo list
搜索 ingress-nginx
helm search repo ingress-nginx
helm pull ingress-nginx/ingress-nginx
将下载好的安装包解压
tar xf ingress-nginx-xxx.tgz
解压后,进入解压完成的目录
cd ingress-nginx
修改 values.yaml
镜像地址:修改为国内镜像
registry: registry.cn-hangzhou.aliyuncs.com image: google_containers/nginx-ingress-controller image: google_containers/kube-webhook-certgen tag: v1.3.0
hostNetwork: true dnsPolicy: ClusterFirstWithHostNet
修改部署配置的 kind: DaemonSet
nodeSelector:
ingress: "true" # 增加选择器,如果 node 上有 ingress=true 就部署
将 admissionWebhooks.enabled 修改为 false
将 service 中的 type 由 LoadBalancer 修改为 ClusterIP,如果服务器是云平台才用 LoadBalancer
kubectl create ns ingress-nginx
为需要部署 ingress 的节点上加标签
kubectl label node k8s-node1 ingress=true
安装 ingress-nginx
helm install ingress-nginx ./ingress-nginx -n ingress-nginx
yamlapiVersion: networking.k8s.io/v1
kind: Ingress # 资源类型为 Ingress
metadata:
name: wolfcode-nginx-ingress
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules: # ingress 规则配置,可以配置多个
- host: k8s.wolfcode.cn # 域名配置,可以使用通配符 *
http:
paths: # 相当于 nginx 的 location 配置,可以配置多个
- pathType: Prefix # 路径类型,按照路径类型进行匹配 ImplementationSpecific 需要指定 IngressClass,具体匹配规则以 IngressClass 中的规则为准。Exact:精确匹配,URL需要与path完全匹配上,且区分大小写的。Prefix:以 / 作为分隔符来进行前缀匹配
backend:
service:
name: nginx-svc # 代理到哪个 service
port:
number: 80 # service 的端口
path: /api # 等价于 nginx 中的 location 的路径前缀匹配
yamlapiVersion: networking.k8s.io/v1
kind: Ingress # 资源类型为 Ingress
metadata:
name: wolfcode-nginx-ingress
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules: # ingress 规则配置,可以配置多个
- host: k8s.wolfcode.cn # 域名配置,可以使用通配符 *
http:
paths: # 相当于 nginx 的 location 配置,可以配置多个
- pathType: Prefix # 路径类型,按照路径类型进行匹配 ImplementationSpecific 需要指定 IngressClass,具体匹配规则以 IngressClass 中的规则为准。Exact:精确匹配,URL需要与path完全匹配上,且区分大小写的。Prefix:以 / 作为分隔符来进行前缀匹配
backend:
service:
name: nginx-svc # 代理到哪个 service
port:
number: 80 # service 的端口
path: /api # 等价于 nginx 中的 location 的路径前缀匹配
- pathType: Exec # 路径类型,按照路径类型进行匹配 ImplementationSpecific 需要指定 IngressClass,具体匹配规则以 IngressClass 中的规则为准。Exact:精确匹配>,URL需要与path完全匹配上,且区分大小写的。Prefix:以 / 作为分隔符来进行前缀匹配
backend:
service:
name: nginx-svc # 代理到哪个 service
port:
number: 80 # service 的端口
path: /
- host: api.wolfcode.cn # 域名配置,可以使用通配符 *
http:
paths: # 相当于 nginx 的 location 配置,可以配置多个
- pathType: Prefix # 路径类型,按照路径类型进行匹配 ImplementationSpecific 需要指定 IngressClass,具体匹配规则以 IngressClass 中的规则为准。Exact:精确匹配>,URL需要与path完全匹配上,且区分大小写的。Prefix:以 / 作为分隔符来进行前缀匹配
backend:
service:
name: nginx-svc # 代理到哪个 service
port:
number: 80 # service 的端口
path: /
一般用于去存储 Pod 中应用所需的一些配置信息,或者环境变量,将配置于 Pod 分开,避免应为修改配置导致还需要重新构建 镜像与容器。
使用 kubectl create configmap -h 查看示例,构建 configmap 对象
与 ConfigMap 类似,用于存储配置信息,但是主要用于存储敏感信息、需要加密的信息,Secret 可以提供数据加密、解密功能。
在创建 Secret 时,要注意如果要加密的字符中,包含了有特殊字符,需要使用转义符转移,例如 转移后为 \,也可以对特殊字符使用单引号描述,这样就不需要转移例如 1289*-!'
使用 ConfigMap 或 Secret 挂载到目录的时候,会将容器中源目录给覆盖掉,此时我们可能只想覆盖目录中的某一个文件,但是这样的操作会覆盖整个文件,因此需要使用到 SubPath
yamlcontainers:
......
volumeMounts:
- mountPath: /etc/nginx/nginx.conf # 挂载到哪里
name: config-volume # 使用哪个 configmap 或 secret
subPath: etc/nginx/nginx.conf # 与 volumes.[0].items.path 相同
volumes:
- configMap:
name: nginx-conf # configMap 名字
items: # subPath 配置
key: nginx.conf # configMap 中的文件名
path: etc/nginx/nginx.conf # subPath 路径
我们通常会将项目的配置文件作为 configmap 然后挂载到 pod,那么如果更新 configmap 中的配置,会不会更新到 pod 中呢?
对于 subPath 的方式,我们可以取消 subPath 的使用,将配置文件挂载到一个不存在的目录,避免目录的覆盖,然后再利用软连接的形式,将该文件链接到目标位置
但是如果目标位置原本就有文件,可能无法创建软链接,此时可以基于前面讲过的 postStart 操作执行删除命令,将默认的吻技安删除即可
由于 configmap 我们创建通常都是基于文件创建,并不会编写 yaml 配置文件,因此修改时我们也是直接修改配置文件,而 replace 是没有 --from-file 参数的,因此无法实现基于源配置文件的替换,此时我们可以利用下方的命令实现
该命令的重点在于 --dry-run 参数,该参数的意思打印 yaml 文件,但不会将该文件发送给 apiserver,再结合 -oyaml 输出 yaml 文件就可以得到一个配置好但是没有发给 apiserver 的文件,然后再结合 replace 监听控制台输出得到 yaml 数据即可实现替换 kubectl create cm --from-file=nginx.conf --dry-run -oyaml | kubectl replace -f-
对于一些敏感服务的配置文件,在线上有时是不允许修改的,此时在配置 configmap 时可以设置 immutable: true 来禁止修改
本文作者:GYC
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!