Skip to content

05 网络与存储

容器默认是相互隔离的。如果Agent容器和Redis容器不在同一个网络中,它们就无法直接通信。另一个常见问题是:容器删除后,容器内部的数据也会随之消失,例如对话记录或数据库文件。

Docker网络用于处理容器通信,Docker存储用于处理数据持久化。

一、端口映射

容器有自己独立的网络命名空间,默认和外部隔离。要从宿主机访问容器里的服务,需要做端口映射。

1.1 基本用法

bash
# 宿主机8080端口 → 容器80端口
docker run -d -p 8080:80 nginx

格式是-p 宿主机端口:容器端口。这时访问http://localhost:8080,请求就会被转发到容器的80端口。

1.2 EXPOSE vs 端口映射

Dockerfile里的EXPOSE只是声明,不会实际发布端口。要从外部访问,必须在docker run时用-p映射,或者在compose.yaml里配置ports

yaml
# compose.yaml
services:
  web:
    ports:
      - "8000:5000"

1.3 端口映射注意事项

映射端口时需要注意以下几点:

  • 一个宿主机端口只能映射给一个容器
  • 不指定宿主机端口让Docker自动分配:-p 80(容器80端口映射到宿主机的随机端口)
  • 绑定到特定网卡:-p 127.0.0.1:8080:80(只允许本机访问)

安全提醒: 端口映射默认绑定到所有网卡(0.0.0.0),意味着任何能访问宿主机的人都可能访问这个端口。数据库这类敏感服务不要直接暴露端口;确实需要映射时,也应尽量绑定到127.0.0.1

二、容器网络

2.1 默认网络

Docker安装后会创建一个默认的bridge网络。直接用docker run启动的容器,默认都会连接到这个网络。

bash
# 查看Docker网络列表
docker network ls

输出类似:

NETWORK ID     NAME      DRIVER    SCOPE
a1b2c3d4e5f6   bridge    bridge    local
f6e5d4c3b2a1   host      host      local
1a2b3c4d5e6f   none      null      local

Docker内置网络如下:

网络说明
bridge默认网络,容器之间通过虚拟网桥通信
host容器直接使用宿主机的网络栈,没有隔离
none没有网络,容器完全断网

2.2 容器间通信

在同一个bridge网络中,容器之间可以用容器名作为主机名互相访问。

bash
# 创建自定义网络
docker network create my-network

# 启动Redis,加入my-network
docker run -d --name redis --network my-network redis:alpine

# 启动Agent服务,加入my-network
docker run -d --name agent --network my-network my-agent:1.0

在Agent容器中,可以直接用redis这个主机名连接Redis:

python
import redis
r = redis.Redis(host='redis', port=6379)

使用Compose时通常不需要手动创建网络。 Compose会自动创建一个默认网络,所有服务都会加入进去,服务名就是主机名。

2.3 网络别名

一个容器也可以配置多个网络别名:

bash
docker run -d --network my-network --network-alias db --network-alias database postgres

其他容器可以用dbdatabase访问这个容器。

三、数据持久化

容器被删除后,容器内部的数据也会被删除。例如在容器中运行Redis并写入数据,执行docker rm删除容器后,这些数据也会消失。

Docker提供了两种常用的数据持久化方式:Volume(数据卷)和Bind Mount(绑定挂载)。

3.1 Volume(数据卷)

Volume是Docker管理的存储区域,它独立于容器生命周期。容器删除后,Volume仍然保留。

bash
# 创建Volume
docker volume create my-data

# 启动容器并挂载Volume
docker run -d -v my-data:/data redis:alpine

-v my-data:/data表示把my-data这个Volume挂载到容器的/data目录。容器写入/data的数据,实际会保存到Volume中。

验证数据持久化:

bash
# 启动Redis并写入数据
docker run -d --name redis1 -v redis-data:/data redis:alpine
docker exec redis1 redis-cli SET mykey "hello"

# 删除容器
docker rm -f redis1

# 用同一个Volume启动新容器
docker run -d --name redis2 -v redis-data:/data redis:alpine
docker exec redis2 redis-cli GET mykey
# 输出: "hello"

数据仍然存在,因为Volume没有随容器一起删除。

3.2 Volume管理

bash
# 列出所有Volume
docker volume ls

# 查看Volume详情
docker volume inspect my-data

# 删除指定Volume
docker volume rm my-data

# 删除所有未使用的Volume
docker volume prune

在Compose里使用Volume:

yaml
services:
  redis:
    image: redis:alpine
    volumes:
      - redis-data:/data

# 声明Volume
volumes:
  redis-data:

docker compose down不会删除Volume,数据会保留。docker compose down -v才会同时删除Volume。

3.3 Bind Mount(绑定挂载)

Bind Mount会把宿主机上的目录直接挂载到容器里。和Volume不同,Bind Mount中的文件直接存放在宿主机上,可以用编辑器直接修改。

bash
# 把当前目录挂载到容器的/app
docker run -d -v $(pwd):/app my-app:1.0

Bind Mount适合开发场景:宿主机上的代码修改后,容器内可以立即看到变化。但它不适合生产环境,因为它依赖宿主机上的具体目录结构。

在Compose里使用Bind Mount:

yaml
services:
  web:
    build: .
    volumes:
      - ./src:/app/src    # 绑定挂载
      - redis-data:/data   # 命名卷

3.4 Volume vs Bind Mount

对比项VolumeBind Mount
管理方Docker管理用户管理
存储位置Docker数据目录宿主机任意目录
可移植性高(不依赖宿主机路径)低(依赖宿主机路径)
适合场景数据持久化(数据库、日志)开发时挂载代码
性能Linux上好,Mac/Windows上有性能问题

生产环境优先用Volume,开发环境常用Bind Mount。

四、网络和存储的组合

结合网络和存储,一个Agent服务可以这样组织:

yaml
services:
  web:
    build: .
    ports:
      - "8000:5000"
    environment:
      - REDIS_HOST=redis
    volumes:
      - app-logs:/app/logs
    depends_on:
      redis:
        condition: service_healthy

  redis:
    image: redis:alpine
    volumes:
      - redis-data:/data
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 5s
      timeout: 3s
      retries: 5

volumes:
  redis-data:
  app-logs:

该配置包含以下内容:

  • web和redis在同一个网络里,web用redis主机名访问redis
  • web的5000端口映射到宿主机的8000端口
  • redis的数据持久化到redis-data
  • web的日志持久化到app-logs
  • 健康检查保证redis就绪后再启动web

五、总结

概念作用
端口映射(-p从宿主机访问容器服务
bridge网络默认网络,容器间用服务名通信
VolumeDocker管理的数据持久化,适合生产
Bind Mount宿主机目录直接挂载,适合开发
depends_on + healthcheck控制启动顺序,保证依赖就绪

实际使用时,可以遵循以下原则:

  1. 端口映射要谨慎——敏感服务不要直接暴露,或者绑定到127.0.0.1
  2. 数据要持久化——数据库、日志等数据要用Volume,否则容器删除后数据也会丢失
  3. 生产用Volume,开发用Bind Mount

后续实战会把前面的概念串联起来,部署一个完整的AI Agent服务。