たかおLab

Docker入門

プログラミング

Dockerとは?

 

Docker is an open platform for developing, shipping, and running applications. Docker enables you to separate your applications from your infrastructure so you can deliver software quickly.

 

 

Dockerの構成要素

 

・Docker Engine … コンテナ仮想化技術。アプリケーションの構築からコンテナ化に至るワークフローを連結

・Docker Hub … 作ったアプリケーション群を共有・管理するSaaSサービス

 

その他、Dockerの概要は以下のURL

http://docs.docker.jp/get-started/overview.html

 

Dockerfile では、コンテナ内の環境で何をするかを定義する

http://docs.docker.jp/engine/tutorials/dockerizing.html

 

 

Dockerクライアントを使ってみる

 

docker run でコンテナを実行しています。

 

・「ubuntu」は実行するイメージ。実行すると、ホスト上にそのイメージがあるかどうか確認し、なければDocker hubから自動でイメージをpullします。

また、イメージによっては複数の派生イメージがある場合があり、それぞれの違いをタグで識別します。

今回はUbuntu14.04を使っていますが、Ubuntu12.04を使いたい場合は、ubuntu:12.04 と書きます。

何もタグを指定しなければ、標準で ubuntu:latest が使用されます。

 

・「/bin/echo」は新しく立ち上がったコンテナ内で実行されるコマンド。

つまり、コンテナが起動したらDockerが新しいUbuntu環境を作成し、その中で /bin/echo を実行し、結果として Hello, world を出力したのち、直ちにコンテナが停止します。

 

・「-t」は新しいコンテナ内に擬似ターミナル(pseudo-tty)を割り当てます。

 

・「-i」はコンテナの標準入力(STDIN)を取得し、双方向に接続できるようにします(正確には標準エラー STDOUT も含めた標準入出力を扱う)。

 

・「/bin/bash」はコンテナ内でBashシェルを起動します。終了させるには exit または Ctrl-D を実行。

 

・「-d」はバックグラウンドで(デーモン化して)コンテナを実行します。

出力は hello, world ではなく、コンテナIDを表示されています。

 

以下のコマンドで、実行中のコンテナを確認できます。

・コンテナに自動で割り当てられた名前は「insane_babbage」

 

これで、コンテナが実行中だと確認できましたが、実行時に指定した処理が正しく行われているか確認できていません。

コンテナの中でどのような処理が行われているか確認するには、 以下のコマンドを実行します。

・デーモンとして動いているのが確認できます。Docker化したアプリケーションの作成に成功です。

 

デタッチド・コンテナ(バックグラウンドで動作しているコンテナ)を停止するには、

 

その後、もう一度、docker psコマンドで確認すると、停止しているのが確認できます。

 

ここまで、ターミナル上で毎回「docker」と入力してきましたが、これが Docker クライアントです。

クライアントとはシンプルなコマンドライン・クライアントであり、コマンドライン・インターフェース(CLI)とも呼びます。

 

Dockerでウェブアプリケーションを実行

 

ここまではdockerクライアントについて学んできましたが、次は多くのコンテナの実行についてです。

これまで実行したコンテナのほとんどは、特に役立つ処理を行わないませんでしたが、今度はDockerを使ったウェブアプリケーションを実行してみましょう。

 

ウェブアプリケーションとして、PythonのFlaskを実行してみます。

・「-P」はコンテナ内部のネットワークで必要なポートをホスト側に割り当てます。これにより、ウェブアプリケーションを参照できるようになります(後述)。

 

・「training/webapp」は既存のイメージで、Flaskが入っています。

 

・最後にコンテナに対して「python app.py」というコマンドを指定することでFlaskが起動します。

 

docker ps で確認すると、PORTS 列に以下の情報が追加されています。

先ほどのコマンドで -P フラグを指定しましたが、これにより Dockerはイメージからホスト側に対して必要なポートを露出します。

今回の場合、コンテナのポート5000(Flaskの標準ポート)をホスト上のポート49115に公開しています。

 

ポートの割り当て設定は変更可能で、今回の例では、-P が -p 5000 を指定するショートカットに当たります。

これは、「コンテナの中のポート5000を、ホスト上のハイポート(典型的な 32768~61000 の範囲にある一時利用ポート)に割り当てる」という意味です。

 

あるいは以下のように、「-p」でポートの指定も可能です。

これは、ホスト上のポート80を、コンテナ内のポート5000に割り当てています。

 

それでは、localhost:49155 にアクセスしてみましょう。

Pythonアプリケーションが動いているはずです。

 

割り当てたポートを確認するのに docker ps コマンドを使ってもいいですが、 docker port を使った方が便利です。

今回、コンテナに自動で割り当てられた名前は「nostalgic_morse」だったので、

 

前回同様、docker logs コマンドでアプリケーションに何が起こっているのか見ることができます。

・「-f」は、tail -f コマンドのように、コンテナの標準出力を見るものです。ここではポート5000 で動作しているFlaskに対する接続ログを表示しています。

 

ログに加え、「docker top」コマンドを使えば、内部で実行しているプロセスを確認できます。

 

「docker inspect」コマンドを使えば、指定したコンテナに対する情報(IPアドレスなど)をJSON形式で得られます。絞り込みも可能。

 

実行後、次のようなJSONが出力されます。

 

コンテナを停止したいときは、

 

停止後、このコンテナを元に戻したい場合は、

 

コンテナを削除したいときは、停止してから、

 

今回はコンテナに自動で名前(nostalgic_morse)が付けられましたが、「 –name」フラグを使えば、自分でもコンテナに名前を付けられます。

こうすれば、「web」というコンテナ名を付けられます。

 

注意点として、コンテナ名はユニークでなければなりません。つまり、web と呼ばれるコンテナはただ一つしか使えません。もし同じコンテナ名を再利用したいならば、古いコンテナを削除する必要があります。

 

 

ここまではDocker Hubからダウンロードしたイメージのみ使っていましたが、今度は自分でイメージを構築し、共有してみましょう。

 

Docker はダウンロードしたイメージをホスト上に保管しており、それらを見ることができます。

もしホスト上にイメージがなければ、Docker はレジストリ(標準のレジストリは Docker Hub)からイメージをダウンロードします。

 

ホスト上にあるイメージの一覧は、

 

ここで、リポジトリとイメージという用語について。

リポジトリとは、名前は同じだがタグは異なる集合。イメージとは、リポジトリ名+タグ のこと。

以下の例の場合、

・リポジトリは、「docker/whalesay」と「hello-world」

・イメージは「fb434121fc77」「91c95931e552」「1234abcd5678」。 2行目と3行目はImage IDが同じであるため、同じイメージであることに注意

 

新しいイメージはコンテナ起動時に自動でダウンロードされますが、あらかじめイメージをダウンロードしたい場合は、「docker pull 」コマンドを使用する。

 

イメージは、いろんな人によって作られていて、Docker Hubのウェブサイトから検索できます。

また、以下のようにdocker searchコマンドでも検索できます。

表示されるのは、イメージ名の一覧、スター(イメージがソーシャル上で有名かどうか測るもの。利用者はイメージを気に入れば”スター”を付けられる )、公式(OFFICIAL)か、自動構築(AUTOMATED)といった状態です。公式リポジトリ とは、Docker 社のサポートよって丁寧に精査されている Docker リポジトリです。自動構築(Automated Build) とは有効なソースコードを元に、イメージ内容が自動構築されたリポジトリです。

 

training/sinatra イメージはユーザ・イメージで、 Docker コミュニティのメンバーに属するもので、メンバーによって構築、メンテナンスされる。ユーザ・イメージは、常にユーザ名がイメージの前に付く。この例のイメージは、training というユーザによって作成されている。

 

対して、ubuntu のようなイメージはベース・イメージまたはルート・イメージと呼ばれる。このベース・イメージは Docker 社によって提供、構築、認証、サポートされていて、単一の単語名として表示される。

 

自分でイメージをカスタマイズする方法には、作成・更新の2つの方法がある。

まずは更新について。イメージから作成したコンテナを更新し、イメージの結果をコミットする。

 

docker commitコマンドで、イメージに対してこのコンテナのコピーをコミットできる。

-m はコミット・メッセージを指定するもの。

-a は更新を行った担当者を指定するもの。

また、新しいイメージを作成する元となるコンテナを指定する。ここでは 0b2616b0e5a8 が相当する。

そして、ターゲットとなるイメージを指定する。ここでは ouruser/sinatra:v2 が相当する。ouruser は新しいユーザ名で、このイメージを書いた人。sinatra はイメージ名。最後に、イメージに対するタグ v2 を指定している。

docker images を使えば、今作成したイメージを確認できる。

作成したイメージを使ってコンテナを作成するには、次のようにする。

 

ここまで、docker commit でイメージを簡単に拡張したが、他のメンバーと共有するには少し不便です。

今回は docker build を使って構築する方法や、イメージをゼロから作成する方法を見ていきます。

 

Dockerfileに、Dockerがどのようにしてイメージを構築するのか、命令セットを記述します。

作成するにはまず、ディレクトリとDockerfileを作成します。

 

以下は、Dockerfile の中身の例です。

冒頭のFROM命令は、Dockerに対して基となるイメージを指定する。

MAINTAINER命令は、誰がこの新しいイメージを管理するか指定する。

最後のRUN命令は、イメージの中で実行するコマンドを指定する。この例ではパッケージのインストールのために、まずはAPTキャッシュを更新し、それから Ruby と RubyGem をインストールし、Sinatra gem をインストールする。

 

また、apt-get update と apt-get install は1行で記述することが推奨されています。
Dockerfileの記述に関する他の推奨内容は、ベストプラクティスを確認してください。

 

あとは、この Dockerfile を用い、docker build コマンドでイメージを構築する。

-t は、新しいイメージがユーザ ouruser に属していること、リポジトリ名が sinatra、タグを v2 に指定している。

また、.(ドット)は使用する Dockerfile の場所を示している。パスの指定もできる。

 

以上で構築プロセスが進行します。まず Docker が行うのは構築コンテクスト(環境や内容物)のアップロードです。典型的なコンテクストとは、構築時のディレクトリです。この指定によって、Docker デーモンが実際のイメージ構築にあたり、ローカルのコンテクストをそこに入れるために必要とします。

この次は Dockerfile の命令を一行ずつ実行します。それぞれのステップで、新しいコンテナを作成し、コンテナ内で命令を実行し、変更に対してコミットするのが見えるでしょう。これは先ほど見た docker commit 処理の流れです。全ての命令を実行したら、イメージ 97feabe5d2ed が残ります(実行時の -t フラグにより、扱いやすいよう ouruser/sinatra:v2 とタグ付けもしています)。そして、作業中に作成された全てのコンテナを削除し、きれいに片付けています。

 

あとは、新しいイメージからコンテナを作成できる。

また、カスタマイズ後のイメージに対しても、docker tagコマンドでタグ付けができます。

 

イメージをカスタマイズした後は、docker pushコマンドを使って Docker Hub に送信できる。これにより、イメージを他人と共有したり、あるいはプライベート・リポジトリにも送信できる。

不要になったホスト上のイメージは、docker rmiコマンドで削除ができる。

 

 

ここまで、イメージの作成について見てきたが、次からはコンテナ同士を通信させるためのネットワークについて解説する。

 

Docker は ネットワーク・ドライバ を使うことで、コンテナのネットワーク(連結や接続する機能)をサポートします。標準では、Docker は bridge (ブリッジ) と overlay (オーバレイ) の2つのネットワーク・ドライバを提供します(一応、自分でネットワーク・ドライバ・プラグインを書き、その自分のドライバでネットワークを作成することも可能)。

ブリッジ・ネットワークは、単一ホスト上で実行している Docker Engine でしか使えない制限があります。オーバレイ・ネットワークは複数のホストで導入でき、高度な使い方ができます。

Docker Engine は、自動的に3つのデフォルト・ネットワークをインストールします。特に指定しなければ、常にbridgeネットワーク上にコンテナを起動します。

 

bridgeネットワークは作成することもできます。

-d は、新たなネットワークに対応するbridgeドライバを利用するためです。しかし、デフォルト値はbridgeになっているので、今回は指定しなくても構いません。

 

以下のコマンドで、ネットワークの一覧を確認できます。

 

ネットワークの中身を確認してみると、中には何も入っていないことがわかります。

 

コンテナの初回起動時に、同時にネットワークへコンテナを追加することができます。

 

同じネットワーク内でコンテナを実行すると、コンテナ同士で通信することができます。

稼働中のコンテナであっても、以下のコマンドでネットワークに接続することができます。

 

db コンテナのシェルを再び開き、ping コマンドを試してみます。

 

 

ここまで、コンテナのネットワークについて見てきました。

次からは、コンテナ内やコンテナ間でのデータ管理について学びます。

それでは、Docker Engine でデータを管理するための、主な手法2つを見ていきます。

・データ・ボリューム

・データ・ボリューム・コンテナ

 

データ・ボリュームとは、1つまたは複数のコンテナ内で、特別に設計されたディレクトリです。

・ボリュームはコンテナ作成時に初期化される。コンテナのベース・イメージ上で、特定のマウント・ポイント上のデータが指定されている場合、初期化されたボリューム上に既存のデータをコピーする。
・データ・ボリュームはコンテナ間で共有・再利用できる。
・データ・ボリュームに対する変更を直接行える。
・イメージを更新しても、データ・ボリューム上には影響はない。
・コンテナ自身を削除しても、データ・ボリュームは残り続ける。

 

docker create か docker run コマンドで -v フラグを使えば、コンテナにデータ・ボリュームを追加できます。-v を複数回使うことで、複数のデータ・ボリュームをマウントできます。以下は、コンテナの中に /webapp という新しいボリュームを作成します。

Dockerfile では、VOLUME命令を使って作成できます。

 

docker inspect コマンドで、ホスト上でボリュームが使っている場所を探せます。

ホスト上の場所にあたるのは、上の “Source” です。コンテナ内のボリューム指定は “Destination” です。RW の表示は、ボリュームの読み書き可能を意味します。

 

また、ホスト上のディレクトリをコンテナ内のパスにマウントすることもできます。

このコマンドは、ホスト上の /src/webapp をコンテナ内の /opt/webapp にマウントします。パス /opt/webapp が既に存在している場合でも、/src/webapp を重複マウントします。しかし、既存の内容は削除しません。マウントを解除したら、再度アクセスが可能になります。

 

Mac または Windows でDocker を使う場合は、自動的に /Users(OS X)または C:\Users(Windows)のマウントを試みます。つまり、OS X上で使っているファイルやディレクトリをマウント可能です。

ホスト上のディレクトリはホストに依存する性質があるため、Dockerfile でマウントできません。これは、「イメージの構築はどこでも実行可能な状態であるべき」という考えからです。

 

ホスト上のディレクトリだけでなく、単一のファイルに対してもマウント可能です。

以下のコマンドでは、コンテナ内のbashシェルをホストに流し込むものです。

コンテナを終了する時に、ホスト上の bash 履歴に対して、コンテナ内で実行したコマンドを履歴として記録します。

 

次に、データ・ボリューム・コンテナについてです。データに永続性を持たせたい場合(例えばコンテナ間での共有や、データを保持しないコンテナから使うなど)には、名前をつけたデータ・ボリューム・コンテナを作成し、そこにデータをマウントするのが良い方法です。

http://docs.docker.jp/engine/tutorials/dockervolumes.html

 

http://docs.docker.jp/engine/tutorials/dockerrepos.html

 

 

 

 

 

 

 

Dockerfileは、たいていは空のディレクトリに配置するのが適当です。 その後にそのディレクトリへは、Dockerfile の構築に必要となるファイルのみを追加します。 ビルドの効率をよくするために、ファイルやディレクトリを除外指定する .dockerignore ファイルをそのディレクトリに置く方法もあります。 .gitignoreと同様の除外パターンの指定方法。

 

また、当たり前だが、不要なパッケージはインストールしない方がいい。例えば、データベースイメージにテキストエディタは必要ない(あれば便利かもしれないが)。

 

アプリケーションを複数のコンテナに分けることにより、スケールアウトやコンテナの再利用が行いやすくなります。そのため、絶対ではないが、一つのコンテナには一つのプロセスだけ実行すべき。

 

複数行にわたる引数は、できるなら後々の変更を容易にするために、その並びはアルファベット順にしましょう。以下のように見やすくなる。

 

 

https://qiita.com/zaki_taka4/items/9d330556542c665b011c

 

https://www.it-swarm.dev/ja/docker/%E3%82%A4%E3%83%A1%E3%83%BC%E3%82%B8%E3%81%A8%E3%83%AA%E3%83%9D%E3%82%B8%E3%83%88%E3%83%AA%E3%81%AE%E9%81%95%E3%81%84%E3%81%AF%E4%BD%95%E3%81%A7%E3%81%99%E3%81%8B%EF%BC%9F/1054767954/