目次

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

Docker 20.10.1

y2sunlight 2020-12-20

Dockerに戻る

関連記事

リンク

PHPを例にとって、Dockerコンテナの作成方法を説明します。この例では、Docker Hubの公開リポジトリ(パブリックリポジトリ)で配布されているPHPコンテナを使って、自分用に設定したPHPのDockerイメージを作成します。

本章の実行環境

本章の実行例は WindowsターミナルのUbuntuターミナルで実行しています。dockerの初期設定については、こちらを参照して下さい。


ベースイメージの取得

Dockerイメージは、多層構造になっていて、それらの各層(レイア)が透過的に重なり1つのファイルシステムを構成しています。各層はディレクトリやファイルを含み、またはメタ情報だけの層もあります。Docker イメージを作成する場合は、ベースとなる層の上に自分のイメージを作成します。このベースとなるイメージを以降は「ベースイメージ」と呼びます。

多くの場合、Dockerイメージは、その基になるベースイメージから始まります。そのイメージは親イメージと呼ばれ、Docker Hub から取得できます。本章では、以下のベースイメージを使用します。

この中の Apache+PHP7.4 用のコンテナから、タグ 7.4-apache のイメージをdocker pull コマンドでダウンロードします:

$ docker pull php:7.4-apache

PHPコンテナのベースイメージはパッケージの依存関係などもありOSのベースが本番環境ともに同じものを利用します。ここで選択したphp:7.4-apache のOSのベースは、このイメージの Dockerfile を調べると debian:buster-slim だという事が分かります。このベースは Debian 10 で処理系なしの軽量な実行環境用のイメージです。

OSのベースイメージ選びについては、以下のサイトが参考になりました:


ベースイメージの調査

ダウンロードしたDockerイメージ php:7.4-apachedocker run コマンドでコンテナとして開始します。この時、操作し易いようにコンテナに名前( php74 )を付け、またホストからブラウザでアクセスできるようにポート 8080 にフォワードしています:

$ docker run --name php74 -d -p 8080:80 php:7.4-apache
$ docker ps
CONTAINER ID   IMAGE            COMMAND                  CREATED         STATUS         PORTS                  NAMES
373a10d11ec1   php:7.4-apache   "docker-php-entrypoi…"   2 minutes ago   Up 2 minutes   0.0.0.0:8080->80/tcp   php74

次に、docker exec コマンドで php74 コンテナ内で、bash コマンドを実行します:

$ docker exec -it php74 bash

これで、ベースイメージを調査する準備ができました。

Apacheの設定ファイル( apache2.conf )の場所を確認します:

# ls -l /etc/apache2/apache2.conf
-rw-r--r-- 1 root root 7224 Aug 25 20:08 /etc/apache2/apache2.conf

Apacheのサイト構成ファイル( 000-default.conf )の場所を確認します:

# ls -l /etc/apache2/sites-available/000-default.conf
-rw-r--r-- 1 1000 1000 1469 Dec 21 06:06 /etc/apache2/sites-available/000-default.conf

以下のようにして、PHPの設定ファイルの場所を調べます。

# php -r "phpinfo();" | grep php.ini
Configuration File (php.ini) Path => /usr/local/etc/php
# ls /usr/local/etc/php -l
total 148
drwxr-xr-x 1 root root  4096 Dec 11 08:24 conf.d
-rw-r--r-- 1 root root 72553 Dec 11 08:24 php.ini-development
-rw-r--r-- 1 root root 72583 Dec 11 08:24 php.ini-production

これで、ApacheとPHPの設定ファイルの場所と名前が分かったので、それをホスト側にコピーします。この作業は、別のターミナルを起動してホスト側で、docker cp コマンドを使って行います:

$ docker cp php74:/etc/apache2/apache2.conf .
$ docker cp php74:/etc/apache2/sites-available/000-default.conf .
$ docker cp php74:/usr/local/etc/php/php.ini-development ./
$ docker cp php74:/usr/local/etc/php/php.ini-production ./


コンテナ内のファイルの変更と追加

設定ファイルの変更

ホスト側で、先にコンテナから取得した以下のファイルを編集します。

ここでは、例として以下のように 000-default.conf を修正します。

000-default.conf
<VirtualHost *:80>
        ...
        # For testing docker
        <Directory /var/www/html>
                Options Indexes FollowSymLinks Includes ExecCGI
                AllowOverride All
                Require all granted
        </Directory>
        ...
</VirtualHost>

編集が終わったら、これらの設定ファイルをコンテナにコピーします。

$ docker cp ./apache2.conf php74:/etc/apache2/
$ docker cp ./000-default.conf php74:/etc/apache2/sites-available/
$ docker cp ./php.ini-development php74:/usr/local/etc/php/php.ini

コンテナを再起動します:

$ docker restart php74

Winodws側のプラウザから http://localhost:8080/ にアクセスするとコンテナのドキュメントルーツのindexが表示されます。


htmlとphpファイルの設置

以下のように、hello.html と info.php を新しく作成します:

hello.html
<html>
<body>
  <p>Hello form Docker!</p>
</body>
</html>
info.php
<?php phpinfo();

作成したファイルをコンテナのドキュメントルートにコピーします:

$ docker cp ./hello.html php74:/var/www/html/
$ docker cp ./info.php php74:/var/www/html/

Winodws側のプラウザから http://localhost:8080/ にアクセスするとコンテナのドキュメントルーツのindexが表示されます。


PHP拡張モジュールの追加

DockerイメージにPHP拡張モジュールを追加する場合の視点は次の4つがあります:

  1. コンパイル済の拡張モジュール — ベースイメージのPHPに既にコンパイルされて追加されている
  2. PHPコア拡張モジュール — 公式PHP Dockerイメージを利用して簡単にインストールできる
  3. PECL拡張モジュール — PECLから入手できる(peclコマンドを使います)
  4. その他の拡張モジュール — phpize、make コマンドなどを使って手動でインストールする

DockerでのPHP拡張モジュールの追加については、是非、以下のURLの「How to install more PHP extensions」の項を一読されることを推奨します。

以下に「その他の拡張モジュール」を除くそれぞれの場合について説明します。


コンパイル済の拡張モジュール

多くの拡張モジュールは既にコンパイルされてモジュールに格納されています。本章では、apache ドキュメントルートに作成した info.php からそれを調べることができます:

http://localhost:8080/info.php

また、コンテナ内部から php -m コマンドでこれを確認することもできます。実行例:

# php -m
[PHP Modules]
Core
ctype
curl
date
dom
fileinfo
filter
ftp
hash
iconv
json
libxml
mbstring
mysqlnd
openssl
pcre
PDO
pdo_sqlite
Phar
posix
readline
Reflection
session
SimpleXML
sodium
SPL
sqlite3
standard
tokenizer
xml
xmlreader
xmlwriter
zlib

これらのモジュールについては既に存在するので追加の必要はありません。


PHPコア拡張モジュールの追加

ここで言う「 PHPコア拡張モジュール」とは公式PHP Dockerイメージ を利用して、インストールできる拡張モジュールを指しています。「公式PHP Dockerイメージ」を親に持つベースイメージを使う場合は、この方法が利用できます。どの拡張モジュールが対象となっているかは、以下の docker-php-extension-installer プロジェクトの Supported PHP extensions を参照して下さい:

これらの拡張モジュールは、圧縮されてDockerイメージの中に含まれており、以下の3つのヘルパースクリプトを使って簡単にインストールできます。

例:gdのインストール

例として PHP拡張モジュール gd をインストールします。gd は使用する画像イメージの種類によって様々なバリエーションがあります。以下のサイトに詳しい説明があります。ここでは、png と jpeg が使えるようにします。

以下の作業は、コンテナ内で行います。

まずは、パッケージの一覧を更新します:

# apt update

gd の使用するパッケージをインストールします:

# apt install -y zlib1g-dev libpng-dev libjpeg62-turbo-dev

gd をインストールし、PHP拡張モジュールとして有効にします:

# docker-php-ext-configure gd --with-jpeg
# docker-php-ext-install -j$(nproc) gd

インストール後、extension_dir の中に gd.so がインストールされています:

# ls /usr/local/lib/php/extensions/no-debug-non-zts-20190902/*.so -l
-rwxr-xr-x 1 root root 426544 Dec 21 08:41 /usr/local/lib/php/extensions/no-debug-non-zts-20190902/gd.so
...

また、php.iniのインクルードファイルが追加されています:

# ls -l /usr/local/etc/php/conf.d/*.ini
-rw-r--r-- 1 root root 16 Dec 21 08:41 /usr/local/etc/php/conf.d/docker-php-ext-gd.ini
...
docker-php-ext-gd.ini
extension=gd.so

exit でコンテナから出て、ホストでコンテナ(php74)を再起動します。

$ docker restart php74

Winodws側のプラウザから http://localhost:8080/info.php にアクセスすると gd がインストールされているのが確認できます。


PECL拡張モジュールの追加

PECLからインストールするには、[https://www.php.net/manual/ja/install.pecl.pear.php|pecl コマンド]を使用します。pecl install を使用してダウンロードしてコンパイルしてから、docker-php-ext-enable を使用して拡張モジュールを有効にします。

例:memcachedのインストール

PECL からインストール例として memcached を取り上げます。以下の作業は、コンテナ内で行います。

まず、パッケージの一覧を更新し、memcached が依存しているパッケージをインストールしておきます:

# apt update
# apt install -y libmemcached-dev

pecl コマンドを使用して、memcached インストールします:

# pecl install memcached

以下は、インストールの実行例です:

# pecl install memcached
pecl/memcached can optionally use PHP extension "igbinary" (version >= 2.0)
pecl/memcached can optionally use PHP extension "msgpack" (version >= 2.0)
...
 
libmemcached directory [no] :      # [Enter]入力
zlib directory [no] :              # [Enter]入力
use system fastlz [no] :           # [Enter]入力
enable igbinary serializer [no] :  # [Enter]入力
enable msgpack serializer [no] :   # [Enter]入力
enable json serializer [no] :      # [Enter]入力
enable server protocol [no] :      # [Enter]入力
enable sasl [yes] :                # [Enter]入力
enable sessions [yes] :            # [Enter]入力
 
...
Build process completed successfully
Installing '/usr/local/lib/php/extensions/no-debug-non-zts-20190902/memcached.so'
install ok: channel://pecl.php.net/memcached-3.1.5
configuration option "php_ini" is not set to php.ini location
You should add "extension=memcached.so" to php.ini

最後に、docker-php-ext-enable を使用して拡張モジュールを有効にします:

# docker-php-ext-enable memcached

インストール後、extension_dir の中に gd.so がインストールされています:

# ls /usr/local/lib/php/extensions/no-debug-non-zts-20190902/*.so -l
-rw-r--r-- 1 root root 729464 Dec 22 13:29 /usr/local/lib/php/extensions/no-debug-non-zts-20190902/memcached.so
...

また、php.iniのインクルードファイルが追加されています:

# ls -l /usr/local/etc/php/conf.d/*.ini
-rw-r--r-- 1 root root 20 Dec 21 11:32 docker-php-ext-memcached.ini
...
docker-php-ext-memcached.ini
extension=memcached

exit でコンテナから出て、ホストでコンテナ(php74)を再起動します:

$ docker restart php74

Winodws側のプラウザから http://localhost:8080/info.php にアクセスすると memcached がインストールされているのが確認できます。


イメージの保存

以下の作業はホストで行います。

開始中のコンテナ(php74)を停止します。

$ docker stop php74

これまでに作成したコンテナをDockerイメージとして保存するには、docker commit コマンドを使います。

$ docker commit php74 myphp74:2020-12-22
sha256:d743369242c56be71e47f1e7ad0f5b218ff8a61c923643fc475c6d01dbb23cda

保存したDockerイメージを docker images コマンドで確認します。

$ docker images
REPOSITORY    TAG          IMAGE ID       CREATED              SIZE
myphp74       2020-12-22   62df1ffadc6f   About a minute ago   439MB
...

保存したDockerイメージを起動します。

$ docker run --name myphp74 -d -p 8080:80 myphp74:2020-12-22
23d84d5ce0837cdbf171695c417fe387793aadbdf497b341d24d398ef9ae809a

Winodws側のプラウザから http://localhost:8080/info.php にアクセスして、gdmemcached がインストールされているか確認して下さい。


Dockerfile

これまでの項では、手動でDockerコンテナを作成しイメージとして保存しました。これら一連のDockerイメージの作成過程を自動化してくれるのが「Dockerfile」です。Dockerfile とは、Docker イメージを作成する時のコマンドを1つのファイルにまとめたもので、Docker コンテナの構成情報を記述するためのファイルです。

これまでの項で作成してものと全く同じDockerイメージを本項では Dockerfile を使って作成します。以下の作業は全てホストで行います。


作業ディレクトリの準備

ホームディレクトリ下に以下の作業ディレクトリを作成します:

~/docker/php7.4

このディレクトリの中にこれまでに作成した次のファイルを準備します。


Dockerfile

以下のように、Dockerfile を編集します:

Dockerfile
FROM php:7.4-apache
#
# Apache/PHP Base Settings
#
COPY ./apache2.conf /etc/apache2/
COPY ./000-default.conf /etc/apache2/sites-available/
COPY ./php.ini-development /usr/local/etc/php/php.ini
#
# /var/www/html/
#
COPY ./hello.html /var/www/html/
COPY ./info.php /var/www/html/
#
# Install PHP Extensions
#
# gd
#
RUN apt-get update
RUN apt-get install -y zlib1g-dev libpng-dev libjpeg62-turbo-dev \
  && docker-php-ext-configure gd --with-jpeg \
  && docker-php-ext-install -j$(nproc) gd
#
# memcached
#
RUN apt-get install -y libmemcached-dev \
  && pecl install memcached \
  && docker-php-ext-enable memcached
Dockerfileで apt を使うと次の警告が出るので apt-get を使いました。
WARNING: apt does not have a stable CLI interface. Use with caution in scripts.
また、apt-get を使うと今度は次の警告がでます。buildの動作的にはは問題なさそうですが調査中です。
debconf: delaying package configuration, since apt-utils is not installed

Dockerfile の詳細については、以下を参照して下さい:


Dockerイメージの作成

Dockerfileの準備が出来たら、docker build コマンドを使って新しい Docker イメージを構築します。

$ docker build -t myphp74:2020-12-23 .

docker images コマンドでDockerイメージの一覧を表示します:

$ docker images
REPOSITORY    TAG          IMAGE ID       CREATED              SIZE
REPOSITORY    TAG          IMAGE ID       CREATED          SIZE
myphp74       2020-12-23   d849c91871fd   15 minutes ago   440MB
myphp74       2020-12-22   62df1ffadc6f   13 hours ago     439MB
...

docker history コマンドでイメージ内のレイヤーを表示します:

$ docker history myphp74:2020-12-23
IMAGE          CREATED          CREATED BY                                      SIZE      COMMENT
d849c91871fd   17 minutes ago   /bin/sh -c apt-get install -y libmemcached-d…   4.19MB
30fc1a25dfb9   18 minutes ago   /bin/sh -c apt-get install -y zlib1g-dev lib…   4.23MB
17d39386f699   18 minutes ago   /bin/sh -c apt-get update                       17.5MB
778c23eca0cd   24 minutes ago   /bin/sh -c #(nop) COPY file:c9b0bd401ba1924c…   17B
5645b898b5af   24 minutes ago   /bin/sh -c #(nop) COPY file:398875164d45e85a…   58B
9fc74c528658   24 minutes ago   /bin/sh -c #(nop) COPY file:f9dcd09c7428c2df…   72.6kB
e0878c88c727   24 minutes ago   /bin/sh -c #(nop) COPY file:0c73f4a9191f660f…   1.54kB
89628e4477f9   24 minutes ago   /bin/sh -c #(nop) COPY file:7a59a6bc15702a48…   7.22kB
fd505f1f4cd8   11 days ago      /bin/sh -c #(nop)  CMD ["apache2-foreground"]   0B
<missing>      11 days ago      /bin/sh -c #(nop)  EXPOSE 80                    0B
<missing>      11 days ago      /bin/sh -c #(nop) WORKDIR /var/www/html         0B
...
<missing>      12 days ago      /bin/sh -c #(nop) ADD file:3a7bff4e139bcacc5…   69.2MB

Dockerfileに記述した降順にレイヤー作成されているのが分かります。CMD [“apache2-foreground”] 以下のレイヤーはベースイメージのものです。


Dockerイメージの起動

Dockerfileから構築したDockerイメージを起動し、Winodws側のプラウザから http://localhost:8080 にアクセスして確認して下さい。

$ docker run --name myphp74a -d -p 8080:80 myphp74:2020-12-23
7980e3ed36186de445238eae2193b3f505fed04ac03a50c5ac3adb6cc7a405dd

このように Dockerfile を使えば、Dockerイメージを素早く作れるだけでなく、GitHubなどのリポジトリによってチーム内で共有することもできます。


イメージのアップロード

ここまでで、新しいDockerイメージの作成に関する説明は終わりました。後は、DockerイメージをDocker Hubにアップロードするだけとなりましたが、Docker Hub に関して本章で説明するのは情報過多なので、改めて以下の章で説明することにします: