Dockerはパフォーマンスに優れた仮想環境を作るプログラム。 得られる可搬性によって、作成したイメージを開発における各ステージ(テスト、ビルド、リリース…)で適用できるようになる。 その意味でCI, CDの基礎的な技術となっている。
バインドマウントしているディレクトリをまるごと削除すると、後からそこにディレクトリをおいても中身がバインドされないことに気づいた。- ワーキングディレクトリ - aaa(ディレクトリ) - test1(ファイル) - test2(ファイル) - bbb(ディレクトリ) - test1(ファイル) - test2(ファイル)
docker run -d -it --name devtest --mount type=bind,source="$(pwd)"/aaa,target=/aaa nginx:latest
docker inspect devtest
$ docker exec -it devtest /bin/sh
> cd /app
> ls
test1 test2
$ rm -rf /tmp/aaa
$ docker exec -it devtest /bin/sh
> cd /app
> ls
(何も出ない)
$ cp -r /tmp/bbb /tmp/aaa
$ docker exec -it devtest /bin/sh
> cd /ap
> ls
(何も出ない)
docker inspect devtest
- File mount does not update with changes from host · Issue #15793 · moby/moby
バインドマウントはinodeで一致しているかで同期を管理しているという。新しく作る場合はinodeが変わるので同期されなくなる。
- mvだとinodeが変わらない。のでバインドマウントをし続けられる。そのシェルセッションで何もしていなくても、別で名前を変えても追従し、ワーキングディレクトリは変わることがある
- cpだとinodeが変わる。のでバインドマウントの同期が切れ、同じ名前のディレクトリを配置しても同期はされない
docker-compose restart
するとまたバインドマウントされるようになった。
サービス名をつけて起動すると、名前を指定して止めることもできるようになる。
docker run -d -p 80:80 --name webserver nginx
docker stop webserver
- moby/moby: Moby Project
- 手元にcloneしている前提
sudo make build # environment
sudo make binary # binary
sudo chown -R $USER:$USER . # なくてもいい
すると、bundles化に実行ファイルが生成される。あとはビルドしたものでデーモンを起動する。
sudo service docker stop # 現状デーモン停止
sudo ./bundles/binary-daemon/dockerd
buildでどこまで成功しているかを確かめるために、コマンドを仕込みたいことがある。デフォルトでは出力されないので、オプションが必要。
docker build . --progress plain --no-cache -t test
docker-compose logs -f
-dオプションはログが出ないので使ってこなかった。これによって卒業できる。
- ボリューム
- データを永続化できる場所のこと
- マウント
- コンテナにホストのディレクトリをマウントすること
ボリュームはマウントしないと、使えるようにはならない。docker-composeのvolumesではボリュームといいつつ書き方によってマウントしてくれる。
docker-composeでコンテナ側からホストのポートへアクセスできるようにする方法。
container:
extra_hosts:
- "host.docker.internal:host-gateway"
あとはコンテナ内のコード側で、 host.docker.internal:{ホストのポート番号}
とすることでホストのポートへアクセスできるようになる。
dockerがsudo権限以外で実行できなくなるときがある。
$ docker ps Got permission denied while trying to connect to the Docker daemon socket
これはログイン中のユーザがdocker権限を持っていないから。
sudo gpasswd -a $(whoami) docker
id $(whoami) # dockerが追加されたのを確認する
コマンドを実行したあと、ログアウトする。sudoなしでdockerコマンドを打てるようになっている。
CIによるコンテナビルドには、–cache-from を使って、レジストリに送信したイメージから各ステージのキャッシュを取得していく方法と、CIのキャッシュ機能を使う方法の2つがある。
レジストリからキャッシュを取る方法には弱点がある。
- キャッシュが登録イメージの1つしかない。たとえば異なるブランチでキャッシュが更新されると、キャッシュが失われる
- –mount=type=…のcacheが、pushイメージには含まれない
- ステージごとにキャッシュ通信(取得+送信)をするが、オーバーヘッドが大きい
- イメージに含めることができるキャッシュ(inline cache)には、minモードしか適用できない。つまりキャッシュに制限があるmoby/buildkit: concurrent, cache-efficient, and Dockerfile-agnostic builder toolkit
のため、CIのキャッシュ機能を使うのが現実的か。複数のキャッシュ…ブランチごと、Gemfileのハッシュ値ごとでハッシュを保持できるためキャッシュがヒットしやすい。キャッシュはひとまとめで保存され、レジストリへの送信イメージは利用イメージだけになる。
ビルド時にだけアクセスできる、cacheマウントを利用できる。マウントと言うが、ホストマシンとは関係ない。マウントディレクトリはビルド後削除されるため、イメージサイズにも優しい。 https://github.com/moby/buildkit/blob/master/frontend/dockerfile/docs/syntax.md
RUN --mount=type=cache,target=/root/.cache/go-build go build
たとえばpackage.jsonに変更があったときも途中から再開できる。ビルドキャッシュがヒットする/しないのゼロイチでなくなる。
- public/assets
- tmp/cache/assets
をキャッシュしておくことで高速化できる。
レジストリのキャッシュを利用してビルドできる。これによって、キャッシュがローカル環境に保持されないCI環境などでもキャッシュを利用して高速にビルドできる。
ポイントは–build-argと–cache-from。 –build-argでメタ情報を含めてビルドする。このイメージをpushしておくことで、次回からキャッシュを利用できる。 –cache-fromによってレジストリにある指定イメージからキャッシュを取得してビルドする。
docker build --target build -t ghcr.io/kijimad/roam-build:master --cache-from ghcr.io/kijimad/roam-build:master --build-arg BUILDKIT_INLINE_CACHE=1 .
docker push ghcr.io/kijimad/roam-build:master
本番用にコンパクトにビルドする場合の例。 node_modulesはいらなくて、ビルド成果物だけあればよい。 ステージを分けることで、意味が明確になり、サイズも小さくできる(高速化)。
COPY package.json $HOME/
COPY front/ $HOME/front/ # front にはビルド対象のjs, tsファイルが配置されている想定。サブモジュールを導入している場合、package.jsonは階層上に複数あるため、COPYしておく必要がある
RUN npm install
COPY babel.config.js $HOME/
COPY tsconfig.json $HOME/
COPY webpack.config.js $HOME/
RUN yarn run build
COPY --from=rails-yarn-build $HOME/public/webpack/ $HOME/public/webpack/
Rails開発をすべてdockerでやる想定。
一発ですべてが準備され、クリーンな環境を構築する。bundle install やyarn install など、立ち上げ続ける前提でないコマンドも含まれる。そのコマンドだけ再度実行したいときは docker-compose restart bundle
などとする。
元ネタ: foremのdocker-compose.yml。
↓あとはdockerizeを設定すれば完璧か。
# 共通のimage名: app
# imageのワーキングディレクトリ: /app
version: '3.7'
services:
mysql:
image: mysql:latest
ports:
- '${MYSQL_PORT:-3306}:3306'
environment:
# DBクライアントでの接続時に必要なので明示する
MYSQL_DATABASE: develop
MYSQL_ROOT_PASSWORD: root
MYSQL_USER: user
MYSQL_PASSWORD: password
MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'
volumes:
- 'mysql-data:/var/lib/mysql'
redis:
image: redis:latest
ports:
- '${REDIS_PORT:-6379}:6379'
memcached:
image: memcached:latest
ports:
- '${MEMCACHED_PORT:-11212}:11211'
rails:
image: app
environment:
RAILS_ENV: development
REDIS_URL: 'redis://redis:6379'
MEMCACHED: 'memcached:11211'
DATABASE_URL: 'mysql2://root@mysql:3306'
depends_on:
- mysql
- redis
- memcached
- bundle
- yarn
- seed
command: bash -c 'bundle exec rails s -b 0.0.0.0'
volumes:
- .:/app:delegated # delegatedで高速化
- gem_data:/usr/local/bundle:delegated # package系は永続化して最初からinstallにならないようにする
- node_modules:/app/node_modules:delegated
ports:
- '3000:3000'
webpack:
image: app
environment:
NODE_ENV: development
WEBPACKER_DEV_SERVER_HOST: 0.0.0.0
command: bash -c 'yarn watch'
volumes:
- .:/app:delegated
- node_modules:/app/node_modules:delegated
ports:
- 8080:8080
sidekiq:
image: app
command: bash -c 'bundle exec sidekiq -C config/sidekiq.yml'
environment:
REDIS_URL: 'redis://redis:6379'
DATABASE_URL: 'mysql2://root@mysql:3306'
volumes:
- .:/app:delegated
- gem_data:/usr/local/bundle:delegated
links:
- mysql
- redis
bundle:
image: app
environment:
RAILS_ENV: development
volumes:
- .:/app:delegated
- gem_data:/usr/local/bundle:delegated
command: bash -c "bundle install --jobs 8" # マシンがいくつ並列処理できるかは`$ getconf _NPROCESSORS_ONLN` で調べられる
yarn:
image: app
environment:
NODE_ENV: development
volumes:
- .:/app:delegated
- node_modules:/app/node_modules:delegated
command: bash -c "yarn install"
seed:
image: app
environment:
DATABASE_URL: 'mysql2://root@mysql:3306'
volumes:
- .:/app:delegated
- gem_data:/usr/local/bundle:delegated
command: bash -c "rake db:seed_fu"
volumes:
gem_data:
node_modules:
mysql_data:
#! /bin/bash
set -e
if [ -f tmp/pids/server.pid ]; then
rm -f tmp/pids/server.pid
fi
cat << EOF
░░▄████████████▄▐█▄▄▄▄█▌░
░░████████████████▌▀▀██▀▀░░
░░████▄████████████▄▄█▌░░░░
░░▄▄▄▄▄██████████████▀ ░░░░
EOF
exec "$@"
おかしくなったときの再起動。
sudo service docker restart
コマンドでDockerコンテナを停止・削除、イメージの削除をする - Qiita
docker stop $(docker ps -q) # 全コンテナ停止
docker rm $(docker ps -q -a) # 全コンテナ削除
docker rmi $(docker images -q) # 全イメージ削除:
ディスク使用率がほぼ100%になっていた。占めているほとんどはDocker関係のようだった。 イメージは削除するようにしてたが、ほかにも色々あるよう。
専用のページがある。 https://docs.docker.com/config/pruning/
非常に多くのゴミがありそうだったので、多少再pullに時間がかかることを許容してすべて削除することにした。
docker system prune
ゴリゴリbuildして試しているときは、気をつけたほうがよさそう。
キャッシュ削除だけ行う。この場合が多そう。
docker builder prune
公式Docker Imageでよく用いられる、コンテナ起動時に実行するスクリプト。 公式のイメージのままで、初回起動時に実行したいフックとして記述できる。
例(Dockerfile): rails-on-kubernetes/Dockerfile at master · tzumby/rails-on-kubernetes
ADD . /myapp
COPY docker-entrypoint.sh /usr/local/bin
ENTRYPOINT ["docker-entrypoint.sh"]
例(entrypoint.sh): rails-on-kubernetes/docker-entrypoint.sh at master · tzumby/rails-on-kubernetes
#!/bin/sh
set -e
if [ -f tmp/pids/server.pid ]; then
rm tmp/pids/server.pid
fi
echo "Waiting for Postgres to start..."
while ! nc -z postgres 5432; do sleep 0.1; done
echo "Postgres is up"
echo "Waiting for Redis to start..."
while ! nc -z redis 6379; do sleep 0.1; done
echo "Redis is up - execuring command"
exec bundle exec "$@"
docker-composeは自動でタグ名をつけてくれたり、マウントしてくれたり、dockerコマンドよりややこしくなりにくい。 単に開発環境として使っているだけでは、ほとんどdocker-composeで事足りる。 が、docker-composeへ依存しているということで、docker-compose関係ない別の文脈で使おうとすると途端に動かなくなる。本質的にdocker-composeはコンテナ間の関係性を記述しているだけで、コンテナ自体を表現しているわけではない。
本当にdockerコンテナとしての正しい使い方をしているかテストするには、コンテナを複数のデプロイやCIで利用してみるのがよい。同じ流れで簡単にできたのなら正しい。簡単にできないなら何かが間違っている。
docker run --rm -v "$PWD/":/roam -w /roam ghcr.io/kijimad/roam:master sh deploy.sh
--rm
: コマンド実行後にコンテナを削除する
-v
: ホストマシンにマウントする。左がホストマシン、右がコンテナ内。
docker run --rm -it ghcr.io/kijimad/roam:master
-it はttyオプション。インタラクティブなシェルを作成する。つけないと、一瞬で消える。
環境変数をオンにすることで、新しい機能が使えるようになる。
export COMPOSE_DOCKER_CLI_BUILD=1
export DOCKER_BUILDKIT=1
docker build .
- npm install するコンテナを作成
- コンテナをマウント
- ホストマシンにないnode_modulesは消える
- エラー
なので、node_modulesもマウントする。
docker run --rm -v "$PWD":/roam -v /roam/node_modules ghcr.io/kijimad/roam_lint:master make textlint
https://rara-world.com/dockerfile-node-modules/ に書いてあった。
dockleというツールでイメージをチェックできる。 goodwithtech/dockle: Container Image Linter for Security, Helping build the Best-Practice Docker Image, Easy to start
自前のイメージにかけるとたくさん見つかった。
$ dockle ghcr.io/kijimad/roam:4f3296b
FATAL - DKL-DI-0001: Avoid sudo command
* Avoid sudo in container : /bin/sh -c yum -y update && yum -y install yum-utils
gcc gcc-c++ make openssl-devel openssh-server readline
nuplot
WARN - CIS-DI-0001: Create a user for the container
* Last user should not be root
INFO - CIS-DI-0005: Enable Content trust for Docker
* export DOCKER_CONTENT_TRUST=1 before docker pull/build
INFO - CIS-DI-0006: Add HEALTHCHECK instruction to the container image
* not found HEALTHCHECK statement
INFO - CIS-DI-0008: Confirm safety of setuid/setgid files
* setgid file: g--x--x--x usr/libexec/openssh/ssh-keysign
* setuid file: urwxr-xr-x usr/sbin/pam_timestamp_check
* setuid file: urwxr-xr-x usr/bin/mount
* setgid file: grwx--x--x usr/libexec/utempter/utempter
* setuid file: urwxr-xr-x usr/bin/chage
* setuid file: urwxr-xr-x usr/bin/su
* setuid file: urwxr-x--- usr/libexec/dbus-1/dbus-daemon-launch-helper
* setuid file: urwxr-xr-x usr/sbin/unix_chkpwd
* setuid file: u--x--x--x usr/bin/sudo
* setgid file: g--x--x--x usr/bin/ssh-agent
* setuid file: urwxr-xr-x usr/bin/umount
* setuid file: urwxr-xr-x usr/bin/gpasswd
* setuid file: urwxr-xr-x usr/bin/newgrp
* setgid file: grwxr-xr-x usr/bin/write
INFO - DKL-LI-0003: Only put necessary files
* Suspicious directory : roam/.git
* Suspicious directory : usr/local/plugins/ruby-build/.git
* Suspicious directory : usr/local/plugins/ruby-build/test/tmp
* Suspicious directory : tmp
* unnecessary file : roam/docker-compose.yml
* unnecessary file : roam/Dockerfile
Amazon.co.jp: Deploying Rails with Docker, Kubernetes and ECS (English Edition) eBook : Acuña, Pablo: Foreign Language Booksに載ってたスクリプト。書いてリポジトリに入れておくとスムーズにビルドやプッシュができる。 レジストリ・ユーザ名・リポジトリを適宜変える。
#!/bin/sh
LC=$(git rev-parse --short HEAD)
docker build -t ghcr.io/kijimad/webapp:${LC} .
docker push ghcr.io/kijimad/webapp:${LC}
docker run するとコンテナ内に入れるが、作ったコンテナはそのままになる。
実行後に削除して欲しい場合は、 docker --rm webapp /bin/sh
などrmオプションを使う。
コンテナ間の接続をしようとして、このようなエラーが出た。
Error connecting to Redis on 127.0.0.1:6379 (Errno::ECONNREFUSED)
127.0…とあることから、コンテナ内のアドレスを見に行ってる。 コンテナ間での通信には、サービス名のアドレスを追加する必要がある。
Dockerコンテナ内でファイルを作成すると、ownerがrootになり編集や削除ができず面倒。 Dockerの内部ではユーザid(uid)やグループid(gid)がホストと異なる。idがホストマシンと合わないためrootとして実行されたことになる、よう。
安易な解決策としては、権限をホストユーザに変更すれば問題ない。 とはいえ、コンテナ内のサービスが新しくファイルを作るたび(たとえばマイグレーションファイル生成)に実行するのは面倒。 If you are running Docker on Linux, the files rails new created are owned by root.
sudo chown -R $USER:$USER .
解決策としてはいくつか種類があるようなのだが、とりあえずできた。 サービスのvolumesにユーザ情報をマウントする。:roは読み取り専用(read onlyか)。 これでidの照合元がホストと同じになる。
volumes:
- /etc/passwd:/etc/passwd:ro
- /etc/group:/etc/group:ro
あとはidを環境変数経由で渡せば、コンテナ内でもホストのユーザが実行したことになる。
sudo docker run -u "$(id -u $USER):$(id -g $USER)" rails /bin/sh
sudo docker-compose run -u "$(id -u $USER):$(id -g $USER)" rails /bin/sh
overrideがある場合、このようになる(長すぎ)。
sudo docker-compose -f docker-compose.yml -f docker-compose-app.override.yml run -u "$(id -u $USER):$(id -g $USER)" rails /bin/sh
Docker コンテナ内で Docker ホストと同じユーザを使う - CUBE SUGAR CONTAINER
Dockerイメージをインターネット上にアップロードできるスペース。 個別にビルドしなくてよくなるためDocker関連の全工程が高速化する。テスト、ローカル、デプロイ…。
サイトをDockerデプロイにしたり、CIをDockerで行うとき。 複数の環境が関係する場合、マルチステージビルドを行うとキャッシュが効くため高速化できる。
- Linux関連のイメージ
- Ruby関連のイメージ
- node関連のイメージ
- Railsアプリのイメージ
のように。 Linux → Ruby + node → Railsという依存関係になる。
Dockrfileはイメージを作る。(image build) docker-compose upは↑で作られたイメージを元にコンテナを作り起動までする。そのなかアプリケーションを走らせて開発する。
image構築 → コンテナ構築 → コンテナ起動 という流れ。
コンテナの作り方には2種類ある。
- 自作する必要があるものは↑Dockerfileで作る
- 既存コンテナ(MySQLとか)はイメージをダウンロードする
コンテナ内部で実行したいコマンドがあるときにやりたいこと、たとえばRailsだと、gemfileが新しくなったときにbundle installしたい。
runは新しくコンテナを作成し、内部でコマンドを実行する。サービス名はdocker-compose.ymlから取っている。つまり立ち上がっているコンテナ名は関係ないのに注意。何も指定してない場合、docker-compose.ymlからサービス名を決定する。ほかのファイルの場合には-fオプションが必要。外部で永続化される…volumeが指定されてるような処理(bundle install)とか、データベース関係はいいのだが、その他は永続化されないので注意。
docker-compose run {サービス名} {shellコマンド}
execはコンテナを再利用してコマンドを実行する。高速。
docker-compose exec {サービス名} {shellコマンド}
docker-compose build --no-cache
docker-compose up --build -d # コンテナ作成する
docker-compose down
Rails Dockerfileで。
CMD bundle exec rails server -b 0.0.0.0
などと書いておくと、外部(Docker外)からアクセスできるようになる。-b 0.0.0.0 がないと別のネットワークからアクセスが不可。コンテナを超えると別のネットワーク扱いになるのでこの記述が必要。
どっちだったか忘れる。 左が公開、右がコンテナ内。だからブラウザでポート8000アクセスできるようになる。
docker run -p 8000:3000 -it bdd92ace66ec
docker ps -a # id確認
docker logs 1111... # idを入れる
使ってないイメージを削除する。
docker images prone
一気に全部削除する。
docker stop $(docker ps -q)
docker rm $(docker ps -aq)
docker rmi $(docker images -q)
解説は↓にある。非常にわかりやすい。Goのミニマル実装もある。
dockerの構成。
- Docker Host
- Docker Daemon
- Container
- Images
- Network
- Docker client
- build, pull, runとか
network, container, image, volumesはCli経由でDocker daemonの機能を呼び出す。 コンテナを一言で言うと「 システムから分離されたプロセス 」。Linux上でunshareコマンドを打つことにより、最速でコンテナを作成できる。
$ sudo unshare -u /bin/bash
# ユーザがrootになった
$ hostname newhost && hostname
-> newhost
# ホスト名を変更した
$ which emacs
-> /usr/bin/emacs # unshareしてない状態だとEmacsはguixディレクトリ化に入っているので、確かに環境が別になっている
コンテナに必要なLinuxの機能3つ。
- Namespace
- プロセスはそれぞれでNamespaceを持っている。unshareはプロセスを分離させNamespaceを作成した
- Control Group
- アプリケーションを特定のリソースセットに制限する。メモリの最大利用数や、プロセス最大実行数を制限できる
cat /sys/fs/cgroup/cpuset/cpuset.cpus
- File System
- 親からマウントされたFile Systemに関するデータのコピーを取得し、親と同じデータ構造へのポインタを取得して変更できるようにする
- cat
/proc/mounts
docker-compose cp が使える。dockerコマンドと違って、コンテナIDを指定する必要がない。
コンテナ → ホストでも、ホスト → コンテナでも、入れ替えて使える。当然、コンテナは前もって起動しておく必要がある。
docker compose cp doc:/usr/share/nginx/html ./
コンテナセキュリティの本。
動かして学ぶ、Docker networkの解説動画。
docker network ls
docker run -itd --rm --name test1 busybox
docker run -itd --rm --name test2 busybox
↑コマンドではネットワークまわりの設定はないが、自動で追加されている。確認する。
↓ホストマシンから確認する。 veth*
が増えている。
ip address show
bridge link
ブリッジをさらに詳しく見る。
docker inspect bridge
↑ docker0
ネットワーク内に追加されている。
ホストネットワークで起動する。
docker run -itd --rm --network host --name test3 nginx
ポートを公開することなく、ホストマシンからアクセスできる。ネットワークは隔離されない。
curl -I http://localhost
curl -I http://172.17.0.1
- Docker ドキュメント日本語化プロジェクト — Docker-docs-ja 24.0 ドキュメント
- 特定のユーザに割り当てられたほ場的なグループと共に実行されます
- 議事 tty(pseudo-tty)の割り当て
コンテナまわりが参考になる。
コンテナの本。
introduce require to load sub-compose projects as dependencies by ndeloof · Pull Request #416 · compose-spec/compose-go
気になる機能追加。-fオプションの上書きは、わかりづらい。
docker networkの解説。
コンテナのLXCとはなにかを解説。
overlayのわかりやすい説明。事象を理解するためには、仕組みを理解していなければいけない。
どうやってignoreしているのだろうか。
https://github.com/kd-collective/buildkit/blob/37d54ebc592a54db8764911eb320d02d2260c5e6/frontend/dockerfile/dockerignore/dockerignore.go#L13
- ファイルを読み込み、パスのスライスを出しているだけ
Golang UK Conf. 2016 - Liz Rice - What is a container, really? Let’s write one in Go from scratch - YouTube
コンテナランタイムを使わずにGoでコンテナを作ることで、コンテナとは何かを学ぶ。
仕組みの説明。
現実的な導入ステップ。
swarmを学ぶ。 Emacs拡張あるいは、Makefile的なのにまとめる。ありがちなbundle-installなどはdocker-composeにワンショットのコマンドを書くことで、定形コマンドを実行することが少なくなった。自動で動かしたいやつはこれでOK。コマンドはdockerだから特殊ということはなく、ローカルと同じようにやれば良い。
用語集 — Docker-docs-ja 20.10 ドキュメント PRを送る。- なお、オリジナルのドキュメントは群は
- ビルド(build)とは、 を使って Docker イメージを構築する工程です。
- イメージ構築に必要なディレクトリに置いてあるファイル群です
- ために、 コピーオンライト 技術と を使います
- ベストな解決作です。
- ENTRYPOINT` に /bin/sh ま
- ユニオン・ファイル・システムで結語するために 技術を使い
とりあえず、👇でよい。
sudo chown -R $USER:$USER .
キャッシュや履歴関係がroot権限でできるので、削除が面倒+コンテナを作るのが邪魔される。
- できないようにする
- 自動削除するようにする
追加した。
生成したファイルがroot権限になってしまう。 だからbundle installを実行すると、その後は通常ユーザでは編集できなくなる。 面倒だし、migrationとか明らかにダメな気がする。簡単な解決策と環境変数によって解決する方法を調べた。
Rails部分をDocker化する。表示はまったく問題なさそう。 リロードするとちゃんとローカルの変更が反映される。最初にルートファイルのdockerfileでベースイメージをビルドして、名前を付ける。
docker build . -t app
各コンテナでは↑で作成したベースイメージappを用いる。
イメージを使う代わりに build .
でも可能だが、各コンテナがイメージをビルドする(中身は同じ)ので遅くごちゃつく。
rails:
image: app
environment:
RAILS_ENV: development
REDIS_URL: redis://redis:6379
MEMCACHED_URL: memcached://memcached:11211
SKIP_RECAPTCHA: "true"
MEMCACHED_HOST: memcached
MEMCACHED: memcached:11211
WEBPACKER_DEV_SERVER_HOST: webpack
CHROME_HOST_NAME: http://selenium_chrome:4444/wd/hub
ports:
- 3000:3000
stdin_open: true
tty: true
command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -b '0.0.0.0'"
volumes:
- .:/rails
- /etc/passwd:/etc/passwd:ro # Linux用
- /etc/group:/etc/group:ro # Linux用
depends_on:
- mysql
sidekiq:
image: app
command: bundle exec sidekiq
links:
- mysql
- redis
webpack:
image: app
environment:
NODE_ENV: development
RAILS_ENV: development
WEBPACKER_DEV_SERVER_HOST: 0.0.0.0
command: yarn watch
volumes:
- .:/rails
- /etc/passwd:/etc/passwd:ro # Linux用
- /etc/group:/etc/group:ro # Linux用
ports:
- 8080:8080
sudo docker-compose up --build
docker-compose {service} restart
docker-compose run rails bundle exec rails c
docker-compose run rails bundle install
docker-compose run rails bundle exec bin/rspec spec/requests/top/top_spec.rb
docker-compose run rails /bin/bash
docker-compose -f docker-compose.yml -f docker-compose-app.override.yml up
もちろん一般性があるならgit管理にするのがベストだが、人によって構成が異なるので仕方ない。とくにMacだと速度に問題あるため、RailsはDockerで立ち上げないのが多数派。
Railsサービスをoverride.ymlに、それ以外のミドルウェアサービスをdocker-compose.ymlに書いてる場合は、明示する必要がある。
docker-compose -f docker-compose.yml -f docker-compose-app.override.yml run rails bundle install
docker-compose runする場合も-fオプションが必要。 runはコンテナを新しく作る…つまりymlを見てるので、指定が必要なのである。
docker-compose -f docker-compose.yml -f docker-compose-app.override.yml exec rails bundle exec rspec --options ./.rspec ./spec/models/user_spec.rb
↑いちいちクソ長いコマンドを打つのは苦痛なので、shellに入って作業すると楽。
sudo docker-compose -f docker-compose.yml -f docker-compose-app.override.yml run rails /bin/sh
MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'
を追加すると入れるように。
パスワードを指定してるとログインできない。
だがこのsqlectron、表示テーブルでの編集ができないので値を書き換えるのに非常に不便。 別のを使ったほうがいいだろう。
- ポートを合わせる
- webpack.config.jsにhostを加える
が必要。
webpack:
build: .
environment:
NODE_ENV: development
RAILS_ENV: development
WEBPACKER_DEV_SERVER_HOST: 0.0.0.0
command: yarn watch
volumes:
- .:/rails
ports:
- 8080:8080
depends_on:
- rails
ホットリロードできるのを確認。 hostを加える必要があった。
devServer: {
contentBase: path.join(__dirname, 'app/assets/javascripts'),
allowedHosts: ['.lvh.me'],
host: '0.0.0.0',
},
コンテナの解説。後半は理解できてない。また必要なときに読む。
$ sudo mount --bind dir1 dir2
みたいに、バインドマウントするコマンドが存在する- Namespace(名前空間)はプロセスをグループ化して、コンテナの隔離された空間を作り出す。独立させたいリソースによっていくつかの機能がある
- Dockerの初期はコンテナ内でコマンドを実行できなかった
- カーネルでsetnsがすべてのNamespaceに対して動作するようになってから、docker execコマンドが実行できるようになった
- Mount NamespaceはLinuxカーネルに最初に実装されたNamespace(2002年)
- あるNamespaceごとに異なるマウントポイントの一覧を持てる
- コンテナ内でマウント操作を行った場合でも、そのマウントはホストOSや他のコンテナから見えないようにできる
$ cat /proc/self/mounts
でマウント状況を確認できる- マウントプロパゲーション
- マウントがほかのディレクトリで反映されるか、反映されないか
歴史が面白い。
コンテナランタイムの標準仕様。
コンテナイメージの標準仕様。
コンテナの解説。
カーネルの変更がコンテナにどう影響しそうだな、という視点すごいな。
docker networkを作り、コンテナを同じnetworkに所属させると、サービス名解決ができる。
Dockerの公式イメージ集。
ヘルスチェックのスタートを指定するオプションを追加するプルリク。
デバッガーモードの提案。気になる。
-fオプションで起動するとき、要素によっては上書きされない問題がある。例えばポートをoverride.ymlに書くと上書きはされず、2つともポート公開されてしまう。その仕様の変更が7年かかって仕様に組み込まれた。
introduce remove to configure runtime autoremove for service containers by ndeloof · Pull Request #364 · compose-spec/compose-spec
removeキーワードの導入。
Docker EngineのAPIリファレンス。
tips。
- ヘルスチェック
- サービスをグループ化
共通化設定。
x-
をサービス名につけると無視される
エイリアスの使い方。
方法。
Haxxnet/Compose-Examples: Various Docker Compose examples of selfhosted FOSS and proprietary projects.
docker-compose集。
github actionsでdocker-composeを使う例。
コンテナ技術の低レイヤーの仕組み。
docker-slim/docker-slim: DockerSlim (docker-slim): Don’t change anything in your Docker container image and minify it by up to 30x (and for compiled languages even more) making it secure too! (free and open source)
dockerイメージを分析してスリムにするツール。
dockerのレイヤーごとにイメージを調査できるツール。
わかりやすい概要。
ソフトウェアのわかりやすい説明。
Web開発用の扱いやすいDockerイメージ。
SaaS開発の方法論。 日本語訳もあった。The Twelve-Factor App (日本語訳)
Dockerのドキュメント。
キャッシュの書き方。
非常に詳しい情報。BuildKitの解説。
ベストプラクティス。