当ドキュメントの目的
docker便利です。好きです。
とはいえ、とっかかりはなかなか苦労しました。
自分が覚える際に躓いた部分や、こうすればスムーズに身につくのではないかと思う方法を記述します。
当ドキュメントではdocker run
コマンドを主軸に、コンテナを作成したり、破棄したりを繰り返して理屈よりも先に体にしみこむことを目的にしています。
dockerを覚えようとされている方の助けになればと思います。
当方がコンテナを作成する際に実行するコマンドは以下のようなものです。
docker run --name example-project \
-it -v /data/example-project:/app \
-w /app -p 3000:3000 -p 4200:4200 \
my-node:1.0 /bin/bash
※上記はあくまで例です。この段階で実行してもmy-node:1.0というイメージがないためエラーになります。
長いコマンドで当初は面食らってしまうと思いますが、当ドキュメントを読み終えたときには理解できるようになることを目標にしています。
環境
当ドキュメントに記載してあるコマンドは、Windows10 WSL2 Ubuntu20.04で実行し、動作確認しました。
ターミナルソフトはWindows Terminalを使用しました。
イメージの取得からコンテナの破棄まで
dockerイメージの取得、コンテナの作成、起動、終了、破棄をコマンドで実行します。
理屈は考えず、とりあえず例の通り実行してみてください。
イメージを取得
以下、特別な記載がなければ、wslのUbuntuのターミナルで実行します。
※Windows Power Shellでも実行可能です。
ubuntu:22.04
イメージを取得します。
docker pull
コマンドを実行します。
クラウド上のレジストリからイメージがダウンロードされます。
docker pull ubuntu:22.04
完了後、docker images
コマンドを実行すると、ダウンロードされたイメージを確認することができます。
docker images
# 結果
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu 22.04 1c5c8d0b973a 3 weeks ago 72.8MB
...
コンテナを作成
docker run
コマンドを実行してコンテナを作成します。
下記の例、いくつかオプション設定有りますが、現時点ではあまり気にしないでください。各々後述します。
docker run --name my-ubuntu -it ubuntu:22.04 /bin/bash
実行すると、"my-ubuntu"というコンテナ名のコンテナが作成されます。
またターミナルのプロンプト(下記の例の"root@hogehoge:/home/user#"の部分)の表記が変わったはずです。
当方の環境だと以下のようになりました。
# docker run コマンド実行
root@hogehoge:/user# docker run --name my-ubuntu -it ubuntu:22.04 /bin/bash
# 実行後
root@479e7ac97829:/#
これは、コンテナの中に入った状態です。
docker runを実行したターミナルとは別にもう一つターミナルを開いてdocker ps
コマンドを実行してください。
実行中のコンテナが一覧されます。
docker ps
# 結果
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
479e7ac97829 ubuntu:22.04 "/bin/bash" 7 minutes ago Up 7 minutes my-ubuntu
ちなみに-a
オプションをつけてdocker ps
コマンドを実行すると、停止しているコマンドも一覧します。
docker ps -a
# 結果例
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
479e7ac97829 ubuntu:22.04 "/bin/bash" 9 minutes ago Up 9 minutes my-ubuntu
d58395d67ee6 my-node:1.0 "docker-entrypoint.s…" 44 hours ago Exited (137) 43 hours ago hoge-container
64ffb5b39354 my-node:1.0 "docker-entrypoint.s…" 44 hours ago Exited (137) 43 hours ago
...
docker run
後のコンテナ内でexit
先の例でdocker run
コマンドを実行後のターミナルで実行します。
exit
コンテナを抜けてホストPCに戻ります。
この時コンテナも終了します。docker ps
コマンドを実行すると、先ほど表示されていたmy-ubuntu
コンテナがリストにないはずです。
コンテナを破棄
作成したコンテナmy-ubuntu
を破棄します。
docker rm my-ubuntu
docker ps
コマンドで、停止中のコンテナもリストアップする-p
オプションを付与して実行してもmy-ubuntu
はリストアップされなくなります。
docker ps -p
# 結果例
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
コマンド解剖
先ほど実行したコマンドを詳しく見ていこうと思います。
docker run --name my-ubuntu -it ubuntu:22.04 /bin/bash
-
--name my-ubuntu
作成するコンテの名称を指定しています。 -
-it
当方はコンテナに入って入力が受け付けられる状態にするためのオプションと理解しています。
理屈は考えずにとりあえず、付与するオプションだと思っています。
が、何とか自分なりに解説します。
-it
は--intereractive
オプションと--tty
オプションを同時に指定しています。
以下のコマンド例は全て同じ実行結果になります。後でこのオプションの有無による実験を行います。# 各々のオプション名を省略せずに記述 docker run --name my-ubuntu --interactive --tty ubuntu:22.04 /bin/bash # 省略値を各々記述 docker exec -i -t my-ubuntu /bin/bash docker run --name my-ubuntu -i -t ubuntu:22.04 /bin/bash # オプション指定に順番はない docker run --name my-ubuntu -t -i ubuntu:22.04 /bin/bash docker run --name my-ubuntu -ti ubuntu:22.04 /bin/bash
-
ubuntu:22.04
dockerイメージを指定しています。 -
/bin/bash
コンテナに入って/bin/bash
コマンドを実行することを指定しています。
/bin/bash
はターミナルソフトです。当方はWindowsにおけるPower Shellやコマンドプロンプトと理解しています。
コンテナ内に入ってターミナルソフトを起動することを指定しています。
-it
オプション実験
-it
オプション無しでdocker run
コマンドを実行してみます。
docker run --name my-ubuntu ubuntu:22.04 /bin/bash
何も起こりません。docker ps -a
を実行すると、my-ubuntu
がリストに上がるのでコンテナは作成されています。
docker ps -a
# 結果例
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f451fa19024d ubuntu:22.04 "/bin/bash" 2 minutes ago Exited (0) About a minute ago my-ubuntu
docker start
コマンド(後述します)でコンテナを起動後、起動中のコンテナを確認するためdocker ps
コマンドを実行してもmy-ubuntu
コンテナはリストに上がりません。
# コンテナ起動
docker start my-ubuntu
# 起動中のコンテナを確認
docker ps
# 結果例
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
# my-ubuntuがない...
当方は、コンテナを起動後、コンテナ内で/bin/bash
を起動した直後にコンテナが終了してしまうものと理解しています。
これでは困るので、コンテナ起動後、コンテナ内のターミナルで入力を受け付ける状態にするために、--interactive
オプションを付与して実行してみます。
# コンテナ削除
docker rm my-ubuntu
# --interactiveオプションを付与してコンテナ作成
docker run --name my-ubuntu --interactive ubuntu:22.04 /bin/bash
# 以下は--interactiveの省略形-iで実行
docker run --name my-ubuntu -i ubuntu:22.04 /bin/bash
パッと見たところ、何も起こっていないのかと思ったのですが、コンテナが作成され、コンテナの中に入っています。
ただしプロンプトが表示されていません。
試しにディレクトリを一覧するls -l
コマンドを実行してみました。
# コンテナを作成
root@hogehoge:/home/user# docker run --name my-ubuntu -i ubuntu:22.04 /bin/bash
# 何も表示されていないがコンテナに入っている。
# lsコマンドを実行してみる。
ls -l
# lsコマンドの結果
total 48
lrwxrwxrwx 1 root root 7 Apr 25 14:03 bin -> usr/bin
drwxr-xr-x 2 root root 4096 Apr 18 2022 boot
drwxr-xr-x 5 root root 340 May 15 08:12 dev
drwxr-xr-x 1 root root 4096 May 15 08:12 etc
...
コマンドは受け付けられていますが、プロンプトの表示がないと不便です。-tty
オプションを付与するとプロンプトが表示されるようになります。
以上のことから、-it
オプションを付与することが必要と考えています。
コンテナの開始、停止
作成したコンテナの開始、終了コマンドについて示します。
開始
docker start
コマンドを実行します。
docker start my-ubuntu
注意
先の例のdocker run
コマンド実行後、そのままコンテナ内に入りましたが、docker start
実行後はコンテナ内には入りません。
コンテナ内に入る
docker exec
コマンドを実行します。
docker exec -it my-ubuntu /bin/bash
プロンプトの表記が変わったことを確認してください。コンテナに入ったことを示しています。
上記のコマンドについて解説します。
-
/bin/bash
コンテナに入って/bin/bash
コマンドを実行することを指定しています。
/bin/bash
はターミナルソフトです。当方はWindowsにおけるPower Shellやコマンドプロンプトと理解しています。
コンテナ内に入ってターミナルソフトを起動することを指定しています。 -
-it
docker run
コマンド時の-it
オプションと同等と理解しています。
コンテナから抜けるにはexit
コマンドを実行します。
exit
docker run
実行後のexit
と異なり、コンテナを抜けた後も、コンテナは停止せずに稼働中です。
docker ps
コマンドを実行して、稼働していることが確認できます。
コンテナを停止
docker stop
コマンドを実行します。
docker stop my-ubuntu
docker ps
コマンドを実行して、コンテナが停止していることを確認してください。
コンテナを破棄
docker rm
コマンドでコンテナを削除します。
docker rm my-ubuntu
docker ps -a
コマンドで、my-ubuntu
コンテナが亡くなったことを確認してください。
コンテナ内でいろいろ操作
コンテナ内でいくつかLinuxコマンドを実行します。
先の例を参考にして、Ubuntuコンテナを作成しコンテナ内に入ります。
# コンテナを作成する。
docker run --name my-ubuntu -it ubuntu:22.04 /bin/bash
# コンテナ内に入る。
docker exec -it my-ubuntu /bin/bash
コンテナ内でファイル作成
以下よりいくつかLinuxコマンドを実行します。
当方はLinuxコマンドについて以下の書籍を参考にしました。
図解! Linuxコマンドのツボとコツがゼッタイにわかる本 著者:高橋 隆雄 出版社:秀和システム
いくつかコマンド出てきますが、覚えようとしなくてよいです。
-
ファイルを作成する
touch
コマンドでファイルをhoge.txt
というテキストファイルを作成します。touch hoge.txt
ls
コマンドを実行すると、ファイルが作成されたことが確認できます。ls -la # 結果 ... -rw-r--r-- 1 root root 0 Mar 30 05:36 hoge.txt ...
-
ファイルを編集する
Ubuntu標準のテキストエディタ
nano
を使ってhoge.txt
を編集します。nano hoge.txt # 結果 bash: nano: command not found
nano
が未インストールのためエラーが表示されました。
apt-get
コマンドを実行してnano
をインストールします。
※nano
既定でインストールされているものと思っていましたが、ubuntu:22.04
dockerイメージから作成するubuntuにはインストールされていない模様です。当ドキュメント作成中に知りました。しかし、ついでにapt-get
コマンド紹介出来て良かったです。echo 'nameserver 8.8.8.8' > /etc/resolv.conf apt-get update apt-get upgrade apt-get install nano
nanoのインストールが完了したところで改めてhoge.txtを編集します。
nano hoge.txt
テキストエディタが起動するので何か入力します。日本語を入力しようとすると文字化けします。日本語対応させる設定有るのですが後述します。
hoge.txtabcdefghijolmnopqrstuvwxyz
ctrl
+x
キーでテキストエディタを終了します。保存するかどうか聞かれるのでy
キーを押して保存します。
編集したテキストの内容を確認します。nano
を起動してもよいですし、cat
コマンドでも確認することができます。cat hoge.txt # 結果 先ほど編集した内容が表示される。 abcdefghijolmnopqrstuvwxyz
-
日本語対応
Linuxの環境変数を設定します。
以下のコマンドを実行します。export LANG=C.UTF-8 export LANGUAGE=en_US: #末尾は";"セミコロンではなく":"コロンであることに注意
nanoで日本語が入力できるようになったことを確認してください。
ただしこの設定は永続化されません。コンテナを抜けて再度、コンテナに入ると先ほどの設定がクリアされてしまいます。
コンテナ内のLinuxの設定ファイルを編集することで、設定値を永続化することができます。
※2023/03/30 当ドキュメント作成時、以下の設定期待した挙動になりませんでした。下記設定方法は主題からは逸れるので読み飛ばしてください。# 設定ファイルを編集する。 nano /etc/profile # 末尾に以下を追記します。 export LANG=C.UTF-8 export LANGUAGE=en_US:
コンテナを終了、破棄
# コンテナを抜ける
exit
# コンテナを終了
docker stop my-ubuntu
# コンテナを破棄
docker rm my-ubuntu
コンテナ内でテキストファイルを作成し、編集、保存しました。
その後コンテナを破棄しました。編集したテキストファイルはどうなったかというと、一緒に破棄されています。
先ほどは簡単なテキストファイルだったのでなんということはありませんが、これが手塩にかけたプログラムコードであったならえらいことです。
コンテナを破棄しても、ホストPCに成果物を残す方法があります。-v
オプションです。
VOLUME
オプション
-v
オプションで、コンテナ内のディレクトをホストPCのディレクトリにマウントします。
※"マウント"当方は紐づけるという理解です。
ホストPC側に/data/example-project
というディレクトリを作成し、コンテナ内の/app
ディレクトリをマウントします。コンテナ内の/app
ディレクトリは、ホストPCで実行するdocker-run
コマンドで作成されます。ついでに-w
オプションで、ワーキングディレクトリが/app
であることを指定します。これにより、コンテナに入った時のカレントディレクトリが/app
になります。
では以下のコマンドを順に実行します。
# ディレクトリを作成する。
mkdir /data
mkdir /data/example-project
# コンテナを作成する。
docker run --name my-project -it -v /data/example-project:/app -w /app ubuntu:22.04 /bin/bash
コンテナ作成後にコンテナ内に入った時に、プロンプトの表示を見てください。
/app
ディレクトリになっているはずです。これは先に実行したdocker run
コマンドの-w
オプションによるものです。
コンテナ内でファイルを作成し、編集、保存します。
# テキストエディタをインストールする準備。
echo 'nameserver 8.8.8.8' > /etc/resolv.conf
apt-get update && apt-get upgrade -y
# テキストエディタをインストールする。
apt-get install nano
# "hoge.txt"を作成する。
touch hoge.txt
# 内容を編集する。
nano hoge.txt
# コンテナを抜ける
exit
テキストファイルを保存後、コンテナを停止します。
※docker run
実行後そのままコンテナ内で作業していた場合、以下は不要です。
docker stop my-project
コンテナ終了後、ホストPCの/data/example-project
ディレクトリを確認してみてください。
# ホストPCでの操作です。
# ディレクトリを移動する。
cd /data/example-project
# カレントディレクトリの内容を一覧する。
ls -l
# 結果
-rw-r--r-- 1 root root 15 3月 30 15:39 hoge.txt
コンテナ内で作成したファイルがリストアップされているはずです。
ファイルの内容を確認してみます。
cat hoge.txt
# 結果
ここにコンテナ内で編集、保存した内容が表示されます。
以上により、-v
オプション指定により、コンテナでの編集内容がホストPCに保存できることが確認できました。
コンテナを破棄しても、コンテナ内での編集が残っていることを確認してみてください。
Dockerfile
先ほどの例でubuntu:22.04
イメージを元にコンテナを作成しました。
その後、テキストエディタのインストール、日本語対応設定を行いました。
以降、ubuntuコンテナを作成して作業するとき、毎回同じようにテキストエディタのインストール、日本語対応設定を行うのでしょうか?
同じ手順を省く方法はないのでしょうか?
あります。Dockerfile
を作成して独自のdockerイメージを作成することができます。
以下に手順を示します。
Dockerfileの作成-docker build
コマンド
以下はホストPCで実行します。
/data/my-ubuntu-image
というディレクトリを作成して、そこにDockerfile
(拡張子なし)を作成します。
# ディレクトリを作成
mkdir /data/my-ubuntu-image
# ディレクトリに移動
cd /data/my-ubuntu-image
# ファイル作成
touch Dockerfile
# テキストエディタで開く
nano Dockerfile
以下のように編集します。
# 元となるdockerイメージ
FROM ubuntu:22.04
# 2バイト文字対応設定
ENV LANG=C.UTF-8
ENV LANGUAGE=en_US:
# テキストエディタnanoをインストールする
RUN apt-get update && apt-get install nano
# ワーキングディレクトリの設定
RUN mkdir /app
WORKDIR /app
docker build
コマンドでイメージを作成します。
docker build -t my-ubuntu:1.0 .
末尾の"."を忘れないでください。これはDockerfile
へのパスを指定しています。
コマンドを実行しているディレクトリにDockerfile
があるのでカレントディレクトリを示す"."を指定しています。
-t
オプションは、タグを指定するオプションです。作成するイメージの名称を指定します。my-ubuntu:1.0
というのはイメージ名my-ubuntu
でバージョンが1.0
であることを示しています。
完了後docker images
コマンドを実行すると、my-ubuntu:1.0
というイメージが作成されたことが確認できます。
docker images
# 結果
REPOSITORY TAG IMAGE ID CREATED SIZE
my-ubuntu 1.0 5e52b0214d5c 3 minutes ago 929MB
作成したイメージからコンテナを作成し動作確認
my-ubuntu:1.0
イメージからコンテナを作成します。
動作確認だけなので、コンテナ終了後、コンテナが破棄される--rm
オプションを付与します。
docker run --rm -it my-ubuntu:1.0 /bin/bash
テキストエディタで日本語入力ができることを確認してください。
nano hoge.txt
ubuntu:22.04
イメージからコンテナを作成したときと異なり、最初から、テキストエディタがインストールされており2バイト文字に対応していることに注目してください。
node
イメージ
node
イメージを用いてNode.jsのコンテナを作成し、ローカルにWebサーバーを建ててブラウザでアクセスするまでを説明します。
nodeイメージについて
当方が最初疑問に思ったところを記述します。
Node.jsはOSではなく処理系です。何故OSではないNode.jsをコンテナに展開してlinuxコマンドが使えるのか?と思ったことがあります。
nodeイメージはNode.jsで開発するためのコンテナを展開するためのイメージであり、LinuxディストリビューションであるDebian上にNode.jsをインストールした状態の環境が展開されます。
つまりnodeイメージを実行して作成されるコンテナのOSはDebianです。
少し話がそれますが、DockerコンテナはLinuxカーネル(WSLの場合、Linuxカーネルをエミュレートしたもの)上で実行されます。Dockerイメージに含まれるOSはLinuxベースである必要があります。
太字の部分、ChatGPTとの対話で情報を得ました。
nodeイメージをベースにdockerイメージを作成
(参考)docker hubのnode:18.15.0のページ
18.15.0
タグの選定理由はNode.jsの公式サイトを確認したとき2023/03/31現在、LTS版のバージョンが18.15.0だったからです。
作業用ディレクトリを/data/node
とします。
mkdir /data/node
cd /data/node
Dockerfile
を作成します。
下の例ではtouch
コマンドでファイル作成せずにnano
コマンドでファイル名をDockerfile
を指定して実行ます。
こうすると、nano
を閉じるときに保存すれば、編集した内容でファイルが作成されます。
nano Dockerfile
Dockerfile
の内容は以下のようにします。
FROM node:18.15.0
# 2バイト文字に対応させる
ENV LANG=C.UTF-8
ENV LANGUAGE=en_US:
# テキストエディタをインストールする。
RUN apt-get update && apt-get install nano
# /appディレクトリを作成し、それを作業ディレクトリとする。
RUN mkdir /app
WORKDIR /app
docker build
コマンドでmy-node
というdockerイメージをタグ1.0
で作成します。
docker build -t my-node:1.0 .
docker ps
コマンドで作成したイメージがリストに表示されることを確認してください。
コンテナを作成
作成したmy-node:1.0
イメージを元にコンテナを作成します。
ホストPC側に/data/node/my-node-project
ディレクトリを作成しこれをコンテナのボリュームに指定します。
mkdir /data/node/my-node-project
docker run --name my-node-project -it -v /data/node/my-node-project:/app -w /app my-node:1.0 /bin/bash
ここからは作成したコンテナ内での作業です。Node.jsでWEBサーバーを建てます。
元となるapp.js
というファイルを作成します。
VSCodeでコンテナにアタッチしてコーディングしてもよいですが、当例ではターミナル上でテキストエディタを用いてコーディングします。この節においてコードの内容は重要ではないのでコードについては考えなくてよいです。ポート3000を使ってローカルにWEBサーバを建てているとだけ理解してください。
nano app.js
app.js
の内容は以下です。
ポート3000でWEBサーバーを建てます。ブラウザ等でhttp://localhost:3000
にアクセスすると、Hello world!
と表示されることを期待しています。
const http = require('http');
const server = http.createServer((req, res) => {
res.end('Hello world!');
});
server.listen(3000);
console.log(`Server listen on port 3000.`);
以下のコマンドで作成したapp.js
を実行します。
node app.js
# 正常な場合、ターミナルに以下のように表示されます。
Server listen on port 3000.
ブラウザでhttp://localhost:3000
にアクセスしてみてください。Hellor world!
が表示され...ません。
これはコンテナ内のport3000がホストPCと繋がっていないためです。
以下より、ブラウザでHello world!
が表示されるようにしていきます。
その前に、まず実行中のapp.js
を停止させ、コンテナも破棄します。
コンテナ作成時に-v
オプションでホストPCのディレクトリにコンテナのワーキングディレクトリをマウントしたので、コンテナを削除しても、ホストPCにコードは残っています。
プログラムの停止はctrl
+c
キーを押します。
その後、exit
でコンテナを抜けてdocker stop
コマンドでコンテナを停止させ、docker rm
コマンドでコンテナを破棄します。
# コンテナ内で実行します。
exit
# 以下よりホストPCで実行します。
docker stop my-node-project
docker rm my-node-project
-p
オプション
docker run
コマンドでコンテナを作成する際、-p
オプションを使用してホストPCとコンテナ内のポートを紐づけます。
docker run --name my-node-project -it -v /data/node/my-node-project:/app -w /app -p 3000:3000 my-node:1.0 /bin/bash
上記コマンドの-p 3000:3000
の部分に注目してください。
ポートの指定の記述方法は-p <ホストのポート>:<コンテナのポート>
です。
ですので上記の例はホストのポート3000をコンテナのポート3000に紐づけています。
また-v
オプションの部分にも注目してください。先ほど破棄したコンテナと同じディレクトリを指定しています。
これにより先ほど破棄したコンテナ内で作成したコード、これが残っているので、これを再利用しています。
コンテナ内でls -l
を実行すると、app.js
があることを確認できます。
# コンテナ内で実行します。
ls -l
# 結果
-rw-r--r-- 1 root root 177 Mar 31 06:28 app.js
ではapp.js
を実行してブラウザでhttp://localhost:3000
にアクセスしてみてください。
node app.js
Hello world!
が表示されたはずです。
まとめ
いかがでしたでしょうか。当方最初はさっぱり分かりませんでしたが、何度かコマンド実行していくうちに何とか理解できるようになりました。何度もコマンドを入力して見るのが良いと思います。
最後に登場したコマンドやファイルについて説明し、当ドキュメントを閉じます。
-
docker pull
コマンド
dockerイメージを取得するコマンドです。指定したイメージをダウンロードします。 -
docker run
コマンド
dockerイメージを元にコンテナを作成するコマンドです。 -
docker start
コマンド
指定したコンテナを開始するコマンドです。 -
docker stop
コマンド
指定したコンテナを停止させるコマンドです。 -
docker ps
コマンド
コンテナを一覧表示するコマンドです。-a
オプション無しで実行すると実行中のコンテナをリストアップし、-a
オプション有りで実行すると、停止中のコンテナもリストアップします。 -
Dockerfile
dockerイメージを作成するための元となるファイルです。 -
docker build
コマンド
作成したDockerfile
を元にdockerイメージを作成します。
以上です。