kubernetes入门
搭建kubernetes环境
⽂档地址:
https://kubernetes.io/zh-cn/docs
搭建方式
kubeadm 工具化部署(推荐新手 / 中小团队)
kubeadm 是官方提供的自动化部署工具,能快速初始化集群,降低搭建复杂度,适合绝大多数场景。
- 核心优势:
- 自动化程度高,只需几条命令即可完成集群初始化。
- 官方维护,兼容性和稳定性有保障,支持集群升级。
- 学习成本低,无需深入理解 K8s 组件底层细节。
- 关键步骤:
- 准备至少 2 台 Linux 服务器(推荐 CentOS/Ubuntu),配置静态 IP、关闭防火墙和 SELinux。
- 在所有节点安装 Docker、kubeadm、kubelet 和 kubectl。
- 在主节点(Master)执行
kubeadm init初始化控制平面。 - 按照初始化输出的提示,在主节点配置 kubectl 命令行工具。
- 在从节点(Worker)执行
kubeadm join命令,将节点加入集群。
二进制手动部署(适合对集群有深度控制需求的场景)
通过手动下载 K8s 各组件(如 kube-apiserver、kube-controller-manager)的二进制包,逐一配置启动,灵活性最高但复杂度也最大。
- 核心优势:
- 组件版本、配置参数可完全自定义,适合特殊业务需求。
- 无依赖工具,集群性能和资源占用可控性更强。
- 能深入理解 K8s 各组件的工作原理,便于问题排查。
- 核心劣势:
- 部署步骤繁琐,需手动配置证书、服务启停脚本、网络插件等。
- 集群升级、维护成本高,需手动处理组件依赖和版本兼容。
Minikube搭建(学习)
Minikube 是 Kubernetes 官方推荐的本地单节点测试 / 学习环境搭建工具,核心优势是 轻量、一键部署、资源占用低,适合新手入门学习、本地开发测试(无需多台服务器),但不适合生产环境(仅单节点,无高可用)。
云服务商托管部署(适合企业级生产环境)
阿里云(ACK)、腾讯云(TKE)、AWS(EKS)等云厂商提供托管 K8s 服务,无需手动维护控制平面,专注于业务容器管理。
- 核心优势:
- 控制平面(Master 节点)由云厂商托管,无需担心高可用和运维。
- 支持弹性扩容、自动修复节点,与云厂商的存储、网络服务无缝集成。
- 提供监控、日志、告警等配套工具,降低运维复杂度。
- 核心劣势:
- 长期使用有服务费用,成本高于自建集群。
- 对云厂商有一定依赖,迁移到其他平台需额外适配。
minikube搭建
主要是为了学习k8s相关命令。
Docker环镜:
1 | |
Mac os
1 | |
1 | |
linux
购买2C8G的虚拟机 中国香港
1 | |
1 | |
1 | |
启动
1 | |
安装kubectl用于验证:
1 | |
1 | |
命令
查看k8s集群信息
1 | |
1 | |
查看节点信息
1 | |
1 | |
查看内部组件
1 | |
1 | |
部署Nginx
1 | |
查看deployment和pod
1 | |
1 | |
暴露80端⼝, 就是service服务
1 | |
转发端⼝(Mini Kube临时)
1 | |
在浏览器访问,可以看到nginx的index.html
Minikube vs Kubeadm 的网络差异
1. Kubeadm 集群的网络(直接暴露)
Kubeadm 是把 Kubernetes 组件(apiserver、kubelet 等)直接部署在宿主机上(或物理节点):
- NodePort 服务会在 宿主机的物理网卡 上监听一个端口(比如 30000-32767 之间);
- 所以你能直接用「宿主机 IP + NodePort 端口」访问(比如
http://192.168.1.100:30080),因为宿主机的端口和 Kubernetes 服务是 “直接绑定” 的。
2. Minikube 集群的网络(隔离在虚拟环境)
Minikube 为了 “一键搭建、不污染宿主机”,会创建一个 独立的虚拟环境(默认是 Docker 容器,也支持 VM):
- 这个虚拟环境相当于一个 “迷你虚拟机”,有自己独立的内网 IP(比如你之前看到的
192.168.49.2); - Kubernetes 集群的所有组件(包括 NodePort 服务)都运行在这个 “虚拟环境” 内部,没有直接绑定宿主机的端口;
- 宿主机和 Minikube 虚拟环境之间是隔离的,所以你直接用「宿主机 IP + NodePort 端口」访问时,宿主机根本不知道这个端口对应的服务在哪里 —— 相当于 “门牌号指到了小区门口,但小区里的房子藏在独立院子里,外面进不去”。
“minikube service” 和 “端口转发” 的本质:打通隔离的 “通道”
既然 Minikube 的服务藏在 “虚拟环境” 里,就需要两种方式 “打通通道”,让外部(宿主机或公网)能访问:
1. minikube service(内网访问:宿主机→Minikube 虚拟环境)
minikube service <服务名> --url 是 Minikube 内置的 “快捷通道”,作用是:
- 自动找到 Minikube 虚拟环境的内网 IP(比如
192.168.49.2); - 找到 NodePort 服务的端口(比如 30080);
- 直接输出「Minikube 内网 IP + NodePort 端口」的访问地址(比如
http://192.168.49.2:30080)。
为什么能访问?
这个地址的 IP 是 Minikube 虚拟环境的内网 IP(宿主机能通过 Docker 桥接网络访问这个 IP),相当于 “直接访问小区里的房子门牌号”,而不是 “小区门口的门牌号”。
适用场景:
- 仅在 宿主机内部访问(比如你在搭建 Minikube 的机器上用浏览器或 curl 访问);
- 简单快捷,无需手动配置,适合开发 / 测试。
2. 端口转发(公网访问:外部机器→宿主机→Minikube 虚拟环境)
如果需要让 宿主机以外的机器(比如同一局域网的其他电脑、公网机器) 访问 Minikube 里的服务,就需要 “端口转发”,本质是:
- 在 宿主机的物理网卡 上监听一个端口(比如 8080);
- 把所有访问「宿主机 IP:8080」的请求,转发到「Minikube 内网 IP:NodePort 端口」(比如
192.168.49.2:30080); - 相当于在 “小区门口” 设一个中转站,外部访客找中转站,中转站再把人领到小区里的房子。
方式 1:kubectl 端口转发(临时,重启失效)
1 | |
方式 2:Minikube 隧道(永久,后台运行)
1 | |
概念
k8s是⼀个服务器集群系统,⽤户可以在集群中部署各种服务,也就是在k8s集群上运⾏⼀个个的容器。
在k8s中, pod是最⼩的管理单元⽽⾮容器,⼀个pod中可以有多个容器。
在k8s集群中,所有内容都可以被抽象为资源,通过操作资源来管理k8s集群。
使⽤kubectl来管理资源
1 | |
commad:对资源具体的操作,如create创建、 get获取、 delete删除
TYPE:指定资源类型,⼤⼩写敏感
NAME:指定资源的名称,⼤⼩写敏感,如果省略名称则显示所有资源
flags:指定可选的参数,如可⽤-s或者-server指定Kubernetes API server的地址和端⼝
1 | |
资源管理⽅式:
命令式对象管理:直接使⽤命令去操作资源
1 | |
命令式对象配置:通过命令配置和配置⽂件去操作资源
1 | |
声明式对象配置:通过apply和配置⽂件操作资源
1 | |
yaml例⼦:
1 | |
1 | |
kubectl create 和 kubectl apply的区别
kubectl create 命令⾸次执⾏时会创建资源,当再次执⾏的时候会报错,因为资源名称在同⼀命名空间内是唯⼀的
kubectl apply在⾸次执⾏的时候也会创建对应的资源,当再次执⾏的时候会根据配置⽂件进⾏升级、扩容等操作,即使配置⽂件没有变化也不影响
Kubernetes资源⽂件yaml参数介绍
yaml⽂件的编写:
不需要从零⼿写,快速编写yaml⽂件,通过命令导出新的yaml⽂件
1 | |
1 | |
pod属性解析:
1 | |
常⽤字段含义
必须存在的属性
| 参数名 | 字段类型 | 说明 |
|---|---|---|
| apiVersion | String | k8s API 的版本,可使用 kubectl apiversions 命令查询 |
| kind | String | 指定 k8s 资源的类型,比如 Pod、Deployment |
| metadata | Object | 元数据对象,固定写值 metadata |
| metadata.name | String | 元数据对象的名字(如 Pod 的名称) |
| metadata.namespace | String | 元数据对象的命名空间(默认值为 default,可自定义) |
| spec | Object | 详细定义资源的核心配置,固定写值 spec |
| spec.containers[] | list | spec 对象的容器列表定义(Pod 至少包含一个容器,列表形式) |
| spec.containers[].name | String | 容器对象的名字(容器列表内唯一,用于标识单个容器) |
| spec.containers[].image | String | 定义容器要使用的镜像名称(如 nginx:1.23.0,需指定镜像版本或 latest) |
spec主要对象
spec.containers
| 参数名 | 字段类型 | 说明 |
|---|---|---|
| spec.containers[].name | String | 定义容器的名字 |
| spec.containers[].image | String | 定义要用到的镜像名称 |
| spec.containers[].imagePullPolicy | String | 定义镜像拉取策略,可选值:1. Always:每次都尝试重新拉取镜像2. Never:仅使用本地镜像3. IfNotPresent:本地有镜像则使用本地,无则拉取在线镜像默认值:Always |
| spec.containers[].command[] | List | 指定容器启动命令(数组类型,可多个),不指定则使用镜像打包时的默认启动命令 |
| spec.containers[].args[] | List | 指定容器启动命令的参数(数组类型,可多个) |
| spec.containers[].workingDir | String | 指定容器的工作目录 |
| spec.containers[].volumeMounts[] | List | 指定容器内部的存储卷配置 |
| spec.containers[].volumeMounts[].name | String | 指定可被容器挂载的存储卷名称(需与 spec.volumes.name 对应) |
| spec.containers[].volumeMounts[].mountPath | String | 指定存储卷在容器内的挂载路径 |
| spec.containers[].volumeMounts[].readOnly | String | 设置挂载路径的读写模式,可选 true(只读)或 false(读写),默认值:false(读写) |
| spec.containers[].ports[] | List | 指定容器需要用到的端口列表 |
| spec.containers[].ports[].name | String | 指定端口名称(需唯一) |
| spec.containers[].ports[].containerPort | String | 指定容器需要监听的端口号 |
| spec.containers[].ports[].hostPort | String | 指定容器所在主机需要监听的端口号(默认与 containerPort 相同);注意:同一主机无法启动该容器的相同副本(端口冲突) |
| 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 的 --cpu-shares 参数 |
| spec.containers[].resources.limits.memory | String | 内存限制,单位支持 MIB(兆字节)、GiB(吉字节) |
| spec.containers[].resources.requests | Object | 指定容器启动和调度时的资源请求(调度器会根据该值分配节点) |
| spec.containers[].resources.requests.cpu | String | CPU 请求,单位为核心数(core),容器启动时的初始化可用 CPU 数量 |
| spec.containers[].resources.requests.memory | String | 内存请求,单位支持 MIB、GiB,容器启动时的初始化可用内存数量 |
spec.volumes
| 参数名 | 字段类型 | 说明 |
|---|---|---|
| spec.volumes[] | List | Pod 的共享存储卷列表(供容器挂载使用) |
| spec.volumes[].name | String | 存储卷的名称,需与 spec.containers[].volumeMounts[].name 完全一致(用于关联容器和存储卷) |
| spec.volumes[].emptyDir | Object | 临时存储卷(Pod 生命周期内有效,Pod 销毁后数据丢失),配置格式:emptyDir: {}(空对象) |
| spec.volumes[].hostPath | Object | 挂载 Pod 所在宿主机的目录(数据持久化到宿主机,跨 Pod 不共享) |
| spec.volumes[].hostPath.path | String | 宿主机上的目录路径(需提前存在或配置 type 自动创建),将被挂载到容器内指定路径 |
| spec.volumes[].secret | Object | 密钥型存储卷,用于挂载集群中预定义的 Secret 对象(存储密码、Token、密钥等敏感数据,挂载后容器内以文件形式访问,数据自动 base64 解码) |
| spec.volumes[].configMap | Object | 配置型存储卷,用于挂载集群中预定义的 ConfigMap 对象(存储非敏感配置数据,如配置文件、环境变量参数等) |
| spec.containers[].livenessProbe | Object | 容器健康检查(存活探针):探测无响应达到阈值后,系统自动重启容器;支持 3 种探测方式:exec(执行命令)、httpGet(HTTP 请求)、tcpSocket(TCP 连接) |
| spec.containers[].livenessProbe.exec | Object | 存活探针类型:执行命令探测(如 ls /tmp/health) |
| spec.containers[].livenessProbe.exec.command[] | List | 探测执行的命令 / 脚本(数组类型,如 ["cat", "/tmp/health"]),命令退出码为 0 表示健康 |
| spec.containers[].livenessProbe.httpGet | Object | 存活探针类型:HTTP 请求探测(如访问容器内 /health 接口) |
| spec.containers[].livenessProbe.tcpSocket | Object | 存活探针类型:TCP 连接探测(如访问容器的 8080 端口) |
| spec.containers[].livenessProbe.initialDelaySeconds | Number | 容器启动后延迟探测的时间(单位:秒),避免容器未启动完成就被误判为不健康 |
| spec.containers[].livenessProbe.timeoutSeconds | Number | 探测超时时间(单位:秒,默认 1 秒);超过该时间无响应则判定为不健康,触发容器重启 |
| spec.containers[].livenessProbe.periodSeconds | Number | 定期探测间隔时间(单位:秒,默认 10 秒);即每隔多久执行一次健康检查 |
Kubernetes常⻅资源类型和缩写
查看资源类型和命令
1 | |
常⽤资源分类和缩写:
1 | |
常⽤资源操作命令:
| 命令分类 | 命令 | 翻译(中文说明) | 补充说明(核心用途) |
|---|---|---|---|
| 基本命令 | create | 创建资源 | 从命令行或文件创建 Kubernetes 资源(如 Pod、Service),例:kubectl create -f pod.yaml |
| 基本命令 | delete | 删除资源 | 删除指定资源,例:kubectl delete pod nginx、kubectl delete -f pod.yaml |
| 基本命令 | edit | 编辑资源 | 在线编辑集群中已存在的资源配置(默认用 vi 编辑器),例:kubectl edit deployment nginx |
| 基本命令 | get | 获取资源 | 查看资源列表或详情,例:kubectl get pods(列表)、kubectl get pod nginx -o yaml(详情) |
| 基本命令 | patch | 更新资源 | 局部修改资源配置(无需编辑完整 YAML),例:kubectl patch pod nginx -p '{"spec":{"replicas":2}}' |
| 基本命令 | explain | 解释资源 | 查看资源的 API 文档和字段说明,例:kubectl explain pod.spec.containers |
| 运行和调试 | run | 运行指定的镜像 | 快速创建并运行 Pod(简化版 create),例:kubectl run nginx --image=nginx:1.23.0 |
| 运行和调试 | expose | 暴露服务 | 将 Pod/Deployment 暴露为 Service(如 NodePort、ClusterIP),例:kubectl expose pod nginx --type=NodePort |
| 运行和调试 | describe | 描述资源内部信息 | 查看资源的详细状态、事件、关联对象等(排障常用),例:kubectl describe pod nginx |
| 运行和调试 | logs | 打印容器在 Pod 中的日志 | 查看 Pod 内容器的运行日志,例:kubectl logs nginx(默认容器)、kubectl logs nginx -c 容器名(多容器) |
| 运行和调试 | attach | 进入运行中的容器(附加到容器) | 实时查看容器的标准输入 / 输出(类似 docker attach),例:kubectl attach nginx -it |
| 运行和调试 | exec | 执行容器中的一个命令 | 在运行的容器内执行命令(排障常用),例:kubectl exec nginx -it -- /bin/bash(进入终端) |
| 运行和调试 | cp | 在 Pod 内外复制文件 | 实现 Pod 与宿主机之间的文件传输,例:kubectl cp 本地文件 nginx:/容器路径 |
| 运行和调试 | scale | 扩容 / 缩容 Pod 的数量 | 调整 Deployment/StatefulSet 的副本数,例:kubectl scale deployment nginx --replicas=3 |
| 运行和调试 | autoscale | 自动扩容 / 缩容 Pod 的数量 | 基于 CPU / 内存使用率自动调整副本数,例:kubectl autoscale deployment nginx --min=1 --max=5 |
| 高级命令 | apply | 应用配置(创建 / 更新资源) | 从文件或命令行配置资源(支持增量更新),例:kubectl apply -f deployment.yaml(推荐优先使用) |
| 高级命令 | label | 管理资源标签 | 为资源添加 / 修改 / 删除标签(用于筛选、调度等),例:kubectl label pod nginx env=test |
| 其他命令 | cluster-info | 集群信息 | |
| version | 版本 |
命名空间和Pod
Namespace:
Namespace是k8s系统中的⼀种⾮常重要资源,它的主要作⽤是⽤来实现多套环境的资源隔离或者多⽤户的资源隔离。
默认情况下, k8s集群中的所有的Pod都是可以相互访问的。
但是在实际中,可能不想让两个Pod之间进⾏互相的访问,那此时就可以将两个Pod划分到不同的namespace下。
k8s通过将集群内部的资源分配到不同的Namespace中,可以形成逻辑上的”组”,以⽅便不同的组的资源进⾏隔离使⽤和管理。
可以通过k8s的授权机制,将不同的namespace交给不同租户进⾏管理,这样就实现了多租户的资源隔离。
结合k8s的资源配额机制,限定不同租户能占⽤的资源,例如CPU使⽤量、内存使⽤量等等,来实现租户可⽤资源的管理。
Kubernetes 会创建四个初始NameSpace名称空间:
default: 没有指明使⽤其它名字空间的对象所使⽤的默认名字空间
kube-system: Kubernetes 系统创建对象所使⽤的名字空间
kube-public: 是⾃动创建的,命名空间下的资源可以被所有⼈访问(包括未认证⽤户)
kube-node-lease: kube-node-lease
查看所有命令空间:
1 | |
1 | |
命名空间操作:
1 | |
1 | |
Pod:
Pod是⼀组容器, 在K8S中,最⼩的单位是Pod, ⼀个Pod可以包含多个容器,但通常情况下我们在每个Pod中仅使⽤⼀个容器,可以把Pod理解成豌⾖荚, Pod内的每个容器是⼀颗颗豌⾖。
Pod 的核⼼是运⾏容器,必须指定容器引擎,⽐如 Docker是其中⼀种技术。
分类:
⾃主创建:直接创建出来的Pod,这种pod删除后就没有了,也不会⾃动重建。
控制器创建:通过控制器创建的pod,这类Pod删除了之后,还会⾃动重建。
Pod运⾏容器数量:
每个Pod中⼀个容器的模式是最常⻅的⽤法, Pod是容器的简单封装, K8S管理Pod⽽不是直接管理容器。
⼀个Pod中同时运⾏多个需要互相协作的容器,它们共享资源,同⼀个Pod中的容器可以作为service单位。
Pod⽹络:
⼀个 pod 包含⼀组容器,⼀个 pod 不会跨越多个⼯作节点。
每个Pod都会被分配⼀个唯⼀的IP地址, Pod中的所有容器共享⽹络空间,包括IP地址和端⼝。
Pod内部的容器可以使⽤localhost互相通信。
Pod存储:
Volume 也可以⽤来持久化Pod中的存储资源,以防容器重启后⽂件丢失。
Pod中 的所有容器都可以访问共享的Volume。
K8S集群中的系统组件都是以Pod⽅式运⾏的:
1 | |
1 | |
Pod底层原型:
每个Pod中都可以包含⼀个或者多个容器,这些容器可以分为两类:
⽤户程序所在的容器: 数量可多可少
Pause容器,这是每个Pod都会有的⼀个根容器,它的作⽤有两个:
以它为依据,评估整个Pod的健康状态
可以在根容器上设置Ip地址,其它容器都此有Ip(PodIP),以实现Pod内部的⽹路通信
实现机制:
通过共享⽹络:通过pause容器,把其他业务容器加⼊到pause容器⾥⾯,让所有业务容器在同⼀个namespace中,可以实现⽹络共享。
通过共享存储: 引⼊数据卷volume的概念,使⽤数据卷进⾏持久化存储。
pod镜像拉取策略imagesPullPolicy:
1 | |
pod资源限制:
requests: 资源请求量,当容器运⾏时,向Node申请的最少保障资源。
limits: 资源上限,容器在Node上所能消耗的最⾼上限
1 | |
pod的创建流程:
通过kubectl apply -f xxx.yaml 创建pod
创建pod的时候:
1 | |
Pod的调度策略:
在默认情况下,⼀个Pod在哪个Node节点上运⾏,是由Scheduler组件采⽤相应的算法计算出来的,这个过程是不受⼈⼯控制的。但是在实际使⽤中,这并不满⾜的需求,因为很多情况下,我们想控制某些Pod到达某些节点上,那么应该怎么做呢?这就要求了解k8s对Pod的调度规则。
影响pod调度的因素:
pod资源限制: scheduler根据requests找到⾜够⼤⼩的node进⾏调度
节点选择器标签(nodeSelector):把节点进⾏区分,例如dev开发环境和prod⽣产环境
例如,当前需要把pod调度到开发环境中,则可以通过scheduler将pod调度到标签选择器中为env_role:dev的node中
1 | |
标签Label和标签选择器
Label:
K8S提供了⼀种机制来为资源进⾏分类,那就是Label(标签),同⼀类资源会拥有相同的标签。
具体形式是key-value的标记对,可以在创建资源的时候设置,也可以在后期添加和修改。
可以附加到各种资源对象上,如Node,Pod,Service,RC等,⼀个资源拥有多个标签,可以实现不同维度的管理。
给某个资源对象定义⼀个Label,就相当于给它打了⼀个标签,可以通过Label Selector(标签选择器)查询和筛选拥有某些Label的资源对象, K8S通过这种⽅式实现了类似SQL的对象查询机制。
每个资源都存在多维度属性。
1 | |
应⽤场景:
未使⽤前,分散难管理,如果需要部署不同版本的应⽤到不同的环境中,难操作。
为Pod打上不同标签,使⽤Label组织的Pod,轻松管理
标签选择器Label selector:
是Kubernetes核⼼的分组机制,通过label selector客户端/⽤户能够识别⼀组有共同特征或属性的资源对象。
对应的资源打上标签后,可以使⽤标签选择器过滤指定的标签。
标签选择器⽬前有两个:
matchLabels ⽤于定义⼀组Label , 基于等值关系(等于、不等于) ,类似于SQL语句中的=或!=
matchExpressions 基于集合关系(属于、不属于、存在) ,类似于SQL语句中的in或 not in
备注:如果同时设置了matchLabels和matchExpressions,则两组条件为 AND关系,即需要同时满⾜所有条件才能完成Selector的筛选
1 | |
NodeSelector标签选择器
nodeSelector是 Pod的Spec 的⼀个字段
使⽤NodeSelector,测试 pod 并指定 nodeSelector 选项绑定节点
1 | |
配置⽂件:
1 | |
1 | |
Pod控制器
Pod Controller控制器
控制器是管理pod的中间层,只需要告诉Pod控制器,想要创建多少个什么样的Pod,它会创建出满⾜条件的Pod,相当于⼀个状态机,⽤来控制Pod的具体状态和⾏为。 controller会⾃动创建相应的pod资源,并在当pod发⽣故障的时候按照策略进⾏重新编排。
通过它来实现对pod的管理,⽐如启动pod、停⽌pod、扩展pod的数量等等。
yaml⽂件中 kind 填写对应的类型即可。
Pod Controller的类型概述:
ReplicaSet:
⼀种副本控制器,简称rs,主要是控制由其管理的pod,使pod副本的数量始终维持在预设的个数。
并⽀持pod数量扩缩容,镜像版本升级。
官⽅建议不要直接使⽤ReplicaSet,⽤Deployments更好,并提供很多其它有⽤的特性。
Deployment:
通过控制ReplicaSet来控制Pod,并⽀持滚动升级、回退版本,适合⽆状态的服务部署。
当某个应⽤有新版本发布时, Deployment会同时操作两个版本的ReplicaSet。
其内置多种滚动升级策略,会按照既定策略降低⽼版本的Pod数量,同时也创建新版本的Pod。
Deployment控制器不直接管理Pod对象,⽽是Deployment 管理ReplicaSet, 再由ReplicaSet管理Pod对象。
DaemonSet:
在K8S集群部署中由于节点数量不定,那么如果我们需要对每个节点中都运⾏⼀个守护进程、⽇志收集进程等情况时,在k8s中如何实现呢?这个时候就是DaemonSet应⽤场景了
这类Pod 运⾏在K8S 集群⾥的每⼀个节点(Node)上,确保所有节点上有且仅有⼀个pod。
有新的节点加⼊ K8S集群后,该 Pod 会⾃动地在新节点上被创建出来。
⽽当旧节点被删除后,它上⾯的 Pod也相应地会被回收掉。
应⽤场景:监控告警Agent、⽇志组件、监控组件等。
StatefulSet:
像RS、 Deployment、 DaemonSet都是⾯向⽆状态的服务,所管理的Pod的IP、名字,启停顺序都是随机。
StatefulSet就是有状态的集合,管理所有有状态的服务。
StatefulSet 中的 Pod 具有黏性的、独⼀⽆⼆的身份标识,重新调度后PodName和HostName不变。
Pod重新调度后还是能访问到相同的持久化数据,基于PVC实现。
分配给每个 Pod 的唯⼀顺序索引, Pod 的名称的形式为
1 | |
应⽤场景:⽐如MySQL、 MongoDB集群。
Horizontal Pod Autoscaler:
可以基于 CPU 利⽤率或其他指标实现Pod⽔平⾃动扩缩。
被伸缩的pod需要是通过deployment或者replica set管理。
HPA不能应⽤于不可伸缩的对象,如: DaemonSets。
由资源来决定控制器⾏为,控制器周期性调整⽬标pod的副本数量,让⽬标pod的实际cpu使⽤率符合⽤户指定的数值。
Job:
普通任务容器控制器,只会执⾏⼀次,只要完成任务就⽴即退出,不需要重启或重建。
容器中的进程在正常运⾏结束后不会对其进⾏重启,⽽是将pod对象置于completed状态。
若容器中的进程因错误⽽终⽌,则需要依据配置确定是否需要重启。
应⽤场景:批处理程序,完成后容器就退出等。
Cronjob:
Linux 中有 cron 程序定时执⾏任务, K8s的 CronJob 提供了类似的功能,可以定时执⾏ Job。
创建的Pod负责周期性任务控制。
应⽤场景:执⾏周期性的重复任务,如备份数据、发送邮件、数据报表、报告⽣成等。
ReplicaSet
早期k8s没那么多控制器,使⽤Replication Controller 来部署、升级Pod,简称RC。
Replica Set – 下⼀代Replication Controller
Yaml模板介绍:
1 | |
replicaset-nginx.yaml
1 | |
1 | |
Deployment
deploy-nginx-pod.yaml
1 | |
1 | |
检查集群中的 Deployment 时,所显示的字段有:
NAME 列出了集群中 Deployment 的名称。
READY 显示应⽤程序的可⽤的“副本”数,格式是“就绪个数/期望个数”。
UP-TO-DATE 显示为了达到期望状态已经更新的副本数。
AVAILABLE 显示可⽤的副本数。
AGE 应⽤程序运⾏的时间。
rollout实现滚动升级
滚动升级 (⾦丝雀发布 or 灰度发布)
对各个实例批次进⾏单独更新,⽽⾮同⼀时刻对所有实例进⾏全部更新,达到不中断服务的更新升级⽅式。
Deployment控制器 给旧版本(old_rs)副本数减少⾄0、给新版本(new_rs)副本数量增⾄期望值(replicas)。
Deployment更新有两种⽅式:
1 | |
Recreate : 删除全部旧的pod,然后创建新的pod
RollingUpdate:滚动升级更新,删除部分,更新部分,在整个更新过程中,存在两个版本的pod。
1 | |
deploy-rollout.yaml
1 | |
查看控制器参数
1 | |
滚动升级:
将nginx版本更新⾄1.15.8
1 | |
发布回滚:
kubectl rollout 版本升级相关介绍
history 升级历史记录
undo 默认回滚上⼀版本 ,使⽤–to-revision回滚到指定版本
pause 暂停版本升级发布
resume 继续恢复刚暂停的版本升级
status 升级状态
1 | |
DaemonSet
daemonset-nginx.yaml
1 | |
1 | |
Job
1 | |
BusyBox:
是⼀个集成了三百多个最常⽤Linux命令和⼯具的软件。
包含了简单的⼯具,例如ls、 cat和echo等等,还包含了⼀些更复杂的⼯具,例grep、 find、 telnet。
1 | |
1 | |
Service
在k8s⾥⾯,每个Pod都会被分配⼀个单独的IP地址,但这个IP地址会随着Pod的销毁⽽消失,重启pod的ip地址会发⽣变化,此时客户如果访问原先的ip地址则会报错。
Service (服务)就是⽤来解决这个问题的, 对外服务的统⼀⼊⼝,防⽌pod失联,定义⼀组pod的访问策略(服务发现、负载均衡)。
⼀个Service可以看作⼀组提供相同服务的Pod的对外访问接⼝,作⽤于哪些Pod是通过标签选择器来定义的。
Service是⼀个概念,主要作⽤的是节点上的kube-proxy服务进程。
定义了3个商品微服务,由⽹关作为统⼀访问⼊⼝, 前端不需要关⼼它们调⽤了哪个后端副本。 然⽽组成这⼀组后端程序的 Pod 实际上可能会发⽣变化, 前端客户端不应该也没必要知道,⽽且也不需要跟踪这⼀组后端的状态。
Service 定义的抽象能够解耦这种关联。
service分类:
ClusterIP:
默认类型,⾃动分配⼀个【仅集群内部】可以访问的虚拟IP。
NodePort:
对外访问应⽤使⽤,在ClusterIP基础上为Service在每台机器上绑定⼀个端⼝,就可以通过: ip+NodePort来访问该服务。
LoadBalancer(花钱的⽅案):
使在NodePort的基础上,借助公有云创建⼀个外部负载均衡器,并将请求转发到NodePort。
可以实现集群外部访问服务的另外⼀种解决⽅案,不过并不是所有的k8s集群都会⽀持,⼤多是在公有云托管集群中会⽀持该类型。
ExternalName(很少):
把集群外部的服务引⼊到集群内部来,在集群内部直接使⽤。没有任何类型代理被创建,这只有 Kubernetes 1.7或更⾼版本的kube-dns才⽀持。
service和pod的关系:
service和pod之间是通过 selector.app进⾏关联的。
1 | |
1 | |
port-targetPort -nodePort-containerPort
port:
是service端⼝,即k8s中服务之间的访问端⼝ ,clusterIP:port 是提供给集群内部客户访问service的⼊⼝。
nodePort:
容器所在node节点的端⼝,通过nodeport类型的service暴露给集群节点,外部可以访问的端⼝。
targetPort:
是pod的端⼝ ,从port和nodePort来的流量经过kubeproxy流⼊到后端pod的targetPort上,最后进⼊容器。
containerPort:
是pod内部容器的端⼝, targetPort映射到containerPort。
4种端⼝作⽤不⼀样, port和nodePort都是service的端⼝。
port暴露给集群内客户访问服务, nodePort暴露给集群外客户访问服务。
这两个端⼝到来的数据都需要经过反向代理kube-proxy流⼊后端pod的targetPod,从⽽到达pod中的容器。
1 | |
ClusterIP
1 | |
NodePort和EndPoint
NodePort
常规业务的场景不全是集群内访问,也需要集群外业务访问。
那么ClusterIP就满⾜不了了, NodePort是其中的⼀种实现集群外部访问的⽅案。
对外访问应⽤使⽤,在ClusterIP基础上为Service在每台机器上绑定⼀个端⼝,就可以通过: ip+NodePort来访问该服务。
1 | |
Endpoint(缩写是ep)
是k8s中的⼀个资源对象,存储在etcd中,记录service对应的所有pod的访问地址。
⾥⾯有个Endpoints列表,就是当前service可以负载到的pod服务⼊⼝。
service和pod之间的通信是通过endpoint实现的。
1 | |
kubernetes提供了两种负载均衡策略:
默认, kube-proxy的策略,如随机、轮询
使⽤会话保持模式,即同个客户端的请求固定到某个pod,在spec中添加sessionAffinity:ClientIP即可
1 | |
数据存储持久化
容器的⽣命周期可能很短,会被频繁地创建和销毁,容器中的⽂件在磁盘上是临时存放的,这给容器中运⾏的较重要的应⽤程序带来⼀些问题
问题⼀ :当容器崩溃时⽂件丢失, kubelet 会重新启动容器,但容器会以⼲净的状态重启,之前保存在容器中的数据也会被清除
问题⼆:当在⼀个 Pod 中同时运⾏多个容器时,常常需要在这些容器之间共享⽂件
Kubernetes 卷(Volume) 这⼀抽象概念能够解决这两个问题,卷的核⼼是包含⼀些数据的⽬录, Pod 中的容器可以访问该⽬录。
Volume是k8s抽象出来的对象,它被定义在Pod上,然后被⼀个Pod⾥的多个容器挂载到具体的⽂件⽬录下。
kubernetes通过Volume实现同⼀个Pod中不同容器之间的数据共享以及数据的持久化存储。
Volume的⽣命周期不与Pod中单个容器的⽣命周期相关,当容器终⽌或者重启时, Volume中的数据也不会丢失。
K8S可以⽀持许多类型的卷, Pod 也能同时使⽤任意数量的卷。
Volume常⻅的类型:
常规存储: EmptyDir、 HostPath
⾼级存储: PV、 PVC
配置存储: ConfigMap、 Secret
其他:⽹络存储系统 NFS、 CIFS,包括云服务商提供的、本地、分布式
EmptyDir
当 Pod 指定到某个节点上时,⾸先创建的是⼀个 emptyDir卷,只要 Pod 在该节点上运⾏卷就⼀直存在。
当 Pod 因为某些原因被从节点上删除时, emptyDir 卷中的数据也会永久删除。
容器崩溃并不会导致 Pod 被从节点上移除,所以容器崩溃时emptyDir 卷中的数据是安全的。
⽤途:临时缓存空间
案例 volume-emptydir.yaml , pod⾥⾯定义两个容器,⼀个产⽣⽇志,⼀个是读⽇志输出到控制台
1 | |
1 | |
hostPath
emptyDir中数据没做持久化,随着Pod的结束⽽销毁,需要持久化到磁盘则选其他⽅式。
hostPath类型的磁盘就是挂在了主机的⼀个⽂件或者⽬录。
案例:某些应⽤需要⽤到docker的内部⽂件,这时只需要挂在本机的/var/lib/docker作为hostPath
HostPath有多种类型,列举常⻅⼏个:
Directory 给定的⽬录路径必须存在。
DirectoryOrCreate 如果给定路径不存在,将根据需要在那⾥创建⼀个空⽬录。
File 给定路径上必须存在对应⽂件。
FileOrCreate 如果给定路径不存在,将根据需要在那⾥创建⼀个空⽂件。
volume-hostpath.yaml:
1 | |
1 | |
emptyDir和hostPath对⽐:
都是本地存储卷⽅式;
emptyDir是临时存储空间,完全不提供持久化⽀持;
hostPath的卷数据是持久化在node节点的⽂件系统中的,即便pod已经被删除了, volume卷中的数据还留存在node节点上;
ConfigMap
需求:
很多应⽤在其初始化或运⾏期间要依赖⼀些配置信息。
⼤多数时候, 存在要调整配置参数所设置的数值的需求。
ConfigMap 是 Kubernetes ⽤来向应⽤ Pod 中注⼊配置数据的⽅法。
ConfigMap介绍(缩写cm):
是K8S的⼀种API对象,⽤来把【⾮加密数据】保存到键值对中,⽐如etcd。
可以⽤作环境变量、命令⾏参数等,将环境变量、配置信息和容器镜像解耦,便于应⽤配置的修改。
使⽤⽅式:
kubectl create configmap 命令,基于⽬录、 ⽂件或者键值对来创建 ConfigMap。
1 | |
⽅式⼀:使⽤命令⾏创建:
1 | |
⽅式⼆:使⽤⽂件创建configmap.yaml
1 | |
1 | |
创建pod的yaml, pod-configmap.yaml,然后吧将创建的configmap挂载进去:
1 | |
1 | |
Secret
需求:
有些配置需要加密存储, ConfigMap只能使⽤明⽂保存,因此不适合。
Secret:
⽤来保存敏感信息,例如密码、秘钥、证书、 OAuth 令牌和ssh key等。
就不需要把这些敏感数据暴露到镜像或者Pod中。
Pod 可以⽤三种⽅式之⼀来使⽤ Secret:
作为挂载到⼀个或多个容器上的卷 中的⽂件
作为容器的环境变量
由 kubelet 在为 Pod 拉取镜像时使⽤。
secret有多个类型:
dockerconfigjson
⽤来存储私有 docker registry的认证信息
Service Account
只要与Kubernetes API有交互的Pod,都会⾃动拥有此种类型的Secret
K8S⾃动创建,并且会⾃动挂载到Pod的/run/secrets/kubernetes.io/serviceaccount ⽬录中
1 | |
Opaque
加密类型为base64,其特点就是将明⽂改为了密⽂
1 | |
secret.yaml
1 | |
1 | |
将secret挂载到Pod的Volume中,创建pod-secretvolume.yaml
1 | |
1 | |
NFS⽹络⽂件系统搭建
什么是NFS(Network File System)
⼀种基于TCP/IP 传输的⽹络⽂件系统协议, 通过使⽤NFS协议,可以像访问本地⽬录⼀样访问远程服务器中的共享资源。
NFS服务的实现依赖于RPC (Remote Process Call,远端过程调⽤)机制,以完成远程到本地的映射过程。
⼀般需要安装nfs-utils、 rpcbind 软件包来提供NFS共享服务,前者⽤于NFS共享发布和访问,后者⽤于RPC⽀持。
采⽤TCP/IP传输⽹络⽂件,适合局域⽹环境,简单操作:
NFS端⼝: 2049
RPC端⼝: 111
NFS 在 K8S Volume⾥⾯的作⽤
当某个节点发⽣故障的时候,该节点上的pod发⽣了转移,如何保证这些pod的数据不丢失呢?
此时就需要引⼊外部⽹络⽂件系统,例如nfs或者其他具有对象存储功能的系统,可以保存当pod发⽣转移的时候数据也不丢失。
部署NFS服务器
1 | |
参数:
rw 共享⽬录可读可写
secure 限制客户端只能从⼩于1024的tcp/ip端⼝连接服务器;
insecure允许客户端从⼤于1024的tcp/ip端⼝连接服务器;
sync 将数据同步写⼊内存缓冲区与磁盘中,效率低,但可以保证数据的⼀致性;
async 将数据先保存在内存缓冲区中,必要时才写⼊磁盘;
1 | |
验证:
showmount -e localhost
NF持久卷挂载
1 | |
1 | |
PV和PVC
Kubernetes ⽀持的存储插件很多:
awsElasticBlockStore - AWS 弹性块存储(EBS)
azureDisk - Azure Disk
azureFile - Azure File
cephfs- CephFS volume
azureDisk - Azure Disk
hostPath - HostPath 卷
nfs- ⽹络⽂件系统 (NFS) 存储
在整个k8s集群中,有⼀些存储的资源,⽐如说NFS、 CIFS等存储,这些存储都是由存储⼯程师去创建的,不同的存储⽅式不⼀样, 如果都掌握才可以使⽤,则很不⽅便的。
所以在k8s中提供了新的对象资源叫做PV(Persistent Volume)和PVC(Persistent Volume Claim),更⽅便⽤户直接进⾏使⽤。
什么是PV 持久卷(Persistent Volume)
是集群中由管理员配置的⼀段⽹络存储,它是集群的⼀部分资源和底层存储密切相关,对象包含存储实现的细节,即 对接NFS、 CIFS等存储系统。
不同的PV会对应到不⽤的存储资源,这样在部署pod的时候直接调⽤集群内部的pv即可。
PV没有命名空间隔离概念。
什么是PVC 持久卷声明 (Persistent Volume Claim)
假如存在很多PV, K8S 要⽤PV的时候直接调⽤某个PV的话,那如果需要的是存储能⼒⽐较⼤存储资源,所以这个时候需要⼀个⼀个去对⽐pv,这样很耗费资源(因为要满⾜需求)。
PVC是⽤户存储的⼀种声明, PVC 可以请求特定的存储空间和访问模式, PVC 消耗的是 PV 资源。
PVC必须与对应的PV建⽴关系, PVC会根据定义的PV去申请。
创建pod的时候会附带⼀个PVC的请求, PVC的请求相当于就是去寻找⼀个合适的pv。
使⽤逻辑:
在 pod 中定义⼀个存储卷(该存储卷类型为 PVC),定义的时候按指定⼤⼩, PVC 必须与对应的 PV 建⽴关系, PVC会根据定义的需求【去 PV 申请】,⽽ PV 是由存储空间创建出来的。
PV和PVC逻辑:
PV 是集群中的【资源】, PVC 是对这些【资源的请求】
PV 和 PVC 之间的相互作⽤遵循这个⽣命周期:
Provisioning(配置) —> Binding(绑定) —> Using(使⽤) —>Releasing(释放) —> Recycling(回收)
1 | |
存储⼤⼩: 存储⼤⼩是可以设置和请求的唯⼀资源。 未来可能会包含 IOPS、吞吐量等属性。
访问模式:⽤户对资源的访问权限:
ReadWriteOnce(RWO):读写权限,只能被单个节点挂载
ReadOnlyMany(ROX): 只读权限,可以被多个节点挂载
ReadWriteMany(RWX):读写权限,可以被多个节点挂载
存储类别:
每个 PV 可以属于某个类,通过将其 storageClassName属性设置为某个 StorageClass 的名称来指定。
特定类的 PV 卷只能绑定到请求该类存储卷的 PVC 申领。
未设置 storageClassName 的 PV 卷没有类设定,只能给到那些没有指定特定 存储类的 PVC 申领。
回收策略(当PV不再被使⽤了之后的处理策略)
保留 Retain – 当PV对象被删除之后,与之相关的位于外部的基础设施中的数据仍然存在(如nfs),需要根据实际情况⼿动回收
回收 Recycle – 相当于在卷上执⾏rm -rf /volume/* 操作,之后该卷可以⽤于新的pvc申领
删除 Delete – 当PV对象被删除之后,与之相关的位于外部的基础设施中的数据也被⼀并删除(如nfs),需要根据实际情况⼿动回收,更多是云⼚商设备
状态( PV 的⽣命周期有4种不同状态):
Available(可⽤) ——⼀块空闲资源还没有被任何声明绑定
Bound(已绑定) ——卷已经被声明绑定
Released(已释放) ——声明被删除,但是资源还未被集群重新声明
Failed(失败) ——该卷的⾃动回收失败
1 | |
NFS+PV和PVC案例
需求:
基于NFS存储,创建2个PV
创建PVC绑定PV
创建Pod挂载PVC
PV和PVC的使⽤:
搭建nfs环境(nfs服务器,基于上⾯的nfs):
1 | |
创建两个PV
1 | |
1 | |
创建PVC,使⽤pvc.yaml (与PV不同, PVC不属于集群资源,拥有⾃⼰的名称空间)
1 | |
1 | |
创建pod 挂载pvc
1 | |
1 | |