强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

IRC 服务器搭建完全指南 / 第 10 章:Docker 部署

第 10 章:Docker 部署

容器化部署让 IRC 服务器的安装、配置和迁移变得简单可靠。本章介绍如何使用 Docker 部署三大主流 IRC 服务端。


10.1 为什么使用 Docker?

10.1.1 Docker 部署 vs 传统部署

特性 传统安装 Docker 部署
环境隔离 ❌ ✅
版本管理 手动 镜像标签
迁移便捷性 低 高
依赖冲突 可能 无
升级风险 高 低(回滚简单)
资源占用 较低 略高(可忽略)
学习成本 低 中
持久化 直接 需配置 volume

10.1.2 Docker 架构

┌──────────────────────────────────────────┐
│               Docker Host                │
│                                          │
│  ┌─────────────┐  ┌─────────────┐       │
│  │  IRC Server │  │  Services   │       │
│  │  Container  │  │  Container  │       │
│  │  (Unreal)   │  │  (Anope)    │       │
│  └──────┬──────┘  └──────┬──────┘       │
│         │                │              │
│         └────────┬───────┘              │
│                  │                      │
│         ┌────────┴────────┐             │
│         │   Docker Network │            │
│         └────────┬────────┘             │
│                  │                      │
│         ┌────────┴────────┐             │
│         │   Volumes       │             │
│         │  - config/      │             │
│         │  - data/        │             │
│         │  - logs/        │             │
│         │  - tls/         │             │
│         └─────────────────┘             │
└──────────────────────────────────────────┘

10.2 Ergo Docker 部署

10.2.1 单容器部署

# 快速启动
docker run -d \
  --name ergo \
  -p 6697:6697 \
  -p 8443:8443 \
  -v /opt/ergo/data:/ircd-data \
  -v /opt/ergo/config:/ircd-config \
  ergochat/ergo:latest

10.2.2 Dockerfile

# Dockerfile
FROM ergochat/ergo:2.14.0

# 设置工作目录
WORKDIR /ircd-data

# 暴露端口
EXPOSE 6667 6697 8080 8443

# 启动命令
CMD ["ergo", "run", "--conf", "/ircd-config/ergo.yaml"]

10.2.3 Docker Compose(Ergo)

# docker-compose.yml
version: "3.8"

services:
  ergo:
    image: ergochat/ergo:2.14.0
    container_name: ergo
    restart: unless-stopped
    ports:
      - "6697:6697"
      - "8443:8443"
      # 明文端口(仅本地调试)
      # - "6667:6667"
    volumes:
      - ./data:/ircd-data
      - ./config/ergo.yaml:/ircd-config/ergo.yaml:ro
      - ./certs/server.crt:/etc/ssl/ergo/server.crt:ro
      - ./certs/server.key:/etc/ssl/ergo/server.key:ro
      - ./logs:/ircd-data/logs
    environment:
      - TZ=Asia/Shanghai
    healthcheck:
      test: ["CMD", "ergo", "version"]
      interval: 30s
      timeout: 10s
      retries: 3
    networks:
      - ircnet

networks:
  ircnet:
    driver: bridge

配置文件 (config/ergo.yaml):

network:
  name: "DockerIRC"

server:
  name: "irc.example.com"

listeners:
  ":6697":
    tls:
      cert: "/etc/ssl/ergo/server.crt"
      key: "/etc/ssl/ergo/server.key"
  ":8443":
    websocket: true
    tls:
      cert: "/etc/ssl/ergo/server.crt"
      key: "/etc/ssl/ergo/server.key"

datastore:
  path: "/ircd-data/ergo.db"

logging:
  - method: "file"
    filename: "/ircd-data/logs/ergo.log"
    level: "info"

10.2.4 生成 TLS 证书

#!/bin/bash
# generate-certs.sh

mkdir -p certs

# 生成自签名证书
openssl req -x509 -newkey rsa:4096 \
  -keyout certs/server.key \
  -out certs/server.crt \
  -days 365 -nodes \
  -subj "/CN=irc.example.com" \
  -addext "subjectAltName=DNS:irc.example.com,DNS:localhost,IP:127.0.0.1"

# 设置权限
chmod 600 certs/server.key
chmod 644 certs/server.crt

10.3 UnrealIRCd Docker 部署

10.3.1 Dockerfile(UnrealIRCd)

# Dockerfile
FROM ubuntu:22.04

# 安装依赖
RUN apt-get update && \
    apt-get install -y \
    wget \
    gnupg2 \
    ca-certificates \
    libssl3 \
    libcurl4 \
    libpcre3 \
    && rm -rf /var/lib/apt/lists/*

# 添加 UnrealIRCd 仓库
RUN wget -qO- https://www.unrealircd.org/downloads/packages.asc | apt-key add - && \
    echo "deb https://www.unrealircd.org/downloads/Linux/deb stable main" > \
    /etc/apt/sources.list.d/unrealircd.list

RUN apt-get update && \
    apt-get install -y unrealircd && \
    rm -rf /var/lib/apt/lists/*

# 复制配置
COPY conf/ /opt/unrealircd/conf/

# 创建数据目录
RUN mkdir -p /opt/unrealircd/data /opt/unrealircd/logs

# 暴露端口
EXPOSE 6697 6900

# 启动命令
CMD ["/opt/unrealircd/unrealircd", "start", "-foreground"]

10.3.2 Docker Compose(UnrealIRCd + Anope)

# docker-compose.yml
version: "3.8"

services:
  unrealircd:
    build:
      context: ./unrealircd
      dockerfile: Dockerfile
    container_name: unrealircd
    restart: unless-stopped
    ports:
      - "6697:6697"
      - "6900:6900"
    volumes:
      - ./unrealircd/conf:/opt/unrealircd/conf:ro
      - ./unrealircd/data:/opt/unrealircd/data
      - ./unrealircd/logs:/opt/unrealircd/logs
      - ./certs:/opt/unrealircd/conf/tls:ro
    environment:
      - TZ=Asia/Shanghai
    networks:
      ircnet:
        ipv4_address: 172.20.0.10

  anope:
    image: anope/anope:latest
    container_name: anope
    restart: unless-stopped
    depends_on:
      - unrealircd
    volumes:
      - ./anope/conf:/opt/anope/conf:ro
      - ./anope/data:/opt/anope/data
      - ./anope/logs:/opt/anope/logs
    environment:
      - TZ=Asia/Shanghai
    networks:
      ircnet:
        ipv4_address: 172.20.0.11

  # 可选:Web 客户端
  kiwiirc:
    image: kiwiirc/kiwiirc:latest
    container_name: kiwiirc
    restart: unless-stopped
    ports:
      - "8080:80"
    volumes:
      - ./kiwiirc/config.json:/opt/kiwiirc/static/config.json:ro
    depends_on:
      - unrealircd
    networks:
      - ircnet

networks:
  ircnet:
    driver: bridge
    ipam:
      config:
        - subnet: 172.20.0.0/16

10.4 InspIRCd Docker 部署

10.4.1 Dockerfile(InspIRCd)

# Dockerfile
FROM inspircd/inspircd:4

# 复制配置
COPY conf/ /opt/inspircd/conf/

# 暴露端口
EXPOSE 6697 6900

# 启动
CMD ["/opt/inspircd/bin/inspircd", "--runasroot", "--config", "/opt/inspircd/conf/inspircd.conf"]

10.4.2 Docker Compose(InspIRCd)

# docker-compose.yml
version: "3.8"

services:
  inspircd:
    image: inspircd/inspircd:4
    container_name: inspircd
    restart: unless-stopped
    ports:
      - "6697:6697"
    volumes:
      - ./conf:/inspircd/conf:ro
      - ./data:/inspircd/data
      - ./logs:/inspircd/logs
      - ./certs:/inspircd/certs:ro
    command: ["--config", "/inspircd/conf/inspircd.conf"]
    networks:
      - ircnet

networks:
  ircnet:
    driver: bridge

10.5 数据持久化

10.5.1 需要持久化的数据

数据类型 说明 持久化方式
配置文件 服务器配置 绑定挂载(bind mount)
数据库 用户账户、频道数据 named volume 或 bind mount
TLS 证书 SSL 证书和密钥 只读绑定挂载
日志文件 运行日志 绑定挂载
MOTD 每日消息 只读绑定挂载

10.5.2 Volume 配置最佳实践

# 使用 named volumes 和 bind mounts 混合
volumes:
  # named volume(Docker 管理)
  ergo-data:
    driver: local

services:
  ergo:
    volumes:
      # 配置文件(只读绑定挂载)
      - ./config/ergo.yaml:/ircd-config/ergo.yaml:ro
      # TLS 证书(只读)
      - ./certs:/etc/ssl/ergo:ro
      # 数据库(named volume)
      - ergo-data:/ircd-data
      # 日志(绑定挂载,便于日志收集)
      - ./logs:/ircd-data/logs

10.5.3 备份策略

#!/bin/bash
# backup-irc.sh - IRC Docker 备份脚本

BACKUP_DIR="/opt/backups/irc/$(date +%Y%m%d_%H%M%S)"
mkdir -p "$BACKUP_DIR"

# 备份容器内数据
docker cp ergo:/ircd-data/ergo.db "$BACKUP_DIR/"
docker cp ergo:/ircd-data/logs/ "$BACKUP_DIR/logs/"

# 备份配置
cp -r ./config "$BACKUP_DIR/"
cp -r ./certs "$BACKUP_DIR/"

# 备份 Docker Compose 文件
cp docker-compose.yml "$BACKUP_DIR/"

# 压缩
tar czf "${BACKUP_DIR}.tar.gz" -C "$BACKUP_DIR" .
rm -rf "$BACKUP_DIR"

# 保留最近 30 天
find /opt/backups/irc/ -name "*.tar.gz" -mtime +30 -delete

echo "备份完成: ${BACKUP_DIR}.tar.gz"
# 使用 cron 定时备份
# crontab -e
0 3 * * * /opt/scripts/backup-irc.sh >> /var/log/irc-backup.log 2>&1

10.6 网络配置

10.6.1 Docker 网络模式

# 网络模式选择
services:
  ergo:
    # 桥接模式(推荐)
    networks:
      - ircnet

    # 主机模式(简化网络配置)
    # network_mode: host

    # 指定端口映射
    ports:
      - "6697:6697"    # IRC TLS
      - "8443:8443"    # WebSocket TLS

10.6.2 容器间通信

# IRC 服务器与服务包通信
services:
  unrealircd:
    networks:
      ircnet:
        ipv4_address: 172.20.0.10

  anope:
    networks:
      ircnet:
        ipv4_address: 172.20.0.11
    # Anope 配置中 uplink 指向 unrealircd
    # uplink: 172.20.0.10:6900

networks:
  ircnet:
    driver: bridge
    ipam:
      config:
        - subnet: 172.20.0.0/16

10.7 反向代理(Nginx + TLS)

# docker-compose.yml 中添加 Nginx
services:
  nginx:
    image: nginx:alpine
    container_name: nginx-proxy
    restart: unless-stopped
    ports:
      - "443:443"
      - "80:80"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
      - ./certs:/etc/nginx/certs:ro
    depends_on:
      - kiwiirc
    networks:
      - ircnet
# nginx/nginx.conf
events {
    worker_connections 1024;
}

stream {
    # IRC TLS 代理
    upstream irc_backend {
        server ergo:6697;
    }

    server {
        listen 6697 ssl;
        proxy_pass irc_backend;

        ssl_certificate /etc/nginx/certs/server.crt;
        ssl_certificate_key /etc/nginx/certs/server.key;
        ssl_protocols TLSv1.2 TLSv1.3;
    }
}

http {
    # WebSocket 代理
    server {
        listen 443 ssl;
        server_name irc.example.com;

        ssl_certificate /etc/nginx/certs/server.crt;
        ssl_certificate_key /etc/nginx/certs/server.key;

        location /webirc {
            proxy_pass http://ergo:8443;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
            proxy_set_header Host $host;
            proxy_read_timeout 86400;
        }

        location / {
            proxy_pass http://kiwiirc:80;
        }
    }
}

10.8 监控与日志

10.8.1 Docker 日志管理

services:
  ergo:
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"

10.8.2 健康检查脚本

#!/bin/bash
# healthcheck.sh

# 检查容器状态
if ! docker ps --filter name=ergo --filter status=running | grep -q ergo; then
    echo "CRITICAL: Ergo 容器未运行"
    docker start ergo
    exit 1
fi

# 检查端口
if ! docker exec ergo ss -tlnp | grep -q ":6697"; then
    echo "WARNING: IRC TLS 端口未监听"
fi

# 检查用户数
USERS=$(docker exec ergo ergo status 2>/dev/null | grep -oP 'users: \K\d+')
echo "当前用户数: $USERS"

10.8.3 Prometheus + Grafana 监控

# docker-compose.yml 添加监控栈
services:
  prometheus:
    image: prom/prometheus:latest
    volumes:
      - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
    ports:
      - "9090:9090"
    networks:
      - ircnet

  grafana:
    image: grafana/grafana:latest
    ports:
      - "3000:3000"
    volumes:
      - grafana-data:/var/lib/grafana
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin
    networks:
      - ircnet

volumes:
  grafana-data:

10.9 完整生产配置

10.9.1 项目结构

irc-docker/
├── docker-compose.yml
├── .env
├── config/
│   ├── ergo.yaml
│   └── nginx.conf
├── certs/
│   ├── server.crt
│   └── server.key
├── data/
│   └── (数据库文件)
├── logs/
│   └── (日志文件)
├── scripts/
│   ├── generate-certs.sh
│   ├── backup.sh
│   └── healthcheck.sh
└── README.md

10.9.2 环境变量配置

# .env
IRC_DOMAIN=irc.example.com
IRC_ADMIN_EMAIL=admin@example.com
ERGO_VERSION=2.14.0
TZ=Asia/Shanghai
LETSENCRYPT_EMAIL=admin@example.com

10.9.3 启动命令

# 首次部署
./scripts/generate-certs.sh
docker compose up -d

# 查看日志
docker compose logs -f ergo

# 更新版本
docker compose pull
docker compose up -d

# 停止服务
docker compose down

# 完全清理(包括数据)
docker compose down -v

10.10 ⚠️ 注意事项

事项 说明
数据持久化 确保 volumes 正确配置,避免数据丢失
文件权限 容器内用户权限与宿主机映射
时区设置 设置 TZ 环境变量确保日志时间正确
资源限制 设置 mem_limit 和 cpus 防止资源耗尽
网络安全 生产环境不要暴露不必要的端口
证书管理 定期更新 TLS 证书
日志大小 配置日志轮转防止磁盘占满
镜像版本 使用固定版本标签而非 latest

扩展阅读


下一章: 第 11 章:故障排查 — 常见问题诊断、连接故障和调试工具。