Kubernetes
官方网站:http://www.kubernetes.io
官方文档:https://kubernetes.io/zh/docs/home/
kubernetes是一种容器边编排机制,用于容器化应用程序的部署,扩展以及管理,目标是让部署容器化应用变得简单高效。

发展经历
Infrastucture as a Service,简称IAAS,基础设施即服务,代表阿里云、亚马逊云
Platform as a Serivce,简称PAAS,平台即服务,代表有:
新浪sae,派单给运维构建环境
Apache Mesos 开源分布式资源管理框架,用于构建资源池
DockerSwarm,轻量级容器资源管理器,功能太少
Kubernetes,领航者,功能全面、稳定,由Google支持,是由brog系统使用go重新演化出来的
Software as a Service,简称SAAS,软件即服务,代表:Office 365、腾讯文档无需安装,直接在浏览器使用
集群架构和组件
Brog(博格)架构

BrogMaster(集群部署)主要负责请求分发。客户可以通过brogcfg配置文件、command-line tools命令行、web browser浏览器三种方式对集群进行调度管理
Scheduler,调度器,由客户端发起的调度将会交给该组件解析,并将任务存储在Google Paxos键值对数据库中
Broglet则会从Paxos中循环读取数据,找到自己需要做的任务进行处理,负责提供计算能力与服务
Kubernetes架构

Master
负责请求的分发
Scheduler调度器:介绍任务给节点,也就是负责将任务分散到不同的node中,并将结果交给ApiServer,ApiServer再将数据写入到etcd(kv数据库)
Controller Manager:处理集群中常规后台任务,一个资源对应一个控制器,而ControllerManager就是负责管理这些控制器的。例如Deployment、Service
api server:Kubernetes API,集群的统一入口(kubectl, web UI, scheduler, etcd, replication controller),各组件协调者,以RESTfulAPI提供接口服务,所有对象资源的增删改查和监听操作都交给APIServer处理后再提交给Etcd存储。
etcd:分布式键值存储系统,用于保存集群状态数据,比如Pod、Service等对象信息
go语言编写的可信赖的分布式的键值存储服务,用于存储关键数据,协助分布式集群正常运转
v2版本只能存储在内存中,v3则会持久化。注意,在k8s v1.11版本中,v2版本已被弃用
采用HTTP协议、C/S架构
架构图:

Node
真正提供计算能力与服务的组件,负责运行Pod和容器
kubelet组件,Master在Node节点上的Agent,管理本机运行容器的生命周期,比如创建容器、Pod挂载数据卷、下载secret、获取容器和节点状态等工作。kubelet将每个Pod转换成一组容器。容器之间的差异通过CRI(容器运行时接口)屏蔽。
kubeproxy,负责写入规则到iptables或者IPVS实现映射访问,以实现在Node节点上实现Pod网络代理,维护网络规则和四层负载均衡工作。
容器引擎,比如Docker、Containerd
集群调用者
Dashboard:给K8s集群提供一个B/S结构的访问体系
kubectl:命令管理k8s集群
CoreDNS:可以为集群中的SVC创建一个A记录(域名IP对应关系解析)
FEDERATION:提供一个可以跨集群多k8s统一管理的功能
PROMETHEUS:普罗米修斯,提供K8s监控能力
ELK:提供k8s集群日志统一分析介入平台
部署Kubernetes
生产环境部署k8s主要的两种方式:
kubeadm,Kubeadm是一个工具,提供kubeadm init和kubeadm join,用于快速部署Kubernetes集群。
部署地址:https://kubernetes.io/docs/reference/setup-tools/kubeadm/kubeadm/
优点:快速、方便
二进制,从官方下载发行版的二进制包,手动部署每个组件,组成Kubernetes集群。
下载地址:https://github.com/kubernetes/kubernetes/releases
优点:可以对部署过程更好的理解
服务器硬件配置推荐:

网络组件的作用
部署网络组件的目的是打通Pod到Pod之间网络、Node与Pod之间网络,从集群中数据包可以任意传输,形成了一个扁平化网络。
目前,主流的网络组件有:
Flannel,几十台
Calico,更大规模
CNI(Container Network Interface,容器网络接口),就是对k8s对接这些三方网络组建的接口。
配置命令补全
连接Kubernetes集群
kubeconfig配置文件
文件位于:~/.kube/config,kubectl 使用kubeconfig认证文件连接到k8s集群,我们可以使用kubectl config指令生成kubeconfig文件;kubeconfig文件主要记录了下面的几个部分的信息:
集群信息:
上下文信息(已经连接的所有集群信息,比如用户,生产环境有可能有多个集群):
当前上下文信息(当前选择的哪个集群)
客户端证书信息
指定kubeconfig执行命令:
不加会默认从家目录读取,可以移动家目录缩短命令:
将配置文件分发给其他机器,就可以连接k8s集群。
连接多个k8s集群
合并配置,context方式,切换context
我的mac上docker-desktop的kubeconfig:
我的windows虚拟机上的kubeconfig:
我想让我的mac上的kubectl可以同时访问这两个集群,将windows虚拟机上的kubeconfig拷贝到mac,并修改名称:
配置 KUBECONFIG 环境变量,是 kubectl 工具支持的变量,变量内容是冒号分隔的 kubernetes config 认证文件路径,以此来合并多个kubeconfig文件:
查看合并后的文件cat ~/.:
注意,不要重名
切换context:
docker desktop

docker-desktop 使用命令更改context:
切换config文件(不推荐)
直接指定配置文件(不推荐)
集群监控
查看资源集群状态
查看master组件状态:
查看node节点状态:
查看集群信息:
查看api资源信息:
查看资源列表:
查看资源的详细信息:
查看集群资源利用率
查看Node资源消耗:
查看Pod资源消耗:
这个过程是:
如果提示: error: Metrics API not available,则需要安装metrics,官方地址:kubernetes-sigs/metrics-server: Scalable and efficient source of container resource metrics for Kubernetes built-in autoscaling pipelines. (github.com)。
安装完毕后再执行命令如下:
管理组件日志
k8s系统组件日志
systemd守护进程管理的组件,比如kubelet
或者查看系统日志
Pod部署的组件:
k8s集群内部部署的应用程序日志
标准输出,容器的标准输出将会输出在宿主机的
/var/lib/docker/containers/<container-id>-json.log下日志文件,比如java log框架打印到某个指定的文件,可以对应用程序内部路径挂载,在宿主机查看;或者使用
kubectl exec -it <Pod名称> -- bash进入容器内部直接查看文件。
收集k8s日志的思路
针对标准输出:以DaemonSet方式在每个Node上部署一个日志收集程序,采集
/var/lib/docker/containers/目录下的所有日志
image-20220114192414927 针对容器中的日志文件:在Pod中增加一个容器运行日志采集器,使用emptyDir共享日志目录让日志采集器读取到日志文件

image-20220114192431691
部署应用

命令方式
使用Deployment控制器部署镜像
使用service发布pod
访问
任意NodeIP:31052即可访问Nginx服务卸载:
kubectl delete delployment web和kubectl delete svc web
yaml方式
编写yaml资源文件
kubectl apply -f 上面的yaml文件卸载
kubectl delete -f 文件
快速生成yaml
根据已有资源生成yaml
查看资源的API
查看所有的API资源
查看所有的API的版本
查看某个API的二级字段
查看某个API的所有级别的字段
查看某个API具体的某个字段的下一级字段
资源
资源:在k8s中,所有的内容都被抽象为资源,当资源被实例化后,成为对象。
集群资源的分类
名称空间(namespace)级别的资源
工作负载资源(workload)
Pod
ReplicationController,v1.11被废弃
ReplicaSet
Deployment
StatefulSet
DaemonSet
Job
CronJob
服务发现/负载均衡资源(ServiceDiscovery LoadBalance)
Service
Ingress
配置与存储资源
Volume
CSI(容器存储接口)
特殊类型存储卷
ConfigMap(配置中心资源类型)
Secret(保存敏感数据)
DownwardAPI(将外部环境中的信息输出给容器)
集群级别的资源
Namespace
Node
Role
ClusterRole
RoleBinding
ClusterRoleBinding
元数据型的资源
HPA
PodTemplate
LimitRange
Deployment

Deployment控制器与其他控制器的最主要目的就是为了方便管理k8s中的容器,而Deployment是最常见的工作负载控制器,是k8s的一个抽象概念,用于更高层次的对象,负责部署、管理Pod。与之类似的控制器还有DaemonSet、StatefulSet等。
主要功能:
管理Pod和ReplicaSet
具有上线部署、副本设定、滚动升级、回滚等功能
提供声明式更新
应用场景:
网站
API
微服务
管理应用生命周期

Deployment可以针对应用生命周期进行管理:
部署
升级
滚动升级:k8s对Pod升级的默认策略,通过使用新版本Pod逐步更新旧版本Pod,实现零停机发布,用户无感知
发布策略主要有:蓝绿、灰度(金丝雀、A/B测试、冒烟测试)、滚动。(停机瀑布式升级已经过时)
部署升级的过程:
水平扩容缩容
扩容/缩容操作实际就是控制ReplicaSet的副本数
回滚(不常用)
回滚是调用ReplicaSet重新部署某个版本(每个版本都有对应的一个ReplicaSet,可以查看rs的信息确认对应的版本号已经所做的改动):

项目下线
ReplicaSet
用途:
Pod副本数量管理,不断对比当前Pod数量和期望Pod数量
Deployment每次发布都会创建一个ReplicaSet作为记录,用于实现回滚
滚动升级,创建新的RS进行逐步替换旧的RS
Pod
最小封装集合(豌豆荚,容器荚),一个Pod中会封装多个容器,也是k8s管理的最小单位。有些服务之间关联性较强,需要共享网络环境、存储环境等。如果使用标准容器则很难完成操作,所以k8s在容器外部增加了一个Pod的概念。

特点:
一个Pod可以理解为一个应用程序示例
Pod中的所有容器始终部署在同一个Node上
Pod中容器共享网络,存储资源
边车模式设计(侧面可以带人的三轮摩托):
通过在Pod中定义专门容器来执行业务容器需要的辅助工作
可以将辅助功能同主业务容器解耦,实现独立发布和能力重用
比如:日志收集、应用监控
Pod对象管理命令
注意:一半没有人直接创建Pod
创建Pod:
kubectl apply -f pod.yaml,kind资源类型为Podkubectl run nginx --image=nginx
查看Pod:
kubectl get podskubectl get pods -w实时查看kubectl describe pod <pod_name>资源的详细信息
查看日志:
kubectl logs <pod_name> [-c 容器名称]kubectl logs <pod_name> [-c 容器名称] -f实时查看
进入容器终端:
kubectl exec <pod_name> [-c 容器名称] -- bash
删除Pod:
kubectl delete pod <pod_name>
Pod的状态
Pending 挂起:Pod已经被k8s系统接受,但是有一个或者多个容器尚未创建。这段时间包括:调度Pod、镜像下载等
Running 运行中:Pod已经被绑定在某个Node上,Pod中的所有容器都已经被创建。至少有一个容器处于运行状态,或者正在处于启动或者重启状态
Succeeded 成功:Pod中的所有容器都被成功终止,并且不会再重启
Failed 失败:Pod中至少有一个容器是失败终止的(容器以非0状态退出或者被系统终止)
Unknown 未知:因为某些原因无法取得Pod状态,通常是因为与Pod所在主机通讯失败
创建Pod的流程

Kubernetes基于list-watch机制的控制器架构,实现组件间交互的解耦。其他组件监控自己负责的资源,当这些组件方发生变化时,kube-apiserver会通知这些组件,这个过程类似发布与订阅。
执行命令创建Pod(或是由ControllerManager发送,比如Deployment控制器创建的),命令行将会通过api发送到APIServer,并将创建pod的配置信息提交给ETCD键值对存储系统
Schedule检测到未绑定节点的Pod,当根据自身算法选择一个合适的节点,并给这个pod打一个标记,比如:nodename=node1;然后响应给apiserver,并写入到etcd中
kubelet通过apiserver发现有分配到自己节点的新pod,于是调用CRI创建容器,随后将容器状态上报给apiserver,然后写入etcd
kubectl get 请求apiserver 获取当前命令空间pod列表状态,apiserver从etcd直接读取
Pod的生命周期

创建pod成功后:
初始化基础容器(pause容器)以完成Pod内网络存储的共享
由pause容器启动一个或者多个init容器,多个init容器链式执行
如果前一个执行完毕,切没有错误,就会执行下一个init容器
如果init容器启动失败,且Pod的重启策略为Always,那么Pod将会不断地重启
作用:在容器创建前,使用初始化容器完成一些工具以及数据的初始化,以防止MainC不安全或者冗余
作用:Init容器使用LinuxNamespace,所以相对于应用程序具有不同的文件视图,他们具有访问Secret的权限,MainC不具备
先于MainC运行,可以用于阻塞启动容器
并发启动所有MainC(业务容器)
对每个主容器进行readiness/liveness 就绪/存活检测
就绪检测之后,容器会变为Ready就绪状态,就绪之后才会开放端口,暴露服务
存活检测跟随整个容器生命,会不间断的对容器的生存情况进行检测,如果不存活,则会根据Pod的重启策略,对Pod进行重启
start/stop 生命周期动作
验证:Pod内多容器网络、资源共享机制
修改yaml资源清单如下:
执行:
验证网络以及资源共享:
验证:每个Pod都会初始化一个pause容器
名称为nginx的容器共有两个,其中一个为pause容器。
环境变量
创建Pod时,可以为其下的容器设置环境变量。
应用场景:
容器内通过环境变量获取Pod信息
容器内应用程序通过用户自定义变量改变应用程序默认行为
环境变量定义方式:
自定义变量值
变量值从Pod属性获取
变量值从Secret、ConfigMap获取
测试:
创建上述pod:
查看环境变量配置是否生效:
进入容器输出环境变量:
init容器/初始化容器
初始化容器用于初始化工作,执行完毕就结束,可以理解为一次性任务
支持大部分应用容器配置,但是不支持健康检查
优先于应用容器执行
应用场景:
环境检查:确保应用容器以来的服务启动后再启动应用容器
初始化配置:例如给应用容器准备配置文件
示例:下载并初始化配置
重启策略 restartPolicy
共有三中那个重启策略,分别用在不同的场景:
Always:当容器终止退出后,总是重新启动容器,是Pod的默认策略。适合需要持续运行提供服务的程序,比如nginx、redis、javaappOnFailure:当容器异常退出(退出状态码非0)时,才重启容器。适合需要周期性运行的程序,比如数据库备份、巡检Never:当容器退出后,从不重启容器。适合一次性运行的程序,比如计算程序、数据离线处理程序
设置Pod的重启策略:
健康检查
健康检查分为三个阶段,位于Init容器运行成功之后:
startupProbe:启动检查,检查成功才由存活检查接手,用于保护慢启动容器(某些容器启动过程时间长,通过启动检查可以排除环境问题,防止长时间启动最后因环境失败的情况)livenessPobe:存活检查,将杀死容器,根据Pod的restartPolicy来操作redinessProbe:就绪检查,检查服务是否正常运行,比如项目是否启动成功。如果检查失败,Kubernetes会把Pod从service endpoints中剔除
其中每种检查都支持一下三种检查方法:
httGet:发送HTTP请求,返回200-400范围状态码为成功exec:执行shell命令返回状态码是0成功tcpSocket:发起TCP Socket建立成功
示例:健康检查-端口探测(http)
部署一个deployment,他的资源清单nginx.yaml如下:
查看部署情况:
查看pod内容器的详细信息,确认livenessProbe和redinessProbe配置是否成功
验证存活检查与就绪检查是否每段时间发送一次请求
验证存活检查失败,是否将杀死容器,并根据Pod的restartPolicy来操作
再次查看pod信息:
重启次数:
验证Kubernetes是否会把Pod从service endpoints中剔除
在执行上述命令之前,使用如下命令持续监测endpoint的状态,可以看到如下的结果:
静态Pod
特点:
Pod由特定节点上的kubelet管理
不能使用控制器
Pod名称标志当前节点名称
应用场景:
k8s搭建就是这种机制,用于启动kube系统组件
工作中不会用
在kubelet配置文件中启用静态Pod参数:
将部署的pod yaml放在该目录由kubelet自动创建,从这个目录移除就会自动移除静态pod。
DaemonSet
功能:
在每个Node上都运行一个Pod
新加入的Node也同样会自动运行一个Pod
应用场景:
网络插件
监控Agent
日志Agent
查看调度失败原因,kubectl describe pod <NAME>
节点CPU/内存不足
有污点,没容忍
没有匹配到节点标签
Service
Service的引入主要解决Pod的动态变化(IP每次部署都不同),并提供统一的访问入口:
**服务发现:**防止Pod失联,找到提供同一个服务的Pod
负载均衡:定义一组Pod的访问策略,并可以避免将流量发送到不可达的Pod上
是集群内服务的代理节点。
Pod和Service的关系
Service 通过标签关联一组Pod
Service通过iptables或者ipvs为一组Pod提供负载均衡的能力
定义与创建Service
创建svc:
查看已经创建的svc:
type字段
常见的Service类型有三种:
ClusterIP,默认值,分配一个IP地址,即VIP,只能在集群内部访问
NodePort,在每个节点上启用一个端口来暴露服务,可以让其通过任意node+端口来进行外部访问;同时也像ClusterIP一样分配一个集群内部IP供集群内部访问

image-20220119151136177 LoadBalance,与NodePort完全一致。除此以外,k8s会请求底层云平台(比如阿里云、腾讯云、AWS等)上的负载均衡,将每个Node([NodeIp]:[NodePort]) 作为后端添加进去

image-20220119152054063
service负载均衡实现机制

Service 底层实现主要有iptables和 ipvs两种网络模式,决定你如何转发流量。
service DNS名称解析
CoreDNS是一个DNS服务器,k8s默认采用pod的方式部署在集群中。CoreDNS服务监视KubernetesAPI,为每一个Service创建DNS A记录用于域名解析。其格式为 <service-name>.<namespace-name>.svc.cluster.local
CoreDNS Yaml文件可以参考: https://github.com/kubernetes/kubernetes/tree/master/cluster/addons/coredns
验证:当创建service时会自动添加一个DNS记录:
创建Deployment以及service,进入容器,测试DNS:
Ingress
既然后又NodePort,为什么还需要Ingress?
NodePort 是基于iptables/ipvs实现的负载均衡器,他是四层转发
四层转发是指在传输层基于IP和Port的转发方式,这种方式的转发不能满足类似域名分流、重定向之类的需求
所以引入的Ingress七层转发(应用层),他可以针对HTTP等应用层协议的内容转发,可以满足的场景更多

Ingress:k8s中的一个抽象资源,用于给管理员提供一个暴露应用的入口定义方法
Ingress Controller:负责流量路由,根据Ingress生成具体的路由规则,并对Pod进行负载均衡
外部用户通过Ingress Controller访问服务,由Ingress规则决定访问哪个Service
IngressController内包含一个Service,也可以通过NodePort暴露端口,让用户访问
然后将流量直接转发到对应的Pod上(注意:只通过Service找到对应的Pod,实际发送并不经过Service,这样更高效)
IngressController是社区提供的一种接口,其下面有很多具体的实现,比如 Nginx、Kong等
最主流的实现为kubernetes/ingress-nginx
部署ingress-nginx
从github中下载yaml配置
ingress-nginx相关镜像位于google镜像仓库中,国内网络无法访问;可以从docker hub上寻找相关镜像,修改yaml中的相关镜像地址
修改用于暴露Ingress-Nginx-Controller的Service的端口暴露方式(ingress controller是pod,负责动态生成nginx配置):
执行部署
kubernetes里命名空间删不掉的问题
如果某个命名空间(此例里是ingress-nginx)迟迟删除不掉,状态一直是Terminating,然后在此命名空间里重新创建资源时报如下错误:
解决方案:
在第一个终端里执行:
kubectl proxy在第二个终端里:
kubectl get namespace ingress-nginx -o json > xx.json更改json文件:

file 改为

file 最后执行:
创建ingress规则(HTTP)
查看ingress规则:
配置hosts,访问这些地址即可。
创建ingress规则(HTTPS)
准备域名证书文件(使用阿里云免费证书,或者使用openssl/cfssl创建自签证书)
将证书文件保存到k8s Secret中
使用Ingress规则配置tls
配置hosts文件,访问: https://ingress.yangsx95.com:30443/
工作原理
IngressController通过与k8s API交互,动态感知集群中Ingress规则变化,然后读取他,按照自定义的规则,规则就是写明了哪个域名对应哪个service,生成一段nginx配置,应用到管理的nginx服务,然后加载生效。以此来达到负载均衡配置即热更新的效果。
工作流程:
StatefulSet(部署有状态应用)
有状态和无状态
Deployment控制器的设计原则:管理的所有Pod一模一样,提供同一个服务,也不考虑在哪台Node运行,可随意扩容缩容。这种应用成为无状态应用。比如web应用程序就是无状态应用。
在实际场景中,并不能满足所有的应用,尤其是分布式应用程序,一般会部署多个实例,不同于无状态应用比如web服务,这些实例之间往往有依赖关系,例如:主从关系、主备关系,这种应用成为有状态应用,比如Mysql集群,ETCD集群。
StatefulSet就是为了解决部署有状态应用而出现的控制器:
给Pod分配一个唯一稳定的网络标志符(主机名、唯一域名):使用Headless Service来维护网络的身份
稳定唯一的持久的存储(唯一的PV和PVC):StatefulSet的存储卷使用VolumeClaimTemplate(卷申请模板),当StatefulSet使用VolumeClaimTemplate创建一个PersisentVolume时,同样也会为每个Pod分配并创建一个对应的PVC
StatefulSet三要素:
域名
主机名
存储(PVC)
部署StatefulSet
调度
配置Pod的资源限制
cpu的单位为毫核(m)或者为浮点数字,比如
500m = 0.5,1000m = 1内存的单位为Mb,GB等,例如
500Mi,1Girequest代表应用程序启动时需要的资源数量,调度器会寻找符合request要求的节点,如果没有Pod就会一直处于pending状态limit代表应用程序运行时最多占用的资源数量,这个值对调度机制并不起决定性的作用,如果request的值满足,那么就会部署容器limit可以防止应用程序假死或者超负荷运行导致主机崩溃的情况,可以更合理控制资源request的值设置的过大会造成资源浪费,被request分配的资源,不管应用程序有没有使用,其他容器都无法再分配使用他们了
如何配置这几个值得大小:
request的值根据应用程序启动并正常提供服务时,大约占用的资源量决定
limit的值不建议超过宿主机实际物理配置的20%,剩余空间用来保证物理机的正常运行
limit的值可以根据request配置:不能大于request、request要小于limit 20%~30%
limit的值也可以根据应用根据实际压测估算
查看pod的资源限制:
查看Node信息,看Node上运行的容器的资源限制情况与Node本身的资源情况:
将Pod分配给指定节点
nodeName
指定节点名称,用于将Pod调度到指定的Node上,不经过调度器。所有污点、节点亲和都将会失效。
nodeSelector
用于将Pod调度到匹配Label的Node上,如果没有匹配的标签,调度会失败
作用:
约束Pod到特定的节点上运行
完全匹配节点标签
应用场景:
专用节点:根据业务线将Node分组管理
配备特殊硬件:部分Node配有SSD硬盘、GPU
示例,去报pod被分配具有ssd硬盘的节点上:
给含有ssd的node,设置一个标签:
查看node的标签信息
创建含有nodeSelect的Pod
验证,确实在node1上
如果不需要标签栏,可以移除标签:
nodeAffinity
节点亲和类似于nodeSelector,可以根据节点上的标签来约束Pod可以调度在哪些节点上。相比于nodeSelector:
匹配有更多的逻辑组合,不只是字符串的完全相等,支持的操作有: In、NotIn、Exist、DoesNotExist、Gt、Lt
调度分为软策略与应策略:
硬(required):必须满足,如果不满足则调度失败
软(preferred):尽量满足,如果不满足也继续调度,满足则调度到目标
参考官方文档:将 Pod 分配给节点 | Kubernetes
示例:
其中,权重值weight的范围为 1~100,权重值越大,这条亲和规则优先级就越高,调度器就会优先选择
污点和污点容忍
Taints:污点,避免Pod调度到特定的Node
Tolerations:污点容忍,允许Pod调度到持有Taints的Node上
应用场景:
保证master节点安全,在master节点含有污点,防止pod在master节点运行
专用节点:根据业务将Node分组管理,希望在默认情况下不调度该节点,只有配置了污点容忍才允许分配
配备特殊硬件:部分Node配有SSD硬盘、CPU,希望在默认情况下不调度该节点,只有配置了污点容忍才允许分配
基于Taint的驱逐
查看master节点的污点:
使用污点和污点容忍:
给节点添加污点:
验证是否正常添加:
配置污点容忍(pod可以容忍有gpu的节点):
删除污点(在后面增加一个减号):
存储
容器中的文件是在磁盘中临时存放的,这给容器中运行比较重要的应用程序带来如下问题:
当容器升级或者崩溃,kubelet会重建容器,容器内的文件会丢失
一个pod中运行多个容器需要共享文件
所以Kubernetes需要数据卷(Volume),常用的数据卷有:
节点本地卷(hostPath,emptyDir)
网络卷(NFS,Ceph,GlusterFS)
公有云(AWS,EBS)
K8s资源(configMap,secret)
所有支持的卷类型,可以参考:卷 | Kubernetes
emptyDir 临时数据卷
是一个临时的存储卷,与Pod的生命周期绑定在一起,如果Pod删除了卷也会被删除。主要用于Pod中的多个容器之间数据共享。
empty实际上是位于宿主机上的一个文件夹,容器都是共享的这个宿主机文件夹。他的位置在:/var/lib/kubelet/pod/podid/volumes/kubernetes.io~empty-dir/data中。
hostPath 节点数据卷
挂载node的文件系统,也就是pod所在的节点上的文件或者目录到pod中的容器。主要应用在Pod中的容器需要访问宿主机的文件的情况,比如DaemonSet。
注意:当因为某些情况pod被调度到其他节点上时,节点数据卷是不会被迁移过去的。
不安全,不建议使用,建议使用共享存储
NFS 网络数据卷
使用nfs网络数据卷共享存储:

NFS服务端一半是集群外的一台主机,而NFS客户端一般是需要使用共享存储的节点。
部署NFS
centos下准备NFS环境:
ubuntu下准备NFS环境:
测试NFS
在任意一个节点上执行:
使用NFS网络数据卷
进入容器查看nfs情况:
PV和PVC
PersistentVolume(PV):对存储资源创建和使用的抽象,使得存储作为集群中的资源管理
PersistentVolumeClaim(PVC):让用户不需要关心具体的Volume实现细节
Pod申请PVC作为卷来使用,Kubernetes通过PVC查找绑定的PV,并Mount给Pod。
pvc与pv是一对一的关系,一块存储只能给一个pvc使用
pvc会向上匹配第一个符合要求的pv,如果满足不了,pod处于pending
存储容量并不能做到有效的限制,他只是一个标志
使用pv和pvc:静态供给
定义需求卷:
定义卷需求,Pod 使用 PersistentVolumeClaim 来请求物理存储
容器应用使用卷需求
pv的访问模式
AccessMode是用来对PV进行访问模式的设置, 用于描述用户应用对存储资源的访问权限,包含以下几种:
ReadWriteOnce:拥有读写权限,但是只能被单个节点挂载
ReadOnlyMany:只读权限,可以被多个节点挂载
ReadWriteMany:读写权限,可以被多个节点挂载
pv的回收策略
Retain:当将pvc删除时,pv进入Released状态,这个状态下保留数据,需要管理员手动清理数据,默认策略,推荐使用
Recycle:清除pv中的数据,效果相同于执行命令
rm -rf /共享目录/*Delete:与pv相连的后端存储也一并删除
pv的状态
一个pv的生命周期中,可能会处于四种不同的状态:
Avaliable:可用状态,还未被任何PVC绑定
Bound:表示PVC已经被PVC绑定
Released:已释放,表示PVC被删除,但是资源还未被集群重新声明
Faild:失败状态,表示PV的自动回收失败
Storage Class
StorageClass是存储类,对一类存储资源的分类,不同的StorageClass可能代表值不同的存储服务的质量等级或者备份策略,比如固态硬盘与机械硬盘,定时备份与不做备份。
官方文档:https://kubernetes.io/zh/docs/concepts/storage/storage-classes/
创建一个StorageClass:
pv动态供给
允许按需创建PV,不需要运维人员每次手动添加,大大降低了维护成本。pv的动态供给主要由StorageClass对象实现。

PVC存储请求被创建,将会由对应的StorageClass自动创建一个PV。StorageClass是存储类,对一类存储志愿的分类与抽象。
NFS
Kubernetes 不包含内部 NFS 驱动。你需要使用外部驱动为 NFS 创建 StorageClass。 这里有些例子:
以subdir为例:
下载三个主要的yaml文件:nfs-subdir-external-provisioner/deploy at master · kubernetes-sigs/nfs-subdir-external-provisioner (github.com)
rabc.yaml:存储供给程序需要创建PV,需要调用K8s API,需要RABC授权deployment.yaml:存储供给程序class.yaml:StorageClass 对象,指定nfs存储供给程序
默认的pv的删除策略为delete,可以在class.yaml文件中进行更改
修改
deployment.yaml,更改镜像地址,否则无法下载镜像修改
deployment.yaml,更改NFS服务端信息,IP以及PATH(注意有两个地方)依次部署这三个yaml文件
查看已经创建的StorageClass:
使用NFS动态供给:
创建上述PVC,并查看PV,应该有自动创建的PV:
ConfigMap

ConfigMap用于应用程序的配置存储,Secret则用于存储敏感数据。ConfigMap共有两种创建方式:
键值对类型键
文件类型键
创建后,其数据将会存储在ETCD中。相应的,Pod也可以通过两种不同的方式获取ConfigMap中的数据到应用程序中:
变量注入
数据卷挂载
创建ConfigMap
使用ConfigMap
Secret
与ConfigMap类似,区别在于Secret主要存储敏感数据,所有数据都要经过base64编码(不加密)。
Secret的创建命令kubectl create secret支持存储创建三种数据类型的Secret:
docker-registry:存储镜像仓库认证信息
generic:密码
tls:存储证书
generic
创建secret:
使用secret(环境变量方式):
使用secret(volume挂载):
安全
k8s安全框架主要由下面3个阶段进行控制,每个阶段都支持插件方式,通过API Server配置来启用插件:
Authentication 鉴权:
Authorization 授权
Admission Control 准入控制
kubectl 发送指令到API Server依次经过这三个步骤进行安全控制,通过后才后继续进行后续的操作。

Authentication 鉴权
k8s API Server提供三种客户端身份认证:
HTTPS证书认证:基于CA证书签名的数字证书认证(kubeconfig,kubectl就是使用这种方式)
HTTP Token认证:通过一个Token来识别用户(ServiceAccount,一般提供给程序使用,但也可以提供给kubectl)
HTTP Basic认证:用户名 + 密码认证(1.19版本废弃)
Authorization 授权
基于RABC完成授权工作。RABC根据API请求属性,决定允许还是拒绝。

主体(subject)
User:用户
Group:用户组
ServiceAccount:服务账号
角色
Role:授权特定命名空间的访问权限
ClusterRole:授权所有命名空间的(也就是整个集群)访问权限
角色绑定
RoleBinding:将角色绑定到主体
ClusterRoleBinding:将集群角色绑定到主体
上图描述了这几个概念之间的关系。
Admission Control 准入控制
Admission Control实际上是一个准入控制器插件列表,发送到 API Server的请求都要经过这个列表中每个准入控制插件的检查,检查不通过则拒绝请求。
启用一个准入控制器:
关闭一个准入控制器:
查看默认启用:
示例:配置一个新的kubectl集群客户端
大致步骤:
用k8s CA(根证书)签发客户端证书
生成kubeconfig配置文件
创建RABC权限策略
指定kubeconfig文件测试权限
证书链的意思是有一个证书机构A,A生成证书B,B也可以生成证书C,那么A是根证书。操作系统预先安装的一些根证书,都是国际上很有权威的证书机构,比如 verisign 、 ENTRUST 这些公司。
这里k8s集群的根证书位于
/etc/kubernetes/pki/ca.crt,可以根据根证书下发子证书。
ca.cer
中间证书和根证书
nginx.cn.cer
你申请的ssl证书
fullchain.cer
包括了 ca.cer 和 nginx.cn.cer 的全链证书
nginx.cn.key
证书的私钥
创建脚本cert.sh,用于生成证书:
执行脚本将会生成:
再创建脚本kubeconfig.sh,使用此脚本创建kubeconfig:
执行完毕后将会生成yangsx.kubeconfig配置文件,然后将文件下发给某个用户,配置给kubectl即可使用。
在未给yangsx这个用户授权之前,做任何操作都无法通过API Server鉴权的:
我们需要通过创建rbac资源,给指定的用户赋予权限,创建rbac.yaml:
使用kube-admin用户创建上述资源清单中的资源:
这样就给用户yangsx分配了权限:
可以查看role、rolebinding的创建情况:
示例:为一个ServiceAccount分配一个只能创建deployment、daemonset、statefulset的权限
ServiceAccount一般提供给程序使用,但也可以给kubectl使用。
实现方式一,通过命令创建:
实现方式二,通过yaml创建:
网络策略
默认情况下,Kubernetes 集群网络没任何网络限制,Pod 可以与任何其他Pod 通信,在某些场景下就需要进行网络控制,减少网络攻击面,提高安全性,这就会用到网络策略。网络策略(Network Policy):是一个K8s资源,用于限制Pod出入流量,提供Pod级别和Namespace级别网络访问控制。
网络策略的应用场景(偏重多租户下):
应用程序间的访问控制,例如项目A不能访问项目B的Pod
开发环境命名空间不能访问测试环境命名空间Pod
当Pod暴露到外部时,需要做Pod白名单
网络策略的工作流程:

创建Network Policy资源
Policy Controller监控网路策略,同步并通知节点上的程序
节点上DaemonSet运行的程序从etcd获取Policy,调用本地Iptables规则
案例:拒绝其他命名空间Pod访问
需求:test命名空间下所有pod可以互相访问,也可以访问其他命名空间Pod,但其他命名空间不能访问test命名空间Pod。
测试:
案例:同一个命名空间下应用之间限制访问
需求:将test命名空间携带run=web标签的Pod隔离,只允许携带run=client1标签的Pod访问80端口。
测试:
案例:只允许指定命名空间中的应用访问
需求:只允许dev命名空间中的Pod访问test命名空间中的pod 80端口
测试:
最后更新于
这有帮助吗?