LoginSignup
38
29

More than 1 year has passed since last update.

Dockerfileの代わりの言語modus、使ってみた

Posted at

まとめ

現状だとメリットと学習コストが釣り合ってないから、まだ使わないかも!
今後書きやすくなったり、並列ビルドの機運が出てきた時に要検討といったところでした。

インストール

linuxであればバイナリがあります。macの場合はビルドしないといけないみたいなのでcargoを使います

🎐 ❯ cargo install modus

Modusfileを書く

書くだけであればほぼDockerfileなので例を見れば理解できると思います。

FROM ubuntu
ENV DEBIAN_FRONTEND noninteractive
WORKDIR /var/www/html
RUN apt update && \
    apt install -y git zip unzip libicu-dev libzip-dev

app :- (
  from("ubuntu"),
  run("apt update && \
      apt install -y git zip unzip libicu-dev libzip-dev")
)
::set_workdir("/var/www/html")
::set_env("DEBIAN_FRONTEND", "nontnteractive").

app :- ここはappという名前の新しいruleを定義しています。 modus build . 'app' というようにビルド対象を指定するのに使います。

他の書き方はドキュメントや、自分など他の人が書いたModusfileを参考にしてください。

実行計画を見る、文法チェックする

文法が正しいかどうかや、実際に実行するとどんなイメージが出来上がるかを確認できます。

# まずghcr.ioにログインしてください(自分の環境では必要でした)
🎐 ❯ docker login ghcr.io -u {username}
# password: {PAT}
🎐 ❯ modus check . # -> OKなら何も出ない
🎐 ❯ modus proof . 'app'
1 proof(s) found for query app

└─ app
   ├─ (
   │  ├─ from("ubuntu")
   │  └─ run("apt update && apt install -y git zip unzip libicu-dev libzip-dev")
   ├─ )::set_workdir("/var/www/html")
   └─  ::set_env("DEBIAN_FRONTEND", "nontnteractive")

ビルドする

modusでビルドしたイメージにはタグがついてないので、つける方法もドキュメントにあります。
実行結果はjsonの形式で出せるので、それをなんやかんやしてつけます。

🎐 ❯ modus build --json . 'app'
[
  {
    "predicate": "app",
    "args": [],
    "digest": "sha256:08495686536f9e93b6a71bbe44e6633ff772a5777bc3ba328ecd4295bce14185"
  }
]
# argsがない場合
🎐 ❯ modus build --json . 'app' | jq '.[] | [.digest, .predicate] | join(" ")' | xargs -I % sh -c 'docker tag %'
# args がある場合
🎐 ❯ modus build --json . 'app(x)' | jq '.[] | [.digest, .predicate + ":" + (.args | join("-"))] | join(" ")' | xargs -I % sh -c 'docker tag %'

実行する

ここまできたらただのdocker imageなので普通に使えます

Modusっぽい書き方1 - ruleの引数

いくつかの環境で同じdockerfileを使う場合、どこか1つのコマンドだけ分けたいって場面ありますよね。

例えば本番環境とローカル環境であれば、本番に必要ないライブラリはインストールしないように書きたいです。modusだとこんな感じに書き分けることができます。

setup_composer("local") :- run("composer install --no-scripts").
setup_composer("prod") :- run("composer install --no-scripts --prefer-dist --no-dev").

app(profile) :- (
  from("php"),
  copy("composer.json", "."),
  copy("composer.lock", "."),
  setup_composer(profile),
  copy(".", ".")
).

実行時の指定でどちらかの環境(profile)を選ぶこともできますし、まとめて指定することもできます。

# 指定する
🎐 ❯ modus proof . 'app("local")'
# 全て
🎐 ❯ modus proof . 'app(X)' # app(profile)でも可

# 結果
2 proof(s) found for query app(x)

└─ app("prod")
   ├─ from("php")
   ├─ copy("composer.json", ".")
   ├─ copy("composer.lock", ".")
   ├─ setup_composer("prod")
   │  └─ run("composer install --no-scripts --prefer-dist --no-dev")
   └─ copy(".", ".")

└─ app("local")
   ├─ from("php")
   ├─ copy("composer.json", ".")
   ├─ copy("composer.lock", ".")
   ├─ setup_composer("local")
   │  └─ run("composer install --no-scripts")
   └─ copy(".", ".")

Modusっぽい書き方2 - 条件分岐をする

phpであればよくある(?)、「ローカル環境だけxdebugを入れたい!」といった要望もかけます。(が、仕様の制約でちょっと汚くなります)

setup_composer("local") :- run("composer install --no-scripts").
setup_composer("prod") :- run("composer install --no-scripts --prefer-dist --no-dev").

setup_xdebug :- (
  run("pecl install xdebug && \
      docker-php-ext-enable xdebug"),
  copy("./xdebug.ini", "/usr/local/etc/php/conf.d/xdebug.ini")
).

app(profile) :- (
  from("php"),
  (
    (
      profile != "prod",
      setup_xdebug
    )
    ;
    (
      run("echo")
    )
  ),
  copy("composer.json", "."),
  copy("composer.lock", "."),
  setup_composer(profile),
  copy(".", ".")
).
🎐 ❯ modus proof . 'app(x)'
2 proof(s) found for query app(x)

└─ app("local")
   ├─ from("php")
   ├─ setup_xdebug
   │  ├─ run("pecl install xdebug && docker-php-ext-enable xdebug")
   │  └─ copy("./docker/8.1/php_xdebug.ini", "/usr/local/etc/php/conf.d/php_xdebug.ini")
   ├─ copy("composer.json", ".")
   ├─ copy("composer.lock", ".")
   ├─ setup_composer("local")
   │  └─ run("composer install --no-scripts")
   └─ copy(".", ".")

└─ app("prod")
   ├─ from("php")
   ├─ run("echo")
   ├─ copy("composer.json", ".")
   ├─ copy("composer.lock", ".")
   ├─ setup_composer("prod")
   │  └─ run("composer install --no-scripts --prefer-dist --no-dev")
   └─ copy(".", ".")

どうやら比較する対象が同じ属性?じゃないといけないみたいです。
今回の例だと setup_xdebug がlayer predicateだから、それと反対にもlayer predicateが必要といったところです。

38
29
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
38
29