Docker入門(第三回)~各種dockerコマンドとDockerイメージ作成について~

こんにちは、横山です。

先月は、以下のコンテナに関係する書籍が発売されましたね。

コンテナ・ベース・オーケストレーション Docker/Kubernetesで作るクラウド時代のシステム基盤」では、物理マシンから、仮想化やコンテナ、クラウドへの移り変わりなどの背景も含めて書かれているのでおすすめです。

また、4/19(火)には、KubernetesやDockerを中心としたコンテナ活用の現状をひとまとめにした開発者のためのイベントである「Japan Container Days v18.04」がありますね。私も楽しみにしています。

はじめに

第二回では、DockerのインストールとDocker Hubで公開されているNginxのDockerイメージを使ってコンテナ起動を行いました。

しかし、実際には、Docker Hubで公開されているDockerイメージそのままではなく、そこに必要なミドルウェアやアプリをインストールして利用する場合が出てきます。第三回、第四回では、基本的なdockerコマンドの説明と自分でDockerイメージを作る手順などを示していきます。また、第五回、第六回では、複数コンテナを起動してコンテナ間通信をする内容を予定しています。

今回の第三回では、主にCentOSのDockerイメージをもとにTomcatが動くコンテナを構築するなかで、各種dockerコマンドについて説明します。また、自分で構築したコンテナから、Dockerイメージを作成し、使用する例を示します。内容のイメージとしては、以下のようになります。赤枠部分が今回の内容で、それ以外の部分は前回(第二回)に説明した内容にあたります。

各種dockerコマンドを使ってみよう

CentOSのDockerイメージを使用し、アプリケーションサーバの一つであるTomcatのインストール、起動を行いながら、基本的なdockerコマンドについて説明します。

CentOSコンテナの起動

まずCentOSのDockerイメージを取得し、コンテナを起動します。docker runの「-v」オプションについては、この後説明するので、今はそのまま実行してください。

[ホスト]
# docker pull centos:7
# mkdir -p /root/tomcat-container/logs
# docker run -it -d -p 18080:8080 -v /root/tomcat-container/logs:/share/logs --name tomcat centos:7

※「/root/tomcat-container/logs」は任意のディレクトリで結構です。

CentOSコンテナの中でTomcatインストール

CentOSコンテナが起動できたので、その中にTomcatをインストールしてみましょう。今回使用しているCentOSのDockerイメージでは、インストール済みのコマンドは限られています。そのため、必要に応じてyumなどでインストールする必要があります。

まず、Tomcatをホスト側にダウンロードします。

(※編集部注:以下 Tomcat のダウンロードは、現在 https://downloads.apache.org/tomcat/tomcat-9/v9.0.44/bin/apache-tomcat-9.0.44-deployer.tar.gz から行えます。tar.gz ファイルのバージョンも、常に最新版へ置き換えください。なお、最新版はこちらのディレクトリをご確認ください。)

[ホスト]
# wget http://www-eu.apache.org/dist/tomcat/tomcat-9/v9.0.6/bin/apache-tomcat-9.0.6.tar.gz

以下のコマンドでホスト側からコンテナ内にファイルをコピーします。

[ホスト]
# docker cp apache-tomcat-9.0.6.tar.gz tomcat:/opt/
(docker cp <ホスト側のファイル> <コンテナ名>:<コンテナ内のコピー先ディレクトリ>)

もちろんコンテナの中でダウンロードも可能です。今回は、ホスト側からコンテナへのファイルコピー方法を示すため、このような手順にしています。

また、コンテナからファイルを取得することも可能です。以下のようなコマンドになります。

# docker cp <コンテナ名>:<コンテナ内のコピー元ファイル> <ホスト側のコピー先ディレクトリ>

次に以下のコマンドでコンテナにログインします。

[ホスト]
# docker exec -it tomcat bash

それでは、コンテナ内でTomcatのインストールをしましょう。

[コンテナ内]
# yum install -y java
# cd /opt/
# tar zxf apache-tomcat-9.0.6.tar.gz
# cd apache-tomcat-9.0.6
# ./bin/startup.sh

これでTomcatが起動しました。物理マシン上にインストールする場合と基本同じです。ブラウザで以下にアクセスすれば、Tomcatの画面が開きます。docker runコマンドの「-p」オプションでホスト側の18080ポートをコンテナ内の8080にポートフォワードするようにしているので、18080ポートを使用することになります。

http://<IPアドレス>:18080/

これでTomcatのコンテナができました。自分でWebアプリケーションを作成していたら、Tomcat配下のwebappsディレクトリに配置すれば、コンテナ内で自分のアプリケーションを起動させることができます。

ホスト側とのディレクトリ共有

ここで注意点があります。Tomcatのログはコンテナのディレクトリにあります。そのため、コンテナが停止してしまったら、ログを取得するために再度コンテナを起動させる必要があります。また、もしコンテナが削除されてしまった場合は、ログの取得すらできなくなってしまいます。実際に運用しているサービスでログが取得できないのは大きな問題ですよね。

それを解決する方法として、ホスト側とコンテナのディレクトリを共有させる方法があります。コンテナ起動コマンド(docker run)で出てきた「-v」オプションが、その設定になります。ポートフォワード設定の「-p」オプションと同様、コロンの左側(/root/tomcat-container/logs)がホスト側、右側(/share/logs)がコンテナ内のディレクトリを表していて、そのディレクトリが共有されるかたちとなります。

さきほど起動したコンテナでは、「-v」オプションを設定して起動しているので、実際に、ホストとコンテナでディレクトリ共有ができているか確認してみましょう。

現状では、Tomcatログはデフォルトのディレクトリ(/opt/apache-tomcat-9.0.6/logs)に出力されているので、コンテナにログインして、ログ出力先を変えましょう。

[コンテナ内]
# cd /opt/apache-tomcat-9.0.6/
# sed -i -e "s/\${catalina.base}\/logs/\/share\/logs/g" ./conf/logging.properties
# ./bin/shutdown.sh
# ./bin/startup.sh
# ls -la /share/logs/

コンテナ内で/share/logs/配下にログが出力されていることが確認できます。次にホスト側で確認します。新しいコンソールを開くか、コンテナからログアウト(exit)し、「-v」オプションで指定したホスト側のディレクトリ(/root/tomcat-container/logs/)を確認してみてください。

[ホスト]
# ls -la /root/tomcat-container/logs/

コンテナ内の「/share/logs/」と同様のファイルが存在するはずです。(タイミングによっては、タイムスタンプのずれがあるかもしれませんが。)これで、ホスト側とコンテナでディレクトリ共有できていることが確認できました。

それでは、試しにコンテナを停止してみましょう。

[ホスト]
# docker ps -a
CONTAINER ID   IMAGE      COMMAND       CREATED          STATUS          PORTS                     NAMES
4ba6f6f55040   centos:7   "/bin/bash"   16 minutes ago   Up 16 minutes   0.0.0.0:18080->8080/tcp   tomcat
# docker stop tomcat
tomcat
# docker ps -a
CONTAINER ID   IMAGE      COMMAND       CREATED          STATUS                        PORTS   NAMES
4ba6f6f55040   centos:7   "/bin/bash"   17 minutes ago   Exited (137) 22 seconds ago           tomcat

これでコンテナが停止しました。先ほど確認したホスト側のディレクトリ(/root/tomcat-container/logs/)を確認してみるとログが残っているはずです。これでコンテナが停止しても、ホスト側でログを確認することができます。コンテナ削除も行って確認したいところですが、先にこのコンテナを使用してやりたいことがあるので、コンテナ削除については、そのあとに確認しましょう。

現状の状態を図に示すと以下のようになります。

今回は、ログをホスト側に出力させておくために共有ディレクトリ設定を使用しましたが、他の目的で使用するケースもあります。ディレクトリに限らず、ファイル指定でも可能です。ホスト側とコンテナ内でディレクトリ共有する目的の例としては、以下のようなケースがあります。

  1. 設定ファイルをホスト側においておき、その設定ファイルをコンテナ内で使用する。
  2. ソースコードがあるディレクトリを共有させて、コンテナ内でビルドやユニットテストを実行できるようにする。

コンテナからDockerイメージを作成し、使ってみよう

Tomcatが動いているコンテナができましたが、ここで作成したコンテナを削除してしまうと、もう一度同じコンテナを使いたいとなった場合に、再度同じ手順を踏む必要があります。また、同じものを増やしたい場合に、再度Tomcatインストールから行うのは手間ですよね。

今回CentOSコンテナで設定したようなことは、Dockerイメージにすることが可能です。Dockerイメージにすることで、そのイメージを使ってコンテナ起動すれば、既に各種ミドルウェアなどがインストールされた状態のコンテナを起動することができます。Dockerイメージを作成する方法は、以下の方法があります。

  1. Dockerfileを使用してDockerイメージを作成する
  2. コンテナからDockerイメージを作成する

1.の「Dockerfile」は、今回実施したインストールコマンドなどを書いたファイルであり、具体的には以下のような内容になります。

FROM centos:7
RUN yum install -y java
CMD ["/bin/bash"]

Dockerfileについての説明は次回の予定ですが、上記のような形式で書かれたファイルをもとにDockerイメージを作成することができます。実行コマンドを書いて管理することで、手順がそのままコード化された状態となり、再現性も担保できるようになります。

また、2.に関しては、現状のコンテナ状態をDockerイメージにするコマンドがあります。ただ、このやり方だと、そのDockerイメージは何の操作をしてできたものなのかもわからない状態になってしまいます。

そのため、Dockerイメージの作成は、基本的には 1.のDockerfileを使用したやり方がよいでしょう。Docker Hubで公開されているDockerイメージも、それぞれDockerfileが公開されていて、それを元に作成されたイメージです。2.のやり方は、暫定的にDockerイメージにしておきたい場合などに行うくらいが良いと思います。

Dockerfileについての詳細な説明は次回行うので、今回はコンテナからDockerイメージを作成するコマンドの紹介をして、作成したイメージを使ってコンテナを起動してみます。

コンテナからDockerイメージの作成

それでは、今回実施したTomcatインストール済みのコンテナをDockerイメージにしてみましょう。

まず、コンテナを停止します。

[ホスト]
# docker stop tomcat

Dockerイメージにする対象のコンテナ名を指定し、Dockerイメージを作成します。

[ホスト]
# docker commit tomcat tomcat-image
(docker commit <コンテナ名> <作成するDockerイメージ名>)

以下のコマンドで新しくDockerイメージができたことを確認します。

[ホスト]
# docker images
REPOSITORY     TAG      IMAGE ID       CREATED          SIZE
tomcat-image   latest   4f0aa49f1e67   48 seconds ago   466MB
centos         7        2d194b392dd1   2 weeks ago      195MB

「tomcat-image」というDockerイメージができていますね。

作成したDockerイメージを使用してコンテナ起動

それでは、作成したDockerイメージを使用してコンテナを起動してみましょう。

[ホスト]
# mkdir -p /root/tomcat-container/logs2
# docker run -it -d -p 18082:8080 -v /root/tomcat-container/logs2:/share/logs --name tomcat2 tomcat-image

上記コマンドの一番後ろで、作成したDockerイメージの「tomcat-image」を指定しています。ホスト側のポートと、ホスト側の共有ディレクトリについては、最初に起動したコンテナとは被らないようにしましょう。

コンテナ状態を確認してみます。

[ホスト]
# docker ps -a
CONTAINER ID   IMAGE          COMMAND       CREATED             STATUS                            PORTS                     NAMES
72472672e66b   tomcat-image   "/bin/bash"   5 seconds ago       Up 2 seconds                      0.0.0.0:18082->8080/tcp   tomcat2
4ba6f6f55040   centos:7       "/bin/bash"   About an hour ago   Exited (137) About an hour ago                              tomcat

tomcat2という名前のコンテナが起動しています。また、IMAGEのところを見ると「centos:7」ではなく、「tomcat-image」になっていますね。では、実際にコンテナの中を確認し、Tomcatも起動してみましょう。

[ホスト]
# docker exec -it tomcat2 bash
[コンテナ内]
# ls /opt
apache-tomcat-9.0.6 apache-tomcat-9.0.6.tar.gz
(Tomcatディレクトリが確かに存在しますね。)
# cd /opt/apache-tomcat-9.0.6
# ./bin/startup.sh

ブラウザから以下にアクセスするとTomcat画面が見れるはずです。(新しく起動したコンテナのホスト側のポートは18082にしたので、注意してください。)

http://<IPアドレス>:18082/

作成したTomcatのDockerイメージを使用すれば、簡単に環境を再現でき、またコンテナを増やすことも容易になります。

また、停止したコンテナは、以下のコマンドで再度起動することができます。18080ポートでサクセスすれば、最初に起動したコンテナ側に接続できます。

[ホスト]
# docker start tomcat
# docker ps -a
CONTAINER ID   IMAGE          COMMAND       CREATED          STATUS          PORTS                     NAMES
72472672e66b   tomcat-image   "/bin/bash"   45 seconds ago   Up 45 seconds   0.0.0.0:18082->8080/tcp   tomcat2
4ba6f6f55040   centos:7       "/bin/bash"   5 seconds ago    Up 5 seconds    0.0.0.0:18080->8080/tcp   tomcat

現状の状態を図に示すと以下のようになります。

コンテナ削除時のログ確認

コンテナ削除時のログがどうなるか、まだ確認していなかったので、試してみましょう。最初に作成したtomcatコンテナを削除し、ホスト側のログ出力ディレクトリを確認します。

[ホスト]
# docker stop tomcat
# docker rm tomcat
# ls -la /root/tomcat-container/logs/

ログが残っていることが確認できるはずです。これで、コンテナが削除されても、ログは残っているので安心ですね。

各種dockerコマンドのまとめ

今回はdockerコマンドがいくつか登場したので、以下に整理しておきます。

Dockerイメージ取得、イメージ一覧確認

# docker pull <Dockerイメージ名>
# docker images

コンテナ起動、コンテナ一覧確認

# docker run -it -d -p <ホスト側ポート>:<コンテナ側ポート> -v <ホスト側ディレクトリ>:<コンテナ側ディレクトリ> --name <コンテナ名> <Dockerイメージ名>
# docker ps -a

※「-p」「-v」オプション以外にも多数のオプションがあります。

コンテナへのログイン

# docker exec -it <コンテナ名> bash

ファイルコピー

(ホスト→コンテナ内)
# docker cp <ホスト側のファイル> <コンテナ名>:<コンテナ内のコピー先ディレクトリ>

(コンテナ内→ホスト)
# docker cp <コンテナ名>:<コンテナ内のコピー元ファイル> <ホスト側のコピー先ディレクトリ>

コンテナからDockerイメージ作成

# docker commit <コンテナ名> <作成するDockerイメージ名>

コンテナ起動、停止

# docker start <コンテナ名>
# docker stop <コンテナ名>

コンテナ削除

# docker rm (-f) <コンテナ名>
※「-f」オプションを付けると、コンテナ起動中でも強制的に削除します。

その他のコマンドについては、公式ページ「Docker Documentation - docker (base command)」から確認できます。

まとめ

今回は、基本的なdockerコマンドの説明と、コンテナを使ったDockerイメージの作成&使用を説明しました。
次回は、今回も少し触れましたが、Dockerfileを使ったDockerイメージ作成について説明する予定です。