Upgrade to Pro — share decks privately, control downloads, hide ads and more …

クジラに乗ったRuby: Dockerを使って、便利な開発環境の構築

クジラに乗ったRuby: Dockerを使って、便利な開発環境の構築

イービルマーシャンズ: https://evilmartians.jp/

出雲ルビーミートアップ: https://izumonomadrubymeetup.peatix.com/

Andrey Novikov

November 11, 2023

Transcript

42 slides
  1. アンドレイといいます バックエンドエンジニア フロントエンドもできます Ruby, Go, TypeScriptを使っています SQL, Dockerfiles, TypeScript, bash…

    オープンソースの大ファン ルビージェムをいくつかを作成して、維持しています 1年前ロシアから日本に引っ越しました 大阪の近くに日本のくらしを楽しんでいます 原付を乗っています。スーパーカブです。 ママチャリも乗って、子供を幼稚園に連れていきます。
  2. 火星で作ったオープンソース Yabeda: Ruby application instrumentation framework Lefthook: git hooks manager

    AnyCable: a real-time server for Rails and beyound PostCSS: A tool for transforming CSS with JavaScript Imgproxy: Fast and secure standalone server for resizing and converting remote images A Figma plugin that ensures UI text is readable by leveraging the new APCA algorithm Overmind: Process manager for Procfile-based applications and tmux 詳しくは evilmartians.com/oss
  3. 開発環境って何? 1. オペレーティングシステム 2. 依存関係ライブラリー (OpenSSLなど ) 3. ルビー 4.

    ルビージェム 5. データベース (PostgreSQL/MySQL, Redis) 6. ソースコードエディタ /IDE 7. git 8. …
  4. 開発環境って何? 1. オペレーティングシステム 2. 依存関係ライブラリー (OpenSSLなど ) 3. ルビー 4.

    ルビージェム 5. データベース (PostgreSQL/MySQL, Redis) 6. ソースコードエディタ /IDE 7. git 8. …
  5. 開発環境の種類 1. ローカル 便利ですが、設定は面倒になるかも、 OSによっては問題になるかも 2. 仮想マシン (Vagrantなど ) 重たいです。

    RAMをたくさん使います。 3. コンテナ (Dockerなど ) 軽いですが、便利な設定は簡単とは言えないです。 今日の話題です。 4. リモート 高速なインターネットが必要です。遅いと DXが悪くなります。 5. 未来のこと (WebAssembly?) Stackblitzのようなプロジェクトは WebAssemblyでブラウザーの中で全てを実現していますが、 Rubyはまだ使えないみたいんです。
  6. ローカル開発環境設定のよくある仕方 1. 手順が記載された READMEファイル 長所 : 少なくとも文書があります 短所 : 長くて面倒くさい、見逃しやすい、古いことが多い

    , 一つの OSだけに対応しています 2. Bash scripts / Makefiles 長所 : 一度に実行できます 短所 : 普段一つの OSだけに対応しています、古いことが多い 3. Docker 長所 : 一度に実行できます、 OSに依存しません、 OSを汚染しません 短所 : 遅くて、不便、毎日使わないと古くなります
  7. 火星流の Dockerの設定の一覧 1. Dockerのイメージは Rubyとライブラリだけを含めています 2. ジェムは別のボリュームにインストールされています 3. データベースも別のボリュームです 4.

    いろいろな性能の設定 5. dip: 便利なコマンドラインツール 6. dip: シェルとの統合 7. Railsテンプレートでマイグレーションスクリプト
  8. 原本の記事 : Ruby on Whales: Dockerizing Ruby and Rails development

    日本語翻訳 : クジラに乗った Ruby: Evil Martians流 Docker+Ruby/Rails開発環境構築 原本 日本語翻訳
  9. Dockerの環境の問題解決 : Dockerfile ` ` # syntax=docker/dockerfile:1 ARG RUBY_VERSION ARG

    DISTRO_NAME=bullseye FROM ruby:$RUBY_VERSION-slim-$DISTRO_NAME ARG DISTRO_NAME # Common dependencies RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ --mount=type=cache,target=/var/lib/apt,sharing=locked \ --mount=type=tmpfs,target=/var/log \ rm -f /etc/apt/apt.conf.d/docker-clean; \ echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cache; \ apt-get update -qq \ && DEBIAN_FRONTEND=noninteractive apt-get install -yq --no-install-recommends \ build-essential \ gnupg2 \ curl \ less \ git # Install PostgreSQL dependencies ARG PG_MAJOR RUN curl -sSL https://www.postgresql.org/media/keys/ACCC4CF8.asc | \ gpg --dearmor -o /usr/share/keyrings/postgres-archive-keyring.gpg \ && echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/postgres-archive-keyring.g $DISTRO_NAME-pgdg main $PG_MAJOR | tee /etc/apt/sources.list.d/postgres.list > /dev/null RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ --mount=type=cache,target=/var/lib/apt,sharing=locked \ --mount=type=tmpfs,target=/var/log \ apt-get update -qq && DEBIAN_FRONTEND=noninteractive apt-get -yq dist-upgrade && \ DEBIAN_FRONTEND=noninteractive apt-get install -yq --no-install-recommends \ libpq-dev \ postgresql-client-$PG_MAJOR # Install NodeJS and Yarn ARG NODE_MAJOR ARG YARN_VERSION=latest RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ --mount=type=cache,target=/var/lib/apt,sharing=locked \ --mount=type=tmpfs,target=/var/log \ apt-get update && \ apt-get install -y curl software-properties-common && \ curl -fsSL https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add - && \ echo "deb https://deb.nodesource.com/node_${NODE_MAJOR}.x $(lsb_release -cs) main" | tee /etc/apt/source apt-get update && \ DEBIAN_FRONTEND=noninteractive apt-get install -yq --no-install-recommends nodejs RUN npm install -g yarn@$YARN_VERSION # Application dependencies # We use an external Aptfile for this, stay tuned COPY Aptfile /tmp/Aptfile RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ --mount=type=cache,target=/var/lib/apt,sharing=locked \ --mount=type=tmpfs,target=/var/log \ apt-get update -qq && DEBIAN_FRONTEND=noninteractive apt-get -yq dist-upgrade && \ DEBIAN_FRONTEND=noninteractive apt-get install -yq --no-install-recommends \ $(grep -Ev '^\s*#' /tmp/Aptfile | xargs) # Configure bundler ENV LANG=C.UTF-8 \ BUNDLE_JOBS=4 \ BUNDLE_RETRY=3 # Store Bundler settings in the project's root ENV BUNDLE_APP_CONFIG=.bundle # Uncomment this line if you want to run binstubs without prefixing with `bin/` or `bundle exec` # ENV PATH /app/bin:$PATH # Upgrade RubyGems and install the latest Bundler version RUN gem update --system && \ gem install bundler # Create a directory for the app code RUN mkdir -p /app WORKDIR /app # Document that we're going to expose port 3000 EXPOSE 3000 # Use Bash as the default command CMD ["/bin/bash"] Ruby on Whales: Dockerfile
  10. Dockerのビルド高速化 RUN --mount のドキュメントを参照してください。 Dockerのレイヤーキャッシュをよく効くために、 RUN --mount を使っています。 ` `

    # Application dependencies # We use an external Aptfile for this, stay tuned COPY Aptfile /tmp/Aptfile RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ --mount=type=cache,target=/var/lib/apt,sharing=locked \ --mount=type=tmpfs,target=/var/log \ apt-get update -qq && DEBIAN_FRONTEND=noninteractive apt-get -yq dist- DEBIAN_FRONTEND=noninteractive apt-get install -yq --no-install-recomm $(grep -Ev '^\s*#' /tmp/Aptfile | xargs) ` ` Dockerfile RUN --mount docs
  11. docker-compose.yml ` ` x-app: &app build: context: . args: RUBY_VERSION:

    '3.2.2' PG_MAJOR: '15' NODE_MAJOR: '18' image: example-dev:1.0.0 environment: &env NODE_ENV: ${NODE_ENV:-development} RAILS_ENV: ${RAILS_ENV:-development} tmpfs: - /tmp - /app/tmp/pids x-backend: &backend <<: *app stdin_open: true tty: true volumes: - ..:/app:cached - bundle:/usr/local/bundle - rails_cache:/app/tmp/cache - node_modules:/app/node_modules - packs:/app/public/packs - packs-test:/app/public/packs-test - history:/usr/local/hist - ./.psqlrc:/root/.psqlrc:ro - ./.bashrc:/root/.bashrc:ro environment: &backend_environment <<: *env REDIS_URL: redis://redis:6379/ DATABASE_URL: postgres://postgres:postgres@postgres:5432 WEBPACKER_DEV_SERVER_HOST: webpacker MALLOC_ARENA_MAX: 2 WEB_CONCURRENCY: ${WEB_CONCURRENCY:-1} BOOTSNAP_CACHE_DIR: /usr/local/bundle/_bootsnap XDG_DATA_HOME: /app/tmp/cache YARN_CACHE_FOLDER: /app/node_modules/.yarn-cache HISTFILE: /usr/local/hist/.bash_history PSQL_HISTFILE: /usr/local/hist/.psql_history IRB_HISTFILE: /usr/local/hist/.irb_history EDITOR: vi depends_on: &backend_depends_on postgres: condition: service_healthy redis: condition: service_healthy services: rails: <<: *backend command: bundle exec rails web: <<: *backend command: bundle exec rails server -b 0.0.0.0 ports: - '3000:3000' depends_on: webpacker: condition: service_started sidekiq: condition: service_started sidekiq: <<: *backend command: bundle exec sidekiq postgres: image: postgres:14 volumes: - .psqlrc:/root/.psqlrc:ro - postgres:/var/lib/postgresql/data - history:/usr/local/hist environment: PSQL_HISTFILE: /usr/local/hist/.psql_history POSTGRES_PASSWORD: postgres ports: - 5432 healthcheck: test: pg_isready -U postgres -h 127.0.0.1 interval: 5s redis: image: redis:6.2-alpine volumes: - redis:/data ports: - 6379 healthcheck: test: redis-cli ping interval: 1s timeout: 3s retries: 30 webpacker: <<: *app command: bundle exec ./bin/webpack-dev-server ports: - '3035:3035' volumes: - ..:/app:cached - bundle:/usr/local/bundle - node_modules:/app/node_modules - packs:/app/public/packs - packs-test:/app/public/packs-test environment: <<: *env WEBPACKER_DEV_SERVER_HOST: 0.0.0.0 YARN_CACHE_FOLDER: /app/node_modules/.yarn-cache volumes: bundle: node_modules: history: rails_cache: postgres: redis: packs: packs-test: Ruby on Whales: docker-compose.yml
  12. Dockerの環境の問題解決 : ボリューム Rubyのジェム NPMのパッケージ データベースのファイル キャッシュなど さらに、コンテナ内の /tmp とアプリの

    tmp/pids に tmpfsを利用されています。 volumes: # … - bundle:/usr/local/bundle - rails_cache:/app/tmp/cache - node_modules:/app/node_modules - packs:/app/public/packs - packs-test:/app/public/packs-test # … ` ` ` `
  13. Dockerの環境の問題解決 : サービス Docker Composeの設定でいろいろなサービスが定義されています。 rails server と rails console

    には異なるサービスが使われています。例えば、サーバーの起動用には、 公開するポート番号を定義します。 サービスは dipの設定では使われています。 DRYの為、拡張のサービス定義も使われています。 x-app と x-backend ヘルスチェック rails db:migrate は依存するデータベースサービスの準備が整うまで待機するようにします。 ` ` ` ` ` ` ` ` ` `
  14. Dockerの環境の問題解決 : 拡張のサービス定義 x-app: &app build: context: . args: #

    Ruby, Node, PostgreSQL versions image: example-dev:1.0.0 environment: &env NODE_ENV: ${NODE_ENV:-development} RAILS_ENV: ${RAILS_ENV:-development} tmpfs: - /tmp - /app/tmp/pids x-backend: &backend <<: *app stdin_open: true tty: true volumes: # see previous slides environment: &backend_environment <<: *env REDIS_URL: redis://redis:6379/ services: rails: <<: *backend command: bundle exec rails web: <<: *backend command: bundle exec rails server -b 0 ports: - '3000:3000' depends_on: webpacker: condition: service_started webpacker: <<: *app command: bundle exec ./bin/webpack-dev- ports: - '3035:3035' environment: <<: *env
  15. Dockerの環境の問題解決 : 設定 # Application configuration to save memory MALLOC_ARENA_MAX:

    2 WEB_CONCURRENCY: ${WEB_CONCURRENCY:-1} # Store caches in Docker volumes BOOTSNAP_CACHE_DIR: /usr/local/bundle/_bootsnap XDG_DATA_HOME: /app/tmp/cache YARN_CACHE_FOLDER: /app/node_modules/.yarn-cache # Convenience devtools HISTFILE: /usr/local/hist/.bash_history PSQL_HISTFILE: /usr/local/hist/.psql_history IRB_HISTFILE: /usr/local/hist/.irb_history
  16. Dip: 不足している DXを追加し直す dip は Docker Composeに基づいたコマンドラインツールです。 短くて、便利なコマンドを追加できます dip provision

    というコマンドで、アプリの環境を再構築できます。 シェルとの統合 ` ` dip rails c # 😎 # instead of docker-compose run --rm app bundle exec rails c # 😫 ` ` eval "$(dip console)" rails c # Dockerの中で起動します 😎 github.com/bibendi/dip
  17. dip.yml ` ` version: '7.1' # Define default environment variables

    to pass # to Docker Compose environment: RAILS_ENV: development compose: files: - .dockerdev/compose.yml project_name: example_demo interaction: # This command spins up a Rails container with the required dependencies (such as da # and opens a terminal within it. runner: description: Open a Bash shell within a Rails container (with dependencies up) service: rails command: /bin/bash # Run a Rails container without any dependent services (useful for non-Rails scripts bash: description: Run an arbitrary script within a container (or open a shell without d service: rails command: /bin/bash compose_run_options: [ no-deps ] # A shortcut to run Bundler commands bundle: description: Run Bundler commands service: rails command: bundle compose_run_options: [ no-deps ] # A shortcut to run RSpec (which overrides the RAILS_ENV) rspec: description: Run RSpec commands service: rails environment: RAILS_ENV: test command: bundle exec rspec rails: description: Run Rails commands service: rails command: bundle exec rails subcommands: s: description: Run Rails server at http://localhost:3000 service: web compose: run_options: [service-ports, use-aliases] yarn: description: Run Yarn commands service: rails command: yarn compose_run_options: [ no-deps ] psql: description: Run Postgres psql console service: postgres default_args: anycasts_dev command: psql -h postgres -U postgres 'redis-cli': description: Run Redis console service: redis command: redis-cli -h redis provision: - dip compose down --volumes - dip compose up -d postgres redis - dip bash -c bin/setup Ruby on Whales: DIP config
  18. DIPの設定:コマンド interaction: bundle: service: rails command: bundle compose_run_options: [ no-deps

    ] # Don't launch database for `bundle install` rspec: service: rails environment: RAILS_ENV: test # overrides the RAILS_ENV command: bundle exec rspec rails: service: rails command: bundle exec rails subcommands: s: service: web compose: run_options: [service-ports, use-aliases]
  19. 試してみよう! OS Docker と Docker Compose Ruby (サポートされているバージョン ) dip

    ジェム 必要な既にインストールされているソフトウェア bundle exec rails app:template \ LOCATION='https://railsbytes.com/script/z5OsoB' ruby-on-whales repo
  20. 原本の記事 : Ruby on Whales: Dockerizing Ruby and Rails development

    日本語翻訳 : クジラに乗った Ruby: Evil Martians流 Docker+Ruby/Rails開発環境構築 原本 日本語翻訳
  21. ありがとうございました! @Envek @Envek @Envek @Envek github.com/Envek @evilmartians @evilmartians @evilmartians_jp (日本語

    ) @evil.martians evilmartians.jp 我々のヤバいブログ : evilmartians.com/chronicles! @hachi8833さんが作ってくれた日本語の翻訳があります! このスライドは次のアドレスでご覧できます : envek.github.io/izumorb-kujira-ni-notta-ruby

More Decks by Andrey Novikov

Other Decks in Programming