Apache Nifiクラスタ構成の備忘録


はじめに

Apache Nifiを最近知った。

WebSocketが使えたり、簡単なMQサーバに出来たり、・・・とデータフローを視覚的にデザインしスケジュールし分散実行することができる。とても面白い。

スタンドアロンは簡単にできたものの、クラスタ構成を作るのに、ずいぶん手間取ったので、設定などの備忘録。

前提

  • Dockerでやる(何台もAWSにEC2立てる金がもったいないので、便宜上です。)
  • 3つのNifiノード(それぞれ、nifi1,nifi2,nifi3というホスト名)
  • 1つのZookeeperノード(zookeeperというホスト名)
  • NiFiにある内蔵Zookeeperは利用しない

(※実運用環境などではZookeeperも複数ノード用意すべきだが、そこは目的とは異なるので割愛)

手順

Dockerイメージの作成

結構ええ加減な作り方してます。使いやすくするには環境変数とかで、パラメータ調整できるようにすべきかもしれませんが、設定ファイルを直接マウントする形で進めます。

Apache Nifi

Dockerfile

FROM openjdk:11-jre

# nifiユーザの作成
RUN addgroup --system --gid 1001 nifi &&\
    adduser --system --home /home/nifi --shell /bin/bash --uid 1001 --gid 1001 nifi &&\
    cd /home/nifi
USER nifi
WORKDIR /home/nifi

# Apache Nifiのダウンロードと展開とパス通す
RUN wget ftp://ftp.riken.jp/net/apache/nifi/1.12.1/nifi-1.12.1-bin.tar.gz &&\
    tar -xf nifi-1.12.1-bin.tar.gz
ENV NIFI_HOME=/home/nifi/nifi-1.12.1
ENV PATH=$PATH:$NIFI_HOME/bin

EXPOSE 8080
CMD ["nifi.sh","run"]

ビルドする

$ sudo docker build -t mynifi .

nifi.properties

Dockerイメージをビルド後、nifi.propertiesをHOST側へ持っていって編集。各ノード分用意する。

$ docker run --rm mynifi cat /home/nifi/nifi-1.12.1/conf/nifi.properties > nifi1.properties
$ vi nifi1.properties

変更するところだけ抜き出し

#(中略)
#ノードのホスト名と合わせる
nifi.remote.input.host=nifi1

#適当なポートを設定
nifi.remote.input.socket=8090

#ノードのホスト名と合わせる
nifi.web.http.host=nifi1

#trueに変更
nifi.cluster.is.node=true

#ノードのホスト名と合わせる
nifi.cluster.node.address=nifi1

# 適当なポートを設定
nifi.cluster.node.protocol.port=8091

# ノードのリーダー選挙時間。デフォ5分が長くて待つのが面倒だったので、ちょっと短くした。
nifi.cluster.flow.election.max.wait.time=1 min

# 複数Zookeeperを指定する時はカンマ区切りで並べる
nifi.zookeeper.connect.string=zookeeper1:2181

state-management.xml

$ sudo docker run --rm mynifi cat /home/nifi/nifi-1.12.1/conf/state-management.xml > state-management.xml
$ vi state-management.xml

<!-- 中略 -->
<cluster-provider>
    <id>zk-provider</id>
    <class>org.apache.nifi.controller.state.providers.zookeeper.ZooKeeperStateProvider</class>
    <!-- Zookeeperの宛先を設定 -->
    <property name="Connect String">zookeeper1:2181</property>
    <property name="Root Node">/nifi</property>
    <property name="Session Timeout">10 seconds</property>
    <property name="Access Control">Open</property>
</cluster-provider>

Apache Zookeeper

NiFiには内蔵Zookeeperがあり、nifi.state.management.embeded.zookeeper.start=trueとすればNiFiと同時にZookeeperも起動できるが、より実運用に近いイメージで外部のZookeeperを使うようにする。

Apache Kafkaなどで他に立てているZookeeperノードがあるなら、そちらに繋げても問題ないと思う。

Dockerfile


FROM openjdk:11-jre

RUN mkdir /home/zookeeper && mkdir /var/lib/zookeeper
WORKDIR /home/zookeeper

RUN wget https://downloads.apache.org/zookeeper/zookeeper-3.6.2/apache-zookeeper-3.6.2-bin.tar.gz &&\
    tar xzf apache-zookeeper-3.6.2-bin.tar.gz

ENV ZOOKEEPER_HOME=/home/zookeeper/apache-zookeeper-3.6.2-bin
ENV PATH=$PATH:$ZOOKEEPER_HOME/bin

COPY Start.sh /home/zookeeper/Start.sh
CMD ["./Start.sh"]

Start.sh

ZookeeperはmyidファイルをZookeeperのデータディレクトリ(/var/lib/zookeeper)に作成しておく必要がある。Dockerコンテナ実行時に環境変数で渡して、生成するようにシェルスクリプトを作成しておく。

#!/bin/bash
echo $ZOOKEEPER_MYID > /var/lib/zookeeper/myid
zkServer.sh start-foreground

zoo.cfg

Zookeeperのconfディレクトリにある、zoo_sample.cfgファイルをコピーして、zoo.cfgという名前で編集する。

$ sudo docker build -t myzookeeper .
$ sudo docker run --rm myzookeeper cat /home/zookeeper/apache-zookeeper-3.6.2/conf/zoo_sample.cfg > zoo.cfg
$ vi zoo.cfg
# 最終行にでも以下を追記する。この1は先ほどのZOOKEEPER_MYIDと紐づく
server.1=zookeeper:2888:3888

Docker-Composeの作成

Dockerイメージの準備ができたので、Docker-Composeファイル作成する

docker-compose.yaml

version: '3'
services:
  zookeeper:
    build: ./zookeeper
    image: "myzookeeper"
    container_name: "zookeeper"
    environment:
      ZOOKEEPER_MYID: 1
    volumes:
      - ./zookeeper/zoo.cfg:/home/zookeeper/apache-zookeeper-3.6.2-bin/conf/zoo.cfg

  nifi1:
    build: ./nifi
    image: "mynifi"
    container_name: "nifi1"
    ports:
      - 8080:8080
    volumes:
      - ./nifi/nifi1.properties:/home/nifi/nifi-1.12.1/conf/nifi.properties
      - ./nifi/state-management.xml:/home/nifi/nifi-1.12.1/conf/state-management.xml
  nifi2:
    build: ./nifi
    image: "mynifi"
    container_name: "nifi2"
    ports:
      - 8081:8080
    volumes:
      - ./nifi/nifi2.properties:/home/nifi/nifi-1.12.1/conf/nifi.properties
      - ./nifi/state-management.xml:/home/nifi/nifi-1.12.1/conf/state-management.xml    
  nifi3:
    build: ./nifi
    image: "mynifi"
    container_name: "nifi3"
    ports:
      - 8082:8080
    volumes:
      - ./nifi/nifi3.properties:/home/nifi/nifi-1.12.1/conf/nifi.properties
      - ./nifi/state-management.xml:/home/nifi/nifi-1.12.1/conf/state-management.xml  

出来上がったディレクトリ構成

+ /project_root
  - docker-compose.yaml
  + /nifi
    - Dockerfile
    - nifi1.properties
    - nifi2.properties
    - nifi3.properteis
    - state-mnagement.xml
  + /zookeeper
    - Dockerfile
    - zoo.cfg
    - Start.sh

実行!

$ sudo docker-compose up -d

1分ほどリーダ選挙が行われるのでしばらく、待つ。docker execでApache NiFiの$NIFI_HOME/logs/nifi-app.logtail -fして眺めてもいい。

http://localhost:8080/nifiにブラウザでアクセス。クラスタマークが3/3になってれば成功。

右側のパン屑から、「Cluster」を選択し各ノードの状態をみる。Nifi2ノードがプライマリにNifi3ノードがコーディネータになった模様。