重磅推荐!一站式技术平台上云的开源项目
大家好,我是章鱼猫。今天介绍的开源项目是用 Go 语言写的一站式云原生 PaaS 平台——Erda,专为企业提供 DevOps、微服务治理、多云管理以及快数据管理等平台级服务。
GitHub 地址→https://github.com/erda-project/erda
Erda 借助云原生的优势为企业打造一个完整的技术平台,助力企业数字化转型。并且已通过大量的企业成功交付案例,积累了大量经验。放心地把服务交给 Erda 打理吧!
进化历程
Erda 的演进历程:
Erda 很早就开始探索云原生 DevOps 实践,最初的平台只拥抱了 Docker 实现了基于 Docker 的手动部署平台,整个设计理念是面向资源的。(2016年:容器化)
而后随着容器编排技术的兴起,选型了 DC/OS(mesos+marathon)作为容器服务技术底座。选择 mesos 也是因为它的出现要远早于 Docker、K8s、Swarm 等,有不少大规模的落地案例,稳定性得到了很好的验证,并且还有很强的扩展能力,在 mesos 之上除了有 marathon、metronome 等服务、任务的调度框架,还支持了不少大数据的框架,比如 Hadoop、Spark 等,这与我们需要发展大数据平台不谋而合。我们的设计理念也调整到以应用为中心,去面向开发者。(2017年:DC/OS)
前期交付的都用一个集群将平台完整的私有化输出到客户环境,但随着客户越来越多资源成本变成了一个大问题。Erda 开始考虑将平台能力 SaaS 化,提供企业租户,并支持多集群管理。客户侧的集群不需要再部署一个完整的 Erda 平台,只需开放口子可以给平台访问即可。在零产品能力损失的情况下,节省了大量的资源,并且客户不需要再关心平台的维护问题。(2018年:多集群架构)
Kubernetes 逐渐成为了业界的事实标准,Erda 提前预知了这个趋势。 在支持多集群架构时就将容器编排层进行了封装抽象,并引入了插件的机制便于未来的扩展。所以后面很平滑地将平台全部切至了 K8s。(2019年:支持 Kubernetes)
Erda 用多集群管理解决的痛点
如今数字化转型已经成为现阶段企业发展的主流趋势,该趋势也促使着云市场的快速增长。我们已经处于云时代,而面向企业又会出现混合云、多云的架构。
混合云:私有云和公有云相互搭配在一起使用。该场景下企业主要结合经济效益或者安全因素进行考量,来获取云计算的各方优势,取长补短。公有云可以获得更多弹性伸缩的能力,私有云可以用于存放企业数据。或者就是企业在尝试迁移上云的一个中间态等等。 多云:包含两个及以上公有云服务提供商。这类场景,客户更多是不希望被单个云服务提供商锁定,把鸡蛋放在一个菜篮子。或者是因为地理位置的原因需要选择其他的服务商。
企业总可能出于各种原因进行多云、混合云的决策。而 Erda 面向企业进行交付时,必然也少不了会面对这些场景。Erda 最终都通过多集群管理的方式输出解决方案,为不同的环境搭建不同的集群,由平台侧统一管理,上层业务可以按需选择不同的集群进行应用的生命周期管理。
除了这些,一些其他的场景也可通过多集群管理的方式解决,比如:
开发/测试/预发/生产环境隔离,把这些环境部署到不同的集群中; 业务与数据的环境隔离,分离到不同的集群中; 提升可扩展性,突破单一集群的节点上线; 等等
综上所述,针对多集群管理,Erda 除了压缩交付的资源诉求,还输出了大量的解决方案,来满足客户的不同场景。
跨集群管理经验分享
上面主要介绍了 Erda 多集群管理的一个背景,及 ToB 交付时如何满足企业的各种场景需求。回到多集群管理会面临的一个大问题,就是如何跨集群进行访问、管理?
经历的阶段
Erda 在 DC/OS 时代,使用了最简单的 basic auth 的方式,直连集群进行管控。
随着客户量越来越大,并且平台支持异构调度之后,管理难度和安全问题凸显。Erda 实现了一套 netportal 的网络管控链路,中心有一个 netportal 组件,边缘则需要在集群端的 nginx configuration 中加一段配置。中心访问用户集群时会统一通过 netportal 进行代理,将流量转发到对端集群的 nginx 上。netportal 和 nginx 之间采用了 https 双向认证的方式进行建连,并且所有的证书都由中心统一签发,提升了通道的安全性。
随着产品战略的提升,开始建设 Erda Cloud,加强 Erda 产品的商业化能力,让用户可以自助地在平台上完成一系列操作,这个就对 netportal 链路产生了巨大挑战。netportal 有不少依赖,比如集群端的 nginx 版本,nginx 需要增加额外的配置,对应的证书需要由中心统一签发等等,这些都无法让用户完成自助操作。而此时 Erda 的容器服务默认换成了 Kubernetes,针对 Kubernetes 访问方式进行了扩展,引入了社区常见的访问方式:KubeConfig、ServiceAccount(Token)。
KubeConfig、ServiceAccount 的方式,会要求客户将 Kubernetes 集群的 ApiServer 暴露在公网上,由平台进行直连。如果没有外加安全措施,这种直连会存在一定的安全隐患。还碰到了有客户无法提供公网入口 IP,而上面所有的方式都是需要有公网入口才能实现。还好客户还不是全封闭的,可以访问公网,于是 Erda 借鉴了 Rancher 的做法,实现了 dialer 的通道管理,可以不必让 Erda 去连接用户的集群,而是在用户的集群安装 cluster agent 来连接 Erda,让用户集群主动建立一条连接,这条连接就变成了 Erda 去管控用户集群的隧道(Tunnel)。
核心组件
Cluster Agent:部署在用户业务集群的组件,会主动去连接 Erda 的 Cluster Dialer,同时会将一些集群信息做上报,例如集群内 kube-apiserver 的地址、访问 token 等。 Cluster Dialer:接收 Cluster Agent 的连接,同时将集群信息注册到 Cluster Manager,跟 Cluster Agent 之间的连接通过 Tunnel Session 维护起来。
Erda 控制平面内的其他组件比如 K8s Manager,可以通过请求 Cluster Dialer,找到要管控集群的 Tunnel Session,再通过这个 Tunnel 去访问对应集群中的 kube-apiserver。
Dialer 的使用
在 Erda 开源项目的 pkg/clusterdialer/dialer.go
模块:
https://github.com/erda-project/erda/blob/master/pkg/clusterdialer/dialer.go
提供了一个 cluster dialer lib,主要提供了以下三个 Dial Function:
type DialContextFunc func(ctx context.Context, network, address string) (net.Conn, error)
type DialContextProtoFunc func(ctx context.Context, address string) (net.Conn, error)
func DialContext(clusterKey string) DialContextFunc {
return func(ctx context.Context, network, addr string) (net.Conn, error) {
logrus.Debugf("use cluster dialer, key:%s", clusterKey)
return getClusterDialer(ctx, clusterKey)(ctx, network, addr)
}
}
func DialContextProto(clusterKey, proto string) DialContextProtoFunc {
return func(ctx context.Context, addr string) (net.Conn, error) {
logrus.Debugf("use cluster dialer, key:%s", clusterKey)
return getClusterDialer(ctx, clusterKey)(ctx, proto, addr)
}
}
func DialContextTCP(clusterKey string) DialContextProtoFunc {
return DialContextProto(clusterKey, "tcp")
}
如果使用 http client 要访问用户集群的 HTTP 服务,可以通过如下方式构造 client:
client = &http.Client{
Transport: &http.Transport{
DialContext: clusterdialer.DialContext(cluster.Name),
},
}
如果使用 K8s client-go 也可以借助 Dial Function 来构造对应的 rest.Config。如下:
rc := &rest.Config{
Host: host,
BearerToken: cluster.ServiceAccountToken,
TLSClientConfig: rest.TLSClientConfig{
CAData: append(caBytes, suffix...),
NextProtos: []string{"http/1.1"},
},
Timeout: 45 * time.Second,
RateLimiter: ratelimit.None,
UserAgent: rest.DefaultKubernetesUserAgent() + " cluster " + cluster.Name,
WrapTransport: func(rt http.RoundTripper) http.RoundTripper {
if ht, ok := rt.(*http.Transport); ok {
ht.DialContext = clusterdialer.DialContext(cluster.Name)
}
return rt
},
}
甚至如果要访问用户业务集群的 MySQL,实现 MySQL 控制台的功能,也可以实现:
import (
"database/sql"
...
"github.com/go-sql-driver/mysql"
...
)
...
mysql.RegisterDialContext("tcp", clusterdialer.DialContextTCP(cluster.Name))
db, _ := sql.Open("mysql", "root@tcp(127.0.0.1:3306)/")
defer db.Close()
...
结束语
一站式企业数字化平台 Erda,目前已服务过 50+ 大中型头部企业并完成交付,行业覆盖了零售、地产、园区、金融、建筑等领域。
沉淀了不少解决方案,未来也仍有一些需要改进的地方,比如支撑企业完成各种容灾方案:异地多活、两地三中心等,集群隧道高可用、安全等问题。
同时 Erda 拥有一个非常开放的社区:
GitHub 地址→https://github.com/erda-project/erda
欢迎广大的开源爱好者和用户加入共同建设,如果你有任何问题,欢迎进群交流!添加下面小助手的微信,即可进群。
👆小助手的微信👆
在混合云的时代下,以应用为中心的多集群架构,也是发展的必然趋势。未来企业的云可以运行在任何地方,交给 Erda 来帮你管理。让我们一起拥抱云原生,一起关注应用本身的价值!
GitHub 地址:https://github.com/erda-project/erda 官网:https://www.erda.cloud/