k8s简介
编排工具:
系统层面
ansible、saltstack
docker容器
docker compose + docker swarm + docker machine
docker compose:实现单机容器编排
docker swarm:实现多主机整合成为一个
docker machine:初始化新主机
mesos + marathon
mesos IDC的操作系统,Apache研发的资源分配工具
marathon 面向容器编排的框架
kubernetes
补充:
开发模式:
瀑布式开发→迭代开发→敏捷开发→DevOps
应用程序的架构:
单体架构→分层架构→微服务
DevOps:
需求→开发→测试→交付→部署
应用模式的开发,把开发与运维整合起来,打破了两者直接的壁垒
CI:持续集成:开发完合并代码到代码仓库然后自动构建部署测试,有问题打回给开发,无问题自动交付给运维方
CD:持续交付:测试完之后自动打包好最终产品,并存放到可以被运维或客户拿到的地方
CD:持续部署:交付完后自动拖出开发包并自动部署,运行时出现的bug自动反馈给开发
常见部署方案:https://blog.csdn.net/hu1010037197/article/details/112670961
早期交付与部署环节因为各种不同系统不同版本的环境因素使其极其的困难,而容器的实现可以使其得以非常容易实现,可以真正的一次编写多次部署
微服务:
把每一个应用都拆解成一个微小的服务,只做一个功能,例如把一个单体应用程序拆解为数百个微服务,让其彼此间进行协作
缺点:分发部署以及微服务互相之间的调用关系变得极其复杂,并且数以百计微服务难免其中的某些微服务会出现很问题,而单靠人工梳理和解决并不现实,容器与编排工具可以完美解决这些问题
正是容器和编排工具的出现使得微服务和DevOps得以容易落地
kubernetes
特性:
自动装箱
自我修复
水平扩展
服务发现和负载均衡
自动发布和回滚
密钥和配置管理
存储编排
批量处理执行
K8S组成与架构
组成:
整个kubernetes由master、node、附件组成
四个核心附件:
dns
Heapster/Metrics Server:用于收集和聚合集群和容器级别的资源使用情况和度量数据,以供监控和自动伸缩等用途。
Kubernetes Dashboard:提供了一个基于 Web 的用户界面,用于可视化管理和监控 Kubernetes 集群。
Ingress Controller:用于将外部网络流量路由到集群内部的服务。常见的 Ingress Controller 包括 Nginx Ingress Controller 和 Traefik。
架构:
kubernetes是一个有中心节点架构的集群系统master/node,一般会有一个或一组(三个master)节点作为主节点来做高可用,各node节点是用来贡献计算能力、存储能等相关资源(运行容器)的节点
master三个核心组件(运行为三个守护进程):
API Server:负责对外提供服务解析请求,并且需要存储整个集群中的个对象的状态信息,向客户端提供服务时使用https协议需要CA与证书
scheduler(调度器):负责观测每个node之上的资源,并根据用户请求要创建容器所需要的资源量找到符合条件的node,然后根据调度算法中的最优算法选择最优node
控制器管理器:负责监控并确保每一个控制器的健康,并且在多个master之上做控制器管理器的冗余
etcd共享存储:由于API Server需要存储整个集群中的对象的状态信息,存储量较大所以就需要etcd来实现;etcd是一个键值存储的数据库系统,而考虑到etcd的重要性,一般需要三个节点做高可用,默认是通过https进行通信,并且通过不同的两个接口分负责内外通信,其中内部通信需要一个点对点通信证书;向客户端提供服务是通过另一套证书实现
node:理论上任何有计算能力可以装容器的机器都能作为node;核心组件:
kubelet(集群代理):与master通信,接收master和调度过来的各种任务并试图让容器引擎(最流行的容器引擎为doker)来执行
docker:容器引擎,运行pod中的容器
kube-proxy:每当pod增删和service需要改变规则需要依赖kube-proxy,每当pod增删时会有一个通知,通知到所有相关联的组件,service收到通知需要kube-proxy修改所有集群内所有节点的iptables
pod控制器:又称之为工作负载(workload),负责监控所管理的每一个容器是否是健康的应用节点数是否符合,确保pod资源符合预期的状态,如果出现异常则向API server发送请求,由kubernetes重新创建启动容器、还可以滚动更新或回滚
控制器有多种类型:
ReplicaSet: 代用户创建指定数量的pod副本数量,确保pod副本数量符合预期状态,并且支持滚动式自动扩容和缩容功能。
ReplicaSet主要三个组件组成:
(1)用户期望的pod副本数量
(2)标签选择器,判断哪个pod归自己管理
(3)当现存的pod数量不足,会根据pod资源模板进行新建
帮助用户管理无状态的pod资源,精确反应用户定义的目标数量,但是RelicaSet不是直接使用的控制器,而是使用Deployment
Deployment:工作在ReplicaSet之上,用于管理无状态应用,目前来说最好的控制器。支持滚动更新和回滚功能;还提供声明式配置,可以随时重新进行声明,随时改变我们在API Server上定义的目标期望状态,只要那些资源支持动态运行时修改。
#更新和回滚功能:Deployment一般会控制两或多个个ReplicaSet,平时只激活运行一个,当更新时逐一停止激活状态的ReplicaSet上的容器并在另一个ReplicaSet上创建直到完成,回滚是相反的动作;可以控制更新方式和节奏:例如定义一次更新几个节点或者先临时加几个pod正常后在删除旧pod使能正常提供服务的pod个数保持一致等等
HPA:二级控制器,负责监控资源,自动伸缩
DaemonSet:用于确保集群中的每一个节点或符合标签选择器的节点上只运行特定的pod副本,通常用于实现系统级后台任务。比如ELK服务日志收集分析工具。只要新增节点就会自动添加此pod副本
Deployment和DaemonSet所部署的服务特性:
服务是无状态的
服务必须是守护进程
StatefulSet:管理有状态应用
Job:只要完成就立即退出,不需要重启或重建;如果任务没完成异常退出才会重建Pod。适合一次性的任务
Cronjob:周期性任务控制,不需要持续后台运行
Statefulset:管理有状态应用,每一个Pod副本都是被单独管理
pod:kubernetes中最小单元,是在容器上又封装一层模拟虚拟机,一个pod里可以有多个容器(一般为一个),其中这多个容器可以共享一个网络名称空间、共享存储卷
两类:
自主式pod:如果node故障,其中的pod也就消失了
pod控制器管理的pod
label(标签):可以用打标签的方式给资源分组,所有对象都可打标签(pod是最重要的一类对象)格式:key=value
selector(标签选择器):根据标签过滤符合条件的资源对象的机制
service[k8s的附加组件]:是一个四层调度器。实际是一个宿主机上的iptables dnat规则和宿主机的一个虚拟的地址负责反向代理后端容器服务,所以如果你创建一个service,service是会反应到整个集群的每一个节点之上的。他是可以被解析的地址也是固定的,但是并不附加在网卡之上;由于后端容器频繁的变更,不断伸缩、创建删除,他们的地址与容器主机名称是不固定的,所以后端容器每次变动,service通过标签选择器获取他们的标签区别并记录他们并同时记录对应的地址与容器名字,因此当服务请求进来后先到service,通过service找到对应的服务并且转发到其中的容器中,不过安装完K8S之后需要在集群中的dns中配置他的域名解析,如果手动修改service地址或名字,dns中的解析记录也会自动修改,如果后端一个服务有多个节点,service支持ipvs,会把规则写入ipvs中进行负载均衡
service规则默认用的是ipvs,如果ipvs
service
dns附件:service想要被发现需要dns服务,dns也是运行在pod之中
监控:监控相关资源利用、访问量、是否故障
示例:在K8S上创建一个NMT
客户→LBaas→node接口→nginx_service→nginx容器→tomcat_service→tomcat→mysql_service→mysql
如果使用的是阿里云,则在云上调用底层LBaas,因为node上可能没有网卡,所以用来负责把请求来的流量调度到node上的对外的接口上,然后通过控制器创建两个pod装载nginx,nginx之上创建一个servece负责接收node接口的流量,并把流量转发给nginx;继续通过控制器创建三个pod装载tomcat,之上在创建一个service,同理再创建两个mysql之上创建一个service
K8S网络与通信
K8S总共有三种网络:
节点网络
集群网络(service网络)
pod网络
通信:
同一个pod之间通信:
是通过lo通信
不同pod之间通信:
是通过“叠加网络”进行通信,把需要传递到pod的IP和端口报文外部再封装一个IP用于不同节点之间的传递,当节点接收到叠加网络报文时进行拆封,然后再根据内部的IP和端口找到对应的服务,当然pod是动态的随时会进行增删就需要通过service来找到具体目标pod
pod与service之间通信:因为service地址实际上只是宿主机上iptables规则地址,创建service后会反应到整个集群的所有节点和宿主机iptables之上,当pod需要与service通信时会把网关指向docker0乔的地址,另外宿主机也可以把docker0乔当作自己的一个网卡,所以宿主机之上pod可以直接与service通信,通过iptables规则表检查指向发送请求
CNI插件体系:容器网络接口,负责接入外部插件网络解决方案,可以运行在pod之上作为集群的一个附加使用,需要共享宿主机的网络名称空间。目的:
负责给pod、service提供ip地址
负责网络策略功能:实现pod隔离,让不同的pod之间根据要求通过添加规则实现互通或隔离,防止托管在pod中的恶意服务截取或攻击其他pod中服务
常见插件:
flannel(叠加网络):只支持网络配置
calico(三层隧道网络):支持网络配置和网络策略
canel:把前两者结合,用flannel配置网络,用calico配置网络策略
...
k8s名称空间:把一个集群根据每一类pod切割成多个名称空间,而切割的这个名称空间边界不是网络边界而是管理边界,例如创建一个项目,项目下可以有多个pod,可以批量管理这个项目中的pod,项目完成可以批量删除整个项目
CA:K8S一般是需要5套CA
etcd与etcd之间
etcd与API Server之间
API Server与用户之间
API Server与kubetel之间
API Server与kube-proxy之间
部署
常用部署方式:
传统手动部署:所有组件运行为系统的守护进行,很繁琐包括做5个CA
kubespray:kubespray是一个基于Ansible的部署方案,根据已经写好的ansible的剧本进行执行,也是把所有组件运行为系统的守护进行
kubeadm(官方提供安装工具):容器化部署,更像是一套完整的脚本封装,比较快速简单
实例:kubeadm安装
至少两核cpu
部署网络环境:
节点网络:172.20.0.0
service网络:10.96.0.0/12
pod网络:10.244.0.0/16 (flannel插件默认)
master+etcd:172.20.0.70
node1:172.20.0.66
node2:172.20.0.67
安装步骤:
(本人用的是:
centos7.9
docker-ce-20.10.8、docker-ce-cli-20.10.8
kubelet-1.20.9、kubeadm-1.20.9、kubectl-1.20.9)
1.所有主机安装docker+kubelet+kubeadm
2.初始化master:kubeadm init(检查前置条件、并会把master三个组件和etcd运行为pod、CA等)
3.初始化node:kubeadm join (检查前置条件、在pod中运行一个kube-proxy、dns、认证等)
文档:
官方文档:https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/
安装参考文档:https://blog.csdn.net/qq_42475194/article/details/126356651
注意:docker跟k8s需要特定版本,版本差距较大会出现不兼容问题。以下是一些常见的 k8s 和 Docker 版本对应关系:
k8s 1.22.x 支持 Docker 20.10.x
k8s 1.21.x 支持 Docker 20.10.x
k8s 1.20.x 支持 Docker 19.03.x
k8s 1.19.x 支持 Docker 19.03.x
k8s 1.18.x 支持 Docker 19.03.x
程序相关目录
rpm -ql kubelet
/etc/kubernetes/manifests ----清单目录
/etc/sysconfig/kubelet ----配置文件
/etc/systemd/system/kubelet.service
/usr/bin/kubelet ----主程序
kubeadm初始化准备(master)
kubeadm init
Flags:
--apiserver-advertise-address string 设置apiserver监听地址(默认所有)
--apiserver-bind-port int32 设置apiserver监听端口(default 6443)
--cert-dir string 设置证书路径(default "/etc/kubernetes/pki")
--config string 设置配置文件
--ignore-preflight-errors strings 预检查时忽略掉出现的错误( Example: 'IsPrivilegedUser,Swap' )
--kubernetes-version string 设置使用的kubernetes版本(default "stable-1")
--pod-network-cidr string pod网络(flannel插件默认网络为 10.244.0.0/16 )
--service-cidr string service网络(default "10.96.0.0/12")
复制kubectl配置文件:需要有sudo权限的普通用户
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
注释:admin.conf文件:kubeadm帮我们自动初始化好的一个被kubectl拿来做配置文件指定连接至K8s的API server并完成认证的配置文件
kubect命令
kubectl:是API Server的客户端程序,这个客户端程序是通过连接master节点上的API server这一个对应的应用程序,这也是整个K8S集群上唯一一个管理入口,kubectl就是这个管理入口的客户端管理工具
面向对象:kubectl仿照于面向对象的开发语言,所有k8s中的资源都可以看做对象类,类中有方法和属性。每当根据给定的参数创建pod时就相当于给类中的方法赋值,相当于实例化对象。
相关命令:
kubectl
version #获取版本信息
cluster-info #获取集群信息
api-versions #查看当前可支持api的版本
-h #获取帮助
describe #获取对象的详细描述信息包括所有可以作为对象的目标如:pod、service、node、deployment等
object NodeName
示例:kubectl describe pod nginx-deploy
get 获取信息
cs #组件状态信息
nodes #节点信息
deployment #查看此控制器已创建的pod
ns #获取名称空间
pods #获取当前正在运行的pod信息
deployment #查看控制器信息
(需要追加到对象之后)
-w #持续监控
-n #指定名称空间
-o
wide #显示扩展信息
yaml #以yaml格式输出信息
--show-labels #(需要追加到对象之后)显示所有标签
-L #输出所有,但是只显示指定的标签的标签值,未指定的不显示
示例:
kubectl get pods -L app,run
-l #标签过滤,只输出指定标签的资源
格式(可指定多个):
等值关系(只过滤KEY/等于/不等于):
KEY_1,...KEY_N/KEY_1=VAL_1,.../KEY_1!=VAL_1,...
集合关系:
KEY in (VAL_1,...VAL_N) 键的值只要是这集合中的一个就匹配
KEY notin (VAL_1,...VAL_N)键的值不是是这集合中的一个就匹配
KEY 有这个键的标签就匹配
!KEY 无这个键的标签就匹配
示例:
kubectl get pods -l app,release --show-labels
kubectl get pods -l release=conary,app=myapp --show-labels
kubectl get pods -l "release in (canary,beta)" #过滤 release这个键的值包含canary,beta的pod
kubectl get pods -l "release notin (canary,beta)" #过滤 release这个键的值不包含canary,beta的pod
services/svc
-n #指定名称空间
# 指定名称空间为 kube-system 时可查看到集群dns服务的代理service IP,从而可以同过此IP解析集群中的其他service标签
run NAME #(控制器名称) 创建并启动
--image='': #指定镜像
--port='': #暴漏端口
--dry-run=true #模拟执行,非真正执行
-- <cmd> <arg1> ... <argN> #指定运行命令和参数
--restart=Never #pod异常后不自动创建
-i
-t
Examples:
kubectl run nginx-deploy --image=nginx:1.14-alpine --port=80 --dry-run=true
测试:在集群中所有node节点都可以使用curl访问此nginx,但只能集群内部访问,想要外部访问需要特殊类型的service
注:每个node会自动生成一个桥和接口,例如: cni0:inet 10.244.1.1 netmask 255.255.255.0 broadcast 10.244.1.255。此node上所有的pod都会在10.244.1.0 网段
kubectl run client --image=busybox -it --restart=Never
查看命令
kubectl get pods -o wide
create #用于创建 Kubernetes 对象。如果对应的资源已经存在,则会返回错误,此时需要先删除原有的资源对象,然后再执行创建操作。如果资源对象不存在,则会自动创建对应的资源对象。适用于初始化资源对象的场景
#Usage:
kubectl create -f FILENAME [options]
#FILENAME:资源配置yaml文件
#[options]:
namespace NAME
deployment NAME
--image=[]
--dry-run='none/server/client'
示例:
kubectl create -f pod-demol.yaml
kubectl create deployment nginx-deploy --image=nginx:1.14-alpine
apply (-f FILENAME | -k DIRECTORY) [options] #用于声明式创建或更新一个 Kubernetes 对象并且可以声明多次。如果该资源对象已经存在,则会首先尝试更新对应的字段值和配置,如果不存在则会自动创建资源对象。适合更新和修改已有的资源对象,因为它会对比新的 YAML 配置文件和已有的资源对象配置,只更新需要更新的部分,而不会覆盖已有的全部配置。
示例:
kubectl create -f pod-demol.yaml
patch
Usage:
kubectl patch (-f FILENAME | TYPE NAME) -p PATCH [options]
options:
-p #打补丁
示例:
kubectl patch pod valid-pod -p '{"spec":{"containers":[{"name":"kubernetes-serve-hostname","image":"new image"}]}}'
kubectl patch deployment myapp-deploy -p '{"spec":{"replicas":5}}'
delete ([-f FILENAME] | [-k DIRECTORY] | TYPE [(NAME | -l label | --all)]) [options]
示例:kubectl delete -f pod-demol.yaml
expose #暴漏服务端口,相当于创建一个service然后把pod服务中的端口映射固定在service上,创建完成后默认为ClusterIP类型所以集群外部依然不能访问,集群内部pod或node可以通过service进行访问服务。首先需要集群中dns找到service,然后service会生成一个iptables或ipvs规则把访问此service指定端口的请求都调度至它用标签选择器关联到的各pod后端(可以用 kubectl describe svc NAME 查看关联了哪些标签,可以用kubectl get pods --show-labels 显示pod有哪些标签 )
#解析的步骤:
kubectl get svc/pod -n kube-system 查到dns的service代理IP为10.96.0.10;
在pod中启动两个服务nginx-deploy并暴漏端口80映射为80,设置其service名字为nginx。因为集群中域名的默认后缀为default.svc.cluster.local,所以nginx域名为nginx.default.svc.cluster.local;
解析测试:host -t A nginx.default.svc.cluster.local 10.96.0.10 解析地址为nginx地址
expose
Usage:
kubectl expose (-f FILENAME | TYPE NAME) [--port=port] [--protocol=TCP|UDP|SCTP] [--target-port=number-or-name] [--name=name] [--external-ip=external-ip-of-service] [--type=type] [options]
#注释:
(-f FILENAME | TYPE NAME):指定需要与创建的service建立连接的pod的控制器的名字
[--port=port]:service的端口
[--target-port=number-or-name]: pod中的端口
[--name=name]:service名称
[--type=type] : Type for this service: ClusterIP, NodePort, LoadBalancer, or ExternalName. Default is 'ClusterIPservice'.
#service的4中主要类型合作用:
1.ClusterIP 是默认的 Service 类型。它将创建一个虚拟的 IP 地址,用于连接客户端和 Pod。这个 IP 地址只能在集群内部使用,无法从集群外访问。这种类型通常用于后端服务,如数据库或缓存服务。
访问路径:集群内部client → ClusterIP:ServicePort → PodIP:containerPort
2.NodePort 允许从集群外部访问 Service,通过将提供的端口号映射到 Pod 的 IP 地址上,同时也会将该端口暴露到集群节点的 IP 地址上。这种类型通常用于开发和测试,不建议在生产环境中使用。
访问路径:集群外部client → [负载均衡器]→NodeIP:NodePort→ClusterIP:ServicePort → PodIP:containerPort
3.LoadBalancer 可以在云环境中借助底层lbaas自动创建外部负载均衡器,并将客户端请求路由到 Pod。该类型的 Service 通常用于公共云或私有云环境中,可以将流量平衡到多个集群节点上,从而提高服务的可靠性和可用性。
访问路径:集群外部client →负载均衡器(Lbaas)→ NodeIP:NodePort→ClusterIP:ServicePort → PodIP:containerPort
4.ExternalName Service 允许 Service 对外暴露一个外部名称,这个名称可以被解析为外部服务的 DNS 名称。该类型的 Service 不会在集群中创建任何负载均衡器或 IP,而是将请求直接转发到指定的外部服务。一般是集群内pod作为客户端需要请求集群外服务时使用。
5.无头service,定义ClusterIP时设置为None。此时解析service域名时直接解析到后端Pod服务
Examples:
kubectl expose deployment nginx-deploy --name=nginx --port=80 --target-port=80 --protocol=TCP
容器中访问测试:
wget -O - -q nginx
wget -O - -q myapp/hostname.html #可查看调度到哪个pod(需要使用此镜像:--image=ikubernetes/myapp:v1)
edit 修改对象信息,包括所有可以作为对象的目标如:pod、service、node、deployment等
object NAME 注:可以直接改service类型,例如把ClusterIP改为 NodePort service的内部集群端口就会自动随机映射为外部端口,可以get查看端口,因此就可以通过外网使用集群中任何节点网络的IP:PORT 访问到此pod中的服务
示例:
kubectl edit svc nginx
scale 伸缩控制器规模
Usage:
kubectl scale [--resource-version=version] [--current-replicas=count] --replicas=COUNT (-f FILENAME | TYPE NAME)
注释:
[--resource-version=version] [--current-replicas=count]:过滤条件
Examples:
kubectl scale --replicas=5 deployment myapp
set
image 更新升级镜像
Usage:
kubectl set image (-f FILENAME | TYPE NAME) CONTAINER_NAME_1=CONTAINER_IMAGE_1 ... CONTAINER_NAME_N=CONTAINER_IMAGE_N
#CONTAINER_NAME_1=CONTAINER_IMAGE_1:指明pod中的哪个容器和镜像,可以指定多个,可以用kubectl describe 查看pod内容器的名称,在Containers:下
Examples:
kubectl set image deployment myapp myapp=ikubernetes/myapp:v2
rollout 管理一个或多个资源的上线
Usage:
kubectl rollout SUBCOMMAND [options]
Commands:
status Show the status of the rollout
Examples:
kubectl rollout status deployment myapp
undo 回滚,默认回滚到上一个版本
Usage:
kubectl rollout undo (TYPE NAME | TYPE/NAME) [flags] [options]
history #查看滚动历史
示例:
kubectl rollout history deployment myapp-deploy
pause #暂停
resume #启动,与先暂停对应
logs PodName
-c containername (如果pod内有多个容器需要指定容器名称)
示例:
kubectl logs myapp-5d587c4d45-5t55g
kubectl logs pod-demol -c myapp
labes 配置标签
#标签相当于附加到对象上的键值对
#一个资源对象可以有多个标签,一个标签也可以被添加至多个资源对象之上;
#标签可以在资源创建时指定,也可以在创建后通过命令管理
#键值对有大小和字符规范限制
Usage:
kubectl label [--overwrite] (-f FILENAME | TYPE NAME) KEY_1=VAL_1 ... KEY_N=VAL_N [--resource-version=version]
Examples:
kubectl label pods foo unhealthy=true 添加标签
kubectl label pods foo unhealthy=yes --overwrite 修改覆盖标签
许多类型的资源都要基于标签选择器关联其他资源例如控制器、service。此时通常使用另外两个字段进行嵌套定义其使用的标签选择器:
matchLabels 直接定义键值(service只支持这一种)
matchExpressions 基于给定的表达式来定义使用标签选择器,格式{key:"KEY",operator:"OPERATOR",values:[VAL1,VAL2....]}
#operator为判断条件,操作符如:In, NotIn,Exists, NotExists
示例:
kubectl explain pod.spec.nodeSelector:
nodeSelector <map[string]string> #节点标签选择器,可以选择让pod运行在哪一类节点上
exec #容器外跳过边界执行容器内命令
Usage:
kubectl exec (POD | TYPE/NAME) [-c CONTAINER] [flags] -- COMMAND [args...] [options]
#[-c CONTAINER]:pod中有多个容器需指定容器名
示例:
kubectl exec myapp-5d587c4d45-h4zxn date
kubectl exec myapp-5d587c4d45-h4zxn -it -- /bin/sh
kubectl exec pod-demol -c myapp -it -- /bin/sh
explain <type>.<fieldName>[.<fieldName>] #查看K8S内建的格式说明
示例:
kubectl explain pods
kubectl explain rs
kubectl explain pods.spec.containers
资源配置清单(一个yaml文件可以定义多个资源,需用—分隔开)
常用资源:对象分类:
工作负载型资源对象:运行应用程序对外提供服务
pod、各种pod控制器、
服务发现及负载均衡
service、ingress
配置与存储
volume、CSI、ConfigeMap(配置中心)、Secret(保存敏感数据)、 DownwordAPI(外部环境信息输出给容器)
集群级资源
namespace、node、role、clusterrole、rolebinding、clusterrolebingding
元数据
HPA、podtemplate、limitrange(资源限制)
资源配置清单可分为以下五部分(配置清单中的一级字段):
(apiserver仅接收json格式的资源定义:执行命令时会自动把你给的内容转换成json格式,而后再提交;查看yaml格式资源配置清单 实例: kubectl get pod myapp-848 -o yaml )
1. apiVersion: 此对象属于K8S的哪一个API版本和群组,一般格式为 group/version 如果省略group则默认为核心组。
例:控制器属于app组;pod属于核心组
查看命令 :kubectl api-versions
2. kind: 资源类别,用于初始化实例化成一个资源对象使用的
3. metadata: 元数据
提供的信息有:name、namespace、labels、annotations(资源注解)
selfLink:每个资源引用方式
固定格式api/GROUP/VERSION/namespaces/NAMESPACE/TYPE/NAME
示例:selfLink: /api/v1/namespaces/default/pods/myapp-848b5b879b-8fhgq
4. spec: 用户期望的目标状态/规格,定义要创建的资源对象需要有怎样的特性或满足怎样的规范(例如它的容器应该有几个;容器应该用哪个镜像创建;容忍哪些污点)
5. status: (只读)显示当前资源的当前的状态,如果当前状态与目标状态不一致,K8S就是为了目标状态定义完后当前状态无限向目标状态靠近或转移,以此来满足用户需要,注意本字段由K8S集群维护,用户不能定义此字段
资源配置清单中自主式Pod的配置([]表示列表):(可以用kubectl explain pod 查看描述文档)
kubectl explain pods:
metadata <Object>
annotations <map[string]string>#资源注解,与label不同的地方在于,它不能用于挑选资源对象,仅用于为对象提供“元数据”,并且字符没有大小等规范限制
spec <Object>
restartPolicy <string> #重启策略
Always #Pod中的容器挂了就重启无论是否是正常终止,默认为Always。
#重启逻辑:频繁重启会给服务器带来压力所以第一次会立即重启,每多一次重启就会增加等待时间,直到每5分钟重启一次
OnFailure #只有状态错误时就重启
Never #从不重启
nodeSelector <map[string]string> #节点标签选择器,可以选择让pod运行在哪一类节点上
nodeName <string> #指定pod运行的节点
hostNetwork <boolean> #设置pod直接使用主机的网络名称空间,此时可以使用主机ip:port直接访问pod,不需要暴露端口。常用在DaemonSet控制器中
hostIPC <boolean> #共享主机IP
hostPID <boolean> #共享主机PID
containers <[]Object>
- name <string> -required-
image <string>
imagePullPolicy <string> #镜像获取途径的策略
# <string>:
Always:远程仓库拉取
Never:要使用本地镜像,如果没有就等待,需要手动拉取镜像到本地
IfNotPresent:如果本地有镜像优先使用
默认用法:
如果镜像标签是latest那么默认值就是Always
除特定标签latest以外,其他标签默认镜像获取途径的策略为IfNotPresent
Cannot be updated:如果每个字段写上这段信息表示对象一旦被创建以后改变这个字段值是不被允许的
ports <[]Object> #注释信息:标注要暴露的端口和端口信息,标注以后可以尝试引用这个名称
- name <string>
containerPort <integer> -required-
protocol <string>
command <[]string>
#自定义容器要运行的程序相当于docker配置中的Entrypoint,但是所给定的代码不是运行在shell中,需要手动指定
如果没有提供command,而docker镜像在制作时有ENTRYPOINT就会运行镜像中的ENTRYPOINT
而如果指定了command,无论指没指定参数,docker镜像中的ENTRYPOINT和CMD都会被忽略
示例:
command:
- "/bin/sh"
- "-c"
- "sleep 3600"h"
args <[]string>
#向Entrypoint传递的参数相当于docker配置中的CMD;如果指定args,则用args作为参数;如果没指定args且没指定command则用镜像中的CMD作为参数
#$(VAR_NAME):在args中引用变量
#$$$(VAR_NAME):进行逃逸,不使用引用的变量替换
env <[]Object> #设置环境变量
- name <string> -required-
value <string> #如果引用别的变量格式:$(VAR_NAME)
lifecycle <Object> #定义终止前和启动后钩子,用来定义启动后与终止前需要立即执行的操作
postStart <Object> #启动后钩子
exec <Object>
httpGet <Object>
tcpSocket <Object>
preStop <Object> #终止前钩子
exec <Object>
httpGet <Object>
tcpSocket <Object>
readinessProbe <Object> #就绪状态检测,与livenessProbe用法相同
livenessProbe <Object> #存活状态检测
exec <Object> #探测行为,执行自定义命令
command <[]string> #如果返回值是成功说明是存活的,如果返回状态码表示存活探测失败
httpGet <Object> #探测行为,向指定的TCP套接字发请求,通过http返回状态码判断
host <string> #defaults to the pod IP.
path <string>
port <string> -required- #可以引用端口名称
tcpSocket <Object> #探测行为,向对指定的http服务发请求
host <string> #defaults to the pod IP.
port <string> -required-
failureThreshold <integer> #探测几次都失败才认为失败,默认3次
periodSeconds <integer> #每一次探测间隔时间默认10秒
timeoutSeconds <integer> #超时时间,默认1秒
initialDelaySeconds <integer> #第一次探测的时间,默认容器启动完就开始探测
示例:(自主式Pod,不受控制器管理)
vim pod-demal.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-demol
namespace: default
labels:
app: myapp1
tier: frontend
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v1
ports:
-name: http
containerPort: 80
readinessProbe:
httpGet:
port: http
path: /index.html
initialDelaySeconds: 1
periodSeconds: 3
livenessProbe:
httpGet:
port: http
path: /index.html
initialDelaySeconds: 1
periodSeconds: 3
- name: busybox
image: busybox:latest
command:
- "/bin/sh"
- "-c"
- "sleep 3600"
- name: busybox-liveness-exec-container
image: busybox:latest
imagePullPolicy: IfNotPresent
command: ["/bin/sh","-c","touch /tmp/healthy; sleep 60; rm -rf /tmp/healthy; sleep 3600"]
livenessProbe:
exec:
command: ["test","-e","/tmp/healthy"]
initialDelaySeconds: 1
periodSeconds: 3
根据创建的配置清单文件创建容器:
kubectl create -f pod-demol.yaml
删除:
kubectl deleted -f pod-demol.yaml
kubectl deleted pods pod-demol
Pod的生命周期:
从创建到结束的所有状态:Pending, Running, Failed, Succeeded, Unknown
#Pending:挂起,请求创建pod时条件不能满足调度没完成。例如已经创建但没找到符合指定tag的节点
#Unknown:未知状态,例如节点上的kubelet故障,API Server无法与之通信所以会出现未知状态
Pod生命周期中的重要行为:
主容器启动前:始化容器,主进程启动前先运行辅助容器init进行初始化容器,甚至和可以运行多个并串行执行,运行完之后退出启动主进程
主容器启动时:执行启动后钩子
主进程运行时:
liveness:存活状态检测,判定主容器是否处于运行状态(runing),此时不一定能对外提供服务
readiness:就绪状态检测,判定容器中的主进程是否已经准备就绪并可以对外提供服务
(无论哪种探测都可以支持三种探测行为:执行自定义命令;向指定的TCP套接字发请求;向对指定的http服务发请求。并根据响应码判断其成功还是失败。即三种探针:ExecAction、TCPSocketAction、HTTPGetAction)
主容器结束后:执行结束后钩子
创建Pod过程:
用户创建Pod后把请求提交给API Server
API Server会把创建请求的目标状态保存到etcd中
API Server会请求调度器进行调度,并把调度的结果、调度的那些节点资源保存到etcd中
节点上的kubelet通过API Server当中的状态变化得知任务通知,并拿到用户此前提交的创建清单
kubelet根据清单在当前节点上创建并启动pod
kubelet把当前pod状态发回给API Server
删除Pod过程:
防止删除Pod时数据丢失会向Pod内的每一个容器发送终止信号,让Pod中的容器正常进行终止,这个终止会给一个默认的宽限期默认30秒。如果过了宽限期还没终止就会重新发送kill信号
资源配置清单中Pod控制器配置
ReplicaSet控制器
kubectl explain rs/ReplicaSet:
kind <string>
metadata <Object>
spec <Object>
replicas <integer> #副本数
selector <Object> -required- #标签选择器
template <Object> #模板,此模板嵌套的就是Pod的配置清单
metadata <Object> #Pod的metadata
spec <Object> #Pod的spec
matchExpressions <[]Object>
matchLabels <map[string]string>
示例:(可以通过kubectl edit rs myapp 直接修改运行中控制器的yaml配置清单内容实现扩缩容和更新镜像等,但是更新镜像需要手动删除容器自动创建后才会是最新镜像)
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: myapp
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: myapp
release: canary
template:
metadata:
name: myapp-pod
labels:
app: myapp
release: canary
environment: qa
spec:
containers:
- name: myapp-container
image: ikubernetes/myapp:v1
ports:
- name: http
containerPort: 80
deployment控制器(大部分配置与ReplicaSet相似)
kubectl explain deploy/deployment:
spec <Object>
revisionHistoryLimit <integer> #保存多少个历史版本,默认是10个
paused <boolean> #开始更新部署时先暂停
strategy <Object> #更新策略
type <string>
#<string>:支持三类更新
Recreate:重建试更新,删一个创建一个
RollingUpdate:滚动更新,为默认更新方法,更新策略需要配置在上级配置的RollingUpdate中
rollingUpdate <Object> #定义滚动更新策略,需要type配置为RollingUpdate才会生效
maxSurge <string> #设置可以超出期望的副本数几个,<string>可以是数字也可以是百分比,默认25%
maxUnavailable <string> #设置最多有几个不可用,<string>可以是数字也可以是百分比,默认25%
示例:
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-deploy
namespace: default
spec:
replicas: 3
selector:
matchLabels:
app: myapp
release: canary
template:
metadata:
labels:
app: myapp
release: canary
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v2
ports:
- name: http
containerPort: 80
DaemonSet控制器(配置文件除了没有replicas,其他大部分与deployment控制器类似,也支持滚动更新策略)
kubectl explain ds/DaemonSet:
spec <Object>
updateStrategy <Object>
rollingUpdate <Object>
maxUnavailable <string> #最多几个不可用,因为每个节点只能部署一个,没有maxSurge选项
type <string> #Can be "RollingUpdate" or "OnDelete"(删除时更新). Default is RollingUpdate.
示例:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: filebeat-ds
namespace: default
spec:
selector:
matchLabels:
app: filebeat
release: stable
template:
metadata:
labels:
app: filebeat
release: stable
spec:
containers:
- name: filebeat
image: ikubernetes/filebeat:5.6.5-alpine
env:
- name: REDIS_HOST
value: redis.default.svc.cluster.local
- name: REDIS_LOG_LEVEL
value: info
资源配置清单中service配置:
kubectl explain svc/service:
clusterIP <string>
#<string> :service的IP,不需要指定因为在集群中会自动分配,如果要指定要确定不要导致ip冲突;也可以设置为None,没有集群IP又称为无头sevice。通过service域名直接解析到后端Pod上
spec <Object>
ports <[]Object>
name <string>
nodePort <integer> #指定节点上的端口,一般不用指定因为只有service类型时nodePort时节点端口才有用
port <integer> -required- #指定对外提供服务的端口
targetPort <string> #容器的端口
protocol <string> #协议,默认为TCP
selector <map[string]string>
type <string>
externalName <string> #type为ExternalName Service时才会有效,解析结果应该是A记录,用的比较少
sessionAffinity <string> #会话粘性,默认情况是不做粘性的,如果设置为ClientIP则来自同一个客户端IP的请求始终调度到同一个后端Pod上去
#<string>: "ClientIP" 或 "None"
ingress Control
service是一个四层调度器因此有个缺陷,它只是工作在TCP/IP协议栈或者OS模型的第四层。因此如果用户访问的是https请求,服务用service代理时CA证书、私钥无法配置,更无法调度https的这种七层协议,这种情我们只能在每个后端服务器配置https。因为https的特点是即贵且慢所以我们需要尽量在调度器上卸载所以需要七层调度器,使在外网时使用https,内网使用http。
解决方案一:
设置一个独特的pod运行在七层用户空间正常的应用程序例如nginx,当用户试图访问某一服务时,我们不让它到达前端service而先到七层代理pod。pod与pod直接可以通过podIP同一网段直接通信完成反向代理
访问路径:集群外部client进行https访问 →负载均衡器(Lbaas)→ NodeIP:NodePort→ClusterIP:ServicePort → PodIP:containerPort(七层代理服务卸载https并把http请求直接反向代理给后端)→PodIP:containerPort(真正提供服务的容器)
弊端:多级调度导致性能低下
方案二:ingress Control
直接让七层代理pod共享节点的网络名称空间并监听宿主机地址端口。而且使用DaemonSet控制器启动此容器,并设置节点污点从而控制节点个数使这些节点只运行一个七层代理服务容器。这个代理pod在K8s上又被称为:ingress Control
访问路径:集群外部client进行https访问→四层负载均衡器→NodeIP:NodePort(Pod中七层代理服务)→PodIP:containerPort(真正提供服务的容器)
后端有多组web,每组提供不同功能的情况下:
方案一:例如nginx代理可以用不同主机名或端口设置4个虚拟主机每个主机代理一组后端
方案二:通过URL映射,每一个路径映射到一组后端服务
七层代理服务:
HAProxy:用的比较少
nginx:默认
Traefik:面向微服务的开发的,能监控自身配置文件变化并自动重载配置文件
Envoy:servicemesh网络中比较倾向的,微服务用的比较多,也能监控自身配置文件变化并自动重载配置文件
在七层代理服务器假如是nginx反代至后端时,因为后端时pod容器所以ip不固定,如何修改nginx上upsteam确认后端IP
解决方案:
在他们中间层设置一个service,但此service不做代理使用只是负责给后端资源分组
K8S上有个ingress资源(注意与ingress Control区分),他可以读取每个service上所属的组包含的后端的IP定义成upsteam server并注入到nginx配置文件中并触发nginx重载配置文件
资源配置清单中ingress配置:(创建ingress资源后,会根据配置自动注入到ingress Control中)
kubectl explain ingress:
apiVersion <string>
kind <string>
metadata <Object>
annotations <map[string]string> #声明用哪种代理
spec <Object>
backend <Object> #定义后端
serviceName <string> #定义后端service
servicePort <string> #后端service端口
rules <[]Object> #定义调度规则
host <string> #通过虚拟主机调度
http <Object>
paths <[]Object> -required- #通过url路径映射调度
tls:定义https时定义
ingress配置清单示例(https协议)
1.用openssh生成一对自谦证书
2.创建secret资源对象用来转换自签证书格式
kubectl create secret tls tomcat-ingress-secret --cert=tls.crt --key=tls.key
#tls:表示对象类型
#tomcat-ingress-secret 自定义名字
#--cert=tls.crt --key=tls.key :指明秘钥对文件
3.创建ingress
#tls为https协议,secretName为指定秘钥认证的secret,tomcat.magedu.com为后端名称虚拟主机,myapp为后端提供服务所属的service,80为后端所提供服务的端口号于service无关
安装和部署ingress-nginx Control(注意k8s不能低于1.19)
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.8.2/deploy/static/provider/cloud/deploy.yaml
#ingress资源创建后会自动注入配置可以通过交互命令查看ingress-nginx中nginx配置信息
存储卷
补充:
因为k8s是一个集群是由调度器调度所以类似于docker的单节点映射本地目录存储卷是行不通的,所以一般需要一个共享存储或者网络存储
同一个pod中的多个容器可以共享一个存储卷:因为存储卷不是属于容器而是属于pod,同一个pod中的容器底层复制的同一个基础架构镜像:pause。
存储卷种类:
非持久存储:
emptyDir:作为容器中临时空目录使用,映射为宿主机目录或者内存,容器删除此目录中的数据也会被删除
hostPath:宿主机目录做映射,pod变更重新创建时需要调度到同一个宿主机上才能实现持久存储
gitRepo:类似与emptyDir,只不过是有内容的。在创建pod时会把指定的一个git仓库内容克隆下来并挂载。如果内容发生改变并不会自动进行推送或远程同步,要实现此功能需要一个辅助容器Sidecar
持久存储:
传统网络存储:SAN(iscsi)、NAS(NFS、CIFS)
分部式存储(文件系统级别、块级别):glusterfs,rbd,cephfs
云存储:
ebs、Azure Disk
资源配置清单中pod存储卷配置:
kubectl explain pod.spec
volumes <[]Object> #在pod中定义存储卷
- name
emptyDir <Object> #emptyDir存储卷
medium <string>
sizeLimit <string>
hostPath <Object> #hostPath存储卷
path <string> -required- #指明宿主机上的路径
type <string>
#DirectoryOrCreate:挂载的宿主机上的目录如果不存在则创建
#Directory:宿主机上必须存在此目录
#FileOrCreate:挂载一个宿主机文件如果不存在则创建
#File:宿主机必须存在此文件
#Socket
#CharDevice:字符类型设备文件
#BlockDevice:块设备文件
nfs <Object> #nfs存储卷,可以实现多个pod同时挂载同一个共享存储
path <string> -required- #nfs共享路径
readOnly <boolean>
server <string> -required- #nfs服务器地址
containers
volumeMounts <[]Object> #在容器中挂载存储卷
- mountPath <string> -required-
name <string> -required-
readOnly <boolean>
ubPathExpr <string>
示例1(emptyDir存储卷):定义一个pod中两个容器,并定义pod中存储卷并分别挂载到两个容器中,第二个容器输入内容到html并作为第一个nginx容器的主页显示。(可以通过curl 这个容器进行验证)
示例2(hostPath存储卷)
示例3(NFS共享存储)
需要各个节点都要安装nfs-utils