Sleezr
购买 Sleezr
Dockerhosts 文件macOS容器本地开发

在 Mac 上用 hosts 文件进行 Docker 开发

为 Docker、docker-compose 和容器网络配置 hosts 文件。将服务映射到本地域名,简化 Mac 开发。

S

Sleezr Team

·6分钟阅读
在 Mac 上用 hosts 文件进行 Docker 开发

无需终端,管理 hosts 文件

Sleezr 让您在 Windows、macOS 和 Linux 上可视化管理环境,支持自动 DNS 刷新和备份。

购买 Sleezr, €4.99

一次性购买

Docker 通过提供隔离、可复现的环境革新了本地开发。然而,通过自定义域名访问容器需要协调 Docker 网络与 Mac 的 hosts 文件。本指南将展示如何将 hosts 文件管理与 Docker、docker-compose 和容器网络无缝集成。

如何在 Docker 中使用 hosts 文件

要在 Mac 上通过自定义域名访问 Docker 容器,请在 /etc/hosts 中将域名映射到 `127.0.0.1`,并发布容器端口(例如 `-p 8080:80`),因为 Docker Desktop 在 localhost 上暴露容器。在容器内部访问宿主机服务时,请使用 `host.docker.internal`,无需修改 hosts 文件。

理解 Docker 网络基础

在配置 hosts 文件之前,需了解 macOS 上 Docker 网络的工作原理。

Docker Desktop 网络架构

Mac 上的 Docker Desktop 在 Linux VM 内运行容器。使用 -p 或 docker-compose 中的 ports: 映射端口时,Docker 会在容器网络与 Mac 的 localhost 之间建立桥接。

YAML
services:
  web:
    image: nginx:alpine
    ports:
      - "8080:80"  # Host:Container

这意味着:

  • Mac 的 8080 端口映射到容器的 80 端口
  • 可通过 localhost:8080127.0.0.1:8080 访问
  • 要使用自定义域名,需在 hosts 文件中添加指向 127.0.0.1 的条目

容器间通信

同一 Docker 网络内的容器可通过 docker-compose.yml 中定义的服务名通信,无需修改 hosts 文件:

YAML
services:
  web:
    image: nginx:alpine
    depends_on:
      - api
  
  api:
    image: node:18
    expose:
      - "3000"

web 容器可通过 http://api:3000 访问 API,无需任何 hosts 文件配置。

为 Docker 服务设置自定义域名

基础 hosts 文件配置

最简单的方式是为每个 Docker 服务映射自定义域名:

BASH
# /etc/hosts
127.0.0.1    api.docker.test
127.0.0.1    frontend.docker.test
127.0.0.1    admin.docker.test

在 docker-compose.yml 中:

YAML
version: '3.8'
services:
  api:
    image: node:18
    ports:
      - "3001:3000"
  
  frontend:
    image: nginx:alpine
    ports:
      - "3002:80"
  
  admin:
    image: nginx:alpine
    ports:
      - "3003:80"

访问服务:

  • http://api.docker.test:3001
  • http://frontend.docker.test:3002
  • http://admin.docker.test:3003

多服务使用标准端口

若偏好标准端口(80、443),每个端口只能运行一个服务,使用不同域名:

BASH
# /etc/hosts
127.0.0.1    api.docker.test
127.0.0.1    frontend.docker.test
YAML
services:
  api:
    image: node:18
    ports:
      - "80:3000"  # 通过 api.docker.test:80 访问
  
  frontend:
    image: nginx:alpine
    ports:
      - "8080:80"  # frontend 使用不同端口

子域名的通配符域名

对动态子域名的应用,使用 dnsmasq 配置通配符 DNS:

BASH
# Install dnsmasq
brew install dnsmasq

# Configure wildcard for .docker.test
echo "address=/.docker.test/127.0.0.1" >> /usr/local/etc/dnsmasq.conf

# Create resolver
sudo mkdir -p /etc/resolver
echo "nameserver 127.0.0.1" | sudo tee /etc/resolver/docker.test

# Start dnsmasq
sudo brew services start dnsmasq

现在任何 *.docker.test 域名都会自动解析到 localhost!

Docker Compose 多服务架构

微服务设置

复杂多服务应用示例:

YAML
version: '3.8'
services:
  # Backend API
  api:
    build: ./api
    ports:
      - "3000:3000"
    environment:
      - DATABASE_URL=postgresql://db:5432/myapp
    depends_on:
      - db
  
  # Frontend Application
  frontend:
    build: ./frontend
    ports:
      - "3001:3000"
    environment:
      - API_URL=http://api:3000
  
  # Admin Panel
  admin:
    build: ./admin
    ports:
      - "3002:3000"
  
  # Database
  db:
    image: postgres:15
    environment:
      POSTGRES_DB: myapp
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
    volumes:
      - postgres_data:/var/lib/postgresql/data
  
  # Redis Cache
  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"

volumes:
  postgres_data:

hosts 文件配置:

BASH
# /etc/hosts
# Docker Services
127.0.0.1    api.docker.test
127.0.0.1    frontend.docker.test
127.0.0.1    admin.docker.test

Docker 内服务发现

容器通过服务名互相发现。frontend 容器可调用 http://api:3000,因为 Docker 内部 DNS 将 api 解析为容器 IP。

从 Mac 外部访问时,使用 hosts 文件条目和映射端口。

高级 Docker 网络模式

自定义 Docker 网络

为不同环境创建隔离网络:

YAML
version: '3.8'
networks:
  frontend_network:
    driver: bridge
  backend_network:
    driver: bridge

services:
  frontend:
    image: nginx:alpine
    networks:
      - frontend_network
    ports:
      - "80:80"
  
  api:
    image: node:18
    networks:
      - backend_network
      - frontend_network
    ports:
      - "3000:3000"

api 服务可从两个网络访问,frontend 仅通过共享网络看到 API。

外部网络

将容器连接到现有网络:

YAML
services:
  web:
    image: nginx:alpine
    networks:
      - existing_network

networks:
  existing_network:
    external: true

Host 网络模式(仅 Linux)

在 Linux 上可使用 host 网络模式。macOS 不直接支持,但可通过端口映射达到类似效果。

端口管理策略

避免端口冲突

运行多个 Docker 项目时,端口冲突很常见。策略:

1. 使用不同端口范围

YAML
# Project A
services:
  web:
    ports:
      - "8000:80"

# Project B  
services:
  web:
    ports:
      - "8001:80"

2. 使用环境变量

YAML
services:
  web:
    ports:
      - "\$\{WEB_PORT:-8080}:80"
BASH
# .env file
WEB_PORT=9000

3. 动态端口分配

YAML
services:
  web:
    ports:
      - "0:80"  # Docker 分配随机端口

查看分配的端口:docker psdocker-compose ps

标准端口与反向代理

使用反向代理(Traefik、Nginx)按域名路由:

YAML
version: '3.8'
services:
  traefik:
    image: traefik:v2.10
    command:
      - "--api.insecure=true"
      - "--providers.docker=true"
      - "--entrypoints.web.address=:80"
    ports:
      - "80:80"
      - "8080:8080"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
  
  api:
    image: node:18
    labels:
      - "traefik.http.routers.api.rule=Host(`api.docker.test`)"
      - "traefik.http.services.api.loadbalancer.server.port=3000"
  
  frontend:
    image: nginx:alpine
    labels:
      - "traefik.http.routers.frontend.rule=Host(`frontend.docker.test`)"

配合 hosts 文件条目,所有服务可通过各自域名在 80 端口访问。

Docker 与本地 HTTPS

为 Docker 服务生成 SSL 证书

使用 mkcert 创建受信任证书:

BASH
# Install mkcert
brew install mkcert
mkcert -install

# Create certificate for Docker services
mkcert api.docker.test frontend.docker.test "*.docker.test"

在 Docker 中配置 HTTPS

YAML
services:
  nginx:
    image: nginx:alpine
    ports:
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
      - ./api.docker.test.pem:/etc/nginx/ssl/cert.pem
      - ./api.docker.test-key.pem:/etc/nginx/ssl/key.pem

Traefik 自动 HTTPS

Traefik 可自动处理 HTTPS:

YAML
services:
  traefik:
    image: traefik:v2.10
    command:
      - "--providers.docker=true"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
      - "--certificatesresolvers.letsencrypt.acme.tlschallenge=true"
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./certs:/certs

组织 Docker 的 hosts 文件条目

按项目组织

按项目分组条目:

BASH
# ===================
# DOCKER PROJECT: E-commerce Platform
# ===================
127.0.0.1    shop.docker.test
127.0.0.1    api.shop.docker.test
127.0.0.1    admin.shop.docker.test

# ===================
# DOCKER PROJECT: Blog Platform
# ===================
127.0.0.1    blog.docker.test
127.0.0.1    cms.blog.docker.test

按环境组织

按环境分离:

BASH
# ===================
# DOCKER: Development
# ===================
127.0.0.1    dev-api.docker.test
127.0.0.1    dev-frontend.docker.test

# ===================
# DOCKER: Staging
# ===================
127.0.0.1    staging-api.docker.test
127.0.0.1    staging-frontend.docker.test

Docker Compose 覆盖模式

开发覆盖

使用 docker-compose.override.yml 做本地开发:

YAML
# docker-compose.yml (base)
version: '3.8'
services:
  api:
    image: node:18
    ports:
      - "3000:3000"

# docker-compose.override.yml (local, gitignored)
version: '3.8'
services:
  api:
    volumes:
      - ./src:/app/src  # Hot reload
    environment:
      - NODE_ENV=development

多个 Compose 文件

BASH
# Development
docker-compose -f docker-compose.yml -f docker-compose.dev.yml up

# Production-like
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up

Docker hosts 文件问题排查

自定义域名无法访问容器

问题:域名能解析但连接被拒绝。

解决

1
验证端口映射:docker ps 应显示 0.0.0.0:PORT->...
2
检查容器是否运行:docker-compose ps
3
验证 hosts 条目:ping api.docker.test 应解析到 127.0.0.1
4
检查防火墙设置

端口已被占用

问题Error: bind: address already in use

解决

1
查找占用端口的进程:lsof -i :8080
2
停止冲突容器:docker stop <container>
3
在 docker-compose.yml 中更改端口映射
4
使用不同端口范围

DNS 解析问题

问题:域名无法解析。

解决

1
验证 hosts 文件语法(无多余空格)
2
刷新 DNS 缓存:sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder
3
若使用通配符,检查 dnsmasq
4
重启 Docker Desktop

容器间通信失败

问题:服务无法互相访问。

解决

1
验证服务在同一网络:docker network inspect <network>
2
使用服务名,而非 localhost
3
检查 depends_on 顺序
4
验证 expose/ports 配置

Docker hosts 文件管理最佳实践

1. 使用一致的命名规范

BASH
# Good: Project-based naming
api.projectname.test
frontend.projectname.test

# Avoid: Generic names
api.test
web.test

2. 记录端口映射

在 README 中包含端口文档:

MARKDOWN
## Local Development

- API: http://api.project.test:3000
- Frontend: http://frontend.project.test:8080
- Admin: http://admin.project.test:3001

3. 版本控制 hosts 文件模板

在项目中创建 hosts.example

BASH
# hosts.example
127.0.0.1    api.project.test
127.0.0.1    frontend.project.test

4. 使用环境特定域名

BASH
# Development
dev-api.project.test

# Staging  
staging-api.project.test

# Local
local-api.project.test

5. 自动化 hosts 文件更新

创建脚本将 docker-compose 服务与 hosts 文件同步:

BASH
#!/bin/bash
# sync-docker-hosts.sh

SERVICES=$(docker-compose config --services)
for service in $SERVICES; do
  PORT=$(docker-compose config | grep -A 5 "$service:" | grep -oP 'd+:d+' | head -1 | cut -d: -f1)
  echo "127.0.0.1    $service.docker.test" >> /tmp/docker-hosts
done

与开发工具集成

热重载与卷挂载

YAML
services:
  api:
    build: ./api
    volumes:
      - ./api/src:/app/src  # Hot reload
    ports:
      - "3000:3000"

通过 api.docker.test:3000 访问,代码自动重载。

数据库访问

YAML
services:
  db:
    image: postgres:15
    ports:
      - "5432:5432"  # Expose for external tools

从 Mac 使用 localhost:5432 连接,或在 hosts 文件中添加 db.docker.test

调试工具

YAML
services:
  api:
    image: node:18
    ports:
      - "3000:3000"
      - "9229:9229"  # Node.js debugger

通过 api.docker.test:9229 附加调试器。

结论

有效管理 Docker 的 hosts 文件需要同时理解 Docker 网络和 macOS DNS 解析。遵循本指南中的模式,你可以:

  • 将容器服务映射到易记的域名
  • 避免多项目间的端口冲突
  • 保持清晰、有序的 hosts 文件配置
  • 简化 Docker 开发工作流

记得使用 .test 域名避免冲突、记录端口映射,并利用 Sleezr 等工具高效管理 hosts 条目。正确配置后,Docker 与 hosts 文件可无缝协作,打造高效的本地开发环境。

对使用 Docker 的团队,可考虑 Sleezr(€4.99)分享 hosts 配置、保持环境一致并消除手动编辑负担。Sleezr 可轻松导出、导入并在全团队同步 hosts 条目。

参考资料

延伸阅读如何在 Mac 上编辑 hosts 文件
延伸阅读本地开发完整指南
分享本文

常见问题

如何通过自定义域名访问 Docker 容器?

在 docker-compose.yml 中将容器端口映射到主机端口,然后在 hosts 文件中添加指向 127.0.0.1 的条目。使用 .test 域名避免冲突。

每个 Docker 容器都需要修改 hosts 文件吗?

仅当你需要自定义域名时。同一 Docker 网络内的容器可通过服务名互相访问,无需修改 hosts 文件。

Docker 网络如何与 hosts 文件交互?

hosts 文件只影响 Mac 的 DNS 解析。Docker 容器使用自己的内部 DNS 和网络。通过映射主机端口,可用 hosts 文件条目访问容器。

在 Mac 上 Docker 能用 .local 域名吗?

不推荐。.local 域名与 macOS Bonjour 冲突。改用 .test 或 .localhost 以获得更好性能和兼容性。

如何与团队分享 Docker hosts 文件配置?

导出 hosts 文件条目并纳入项目文档。Sleezr 等工具可轻松在团队成员间分享和同步 hosts 文件配置。

相关文章