4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

docker runコマンドをマッスルメモリーする

Posted at

当ドキュメントの目的

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.04dockerイメージから作成する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.txt
    abcdefghijolmnopqrstuvwxyz
    

    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

以下のように編集します。

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の内容は以下のようにします。

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!と表示されることを期待しています。

app.js
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イメージを作成します。

以上です。

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?