负载均衡与云原生服务自动部署实践
概览
百度智能云的云原生产品,称为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}
一次完整的网站部署的典型示例输出,如下图所示。
示例代码下载:[负载均衡与云原生服务自动部署代码示例]