ruby-on-rails 在AWS ECS Fargate部署的具有公共IP的网页上显示“无法访问此站点”

jecbmhm3  于 4个月前  发布在  Ruby
关注(0)|答案(1)|浏览(66)

我正在尝试通过ECS fargate部署由docker + RDS(mysql,port 3306)构建的ruby on rails应用程序(port 3000)。我在cloudwatch上检查了我的数据库和ruby on rails应用程序,它的构建成功。(请确保服务器正在运行,数据库已初始化)
然而,即使构建成功结束,也无法使用公共IP访问我的ruby on rails应用程序。浏览器上仅返回消息->无法访问此站点..或..响应时间过长。我下面的代码有什么问题?我正在等待AWSMaven的帮助。

main.tf

provider "aws" {
  region = "ap-northeast-1"

  default_tags {
    tags = {
      Owner     = "[email protected]"
      Terraform = "true"
    }
  }
}

# VPC
resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/16"
  instance_tenancy     = "default"
  enable_dns_hostnames = true
  enable_dns_support   = true
  tags = {
    Name = "app"
  }
}

# Subnet
resource "aws_subnet" "public_1a" {
  vpc_id            = aws_vpc.main.id
  availability_zone = "ap-northeast-1a"
  cidr_block        = "10.0.1.0/24"
  map_public_ip_on_launch = true
  tags = {
    Name = "app-public-1a"
  }
}

resource "aws_subnet" "public_1c" {
  vpc_id            = aws_vpc.main.id
  availability_zone = "ap-northeast-1c"
  cidr_block        = "10.0.2.0/24"
  map_public_ip_on_launch = true
  tags = {
    Name = "app-public-1c"
  }
}

resource "aws_subnet" "public_1d" {
  vpc_id            = aws_vpc.main.id
  availability_zone = "ap-northeast-1d"
  cidr_block        = "10.0.3.0/24"
  map_public_ip_on_launch = true
  tags = {
    Name = "app-public-1d"
  }
}

resource "aws_subnet" "private_1a" {
  vpc_id            = aws_vpc.main.id
  availability_zone = "ap-northeast-1a"
  cidr_block        = "10.0.10.0/24"

  tags = {
    Name = "app-public-1a"
  }
}

resource "aws_subnet" "private_1c" {
  vpc_id            = aws_vpc.main.id
  availability_zone = "ap-northeast-1c"
  cidr_block        = "10.0.20.0/24"

  tags = {
    Name = "app-private-1c"
  }
}

resource "aws_subnet" "private_1d" {
  vpc_id            = aws_vpc.main.id
  availability_zone = "ap-northeast-1d"
  cidr_block        = "10.0.30.0/24"

  tags = {
    Name = "app-private-1d"
  }
}

# Internet Gateway
resource "aws_internet_gateway" "main" {
  vpc_id = aws_vpc.main.id

  tags = {
    Name = "app"
  }
}

# Elastic IP
resource "aws_eip" "nat_1a" {
  vpc = true

  tags = {
    Name = "app-natgw-1a"
  }
}

# NAT Gateway
resource "aws_nat_gateway" "nat_1a" {
  subnet_id     = aws_subnet.public_1a.id
  allocation_id = aws_eip.nat_1a.id

  tags = {
    Name = "app-1a"
  }
}

resource "aws_eip" "nat_1c" {
  vpc = true

  tags = {
    Name = "app-natgw-1c"
  }
}

resource "aws_nat_gateway" "nat_1c" {
  subnet_id     = aws_subnet.public_1c.id
  allocation_id = aws_eip.nat_1c.id

  tags = {
    Name = "app-1c"
  }
}

resource "aws_eip" "nat_1d" {
  vpc = true

  tags = {
    Name = "app-natgw-1d"
  }
}

resource "aws_nat_gateway" "nat_1d" {
  subnet_id     = aws_subnet.public_1d.id
  allocation_id = aws_eip.nat_1d.id

  tags = {
    Name = "app-1d"
  }
}

# Route Table
resource "aws_route_table" "public" {
  vpc_id = aws_vpc.main.id

  tags = {
    Name = "app-public"
  }

  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.main.id
  }
}

# Route
resource "aws_route" "public" {
  destination_cidr_block = "0.0.0.0/0"
  route_table_id         = aws_route_table.public.id
  gateway_id             = aws_internet_gateway.main.id
}

# Association
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" "public_1d" {
  subnet_id      = aws_subnet.public_1d.id
  route_table_id = aws_route_table.public.id
}

# Route Table (Private)
resource "aws_route_table" "private_1a" {
  vpc_id = aws_vpc.main.id

  tags = {
    Name = "app-private-1a"
  }
}

resource "aws_route_table" "private_1c" {
  vpc_id = aws_vpc.main.id

  tags = {
    Name = "app-private-1c"
  }
}

resource "aws_route_table" "private_1d" {
  vpc_id = aws_vpc.main.id

  tags = {
    Name = "app-private-1d"
  }
}

# Route (Private)
resource "aws_route" "private_1a" {
  destination_cidr_block = "0.0.0.0/0"
  route_table_id         = aws_route_table.private_1a.id
  nat_gateway_id         = aws_nat_gateway.nat_1a.id
}

resource "aws_route" "private_1c" {
  destination_cidr_block = "0.0.0.0/0"
  route_table_id         = aws_route_table.private_1c.id
  nat_gateway_id         = aws_nat_gateway.nat_1c.id
}

resource "aws_route" "private_1d" {
  destination_cidr_block = "0.0.0.0/0"
  route_table_id         = aws_route_table.private_1d.id
  nat_gateway_id         = aws_nat_gateway.nat_1d.id
}

# Association (Private)
resource "aws_route_table_association" "private_1a" {
  subnet_id      = aws_subnet.private_1a.id
  route_table_id = aws_route_table.private_1a.id
}

resource "aws_route_table_association" "private_1c" {
  subnet_id      = aws_subnet.private_1c.id
  route_table_id = aws_route_table.private_1c.id
}

resource "aws_route_table_association" "private_1d" {
  subnet_id      = aws_subnet.private_1d.id
  route_table_id = aws_route_table.private_1d.id
}

# SecurityGroup
resource "aws_security_group" "app-app" {
  name        = "app-app"
  description = "app-app"
  vpc_id      = aws_vpc.main.id

  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name = "app-app"
  }
}

# SecurityGroup
resource "aws_security_group" "app-http" {
  name        = "app-http"
  description = "aws_security_group"
  vpc_id      = aws_vpc.main.id

  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name = "app-http"
  }
}

# SecurityGroup
resource "aws_security_group" "app-db" {
  name        = "app-db"
  description = "aws_security_group"
  vpc_id      = aws_vpc.main.id

  ingress {
    from_port   = 3306
    to_port     = 3306
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name = "app-db"
  }
}

resource "aws_ecs_task_definition" "main" {
  family                   = "app"
  network_mode             = "awsvpc"
  cpu                      = "1024"
  memory                   = "2048"

  requires_compatibilities = ["FARGATE"]
  execution_role_arn       = aws_iam_role.main.arn

  runtime_platform {
    operating_system_family = "LINUX"
    cpu_architecture        = "X86_64"
  }

  container_definitions = jsonencode([
    {
      "name": "web",
      "image": RUBY ON RAILS IMGAE ECR URL IS HERE..,
      "portMappings": [
        {
          "containerPort": 3000,
          "hostPort": 3000,
          "protocol": "tcp"
        }
      ],
      "essential": true,
      "command": [
        "bash",
        "-c",
        "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
      ],
      "network_configuration": {
        "awsvpc_configuration": {
          "subnets": [aws_subnet.public_1a.id, aws_subnet.public_1c.id, aws_subnet.public_1d.id],
          "security_groups": [aws_security_group.app-app.id]
        }
      },
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "app",
          "awslogs-region": "ap-northeast-1",
          "awslogs-stream-prefix": "ecs"
        }
      },
      "environment": [
        {
          "name": "RAILS_RELATIVE_URL_ROOT",
          "value": "/"
        }
      ]
    }
  ])
}


# ECS Cluster
resource "aws_ecs_cluster" "main" {
  name = "app"
}

# ECS Service
resource "aws_ecs_service" "main" {
  name            = "app"
  launch_type     = "FARGATE"
  desired_count   = 1
  cluster         = aws_ecs_cluster.main.name
  task_definition = aws_ecs_task_definition.main.arn
  health_check_grace_period_seconds = 90

  deployment_controller {
    type = "ECS"
  }
  deployment_maximum_percent = 200
  deployment_minimum_healthy_percent = 100

  lifecycle {
    ignore_changes = [desired_count, task_definition]
  }

  load_balancer {
    target_group_arn = aws_alb_target_group.main.arn
    container_name   = "app-app"
    container_port   = 3000
  }

  network_configuration {
    subnets         = [aws_subnet.public_1a.id, aws_subnet.public_1c.id, aws_subnet.public_1d.id]
    security_groups = [
      aws_security_group.app-app.id
    ]
    assign_public_ip = true
  }


}

# ECR
resource "aws_ecr_repository" "main" {
  name                 = "app"
  image_tag_mutability = "MUTABLE"

  image_scanning_configuration {
    scan_on_push = true
  }
}

# IAM ROLE
resource "aws_iam_role" "main" {
  name = "app"
  assume_role_policy = data.aws_iam_policy_document.role_policy.json

  inline_policy {
    name   = "EcsTaskExecutionPolicy"
    policy = data.aws_iam_policy_document.ecs_task_policy.json
  }
}


data "aws_iam_policy_document" "ecs_task_policy" {
  statement {
    sid = "EcsTaskPolicy"

    actions = [
      "ecr:BatchCheckLayerAvailability",
      "ecr:GetDownloadUrlForLayer",
      "ecr:BatchGetImage"
    ]

    resources = [
      "*"
    ]
  }
  statement {

    actions = [
      "ecr:GetAuthorizationToken"
    ]

    resources = [
      "*"
    ]
  }

  statement {

    actions = [
      "logs:CreateLogGroup",
      "logs:CreateLogStream",
      "logs:PutLogEvents"
    ]

    resources = [
      "*"
    ]
  }
}

data "aws_iam_policy_document" "role_policy" {
  statement {
    actions = ["sts:AssumeRole"]

    principals {
      type        = "Service"
      identifiers = ["ecs-tasks.amazonaws.com"]
    }
  }
}


 # ALB
 resource "aws_alb" "main" {
   name               = "app"
   internal           = false
   enable_deletion_protection = false
   security_groups = [
     aws_security_group.app-http.id
   ]
   subnets         = [aws_subnet.public_1a.id, aws_subnet.public_1c.id, aws_subnet.public_1d.id]
 }

 # Listener
 resource "aws_alb_listener" "main" {
   port     = "80"
   protocol = "HTTP"

   load_balancer_arn = aws_alb.main.arn

   default_action {
     type             = "forward"
     target_group_arn = aws_alb_target_group.main.arn

   }
 }

 resource "aws_alb_target_group" "main" {
   name        = "app-targetgroup2"
   port        = 3000
   protocol    = "HTTP"
     depends_on           = [aws_alb.main]
   target_type          = "ip"
   vpc_id = aws_vpc.main.id
   deregistration_delay = 15

  health_check {
    interval            = 120
    path                = "/"
    port                = "3000"
    protocol            = "HTTP"
    timeout             = 110
    unhealthy_threshold = 2
    matcher             = 200
  }

   lifecycle {
     create_before_destroy = true
   }
 }

# ALB Listener Rule
resource "aws_alb_listener_rule" "main" {
  listener_arn = aws_alb_listener.main.arn
  priority     = 100
  depends_on = [aws_alb_target_group.main]

  condition {
    path_pattern {
      values = ["/"]
    }
  }

  action {
    type             = "forward"
    target_group_arn = aws_alb_target_group.main.arn
  }
}
*/

resource "aws_cloudwatch_log_group" "name" {
  name = "app"
  retention_in_days = 7
}

resource "aws_db_subnet_group" "main" {
  name        = "app-db-subnet"
  description = "app-db-subnet"
  subnet_ids  = [
    aws_subnet.public_1a.id,
    aws_subnet.public_1c.id,
    aws_subnet.public_1d.id
  ]

  tags = {
    Name = "app-db-subnet-group"
  }
}

resource "aws_db_instance" "main" {
  identifier          = "app-db"
  engine              = "mysql"
  engine_version      = "5.7"
  instance_class      = "db.t2.micro"
  allocated_storage   = 20
  storage_type        = "gp2"
  db_name             = "app_rails_production"
  username            = "root"
  password            = "password"
  port                = 3306
  multi_az            = true
  skip_final_snapshot = true

  vpc_security_group_ids = [aws_security_group.app-db.id]
  db_subnet_group_name   = aws_db_subnet_group.main.name
}

字符串

docker-compose.yml(在ruby on rails中)(在ecs中构建没有问题)

version: '3'
services:
  web:
    build: .
    command: /bin/sh -c "rm -f tmp/pids/server.pid &&
                     bundle exec rails s -p 3000 -b '0.0.0.0'"
    ports:
      - "3000:3000"
    platform: linux/x86_64
  db:
    image: mysql
    ports:
      - 3306:3306
    platform: linux/x86_64
    volumes:
      - db-data:/var/lib/mysql

volumes:
  db-data:
    driver: local

database.yml(在ruby on rails中)(在ecs中构建没有问题)

default: &default
  adapter: mysql2
  encoding: utf8
  username: root
  password: password
  port: 3306
  pool: 5

development:
  <<: *default
  database: development

test:
  <<: *default
  database: test

production:
  <<: *default
  database: production


DOCKERFILE(在ruby on rails中)(在ecs中构建没有问题)

FROM --platform=linux/amd64 ubuntu
FROM ruby:2.6.6

ENV LANG="C.UTF-8"

WORKDIR /usr/src/app

RUN set -eu \
  && curl -sSL https://deb.nodesource.com/setup_16.x | bash - \
  && apt-get update \
  && apt-get install -y \
    default-mysql-client \
    ftp \
    vim \
    shared-mime-info \
    libjemalloc-dev \
    libjemalloc2 \
    libappindicator1 \
    fonts-liberation \
    libappindicator3-1 \
    libasound2 \
    libnspr4 \
    libnss3 \
    libxss1 \
    libu2f-udev \
    libvulkan1 \
    xdg-utils \
    libgbm1 \
    nodejs \
    yarn \
    cmake \
  && apt-get clean \
  && rm -rf /var/lib/apt/lists/* \
  && ln -nfs /usr/lib/$(uname -m)-linux-gnu/libjemalloc.so.2 /usr/local/lib/libjemalloc.so.2

COPY Gemfile Gemfile.lock ./
RUN gem update --system 3.2.3
RUN gem install bundler -v 2.4.22
RUN gem install nokogiri --platform=ruby
RUN gem update --system 3.2.3
RUN gem install mysql2
RUN bundle config set force_ruby_platform true
RUN bundle install
RUN bundle update

ARG BUNDLE_ENTERPRISE__CONTRIBSYS__COM
ARG BUNDLE_GITHUB__COM

COPY . .

RUN mkdir -p \
  tmp/cache \
  tmp/sockets \
  tmp/pids \
  tmp/cache/assets
CMD /bin/sh -c "rm -f tmp/pids/server.pid && rm -f tmp/mysql.sock && bundle exec rails s -p 3000 -b '0.0.0.0'"


我所尝试的:
删除health_check -> Task failed ELB health checks in (target-group .....) ERROR删除load_balance设置-> Scaling activity initiated by ... ERROR删除私有配置->没有更改
我觉得路由、安全组或端口设置有问题。欢迎任何建议。谢谢。

ubbxdtey

ubbxdtey1#

名为app-app的安全组仅允许端口80上的入站流量,但ECS任务侦听端口3000。您需要更改该安全组以允许端口3000而不是端口80上的入站流量。
修复后,负载均衡器应该能够到达ECS容器,并且希望健康检查将开始通过。如果健康检查开始通过,那么您应该能够在浏览器中转到负载均衡器的DNS名称以访问您的应用程序。
此外,在解决安全组问题后,您应该能够直接转到Web浏览器中的应用程序,位于Fargate任务的公共IP地址,如:http://public-ip:3000。请注意,如果您直接转到任务的IP地址,而不是通过负载均衡器,则需要将容器端口:3000附加到地址。
您还有一个额外的aws_alb_listener_rule资源,它执行与默认侦听器规则相同的操作,因此可以直接将其删除。
您在aws_route_table" "public"资源的route块中定义了一次到Internet Gateway的路由,然后在单独的"aws_route" "public"资源中定义了一次。这不仅是冗余的,而且可能会导致在两个资源中定义相同内容的问题。由于Terraform正在管理aws_route_table资源,因此您应该删除冗余的aws_route资源。

**注意:**如果删除冗余资源,我会连续运行terraform apply几次,直到它说没有发现任何更改。

相关问题