【 docker入門 】 dockerでコンテナを作ってアクセスする手順とコマンドのまとめ
はじめに
docker入門 シリーズとして今後コンテナ関連の投稿を増やしていこうと思います。
多くのサイトでコンテナ、Dockerについての説明が紹介されております。
この記事は、実際にDockerをインストールした後から「実際に動かしてみましょう!」ということで、コンテナを起動してアクセスするところまでをご紹介します。
コンテナの概要
概要は、少し調べただけでもかなり情報が出てくるのでここでは、あまり深く触れません。
IT用語辞典によると
コンピュータの仮想化の方式の一つで、稼働中のオペレーティングシステム(OS)の一部を分離して他と隔離された専用のエリアを用意し、その上でソフトウェアを動作させる方式をコンテナ型仮想化という。隔離された領域のことをコンテナという
T用語辞典から引用(2021/7/11): IT用語辞典
とのこと。
例えば、macでnginxを実行するコンテナを起動した場合、nginxはmacのプロセスとして隔離されたエリアで実行されます。
このプロセスが実行されている隔離されたエリアをコンテナと言っているんだなーという理解でOKかと思います。
ここでの隔離とは、ディレクトリ構造、ファイル名などが複数のコンテナで重複していても問題なく動作できるようになっているという感じです。
仮想サーバとは、隔離する単位が違うニュアンスでOKかと思います。
図の様に複数のコンテナで同じパス、同じ名前のファイルが存在していても隔離されているのでそれぞれ上書きされることなく保持できます。
ちなみに隔離はnamespacesという機能をコンテナエンジン(dockerなど)がうまいこと使って実現しているそうです。
公式のDockerイメージを使ってコンテナを起動
まずは、コンテナを動かしてみます。
Dockerでは一つのコンテナをDockerイメージという形にしておくことで同じコンテナを複数作ったり、開発者同士で共有することができます。
まずは、難しいことを考えず公式が配布しているnginxのDockerイメージを使ってコンテナを起動します。
結果は以下の通り。(出てくるコマンドやオプションについては後ろの方でまとめています。)
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
$ docker run --name web_nginx -p 8080:80 -d nginx:latest
Unable to find image 'nginx:latest' locally
latest: Pulling from library/nginx
b4d181a07f80: Already exists
66b1c490df3f: Already exists
d0f91ae9b44c: Already exists
baf987068537: Already exists
6bbc76cbebeb: Already exists
32b766478bc2: Already exists
Digest: sha256:353c20f74d9b6aee359f30e8e4f69c3d7eaea2f610681c4a95849a2fd7c497f9
Status: Downloaded newer image for nginx:latest
1d70d6de67c4cb68e4bffb607c42ef5df8232da39cfe606fe1cb568974e29114
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest 4cdc5dd7eaad 4 days ago 133MB
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1d70d6de67c4 nginx:latest "/docker-entrypoint.…" 13 seconds ago Up 10 seconds 0.0.0.0:8080->80/tcp, :::8080->80/tcp web_nginx
http://localhost:8080 にアクセスしnginxのデフォルトページが表示されることが確認できます。
確認できたら以下のコマンドでコンテナを削除します。
$ docker stop web_nginx
web_nginx
$ docker rm web_nginx
web_nginx
次に、index.htmlを作成し同じURLでアクセスした時にindex.htmlを表示させます。
仮想サーバであれば、所定のディレクトリにhtmlファイルを配置すれば良いですが、コンテナはプロセスであるため同じようなことができません。
コンテナの場合は、コンテナが実行されているPCやサーバ(ローカルマシン)のディレクトリをマウントすることで実現します。
まずは、以下のようにhtmlファイルを配置します。
$ mkdir /Users/hito/docker-tutorial/html
$ cd /Users/hito/docker-tutorial/html
$ echo "<h1>HelloWorld</h1>" > index.html
$ pwd
/Users/hito/docker-tutorial/html
$ cat index.html
<h1>HelloWorld</h1>
htmlファイルの準備ができたらdocker run
コマンドをマウントするパスを指定して実行します。
今回は-v /Users/hito/docker-tutorial/html:/usr/share/nginx/html:ro
と指定していますので、
ローカルマシンの/Users/hito/docker-tutorial/html
がコンテナの/usr/share/nginx/html
にマウントされます。
最後の:roはReadOnlyを指定するものです。
$ docker run --name web_nginx_helloworld -p 8080:80 -v /Users/hito/docker-tutorial/html:/usr/share/nginx/html:ro -d nginx
18bf3f0e3de47008163d6c02b7c24e491d3679d4133ace66c5660b97cd8b30cb
起動したコンテナにアクセスしてみると、、、
自分で作成した、htmlファイルが表示されました!
ここまでやったときの構成は以下の通りになります。お疲れ様でした!
ありそうなエラー
私が色々試していた時に出会ったエラーをまとめておきます。
参考になれば幸いです
docker: Error response from daemon: Conflict. The container name “コンテナ名" is already in use by container “コンテナID". You have to remove (or rename) that container to be able to reuse that name.
web_nginx_helloworldという名前のコンテナが既に存在するためエラーとなりました。。
停止中のコンテナも重複と判定されてしまうので、docker ps -
aで確認、docker rm
でコンテナを削除しましょう。
docker: Error response from daemon: Conflict. The container name "/web_nginx_helloworld" is already in use by container "c818fa4dd3284a6909867800f8adc7cfafd93af5a528576ae8926a12af3179b1". You have to remove (or rename) that container to be able to reuse that name.
See 'docker run --help'.
類似しているものでローカル側でマッピングしているポートが重複した場合もalready in useでエラーになります。
Cannot connect to the Docker daemon at unix:///Users/user/.docker/run/docker.sock. Is the docker daemon running?
今も時々引っかかりますが、dockerが起動していないです。
dockerコマンドを実行するとdockerデーモンというものが動いてコンテナに関するあれこれをよしなにやってくれるのですが、それが起動していないのでエラーになっています。
この状態では、docker ps
やdocker run
とやっても同じエラーになってしまいます。
dockerDesktopやdockerのサービスが起動しているか確認しましょう。
今回出てきたコマンドの解説
docker ps
起動中のコンテナを確認するコマンドです。
オプションを指定することで停止中のコンテナも確認できます。
何度も実行するコマンドなのでオプション含め覚えてしまいましょう!
# 実行中のコンテナを表示
$ docker ps
# 停止中のコンテナも含めて表示
$ docker ps -a
# docker psの結果からコンテナIDのみを取得
$ docker ps -aq
-aオプション
停止中のコンテナも含めて表示するオプションです。
新しくコンテナを起動しようとして、コンテナ名やポートの重複で作成できなかった時などこのコマンで確認すると大体停止中のコンテナとかぶっていたりします。
-q
docker ps
で表示される情報のうちコンテナIDのみ取得するコマンドです。
不要なコンテナが溜まった時にdocker stop
やdocker rm
といった停止系のコマンドと組み合わせて一括で削除する時に使っています。
# 実行中のコンテナを全部停止する
$ docker stop `docker ps -q`
docker run
必要なdockerイメージをdocker hub(dockerイメージが集約されているリポジトリ)からダウンロードしてコンテナを実行してくれるコマンドです。
dockerイメージについては別記事に詳しく記載しようと思いますが、コンテナの実行に必要なファイルをまとめたファイルシステムのことです。
最初はコンテナの素くらいの感覚で良いかと思います。
dockerイメージがローカルマシン上に存在しない場合はdocker hubからイメージを検索して取得するという動きをしてくれます。
docker hubから取得する場合はインターネット経由で必要なイメージをダウンロードしてくるので少し時間がかかります。
一度実行したイメージはローカルマシンにダウンロードされますので2回目以降はすぐに実行することができます。
$ docker run --name [コンテナ名(任意)] -p [ローカルポート]:[コンテナ側ポート] -d -v [ローカルマシン側ディレクトリ]:[コンテナ側ディレクトリ][:オプション] [イメージ名]
以下、使っているオプションの解説です。
–name [コンテナ名]
起動するコンテナに名前をつけられます。
指定は任意で、指定しなかった場合ランダムな名前がdockerによって割り当てられます。
ランダムな名前は、形容詞+著名な科学者やハッカーの組み合わせで選択されるようです。
遊び心があっていいですね。Ubuntuの開発コードも形容詞+動物になっていていいですよね。(DiscoDingoとGroovyGorillaが好きです。)
-p [ローカルポート]:[コンテナ側ポート]
ローカルPCのポートとコンテナのポートを対応付けるためのオプションです。
ローカルポートにはローカルマシンでListenするポートを指定し、コンテナ側ポートにはコンテナがListenしているポートを指定します。
今回はnginxをコンテナで起動したのでデフォルトで80番ポートをListenしていますので、-p 8080:80
とすることで、ローカルマシンの8080番ポートに来たアクセスを、コンテナの80番ポートに流すことができます。
-d(デタッチモード)
記事の最初にも記載しましたが、コンテナはプロセスであるためフォアグラウンドで実行するとターミナルを占領してしまい他の操作ができなくなってしまいます。
できれば、サーバやバッチの処理はバックグラウンドで実行していて欲しいものですよね。
参考までに、先程のnginxのコンテナを-dオプションなしで実行してみると以下のようになります。
$ docker run --name tmp-nginx -p 8080:80 nginx
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
2021/07/10 22:06:28 [notice] 1#1: using the "epoll" event method
2021/07/10 22:06:28 [notice] 1#1: nginx/1.21.1
2021/07/10 22:06:28 [notice] 1#1: built by gcc 8.3.0 (Debian 8.3.0-6)
2021/07/10 22:06:28 [notice] 1#1: OS: Linux 5.10.25-linuxkit
2021/07/10 22:06:28 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
2021/07/10 22:06:28 [notice] 1#1: start worker processes
2021/07/10 22:06:28 [notice] 1#1: start worker process 31
2021/07/10 22:06:28 [notice] 1#1: start worker process 32
実行してみると分かりますが、nginxのログが出続けてしまいます。(フォアグラウンドで実行されている状態)
このプロセスをCtrl+C
などで止めてしまうとコンテナが終了してしまいます。
-dオプションをつけた場合は、
$ docker run --name tmp-nginx -d nginx
6f9115fc62277d07cc0d01dd6a12aee6457b2dae5388f6925f51bccd5e8b68c2
$
このようにコンテナをバックグラウンドで実行することができます。
-v [ローカルマシン側ディレクトリ]:[コンテナ側ディレクトリ][:オプション]
コンテナにマウントするボリュームを指定します。
上の方でやったように、ローカルマシンのディレクトリと、コンテナのディレクトリを対応させることでコンテナないのディレクトリとして使うことができます。
今回のように、
$ docker run --name web_nginx_helloworld -p 8080:80 -v /Users/hito/docker-tutorial/html:/usr/share/nginx/html:ro -d nginx
と指定した場合、ローカルマシンの/Users/hito/docker-tutorial/html
の内容が、コンテナ側で、コンテナ内の/usr/share/nginx/html
として認識することができます。
[イメージ名]
コンテナ起動に使うイメージ名を指定します。
ダウンロード済みのイメージを使う場合は、docker images
コマンドでイメージ名を確認することができます。
REPOSITORYの列がイメージ名です。
docker images 24.1s 火 2/ 8 22:05:43 2022
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest c316d5a335a5 13 days ago 142MB
docker stop/start/rm
コンテナを停止(stop)/開始(start)/削除(rm)するコマンドです。
注意点としては、コンテナは停止しても使用しているポートやコンテナ名は保持されるため先程のような重複エラーの原因になります。
コンテナを削除する際には、合わせてdocker rm コマンドも実行するのを忘れないようにしましょう。
docker stopで停止したコンテナは、docker startコマンドで開始することで、同じコンテナを起動することができます。
docker rmコマンドでコンテナを削除した場合は、docker startで開始することはできないので注意が必要です。
コンテナを削除した場合はdocker runコマンドでまた新しいコンテナを作成する必要があります。
それぞれの実行結果です。
# コンテナを起動
$ docker run --name sample -p 8080:80 -d nginx 259ms 火 2/ 8 22:15:17 2022
bfb223b07b85f89313eef89991475ed16f7bde1debae96750218411f38a9bd81
# コンテナIDを確認
$ docker ps 火 2/ 8 22:16:23 2022
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
bfb223b07b85 nginx "/docker-entrypoint.…" 55 seconds ago Up 53 seconds 0.0.0.0:8080->80/tcp, :::8080->80/tcp sample
# コンテナを停止
$ docker stop sample
sample
# 稼働中のコンテナを確認
$ docker ps 2061ms 火 2/ 8 22:17:55 2022
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
# さっきのコンテナを開始
$ docker start sample 519ms 火 2/ 8 22:18:34 2022
sample
# コンテナIDを確認 => 停止前と同じIDなので同じコンテナが稼働していることがわかる。
docker ps 1832ms 火 2/ 8 22:18:59 2022
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
bfb223b07b85 nginx "/docker-entrypoint.…" 3 minutes ago Up 21 seconds 0.0.0.0:8080->80/tcp, :::8080->80/tcp sample
# コンテナを停止して削除する
$ docker stop sample
sample
$ docker rm sample
sample
# 同じコンテナを開始してみる => コンテナが見つからずエラーになる
$ docker start sample 565ms 火 2/ 8 22:21:49 2022
Error response from daemon: No such container: sample
Error: failed to start containers: sample
# 同じコマンドでコンテナを再作成
docker run --name sample -p 8080:80 -d nginx 278ms 火 2/ 8 22:22:49 2022
d45f5824184a50cbfd73b663dfcd83c70770b44f17b7505305696b04967d99ef
# 稼働中のコンテナを確認 => コンテナIDが違うのでさっきまでのコンテナとは別物ということがわかる
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d45f5824184a nginx "/docker-entrypoint.…" 35 seconds ago Up 32 seconds 0.0.0.0:8080->80/tcp, :::8080->80/tcp sample