眼鏡止水

FPGA、ネットワーク機器、料理、そしてメガネ女子。

【CCR2116】MikroTikルータでPi-holeのDockerコンテナを動かしてみた

背景

筆者宅 (いけおじハウス) では、ラトビアMikroTik社のCCR2116-12G-4S+がメインのルータとして利用されています。 このルータは2GHz, 16コア16スレッドのARM64 CPU、16GBのRAM、4つのSFP+ポートなどを搭載し、RouterOSと呼ばれるOSを用います。

mikrotik.com

RouterOSは、バージョン7.4beta4からコンテナ機能を利用できるようになりました。 これにより、Docker Hubなどで公開されている各種アプリケーションをルータ上で簡単に実行することが可能になります。 もちろん、いけおじハウスのCCR2116 (アイキャッチ画像の白い機器) でもこれを利用することができます。

コンテナ機能の解説として、RouterOSのドキュメントが公開されています。 リンク先の記事では、Pi-holeと呼ばれる軽量でグラフィカルなDNSサーバアプリケーションをインストールし動作させる方法が紹介されています。

pi-hole.net

しかしながら、紹介されている手順にはいくつかハマるポイントがありました。 そこで、それらを踏まえ、CCR2116でPi-holeのDockerコンテナを実行しDNSサーバとして利用する手順の備忘録を示します。

なお、本記事の手順に基づいて作業を行った結果生じたいかなる損失に対して、筆者は責任を負いかねます。 また、本記事に記したIPアドレス等の情報は、いけおじハウスで実際に運用しているものとは異なります。

作業

作業は以下の手順で行いました。

  1. NVMe SSDの接続
  2. コンテナ拡張機能のインストールと有効化
  3. コンテナ用ネットワークセグメントの作成
  4. 環境変数とマウントの設定
  5. コンテナイメージのダウンロードとコンテナの起動
  6. 上流DNSサーバとして登録

順を追って説明します。

1. NVMe SSDの接続

CCR2116は128MBの内蔵ストレージを持ちます。 しかし、今後複数のコンテナを動かす可能性を考慮すると、ストレージを別途追加することが好ましいです。 CCR2116は1TBまでのNVMe SSDを接続可能なM.2ポートも持つため、そこにSSDを増設します。 本記事では作業手順は省略します。

今回、筆者はAmazonのセールで購入した1TBのSSDを接続しました。 以下のリンクからそのSSDを購入いただけます。

2. コンテナ拡張機能のインストールと有効化

RouterOSはバージョン7.4beta4コンテナ機能に対応していますが、これは追加パッケージに含まれる拡張機能として提供されています。 そのため、RouterOSのダウンロードページから拡張機能を入手し、それをルータにインストールします。 CCR2116のCPU (https://en.wikichip.org/wiki/annapurna_labs/alpine/al73400) のアーキテクチャは64-bitのARMv8なので、RouterOSと同じバージョンかつARM64版のExtra packagesをダウンロードします。 ダウンロードしたZIPファイルに含まれるcontainer*.npkWinBoxなどでルータに転送しルータを再起動すると、拡張機能がインストールされます

RouterOSのExtra packagesをダウンロードする。CCR2116ではARM64版を選択する。

拡張機能のインストール後、ルータに接続したコンソールで以下のコマンドを実行し、コンテナ機能を有効化します。 あるいは、WinBoxやHTTPで接続してGUIで以下のコマンドに相当する設定を行います。

/system/device-mode/update container=yes

3. コンテナ用ネットワークセグメントとコンテナ用ネットワークインタフェースの作成

コンテナたちが利用するネットワークセグメントを作成します。 筆者はコンテナネットワークに疎いためこの作業の目的はわかりません。 以下のコマンドを実行するか、これに相当する操作をGUI上で行います。

/interface/bridge/add name=containers
/ip/address/add address=172.17.0.1/24 interface=containers

1行目では、containersという名前のブリッジを作成します。 ブリッジについては公式ドキュメントをご参照ください。 2行目では、containersブリッジに172.17.0.1/24というIPアドレスを割り当てます。

次に、今回作成するコンテナが独占的に利用する仮想インタフェースを作成し、ブリッジに接続します。 以下のコマンドを実行するか、これに相当する操作をGUI上で行います。

/interface/veth/add name=veth1 address=172.17.0.2/24 gateway=172.17.0.1
/interface/bridge/port add bridge=containers interface=veth1

1行目では、veth1という名前のインタフェースを、自身のIPアドレスは172.17.0.2/24に、ゲートウェイのIPアドレスは172.17.0.1 (ブリッジのIPアドレス) に設定して作成します。 2行目では、containersブリッジにveth1インタフェースを接続します。

最後に、コンテナ用ネットワークセグメントから外に出る通信のためのNATを設定します。 以下のコマンドを実行するか、これに相当する操作をGUI上で行います。

/ip/firewall/nat/add chain=srcnat action=masquerade src-address=172.17.0.0/24

この操作はファイアウォールの既存のエントリの内容によっては不要かもしれません。

4. 環境変数とマウントの設定

Pi-holeコンテナの環境変数を設定します。 以下のコマンドを実行するか、これに相当する操作をGUI上で行います。

/container/envs/add name=pihole_envs key=TZ value="Asia/Tokyo"
/container/envs/add name=pihole_envs key=WEBPASSWORD value="mysecurepassword"
/container/envs/add name=pihole_envs key=DNSMASQ_USER value="root"

1行目では、利用するタイムゾーンを設定します。 筆者は日本時間を主に利用しているため、値にはAsia/Tokyoを指定します。 2行目では、Pi-holeのWEBインタフェースにログインするためのパスワードを設定します。 値は適宜変更します。 3行目では、Pi-holeのバックエンド (?) であるdnsmasqの実行ユーザを指定すると思われますが、詳細は理解していません。

ホストのディレクトリ (ルータの物理ディスク上のディレクトリ等) をマウントしPi-holeやdnsmasqのディレクトリとして利用することができます。 この部分はファイルシステムに直接アクセスしたい場合のみ必要になるかもしれません。 以下のコマンドを実行するか、これに相当する操作をGUI上で行います。

/container/mounts/add name=etc_pihole src=nvme1/etc dst=/etc/pihole
/container/mounts/add name=dnsmasq_pihole src=nvme1/etc-dnsmasq.d dst=/etc/dnsmasq.d

nameにはマウントポイントの名前を、srcにはホストのディレクトリパスを、dstにはマウントポイントのパスを指定します。 筆者はNVMe SSD上のディレクトリをマウントするため、srcのパスをnvme1から始まるようにしました。 詳細は省きますが、ホスト側のディレクトリはWinBoxなどであらかじめ作成しておかないと自由にアクセスできないという印象を受けています。

5. コンテナイメージのダウンロードとコンテナの起動

コンテナイメージの取得にはいくつかの方法がありますが、筆者は外部のDockerレジストリからダウンロードをする方法を取りました。 以下のコマンドを実行するか、これに相当する操作をGUI上で行います。

/container/config/set registry-url=https://registry-1.docker.io tmpdir=nvme1/pull
/container/add remote-image=pihole/pihole:latest interface=veth1 root-dir=nvme1/pihole mounts=dnsmasq_pihole,etc_pihole envlist=pihole_envs

1行目では、https://registry-1.docker.ioをダウンロード元のDockerレジストリとします。 また、ダウンロードした一時ファイルをSSD上のディレクトリ (nvme1/pull) に保存するものとします。 2行目では、Pi-holeのコンテナイメージ (pihole/pihole) の最新版をダウンロードします。 このとき、コンテナの使用する仮想インタフェースをveth1に、コンテナの√ディレクトリをSSD上のnvme1/piholeにします。 また、上で設定したマウントポイントや環境変数も使用します。

その後、以下のコマンドを実行することでコンテナの状態を確認できます。

/container/print

次に、コンテナの起動を行います。 以下のコマンドを実行するか、これに相当する操作をGUI上で行います。 NUMBERには上記の/container/printで表示されるコンテナ番号を入力します。

/container/start NUMBER

再度/container/printを実行しstatus=runningとなっていれば、コンテナは起動していると判断できます。

必要に応じて、ルータの起動時にコンテナも自動的に起動するよう設定します。 以下のコマンドを実行するか、これに相当する操作をGUI上で行います。

/container/set NUMBER start-on-boot=yes

6. 上流DNSサーバとして登録

上記の設定が終わっただけでは、コンテナのIPアドレスに対する通信ができませんでした。 そこで、ルータを再起動したところ、WEBブラウザからWEBインタフェースにアクセスできました。 注意点としては、WEBインタフェースにアクセスするアドレスは<veth1 IP Address>/adminであるということが挙げられます。 以下に、Pi-holeのログイン画面を示します。 環境変数WEBPASSWORDで設定したパスワードを用いてログインします。

Pi-holeのログイン画面。環境変数で設定したパスワードでログインする。

ログインに成功すると以下に示すようなダッシュボードが表示されます。 処理したDNSクエリ数などがグラフィカルに表示されます。 図は設定を反映ししばらく運用した後のものであるためすでに数万件のクエリを処理したことになっていますが、初期状態ではこれらはすべて0です。

Pi-holeのダッシュボード。処理したDNSクエリ数などが表示される。

さて、RouterOSのドキュメントにはファイアウォールに宛先NATの設定を施すことで、ルータのIPアドレスを用いてPi-holeのWEBインタフェースにアクセスする方法が紹介されています。 筆者はこれを行う必要性を理解していません。 実は、containersブリッジを作成した段階でveth1を含むネットワークセグメントへのルーティング情報が作成されており、veth1のIPアドレスと直接通信できるようになっているようです。 /ip/route/printコマンドを実行することでルーティングテーブルにcontainersブリッジをゲートウェイとするエントリが追加されていることを確認できます。

閑話休題、Pi-holeを上流キャッシュDNSサーバとして利用するよう設定します。 なお、この操作はルータのDNS機能を用いてインターネットアクセスの名前解決を行っていることが前提と考えられます。 以下のコマンドを実行するか、これに相当する操作をGUI上で行います。

/ip/dns/set servers=172.17.0.2

上流キャッシュDNSサーバにveth1のIPアドレスを指定します。 これにより、ルータのキャッシュDNSサーバはPi-holeにDNS要求を行うようになります。 しばらく運用すると、先に示した図のように処理済みクエリ数が増加していくことが見て取れます。

最後に

本記事では、MikroTik社のRouterOSで利用可能なコンテナ機能を用いてPi-holeのDNSサーバを利用する方法を述べました。 SSDを増設しコンテナのデータを保存する方法や、作業におけるいくつかの注意点も述べました。

本記事の内容で得た知見を用いて、RouterOSのコンテナ機能でNginxのサーバを動作させ外部に公開することができました。 Nginxコンテナの設定等も後日記事にする可能性があります。

LICENSE

アイキャッチ画像のPi-holeロゴ

Copyright (c) 2017 Pi-hole
Released under the MIT license
https://github.com/pi-hole/graphics/blob/master/LICENSE