毎年恒例の近況報告と docker-compose を使うコツ5選

こんにちは!

Tech KAYAC Advent Calendar 2018 11日目を担当する荒賀(@ken39arg)です。

近況報告

※ お前の近況なんぞ興味ないよという方がほとんどだと思いますので、どうぞこのセクションはすっ飛ばしてください

アドベントカレンダーでは昨年一昨年と2年連続で筋肉について書いてきましたが、
今年は「筋肉は裏切らない」というフレーズが流行語大賞にノミネートされるほど筋肉に大きな注目があつまる中、筋肉の定義としては「魅せる筋肉」とされているように感じております。

しかし、過去の記事でも言及している通り、私は持久系スポーツを楽しんでいるため遅筋の強化を行っており、パワーや大きさを作る速筋に関しては憧れてはいるものの距離をおいているという立場を取っているため、以後会社のブログで筋肉に関して語ることは控えていきたいと考えております。

また、魅せる筋肉といえば、私なんかよりも遥かに筋肉を愛する沖縄出身の自称ボディビルダーのiOSエンジニアがカヤックのメンバーとなりましたので筋肉キャラクターは彼に委譲していきたい所存でございます。

彼も今年のアドベントカレンダーで何かを書いてくれるとのことですので大変期待しております。

筋肉的活動報告

念の為、今年の筋肉的活動に関しても昨年同様ご報告させていただきますと、大変悔しい結果となってしまいました。

  • 館山若潮マラソン 3:17:24 (自己BESTは 3:08:39)
  • 湘南OWS 10km 中止

また下記の記事を拝見したところ、非常に共感したと同時に恥ずかしくもあり脇から汗が止まらない気持ちにもなりました。

そうやって始めた運動に,2つ目の理由でのめり込んでいく。それは「目に見える成果」だ。歳を取るにつれ仕事では立場が上になり,大きな目に見える成果を出しづらくなる。「⁠僕はこれを作りました!」のような成果は減り,「⁠チームを助けました」「⁠チーム全体が動きやすいように整備しました」などのように自分の成果として実感しづらいものが多くなる。一方で運動は,短期間で明らかに体に変化を感じる。体が軽くなった,痩せた,筋肉が付いたなど,すぐに自分自身による目に見える成果が出る。これが中毒性のあるフィードバックループになる。仕事では得られなくなった達成感による気持ち良さが,運動を続けさせるのだ。

最終回 エンジニアはどこに行くのか:継続は力なり―大器晩成エンジニアを目指して|gihyo.jp … 技術評論社

これらの要因もあり、筋肉については語らないというより語りたくないという方が真実かもしれません。

家庭に関する報告

家庭に関しましては、2012年のアドベントカレンダーを書いた頃に生まれた長男は、6歳にして僕よりはるかにスプラトゥーンが上手く、
2014年のアドベントカレンダーを書く直前に生まれた次男は、なんだかよくわかりませんが日々僕にパンチを繰り出しており、徐々に拳を固く握るのがうまくなっていることが悩みです。いつ頃やめさせたら良いのでしょうか...

仕事に関する報告

仕事の方はと言いますと、今年はプログラミング言語や働く場所を何度か変えながらいくつかのチームに関わったのですが、気がついたら「結局GitHubさえあれば仕事は楽しい」という境地にたどり着いておりました。
この話をゲーム事業部の「ラウンドテーブル*1」の場でしたら意外とウケが良かったので、アドベントカレンダーのネタは「仕事が楽しくなるGitHub◯個の機能」みたいなのにしようと思っていたのですが、書いてみたら大変エモ要素が強く、来年の自分が見たら恥ずかしくなるような仕上がりになってしまったので、プログラミング言語やチームが変わってもお世話になりっぱなしのdocker-composeについていくつかのTipsを書こうということにしました。

手元の開発環境で docker-compose を使うコツ5選

はじめに

今年はメイン言語としてGolangを使っているチームとPerlを使っているチームを行き来し、またISUCON8の問題作成では、多数の言語での開発を行うという事をしてきました。

これらの開発は基本的に手元のMacBook Proで行っています。また、基本的にPCを持ち帰らない主義なので、自宅のMacBookでも緊急時にはコードを開くこともあります。(ISUCONの問題作成は会社と自宅や移動先では異なるPCを使っていました)

この複数のチームやプロジェクトを複数のPCでストレスなく利用するために必須なのがGitHubDocker(docker-compose)です。

ちなみに、ISUCON8の講評で触れるのをすっかり忘れていましたが、ISUCON8本戦のdocker-composeは集大成的な設定だと思いますので参考までに見ていただければと思います。

https://github.com/isucon/isucon8-final/tree/master/webapp

例えば下記のようにファイルを切り替えて振る舞いを変えることができました。

# mockを使いgo言語で開発
$ docker-compose -f docker-compose.yml -f docker-compose.mockservice.yml -f docker-compose.go.yml up

# mockを使わずにrubyで開発
$ docker-compose -f docker-compose.yml -f docker-compose.ruby.yml up

以下では、私(とチーム)がdocker-composeをどのように設定しているかを、少しでも知らない人が多そうなTipsに絞って紹介しようと思います。

1. data volume を使おう

例えばデータ永続化や各種言語の依存パッケージなどdockerを起動する度に初期化していたら時間がかかるというものをdata volumeという仕組みで永続化することができます。

data volumeを知らずに、依存パッケージをインストールするパスをマウントしたり、データ保存用にgitignoreしたディレクトリを作ってそこをマウントしたりするということをよく見かけますが(僕もそうしていました)、これだと、dockerを経由せずにうっかりcarton installbundle installなどのインストールコマンドを実行すると不都合が起きる場合もありますし、.gitignoreも汚れていきます。

そこで上記のリンクに沿って下記のようにdocker-compose.ymlを設定することで、なんかよしなな場所(/var/lib/docker 以下など)にデータを永続化してくれます。

version: '2'
services:
  isucoin:
    build: ruby
    environment:
      BUNDLE_PATH: "/bundle"
    volumes:
      - bundle:/bundle
  mysql:
    image: mysql:8
    volumes:
      - mysql:/var/lib/mysql
volumes:
  mysql:
  bundle:

volumeの管理は下記のコマンドだけ覚えておけば十分でしょう

# 一覧
$ docker volume ls
# 削除
$ docker volume rm <VOLUME>...

2. 複数のcomposeファイルを使おう

意外と知られていない気がしますが、docker-compose.yml-fで好きな場所の好きなファイルを指定することができます。
またdocker-compose.ymlの他にdocker-compose.override.ymlも上書き用として デフォルト で読み込まれます。

例えば、docker-compose.yml のみコミットしておいて、各自の環境に合わせて docker-compose.override.yml で上書きしこちらはgitignoreするということができます。

また、-fオプションを使ってファイルを指定すると同名のserviceを上書きするということができるので、あるマイクロサービスを別の言語でリプレイースする際などに役立つと思います。

このテクニックを使って言語実装を切り替えたのが上述したISUCON8本戦のdocker-composeです。

この他に extends を使うことで共通のサービスの起動オプションだけを変更した複数のサービスを作るようなこともできます。

例えば管理画面とフロントで起動ファイルが異なるようなperlアプリケーションの場合、下記のように設定を共有することができます

  • app.yml
version: "2"
services:
  app:
    build: ./docker/app
    image: app
    volumes:
      - "./app:/app"
      - perllocallib:/perl/local
    environment:
      PERL_CARTON_PATH: /perlapp/web/local.x86_64-linux
      TZ: Asia/Tokyo
    working_dir: /app
volumes:
  perllocallib:
  • docker-compose.yml
version: "2"
services:
  front:
    extends:
      file: app.yml
      service: app 
    command: carton exec -- plackup -s Starlet --port=1234 app.psgi

  admin:
    extends:
      file: app.yml
      service: app 
    command: carton exec -- plackup -s Starlet --port=1235 admin.psgi

3. /docker-entrypoint-initdb.d で MySQL(PostgreSQL)の初期データを共有しよう

MySQLやPostgreSQLの公式イメージでは /docker-entrypoint-initdb.d 以下に配置した .sh .sql .sql.gz を自動的に読み込んでくれます。

起動順が保証されているわけではありませんが for f in /docker-entrypoint-initdb.d/*; do でloopを回しているのでファイル名を昇順になるように配置しておけば意図したとおりに実行されるはずです。

例) https://github.com/isucon/isucon8-final/tree/master/webapp/sql

ここを設定しておくことで、開発中にデータを初期化したらまた初期データを入れることからやり直しになるなどの問題が回避でき、PCを変更しても同じデータを容易に再現することができます。

4. env_file

環境変数の設定としてenvironment(docker run -eオプション)はよく使われていると思いますが、env_file(docker run --env-fileオプション)もありこちらも非常に便利です。

特にdocker-composeenv_fileの値をenvironmentが上書きするようになっているため、例えば起動モードが環境変数で分かれるようなアプリがある場合は下記のようにすることができます

  • .envrc
TZ=Asia/Tokyo
GOPATH=/home/app/go
ENV=develop
MODE=front
  • docker-compose.yml
version: "2"
services:
  front:
    image: golang:1.11
    env_file: .envrc
    environment:
      MODE: front
    command: go run main.go

  front:
    image: golang:1.11
    env_file: .envrc
    environment:
      MODE: admin
    command: go run main.go

また、direnvなんかを使っている場合は同じファイルを共有できたりしてとても便利です。

5. ダミーのアプリケーションを使おう

これらのテクニックが役に立つほど、複数のマイクロサービスを扱っていたり、管理画面とフロントで別れているなどしている場合、実際に全部入りにしたdocker-composeを立ち上げるとファンが全力を出し始めるため、使うものだけを動かしたいというケースがあります。

また、実はISUCON8本戦の問題は単体のdocker-compose.ymlだけでは動きません。

これらのケースでとりあえずダミーの超軽いWebアプリケーションを動かしたい、レスポンスは何でも良いというような時に、任意のポートを開いて404 Not Found を返すだけのできるだけ軽いイメージがあったら嬉しいなという需要が僕の中で生まれたので作りました。

使い方は docker-compose.yml にまず下記のように書きます

version: "2"
services:
  nginx:
    image: nginx
    ports:
      - 80:80
    links:
      - front
      - admin
  front:
    image: ken39arg/notfound
    environment: 1234
  admin:
    image: ken39arg/notfound
    environment: 1235

そして、 front.yml や admin.yml に各々の設定を書き、管理画面だけの開発をしたいときは下記のように起動すると、frontは起動しないもののlinkとしてはnotfoundが肩代わりして成立しますのでnginxなどのserviceから参照は問題なく行えるのです。

$ docker-compose -f docker-compose.yml -f admin.yml up

※ 実はこのアイデアを思いついたのはつい数日前で、実際にlocalで動かしてみたらファンが静かになって幸せになったので紹介してみましたが、もっと良い方法などが既にあるかもしれません。

終わりに

今回のネタでGitHubへの愛を書こうと思っていたのですが、ちょっと37歳にもなってエモい記事を書くのはどうかという気がしてきましたので、よーく考えた結果、PullRequestのReviewで僕が指摘しがちなdocker-composeについて書いてみました。

GitHubの存在と合わせて開発のポータビリティが年々上がってきて最高だなと思う今日このごろです。
おかげさまで、子供が小学生になっても、趣味にますますのめり込んでも、もうしばらくはストレスなくWebサーバーサイドエンジニアを続けられそうです。
ありがたや。

カヤックではエンジニアを募集しております!

*1:カヤックのゲームチームでは同じ職種で普段一緒に働いていない人と、テーマを決めてざっくばらんな座談会をする会を指すことが多い