砂漠の旅人(たびと)|新天地:たびとの旅路

電脳砂漠を旅する、ある旅人の日記。フロッピーを頼りに歩いた日から、クラウドの地平を見つめる今日まで。見つけたオアシスも、迷い込んだ砂の迷宮も、全てこの羊皮紙に。

魂に、定刻の鼓動を ~Dockerfileとcronで操る、.NETバッチ処理~

旅の途中、興味深いオアシスを見つけた。忘れないうちに、この羊皮紙に記しておくとしよう。

「一定間隔で、自動的に魔法を発動させたい…」 かつて私がAIシステムという巨大なゴーレムを創り上げた時、この切実な問題に直面した。情報の砂漠を彷徨い、試行錯誤の末に辿り着いた答え。それは、.NET 6で創り上げた魂を、Dockerfileでビルドし、cronという古の魔法で、定刻に呼び覚ますというものだった。

今回は、WSL2 Ubuntuという名の祭壇で、その儀式の全てを再現する。これは、単なるバッチ処理ではない。コンテナという異次元の箱庭で、魂の錬成から、その魂に周期的な鼓動を与えるまでを、一気通貫で執り行う、壮大な錬金術の記録である。

この羊皮紙のあらまし

この羊皮紙が導く者

  • Dockerという箱庭で、.NET 6アプリという魂を、ビルドから実行まで完結させたいと願う者
  • cronという古の魔法を使い、コンテナ内のゴーレムに、周期的な命を吹き込みたい探求者

儀式の準備:祭壇を整える

まずは、WSL2 Ubuntuという祭壇に、Dockerと.NET 6という、二つの魔法体系を築いておく必要がある。その方法は、過去の羊皮紙に記されているので、ここでは割愛しよう。

第一の儀式:魂の設計図(ソースコードとDockerfile)

VS Codeという魔法の工房で、我々の世界の設計図を描いていく。

これから創造する、世界の設計図

世界の契約書:docker-compose.yml

まずは、この箱庭に「batch」という名の魂を宿らせることを、docker-compose.ymlに宣言する。これが、我々の世界の全てを定義する、契約の書だ。

version: '3.8'
services:
  batch:
    container_name: 'batch'
    build:
      context: ./source
      dockerfile: Dockerfile
    environment:
      TZ: Asia/Tokyo
    tty: true
    restart: always
    stdin_open: true

魂の設計図その1:BackApp

dotnet new consoleで、簡単な魂の素体(コンソールアプリ)を創り出す。この魂は、目覚めるたびに、現在時刻を/tmp/testfile.txtという羊皮紙に記録する、という単純な使命を帯びている。

Console.WriteLine("Hello, World!");
using var sw = new StreamWriter("/tmp/testfile.txt");
sw.WriteLine(DateTime.Now);

魂の設計図その2:crontab

魂に、いつ目覚めるべきかを教える、運命のスケジュール帳だ。「1分ごとに」という、短い周期の運命をここに刻む。

*/1 * * * * /app/BackApp

魂の錬成工程:Dockerfile

これが、今回の錬金術の核心だ。魂の素体をビルドし、運命のスケジュール帳を組み込み、そしてcronという名の心臓を動かす、その全工程を記した魔導書である。

# ビルド環境:.NET SDKという名の広大な工房
FROM mcr.microsoft.com/dotnet/sdk:6.0-focal AS build
WORKDIR /source
COPY ["./BackApp/BackApp.csproj", "BackApp/"]
RUN dotnet restore "./BackApp/BackApp.csproj"
COPY . .
RUN dotnet build "./BackApp/BackApp.csproj" -c Release -o /app/build

FROM build AS publish
WORKDIR /source
RUN dotnet publish "./BackApp/BackApp.csproj" -c Releasse -o /app/publish

# 実行環境:.NET Runtimeという名の、戦闘に特化した器
FROM mcr.microsoft.com/dotnet/runtime:6.0.6-focal AS runtime
COPY ["crontab", "/var/spool/cron/crontabs/root"]
WORKDIR /app
COPY --from=publish /app/publish .
WORKDIR /

# cronという古の魔法を使うための、追加の道具
RUN apt-get update && apt-get -y install --no-install-recommends \
      busybox-static \
    && apt-get -y clean \
    && rm -rf /var/lib/apt/lists/*

# 魂に、定刻の鼓動を与える心臓を起動する
ENTRYPOINT ["/usr/bin/busybox", "crond", "-f", "-l", "2", "-L", "/dev/stderr"]

最終儀式:魂の召喚と、鼓動の確認

全ての設計図が揃ったら、docker-compose buildで魂を錬成し、docker-compose up -dで箱庭に魂を召喚する。

$ cd ~/batsv
$ docker-compose build
$ docker-compose up -d

召喚した魂が宿る器に入り込み(docker-compose exec batch /bin/bash)、/tmp/testfile.txtの中身を覗き見る。1分ごとに、その羊皮紙に新たな時刻が刻まれていれば、儀式は成功だ。魂は、確かに、定刻通りに鼓動している。

羊皮紙を巻く前に

Dockerfileの中で、.NETアプリのビルドから実行までを完結させ、cronで定期実行させる。この一連の儀式は、情報が少なく、当時は試行錯誤の連続だった。 しかし、一度この魔法体系を理解してしまえば、その応用範囲は無限に広がる。

この羊皮紙が、同じように自動化という名のゴーレムを、よりスマートに、より力強く運用したいと願う、未来の冒険者の助けとなることを願う。

東の空が白んできた。次のオアシスへ向けて、そろそろ荷造りを始めるとしよう。

砂漠で見つけた魔法のランプ

ラクダの独り言

ご主人が、箱の中に創ったゴーレムに「1分ごとに起きろ」だの「時間を記録しろ」だの、細かい命令を下している。俺に言わせりゃ、そんなもん、自分で時計を見りゃ済む話だろうに。まったく、人間ってのは、自分の代わりに働かせるのが本当に好きだな。そのうち、俺の代わりに歩くゴーレムとか創り出すんじゃねえか?やれやれだぜ。