Docker お勉強 01 起動・イメージ作成
Redmineプラグインのもくもくをやるのに、Dockerで開発環境を準備する事にしたけれど、使い方を全く知らないので少しづつお勉強します。
さくらのナレッジ の Docker入門でお勉強して、覚え書きをここへ記載します。
公開されているDockerイメージを使用し、コンテナの基本的な操作
Dockerイメージ、コンテナのライフサイクル
- 公開されているDockerイメージの取得
- それをもとにコンテナを起動
- コンテナの停止・削除
- Dockerイメージの削除
公開されているDockerイメージの取得
「hello-world」というDockerイメージを使用して、コンテナを起動。
# docker run hello-world
このhello-worldイメージは、コンテナ起動をしたら、コンテナの中でメッセージを出力するようなDockerイメージとなっています。
docker run
Dockerイメージを使用して、コンテナを起動するコマンド
※最初はローカル環境にはDockerイメージはありません。そのため、Docker Hubに探しに行き、存在すればDockerイメージをダウンロードします。
コンテナの状態
# docker ps -a CONTAINER ID IMAGE COMMAND CREATED c1b9013f9f66 hello-world "/hello" 27 minutes ago STATUS PORTS NAMES Exited (0) 27 minutes ago distracted_swirles
CONTAINER ID | コンテナのID | 備考 |
---|---|---|
IMAGE | 使用したDockerイメージ | |
COMMAND | コンテナ起動時にコンテナ内で実行するコマンド | |
CREATED | コンテナを作成したタイミング | |
STATUS | コンテナ状態 | Exited:停止中 Up: 起動中 |
PORTS | ポートフォワード設定 | |
NAMES | コンテナの名前 |
※コンテナの名前は、指定しなければ自動で設定されます。
(コンテナの名前の指定の仕方は後ほど)
※ コンテナは、1プロセスは動いている必要があります。
今回のhello-worldイメージでは、メッセージを出力するだけのプロセスだったため、そのプロセスが終了したタイミングでコンテナは停止しています。
Dockerコンテナ、イメージを削除する
コンテナ一覧
# docker ps -a CONTAINER ID IMAGE COMMAND CREATED c1b9013f9f66 hello-world "/hello" 27 minutes ago STATUS PORTS NAMES Exited (0) 27 minutes ago distracted_swirles
※停止中のものをそのままにしておくと、ゴミデータが残ったままになったり、ディスク圧迫にもつながるので、不要になったものは削除を忘れないようにしましょう。
※「docker ps」(「-a」を付けない)と実行すると、停止中のコンテナは表示されないので、注意してください。
気づいたらたくさんの不要コンテナが溜まっていた、ということにもなりかねません。
イメージ一覧
# docker images REPOSITORY TAG IMAGE ID CREATED SIZE hello-world latest f2a91732366c 3 months ago 1.85kB
※イメージについても、不要なイメージは削除しましょう。
特に、JenkinsなどのCI(Continuous Integration) ツールを使用して、Dockerイメージの作成やコンテナ起動を自動で実行するような場合、気づかないうちに不要データが残り続けて、ディスクを圧迫することになるので注意しましょう。
(Disk Fullを起こすと、Docker環境の復元も困難になる場合があるので、十分注意したほうが良いです。)
コンテナを削除
# docker rm <コンテナ名> または # docker rm <CONTAINER ID>
例:
docker rm distracted_swirles docker rm c1b9013f9f66
Dockerイメージの削除
コンテナを削除しても、Dockerイメージまでは削除されません。
# docker rmi <Dockerイメージ名> または # docker rmi <IMAGE ID>
例:
# docker rmi hello-world または # docker rmi f2a91732366c
Nginxイメージを使ってコンテナを動かしてみる
NginxのDockerイメージを取得
# docker pull nginx
取得したNginxイメージを使用してコンテナを起動
Nginxコンテナが起動するので、8181ポートに外からアクセスできるように設定すれば(Firewallなど)、以下のURLでNginxにアクセスすることができます。
http://<作成したインスタンスのIPアドレス>:8181/
# docker run -d --name nginx-container -p 8181:80 nginx
実行コマンドのオプション
オプション | 説明 |
---|---|
-d | コンテナをバックグラウンド実行します。 このオプションを付けない場合、コンテナ起動時に実行されるコマンドを実行した状態になり、例えばそのコマンドのコンソール出力が表示された状態になります。 |
–name | コンテナ名を指定します。 (指定しない場合、自動で名前がつく) |
-p | ホストとコンテナ間のポートフォワード設定。 基本的には、「-p <ホスト側のポート>:<コンテナ側のポート>」で書きます。 (ホスト側を省略すると自動で設定されます。) コンテナは、Dockerにより作成されるネットワークに属するため、このオプションを使わないと、ホストのIPアドレスを用いて、コンテナで使用しているポートにはアクセスができません。 |
コンテナ状態を確認
Nginxイメージの場合は、コンテナ起動時にnginxプロセスが実行されたままの状態になるため、コンテナも停止せずに起動状態となります。
docker ps コマンドで見てみると、STATUSが「Up」となっています。
# docker ps -a CONTAINER ID IMAGE COMMAND CREATED a61413193f44 nginx "nginx -g 'daemon ..." 7 days ago STATUS PORTS NAMES Up 8 seconds 0.0.0.0:8181->80/tcp nginx-container
コンテナを停止する
# docker stop nginx-container nginx-container
Proxy配下でDockerを使用する場合
Docker CEの場合
# mkdir -p /etc/systemd/system/docker.service.d # vi /etc/systemd/system/docker.service.d/http-proxy.conf [Service] Environment="HTTP_PROXY=http://<プロキシサーバのIPアドレス>:<プロキシサーバのポート>/ HTTPS_PROXY=http://<プロキシサーバのIPアドレス>:<プロキシサーバのポート>/" # systemctl daemon-reload # systemctl restart docker
Docker for Mac/Windowsの場合 メニューからたどる
preferences > proxies
公開Dockerイメージにミドルウェアやアプリをインストールして利用する
CentOSのDockerイメージをもとにTomcatが動くコンテナを構築するなかで、各種dockerコマンドについて説明します。
また、自分で構築したコンテナから、Dockerイメージを作成し、使用します。
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
ディレクトリが存在していてもエラーメッセージを表示せず、 現在あるディレクトリはそのままにして新規に作成することはなく子ディレクトリを作成する。
CentOSコンテナの中でTomcatインストール
今回使用しているCentOSのDockerイメージでは、インストール済みのコマンドは限られています。
そのため、必要に応じてyumなどでインストールする必要があります。
まず、Tomcatをホスト側にダウンロード
コンテナの中でダウンロードも可能です。
今回は、ホスト側からコンテナへのファイルコピー方法を示すため、このような手順にしています。
[ホスト]
# wget http://www-eu.apache.org/dist/tomcat/tomcat-9/v9.0.6/bin/apache-tomcat-9.0.6.tar.gz
以下のコマンドでホスト側からコンテナ内にファイルをコピー
[ホスト] docker cp <ホスト側のファイル> <コンテナ名>:<コンテナ内のコピー先ディレクトリ>
# docker cp apache-tomcat-9.0.6.tar.gz tomcat:/opt/
また、コンテナからファイルを取得することも可能です。以下のようなコマンドになります。
docker cp <コンテナ名>:<コンテナ内のコピー元ファイル> <ホスト側のコピー先ディレクトリ>
コンテナにログイン
[ホスト]
# docker exec -it tomcat bash
docker exec [オプション] [コンテナ] [コマンド] [引数...]
オプション | 説明 |
---|---|
-d, --detach | 指定したコマンドをコンテナ内でバックグラウンドで実行します。 |
-e, --env <定義> | 指定したコマンドを実行する際に環境変数を適用します。 |
-i, --interactive | 指定したコマンドを実行した後、コンテナの標準入力をDockerホストの標準入力と接続します。 |
-t, --tty | コンテナ内で疑似的な仮想端末を割り当てて、Dockerホストの標準出力と接続します。 |
--privileged | 指定したコマンドを特権モードで実行します。 |
-u, --user | 指定したコマンドを特定ユーザで実行します。 |
-w, --workdir | コンテナ内でコマンドを実行する際の作業ディレクトリが指定できます。 |
コンテナ内で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ポートを使用することになります。
これでTomcatのコンテナができました。 自分でWebアプリケーションを作成していたら、Tomcat配下のwebappsディレクトリに配置すれば、コンテナ内で自分のアプリケーションを起動させることができます。
ホスト側とのディレクトリ共有
注意点
そのため、コンテナが停止してしまったら、ログを取得するために再度コンテナを起動させる必要があります。
また、もしコンテナが削除されてしまった場合は、ログの取得すらできなくなってしまいます。
実際に運用しているサービスでログが取得できないのは大きな問題です。
解決する方法
ホスト側とコンテナのディレクトリを共有させる方法があります。
docker run「-v」オプションが、その設定になります。
コロンの左側(/root/tomcat-container/logs)がホスト側、右側(/share/logs)がコンテナ内のディレクトリを表していて、そのディレクトリが共有されるかたちとなります。
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)し、ホスト側のディレクトリ(/root/tomcat-container/logs/)を確認してみてください。
[ホスト]
# ls -la /root/tomcat-container/logs/
これでコンテナが停止しても、ホスト側でログを確認することができます。
試しにコンテナを停止
[ホスト]
# docker stop tomcat tomcat
これでコンテナが停止しました。
先ほど確認したホスト側のディレクトリ(/root/tomcat-container/logs/)を確認してみるとログが残っているはずです。
その他、ホスト側とコンテナ内でディレクトリ共有する目的の例としては、以下のようなケースがあります。
・設定ファイルをホスト側においておき、その設定ファイルをコンテナ内で使用する。 ・ソースコードがあるディレクトリを共有させて、コンテナ内でビルドやユニットテストを実行できるようにする。
コンテナからDockerイメージを作成し、使用する。
ここで作成したコンテナを削除してしまうと、もう一度同じコンテナを使いたいとなった場合に、再度同じ手順を踏む必要があります。
(また、同じものを増やしたい場合に、再度Tomcatインストールから行うのは手間です)
Dockerイメージにすることで、そのイメージを使ってコンテナ起動すれば、既に各種ミドルウェアなどがインストールされた状態のコンテナを起動することができます。
Dockerイメージを作成する方法は、以下の方法があります。
- Dockerfileを使用してDockerイメージを作成する
- コンテナからDockerイメージを作成する
Dockerfile
今回実施したインストールコマンドなどを書いたファイル。
手順がそのままコード化された状態となり、再現性も担保できるようになります。
具体的には以下のような内容になります。
FROM centos:7 RUN yum install -y java CMD ["/bin/bash"]
コンテナからDockerイメージを作成
- 現状のコンテナ状態をDockerイメージにするコマンドがあります。
このやり方だと、そのDockerイメージは何の操作をしてできたものなのかもわからない状態になってしまいます。 - Dockerイメージの作成は、基本的には 1.のDockerfileを使用したやり方がよい。
(Docker Hubで公開されているDockerイメージも、それぞれDockerfileが公開されていて、それを元に作成されたイメージです。)
暫定的にDockerイメージにしておきたい場合などに行うくらいが良い。
まず、コンテナを停止
[ホスト]
# docker stop tomcat
コンテナ名を指定し、Dockerイメージを作成
[ホスト]
docker commit <コンテナ名> <作成するDockerイメージ名>
# docker commit tomcat tomcat-image
新しくDockerイメージができたことを確認
[ホスト]
# docker images
作成したDockerイメージを使用してコンテナ起動
[ホスト]
コマンドの一番後ろで、作成したDockerイメージの「tomcat-image」を指定しています。
ホスト側のポートと、ホスト側の共有ディレクトリについては、最初に起動したコンテナとは被らないようにしましょう。
# mkdir -p /root/tomcat-container/logs2 # docker run -it -d -p 18082:8080 -v /root/tomcat-container/logs2:/share/logs --name tomcat2 tomcat-image
コンテナ状態を確認してみます。
[ホスト]
tomcat2という名前のコンテナが起動しています。
また、IMAGEのところを見ると「centos:7」ではなく、「tomcat-image」になっています。
# docker ps -a CONTAINER ID IMAGE COMMAND CREATED 72472672e66b tomcat-image "/bin/bash" 5 seconds ago 4ba6f6f55040 centos:7 "/bin/bash" About an hour ago STATUS PORTS NAMES Up 2 seconds 0.0.0.0:18082->8080/tcp tomcat2 Exited (137) About an hour ago tomcat
実際にコンテナの中を確認し、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にした)
停止したコンテナは、以下のコマンドで再度起動することができます。
18080ポートでアクセスすれば、最初に起動したコンテナ側に接続できます。
[ホスト]
# docker start tomcat # docker ps -a CONTAINER ID IMAGE COMMAND CREATED 72472672e66b tomcat-image "/bin/bash" 45 seconds ago 4ba6f6f55040 centos:7 "/bin/bash" 5 seconds ago STATUS PORTS NAMES Up 45 seconds 0.0.0.0:18082->8080/tcp tomcat2 Up 5 seconds 0.0.0.0:18080->8080/tcp tomcat