kikimo

利用 ansible 部署 zookeeper 集群

本文介绍如何利用 ansible 部署 zookeeper 集群。 zookeeper 的部署可以分为以下几个步骤:

  1. 在部署节点创建部署目录
  2. 上传并解压 zookeeper 应用包
  3. 初始化 zookeeper 配置文件
  4. 启动 zookeeper 服务

步骤 1-3 可用 ansible task 来实现, 最后一个步骤使用 handler 来实现, 利用 handler 的好处在于: 只有步骤 1-3 中对节点配置做了变更后才会触发 zookeeper 重启。

需要创建的部署目录有:

  1. /opt/infra, 这个目录作为 zookeeper 的安装目录
  2. /tmp/zookeeper, 这个目录作为 zookeeper 的 data 目录
  tasks:
    - name: Create zookeeper installation directory
      file:
        path: "{{item}}"
        state: directory
      notify: Restart zookeeper service
      with_items:
          - /opt/infra
          - /tmp/zookeeper

这里使用了with_items迭代创建目录, 如果文件是第一次创建notify指令会调用Restart zookeeper service handler来重启 zookeeper 服务。

上传 zookeeper 包:

    - name: Upload zookeeper package
      unarchive:
        src: ./infra_pkgs/apache-zookeeper-3.5.7-bin.tar.gz
        dest: /opt/infra
      notify: Restart zookeeper service

这里使用unarchive模块来传输和解压 zookeeper 包, 很神奇的一点是unarchive模块能感知到文件解压后跟之前对比是否有变化, 根据这一点我们我们仍旧可以是用notify指令来触发 zookeeper 重启的handler。 关于handler的知识点:

  1. 所有task都执行完以后才会执行被触发的handler
  2. 如果多个task都触发了同一个handler, 那么这个handler最终也只会被执行一次。

初始化 zookeeper 配置:

    - name: Init zookeeper config
      template:
        src: "{{item.src}}"
        dest: "{{item.dest}}"
      with_items: "{{cfg_files}}"
      notify: Restart zookeeper service

需要初始化的配置文件我们放在变量cfg_files中, 配置文件使用模板来渲染,所以我们用到了template模块; cfg_files是一个字典列表, 每个字典中的src字段对应本地模板文件, dest对应模板渲染后的上传路径。

  vars:
      cfg_files:
        - src: "./infra_pkgs/zoo.cfg.j2"
          dest: "/opt/infra/apache-zookeeper-3.5.7-bin/conf/zoo.cfg"
        - src: "./infra_pkgs/myid.j2"
          dest: "/tmp/zookeeper/myid"
        - src: "./infra_pkgs/zk.sh"
          dest: "/etc/profile.d/zk.sh"

一共有三个模板, zoo.cfg.j2是 zookeeper 的配置文件模板:

tickTime=2000
initLimit=10
syncLimit=5
dataDir=/tmp/zookeeper
dataDir={{zk_data_dir}}
dataLogDir={{zk_datalog_dir}}
clientPort=2181

# server.1=@zknode1:2888:3888
# server.2=@zknode2:2888:3888
# server.3=@zknode3:2888:3888
{% for server in zk_servers %}
server.{{loop.index}}={{server.ip}}:{{zk_communication_port}}:{{zk_election_port}}
{% endfor %}

autopurge.snapRetainCount=5
autopurge.purgeInterval=1
maxClientCnxns=2000

zk_servers是个字典变量, 里面存放了 zookeeper 的节点配置信息, 这是个字典列表变量, 后面会介绍。 这里我们通过迭代zk_servers变量渲染出 zookeeper 服务的节点配置。

./infra_pkgs/myid.j2是 zookeeper 的myid文件模板:

{% for server in zk_servers %}
{% if inventory_hostname == server.ip %}
{{server.myid}}
{% endif %}
{% endfor %}

节点的myid信息存放在变量zk_servers变量中, 这里我们通过迭代zk_servers列表, 通过和inventory_hostname对比(inventory_hostname存放当前操作的节点名)获取当前节点的myid信息。

./infra_pkgs/zk.sh模板用户渲染 zookeeper 的profile配置文件:

export ZK_HOME=/opt/infra/apache-zookeeper-3.5.7-bin
export PATH=$PATH:$ZK_HOME/bin

在以上模板中可以看到几个前面没提过的变量: zk_data_dir, zk_data_dir, zk_datalog_dir 等, 这些变量是 zookeeper 的配置变量, 用于控制诸如:zookeeper 集群都包含哪些机器,zookeeper 的数据目录,服务端口等配置。 我们通过命令行参数传递这些变量:

$ ansible-playbook zookeeper.yaml \
    -e '{ "zk_servers": [ {"ip": "127.0.0.1", "myid": 1 } ], "zk_election_port": 3888, "zk_communication_port": 2888, "zk_data_dir": "/tmp/zookeeper", "zk_datalog_dir": "/opt/infra/apache-zookeeper-3.5.7-bin/logs" }'

服务重启handler

  handlers:
    - name: Restart zookeeper service
      shell:
        cmd: /opt/infra/apache-zookeeper-3.5.7-bin/bin/zkServer.sh restart

这里通过shell模块直接执行指令/opt/infra/apache-zookeeper-3.5.7-bin/bin/zkServer.sh restart来重启 zookeeper 服务, 这个做法目前有个问题, 如果服务启动失败了整个部署脚本仍然会显示部署成功, 这是需要优化的一个点。

来看完整的 ansibleplaybook

---
- hosts: "{{ zk_servers | map(attribute='ip') | list }}"
  vars:
      cfg_files:
        - src: "./infra_pkgs/zoo.cfg.j2"
          dest: "/opt/infra/apache-zookeeper-3.5.7-bin/conf/zoo.cfg"
        - src: "./infra_pkgs/myid.j2"
          dest: "/tmp/zookeeper/myid"
        - src: "./infra_pkgs/zk.sh"
          dest: "/etc/profile.d/zk.sh"
  gather_facts: no
  user: root
  tasks:
    - name: Create zookeeper installation directory
      file:
        path: "{{item}}"
        state: directory
      notify: Restart zookeeper service
      with_items:
          - /opt/infra
          - /tmp/zookeeper
    - name: Upload zookeeper package
      unarchive:
        src: ./infra_pkgs/apache-zookeeper-3.5.7-bin.tar.gz
        dest: /opt/infra
      notify: Restart zookeeper service
    - name: Init zookeeper config
      template:
        src: "{{item.src}}"
        dest: "{{item.dest}}"
      with_items: "{{cfg_files}}"
      notify: Restart zookeeper service
  handlers:
    - name: Restart zookeeper service
      shell:
        cmd: /opt/infra/apache-zookeeper-3.5.7-bin/bin/zkServer.sh restart

通过管道映射处理, 我们把zk_servers变量中的节点 IP 地址提取出来, 这些 IP 是我们要部署的目标机器:{{ zk_servers | map(attribute='ip') | list }}