现在 Fargate 支持 EFS,使用 Terraform 构建您的 WordPress 环境

我叫寺冈,是一名基础设施工程师。

AWS 有一项名为“Amazon ECS”的服务,它有两种启动模式:“Amazon EC2”和“AWS Fargate”。

Fargate 非常方便,因为容器执行环境完全由 AWS 管理,无需管理集群。但是,由于其特性限制,无法将持久卷挂载到容器,并且存储会在任务停止后立即被删除。

Fargate 任务存储

这次我们测试的 WordPress 是在容器中启动的,所有发布文章中使用的图像都存储在本地卷中,因此如果存储被删除,就会出现问题。

如果您仍然想使用 Fargate,因为它很方便,我们有好消息要告诉您:
Fargate 平台 1.4 版本现在支持 EFS 端点。

AWS Fargate 发布平台版本 1.4

这样我们就可以在容器之间共享数据,同时还能保留持久数据

本次配置已验证

如果按照本文中的说明进行构建,最终将得到以下配置:

整个构建过程均使用 Terraform 完成,代码如下所示。
使用的 Terraform 版本为 0.12.24。
请注意,在参考此代码时,版本信息可能存在差异。

我写的代码

目录结构如下:

$ tree . ├── README.md ├── alb.tf ├── efs.tf ├── fargate.tf ├── iam.tf ├── provider.tf ├── rds.tf ├── roles │ ├── fargate_task_assume_role.json │ └── fargate_task_execution_policy.json ├── securitygroup.tf ├── ssm.tf ├── tasks │ └── container_definitions.json ├── terraform.tfstate ├── terraform.tfstate.backup ├── variables.tf └── vpc.tf 2 个目录,16 个文件

提供商.tf

提供商“aws” { access_key = var.access_key Secret_key = var.secret_key 区域 = var.region Should_role { role_arn = var.role_arn } }

变量.tf

#################### # 提供程序 ###################### 变量 "access_key" { 描述 = " AWS 访问密钥" } 变量 "secret_key" { 描述 = "AWS 密钥" } 变量 "role_arn" { 描述 = "AWS Role Arn" } 变量 "region" { 默认 = "ap-northeast-1" }

vpc.tf

#################### # VPC ################### resource "aws_vpc" "vpc" { cidr_block = "10.0.0.0/16" enable_dns_support = true enable_dns_hostnames = true tags = { Name = "vpc-fargate-efs" } } #################### # 子网 ################### resource "aws_subnet" "public_1a" { vpc_id = aws_vpc.vpc.id availability_zone = "${var.region}a" cidr_block = "10.0.10.0/24" map_public_ip_on_launch = true tags = { Name = "subnet-fargate-efs-public-1a" } } resource "aws_subnet" "public_1c" { vpc_id = aws_vpc.vpc.id availability_zone = "${var.region}c" cidr_block = "10.0.11.0/24" map_public_ip_on_launch = true tags = { Name = "subnet-fargate-efs-public-1c" } } resource "aws_subnet" "dmz_1a" { vpc_id = aws_vpc.vpc.id availability_zone = "${var.region}a" cidr_block = "10.0.20.0/24" map_public_ip_on_launch = true tags = { Name = "subnet-fargate-efs-dmz-1a" } } resource "aws_subnet" "dmz_1c" { vpc_id = aws_vpc.vpc.id availability_zone = "${var.region}c" cidr_block = "10.0.21.0/24" map_public_ip_on_launch = true tags = { Name = "subnet-fargate-efs-dmz-1c" } } resource "aws_subnet" "private_1a" { vpc_id = aws_vpc.vpc.id availability_zone = "${var.region}a" cidr_block = "10.0.30.0/24" map_public_ip_on_launch = true tags = { Name = "subnet-fargate-efs-private-1a" } } resource "aws_subnet" "private_1c" { vpc_id = aws_vpc.vpc.id availability_zone = "${var.region}c" cidr_block = "10.0.31.0/24" map_public_ip_on_launch = true tags = { Name = "subnet-fargate-efs-private-1c" } } #################### # 路由表################### resource "aws_route_table" "public" { vpc_id = aws_vpc.vpc.id tags = { Name = "route-fargate-efs-public" } } resource "aws_route_table" "dmz" { vpc_id = aws_vpc.vpc.id tags = { Name = "route-fargate-efs-dmz" } } resource "aws_route_table" "private" { vpc_id = aws_vpc.vpc.id tags = { Name = "route-fargate-efs-private" } } #################### # IGW #################### resource "aws_internet_gateway" "igw" { vpc_id = aws_vpc.vpc.id tags = { Name = "igw-fargate-efs" } } ################### # NATGW #################### resource "aws_eip" "natgw" { vpc = true tags = { Name = "natgw-fargate-efs" } } resource "aws_nat_gateway" "natgw" { allocation_id = aws_eip.natgw.id subnet_id = aws_subnet.public_1a.id tags = { Name = "natgw-fargate-efs" } depends_on = [aws_internet_gateway.igw] } #################### # 路由 #################### resource "aws_route" "public" { route_table_id = aws_route_table.public.id destination_cidr_block = "0.0.0.0/0" gateway_id = aws_internet_gateway.igw.id depends_on = [aws_route_table.public] } resource "aws_route" "dmz" { route_table_id = aws_route_table.dmz.id destination_cidr_block = "0.0.0.0/0" nat_gateway_id = aws_nat_gateway.natgw.id depends_on = [aws_route_table.dmz] } ################### # 路由关联 ################### resource "aws_route_table_association" "public_1a" { subnet_id = aws_subnet.public_1a.id route_table_id = aws_route_table.public.id } resource "aws_route_table_association" "public_1c" { subnet_id = aws_subnet.public_1c.id route_table_id = aws_route_table.public.id } resource "aws_route_table_association" "dmz_1a" { subnet_id = aws_subnet.dmz_1a.id route_table_id = aws_route_table.dmz.id } resource "aws_route_table_association" "dmz_1c" { subnet_id = aws_subnet.dmz_1c.id route_table_id = aws_route_table.dmz.id } resource "aws_route_table_association" "private_1a" { subnet_id = aws_subnet.private_1a.id route_table_id = aws_route_table.private.id } resource "aws_route_table_association" "private_1c" { subnet_id = aws_subnet.private_1c.id route_table_id = aws_route_table.private.id }

securitygroup.tf

#################### # 安全组 ################### resource "aws_security_group" "alb" { name = "alb-sg" description = "用于 ALB" vpc_id = aws_vpc.vpc.id } resource "aws_security_group" "fargate" { name = "fargate-sg" description = "用于 Fargate" vpc_id = aws_vpc.vpc.id } resource "aws_security_group" "efs" { name = "efs-sg" description = "用于 EFS" vpc_id = aws_vpc.vpc.id } resource "aws_security_group" "rds" { name = "rds-sg" description = "用于 RDS" vpc_id = aws_vpc.vpc.id } ##################### # 安全组规则 ##################### resource "aws_security_group_rule" "allow_http_for_alb" { security_group_id = aws_security_group.alb.id type = "ingress" protocol = "tcp" from_port = 80 to_port = 80 cidr_blocks = ["0.0.0.0/0"] description = "allow_http_for_alb" } resource "aws_security_group_rule" "from_alb_to_fargate" { security_group_id = aws_security_group.fargate.id type = "ingress" protocol = "tcp" from_port = 80 to_port = 80 source_security_group_id = aws_security_group.alb.id description = "from_alb_to_fargate" } resource "aws_security_group_rule" "from_fargate_to_efs" { security_group_id = aws_security_group.efs.id type = "ingress" protocol = "tcp" from_port = 2049 to_port = 2049 source_security_group_id = aws_security_group.fargate.id description = "from_fargate_to_efs" } resource "aws_security_group_rule" "from_fargate_to_rds" { security_group_id = aws_security_group.rds.id type = "ingress" protocol = "tcp" from_port = 3306 to_port = 3306 source_security_group_id = aws_security_group.fargate.id description = "from_fargate_to_rds" } resource "aws_security_group_rule" "egress_alb" { security_group_id = aws_security_group.alb.id type = "egress" protocol = "-1" from_port = 0 to_port = 0 cidr_blocks = ["0.0.0.0/0"] description = "出站全部" } 资源 "aws_security_group_rule" "egress_fargate" { security_group_id = aws_security_group.fargate.id type = "egress" protocol = "-1" from_port = 0 to_port = 0 cidr_blocks = ["0.0.0.0/0"] description = "出站全部" } 资源 "aws_security_group_rule" "egress_efs" { security_group_id = aws_security_group.efs.id type = "egress" protocol = "-1" from_port = 0 to_port = 0 cidr_blocks = ["0.0.0.0/0"] description = "出站全部" } 资源 "aws_security_group_rule" "egress_rds" { security_group_id = aws_security_group.rds.id type = "egress" protocol = "-1" from_port = 0 to_port = 0 cidr_blocks = ["0.0.0.0/0"] description = "出站全部" }

alb.tf

#################### # ALB ################### resource "aws_lb" "alb" { name = "alb-fargate-efs" internal = false load_balancer_type = "application" security_groups = [ aws_security_group.alb.id ] subnets = [ aws_subnet.public_1a.id, aws_subnet.public_1c.id ] } ################### # Target Group ################### resource "aws_lb_target_group" "alb" { name = "fargate-efs-tg" port = "80" protocol = "HTTP" target_type = "ip" vpc_id = aws_vpc.vpc.id deregistration_delay = "60" health_check { interval = "10" path = "/" port = "traffic-port" protocol = "HTTP" timeout = "4" healthy_threshold = "2" unhealthy_threshold = "10" matcher = "200-302" } } ################### # 监听器 #################### resource "aws_lb_listener" "alb" { load_balancer_arn = aws_lb.alb.arn port = "80" protocol = "HTTP" default_action { type = "forward" target_group_arn = aws_lb_target_group.alb.arn } }

efs.tf

#################### # EFS ################### resource "aws_efs_file_system" "efs" { creation_token = "fargate-efs" provisioned_throughput_in_mibps = "50" throughput_mode = "provisioned" tags = { Name = "fargate-efs" } } #################### # 挂载目标 ################### resource "aws_efs_mount_target" "dmz_1a" { file_system_id = aws_efs_file_system.efs.id subnet_id = aws_subnet.dmz_1a.id security_groups = [ aws_security_group.efs.id ] } resource "aws_efs_mount_target" "dmz_1c" { file_system_id = aws_efs_file_system.efs.id subnet_id = aws_subnet.dmz_1c.id security_groups = [ aws_security_group.efs.id ] }

rds.tf

#################### # 参数组 ################### resource "aws_db_parameter_group" "rds" { name = "fargate-efs-pg" family = "mysql5.7" description = "for RDS" } #################### # # 子网组 ################### resource "aws_db_subnet_group" "rds" { name = "fargate-efs-sg" description = "for RDS" subnet_ids = [ aws_subnet.private_1a.id, aws_subnet.private_1c.id ] } #################### # 实例 #################### resource "aws_db_instance" "rds" { identifier = "fargate-efs-db01" engine = "mysql" engine_version = "5.7" instance_class = "db.t3.micro" storage_type = "gp2" allocate_storage = "50" max_allocated_storage = "100" username = "root" password = "password" final_snapshot_identifier = "fargate-efs-db01-final" db_subnet_group_name = aws_db_subnet_group.rds.name parameter_group_name = aws_db_parameter_group.rds.name multi_az = false vpc_security_group_ids = [ aws_security_group.rds.id ] backup_retention_period = "7" apply_immediately = true }

fargate.tf

#################### # 集群 ################### resource "aws_ecs_cluster" "cluster" { name = "cluster-fargate-efs" setting { name = "containerInsights" value = "disabled" } } #################### # 任务定义 ################### resource "aws_ecs_task_definition" "task" { family = "task-fargate-wordpress" container_definitions = file("tasks/container_definitions.json") cpu = "256" memory = "512" network_mode = "awsvpc" execution_role_arn = aws_iam_role.fargate_task_execution.arn volume { name = "fargate-efs" efs_volume_configuration { file_system_id = aws_efs_file_system.efs.id root_directory = "/" } } requires_compatibilities = [ "FARGATE" ] } ################### # 服务 ################### resource "aws_ecs_service" "service" { name = "service-fargate-efs" cluster = aws_ecs_cluster.cluster.arn task_definition = aws_ecs_task_definition.task.arn desired_count = 2 launch_type = "FARGATE" platform_version = "1.4.0" load_balancer { target_group_arn = aws_lb_target_group.alb.arn container_name = "wordpress" container_port = "80" } network_configuration { subnets = [ aws_subnet.dmz_1a.id, aws_subnet.dmz_1c.id ] security_groups = [ aws_security_group.fargate.id ] assign_public_ip = false } }

container_definition.json

[ { "name": "wordpress", "image": "wordpress:latest", "essential": true, "portMappings": [ { "containerPort": 80, "hostPort": 80 } ], "mountPoints": [ { "containerPath": "/var/www/html", "sourceVolume": "fargate-efs" } ], "secrets": [ { "name": "WORDPRESS_DB_HOST", "valueFrom": "WORDPRESS_DB_HOST" }, { "name": "WORDPRESS_DB_USER", "valueFrom": "WORDPRESS_DB_USER" }, { "name": "WORDPRESS_DB_PASSWORD", "valueFrom": "WORDPRESS_DB_PASSWORD" }, { "name": "WORDPRESS_DB_NAME", "valueFrom": "WORDPRESS_DB_NAME" } ] } ]

iam.tf

#################### # IAM 角色 ################### resource "aws_iam_role" "fargate_task_execution" { name = "role-fargate_task_execution" assume_role_policy = file("./roles/fargate_task_assume_role.json") } #################### # IAM 角色策略 ################### resource "aws_iam_role_policy" "fargate_task_execution" { name = "execution-policy" role = aws_iam_role.fargate_task_execution.name policy = file("./roles/fargate_task_execution_policy.json") }

fargate_task_assume_role.json

{ "版本": "2012-10-17", "声明": [ { "效果": "允许", "主体": { "服务": "ecs-tasks.amazonaws.com" }, "操作": "sts:AssumeRole" } ] }

fargate_task_execution_policy.json

{ "版本": "2012-10-17", "语句": [ { "效果": "允许", "操作": "ssm:GetParameters", "资源": "*" } ] }

ssm.tf

#################### # 参数 ################### resource "aws_ssm_parameter" "wordpress_db_host" { name = "WORDPRESS_DB_HOST" description = "WORDPRESS_DB_HOST" type = "String" value = aws_db_instance.rds.address } resource "aws_ssm_parameter" "wordpress_db_user" { name = "WORDPRESS_DB_USER" description = "WORDPRESS_DB_USER" type = "String" value = "wordpress" } resource "aws_ssm_parameter" "wordpress_db_password" { name = "WORDPRESS_DB_PASSWORD" description = "WORDPRESS_DB_PASSWORD" type = "String" value = "password" } resource "aws_ssm_parameter" "wordpress_db_name" { name = "WORDPRESS_DB_NAME" description = "WORDPRESS_DB_NAME" 类型 = "字符串" 值 = "wordpress" }

RDS初始设置

为 WordPress 创建数据库和用户。

$ 创建数据库 wordpress; $ 创建用户 'wordpress'@'%',使用 mysql_native_password 密码 'password' 进行标识; $ 授予 wordpress@'%' 对 wordpress.* 的所有权限;

操作确认

运行 terraform apply 后,将启动两个 Fargate 任务,这两个任务将访问 ALB 端点。

WordPress界面将会出现,完成初始设置后,网站将显示如下图所示。
目前为止,一切正常。

现在我们来谈谈主要内容:从管理面板发布带有图片的文章。

按下提交按钮后,您将被重定向到文章页面,您可以通过反复按 F5 键来刷新该页面。

如果 EFS 未被正确识别,重新加载屏幕可能会导致图像有时显示有时不显示,但我随意地重新加载了大约 100 次屏幕,并没有出现任何显示中断,所以看起来没问题。

概括

Fargate 和 EFS 的集成极大地扩展了云构建的设计可能性。
平台版本 1.4 还包含许多其他实用更新,我们鼓励您试用。

如果您觉得这篇文章有帮助,请点赞!
1
加载中...
1 票,平均:1.00 / 11
8,787
X Facebook 哈特纳书签 口袋

写这篇文章的人

关于作者

寺冈由纪

于 2016 年加入 Beyond,目前是他担任基础设施工程师
MSP 的第六个年头,他负责排除故障,同时
使用 AWS 等公共云设计和构建基础设施。
最近,我
一直在使用 Terraform 和 Packer 等 Hashicorp 工具作为构建 Docker 和 Kubernetes 等容器基础设施以及自动化操作的一部分,并且我
还扮演了在外部学习小组和研讨会上发言的传播者的角色。

・GitHub
https://github.com/nezumisannn

・演示历史
https://github.com/nezumisannn/my-profile

・演示材料(SpeakerDeck)
https://speakerdeck.com/nezumisannn

・认证:
AWS认证解决方案架构师-
谷歌云专业云架构师