Tech Racho エンジニアの「?」を「!」に。
  • IT Tips

docker-composeを便利にするツール「dip」を使ってみた

更新履歴

* 2019/11/27: 初版公開
* 2020/05/01: サブコマンド実行部分に追記
* 2021/04/14: dip 7.0に合わせて更新
* 2021/07/16: `docker-compose`コマンドを`docker compose`に置き換え

dipとは

dipは、Rails開発会社のEvil Martiansのメンバーが作った、docker-composeでの作業を能率的に行えるツールです。dipはDocker Interaction Processの略だそうです。

bibendi/dip - GitHub

dipはRubyで書かれているのでRuby実行環境が必要です。元々Rails向けに作られたツールのようですが、Evil MartiansのReactアプリにもdip.xmlがあることからわかるように、Railsに限らず一般のdocker-composeでも使えます。私の場合はローカル開発環境でのみ使っています。

追記(2021/04/14)

以前は単独の実行可能バイナリ版dipもリリースされていましたが、バージョン7からは廃止されました(参考: [dipインストール方法](https://github.com/bibendi/dip#installation))。これに伴い、`gem`コマンド以外のインストール手順を削除しました。

Evil Martiansはdipの記事を書くと言ってましたが、未だに出ていないので自分で記事を書いてみました😆。

追記(2021/05/20)

その後Evil Martiansもdip記事を公開しました。

Docker ComposeとDipで開発用コンテナを再利用可能にする(翻訳)

dipのREADMEにはシェルと統合してdipを省略する方法も書かれていますが、ちょいやりすぎ感あったので自分はやっていません。

必要なもの

  • Ruby 2.5以上
  • Dockerとdocker-composeがインストールされていること
  • docker-compose.ymlファイル

インストール

以下の方法でdipをインストールし、dip.ymlをdocker-compose.ymlと同じ階層に置きます。

gemコマンドでのインストール

gem install dip

dip.ymlの設定

dipリポジトリのREADMEにある以下のdip.ymlを自分の用途に応じてカスタマイズします。interaction:の下のサブコマンドを適宜カスタマイズします。

# Required minimum dip version
version: '7.0'

environment:
  COMPOSE_EXT: development

compose:
  files:
    - docker/docker-compose.yml
    - docker/docker-compose.$COMPOSE_EXT.yml
    - docker/docker-compose.$DIP_OS.yml
  project_name: bear

interaction:
  shell:
    description: Open the Bash shell in app's container
    service: app
    command: bash
    compose:
      run_options: [no-deps]

  bundle:
    description: Run Bundler commands
    service: app
    command: bundle

  rake:
    description: Run Rake commands
    service: app
    command: bundle exec rake

  rspec:
    description: Run Rspec commands
    service: app
    environment:
      RAILS_ENV: test
    command: bundle exec rspec

  rails:
    description: Run Rails commands
    service: app
    command: bundle exec rails
    subcommands:
      s:
        description: Run Rails server at http://localhost:3000
        service: web
        compose:
          run_options: [service-ports, use-aliases]

  sidekiq:
    description: Run sidekiq in background
    service: worker
    compose:
      method: up
      run_options: [detach]

  psql:
    description: Run Postgres psql console
    service: app
    default_args: db_dev
    command: psql -h pg -U postgres

  clean_cache:
    description: Delete cache files on the host machine
    command: rm -rf $(pwd)/tmp/cache/*

provision:
  - dip compose down --volumes
  - dip clean_cache
  - dip compose up -d pg redis
  - dip bash -c ./bin/setup```

なおprovision:というコマンドは固定されているらしく、他の名前にできませんでした。

自分のカスタマイズ例

これは以下の記事で自分が使っているdip.ymlです。

Rails 6.1のDocker開発環境構築をEvil Martians流にやってみた(更新)

dip bashdip rubocopは長いのでdip shdip copにしてみました。

なおtest:というサブコマンドは予約語なのか認識できなかったので、minitest:としました。

version: '7.0'

environment:
  RAILS_ENV: development

compose:
  files:
    - docker-compose.yml

interaction:
  sh:
    description: Open the app container bash shell
    service: backend
    command: /bin/bash
    compose_run_options: [no-deps]

  bundle:
    description: Run bundler command
    service: backend
    command: bundle
    compose_run_options: [no-deps]

  rake:
    description: Run rake command
    service: backend
    command: bundle exec rake

  rails:
    description: Run rails command
    service: backend
    command: bundle exec rails
    subcommands:
      s:
        description: Start rails server
        service: rails
        compose_run_options: [service-ports]

  yarn:
    description: Run yarn command
    service: backend
    command: yarn
    compose_run_options: [no-deps]

  minitest:
    description: Run minitest
    service: backend
    environment:
      RAILS_ENV: test
    command: bundle exec rails test

  cop:
    description: Run rubocop
    service: backend
    default_args: -a
    command: bundle exec rubocop
    compose_run_options: [no-deps]

  psql:
    description: Run psql console
    service: postgres
    command: psql -h postgres -U postgres -d postgres

  inspect_all:
    description: Run all checkers
    service: backend
    command: bundle exec license_finder
    command: bundle exec rails test
    command: bundle exec rails_best_practices .
    command: bundle exec bundle-audit
    command: bundle exec brakeman

provision:
  - dip compose up -d postgres
  - dip compose up -d webpacker
  - dip yarn install --check-files
  - dip rails db:prepare
  - dip rails db:prepare RAILS_ENV=test

使い方

dip.ymlのあるディレクトリでdip lsすると、dip.ymlで設定したサブコマンドの一覧が表示されます。dip helpとするとさらに詳しいヘルプが表示されます。

$ dip ls
sh           # Open the app container bash shell
bundle       # Run bundler command
rake         # Run rake command
rails        # Run rails command
rails s      # Start rails server
yarn         # Run yarn command
minitest     # Run minitest
cop          # Run rubocop
psql         # Run psql console
inspect_all  # Run all checkers

あとはdip サブコマンドを実行するだけです。

サブコマンドにはdip bundle installdip rails consoleのようにオプションも追加できます。

dip sshdip nginxなど凝った機能がいろいろあるようですが、その辺りはまだ追求していません。

dipの便利な点

Dockerが公式にこういうツールを出せばいいのにと思っちゃいました。

1. コンテナにログインせずに作業できる

bundle installrails dbconsoleyarn install --check-filesといった決まりきったコマンドを実行するのに、いちいちシェルでログインするのは面倒です。また、Dockerのシェルの安定性にもちょっと不安があります。

dipならdip bundle installdip rails dbconsoledip yarn install --check-filesで実行できます。

なおGemfileがない状態でのrails newはさすがにログインが必要でした。

2. コンテナの起動状態を気にしなくてよい

docker-composeでコンテナに入る場合、コンテナが起動していなければdocker compose run app bash、コンテナが起動していればdocker compose exec app bashとするなど、面倒な使い分けが必要になります。

そもそもdocker composeというコマンドが長すぎですよね。自分はdcomというbashエイリアスを作っているほどです。

dipなら、たとえば自分の設定したdip shdip rails sはコンテナが起動していなくても使え、dipが終了すればコンテナも終了してくれます。コンテナの二重起動を気にしなくてよくなるのは本当にありがたいです😂。

その分起動は少々遅くはなると思います。

まあ自分は何か作業した後はdcom downを実行する癖が付いてしまいましたが。

3. 複数のサブコマンド実行が書きやすい

追記(2020/05/01)この方法は現在使えなくなったようです😢。
追記(2021/04/22)dipバージョン7で再び使えることを確認しました。

docker-composeの中でシェルコマンドを複数実行しようとすると、たとえば以下のように&&でつなげてbash -cで実行するというダルい書き方になってしまいます。

command: bash -c "elasticsearch -d && elasticsearch --http.port=9250"

コマンドを5つも6つもつなげると美しくありませんし、シェルスクリプトに追い出すのも何だか敗北感があります。

dipなら自分のサブコマンドにcommand:を複数書けます。ただしこの方法はドキュメントに見当たらないので、サポート外機能のつもりで使っています。

  inspect_all:
    description: Run all checkers
    service: backend
    command: bundle exec license_finder
    command: bundle exec rails test
    command: bundle exec rails_best_practices .
    command: bundle exec bundle-audit
    command: bundle exec brakeman

4. Dockerfileやdocker-compose.ymlの変更が基本的に不要

dip.ymlはDockerfileやdocker-compose.ymlと別に設定できるので、うかつにこれらを変更してチームの人に怒られずに済みます。dip.ymlを~/.gitignore_globalに加えておけば自分用に心ゆくまでカスタマイズできます。

試していませんが、さすがにsshログイン機能などを使う場合はdocker-compose.ymlの変更も必要そうです。

services:
  web:
    environment:
      - SSH_AUTH_SOCK=/ssh/auth/sock
    volumes:
      - ssh-data:/ssh:ro

volumes:
  ssh-data:
    external:
      name: ssh_data

おたより発掘

関連記事

クジラに乗ったRuby: Evil Martians流Docker+Ruby/Rails開発環境構築(翻訳)


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。