Dockerの仕組みを知ろう #dockerbg

E6727b541b294abc62c3dca7cbeb4ab4?s=47 dockerbg
August 01, 2019

Dockerの仕組みを知ろう #dockerbg

E6727b541b294abc62c3dca7cbeb4ab4?s=128

dockerbg

August 01, 2019
Tweet

Transcript

  1. Docker の仕組みを知ろう 『 Docker/Kubernetes 実践コンテナ開発入門』読書会 特別編 第 2 回

  2. Linux インフラ のサポートを仕事にしているスピカーが、 Docker をとりまく基盤技術と Docker の動作概 要を説明してみるので、 みんなで一緒に仕組みを確認しながら勉強しよう! このセッションの趣旨

    2020 年までには、コンテナの本格的な普及期に入ると予想されるなど、 Docker ( コンテナ ) の脚光が日に日に増 してきています。 これにより、実際にコンテナを現場で利用したり、コンテナ開発について勉強する機会も増えてきました。 ( この会で は勉強のため『 Docker/Kubernetes 実践コンテナ開発入門』 の読書会してました。) ある程度 Docker ( コンテナ ) を利用した開発方法については理解してきたものの、 コンテナ が実際にどのような仕組みで動いているのかよくわからず、スッキリ しないまま利用/勉強しているのでど うにかしたい。
  3. 名前 : Kenji Fujii 所属 : Red Hat 職種 :

    テクニカルサポート 出身 : 広島 しまなみ方面 趣味 : お酒 ( 最近 ), ランニング ( ダイエット ), ドライブ ( バイク ), 野球 スピーカ自己紹介
  4. このセッションの内容や意見は個人的見解であり、必ずしも所属組 織の見解を示すものではありません。 はじめに 動作概要を理解することが今回の目的 ( アプリ開発者の場合は必要十 分の内容 ) のため、動作の詳細については大まかな説明となっている部 分があり、

    実際の詳細とは違う場合がありますことはご了承ください。 今後、さらに詳細な仕組みを理解する必要がある方は、このことを踏まえ た上で、今後の理解の足掛かりとして利用して頂けたら幸いです。
  5. お手元の PC で Docker 環境に接続できたら、 Linux 製品 ( ディストリビューション )

    の種類を確認してみてください。 Docker は元々、 Linux 上で動作することが前提のツールのため、 Linux 以外の環境 (Windows, Mac) でも、基本的には、 Linux が動作する 仮想マシンを稼働させて、その Linux 上で Docker を利用しています。 PC が Linux 以外の環境の方は、上記のコマンドでどのような Linux が利用されているか確認ください。 Windows 上で直接動作する Windows コンテナ Docker も現在は存在 (https://docs.microsoft.com/en-us/virtualization/windowscontainers/about/index) # cat /etc/*-release NAME="Red Hat Enterprise Linux Server" VERSION="7.6 (Maipo)" ID="rhel" ID_LIKE="fedora" VARIANT="Server" VARIANT_ID="server" VERSION_ID="7.6" PRETTY_NAME=RHEV ANSI_COLOR="0;31" CPE_NAME="cpe:/o:redhat:enterprise_linux:7.6:GA:server" HOME_URL="https://www.redhat.com/" BUG_REPORT_URL="https://bugzilla.redhat.com/" REDHAT_BUGZILLA_PRODUCT="Red Hat Enterprise Linux 7" REDHAT_BUGZILLA_PRODUCT_VERSION=7.6 REDHAT_SUPPORT_PRODUCT="Red Hat Enterprise Linux" REDHAT_SUPPORT_PRODUCT_VERSION="7.6" Red Hat Enterprise Linux Server release 7.6 (Maipo) Red Hat Enterprise Linux Server release 7.6 (Maipo) 環境の確認
  6. Linux の簡単なおさらい

  7. ハードウェア OS (windows や linux カーネル) プロセス プロセス プロセス プロセス

    Windows も Linux も原理は同じでこの構成で コンピューターを制御して処理を実行 デスクトップ画面やコンソールもプロセスの 一つ (クリックやキーボードの入力をまっている ) Apach や Nginx といった サーバープロセス アプリケーションが実行 ( メモリにロード ) されると、 OS はプロセスとして管理、実行 します OS とプロセス
  8. ハードウェア Linux カーネル プロセス プロセス プロセス プロセス Linux では、カーネルが処理する際に利用するメモリ領域をカーネル空間、 ユーザーアプリケー

    ションが利用する際の領域をユーザー空間とそれぞれ分けて管理しています。 カーネル空間とユーザー空間 ユーザー空間 カーネル空間 ユーザー空間、カーネル空間として、メモリを分けて管理することで互いの影響範囲を 限定することが可能になります。 ( 例 : ユーザープロセスの終了でシステムが終了するといったことが発生しない )
  9. Linux では、ディスク上のプログラムファイルやディレクトリ、メモリ上の疑似ファイルまで、すべて ファイルとして扱える (※) ように、複数のファイルシステムで構成されています。 これにより、ユーザーやアプリケーションが簡単にデータにアクセスできるようになっています。 ファイルシステム / ├bin ├boot

    ├etc ├home ├lib ├lib64 ├media ├mnt ├var ├tmp ├root ├run ├sbin ├usr ├opt ├sys ├dev ├run └proc APP プロセス メモリ VFS ログイン プロセス /bin/bash この例では、 / と /boot が同じディスクで別パーティション、 /opt は別のディスクで分けて利用している場合です ユーザー空間 カーネル空間 物理 (ハードウェア ) (※) 共通のインタフェース VFS を経由することでどのファイルも 同じようにアクセスが可能 mount mount mount mount
  10. 実際に Linux コマンドでプロセスを確認してみよう

  11. ps や top でプロセスの状態を確認 # ps aux --sort -rss USER

    PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND kfujii 8119 0.6 19.1 3414608 161272 tty2 Sl+ 19:48 0:15 /usr/bin/gnome-shell kfujii 8395 0.1 5.0 1352852 42248 tty2 Sl+ 19:49 0:03 /usr/bin/gnome-software --gapplication-service kfujii 9252 0.0 4.0 628264 33736 ? Ssl 20:14 0:00 /usr/libexec/gnome-terminal-server kfujii 8020 0.1 3.6 505760 30340 tty2 Sl+ 19:48 0:02 /usr/libexec/Xorg vt2 -displayfd 3 -auth /run/user/1000/gdm/Xauthority -background none -noreset -keeptty -verbose 3 root 8837 0.2 2.6 177712 22384 ? Ss 19:51 0:04 /usr/libexec/sssd/sssd_kcm --uid 0 --gid 0 --logger=files root 9344 0.0 1.3 380080 11672 ? S<sl 20:15 0:00 /usr/bin/pulseaudio –daemonize=no : プロセスの確認
  12. 以下のコマンドでどのような docker 関連のプロセスが起動しているか 確認してみてください。 # ps -ef | grep docker

    プロセスの確認 このセッションで利用する RHEL7.6 環境では、 dockerd といったデーモンではな く、 dockerd-current といったデーモンが起動しています。 実際に利用されている docker 環境 (Windows, Mac) と比較してみてください。 < 確認 1>
  13. Linux では、 /proc ファイルシステムの各ファイルから カーネルが管理している情報にアクセ スできます。 これにより、例えばプロセスの情報を参照したり、カーネルパラメータの変更 ( チューニング )

    が 可能 になっています。 # cat /proc/4011/status Name: dockerd-current Umask: 0022 State: S (sleeping) Tgid: 4011 Ngid: 0 Pid: 4011 PPid: 1 TracerPid: 0 Uid: 0 0 0 0 Gid: 0 0 0 0 FDSize:128 Groups: VmPeak: 565932 kB VmSize: 565868 kB VmLck: 0 kB VmPin: 0 kB VmHWM: 78000 kB VmRSS: 63708 kB カーネルが管理しているプロセス情報をみるには /proc/ プロセス ID/status を参照します。 ls ,top , vmstat などは、基本的に /proc/ から参照できるカーネル情報を表 示していることになります。 ※ 補足 /proc はチューニングの観点では Windows での レジストリに近い存在 Mac OS には /proc などはなく sysctl コマンドベースで確認やチューニングが可能 プロセスの確認
  14. dockerd-current のプロセス ID を調べて dockerd-current プロセスの /proc/ プロセス ID/status を確認してみてください。

    # ps -ef | grep dockerd-current | grep -v grep プロセスの確認 他のプロセスでも同じように確認できますので、 dockerd-current が存在しなければ 別のプロセスで確認ください。 < 確認 2> もしくは # pidof dockerd-current # cat /proc/ プロセス ID/status (1) PID 確認 (2) /proc/ プロセス ID/status の確認
  15. 実際に Linux コマンドでファイルシステムを確認してみよう

  16. / ├── bin ├── boot ├── dev ├── etc ├──

    home ├── lib ├── lib64 ├── media ├── mnt ├── opt ├── proc ├── root ├── run ├── sbin ├── srv ├── sys ├── tmp ├── usr └── var ファイルシステムの確認 Linux ファイルシステムの構成は、 Filesystem Hierarchy Standard ( FSH )といった標準規格 が存在しており、基本的にどの Linux デストリビューション でも同じような構成になっています。
  17. (1) tree コマンドで、 RHEL7 環境のファイルシステム構成を確認してみてください。 # tree / -L 1

    ファイルシステムの確認 < 確認 3> # df -Th (2) df コマンド ファイルシステムのタイプを確認 tree コマンドを利用するには、 RHEL 環境では tree パッケージをインストールする必要があります。 ( このセッションではすで にインストール済み ) tmpfs はファイルシステムのディレクトリ PATH
  18. Linux でプログラムが実行される流れを理解

  19. カーネル ハードウェア 親プロセス # # ls カーネル ハードウェア 親プロセス 子プロセス

    /bin/ bash # ls anaconda-ks.cfg test.py /bin/ bash カーネル ハードウェア 親プロセス 子プロセス /usr/bin/ls /bin/ bash コマンドが実行されると (bash が ls を実行すると ) カーネルは Fork して子プロセスを生成 カーネルは Exec して子プロセス上でコ マンドを実行 親プロセス ここでは /bin/bash (ls は /usr/bin/ls のエイリアス ) カーネル ハードウェア 親プロセス /bin/ bash 子プロセスは処理を実行し ( 必要があれば ) 出力し 終了コードをカーネルに返して終了 (exit) 子プロセス 出力 Linux コマンドを実行する際の流れ
  20. # ls プログラムがコマンドであれば、 そのコマンドだけがあれば動作するように思えるが。。 / ├── bin ├── dev ├──

    etc ├── home ├── lib ├── media ├── mnt ├── op ├── proc ├── root ├── run ├── sbin ├── srv ├── sys ├── tmp ├── usr └── var プログラムが動作するためには、ライブラリや設定ファイルなどが必要 ライブラリを置くディレクトリ プログラムを実行するのに必要なものを考える
  21. プログラムを実行するのに必要なものを考える < 確認 4> ( 注意 : 以下の確認は壊れてもいいテスト環境で実施ください) ls コマンドが実行される際に必要なライブラリファイルを確認して、そのライブラリがない

    と ls コマンドが動作しないことを以下の手順で確認してみてください。 # ldd /usr/bin/ls (1) ライブラリファイルの 確認 # mv /lib64/libcap.so.2 /lib64/libcap.so.2.bk (2) ライブラリファイル /lib64/libcap.so.2 をリネーム # ls (3) ls が動作しないことを確認
  22. プログラムを実行するのに必要なものを考える < 確認 4 つづき > # mv /lib64/libcap.so.2.bk /lib64/libcap.so.2

    (4) ライブラリファイルを元に戻す # ls (5) ls が動作することを確認 もし誤って、 libc (/lib64/libc.so.6) をリネームしたら、どのコマンドも動作しなくなります。 その場合は、 ldconfig コマンドを実行してから、 mv で元に戻してください。
  23. 実行環境 カーネル ハードウェア /var/lib/ --- ライブラリ /usr//bin --- プログラム /etc

    --- 設定ファイル /var/log --- ログ出力先 /var/data --- データ プロセス プロセス 広義の OS ( カーネルと実行環境 ) Ubuntu と RHEL では 実行環境内のファイルも カーネルも違いますが、 同じ Linux カーネルのため、 RHEL の カーネル上でも Ubuntu の実行環境が 基本的に動作します。 プログラムを実行するのに必要なものを考える プログラムを実行するためには、ファイルシステム上の各 種ファイルやディレクトリ (実行環境)が必要 実行環境
  24. コンテナを理解する

  25. プロセスをグループ化し、各種リソースを他のグループ(コンテナ)から隔離した空間で利用できる ようにしたもの OS( カーネルは同じ ) だが、コンテナ同士は他を知ることはなく、自身のみ が、 OS を利用していると見なして動作 LIBS

    App1 プロセス OS コンテナ LIBS App3 プロセス LIBS App2 プロセス コンテナ コンテナとは
  26. つまり 隔離した空間とは、コンテナごとの実行環境を用意し、ユーザー空間を分けて利用するということ コンテナとは ハードウェア Linux カーネル) プ ロ セ ス

    プ ロ セ ス プ ロ セ ス プ ロ セ ス カーネル空間 ユーザー空間 ハードウェア Linux カーネル) 実行環境 プ ロ セ ス プ ロ セ ス プ ロ セ ス プ ロ セ ス 実行環境 実行環境 ユーザー 空間 A ユーザー 空間 B 通常利用時 コンテナ利用時 どのプロセスも、実行環境とユーザー 空間も同じものを利用 各コンテナのプロセスごとに、それぞれの実行環 境とユーザー空間を持って動作(親とも別の実行 環境とユーザー空間をもつ) カーネル空間 /var/lib/ --- ライブラリ /usr//bin --- プログラム /etc --- 設定ファイル /var/log --- ログ出力先 /var/data --- データ /var/lib/ --- ライブラリ /usr//bin --- プログラム /etc --- 設定ファイル /var/log --- ログ出力先 /var/data --- データ
  27. Namespaces Namespaces cgroup SElinux ハードウェア Kernel 標準の Namespaces , cgroup

    , SElinux 機能などを利用してコンテナを実現 とくに重要なのが、ユーザー空間を分ける、 Namespace になります。 コンテナは kernel 標準の機能で実現 カーネル空間 プ ロ セ ス プ ロ セ ス プ ロ セ ス プ ロ セ ス 実行環境 実行環境 ユーザー 空間 A ユーザー 空間 B /var/lib/ --- ライブラリ /usr//bin --- プログラム /etc --- 設定ファイル /var/log --- ログ出力先 /var/data --- データ /var/lib/ --- ライブラリ /usr//bin --- プログラム /etc --- 設定ファイル /var/log --- ログ出力先 /var/data --- データ コンテナ コンテナ
  28. コンテナの実体は、実行したいアプリケーションが含まれるている実行環境になります。 OS( カーネル)は含まれていないことを理解ください。 プログラムを実行するには OS と 実行環境が必要 (P23) ↓ コンテナ環境の場合は動かしたいアプリケーションごとにコンテナ実行環境を用意し

    OS は同じものを利用 コンテナの実体 実行環境 /var/lib/ --- ライブラリ /usr/bin --- プログラム A /etc --- 設定ファイル /var/log --- ログ出力先 /var/data --- データ ハードウェア Linux カーネル) プ ロ セ ス A 実行環境 実行環境 カーネルは同じものを利用 つまり、動かしたいアプリごとに、実行環境を用意してコンテナ(アプリ ) を起動させます。 プ ロ セ ス B アプリケーションごとに 実行環境を用意 コンテナ B コンテナ A
  29. コンテナの状態遷移 カーネル ハードウェア 起動 実行環境 A プロセス コンテナ 新しいユーザー空間で起動 実行環境

    A 停止 削除 実行環境 A コンテナイメージをダウンロードとは、実行環境を用意することに相当します。 コンテナには、起動、停止 の状態が存在します。 ( プロセス起動、停止に相当) 削除とは、実行環境 ( コンテナイメージ)を削除することに相当します。 コンテナは常にホスト上のカーネルで動作することになります。 コンテナが起動すると、他のコンテナ空間や領域は基本的に参照できません。 実行環境 A /var/lib/ --- ライブラリ /usr//bin --- プログラム A /etc --- 設定ファイル /var/log --- ログ出力先 /var/data --- データ 実行環境を用意
  30. コンテナを手で作る場面を考えてみる

  31. 1. まず実行したいアプリケーションの実行環境イメージ(コンテナイメージ ) を用意します。 実行環境 A / ├── bin ├──

    lib ├── lib64 ├── opt │ └── bin │ └── hello.sh └── usr これは、動作させたいプログラム (hello.sh) が実行するために必要なファイルが入った実行環境を 用意して、 tar で固めたものになります。 Docker で image をダウンロードしますが、これも実質は 実行環境を tar で固めたも のが含まれています。 ( メタデータとか差分データも含まれて違いはありますが基本は 実行環境の tar です ) コンテナを手で実行すると仮定した際の流れ
  32. 2. 実際に RHEL7 環境に存在する実行環境のファイルを利用して、シェルプログラム (hello.sh) が動作するだけのコンテナ用の実行環境イメージを test.tar を作成してみます。 コンテナを手で実行すると仮定した際の流れ 実行環境

    A /test ├── bin ├── lib ├── lib64 ├── opt │ └── bin │ └── hello.sh └── usr # mkdir -p test/usr # cp -r /bin test/ # cp -r /lib test/ # cp -r /lib64 test/ # cp -r /usr/bin /usr/lib /usr/lib64/ test/usr/ # mkdir -p test/opt/bin # echo sleep 260 > test/opt/bin/hello.sh # chmod 755 test/opt/bin/hello.sh # tar cvf test.tar ./test
  33. 3. コンテナを実行したいホストで、コンテナごとのディレクトリを用意し、 作成した実行環境イメージ を展開 (tar ファイルを展開 ) します。 / ├──

    bin ├── dev ├── etc ├── lib ├── media ├── mnt ├── op ├── proc ├── root ├── run ├── sbin ├── srv ├── sys ├── tmp ├── usr └── var └── lib └── containers │── test │ │ │ │ │ │ コンテナを手で実行すると仮定した際の流れ / ├── bin ├── lib ├── lib64 ├── opt │ └── bin │ └── hello.sh └── usr # cp test.tar /var/lib/containers/. # cd /var/lib/containers/ # tar xvf test.tar ここでは、 /var/lib/containers/ 配下に展開します。 展開することで、左のような構成ができます。
  34. 4. コンテナを実行したい環境に chroot します。 これにより コンテナプロセスが動作する ファイルシステムが限定され、他のファイルシステム領域への影響を防ぎます。 # chroot /var/lib/containers/test

    chroot することで、 /var/lib/containers/test/ が / になりホ スト上のそれ以外のフィルが見えなくなります。 # tree / -L 1 / ├── bin -> usr/bin ├── lib -> usr/lib ├── lib64 -> usr/lib64 ├── opt └── usr コンテナを手で実行すると仮定した際の流れ / ├── bin ├── dev ├── etc ├── lib ├── media ├── mnt ├── op ├── proc ├── root ├── run ├── sbin ├── srv ├── sys ├── tmp ├── usr └── var └── lib └── containers │── test │ │ │ │ │ │ / ├── bin ├── lib ├── lib64 ├── opt │ └── bin │ └── hello.sh └── usr chroot により この範囲内でのみアクセ スが可能
  35. 5. unshare コマンドを利用して、現在の名前空間 ( ユーザー空間)とは別のユーザー空間に 変更してしてコンテナプロセス (hello.sh) を実行 # unshare

    -u -i -p --net -m --propagation unchanged --fork /opt/bin/hello.sh カーネル ハードウェア chroot した bash プロセス fork 名前空間を変えて実行 実行環境 A 実行環境 A コンテナを手で実行すると仮定した際の流れ /opt/bin/hello.sh 名前空間 A 名前空間 B 実行環境 A /opt/bin/hello.sh 隔離されたコンテナプロセスが起動 / ├── bin ├── dev ├── etc ├── lib ├── media ├── mnt ├── op ├── proc ├── root ├── run ├── sbin ├── srv ├── sys ├── tmp ├── usr └── var └── lib └── containers │── test │ │ │ │ │ │ / ├── bin ├── lib ├── lib64 ├── opt │ └── bin │ └── hello.sh └── usr 実行環境 A
  36. 手動で起動したコンテナプロセス /opt/bin/hello.sh が本当に新しい名前空間で動作している か確認してみます。 カーネル ハードウェア ログイン プロセス 名前空間を変えて実行 実行環境

    A 実行環境 A プロセス隔離の仕組み (Namespace について ) /opt/bin/hello.sh 名前空間 A 名前空間 B
  37. # ls -tlr /proc/$$/ns 合計 0 lrwxrwxrwx. 1 root root

    0 1 月 10 09:01 uts -> uts:[4026531838] lrwxrwxrwx. 1 root root 0 1 月 10 09:01 user -> user:[4026531837] lrwxrwxrwx. 1 root root 0 1 月 10 09:01 pid -> pid:[4026531836] lrwxrwxrwx. 1 root root 0 1 月 10 09:01 net -> net:[4026531956] lrwxrwxrwx. 1 root root 0 1 月 10 09:01 mnt -> mnt:[4026531840] lrwxrwxrwx. 1 root root 0 1 月 10 09:01 ipc -> ipc:[4026531839] 通常のプロセスがどの名前空間を持っていることは /proc/<pid>/ns から確認できます。 通常であれば、枠の中は、システムのどのプロセスも同じ値 ( 同じ名前空間)を持っています。 プロセス隔離の仕組み (Namespace について ) # ls -tlr /proc/$$/ns 親となる環境で、自身のログインシェルのプロセスがどのような 名前空間を持っているか確認します。 以下のコマンドを実行してみてください。 以下のような数字が見えるかと思います。
  38. # ls -tlr /proc/$$/ns total 0 lrwxrwxrwx. 1 root root

    0 Jul 31 18:34 uts -> uts:[4026531838] lrwxrwxrwx. 1 root root 0 Jul 31 18:34 user -> user:[4026531837] lrwxrwxrwx. 1 root root 0 Jul 31 18:34 pid -> pid:[4026531836] lrwxrwxrwx. 1 root root 0 Jul 31 18:34 net -> net:[4026531956] lrwxrwxrwx. 1 root root 0 Jul 31 18:34 mnt -> mnt:[4026531840] lrwxrwxrwx. 1 root root 0 Jul 31 18:34 ipc -> ipc:[4026531839] # ls -tlr /proc/$(pidof systemd)/ns total 0 lrwxrwxrwx. 1 root root 0 Jul 31 21:53 uts -> uts:[4026531838] lrwxrwxrwx. 1 root root 0 Jul 31 21:53 user -> user:[4026531837] lrwxrwxrwx. 1 root root 0 Jul 31 21:53 pid -> pid:[4026531836] lrwxrwxrwx. 1 root root 0 Jul 31 21:53 net -> net:[4026531956] lrwxrwxrwx. 1 root root 0 Jul 31 21:53 mnt -> mnt:[4026531840] lrwxrwxrwx. 1 root root 0 Jul 31 21:53 ipc -> ipc:[4026531839] プロセス隔離の仕組み (Namespace について ) # ls -tlr /proc/$$/ns # ls -tlr /proc/$(pidof systemd)/ns 他のプロセスも同じか確認してみます。 自身のシェルのプロセス ID と、 systemd プロセス ID の 名前空間が同じかみて みます。 この場合、枠の中は同じ値(同じ名前空間)になっていることが確認できます。 以下のコマンドを実行してみてください。 名前空間が同じ
  39. # ps -ef | grep hello.sh root 27229 27214 0

    22:17 pts/1 00:00:00 unshare -u -i -p --net -m --propagation unchanged --fork /opt/bin/hello.sh root 27230 27229 0 22:17 pts/1 00:00:00 /bin/sh /opt/bin/hello.sh root 27267 3919 0 22:17 pts/0 00:00:00 grep --color=auto hello.sh 次に、手動で動かしたコンテナプロセス /opt/bin/hello.sh が別の名前空間で動いて いるか確認してみます。 コンテナプロセスも親環境で動作しているプロセスですので、親環境で /opt/bin/hello.sh が動作していることを確認ください。 プロセス隔離の仕組み (Namespace について ) # ps -ef | grep hello.sh 以下の場合は、 PID 27230 で動作していることが分かります。
  40. # ls -tlr /proc/$$/ns total 0 lrwxrwxrwx. 1 root root

    0 Jul 31 18:34 uts -> uts:[4026531838] lrwxrwxrwx. 1 root root 0 Jul 31 18:34 user -> user:[4026531837] lrwxrwxrwx. 1 root root 0 Jul 31 18:34 pid -> pid:[4026531836] lrwxrwxrwx. 1 root root 0 Jul 31 18:34 net -> net:[4026531956] lrwxrwxrwx. 1 root root 0 Jul 31 18:34 mnt -> mnt:[4026531840] lrwxrwxrwx. 1 root root 0 Jul 31 18:34 ipc -> ipc:[4026531839] ls -tlr /proc/27230/ns total 0 lrwxrwxrwx. 1 root root 0 Jul 31 22:18 uts -> uts:[4026532190] lrwxrwxrwx. 1 root root 0 Jul 31 22:18 user -> user:[4026531837] lrwxrwxrwx. 1 root root 0 Jul 31 22:18 pid -> pid:[4026532192] lrwxrwxrwx. 1 root root 0 Jul 31 22:18 net -> net:[4026532194] lrwxrwxrwx. 1 root root 0 Jul 31 22:18 mnt -> mnt:[4026532189] lrwxrwxrwx. 1 root root 0 Jul 31 22:18 ipc -> ipc:[4026532191] プロセス隔離の仕組み (Namespace について ) # ls -tlr /proc/$$/ns # ls -tlr /proc/27230/ns 自身のシェルのプロセス ID と、 コンテナプロセス /opt/bin/hello.sh のプロセス ID の 名前空間が違うことを確認してみます。 この場合、枠の中は違う値(違う名前空間)になっていることが確認できます。 以下のコマンドを実行してみてください。 ( コンテナの PID はここでは 27230 とした場合 ) 名前空間が違う
  41. # ls -tlr /proc/$$/ns total 0 lrwxrwxrwx. 1 root root

    0 Jul 31 18:34 uts -> uts:[4026531838] lrwxrwxrwx. 1 root root 0 Jul 31 18:34 user -> user:[4026531837] lrwxrwxrwx. 1 root root 0 Jul 31 18:34 pid -> pid:[4026531836] lrwxrwxrwx. 1 root root 0 Jul 31 18:34 net -> net:[4026531956] lrwxrwxrwx. 1 root root 0 Jul 31 18:34 mnt -> mnt:[4026531840] lrwxrwxrwx. 1 root root 0 Jul 31 18:34 ipc -> ipc:[4026531839] # ls -tlr /proc/2888/ns total 0 lrwxrwxrwx. 1 root root 0 Aug 1 11:32 uts -> uts:[4026532190] lrwxrwxrwx. 1 root root 0 Aug 1 11:32 user -> user:[4026531837] lrwxrwxrwx. 1 root root 0 Aug 1 11:32 pid -> pid:[4026532192] lrwxrwxrwx. 1 root root 0 Aug 1 11:32 net -> net:[4026532194] lrwxrwxrwx. 1 root root 0 Aug 1 11:32 mnt -> mnt:[4026532189] lrwxrwxrwx. 1 root root 0 Aug 1 11:32 ipc -> ipc:[4026532191] プロセス隔離の仕組み (Namespace について ) # unshare -u -i -p --net -m --propagation unchanged --fork bash 次に、コンテナプロセスの中で直接コマンドを実行してみます。 これで、新しい名前空間で bash がコンテナプロセスとして起動しましたので、 ここでコマンドを実行すると、新しいコンテナの名前空間でコマンドが実行されることになります。 chroot した状態で以下のコマンドを実行ください。 名前空間が違う # sleep 360 ホスト側で、 sleep の PID を見つけて、自分のシェルの名前空間( ID )を比較すると違いが確 認できます。 ( 以下は sleep の pid が 2888 の場合 )
  42. 確認したように、 Docker 以前からコンテナを利用できましたが、商用環境を除いては、 あまり利用さていませんでした。 ( オープンソースでの利用は、 google などごく一部だけ ) 理由

    洗練された管理ツールが存在しておらずコンテナが扱いずらい 認知不足 コンテナを使用することのメリットが感じられなかった ( 大規模向き ) など。。 Docker 以前からコンテナは利用可能 なお、 Docker の中では、手動で確認したような unshare などをそのまま呼び出して利 用していません、もっと洗練した
  43. Docker の 登場

  44. コンテナ型仮想化ソフトウェアの一つであり、カーネルの既存の機能を利用 (namespace な どを利用 ) して簡単にコンテナを生成、管理できるようにしたツール 複数のアプリケーションを独立して実行、管理することが可能 実行環境 APP ハードウェア

    ハードウェア コンテナ コンテナ仮想環境 カーネル Docker Docker は、単にコンテナを作成、実行、管理 する機能を提供するだけでなく、 これまでの開発フローを一新すための仕組やアイディアも提供 Docker とは
  45. ※ 最近では runc など Docker デーモン(常駐プロセス ) でない構成もあります (Podman) コンテナ

    コンテナ Docker デーモン Namespaces Namespaces cgroup SElinux Linux カーネル ハードウェア Docker file Docker クライアント LIBS APP LIBS APP イメージ LIBS APP イメージ プライベートレジストリ libcontainer 自動化 インフラをコード化 イメージの 差分管理 Overlay ストレージレイア 軽量で、高速な デプロイの実現 安全なイメージの提供 イメージ レジストリ LIBS APP イメージ 実行環境 実行環境 APP Docker アーキテクチャと特徴
  46. Docker の 目的

  47. Docker は、単に軽量であるコンテナ環境を提供 / 管理できることだけが目的ではなく、 DevOps 、マイクロサービスなどといった新しい開発手法の実現の仕組を提供することを意識して 実現しています。 A B 実行環境

    本番 A 実行環境 B 本番 NG コンテナによってアプリと実行環境がパッケージ化さ れているので、他への影響がなく、簡単に削除してデ プロイが可能、テストも自動化されているので管理者 は安心して変更を許可できる (DevOps の考え方 ) Docker 従来 これから 新機能 パッチ 実行環境 A+ 新しいコンテナ 削除 ( 削除してもすぐに戻せる ) Developer Developer 運用管理者( Ops ) 運用管理者( Ops ) 従来型の環境では、管理者は、 A へのアップ デートが B に影響しすることを恐れて、アップ デートを許可できない。。 なぜ Docker (コンテナ )?
  48. Docker( コンテナ ) によって新しいインフラの考が生まれ、より安全でスピーディーなアプリ ケーションの提供が実現可能に Immutable Infrastructure Immutable Infrastructure では、パッケージのアップデートなどサーバに直接設定を加えるのではなく一度

    作ったら一切変更せず、 変更が必要になったらコンテナを作り直して、現在のコンテナを捨てて、入れ替えます。これにより、状態が変わ ることによる 問題を避けることが可能 マイクロサービス (Micro Service) 軽量なコンテナの特徴を生かして、アプリケーションを可能な限り小さい単位でコンテナを分離します。 これにより、依存関係を減らせ、開発やアップデートが簡単になります。 Infrastructure as Code インフラの構成をコードで記述し自動化することで、問題を減らし管理が容易になります。 DevOps これまで、インフラ管理とソフトウェアの開発は分離されていました。 Docker によってインフラの状態をコードと して記述できるため、ソフトウェア開発とインフラ管理を統合して、他の開発に影響なくし、効率よく開発できるよ うになります。 なぜ Docker (コンテナ )?
  49. Docker の 基本コマンドの動作を確認してみる

  50. イメージ レジストリ LIBS APP イメージ 実行環境 実行環境 APP / :

    ├── run ├── sbin ├── srv ├── sys ├── tmp ├── usr └── var └── lib └── docker │ ── overlay2 ── │ xxxxxxxxxxxxx # docker pull alpine:latest 1. 指定したイメージがローカルになれば レポジトリからイメージ をダウンロードし、 /var/lib/docker/overlay2 など 所定の場所に一意の名前のディレクトリ配下に 展開されます。 ( 手動での確認の際の、 tar ファイルを展開した際と同様な動きになります。 ) /var/lib/ --- ライブラリ /usr//bin/A – A プログラム /etc --- 設定ファイル /var/log --- ログ出力先 /var/data --- データ 基本コマンド (docker pull) の流れを確認
  51. # docker inspect alpine 基本コマンド (docker pull) の流れを確認 Pull したイメージがどのディレクトリに配置されるかは、以下のコマンドで確認できます。

    # docker inspect alpine [ { "Id": "sha256:b7b28af77ffec6054d13378df4fdf02725830086c7444d9c278af25312aa39b9", "RepoTags": [ "docker.io/alpine:latest" : : "Architecture": "amd64", "Os": "linux", "Size": 5581746, "VirtualSize": 5581746, "GraphDriver": { "Name": "overlay2", "Data": { "MergedDir": "/var/lib/docker/overlay2/939eac4675e837b50c01f53a23da4b0fa178f63be19b2fdedf984eee5dc02f5f/merged", "UpperDir": "/var/lib/docker/overlay2/939eac4675e837b50c01f53a23da4b0fa178f63be19b2fdedf984eee5dc02f5f/diff", "WorkDir": "/var/lib/docker/overlay2/939eac4675e837b50c01f53a23da4b0fa178f63be19b2fdedf984eee5dc02f5f/work" } : : : 例
  52. イメージ レジストリ LIBS APP イメージ 実行環境 実行環境 APP / :

    ├── run ├── sbin ├── srv ├── sys ├── tmp ├── usr └── var └── lib └── docker │ ── overlay2 ── │ xxxxxxxxxxxxx # docker run -d alpine sleep 360 1. イメージがローカルになれば、レジストリからイメージをダウンロードし、 /var/lib/docker/overlay2 など 所定の場所に一意の名前のディレクトリ配下に 展開されます。 (tar の中身が展開 ) /var/lib/ --- ライブラリ /usr//bin/A – A プログラム /etc --- 設定ファイル /var/log --- ログ出力先 /var/data --- データ 基本コマンド (docker run) の流れを確認
  53. / : ├── run ├── sbin ├── srv ├── sys

    ├── tmp ├── usr └── var └── lib └── docker │ ── overlay2 ── │ xxxxxxxxxxxxx 2. 展開したベースイメージから、スナップショット相当の領域を確保します。 ( これはストレージドライバの仕組で行います。最近では overlay) /var/lib/ --- ライブラリ /usr//bin/A – A プログラム /etc --- 設定ファイル /var/log --- ログ出力先 /var/data --- データ 基本コマンド (docker run) の流れを確認
  54. / : ├── run ├── sbin ├── srv ├── sys

    ├── tmp ├── usr └── var └── lib └── docker │ ── overlay2 ── │ xxxxxxxxxxxxx 3. スナップショット相当のイメージ領域 が mount されて、 指定されたコマンド(ここでは sleep 360) を 名前空間を変えるなどコンテナ化して プロセス を実行します。 /var/lib/ --- ライブラリ /usr//bin/ – プログラム /etc --- 設定ファイル /var/log --- ログ出力先 /var/data --- データ /bin/sleep 360 隔離されたコンテナが起動 基本コマンド (docker run) の流れを確認 / /var/lib/ --- ライブラリ /usr//bin/ –- プログラム /etc --- 設定ファイル /var/log --- ログ出力先 /var/data --- データ mount
  55. # mount | grep work # docker run -d alpine

    sleep 30 # mount | grep work overlay on /var/lib/docker/overlay2/3d7a71bd1999bfda09797aac3bc708a3ce1e61b956edbf38531f636a1a1e0dc6/merged type overlay (rw,relatime,context="system_u:object_r:container_file_t:s0:c231,c692",lowerdir=/var/lib/docker/overlay2/l/4IG3JBL3RISQKJ2QZBXEG7JL3T:/var/lib/docker/overlay 2/l/JLLOIDESKNJNRGHUHUQPML34EO,upperdir=/var/lib/docker/overlay2/3d7a71bd1999bfda09797aac3bc708a3ce1e61b956edbf38531f636a1a1e0dc6/diff,work dir=/var/lib/docker/overlay2/3d7a71bd1999bfda09797aac3bc708a3ce1e61b956edbf38531f636a1a1e0dc6/work) 基本コマンド (docker run) の流れを確認 docker run でコンテナを起動させ、 ホスト上で mount コマンドを実行すると、コンテナが起動している間、スナップショット相当の イメージレイアが overlay mount されていることが確認できます。
  56. / : ├── run ├── sbin ├── srv ├── sys

    ├── tmp ├── usr └── var └── lib └── docker │ ── overlay2 ── │ xxxxxxxxxxxxx 4. プロセスが終了 ( コンテナが起動 ) が終了しても、コンテナ領域は残ったままとなります ( コンテナの停止状態 ) /var/lib/ --- ライブラリ /usr//bin/A – A プログラム /etc --- 設定ファイル /var/log --- ログ出力先 /var/data --- データ 基本コマンド (docker run) の流れを確認 コンテナプロセスが終了しても コンテナ領域は残ったまま /bin/sleep 360
  57. / : ├── run ├── sbin ├── srv ├── sys

    ├── tmp ├── usr └── var └── lib └── docker │ ── overlay2 ── │ xxxxxxxxxxxxx 5. 再度、 run すると新しいコンテナ領域がスナップショットで作成されて (1) から (4) が繰り返されます。 (1) ではすでにイメージがあるので、 (2) に移ります。 /var/lib/ --- ライブラリ /usr//bin/A – A プログラム /etc --- 設定ファイル /var/log --- ログ出力先 /var/data --- データ 基本コマンド (docker run) の流れを確認 コンテナプロセスが終了しても コンテナ領域は残ったまま /bin/sleep 360 コンテナプロセスが終了しても コンテナ領域は残ったまま
  58. # docker run -d alpine sleep 1 # ls /var/lib/docker/overlay2

    | wc -l # docker run -d alpine sleep 1 # ls /var/lib/docker/overlay2 | wc -l 基本コマンド (docker run) の流れを確認 コンテナを生成するごとに、 /var/lib/docker/overlay2 配下のファイルが増え続けることを確認ください docker containers ls で現在起動しているコンテナが確認でき、 ls -a とすることで停止してい るコンテナが確認できるのは、 コンテナの領域は残り続け、いつでも再利用できる仕組みのため # docker run -d alpine sleep 10 # docker container ls # docker container ls -a
  59. docker build は、 docker デーモンが、 Dockerfile の内容に従ってコンテナイメージを作成します。 build しただけではコンテナは実行されません。 基本コマンド

    (docker build) の流れを確認 Docker デーモン docker build Dockerfile Docker クライアント コンテナイメージ
  60. # docker build -t test . # docker container run

    test ここでは、以下のようなコマンドで、 Dockerfile から ビルドしたイメージを run する場合を考えます。 1. Hello と表示するだけの python スクリプトファイルを hello.py として作成します。 # cat hello.py print("Hello") 2. 以下の内容の Dockerfile を作成します # cat Dockerfile FROM python:latest RUN mkdir /work COPY hello.py /work CMD ["python", "/work/hello.py"] 基本コマンド (docker build) の流れを確認
  61. # docker build -t test . 3. Docker ファイルから、 test

    といったタグ名を付けてイメージを作成するために以下のコマンドを実行| します。 . ( ドット ) は Docker ファイルが存在する場所である直下のディレクトリを意味します。 FROM python:latest RUN mkdir /work COPY hello.py /work CMD ["python", "/work/hello.py"] 上記のコマンドが実行されると Docker ファイルに従って処理が実行されます。 レジストリ 実行環境 / : ├── run ├── sbin ├── srv ├── sys ├── tmp ├── usr └── var └── lib └── docker │ ── overlay2 ── │ xxxxxxxxxxxxx /var/lib/ --- ライブラリ /usr//bin/A – A プログラム /etc --- 設定ファイル /var/log --- ログ出力先 /var/data --- データ FROM イメージがローカルになれば レポジトリからイメージ をダ ウンロードし、 /var/lib/docker/overlay2 など 所定の 場所に一意の名前のディレクトリ配下に 展開されます。 (tar の中身が展開と同様 ) 基本コマンド (docker build) の流れを確認
  62. FROM python:latest RUN mkdir /work COPY hello.py /work CMD ["python",

    "/work/hello.py"] / : ├── run ├── sbin ├── srv ├── sys ├── tmp ├── usr └── var └── lib └── docker │ ── overlay2 ── │ xxxxxxxxxxxxx /var/lib/ --- ライブラリ /usr//bin/A – A プログラム /etc --- 設定ファイル /var/log --- ログ出力先 /var/data --- データ RUN 展開された領域でコマンドを実行します。ここでは mkdir /work で /work ディレクトリが作成されます 基本コマンド (docker build) の流れを確認 作成 /work
  63. FROM python:latest RUN mkdir /work COPY hello.py /work CMD ["python",

    "/work/hello.py"] / : ├── run ├── sbin ├── srv ├── sys ├── tmp ├── usr └── var └── lib └── docker │ ── overlay2 ── │ xxxxxxxxxxxxx /var/lib/ --- ライブラリ /usr//bin/A – A プログラム /etc --- 設定ファイル /var/log --- ログ出力先 /var/data --- データ /work COPY Docker コマンドで指定した . ( カレントディレクトリ)に存在する フィルを展開したコピーします。 ここでは、 hello.py を 展開された領域に作成された /work 配下 にコピーされ /work/hello.py が作成されます hellop.py コピー 基本コマンド (docker build) の流れを確認
  64. FROM python:latest RUN mkdir /work COPY hello.py /work CMD ["python",

    "/work/hello.py"] / : ├── run ├── sbin ├── srv ├── sys ├── tmp ├── usr └── var └── lib └── docker │ ── overlay2 ── │ xxxxxxxxxxxxx /var/lib/ --- ライブラリ /usr//bin/A – A プログラム /etc --- 設定ファイル /var/log --- ログ出力先 /var/data --- データ /work CMD コンテナ起動時に実行するコマンドを指定します。 Build 時には、ここに記載した内容が、メタ情報ファイルに 記録されます CMD の内容 を記録 メタデータ 基本コマンド (docker build) の流れを確認
  65. # docker inspect test : : "Cmd": [ "/bin/sh", "-c",

    "#(nop) ", "CMD [\"python\" \"/work/hello.py\"]" ], : : : 4. build コマンドが正常に作成したら、 CMD がメタ情報に記録されていることは 以下のコマンドで確認できます。 基本コマンド (docker build) の流れを確認
  66. / : ├── run ├── sbin ├── srv ├── sys

    ├── tmp ├── usr └── var └── lib └── docker │ ── overlay2 ── │ xxxxxxxxxxxxx # docker container run test Hello 5. build 後に、 docker run を実行すると、すでにイメージがあるので、コンテナのスナップ領域が作成され メタ情報 に記録された CMD が実行されます。 今回は、 CMD で指定した /work/hello.py 実行され、” Hello” の文字が表示されるはずです。 /work/hello.py /var/lib/ --- ライブラリ /usr//bin/A – A プログラム /etc --- 設定ファイル /var/log --- ログ出力先 /var/data --- データ /work メタデータ 基本コマンド (docker build) の流れを確認
  67. / : ├── run ├── sbin ├── srv ├── sys

    ├── tmp ├── usr └── var └── lib └── docker │ ── overlay2 ── │ xxxxxxxxxxxxx # docker commit コンテナ名 1. コンテナ内で変更した際に、その変更内容をイメージとして残したい場合は、 commit をすることで 新しいイメージが作成されます。 この際のイメージは、ベースとなるイメージから、変更した分の差分だけがイメージとして作成つまり、 新しいイメージを参照する際は、ベースイメージ + 差分イメージ といった階層 ( レイヤ)イメージで Docker は扱います。 xxxxxxxxxxxxx ( ベースと差分で ) 新しいイメージ 基本コマンド (docker commit) の流れを確認 ベースイメージ 差分イメージ
  68. # docker run -it alpine /bin/sh 2. ベースとなるイメージでコンテナを起動して /bin/sh でコンテナ内に入ります

    3. コンテナ内で任意のファイルを作成して exit でコンテナを停止 # echo hello > aaa.txt # docker images 1. 変更前の image 、コンテナを確認 # docker container ls -a 4. 作成されたコンテナを確認して、 commit # docker container ls -a # docker commit コンテナ ID 5. 新しいイメージができたことを確認して、 save で 新しいイメージとベースイメージ ( ここでは alpine) それぞれのイメージファイルを抽出 # docker images # docker save 新しいイメージ ID > new.tar # docker save alpine > base.tar 変更を加えたイメージはレイヤごとの tar が作成され ることの確認 (docker save)
  69. # tar tvf base.tar drwxr-xr-x 0/0 0 2019-06-20 06:19 4d2b17408c08f4424d1c585dc9b85633eba823469a318f0ebf4bcdd4ba62bba7/

    -rw-r--r-- 0/0 3 2019-06-20 06:19 4d2b17408c08f4424d1c585dc9b85633eba823469a318f0ebf4bcdd4ba62bba7/VERSION -rw-r--r-- 0/0 1184 2019-06-20 06:19 4d2b17408c08f4424d1c585dc9b85633eba823469a318f0ebf4bcdd4ba62bba7/json -rw-r--r-- 0/0 5843968 2019-06-20 06:19 4d2b17408c08f4424d1c585dc9b85633eba823469a318f0ebf4bcdd4ba62bba7/layer.tar -rw-r--r-- 0/0 1512 2019-06-20 06:19 4d90542f0623c71f1f9c11be3da23167174ac9d93731cf91912922e916bab02c.json -rw-r--r-- 0/0 202 1970-01-01 09:00 manifest.json -rw-r--r-- 0/0 89 1970-01-01 09:00 repositories # tar tvf new.tar drwxr-xr-x 0/0 0 2019-06-20 13:29 8789006f2f68122b9346a556e085557e0b47e3f298c2a2b7fb696863954f70dd/ -rw-r--r-- 0/0 3 2019-06-20 13:29 8789006f2f68122b9346a556e085557e0b47e3f298c2a2b7fb696863954f70dd/VERSION -rw-r--r-- 0/0 1052 2019-06-20 13:29 8789006f2f68122b9346a556e085557e0b47e3f298c2a2b7fb696863954f70dd/json -rw-r--r-- 0/0 3072 2019-06-20 13:29 8789006f2f68122b9346a556e085557e0b47e3f298c2a2b7fb696863954f70dd/layer.tar drwxr-xr-x 0/0 0 2019-06-20 13:29 dbd470339949cd2648dd5483334c493fc5fb9a2901efa82fca5642749c6edf27/ -rw-r--r-- 0/0 3 2019-06-20 13:29 dbd470339949cd2648dd5483334c493fc5fb9a2901efa82fca5642749c6edf27/VERSION -rw-r--r-- 0/0 406 2019-06-20 13:29 dbd470339949cd2648dd5483334c493fc5fb9a2901efa82fca5642749c6edf27/json -rw-r--r-- 0/0 5843968 2019-06-20 13:29 dbd470339949cd2648dd5483334c493fc5fb9a2901efa82fca5642749c6edf27/layer.tar -rw-r--r-- 0/0 1446 2019-06-20 13:29 e59d8c5563c9dbfd17dd915a11deecaa4d1e85d064f9cd464c1b8c3e53444edc.json -rw-r--r-- 0/0 266 1970-01-01 09:00 manifest.json 7. ベースと新しいイメージファイルの中の比較 ( 差分が増えていることを確認 ) 増えている 変更を加えたイメージはレイヤごとの tar が作成され ることの確認 (docker save)
  70. # docker images # docker save イメージ ID > image.tar

    # tar tvf image.tar drwxr-xr-x 0/0 0 2019-06-20 13:29 8789006f2f68122b9346a556e085557e0b47e3f298c2a2b7fb696863954f70dd/ -rw-r--r-- 0/0 3 2019-06-20 13:29 8789006f2f68122b9346a556e085557e0b47e3f298c2a2b7fb696863954f70dd/VERSION -rw-r--r-- 0/0 1052 2019-06-20 13:29 8789006f2f68122b9346a556e085557e0b47e3f298c2a2b7fb696863954f70dd/json -rw-r--r-- 0/0 3072 2019-06-20 13:29 8789006f2f68122b9346a556e085557e0b47e3f298c2a2b7fb696863954f70dd/layer.tar drwxr-xr-x 0/0 0 2019-06-20 13:29 dbd470339949cd2648dd5483334c493fc5fb9a2901efa82fca5642749c6edf27/ -rw-r--r-- 0/0 3 2019-06-20 13:29 dbd470339949cd2648dd5483334c493fc5fb9a2901efa82fca5642749c6edf27/VERSION -rw-r--r-- 0/0 406 2019-06-20 13:29 dbd470339949cd2648dd5483334c493fc5fb9a2901efa82fca5642749c6edf27/json -rw-r--r-- 0/0 5843968 2019-06-20 13:29 dbd470339949cd2648dd5483334c493fc5fb9a2901efa82fca5642749c6edf27/layer.tar -rw-r--r-- 0/0 1446 2019-06-20 13:29 e59d8c5563c9dbfd17dd915a11deecaa4d1e85d064f9cd464c1b8c3e53444edc.json -rw-r--r-- 0/0 266 1970-01-01 09:00 manifest.json # docker container ls -a # docker export コンテナ ID > export.tar # tar tvf -rwxr-xr-x 0/0 0 2019-06-20 13:29 .dockerenv drwxr-xr-x 0/0 0 2019-06-20 02:14 bin/ lrwxrwxrwx 0/0 0 2019-06-20 02:14 bin/arch -> /bin/busybox lrwxrwxrwx 0/0 0 2019-06-20 02:14 bin/ash -> /bin/busybox lrwxrwxrwx 0/0 0 2019-06-20 02:14 bin/base64 -> /bin/busybox lrwxrwxrwx 0/0 0 2019-06-20 02:14 bin/bbconfig -> /bin/busybox -rwxr-xr-x 0/0 833104 2019-06-13 02:52 bin/busybox lrwxrwxrwx 0/0 0 2019-06-20 02:14 bin/cat -> /bin/busybox lrwxrwxrwx 0/0 0 2019-06-20 02:14 bin/chgrp -> /bin/busybox lrwxrwxrwx 0/0 0 2019-06-20 02:14 bin/chmod -> /bin/busybox save の場合は、イメージを指定して差分ごとの情報を出力、 export は コンテナを指定してコンテ ナ内のフィルシステムすべてをまとめたて出力 save の場合 ( 差分ごとのメタ情報と tar) export の場合 ( ファイルベース ) docker export した tar を docker Import して作成したイメージは、差分がな いシングルレイヤの状態になります。 docker save と docker export の違い
  71. Docker の その他コマンド

  72. # docker info Containers: 7 Running: 0 Paused: 0 Stopped:

    7 Images: 2 Server Version: 18.09.6 Storage Driver: overlay2 Backing Filesystem: xfs Supports d_type: true Native Overlay Diff: true Logging Driver: json-file Cgroup Driver: cgroupfs Plugins: Volume: local Network: bridge host macvlan null overlay Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog Swarm: inactive Runtimes: runc Default Runtime: runc Init Binary: docker-init containerd version: bb71b10fd8f58240ca47fbb579b9d1028eea7c84 runc version: 2b18fe1d885ee5083ef9f0838fee39b62d653e30 init version: fec3683 Security Options: seccomp Profile: default Kernel Version: 3.10.0-957.el7.x86_64 Operating System: RHEV OSType: linux Architecture: x86_64 CPUs: 1 Total Memory: 991.1MiB Name: docker ID: 4Q3V:K4R7:G2RC:LE3G:RQUM:KWH2:BQVX:QGUG:TFJS:7RND:6X2K:XJPG Docker Root Dir: /var/lib/docker Debug Mode (client): false Debug Mode (server): false Registry: https://index.docker.io/v1/ Labels: Experimental: false Insecure Registries: 127.0.0.0/8 Live Restore Enabled: false Product License: Community Engine WARNING: bridge-nf-call-iptables is disabled WARNING: bridge-nf-call-ip6tables is disabled 利用しているストレージドライバ 現在利用している コンテナとイメージ数 docker info コマンドで、 docker 環境の状況が確認できます。 基本コマンド (docker info )
  73. # docker inspect コンテナ ID( もしくはイメージ ID) [ { "Id":

    "sha256:e59d8c5563c9dbfd17dd915a11deecaa4d1e85d064f9cd464c1b8c3e53444edc", "RepoTags": [], "RepoDigests": [], "Parent": "sha256:4d90542f0623c71f1f9c11be3da23167174ac9d93731cf91912922e916bab02c", "Comment": "", "Created": "2019-06-20T04:29:48.606858333Z", "Container": "8d713cafb0d8446e99c54e03b0bd4d88d6c0b283dd1e7690331ec652a93278f2", "ContainerConfig": { "Hostname": "8d713cafb0d8", "Domainname": "", "User": "", "AttachStdin": true, "AttachStdout": true, "AttachStderr": true, "Tty": true, "OpenStdin": true, "StdinOnce": true, "Env": [ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" ], "Cmd": [ "/bin/sh" ], "Image": "alpine", "Volumes": null, "WorkingDir": "", "Entrypoint": null, "OnBuild": null, "Labels": {} }, "DockerVersion": "18.09.6", : "VirtualSize": 5581762, "GraphDriver": { "Data": { "LowerDir": "/var/lib/docker/overlay2/40431a1443499468f5517d502e6ad289b36bcf7269d079ea166c8c03d2015fd4/diff", "MergedDir": "/var/lib/docker/overlay2/9e56c635039f1b40136e5ea98443d9b6eabdaad01bf767b30ff309cf0d510c49/merged", "UpperDir": "/var/lib/docker/overlay2/9e56c635039f1b40136e5ea98443d9b6eabdaad01bf767b30ff309cf0d510c49/diff", "WorkDir": "/var/lib/docker/overlay2/9e56c635039f1b40136e5ea98443d9b6eabdaad01bf767b30ff309cf0d510c49/work" }, "Name": "overlay2" }, "RootFS": { "Type": "layers", "Layers": [ "sha256:256a7af3acb11f89914205b6eef07e05e4196e898329575d97185758b450eb52", "sha256:46473c70dc885ffc66962eb0c9a67df17ab1e737fe564a36323ff396d2298472" ] }, "Metadata": { "LastTagTime": "0001-01-01T00:00:00Z" } } ] docker inspect コマンドで、イメージやコンテナのメタ情報が確認できます。 基本コマンド (docker inspect )
  74. コンテナ / イメージ 削除 # docker ps # docker ps

    -a # docker rm コンテナ ID # docker images -a # docker rmi イメージ ID コンテナ削除 イメージ削除 / : ├── run ├── sbin ├── srv ├── sys ├── tmp ├── usr └── var └── lib └── docker │ ── overlay2 ── │ イメージ削除 (docker rmi) コンテナ削除 (docker rm) xxxxxxxxxxxxx
  75. コンテナ作成の練習として python による 簡易 WEB サーバーコンテナを作成する例です。 簡易 WEB サーバ コンテナ作成例

    # docker search centos ...(1) # docker pull centos ...(2) # docker images ...(3) # docker run -it --name testweb_c1 centos /bin/bash ...(4) ( コンテナ内で実行 ) ...(5) # echo "This is a test page." > /opt/index.html # exit # docker ps -l ...(6) # docker commit testweb_c1 testweb:devel ...(7) # docker run -d --name testweb_c2 -p 80:80 --expose 80 -w /opt testweb:devel python -m SimpleHTTPServer 80 ...(8) # curl http://localhost ...(9) # docker stop testweb_c2 ...(10) # docker commit testweb_c2 testweb:production ...(11) # docker run -d -p 80:80 testweb:production ...(12) 1. centos というキーワードで、コンテナーイメージを検索 2. centos" というイメージをダウンロード 3. ホスト上に保存されているコンテナーイメージを確認 4. testweb_c1 という名前を付け、 Web サーバー構築用のコンテナーを起動 . /bin/bash でコンテナー内で対話的な操作を行う 5. Web サーバー構築作業 6. 直近で起動したコンテナーの情報を確認 7. コンテナー内の変更を反映させるため、 "testweb:devel" という一時的なコンテナーイメージを作成 8. testweb_c2 という名前を付け、 Web サーバー実行のためのコンテナーを起動 . -d オプションを付けているため、バックグラウンドで 実行し続ける 9. Web サーバーへのアクセスを確認 10. コンテナーを停止 11. testweb_c2 コンテナーから完成版コンテナーイメージを作成 12. 完成したコンテナーイメージからコンテナーを起動
  76. Docker 補足

  77. コンテナ A apache # docker run -d -p 8000:80 -v

    /work:/opt/work -v /data –volumes-from コンテナ B mytest/ コンテナ A Docker クライアント Docker デーモン コマンド例 : /opt/work /work /data /var/lib/docker/volumes/A* LIBS apache run 8000 80 イメージ ローカルになければ pull コンテナ B /var/lib/docker/volumes/B* -d デタッチモード -p 8000:80 ホストのポート 8000 とコンテナ内のポート 80 とマッピングします。 -v /work: /opt/work ホストの /work を コンテナ内の /opt/work とバインドします。 (/opt/work がコンテナに なければ作成されます。 ) -v /data ホストの docker ボリューム領域 /var/lib/docker/volumes/ コンテナ ID*/_data とバイン ドします。 ( コンテナに /data がなければ作成されます ) –volumes-from コンテナ B コンテナ B が持つ ボリューム領域 -v /vol を参照する。 /vol /vol OS docker run のオプション
  78. Docker デーモン Docker クライア ント コンテナ LIBS docker pull docker

    search docker push docker run docker build docker images docker commit docker ps docker rm docker rmi docker inspect docker exec docker save docker load docker export docker import docker start docker stop docker kill docker info : 各コマンドの詳細は # man docker コマンド名で確認できます。 レジストリ # ( 例 ) # man docker run pull push run LIBS APP イメージ commit LIBS APP イメージ rmi コンテナ rm load export save tar tar tar tar コンテナ内のファ イルシステムを tar で 1 つにし たファイル イメージ内の差分情報をファイル (tar) にしてそれをアーカイブ した tar ファイル build LIBS APP イメージ export された tar からできた 新しいイメージ import start stop コンテナ イメージ kill docker コマンド遷移
  79. コンテナ 1 172.17.0.18 172.17.42.1 Docker0 bridge veth002aa7av veth6df8377 veth7b0e4c6 192.168.50.16

    eth0 コンテナ 2 172.17.0.19 eth0 コンテナ 3 172.17.0.20 eth0 外部からのアクセスはホストのポートをコンテナのポートにマッピング ( ポートフォワード ) する ことでアクセス可能 eth0 iptables # docker run -d --rm -p 8000:80 コンテナ 1:production ポートフォワーディング コンテナからは、ポートフォワーディングによって外部にアクセスされます。 上記の場合は、 http://192.168.50.16:8000 でコンテナ 1 にアクセス可能 docker ネットワーク
  80. イメージレイヤーでコンテナの差分管理を実現するには、 Storage Driver を 利用しますが、 Docker では Storage Driver を選択できるようになっています。

    "aufs", "btrfs", "zfs", "devicemapper", "overlay", "vfs", 最近のデフォルト (RHEL7.6 現在 ) Namespaces Namespaces cgroup SElinux Linux カーネル ハードウェア Overlay ストレージレイア Docker デーモン Docker クライ アント libcontainer コンテナ docker ネットワーク
  81. Docker では、 cgroup を利用して、各コンテナごとのプロセスのリソースをまとめて管理してい ます。必要に応じてリソースを制限することも可能です。 # docker run -d -p

    80:80 --cpuset-cpus 1 -c 512 -m 512m rhel_httpd /usr/sbin/httpd -DFOREGROUND ( 例 ) --cpuset-cpus 1 --- CPU コア 1 を指定 -c 512 --- CPU 使用の優先度の相対比 512 ( デフォルトの 1024 に対して ) -m 512m --- メモリ使用量は 512M Namespaces Namespaces cgroup SElinux Linux カーネル ハードウェア Overlay ストレージレイア Docker デーモン Docker クライアント コンテナ Cgroup について
  82. サーバー仮想化とコンテナ仮想化

  83. カーネル ハードウェア 実行環境 A プロセス 実行環境 B プロセス カーネル ハードウェア

    実行環境 仮想マシン OS プロセス プロセス 実行環境 サーバー仮想化 コンテナ仮想化 コンテナ仮想化の場合、カーネルを共有して直接実行するので、起動が早いのは明らか さらに Docker を利用するこことで、コンテナの追加、変更、削除が簡単になるので、コンテナベースの開発が可能 サーバ仮想化とコンテナ仮想化
  84. ホストベース型 ハイパーバイザー型 現在の主流はハイパーバイザー型 カーネル ハードウェア 実行環境 仮想マシン OS プロセス プロセス

    実行環境 仮想化ソフト (VirtualBox,WorkstationPlayer など ) ハイパーバイザー ハードウェア 実行環境 仮想マシン OS プロセス プロセス 実行環境 サーバ仮想化の種類
  85. ハイパーバイザー は、ソフト、 ハイパーバイザー は、ソフト、 OS OS 、ハード それぞれの仮想化機能を合わせて 、ハード それぞれの仮想化機能を合わせて

    仮想マシンをゲストに提供するので、ゲストは物理環境と同等のパフォーマンスの実現が可能 仮想マシンをゲストに提供するので、ゲストは物理環境と同等のパフォーマンスの実現が可能 => => 複数のサーバーを集約して管理することができ、スペース、コストの改善が可能に 複数のサーバーを集約して管理することができ、スペース、コストの改善が可能に ハイパーバイザー ハードウェア 実行環境 仮想マシン OS プロセス プロセス 実行環境 Intel VT 仮想化機構 ハード、 ハード、 kernel, kernel, ユーザーレベルが協力して処 ユーザーレベルが協力して処 理するため物理同様の速度を提供 理するため物理同様の速度を提供 KVM Linux, AWS,Google Cloud Xen VMware Hyper-v Windows, Azure xhyve Mac ハイパーバイザー製品 ホストベースの場合は、仮想化ソフトがすべて仮想マシンを 制御するので遲い ( 本番では利用不可 ) サーバ仮想化 ( ハイパーバイザー型 ) の用途
  86. コンテナ型である、 コンテナ型である、 Docker Docker は、単に軽量の環境を管理運用するだけでなく、 差分ファイルシステムなどを利 は、単に軽量の環境を管理運用するだけでなく、 差分ファイルシステムなどを利 用して、開発スピードの向上、安全な更新、削除を実現するための仕組を提供することが主な目的 用して、開発スピードの向上、安全な更新、削除を実現するための仕組を提供することが主な目的

    実行環境 A 実行環境 B 実行環境 A+ 新しいコンテナ 削除 ( 削除してもすぐに戻せる ) Developer OS ハードウェア コンテナ Docker コンテナ型 仮想化 (Dokcer)
  87. カーネル ハードウェア 実行環境 A プロセス カーネル ハードウェア 実行環境 仮想マシン OS

    プロセス プロセス 実行環境 ◦ メリット • ゲスト OS を選べる (Linux , Windows) • マイグレーションなど柔軟なリソース管理が可能 ▲ デメリット • ハードウェアの機能も利用するためハードウェアが限定される場合がある • 起動に時間がかかる • サイズが大きい ◦ メリット ▲ デメリット • 別種類の OS を起動できない (Linux 上で Windows 環境を実行できない ) □ 用途 □ 用途 • サーバー集約、コスト削減、長期利用 • 使い捨ての環境、大量に同じ環境を作成するなどの クラウド基盤等でのサービス提供に適している • DepOps , マイクロサービスの実現 • 起動が速い • 軽量 ( 必要なメモリ、領域のサイズが小さい ) • ポータビリティに優れている 仮想環境といっても用途が違う! ( コンテナを利用してサーバ集約といったことは可能だが本来の用途ではない ) サーバー仮想化 コンテナ仮想化 サーバ仮想化とコンテナ仮想化の比較
  88. Thank you