本文是一篇kubernetes(下文用k8s代替)的入门文章,将会涉及k8s的架构、集群搭建、一个Redis的例子,以及如何使用operator-sdk开发operator的教程。在文章过程中,会穿插引出Pod、Deployment、StatefulSet等k8s的概念,这些概念通过例子引出来,更容易理解和实践。文章参考了很多博客以及资料,放在最后参考资料部分。
一k8s架构我们看下k8s集群的架构,从左到右,分为两部分,第一部分是Master节点(也就是图中的ControlPlane),第二部分是Node节点。
Master节点一般包括四个组件,apiserver、scheduler、controller-manager、etcd,他们分别的作用是什么:
Apiserver:上知天文下知地理,上连其余组件,下接ETCD,提供各类api处理、鉴权,和Node上的kubelet通信等,只有apiserver会连接ETCD。
Controller-manager:控制各类controller,通过控制器模式,致力于将当前状态转变为期望的状态。
Scheduler:调度,打分,分配资源。
Etcd:整个集群的数据库,也可以不部署在Master节点,单独搭建。
Node节点一般也包括三个组件,docker,kube-proxy,kubelet
Docker:具体跑应用的载体。
Kube-proxy:主要负责网络的打通,早期利用iptables,现在使用ipvs技术。
Kubelet:agent,负责管理容器的生命周期。
总结一下就是k8s集群是一个由两部分组件Master和Node节点组成的架构,其中Master节点是整个集群的大脑,Node节点来运行Master节点调度的应用,我们后续会以一个具体的调度例子来解释这些组件的交互过程。
二搭建k8s集群上面说完了k8s集群中有哪些组件,接下来我们先看下如何搭建一个k8s集群,有以下几种方法(参考文末链接):
当我们安装了DockerDesktopAPP之后,勾选k8s支持就能搭建起来。
使用MiniKube来搭建,社区提供的一键安装脚本。
直接在云平台购买,例如阿里云ack。
使用kubeadmin,这是k8s社区推荐的可以部署生产级别k8s的工具。
使用二进制,下载各组件安装,此教程需要注意,下载的各组件版本要和博客中保持一致,就可以成功。
本文后面的例子均采用本地DockerDesktopAPP搭建的k8s。
➜~kubectlversionClientVersion:{Major:"1",Minor:"21",GitVersion:"",GitCommit:"3cce4a82b44f032d0cd1a1790e6d2f5a55d20aae",GitTreeState:"clean",BuildDate:"2021-08-11T18:16:05Z",GoVersion:"",Compiler:"gc",Platform:"darwin/amd64"}ServerVersion:{Major:"1",Minor:"21",GitVersion:"",GitCommit:"3cce4a82b44f032d0cd1a1790e6d2f5a55d20aae",GitTreeState:"clean",BuildDate:"2021-08-11T18:10:22Z",GoVersion:"",Compiler:"gc",Platform:"linux/amd64"}三从需求出发下面我们从一个实际的需求出发,来看看如何在k8s上部署Redis服务。
部署一个Redis服务
支持高可用
提供统一的Point访问地址
1部署单机版
如果我们想在k8s上部署一个单机版本Redis,我们执行下面的命令即可:
➜~kubectlrunredis--image=redispod/rediscreated➜~kubectlgetpodsNAMEREADYSTATUSRESTARTSAGEredis1/1Running05s
可以用kubectlexec来进入到Pod内部连接Redis执行命令:
➜~kubectlexec-itredis--bashroot@redis:/data类型为statefulsetmetadata:name:redis-sfs这里的service下面解释replicas:2镜像版本command:-bash-"-c"-|set-exordinal=`hostname|awk-F'-''{print$NF}'`如果是0,作为主echo/tmp/""/tmp/按照redis-sfs-11/1Running028s接着我们继续看下主从关系生效了没,查看redis-sfs-1的日志,却发现:
➜~kubectllogs-fredis-sfs-11:S05Nov202108:02:44.243*:63791:S05Nov202108:02:50.287这里的None就是Headless的意思,表示会主动由k8s分配ports:-port:6379name:redis-sfsselector:app:redis-sfs
再次查看,发现redis-sfs-1已经主备同步成功了,因为创建HeadlessService之后,在集群中就是唯一可访问的了。
➜~/redis-sfscreated➜~kubectlgetserviceNAMETYPECLUSTER-IPEXTERNAL-IPPORT(S)/TCP24dredis-sfsClusterIPNonenone6379/TCP33s➜~kubectllogs-fredis-sfs-11:S05Nov202108:23:31.341*:63791:S05Nov202108:23:31.345*MASTER-REPLICAsyncstarted1:S05Nov202108:23:31.345*:S05Nov202108:23:31.346*MasterrepliedtoPING,replicationcancontinue1:S05Nov202108:23:31.346*Partialresynchronizationnotpossible(nocachedmaster)1:S05Nov202108:23:31.348*Fullresyncfrommaster:29d1c03da6ee2af173b8dffbb85b6ad504ccc28f:01:S05Nov202108:23:31.425*MASTER-REPLICAsync:receiving175bytesfrommastertodisk1:S05Nov202108:23:31.426*MASTER-REPLICAsync:Flushingolddata1:S05Nov202108:23:31.426*MASTER-REPLICAsync:LoadingDBinmemory1:S05Nov202108:23:31.431*:S05Nov202108:23:31.431*RDBage0seconds1:S05Nov202108:23:31.431*:S05Nov202108:23:31.431:6379:6379
此时无论我们删除哪个Pod,它都会按照原来的名称被拉起来,从而可以保证准备关系,这个例子只是一个StatefulSet的示例,分析下来可以发现,虽然它可以维护主备关系,但是当主挂了的时候,此时备无法切换上来,因为没有组件可以帮我们做这个切换操作,一个办法是用RedisSentinel,可以参考这个项目的配置:k8s-redis-ha-master,如果你的k8s较新,需要merge此PR.
六Operator虽然有了StatefulSet,但是这只能对基础版有用,如果想自己定制更加复杂的操作,k8s的解法是operator,简而言之,operator就是定制自己k8s对象及对象所对应操作的解法。
那什么是对象呢?一个Redis集群,一个etcd集群,zk集群,都可以是一个对象,现实中我们想描述什么,就来定义什么,实际上我们定一个是k8syaml中的kind,之前的例子中,我们使用过Pod,Deployment,StatefulSet,它们是k8s默认实现,现在如果要定义自己的对象,有两个流程:
定义对象,比如你的集群默认有几个节点,都有啥组件
定义对象触发的操作,当创建对象时候要做什么流程,HA时候要做什么流程等
operator的方式是基于编程实现的,可以用多种语言,用的最多的就是go语言,通常大家会借助operator-sdk来完成,因为有很多代码会自动生成。相当于operator会生成框架,然后我们实现对应的业务逻辑。
1准备工作
安装好go环境
安装operator-sdk
2初始化项目
然后我们按照官网的sdk例子,来一步一步实现一个memcached的operator,这里也可以换成Redis,但是为了保证和官网一致,我们就按照官网来创建memcachedoperator。
➜~cd$GOPATH/src➜srcmkdirmemcached-operator➜srccdmemcached-operator➜memcac/yangbodong22011/memcached-operator--skip-go-version-check//这里需要注意domain最好是和你在,因为后续会发布docker镜像WritingkustomizemanifestsforyoutoeditWritingscaffoldforyoutoeditGetcontrollerruntime:$/controller-runtime@:$gomodtidyNext:definearesourcewith:$operator-sdkcreateapi
3创建API和Controller
➜memcached-operatoroperator-sdkcreateapi--groupcache--versionv1alpha1--kindMemcached--resource--controllerWritingkustomizemanifestsforyoutoeditWritingscaffoldforyoutoeditapi/v1alpha1/memcached_/memcached_:$gomodtidyRunningmake:$makegeneratego::/controller-tools/cmd/controller-gen@:installingexecutableswith'goget',use'goget-d'.Toinstallusingrequirementsofthecurrentmodule,use'goinstall'.Toinstallignoringthecurrentmodule,use'goinstall'withaversion,like'/cmd@latest'.Formoreinformation,see'gohelpget'or'gohelpinstall'.goget://Users/yangbodong/go/src/memcached-operator/bin/controller-genobject:headerFile="hack/"paths="./"➜memcached-operator
上面的步骤实际上生成了一个operator的框架,接下来我们首先来定义memcached集群都包括啥,将默认实现修改为Size,表示一个Memcached集群中Memcached的数量,最后调用makegenerate和makemanifests来自动生成deepcopy和CRD资源。
➜memcached-operatorvimapi/v1alpha1/memcached_//修改下面Memcached集群的定义//MemcachedSpecdefinesthedesiredstateofMemcachedtypeMemcachedSpecstruct{//+kubebuilder:validation:Minimum=0//SizeisthesizeofthememcacheddeploymentSizeint32`json:"size"`}//MemcachedStatusdefinestheobservedstateofMemcachedtypeMemcachedStatusstruct{//NodesarethenamesofthememcachedpodsNodes[]string`json:"nodes"`}➜memcached-operatormakegenerate/Users/yangbodong/go/src/memcached-operator/bin/controller-genobject:headerFile="hack/"paths="./"➜memcached-operatormakemanifests/Users/yangbodong/go/src/memcached-operator/bin/controller-gen"crd:trivialVersions=true,preserveUnknownFields=false"rbac:roleName=manager-rolewebhookpaths="./"output:crd:artifacts:config=config/crd/bases➜memcached-operator4实现Controller
接下来是第二步,定义当创建一个Memcached集群时候,具体要干啥。
➜memcached-operatorvimcontrollers/memcached_,注意,//注释中的也要换,实际不是注释,而是一种格式➜memcached-operatorgomodtidy;makemanifests/Users/yangbodong/go/src/memcached-operator/bin/controller-gen"crd:trivialVersions=true,preserveUnknownFields=false"rbac:roleName=manager-rolewebhookpaths="./"output:crd:artifacts:config=config/crd/bases5发布operator镜像
➜memcached-operatorvimMakefile将-IMG?=controller:latest改为+IMG?=$(IMAGE_TAG_BASE):$(VERSION)➜memcached-operatordockerlogin//提前登录下'thaveaDockerID,headoverto!Yourpasswordwillbestoredunencryptedin/Users/yangbodong/.docker/➜memcached-operatorsudomakedocker-builddocker-push==writingimagesha256:a7313209==/yangbodong22011/memcached-operator:0.0.10.0sfac03a24e25a:Pushed6d75f23be3dd::digest:sha256:242380214f997d98186df8acb9c13db12f61e8d0f921ed507d7087ca4b67ce59size:739
6修改镜像和部署
➜memcached-operatorvimconfig/manager/:controller:latest修改为yangbodong22011/memcached-operator:0.0.1➜memcached-operatorvimconfig/default/manager_auth_proxy_因为国内访问不了:/kubebuilder/kube-rbac-proxy:修改为kubesphere/kube-rbac-proxy:➜memcached-operatormakedeployconfigmap/memcached-operator-manager-configcreatedservice/memcach/memcached-operator-controller-managercreated➜memcached-operatorkubectlgetdeployment-nmemcached-operator-system//ready说明operator已经部署了NAMEREADYUP-TO-DATEAVAILABLEAGEmemcached-operator-controller-manager1/11131s➜memcached-operator
7创建Memcached集群
➜memcached-operatorcatconfig/samples/cache_v1alpha1_:/v1alpha1kind:Memcachedmetadata:name:memcached-samplespec:size:1➜memcached-operatorkubectlapply-fconfig/samples/cache_v1alpha1_/memcached-samplecreated➜memcached-operatorkubectlgetpodsNAMEREADYSTATUSRESTARTSAGEmemcached-sample-6c765df685-xhhjc1/1Running0104sredis1/1Running0177mredis-deployment-866c4c6cf9-zskkb1/1Running03h4mredis-sfs-01/1Running0112mredis-sfs-11/1Running0112m➜memcached-operator
可以通过kubectllogs来查看operator的日志:
➜~kubectllogs-fdeployment/memcached-operator-controller-manager-nmemcached-operator-system2021-11-05T09:50:46.042{"reconcilergroup":"","reconcilerkind":"Memcached","name":"memcached-sample","namespace":"default","":"default","":"memcached-sample"}至此,我们的operator-sdk的任务暂时告一段落。
七总结本文介绍了k8s的架构,各组件的功能,以及通过一个循序渐进的Redis例子介绍了k8s中Pod,Deployment,StatefulSet的概念,并通过operator-sdk演示了一个完整的operator制作的例子。
八参考资料[1]《深入剖析Kubernetes》张磊,CNCFTOC成员,at阿里巴巴。
[2]《Kubernetes权威指南》第五版
[3]《Large-scaleclustermanagementatGooglewithBorg》
[4]
[5]
[6]
[7]
[8]
[9]
[10]
[11]
[12]
[13]
作者|凡澈
本文为阿里云原创内容,未经允许不得转载。





