基于负载均衡器水平扩展的 Two-Tier 架构
关键词:ULB, Two-Tier
摘要
Two-Tier 架构是互联网最常见的应用部署方案,通常指由负载均衡器作为前端流量入口,通过一定的负载均衡策略,卸载流量至后端应用服务器的通用架构。
这种部署方案的特点有:
- 应用服务器是无状态的,可以随业务的扩张尽可能地水平扩展。
- 通过负载均衡器,可以完成用户无感知的,单一地域跨可用区的容灾切换。
ULB 是 UCloud 提供的 4/7 层负载均衡器,用于在多台云主机间实现应用程序流量的自动分配。可实现故障自动切换,提高业务可用性和资源利用率。
此案例使用 Terraform 创建如下资源:
- 创建一个 VPC 和 一个 Subnet,将接下来创建的所有资源都划进这个子网中
- 创建一台 ULB 并创建一个虚拟服务器实例用来对外提供 80 端口的监听服务,并为该 ULB 绑定一个公网弹性 IP 以供外网访问。
- 并行批量创建 N 台云主机,添加它们作为 ULB 的后端节点,配置从 ULB 到后端节点的转发规则和负载均衡策略。
使用 Terraform 来创建云主机可以享有由基础设施既代码 (IaC) 带来的便利,定义复杂的,具有一定规模的基础设施架构,并且可以通过修改 HCL 文件,对已建成的基础设施进行任意方向的扩展。例如:
- 通过修改主机实例的定义,可以做到单一应用服务器的升降级(Scale-Up,Scale-Down)
- 通过修改主机实例的数量,可以做到 ULB 后端应用实例的规模伸缩(Scale-In,Scale-Out)
使得对基础设施的动态管理成为一个无需额外研发成本的自动化操作。
此案例需要一个可用的 UCloud 帐号,以及确保目标可用区有足够的权限和配额可以创建云主机,ULB,VPC,EIP 和防火墙。并从下方 操作步骤 中拷贝,或克隆 官方仓库 以获取完整的 案例演示代码。
拓扑图
操作步骤
定义资源
首先创建基础设施代码文件,可从 官方样例 中获取全部源码文件,此源码文件需要使用 terraform 0.12+。
该样例中包含:
一个 variables.tf 文件,用于定义输入参数,代码详情如下:
variable "region" {
default = "cn-bj2"
}
variable "zone" {
default = "cn-bj2-05"
}
variable "instance_password" {
default = "ucloud_2020"
}
variable "instance_count" {
default = 2
}
variable "count_format" {
default = "%02d"
}
一个 main.tf 文件,用于建立一个从云资源到代码的映射,代码详情如下:
# 指定 UCloud Provider 和配置信息
provider "ucloud" {
region = var.region
}
# 查询默认可用区中的主机镜像
data "ucloud_images" "default" {
availability_zone = var.zone
name_regex = "^CentOS 7.[1-2] 64"
image_type = "base"
}
# 创建外网防火墙
resource "ucloud_security_group" "default" {
name = "tf-example-two-tier"
tag = "tf-example"
# HTTP access from LAN
rules {
port_range = "80"
protocol = "tcp"
cidr_block = "0.0.0.0/0"
policy = "accept"
}
# HTTPS access from LAN
rules {
port_range = "443"
protocol = "tcp"
cidr_block = "0.0.0.0/0"
policy = "accept"
}
}
# 创建 VPC
resource "ucloud_vpc" "default" {
name = "tf-example-two-tier"
tag = "tf-example"
# vpc network
cidr_blocks = ["192.168.0.0/16"]
}
# 创建 Subnet 到 VPC 下
resource "ucloud_subnet" "default" {
name = "tf-example-two-tier"
tag = "tf-example"
# subnet's network must be contained by vpc network
# and a subnet must have least 8 ip addresses in it (netmask < 30).
cidr_block = "192.168.1.0/24"
vpc_id = ucloud_vpc.default.id
}
# 创建多台 web 服务器
resource "ucloud_instance" "web" {
availability_zone = var.zone
instance_type = "n-basic-2"
image_id = data.ucloud_images.default.images[0].id
root_password = var.instance_password
boot_disk_type = "cloud_ssd"
name = "tf-example-two-tier-${format(var.count_format, count.index + 1)}"
tag = "tf-example"
# we will put all the instances into same vpc and subnet,
# so they can communicate with each other.
vpc_id = ucloud_vpc.default.id
subnet_id = ucloud_subnet.default.id
# this security group allows HTTP and HTTPS access
security_group = ucloud_security_group.default.id
count = var.instance_count
}
# 创建负载均衡
resource "ucloud_lb" "default" {
name = "tf-example-two-tier"
tag = "tf-example"
# we will put all the instances into same vpc and subnet,
# so they can communicate with each other.
vpc_id = ucloud_vpc.default.id
subnet_id = ucloud_subnet.default.id
}
# 创建基于 http 协议的负载均衡监听器
resource "ucloud_lb_listener" "default" {
load_balancer_id = ucloud_lb.default.id
protocol = "http"
port = 80
}
# 挂载云主机到负载均衡监听器
resource "ucloud_lb_attachment" "default" {
load_balancer_id = ucloud_lb.default.id
listener_id = ucloud_lb_listener.default.id
resource_id = ucloud_instance.web[count.index].id
port = 80
count = var.instance_count
}
# 创建负载均衡监听器转发规则
resource "ucloud_lb_rule" "default" {
load_balancer_id = ucloud_lb.default.id
listener_id = ucloud_lb_listener.default.id
backend_ids = ucloud_lb_attachment.default.*.id
domain = "www.ucloud.cn"
}
# 创建外网弹性 EIP
resource "ucloud_eip" "default" {
bandwidth = 2
charge_mode = "bandwidth"
name = "tf-example-two-tier"
tag = "tf-example"
internet_type = "bgp"
}
# 绑定 EIP 到负载均衡
resource "ucloud_eip_association" "default" {
resource_id = ucloud_lb.default.id
eip_id = ucloud_eip.default.id
}
生成执行计划
在当前目录下执行 terraform plan 命令,查看编排计划:
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.
data.ucloud_zones.default: Refreshing state...
data.ucloud_images.default: Refreshing state...
------------------------------------------------------------------------
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
+ ucloud_eip.default
id: <computed>
bandwidth: "2"
charge_mode: "bandwidth"
charge_type: "month"
create_time: <computed>
expire_time: <computed>
internet_type: "bgp"
ip_set.#: <computed>
name: "tf-example-two-tier"
public_ip: <computed>
remark: <computed>
resource.%: <computed>
status: <computed>
tag: "tf-example"
+ ucloud_eip_association.default
id: <computed>
eip_id: "${ucloud_eip.default.id}"
resource_id: "${ucloud_lb.default.id}"
resource_type: <computed>
+ ucloud_instance.web[0]
id: <computed>
auto_renew: <computed>
availability_zone: "cn-bj2-05"
boot_disk_size: <computed>
boot_disk_type: <computed>
charge_type: "month"
cpu: <computed>
create_time: <computed>
data_disk_size: <computed>
data_disk_type: <computed>
disk_set.#: <computed>
expire_time: <computed>
image_id: "uimage-f1chxn"
instance_type: "n-basic-2"
ip_set.#: <computed>
memory: <computed>
name: "tf-example-two-tier-01"
private_ip: <computed>
remark: <computed>
root_password: <sensitive>
security_group: "${ucloud_security_group.default.id}"
status: <computed>
subnet_id: "${ucloud_subnet.default.id}"
tag: "tf-example"
vpc_id: "${ucloud_vpc.default.id}"
+ ucloud_instance.web[1]
id: <computed>
auto_renew: <computed>
availability_zone: "cn-bj2-05"
boot_disk_size: <computed>
boot_disk_type: <computed>
charge_type: "month"
cpu: <computed>
create_time: <computed>
data_disk_size: <computed>
data_disk_type: <computed>
disk_set.#: <computed>
expire_time: <computed>
image_id: "uimage-f1chxn"
instance_type: "n-basic-2"
ip_set.#: <computed>
memory: <computed>
name: "tf-example-two-tier-02"
private_ip: <computed>
remark: <computed>
root_password: <sensitive>
security_group: "${ucloud_security_group.default.id}"
status: <computed>
subnet_id: "${ucloud_subnet.default.id}"
tag: "tf-example"
vpc_id: "${ucloud_vpc.default.id}"
+ ucloud_lb.default
id: <computed>
create_time: <computed>
expire_time: <computed>
internal: <computed>
ip_set.#: <computed>
name: "tf-example-two-tier"
private_ip: <computed>
remark: <computed>
subnet_id: "${ucloud_subnet.default.id}"
tag: "tf-example"
vpc_id: "${ucloud_vpc.default.id}"
+ ucloud_lb_attachment.default[0]
id: <computed>
listener_id: "${ucloud_lb_listener.default.id}"
load_balancer_id: "${ucloud_lb.default.id}"
port: "80"
private_ip: <computed>
resource_id: "${ucloud_instance.web.*.id[count.index]}"
resource_type: <computed>
status: <computed>
+ ucloud_lb_attachment.default[1]
id: <computed>
listener_id: "${ucloud_lb_listener.default.id}"
load_balancer_id: "${ucloud_lb.default.id}"
port: "80"
private_ip: <computed>
resource_id: "${ucloud_instance.web.*.id[count.index]}"
resource_type: <computed>
status: <computed>
+ ucloud_lb_listener.default
id: <computed>
domain: <computed>
health_check_type: <computed>
idle_timeout: <computed>
listen_type: <computed>
load_balancer_id: "${ucloud_lb.default.id}"
method: "roundrobin"
name: <computed>
path: <computed>
persistence: <computed>
persistence_type: "none"
port: "80"
protocol: "http"
status: <computed>
+ ucloud_lb_rule.default
id: <computed>
backend_ids.#: <computed>
domain: "www.ucloud.cn"
listener_id: "${ucloud_lb_listener.default.id}"
load_balancer_id: "${ucloud_lb.default.id}"
+ ucloud_security_group.default
id: <computed>
create_time: <computed>
name: "tf-example-two-tier"
remark: <computed>
rules.#: "2"
rules.2733123863.cidr_block: "0.0.0.0/0"
rules.2733123863.policy: "accept"
rules.2733123863.port_range: "443"
rules.2733123863.priority: "high"
rules.2733123863.protocol: "tcp"
rules.845396726.cidr_block: "0.0.0.0/0"
rules.845396726.policy: "accept"
rules.845396726.port_range: "80"
rules.845396726.priority: "high"
rules.845396726.protocol: "tcp"
tag: "tf-example"
+ ucloud_subnet.default
id: <computed>
cidr_block: "192.168.1.0/24"
create_time: <computed>
name: "tf-example-two-tier"
remark: <computed>
tag: "tf-example"
vpc_id: "${ucloud_vpc.default.id}"
+ ucloud_vpc.default
id: <computed>
cidr_blocks.#: "1"
cidr_blocks.3901788224: "192.168.0.0/16"
create_time: <computed>
name: "tf-example-two-tier"
network_info.#: <computed>
remark: <computed>
tag: "tf-example"
update_time: <computed>
Plan: 12 to add, 0 to change, 0 to destroy.
------------------------------------------------------------------------
Note: You didn't specify an "-out" parameter to save this plan, so Terraform
can't guarantee that exactly these actions will be performed if
"terraform apply" is subsequently run.
可以看到即将创建两台云主机、一个外网弹性 EIP、一个外网防火墙、一个负载均衡、一个负载均衡监听器、一个负载均衡监听器规则、一个 VPC、一个 Subnet、两台主机分别与负载均衡监听器的挂载关系、EIP 与负载均衡的挂载关系。
执行编排
执行 terraform apply 命令并确认,执行编排计划:
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
可通过 控制台 确认资源已创建完成。
参考文献
最近更新时间:2021-10-19 09:36:07