在 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:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: >
      {"apiVersion":"v1","data":{"application.properties":"\nserver.port=8080"},"kind":"ConfigMap","metadata":{"annotations":{},"name":"canal-admin-configmap","namespace":"canal"}}
  creationTimestamp: '2024-08-15T08:38:31Z'
  name: canal-admin-configmap
  namespace: canal
  resourceVersion: '2291952292'
  uid: 37ec96ff-5187-4585-a7ad-1dfce51cf7d2

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

Canal Deployer

(待续)