时间:2022-11-12 18:38:01
前言是kubernetes (以下用k8s代替)的入门报道。 介绍k8s的体系结构、集群构建、Redis示例以及如何使用operator-sdk开发operator的教程。 在文章中,穿插引出Pod、Deployment、StatefulSet等k8s的概念。 这些概念通过例子引出,容易理解和实践。 文章参考了很多博客和资料,放在了最后的参考资料部分。
让我们来看看k8s体系结构k8s集群的体系结构。 从左到右,分为两个部分。 第一部分是主节点,即图的控制平面,第二部分是节点。 主节点通常包括四个组件: apiserver、调度器、控制器管理器和etcd。 各自的作用是什么?
Apiserver (提供上知天文下知地理、上连其余组件、下接ETCD、各种api处理、认证、与Node上的kubelet的通信等,只有Apiserver与ETCD连接。 Controller-manager控制各种类型的controller,并通过控制器模式将当前状态转换为所需状态。 调度器:调度、评分和资源分配。 Etcd :整个群集的数据库也可以单独构建,而不部署在主节点上。 节点通常还包括三个组件:文档、kube-proxy和kubelet
Docker :具体的跑步APP运动生涯。 Kube-proxy :主要负责互联网的开通,初期利用iptables,现在使用ipvs技术。 Ubelet :管理代理、容器的生命周期。 总之,k8s集群是由两个组件Master和Node节点组成的体系结构,其中Master节点是整个集群的大脑,Node节点执行Master节点调度。 通过具体的调度实例说明了这些组件的交互过程。
() k8s集群的构建)以上,对k8s集群中有哪些组件进行了说明。 接下来,我们来看看如何构建k8s集群。 有以下方法(参照文末链接) :
安装Docker Desktop APP后,可以通过选中k8s支持来构建它。 使用MiniKube构建的社区提供的一键安装脚本。 直接在AlibabaCloud (阿里巴巴云) ack等云平台上购买。 使用kubeadmin。 这是k8s社区推荐的可部署生产级k8s的工具。 使用二进制文件下载并安装每个组件。 在本教程中,需要注意的是,如果下载的每个组件的版本与博客相匹配,则会成功。 本文后面的例子都采用本地Docker Desktop APP构建的k8s。
~ kubectlversionclientversion:version.info { major:'1',Minor:'21 ',GitVersion:'v1.21.4 ',git commit:' GoVersion:'go1.16.7 ',Compiler:'gc ',platform:' Darwin/amd64 ' } server version:version.info { major:' git version:' v1. 21.4 ' git commit:'3CCE 4a 82 b44 f 032 d0cd1a 1790 E6 D2 F5 a55 d 20 aae ',GitTreeState:'clean ',builddate:buildate
部署Redis服务支持高可用性并提供统一的EndPoint访问地址1部署独立版本要在k8s上部署独立版本的Redis,请运行以下命令:
~ kubectlrunredis---image=red ispod/redis created~kubectlgetpodsnamereadystatusrestartsageredis1/1running 05 s为kubectlged
~ kubectlexec-it redis-- bash root @ redis:/data # redis-CLI 127.0.0.1:6379 ping pong 127.0.0.0.1:6379左右
2 Pod和Deployment介绍最初的k8s概念——pod。 Pod是k8s中最小的调度单位,一个Pod可以包含多个文档。 所有这些Docker都安排在同一个Node上,这些Docker可以共享NetWork Namespace并声明共享同一个volumespace,这样做有什么好处呢? 在现实世界中,许多APP应用程序必须部署在同一台机器上。 例如,Redis日志收集插件要收集日志,必须将其部署在与Redis相同的计算机上才能读取Redis日志。 在解释背景时,他说Docker Swarm存在一些问题,其中之一只是基于Docker时间表。 您可以设置亲和度,使两台Docker调度在同一台计算机上,但由于不能调度在一起,因此一台Docker会提前调度在资源较少的计算机上,从而导致第二台Docker的调度失败例如,有两个容器: Redis和日志收集组件,a和b,每个组件需要2g内存。 目前有两台node、node1 3.5内存和node2 4g内存。 在Docker Swarm的调度策略下,首先调度Redis。 虽然可能先调度node1,然后再调度日志收集组件,但是在k8s上,调度是根据pod进行调度的,如果两个组件位于一个pod上,则调度不会考虑node1 Pod现在可以运行Redis服务,但不具有高可用性。 Pod绑定到节点( Node )后,除非绑定发生更改(除非Pod.spec.node字段发生更改),否则它不会离开节点。 这意味着,如果此主机关闭,此pod不会主动迁移到其他节点。 为了使服务能够一直持续下去,需要使用Deployment这样的控制器。
~ kubectlcreatedeploymentredis-deployment-- image=redis deployment.apps/redis-deployment created~kubectlgetpodsnamet 1 running 032 m redis-deployment-866 C4 c6cf9- 8888881running 08 s~redis-deployment-866 C4 c6cf9- 8z8k 5刚才是用kubectl create制作的
~ kubectldeletepodredisredis-deployment-866 C4 c6cf9- 8z8k5pod ' redis ' deleted pod ' redis-deployment-866 C4 c6cf9- 888888 6 c4c 6cf9- zsk kb1/1 running 010 s-redis已消失,但redis-deployment-866 c4c 6cf9- ZZ ing6deployment定义了多个Pod,可为APP应用程序提供迁移能力如果只是使用Pod,则在实际计划在具有APP事务的计算机上之后,即使计算机停机,APP事务也不会自动迁移;但是,如果使用部署,则会调用ReplicaSet (控制器)以获取当前类
在3 k8s使用yaml编写命令的k8s中,可以使用kubectl创建简单的服务,但也可以通过提供yaml文件来创建复杂的服务。 例如,用于创建上面Pod的命令可以替换为下面的yaml文件。 运行kubectl create时,您会看到已创建了redis Pod。
~ cat pod.yamlapiversion:v1 kind:pod metadata:name:redis spec:containers:- name:red isimage:redis~kubectlcreate artsageredis1/1running 06 sredis-deployment-866 C4 c6cf9- zsk B1/1 running06m32s四k8s组件调用流k8s群集分发后,k8s群集是什么
首先,控制器-管理器、调度器和kubelet启动apiserver和List-Watch模型,List获得当前状态,Watch获得期望状态,k8s集群获得当前状态以达到期望状态kubectl向apiserver发出命令,在认证处理后将制作信息保存到etcd中。 部署的实现需要使用ReplicaSet控制器,在控制器- manager事先获取当前状态( pod=0),然后接收到期望的状态时,创建复制之后,Node的kubelet真的把docker拉了出来。 在这些步骤中,apiserver的作用是不言而喻的,所以即使说将剩下的组件连接在上面,将ETCD连接在下面,apiserver也可以横向扩展,由于负载均衡,ETCD在k8s架构中会成为瓶颈第一次看到该体系结构时,我就想,为什么apiserver、计划程序和控制器-管理器不合并单个组件? 其实在谷歌博客上,borgmaster就是这样。 功能也是这些功能,但在一起了。 最后,在簇长大后,borgmaster发现了一些性能问题,包括kubelet的心率,所以k8s从一开始就是开源的,在设计中有三个组件应该更容易维护代码。
在部署五个主从版本之前,我们部署了Redis的独立版本,并通过部署继续运行服务。 接下来,我们来看看主从版本是如何部署的。 一个难点是如何确定主从的同步关系。
1 StatefulSetk8s为有状态APP应用设计了一个名为StatefulSet的控制器,主要通过以下两个特性为有状态APP应用提供服务:
拓扑状态-实例的创建顺序和编号按顺序进行编号,并根据name-index编号,例如redis-0、redis-1等。 存储状态:通过声明使用外部存储器(如云),可以存储数据并通过重新启动Pod、重新安排等读取云中的数据。 让我们看一下Redis的StatefulSet的例子。
API version:apps/v1 kind:stateful set #类型为statefulsetmetadata:name:redis-SFS # app名称spec: serviceName: redis-sfs # 两个副本selector:match labels:app:redis-SFS template:metadata:labels:app:redis-SFS spec:containers:- name:rame:me ommand:- bash-'-c '-| set-ex ordinal=` hostname|awk-f '-' { print $ nf } ` # hostname使用序列if [ $ ordiname redis.conf else echo ' slaveofredis-SFS-0.redis-SFS 6379 '/tmp/redis.conf #为1时,准备fi redis-server/tmp/redis
~ kubectlcreate-f server.yamlstatefulset.apps/redis-SFS created~kubectlgetpodsnamereadystatusrestartsageredis1/1 running 065 m redis-deployment-866 C4 c6cf9- zsk kb1/1 running 071 m redis-SFS-01/1 running 033 s # redis-SFS-11/1 runnnn
~ kubectllogs-Fred is-SFS-11:s 05 nov 202108:02:44.243 * connectingtomasterredis-SFS-0.redis-SFS:63791:s05 unabletoconnecttomaster:resourcetemporarilyunavailable .2heable 这是因为我们还没有互相认识。 这种相互识别需要使用名为Headless Service的服务,这是k8s项目中用于将一组Pod暴露给外部访问的机制。 例如,如果一个部署有三个Pod,我就可以定义一个服务。 然后,用户只要有权访问此服务,就可以访问特定的Pod。 一般有两种方法。
VIP :访问VIP并随机返回一个后端PodDNS。 用DNS解决为有后端的Pod的头服务可以用DNS的方式解决为某个Pod的地址。 这个DNS地址的规则如下。
创建与群集对应的头服务。
API version:v1 kind:service metadata:name:redis-SFS labels:app:redis-SFS spec:cluster IP:none #此none为Headless redis-sfs-1在创建头服务后发现主准备同步成功
~ kubectlcreate-f service.YAML service/redis-SFS created~kubectlgetservicenametypecluster-IP external-ipport TCP 24 dred is-sfsclusteripnone 6379/TCP 33 s~kubectllogs-Fred is-SFS-1.1:connectingtomasterredis-SFS-0.redis 主复制同步开始1:s 05 nov 2005 nonblockingconnectforsyncfiredtheevent.1:s 05 nov 202108:23:31.346 *主复制复制内容.1: s 05 nov 202108:23:31.346 * partialresynchronizationnotpossible ( nocache dmaster )1: s 05 nov 2005 fullresyncfrommaster:29 D1 c 03 da6ee 2af 173 b8d fbb 85 b6ad 504 * master-replicasync:receiving 175 bytesfrommastertodisk1: s 05 nov 202108:23:31.426 * master-replicasync:flushingolddolddinc master-replicasync:loadingdbinmemory1: s 05 nov 2021 001 loadingrdbproducedbyversion 6.2.61:s 05 nov 202108:23:31.431 *。 rdbmemoryusagewhencreated 1.83 mb1:s 05 nov 202108:23:31.431 # doneloadingrdb,keys loaded: 0, keys expired:0.1:s 05 nov 202108:23:31.431 * master-replicasync:finishedwithsuccess ^ c至kubectlexec-it redis-SFS redis-CLI-hred is-SFS-0.redis-SFS.default.SVC.cluster.local redis-SFS-0.redis-SFS.default.SVC . 此示例只是一个StatefulSet示例,通过分析,它可以维持主准备关系,但当主挂起时,此时无法切换准备。 因为没有组件可以帮忙这个。一个方法是使用Redis Sentinel,可以参考这个项目的配置: k8s-redis-ha-master,如果你的k8s是新的,可以和merge
六操作器有StatefulSet,但这只对基础版有用。 如果想自己定制更复杂的操作,k8s的解法是操作者。 简单地说,Operator是定制自己的k8s对象和与对象相对应的操作的解法。 那对象是什么呢? 一个Redis簇、一个etcd簇、zk簇可以是一个对象,现实中我们想要描述什么,定义什么,实际上决定了k8s yaml中的kind。 上一个示例使用了Pod、Deployment和StatefulSet。 这些是k8s的默认实现
定义对象。 例如,在你的集群中默认有几个节点。 都有哪些组件可以定义和触发对象的操作。 创建对象时要执行什么过程? HA的时候做什么样的过程? 等操作器的方式是基于编程实现的,可以使用多种语言。 使用最多的是go语言,通常在operator-sdk中进行。 因为很多代码会自动生成。 operator生成框架并实现相应的业务逻辑。
1准备工作
先安装go环境,再安装operator-sdk2初始化项目,然后按照官网上的sdk示例,一步一步实现memcached的operator。 此处也可以替换为Redis,但为了确保与官方网站一致,我们将根据官方网站创建memcached operator。
~ CD $ go path/srcsrcmkdirmemcached-operatorsrccdmemcached-operator memcached-operator-sdkin it-- domainyangbodong 22000 memcached-operator-- skip-go-version-check//请注意,此处domain与您在https://hub.docker.com上的注册名称相同。 之后, docker镜像writingkustomizemanifestsforyoutoedit . writingscaffoldforyoutoedit . getcontrollerruntime:$ gogetsigs.k8s update dependencies:$ gomodtidynext:definearesourcewith:$ operator-sdkcreateapi 3创建API和contreateAPI3
memcached-operator-sdkcreateapi---group cache---version v1 alpha1--- kind memcached-- resource t . API/v1 alpha1/memcached _ types.go controllers/memcached _ controller.goupdatedependencies:$ gomodtidyrunningmake:$ makegeneratego:creatingnewgo.mod:moduletmpdotmpdon controller-gen @ v 0.6.1 go get:installingexecutableswith ' go get ' inmodulemodeisdeprecated.toadjustandownloadependencied use ' go get-d '.toinstallusingrequirementsofthecurrentmodule,use ' go install '.toinstallignoringthecurrentmodule use like ' goinstallexample.com/cmd @ latest '.for more information, see https://golang.org/doc/go-get-install-deprecationorrun ' gohelpget ' or ' gohelpinstall '…go get:added sigs.k888 在controller-gen object:header file=' hack/boilerplate.go.txt ' pile . memcached-operator的上面的步骤中,实际上是operator 然后,首先定义memcached群集中包含的内容,将缺省实现更改为Size,指示memcached群集中的memcached的数量,最后调用make generate和mached
memcached-operatorvimapi/v1 alpha1/memcached _ types.go//更改以下memcached群集定义/memcachedspecdefinesthedesiredstateofmemcachedtypemcachedspecstruct {//kube builder:validation:minimum=0/sizeisthesizeofthememcacheddeploymentsizeint 32 ` JSON:' size ` }//memcachedstatusdefinestheobservedstateofmemchedtypemed nodesarethenamesofthememcachedpodsnodes [ ] sodes Jon:' nodes ' ` } memcached-operatormakegenerate/users/yangbo dong/gong controller boilerplate.go.txt ' paths=' . ' memcached-operatormakemanifests/users/yangbo dong/go/src/memcached-oper controller-gen ' CRD:trivial versions=true,preserveunknownfields=false ' RBAC:rolename=manager-manger
memcached-operatorvimcontrollers/memcached _ controller.go https://raw.github user content.com/operator-framework/ork //请注意,注释中的也必须转换。 实际上不是评论,而是格式mmong。make manifests/users/yangbo dong/go/src/memcached-operator/bin/controller-gen ' CRD preserveunknownfields=false ' RBAC:rolename=manager-rolewebhookpaths='./. ' output:CRD:artifacts:config=操作器镜像memcached -操作器vim makefile将-IMG=controller:latest更改为img=$(image_tag_base($ ) $(VERSION ) memcached-operatordockerlogin//dockerloginwithyourdockeridtopushandpullimagesfromdockerhub.if you don ' thaveadockerid herid yourpasswordwillbestoredunencryptedin/users/yangbo dong/. docker/config.JSON.configureacredentialhertoremovethison engine/reference/command line credentials-storeloginsucceedemcached-operatorsudomakedocker-build docker-push .==writingimagesha 256 545 a0.0s==namingtodocker.io/yangbo dong 22011/memcached-operator:0.0.10.0 sfac 03 a 24 e 25 a:pushed6d 75 f 23 be 3d:3d
memcached-operatorvimconfig/manager/manager.YAML image:controller:latest在yangbo dong 22011/memcached-operator :中manager_auth_proxy_patch.YAML是国内适用于gcr.io image:gcr.io/kube builder/由于无法访问kube-RBAC-proxy:v 0.8.kube-RBAC-proxy:v 0.8.0 memcached-operatormakedeploy . config map/memcached-operator-manager-configcreatedservice memcached-operator-controller-metrics-servicecreatedepdepeped memcached-operator-controller-managercreatedmemcached-operatorkubectlgetdeployment-n memcached-operator-system/系统就绪说明操作器已命名为namereadyup-to-dateavailableagememcached-operator-controller-manager1/1131 s memcached-operator
memcached-operatorcatconfig/samples/cache _ v1 alpha1_ memcached.yamlapiversion:cache.yangbo dong 22011/v1 alpha1kind:memcached metadata:name:memcached-samplespec:size:1 memcached-operatorkubectlapply-fconfig/sampleer cache _ v1 alpha1_ memcached.YAML memcached.cache.yangbo dong 22011/memcached-samplecreatedmemcached-operatorkubectlgetpodsnamereadystatusrestartsagememcached-sample-6c 765 df 685-xh hjc11 4c6cf9- zsk kb1/1 running 03 h4m redis-SFS-01/1 running 0112 m redis-SFS-11/1 running
~ kubectl logs -f deployment/memcached-operator-controller-manager-n memcached-operator-system 2021-11-05t 09:50:46.042 zinfocontroller-rrer . yangbodong22011 ',' reconciler kind': 'Memcached ',' name ':' memcached ' ' deployment.namespace ':' default,'
七本文通过k8s的体系结构、各个组件的功能,以及逐次的Redis示例介绍了k8s中Pod、Deployment、StatefulSet的概念,并通过operator-sdk实现了完整的operator
八参考资料[1] 《深入剖析Kubernetes》张磊,CNCF TOC成员,at阿里巴巴。 [2] 《Kubernetes 权威指南》第5版[3] 《Large-scale cluster management at Google with Borg》3359 research.Google/pubs/pubs/pub 43438/[4] https://ww.red hat.com/zh/topics/topics https://how-docker-broke-in-half.html [6] https://landscape.cn cf.io/[6] 3359 3359 mini kube.sigs.k8s.io/docs/sn 3359 github.com Chiang Chou/p/k8s-1.html [ 12 ] https://github.com/taro sky/k8s-redis-ha [ 13 ] 3https://SDK.operate article/804858 UTM _ content=g _ 1000308695本文为AlibabaCloud (阿里巴巴云)原创内容,未经许可不得转载。