在 Ubuntu 服务器上同时运行多个 Docker 容器,核心逻辑其实非常清晰:Docker 本身就是为了隔离和并发设计的。只要你的宿主机(Ubuntu)资源(CPU、内存、磁盘 I/O)足够,你可以轻松启动几十甚至上百个容器。
这里不整虚的,直接分场景给你几种最主流、最稳妥的操作方案,从手动到自动化,按复杂度递增。
1. 基础版:手动并行启动(适合少量服务)
这是最直接的方式。每个容器都有独立的名称和网络空间,互不干扰。
关键原则:
- 必须指定
--name:如果不指定,Docker 会随机生成名字,后期管理极其痛苦。 - 端口映射要错开:如果两个容器都对外暴露了同一个宿主机端口(如 80),第二个容器启动时会报错
port is already allocated。
示例命令:
# 启动第一个 Web 服务 (Nginx),占用宿主机 8080 端口
docker run -d --name web-app-1 -p 8080:80 nginx:latest
# 启动第二个数据库服务 (MySQL),占用宿主机 3306 端口
docker run -d --name mysql-db -p 3306:3306 -e MYSQL_ROOT_PASSWORD=yourpassword mysql:8.0
# 启动第三个应用服务,使用自定义网络以便内部通信
docker network create my-net
docker run -d --name app-backend --network my-net your-custom-image
验证是否都在跑:
docker ps
你会看到多个 STATUS: Up 的状态。
2. 进阶版:使用 Docker Compose(推荐用于多服务关联)
当你的应用由多个部分组成(比如前端 Nginx + 后端 Node.js + 数据库 MySQL),手动敲 docker run 容易出错且难以维护。Docker Compose 是行业标准解决方案。
它通过一个 YAML 文件定义所有容器的配置、依赖关系和网络。
步骤:
-
确保 Ubuntu 安装了 Docker Compose(通常安装 Docker 时已附带
docker-compose-plugin)。docker compose version -
创建
docker-compose.yml文件:
version: '3.8'
services:
# 前端服务
frontend:
image: nginx:alpine
ports:
- "80:80"
networks:
- app-network
# 后端 API
backend:
image: node:18-alpine
command: npm start
depends_on:
- database
networks:
- app-network
# 数据库
database:
image: postgres:15
environment:
POSTGRES_PASSWORD: secret
volumes:
- db-data:/var/lib/postgresql/data
networks:
- app-network
volumes:
db-data:
networks:
app-network:
driver: bridge
- 一键启动所有容器:
docker compose up -d
优势:
- 原子性:一起启动,一起停止。
- 依赖管理:
depends_on保证数据库先于后端启动。 - 网络互通:默认在同一网络下,容器间可以通过服务名(如
database)直接访问,无需配置复杂 IP。
3. 生产环境版:集群与编排(Kubernetes / Docker Swarm)
如果你是在阿里云 ECS、腾讯云 CVM 或 AWS EC2 上部署大规模应用,单机手动管理几十个容器会陷入混乱。这时需要引入编排工具。
A. Docker Swarm(轻量级,内置于 Docker)
适合中小规模集群,配置简单。
# 初始化 swarm 集群
docker swarm init
# 部署 stack(基于 compose 文件)
docker stack deploy -c docker-compose.yml mystack
B. Kubernetes (K8s)(工业标准,复杂但强大)
国内大厂普遍采用 K8s。你需要搭建 K8s 集群(可以使用 kubeadm、kops 或直接购买云厂商的 ACK/TKE 托管版)。
在 K8s 中,你不再直接操作“容器”,而是操作 Pod 和 Deployment。
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-web-app
spec:
replicas: 3 # 自动运行 3 个副本,实现高可用
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
为什么选 K8s?
- 自愈能力:容器挂了自动重启。
- 水平扩展:流量大了自动增加 Pod 数量。
- 资源调度:智能分配 CPU/内存,避免单机过载。
4. 关键注意事项(避坑指南)
在实际操作中,很多人遇到“容器跑不起来”或“性能差”,通常是以下原因:
-
资源限制(Cgroups):
- 不要无限制地拉取镜像和启动容器。务必为每个容器设置资源上限,防止某个容器吃光服务器内存导致 OOM(Out of Memory)。
docker run -d --name limited-app --memory="512m" --cpus="1.0" my-image
- 不要无限制地拉取镜像和启动容器。务必为每个容器设置资源上限,防止某个容器吃光服务器内存导致 OOM(Out of Memory)。
-
持久化数据:
- 绝对不要把重要数据存在容器的可写层里!容器一删,数据全没。
- 使用 Volume(卷)或挂载宿主机的目录。
docker run -d -v /host/data:/container/data my-image
-
日志管理:
- 多个容器同时输出日志,很快会撑爆
/var/log/docker.log。 - 建议配置 logrotate,或者将日志输出到 ELK(Elasticsearch, Logstash, Kibana)等集中式日志系统。
- 多个容器同时输出日志,很快会撑爆
-
防火墙与安全组:
- Ubuntu 自带
ufw,云服务器有安全组。 - 只开放必要的端口(如 80, 443, 22)。不要随意
-p 0.0.0.0:8080:80暴露调试端口到公网。
- Ubuntu 自带
-
网络模式选择:
bridge(默认):大多数情况够用。host:性能最好,无 NAT 开销,但端口冲突风险极高,慎用。none:完全无网络,用于离线计算任务。
总结建议
- 个人项目/测试环境:直接用
docker compose,一个 YAML 文件搞定所有依赖,省心省力。 - 小型生产环境:继续使用
docker compose,配合systemd守护进程,确保开机自启。 - 大型分布式系统:上 Kubernetes(K8s),或者直接使用云厂商的容器服务(如阿里云 ACK、腾讯云 TKE),免去运维底层基础设施的麻烦。
记住,Docker 只是容器运行时,真正的挑战在于架构设计和运维规范。先从 Compose 开始,逐步演进到更复杂的编排体系。
云技术博客