在 K8s 部署和运行 Canal 集群

相关背景

本文是基于 Canal 最新源码,对于其进行符合业务的优化后,再编译、打包和部署到 K8s。同时,由于在之前的文章已经讨论过 Canal 的 binlog 账户创建、 MySQL 数据库部署,以及相关包变更等,下文不再涉及此类内容。

由于使用 RocketMQ 的服务模式,避免无效编译打包,将目录下 pox.xml 文件中,关于 client-adapterexample 相关模块注释。

在 Canal 源码中(根目录下),docker 文件夹中的脚本文件(*.sh)的功能,是将源码编译打包为容器,以及运行容器。相关文件用途说明如下:

  • build.sh:将源码编码打包为 canal-admincanal-deployer 两个容器镜像;
  • Dockerfile: 用于定义和构建 canal-deployer Docker 镜像;
  • Dockerfile_admin: 用于定义和构建 canal-admin Docker 镜像;
  • image/app.sh: 用于容器启停 canal-deployer 应用;
  • image/app_admin.sh: 用于容器启停 canal-admin 应用;

其它文件暂不作说明。现分 Canal Admin 和 Canal Deployer 两个部分,讨论如何进行 K8s 部署和运行。

Canal Admin

变更运行脚本

由于适配现有 CI/CD 流水线,需要将build.sh转化为流水线步骤,以及调整相应的脚本文件:image/app_admin.sh

转化 build.sh 为流水线步骤

build.sh 中 Admin 相关的内容如下:

rm -rf $BASE/canal.*.tar.gz ;
cd $BASE/../ && mvn clean package -Dmaven.test.skip -Denv=release && cd $current_path ;
cp $BASE/../target/canal.admin-*.tar.gz $BASE/
docker build --no-cache -t canal-admin:xxx $BASE/ -f $BASE/Dockerfile_admin

其中变量 $BASEbuild.sh的目录路径,即/path/canal/docker,该文件实现功能步骤如下:

  1. 删除该目录下名称格式为 canal.*.tar.gz 的所有文件;
  2. 回到 /path/canal 目录,使用 Maven 清理并打包 Canal 源码,生成的最终压缩文件在 /path/canal/target 目录下;
  3. /path/canal/target 目录中的名称格式为 canal.admin-*.tar.gz 的文件,复制到目录 /path/canal/docker
  4. 根据/path/canal/docker/Dockerfile_admin 文件的定义,将目录 /path/canal/docker 下的相关文件打包为容器镜像。

变更 image/app_admin.sh

由于使用独立的 MySQL 的数据库,容器中 MySQL 不再使用,因此,需要移除该文件中 MySQL 相关的内容。与此同时,使用独立的数据库,需要将 K8s 的 ConfigMap 配置的 application.yml 替换到原 conf 下,即在 start_admin() 函数中,添加以下内容:

/bin/rm -f /home/admin/canal-admin/conf/application.yml
cp -f /appconfig/application.yml /home/admin/canal-admin/conf/application.yml

上述代码功能为先删除原有默认配置,再复制 K8s 的 ConfigMap 配置的 application.yml 替换原有配置。

其中,appconfig 为 K8s 的 ConfigMap 挂载目录,在此之前,需要在 K8s 上新建 Key 为 application.yml 的配置,容器启动时,会在 appconfig 目录下,将该配置生成 application.yml文件。

若不这样处理,k8s 部署 canal-admin 数据保存不到canal_manager 中

image/app_admin.shstart_admin() 函数最终如下:

function start_admin() {
    /bin/rm -f /home/admin/canal-admin/conf/application.yml
    cp -f /appconfig/application.yml /home/admin/canal-admin/conf/application.yml
    echo "start admin ..."
    serverPort=`perl -le 'print $ENV{"server.port"}'`
    if [ -z "$serverPort" ] ; then
        serverPort=8080
    fi
    su admin -c 'cd /home/admin/canal-admin/bin/ && sh restart.sh 1>>/tmp/start.log 2>&1'
    sleep 5
    #check start
    checkStart "canal" "nc 127.0.0.1 $serverPort -w 1 -zv 2>/tmp/nc.out && cat /tmp/nc.out | grep -c Connected" 30
}

源码编译打包

在使用流水线进行打包前,我们可以在相关环境使用以下命令进行预验证:

mvn clean package -Dmaven.test.skip -Denv=release

Linux 环境打包生成的文件在在 /path/canal/target 目录下,文件名称格式为 canal.admin-*.tar.gzcanal.deployer-*.tar.gz

构建容器镜像

调整 Docker 代理地址

因中国内政策原因,无法访问 hub.docker.com 获取镜像,构建容器镜像前,需要更新可用的国内镜像代理,以下是截止目前可用的代理地址:

{
  "registry-mirrors": [
    "https://docker.chenby.cn",
    "https://hub-mirror.c.163.com",
    "https://registry.docker-cn.com",
    "https://mirror.ccs.tencentyun.com",
    "https://hub-mirror.c.163.com"
  ]
}

调整 Dockerfile_admin

canal-admin 运行容器不需要 MySQL,我们也不需要将其打包到容器镜像,只需要 Dockerfile_admin 中基础镜像,变更为 (canal-deployer)Dockerfile 中使用的基础镜像,即

##删除原 FROM canal/osadmin:v3-amd64,替换为
FROM canal/osbase:v3-amd64

构建镜像

执行构建命令:

docker build --no-cache -t canal-admin:xxx /path/canal/docker/ -f /path/canal/docker/Dockerfile_admin

构建完成后,再将该包上传到 harbor,然后删除本地镜像,以释放空间。

部署到 K8s

由于 canal-admin-service.yamlcanal-admin-deployment.yaml,视环境而定,这里不再赘述。只给出 canal-admin-configmap.yaml 部分配置:

apiVersion: v1
data:
  application.yml: |-
    server:
      port: 8080
    spring:
      jackson:
        date-format: yyyy-MM-dd HH:mm:ss
        time-zone: GMT+8

    spring.datasource:
      address: ipaddress:3306
      database: canal_manager
      username: canal_user
      password: canal_password
      driver-class-name: com.mysql.jdbc.Driver
      url: jdbc:mysql://${spring.datasource.address}/${spring.datasource.database}?useUnicode=true&characterEncoding=UTF-8&useSSL=false
      hikari:
        maximum-pool-size: 30
        minimum-idle: 1

    canal:
      adminUser: admin
      adminPasswd: 123456
kind: ConfigMap
metadata:
  name: canal-admin-configmap
  namespace: canal

上述配置中 server.port=8080,是通过 K8s 设定 canal-admin-service 的端口是 8080需要保持一致,否则无法访问

Canal Deployer

Canal Deployer 也称 Canal Server,是本次部署的关键,决定 Canal 能否应用的成败。

本文不会说明如何成功运行 ZooKeeper(以下称“ZK”),但一定要确保有正常可用的 ZK。由于 Canal Admin 需要通过 ZK 获取 Canal Server 运行状态,以及 Canal Server 执行 binlog 同步也无法离开 ZK,如果没有正常 ZK,就无法确定 Canal 是否部署成功,也无法开展正常业务。(忽视了 ZK 的可用性,让我额外花了两天排查问题。)

变更运行脚本

与 Admin 一样,