Docker
Overview
Dockerについてまとめているセクション。
参考
Dockerfile(リフェレンス)
入門Docker
軽量なDockerfileの作り方
Dockerfile ベストプラティクス(かなりすごい)
Dockerセキュリティ(これもLTに入れる)
docker container prune -f;
docker image prune -f;
docker volume prune -f
そもそもコンテナーとは
コンテナーとはアプリケーションの 実行環境をパッケージ化し、それをデプロイ、実行するためのテクノロジーのこと。
- アプリケーションコード
- ライブラリ
- プログラミング言語のランタイム
アプリケーションを実行するための依存関係をコンテナーイメージとしてパッケージ化する。
また、パッケージ化されたコンテナーイメージは任意の場所で実行されるコンテナーランタイムによりコンテナーとして実行ができるようになる。
コンテナーを利用することで得られるメリット
可搬性を得ることができる。
※どこでも同じ環境を再現できる
昨今の開発
コンテナーの持つ可搬性によりさまざまなメリットが得られ、ユーザーがよりアプリケーション開発に集中できることから、サーバーレステクノロジーと同様にモダンアプリケーションにおける重要な選択肢の1つとなっています。
Lambdaの方が抽象度高く、多くの作業をAWSにオフロードできる。
Lambdaで要件を満たせない場合にAmazon ECSやAmazon EKSの採用を検討することになる。
AWS Lambda関数の**タイムアウト設定は最大で15分のため、**それ以上の実行時間が想定されるアプリケーションでは採用が難しくなる。
そのような場合、アプリケーションの実行環境としてコンテナーが候補に挙がるため、Amazon ECSやAmazon EKSが選択肢に出てくる。
サーバーレスとコンテナー使い分ける指標
アプリケーション開発により多くの時間や人を投資できる選択肢はどれかという観点で整理する考え方。
コンテナーをアプリケーション実行環境へする場合
Amazon EC2あるいはAWS Fargateが選択肢となる。
Fargateを利用すると、Dockerなどのコンテナランタイムを含むAmazonEC2インスタンスの管理が不要となるため、コンテナワークロードの運用負荷が軽減されます
Docker Linter
DockerfileのLinterとしてhadolintというものがデファクトスタンダードとして存在する。
Volume Trick
まず、node_modulesはDockerイメージにホストからコピーしてはいけません。node_modulesはgitでも無視するはずなので、新しく環境構築する人のディレクトリにはそもそも入ってませんし、イメージをリビルドするときにホストのnode_modulesからイメージ内のnode_modulesが上書きされることも避ける必要があるからです。
Volume Trick
は通常、Docker環境でNode.jsアプリケーションを開発する際に node_modules
ディレクトリを効果的に管理する方法として使用される
1. パフォーマンス向上
ホストマシンとDockerコンテナー間で node_modules
ディレクトリを共有すると、パフォーマンスが低下することがあります。Volumeを使用することで、この問題を回遍することが可能です。
2. 環境の違いの管理
異なるOSや環境で動作させる際に、異なる依存関係やバイナリを必要とするパッケージが存在することがあります。Volumeを使用することで、コンテナー内で専用の node_modules
ディレクトリを保持でき、ホストOSとは異なる環境での依存関係の問題を回避できます。
3. ホストマシンのディスクスペースの節約
node_modules
ディレクトリはしばしば大きく、多くのプロジェクトをホストマシンに保持している場合、ディスクスペースを大量に消費します。Volumeを使用すると、これらのディレクトリをコンテナー化された環境内に保持でき、ホストマシンのディスクスペースを節約できます。
4. 簡単な依存関係の管理
開発中に依存関係を迅速にインストール/アンインストールする必要がある場合、Volumeを使用することで、ホストマシンの影響を受けずにこれを行うことができ ます。
5. コンテナーの再利用
コンテナーを再起動したり、新しいコンテナーを起動したりする際に、すでにインストールされている依存関係を再利用できます。
これにより、新しいコンテナーの起動時間が短縮されます。
6. ホストとコンテナー間の依存関係の競合を回避
ホストマシンとDockerコンテナーで異なるバージョンの依存関係を使用することが可能。
これにより、ホストとコンテナー間で依存関係の競合が発生するのを避けることができます。
注意: ただし、Volume Trickを使用すると、node_modules
ディレクトリの管理が複雑になる可能性があり、とくに新しい依存関係を追加または削除する際に問題が発生することがあります。また、ボリュームはDockerホストのディスクスペースを使用しますので、大量のデータを保持する長期間稼働するボリュームはディスクスペースを消耗します。このため、定期的なメンテナンスが必要となることもあります。
Docker が軽い方がいい理由
Docker imageの中身を見る(レイヤー)
以下の要望があるときに見られる
作成したイメージがどうなっているかを確認したいとき。
レイヤーについて詳しく見られる。
docker save -o [name].tar [image id]
Docker mysql
dockerでvolumeをマウントした時のファイルowner問題
ホスト側のファイルをコンテナー内で使いたい場合や、逆にコンテナーで作ったファイルにホストからアクセスしたい場合に有用なのだが、ファイルのアクセス権限について考慮すべき点がある。 ちなみにdocker for macで試したところ、上記の問題は起きない。 コンテナー内からはownerがrootとして表示されるが、mac上からは自ユーザーがownerとして表示されている。docker for macの中でうまく解決してくれているようだ。
docker 仕組み
参考URL
Dockerはビルドのステップごとにファイルシステムの変更差分を積み重ねることでイメージを作成する。
先にGemfileをイメージに組み込んでbundle installを実行しておかなければソースコードを変更するたびに毎回bundle installをする必要がある。
# 先にGemfileを転送しbundle installする
COPY --chown=rails Gemfile Gemfile.lock package.json yarn.lock /app/
RUN bundle install
RUN yarn install
上記のような工夫をすることでGemfileの内容に変化がなかった場合は bundle install
の工程までキャッシュを利用することが可能になり2回目以降のビルドが大きく高速化される。
インストールするimageの中を確認する
そのイメージになにが含まれているのか確認する方法
$ docker run -it alpine:3.11
言語のalpineだと/bin/shなどで起動する必用がある。
$ docker run -it alpine:3.11 /bin/sh
docker-composeではない起動方法
- Dockerfileを用意する
- build
Docker コマンド一覧
run imagesからコンテナーを起動する。
exec 起動中のコンテナーに入る
リモートサーバー内のDockerにローカルから接続する
Dockerでもlocalhostでも起動した時に 0.0.0.0
などパブリックドメインで公開すればアクセスできる。
0.0.0.0
Docker セキュリティ
コンテナセキュリティの課題は、ダウンロードしたコンテナイメージが期待通りであるか。 セキュリティと一貫性の観点から期待通りのイメージがダウンロードされることの保証が重要。 Dockerのイメージタグは便利だが常に一貫した特定のイメージを指すとは限らないためSHA-256ハッシュを使ってイメージを識別すること
TODO: これLT アプリケーションがrootで実行されている もしアプリケーションにOSコマンドインジェクションやディレクトリトラバーサルなどの脆弱性があり、それが悪用された場合アプリケーションがroot権限で実行されていると悲惨なことになります
docker security
Docker パーミッション
LinuxではDockerを実行した場合、作成されたファイルの所有権が root
になる(公式はrootで対応するなと言っている)
そのためDockerfileの ADD/COPY
に --chown
オプションができており、それ用のuserを作成するルールになっている。
Dockerfile ---chown 参考URL
Dockerイメージを軽くする
Dockerfile ビルダーパターン
マルチステージビルドとも呼ばれていることがある。 ビルダーパターンなど(FROMが2度現れること)がある。 つまり、xxxパターンを調べて勉強しろ
マルチステージビルド
マルチステージビルドは、Docker17.05以上で利用できる新機能 前のステージでビルドされた成果物をこの新しいステージへコピーする 最終的なイメージでは取り残され最終的なイメージへは保存されない。 ※つまり、TypeScriptをコンパイルするステージ⇨最 終的なJSを実行するステージに分けることができる。
COPY --from=0
Docker image削除
containerを削除してからではないとimageが削除できない。
dockerignoreとは
docker buildでimageを作成する際に無視するファイル・ディレクトリを設定できる。 ※mountの場合は無視ができない。
Dockerのマウント種類
参考URL mountディレクトリの恐ろしさ たとえばDockerfile内でCopyをした場合、コピーされるがバインドマウントのためではないため編集しても反映されない。
そのためdocker imageを作成するためだけを意識すること また、COPYでせっかく全部コピーしてもバインドマウントで同じディレクトリを指定した場合にバインドマウントの中身ですべて消される。これが注意!!
alpine linux
alpine linuxは基本 GCC などの C コンパイラが含まれていない(つまり開発ツール)
alpine linuxにyarnいれる python:alpineにCコンパイラをインストール
Docker 参考文献
お前らのDockerfileは重い。 世界一わかりみが深いコンテナー Docker での Node 環境構築 Docker 環境構築best practice
Dockerコンテナー内のアプリケーションport
Dockerコンテナー内のアプリケーションは、デフォルトでネットワークトラフィックを受け入れている。
→http://127.0.0.1:3000
このインターフェースは外部トラフィックを受け入れないため、機能しないのも不思議ではありません。これを機能させるには、nuxtアプリのHOST環境変数を**0.0.0.0(すべてのIPアドレス)**に設定する必要がある。
コ ンテナーのサーバがlocalhostでlistenしていると、ホストマシンからアクセスした際にエラーが起きることを確認した。 これは、ホストマシンのlocalhostとコンテナーーのlocalhostが異なるため
ホストマシンとcontainerはnamespaceで区切られていて別のマシンと捉えて構わないため、containerのloopback interfaceにはホストマシンからはアクセスできない。
イメージをビルドするタイミングとは?
- Dockerfileを書き換えた時。
- パッケージ管理を行うファイルを書き換えた時
Dockerを軽くする方法
- RUNはチェーンする(&&)とにかくつなげる。RUN毎にレイヤーが作成されてしまうため(実際これもどうなんだろうと言われている)
- 産業廃棄物(docker build)時に生じた、アプリケーション実行には不要なツールやファイルを削除する
- yumやapt-getのゴミ
- ビルドに使用したソース
- gitですら産業廃棄物
- 成果物を残すことを意識する
- yarn installなどを早めたい
docker-compose.yml => Dockerfileへ環境変数を渡す方法(1)
渡す側(docker-compose.yml)と 受け取る側(Dockerfile)双方の設定が必要。
- docker-compose.ymlから渡す args ... Dockerイメージをビルド(作成)する際に引数を渡すために使用します。
この仕組みを使ってDockerfileへ環境変数を渡します。
services:
api:
build:
context: ./api
args:
# キー: 値
WORKDIR: $WORKDIR
# この書き方でもOK
- WORKDIR=$WORKDIR
- Dockerfileで 受け取る
ARG命令を使います。 指定する値はdocker-compose.ymlで渡したキーの名前です。 受け取った後はDockerfile内で変数として扱うことができます
ARG WORKDIR
ENV HOME=/${WORKDIR}
docker-compose.yml => コンテナーーへ環境変数を渡す方法
- environment
※これは扱う環境変数が少ない場合に使用する。
services:
api:
environment:
POSTGRES_PASSWORD: $POSTGRES_PASSWORD
# この書き方でもOK
- POSTGRES_PASSWORD=$POSTGRES_PASSWORD
- env_file
env_fileを使用する場合は、環境変数を格納したファイルパスを指定します。 相対パス、絶対パスどちらでも良い。 これは扱う環境変数が多い場合に使用します。
services:
api:
env_file: ./.env
ベースイメージを調べる方法
重いイメージは本当にいいことがない。 参考URL
ベースイメージのRubyバージョンを調べる手順 ちょっと豆知識。これからのプログラミング人生のために。
Rubyのバージョンは開発時点の安定版を使用するようにしましょう。
以下の手順でバージョンを調べます。
- まず、Rails6に必要なRubyのバージョンを知る。
- Railsガイド => Ruby 2.5.0以降が必要
- 次にRuby 2.5.0以上の安定版を知る。
- Ruby => 安定版は2.7.1
- 最後にRuby 2.7.1のベースイメージを調べる。
- Docker Hub => 2.7.1-alpineを採用
最近はオフィシャルでもAlpine版が存在している。
こうしたいんだぜという時の逆引きdocker
コマンド
近年Dockerコマンドはできるだけ次の書式に統一しようとしている
$docker コマンド 操作 オプション
docker word
デタッチモード: コンテナーー内に入らずバックグラウンドで動作する状態のこと。 -dでやる
dockerの基本運用概念
バインドマウントやボリュームマウントは別の場所に置き、コンテナーー自体は破棄されても問題ないような運用を心がけるべき方針
開発におけるdocker導入のメリット
メリット
-
同一性 複数人で開発する際に、環境の差が生まれない。
-
カプセル化 アプリケーション込みの環境をコンテナーーというカプセルに隠蔽できる。 コンテナーーという単位に対するテストが可能に。 コンテナーーを捨てる・再生成するのが容易。
-
ポータビリティ(一貫性とも) 開発に使ったコンテナーーをCIでテストできる。 CIでテストしたコンテナーーをサーバーにデプロイできる。 デプロイしたコンテナーーをスケールできる。
-
ひとつのサーバにwebサーバを同居できる(Apache) 1台のDockerホストに2台のWebサーバを同居させることができるなど。
メリットで防げる消耗
-
おれの環境では動いた。 はい。 複数の開発者で同一の環境で開発できるので防げる。
-
ローカルで通ったテストがCIでコケる。 開発と同一の環境でテストできるので防げる。 bundle install, npm installに失敗してテストがコケる。
-
依存ライブラリのフェッチに成功したイメージでテストすることで防げる。 コードを変更していないのにアプリケーションの挙動が変わった。go getしてるライブラリの挙動がいつの間にか変わってたぽい。
-
依存ライブラリをフェッチしたイメージを共有することで、バージョンを固定できる。 nginxの設定を変更したい。サーバにログインするためのSSHキーどれだっけ。 手元で設定して動作を確認しDockerイメージをデプロイできるので、設定変更のためにサーバーにログインする必要がなくなる。 さらに、正しく設定できているかブラックボックステストすることも可能に。
デメリット
-
学習コスト コンテナーを立ち上げるあたりまではコスト低めだが、実際に開発環境としてDockerを使うあたりから「これどうやってやるんだろう」「どちらの方法で設定するのが良いのだろう」のノウハウが出てくる感じになる。 開発者全員に深い知識が必要かというとそうではないが、問題解決できる知識を持った人間が開発陣に最低一人は必要。
-
ローカルでの開発とほぼ遜色ない環境でコードを書くことができるということを周知するためのコスト
-
完全な分離ではない。
DockerFile とは(カスタムイメージを作成した時)
docker buildでカスタムimageを作成するファイル 公開されている Docker イメージをそのまま使う場合は必要なく、カスタマイズしたい場合に作成する。
必要な理由 ベースとなるイメージとそのイメージに対して、どのような操作をするのかを記したDockerfileと呼ばれるファイルを用意しそのDockerfile通りにコンテナーに対して変更やファイルコピーを加えることによってイメージを作成する。
カスタムイメージの作り方
2つある。
-
コンテナーから作る ベースとなるイメージからコンテナーを起動し、そのコンテナーに対して、
docker exec
でシェルで入って操作したりdokcer cp
でファイルをコピーしたりし調整を加える。 その後docker commit
コマンドを使いイメージ化する。 デメリットが存在する -
Dockerfileから作る ベースとなるイメージとそのイメージに対して、どのような操作をするのかを記したDockerfileと呼ばれるファイルを用意しそのDockerfile通りにコンテナーに対して変更やファイルコピーを加えることによってイメージを作成する。 イメージの作成には
docker build
を実行する。
メリット Dockerfileは、ベースとなるイメージに対する変更指示をまとめたファイル。これを見れば悪意ある操作や間違った操作が加えられていないかが一目瞭然 Dockerfileは改良しやすいメリットがある。