Docker の仕組みについて勉強しよう #dockerbg

Docker の仕組みについて勉強しよう #dockerbg

E6727b541b294abc62c3dca7cbeb4ab4?s=128

dockerbg

June 20, 2019
Tweet

Transcript

  1. Docker の仕組について勉強しよう 『 Docker/Kubernetes 実践コンテナ開発入門』読書会 特別編

  2. このセッションの趣旨 最近、 Docker ( コンテナ ) を利用した開発やシステムが脚光を 浴びていて、実際に勉強したり、試したりしているが、 なぜコンテナなのか、 Docker

    は実際どのように動いているの かよく理解できず、開発してても、もやもや感がはんぱない。 最近のアプリ開発はうといが、 Linux などの基盤技術は、まあま あ知っている スピーカーが、 Docker をとりまく基盤技術と Docker の動作概要を説明していくので、一緒に確認しながら勉 強しよう!
  3. スピーカー 自己紹介 名前 : Kenji Fujii ( 藤井 健治 )

    所属 : Red Hat 職種 : テクニカルサポート 出身 : 広島 しまなみ方面 趣味 : お酒 ( 最近 ), ランニング ( ダイエット ), ドライブ ( バイク ), 野球 このセッションは、会社を代表しての説明ではありません。 あくまで勉強会で勉強している参加者による一つの見解と説明になります。
  4. セッション前の確認

  5. お手元の PC で Docker が利用できる環境があれば、 Linux 製品 ( ディストリビューション )

    の種類を確認してみてください。 セッションの中のコマンドを試しながら行うと理解が進むかもしれません。 ( 一部のコマンドは、 RHEL でしか提供していないものもあるのでその辺りはご了承ください ) Linux のバージョンを確認 Docker は元々、 Linux 上で動作することが前提のツールのため、 Linux 以外の環境 (WIndows, Mac) でも、仮想マシンを利用して Linux を起動して Docker を利用しています。 Windows 上で直接動作する Docker も現在は存在 ( 後で説明予定。。 ) # 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. プログラムが OS(Linux) で動作する簡単なおさらい

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

    Windows も Linux も原理は同じでこの構成で コンピューターを制御して処理を実行 OS と プロセス デスクトップ画面やコンソールもプロセスの 一つ (クリックやキーボードの入力をまっている ) Apach や Nginx といった サーバープロセス アプリケーションが実行されると、 OS はプロセスとして管理、実行 します
  8. Linux 上では、 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 :
  9. Linux では、 /proc/ 配下のファイルから カーネルが管理しているプロセス 情報を参照したり、カーネルパラメータの変更 ( チューニング ) が可能

    プロセスの確認 # pidof dockerd 4011 # cat /proc/4011/status Name: dockerd 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 コマンドベースで確認やチューニングが可能
  10. Linux でプログラムが実行される流れを理解

  11. カーネル ハードウェア プロセス Linux コマンドを実行する際のプロセスの流れ # # 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) 子プロセス 出力
  12. プログラムを実行するのに必要なものを考える # python test.py Hello! プログラムがコマンドであれば、 そのコマンドだけがあれば動作するように思えるが。。 / ├── bin

    ├── dev ├── etc ├── home ├── lib ├── media ├── mnt ├── op ├── proc ├── root ├── run ├── sbin ├── srv ├── sys ├── tmp ├── usr └── var プログラムが動作するためには、ライブラリや設定ファイルなどが必要 ライブラリを置くディレクトリ
  13. 実行環境 カーネル ハードウェア /var/lib/ --- ライブラリ /usr//bin --- プログラム /etc

    --- 設定ファイル /var/log --- ログ出力先 /var/data --- データ プロセス プロセス 広義の OS ( カーネルと実行環境 ) プログラムを実行するには OS と 実行環境が必要 (OS の種類 ) Ubuntu RHEL Windows Mac
  14. コンテナを理解する

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

    LIBS App1 プロセス OS コンテナ LIBS App3 プロセス LIBS App2 プロセス コンテナ
  16. 隔離した空間などは kernel 標準 機能で実現 Namespaces Namespaces cgroup SElinux Linux カーネル

    コンテナ コンテナ コンテナ コンテナ コンテナ コンテナ ハードウェア 名前空間 1 名前空間 2 プロセス プロセス プロセス Kernel 標準の Namespaces , cgroup , SElinux 機能を利用してコンテナを実現
  17. コンテナの実体 コンテナの実体は基本的に、実行したいアプリケーションが含まれるている実行環境を コンテナごとに用意して、隔離されるように実行したもの コンテナには、起動、停止、削除 の状態が存在する ( プロセス起動、停止、実行環境の削除に相当) コンテナが起動すると、他のコンテナ空間や領域は基本的に参照できません。 ( この仕組は

    Linux の機能で提供 ) 実行環境 A プロセス カーネル ハードウェア 実行環境 A 実行環境 B 実行環境 B プロセス 起動 起動 プログラムを実行するには OS と 実行環境が必要 (P12) ↓ コンテナ環境の場合はコンテナごと実行環境を用意し OS は同じものを利用
  18. コンテナを手で作る場面を考えてみる

  19. コンテナ環境を手でつくると仮定した際の流れ 1. まず、コンテナごとの実行環境のベースとなる実行環境イメージを用意 実行環境 A 実行環境 B /var/lib/ --- ライブラリ

    /usr//bin/A --- A プログラム /etc --- 設定ファイル /var/log --- ログ出力先 /var/data --- データ /var/lib/ --- ライブラリ /usr//bin/B ---B プログラム /etc --- 設定ファイル /var/log --- ログ出力先 /var/data --- データ これは、動作させたいプロゴラムが必要な実行環境を用意して、 tar で固めたものにな ります。 # cd /appl # ls bin etc lib run srv tmp var dev home media opt root sbin sys usr # tar cvf A.tar.xz . Docker で image をダウンロードしますが、これも実質は 実行環境を tar で固 めたようなもの。 ( メタデータとか差分データも含まれて違いはありますが )
  20. コンテナ環境を手でつくると仮定した際の流れ 2. コンテナを実行したいホストで、コンテナごとのディレクトリを用意して 実行環境を展開 (tar ファイルを展開 ) / ├── bin

    ├── dev ├── etc ├── lib ├── media ├── mnt ├── op ├── proc ├── root ├── run ├── sbin ├── srv ├── sys ├── tmp ├── usr └── var └── lib └── container │── myApp1 │ │ │ │ │ │── myApp2 ホスト /var/lib/ --- ライブラリ /usr//bin/A – A プログラム /etc --- 設定ファイル /var/log --- ログ出力先 /var/data --- データ /var/lib/ --- ライブラリ /usr//bin/A – B プログラム /etc --- 設定ファイル /var/log --- ログ出力先 /var/data --- データ
  21. コンテナ環境を手でつくると仮定した際の流れ 3. コンテナを実行したい環境に chroot / ├── bin ├── dev ├──

    etc ├── lib ├── media ├── mnt ├── op ├── proc ├── root ├── run ├── sbin ├── srv ├── sys ├── tmp ├── usr └── var └── lib └── container │── myApp1 │ │ │ │ │ │ ホスト /var/lib/ --- ライブラリ /usr//bin/A – A プログラム /etc --- 設定ファイル /var/log --- ログ出力先 /var/data --- データ # chroot /var/lib/container/myApp1/ chroot することで、 /var/lib/container/myApp1/ が / にな りホスト上のそれ以外のフィルが見えなくなります。 # cd / # tree / ├── etc ├── user │ └── bin │ └── A └── var ├── data ├── lib └── log
  22. コンテナ環境を手でつくると仮定した際の流れ 4. 実行したいプログラムを名前空間を変えて実行 (unshare コマンド ) / ├── bin ├──

    dev ├── etc ├── lib ├── media ├── mnt ├── op ├── proc ├── root ├── run ├── sbin ├── srv ├── sys ├── tmp ├── usr └── var └── lib └── container │── myApp1 │ │ │ │ │ │ ホスト /var/lib/ --- ライブラリ /usr//bin/A – A プログラム /etc --- 設定ファイル /var/log --- ログ出力先 /var/data --- データ # unshare -i -n -p -m -f /usr/bin/A カーネル ハードウェア プロセス /usr/bin/A /bin/ bash 名前空間を変えて実行 実行環境 A /usr/bin/A 隔離されたコンテナが起動 実行環境 A 実行環境 A
  23. コンテナを隔離するための機能

  24. Namespace について # 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 から確認できます。 通常であれば、システムのどのプロセスも同じ名前空間 ( 同じ値)を持っています。 コンテナでは、各コンテナプロセスごとに違う値を持っています。 (user 現在利用されていなので除く ) RHEL などでは、 unshare コマンドで namespace を変更することが可能。 Docker では、もちろん unshare などではなく、 namespace を変更する機能を実装しています。 ▪ プロセス隔離の仕組み (Namespace について )
  25. Namespace について # pidof dockerd 4532 # ls -tlr /proc/4532/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] Dockerd と 自分のシェルの名前空間が同じか確認しみましょう ▪ 実際に確認してみる # 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] $$ は自身の PID が入っている環境変数 名前空間が同じ
  26. Namespace について # pidof dockerd 4532 # ls -tlr /proc/4532/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] Dockerd と コンテナで起動する sleep コマンドプロセスが 違う名前空間であることを確認 ▪ 実際に確認してみる # docker run -d alpine sleep 120 84e219be2ccc7313f9552abbe301c0bd948dd6e446a148e5b913133f0677f488 # ps -ef | grep sleep root 6078 6062 0 16:23 ? 00:00:00 sleep 120 # ls -tlr /proc/6078/ns/ total 0 lrwxrwxrwx. 1 root root 0 6 月 19 16:23 net -> net:[4026532217] lrwxrwxrwx. 1 root root 0 6 月 19 16:23 uts -> uts:[4026532213] lrwxrwxrwx. 1 root root 0 6 月 19 16:23 user -> user:[4026531837] lrwxrwxrwx. 1 root root 0 6 月 19 16:23 pid -> pid:[4026532215] lrwxrwxrwx. 1 root root 0 6 月 19 16:23 mnt -> mnt:[4026532212] lrwxrwxrwx. 1 root root 0 6 月 19 16:23 ipc -> ipc:[4026532214] 名前空間が違う!
  27. Linux では以前からコンテナを利用できましたが、あまり利用さていませんでした。 (google などごく一部だけ ?) Docker 以前もコンテナは利用可能 理由 ツールの不足で扱いずらい 認知不足

    使用することのメリットがあまり感じられなかった ( 大規模向き ) など
  28. Docker の 登場

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

    ハードウェア ハードウェア コンテナ コンテナ仮想環境 カーネル Docker Docker は、単にコンテナを作成、実行、管理 できる機能を提供するのではなく、 この仕組を開発で利用し、これまでの開発フローを見直すための仕組やアイディアも提供
  30. Docker アーキテクチャと特徴 ※ 最近では runc など Docker デーモン(常駐プロセス ) でない構成もあります

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

  32. Docker( コンテナ ) は、 DevOps 、マイクロサービスなどを実現するための仕組を提供 A B 実行環境 本番

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

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

  35. 基本コマンド (docker pull) の流れを確認 イメージ レジストリ LIBS APP イメージ 実行環境

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

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

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

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

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

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

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

    # 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 FROM イメージがローカルになれば レポジトリからイメージ をダウンロー ドし、 /var/lib/docker/overlay2 など 所定の場所に一意の名前のディレ クトリ配下に 展開されます。 (tar の中身が展開と同様 ) /var/lib/ --- ライブラリ /usr//bin/A – A プログラム /etc --- 設定ファイル /var/log --- ログ出力先 /var/data --- データ
  43. 基本コマンド (docker build) で作成したイメージを実行 (run) するまで の流れを確認 ( 3 )

    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 RUN 展開された領域でコマンドを実行します。ここでは mkdir /work /work ディレクトリが作成されます /var/lib/ --- ライブラリ /usr//bin/A – A プログラム /etc --- 設定ファイル /var/log --- ログ出力先 /var/data --- データ /work 作成
  44. 基本コマンド (docker build) で作成したイメージを実行 (run) するまで の流れを確認 ( 3 )

    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 COPY Docker コマンドで指定した . ( カレントディレクトリ)に存在するフィルを展 開したコピーします。 ここでは、 hello.py を 展開された領域に作成された /work 配下にコピー され /work/hello.py が作成されます /var/lib/ --- ライブラリ /usr//bin/A – A プログラム /etc --- 設定ファイル /var/log --- ログ出力先 /var/data --- データ /work hellop.py コピー
  45. 基本コマンド (docker build) で作成したイメージを実行 (run) するまで の流れを確認 ( 3 )

    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 CMD コンテナ起動時に実行するコマンドを指定します。 Build 時には、ここに記載した内容が、メタ情報ファイルに記録されます /var/lib/ --- ライブラリ /usr//bin/A – A プログラム /etc --- 設定ファイル /var/log --- ログ出力先 /var/data --- データ /work CMD の内容 を記録 メタデータ
  46. 基本コマンド (docker build) で作成したイメージを実行 (run) するまで の流れを確認 ( 4 )

    # docker inspect test "Cmd": [ "/bin/sh", "-c", "#(nop) ", "CMD [\"python\" \"/work/hello.py\"]" ], 4. build コマンドが正常に作成したら、 CMD がメタ情報に記録されていることは以下のコマンドで確認できます。
  47. 基本コマンド (docker build) で作成したイメージを実行 (run) するまで の流れを確認 ( 5 )

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

    ├── srv ├── sys ├── tmp ├── usr └── var └── lib └── docker │ ── overlay2 ── │ xxxxxxxxxxxxx # docker commit コンテナ名 1. コンテナ内で変更た際に、それをイメージとして残したい場合は、 commit をすることで新しいイメージが作成されるが、 この際のイメージは、ベースとなるイメージから、変更した分の差分だけがイメージとして作成 つまり、新しいイメージを参照する際は、ベースイメージ + 差分イメージ といった階層 ( レイヤ)イメージで Docker は扱います。 xxxxxxxxxxxxx ベースイメージ 差分イメージ ( ベースと差分で ) 新しいイメージ
  49. docker save コマンドで、変更を加えているイメージでは レイヤごとの tar で構成されている( tar ファイルが増えている ) ことを確認してみる

    # 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
  50. # tar tvf alpine.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 docker save コマンドで、変更を加えているイメージでは レイヤごとの tar で構成されている( tar ファイルが増えている ) ことを確認してみる 7. ベースと新しいイメージファイルの中の比較 ( 差分が増えていることを確認 ) 増えている
  51. docker save コマンド と docker export の違い # 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 images # docker export コンテナ ID > export # 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 して作成したイメージは、差分が ないシングルレイヤの状態になります。
  52. Docker の その他コマンド

  53. 基本コマンド (docker info コマンド ) # 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 環境の状況が確認できます。
  54. 基本コマンド (docker inspect コマンド ) # 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 コマンドで、イメージやコンテナのメタ情報が確認できます。
  55. Docker 補足

  56. コンテナ 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 のオプション
  57. 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 sav e tar tar tar tar コンテナ内のフ ァイルシステ ムを tar で 1 つ にしたファイ ル イメージ内の差分情報をファイ ル (tar) にしてそれをアーカイブ した tar ファイル build LIBS APP イメージ export された tar からできた 新しいイメージ import start stop コンテナ イメージ kill docker コマンド遷移図
  58. コンテナ 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 のネットワーク
  59. イメージレイヤーでコンテナの差分管理を実現するには、 Storage Driver を 利用しますが、 Docker では Storage Driver を選択できるようになっています。

    "aufs", "btrfs", "zfs", "devicemapper", "overlay", "vfs", 最近のデフォルト (RHEL7.6 現在 ) Namespaces Namespaces cgroup SElinux Linux カーネル ハードウェア Overlay ストレージレイア イメージレイヤー Docker デーモン Docker クライ アント libcontainer コンテナ
  60. Cgroup について 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 クライアント コンテナ
  61. サーバー仮想化とコンテナ仮想化

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

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

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

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

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

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