强曰为道

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

第 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=[email protected]
ERGO_VERSION=2.14.0
TZ=Asia/Shanghai
LETSENCRYPT_EMAIL=[email protected]

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_limitcpus 防止资源耗尽
网络安全生产环境不要暴露不必要的端口
证书管理定期更新 TLS 证书
日志大小配置日志轮转防止磁盘占满
镜像版本使用固定版本标签而非 latest

扩展阅读


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