Kubernetes
时间轴
2025-10-14
init
Kubernetes 简述和特性
k8s 简述
- k8s 是谷歌在 2014 年开源的容器化集群管理系统
- 使用 k8s 进行容器化应用部署
- 使用 k8s 利于应用扩展
- k8s 目标是是让部署容器化应用更简洁和高效
k8s 功能
- 自动装箱
- 自动修复(自愈能力)
- 水平扩展
- 服务发现
- 滚动更新
- 版本回退
- 密钥和配置管理(类似热部署)
- 存储编排
- 批处理
k8s 集群架构组件
Master(主控节点)和 Node(工作节点)
(1) master 组件
- apiserver
集群统一入口,以 restful 方式,交给 etcd 存储
- scheduler
节点调度,选择 node 节点应用部署
- controller-manager
处理集群中常规后台任务,一个资源对应一个控制器
- etcd
存储系统,用于保存集群相关的数据
(2) node 组件
- kubeelet
master 派到 node 节点的代表,管理本机容器
- kube-proxy
提供网络代理,实现负载均衡等操作
k8s 核心概念
- Pod
- 最小部署单元
- 一组容器的集合
- 共享网络
- 生命周期是短暂的
- Controller
- 确保预期的 pod 副本数量
- 无状态应用部署
- 有状态应用部署
- 确保所有的 node 运行同一个 pod
- 一次性任务和定时任务
- Service
定义一组 pod 的访问规则
Master(主节点): 控制 Kubernetes 节点的机器,也是创建作业任务的地方。
- Node(节点): 这些机器在 Kubernetes 主节点的控制下执行被分配的任务。
- Pod: 由一个或多个容器构成的集合,作为一个整体被部署到一个单一节点。同一个 pod 中的容器共享 IP 地址、进程间通讯(IPC)、主机名以及其它资源。Pod 将底层容器的网络和存储抽象出来,使得集群内的容器迁移更为便捷。
- Replication controller(复制控制器): 控制一个 pod 在集群上运行的实例数量。
- Service(服务): 将服务内容与具体的 pod 分离。Kubernetes 服务代理负责自动将服务请求分发到正确的 pod 处,不管 pod 移动到集群中的什么位置,甚至可以被替换掉。
- Kubelet: 这个守护进程运行在各个工作节点上,负责获取容器列表,保证被声明的容器已经启动并且正常运行。
- kubectl: 这是 Kubernetes 的命令行配置工具
k8s 集群搭建
- 搭建环境平台规划
- 单 master 集群
缺点:master 挂掉就寄了
- 多 master 集群
高可用的集群
- 服务器硬件配置要求
- 测试环境:
master: 2 核 4G 20G
node: 4 核 8G 40G
- 生产环境:
更高要求
- 搭建 k8s 集群部署方式
- kubeadm
一个 k8s 部署工具,提供 kubeadmin init 和 kubeadm josin,用于快速部署 kubernetes 集群
- 二进制包
从 github 下载发行版二进制包,各个组件要单独部署
kubeadm 方式搭建
https://kubernetes.io/zh-cn/docs/setup/production-environment/tools/kubeadm/install-kubeadm/
1 | # 设置服务器hostname |
- 安装 3 台虚拟机,安装操作系统
- 对三个安装之后的操作系统进行初始化操作
- 在三个节点安装 docker kubelet,kubeadm kubectl,更改 docker 源
- 在 master 节点执行 kubeadm init 命令进行初始化
- 在 node 节点上执行 kubeadm join 命令把 node 节点添加到当前集群里面
二进制包搭建
- 创建多台虚拟机,安装 Linux 操作系统
- 操作系统初始化
- 为 etcd 和 apiserver 自签证书
- 部署 etcd 集群
- 部署 master 组件
kube-apiserver,kube-controller-manager,kube-scheduler,etcd
- 部署 node 组件
kebelet,kube-proxy,docker,etcd
- 部署集群网络
k8s 集群命令行工具 kubectl
kubectl 是 Kubernetes 集群的命令行工具,通过 kubectl 能够对集群本身进行管理,并能够在集群上进行容器化应用的安装部署
1 | $ kubectl [command] [type] [name] [flags] |
yaml 文件说明
文件书写格式
通过缩进表示层级关系
不能用 tab 键表示缩进
: 后加一个空格
一般开头缩进两个空格
字符后缩进一个空格
—- 表示一个新的 yaml 文件的开始
使用#代表注释
yaml 文件示例
字段 | 说明 |
---|---|
apiVersion | Api 版本 |
kind | 资源类型 |
metadata | 资源元数据 |
spec | 资源规格 |
replicas | 副本数量 |
selector | 标签选择器 |
template | Pod 模板 |
metadata | Pod 元数据 |
spec | Pod 规格 |
container | 容器配置 |
如何快速编写 yaml 文件
- 使用kubectl create命令生成 yaml 文件
1 | $ kubectl create deployment web --image=nginx -o yaml --dry-run > web1.yaml |
Kubernetes 核心技术
Pod
Pod 概述
Pod 是 k8s 系统中可以创建(部署)和管理的最小单元
k8s 不会直接处理容器,而是 Pod,Pod 可以包含多个容器(一组容器的集合)
一个 pod 中共享网络命名空间
- 每一个 Pod 都有一个特殊的被称为”根容器”的 Pause 容器。Pause 容器对应的镜像属于 k8s 平台的一部分,除了 Pause 容器,每个 Pod 还包含一个或者多个紧密相关的用户业务容器。
- Pod 是短暂的
Pod 存在的意义
- 创建容器使用 docker,一个 docker 对应一个容器,一个容器有进程,一个容器运行一个应用程序
- Pod 是多进程设计,可以运行多个应用程序;一个 Pod 有多个容器,一个容器里面运行一个应用程序
- Pod 存在是为了亲密性交互:
- 两个应用之间进行交互
- 网络之间进行调用
- 两个应用需要频繁调用
Pod 实现机制
- 共享网络
容器本身是相互隔离的,k8s 利用 Pod 的 Pause 容器(info 容器),吧其他业务容器加入到 Pause 容器中,让所有业务容器在同一个名称空间中,可以实现网络共享
- 共享存储
Pod 持久化数据:日志数据,业务数据
使用 Volume 数据卷进行持久化存储
Pod 镜像拉取策略
imagePullPolicy
IfNotPresent: 默认值,镜像在宿主机上不存在时才拉取
Always: 每次创建 Pod 都会拉取一次镜像
Never: Pod 永远不会主动拉取这个镜像,需要手动拉取
Pod 资源限制
1c = 1000m(1 核 cpu)
Pod 重启机制
restartPolicy
Always: 当容器终止推出后,总是重启容器,默认策略
OnFailure: 当容器异常退出(退出状态码非 0)时才重启容器
Never: 当容器终止推出时,从不重启容器
Pod 健康检查
容器检查:
检测不出 java 堆内存溢出(状态还是 running)
应用层面健康检查:
echo $?表示 linux 上一条命令是否执行成功
创建 Pod 流程
- master 节点
createpod — apiserver — etcd
scheducler — apiserver —etcd — 调度算法,吧 pod 调度到某个 node 节点上
- node 节点
kubelet —apiserver —读取 etcd 拿到分配给当前节点 pod —docker 创建容器
影响调度的属性
pod 资源限制: resources
节点选择器标签影响 Pod 调度
需要先对节点打标签
1 | $ kubectl label node k8snode1 env_role=prod |
- 节点亲和性影响 Pod 调度
节点亲和性 nodeAffinity 和之前 nodeSelector 基本一样的,根据节点上标签约束来决定 Pod 调度到哪些节点上
(1) 硬亲和性(requireDuringSchedulingIgnoreDuringExecution)
约束条件必须满足
(2) 软亲和性(preferredDuringSchedulingIgnoredDuringExecution)
尝试满足,不保证
常用的操作符(operator):
In NotIn Exists Gt Lt DoesNotExists
反亲和性:使用 NotIn 和 DoesNotExists
- 污点和污点容忍
- 基本介绍:
nodeSelector 和 nodeAffinity: Pod 调度到某些节点上,Pod 属性,调度的时候实现
Taint 污点: 节点不做普通分配调度,是节点属性
- 场景
专用节点
配置特点硬件节点
基于 Taint 驱逐
1 | # 查看当前节点的污点情况 |
污点值有三个:
NoSchedule: 一定不被调度
PreferNoSchedule: 尽量不被调度
NoExecute: 不会调度,而且还会驱逐 Node 已有 Pod
为节点添加污点
kubectl taint node [node] key=value:污点三个值
1 | $ kubectl get pods |
删除污点
1 | $ kubectl taint node k8snode1 env_role:NoSchedule- |
污点容忍:
Controller
什么是 Controller
在集群上管理和运行容器的对象
Pod 和 Controller 关系
Pod 通过 Controller 实现应用的运维,比如伸缩,滚动升级等
- Pod 和 Controller 之间通过 label 标签建立关系
deployment 应用场景
- 部署无状态应用
- 管理 Pod 和 ReplicaSet
- 部署,滚动升级等功能
应用场景: web 服务,微服务
使用 deployment 部署应用(yaml)
1 | # 导出yaml文件 |
应用升级回滚和弹性伸缩
1 | # 应用升级 |
无状态和有状态的区别
- 无状态
- 认为 Pod 都是一样的(副本都是一样的)
- 没有顺序要求
- 不用考虑在哪个 node 运行
- 随意进行伸缩和扩展
- 有状态
- 上面因素都需要考虑到
- 让每个 pod 独立,保持 pod 启动顺序和唯一性(唯一的网络标识符,持久存储,有序,比如 mysql 主从)
部署有状态的应用
- 无头 service:
- ClusterIP: node
StatefulSet部署有状态应用
执行后查看 pod,有 3 个 Pod,每个都是唯一的名称
查看 svc, ClusterIP 为 None
deployment 和 statefulset 区别:有身份的(唯一标识的)
- 根据主机名+按照一定规则生成域名
- 唯一域名
格式: 主机名称.service 名称.名称空间.svc.cluster.local
example: nginx-statefulset-0.nignx.default.svc
部署守护进程 DaemonSet
- 在每个 node 上运行一个 pod,新加入的 node 也同样运行在一个 Pod 里面
- 例子:在每个 node 节点安装数据采集工具
1 | $ kubectl delete statefulset --all |
job(一次性任务)和 cronjob(定时任务)
1 | $ kubectl create -f job.yaml |
定时任务:
1 | $ kubectl apply -f cronjob.yaml |
Service
Service 是什么
定义一组 Pod 的访问规则
Service 存在意义
防止 Pod 失联(服务发现)
定义一组 Pod 访问策略(负载均衡)
Pod 和 Service 的关系
根据 label 标签建立关系
常用 Service 类型
- ClusterIP: 集群内部使用
- NodePort: 对外访问应用使用
- LoadBalancer: 对外访问应用使用,公有云
1 | $ kubectl get svc |
node 内网部署应用,外网一般不能访问到:
用一台可以进行外网访问的机器,安装 nginx,反向代理
手动把可以访问节点添加到 nginx
LoadBalancer: 公有云,把负载均衡,控制器
配置管理
Secret
作用: 加密数据存在 etcd 里面,让 Pod 容器以挂载 Volume 的方式进行访问
场景: 凭证
base64 编码
1 | $ echo -n "admin" | base64 |
1.创建 secret 加密数据
1 | $ kubectl create -f secret.yaml |
- 以变量的形式挂载到 pod 容器中
valueFrom
1 | $ kubectl apply -f secret-val.yaml |
- 以 Volume 挂载数据卷中
1 | $ kubectl delete -f secret-val.yaml |
ConfigMap
作用:存储不加密数据到 etcd 中,让 Pod 以变量或者 Volume 挂载到容器中
场景:配置文件
1.创建配置文件
1 | $ kubectl delete secret --all |
2.创建 configmap
1 | $ kubectl create configmap redis-config --from-file=redis.properties |
3.以 Volume 挂在到 Pod 容器中
1 | $ kubectl apply -f cm.yaml |
4.以变量形式挂载
(1)创建 yaml,声明变量信息 configmap 创建
(2)以变量挂载
1 | $ kubectl apply -f myconfig.yaml |
1 | $ kubectl apply -f config-var.yaml |
k8s 集群安装机制
概述
访问 k8s 集群的时候要经过三个步骤完成具体操作
(1) 认证
(2) 鉴权(授权)
(3) 准入控制
进行访问的时候,过程中都需要经过 apiserver,apiserver 做统一协调,比如门卫,访问过程中需要证书,token,或者用户名+密码,如果访问 pod 需要 serviceAccount
第一步认证
- 传输安全: 对外不暴露 8080 端口,只能内部访问,对外使用端口 6443
- 认证: 客户端身份认证常用方式:
- https 证书认证,基于 ca 证书
- http token 认证,通过 token 识别用户
- http 基本认证,用户名+密码认证
第二步 鉴权
- 基于 RBAC 进行鉴权操作
- 基于角色访问控制
第三步 准入控制
- 就是准入控制器的列表,如果列表友情就内容就通过
RBAC 基于角色的访问控制
Role Based Access Control
- 角色
role: 角色,特定命名空间的访问权限
clusterRole: 对所有命名空间的访问权限
1 | # 查看命名空间 |
- 角色绑定
- roleBinding: 角色绑定到主题
- ClusterRoleBinding: 集群角色绑定到主体
- 主体
- user: 用户
- group: 用户组
- serviceAccount: 服务账号
RBAC 实现鉴权
1 | # 1.创建命名空间 |
1 | # 3.创建角色 |
1 | # 4.创建角色绑定 |
- 使用证书
1 | $ vim rbac-user.sh |
Ingress
概述
- 把端口号对外暴露,通过 ip+端口号进行访问,使用 Service 里面的 NodePort 实现
- NodePort 缺陷
- 在每个节点上都会起到端口,在访问时候通过任何节点,通过节点 ip+暴露端口实现访问
- 意味着灭个端口只能使用一次,一个端口对应一个应用
- 实际访问中都是用域名,根据不同的域名跳转到不同端口服务中
Ingress 和 Pod 关系
- pod 和 ingress 通过 service 关联的
- ingress 作为统一入口,由 service 关联一组 pod
使用 ingress
使用 Ingress 对外暴露应用
- 创建 nginx 应用,对外暴露端口使用
1 | $ kubectl create deployment web --image=nginx |
- 部署 ingress controller
1 | $ kubectl apply -f ingress-con.yaml |
1 | $ vim ingress-h.yaml |
Helm
概述
之前部署应用的基本过程:
编写 yaml 文件: deployment,Service,Ingress
如果使用之前方式部署单一应用,少数服务的应用,比较合适
如果部署微服务项目,可能有几十个服务,每个服务都有一套 yaml 文件,需要维护大量 yaml 文件,版本管理特别不方便
使用 helm 可以解决哪些问题?
- 使用 helm 可以把这些 yaml 作为一个整体管理
- 实现 yaml 高效服用
- 使用 helm 应用级别的版本管理
helm 介绍
Helm 是一个 k8s 的包管理工具,就像 Linux 下的包管理器如 yum/apt 等,可以很方便的将之前打包好的 yaml 文件部署到 k8s 上
三个重要概念
helm
- 是一个命令行客户端工具
Chart
- 是把 yaml 打包,是 yaml 集合
Release
- 基于 chart 部署实体,应用级别的版本管理
https://helm.sh/docs/intro/quickstart/
安装
https://helm.sh/docs/intro/install/
添加仓库
1 | $ helm repo add brigade https://brigadecore.github.io/charts |
使用 helm 快速部署应用
- 使用命令搜索应用
1 | $ helm search repo 名称 |
- 根据搜索内容选择安装
1 | $ helm install 安装之后的名称 搜索之后的名称 |
- 查看安装后的状态
1 | $ helm list |
example
1 | $ helm search repo weave |
如何自己创建 Chart
- 使用命令创建 chart
1 | $ helm create mychart |
- Chart.yaml: 当前 chart 属性配置信息
- templates: 编写 yaml 文件放到这个目录中
- values.yaml: yaml 文件可以使用的全局变量
- 在 templates 文件夹下创建两个 yaml 文件
- deployment.yaml
- service.yaml
1 | $ kubectl create deployment web1 --images=nginx --dry-run -o yaml > deployment.yaml |
- 安装 mychart
1 | $ helm install web1 mychart/ |
4.应用升级
1 | $ helm upgrade chart名称 chart文件夹 |
实现 yaml 高效服用
通过传递参数,动态渲染模板,yaml 内容动态传入参数生成
- 在 values.yaml 定义变量和值
- 在具体 yaml 文件中获取定义变量和值
- yaml 文件大体上有这几个地方是不同的
- image
- tag
- label
- port
- replicas
一.在 values.yaml 定义变量和值
1 | replicas: 1 |
二.在 templates 的 yaml 文件中使用 values.yaml 定义变量
- 通过表达式形式使用全局变量
比如
1 | $ helm install --dry-run web2 mychart/ |
持久化存储
数据卷 emptydir,是本地存储,pod 重启,数据不存在了,需要对数据持久化存储
nfs 网络存储
pod 重启,数据还是在的
第一步 找一台服务器 nfs 服务端
(1) 安装 nfs
1 | $ yum install -y nfs-utils |
(2) 设置挂载路径
1 | $ vim /etc/exports |
(3) 对外挂在路径需要先创建出来
1 | $ mkdir /data/nfs |
第二步 在 k8s 集群 node 节点上安装 nfs
1 | $ yum install -y nfs-utils |
第三步 在 nfs 服务器启动 nfs 服务
1 | $ systemctl start nfs |
第四步 在 k8s 集群中部署应用使用 nfs 持久网络存储
1 | $ mkdir pv |
1 | $ kubectl describe pod nginx-dep1-79x79jg79-9sn8gx |
PV 和 PVC
- PV: 持久化存储,对存储资源进行抽象,对外提供可以调用的地方(生产者)
- PVC: 用户调用不需要关心内部实现细节(消费者)
- 实现流程:
1 | $ vim pvc.yaml |
1 | $ kubectl apply -f pvc.yaml |
1 | $ vim pv.yaml |
1 | $ kubectl apply -f pv.yaml |
k8s 集群资源监控
监控指标
- 集群监控
- 节点资源利用率
- 节点数
- 运行 pods
- Pod 监控
- 容器指标
- 应用程序
监控平台
prometheus+Grafana
(1) prometheus
- 开源的
- 监控,报警,数据库
- 以 HTTP 协议周期性抓取被监控的组件状态
- 不需要复杂的继承过程,使用 http 接口接入就可以了
(2) Grafana
- 开源的数据分析和可视化工具
- 支持多种数据源
部署:
https://developer.aliyun.com/article/836300
搭建高可用集群
高可用集群技术
部署
https://kubernetes.io/zh-cn/docs/setup/production-environment/tools/kubeadm/high-availability/