恥ずかしながら最近になって知ったワークフローエンジン Apache Airflow。
AWSのマネージドサービスとしての提供もされるなどそれなりの注目度のOSS製品ということで、どんなものか見てみたくなりました。
※あらかじめ申し上げておきますが、ここに示す手順は「参考URL」に示した記事に示された内容を一部端折りながらもほぼそのままにつなぎ合わせたものになっています。こうした記事を執筆してくださった皆さま、ありがとうございます。そしてオリジナリティのない、個人用備忘録みたいな投稿でごめんなさい。。
構成
今回はこの Airflow v2.3.2 を次のような構成で動かしてみます:
- ホストマシン:Surface Go 3
- ホストOS:Windows 11 Home
- 仮想化基盤:Windows Subsystem for Linux 2(WSL2)
- ゲストOS:Alpine Linux Minimal root filesystem v3.16.0 x86_64
- コンテナ基盤:Docker v20.10.16
- オーケストレーションツール:docker-compose v1.29.2
ホストOSを動かすマシンについては本当はCPUもメモリも強めがよいのだろうなと思いますが、無い袖は振れないわけで今回はSurface Go 3で挑戦です。
Airflowの公式ガイドでは docker-compose を利用して構築する方法は本番利用に耐えるものではないと警告されています。
今回の構築もあくまでもお勉強が目的です。
Dockerとdocker-composeのおかげで、Windows OS、それもリソースの限られたマシンで動作確認をすることができます。
参考URL
構築にあたって次のWebページを参考にさせていただきました:
- https://zenn.dev/ttani/articles/wsl2-docker-setup
- https://zenn.dev/ignorant/articles/wsl2_alpine_docker
- https://news.line.me/articles/oa-ascii/1516b3178859
- https://atmarkit.itmedia.co.jp/flinux/rensai/linuxtips/310delvcon.html
- https://text.superbrothers.dev/200328-how-to-avoid-pid-1-problem-in-kubernetes/
- https://airflow.apache.org/docs/apache-airflow/stable/start/docker.html
WSL2のインストール
まずは一番の土台となるWSL2のインストールから。
「Windowsの機能の有効化または無効化」で「Linux用Windowsサブシステム」と「仮想マシンプラットフォーム」に☑をして「OK」。
途中OS再起動を求められるので従います。
続いてMicrosoft社のWebサイトでLinuxカーネル更新プログラムをダウンロードし、インストールします。
ダウンロード元ページはこちら。
これはPowerShellで wsl --update
するのとと同じことだろうと考えています。
更新プログラムのインストールが終わったらPowerShellを起動。
次のコマンドを実行します:
wsl --set-default-version 2
wsl --status
WSLで仮想マシンを作成するときのデフォルトのバージョンとして 2
を指定。
WSLのインストールはもちろん上記の設定が正しく行われているかを確認します。
いい感じ。
これでWSL2のインストールは完了です。
Alpine Linuxのインストール
続いてWSL2の上にAlpine Linuxを導入します。
このディストリビューションはとにかく軽量なのがうれしいポイント。
このあと構築を進めていくと結局まあまあのサイズになってしまうのですが、それでもなるべく小さなサイズに収めたい。
目的はLinuxの上にDockerを導入しそのDockerでAirflowを動かすこと。その目的に寄与しないものは何も要りません。
──前置きはこのへんで。
Alpine LinuxのダウンロードページからMinimal root filesystem(Mini Root Filesystem)エディションの x86_64アーキテクチャ向けイメージ alpine-minirootfs-3.16.0-x86_64.tar.gz
をダウンロードします。
仮想マシンイメージが配置されるフォルダを用意(今回は .\devel\wsl\alpine
)し、ダウンロードしたイメージをWSLにインポートします:
wsl --import alpine .\devel\wsl\alpine .\Downloads\alpine-minirootfs-3.16.0-x86_64.tar.gz
wsl -l -v
wsl --status
wsl --status
の結果を見ると「既定の配布」(デフォルトのディストリビューション)に alpine
と表示されています:
Alpine Linuxを起動してみます:
PS C:\Users\mizuk> wsl -l -v
NAME STATE VERSION
* alpine Stopped 2
PS C:\Users\mizuk> wsl
TABLET-07LV9VBK:/mnt/c/Users/mizuk# ls -la devel/wsl/alpine/
total 78848
drwxrwxrwx 1 root root 4096 Jul 5 11:38 .
drwxrwxrwx 1 root root 4096 Jul 5 11:37 ..
-rwxrwxrwx 1 root root 80740352 Jul 5 11:44 ext4.vhdx
TABLET-07LV9VBK:/mnt/c/Users/mizuk# exit
PS C:\Users\mizuk> wsl -l -v
NAME STATE VERSION
* alpine Running 2
PS C:\Users\mizuk> wsl -t alpine
PS C:\Users\mizuk> wsl -l -v
NAME STATE VERSION
* alpine Stopped 2
Dockerのインストール
Dockerをインストールします。
wsl
コマンドでAlpine Linuxを再度起動&ログインしたあと、
まずは前提として必要なパッケージや設定を施していきます。今回は作業用のLinuxユーザーとして penguin
を追加して sudo
できるようにしています:
apk add --no-cache tzdata sudo
install -Dm 644 /usr/share/zoneinfo/Asia/Tokyo /etc/zoneinfo/Asia/Tokyo
export TZ='Asia/Tokyo'
"export TZ='$TZ'" >> /etc/profile.d/timezone.sh
apk del tzdata
echo '%wheel ALL=(ALL) ALL' > /etc/sudoers.d/wheel
apk add --no-cache bash bash-completion
adduser penguin -s /bin/bash
adduser penguin wheel
いよいよDockerをインストールします。ついでにDockerをサービス(デーモン)として起動させるためOpenRCもインストールします(default=penguin
のところは作業用ユーザー名に合わせて変えてください):
apk add --no-cache docker openrc
addgroup penguin docker
cat <<EOF > /etc/wsl.conf
[user]
default=penguin
[interop]
appendWindowsPath=false
[boot]
command = "/usr/bin/env -i /usr/bin/unshare --pid --mount-proc --fork --propagation private -- sh -c 'exec /sbin/init'"
EOF
exit
wsl -t alpine
wsl
whoami
最後にAlpine Linuxを再起動してログインユーザー名を確認しています。
OpenRCによるサービス化(デーモン化)
DockerやOpenRCのインストールが済んだので、Alpine Linuxを起動するたびに自動でDockerエンジンが起動するように設定します。
まずはOpenRCでDockerを起動できることを確認し:
sudo su -
rc-status
rc-service docker start
rc-status
しかるのち自動起動の設定を行います:
rc-update add docker default
rc-status
rc-update show default
念には念を入れてという感じですが、余計なプロセスにリソースを食われないように、不要なTTYを停止します:
vi /etc/inittab
viを :wd
で抜け編集を終えたら、Alpine Linuxからログアウトし再起動します。
PID1問題対策
きちんと理解していないのですが、DockerにはPID 1問題というものがあり、Dockerで起動したプロセスをシグナルで制御できないリスク(プロセス上でうごくコマンドにより制御できたりできなかったりする)があるので、これにあらかじめ対処します。
sudo su -
echo '%wheel ALL=(ALL) NOPASSWD: /usr/bin/nsenter' >> /etc/sudoers.d/wheel
vi /etc/profile.d/wsl-init.sh
wsl-init.sh
には以下の内容を書き込みます:
#!/bin/bash
# Get PID of /sbin/init
sleep 1
pid="$(ps -o pid,args | awk '$2 ~ /\/sbin\/init/ {print $1}')"
# Run WSL service script
if [ "$pid" -ne 1 ]; then
# Export ENV variables
if [ "$USER" != "root" ]; then
[ -f "$HOME/.openrc.env" ] && rm "$HOME/.openrc.env"
export > "$HOME/.openrc.env"
fi
echo "Entering /sbin/init PID: $pid"
exec sudo /usr/bin/nsenter -p -m -t "${pid}" -- su - "$USER"
fi
# Import ENV variables
if [ -f "$HOME/.openrc.env" ]; then
set -a
source "$HOME/.openrc.env"
set +a
rm "$HOME/.openrc.env"
fi
viを :wq
で抜けて編集を終えたらまたAlpine Linuxを再起動します。
そして次のようにしてコンテナの起動が問題なくできることを確認します:
docker container run --rm hello-world
docker image rm hello-world
この時点でAlpine Linuxの仮想マシンイメージは302MBほど。。
Dockerを導入する前は二桁だった気がするのですが、導入にともないガツンとサイズが増しました。
docker-composeのインストール
Airflowを稼動させる方法としてローカル、コンテナ、Kubernetes、SaaSなど複数の選択肢がありますが、今回はもちろんコンテナを利用します。
Airflowは worker
、schedular
、webserver
などの複数のコンポーネントからなるので、それらを正しい構成・順番で起動していく必要があります。
そのためにdocker-composeをインストールします:
sudo su -
apk add --no-cache docker-compose
exit
これでまた70MBほど増量です。。
Airflowのインストール
ようやく主役の登場です。
公式サイトから docker-compose.yaml をダウンロードします。
ダウンロードしたファイルを適用な場所(今回は C:\Users\mizuk\devel|wsl
)に置いたら、Alpine Linuxで docker-compose up
コマンドを実行します:
docker-compose -f /mnt/c/Users/mizuk/devel/wsl/docker-compose.yaml.txt up
イメージのダウンロード(pull)とコンテナ起動が順番に行われていきます:
AirflowやCeleryのASCIIアートが表示されたりして:
最後に、HTTPリクエストのログが定期的に出力されるようになったら起動したサインです:
Webブラウザで http://localhost:8080
にアクセスするとAirflowのWeb UIが表示されます(IDとパスワードは YMLファイルに記述されています):
ログインすると、サンプルのワークフローを閲覧したり実行したり出来ます:
おっかなびっくり実行してみた図:
以上で、Windows11でApache Airflowを起動するまでが完了です。
一連の作業が終わった時点でAlpine Linuxの仮想マシンイメージは 2.4GBを超えていました。。。