コンテナ課題をやった時のメモ

ARGはビルド時にしか使わない環境変数を定義するコマンドで、何も指定しないと最初に定義した環境変数を利用する
FYI:
- ARGはENVと違って、ビルドする際にコマンドラインから値を上書きできます。
- そのため、独自イメージをビルドする際にベースイメージのタグ(バージョン的なもの)を動的に変えてビルドすることができます。
- バージョンを上げ下げして動くか検証したいケースとかで、サクッとバージョンを変えられるのがメリットなのかと感じました(そういう機会の頻度は少ないかもですが)。
## Dockerfile
ARG RUBY_VERSION=3.3.1
FROM docker.io/library/ruby:$RUBY_VERSION-slim AS base
RUN echo $RUBY_VERSION
## shell
docker build . --no-cache
// 省略
=> [internal] load metadata for docker.io/library/ruby:3.3.1-slim
docker build . --no-cache --build-arg RUBY_VERSION='3.0.0'
// 省略
=> [internal] load metadata for docker.io/library/ruby:3.0.0-slim

docker build とは
Dockerfile から独自のイメージをビルドするためのコマンド。https://qiita.com/YumaInaura/items/e7155b309e109bc75cf8

ランタイムには、「プログラムが実行されている時間(実行時)」と、「その実行を支える実行に必要なプログラムや環境」の2つの意味があります。プログラムを動かすための環境として、JavaやPythonなどの言語が提供する「ランタイム環境」や、Microsoft Accessの「ランタイム版」のように、開発機能を省いた実行専用のプログラムを指すことが多いです。
ランタイム(実行時)
プログラムがコンピュータ上で実際に動いている間、つまり「実行されている時間」そのものを指します。
この時間中にメモリ管理や例外処理などの処理が行われ、プログラムが機能します。
対義語は「コンパイル時(開発時)」で、コードが機械語に変換される前の段階を指します。
ランタイム(実行環境/ライブラリ)
プログラムを実行するために必要なソフトウェアやライブラリ、プログラム群を指します。
多くのランタイムは、ソフトウェアを開発する企業が無料で提供しており、特定の言語やアプリケーションの実行に必要な機能を提供します。
例1:言語のランタイム環境
JavaやPythonなどのプログラミング言語には、その言語で書かれたコードを実行するために必要な環境(ランタイム環境)があります。これがなければ、その言語で書かれたプログラムは動きません。例2:アプリケーションのランタイム版。
Microsoft OfficeのAccessのように、開発機能は持たず、作成済みのデータベースファイルを開いて操作するだけの「ランタイム版」も存在します。これは、開発者以外のユーザーがアプリケーションを利用するために提供されます。
プログラム実行時に遭遇する「ランタイムエラー」も、この実行時の環境や仕組みに関連するエラーを指します。
この解説普通にわかりやすい。
ARGで定義した環境変数は、ランタイム環境には引き継がれない。

RUNを使うと、イメージのシェルからコマンドを実行できる
RUN 命令は、現在のイメージよりも上にある新しいレイヤでコマンドを実行し、その結果を コミット(確定)commit します。結果が確定されたイメージは、 Dockerfile の次のステップで使われます。
厳密にいうと上の意味。

通常、 Docker イメージを自動構築できるように定義するのが Dockerfile と呼ぶ設定ファイルであり、このファイル内でイメージを構成する命令を書きます。この命令の1つ1つが、概念上のイメージ・レイヤに相当します。
独自イメージはDockerfileで定義するお。
独自イメージはイメージレイヤーで構成されていて、Dockerfileの命令の一つ一つがイメージレイヤを表している。

メモリアロケータとは
メモリアロケータは、プログラムが実行時に動的にメモリを要求・解放する際の管理を行うシステムです。
基本的な役割
メモリの割り当て(allocation)
- プログラムが「100バイトのメモリが欲しい」と要求したら、空いている場所を探して提供
メモリの解放(deallocation)
- 使い終わったメモリを「空き」として管理
メモリの管理
- どこが使用中で、どこが空いているかを記録
mallocの意味
malloc = Memory ALLOCation(メモリ・アロケーション)
memory(メモリ)
allocation(割り当て)

ENV RAILS_ENV="production" \
BUNDLE_DEPLOYMENT="1" \
BUNDLE_PATH="/usr/local/bundle" \
BUNDLE_WITHOUT="development" \
LD_PRELOAD="/usr/local/lib/libjemalloc.so"
"RAILS_ENV"はrailsが実行される環境を定義するために使う
deployment (BUNDLE_DEPLOYMENT)
frozen を true に設定し、path を vendor/bundle に設定するのと同じです。
Gemfile.lockへの自動変更を一切許可しない。ロックファイルが記述どおりに正確にインストールできない場合、Bundlerコマンドはブロックされる。通常、これはGemfileを手動で変更した際に、
bundle lock
またはbundle install
でロックファイルを更新し忘れた場合に発生する。
frozenはgemfile.lockへの自動更新を一切許可しないオプション。
gemfileにgemを追加して、bundle i --frozenをやってもダウンロードできない。
本番と開発環境で使うgemを統一したいので追加してる
通常のbundle install:
「Gemfile.lockと違いがあれば、自動的に修正してインストール」
bundle install --frozen:
「Gemfile.lockと違いがあれば、エラーで止める」
「違いがなければ、普通にインストール」
BUNDLE_PATH
$GEM_HOME や $GEM_PATH の値に関係なく、バンドル内のすべての gem が配置されるディスク上の場所。この場所に見つからない gem は bundle install でインストールされます。Bundler 4 ではリポジトリルートからの相対パス .bundle がデフォルトとなり、Bundler 4 以前ではデフォルトのシステムパス (Gem.dir) がデフォルトとなります。
BUNDLE_WITHOUT
Bundlerがインストールすべきでないgemのグループを、スペースまたはコロン(:)で区切ったリスト。
スペースまたはコロン(:)で区切られた、Bundlerがインストールすべきでないグループのリスト。

root@8ece656a9053:/rails# echo $BUNDLE_PATH
/usr/local/bundle
root@8ece656a9053:/rails# ls /usr/local/bundle
ruby
root@8ece656a9053:/rails# ls /usr/local/bundle/ruby
3.3.0
root@8ece656a9053:/rails# ls /usr/local/bundle/ruby/3.3.0
bin build_info cache doc extensions gems plugins specifications
root@8ece656a9053:/rails# ls /usr/local/bundle/ruby/3.3.0/gems
bundler-2.5.20
root@8ece656a9053:/rails# bundle i
Fetching gem metadata from https://rubygems.org/.........
root@8ece656a9053:/rails# ls /usr/local/bundle/ruby/3.3.0/gems
ast-2.4.3 crass-1.0.6 language_server-protocol-3.17.0.5 ostruct-0.6.3 regexp_parser-2.11.2 unicode-emoji-4.1.0
base64-0.3.0 date-3.4.1 lint_roller-1.1.0 parallel-1.27.0 ruby-progressbar-1.13.0 uri-1.0.3
bcrypt_pbkdf-1.1.1 dotenv-3.1.8 logger-1.7.0 prettyprint-0.2.0 securerandom-0.4.1 useragent-0.16.11
benchmark-0.4.1 drb-2.2.3 marcel-1.0.4 prism-1.5.0 sqlite3-2.7.3-x86_64-linux-gnu websocket-extensions-0.1.5
bigdecimal-3.2.3 ed25519-1.4.0 mini_mime-1.1.5 raabro-1.4.0 stringio-3.1.7 zeitwerk-2.7.3
builder-3.3.0 erb-5.0.2 minitest-5.25.5 racc-1.8.1 thor-1.4.0
bundler-2.5.20 erubi-1.13.1 msgpack-1.8.0 rack-3.2.1 thruster-0.1.15-x86_64-linux
concurrent-ruby-1.3.5 io-console-0.8.1 net-ssh-7.3.0 rainbow-3.1.1 timeout-0.4.3
connection_pool-2.5.4 json-2.13.2 nio4r-2.7.4 rake-13.3.0 tsort-0.2.0
root@8ece656a9053:/rails#
確かにbundle pathにインストールされてるな
:development, :test と書かれたgemは、両方のグループに属するという意味です。どちらか一つでも除外されると、そのgemはインストールされません。
なるほど。

WORKDIR 命令は、Dockerfile 内で以降に続く RUN 、 CMD 、 ENTRYPOINT 、 COPY 、 ADD 命令の処理時に(コマンドを実行する場所として)使う 作業ディレクトリworking directory を指定します。

- WORKDIR /railsを実行すると、作業ディレクトリがルートディレクトリから/railsになる。
- ルートディレクトリで作業するとシステムレベルのファイルを誤って上書きしてしまったり、予期せぬ問題が発生する恐れがあるので、安全性観点やメンテのしやすさから、作業ディレクトリを変更している。

マルチステージビルドを使うと、イメージを軽量化できる。
イメージを軽量化することで、コンテナの作成時間やイメージのダウンロード時間を減少できる。

# syntax=docker/dockerfile:1
# check=error=true
# This Dockerfile is designed for production, not development. Use with Kamal or build'n'run by hand:
# docker build -t cloud_practice .
# docker run -d -p 80:80 -e RAILS_MASTER_KEY=<value from config/master.key> --name cloud_practice cloud_practice
# For a containerized dev environment, see Dev Containers: https://guides.rubyonrails.org/getting_started_with_devcontainer.html
# Make sure RUBY_VERSION matches the Ruby version in .ruby-version
ARG RUBY_VERSION=3.3.1
FROM docker.io/library/ruby:$RUBY_VERSION-slim AS base
# # Rails app lives here
WORKDIR /rails
# Install base packages
RUN apt-get update -qq && \
apt-get install --no-install-recommends -y curl libjemalloc2 libvips sqlite3 && \
ln -s /usr/lib/$(uname -m)-linux-gnu/libjemalloc.so.2 /usr/local/lib/libjemalloc.so && \
rm -rf /var/lib/apt/lists /var/cache/apt/archives
# # Set production environment variables and enable jemalloc for reduced memory usage and latency.
ENV RAILS_ENV="production" \
BUNDLE_DEPLOYMENT="1" \
BUNDLE_PATH="/usr/local/bundle" \
BUNDLE_WITHOUT="development" \
LD_PRELOAD="/usr/local/lib/libjemalloc.so"
# Throw-away build stage to reduce size of final image
FROM base AS build
# Install packages needed to build gems
RUN apt-get update -qq && \
apt-get install --no-install-recommends -y build-essential git libyaml-dev pkg-config && \
rm -rf /var/lib/apt/lists /var/cache/apt/archives
# Install application gems
COPY Gemfile Gemfile.lock vendor ./
RUN bundle install && \
rm -rf ~/.bundle/ "${BUNDLE_PATH}"/ruby/*/cache "${BUNDLE_PATH}"/ruby/*/bundler/gems/*/.git && \
bundle exec bootsnap precompile --gemfile
# Copy application code
COPY . .
# Precompile bootsnap code for faster boot times
RUN bundle exec bootsnap precompile app/ lib/
# Final stage for app image
FROM base
# Run and own only the runtime files as a non-root user for security
RUN groupadd --system --gid 1000 rails && \
useradd rails --uid 1000 --gid 1000 --create-home --shell /bin/bash
USER 1000:1000
# Copy built artifacts: gems, application
COPY --chown=rails:rails --from=build "${BUNDLE_PATH}" "${BUNDLE_PATH}"
COPY --chown=rails:rails --from=build /rails /rails
# Entrypoint prepares the database.
ENTRYPOINT ["/rails/bin/docker-entrypoint"]
# Start server via Thruster by default, this can be overwritten at runtime
EXPOSE 80
CMD ["./bin/thrust", "./bin/rails", "server"]
build時にしか使わないパッケージとかを最終的なイメージに含めないようにできるのか。

RUN apt-get update -qq && \
apt-get install --no-install-recommends -y build-essential git libyaml-dev pkg-config && \
rm -rf /var/lib/apt/lists /var/cache/apt/archives
このコマンドで インストールされているパッケージは、主にRubyのgemをビルドするために必要な開発ツールです。それぞれの役割を説明します:
各パッケージの役割
build-essential
- GCCコンパイラ、make、その他の基本的なビルドツールを含むメタパッケージ
- ネイティブ拡張(C言語で書かれた部分)を持つgemをコンパイルするために必要
- 例:nokogiri、puma、pg、mysql2などのgemはC拡張を含むため、これらのツールが必要
git
- バージョン管理システム
- Gemfileでgit:オプションを使ってGitHubから直接gemを取得する場合に必要
- 例:gem 'rails', git: 'https://github.com/rails/rails.git'
libyaml-dev
- YAML処理ライブラリの開発用ヘッダファイル
- psych gem(RubyのYAMLパーサー)のビルドに必要
- Railsアプリケーションでは設定ファイル(database.yml等)の読み込みに使用
pkg-config
- ライブラリのコンパイルフラグやリンクフラグを管理するツール
- ネイティブ拡張を持つgemが依存ライブラリを正しく見つけるために使用

やっぱビルド時にしか使わないパッケージだよな

以下のdockerfileでdocker buildを実行すると、アプリのコード変更するたびにキャッシュが効かないでbundle installが実行される
COPY . .
RUN bundle install && \
rm -rf ~/.bundle/ "${BUNDLE_PATH}"/ruby/*/cache "${BUNDLE_PATH}"/ruby/*/bundler/gems/*/.git && \
bundle exec bootsnap precompile --gemfile
COPY Gemfile Gemfile.lock vendor ./
=> [base 1/3] FROM docker.io/library/ruby:3.3.1-slim@sha256:25ee093f9d3405b4eb6c94b760160293314355c5255ef7974027d1d3d5a33e5f 0.0s
=> [internal] load build context 0.0s
=> => transferring context: 3.07kB 0.0s
=> CACHED [base 2/3] WORKDIR /rails 0.0s
=> CACHED [base 3/3] RUN apt-get update -qq && apt-get install --no-install-recommends -y curl libjemalloc2 libvips sqlite3 && ln -s /usr/lib/$(uname -m)-linu 0.0s
=> CACHED [build 1/4] RUN apt-get update -qq && apt-get install --no-install-recommends -y build-essential git libyaml-dev pkg-config && rm -rf /var/lib/apt/l 0.0s
=> [build 2/4] COPY . . 0.1s
=> [build 3/4] RUN bundle install && rm -rf ~/.bundle/ "/usr/local/bundle"/ruby/*/cache "/usr/local/bundle"/ruby/*/bundler/gems/*/.git && bundle exec bootsna 62.2s
=> [build 4/4] COPY Gemfile Gemfile.lock vendor ./ 0.0s
=> exporting to image 2.3s
=> => exporting layers 2.3s
=> => writing image sha256:e19eeedc65b6be87362949e453894772779732962bcf1370ed6b8757045c150f 0.0s
2回目実行(キャッシュ効いてる)
=> [base 1/3] FROM docker.io/library/ruby:3.3.1-slim@sha256:25ee093f9d3405b4eb6c94b760160293314355c5255ef7974027d1d3d5a33e5f 0.0s
=> [internal] load build context 0.0s
=> => transferring context: 3.07kB 0.0s
=> CACHED [base 2/3] WORKDIR /rails 0.0s
=> CACHED [base 3/3] RUN apt-get update -qq && apt-get install --no-install-recommends -y curl libjemalloc2 libvips sqlite3 && ln -s /usr/lib/$(uname -m)-linu 0.0s
=> CACHED [build 1/4] RUN apt-get update -qq && apt-get install --no-install-recommends -y build-essential git libyaml-dev pkg-config && rm -rf /var/lib/apt/l 0.0s
=> CACHED [build 2/4] COPY . . 0.0s
=> CACHED [build 3/4] RUN bundle install && rm -rf ~/.bundle/ "/usr/local/bundle"/ruby/*/cache "/usr/local/bundle"/ruby/*/bundler/gems/*/.git && bundle exec b 0.0s
=> CACHED [build 4/4] COPY Gemfile Gemfile.lock vendor ./ 0.0s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:e19eeedc65b6be87362949e453894772779732962bcf1370ed6b8757045c150f 0.0s
コード編集して実行した後(COPYからキャッシュ効いてない)
=> [base 1/3] FROM docker.io/library/ruby:3.3.1-slim@sha256:25ee093f9d3405b4eb6c94b760160293314355c5255ef7974027d1d3d5a33e5f 0.0s
=> [internal] load build context 0.0s
=> => transferring context: 3.15kB 0.0s
=> CACHED [base 2/3] WORKDIR /rails 0.0s
=> CACHED [base 3/3] RUN apt-get update -qq && apt-get install --no-install-recommends -y curl libjemalloc2 libvips sqlite3 && ln -s /usr/lib/$(uname -m)-linu 0.0s
=> CACHED [build 1/4] RUN apt-get update -qq && apt-get install --no-install-recommends -y build-essential git libyaml-dev pkg-config && rm -rf /var/lib/apt/l 0.0s
=> [build 2/4] COPY . . 0.1s
=> [build 3/4] RUN bundle install && rm -rf ~/.bundle/ "/usr/local/bundle"/ruby/*/cache "/usr/local/bundle"/ruby/*/bundler/gems/*/.git && bundle exec bootsna 59.8s
=> [build 4/4] COPY Gemfile Gemfile.lock vendor ./ 0.0s
=> exporting to image 3.5s
=> => exporting layers 3.5s
=> => writing image sha256:8b690bbecbf49520cd6847555cb334407c81c7793a5fdf42f606c0440c995f62 0.0s

たしかに、この順番だとアプリのコードいじっても、Gemfileとか編集してない限りはちゃんとbundle iのキャッシュが効いてる。
COPY Gemfile Gemfile.lock vendor ./
RUN bundle install && \
rm -rf ~/.bundle/ "${BUNDLE_PATH}"/ruby/*/cache "${BUNDLE_PATH}"/ruby/*/bundler/gems/*/.git && \
bundle exec bootsnap precompile --gemfile
COPY . .
=> [base 1/3] FROM docker.io/library/ruby:3.3.1-slim@sha256:25ee093f9d3405b4eb6c94b760160293314355c5255ef7974027d1d3d5a33e5f 0.0s
=> [internal] load build context 0.0s
=> => transferring context: 3.07kB 0.0s
=> CACHED [base 2/3] WORKDIR /rails 0.0s
=> CACHED [base 3/3] RUN apt-get update -qq && apt-get install --no-install-recommends -y curl libjemalloc2 libvips sqlite3 && ln -s /usr/lib/$(uname -m)-linu 0.0s
=> CACHED [build 1/4] RUN apt-get update -qq && apt-get install --no-install-recommends -y build-essential git libyaml-dev pkg-config && rm -rf /var/lib/apt/l 0.0s
=> CACHED [build 2/4] COPY Gemfile Gemfile.lock vendor ./ 0.0s
=> CACHED [build 3/4] RUN bundle install && rm -rf ~/.bundle/ "/usr/local/bundle"/ruby/*/cache "/usr/local/bundle"/ruby/*/bundler/gems/*/.git && bundle exec b 0.0s
=> [build 4/4] COPY . . 0.1s
=> exporting to image 0.1s
=> => exporting layers 0.0s
=> => writing image sha256:6c1d9c2de80eab5ff07946f829aeed71431c9d70a2c54386a0b41332ecd4695a 0.0s
↓
(アプリのコード変えた後も、ちゃんとキャッシュきいてる。コードいじったからbuildだけきいてない)
=> [base 1/3] FROM docker.io/library/ruby:3.3.1-slim@sha256:25ee093f9d3405b4eb6c94b760160293314355c5255ef7974027d1d3d5a33e5f 0.0s
=> [internal] load build context 0.0s
=> => transferring context: 3.16kB 0.0s
=> CACHED [base 2/3] WORKDIR /rails 0.0s
=> CACHED [base 3/3] RUN apt-get update -qq && apt-get install --no-install-recommends -y curl libjemalloc2 libvips sqlite3 && ln -s /usr/lib/$(uname -m)-linu 0.0s
=> CACHED [build 1/4] RUN apt-get update -qq && apt-get install --no-install-recommends -y build-essential git libyaml-dev pkg-config && rm -rf /var/lib/apt/l 0.0s
=> CACHED [build 2/4] COPY Gemfile Gemfile.lock vendor ./ 0.0s
=> CACHED [build 3/4] RUN bundle install && rm -rf ~/.bundle/ "/usr/local/bundle"/ruby/*/cache "/usr/local/bundle"/ruby/*/bundler/gems/*/.git && bundle exec b 0.0s
=> [build 4/4] COPY . . 0.1s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:c970abbc1682b357d8b8a064706ae034aa8b0787115ad0358092e37bfa3882f5

Gemfileいじるとちゃんとキャッシュ聞いてなかった。
=> [base 1/3] FROM docker.io/library/ruby:3.3.1-slim@sha256:25ee093f9d3405b4eb6c94b760160293314355c5255ef7974027d1d3d5a33e5f 0.0s
=> CACHED [base 2/3] WORKDIR /rails 0.0s
=> CACHED [base 3/3] RUN apt-get update -qq && apt-get install --no-install-recommends -y curl libjemalloc2 libvips sqlite3 && ln -s /usr/lib/$(uname -m)-linu 0.0s
=> CACHED [build 1/4] RUN apt-get update -qq && apt-get install --no-install-recommends -y build-essential git libyaml-dev pkg-config && rm -rf /var/lib/apt/l 0.0s
=> [build 2/4] COPY Gemfile Gemfile.lock vendor ./ 0.0s
=> [build 3/4] RUN bundle install && rm -rf ~/.bundle/ "/usr/local/bundle"/ruby/*/cache "/usr/local/bundle"/ruby/*/bundler/gems/*/.git && bundle exec bootsna 62.6s
=> [build 4/4] COPY . . 0.1s
=> exporting to image 2.6s
=> => exporting layers 2.6s
=> => writing image sha256:5a575dbfcd24b32bfc1d1b3fc3faab8e47be5d0c10d1af74e1ab30f9a8abd6b5 0.0s

DockerはDockerfileに書かれた内容を解釈してイメージを作ってくれるわけですが、1つ1つの命令をレイヤー(層)とし、積み重ねてイメージを作成します。
レイヤーに変更がなければDockerは以前の結果を再利用してくれます(レイヤーキャッシュ)。逆に変更があれば、それ以降のレイヤーは再度作成されます。
ドキュメントによると、「COPY」と「ADD」はファイルの内容やメタデータ(最終アクセス時刻や更新時刻は含まない)から作られたハッシュを元に、変更がないかチェックされます。
「RUN」は単に実行するコマンド文字列(実行により変更されたファイルは見ない)が変化していないかチェックされます。
このように書くと、ソースコードを書き換えても新たにライブラリを追加しなければレイヤーキャッシュが使われます。
わかりやすい。
ソースコードは変更頻度高いから、それを先に命令で書いちゃうと、ライブラリインストールの命令とかが毎回走ったりして、待ち時間がめんどくさい

関係性
RAILS_MASTER_KEY
↓ (復号化)
credentials.yml.enc
↓ (含まれる)
SECRET_KEY_BASE(および他の機密情報)
↓ (使用)
アプリケーションの暗号化処理
RAILS_MASTER_KEY
役割: credentials.yml.encファイルを復号化するための鍵
- Rails 5.2以降で導入された機能
- config/credentials.yml.encという暗号化されたファイルを復号化するために使用
- このファイルの中にSECRET_KEY_BASEやAPIキーなどの機密情報を安全に保存できる
SECRET_KEY_BASE
役割: アプリケーションレベルでの暗号化・署名に使用される鍵
- セッションの暗号化
- cookieの署名
- CSRFトークンの生成
RAILS_MASTER_KEY:
- config/master.keyファイルまたは環境変数で管理
- 絶対にGitにコミットしない
- 本番環境では環境変数RAILS_MASTER_KEYとして設定
SECRET_KEY_BASE:
- Rails 5.2以降は通常credentials.yml.enc内に暗号化して保存
- credentials.yml.encはGitにコミット可能(暗号化されているため)
この仕組みにより、SECRET_KEY_BASEを含む機密情報を安全にバージョン管理できるようになっています。再試行

bin/rails credentials:editでconfig/credentials.yml.encを複合できて、そこにsecret_key_baseが定義されてた。
# smtp:
# user_name: my-smtp-user
# password: my-smtp-password
#
# aws:
# access_key_id: 123
# secret_access_key: 345
# Used as the base secret for all MessageVerifiers in Rails, including the one protecting cookies.
secret_key_base: e15 // 省略

config/master.keyの中の文字適当に変えて、複合実行したら失敗した。なるほどな
bin/rails credentials:edit
Editing config/credentials.yml.enc...
Couldn't decrypt config/credentials.yml.enc. Perhaps you passed the wrong key?

RAILS_MASTER_KEYはconfig/master.keyファイルまたは環境変数で管理するのか。

Rails.application.credentialsでcredentialsの情報にアクセスできる。
cloud-practice(dev):004> Rails.application.credentials.to_h
=>
{:smtp=>{:user_name=>"my-smtp-user", :password=>"my-smtp-password"},
:secret_key_base=>"e156d298

1. Rails.application.credentials へのアクセス
アセットプリコンパイル中に実行されるコードで、credentialsにアクセスしようとする場合:
ruby# config/initializers/some_initializer.rb
Rails.application.configure do
config.some_api_key = Rails.application.credentials.api_key
end
# app/javascript/packs/application.js.erb
window.API_ENDPOINT = '<%= Rails.application.credentials.api_endpoint %>';

secrete_key_baseを指定すると、RAISL_MASTER_KEYを指定しなくても起動できる
docker run -it -e SECRET_KEY_BASE=dummy_key_for_console 761016540357 bash
rails@d7b99e208908:/rails$ bin/rails c
Generating image variants require the image_processing gem. Please add `gem 'image_processing', '~> 1.2'` to your Gemfile.
Loading production environment (Rails 8.1.0.beta1)
cloud-practice(prod):001> Rails.application.credentials
=> #<ActiveSupport::EncryptedConfiguration:0x00000000012200>
cloud-practice(prod):002> Rails.application.credentials.to_h
=> {}
cloud-practice(prod):003> exit
rails@d7b99e208908:/rails$ exit
exit
docker run -it 761016540357 bash
rails@70cf742a1770:/rails$ ls
Gemfile Gemfile.lock README.md Rakefile app bin compose.yml config config.ru db lib log public script storage test tmp vendor
rails@70cf742a1770:/rails$ bin/rails c
/usr/local/bundle/ruby/3.3.0/gems/railties-8.1.0.beta1/lib/rails/application/configuration.rb:550:in `secret_key_base=': Missing `secret_key_base` for 'production' environment, set this string with `bin/rails credentials:edit` (ArgumentError)
raise ArgumentError, "Missing `secret_key_base` for '#{Rails.env}' environment, set this string with `bin/rails credentials:edit`"
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
from /usr/local/bundle/ruby/3.3.0/gems/railties-8.1.0.beta1/lib/rails/application/configuration.rb:532:in `secret_key_base'
docker run -it -e RAILS_MASTER_KEY=68//省略 bash
rails@b2b1a7d5a89c:/rails$ bin/rails c
Generating image variants require the image_processing gem. Please add `gem 'image_processing', '~> 1.2'` to your Gemfile.
Loading production environment (Rails 8.1.0.beta1)
cloud-practice(prod):001> Rails.application.credentials
=> #<ActiveSupport::EncryptedConfiguration:0x0000000000be28>
cloud-practice(prod):002> Rails.application.credentials.to_h
=> {:secret_key_base=>"e15//省略"}
RAILS_MASTER_KEYを指定しなくてもうまくいくのか

.dockerignoreにconfig/master.keyを設定しているから、コンテナにconig/master.keyがコピーされなくて、つまり、RAILS_MASTER_KEYでマスターキーを渡すしかないってこと。
故にRIALS_MASTER_KEYを渡してない状態でコンテナ環境でビルドするときに、assets precompileが失敗するのか。
多分以下のエラーが出る
ArgumentError: Missing secret_key_base for 'production' environment, set this string with rails credentials:edit
本番環境で画像ビルドステップの一環としてアセットをコンパイルする際、実際の RAILS_MASTER_KEY を渡す必要があるのは不便です。そこで、開発環境やテスト環境と同様に、ダミーの secret_key_base を ENV["SECRET_KEY_BASE_DUMMY"] = 1 のように渡せるようにします。これにより、実際の認証情報やメッセージ検証機能へのアクセスは一切行われませんが、ビルドステップは完了します。通常、ビルドステップではこれらの情報は必要ないためです。
わかりそうでわからない。


apt-getは、DebianやUbuntuなどのLinuxディストリビューションで使用されるコマンドラインツール

groupadd コマンドは新しいグループを作成するために使う。
-r, --system は、システムグループを作成するためのオプション
--gidは、新規のグループidを指定している
linuxの/etcディレクトリは設定ファイルなどが入っているディレクトリ

グループにも、ユーザーグループとシステムグループって概念がある。
“system group“にどこかピンとこないのだが、『システムを稼動させる為に存在するグループ』という認識をすることにした。ここで言う『システム』は例えばMongoDBであったりZooKeeperであったり。サービス(デーモン)として稼動させるプログラムを動かす為だけに存在させる、という認識を持った(あくまで自身がそう思っただけである)。
システムグループは、システムを稼働させるために存在するグループ。

whoamiコマンドで、、現在サーバーにログインしているユーザー名を簡単に見れる。

useraddは新規ユーザーを作成し、ユーザーごとの設定を決めるコマンド
useradd [オプション] ユーザー名
--uidで、作成するユーザーのユーザーIDを指定する
--gidで、ユーザーが所属するグループを指定する。
useraddコマンドの--shellオプション(または短縮オプション-s)は、新規ユーザーのログインシェルを指定するために使用する。
useraddの--create-homeは、ユーザーのホームディレクトリが存在しない場合、作成する
DockerfileのUSER命令は、UIDとGIDを指定する。

cat /etc/groupでグループ一覧見れる

--chownオプションの動作
COPY --chown=rails:railsの意味:
最初のrails: 所有者としてrailsを指定
2番目のrails: グループとしてrailsを指定
COPYする際にchownオプションを使って、そのファイル/ディレクトリの所有者と所有グループを指定できたのか。

ls -la file.txt
-rw-r--r-- 1 user1 group1 1234 Jan 1 10:00 file.txt
この権限表示の意味:
最初の3文字 (rw-): 所有者(user1)の権限
次の3文字 (r--): 所有グループ(group1)の権限
最後の3文字 (r--): その他のユーザーの権限
ファイルの所有者とグループを確認
ls -l file.txt
-rw-r--r-- 1 user1 developers 1234 Jan 1 10:00 file.txt
↑所有者(user1) ↑所有グループ(developers)
id ユーザー名でユーザーのidや所属するグループidを見れる。
# user2がdevelopersグループに所属している場合
id user2
# uid=1002(user2) gid=1002(user2) groups=1002(user2),1003(developers)
# user2はグループ権限(r--)でアクセスできる

ファイルには権限が振られている。あと所有者と所有グループを指定されている。
所有グループは所属していれば、所有グループに所属していなければ、所有グループの権限でファイルを操作できない
# ファイルの詳細
ls -l project.txt
-rw-rw-r-- 1 alice developers 100 Jan 1 10:00 project.txt
# ↑ ↑ ↑
# 所有者:rw グループ:rw 所有グループ:developers
# bobがdevelopersグループに属している場合
id bob
# uid=1002(bob) gid=1002(bob) groups=1002(bob),1003(developers)
# bobはグループ権限(rw)でファイルを操作できる
cat project.txt # 読める(r権限)
echo "追記" >> project.txt # 書ける(w権限)

rootユーザーは、すべてのファイルを操作できる。

# Run and own only the runtime files as a non-root user for security
RUN groupadd --system --gid 1000 rails && \
useradd rails_user --uid 1001 --gid 1000 --create-home --shell /bin/bash
USER 1001:1000
# Copy built artifacts: gems, application
COPY --chown=rails_user:rails --from=build "${BUNDLE_PATH}" "${BUNDLE_PATH}"
COPY --chown=rails_user:rails --from=build /rails /rails
rails_user@95bed36d2468:/rails$ ls -al
total 100
drwxr-xr-x 1 root root 4096 Sep 14 01:18 .
drwxr-xr-x 1 root root 4096 Sep 14 01:27 ..
-rw-r--r-- 1 rails_user rails 348 Sep 13 08:42 .gitattributes
-rw-r--r-- 1 rails_user rails 249 Sep 13 08:42 .rubocop.yml
-rw-r--r-- 1 rails_user rails 6 Sep 13 08:42 .ruby-version
-rw-r--r-- 1 rails_user rails 1979 Sep 13 12:15 Gemfile
-rw-r--r-- 1 rails_user rails 8933 Sep 13 12:15 Gemfile.lock
-rw-r--r-- 1 rails_user rails 17 Sep 13 08:44 README.md
-rw-r--r-- 1 rails_user rails 227 Sep 13 08:42 Rakefile
drwxr-xr-x 7 rails_user rails 4096 Sep 13 11:47 app
drwxr-xr-x 2 rails_user rails 4096 Sep 13 11:47 bin
-rw-r--r-- 1 rails_user rails 2591 Sep 13 08:52 compose.yml
drwxr-xr-x 5 rails_user rails 4096 Sep 13 13:52 config
-rw-r--r-- 1 rails_user rails 160 Sep 13 08:42 config.ru
drwxr-xr-x 2 rails_user rails 4096 Sep 13 11:47 db
drwxr-xr-x 3 rails_user rails 4096 Sep 13 11:47 lib
drwxr-xr-x 2 rails_user rails 4096 Sep 13 08:46 log
drwxr-xr-x 2 rails_user rails 4096 Sep 13 11:47 public
drwxr-xr-x 2 rails_user rails 4096 Sep 13 08:46 script
drwxr-xr-x 2 rails_user rails 4096 Sep 13 08:46 storage
drwxr-xr-x 8 rails_user rails 4096 Sep 13 11:47 test
drwxr-xr-x 5 rails_user rails 4096 Sep 13 11:47 tmp
drwxr-xr-x 2 rails_user rails 4096 Sep 13 08:46 vendor
rails_user@95bed36d2468:/rails$ whoami
rails_user
rails_user@95bed36d2468:/rails$ id rails_user
uid=1001(rails_user) gid=1000(rails) groups=1000(rails)
rails_user@95bed36d2468:/rails$
確かにrails_user, railsでファイルがコピーされてた

上記のように、デフォルトではDockerコンテナはUID 0、またはrootとして実行されます。 つまり、Dockerコンテナが侵害された場合、攻撃者はコンテナに割り当てられたすべてのリソースに対してホストレベルのルートアクセス権を持つことになります。 root以外のユーザーを使用すると、攻撃者がコンテナで実行されているアプリケーションから抜け出すことができたとしても、コンテナがroot以外のユーザーとして実行されている場合、攻撃者の権限は制限されます。
確かにrails_user作った場合だと、sudoコマンド最初から使えないのか。つまり作ったユーザーだとsudo権限がついてないのか。
ails_user@4047368ce958:/rails$ sudo -l
bash: sudo: command not found
rails_user@4047368ce958:/rails$ sudo cat .rubocop.yml
bash: sudo: command not found
rails_user@4047368ce958:/rails$
su -でルートユーザーに切り替えられるけどパスワードが必要。
rails_user@4047368ce958:/rails$ sudo cat .rubocop.yml
bash: sudo: command not found
rails_user@4047368ce958:/rails$ su -
Password:
rootユーザーでログインできちゃうと不正アクセスされた時にやりたい放題できる。
dockerfileはデフォルトでrootユーザーでアクセスできちゃうので、なので、サーバーにログインするデフォルトのユーザーを変えてる。
# syntax=docker/dockerfile:1
# check=error=true
# This Dockerfile is designed for production, not development. Use with Kamal or build'n'run by hand:
# docker build -t cloud_practice .
# docker run -d -p 80:80 -e RAILS_MASTER_KEY=<value from config/master.key> --name cloud_practice cloud_practice
# For a containerized dev environment, see Dev Containers: https://guides.rubyonrails.org/getting_started_with_devcontainer.html
# Make sure RUBY_VERSION matches the Ruby version in .ruby-version
ARG RUBY_VERSION=3.3.1
FROM docker.io/library/ruby:$RUBY_VERSION-slim AS base
# # Rails app lives here
WORKDIR /rails
# Install base packages
RUN apt-get update -qq && \
apt-get install --no-install-recommends -y curl libjemalloc2 libvips sqlite3 && \
ln -s /usr/lib/$(uname -m)-linux-gnu/libjemalloc.so.2 /usr/local/lib/libjemalloc.so && \
rm -rf /var/lib/apt/lists /var/cache/apt/archives
# # Set production environment variables and enable jemalloc for reduced memory usage and latency.
ENV RAILS_ENV="production" \
BUNDLE_DEPLOYMENT="1" \
BUNDLE_PATH="/usr/local/bundle" \
BUNDLE_WITHOUT="development" \
LD_PRELOAD="/usr/local/lib/libjemalloc.so"
# Throw-away build stage to reduce size of final image
FROM base AS build
# Install packages needed to build gems
RUN apt-get update -qq && \
apt-get install --no-install-recommends -y build-essential git libyaml-dev pkg-config && \
rm -rf /var/lib/apt/lists /var/cache/apt/archives
# Install application gems
COPY Gemfile Gemfile.lock vendor ./
RUN bundle install && \
rm -rf ~/.bundle/ "${BUNDLE_PATH}"/ruby/*/cache "${BUNDLE_PATH}"/ruby/*/bundler/gems/*/.git && \
bundle exec bootsnap precompile --gemfile
COPY . .
# Copy application code
# Precompile bootsnap code for faster boot times
RUN bundle exec bootsnap precompile app/ lib/
# Final stage for app image
FROM base
# Run and own only the runtime files as a non-root user for security
RUN groupadd --system --gid 1000 rails && \
useradd rails_user --uid 1001 --gid 1000 --create-home --shell /bin/bash
USER 1001:1000
# Copy built artifacts: gems, application
COPY --chown=rails_user:rails --from=build "${BUNDLE_PATH}" "${BUNDLE_PATH}"
COPY --chown=rails_user:rails --from=build /rails /rails
# Entrypoint prepares the database.
ENTRYPOINT ["/rails/bin/docker-entrypoint"]
# Start server via Thruster by default, this can be overwritten at runtime
EXPOSE 80
CMD ["./bin/thrust", "./bin/rails", "server"]

# syntax=docker/dockerfile:1
# check=error=true
# This Dockerfile is designed for production, not development. Use with Kamal or build'n'run by hand:
# docker build -t cloud_practice .
# docker run -d -p 80:80 -e RAILS_MASTER_KEY=<value from config/master.key> --name cloud_practice cloud_practice
# For a containerized dev environment, see Dev Containers: https://guides.rubyonrails.org/getting_started_with_devcontainer.html
# Make sure RUBY_VERSION matches the Ruby version in .ruby-version
ARG RUBY_VERSION=3.3.1
FROM docker.io/library/ruby:$RUBY_VERSION-slim AS base
# # Rails app lives here
WORKDIR /rails
# Install base packages
RUN apt-get update -qq && \
apt-get install --no-install-recommends -y curl libjemalloc2 libvips sqlite3 && \
ln -s /usr/lib/$(uname -m)-linux-gnu/libjemalloc.so.2 /usr/local/lib/libjemalloc.so && \
rm -rf /var/lib/apt/lists /var/cache/apt/archives
# # Set production environment variables and enable jemalloc for reduced memory usage and latency.
ENV RAILS_ENV="production" \
BUNDLE_DEPLOYMENT="1" \
BUNDLE_PATH="/usr/local/bundle" \
BUNDLE_WITHOUT="development" \
LD_PRELOAD="/usr/local/lib/libjemalloc.so"
# Throw-away build stage to reduce size of final image
FROM base AS build
# Install packages needed to build gems
RUN apt-get update -qq && \
apt-get install --no-install-recommends -y build-essential git libyaml-dev pkg-config && \
rm -rf /var/lib/apt/lists /var/cache/apt/archives
# Install application gems
COPY Gemfile Gemfile.lock vendor ./
RUN bundle install && \
rm -rf ~/.bundle/ "${BUNDLE_PATH}"/ruby/*/cache "${BUNDLE_PATH}"/ruby/*/bundler/gems/*/.git && \
bundle exec bootsnap precompile --gemfile
COPY . .
# Copy application code
# Precompile bootsnap code for faster boot times
RUN bundle exec bootsnap precompile app/ lib/
# Final stage for app image
FROM base
# Run and own only the runtime files as a non-root user for security
# RUN groupadd --system --gid 1000 rails && \
# useradd rails_user --uid 1001 --gid 1000 --create-home --shell /bin/bash
# USER 1001:1000
# # Copy built artifacts: gems, application
# COPY --chown=rails_user:rails --from=build "${BUNDLE_PATH}" "${BUNDLE_PATH}"
# COPY --chown=rails_user:rails --from=build /rails /rails
COPY --from=build "${BUNDLE_PATH}" "${BUNDLE_PATH}"
COPY --from=build /rails /rails
# Entrypoint prepares the database.
ENTRYPOINT ["/rails/bin/docker-entrypoint"]
# Start server via Thruster by default, this can be overwritten at runtime
EXPOSE 80
CMD ["./bin/thrust", "./bin/rails", "server"]
確かにrootでログインしているし、rootがファイルの所有者と所有グループになっている。
docker run -it 8af4ea4157af bash
root@88355813a4e5:/rails# ls -al
total 100
drwxr-xr-x 1 root root 4096 Sep 14 01:43 .
drwxr-xr-x 1 root root 4096 Sep 14 01:45 ..
-rw-r--r-- 1 root root 348 Sep 13 08:42 .gitattributes
-rw-r--r-- 1 root root 249 Sep 13 08:42 .rubocop.yml
-rw-r--r-- 1 root root 6 Sep 13 08:42 .ruby-version
-rw-r--r-- 1 root root 1979 Sep 13 12:15 Gemfile
-rw-r--r-- 1 root root 8933 Sep 13 12:15 Gemfile.lock
-rw-r--r-- 1 root root 17 Sep 13 08:44 README.md
-rw-r--r-- 1 root root 227 Sep 13 08:42 Rakefile
drwxr-xr-x 7 root root 4096 Sep 13 11:47 app
drwxr-xr-x 2 root root 4096 Sep 13 11:47 bin
-rw-r--r-- 1 root root 2591 Sep 13 08:52 compose.yml
drwxr-xr-x 5 root root 4096 Sep 13 13:52 config
-rw-r--r-- 1 root root 160 Sep 13 08:42 config.ru
drwxr-xr-x 2 root root 4096 Sep 13 11:47 db
drwxr-xr-x 3 root root 4096 Sep 13 11:47 lib
drwxr-xr-x 2 root root 4096 Sep 13 08:46 log
drwxr-xr-x 2 root root 4096 Sep 13 11:47 public
drwxr-xr-x 2 root root 4096 Sep 13 08:46 script
drwxr-xr-x 2 root root 4096 Sep 13 08:46 storage
drwxr-xr-x 8 root root 4096 Sep 13 11:47 test
drwxr-xr-x 5 root root 4096 Sep 13 11:47 tmp
drwxr-xr-x 2 root root 4096 Sep 13 08:46 vendor
root@88355813a4e5:/rails# whoami
root
root@88355813a4e5:/rails# id root
uid=0(root) gid=0(root) groups=0(root)
root@88355813a4e5:/rails#

DockerfileのENTRYPOINTは、イメージからコンテナを作る時に実行するコマンドを指定する。
CMDも同様だが、CMDは簡単に上書きできる。

bin/rails db:setupコマンドは、「データベースの作成」「スキーマの読み込み」「seedデータを用いたデータベースの初期化」をまとめて実行します。
- データベースの作成
- スキーマの読み込み
- seed
の3つを考えとく。
bin/rails db:prepareはbin/rails db:setupの冪等版。
上の3つを順番に実行するが、もしすでに実行してたら実行しない。

#!/bin/bash -e
echo "Running entrypoint script..."
echo "Command: ${@}"
echo "${@: -2:1}"
echo "${@: -1:1}"
# If running the rails server then create or migrate existing database
if [ "${@: -2:1}" == "./bin/rails" ] && [ "${@: -1:1}" == "server" ]; then
echo "=== Preparing database... ==="
./bin/rails db:prepare
echo "=== Database preparation completed ==="
fi
exec "${@}"
docker run -it -e RAILS_MASTER_KEY="699//省略" ff7eee09ecf6 ./bin/rails server
Running entrypoint script...
Command: ./bin/rails server
./bin/rails
server
=== Preparing database... ===
Generating image variants require the image_processing gem. Please add `gem 'image_processing', '~> 1.2'` to your Gemfile.
=== Database preparation completed ===
=> Booting Puma
=> Rails 8.1.0.beta1 application starting in production
=> Run `bin/rails server --help` for more startup options
Generating image variants require the image_processing gem. Please add `gem 'image_processing', '~> 1.2'` to your Gemfile.
Puma starting in single mode...
* Puma version: 7.0.2 ("Romantic Warrior")
* Ruby version: ruby 3.3.1 (2024-04-23 revision c56cd86388) +YJIT [x86_64-linux]
* Min threads: 3
* Max threads: 3
* Environment: production
* PID: 1
* Listening on http://0.0.0.0:3000
Use Ctrl-C to stop

"${@: -2:1}"は渡した引数の最後から二番目の一つ
"${@: -1:1}"は渡した引数の最後から1番目の一つ

渡し方にdb prepareが実行されるかが依存しているのがなんか微妙な感じするな。

entroypoint命令だからimageビルド時には実行されないのか。確かにdbのイメージビルド時に実行しても意味ないか。


cmd命令はコンテナで実行するデフォルトのコマンドを指定する
ユーザーが明示的にコマンドを指定すれば、cmdは無視される。
コンテナでwebサーバーのコマンドを起動させたり、bashのコマンドを実行させたりできる。
entroypoint命令で指定したコマンドは基本変更できない。entorypoiint命令を指定した場合、docker runの最後に指定するコマンドは、このentroypointで指定したコマンドへの引数となる。(先ほどのコードブロック見ればbin/rails serverが渡っていることがわかる)

/bin/sh がシェルプログラム
-c オプションが「次の文字列をコマンドとして実行せよ」という指示

シェルインジェクションとは、OSコマンドインジェクションの別名で、ウェブアプリケーションなどの脆弱性を悪用し、不正なOSコマンドを実行させるサイバー攻撃のことです。
攻撃者は、ユーザーからの入力を受け付ける部分(フォームやURLパラメータなど)に悪意のある文字列を注入(インジェクション)します。プログラムがその入力値を適切に検証・無害化することなくOSのシェルに渡してしまうと、攻撃者の意図するコマンドが実行されてしまいます。
シェル形式のメリットは
- 環境変数が使える
- シェルの機能(パイプなどが使える)
- 一般的なシェルコマンドをそのまま記述可能
exec形式のデメリットは、シェルの機能(環境変数やパイプなどが使えないこと)

CMD命令やENTORYPOIINT命令は、RUN命令と同様、シェル形式とexec形式のいずれの書式も取ることができる。

Thrusterについて
Thrusterは、RailsアプリケーションのためのHTTPキャッシュプロキシです。主な特徴:
Puma(Railsサーバー)の前に配置してパフォーマンスを向上
HTTP/2サポート
自動的なgzip圧縮
キャッシュ機能

Thrustster初めて知った。nginxみたいなプロキシなのか。

Gem.bin_pathで、gemの実行可能ファイルのパスを取得してる。
cloud-practice(prod):002> Gem.bin_path("thruster", "thrust")
=> "/usr/local/bundle/ruby/3.3.0/gems/thruster-0.1.15-x86_64-linux/exe/thrust"
loadメソッドの基本
Rubyには外部のソースファイルを読み込むメソッドとして、先ほど説明したrequireの他にloadメソッドもあります。なおrequireメソッドは1回しか使用できませんが、loadメソッドは何度も使用可能です。
loadメソッド初めて知った。

without (BUNDLE_WITHOUT)
Bundlerがインストールするべきではない、:区切りのGemのグループのリストを指定します。
:区切りで行ける
export BUNDLE_WITHOUT=development:test
引数無しで実行すると、現在バンドルされているの全てのBundler設定と、 どこにそれが設定されたのかを示す一覧を出力します。
bundle configで現時点のbundlerの設定を確認できる。
bundle listでローカルプロジェクトでbundler経由してインストールされたgemの一覧を取得できる。
もし個別のgemが見たいならbundle info使う。

bootsnapは、railsの起動時の処理を最適化する(パスとrubyのコンパイル結果をキャッシュ)ことで起動時間を短縮してくれる便利なgemです。
なるほど。起動時間を短縮してくれるgemなのか。
bootsnapはデフォルトで、tmp/cacheにキャッシュを作成するので、これを削除するとイメージサイズを減少できる。
require 'bootsnap'
env = ENV['RAILS_ENV'] || "development"
Bootsnap.setup(
cache_dir: 'tmp/cache', # Path to your cache
ignore_directories: ['node_modules'], # Directory names to skip.
development_mode: env == 'development', # Current working environment, e.g. RACK_ENV, RAILS_ENV, etc
load_path_cache: true, # Optimize the LOAD_PATH with a cache
compile_cache_iseq: true, # Compile Ruby code into ISeq cache, breaks coverage reporting.
compile_cache_yaml: true, # Compile YAML into a cache
compile_cache_json: true, # Compile JSON into a cache
readonly: true, # Use the caches but don't update them on miss or stale entries.
)

rubyの$LOAD_PATH
Rubyライブラリをロードするときの検索パスである。
$PATHに似てるな。

buildkitはdockerのビルダー

build.dockefile
dockerfile は代替の Dockerfile を設定します。相対パスはビルドコンテキストから解決されます。Compose は、Dockerfile を定義するために絶対パスを使用することについて警告します。これは Compose ファイルの移植性を妨げるためです。
設定された場合、dockerfile_inline 属性は許可されず、Compose は両方が設定された Compose ファイルを拒否します。
dockerfileはビルドコンテキストからのパスとして解決される。
build.context
コンテキストは、Dockerfileを含むディレクトリへのパス、またはGitリポジトリへのURLのいずれかを定義します。
指定された値が相対パスである場合、プロジェクトディレクトリからの相対パスとして解釈されます。絶対パスを使用してビルドコンテキストを定義すると、Composeファイルの移植性が損なわれるため、Composeは警告を表示します。
こっちの説明の方がわかりやすいか
build.contextでdocker buildのビルドコンテキストを示しているのか
値が相対パスとして指定される場合、 Compose ファイルの場所からの相対パスと解釈する 必要がありますMUST
相対パス指定してたら、composeファイルのディレクトリからの相対パスとして扱ってくれるから、プロジェクト内であるディレクトリにいた状態でdocker compose しても問題ないのか。

このドキュメントわかりやすい
docker buildコマンドを実行したときの、カレントなワーキングディレクトリのことを ビルドコンテキスト(build context)と呼びます。 デフォルトで Dockerfile は、カレントなワーキングディレクトリにあるものとみなされます。 ただしファイルフラグ(-f)を使って別のディレクトリとすることもできます。 Dockerfileが実際にどこにあったとしても、カレントディレクトリ配下にあるファイルやディレクトリの内容がすべて、ビルドコンテキストとして Docker デーモンに送られることになります。
イメージのビルドには必要のないファイルを誤って含めてしまうと、ビルドコンテキストがそれだけ大きくなり、結果としてサイズの大きなイメージが生成されることになります。 こうしてしまうと、イメージビルドの時間、このイメージをプッシュしたりプルしたりする時間が、その分だけ要することとなり、コンテナーの実行時の容量も増えてしまいます。 ビルドコンテキストのサイズがどれだけになったかは、Dockerfileを使ってビルド処理を行った際の以下のようなメッセージを確認すればわかります。

ビルドコンテキストとはのこの説明わかりやすい

lsof -iのiはinternetのi
-iオプションは、インターネット(ネットワーク)接続に関する情報を表示するために使用されます。

Dockerの本番環境で秘密情報を使う際に、環境変数を使うことは推奨されてません。
秘密情報を扱うには、コンテナオーケストレーションのsecret supportを使うことが推奨されてます。
Docker Composeには秘密情報を扱うために、secretsがあります。(Docker ComposeのsecretsはDocker Swarmと併用することが前提の機能です)
Dockerfile(docker-compose.yamlではない)で
ENVやARGを使い環境変数を設定すると、Docker imageに変数の中身まで焼き付いてしまうため注意が必要です。
秘密情報を環境変数で定義するならやめた方が良いかも。bundlerの設定とかを環境変数にするなら別によけど。

chownはファイルやディレクトリの所有者を変更するコマンド
chown <[所有者]or[所有者:グループ]> <ファイルorディレクトリ>
chown -R rails_user:rails /rails/tmp /rails/log && \
-Rはディレクトリ内の所有者とかも変えるコマンド

secrets

.envで定義した環境変数はdocker-compose.ymlに勝手に渡されている。
しかし、それだけだとコンテナには環境変数は渡らないので、envorinmentかenv_fileでコンテナまで渡すようにする必要がある
app:
build: .
environment:
- HOGE_ENV=$HOGE_ENV

docker-compose.ymlのuserで、コンテナにログインするユーザーを変えられる。
DeockerfileのUID:GIDと同じだな
user: "1001:1000" # 非 root 実行(Q33)

envの説明わかりやすい

HTTP の 503 Service Unavailable はサーバーエラーレスポンスステータスコードで、サーバーがリクエストを処理する準備ができていないことを示します。
よくある原因としては、サーバーがメンテナンスのために停止しているか、過負荷状態であることが挙げられます。
503初めて知った。依存サービスが不健康の際に使うと良いステータスコードかも
ロードバランサーやヘルスチェックツールは、200番台のステータスコードを「健康」と解釈する可能性があるから、そこはよくチェックした方が良いかも。何をもって健康とするか。

depndends_onのオプションを詳しく解説している記事

多分cmdが成功するかを見てる

終了コード0は正常終了でそれ以外は失敗

ファイルのアップロードで保存されるディレクトリ。Active Storageなどを使ってファイルをアップロードしたときに、保存先がローカルディスクになっていると使用されるらしい。
チュートリアルで触れることはなかった。
Railsにおけるstorageディレクトリは、Active Storageでアップロードされたファイルやディスクサービス用のSQLiteデータベースが格納される場所です。Active StorageはRailsが公式に提供する機能で、ファイルをローカルだけでなくAmazon S3などのクラウドストレージにも保存できます。
デフォルトだとstorageディレクトリに、active storageでアップロードされたファイルのデータが保存される。

config.cache_storeを明示的に指定しない場合、デフォルトのキャッシュストア実装("#{root}/tmp/cache/")が使われます。
なるほど

env_file:
- .env.development
- .env.test
どっちも読み込まれる

tmpfs

override初めて知った

バインドマウントとボリュームを同時に設定した場合、ボリュームが優先される。
そのため、node_modulesに関しては、ホスト側の影響を受けることがなくなり、node_modulesが削除されません。 ただし、この方法では、node_modulesはバインドマウントから除外されることになり、ホスト側のnode_modulesが空になってしまう。
volumes:
- node_modules-data:/var/app/node_modules
- .:/var/app:cached

ボリューム周りのこの記事参考になるかも