第 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_limit 和 cpus 防止资源耗尽 |
| 网络安全 | 生产环境不要暴露不必要的端口 |
| 证书管理 | 定期更新 TLS 证书 |
| 日志大小 | 配置日志轮转防止磁盘占满 |
| 镜像版本 | 使用固定版本标签而非 latest |
扩展阅读
下一章: 第 11 章:故障排查 — 常见问题诊断、连接故障和调试工具。