努力
加油

在阿里云ECS实例中如何部署多个Docker应用?

在阿里云 ECS 实例中部署多个 Docker 应用,核心思路并非简单地在同一台机器上运行多个 docker run 命令,而是通过容器编排或反向XX + 网络隔离来实现资源的合理分配、端口管理以及服务发现。

作为有经验的运维或开发者,我们通常会根据业务规模选择以下三种主流方案。我将按从“轻量级”到“企业级”的顺序进行解析,并重点说明阿里云环境下的最佳实践。


方案一:Docker Compose(适合中小规模、单机部署)

这是最经典且上手最快的方式。适用于微服务数量较少(如 < 20 个)、资源竞争不激烈的场景。

1. 核心逻辑

利用 docker-compose.yml 文件定义多个服务的依赖关系、网络配置和卷挂载。Compose 会自动创建一个自定义网络,使容器间可以通过服务名互相访问。

2. 实施步骤

第一步:准备目录结构

mkdir -p /opt/docker-apps/myproject
cd /opt/docker-apps/myproject

第二步:编写 docker-compose.yml
假设我们要部署一个 Nginx 前端、一个 Node.js API 和一个 MySQL 数据库。

version: '3.8'
services:
  nginx:
    image: nginx:alpine
    ports:
      - "80:80"   # 对外暴露 HTTP
      - "443:443" # 对外暴露 HTTPS
    volumes:
      - ./nginx/conf.d:/etc/nginx/conf.d
      - ./html:/usr/share/nginx/html
    depends_on:
      - api
    networks:
      - app-network

  api:
    image: node:16-alpine
    command: npm start
    volumes:
      - ./api:/app
      - /app/node_modules
    networks:
      - app-network
    environment:
      - DB_HOST=db
      - DB_USER=root
      - DB_PASS=secret

  db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: secret
      MYSQL_DATABASE: mydb
    volumes:
      - db-data:/var/lib/mysql
    networks:
      - app-network

volumes:
  db-data:

networks:
  app-network:
    driver: bridge

第三步:启动服务

docker compose up -d

3. 阿里云 ECS 注意事项

  • 安全组配置:务必在阿里云控制台的安全组中开放 80/443 端口。不要直接暴露数据库端口(3306)。
  • 资源限制:在 docker-compose.yml 中为每个服务添加 deploy.resources.limits 或使用 mem_limit/cpus 防止某个应用耗尽 ECS 内存导致其他应用崩溃。

方案二:Nginx 反向XX + 独立容器(适合多域名/子路径路由)

如果你希望多个应用共享同一个 IP,但通过不同的域名或 URL 路径访问,这是标准做法。

1. 架构设计

  • 入口层:一个 Nginx 容器作为反向XX,监听 80/443。
  • 应用层:各个业务应用以独立容器运行,内部端口随机或不冲突即可,无需暴露给公网。
  • 网络层:所有容器加入同一个 Docker 自定义网络,实现 DNS 解析互通。

2. 关键配置示例

Nginx 配置 (default.conf)

server {
    listen 80;
    server_name app1.example.com;

    location / {
        proxy_pass http://app1_container:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

server {
    listen 80;
    server_name app2.example.com;

    location / {
        proxy_pass http://app2_container:8080;
        proxy_set_header Host $host;
    }
}

启动脚本

# 创建网络
docker network create shared-net

# 启动 App1
docker run -d --name app1 --network shared-net -p 3000:3000 myapp:v1

# 启动 App2
docker run -d --name app2 --network shared-net -p 8080:8080 myapp:v2

# 启动 Nginx (挂载上述配置文件)
docker run -d --name nginx-proxy 
  -p 80:80 
  -v ./nginx/conf.d:/etc/nginx/conf.d 
  --network shared-net 
  nginx:alpine

提示:对于生产环境,建议使用 Traefik 或 Caddy 替代手动配置 Nginx,它们支持自动 SSL 证书申请(Let’s Encrypt),极大简化运维。


方案三:Kubernetes (ACK) 或 Swarm(适合大规模、高可用)

当应用数量超过数十个,或需要自动扩缩容、故障自愈时,单机 Docker Compose 不再适用。此时应转向集群化部署。

选项 A:阿里云 ACK (托管 Kubernetes)

  • 优势:完全托管,无需维护 Master 节点;与阿里云 VPC、SLB、云盘深度集成;符合国内合规要求。
  • 部署流程:
    1. 在阿里云控制台创建 ACK 集群。
    2. 使用 kubectl 连接集群。
    3. 将你的应用打包为 Helm Chart 或直接编写 YAML 部署文件。
    4. 利用 Ingress Controller 实现外部访问。

选项 B:Docker Swarm

  • 优势:比 K8s 轻量,配置简单,原生支持滚动更新和服务发现。
  • 适用场景:小型团队快速搭建高可用集群。
# 初始化 Swarm
docker swarm init

# 部署服务
docker service create --name web --replicas 3 -p 80:80 nginx

阿里云 ECS 专属优化建议(Pro Tips)

无论采用哪种方案,以下操作能显著提升稳定性和安全性:

1. 磁盘性能与数据持久化

  • 问题:ECS 系统盘通常为高效云盘或 SSD,但频繁读写日志可能导致 IOPS 瓶颈。
  • 解决:
    • 将数据库等写密集型数据挂载到 ESSD 云盘。
    • 使用 docker volume 或绑定宿主机的独立数据盘目录。
    • 定期清理 /var/lib/docker 下的未使用镜像和容器,避免撑爆系统盘。

2. 安全组最小化原则

  • 严禁:不要在安全组中开放 2375/2376(Docker API)端口。
  • 推荐:只开放 Web 服务所需的 80/443 端口。数据库、Redis 等服务仅允许在 Docker 内部网络通信,不映射到宿主机端口。

3. 日志管理

  • Docker 默认日志驱动为 json-file,长期运行会占用大量磁盘空间。
  • 修改 daemon.json:
    {
    "log-driver": "json-file",
    "log-opts": {
      "max-size": "10m",
      "max-file": "3"
    }
    }
  • 进阶:在阿里云环境中,可考虑安装 SLS Agent(阿里云日志服务),将 Docker 日志直接采集到 SLS,便于集中监控和分析。

4. 资源隔离与监控

  • 使用 htop 或阿里云云监控插件实时监控 ECS 的 CPU、内存和网络流量。
  • 为 Docker 设置 cgroup 限制,防止单个容器 OOM(Out of Memory)影响宿主机稳定性。

总结建议

场景 推荐方案 理由
个人项目、测试环境、<5 个服务 Docker Compose 简单、易维护、一键启停
多域名、中等复杂度、需统一出口 Nginx/Traefik + 独立容器 灵活的路由控制,清晰的边界
企业级、高可用、自动扩缩容 阿里云 ACK (Kubernetes) 生态完善、官方支持、符合生产标准

最后提醒:在阿里云 ECS 上部署前,请确保已购买足够的带宽和数据盘容量,并根据业务峰值预留至少 20%-30% 的资源余量,以应对突发流量。