ansible、saltstack
docker compose:实现单机容器编排
docker swarm:实现多主机整合成为一个
docker machine:初始化新主机
mesos IDC的操作系统,Apache研发的资源分配工具
瀑布式开发→迭代开发→敏捷开发→DevOps
单体架构→分层架构→微服务
过程:
需求→开发→测试→交付→部署
应用模式的开发把开发与运维整合起来,打破了两者直接的壁垒。
CI(持续集成):
开发完合并代码到代码仓库然后自动构建部署测试,有问题打回给开发,无问题自动交付给运维方
CD(持续交付):
测试完之后自动打包好最终产品,并存放到可以被运维或客户拿到的地方
CD(持续部署):
交付完后自动拖出开发包并自动部署,运行时出现的bug自动反馈给开发
常见部署方案
容器化部署优势:
早期交付与部署环节因为各种不同系统不同版本的环境因素使其极其的困难,而容器的实现可以使其得以非常容易实现,可以真正的一次编写多次部署
微服务:
把每一个应用都拆解成一个微小的服务,只做一个功能,例如把一个单体应用程序拆解为数百个微服务,让其彼此间进行协作
缺点:
分发部署以及微服务互相之间的调用关系变得极其复杂,并且数以百计微服务难免其中的某些微服务会出现很问题,而单靠人工梳理和解决并不现实,容器与编排工具可以完美解决这些问题
解决方案:
正是容器和编排工具的出现使得微服务和DevOps得以容易落地
自动装箱
自我修复
水平扩展
服务发现和负载均衡
自动发布和回滚
密钥和配置管理
批量处理执行
整个kubernetes由master、node、组件、附件组成
kubernetes是一个有中心节点架构的集群系统master/node,一般会有一个或一组(三个master)节点作为主节点来做高可用,各node节点是用来贡献计算能力、存储能等相关资源(运行容器)的节点
负责对外提供服务解析请求,并且需要存储整个集群中的个对象的状态信息,向客户端提供服务时使用https协议需要CA与证书
负责观测每个node之上的资源,并根据用户请求要创建容器所需要的资源量找到符合条件的node,然后根据调度算法中的最优算法选择最优node
负责监控并确保每一个控制器的健康,并且在多个master之上做控制器管理器的冗余
由于API Server需要存储整个集群中的对象的状态信息,存储量较大所以就需要etcd来实现;etcd是一个键值存储的数据库系统,而考虑到etcd的重要性,一般需要三个节点做高可用,默认是通过https进行通信,并且通过不同的两个接口分负责内外通信,其中内部通信需要一个点对点通信证书;向客户端提供服务是通过另一套证书实现
与master通信,接收master和调度过来的各种任务并试图让容器引擎(最流行的容器引擎为doker)来执行
容器引擎,运行pod中的容器
每当pod增删和service需要改变规则需要依赖kube-proxy,每当pod增删时会有一个通知,通知到所有相关联的组件,service收到通知需要kube-proxy修改所有集群内所有节点的iptables
工作负载(workload)负责监控所管理的每一个容器是否是健康的应用节点数是否符合,确保pod资源符合预期的状态,如果出现异常则向API server发送请求,由kubernetes重新创建启动容器、还可以滚动更新或回滚
代用户创建指定数量的pod副本数量,确保pod副本数量符合预期状态,并且支持滚动式自动扩容和缩容功能。
帮助用户管理无状态的pod资源,精确反应用户定义的目标数量,但是RelicaSet不是直接使用的控制器,而是使用Deployment
ReplicaSet主要三个组件组成:
(1)用户期望的pod副本数量
(2)标签选择器,判断哪个pod归自己管理
(3)当现存的pod数量不足,会根据pod资源模板进行新建
工作在ReplicaSet之上,用于管理无状态应用,目前来说最好的控制器。支持滚动更新和回滚功能;还提供声明式配置,可以随时重新进行声明,随时改变我们在API Server上定义的目标期望状态,只要那些资源支持动态运行时修改。
更新和回滚功能:
Deployment一般会控制两或多个个ReplicaSet,平时只激活运行一个,当更新时逐一停止激活状态的ReplicaSet上的容器并在另一个ReplicaSet上创建直到完成,回滚是相反的动作;可以控制更新方式和节奏:例如定义一次更新几个节点或者先临时加几个pod正常后在删除旧pod使能正常提供服务的pod个数保持一致等等
HPA:二级控制器,负责监控资源,自动伸缩
用于确保集群中的每一个节点或符合标签选择器的节点上只运行特定的pod副本,通常用于实现系统级后台任务。比如ELK服务日志收集分析工具。只要新增节点就会自动添加此pod副本
Deployment和DaemonSet所部署的服务特性:
服务是无状态的
服务必须是守护进程
管理有状态应用
只要完成就立即退出,不需要重启或重建;如果任务没完成异常退出才会重建Pod。适合一次性的任务
周期性任务控制,不需要持续后台运行
管理有状态应用,每一个Pod副本都是被单独管理
kubernetes中最小单元,是在容器上又封装一层模拟虚拟机,一个pod里可以有多个容器(一般为一个),其中这多个容器可以共享一个网络名称空间、共享存储卷
两类:
自主式pod:如果node故障,其中的pod也就消失了
pod控制器管理的pod
可以用打标签的方式给资源分组,所有对象都可打标签(pod是最重要的一类对象)格式:key=value
根据标签过滤符合条件的资源对象的机制
是一个四层调度器。实际是一个宿主机上的iptables dnat规则和宿主机的一个虚拟的地址负责反向代理后端容器服务,所以如果你创建一个service,service是会反应到整个集群的每一个节点之上的。他是可以被解析的地址也是固定的,但是并不附加在网卡之上;由于后端容器频繁的变更,不断伸缩、创建删除,他们的地址与容器主机名称是不固定的,所以后端容器每次变动,service通过标签选择器获取他们的标签区别并记录他们并同时记录对应的地址与容器名字,因此当服务请求进来后先到service,通过service找到对应的服务并且转发到其中的容器中,不过安装完K8S之后需要在集群中的dns中配置他的域名解析,如果手动修改service地址或名字,dns中的解析记录也会自动修改,如果后端一个服务有多个节点,service支持ipvs,会把规则写入ipvs中进行负载均衡
service规则默认用的是ipvs,如果不支持ipvs则自动降为iptables
监控相关资源利用、访问量、是否故障
service想要被发现需要dns服务,dns也是运行在pod之中
用于收集和聚合集群和容器级别的资源使用情况和度量数据,以供监控和自动伸缩等用途。
提供了一个基于 Web 的用户界面,用于可视化管理和监控 Kubernetes 集群。
用于将外部网络流量路由到集群内部的服务。常见的 Ingress Controller 包括 Nginx Ingress Controller 和 Traefik。
在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
节点网络
集群网络(service网络)
pod网络
是通过lo通信
是通过“叠加网络”进行通信,把需要传递到pod的IP和端口报文外部再封装一个IP用于不同节点之间的传递,当节点接收到叠加网络报文时进行拆封,然后再根据内部的IP和端口找到对应的服务,当然pod是动态的随时会进行增删就需要通过service来找到具体目标pod
因为service地址实际上只是宿主机上iptables规则地址,创建service后会反应到整个集群的所有节点和宿主机iptables之上,当pod需要与service通信时会把网关指向docker0乔的地址,另外宿主机也可以把docker0乔当作自己的一个网卡,所以宿主机之上pod可以直接与service通信,通过iptables规则表检查指向发送请求
负责接入外部插件网络解决方案,可以运行在pod之上作为集群的一个附加使用,需要共享宿主机的网络名称空间。
负责给pod、service提供ip地址
负责网络策略功能:实现pod隔离,让不同的pod之间根据要求通过添加规则实现互通或隔离,防止托管在pod中的恶意服务截取或攻击其他pod中服务
flannel(叠加网络):只支持网络配置
calico(三层隧道网络):支持网络配置和网络策略
canel:把前两者结合,用flannel配置网络,用calico配置网络策略
...
etcd与etcd之间
etcd与API Server之间
API Server与用户之间
API Server与kubetel之间
API Server与kube-proxy之间
把一个集群根据每一类pod切割成多个名称空间,而切割的这个名称空间边界不是网络边界而是管理边界,例如创建一个项目,项目下可以有多个pod,可以批量管理这个项目中的pod,项目完成可以批量删除整个项目
所有组件运行为系统的守护进行,很繁琐包括做5个CA
kubespray是一个基于Ansible的部署方案,根据已经写好的ansible的剧本进行执行,也是把所有组件运行为系统的守护进行
容器化部署,更像是一套完整的脚本封装,比较快速简单
至少两核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、认证等)
官方文档
!!!安装参考文档,比较详细可以直接照着这个安装就行
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 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")
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并完成认证的配置文件
是API Server的客户端程序,这个客户端程序是通过连接master节点上的API server这一个对应的应用程序,这也是整个K8S集群上唯一一个管理入口,kubectl就是这个管理入口的客户端管理工具
kubectl仿照于面向对象的开发语言,所有k8s中的资源都可以看做对象类,类中有方法和属性。每当根据给定的参数创建pod时就相当于给类中的方法赋值,相当于实例化对象。
kubectl
version #获取版本信息
cluster-info #获取集群信息
api-versions #查看当前可支持api的版本
-h #获取帮助
explain
示例:
kubectl explain pod.spec.volumes.pvc
describe #获取对象的详细描述信息包括所有可以作为对象的目标如:pod、service、node、deployment等
示例:kubectl describe pod nginx-deploy
get 获取信息
cs #组件状态信息
nodes #节点信息
deployment #查看此控制器已创建的pod
ns #获取名称空间
pods #获取当前正在运行的pod信息
deployment #查看控制器信息
services/svc #查看service信息
(以下命令需要追加到对象之后)
-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
(以上命令需要追加到对象之后)
run NAME #(控制器名称) 创建并启动
--image='': #指定镜像
--port='': #暴漏端口
--dry-run=true #模拟执行,非真正执行
--
--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 对象。如果对应的资源已经存在,则会返回错误,此时需要先删除原有的资源对象,然后再执行创建操作。如果资源对象不存在,则会自动创建对应的资源对象。适用于初始化资源对象的场景
-f 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 #命令允许用户对运行在 Kubernetes 集群中的资源进行局部更新。相较于我们经常使用的 kubectl apply 命令,kubectl 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地址
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
Pending, Running, Failed, Succeeded, Unknown
#Pending:挂起,请求创建pod时条件不能满足调度没完成。例如已经创建但没找到符合指定tag的节点
#Unknown:未知状态,例如节点上的kubelet故障,API Server无法与之通信所以会出现未知状态
主容器启动前:始化容器,主进程启动前先运行辅助容器init进行初始化容器,甚至和可以运行多个并串行执行,运行完之后退出启动主进程
主容器启动时:执行启动后钩子
主进程运行时:
liveness:存活状态检测,判定主容器是否处于运行状态(runing),此时不一定能对外提供服务
readiness:就绪状态检测,判定容器中的主进程是否已经准备就绪并可以对外提供服务
(无论哪种探测都可以支持三种探测行为:执行自定义命令;向指定的TCP套接字发请求;向对指定的http服务发请求。并根据响应码判断其成功还是失败。即三种探针:ExecAction、TCPSocketAction、HTTPGetAction)
主容器结束后:执行结束后钩子
用户创建Pod后把请求提交给API Server
API Server会把创建请求的目标状态保存到etcd中
API Server会请求调度器进行调度,并把调度的结果、调度的那些节点资源保存到etcd中
节点上的kubelet通过API Server当中的状态变化得知任务通知,并拿到用户此前提交的创建清单
kubelet根据清单在当前节点上创建并启动pod
kubelet把当前pod状态发回给API Server
防止删除Pod时数据丢失会向Pod内的每一个容器发送终止信号,让Pod中的容器正常进行终止,这个终止会给一个默认的宽限期默认30秒。如果过了宽限期还没终止就会重新发送kill信号
apiserver仅接收json格式的资源定义:执行命令时会自动把你给的内容转换成json格式,而后再提交;查看yaml格式资源配置清单 实例: kubectl get pod myapp-848 -o yaml
一个yaml文件可以定义多个资源,需用—分隔开
此对象属于K8S的哪一个API版本和群组,一般格式为 group/version 如果省略group则默认为核心组。
例:控制器属于app组;pod属于核心组
查看命令 :kubectl api-versions
资源类别,用于初始化实例化成一个资源对象使用的
提供的信息有:name、namespace、labels、annotations(资源注解)
selfLink:每个资源引用方式
固定格式:
api/GROUP/VERSION/namespaces/NAMESPACE/TYPE/NAME
示例:selfLink: /api/v1/namespaces/default/pods/myapp-848b5b879b-8fhgq
用户期望的目标状态/规格,定义要创建的资源对象需要有怎样的特性或满足怎样的规范(例如它的容器应该有几个;容器应该用哪个镜像创建;容忍哪些污点)
显示当前资源的当前的状态,如果当前状态与目标状态不一致,K8S就是为了目标状态定义完后当前状态无限向目标状态靠近或转移,以此来满足用户需要,注意本字段由K8S集群维护,用户不能定义此字段
([]表示列表)
kubectl explain pods:
metadata
(自主式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
kubectl explain rs/ReplicaSet:
kind
metadata
spec
replicas
selector
template
metadata
spec
matchExpressions <[]Object>
matchLabels
(可以通过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
(大部分配置与ReplicaSet相似)
kubectl explain deploy/deployment:
spec
revisionHistoryLimit
paused
strategy
type
#
Recreate:重建试更新,删一个创建一个
RollingUpdate:滚动更新,为默认更新方法,更新策略需要配置在上级配置的RollingUpdate中
rollingUpdate
maxSurge
maxUnavailable
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
(配置文件除了没有replicas,其他大部分与deployment控制器类似,也支持滚动更新策略)
kubectl explain ds/DaemonSet:
spec
updateStrategy
rollingUpdate
maxUnavailable
type
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
用法:
kubectl explain svc/service:
clusterIP
#
spec
ports <[]Object>
name
nodePort
port
targetPort
protocol
selector
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映射,每一个路径映射到一组后端服务
在七层代理服务器假如是nginx反代至后端时,因为后端时pod容器所以ip不固定,如何修改nginx上upsteam确认后端IP
解决方案:
在他们中间层设置一个service,但此service不做代理使用只是负责给后端资源分组
K8S上有个ingress资源(注意与ingress Control区分),他可以读取每个service上所属的组包含的后端的IP定义成upsteam server并注入到nginx配置文件中并触发nginx重载配置文件
(注意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配置信息
(创建ingress资源后,会根据配置自动注入到ingress Control中)
kubectl explain ingress:
apiVersion
kind
metadata
annotations
kubectl create secret tls tomcat-ingress-secret --cert=tls.crt --key=tls.key
#tls:表示对象类型
#tomcat-ingress-secret 自定义名字
#--cert=tls.crt --key=tls.key :指明秘钥对文件
#tls为https协议,secretName为指定秘钥认证的secret,tomcat.magedu.com为后端名称虚拟主机,myapp为后端提供服务所属的service,80为后端所提供服务的端口号于service无关
同一个pod中的多个容器可以共享一个存储卷:因为存储卷不是属于容器而是属于pod,同一个pod中的容器底层复制的同一个基础架构镜像:pause。
emptyDir:作为容器中临时空目录使用,映射为宿主机目录或者内存,容器删除此目录中的数据也会被删除
hostPath:宿主机目录做映射,pod变更重新创建时需要调度到同一个宿主机上才能实现持久存储
gitRepo:类似与emptyDir,只不过是有内容的。在创建pod时会把指定的一个git仓库内容克隆下来并挂载。如果内容发生改变并不会自动进行推送或远程同步,要实现此功能需要一个辅助容器Sidecar
传统网络存储:SAN(iscsi)、NAS(NFS、CIFS)
分部式存储(文件系统级别、块级别):glusterfs,rbd,ceph
ebs、Azure Disk
kubectl explain pod.spec
volumes <[]Object> #在pod中定义存储卷
- name
emptyDir
medium
sizeLimit
hostPath
path
type
#DirectoryOrCreate:挂载的宿主机上的目录如果不存在则创建
#Directory:宿主机上必须存在此目录
#FileOrCreate:挂载一个宿主机文件如果不存在则创建
#File:宿主机必须存在此文件
#Socket
#CharDevice:字符类型设备文件
#BlockDevice:块设备文件
nfs
path
readOnly
server
containers
volumeMounts <[]Object> #在容器中挂载存储卷
- mountPath
name
readOnly
ubPathExpr
定义一个pod中两个容器,并定义pod中存储卷并分别挂载到两个容器中,第二个容器输入内容到html并作为第一个nginx容器的主页显示。(可以通过curl 这个容器进行验证)
需要各个节点都要安装nfs-utils
PVC:持久化卷声明.把k8s和存储卷剥离开,对于真正使用存储的用户不需要关心底层的存储实现细节降低使用者的门槛,只需要直接使用 PVC 即可。PVC 是用户存储的一种声明,PVC 和 Pod 比较类似,Pod 消耗的是节点,PVC 消耗的是 PV 资源,Pod 可以申请 CPU 和内存,而 PVC 可以申请特定的存储空间和访问模式。
存储逻辑:如上图所示在pod中只需要定义存储卷并指定存储大小,而这个存储卷必须与当前名称空间的pvc建立直接绑定关系,pvc必须与pv建立直接绑定关系,pv是真正某个存储设备上的存储空间。所以pvc与pv是k8s之上的抽象的、标准的资源,他俩的创建方式跟在k8s之上创建service等没啥区别。存储工程师把底层存储每一个存储空间先划割好,k8s管理员他需要把每一个存储空间给映射到系统上做成pv和创建好pvc。用户只需要自己定义pod,在pod中定义使用pvc。而在pvc与pv之间,当pvc不被调用时是没有用的空载的,当有人调用pvc时他需要与pv绑定起来,相当于pvc上的数据放到pv上的。pvc要绑定哪一个pv取决于pod创建者定义的存储空间的大小、访问模型(一人读一人写、多人读多人写等)、标签等,如果找不到合适的pv则会阻塞挂起。pvc与pv是一一对应的关系,如果某个pv把pvc占用了就不能被其他pvc占用了。而一个pvc创建后就相当于一个存储卷,此存储卷却可以被多个pod所访问,需不需要支持多个pod访问是根据其定义的访问模式决定
kubectl explain pod.spec.volumes
persistentVolumeClaim
claimName
readOnly
kubectl explain pvc
apiVersion: v1
kind: PersistentVolumeClaim
metadata
spec
accessModes <[]string> #访问模型必须是pv访问模型的子集
#访问模型帮助文档
resources
limits
requests
#与定义pod中的存储卷用法类似
#注意配置时定义pv的时候一定不要加名称空间,因为pv是集群级别的不属于名称空间下的所有名称空间都可以用,但是pvc是属于名称空间下的。名称空间也是集群级别的资源
kubectl explain pv
apiVersion: v1
kind: PersistentVolume
metadata
spec
accessModes <[]string> #指定访问模型,是个列表所以可以定义多种
ReadWriteOnce #单路读写,简写RWO
ReadOnlyMany #多路只读,简写ROX
ReadWriteMany #多路读写,简写 RWX
#访问模型帮助文档
persistentVolumeReclaimPolicy #回收策略,pvc被释放后被绑定的pv里面的数据处理方式
Retain #保留数据
capacity
nfs
path
readOnly
server
/data/volumes/v1 172.20.0.0/16(rw,no_root_squash)
/data/volumes/v2 172.20.0.0/16(rw,no_root_squash)
/data/volumes/v3 172.20.0.0/16(rw,no_root_squash)
/data/volumes/v4 172.20.0.0/16(rw,no_root_squash)
/data/volumes/v5 172.20.0.0/16(rw,no_root_squash)
查看是否有pv被绑定: kubectl get pv
pvc申请的时候未必就有现成的pv符合其指定的条件,k8s和存储工程师也不可能时时在线处理
可以把各种各样的底层存储尚未做成pv的存储空间都拿出来再根据各种存储的性能(如IO等)、质量(如冗余、价钱等)做一个分类并定义好存储类(StorageClass)。pvc在申请pv时不针对某个pv而是针对某个存储类(StorageClass),可以动态创建出一个符合要求的pv来,借助这么一个中间层来完成资源的分配。
注意:存储设备必须要支持restful风格请求接口
例如ceph有好多的本地磁盘一共凑出了4个PB的空间,这些空间需要再划分成它的子单位image才能拿来使用,每个image相当于一个磁盘或一个分区。当试图请求一个20G的pv时,通过ceph的restful接口请求立即划分出一个20G大小的image并格式化完成通过ceph导出来,然后在集群中定义成20G大小的pv,接着跟pvc绑定