Slide 1

Slide 1 text

Qall - Docker で作る Quipper の開発環境 @mtsmfm Fumiaki Matsushima 2018.03.25 Rails Developers Meetup 2018: Day 2

Slide 2

Slide 2 text

➔ Quipper Ltd 所属 ➔ Ruby と麻雀が好き ➔ 西日暮里.rb 主催 ➔ GraphQL Tokyo 主催 @mtsmfm.inspect

Slide 3

Slide 3 text

https://www.quipper.com/

Slide 4

Slide 4 text

https://studysapuri.jp/

Slide 5

Slide 5 text

https://github.com/kyanny/railsdm2018/blob/37a08ecef5d295a6d14838f34baa105fbc6c3f53/Quipper%20%E3%81%AB% E3%81%8A%E3%81%91%E3%82%8B%E3%80%8C%E9%96%A2%E5%BF%83%E3%81%AE%E5%88%86%E9%9B%A2% E3%80%8D%E3%81%AE%E6%AD%B4%E5%8F%B2.pdf

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

技術的負債を作らないのは不可能。 簡単に返済できる環境を作る。 - @masatomo, Quipper Ltd CTO

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

Tegaki-jan http://mtsmfm.github.io/tegaki-jan/

Slide 10

Slide 10 text

https://github.com/mtsmfm/language_server-ruby

Slide 11

Slide 11 text

西日暮里.rb https://ninirb.github.io

Slide 12

Slide 12 text

https://nishinipporirb.doorkeeper.jp/events/71936

Slide 13

Slide 13 text

GraphQL Tokyo https://www.meetup.com/ja-JP/GraphQL-Tokyo/

Slide 14

Slide 14 text

https://www.meetup.com/ja-JP/GraphQL-Tokyo/events/248222891/

Slide 15

Slide 15 text

開発環境 Docker 縛り歴 1年半

Slide 16

Slide 16 text

No content

Slide 17

Slide 17 text

Qall - Docker で作る Quipper の開発環境 @mtsmfm Fumiaki Matsushima 2018.03.25 Rails Developers Meetup 2018: Day 2

Slide 18

Slide 18 text

Qall - Quipper All

Slide 19

Slide 19 text

➔ 開発環境としての Docker の啓蒙 ➔ Docker 上の開発環境を前提とした ツールの整備の促進 発表の目的

Slide 20

Slide 20 text

大事なことは最初に

Slide 21

Slide 21 text

Docker で やさしい開発環境を 作っていこう

Slide 22

Slide 22 text

01 02 03 Agenda | Qall がなぜ必要か Qall の構成 課題

Slide 23

Slide 23 text

01Qall がなぜ必要か

Slide 24

Slide 24 text

A. セットアップが めんどくさいから

Slide 25

Slide 25 text

生徒用 先生用 保護者 用 管理者 用 コンテン ツ 入稿用 Mongo Postgres ...

Slide 26

Slide 26 text

生徒用 先生用 保護者 用 管理者 用 コンテン ツ 入稿用 Mongo Postgres ...

Slide 27

Slide 27 text

生徒用 Mongo Postgres Memcached Redis API Front Worker

Slide 28

Slide 28 text

➔ API + フロント + ワーカー + etc… を各アプリ毎に ➔ 単機能の開発だと全部は要らないことが多い ◆ あまり改修が入らないところのセットアップが 後回しにされがち ◆ 障害調査などとっさの時に困る システム全体の構成要素は増え続ける

Slide 29

Slide 29 text

ドキュメントは劣化していく

Slide 30

Slide 30 text

特に新入りには厳しい!

Slide 31

Slide 31 text

生徒用 先生用 保護者 用 管理者 用 コンテン ツ 入稿用 Mongo Postgres 全部まとめて Docker Compose で ...

Slide 32

Slide 32 text

Qall の構成 02

Slide 33

Slide 33 text

➔ 各リポジトリには Docker 固有のファイルを(ひとまず)持たない ◆ 最小公倍数的な Dockerfile を 1 つ ◆ 違うところは build arg で回避 ➔ 各リポジトリは qall 上に clone してくる Qall の基本方針

Slide 34

Slide 34 text

qall |----- Dockerfile |----- docker-compose.yml |----- repos | |----- student-api | |----- student-front | |----- ... |----- envs |----- student-api.env |----- student-front.env |----- ... 各リポジトリ 各リポジトリ毎の ローカル用環境変数

Slide 35

Slide 35 text

日常的に使うと 見えてくる問題

Slide 36

Slide 36 text

➔ rails new したての状態で、bin/rails -T がローカルと比べて 10 倍以 上遅いんだけど??? Docker for Mac が遅い

Slide 37

Slide 37 text

macOS Docker CLI $ dc run app rails s $ alias dc=docker-compose

Slide 38

Slide 38 text

Hypervisor Framework (VM) Linux Docker Container Engine macOS Docker CLI $ dc run app rails s $ alias dc=docker-compose

Slide 39

Slide 39 text

Hypervisor Framework (VM) Linux OSXFS Docker Container Engine macOS Rails gem rails s Docker CLI $ dc run app rails s $ alias dc=docker-compose

Slide 40

Slide 40 text

Hypervisor Framework (VM) Linux OSXFS Docker Container Engine macOS Rails gem rails s Docker CLI R/Wがすごく遅い $ dc run app rails s $ alias dc=docker-compose

Slide 41

Slide 41 text

User-guided cache https://blog.docker.com/2017/05/user-guided-caching-in-docker-for-mac/#h.72tgxspoi9yj

Slide 42

Slide 42 text

User-guided cache https://blog.docker.com/2017/05/user-guided-caching-in-docker-for-mac/#h.72tgxspoi9yj 10秒

Slide 43

Slide 43 text

User-guided cache https://blog.docker.com/2017/05/user-guided-caching-in-docker-for-mac/#h.72tgxspoi9yj 10秒 rake -T

Slide 44

Slide 44 text

rake -T が10秒?!?!?!

Slide 45

Slide 45 text

使い物にならない

Slide 46

Slide 46 text

OSXFS を使わない

Slide 47

Slide 47 text

案1. docker-sync

Slide 48

Slide 48 text

Docker Container Engine macOS Docker CLI app gem $ docker-sync start

Slide 49

Slide 49 text

Docker Container Engine macOS Docker CLI docker-sync app gem $ docker-sync start

Slide 50

Slide 50 text

Docker Container Engine macOS Docker CLI docker-sync OSXFS app gem app gem /host_sync $ docker-sync start

Slide 51

Slide 51 text

Docker Container Engine macOS Docker CLI docker-sync OSXFS app gem app gem /host_sync app gem /app_sync Unison で同期 $ docker-sync start

Slide 52

Slide 52 text

Docker Container Engine macOS Docker CLI docker-sync OSXFS app gem app gem /host_sync app gem /app_sync $ dc run app rails s $ alias dc=docker-compose

Slide 53

Slide 53 text

Docker Container Engine macOS rails s Docker CLI docker-sync OSXFS app gem app gem /host_sync app gem /app_sync $ dc run app rails s $ alias dc=docker-compose

Slide 54

Slide 54 text

Docker Container Engine macOS rails s Docker CLI docker-sync OSXFS app gem app gem /host_sync app gem /app_sync 遅い 速い $ dc run app rails s $ alias dc=docker-compose

Slide 55

Slide 55 text

理屈上は ローカルと同じ速度になる

Slide 56

Slide 56 text

docker-sync よく死ぬ問題

Slide 57

Slide 57 text

Docker Container Engine macOS rails s Docker CLI docker-sync OSXFS app gem app gem /host_sync app gem /app_sync なぜか死ぬことがある

Slide 58

Slide 58 text

➔ OSXFS がうまく更新できていなかったり、Unison が同期に失敗したり ➔ 問題が起きたときに気づくのが非常に難しい ◆ エディタ上は保存しているのにコンテナ内には反映されていないか もしれない事を常に気にしないといけない docker-sync よく死ぬ問題

Slide 59

Slide 59 text

案2. R/W が多いところを ひたすら Volume 化

Slide 60

Slide 60 text

Hypervisor Framework (VM) Linux Docker Container Engine macOS rails s $ dc run app rails s Docker CLI BUNDLE_PATH を Volume に gem app Gem 以外は諦める OSXFS $ alias dc=docker-compose

Slide 61

Slide 61 text

➔ vendor/bundle、tmp、node_modules とか ◆ sprockets 使っているときは tmp がよく効く ➔ ディレクトリがないところに mount すると所有者が root に なってしまうため、Rails コマンドなどを実行するユーザとして Dockerfile 内で予め作っておく R/W が多いところは Volume に

Slide 62

Slide 62 text

速度か安定性か

Slide 63

Slide 63 text

速度 >>> 安定性

Slide 64

Slide 64 text

- binding.pry 書いたのに止まらない - なんか SyntaxError - テスト落ちる

Slide 65

Slide 65 text

エディタを睨んでも わからない -> docker-sync 死んでる

Slide 66

Slide 66 text

速度 >>> 安定性 そう思った時期もありました

Slide 67

Slide 67 text

docker-sync なしでも動くように

Slide 68

Slide 68 text

誰も使わなくなったので 設定を完全削除

Slide 69

Slide 69 text

速度 <<< 安定性

Slide 70

Slide 70 text

https://github.com/mtsmfm/rails-on-docker-benchmark

Slide 71

Slide 71 text

※実際は app 以下が 育つことで もっと docker-sync の方が速 くなる

Slide 72

Slide 72 text

Dockerfile の例 ARG QALL_REPO_NAME ARG QALL_MOUNT_DIRS RUN mkdir -p /quipper/$QALL_REPO_NAME && \ cd /quipper/$QALL_REPO_NAME && \ (test -z "$QALL_MOUNT_DIRS" || mkdir -p $QALL_MOUNT_DIRS) && \ chown -R quipper:quipper /quipper

Slide 73

Slide 73 text

➔ Bash とか Pry とかのヒストリバックが C-p のあとに何か押さないと動かない ➔ C-p C-q が Docker のデフォルトのデタッチキーバインド ◆ Docker CLI なら config.json で上書きできるが、 Docker Compose だと config.json を見ない... Compose 介すと C-p が動かない

Slide 74

Slide 74 text

直した

Slide 75

Slide 75 text

https://github.com/docker/docker-py/pull/1826

Slide 76

Slide 76 text

docker-compose 1.20 (docker-py 3.0.0) から ~/.docker/config.json を 見てくれるように

Slide 77

Slide 77 text

➔ localhost:3000 が生徒用で、localhost:3001 が先生用で... Port 番号が覚えられない

Slide 78

Slide 78 text

Pow ってあったね

Slide 79

Slide 79 text

➔ .test でアクセスできるようにしてくれるやつ Pow http://pow.cx/

Slide 80

Slide 80 text

Docker でも欲しい

Slide 81

Slide 81 text

作った

Slide 82

Slide 82 text

https://mtsmfm.github.io/2017/06/29/yaichi.html

Slide 83

Slide 83 text

➔ http://.localhost でアクセスできる ◆ http://localhost には一覧が出る ◆ ngx-mruby 製 ◆ HMR などもちゃんと動く Yaichi

Slide 84

Slide 84 text

https://hub.docker.com/r/mtsmfm/yaichi/

Slide 85

Slide 85 text

➔ このリポジトリには mongo と pg と redis と memcached 、こっちは redis は要らなくて... ◆ リポジトリ毎に欲しくなるミドルウェアと、それに対応した環境変数を 都度書くのがめんどくさすぎる 複雑化する docker-compose.yml

Slide 86

Slide 86 text

docker-compose.yml.erb

Slide 87

Slide 87 text

api: ruby_version: 2.5.0 nodejs_version: 6.13.1 commands: default: bundle exec rails s -b 0.0.0.0 worker: bundle exec rake resque:start depends_on: [mongo, redis] mount_dirs: [tmp] こんな感じの YAML を元にする Build args に 各々 service と command に Build args に リポジトリ単位の service に

Slide 88

Slide 88 text

services: api: &api container_name: qall-api command: bundle exec rails s -b 0.0.0.0 build: context: . args: RUBY_VERSION: 2.5.0 NODEJS_VERSION: 6.13.1 QALL_REPO_NAME: api QALL_MOUNT_DIRS: tmp working_dir: /quipper/api volumes: - vendor:/vendor - home:/home/quipper - ./repos:/quipper:cached - tmp-api:/quipper/api/tmp environment: BUNDLE_PATH: /vendor/bundle/2.5.0 MONGODB_HOST: mongo REDIS_URL: redis://redis-api env_file: - envs/common.env - envs/api.env depends_on: [mongo, redis-api] tty: true stdin_open: true api-worker: <<: *api container_name: qall-api-worker command: bundle exec rake resque:start mongo: container_name: qall-mongo image: mongo volumes: - mongo-data:/data/db redis-api: container_name: qall-redis-api image: redis:alpine yaichi: container_name: qall-yaichi image: mtsmfm/yaichi ports: - 80:3000 volumes: - /var/run/docker.sock:/var/run/docker.sock volumes: home: mongo-data: vendor: tmp-api:

Slide 89

Slide 89 text

https://gist.github.com/mtsmfm/3235b3fc4a55baa45d8538f8acab911e

Slide 90

Slide 90 text

課題 03

Slide 91

Slide 91 text

1. Qall としての課題 2. Docker 上開発環境を 取り巻く課題

Slide 92

Slide 92 text

➔ 本番 (Deis) と同じイメージに ➔ 各リポジトリ毎に Dockerfile を ➔ 個々人で docker build せずに pull する構造に ➔ docker-compose やめて k8s に移行 ◆ helm? Qall の課題

Slide 93

Slide 93 text

Docker 上開発環境を 取り巻く課題

Slide 94

Slide 94 text

Docker 化によって、 今までのように 動かなくなるものも

Slide 95

Slide 95 text

➔ letter_opener ◆ コンテナ上にブラウザがいない ➔ ChromeDriver による E2E テスト ◆ コンテナ上にブラウザがいない 今まで通りでは動かなくなるが 解決策があるもの

Slide 96

Slide 96 text

➔ SMTP サーバと Web インターフェースがくっついたものを Docker 上 で立てるのが楽 ◆ sj26/mailcatcher ◆ djfarrelly/maildev letter_opener

Slide 97

Slide 97 text

➔ Selenium の公式イメージを使って、Remote Driver として セットアップ ◆ selenium/standalone-chrome-debug はデスクトップ環境が ついてきて、 VNC でログインできて便利 ChromeDriver (Selenium)

Slide 98

Slide 98 text

詳しくはこっちを https://speakerdeck.com/mtsmfm/rails-system-test-on-docker

Slide 99

Slide 99 text

➔ save_and_open_page ◆ スクショ.png を ホストに見えるところに置けば開けるが... ➔ bundle open ◆ Gem はホストにない ◆ エディタはホストにある 今までのように動かなくなるもの

Slide 100

Slide 100 text

➔ Linter などのエディタ連携 ◆ 基本ホストにインストールされている前提 ◆ Gem がコンテナ内にしかない ● ホストからは見えないファイルがある 今までのように動かなくなるもの

Slide 101

Slide 101 text

➔ 静的解析にしろ、動的解析にしろ、アプリと同一環境、 同一イメージじゃないと得られない情報がある ➔ docker-compose の起動コストが高い ◆ Docker 上で何かプロセスを上げといて、そいつとエディタを繋げ ればいいのでは? ● それ Language Server で Docker 時代のエディタ連携

Slide 102

Slide 102 text

http://rubykaigi.org/2017/presentations/mtsmfm.html

Slide 103

Slide 103 text

特に OSS とか セットアップの 敷居低いほうがいいよね

Slide 104

Slide 104 text

docker-py は手元でも docker 上でテスト https://github.com/docker/docker-py/blob/a4e642b015c50d9c628413341ed00c89599f66be/Makefile

Slide 105

Slide 105 text

https://github.com/mtsmfm/docker-rails-dev-box rails/rails-dev-box の Docker 版

Slide 106

Slide 106 text

ホストOS上に 何がいるべきか よくわからなくなってくる

Slide 107

Slide 107 text

エディタ、ブラウザ etc も Docker 上であるべき?

Slide 108

Slide 108 text

みたいな議論がしたい

Slide 109

Slide 109 text

そもそも Docker 上に 開発環境作っている人が 少ない (?)

Slide 110

Slide 110 text

既に環境ができている人、 慣れている人からすると 移行するメリットが薄い

Slide 111

Slide 111 text

人もアプリも協働するもの

Slide 112

Slide 112 text

Docker で やさしい開発環境を 作っていこう

Slide 113

Slide 113 text

No content