こんにちは。takapy(@takapy0210)です。
本記事は、転職カウントダウンカレンダー 2日目の記事です。
- はじめに
- ホスト型仮想化とコンテナ型仮想化の違い
- Docker for Macについて
- Dockerコンテナの実行
- Docker Hubとは
- Dockerイメージとは
- 自分でDockerイメージファイルを作成する
- DockerHubにイメージをPushする
- コンテナを起動してみる
- ホスト上のディレクトリをコンテナにマウントする
- コンテナのライフサイクル
- コンテナのシェルへの接続
- コンテナを停止・削除する
- 参考
はじめに
次の職場ではDockerを利用してサービス運用をしているため、事前に知識を蓄えておいた方が良いだろうということで勉強しています。機械学習エンジニアでも学習基盤の知識・インフラ面の知識という部分は身につけておいて損はないと思っていたりします。
本記事では、Dockerのインストールから、Dockerイメージの作成、DockerHubへのプッシュ、コンテナのシェルへの接続方法などについて記載しています。内容が多くなりそうなので、数回に分けてまとめようと思います。
初心者ゆえ内容に誤りがある可能性もありますが、ご了承ください。
ホスト型仮想化とコンテナ型仮想化の違い
仮想化のオーバーヘッド
従来の仮想化(ホスト型仮想化)
リソース(CPUや使用率など)の面でオーバーヘッドが多く、起動や停止にも時間がかかります。
コンテナ型仮想化
コンテナはアプリケーション実行に必要なものだけを含み、ホストOSのカーネルを使用するため、動作が早くリソースの使用率も少なくて済みます。
アプリケーション実行の再現性
従来の仮想化(ホスト型仮想化)
仮想マシンの環境の違いにより、アプリケーションが動作しなくなる可能性があります。
コンテナ型仮想化
特定のアプリケーションを動作させるために必要なものは、後述するDockerイメージにまとまっており、同じDockerイメージからコンテナを起動する限り、環境が異なっていても同様に動作します。ステージング環境では動作するけど、本番環境で動作しないという心配事がなくなるのはとてもメリットが大きいと感じました。
OSの自由度
従来の仮想化(ホスト型仮想化)
仮想マシン上で任意のOSを動作させることができます。(Windows上の仮想環境にLinuxをインストールするなど)
コンテナ型仮想化
コンテナはホストOSのカーネルを使用して動作するので、WindowsOS上で直接Linuxコンテナは動作させることはできません。また、反対にLinuxOS上で直接Windowsコンテナも動作させることはできません。(これは一般的なコンテナ型仮想化の話でDockerの話ではありません)
分離レベル
従来の仮想化(ホスト型仮想化)
ハードウェアレベルで仮想化されており、ホストOSや仮想マシン間の分離レベルが高く、それぞれが影響を受けにくいいです。
コンテナ型仮想化
OS上の1プロセスとして動作するコンテナ型仮想化は、従来の仮想化に比べて分離レベルは低いです。要求されるセキュリティレベルの度合いによっては1つの懸念点となる可能性もありそうですが、ホスト型仮想化・コンテナ型仮想化のいずれにせよ、侵入されにくい設定や構成にする必要があります。
Docker for Macについて
DockerはそもそもLinux環境で動くのものであり、MacOSやWindowsOS上ではVirtualBoxなどVMを立てて動かすものです。MacでDockerをサポートするツールという位置付けでDocker for Macがあります。
インストール
Docker公式HPからインストールが行えます。この辺の記事はWeb上にたくさんあるので省略します。
Docker for Mac上でコンテナがどのように動作しているのか
冒頭でも述べましたが、MacOS上で直にコンテナが動作するのではなく、実際にはHyperKitというMacネイティブの仮想化環境が裏で動いています。こいつが軽量なLinuxを動作させ、その上でコンテナが動作しています。
Dockerコンテナの実行
hello-worldコンテの実行
下記コマンドをターミナル上かた実行し、hello-worldというイメージを取得してコンテナを起動してみます。
$ docker run hello-world ~~~~ Hello from Docker! This message shows that your installation appears to be working correctly. To generate this message, Docker took the following steps: 1. The Docker client contacted the Docker daemon. 2. The Docker daemon pulled the "hello-world" image from the Docker Hub. (amd64) 3. The Docker daemon created a new container from that image which runs the executable that produces the output you are currently reading. 4. The Docker daemon streamed that output to the Docker client, which sent it to your terminal. ~~~~
上記ステップを図で表すと下記のようになります。
初回実行時、「hello-world」イメージはローカルに存在していないため、Docker Hubまで取得しにいきます。2回目以降の実行ではローカルにイメージがあるため、②、③の手順は省略されます。
docker runコマンドは何をしているのか
$ docker runコマンドは、分割すると下記3つのコマンドを実行していることと同じになります。
$ docker pull:イメージの取得
$ docker create:コンテナの作成
$ docker start:コンテナの起動
Docker Hubとは
Dockerイメージのレジストリサービスで、Dockerイメージの公開や検索、ダウンロードが行えます。
Dockerイメージとは
コンテナ実行に必要なファイルをまとめたファイルシステムです。phpやruby、pythonの実行環境が必要となった場合に、これらのイメージからコンテナを起動すれば、すぐに動作環境を構築できたりします。
DockerイメージはAUFSという特殊なファイルシステムが使用されています。また、イメージ上のデータはレイヤで構成され、すべて読み取り専用となっています。
Dockerイメージダウンロードの動作
例としてwhalesayコンテナを実行しながら、Dockerイメージのダウンロード動作について見てみます。
whalesayコンテナとは、引数で渡した文字列をクジラのAAに喋らせることができるものです。
$ docker run docker/whalesay cowsay Hello! Unable to find image 'docker/whalesay:latest' locally latest: Pulling from docker/whalesay e190868d63f8: Pull complete 909cd34c6fd7: Pull complete 0b9bfabab7c1: Pull complete a3ed95caeb02: Pull complete 00bf65475aba: Pull complete c57b6bcc83e3: Pull complete 8978f6879e2f: Pull complete 8eed3712d2cf: Pull complete Digest: sha256:178598e51a26abbc958b8a2e48825c90bc22e641de3d31e18aaf55f3258ba93b Status: Downloaded newer image for docker/whalesay:latest ________ < Hello! > -------- \ \ \ ## . ## ## ## == ## ## ## ## === /""""""""""""""""___/ === ~~~ {~~ ~~~~ ~~~ ~~~~ ~~ ~ / ===- ~~~ \______ o __/ \ \ __/ \____\______/
実際の処理を一つずつ確認していきます。
$ docker run docker/whalesay cowsay Hello!
ここでのcowsay Hello!
は、whalesayコンテナ内で呼び出すコマンドを表しています。このように記述することで、コンテナが立ち上がった後にコマンドを実行することができます。
Unable to find image 'docker/whalesay:latest' locally
今回指定しているdocker/whalesay:latest
のイメージがローカルに存在していないことを表しています。
latest: Pulling from docker/whalesay
latestタグのイメージをDockerHubのdocker/whalesayリポジトリからPullしていることを表しています。
ローカルにあるDockerイメージ一覧を確認する
$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE hello-world latest fce289e99eb9 6 weeks ago 1.84kB docker/whalesay latest 6b362a9f73eb 3 years ago 247MB
Dcokerイメージを複製する
イメージを複製しても、IMAGE IDは変化しません。つまり、同じイメージということです。
$ docker tag docker/whalesay my_whalesay $ docker images REPOSITORY TAG IMAGE ID CREATED SIZE hello-world latest fce289e99eb9 6 weeks ago 1.84kB docker/whalesay latest 6b362a9f73eb 3 years ago 247MB my_whalesay latest 6b362a9f73eb 3 years ago 247MB
また、:tag名
を付与することで、異なるTAGをつけてイメージを複製することもできます。
$ docker tag docker/whalesay my_whalesay:ver1 $ docker images REPOSITORY TAG IMAGE ID CREATED SIZE hello-world latest fce289e99eb9 6 weeks ago 1.84kB docker/whalesay latest 6b362a9f73eb 3 years ago 247MB my_whalesay latest 6b362a9f73eb 3 years ago 247MB my_whalesay ver1 6b362a9f73eb 3 years ago 247MB
ローカルのイメージを削除する
すでにイメージからコンテナを生成してしまっている場合は、コンテナの削除をした後にイメージを削除するか、-f
オプションを付与して強制削除する必要があります。
削除時も、特にTAG指定しなかった場合はlatest
TAGが付いているイメージが削除されます。
$ docker rmi docker/whalesay Untagged: docker/whalesay:latest Untagged: docker/whalesay@sha256:178598e51a26abbc958b8a2e48825c90bc22e641de3d31e18aaf55f3258ba93b $ docker images REPOSITORY TAG IMAGE ID CREATED SIZE hello-world latest fce289e99eb9 6 weeks ago 1.84kB my_whalesay latest 6b362a9f73eb 3 years ago 247MB my_whalesay ver1 6b362a9f73eb 3 years ago 247MB
自分でDockerイメージファイルを作成する
イメージを作成するには、Dockerfileというイメージの定義ファイルを作成する必要があります。Dockerfileからイメージを作成することをイメージビルドと言ったりします。
まずはDockerfileを下記のような内容で作成します。ファイル名はDockerfile
とします。
FROM docker/whalesay:latest RUN apt-get -y update && apt-get install -y fortunes CMD /usr/games/fortune | cowsay
FROM
イメージを作成する際に、基となるイメージを指定するコマンドです。基のイメージのレイヤの上に新しいレイヤをカスタマイズして追加することができます。RUN
イメージに新しいパッケージをインストールしたりできます。CMD
コンテナ起動時に動作させたいコマンドを指定することができます。
ここまでで、イメージをビルドさせる準備ができました。
実際にイメージからビルドするコマンドは下記となります。
$ docker build -t docker-whale .
-t docker-whale
の部分はイメージ名を指定しており、末尾の.
はビルドコンテキストを指定しています。
ビルドコンテキストとは、イメージを作成する際にアクセスできるディレクトリやファイルの範囲を指定するものです。(上記ではカレントディレクトリを指定しています)イメージ内に含めたいファイルがある場合は、このビルドコンテキスト内からコピーすることが可能になります。
また、このビルドコンテキストで指定したディレクトリにあるDockerfileから、イメージを作成することになるので、Dockerfileの作成場所にも注意が必要です。
今回のDockerfileの内容だと、fortunesパッケージ
をインストールしたレイヤが1つ、cowsay
コマンドを実装したレイヤが1つ追加されるようになります。
イメージビルド後、docker images
コマンドで確認してみます。
$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE docker-whale latest ff32c5edd7f9 About a minute ago 278MB hello-world latest fce289e99eb9 6 weeks ago 1.84kB docker/whalesay latest 6b362a9f73eb 3 years ago 247MB my_whalesay latest 6b362a9f73eb 3 years ago 247MB my_whalesay ver1 6b362a9f73eb 3 years ago 247MB
docker-whale
というイメージが作成されていることが分かります。
このイメージからコンテナを起動して、動作を確認してみます。
$ docker run docker-whale _________________________________________ / P.S. Perl's master plan (or what passes \ | for one) is to take over the world like | | English did. Er, *as* English did... | | | | -- Larry Wall in | \ <199705201832.LAA28393@wall.org> / ----------------------------------------- \ \ \ ## . ## ## ## == ## ## ## ## === /""""""""""""""""___/ === ~~~ {~~ ~~~~ ~~~ ~~~~ ~~ ~ / ===- ~~~ \______ o __/ \ \ __/ \____\______/
ビルドキャッシュについて
Dockerfileによりイメージビルドすると、コマンドがキャッシュされます。このビルドキャッシュによって2回目以降のイメージビルドを高速に行うことができます。
しかし、例えば2回目以降に同じDockerfileでイメージビルドを行うとそのキャッシュが使用され、Dockerfileで記述したコマンド(例えばapt-get -y update
など)が実行さない、という問題が発生する可能性があります。
それを防ぐためには、--no-cache
オプションをつける必要があります。
$ docker build --no-cache -t docker-whale .
DockerHubにイメージをPushする
リポジトリにイメージを追加してみます。
DockerHubにターミナルからログイン
$ docker login
DockerHubにおけるタグ付けのルール
下記のようにタグ付けを行います。(タグ名は省略可能)
<Docker ID>/<イメージ名>:<タグ名>
実際にやってみます。
$ docker tag docker-whale takapy0210/docker-whale:ver1 $ docker images REPOSITORY TAG IMAGE ID CREATED SIZE docker-whale latest ff32c5edd7f9 28 minutes ago 278MB takapy0210/docker-whale ver1 ff32c5edd7f9 28 minutes ago 278MB hello-world latest fce289e99eb9 6 weeks ago 1.84kB docker/whalesay latest 6b362a9f73eb 3 years ago 247MB my_whalesay latest 6b362a9f73eb 3 years ago 247MB my_whalesay ver1 6b362a9f73eb 3 years ago 247MB
takapy0210/docker-whale
というリポジトリが作成されていることがわかります。
Push
Pushのコマンドは下記です。
$ docker push <Docker ID>/<イメージ名>:<タグ名>
実践してみます。
$ docker push takapy0210/docker-whale:ver1
DockerHub上でリロードすると、確かにPushできていることが確認できます。
コンテナを起動してみる
$ docker run --name test-nginx -d -p 8080:80 nginx
test-nginx
はコンテナ名を設定しています。また、8080
はホスト側のポート番号、80
はコンテナ側のポート番号を表しています。
起動後、ブラウザからhttp://localhost:8080/にアクセスすることにより、nginxが起動していることが確認できるかと思います。
ホスト上のディレクトリをコンテナにマウントする
nginxのDockerHubリポジトリに記載のあるように、下記コマンドで静的ページをマウントしてnginxで動作させることができます。
$ docker run --name some-nginx -v /some/content:/usr/share/nginx/html:ro -d nginx
-v
の引数でホスト側のディレクトリとコンテナ側のマウンポイントを指定しています。
このようにファイルマウントすることで、手元でコンテンツの更新を行ったり、ソースコードをコンテナに含めずに、Githubなどで管理することができるようになります。
実際にやってみます。まずは、htmlファイルをローカルに作成します。(フルパス:/Users/takapy/Documents/03_docker/docker-tutrial/html)
<!DOCTYPE html> <html> <body> <h1>MyFirst Heading</h1> <p>My first paragraph.</p> </body> </html>
この状態で、下記コマンドを実行します。
$ docker run --name first-nginx -v /Users/takapy/Documents/03_docker/docker-tutrial/html/:/usr/share/nginx/html:ro -d -p 8080:80 nginx
ブラウザからhttp://localhost:8080/にアクセスすると、上記htmlの内容が表示されていることが確認できると思います。
コンテナのライフサイクル
Dockerのステータスは下記のようなコマンドで確認できます。
$ docker ps
$ docker ps -a
コンテナのシェルへの接続
下記の2パターンで接続することが可能です。
docker attachを使用する
$ docker attach <コンテナ名またはコンテナID>
※シェル接続できるのはコンテナでシェルを実行している場合のみです。また、exitでシェルを抜けるとコンテナも停止してしまいます。Ctrl+P → Ctrl+Q でコンテナを停止させることなくシェルを抜けることができます。
docker execを使用する
$ docker exec -it <コンテナ名またはコンテナID> /bin/bash
※/bin/bashを実行していますが、bashがなければ別のシェルを指定してください。
それでは実際に起動中のコンテナに接続してみます。例としてubuntuのコンテナを実行してみます。
$ docker run --name connect-test -it -d ubuntu /bin/bash $ docker attach connect-test -- または下記 $ docker exec -it connect-test /bin/bash
上記のようにしてubuntuへ接続することができます。
コンテナを停止・削除する
停止させる場合は docker stop <CONTAINER IDまたはNAME>
で停止できます。また、停止させたあとであればdocker rm <CONTAINER IDまたはNAME>
でコンテナを削除することもできます。
$ docker stop b7f098b3b774 $ docker rm b7f098b3b774
参考
ゼロからはじめる Dockerによるアプリケーション実行環境構築
以上。