先日、CloudflareをDDNS(Dynamic DNS)として使いたいと思い、グローバルアドレスを自動更新する仕組みをDockerで動かそうと考えました。
そこで、既存のDockerイメージを探して試してみたのですが、どうも要件に合い、かつうまく動作するものが見つかりませんでした。
求めていた機能などは以下の通りです。
- 取得したグローバルIPアドレスを複数のレコードを更新できる
- IPv6アドレスも取得できる
- レコードによりIPv4アドレスのみ、IPv6アドレスのみを設定できる
- 複数のゾーン(ドメイン)に含まれるレコードを更新できる
普通、1つのホスト名(サブドメイン)にAレコードとAAAAレコードを1つずつ設定し、あとは必要に応じてCNAMEレコードを設定すれば十分なので、わざわざIPv4とIPv6のみのホスト名を作りたいとか、複数のゾーンを更新したいとかいった変なことをする人は少ないのでしょう。
一応、上記の機能を持ってそうなイメージもありましたが、私の環境ではうまくIPv6アドレスが取れなかったりしました。1レコードのみ更新できるDockerイメージから複数のコンテナを起動するという方法も考えましたが、それも不細工な話です。
そこで、ひとつ自分で書いてしまおうと考え、何番煎じか分かりませんが、CloudFlareをDDNSとして使うDockerイメージ(マルチゾーン・マルチレコード対応)を作ってみました。
最初はPythonで少し書き始めたのですが、他の人にも使ってもらうにはイメージサイズが小さいほうがよさそうですし、ルーターなどDockerやPythonが入っていない環境でも使えたほうが良いかなと考え、シェルスクリプトで書きました。Alpineの公式イメージに入っているBusyBoxで動くように書いています。Alpineのイメージにcurlとjqだけ追加すれば動くようにしたので、ダウンロードサイズは4MB弱まで小さくすることができました。
書いているうちに、グローバルアドレスの変更時にWebhookを叩いたりするために任意のコマンドを実行する機能を入れたり、レコードによっては固定のアドレスを設定したり、終了時にレコードを削除したりといった、自分でも使うかどうか分からない機能を入れた結果、以下のような特徴を持つスクリプトとなりました(README.ja.mdから抜粋)。
- 小さなDockerイメージ
- このイメージのダウンロードサイズ(圧縮サイズ)は4MB未満です。
- 複数のアーキテクチャに対応
- Dockerイメージはamd64, 386, arm64, arm/v7, arm/v6に対応しています。さらに、他のアーキテクチャであってもDockerを使わずにこのシェルスクリプトを実行することができます。
- BusyBoxで実行可能なシェルスクリプト
- BusyBox のシェルで動作するように設計されています。他にも、Bashはもちろん、DebianやUbuntuの/bin/shとして採用されているdashでも動作します。
- 複数のゾーン・レコードに対応
- 複数のゾーンに含まれる、複数のレコードを更新することができます。
- IPv4とIPv6の両方をサポート
- IPv4 アドレスだけでなく、IPv6 アドレスにも対応しています。
- グローバルIPアドレスの確実な取得
- 間違ったグローバルIPアドレスを設定しないよう、複数の取得元からアドレスを取得し、一致することを確認してから処理を実行します。
- IPアドレス取得方法のカスタマイズが可能
- デフォルトでは、IPアドレスを外部HTTPSサーバーより取得します。設定により、外部DNSサーバーから取得させることも可能です。また、IPアドレスを取得する独自のコマンドを設定することもできます。レコードごとに、固定IPアドレスや独自のIPアドレス取得用コマンドの指定も可能です。
- キャッシュ機能によるCloudflare API呼び出し回数の節約
- 各レコードの設定状態をキャッシュすることにより、API呼び出し回数を節約します。キャッシュの期限が切れるまで、グローバルIPアドレスが変わらない限り、APIアクセスを行いません。キャッシュの有効期間は設定ファイルで変更できます(デフォルトは1時間)。
- 処理にあわせて実行する外部コマンドを設定可能
- レコードの作成・更新・削除時などに、外部コマンドを実行することができます。curlコマンドを使って、WebhookにPOSTリクエストを送信するといったことも可能です。
Dockerイメージの生成は、Github Actionsで行いました。以下のアクションを使えば、GitHubで各アーキテクチャ(amd64,i386,arm64,armhfなど)のイメージ生成と、Docker HubとGitHub Container Registry(ghcr.io)へのアップロードを自動でやってくれます。
.github/workflows/docker-publish.ymlを作成し、とりあえず手動で実行したところ、問題なくアップロードされ、Docker Hubから取得できるようになりました。普通は、特定のブランチ(普通はmainもしくはmaster)にpushされると自動でテスト・生成・アップロードを行う形で運用するようです。
コメント