1、背景
公司部分业务功能的实现是有状态的方式实现,部署在亚马逊的ec2上,为了方便这部分业务进行容器化改造,需要调研业界常见的有状态服务容器上部署方式,通过开源的方案来查看里面架构和实现逻辑,进行讨论来找出一种适合公司业务的部署改造方式。
这里通过etcd集群在容器上部署的案例来进行了解。这个项目通过etcd-operator自定义控制器来实现对etcd集群的管理:创建,删除,升级,漂移等
2、controller实现
当前自定义控制器常见的有两种:
-
一种是使用 code-generater 方式生成对于资源客户端代码,controller-manager组件以及很多开源operator都使用此种方式
-
一种是使用 operator-sdk 方式生成对应controller代码框架,此方式是更高层次的封装,简化用户侧的代码,开发效率较高
下图是控制器工作流程,使用 client-go k8s客户端连接集群,将关注的资源的变更(增删改)放入队列,供自定义控制器来实现自定义的控制逻辑
3、有状态和无状态服务区别
有状态服务和无状态服务区别
-
实例数量:无状态服务可以有一个或多个实例,可以横向扩容,k8组件里的kube-apiserver服务;有些有状态的服务即使部署多个,也只有一个服务进行工作。或者某个节点为主,其余为从
-
存储卷:无状态服务可以有存储卷,也可以没有,即使有也无法备份存储卷里面的数据;有状态服务必须要有存储卷,并且在创建服务时,必须指定给该存储卷分配的磁盘空间大小。
-
数据存储:无状态服务运行过程中的所有数据(除日志和监控数据)都存在容器实例里的文件系统中,如果实例停止或者删除,则这些数据都将丢失,无法找回;而对于有状态服务,凡是已经挂载了存储卷的目录下的文件内都可以随时进行备份,备份的数据可以下载,也可以用于恢复新的服务
k8s自带有状态服务控制器statefulset,其应用场景包括:
-
稳定的持久化存储,即Pod重新调度后还是能访问到相同的持久化数据,基于PVC来实现
-
稳定的网络标志,即Pod重新调度后其PodName和HostName不变,基于Headless Service(即没有Cluster IP的Service)来实现
-
有序部署,有序扩展,即Pod是有顺序的,在部署或者扩展的时候要依据定义的顺序依次依次进行(即从0到N-1,在下一个Pod运行之前所有之前的Pod必须都是Running和Ready状态),基于init containers来实现
-
有序收缩,有序删除(即从N-1到0)
常见的有状态业务场景
常见服务 |
etcd集群 |
statefulset方式 |
---|---|---|
访问方式 | 客户端通过svc访问后端随机ip,etcd从节点将请求代理到主节点,pod名字不固定 | 客户端通过handless service方式访问具体的pod |
存储 | 每个pod需要挂载单独的pvc来存取数据,没有严格的pod和pvc挂载对应关系 | 固定的pod需要挂载对应的pvc |
有序部署 | 部署启动有顺序要求,第一个启动的pod参数为new,其余加入的pod参数为exist | 有序部署,有序收缩 |
备注:不管是通过svc方式,还是通过handless方式,还是通过注册中心方式,都是为了感知pod切换事件,只是有些是从客户端进行感知进行额外操作,有些是从服务侧来进行感知处理。
4、etcd-operator使用
因项目比较旧,api版本不知道当前公司1.21版本的k8环境。经测试,可用的环境为:k8s 1.12,go 1.12,dep管理工具
创建crd描述和启动控制器
#kubectl apply -f deployment.yaml deployment.apps/etcd-operator created
#kubectl get crd NAME CREATED AT etcdclusters.etcd.database.coreos.com 2021 - 12 -21T05: 28 :31Z
#kubectl get pod NAME READY STATUS RESTARTS AGE etcd-operator-5c6bddb7f6-pzxmr 1 / 1 Running 0 5m28s |
创建etcd集群
$ cat example/example-etcd-cluster.yaml apiVersion: "etcd.database.coreos.com/v1beta2" kind: "EtcdCluster" metadata: name: "example-etcd-cluster" spec: size: 3 version: "3.2.13"
#kubectl apply -f example-etcd-cluster.yaml etcdcluster.etcd.database.coreos.com/example-etcd-cluster created
#kubectl get pod NAME READY STATUS RESTARTS AGE example-etcd-cluster-g8bp4lncsc 1 / 1 Running 0 2m26s example-etcd-cluster-tcw4d8p6j2 1 / 1 Running 0 65s example-etcd-cluster-tzcq4dlgcb 1 / 1 Running 0 106s
#kubectl describe svc example-etcd-cluster Name: example-etcd-cluster Namespace: default Labels: app=etcd etcd_cluster=example-etcd-cluster Annotations: service.alpha.kubernetes.io/tolerate-unready-endpoints: true Selector: app=etcd,etcd_cluster=example-etcd-cluster Type: ClusterIP IP: None Port: client 2379 /TCP TargetPort: 2379 /TCP Endpoints: 172.30 . 22.4 : 2379 , 172.30 . 23.3 : 2379 , 172.30 . 24.4 : 2379 Port: peer 2380 /TCP TargetPort: 2380 /TCP Endpoints: 172.30 . 22.4 : 2380 , 172.30 . 23.3 : 2380 , 172.30 . 24.4 : 2380 Session Affinity: None Events: <none> |
查看集群状态
ETCDCTL_API= 3 etcdctl -w table --cluster --endpoints http: //example-etcd-cluster-client:2379 endpoint statu +------------------------------------------------------------------------------+------------------+---------+---------+-----------+-----------+------------+ | ENDPOINT | ID | VERSION | DB SIZE | IS LEADER | RAFT TERM | RAFT INDEX | +------------------------------------------------------------------------------+------------------+---------+---------+-----------+-----------+------------+ | http: //example-etcd-cluster-g8bp4lncsc.example-etcd-cluster.default.svc:2379 | 430d76ef082b59eb | 3.2.13 | 25 kB | true | 25 | 9 | | http: //example-etcd-cluster-tzcq4dlgcb.example-etcd-cluster.default.svc:2379 | 94b5e0613b0fec12 | 3.2.13 | 25 kB | false | 25 | 9 | | http: //example-etcd-cluster-tcw4d8p6j2.example-etcd-cluster.default.svc:2379 | dce8dfcdd2583801 | 3.2.13 | 25 kB | false | 25 | 9 | +------------------------------------------------------------------------------+------------------+---------+---------+-----------+-----------+------------+ |
漂移
如果master所在pod因意外宕机,其余pod会使用raft协议重新进行选举,选举过程在外面看来就是多个pod之间进行网络通信,因此我们只要保证网络畅通即可,operator会重新启动一个pod。
并且外部是通过svc方式进行访问,所以宕机的pod会从svc中摘除,服务不会受影响
删除
删除crd和删除controller不会导致etcd集群意外删除,删除对应etcd应用(example-etcd-cluster)会删除所有pod资源
5、etcd-operator源码架构
代码:https://github.com/coreos/etcd-operator/
项目实现三个operator
operator |
实现功能 |
crd |
---|---|---|
etcd-operator |
etcd集群创建删除,pod,svc管理 |
etcdclusters.etcd.database.coreos.com |
etcd-backup-operator |
备份etcd数据到对象存储 |
etcdbackups.etcd.database.coreos.com |
etcd-restore-operator |
从存储还原etcd数据到新集群 | etcdrestores.etcd.database.coreos.com |
备注:
-
删除使用了级联删除,没有控制器干预 https://www.infoq.cn/article/s3cjwoyqfrsjsebdutfy
-
检测版本不一致是通过对比pod的annotations里面etcd.version字段来判断是否为新版本
依赖解决
Etcd-operator 1、go mod init etcd-operator replace ( github.com/coreos/bbolt => go.etcd.io/bbolt v1.3.5 go.uber.org/atomic => github.com/uber-go/atomic v1.5.0 ) 使用dep 安装 https://cloud.tencent.com/developer/article/1433229 把文件放到src目录 进入src的项目目录 如果有自己的mod文件,要删除 执行脚本 ./hack/update_vendor.sh Go版本要降低,注意go是否为自己装的go 1.12,而不是系统带的 终于可以了 没法执行build镜像不存在,可以打成二进制,再执行dockerfile
–
–
–
评论前必须登录!
注册