www.docker.com
Docker Documantaition
Docker Hub
Docker Hub Official Repos
Dockerイメージの理解とコンテナのライフサイクル
64 bit アーキテクチャな Linux OS 上で動作する Go 言語製の Linux Container 構成ツール。「アプリケーションをプラットフォームに依存せず確実に動かす」ことや「開発者が手軽にアプリケーションの実行環境を手に入れる」ことにフォーカスしており、「インフラのプラットフォームを仮想化して提供する」ことを目的とした Virtual Box や VMWare などの VM (Virtual Machine) とは思想が異なる。
コンテナは Linux 上で動作する仮想実行環境 (要はプロセス) で VM に比べて低コストで作成・運用可能。Docker を使用すると アプリケーションは Linux OS 上のコンテナ内に「サービス」プロセスとして常駐する ことになる。
各インフラプラットフォームでも最近はこの「コンテナ実行環境」を提供しており、開発だけでなく本番環境でもガンガン利用されている。
- docker の v.17 くらいの変更 docker container / image コマンド新旧比較
- docker compose の v2 変更 Docker Compose V2(Version 2) GA のまとめ
Limit a container's resources - docs.docker.com
デフォルトでは、コンテナはリソース制約を持たず、ホストのカーネルスケジューラが許す限り多くのリソースを使用できます。
Dockerコンテナで利用できるリソースや権限を制限する
仮想化技術を利用するメリットの1つに、柔軟にリソースを管理できる点がある。Dockerでは古くからコンテナに割り当てるCPUリソースやメモリ容量を指定する機能があったが、Docker 1.6以降では割り当てるCPUリソースやメモリをより詳細に指定できるようになった。また、Docker 1.10ではブロックI/Oに関する制限も設定できるようになっている。
# コンテナのリソース状況確認
$ docker stats
Dockerfile は Docker コンテナのイメージ生成を自動化する ためのファイル。例えば ruby:2.5.3
のようなコンテナイメージは公式 ( DockerHub ) で提供されているが、開発者がそのイメージをベースに何らかのアプリケーションを実装しようと思った場合 Dockerfile でカスタムコンテナイメージを生成 して、そのイメージからコンテナを立ち上げるのが一般的な開発手順。
Dockerfile は一見バッチのようだが、実際は「どんなプラットフォームでも常に同一の実行環境を提供する」ことを目的としたコンテナのレシピであり、仕様が少し複雑。FROM で指定した元ネタに対して RUN による変更をコミットとして重ね、次回以降のビルドのためにキャッシュしたりしている。
FROM ubuntu # ubuntu:latest をベースにしてイメージ作成
ENV LANG C.UTF-8 # POSIX から UTF-8 にロケール変更
RUN apt-get update # e.g. ) 冪等性のない更新の結果をコミット
RUN apt-get install ruby # e.g. ) ruby のインストール結果をコミット
WORKDIR /app # RUN / COPY などの実行ディレクトリを変更
COPY hoge /app/hoge # ファイルやディレクトリをコンテナへコピー
CMD rails s # プロセス実行時に必ず走るエントリーポイント
ロケールについて、日本語 ja_JP.UTF-8 は大体のベースイメージに存在しないので下手に指定するとエラーになる。また、デフォルトは POSIX なのでこれも UTF-8 にしておかないと怖い。コンテナ内の Linux ファイルシステムなどでマルチバイトをむき出しで利用しない限りは
C.UTF-8
にしておくのが無難みたい ... 参考 - Dockerではコンテナのlocaleの再確認を
CMD はコンテナ実行時に走らせるコマンドで必須となる。また、このとき実行するコマンドは フォアグランドで実行され続けるもの ( = バックグランドで動作・終了しないもの ) でなければコンテナが終了してしまうので注意するコト。
dockerのENTRYPOINTとCMDの書き方と使い分け、さらに併用
Dockerfileを極めて、Dockerマスターになろう!Dockerではコマンドをフォアグラウンドで動かさないとコンテナが停止してしまいます。特に、 デーモンプログラム は、 デフォルトでバックグランド動作をするため 設定したものの 「起動しない/自動的に停止してしまう」 といった不具合に遭う原因となるので注意が必要です。
例えばnginxはデフォルトはデーモンとして動くので、(nginxの)daemon off設定を行い、 フォアグラウンドで動かす必要があります。
ENTRYPOINT /usr/sbin/nginx -g 'daemon off;' -c /etc/nginx/nginx.conf
Docker の静的解析ツール、Haskell 製なのでインストールには Stack が必要。
# Install
$ git clone https://github.com/hadolint/hadolint
$ cd hadolint
$ stack install
# Lint
$ hadolint /path/to/Dockerfile
# Pull docker image.
$ docker pull centos:7
$ docker images
> REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
> centos 7 5182e96772bf 2 days ago 200MB
# Run container at once.
$ docker run -it --rm centos:7 echo 'hello'
> hello
# Run with mounting host directory. - https://goo.gl/qe2B6m
$ docker run -v .:/home/root centos:7 /bin/bash
# Launch shell on container.
$ docker exec -it ${CONTAINER_NAME} bash
# List running containers.
$ docker ps
$ docker ps -a # With stopping containers
# Get ID
$ docker ps | grep unicorn | awk '{print $1}' # unicorn とかいう名前つきコンテナの ID 部分だけ取得
# Control containers.
$ docker start ${CONTAINER_NAME}
$ docker stop ${CONTAINER_NAME}
$ docker rm ${CONTAINER_NAME}
$ docker rm $(docker ps -aq) # Remove all containers.
$ docker restart ${CONTAINER_NAME}
# Remove images.
$ docker image prune # Remove all <none> images.
$ docker rmi ${IMAGE_ID}
# Check disk.
$ docker system df
# Prune build caches.
$ docker builder prune
# Prune all objects.
$ docker system prune
# Destroy all.
$ docker stop $(docker ps -a -q)
$ docker rm $(docker ps -a -q)
$ docker rmi $(docker images -q)
$ docker volume rm $(docker volume ls -qf dangling=true)
$ docker-machine restart
Docker のイメージは Docker Hub などのリポジトリホスティングサービスに保存するのが一般的だが、ファイルとしてエクスポート/インポートすることも可能。
# save
$ docker pull busybox
$ docker save busybox > busybox.tar
# load
$ docker load -i busybox.tar
$ docker run -t busybox /bin/echo "Hello World"
# Attach STDIN & STDOUT process to container.
$ docker attach ${CONTAINER_NAME}
# exit するとコンテナ停止 + シェル終了
# コンテナを止めずにシェル終了するなら ctrl + q
# Create /bin/bash process onto container.
$ docker exec -it ${CONTAINER_NAME} /bin/bash
# exit でも新しく生まれた /bin/bash プロセスが死ぬだけでコンテナは止まらず
$ docker run [option] [(user/)image] [command]
オプション | 説明 |
---|---|
-a, --attach | 起動したコンテナのコンソール出力をホストのコンソールへ出力 |
-d, --detach | コンテナをバックグラウンドで起動 |
-h, --hostname | 起動したコンテナ内に設定されるホスト名を指定 |
-b, --bind | ネットワークのバインド -b 0.0.0.0 で外部から参照可能に |
-i, --interactive | attach していなくても標準出力をオープン |
-m, --memory | メモリの使用量を制限 -m 200m で 200 MB |
--name | 管理用の名前を設定 --name 'my_server' |
-p, --publish | ポートフォワーディングを設定 -p コンテナ側ポート:ホスト側ポート |
--rm | コンテナの実行終了時にコンテナを削除 |
-t, --tty | コンテナの標準出力を tty に attach ( -i と一緒に用いる ) |
-v, --volume | マウントを設定 ( 主にホストの特定のディレクトリへ ) |
-w | ワークディレクトリの指定 -w="/usr/local/docker" |
Docker 開発で、コンテナ内で依存を全て取り扱う ... 具体的にはコンテナ内で bundle install
や yarn install
を実行するような開発環境では、当然ホスト側のエディタからゲスト側の Linter 実体などを参照できない。( もっと言えば vendor
配下なんかはファイル見ることもできん ) 。
このような場合に以下コマンドで ランコマンド実行時のみ一時的にホスト / ゲスト間で vendor
や node_modules
をマウントさせ、結果ホスト側からコンテナ内でインストールした依存パッケージ群を参照する ような手法がとれる。
$ docker run --rm -v $PWD:/app -w /app $APP_IMAGE_NAME bundle install --path=vendor/bundle
$ docker run --rm -v $PWD:/app -w /app $APP_IMAGE_NAME yarn install
コンテナ $APP_IMAGE_NAME
内で bundle install
などを行った結果生まれる ./vendor/bundle
について -v
で実行ディレクトリとゲスト側の WORKDIR をマウントしているためにホスト側の ./vendor/bundle
にもモノが入る仕組み。
Use volumes - docs.docker.com
Docker for Windows で postgres コンテナの Volume マウントを安全にする
Docker コンテナで DB サーバを建てた場合、プロセスが死ぬと中のデータも当然消えてしまう。対処としてデータ領域を Docker ホストにマウントするのが一般的だが Windows だとコケる。Named Volume を切って逃がすのがよろしいみたい。
因みに DB のデータを volumes
で外だししている場合に、パスワードを途中で変えたりすると接続情報が正しくても弾かれたりする。そのような場合は一度当該ボリュームを docker volume rm
で削除して再度接続してみること。
railsをdockerで構築して、Host ‘172.18.0.5’ is not allowed to connect to this MySQL server
# docker run 時にマウント先を Named Volume へ指定
$ docker run -d -v database:/var/lib/postgresql/data postgres:9.6.3
# docker-compose.yml で DB データのマウント先を Named Volume へ設定
services:
db:
image: postgres:9.6.3
volumes:
- database:/var/lib/postgresql/data
volumes:
database:
volumes
の実格納場所は Docker のインストール場所による。CentOS に yum で入れた場合は /var/lib/docker/volumes
配下に格納される。このため ストレージ設計の関係でデータ領域を別パーティションへ分けたい場合は docker のデータルートを変更する必要がある ( シンボリックリンクとかでもイケそうだけど、削除が上手く働かなかったりする ) 。
# 実際に Docker ホストのどこにあるのか確認 → 開発時にここを参照
#
$ docker volume ls
> DRIVER VOLUME NAME
> local database
$ docker inspect database
> {
> CreatedAt": "2018-10-01T18:44:50Z",
> "Driver": "local",
> "Labels": {},
> "Mountpoint": "/mnt/sda1/var/lib/docker/volumes/database/_data",
> "Name": "database",
> "Options": {},
> "Scope": "local"
> }
# Docker のデータルートを変更したい場合
#
$ systemctl stop docker
$ vi /etc/docker/daemon.json
> {
> "data-root": "/path/to/another-dir"
> }
$ mv /var/lib/docker /path/to/another-dir
$ systemctl start docker
dockerで開発環境構築時にvendor,node_modulesなどのフォルダをどうやっていくか
DockerでのNodeアプリ構築で学んだこと > node_modulesのボリュームトリック
通常プロジェクトごとの vendor
や node_modules
などバック/フロントの依存パッケージ群は、Docker 開発時は 普通にプロジェクトディレクトリをマウントしてコンテナ側で依存をインストールした場合、中身がコンテナ側から覗けない ことが面倒になる。
これを解決するためによく取られている手法が Volume Trick と呼ばれる手法。ホストからコンテナにマウントする際に消されたくないフォルダを Docker Volume としてマウントすることで、コンテナから依存パッケージが覗けるようになる。
# docker-compose.yml
services:
web:
build:
context: ./laravel
volumes:
- ./laravel:/var/www
#
# ↓ で依存パッケージフォルダを名前付き Volume でマウント
#
- node_modules:/var/www/node_modules
volumes:
node_modules: # ここで名前付き Volume を定義
driver: local # これがない場合は /var/lib/docker/ 配下のディレクトリに勝手に領域が作られる
上記手法でコンテナに入って依存を除くことはできるようになったが、このままでは ホスト OS から依存パッケージが参照できない 問題が残る ( 依存解決をすべてコンテナ内でやっている場合は ) 。これに関しては少しハックだが Docker コマンドで一時的にマウントポイントやワーキングディレクトリを指定しながら特定コマンドをコンテナで実行する ことで 特定コマンドにより生成されるファイル群だけホストにも持ってくるにょん みたいなことで解決できる気がする。
$ export IMAGE_NAME="node:10-alpine" # docker ps や docker-compose.yml で確認
$ export INSTALL_COMMAND="npm install" # yarn install とか bundle install とか
$ export WORK_DIR="/app" # プロジェクトによっては /var/www とか
$ cd my-project-root
$ docker run --rm -v $PWD:$WORK_DIR -w $WORK_DIR $IMAGE_NAME $INSTALL_COMMAND
1 つのサービスを実現するために、言語処理系 / DB サーバ / Web サーバ / アプリケーションなど、それぞれのプロセス ( コンテナ ) を Docker で立ち上げようとする場合、 docker run
コマンドを組み合わせたバッチを組む必要がある。docker-compose は それら複数コンテナ設定を 1 つの .yml
ファイルに記述しまとめて起動・管理することで 複数のコンテナを 1 つのサービスとして管理できるようにする ツール。複数コンテナを組み合わせる Docker 開発では必ずと言ってよいほど利用する。
# docker-compose.yml に定義されたサービス ( 複数コンテナ ) を操作
$ docker-compose pull # ベースイメージをまとめて docker pull
$ docker-compose build # 全てのサービスをまとめて docker build
$ docker-compose build --no-cache # キャッシュを無効化
$ docker-compose ps # 全サービスプロセス出力
$ docker-compose logs -f # 全サービスログ出力 ( -f が tail オプション )
$ docker-compose stop # 全サービス停止
$ docker-compose rm # 全サービス削除 ( 停止してるやつだけ )
$ docker-compose down # 全サービス停止 → 削除
# サービスのワンオフ実行 ( イメージの変更としてコミットされない )
$ docker-compose run --rm ${SERVICE} ${COMMAND} # pull 前なら pull も
$ docker-compose run --rm ${SERVICE} ${COMMAND} --build # run して build
# サービスの開始 / 再起動 ( .yml > services > service > command を自動実行 )
$ docker-compose up # アタッチドモード ( コンソール占領 ) Ctrl+C で終了
$ docker-compose up -d # デタッチドモード ( バックグラウンド実行 )
$ docker-compose restart # .yml や .env 変更などは反映されません
# サービス ( コンテナ ) へ /bin/bash で入る
$ docker-compose exec ${SERVICE} /bin/bash # bash だけでもいける
- v2 はローカルでの構成用で
extends
やmem_limit
サポートしている- 2020.12 時点で最新は
2.4
- 2020.12 時点で最新は
- v3 は Docker Engine (Swarm) での構成に互換性を持ち本番でのクラスター構成を想定している
- 2020.12 時点で最新は
3.8
- オーケストレーション前提なので
mem_limit
などのオプションは--compatibility
フラグをつけないと使えない
- 2020.12 時点で最新は
version: '3'
などの指定はversion: '3.0'
と同義なので注意- ローカル開発環境での利用は
2.x
を選んどけばよさそう
# docker-compose.yml のサンプル
# db: MySQL や PostgreSQL を入れる想定
# app: Rails とかを入れる想定
# web: Apache や nginx を入れる想定
version: '2.3' # Compose file バージョン指定
volumes: # 使用する Named Volume を指定
database: # DB データ領域をホストへマウントして永続化
services: # 構成サービスを列挙
db: # サービス名
dns: 8.8.8.8 # DNS の指定
image: postgres # build 時ベースイメージ
environment: # 環境変数 ( ビルド後の run 時に参照可能に )
- LANG=C.UTF-8 # 値を固定してコンテナへ引き渡し
- TZ # ホスト環境変数を引継ぎコンテナへ
volumes:
- database:/var/lib/postgresql/data
app:
build: . # どこの Dockerfile でビルドするか指定
env_file: .env # ビルド後 run 時反映 & environment 併用不可
volumes: # コンテナからホストへマウントするボリューム
- .:/app
- /app/.venv # マウントから除外する例 (厳密には空領域を割り当ててる)
- /app/node_modules # ref. https://bit.ly/2MJLM8T
depends_on: # 依存サービス / build 順序設定
- db
web:
build: # ビルド詳細設定
context: . # ここの ↓ の Dockerfile 使え
dockerfile: Dockerfile.web
args: # ビルド時に必要な環境変数のセット
HOST: $HOST # Dockerfile で ARG で使用宣言が必要
ports:
- "80:80" # ポートフォワーディング
- "443:443" # ローカル開発で自己証明書使うとき用
volumes_from: # 他サービスのボリュームをマウント
- app:rw # :rw など権限設定可能
depends_on:
- app
docker-compose.yml > env_file, environment
からコンテナに環境変数を渡せるが build 時の Dockerfile 内ではこの環境変数は使えない ことに注意。
docker-compose.yml > build > args
に渡した環境変数を ARG
で export
したことにできるので、Dockerfile で環境変数渡したいなら ↓ のようにする。これ五千回くらい調べなおしてる。
.env
で定義docker-compose.yml > env_file:
でロードbuild: > args:
でDockerfile
で読み取れるようにしてやるDockerfile > ARG
で呼び出す (=export
する)
docker-compose のバージョンによっては Windows 環境だと相対パス .
を解釈できずコケる場合がある。環境変数 $PWD
を利用して回避するか、docker-compose 1.9.0 以上なら環境変数 COMPOSE_CONVERT_WINDOWS_PATHS
を 1
にすることで回避。
設定を環境変数に格納する - 12factor.net
Docker-Compose の変数定義についてDocker を用いた開発では「サーバに SSH で入って環境設定ファイルをいじって ... 」というような 実行環境への手作業の環境設定は基本行わない 。厳密には行えるが、Docker の「サービスをバイナリとしてビルド → デプロイ → ランタイム」という設計思想上とてもやりづらい。サービスは デプロイされるタイミングで「環境変数」によって振る舞いを変える べきであり ソースコードに認証情報や環境設定のべた書き をするべきでない。1 リポジトリ 1 サービスかつ、1 リポジトリ複数環境ということのよう。
docker-compose はデフォルトで同階層の .env
ファイルやホストの export
による環境変数をロードして docker-compose.yml
内で展開できる。これら環境変数は各サービスの environment
設定に「値なしで」指定することでコンテナへ引き渡すことができる。
$ vi .env
> VARIABLE=hoge
# docker-compose.yml
services:
web:
command: env # build 時に環境変数みせろ ( 意訳 )
enviroment: # .env で全サービス設定管理 → ここで明示がいいかな?
- VARIABLE
$ docker-compose up
> Recreating web_1 ... done
> Attaching to web_1
web_1 | PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
web_1 | HOSTNAME=59ca518d8971
web_1 | HOME=/root
web_1 | VARIABLE=hoge # これらの値は Docker コンテナからも参照可能
how to reach another container from a dockerised nginx - Stack Overflow
docker+rails+puma+nginx+postgres (Production ready)
同一の Docker ホストでは、別コンテナをサービスを提供する「ホスト」としてコンテナ名で参照できる。システムのフロントに nginx などの WEB サーバを置いて、リクエストを各サービスにプロキシして捌かせたいときとかに便利。
# nginx.conf にて app コンテナの 3000 ポートへ飛ばす例
upstream app {
server app:3000;
}
server {
listen 80;
server_name www.example.com;
keepalive_timeout 5;
location ~ /\. {
deny all;
}
location ~* ^.+\.(rb|log)$ {
deny all;
}
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
if (-f $request_filename) {
break;
}
if (-f $request_filename.html) {
rewrite (.*) $1/index.html break;
}
if (-f $request_filename.html) {
rewrite (.*) $1.html break;
}
if (!-f $request_filename) {
proxy_pass http://app; # ファイルがない場合は app へ振り分け
break;
}
}
location ~* \.(ico|css|gif|jpe?g|png|js)(\?[0-9]+)?$ {
expires max;
break;
}
}
Docker上のNginxのconfに環境変数(env)を渡すたったひとつの全く優れてない方法(修正:+優れている方法) echo、printfでパイプから受けた値を出力する
PHP - hub.docker.com
MySQL - hub.docker.com
DockerでLAMP環境
docker-composeを使ってmy.cnfの共有は気を付けよう!
VirtualHostのServerNameに環境変数を入れる
Docker の php:apache で OpenSSL を有効にする
GitHub: yano3nora/lampdock
Quickstart: Compose and Rails
Nginx + Rails (Puma) on Docker のいくつかの実用パターン
Docker + Rails + Puma + Nginx + MySQL
Rails アプリケーションを Docker を使って開発する、ほとんどの人が通る(であろう)道
ポートを指定してPumaを起動するとsocketファイルをlistenしなくなる
VagrantとVirtualBoxでCentOSにnginxとpumaのRails環境を構築する
railsでpumaが走らない時に怪しむべきtmp以下Nginx を別コンテナにして、ロードバランサ的に利用しつつ各サービスに振り分けるような複雑な構成をとる場合は VOLUME を使って static/public なディレクトリを nginx 用に別途マウントし、EXPOSE で Puma のポートを空けて Nginx からのぞけるようにしてあげればよい。ただし Heroku などのコンテナ環境では VOLUME や EXPOSE が使えなかったり、各コンテナが別 dyno 管理になるため微妙。このへんは展開するプラットフォームによる。
GitHub: yano3nora/railsdock
Laravelの環境をDockerで構築するチュートリアル
PHP GD をインストールするための Dockerfile の少し複雑な内容メモ
Dockerのphpイメージでzip extensionを使えるようにする
mcrypt extension
mbstring extension
GitHub: yano3nora/lempdock
Docker Compose と Django - docs.docker.jp
Docker-Compose x Python3.6 + Nginx + MariaDB10 + uWSGI + Django - qiita.com
GitHub: yano3nora/djangdock