【Docker】Dockerをはじめてみる
Dockerとは
Dockerはアプリケーションを開発、配布、実行するためのオープンプラットフォームです。 コンテナと呼ばれる仮想化技術を使用し、分離された環境でアプリケーションをパッケージ化して実行する機能を提供します。
少し難しいかもしれないので、まずは基本的なことについてから簡単に説明をしていきます。
仮想化
仮想化は、コンピュータ上で仮想的なリソースや環境を作り出す技術です。 例えばサーバー仮想化であれば、1台の物理サーバー上に複数の仮想サーバーを構築することができ、物理サーバーのメモリやストレージなどのハードウェアリソースをそれぞれの仮想サーバーに割り当てます。 これら仮想化の管理にはソフトウェアが必要で、代表的なものとしてVMware、Microsoft Hyper-V、XenServerなどが利用されています。
仮想化技術は、主にホストOS型、ハイパーバイザー型、コンテナ型の3つに分類されます。
ホストOS型は、ホストOSに仮想化ソフトウェアをインストールし、仮想サーバーを構築します。 ハイパーバイザー型は、ホストOSを必要とせず、ハードウェアにインストールした仮想化ソフトウェアによって仮想サーバーを構築します。 どちらにもメリット、デメリットがありますが、共通していることは、仮想サーバー上のOS(ゲストOS)上でアプリケーションを動かす必要があります。
コンテナ
コンテナは、ゲストOSを必要とせず、様々なアプリケーション(ソフトウェア)を入れて実行することができます。 例えばPHP、Nginx、MySQLを入れて、コンテナ内でWEBアプリケーションを構築するといったことが可能です。 (※ゲストOSが利用できないということではありません。)
各々のコンテナは隔離された状態で動いています。 コンテナからホストOSや他のコンテナのプロセスにアクセスすることはできません。 またリソースも隔離されており、コンテナ毎にルートディレクトリやIPアドレスなどが割り当てられます。
開発者にとって、コンテナの利用にはいくつかのメリットがあります。
- アプリケーションの管理OS上にインストールしたアプリケーションの管理は非常に面倒です(私感)。 過去の開発で使用したアプリケーションがそのまま残り続けるなんてことはよくあることだと思います。 例えばJavaなど複数バージョンの管理(同居管理)が必要なものもあります。
コンテナを利用すれば、コンテナ単位でアプリケーションを管理でき、不要になればコンテナを停止・削除するだけで済みます。 バージョンの同居もコンテナで分ければ問題ではなくなります。
- 環境の管理・移行・分配コンテナは、イメージとして出力することで他の端末にスムーズに移すことなどができます。 例えば新規の開発メンバーが開発環境を構築する場合、必要なアプリケーションを個別にインストールするのではなく、イメージを渡せば簡単に構築できますし、統一も取れます。 また前述のようにコンテナはホストOSからは隔離された環境のため、開発者毎のOSの種類やバージョンに依存しません。
- デプロイコンテナはそのまま本番環境として利用することができます。 本番環境へデプロイする場合は、対象コンテナのイメージを作成し、それを本番環境で展開するといった感じです。 このイメージの作成〜本番環境の展開までのデプロイ作業は、CI/CDによって自動化が可能です。
便利ではあるのですが、他の仮想化と比べて学習コストが高いのが難点です。 (備忘録的な記事のため、筆者も執筆時点ではよくわかっていないです。)
コンテナを利用するために、DockerやKubernetesといったソフトウェアが必要となります。 Dockerは単一のコンテナを作成・実行するためのもので、Kubernetesは複数のコンテナを管理するためのものになります。 Docker単体でも利用は可能ですが、複数のコンテナを利用する場合はKubernetesと組み合わせて使用することが多いようです。
イメージ
Dockerでコンテナを構築する上で重要になるのがDockerイメージです。 イメージは、コンテナを構築するためのファイルやスクリプト、設定などがまとめられたテンプレートになります。 このテンプレートからコンテナを作成することになります。 イメージは変更ができないため、同じイメージであればどの環境でも同じコンテナ環境が構築されます。 そのため、前述のような開発者への配布やデプロイの自動化などが可能になるわけです。
イメージ自体の作成にはDockerfileを用います。 Dockerfileは、使用するアプリケーションの情報などコンテナの構成要素をテキストベースで記述したファイルであり、これをビルドすることによってイメージを作成します。 またコンテナそのものからイメージを作成することも可能です。
イメージは、Docker Hubなどのレジストリで公開されているものもあり、ここから必要なイメージを取得(pull)することができます。 また自身で作成したイメージをDocker Hubに登録(push)することもできます。
Dockerのインストール
以下サイトからOSに該当するファイルを取得してインストールをします。 インストール手順は下記サイトに記載があるため、ここでの説明は省きます。
https://matsuand.github.io/docs.docker.jp.onthefly/get-docker/
インストール後、以下コマンドでDockerのバージョンが確認できることを試してみてください。
$ docker --version
Docker version 24.0.7, build afdd53b
Dockerの基本操作
Dockerは以下のようなコマンドを用いて操作します。
コマンド | 説明 |
---|---|
image pull | Docker HubからDockerイメージを取得する |
image ls | 取得済みのDockerイメージの一覧を表示する |
image rm | 取得済みのDockerイメージを削除する |
image save | イメージをファイルに保存する |
image load | イメージのファイルを読み込む |
container run | Dockerイメージからコンテナを作成する |
container ls | コンテナ一覧を取得する |
container rm | コンテナを削除する |
container start | 停止中のコンテナを起動する |
container stop | 起動中のコンテナを停止する |
container kill | 起動中のコンテナを強制的に停止する |
container exec | コンテナ上のコマンドを実行する |
container commit | コンテナの変更状態からDockerイメージを作成する |
Docker v1.13以降コマンドが新しくなっています。旧コマンドも利用できますがここでは新コマンドを使用していきます。
イメージの操作
まずはコンテナの作成に必要なイメージを取得します。 以下はubuntuのイメージを取得する例です。
$ docker image pull ubuntu
ubuntuのレジストリは以下のURLにあります。
このページのTagsタブを開いてみてください。
同じubuntuでもバージョンが異なれば構成、すなわちイメージファイルも異なります。
このバージョン(イメージ)の違いをタグをつけることによって判別できるようになっています。
上記のコマンドではlatest(最新)のubuntuイメージが取得できていると思います。
タグを指定する場合はimage:tag
のようにします。
$ docker image pull ubuntu:20.04
取得したイメージは以下のコマンドで表示できます。
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu latest e2e172ecd069 13 days ago 69.3MB
ubuntu 20.04 fde9c12d7d3f 6 weeks ago 65.7MB
ここに表示されているIMAGE ID
は、イメージを一意に識別するための情報となります。
タグは同じイメージに複数設定できるため、別のタグでも同じイメージということがあります。
これを判断するためにIMAGE ID
の値を比較します。
イメージを削除するには以下のコマンドを実行します。
$ docker image rm ubuntu
この場合はlatestのイメージが削除されます。
タグを指定する場合は、取得時と同様にimage:tag
とします。
$ docker image rm ubuntu:20.04
またIMAGE ID
を指定することでも削除できます。
$ docker image rm e2e172ecd069
コンテナの作成
コンテナを作成するためには以下のコマンドを実行します。
$ docker container run hello-world
478afc919002: Pull complete
Digest: sha256:4bd78111b6914a99dbc560e6a20eab57ff6655aea4a80c50b0c5491968cbc2e6
Status: Downloaded newer image for hello-world:latest
Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
(arm64v8)
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.
To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash
上記はhello-world
というイメージを使用してコンテナを作成しています。
上記のように実行結果が表示されていれば成功です。
指定したイメージが端末上に存在しない場合は、pullが実行されます。
次に以下のコマンドでubuntuのコンテナを作成します。
$ docker container run -it ubuntu bash
root@c0b56aa19d60:/# ls
bin boot dev etc home lib media mnt opt proc root run sbin srv sys tmp usr var
root@c0b56aa19d60:/# exit
するとターミナルがroot@XXXXXXX
のようになります。
これはbashを通じてubuntuのコンテナにアクセスしている状態になります。
試しにls
コマンド実行してみると、ubuntuのディレクトリ構成が表示されます。
終了する場合はexit
コマンドを実行します。
オプション指定している-i
と-t
についてですが、これによってターミナルからubuntuが操作できるようになります。
コンテナはデフォルトではターミナルからの標準入力を受け付けませんが、-i
によって受け付けるようになります。
試しに-i
のみで実行してみます。
$ docker container run -i ubuntu bash
ls #lsと入力してEnter
bin
boot
dev
etc
home
lib
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var
exit #exitと入力してEnter
実行すると何も表示されませんが、先ほどと同様にls
コマンドなどを実行するとその実行結果が表示されます。
一応操作はできますが、かなり見にくい状態です。
そこで-t
によって擬似的なTTY(Teletypewriter)を割り当てます。TTYとは標準入力となっている端末デバイスであり、これにより表示結果が整形されます。
ひとまずは-it
はおまじないと思っていても問題ないかと思います。
コンテナの操作
では一度現在コンテナの状態を以下のコマンドで確認します。
-a
オプションは停止中のコンテナを表示に含めます。オプションがない場合は起動中のコンテナのみが表示されます。
$ docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c0b56aa19d60 ubuntu "bash" 23 seconds ago Exited (0) 5 seconds ago hardcore_wing
bd3a99508f88 hello-world "/hello" 15 minutes ago Exited (0) 14 minutes ago funny_mirzakhani
表示結果のCONTAINER ID
とNAMES
はコンテナを識別するための値です。
コンテナを操作の際には、どちらかの値で対象のコンテナを指定します。
ここではNAMES
を使用することとします。
上記ではNAMES
はランダムに生成されていますが、コンテナ作成時に--name
オプションによって指定することができます。
$ docker container run -it --name ubuntu_test ubuntu bash
STATUS
はコンテナの状態を表します。Exited
は現在停止していることを表します。
試しに以下のコマンドでubuntuのコンテナを起動し、STATUS
の値を確認します。
$ docker container start hardcore_wing
$ docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c0b56aa19d60 ubuntu "bash" 5 minutes ago Up 4 seconds hardcore_wing
bd3a99508f88 hello-world "/hello" 20 minutes ago Exited (0) 19 minutes ago funny_mirzakhani
見ての通りSTATUS
がUp
になりました。これは起動中であることを表しています。
コンテナを停止させる場合は以下のコマンドを実行します。
$ docker container stop hardcore_wing
コンテナを再起動させる場合は以下のコマンドを実行します。
$ docker container restart hardcore_wing
コンテナを削除する場合は以下のコマンドを実行します。
起動中のコンテナはそのままでは削除できないため、停止するか-f
オプションを指定します。
$ docker container rm hardcore_wing
$ docker container rm -f hardcore_wing
コマンドの実行
上記のdocker container start
によってコンテナを起動させることはできましたが、docker container run
の時のようにubuntuのコンテナを操作できる状態にはありません。
コンテナを操作するためには以下のコマンドを実行します。
$ docker container exec -it hardcore_wing bash
これは、対象コンテナのbash
コマンドを実行するという内容になります。
例えばbash
をls
に変えると、ubuntuのルートディレクトリの情報が表示されます。
$ docker container exec -t hardcore_wing ls
bin boot dev etc hello.txt home lib media mnt opt proc root run sbin srv sys tmp usr var
このようにコンテナ内のコマンドは、docker container exec
によって実行することが可能です。
イメージの作成
現在のコンテナの状態からイメージを作成することを考えます。 違いがわかるようにコンテナ内にファイルを作成しておきます。
$ docker container exec -it hardcore_wing bash
root@c0b56aa19d60:/# echo Hello World > hello.txt
root@c0b56aa19d60:/# ls
bin boot dev etc hello.txt home lib media mnt opt proc root run sbin srv sys tmp usr var
コンテナからイメージを作成するためには以下のコマンドを実行します。
$ docker container commit hardcore_wing myubuntu:1.0
myubuntu:1.0
はイメージ名とタグになります。
docker image ls
でイメージが作成されているか確認します。
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
myubuntu 1.0 202ec66e7ed0 34 minutes ago 69.3MB
ubuntu latest e2e172ecd069 2 weeks ago 69.3MB
次に作成したイメージでコンテナを作成し、イメージ作成前に作ったhello.txt
があるかを確認します。
$ docker container run -it myubuntu bash
root@86b7df2ccefe:/# ls
bin boot dev etc hello.txt home lib media mnt opt proc root run sbin srv sys tmp usr var
root@86b7df2ccefe:/# cat hello.txt
Hello World!
このようにdocker container commit
によってコンテナの状態からイメージを作成することができます。
イメージの保存・読込
イメージは以下のコマンドでアーカイブファイルとして保存することができます。
$ docker image save -o myubuntu_image.tar myubuntu
先ほど作成したmyubuntu
のイメージを、myubuntu_image.tar
という名前でカレントディレクトリに保存しました。
保存したアーカイブファイルは、以下のコマンドで再度イメージとして読み込むことができます。
$ docker image load -i myubuntu_image.tar
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
myubuntu 1.0 202ec66e7ed0 About an hour ago 69.3MB
デタッチモード
NgnixをDockerで起動させてみます。
$ docker container run -it -p 8080:80 --name webserver nginx
-p
オプションはポートの割り当てになります。上記は80番ポートを8080番ポートになるような指定になります。
http://localhost:8080
にアクセスしてWelcome to nginx!
と表示されれば問題なく起動できています。
終了する場合はCtrl + C
を入力します。
Nginxの起動中、ターミナルはNginxのログが出力されており、使用できない状態になっているかと思います。
それでは困るため、Nginx起動中もターミナルが利用できるように-d
オプションを指定します。
$ docker container run -dit -p 8080:80 --name webserver nginx
これによってターミナルが利用できる状態になったかと思います。
この状態をデタッチモードといい、-d
はデタッチモード(バックグラウンド)で起動するというオプションになります。
オプションを指定しなかった場合は、アタッチモードという状態(フォワグラウンド)で起動しています。
ubuntuではアタッチモードで問題ないのですが、Nginxのようにデタッチモード出ないと困るケースもあります。
デタッチモードで起動したコンテナをアタッチモードに変更するには、以下のコマンドを使用します。
$ docker container attach webserver
アタッチモードからデタッチモードに変更するには、Ctrl + P + Q
を入力します。
ここで注意が必要なのは、コンテナ作成時に-it
オプションを指定しなければ、上記キー入力は効果がありません。