You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ECS部署Rust应用后服务连接失败,健康检查未通过求助

问题:ECS Fargate上的Rust应用API无法访问

我希望在ECS中运行一个包含健康API和WebSocket API的Rust应用,该应用在本地运行正常,但无论是从本地机器连接ECS上的两个API,还是ECS内部通过localhost调用健康API均失败。我已确认安全组允许所有流量,相关信息如下:

部署步骤

  • 开发提供WebSocket和HTTP端点的Rust应用;
  • 构建镜像并上传至ECR;
  • 在ECS中创建含1个公有子网的集群,采用Fargate作为基础设施;
  • 在任务定义中映射3014、3015端口为TCP协议,配置健康检查命令CMD-SHELL curl -f localhost:3015/health;
  • 将任务部署为集群服务,日志显示服务启动成功,但无法通过公网IPv4地址连接任一API。

Rust核心代码(main.rs)

use std::net::SocketAddr;
use tokio::net::TcpListener;
use warp::Filter;
use warp::hyper::StatusCode;

#[tokio::main]
async fn main() {
    println!("Starting up...");
    let url = "0.0.0.0:3014";
    let listener = TcpListener::bind(url)
        .await
        .unwrap();

    println!("Listing on default URL");

    tokio::spawn(async move {
        run_health_check().await;
    });

    loop {
        match listener.accept().await {
            Ok((stream, _)) => {
                let addr = stream.peer_addr().expect("connected streams should have a peer address");
                println!("Peer address: {}", addr);

                let ws_stream = tokio_tungstenite::accept_async(stream)
                    .await
                    .expect("Error during the websocket handshake occurred");

                println!("New WebSocket connection: {}", addr);

                drop(ws_stream);
            }
            Err(e) => panic!("{:#?}", e),
        }
    }
}

async fn run_health_check() {
    let routes = warp::get()
        .and(warp::path("health"))
        .map(move || Ok(warp::reply::with_status("", StatusCode::OK)))
        .with(warp::cors().allow_any_origin());

    let socket_address: SocketAddr = "0.0.0.0:3015".to_string().parse().unwrap();

    warp::serve(routes).run(socket_address).await;
}

ECS任务定义配置

{
    "taskDefinitionArn": "arn:aws:ecs:eu-central-1:XXXX:task-definition/websocket:3",
    "containerDefinitions": [
        {
            "name": "websocket",
            "image": "XXX.dkr.ecr.eu-central-1.amazonaws.com/hello3",
            "cpu": 0,
            "links": [],
            "portMappings": [
                {
                    "name": "websocket-3015-tcp",
                    "containerPort": 3015,
                    "hostPort": 3015,
                    "protocol": "tcp",
                    "appProtocol": "http"
                },
                {
                    "name": "websocket-3014-tcp",
                    "containerPort": 3014,
                    "hostPort": 3014,
                    "protocol": "tcp",
                    "appProtocol": "http"
                }
            ],
            "essential": true,
            "entryPoint": [],
            "command": [],
            "environment": [],
            "environmentFiles": [],
            "mountPoints": [],
            "volumesFrom": [],
            "secrets": [],
            "dnsServers": [],
            "dnsSearchDomains": [],
            "extraHosts": [],
            "dockerSecurityOptions": [],
            "dockerLabels": {},
            "ulimits": [],
            "logConfiguration": {
                "logDriver": "awslogs",
                "options": {
                    "awslogs-create-group": "true",
                    "awslogs-group": "/ecs/websocket",
                    "awslogs-region": "eu-central-1",
                    "awslogs-stream-prefix": "ecs"
                },
                "secretOptions": []
            },
            "healthCheck": {
                "command": [
                    "CMD-SHELL curl -f localhost:3015/health"
                ],
                "interval": 30,
                "timeout": 5,
                "retries": 3
            },
            "systemControls": []
        }
    ],
    "family": "websocket",
    "executionRoleArn": "arn:aws:iam::XXX:role/ecsTaskExecutionRole",
    "networkMode": "awsvpc",
    "revision": 3,
    "volumes": [],
    "status": "ACTIVE",
    "requiresAttributes": [
        {
            "name": "com.amazonaws.ecs.capability.logging-driver.awslogs"
        },
        {
            "name": "com.amazonaws.ecs.capability.docker-remote-api.1.24"
        },
        {
            "name": "ecs.capability.execution-role-awslogs"
        },
        {
            "name": "com.amazonaws.ecs.capability.ecr-auth"
        },
        {
            "name": "com.amazonaws.ecs.capability.docker-remote-api.1.19"
        },
        {
            "name": "com.amazonaws.ecs.capability.docker-remote-api.1.17"
        },
        {
            "name": "ecs.capability.container-health-check"
        },
        {
            "name": "ecs.capability.execution-role-ecr-pull"
        },
        {
            "name": "com.amazonaws.ecs.capability.docker-remote-api.1.18"
        },
        {
            "name": "ecs.capability.task-eni"
        },
        {
            "name": "com.amazonaws.ecs.capability.docker-remote-api.1.29"
        }
    ],
    "placementConstraints": [],
    "compatibilities": [
        "EC2",
        "FARGATE"
    ],
    "requiresCompatibilities": [
        "FARGATE"
    ],
    "cpu": "1024",
    "memory": "3072",
    "runtimePlatform": {
        "cpuArchitecture": "ARM64",
        "operatingSystemFamily": "LINUX"
    },
    "registeredAt": "2022-12-11T11:19:54.622Z",
    "registeredBy": "arn:aws:iam::465984508737:root",
    "tags": [
        {
            "key": "ecs:taskDefinition:createdFrom",
            "value": "ecs-console-v2"
        },
        {
            "key": "ecs:taskDefinition:stackId",
            "value": "arn:aws:cloudformation:eu-central-1:XX:stack/ECS-Console-V2-TaskDefinition-c246faa1-4ba5-4b54-ac4a-49ae00ab2f0d/8fd98e10-7944-11ed-abb2-0a564ca58c2a"
        }
    ]
}

Dockerfile

FROM rustlang/rust:nightly-bullseye AS builder

WORKDIR app

COPY . .
RUN cargo build --bin hello -Z sparse-registry

FROM debian:11.5
COPY --from=builder ./app/target/debug/hello .

CMD ["./hello"]

请问我哪里配置出现了问题?


解决方案

1. Docker镜像缺少健康检查依赖

你使用的debian:11.5基础镜像默认未安装curl,导致健康检查命令执行失败,容器会被标记为不健康,进而影响服务可用性。

修改Dockerfile,在最终阶段安装curl:

FROM rustlang/rust:nightly-bullseye AS builder

WORKDIR app

COPY . .
RUN cargo build --bin hello -Z sparse-registry

FROM debian:11.5
# 安装curl并清理APT缓存以减小镜像体积
RUN apt-get update && apt-get install -y --no-install-recommends curl \
    && rm -rf /var/lib/apt/lists/*
COPY --from=builder ./app/target/debug/hello .

CMD ["./hello"]

2. Fargate任务未分配公网IP

在awsvpc网络模式下,部署在公有子网的Fargate任务默认不会分配公网IP,导致外部无法通过公网地址访问服务。

解决:

  • 创建ECS服务时,在网络配置中勾选「启用自动分配公网IP」;
  • 若通过CLI或CloudFormation部署,需设置assignPublicIp: ENABLED。

3. 端口映射配置冗余(Fargate模式)

Fargate的awsvpc网络模式中,hostPort配置会被忽略(每个任务拥有独立网络栈),建议修改端口映射,移除hostPort字段,或保持与containerPort一致(不影响功能,但更规范)。

额外验证步骤

  • 登录同VPC内的EC2实例,尝试访问任务的内网IP+端口(如http://<任务内网IP>:3015/health),确认容器内服务是否正常运行;
  • 查看ECS任务日志,确认run_health_check函数是否成功启动warp服务,有无panic信息;
  • 确认安全组入站规则允许3014、3015端口的TCP流量(你已确认,但再次核对避免遗漏)。

内容的提问来源于stack exchange,提问作者J. Doe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 15:25:15