メインコンテンツに移動
デベロッパーのためのクラウド活用方法

コンテナイメージを実際に作成してみよう ! ~ スペシャリストから学ぶコンテナ技術 第 3 回

2021-08-03 | Author : 原田 和則 / 林 政利

はじめに

こんにちは、テクニカルソリューションアーキテクトの原田です。

スペシャリストから学ぶコンテナ技術 第 1 回」では、環境差分をなくすための手段の 1 つとしてコンテナならびにコンテナ技術について紹介しました。

スペシャリストから学ぶコンテナ技術 第 2 回」では、コンテナ実装のソフトウェアとしてデファクトスタンダードになっている Docker が生まれた背景について紹介しました。

今回は、コンテナイメージの作成を実際に行って、Docker の使い方の基礎を紹介します。
本記事は、原田とコンテナスペシャリスト ソリューションアーキテクトの 林 (@literalice) の共同執筆となります。


(動作環境について)
私の環境は Mac で、Docker for Desktop を利用しています。
この記事はハンズオンでありませんが、Windows や Linux 上でも動きますので、一緒にお試しいただくことも可能です。その場合は、Docker for Desktop を こちらの Docker 社の Web サイト からダウンロード & インストールを行ってください。


X ポスト » | Facebook シェア » | はてブ »

builders.flash メールメンバー登録

builders.flash メールメンバー登録で、毎月の最新アップデート情報とともに、AWS を無料でお試しいただけるクレジットコードを受け取ることができます。 
今すぐ登録 »

何はともあれコンテナを起動する

Docker の場合、コンテナはコンテナイメージから起動します。

「コンテナ」と「コンテナイメージ」の違いが分からないというのは Docker 入門あるあるの 1 つで、詳しい説明は Docker Docs に任せますが、ここでは、「コンテナイメージ = コンテナのテンプレートファイル」、「コンテナ = イメージ ( テンプレート ) から起動した実体 」という理解で十分です。

既に AWS をご利用中の方であれば、 Amazon マシンイメージ (AMI) と EC2 インスタンスの関係と似ていると言えばピンとくるかもしれません。
このコンテナイメージは、誰かがあらかじめ作ったものを利用することも、自分で作成することも可能です。

それではさっそく、具体的に Ubuntu 18.04 のコンテナを起動してみます。
先ほど説明したとおり、Ubuntu 18.04 のコンテナを起動するには、Ubuntu 18.04 のコンテナイメージが必要となるため、まずはそれをローカルにダウンロードします。

コンテナイメージのダウンロード

コンテナイメージをダウンロードする方法ですが、docker pull コマンドでダウンロードできます。コンテナイメージの中身が Ubuntu であっても、Amazon Linux 2 であっても、つまり、中身がどんなイメージであっても、docker pull でダウンロードできます。すごく便利ですね。

これでコンテナイメージをダウンロードする方法は分かりましたが、肝心の「どこ」からダウンロードすればいいかがまだ謎ですね。つまり、どこかにコンテナイメージの保存場所があるわけです。この保存場所のことを一般的にコンテナレジストリ (Container Registry) と言います。

コンテナレジストリからdocker pullコマンドを使ってコンテナイメージを取得する流れを示す日本語の図。

コンテナレジストリ

このコンテナレジストリを提供しているサービスはいくつかあり、その中の 1 つが Docker Hub で、名前を聞いたことある読者の方も多いのではないでしょうか。AWS でも、コンテナレジストリとして、Amazon Elastic Container Registry (ECR) というサービスを提供しており、プライベート用/パブリック用のコンテナレジストリとしてご利用いただけます。

今回は ECR 上に公開されている Ubuntu 18.04 のコンテナイメージ をダウンロードします。

コマンド / コード

bash
$ docker pull public.ecr.aws/ubuntu/ubuntu:18.04   # docker pull <コンテナイメージの公開パス:タグ>  
 
18.04: Pulling from ubuntu/ubuntu
030309cad0ba: Downloading [================>                                  ]  21.44MB/65.62MB
1e77dd81f9fa: Download complete 
6f15325cc380: Download complete 
Status: Downloaded newer image for public.ecr.aws/ubuntu/ubuntu:18.04

ダウンロードの確認

ダウンロードが終わりましたね。念の為、確認します。
ローカルに保存されているコンテナイメージの確認には、 docker images コマンドを利用します。

コマンド / コード

bash
$ docker images
REPOSITORY                                                                                 TAG                 IMAGE ID            CREATED             SIZE   
public.ecr.aws/ubuntu/ubuntu                                                               18.04               6e5f35703668        3 months ago        63.3MB

確認結果

コンテナイメージが 1 つ表示されており、Ubuntu 18.04 のコンテナイメージがローカルに保存されていることが分かります。

それでは、次に、このコンテナイメージから Ubuntu 18.04 コンテナを起動します。

コンテナイメージからコンテナの起動

先ほど、どんなコンテナイメージでも docker pull コマンドでダウンロードできるというお話をしましたが、コンテナの起動に関しても、同様なコマンドが用意されています。それが docker run コマンドです。

つまり、中身がどんなコンテナでも docker run というコマンドで、コンテナイメージからコンテナを起動できます。すごく便利ですね。

それではコンテナを起動してみます。

コンテナイメージから 'docker run' コマンドでコンテナを生成する流れを日本語で示した図。左に青いキューブのコンテナイメージ、右にオレンジ色のコンテナ、中央に 'docker run' コマンド、下にノートパソコンと人物のイラストが描かれている。

コンテナの起動

コマンド / コード

bash
$ docker run -it public.ecr.aws/ubuntu/ubuntu:18.04 bash   ## docker run <起動オプション> <コンテナイメージ> <コンテナ起動時に実行するコマンド>
root@a603c316cdb8:/#  ###コンテナ内のbash###

コンテナ内での作業

Ubuntu 18.04 コンテナイメージからコンテナが起動して、その中で root ユーザーとして bash が起動しています。

やや見にくいのですが、以下の部分は、Ubuntu コンテナ内の bash を表示しています。

コンテナ内のBashプロンプト

コマンド / コード

bash
root@a603c316cdb8:/#

OS とユーザーの確認

試しに、OS やユーザーを確認してみると、OS が Ubuntu 18.04 であること、そして、root ユーザーとして bash を起動していることが分かります。

次に、このコンテナ中で、Node.js で書いた簡単なアプリケーションを動かしてみたいと思います。

OSとユーザー情報の確認

コマンド / コード

bash
root@a603c316cdb8:/# whoami
root

root@a603c316cdb8:/# cat /etc/os-release 
NAME="Ubuntu"
VERSION="18.04.5 LTS (Bionic Beaver)"
~ 省略 ~

コンテナ内で簡単なアプリケーションを動かす

まず、このコンテナに Node.js をインストールします。
コンテナとして動いてはいますが、中身は Ubuntu 18.04 ですので、apt コマンドでインストールします。

Node.jsのインストール

コマンド / コード

bash
root@a603c316cdb8:/# apt update
~ 省略 ~
root@a603c316cdb8:/# apt install -y nodejs   ## Node.js のインストール
~ 省略 ~
root@a603c316cdb8:/# which node   ## Node.js がインストールされたことを確認
/usr/bin/node

アプリケーションコードを用意して、コンテナ内で実行する

それでは、次に、簡単なアプリケーションコードを 1 つ用意して、実行してみます。
具体的には、標準出力に Hello, world と表示するだけの JavaScript コード (index.js) をコンテナ内で作成し、実行します。

JavaScript コードの作成と実行

コマンド / コード

javascript
root@a603c316cdb8:/# echo "console.log('Hello, world')" > index.js   # JavaScript コードの作成
root@a603c316cdb8:/#
root@a603c316cdb8:/# node index.js  # 作成したコードを実行
Hello, world

アプリケーション入りコンテナの完成

Hello, world と表示されているので、問題なくアプリケーションが動いていることが確認できました。
かなりシンプルなのであまり実感はないかもしれませんが、これでアプリケーションがインストールされたコンテナの完成です。

次に、このアプリケーション入りコンテナを再利用 (例えば、別の環境でも同じコンテナを起動) できるように、コンテナイメージを作成します。

コンテナイメージ作成プロセスを示した日本語の図解。左に『コンテナ』、右に『アプリケーション入りコンテナ』があり、コンテナ内でapt installコマンドを実行する流れが矢印で示されている。下にノートパソコンで作業する人物のイラスト。

コンテナからコンテナイメージを作成する

コンテナ内での作業は終わっているので、コンテナから抜け、Mac の bash に戻ります。

コンテナからの離脱

コマンド / コード

javascript
root@a603c316cdb8:/# exit   # コンテナから抜けます
$  
$  # Mac の bash に戻る

コンテナの状態確認

次に docker ps -a というコンテナ一覧を表示するコマンドを実行して、コンテナの状態を確認してみます。

コンテナ一覧の表示

コマンド / コード

bash
$ docker ps -a   # コンテナ一覧を表示するコマンド
CONTAINER ID        IMAGE                                 COMMAND    CREATED             STATUS                      PORTS                               NAMES
a603c316cdb8        public.ecr.aws/ubuntu/ubuntu:18.04    "bash"     About an hour ago   Exited (0) 43 seconds ago                                       boring_kalam

コンテナ情報の解説

このコンテナは、 a603c316cdb8 という CONTAINER ID を持っており、STATUS が Exited (0) 43 seconds ago となっているため、43 秒前に正常終了しているといったことが分かります。

コンテナイメージの作成

では、このコンテナからコンテナイメージを作ります。
コンテナからコンテナイメージを作るには、docker commit コマンドを利用します。

以下のコマンドで、hello-node-app という名前でコンテナイメージを作成し、そのコンテナイメージに v1 というタグをつけています。ここで、先ほど確認した CONTAINER ID である a603c316cdb8 を使用します。

コンテナイメージの作成 (commit)

コマンド / コード

bash
$ docker commit a603c316cdb8 hello-node-app:v1   # docker commit <コンテナID> <コンテナイメージ名:タグ>
sha256:82502034c657ef02b185c35e77e4ec277e9e23100133b7a65cf1279ea062c5f9

作成の確認

これで、hello-node-app というコンテナイメージが作成されたはずですが、念の為、確認しましょう。
A Japanese language diagram showing the process of using the Docker commit command to create a container image from a running container, with icons and labeled steps for application container and container image.

作成したコンテナイメージの確認

コンテナイメージの確認には、 docker images コマンドを利用します。先ほども使いましたね。

イメージ一覧の再確認

コマンド / コード

bash
$ docker images
REPOSITORY                            TAG                 IMAGE ID            CREATED             SIZE                                                                                TAG                 IMAGE ID            CREATED             SIZE
hello-node-app                        v1                  82502034c657        8 minutes ago       161MB
public.ecr.aws/ubuntu/ubuntu          18.04               6e5f35703668        3 months ago        63.3MB

動作確認

もともとあった Ubuntu 18.04 のコンテナイメージに加えて、先ほど作成した hello-node-app コンテナイメージが増えています。これで、コンテナイメージが作成されていることが確認できました。

それでは、 この hello-node-app コンテナイメージを使ってコンテナを起動してみます。

作成したコンテナイメージからコンテナを起動する

コンテナの起動コマンドは docker run でしたね。さっそく、起動してみます。
今回は、コンテナ内で bash を起動せずに、コンテナ起動時に アプリケーションを実行 (node index.js) してみます。

コンテナの実行

コマンド / コード

javascript
$ docker run hello-node-app:v1 node index.js
Hello, world
$ 

実行結果

Hello, world と表示されているので、アプリケーションは問題なく動いているようです。

動作確認もできたので、これで、アプリケーション入りのコンテナイメージ作成は完了です。

A diagram in Japanese illustrating the process of running an application in a Docker container. It shows a container image with an application, the command '$ docker run ... node index.js', and the resulting container running the app which outputs 'Hello world!!'. A user is shown at a computer at the bottom of the diagram.

docker commit でのコンテナイメージの作成振り返り

今までの流れを少し振り返ってみましょう。

今回は大きく分けて以下の 3 つの手順でアプリケーション入りのコンテナイメージ作成を行いました。

  • docker run コマンドで、Ubuntu 18.04 のコンテナを起動
  • コンテナ内作業で、Node.js のインストールとアプリケーションコードの用意
  • docker commit コマンドで、アプリケーション入りコンテナからコンテナイメージの作成

これらの手順は、使用する OS や動作させるアプリケーションによって多少変わってくると思いますが、基本的には手作業で行います。特に、2 つ目のコンテナ内作業は、今回は簡単なアプリケーションだったため手作業でも特に問題はないかもしれませんが、ビジネスアプリケーションの場合は、フレームワークや依存ライブラリをインストールしたりなど複雑なセットアップ手順が必要なことが多いです。

そして、手順が複雑であればあるほど、どうしても作業ミスが発生しやすくなります。
つまり、環境差分をなくすために Docker を採用したにも関わらず、コンテナイメージの作成が手作業だったために、作成されたコンテナイメージ自体を信用できないといった本末転倒なことになりかねません。

そのため、実運用だと、コンテナイメージを作成する手段として docker commit を使うことはあまりなく、その代わりに Dockerfile という定義ファイルと docker build というコマンドを使って、コンテナイメージを作成することがほとんどです。

ユーザーが『docker run』コマンドで作業用コンテナを起動し、その中で作業を行った後、『docker commit』コマンドでアプリケーション入りのコンテナイメージを作成する流れを示した日本語のイラスト図です。

Dockerfile と docker build でのコンテナイメージの作成

アプリケーションを作るとき、アプリケーションコード以外にも設定ファイルなどいろいろ書くと思いますが、Docker にも設定ファイルがいくつかあります、その 1 つが Dockerfile です。ただ、データベースの接続情報やログの設定といったパラメーターを記載するのではなく、Dockerfile にはこういうコンテナイメージをつくりたいという定義を書きます。

先ほどのコンテナイメージ作成の手順をステップに分けると、以下の 4 つのステップでコンテナを作り、その後、コンテナイメージを作りました。

  • *Ubuntu 18.04 コンテナの中で
  • apt updateapt install -y nodejs を実行し、Node.js をインストール
  • echo "console.log('Hello, world')" > index.js を実行し、アプリケーションコードを用意
  • node index.js を実行し、アプリケーションを実行このステップを Dockerfile に書いてみます。

このステップを Dockerfile に書いてみます。

A Japanese-language diagram illustrating the Dockerfile build process, showing the steps from preparing a Dockerfile, running the 'docker build' command, to creating a container image with an application inside.

Dockerfile とは

アプリケーションを作るとき、アプリケーションコード以外にも設定ファイルなどいろいろ書くと思いますが、Docker にも設定ファイルがいくつかあります、その 1 つが Dockerfile です。ただ、データベースの接続情報やログの設定といったパラメーターを記載するのではなく、Dockerfile にはこういうコンテナイメージをつくりたいという定義を書きます。

先ほどのコンテナイメージ作成の手順をステップに分けると、以下の 4 つのステップでコンテナを作り、その後、コンテナイメージを作りました。

  • *Ubuntu 18.04 コンテナの中で
  • apt updateapt install -y nodejs を実行し、Node.js をインストール
  • echo "console.log('Hello, world')" > index.js を実行し、アプリケーションコードを用意
  • node index.js を実行し、アプリケーションを実行このステップを Dockerfile に書いてみます。

このステップを Dockerfile に書いてみます。

Dockerfile を作る

それでは、テキストエディタで、Dockerfile というファイルを作成し、以下の内容を記載します。

Dockerfileの例

Dockerfileの例

bash
FROM public.ecr.aws/ubuntu/ubuntu:18.04

RUN apt update && apt install -y nodejs

RUN echo "console.log('Hello, world')" > index.js

CMD ["node", "index.js"]

Dockerfile の解説

いかがでしょうか ?
FROM、RUN や CMD の正確な意味は分からなかったとしても、前述の 4 つステップと 1 つ 1 つ比較すると何をやっているのかなんとくなる分かるかと思います。

正確な意味やその他の使い方は こちらの Dockerfile リファレンス に任せますが、今の時点では、以下のような理解で大丈夫です。

Dockerfileの命令

FROM

これから作成するコンテナイメージのベースになるコンテナイメージを指定します。これをベースイメージと言ったりします。
アプリケーション開発に限らず、モノを作る際、なにかベースとなるものがあって、それに修正やアレンジを加えて、新しいモノを作るっていうことをよくやると思うんですが、Docker でもそれを行います。

RUN

ベースイメージから起動したコンテナ内で実行するコマンドを記載します。
複数行書くことも可能で、起動したコンテナの中で、上から順番に記載したコマンドを実行してくれます。
今回だと、Node.js のインストールやアプリケーションコードの用意を行っています。

CMD

作成したコンテナイメージからコンテナを起動した際に、デフォルトで実行してくれるコマンドを指定します。ここには、アプリケーションの実行コマンドを書くことが多いです。
コンテナを起動 (docker run) するだけで、コンテナ内のアプリケーションが起動してくれるのですごく便利です。
CMD の 代わりに ENTRYPOINT を使うこともあります。若干違いはありますが、詳細な説明はここでは割愛します。

Docker 入門者あるある ~ RUN と CMD の違いに悩む ~

Docker 入門者あるあるの 1 つですが、RUN と CMD の用途がごちゃ混ぜになってしまうことがあります。
例えば、以下のように、CMD とすべきところが RUN となっていたりすることがあります。

Dockerfileの間違い例

CMD で指定すべきコマンドを RUN で指定してしまっている例です。

bash
*# Dockerfile 間違い例*
FROM public.ecr.aws/ubuntu/ubuntu:18.04

RUN apt update && apt install -y nodejs

RUN echo "console.log('Hello, world')" > index.js

RUN node index.js   # 正しくは CMD ["node", "index.js"]

RUN と CMD の使い分け

現時点では以下の理解で十分です。

  • RUN は、アプリケーション動作環境のセットアップコマンド (コンテナイメージの作成の際に実行するコマンド)を書く
  • CMD は、アプリケーションの起動コマンド (コンテナ起動時に自動実行されるコマンド) を書く

(node index.js は、アプリケーションを実行するコマンドなので、RUN ではなくて CMD を使うということですね)

Dockerfileの完成

以上で、Dockerfile の完成です。

次に、この Dockerfile を使って、コンテナイメージの作成 (ビルド) を行います。

An illustration showing a person in front of a laptop with Japanese text reading 'Dockerfile の作成' (Dockerfile Creation), representing the process of creating a Dockerfile.

docker build コマンドを使ったコンテナイメージの作成

Dockefile に記載した内容に沿って、コンテナイメージを作成するには docker build というコマンドを利用します。どんなアプリケーションを利用しているか問わず Dockerfile といった必要なファイルを用意しておけば、docker build コマンドで、コンテナイメージを作成することができます。すごく便利ですね。

さっそく コンテナイメージの作成 (ビルド) を行います。
hello-node-app という同じコンテナイメージ名で、今度は v2 というタグ をつけて、コンテナイメージを作成します。

コンテナイメージのビルド

コマンド / コード

bash
$ docker build -t hello-node-app:v2 .   # docker build -t <コンテナイメージ名:タグ> <Dockerfileが存在しているディレクトリ>

Sending build context to Docker daemon  2.048kB
### Step1: ベースイメージの指定
Step 1/4 : FROM public.ecr.aws/ubuntu/ubuntu:18.04
 ---> 6e5f35703668

### Step2: アップデートと Node.js のインストール
Step 2/4 : RUN apt update && apt install -y nodejs
 ---> Running in d0d0490b2526
Get:1 http://archive.ubuntu.com/ubuntu bionic InRelease [242 kB]
~ 省略 ~

### Step3: アプリケーションコードの用意
Step 3/4 : RUN echo "console.log('Hello, world')" > index.js
 ---> Running in ef04fd44bde1

### Step4: コンテナ起動時に、アプリケーションが自動実行されるように設定
Step 4/4 : CMD ["node", "index.js"]
 ---> Running in 2781f17e96aa

Successfully built b978ea3f75e2
Successfully tagged hello-node-app:v2

ビルドプロセスの確認

Dockerfile の中身が、上から順番に Step1, Step2, Step3, Step4 と実行されて、最終的に hello-node-app:v2 というコンテナイメージが作成されていることが分かります。
A Japanese-language diagram depicting the Dockerfile build process, showing a developer, a Dockerfile, the 'docker build' command, and the resulting application container image.

作成したコンテナメージの動作確認

docker images コマンドで、コンテナイメージ一覧を確認すると、v2 というタグがついた hello-node-app というコンテナイメージが確認できます。

イメージ一覧の最終確認

コマンド / コード

bash
$ docker images
REPOSITORY                                                                                 TAG                 IMAGE ID            CREATED             SIZE                                                                                TAG                 IMAGE ID            CREATED             SIZE
hello-node-app                                                                             v1                  82502034c657        58 minutes ago      161MB
hello-node-app                                                                             v2                  b978ea3f75e2        26 minutes ago      161MB
public.ecr.aws/ubuntu/ubuntu                                                               18.04               6e5f35703668        3 months ago        63.3MB

イメージの動作確認

作成したコンテナイメージからコンテナを起動し、アプリケーションの動作確認をしてみます。

Dockerfile 内の CMD の記述で、コンテナ起動時に自動でnode index.js を実行するはずなので、 docker run だけ実行すれば、勝手にアプリケーションが実行されるはずですね。
それではやってみましょう。

v2イメージの実行

コマンド / コード

bash
$ docker run -t hello-node-app:v2
Hello, world

動作確認

Hello, world と出力されていますね。確かに docker run だけで、アプリケーションが起動したことが確認できました。

動作確認もできたので、これで Dockerfile と docker build コマンドを使ったコンテナイメージ作成は完了です。

A Japanese-language diagram explaining how a Docker container image with a Node.js application executes. The visual shows the process from running a Docker container to automatic execution of 'node index.js' as defined in the Dockerfile, with a 'Hello world!!' output message.

まとめ

今回は Docker を使って、アプリケーション入りのコンテナイメージを実際に作成しました。コンテナイメージの作成方法は大きく分けて 2 通り(docker commitdocker build) あり、それぞれ実際に行ってみました。

まず、コンテナ内作業でアプリケーションの動作確認をセットアップしたあと docker commit でコンテナイメージを作成する方法です。次に、コンテナイメージのセットアップやアプリケーション起動手順を記載した Dockerfile を用意して docker build でコンテナイメージ作成する方法です。

どちらの方法でも、最終的にアプリケーション入りのコンテナイメージが作成されるという結果は変わりませんが、途中で述べたように、手作業を極力減らすことで作業ミスを減らすことができたり、自動化の仕組みに載せやすいといった観点などで、実ワークロードだと、後者の「 Dockerfile と docker build を使いコンテナイメージを作成する」ことがほとんどです。

今回の第 3 回は、コンテナイメージの作成にフォーカスして、Docker の基本的な使い方を紹介しました。

次回は、作成したコンテナイメージをコンテナレジストリにアップロードして、別の環境でコンテナを動かしてみながら、少し発展的な内容にも触れてみたいと思います。

A Japanese-language diagram illustrating the Dockerfile build process, showing the steps from preparing a Dockerfile, running the 'docker build' command, to creating a container image with an application inside.

筆者プロフィール

Portrait of an individual with short dark hair and a striped shirt, facing the camera, against a black background.

原田 和則

アマゾン ウェブ サービス ジャパン合同会社
テクニカルソリューションアーキテクト

インフラエンジニアとして経験を積む中で、クラウドに携わりたい想いで AWS へ。
業種業態、技術領域を問わず、様々なお客様の AWS 活用支援を行っています。

A portrait photo of a person with short dark hair and glasses, smiling and wearing a jacket, standing indoors in front of a reflective wall.

林 政利

(@literalice)
アマゾン ウェブ サービス ジャパン合同会社
コンテナスペシャリスト ソリューションアーキテクト

フリーランスや Web 系企業で業務システムや Web サービスの開発、インフラ運用に従事。近年はベンダーでコンテナ技術の普及に努めており、現在、AWS Japan で Amazon ECS や Amazon EKS でのコンテナ運用や開発プロセス構築を中心にソリューションアーキテクトとして活動中。