负载均衡与云原生服务自动部署实践
概览
百度智能云的云原生产品,称为CCE(Cloud Container Engine,云平台容器引擎)。CCE是高度可扩展的高性能容器管理服务,租户只需通过简单的OpenAPI调用即可在托管的云服务器集群上轻松运行应用程序。下面将以百度智能云网络负载均衡、CCE、EIP等产品为例,演示如何实现负载均衡与云原生服务的快速部署与启动。在演示开始前,需要参考官网文档,准备以下环境与配置。 (1)Go 1.3及以上的软件环境。
(2)安装Go SDK工具包。
(3)安装Client-Go及相关包。
(4)获取Access Key和Secret Key以进行身份认证。
部署架构,如下图所示。架构中采用EIP作为Internet公网访问的入口,通过将EIP绑定至负载均衡实例实现公网请求分发。通过CCE提供云服务快速部署、扩展与监控能力。

负载均衡与云原生服务自动部署实践
1.CCE设置
在百度智能云创建CCE时,需要针对以下参数进行设置。
1)付费方式
在创建CCE前,开发者需要确定资源的计费方式和所在地域。CCE本身不产生费用,但是其关联的计算资源和服务,例如BCC(Baidu Cloud Compute,百度云计算)、BLB、EIP等均需付费使用。百度智能云支持的付费方式分为两种:包年包月和按量付费。购买包年包月服务属于预付费(PrePaid)类型,即在新建资源时支付费用;按使用量付费属于后付费(PostPaid)类型。各资源的后付费计费因素,如下表所示。
| 资源类型 | 计费因素 | 
|---|---|
| BCC | 机型配置,如CPU、内存、物理存储等 | 
| BLB | 实例类型,如普通实例、应用实例、IPv6实例 | 
| EIP | 公网带宽、公网流量 | 
本示例中,采用按使用量付费方案,相关代码如下所示。
1import "github.com/baidubce/bce-sdk-go/services/bcc/api"
2
3// 后付费类型
4InstanceChargingType: api.PaymentTimingPostPaid 
            2)集群Master设置
CCE支持两类K8s集群托管方式:标准托管集群和标准独立集群。标准托管集群的Master由CCE完全托管,开发者只需要购买工作节点运行工作负载即可。标准独立集群则需要开发者自行控制集群Master完成服务器集群的规划、维护、升级等。本示例中使用标准托管集群,利用CCE管理集群Master,相关代码如下所示。
1import "github.com/baidubce/bce-sdk-go/services/cce/v2/types"
2
3// 集群Master类型设置
4MasterType: types.MasterTypeManaged,
5// Master工作节点数量,控制台默认数量为3或5,通过SDK可以设置为1
6ClusterHA: 1,
7// 为API Server自动绑定EIP以利用公网进行连接
8ExposedPublic: true,
            3)K8s版本
K8s版本由客户的需求决定,若无特殊需求,则开发者可以根据情况自行选择。需要注意的是,后续Client-Go版本应与此处CCE中的K8s版本对应,对应规则较为直观:在K8s版本≥1.7.0的情况下,若K8s版本为1.X.Y,那么Client-Go版本应为v0.X.Y。本示例中选择K8s版本为1.28.8,使用的Client-Go版本则为0.28.8,相关代码如下所示。
1// K8s版本设置
2K8SVersion: "1.28.8" 
            4)集群规模
默认的集群规模为L50,最多支持管理50个集群中的节点(Node),1500个Pod。本示例中选择默认配置。
5)容器运行时
容器运行时(Container Runtime)是K8s的重要组件之一,负责管理镜像和容器的生命周期。CCE支持使用Containerd和Docker两种常见的容器运行时。Containerd与Docker相比,具有调用链更短、组件更少、更稳定、占用节点的资源更少的特点。因此,本示例使用Containerd作为容器运行时。创建CCE的容器运行时选项,如下图所示。

容器运行时设置,相关代码如下所示。
1import "github.com/baidubce/bce-sdk-go/services/cce/v2/types"
2
3// 容器运行时设置为Containerd
4RuntimeType: types.RuntimeTypeContainerd
            6)节点名称
开发者可以选择用内网IP或主机名称作为节点名称。在节点加入集群后将不能修改节点名称,默认情况下使用内网IP作为节点名称。本示例中选择默认设置。
7)子网划分
子网划分涉及到APIServer、Master、Node、BLB间的通信,错误的配置可能引发CCE创建失败、服务配置受阻及服务不可用等意外情况。在配置中,CCE中所有的设备都应该处于同一VPC下,按功能划分为APIServer子网、BLB Service子网、Node子网,其中APIServer子网和BLB Service子网可以使用同一子网,但不能与Node子网冲突。另外,还需在内部地址中配置容器网段和ClusterIP网段,这两个网段不能与任何网段冲突。子网划分如下表所示。
| 子网名称 | SDK参数 | 配置 | 
|---|---|---|
| 集群网络 | VPCID | 192.168.0.0/16 | 
| APIServer子网 | ClusterBLBVPCSubnetID | 192.168.16.0/20 | 
| BLB Service子网 | LBServiceVPCSubnetID | 192.168.16.0/20 | 
| 容器网段 | ClusterPodCIDR | 172.28.0.0/16 | 
| ClusterIP 网段 | ClusterIPServiceCIDR | 172.31.0.0/16 | 
子网可以在百度智能云VPC产品中创建,创建VPC的详细过程可参考“私有网络VPC-操作指南-VPC”,相关代码如下所示。
1import "github.com/baidubce/bce-sdk-go/services/cce/v2/types"
2
3// VPC设定,填写自己创建的VPCID
4VPCID: "vpc-********",
5// API Server子网网段设置,填写上述VPC下的子网ID
6ClusterBLBVPCSubnetID: "sbn-********",
7// LB Service子网网段设置,填写上述VPC下的子网ID
8LBServiceVPCSubnetID: "sbn-********",
9// 容器网段设置,填写任意不冲突的内网网段
10ClusterPodCIDR: "172.28.0.0/16",
11// Cluster内部在Pod和Node间进行中继的虚拟IP地址,填写任意不冲突的内网网段
12ClusterIPServiceCIDR: "172.31.0.0/16",
            8)容器网络模式
CCE支持两种容器网络模式:VPC路由模式和VPC-ENI模式。VPC路由模式下的网络拓扑,如下图所示。

在VPC路由模式下,集群内Pod与Node处于两个网段,通过VPC路由将跨Node的Pod互相连接,配合百度智能云VPC产品的高速网络,可以给集群提供高性能和高稳定性的容器网络服务。VPC-ENI模式下的网络拓扑,如下图所示。集群内Pod与Node的IP地址均来自同一VPC,因此Pod能够复用百度智能云VPC产品所有特性。但由于弹性网卡辅助IP数量的限制,因此单个Node上可以创建的Pod有数量限制。
本示例中选择VPC路由模式。容器网络模式设置为VPC路由的相关代码如下所示。
1import "github.com/baidubce/bce-sdk-go/services/cce/v2/types"
2
3// 容器网络模式设置为VPC路由
4Mode: types.ContainerNetworkModeVPCRouteVeth,
            9)Kube-Proxy模式
容器引擎CCE支持IPVS与iptables两种方案在K8s集群中实现服务发现与负载均衡。其中,iptables方案成熟稳定但性能较低;IPVS方案性能较好,适用于集群存在大量Service、对负载均衡有较高性能要求的场景。本示例使用IPVS模式进行代理,相关代码如下所示。
1import "github.com/baidubce/bce-sdk-go/services/cce/v2/types"
2
3// Kube-Proxy模式设置为IPVS
4KubeProxyMode: types.KubeProxyModeIPVS,
            10)CCE详细配置
上面介绍了创建一个CCE所必需参数配置,通过Go-SDK编写完整的配置,相关代码如下所示。
1import (
2	ccev2 "github.com/baidubce/bce-sdk-go/services/cce/v2"
3	"github.com/baidubce/bce-sdk-go/services/cce/v2/types"
4	"github.com/baidubce/bce-sdk-go/services/bcc/api"
5)
6
7// 新建创建集群的参数
8args := &ccev2.CreateClusterArgs{
9		CreateClusterRequest: &ccev2.CreateClusterRequest{
10			ClusterSpec: &types.ClusterSpec{
11			ClusterName: "aCluster", 
12			K8SVersion: "1.28.8", 
13			RuntimeType: types.RuntimeTypeContainerd,
14			VPCID: "vpc-********", 
15			MasterConfig: types.MasterConfig{
16				MasterType: types.MasterTypeManaged,
17				ClusterHA: 1,
18				ExposedPublic: true,
19				ClusterBLBVPCSubnetID: "sbn-********",
20			},
21			ContainerNetworkConfig: types.ContainerNetworkConfig{
22				Mode: types.ContainerNetworkModeVPCRouteVeth,
23				LBServiceVPCSubnetID: "sbn-********",
24				ClusterPodCIDR: "172.28.0.0/16",
25				ClusterIPServiceCIDR: "172.31.0.0/16",
26				KubeProxyMode: types.KubeProxyModeIPVS,
27				NodePortRangeMin: 30000,
28				NodePortRangeMax: 32767,
29			},
30		  },
31		},
32	  }
            2.云服务器BCC设置
开发者在创建CCE时可以使用已有云服务器BCC,也可以联动创建新的BCC实例作为CCE节点。在示例中创建BCC所需的参数设置如下。
1)Node子网
Node子网是节点间通信的网段,需要设定在CCE集群所在VPC下。本示例在VPC网段192.168.0.0/16基础下新建Node子网nodeSubnet,网段为192.168.32.0/20。相关代码如下所示。
1// 指定Node所属的VPC,需要和CCE在同一VPC下
2VPCID: "vpc-********",
3// 指定Node所属的子网ID,应为上面VPC的一个子网
4VPCSubnetID: "sbn-********",
            2)Node资源
云服务器BCC提供不同的实例规格,以适应租户不同的业务场景。实例规格由CPU、内存、存储、异构硬件和网络带宽组成不同的组合。开发者可以根据用户流量和服务计算负载选择所需的BCC机型。常用的Intel X86云服务器BCC实例按照使用场景可以分为5个类别。5种典型BCC实例的适用场景,如下表所示。
| 实例类型 | 典型实例 | 适用场景 | 
|---|---|---|
| 经济型实例 | 经济型e1 | 中小型网站建设,开发测试,轻量级应用 | 
| 通用型实例 | 通用型g5 | 各种类型和规模的企业级应用,数据分析和计算,中小型数据库系统、缓存、搜索集群,计算集群、依赖内存的数据处理 | 
| 计算型实例 | 计算型c5 | Web前端服务器,大型多人在线游戏(MMO)前端,数据分析、批量计算、视频编码,高性能科学和工程应用 | 
| 内存型实例 | 内存型m5 | 高性能数据库、内存数据库,数据分析与挖掘、分布式内存缓存,Hadoop、Spark群集以及其他企业大内存需求应用 | 
| 本地SSD型实例 | 本地SSD型I5 | OLTP、高性能关系型数据库,NoSQL数据库(如Cassandra、MongoDB等),Elasticsearch等搜索场景 | 
本示例选用通用型实例,规格为bcc.g5.c2m8的机型进行部署,其具有2核CPU、8GB内存。BCC机型选定后,需要为BCC申请系统盘存储资源。目前可选的存储资源类型包括:通用型HDD、高性能云磁盘、通用型SSD、增强型SSD_PL1、增强型SSD_PL2。随机读写速度、吞吐量依次升高,访问时延依次降低。本示例选用40GB的增强型SSD_PL1作为BCC的系统盘,相关代码如下所示。
1import "github.com/baidubce/bce-sdk-go/services/cce/v2/types"
2
3// 实例资源设定
4InstanceResource: types.InstanceResource{
5				  CPU: 2,
6				  MEM: 8,
7				  RootDiskSize: 40,
8				  RootDiskType: "enhanced_ssd_pl1",
9				  LocalDiskSize: 0,
10				  CDSList: []types.CDSConfig{},
11				  MachineSpec: "bcc.g5.c2m8",
12				}
            3)Node镜像
为Node安装操作系统,开发者可以根据需求选择BaiduLinux、Centos、Ubuntu、Rocky Linux等操作系统镜像。本示例选择BaiduLinux 3.0 X86_64为操作系统镜像,相关代码如下所示。
1import (
2	"github.com/baidubce/bce-sdk-go/services/cce/v2/types"
3	"github.com/baidubce/bce-sdk-go/services/bcc/api"
4)
5
6// 利用镜像ID选择对应的镜像,此处为BaiduLinux
7ImageID: "7183****-3e24-464d-9c02-a73***",
8InstanceOS: types.InstanceOS{
9	ImageType: api.ImageTypeSystem, // 镜像的类型
10}
            4)其余Node配置
除了上述配置外,Node还需配置:是否自动申请弹性公网IP、管理员账户密码、SSH密钥、实例付费类型、容器运行时类型等,相关代码如下所示。
1import (
2    "github.com/baidubce/bce-sdk-go/services/cce/v2/types"
3    "github.com/baidubce/bce-sdk-go/services/bcc/api"
4)
5
6NeedEIP: false,                  // 是否需要EIP:否;CCE节点不需要绑定EIP
7AdminPassword: "Key******",     // 管理员账户密码
8SSHKeyID: "",                               // SSH密钥
9InstanceChargingType: api.PaymentTimingPostPaid, // 付费类型:后付费
10RuntimeType: types.RuntimeTypeContainerd,   // 容器运行时类型:Containerd运行时
            3.创建CCE及BCC实例
百度智能云在北京、广州、香港等多个地域设有数据中心,在使用SDK创建资源时需根据数据中心选择服务接入点。在创建实例之前需要配置Access Key、Secret Key、服务接入点等参数,相关代码如下所示。
1import (
2ccev2 "github.com/baidubce/bce-sdk-go/services/cce/v2"
3)
4accessKeyId, secretAccessKey := "Your AK", "Your SK"
5cceEndpoint := "https://cce.bj.baidubce.com"
6cceClient, err := ccev2.NewClient(accessKeyId, secretAccessKey, cceEndpoint)
7if err != nil {
8fmt.Println("create cce client failed, err:", err)
9}
            上述代码创建的cceClient是一个ccev2.Client类型的指针。接下来,通过cceClient创建CCE及与其联动的BCC实例,相关代码如下所示。具体参数设置见前文说明。
1// 联动创建CCE和BCC
2clusterArgs := &ccev2.CreateClusterArgs{
3		CreateClusterRequest: &ccev2.CreateClusterRequest{
4		  ClusterSpec: &types.ClusterSpec{
5			ClusterName: "aCluster",
6			K8SVersion: "1.28.8",
7			RuntimeType: types.RuntimeTypeContainerd,
8			VPCID: "vpc-********",
9			MasterConfig: types.MasterConfig{
10			  MasterType: types.MasterTypeManaged,
11			  ClusterHA: 1,
12			  ExposedPublic: true,
13			  ClusterBLBVPCSubnetID: "sbn-********",
14			},
15			ContainerNetworkConfig: types.ContainerNetworkConfig{
16			  Mode: types.ContainerNetworkModeVPCRouteVeth,
17			  LBServiceVPCSubnetID: "sbn-********",
18			  ClusterPodCIDR: "172.28.0.0/16",
19			  ClusterIPServiceCIDR: "172.31.0.0/16",
20			  KubeProxyMode: types.KubeProxyModeIPVS,
21			  NodePortRangeMin: 30000,
22			  NodePortRangeMax: 32767,
23			},
24		  },
25		  NodeSpecs: []*ccev2.InstanceSet{
26			{
27			  Count: 2,
28			  InstanceSpec: types.InstanceSpec{
29				InstanceName: "",
30				ClusterRole: types.ClusterRoleNode,
31				Existed: false,
32				MachineType: types.MachineTypeBCC,
33				InstanceType: "34",
34				VPCConfig: types.VPCConfig{
35				  VPCID: "vpc-********",
36				  VPCSubnetID: "sbn-********",
37				  SecurityGroupType: "normal",
38				  SecurityGroup: types.SecurityGroup{
39					CustomSecurityGroupIDs: []string{},
40					EnableCCERequiredSecurityGroup: true,
41					EnableCCEOptionalSecurityGroup: false,
42				  },
43				},
44				InstanceResource: types.InstanceResource{
45				  CPU: 2,
46				  MEM: 8,
47				  RootDiskSize: 40,
48				  RootDiskType: "enhanced_ssd_pl1",
49				  LocalDiskSize: 0,
50				  CDSList: []types.CDSConfig{},
51				  MachineSpec: "bcc.g5.c2m8",
52				},
53				ImageID: "7183****-3e24-464d-9c02-a73***",
54				InstanceOS: types.InstanceOS{
55				  ImageType: api.ImageTypeSystem,
56				},
57				NeedEIP: false,
58				AdminPassword: "Key*******",
59				SSHKeyID: "",
60				InstanceChargingType: api.PaymentTimingPostPaid,
61				RuntimeType: types.RuntimeTypeContainerd,
62			  },
63			},
64		  },
65		},
66	  }
67// 调用接口,利用args创建CCE和BCC
68respCreateCluster, err := ccev2Client.CreateCluster(args)
69if err != nil {
70    fmt.Println(err.Error())
71    return ""
72}
73// 从返回值中提取出ClusterID
74s, _ := json.MarshalIndent(respCreateCluster.ClusterID, "", "\t")
75fmt.Println("Creating CCE-Cluster, Cluster ID : "+ string(s))
76clusterID := string(s)[1:len(string(s))-1] // 得到的ID字符串会包含双引号,在此处去除双引号
            CCE实例列表页,如下图所示。如果出现了名为aCluster的CCE集群,则表示创建成功。点击集群名称查看详细内容,切换到Worker页面。

两个关联的Worker节点,如下图所示。可以看到设置中添加的两台BCC已创建成功。

4.创建负载均衡实例关联EIP
首先利用Deployment机制拉取容器镜像部署Nginx,然后以Service形式新建挂载了EIP的负载均衡实例,并与Nginx相关联。通过在创建CCE时返回的ClusterID,租户可以调用GetKubeConfig方法查询到可供Client-Go连接K8s集群的认证文件kubectl.conf,相关代码如下所示。
1configArgs := &ccev2.GetKubeConfigArgs{
2ClusterID: "cce-********",
3KubeConfigType: ccev2.KubeConfigTypePublic, // 类型选公网IP,否则外网连不上
4}
5
6// 提取指定CCE的K8s kubeconf文件内容
7respGetConfig, err1 := ccev2Client.GetKubeConfig(configArgs)
8if err1 != nil {
9fmt.Println(err1)
10}
11
12// 选取真正的conf文件内容,写入到本地
13configStr := respGetConfig.KubeConfig
14fileName := "kubectl.conf"
15filePtr, err := os.Create(fileName)
16if err != nil {
17fmt.Println(err)
18}
19_, err = io.WriteString(filePtr, testStr)
20if err != nil {
21fmt.Println(err)
22}
23// 接下来利用Client-Go和kubectl.conf连接K8s集群,得到配置接口clientSet。
24import (
25    "K8s.io/client-go/kubernetes"
26	"K8s.io/client-go/tools/clientcmd"
27)
28
29// 从kubectl.conf文件中提取所需的配置项config
30ccev2Config := "./kubectl.conf"
31config, err3 := clientcmd.BuildConfigFromFlags("", ccev2Config) // 从ccev2Config创建config文件
32if err3 != nil {
33fmt.Println(err3)
34}
35
36// 利用config连接K8s
37clientSet, err := kubernetes.NewForConfig(config) // 利用config文件连接K8s集群,得到clientSet
38if err != nil {
39fmt.Println(err)
40}
41// 通过clientSet创建一个Deployment,在容器中拉取Nginx镜像以部署网站服务。
42import (
43	appsv1 "K8s.io/api/apps/v1"
44	corev1 "K8s.io/api/core/v1"
45	resource "K8s.io/apimachinery/pkg/api/resource"
46	metav1 "K8s.io/apimachinery/pkg/apis/meta/v1"
47    )
48
49var podsNum int32 = 2
50
51deployArgs := &appsv1.Deployment{
52	ObjectMeta: metav1.ObjectMeta{
53		Name: "nginx-deployment", //服务名称
54		Namespace: "default", // 默认命名空间
55	},
56	Spec: appsv1.DeploymentSpec{
57		Replicas: &podsNum, // 副本数
58		Selector: &metav1.LabelSelector{
59			MatchLabels: map[string]string{
60				"app": "nginx", // 应用为nginx,需要与部署类型对应
61			},
62		},
63		Template: corev1.PodTemplateSpec{
64			ObjectMeta: metav1.ObjectMeta{
65				Labels: map[string]string{
66					"app": "nginx",
67				},
68			},
69			Spec: corev1.PodSpec{
70				Containers: []corev1.Container{
71					{
72						Name: "nginx", // 容器名称为nginx
73						Image: "hub.baidubce.com/cce/nginx-alpine-go:latest", // nginx容器镜像
74						Ports: []corev1.ContainerPort{
75							{
76								Name: "http", 
77								Protocol: corev1.ProtocolTCP,
78								ContainerPort: 80, // 端口号80
79							},
80						},
81						Resources: corev1.ResourceRequirements{
82							Limits: map[corev1.ResourceName]resource.Quantity{ // 每一个容器的资源设置
83								corev1.ResourceCPU: resource.MustParse("200m"), 
84								corev1.ResourceMemory: resource.MustParse("512Mi"),
85							},
86							Requests: map[corev1.ResourceName]resource.Quantity{
87								corev1.ResourceCPU: resource.MustParse("200m"),
88								corev1.ResourceMemory: resource.MustParse("512Mi"),
89							},
90						},
91					},
92				},
93			},
94		},
95	},
96}
97
98 // 创建一个Deployment任务,在容器中拉取nginx镜像。
99	resp, err := clientSet.AppsV1().Deployments("default").Create(context.Background(), deployment, metav1.CreateOptions{})
100	if err != nil {
101		fmt.Println(err)
102	}
103	fmt.Printf("Deployment created: %s\n", resp.GetObjectMeta().GetName())
            无状态部署页面,如下图所示。由于没有关联对外接口,不存在网络流量,所以CPU占用为0。
容器列表页面,如下图所示。在“CCE集群→查询工作负载→无状态部署”页面,看到刚才新建的“nginx-deployment”,且状态为“运行中”。

WebSSH页面,如下图所示。点击工作负载名称,可以在里面的选项页中查看相关的Pod;点击右侧的WebSSH,从一个Pod向另一个Pod使用curl命令发起HTTP请求。如果顺利返回Nginx页面,则说明Nginx部署成功。

为了使网站能够提供外网访问,需要在CCE下创建一个负载均衡实例并绑定EIP。操作可以通过clientSet创建负载均衡服务实现,相关代码如下所示。
1import (
2        corev1 "K8s.io/api/core/v1"
3        metav1 "K8s.io/apimachinery/pkg/apis/meta/v1"
4        "K8s.io/apimachinery/pkg/util/intstr"
5    )
6    
7svcArgs := &corev1.Service{
8	TypeMeta: metav1.TypeMeta{
9		Kind:       "Service", // 服务类型
10		APIVersion: "v1",
11	},
12	ObjectMeta: metav1.ObjectMeta{
13		Name: "test-service", // 服务名称
14	},
15	Spec: corev1.ServiceSpec{
16		Ports: []corev1.ServicePort{
17			{
18				Protocol:  "TCP", // TCP协议,用四层负载均衡
19				Port:      80, // 80端口转入
20				TargetPort: intstr.FromInt(80), // 80端口转出
21					},
22		},
23		Selector: map[string]string{
24			"app": "nginx", // 选择名字为nginx的应用,需要与前文中Deployment的app标签相对应
25		},
26		Type: corev1.ServiceTypeLoadBalancer, //类型为LoadBalancer,会自动创建BLB并申请EIP
27		ExternalTrafficPolicy: corev1.ServiceExternalTrafficPolicyCluster, 
28	},
29}
30    // 调用服务创建接口,创建负载均衡服务,由于设定了标签,所以可以直接连接Deployment
31resp, err := clientSet.CoreV1().Services("default").Create(context.TODO(),svcInstance, metav1.CreateOptions{})
32fmt.Println(resp)
            服务列表页面,如下图所示。在云控制台,能够发现在“流量接入→服务列表”中创建了名为“test-service”的服务,说明利用Client-Go创建负载均衡服务成功,新建了负载均衡实例并绑定了EIP。

在公网客户端访问EIP地址,如下图所示。成功显示Nginx页面,说明使用负载均衡实例成功创建了公网服务。
重新进入“查询工作负载→无状态部署页面”。默认命名空间下的无状态部署,如下图所示。查看CPU有使用量,说明请求已成功到达Nginx服务。

目前为止,通过百度智能云SDK部署了网站服务。为了实现网站的自动化部署,需要在代码中创建CCE和Deployment时补充循环等待逻辑。自动化部署流程,相关代码如下所示。
1package main
2
3import (
4	"context"
5	"encoding/json"
6	"fmt"
7	"io"
8	"os"
9	"time"
10
11	"github.com/baidubce/bce-sdk-go/services/bcc/api"
12	ccev2 "github.com/baidubce/bce-sdk-go/services/cce/v2"
13	"github.com/baidubce/bce-sdk-go/services/cce/v2/types"
14	appsv1 "K8s.io/api/apps/v1"
15	corev1 "K8s.io/api/core/v1"
16	resource "K8s.io/apimachinery/pkg/api/resource"
17	metav1 "K8s.io/apimachinery/pkg/apis/meta/v1"
18	"K8s.io/apimachinery/pkg/util/intstr"
19	"K8s.io/client-go/kubernetes"
20	"K8s.io/client-go/tools/clientcmd"
21)
22
23func main() {
24	AK, SK := "Your AK", "Your SK"
25	cceEndpoint := "https://cce.bj.baidubce.com"
26	cceClient, err := ccev2.NewClient(AK, SK, cceEndpoint)
27	if err != nil {
28		fmt.Println("create cce client failed, err:", err)
29	}
30
31	// 集群的参数设置与创建
32	clusterArgs := retClusterArgs()
33	respCreateCluster, err := cceClient.CreateCluster(clusterArgs)
34	if err != nil {
35		fmt.Println(err.Error())
36		return
37	}
38	s, _ := json.MarshalIndent(respCreateCluster.ClusterID, "", "\t")
39	fmt.Println("Creating CCE-Cluster, Cluster ID : " + string(s))
40	clusterID := string(s)[1 : len(string(s))-1]
41
42	// 拉取K8s设置
43	configArgs := retKubeConfigArgs(clusterID)
44	respGetConfig, err := cceClient.GetKubeConfig(configArgs)
45	for timeUsed := 0; ; {
46		if err != nil {
47			time.Sleep(10 * time.Second)
48			timeUsed += 10
49			fmt.Println("CCE-Cluster Creating......", timeUsed/60, "MIN")
50			respGetConfig, err = cceClient.GetKubeConfig(configArgs)
51		} else {
52			break
53		}
54	}
55	fmt.Println("Create CCE-Cluster Master OK!!")
56
57	//保存K8s设置至本地文件"kubectl.conf"
58	testStr := respGetConfig.KubeConfig
59	fileName := "kubectl.conf"
60	filePtr, err := os.Create(fileName)
61	if err != nil {
62		fmt.Println(err)
63	}
64	_, err = io.WriteString(filePtr, testStr)
65	if err != nil {
66		fmt.Println(err)
67	}
68	fmt.Println("Fetching K8s-Config OK!!")
69
70	// 利用Client-Go连接K8s,创建客户端
71	cceConfig := "./kubectl.conf"
72	config, err := clientcmd.BuildConfigFromFlags("", cceConfig)
73	if err != nil {
74		fmt.Println(err)
75		return
76	}
77	clientSet, err := kubernetes.NewForConfig(config)
78	if err != nil {
79		fmt.Println(err)
80		return
81	}
82	fmt.Println("Creating K8s Client OK!!")
83
84	// 利用客户端创建无状态部署
85	deployArgs := retDeployArgs()
86	_, err = clientSet.AppsV1().Deployments("default").Create(context.Background(), deployArgs, metav1.CreateOptions{})
87	for timeUsed := 0; ; {
88		if err != nil {
89			time.Sleep(10 * time.Second)
90			timeUsed += 10
91			fmt.Println("Creating Deployment, Waiting Cluster Workers......", timeUsed/60, "MIN")
92			_, err = clientSet.AppsV1().Deployments("default").Create(context.Background(), deployArgs, metav1.CreateOptions{})
93		} else {
94			break
95		}
96	}
97	fmt.Println("Create Deployment OK!!")
98
99	// 利用客户端创建负载均衡服务
100	svcArgs := retSvcArgs()
101	_, err = clientSet.CoreV1().Services("default").Create(context.Background(), svcArgs, metav1.CreateOptions{})
102	if err != nil {
103		fmt.Println(err)
104		return
105	}
106	fmt.Println("Create LB Service OK!! All Procedures Complete, Congradulations!")
107}
108
109func retClusterArgs() *ccev2.CreateClusterArgs {
110	args := &ccev2.CreateClusterArgs{
111		CreateClusterRequest: &ccev2.CreateClusterRequest{
112			ClusterSpec: &types.ClusterSpec{
113				ClusterName: "aCluster",
114				K8SVersion: "1.28.8",
115				RuntimeType: types.RuntimeTypeContainerd,
116				VPCID: "vpc-******",
117				MasterConfig: types.MasterConfig{
118					MasterType: types.MasterTypeManaged,
119					ClusterHA: 1,
120					ExposedPublic: true,
121					ClusterBLBVPCSubnetID: "sbn-******",
122				},
123				ContainerNetworkConfig: types.ContainerNetworkConfig{
124					Mode:  types.ContainerNetworkModeVPCRouteVeth,
125					LBServiceVPCSubnetID: "sbn-******",
126					ClusterPodCIDR: "172.28.0.0/16",
127					ClusterIPServiceCIDR: "172.31.0.0/16",
128					KubeProxyMode: types.KubeProxyModeIPVS,
129					NodePortRangeMin: 30000,
130					NodePortRangeMax: 32767,
131				},
132			},
133			NodeSpecs: []*ccev2.InstanceSet{
134				{
135					Count: 2,
136					InstanceSpec: types.InstanceSpec{
137						InstanceName: "",
138						ClusterRole: types.ClusterRoleNode,
139						Existed: false,
140						MachineType:  types.MachineTypeBCC,
141						InstanceType: "34",
142						VPCConfig: types.VPCConfig{
143							VPCID: "vpc-******",
144							VPCSubnetID: "sbn-******",
145							SecurityGroupType: "normal",
146							SecurityGroup: types.SecurityGroup{
147								CustomSecurityGroupIDs: []string{},
148								EnableCCERequiredSecurityGroup: true,
149								EnableCCEOptionalSecurityGroup: false,
150							},
151						},
152						InstanceResource: types.InstanceResource{
153							CPU: 2,
154							MEM: 8,
155							RootDiskSize: 40,
156							RootDiskType: "enhanced_ssd_pl1",
157							LocalDiskSize: 0,
158							CDSList: []types.CDSConfig{},
159							MachineSpec: "bcc.g5.c2m8",
160						},
161						ImageID: "7183****-3e24-464d-9c02-a73***",
162						InstanceOS: types.InstanceOS{
163							ImageType: api.ImageTypeSystem,
164						},
165						NeedEIP: false,
166						AdminPassword: "******",
167						SSHKeyID: "",
168						InstanceChargingType: api.PaymentTimingPostPaid,
169						RuntimeType: types.RuntimeTypeContainerd,
170					},
171				},
172			},
173		},
174	}
175	return args
176}
177
178func retKubeConfigArgs(clusterID string) *ccev2.GetKubeConfigArgs {
179	args := &ccev2.GetKubeConfigArgs{
180		ClusterID: clusterID,
181		KubeConfigType: ccev2.KubeConfigTypePublic,
182	}
183	return args
184}
185
186func retDeployArgs() *appsv1.Deployment {
187	var podsNum int32 = 2
188	args := &appsv1.Deployment{
189		ObjectMeta: metav1.ObjectMeta{
190			Name: "nginx-deployment",     // 服务名称
191			Namespace: "default",          // 默认命名空间
192		},
193		Spec: appsv1.DeploymentSpec{
194			Replicas: &podsNum, // 副本数
195			Selector: &metav1.LabelSelector{
196				MatchLabels: map[string]string{
197					"app": "nginx", //标签为 应用:nginx,需要与部署类型对应
198				},
199			},
200			Template: corev1.PodTemplateSpec{
201				ObjectMeta: metav1.ObjectMeta{
202					Labels: map[string]string{
203						"app": "nginx",
204					},
205				},
206				Spec: corev1.PodSpec{
207					Containers: []corev1.Container{
208						{
209							Name: "nginx",   // 容器名称为nginx
210							Image: "hub.baidubce.com/cce/nginx-alpine-go:latest",							Ports: []corev1.ContainerPort{
211								{
212									Name: "http",
213									Protocol: corev1.ProtocolTCP,
214									ContainerPort: 80, // 端口号80
215								},
216							},
217							Resources: corev1.ResourceRequirements{
218								Limits: map[corev1.ResourceName]resource.Quantity{ // 每一个容器的资源设置
219									corev1.ResourceCPU: resource.MustParse("200m"),
220									corev1.ResourceMemory: resource.MustParse("512Mi"),
221								},
222								Requests: map[corev1.ResourceName]resource.Quantity{
223									corev1.ResourceCPU:resource.MustParse("200m"),
224									corev1.ResourceMemory: resource.MustParse("512Mi"),
225								},
226							},
227						},
228					},
229				},
230			},
231		},
232	}
233	return args
234}
235
236func retSvcArgs() *corev1.Service {
237	args := &corev1.Service{
238		TypeMeta: metav1.TypeMeta{
239			Kind: "Service", // 服务类型
240			APIVersion: "v1",
241		},
242		ObjectMeta: metav1.ObjectMeta{
243			Name: "test-service", // 服务名称
244		},
245		Spec: corev1.ServiceSpec{
246			Ports: []corev1.ServicePort{
247				{
248					Protocol: "TCP",// TCP协议,四层负载均衡
249					Port: 80,                 // 80端口转入
250					TargetPort: intstr.FromInt(80), // 80端口转出
251				},
252			},
253			Selector: map[string]string{
254				"app": "nginx", //选择名字为nginx的应用,需要与前文中Deployment的app标签相对应
255			},
256			Type: corev1.ServiceTypeLoadBalancer, // 类型为LoadBalancer。这会自动创建BLB并申请、连接EIP
257			ExternalTrafficPolicy: corev1.ServiceExternalTrafficPolicyCluster,
258		},
259	}
260	return args
261}
            一次完整的网站部署的典型示例输出,如下图所示。

示例代码下载:[负载均衡与云原生服务自动部署代码示例]
