Skip to content

Canal 部署(集群 192.168.122.31 / RKE2)

使用私有仓库镜像在 K8s 集群部署 Canal v1.1.8(MySQL binlog 增量订阅与消费组件)。

架构

                 ┌──────────────────────────────────────────────┐
                 │ namespace: canal                             │
   NodePort      │  ┌─────────────┐          ┌────────────────┐ │
  :30889 ──────► │  │ canal-admin │◄────────►│ canal-server-0 │ │
   (Web UI)      │  │  :8089      │  11110   │ 11111/11110/   │ │
                 │  └──────┬──────┘          │ 11112          │ │
                 │         │                 └───────┬────────┘ │
                 └─────────┼─────────────────────────┼──────────┘
                           │ JDBC (canal_manager 库) │ binlog 伪装从库
                           ▼                         ▼
                 ┌─────────────────────────────────────────────┐
                 │ namespace: mysql                            │
                 │ mysql-primary.mysql.svc.cluster.local:3306  │
                 └─────────────────────────────────────────────┘
组件说明端口
canal-servercanal deployer,伪装 MySQL slave 拉取 binlog11111 (客户端 TCP) / 11110 (admin) / 11112 (metrics)
canal-admin管理控制台 Web UI8089 → NodePort 30889

前置条件(已完成)

  1. 镜像已推送私有仓库:
    • 192.168.122.156:30000/canal/canal-admin:v1.1.8
    • 192.168.122.156:30000/canal/canal-server:v1.1.8
    • (Harbor canal 公共项目,ddn-k8s/docker.io/canal/* 同步而来)
  2. RKE2 节点 /etc/rancher/rke2/registries.yaml 已配置私有仓库认证(HTTP + insecure_skip_verify),拉取无需 imagePullSecret。
  3. MySQL 8.4(复用 mysql 命名空间已有主从集群):
    • log_bin=ONbinlog_format=ROWbinlog_row_image=FULL
    • 已创建 canal 用户(caching_sha2_password,Canal 1.1.5+ 自研协议与 mysql-connector-j 8.0.33 均支持;无需开启已禁用的 mysql_native_password)。
    • 已导入 canal_manager 元数据库(脚本来自 canal-admin 镜像内置 /home/admin/canal-admin/conf/canal_manager.sql)。

公网访问(HTTPS)

地址:https://ai-ear.cn:30889/(公网出口经 Traefik TLS 终止 + basicAuth)

外网 → https://ai-ear.cn:30889
  → 公网 8.153.84.140 Traefik v3(ep30889,TLS 终止 + basic-auth 中间件)
  → 127.0.0.1:19089(frps 隧道,remotePort)
  → 本机 frpc(systemd user service: frpc-canal-admin.service)
  → 192.168.122.31:30889(K8s NodePort → canal-admin Pod:8089)
位置配置
公网反向代理8.153.84.140:/etc/traefik/traefik.yamlentryPoint ep30889: ":30889"
路由/服务8.153.84.140:/etc/traefik/dynamic.yamlrouter canal-admin-30889(basic-auth + tls)→ service svc-19089http://127.0.0.1:19089
frp 隧道本机 /home/xxx/config/frp/frpc-canal-admin.tomlremotePort=19089 → localIP=192.168.122.31 localPort=30889
frpc 服务本机 ~/.config/systemd/user/frpc-canal-admin.servicesystemctl --user status frpc-canal-admin

访问凭据(两层)

  1. basicAuth(Traefik 层):\1xxx\2(/etc/traefik/.htpasswd,与其他 9xxx 服务共用)
  2. canal-admin 应用登录:\1xxx\2
bash
# 验证
curl -sk -o /dev/null -w '%{http_code}\n' https://ai-ear.cn:30889/            # 401(无 basicAuth)
curl -sk -u 'admin:xxx' -o /dev/null -w '%{http_code}\n' \
  https://ai-ear.cn:30889/                                                    # 200

文件清单

canal/
├── README.md                     # 本文档
├── 00-namespace.yaml             # namespace canal
├── 01-secret.yaml                # 三个密码(mysql/admin 登录/server admin 端口)
├── 02-canal-server.yaml          # ConfigMap + StatefulSet + Service(PVC 持久化位点)
├── 03-canal-admin.yaml           # ConfigMap + Deployment + NodePort Service
└── mysql-init/
    ├── init-user.sql             # canal 用户创建与授权(已执行,留档)
    └── canal_manager.sql         # canal-admin 元数据库表结构(已执行,留档)

关键实现细节

1. 为什么用 initContainer 注入配置?

  • canal-admin:启动脚本用 perl 读取 spring.datasource.address 这类带点号的环境变量,而 K8s env 名称必须是 [A-Za-z_][A-Za-z0-9_]*(不允许点号),无法直接注入 → 由 initContainer 渲染 application.yml 后整目录挂载。
  • canal-server:镜像内 conf/example/instance.properties 为硬编码值(无 ${ENV} 占位符),同样由 initContainer 从 ConfigMap 注入并替换密码占位符。
  • initContainer 仅首次启动复制镜像默认配置,之后只更新配置文件,PVC 中的 meta.dat 位点数据得以保留,Pod 重启不丢位点。

2. MySQL 8.4 认证兼容

  • MySQL 8.4 默认禁用 mysql_native_password 插件(SHOW PLUGINS 为 DISABLED,且无法运行时安装)。
  • canal-server binlog 连接使用 Canal 自研 MySQL 协议(1.1.5+ 支持 caching_sha2_password RSA 公钥交换)。
  • canal-admin 携带 mysql-connector-j-8.0.33,JDBC URL 需追加 allowPublicKeyRetrieval=true(无 SSL 场景下 caching_sha2_password 首次认证需取服务端 RSA 公钥)。

3. 端口规划

服务类型端口
canal-adminNodePort30889 → 8089
canal-serverClusterIP11111 / 11110 / 11112

凭证

用途账号密码xxx
MySQL canal 用户canalkFiuzPs1I7sU9i6zpXehSecret canal-secret/mysql-password
canal-admin Web 登录adminCanal@2026#AdminSecret canal-secret/admin-login-password
canal-server admin 端口 (11110)adminxxxSecret canal-secret/server-admin-password

部署/更新

bash
export KUBECONFIG=~/.kube/config-122.31
kubectl apply -f 00-namespace.yaml -f 01-secret.yaml -f 02-canal-server.yaml -f 03-canal-admin.yaml
kubectl -n canal get pods -w

MySQL 初始化(仅新环境需要):

bash
kubectl exec -i -n mysql mysql-primary-0 -c mysql -- mysql -uroot -p'&lt;root密码&gt;' < mysql-init/init-user.sql
# canal_manager.sql 可从 canal-admin 镜像提取,本目录已留档
kubectl exec -i -n mysql mysql-primary-0 -c mysql -- mysql -uroot -p'&lt;root密码&gt;' < mysql-init/canal_manager.sql

验证

bash
# 1. Pod 状态(两者均 1/1 Running)
kubectl -n canal get pods

# 2. canal-server 日志(出现 "the canal server is running now" 即成功)
kubectl -n canal exec canal-server-0 -- tail -20 /home/admin/canal-server/logs/canal/canal.log
# example instance 连接成功标志:
#   find start position successfully, EntryPosition[journalName=mysql-bin.xxxxx...]

# 3. 登录 API 验证(返回 code:20000 与 token)
curl -s -X POST http://<节点IP>:30889/api/v1/user/login \
  -H 'Content-Type: application/json' \
  -d '{"username":"admin","password":"Canal@2026#Admin"}'

# 4. 端到端 binlog 捕获验证: 向 MySQL 写数据后查看 produce 计数增长
kubectl -n canal exec canal-server-0 -- wget -qO- 'http://127.0.0.1:11112/metrics?dest=example' \
  | grep canal_instance_store_produce_seq

canal-admin 登录密码的存储格式(重要)

canal_manager.sql 预置 admin 用户(官方默认密码 xxx),密码列存储为 大写十六进制的双重 SHA1SHA1(SHA1(password))(登录比对采用 MySQL-4.1.1 scramble 认证,SecurityUtil.scramble411/scrambleServerAuth)。

application.yml 中的 canal.adminPasswd 仅当数据库中不存在 admin 用户时 才作为初始化密码生效;本部署已导入预置用户,故直接更新数据库:

bash
HASH=$(python3 -c "import hashlib; print(hashlib.sha1(hashlib.sha1(b'<新密码>').digest()).hexdigest().upper())")
kubectl exec -n mysql mysql-primary-0 -c mysql -- \
  mysql -uroot -p'<root密码>' -e "UPDATE canal_manager.canal_user SET password='xxx' WHERE username='xxx';"
# 注意: canal-admin 有 EBean L2 缓存,更新后需重启 Pod: kubectl -n canal delete pod -l app=canal-admin

在 canal-admin 中纳管 canal-server

  1. 登录 Web UI(http://<节点IP>:30889)
  2. Canal Server → 主机管理 → 新建
    • 主机地址:canal-server.canal.svc(或 Pod IP),端口 11110
    • 账号:xxx server-admin-password
  3. 新建 Instance:名称 example,数据源指向 mysql-primary.mysql.svc.cluster.local:3306,dbUsername/dbPassword 使用 canal 用户,投放到该 Server。 (本部署 canal-server 已通过 ConfigMap 内置 example instance,可直接在界面查看运行状态。)

客户端连接示例

地址: canal-server.canal.svc.cluster.local:11111
destination: example

常用运维

bash
# 查看 binlog 位点
kubectl -n canal exec canal-server-0 -- cat /home/admin/canal-server/conf/example/meta.dat

# 重启(位点保留在 PVC)
kubectl -n canal rollout restart statefulset/canal-server

# 完全重建(会重新从 binlog 起始位置消费,慎用)
kubectl -n canal delete pvc conf-canal-server-0 && kubectl -n canal delete sts canal-server
kubectl apply -f 02-canal-server.yaml