安畅SmartOps混合云平台架构的演进之道

前言

2021年,“十四五规划纲要草案”提出“加快数字发展,建设数字中国”,云计算不仅是“新基建”中的新型基础设施,更是数字化场景的重要基座,为上层智能应用加速落地提供了重要保障。因此,积极采用云上数字化战略已成为越来越多企业转型的核心。云上数字化转型往往涉及到多个方面,如架构现代化、应用现代化、云原生安全等诸多领域。今天就让我们通过安畅SmartOps混合云管理平台自身的架构现代化实践,来了解企业如何规划并构建云上现代化架构。

关于SmartOps:

安畅SmartOps是一款SaaS模式的云管理平台,通过统一视角实现多云资源纳管,权限分配、通过监控、费用分析帮你更合理的管控费用支出,加上强大的审计、工单、运维自动化等功能帮助你更高效的管理云资源。

一、SmartOps如何从微服务架构演进到云原生架构

云时代企业需要更完善的技术架构帮助自身应用获得更好的敏捷性、用户体验与更低的成本,而这些正好就是云原生架构专注解决的技术点。

SmartOps随着平台支撑客户的增长,在安全、性能、稳定性等方面都提出了更高的要求。为适应业务发展诉求,架构也需进行迭代升级。原始基于Spring Cloud全家桶的微服务架构,也在逐渐演进为基础设施下沉的云原生架构,充分让应用生于云、长于云,削减技术债务并且专注业务创新。

下图为SmartOps架构全景:

  • 接入层:通过WAF/SLB,配合NAT网关治理出方向流量,部署堡垒机进行运维等,或使用其他辅助业务进行支撑;

  • 应用层:采用腾讯TKE进行业务容器部署,配合K8s原生服务注册发现/配置中心/分布式调度中心/日志/监控/告警/链路追踪/DevOps等构筑完整应用体系;

  • 数据层:存储使用有云硬盘/对象存储/CFS,数据库有MongoDB分片集群/MySQL/Redis/ElasticSearch/RabbitMQ进行各类业务数据计算和存储。

二、SmartOps流量管控全景

2.1 南北流量

业务流量:业务流量入口最外层经过WAF进行安全防护,之后进入到公有云公网负载均衡,然后到TKE集群的NodePort实现流量接入;出口通过NAT网关实现流量分发。其他服务:其他支撑服务,如堡垒机,日志、监控等其他应用web通过堡垒机配合弹性公网IP/NAT网关实现流量接入与分发。

2.2 东西流量

在容器集群内,服务通过Kubernetes API-Server获取后端一组Service Pod真实IP,业务POD通过Calico网络进行POD与POD直接流量通讯。

三、SmartOps安全管控全景

3.1 SmartOps安全全景

  • 全场景的安全架构规划:从网络边界、内部网络、各类基础设施、数据、业务应用到后期监控响应,在各层面均进行安全管控设计,实现全方位立体式防护;

  • 云安全产品防护:借助SaaS安全产品实现安全体检(漏洞扫描、挂马检测、网站后门检测、端口安全检测等)与安全防御(DDoS 防护、入侵检测、访问控制来保证数据安全与用户隐私)以及安全监控与审计,形成事前、事中、事后的全过程防护;

  • 业界主流安全工具平台赋能,如:

    KubeLinter/Kubescape/Nessus/Sonarqube/AppScan等,严格把控平台从设计、开发、测试、部署、上线、运维等各流程安全,将SecDevOps贯彻在平台生命周期中,确保平台的安全性;

  • 安全认证可信:SmartOps已获得三级等保认证,并且通过MSS服务(Managed Security Service,安全托管服务)持续对SmartOps进行日常安全运维。

3.2 SmartOps分层安全架构

  • 接入层:守护边界网络安全,对业务流量及运维支持流量进行安全防护;

  • 应用层:平台采用安全框架,并严格遵守SDLC,将SecDevOps安全最佳实践应用在全生命周期;

  • 运维层:进行MSS持续性运维,对应用无论从外部探测到分布式链路,均进行安全可观测性实施;

  • 云平台层:利用云平台提供安全产品及能力,践行云平台安全最佳实践,保护云上资源及运维安全;

  • K8s层:利用K8s内置安全机制,配合业界主流安全工具平台进行安全检测,及时快速反馈;

  • 容器层:凭借公有云镜像安全能力,同时配合业界镜像安全扫描工具,确保镜像分层可信;

  • 数据层:通过业务逻辑数据加密及各云基础设施高可用部署,同时进行业务数据备份恢复和安全审计;

  • 系统层:通过对云服务器进行系统安全加固、漏洞补丁管理,确保系统安全。

四、从DevOps到SecDevOps的演进

4.1 DevOps V1.0

起初DevOps使用Gitlab CI进行管控。

  • CI/CD:各业务代码仓库保护.gitlab.yml,利用Gitlab CI进行CI和CD过程;

  • 镜像管理:构建出来的镜像使用镜像仓库Harbor进行管理;

  • 容器编排:在CD过程中,利用kubectl set image进行容器编排部署,自建Kubernetes集群进行业务容器编排管理;

  • 高可用:当某个节点出现故障时,Kubernetes 会自动创建一个新的GitLab-Runner 容器,并挂载同样的Runner 配置,使服务达到高可用;

  • 弹性伸缩:触发式任务执行会最大程度利用资源,每次运行脚本任务时Gitlab-Runner会自动创建一个或多个新的临时 Runner来运行Job;

  • 资源最大化利用:动态创建Pod运行Job,资源自动释放,而且 Kubernetes 会根据每个节点资源的使用情况,动态分配临时Runner 到空闲的节点上创建,降低出现因某节点资源利用率高还排队等待在该节点的情况;

  • 扩展性好:当 Kubernetes 集群的资源严重不足而导致临时Runner 排队等待时,可以很容易的添加一个 Kubernetes Node到集群中,从而实现横向扩展。

利用Gitlab CI 共享模块库,可最大程度实现CI代码复用性。

4.2 DevOps V1.1

在原始CI/CD流程中缺乏安全方面全场景检测,在代码、镜像、环境配置等场景均存在各类安全风险,因此必须实行安全左移。主要从以下五个阶段实现在安全全场景建设:

第一阶段:威胁建模(场景分析)梳理并绘制软件生命周期可能引发安全问题的场景;梳理平台架构存在安全风险的部件以及敏感数据的流向,帮助全员建立安全模型并提升团队安全意识;

第二阶段:通过安全扫描(DevOps集成安全)评估代码安全风险,确保不存在安全漏洞。此处包括手动和自动代码审查。在此步骤中,使用了 lint 和 scan 等AppSec 工具。由于处于软件开发生命周期的早期,此阶段允许工程师解决大多数安全漏洞和缺陷;

第三阶段:针对工具检测出来的安全风险问题以可视化的方式呈现并进行周期性通知,让全员知道安全问题;

第四阶段:进入补救修复阶段,通过sonarqueb代码管理工具可以针对发现的漏洞、缺陷提出修复建议,这样的操作是为了在出现安全问题时更容易处理它们;

第五阶段:进入监控阶段,跟踪监控发现的漏洞,努力减轻或消除他们,并对应用程序进行安全评估。通过跟踪和管理风险,在软件生命周期中作出决策对安全风险进行持续性安全实施。

4.3 SecDevOps V1.2

  • 开发阶段:从安全意识培训、安全编码、代码静态扫描到最后进行提交代码Code Review,将安全左移到研发全流程中(安全性已成为软件生命周期不可分割的一部分,所以进一步向左转移安全性,SecDevOps而非DevSecOps);

  • CI/CD:通过Gitlab+Drone CI+Argo CD进行持续集成持续部署,其中代码单元测试可以利用代码及配置检测工具进行代码扫描,实现合规检测;

  • 制品管理:利用镜像安全工具对制品镜像进行分层安全分析及漏洞安全扫描,确保镜像layer安全可控;

  • 容器管理:利用kube-bench/kubeEye/kube-eventer等对容器集群、业务容器进行合规检测与异常事件告警;

  • 业务管理:进行持续性MSS运维,利用Nessus/Acunetix/AppScan等业务系统进行安全漏洞扫描以及持续性安全运维。

上图为CI/CD WorkFlow,在CI最后一步通过Trigger触发CD Action,进行配置部署仓库修改、Argo CD检测到配置的修改以及最新资源的部署。

利用基于 Kubernetes 的声明式 Gitops 持续部署工具Drone CI + Argo CD,可以更便捷地进行应用定义、环境配置和变量管理。代码及配置资源声明清单也都存储在代码仓库受版本管理,使得应用发布及生命周期管理实现自动化且具备可审计性。

在SecDevOps中没有永远的安全。我们只需专注于解决核心安全问题,预测安全风险,尽可能降低安全隐患,并且在流程中贯彻安全意识,借助安全工具尽可能降低安全风险并持续优化。

安全是为了业务保驾护航及降低后期安全技术债务,而不是阻碍研发效能的提升,因此开发团队应遵守安全措施集成到开发过程中,不是完成开发后再去检测修复。安全与效能应该紧密结合,同进发展。

五、基于云原生架构的SmartOps

5.1 API网关

在微服务架构中,API网关负责各类应用请求路由、API组合和协议转换,同时一些API网关也负责验证、鉴权、负载均衡、协议转换、数据缓存等,其中框架网关有Netflix Zuul、Spring Cloud Gateway,云原生网关有Ingress-Treafik/Nginx/APISIX、Kong、Istio、Linkerd等。在SmartOps微服务架构中采用Spring Cloud Gateway作为API网关方案,部分认证鉴权使用Spring Cloud Gateway完成,因此需配合云上LB进行流量接入。

关于K8s流量接入可以参考:《Kubernetes 集群中流量暴露的几种方案》

通过使用LB + NodePort + Spring Gateway方案,结合公有云七层负载均衡,可以实现一个域名端口对应多个 Service,如图可以根据 path 路径,/cmp 对应 NodePort 的 32111,/gateway 对应 NodePort 的 32000 端口,不仅可以实现高可用还可以实现SSL卸载。

  • LB:使用公有云的七层负载均衡可以实现根据域名流量转发和负载均衡,与SSL的卸载功能;

  • NodePort:利用TKE负载均衡的NodePort实现从LB流量转发到K8s集群内部,实现流量接入;

  • Spring Gateway:使用Spring Gateway作为API网关入口,进行认证和鉴权及南北流量服务请求的转发。

5.2 服务注册发现的演进

我们针对SmartOps服务注册发现中心进行演进升级,由原始Spring Cloud Consul方式演进为Spring Cloud Kubernetes方式,并直接利用Kubernetes内部服务注册发现底层能力。

5.2.1 通用服务注册发现

在微服务架构中,由于服务众多且单个服务具有多个实例同时部署在Kubernetes集群中,实例的IP地址是可能随时变化的,需针对该情况对服务调用进行集中统一管理,因此我们引入服务注册发现机制。

服务注册和发现的意思是指服务进程在注册中心注册自己的位置,客户端应用进程向注册中心发起查询来获取服务的位置,服务发现的一个重要作用就是提供一个可用的服务列表。通过统一集中化管理使得服务直接仅通过服务名称即可调用,无需知道具体实例的IP地址。

5.2.2 Spring Cloud Consul

在Spring Cloud Consul服务注册发现方案中,各微服务注册到Consul Server上,服务间调用从Consul获取其他应用信息实现服务发现,在客户端发起对目标端请求中,客户端使用包括Ribbon和Spring Cloud LoadBalancer等实现负载均衡:

使用方式比较简单,引入依赖及配置相关信息:

引入依赖

<dependency>

<groupId>org.springframework.cloud</groupId>

<artifactId>spring-cloud-starter-consul-discovery</artifactId>

</dependency>

配置Consul信息:

Consul配置

server:

  port: 8206

spring:

  application:

    name: consul-user-service

  cloud:

    consul: #Consul服务注册发现配置

      host: localhost

      port: 8500

      discovery:

        service-name: ${spring.application.name}

在该架构中,业务遇到过以下挑战:

 1.Consul Cluster需要采用高可用部署,该组建需要投入额外成本进行维护。

 2.业务部署在Kubernetes集群内,需以DaemonSet方式部署Consul Client至每个业务Node,当Node出现故障宕机会出现应用注册脏数据,这些需手动处理,易造成业务请求异常。

5.2.3 Kubernetes Service方式

5.2.3.1 Kubernetes服务注册发现

利用云原生实现服务注册发现,需先理解Kubernetes中Service自动注册DNS过程:

1. 向API Server 用 POST 方式提交一个新的Service 定义;

2. 这个请求需要经过认证、鉴权以及其它的准入策略检查之后才会放行;

3. Service 得到一个 ClusterIP(虚拟 IP 地址)并保存到集群数据仓库;

4. 在集群范围内传播 Service 配置;

5. 集群DNS 服务得知该 Service 的创建,据此创建必要的DNS A 记录。

总体来说,Kubernetes的服务注册与发现主要通过Etcd+CoreDNS来实现,其中又包含了endpoints/kube-proxy等组件的协同。

5.2.3.2 Spring Boot+K8s Service服务注册发现方案

方案简介:使用 K8s 原生Service/Endpoints/Coredns/Etcd等内置资源对象和相关服务组建实现服务注册发现过程,服务注册和服务发现均通过内置Service对象完成,借助K8s Service的负载均衡能力可减少额外部署和维护服务注册发现中心成本,针对高级流量治理功能需要借助其他服务治理框架实现。

服务注册:Spring Boot 应用配置提供service服务,启动后k8s集群针对调用该service,后端会返回具体的pod列表。

服务发现:在同一名称空间,直接使用service信息发起调用。

方案特点:

优势:负载均衡算法在服务端实现(service 的原生负载均衡算法),后期可使用服务治理框架,例如istio/linkerd进行服务治理。

不足:服务直接通过k8s服务发现,经过service一层在宿主机请求通过iptables/ipvs转发一层,性能稍弱。

5.2.4 Spring Cloud Kubernetes方式

5.2.4.1 通用方案

Spring Cloud Kubernetes 服务注册发现:

服务注册通过Spring Cloud应用的service资源对象进行注册,服务发现通过项目引入Spring-cloud-kubernetes-discovery的jar包,利用Kubernetes-client与API-server进行Rest调用获取Service后端关联的Endpoints信息,通过spring cloud openFeign完成服务间的通信,Spring Cloud ribbon实现负载均衡。采用如上几个模块,可以在k8s的环境下实现重试、超时、限流、负载均衡等常用功能。

5.2.4.2 Spring Cloud Kubernetes 服务注册发现-东西流量

Spring Cloud Kubernetes 服务注册发现-东西流量:

方案简介:使用Kubernetes原生service/endpoints/coredns/etcd组建实现服务注册过程,服务发现通过Spring Cloud Kubernetes调用Kubernetes API-server获取后端服务Pod的IP/Port,利用openFeign完成服务间调用并且利用ribbon可实现客户端负载均衡。

服务注册:Spring Cloud应用配置有service的服务,启动后k8s集群针对调用该service,后端会返回具体的pod列表。

服务发现:通过Spring Cloud Kubernetes调用Kubernetes API-server获取后端服务Pod的IP/Port。

方案特点:

优势:服务直接通过k8s服务发现,获取service后的实例POD IP和端口,流量直接对POD发起,不经过service转发,性能高;

不足:负载均衡在调用端(客户端)实现,例如ribbon,后期服务治理框架如Istio/Linkerd可能需改造。

5.2.4.3 Spring Cloud Kubernetes 服务注册发现-南北流量

Spring Cloud Kubernetes 服务注册发现-南北流量:

方案简介:使用Kubernetes原生service/endpoints/coredns/etcd组建实现服务注册过程,Springboot Gateway 使用Spring Cloud Kubernetes 与api Server的http交互,获取后端 服务 Services / Endpoints,完成服务请求转发。

服务注册:Spring Cloud应用配置有service的服务,启动后k8s集群针对调用该service,后端会返回具体的pod列表。

服务发现:服务发现通过Spring Cloud Kubernetes调用Kubernetes API-server获取后端服务Pod的IP/Port,Gateway进行请求转发。

方案特点:

优势:Gateway服务通过k8s服务发现,获取service后的实例POD IP和PORT,从而发起针对POD调用,该请求不经过Service转发,性能较高;

不足:负载均衡在调用端(客户端)实现,例如ribbon,后期服务治理框架如Istio/Linkerd可能需改造。

5.3 配置中心

传统的静态配置方式要想修改某个配置只能修改之后重新发布应用。如实现动态性,可以选择使用数据库通过定时轮询访问数据库来感知配置的变化。轮询频率低感知配置变化的延时长,轮询频率高感知配置变化的延时短,比较损耗性能,需要在实时性和性能之间做折中。配置中心专门针对这个业务场景,兼顾实时性和一致性来管理动态配置。

SmartOps原始配置中心为Spring Cloud Config方案,需要考虑以下问题:

  • 需要独立在K8s中部署Config服务;

  • 需要考虑Config服务的高可用性;

  • 由于Config服务需要链接私网git repo,需考虑安全问题与网络互通问题。

以下列出了一些其他配置中心的功能点对比:

演进方向:由于业务在Kubernetes上,所以应尽可能利用K8s原生配置管理能力,将配置中心不可控性托付给K8s,使用K8s原生configmap和secret资源无需考虑单独部署配置中心,不用引入新服务。如果configmap/secret发生变更,服务能及时监控到这一变化从而按照配置更新策略进行动态更新或者服务重启,如下选用Spring Cloud Kubernetes配置中心示意图:

Spring Cloud Kubernetes 配置中心方案简介:spring-cloud-starter-kubernetes-config是spring-cloud-starter-kubernetes下的一个库,作用是将kubernetes的configmap与SpringCloud Config结合起来。Spring-boot-actuator/spring-boot-actuator-autoconfigure 两个包的引入,使得应用可以进行热更新,当configmap/secret发生变更的时候,可以不重启Pod或进程进行热变更配置。

方案特点:

优势:使用K8s内置配置资源,无需再次引入第三次配置中心服务,也不用考虑引入的配置中心服务高可用部署,在云原生架构架构中,配置中心下沉至基础设施层,既解耦配置与代码还极大的减少了配置服务本身的维护成本。

不足:dev/test 环境也需要上K8s,为了确保环境一致性, 需要将配置资源configmap/secret引入到GitOps流程中。

利用云原生配置管理,安全性问题Secret存储了相对敏感的信息,需结合其他工具或解决方案解决,例如后期可以配合Vault 或者Sealed Secrets解决K8s配置安全性问题,针对热更新可利用reloader或其他方案解决。

5.4 分布式任务调度

在平台中存在大量定时任务,而且很多服务任务实现方式不一致,一旦遇到问题排错成本高、很难统一管控。针对此困境,我们需进行集中化分布式任务调度平台改造,选用轻量级xxl-job中心式的调度平台,不仅开箱即用,而且操作简易、上手快,与SpringBoot有非常好的集成且监控界面就集成在调度中心、界面也非常简洁。选取xxl-job做调度平台,承担的调度中心职责有:1)负责管理调度信息,按照调度配置发出调度请求,自身不承担业务代码。2)支持可视化界面,可以在调度中心对任务进行新增、更新、删除,会实时生效。3)支持监控调度结果,查看执行日志,查看调度任务统计报表,任务失败告警等等。4)执行器:负责接收调度请求,执行调度任务的业务逻辑。执行器启动后需要注册到调度中心,接收调度中心发出的执行请求、终止请求、日志请求等等。

  • 同一个服务多个实例的任务存在互斥时,需要统一的调度;

  • 任务调度需要支持高可用、监控、故障告警;

  • 需要统一管理和追踪各个服务节点任务调度的结果,需要记录保存任务属性信息等。

利用其高可用部署在Kubernetes集群中,实现分布式任务调度集中管控,可大幅降低开发成本并且提升研发效能,极大程度解决后台任务难管控的问题。

六、SmartOps架构可观测性建设

6.1 Logging

之前SmartOps采用Graylog 日志监控方案,在代码内部引入日志采集jar包,将日志数据收集在graylog server端。目前graylog server部署在K8s集群内,而Graylog server使用MongoDB和ES,由于ES和MongoDB占用K8s集群资源,这存在一定问题,本次改造目标为:

  • 日志服务下沉到基础设施层与业务低耦合,业务人员仅需关注自身业务;

  • 日志服务无侵入业务代码;

  • 开发服务适配多语言;

  • 不占用过多K8s资源;

  • 打造易维护、扩展性更强的日志监控方案。

业务日志遵循一定规范,如将日志输出到stdout/stderr,在Node上以Ds方式部署日志采集Pod,针对打印到控制台日志进行查看分析。

6.2 Tracing

分布式链路使用了链路追踪的 API 规范,支持多种编程语言,与平台、厂商无关,使得开发人员能够方便地添加或更换链路跟踪系统的实现,虽然OpenTracing不是一个标准规范,但现在大多数链路跟踪系统都在尽量兼容OpenTracing。目前业界主流API标准的就有 SkyWalking、Jaeger、Zipkin、Open Telemetry、 Pinpoint、CAT等。

SmartOps由于内部服务特殊性,目前选用业界主流Skywalking作为APM系统服务链路追踪进行日常服务定位及排错。在追踪系统,平台更关注请求的质量和服务可行性,利用其优化系统排查问题。

6.3 Metrics

在Metrics方面,主要利用云平台告警结合Prometheus+Grafana的方式实现,并配合外部站点探测实现全场景平台Metrics指标分析及告警,配合高可用架构及云原生故障自愈能力能最大程度保障系统SLA。

日志系统、度量系统、追踪系统这三个纬度所关注的重点不同,日志系统用于记录应用或系统事件,日志也是排查问题和取证的主要依据;度量系统更多关注事件聚合,当达到设置告警,关于进行系统状态的反馈及后续的自适应策略;APM系统帮助我们更深入全面了解环境、可视化整个应用程序和基础架构堆栈,应用场景丰富并且提供全链路追踪。

七、未来方向

7.1 云原生最佳实践原则落实

  • 服务化原则:使用微服务架构,服务内功能高度内聚,模块间通过公共功能提取增加软件复用程度,从架构层面抽象化业务模块关系,标准化服务流量传输,帮助业务模块基于服务流量的策略控制与治理;

  • 弹性原则:系统的部署规模可以随着业务量的变化自动伸缩,无须根据事先的容量规划准备固定的硬件和软件资源,而且可以动态扩容,降低企业IT成本;

  • 可观测原则:在云分布式系统中,主动通过日志、链路跟踪和度量等手段,让每次业务请求获悉背后服务的调用耗时、返回值,下钻到每次第三方软件调用、SQL请求、节点拓扑、网络响应,使运维、开发和业务人员实时掌握系统情况;

  • 所有过程自动化原则:通过 IaC(Infrastructure as Code)、GitOps、OAM(Open Application Model)、Kubernetes operator 和大量自动化交付工具在 CI/CD 流水线中的实践,一方面标准化企业内部的软件交付过程,另一方面在标准化的基础上进行自动化,通过配置数据自描述和面向终态的交付过程,让自动化工具理解交付目标和环境差异,实现整个软件交付和运维的自动化;

  • 零信任原则:零信任对访问控制进行了范式上的颠覆,引导安全体系架构从“网络中心化”走向“身份中心化”,其本质诉求是以身份为中心进行访问控制;

  • 架构持续演进原则:云原生架构本身应该是一个具备持续演进能力的架构,而不是一个封闭式架构,在演进过程中需注意对新建应用架构控制策略及对遗留系统迁移改造成本考虑及风险评估。

7.2 行业赋能

目前,安畅SmartOps混合云管平台已沉淀众多行业客户,在稳定、安全、实用方面赋能不同领域用户进行现代化云上管控:

  • 在互联网行业,SmartOps可以颠覆传统的基础设施及运维模式,带来了可编排、极速全局管控、自服务运维的能力;

  • 在教育行业,借助SmartOps的资源纳管能力和资源抽象能力,助力高校填补公有云技术迭代与高校技术管理人员技能间的鸿沟,打破院级/科系数据孤岛,面向高校用户提供统一的服务目录;

  • 在政务行业,SmartOps支持国产化部署,满足基础设施自主可控,以平台的实时统一监管、宏观调度、审计等能力,帮助客户降低成本和运维压力,实现不同部门统一规范,推动跨部门业务协同;

  • 在工业领域,基于SmartOps预算管理、资源交付、资源运营能力,大幅提升资源的交付效率及资源使用率,从而降低项目成本。

7.3 架构演进策略

近年来商业世界的发展趋势,数字化转型的出现使得企业越来越多业务演变成数字化业务,数字化对于业务渠道、竞争格局、用户体验等诸多方面都带来更加严苛的要求,这就要求技术具备更快的迭代速度。架构的演进不是一蹴而就,而是不同时期为了更好的支撑业务发展进行适配发展的行为,为了技术而进行不合适的过度架构设计是不负责任的行为,将业务与架构共同朝着既定目标共同成长才是最佳策略。如果您企业的数字化转型之旅需要一位专业的伙伴,那拥有海量云上最佳实践的安畅或许是您最好的选择!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值