为 Node.js 工作负载选择 EC2、ECS 还是 EKS
对比了EC2、带Fargate的ECS以及EKS在运行Node.js应用方面的差异,帮助您根据团队的规模和技能水平选择合适的AWS计算服务。
来源: EC2 vs ECS vs EKS for Node.js: Which AWS Service Should You Actually Choose?
当需要将 Node.js 后端迁移到 Amazon Web Services 时,几乎必须立即做出选择。AWS 控制台提供了至少三种不同的计算产品:Amazon EC2、Amazon ECS 和 Amazon EKS。
如果你向他人咨询,会得到相互矛盾的建议。有些开发人员认为在 EC2 上使用普通虚拟机是最简单且最佳的选择;另一些人则坚持认为,如果想要真正现代化的架构,没有什么能比通过 EKS 运行 Kubernetes 更好。与此同时,许多生产平台团队已悄悄将其所有微服务统一采用 ECS 作为标准方案。
选择错误的工具往往会导致两种令人沮丧的结果:要么不得不手动修补操作系统并管理服务器,要么为了维持一个简单的 Express API 运行而深陷于 Kubernetes 配置文件之中——这样的 API 每秒可能只能处理几十次请求。
此对比摒弃了各种宣传噱头,直接探讨 EC2、ECS 和 EKS 在 Node.js 应用方面的表现:它们各自对团队运营有哪些要求,以及如何根据自身情况选出最合适的选项。
三种服务的简要说明
在比较各种优缺点之前,先明确每种服务的具体内容会更有帮助。
+-------------------------------------------------------------------------+
| Amazon EKS |
| Fully managed Kubernetes. High control, high complexity, multi-cloud. |
+-------------------------------------------------------------------------+
▲
│ Built for complex orchestration
+-------------------------------------------------------------------------+
| Amazon ECS |
| AWS-native container orchestration. Fast, simple, deeply integrated. |
+-------------------------------------------------------------------------+
▲
│ Built for containers
+-------------------------------------------------------------------------+
| Amazon EC2 |
| Raw virtual machines in the cloud. Full OS access, manual maintenance.|
+-------------------------------------------------------------------------+
1. Amazon EC2(弹性计算云)
EC2会为你提供一台虚拟机,称为“实例”。你可以选择操作系统——Ubuntu和Amazon Linux是常见的选择——通过SSH登录,安装Node.js以及PM2这样的进程管理器,然后自行启动应用程序。
从内核到上层的一切都在你的直接控制之下。
2. Amazon ECS(弹性容器服务)
ECS是AWS用于管理Docker容器的系统。你无需直接管理操作系统,只需将Node.js应用程序打包成Docker镜像,然后指示ECS保持一定数量的该容器运行且状态良好——比如四个副本。
如果将 ECS 与它的无服务器计算层 AWS Fargate 结合使用,就完全无需管理容器底层的服务器了。AWS 会根据需求自动为每个容器分配 CPU 和内存。
3. Amazon EKS(弹性 Kubernetes 服务)
EKS 在 AWS 基础设施之上提供托管式的 Kubernetes 集群。Kubernetes 本身是由谷歌发起的开源容器编排标准。
使用 EKS 时,AWS 负责 Kubernetes 的控制平面——即主节点,而你仍需负责定义容器组、部署、服务、入口规则以及网络策略。
为何 Node.js 的特性在此处很重要
在选定某项服务之前,值得回顾一下 Node.js 的实际运行机制:
- JavaScript 执行为单线程模式:Node.js 进程仅使用一个 CPU 核心来运行 JavaScript 代码。在拥有 8 核心的 EC2 实例上运行一个进程时,除非明确启动多个进程集群或将任务分配到多个实例上,否则其余 7 个核心将处于闲置状态。
- 启动速度快且占用资源少:容器化的 Node.js 应用通常可在两秒内启动运行,这使其非常适合基于容器和自动扩缩容架构构建的环境。
- 工作负载多为 I/O 密集型:大多数 Node.js 服务的大部分时间都用于等待数据库响应、外部 API 调用或磁盘操作,而非执行高强度的 CPU 计算。
这些特性直接影响着在这三项服务中扩展的难易程度。
1. Amazon EC2:最大程度的控制,繁重的维护工作
使用EC2的感觉很像在自己的Linux机器上开发,因为它本质上就是一台Linux机器。
Bash
# Typical manual setup on an EC2 instance:
sudo apt update && sudo apt install -y nodejs npm
git clone https://github.com/your-org/api.git
cd api && npm ci --omit=dev
npm install -g pm2
pm2 start app.js -i max
Traffic ──> Application Load Balancer (ALB)
│
┌────────┴────────┐
▼ ▼
[EC2 Instance] [EC2 Instance]
├─ Node Process ├─ Node Process
├─ Node Process ├─ Node Process
└─ PM2 Manager └─ PM2 Manager
优点:
- 价格可预测:您只需按照所选择的实例规格支付固定的每小时费用。
- 完全的系统访问权限:您可以查看系统日志,通过
sysctl调整内核参数,或安装应用程序所需的任何本地库。
缺点:
在EC2上运行生产级工作负载需要大量的手动维护工作。您需要负责:
- 应用操作系统安全补丁。
实际开发者见解: 对于几乎不会发生变化的单一单体应用,EC2 效果不错。但一旦需要运行三到四个微服务,将它们分散在不同的 EC2 实例上要么会浪费资源,要么会导致服务器配置变得混乱。
2. Amazon ECS:大多数团队的理想选择
如果你的 Node.js 应用已经位于 Docker 容器中,那么在 AWS 上 ECS 通常是最高效的解决方案。
编写可用于生产环境的 Node.js Dockerfile 并不复杂:
# Multi-stage Dockerfile for Node.js
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
FROM node:20-alpine
WORKDIR /app
ENV NODE_ENV=production
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
USER node
EXPOSE 3000
CMD ["node", "server.js"]
将图像推送到 Amazon ECR(弹性容器注册表)后,你需要创建一个 ECS 任务定义,其中需指定:
- 容器的 CPU 配置(例如
0.5 vCPU)和内存配置(例如1 GB)。 - 从 AWS Secrets Manager 或 Parameter Store 中获取的环境变量。
- 健康检查端点。
Traffic ──> ALB
│
├── Path /api/users ──> [ECS Task: Users] (0.5 vCPU)
└── Path /api/orders ─> [ECS Task: Orders] (0.5 vCPU)
[ECS Task: Orders] (0.5 vCPU)
为何 ECS 与 Fargate 非常适合 Node.js:
ECS 与 Fargate的结合完全省去了服务器层——无需管理任何底层的 EC2 实例。
当流量激增时,ECS 可以在几秒钟内启动五个新任务。由于 Node.js 进程的占用资源较少,你可以以较小的粒度来配置计算资源(如 0.25 vCPU 和 512 MB RAM),这样就能将空闲资源及成本维持在接近零的水平。
权衡因素:
- AWS锁定效应:ECS的配置是针对AWS设计的。为ECS编写的任务定义JSON文件若不进行修改,则无法直接用于Google Cloud或Azure。
- 工具生态系统较为薄弱:ECS虽能与CloudWatch和IAM良好集成,但其第三方插件生态系统远不及围绕Kubernetes发展起来的那套完善。
3. Amazon EKS:企业级规模与可移植性
EKS是AWS提供的托管版Kubernetes服务。Kubernetes的功能不仅限于运行容器,它还提供了网络管理、服务发现、滚动部署以及密钥管理的统一平台。
apiVersion: apps/v1
kind: Deployment
metadata:
name: node-api
spec:
replicas: 3
selector:
matchLabels:
app: node-api
template:
metadata:
labels:
app: node-api
spec:
containers:
- name: node-api
image: 123456789012.dkr.ecr.us-east-1.amazonaws.com/node-api:v1.2.0
resources:
limits:
cpu: "500m"
memory: "512Mi"
requests:
cpu: "250m"
memory: "256Mi"
ports:
- containerPort: 3000
优势:
- 真正的可移植性:相同的 YAML 配置文件即可在 EKS、Google 的 GKE、Azure 的 AKS,或是您自己数据中心的服务器上运行。
- 丰富的生态系统:Helm、ArgoCD、Prometheus 和 Istio 等工具可通过标准配置实现集成。
- 精确的自动扩缩容控制:您可以使用 KEDA(Kubernetes 事件驱动型自动扩缩容)根据自定义指标——如 SQS 队列中的消息数量或 Redis 缓冲区的大小——来调整容器的规模。
权衡因素:
Kubernetes 也会带来较大的运营负担:
- 控制平面成本:EKS 仅为了维持控制平面的运行,每个集群每月就需要大约 73 美元的费用,这还不包括用于工作节点和运行容器的支出。
常见错误: 有些团队仅仅因为 Kubernetes 是行业默认选择就选用 EKS。对于规模较小的工程团队——开发者人数少于 15 人——维护 Kubernetes 集群可能会占用资深工程师每周 20% 到 30% 的时间,而这些时间本可以用于产品开发本身。
直接对比
| 功能特性 | Amazon EC2 | Amazon ECS (Fargate) | Amazon EKS |
|---|---|---|---|
| 抽象层次 | 虚拟机 | 容器 | 容器加 Pod |
| 部署复杂度 | 低 | 低至中等 |
实用的决策方法
不必为每个功能纠结,只需遵循这条简单的原则:
何时选择 EC2:
- 您的 Node.js 应用属于旧版,依赖本地后台守护进程、特定操作系统的软件,或必须存储在本地磁盘上的文件。
- 您正在使用每月5美元的实例快速搭建原型,此时价格是唯一需要考虑的因素。
何时选择带 Fargate 的 ECS:
- 您希望运行现代化的容器化 Node.js 服务,而无需亲自管理底层操作系统。
- 您的团队由后端工程师组成,没有专门的基础设施或 DevOps 专家。
- 您完全致力于 AWS 生态系统(DynamoDB、SQS、RDS、IAM),并希望获得开箱即用的安全集成功能。
- 这种架构适用于大约80%在 AWS 上构建应用的公司,因此是合理的默认选择。
何时选择 EKS:
- 您需要运行数十甚至数百个采用多种语言开发的微服务,如 Node.js、Go、Python 和 Java。
- 您的组织要求采用多云或混合云架构,且需要在各处使用统一的工具。
- 您已经拥有能够安全监控、保护及升级 Kubernetes 集群的平台或 SRE 团队。
总结
优秀的云架构并非在于选择最炫酷的技术,而在于挑选那些能以最低维护成本解决问题方案。
具体到 Node.js:
- EC2 虽能让您完全掌控服务器,但需要您承担常规的服务器维护工作。
- EKS 虽能提供强大的功能以及跨生态系统迁移的能力,但会带来较高的复杂度及集群管理开销。
明智的做法是从小规模开始:将您的应用封装在精简的Docker容器中,先在ECS上运行,只有当组织规模确实超出其承载能力时再转向Kubernetes。由于容器本身不会改变,因此一旦时机成熟,它已经为部署到EKS做好了准备。