docker上でcrondを動かしてみた

このサーバで使用しているDynamic DNSはMyDNS.JPなのだが、当然QNAPは海外のメージャーなDDNSしか対応していない=MyDNS.JPには対応していないので、DDNSのIPアドレスの更新を自前で行う必要がある。

そこでDDNSのIPアドレス更新コマンドをcrondで定期的に実行することになるのだが、当初QNAPネイティブのcrondを使っていたのだが、QNAPのファームウェアを更新してからQNAPネイティブなcrondでのコマンド実行が正常に動作しなくなった。

QNAPネイティブで動かしている限りQNAPに開発者登録をして常に最新情報をウォッチし続けなければ今回のような仕様変更に追随できなくなる。それどころか今回のようにファームウェアのアップデート時のQNAP再起動に伴うアプリの停止&起動が行われた瞬間にアプリが動かなくなるのが怖い。

そこでDDNSの更新コマンドをContainer Station(docker)上でcrondを動かす方向でQPKGを再作成するのだが…

どうせならcrondの実行計画は固定にしないでQNAPのWebUI上で変更できる汎用アプリにしたいと思ったので、docker上で動くcrondにホスト側の設定ファイルを読み込ませようと思ってネット上で「docker + crond」情報を検索するがヒットするのはDockerfileで「RUN echo 〜 >crontabs」か「COPY file crontabs」を記述する固定方式ばかり。

しかもQNAPではQPKGアプリをインストールした時のユーザーでホスト側のファイルオーナーが設定されてしまうが、docker内はrootで動いてて。crond固有の制限事項(crontabsファイルのオーナーやアクセス権限などの制限事項)の影響もあって、ホスト側のcrontabsファイルを直接docker内のcrondの設定ファイルにmountする方法では正常に動作しないことも考えられる。

そこで考えたのが、dockerのENTRYPOINTで指定・実行するシェルスクリプト内でcrontabコマンドをを使って設定ファイルを読み込ませることに。そして完成したのが以下のようなDockerfileとdocker-entrypoint.sh。

Dockerfile

FROM alpine:latest

RUN apk add --no-cache tzdata

COPY ./docker-entrypoint.sh /
RUN chmod 755 /docker-entrypoint.sh
ENTRYPOINT [ "/docker-entrypoint.sh" ]

CMD [ "crond", "-f" ]

docker-entrypoint.sh

#!/bin/sh
set -e

# Update crontabs settings
CRONTABS="/root/crontabs"
if [ -f ${CRONTABS} ]; then
  crontab ${CRONTABS}
fi

exec "$@"

あとは「docker build -t crond:latest .」って感じでビルドして、「docker run -d -v ./crontabs:/root/crontabs crond」って感じで実行するだけ。更新もホスト側でcrontabsファイルを編集して「docker restart crond」するだけ。

Share

3年ぶりの書き込みは…

この3年間、何も書き込みをしていなかった理由の一つはコロナであったことは明らかなんですが、それでも何事も無ければ新たに書き込みをすることはなかったかも知れないが、今回は3年ぶりに書き込みをすることに。

ことの発端は先月初めに使用しているサーバ(QNAP)の設定をミスって、最新版ファームウェアへのアップデートで間違ってベータ版のファームウェアをインストールしてしたのが、運の尽きだった。

これまでQNAPを使っていろいろ実験していた影響でQNAPの環境を汚していたことは事実だが、今回のベータ版のファームウェアへアップデートした途端にQNAP搭載のWebサーバが全く起動しなくなってしまったのだ!

当然このブログへもアクセスできなくなってしまったので、Google Search Consoleからエラーが入るようになったので、このままブログを辞めてしまおうかとも思ったのだが、最近QNAP上のContainer StationがほぼDocker化した影響もあり、サーバのSSL証明書の更新に使用するLet’s EncryptもDocker化していたので、WordPressもContainer Station(Docker)上で実行するようにしてしまえば、管理が楽かな〜などと考えて復活させてみることに。

また、ちょうどタイミング的にGWだったこと、コロナの影響で今年のGWの旅行の手配が遅れた影響でGWの希望の飛行機のチケットが手に入らず、高額なチケットを買ってまで海外旅行をするか悩んでいたところに、仕事でもGW中に片付けておきたい作業が出てきたので、今年のGWは海外旅行に行くことを諦めて、QNAPの復旧と環境整備に充てることにした。

QNAP本体はHDD上のデータをバックアップ、SQL内のデータをsqldumpで抜き出すなどしてから工場出荷時に初期化することで復旧は早かったんですが、問題はDocker対応(というかQDKでQNAPのパッケージ化)させていなかったWordPressたち。

今回同じようにContainer Station(Docker)に移したOpenPNEは簡単に動作させることができたのに、WordPressだけは何故かうまく動作せず、その原因究明までに少し時間がかかってしまったが無事に本日ほぼ復旧が終わったので、動作確認を兼ねて、3年ぶりの書き込みをすることに。

今回復旧に手間取った一番の理由が、QNAP上のWebサーバはLet’s EncryptでSSL化しているが、Container Station(Docker)上で動かしているWordPressは非SSLなので、QNAP側のSSLから非SSLのWordPressへのプロキシーの設定なのだが。

OpenPNEは単純なProxyPass / ProxyPassReverseの設定だけで何の問題なく動作したのに、WordPressでは「RequestHeader set X-Forwarded-Proto https」を設定しないと正しく動作しないということに気がつくまで時間がかかってしまったこと。

コロナも事実上終わり海外旅行にも行けるようになったけど、流石に3年のブランクは大きいというか怠癖がついてしまったというか、コロナ前のようにブログが復活できるか分かりませんが、リハビリも兼ねてボチボチやっていこうと思います。

Share

Container Stationの限界か

docker の使い方にも慣れてきて、docker の仕組みも何となく分かるようになってきたので、前回 qbus の利用を諦めて、docker だけでアプリケーションを作成しようと思ったので、これまで実験的に作成してきた QNAP 用のアプリを docker + QDK で記述し直してみたのだが、Container Station にまた別の問題がある事が発覚した。

私の使っている QNAP は CPU が arm32v7 なので、最初はアプリのインストール時に Dockerfile から QNAP 上で直接ビルドしていたのだが、docker 本来の使い方から考えれば、開発は別の PC で出来た方が良いというか自然な流れだよな〜と思って、Docker Desktop を使って PC 上で行うように変更してみた。

しかし、そうすると作成したイメージを QNAP 上へどうやって持っていくのか?という問題が発生する。一番素直な方法は docker hub を利用する事だろうが、今後仕事で docker hub が使えない環境だってあるかも知れないと思って、独自に docker の registry を QNAP 上で立ち上げ、そこを経由する方法を検討してみた。

ネットの情報を参考に、PC 上で docker buildx を使ってマルチ・アーキテクチャのイメージをビルドして、QNAP 上で立ち上げた独自の registry に push するところまでは問題なく動作した。

ところが、QDK のインストーラ内で docker pull を行うと独自レジストリの認証が正しく利用されないという問題が発生。QNAP では ssh でログインできるのは admin アカウントのみ。しかし WebUI の App Center を admin 以外の管理者アカウントで実行すると admin アカウント保存した認証情報は使用されない。

流石に ID/PW を QDK のインストールスクリプト内に直接記述する訳にもいかないので、イメージの管理や docker pull の方法については別の方法を考える必要がありそうだ。

Share

qbusコマンドにも限界か!?

今回は結論から書こうかと思います。Container Sation の WebUI 機能を使った処理を諦める方向で軌道修正する事になりそうです。Container Sation の WebUI 機能はバグが多過ぎます。

前の投稿にも書きましたが qbus コマンドを使ってアプリケーションの作成を行う方法は「バックグラウンドタスク」の非公開機能で実現できました。

それじゃ通常のコンテナ作成も「バックグラウンドタスク」で…と思ったのだが何故か正常に動作しない!ボリュームのホスト側のバインド先の指定に絶対パスを指定しているにも関わらず、パスの先頭に勝手に /share が追加されてしまったのだ!

通常のコンテナ作成では問題なかったので、「バックグラウンドタスク」の不具合だと思われる。元々 WebUI を使った操作でも Advanced Settings の内容が正常に反映されない問題があるなど、Container Station の不具合は目に余る状態だったので qbus にも同じような問題が存在している事が証明されたようなものだ。

ここ数日の docker 及び Container Station を使った実験で、docker の仕組みをより深く考察する事もできた影響か、docker 本来の使い方をするためにも、qbus コマンドなどの QNAP 独自コマンドを使わずに、docker コマンドだけでコンテナ開発を行っていく方が良いように思えてきた。

Container Station の WebUI 機能が使えない事さえ我慢すれば(苦笑)

ただ作成したアプリのインストールには QDK を利用したいなぁ〜とは思っているので、docker コマンドと QDK とのいいとこ取りができればベストなんだけど、はてさてそうなる事か。

Share

Container Stationの非公開機能!?

前の投稿でも書きましたが、Dockerコマンドではなく、qbusコマンドを使ったContainer Stationのコンテナ操作は問題なく行える事が分かりました。しかし、アプリケーション(docker-composeに相当するContainer Stationの機能)については一番最初の「作成」に関するドキュメントが全くない!

アプリケーションの情報取得や開始・停止・削除などのコマンドは存在するが、肝心の「作成」だけがドキュメントに存在しないのだ。

そこでドキュメントを隅々まで読んでいくと「コンテナの作成」や「イメージのダウンロード」などの機能を同期的に行う通常の機能以外に「バックグラウンドタスク」という非同期で行う機能が存在している事に気がついた。

この「バックグラウンドタスク」の中に「アプリケーションの作成」に相当すると思われる機能の記載は存在するのだが、説明文のパラメータにはdocker-compose.ymlを指定する方法が記載されていない。

説明文に合わせる形で適当にパラメータを指定して、実行してみるとが、CLI(qbusの実行結果)では成功するのが、実際にアプリケーションが作成される事がなかった。

しかも良く見れば、WebUI側のタスク一覧に「エラーが発生した」という実行結果が残っていたのを発見!

そこで、WebUI側でアプリケーションを作成してみて作成中の「バックグラウンドタスク」の情報を取得してみたり、WebUIで作成したアプリケーションの情報を取得してみて、ドキュメントの情報と何が違うのか詳しく比較してみたところ、WebUIで作成したアプリケーションのタスク・カテゴリは “application” ではなく “application_cutstom” になっている!!

そこで、qbusのURIをapplicationからapplication_customへ変更して、パラメータもWebUIで実行した時の情報を参考に修正して実行したところ、CLIの実行結果がエラーに、しかもエラー内容が具体的になった!!

実行パラメータの正しくない部分を微調整して、qbusを実行したらWebUI側のタスク一覧に「作成中」の表示が出た!!!そして暫く待つと無事にアプリケーションが作成されたのだ!!!

これが、その時のコマンドの抜粋だ!

qbus post com.qnap.container/api/v1/background/application_custom '{"name":"sshclientx","yml":"version:'"'"'3'"'"'\n\nservices:\n〜"}'

最初単純に”yml”の値の部分にdocker-compose.ymlの内容をコピペしていただけだったものだから「version: ‘3’」の部分が正しく認識されていなかったようで、引用符の処理を修正する事で、無事認識してアプリケーションの作成に成功した。

それでも問題があるとすれば、この機能が非同期でのアプリケーション作成なので、同期的な処理にするのが面倒な事かな。

さて、ここまで来ると本当にこのままqbusコマンドでのContainer StationのWebUI機能を十分に利用できる形にするのか、dockerコマンドでContainer StationのWebUIでの操作を諦めるか、それとも第3の道を探すのか…悩むところだ。

特にdockerの勉強が進んで、イメージ・コンテナ・レジストリの正しい(?)扱い方と今後の仕事への応用や実運用と、composeや将来的にはswarmやkubernetesまで視野に入れると自前でレジストリを立ち上げる第3の道も候補になり得るのか…と考え始めている。

Share

Container Stationコマンド

Container Stationをインストールするとbinディレクトリにdockerやdocker-composeを含む様々なツールがインストールされるが、その中でキモになると思われるコマンドが、qbusである。

Container StationのWebUI機能をCLIからでも利用できるようにするためにのインターフェース(API)へのアクセスをqbusから行うからである。

https://qnap-dev.github.io/container-station-api/index.html

Container Stationのインターフェース(API)の仕様については、上記ページにまとめられているので、基本的にはこちらを参照して実装していく事になるのだが、問題は記載されているサンプルが全てcurlで書かれており、しかも、認証(セッション)情報をCookieに保存して利用するWebUI専用になっており、QNAPのCLI環境(ssh)からは使えない…

そこで活躍するのがqbusコマンドである。例えば、Inspect a containerの

curl -sq -XGET -b cookies.txt http://${QIP}:${QPORT}/containerstation/api/v1/container/docker/<container_id>/inspect

という処理が、qbusだと

qbus get com.qnap.container/api/v1/container/docker/<container_id>/inspect

というコマンドで実行できるのだ!!

qbusについてはネット上で情報を探しているのだが、詳しい情報・説明は未だ見つかっていない。とりあえず、Container Stationの最低限の機能(コンテナ一覧の取得、コンテナの作成、削除、開始、停止、コンテナ情報の取得など)が問題なく使える事は確認できた。

当然、Container SationのWebUIに存在しない機能、例えば、Dockerfileのビルドなどはqbusで実行する事はできないので、これらの機能を使い方い場合には相変わらずdockerコマンドを利用する事になる。

まだ未調査のdocker-composeに相当する機能がqbusだとどうなるのか、qbusにビルド機能はないと思われるので、おそらくビルドしない形のyamlにのみ対応しているのだろうとは思うが…

Share

Docker vs Container Station

QNAPのNASに搭載されているのは正確にはDockerではなくContainer Stationだと言う事を忘れては行けない!!

sshでTS-431Pにログインできるのはadminアカウントのみ(≠管理者権限のアカウント)だし、dockerやdocker-composeなどのコマンドは存在しているが、ssh上でこれらのコマンドを使って作成したイメージやコンテナをContainer Stationから操作できないパターンがあったりして互換性に問題が山積みだ。

更にTS-431PはCPUがarm32系なので普通にDockerfileやdocker-compose.ymlにOfficialなイメージを指定すると存在しないために使えない事も多い。

これらの問題を解決するために、

  • コンテナ作成コマンドにdocker/docker-composeを使用せず、Container Stationのqbusコマンドで代用する。
  • arm32v7のOfficial互換イメージで使えそうなイメージに、Officialと同じtagをローカルでだけ付与する前処理を入れる形で誤魔化す。

という対策を行う事で何とかDocker Desktopで開発したアプリをTS-431P上にインストールしても使えそうな雰囲気になってきた。

ついでに、アプリをQDKでqpkg形式にする事で、QNAP上のApp Centerからインストールする事もできるようになって便利かな〜と思っている。

これまで実験してきた内容は整理できた段階で、一度ブログに記載しようとは思っているけど、今は未解決状態のmariadbのarm32v7イメージ作成をどう解決するかを考え中…

Share