====== Docker コンテナイメージの作成(Build) ====== Docker 20.10.1 --- //[[http://www.y2sunlight.com|y2sunlight]] 2020-12-20// [[docker:top|Dockerに戻る]] 関連記事 * [[wsl2:ubuntu:docker|WSL2/Ubuntu に Docker をインストールする]] * [[docker:20:basic|Dcoker コンテナの基本的な利用方法(Run)]] * Docker コンテナイメージの作成(Bulid) リンク * [[https://docs.docker.jp/engine/reference/commandline/index.html|Docker コマンドリファレンス]] --- Docker日本語ドキュメント * [[https://docs.docker.jp/engine/reference/builder.html|Dockerfile リファレンス]] --- Docker日本語ドキュメント * [[https://hub.docker.com/_/php|PHPのDocker公式イメージ]] --- Docker Hub PHPを例にとって、Dockerコンテナの作成方法を説明します。この例では、Docker Hubの公開リポジトリ(パブリックリポジトリ)で配布されているPHPコンテナを使って、自分用に設定したPHPのDockerイメージを作成します。 === 本章の実行環境 ==== * Windows10Pro / WSL2 * Ubuntu 20.04.1 LTS 本章の実行例は WindowsターミナルのUbuntuターミナルで実行しています。dockerの初期設定については、[[wsl2:ubuntu:docker#初期設定|こちら]]を参照して下さい。 ---- ===== ベースイメージの取得 ===== Dockerイメージは、多層構造になっていて、それらの各層(レイア)が透過的に重なり1つのファイルシステムを構成しています。各層はディレクトリやファイルを含み、またはメタ情報だけの層もあります。Docker イメージを作成する場合は、ベースとなる層の上に自分のイメージを作成します。このベースとなるイメージを以降は「ベースイメージ」と呼びます。 多くの場合、Dockerイメージは、その基になるベースイメージから始まります。そのイメージは親イメージと呼ばれ、Docker Hub から取得できます。本章では、以下のベースイメージを使用します。 * [[https://hub.docker.com/_/php|]] --- PHP Docker公式イメージ この中の Apache+PHP7.4 用のコンテナから、タグ ''7.4-apache'' のイメージを[[http://docs.docker.jp/v17.06/engine/reference/commandline/pull.html|docker pull]] コマンドでダウンロードします: $ docker pull php:7.4-apache PHPコンテナのベースイメージはパッケージの依存関係などもありOSのベースが本番環境ともに同じものを利用します。ここで選択した''php:7.4-apache'' のOSのベースは、このイメージの [[https://github.com/docker-library/php/blob/0274f58b8dcf68a23d8fd77101d2d4c74d38fc65/7.4/buster/apache/Dockerfile|Dockerfile]] を調べると ''debian:buster-slim'' だという事が分かります。このベースは Debian 10 で処理系なしの軽量な実行環境用のイメージです。 OSのベースイメージ選びについては、以下のサイトが参考になりました: * https://blog.mosuke.tech/entry/2020/07/09/container-image-size/ \\ ===== ベースイメージの調査 ===== ダウンロードしたDockerイメージ ''php:7.4-apache'' を [[http://docs.docker.jp/v17.06/engine/reference/commandline/run.html|docker 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 次に、[[http://docs.docker.jp/v17.06/engine/reference/commandline/run.html|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の設定ファイルの場所と名前が分かったので、それをホスト側にコピーします。この作業は、別のターミナルを起動してホスト側で、[[http://docs.docker.jp/v17.06/engine/reference/commandline/run.html|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 ./ \\ ===== コンテナ内のファイルの変更と追加 ===== ==== 設定ファイルの変更 ==== ホスト側で、先にコンテナから取得した以下のファイルを編集します。 * apache2.conf --- Apacheの設定ファイル * 000-default.conf --- Apacheのサイト構成ファイル * php.ini-development --- PHPの設定ファイル ここでは、例として以下のように ''000-default.conf'' を修正します。 ... # For testing docker Options Indexes FollowSymLinks Includes ExecCGI AllowOverride All Require all granted ... * ドキュメントルート ''/var/www/html'' のファイル一覧表示を許可 * その他、ほとんどの操作を許可しています 編集が終わったら、これらの設定ファイルをコンテナにコピーします。 $ 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が表示されます。 [{{:docker:20:build:docker-20-build01.png?nolink}}] \\ ==== htmlとphpファイルの設置 ==== 以下のように、hello.html と info.php を新しく作成します:

Hello form Docker!

作成したファイルをコンテナのドキュメントルートにコピーします: $ docker cp ./hello.html php74:/var/www/html/ $ docker cp ./info.php php74:/var/www/html/ Winodws側のプラウザから ''http://localhost:8080/'' にアクセスするとコンテナのドキュメントルーツのindexが表示されます。 [{{:docker:20:build:docker-20-build02.png?nolink}}] \\ ===== PHP拡張モジュールの追加 ===== DockerイメージにPHP拡張モジュールを追加する場合の視点は次の4つがあります: - コンパイル済の拡張モジュール --- ベースイメージのPHPに既にコンパイルされて追加されている - PHPコア拡張モジュール --- [[https://hub.docker.com/_/php/|公式PHP Dockerイメージ]]を利用して簡単にインストールできる - PECL拡張モジュール --- PECLから入手できる(peclコマンドを使います) - その他の拡張モジュール --- phpize、make コマンドなどを使って手動でインストールする DockerでのPHP拡張モジュールの追加については、是非、以下のURLの「How to install more PHP extensions」の項を一読されることを推奨します。 * https://hub.docker.com/_/php 以下に「その他の拡張モジュール」を除くそれぞれの場合について説明します。 \\ ==== コンパイル済の拡張モジュール ==== 多くの拡張モジュールは既にコンパイルされてモジュールに格納されています。本章では、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コア拡張モジュール」とは[[https://hub.docker.com/_/php/|公式PHP Dockerイメージ]] を利用して、インストールできる拡張モジュールを指しています。「公式PHP Dockerイメージ」を親に持つベースイメージを使う場合は、この方法が利用できます。どの拡張モジュールが対象となっているかは、以下の ''docker-php-extension-installer'' プロジェクトの ''Supported PHP extensions'' を参照して下さい: * https://github.com/mlocati/docker-php-extension-installer これらの拡張モジュールは、圧縮されてDockerイメージの中に含まれており、以下の3つのヘルパースクリプトを使って簡単にインストールできます。 * ''docker-php-ext-configure'' --- 拡張モジュールにカスタム構成が必要な場合に ''docker-php-ext-install'' の前に実行します。 * ''docker-php-ext-install'' --- 拡張モジュールをインストールします。 * ''docker-php-ext-enable'' --- ''pecl'' コマンドなど、''docker-php-ext-instal'' 以外で拡張モジュールをインストールした後に使用し、''php.ini'' に拡張モジュールの有効性を設定します。 === 例:gdのインストール === 例として PHP拡張モジュール ''gd'' をインストールします。gd は使用する画像イメージの種類によって様々なバリエーションがあります。以下のサイトに詳しい説明があります。ここでは、png と jpeg が使えるようにします。 * https://tt-computing.com/docker-php-gd 以下の作業は、コンテナ内で行います。 まずは、パッケージの一覧を更新します: # 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 * ''docker-php-ext-configure'' は ''docker-php-ext-install'' の前で実行する必要があります。 * ''docker-php-ext-install'' の ''-j$(nproc)'' オプションは同時実行できる処理数で、CPU数を指定しています。 * ''docker-php-ext-enable'' は ''docker-php-ext-install'' によって実行されます。 インストール後、''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 ... extension=gd.so ''exit'' でコンテナから出て、ホストでコンテナ(''php74'')を再起動します。 $ docker restart php74 Winodws側のプラウザから ''http://localhost:8080/info.php'' にアクセスすると ''gd'' がインストールされているのが確認できます。 [{{:docker:20:build:docker-20-build03.png?nolink}}] \\ ==== PECL拡張モジュールの追加 ==== [[https://pecl.php.net/|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 * インストールの最中にオプションを聞かれますが、全て[Enter]を入力します。 最後に、''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 ... extension=memcached exit でコンテナから出て、ホストでコンテナ(php74)を再起動します: $ docker restart php74 Winodws側のプラウザから ''http://localhost:8080/info.php'' にアクセスすると ''memcached'' がインストールされているのが確認できます。 [{{:docker:20:build:docker-20-build04.png?nolink}}] \\ ===== イメージの保存 ===== 以下の作業はホストで行います。 開始中のコンテナ(''php74'')を停止します。 $ docker stop php74 これまでに作成したコンテナをDockerイメージとして保存するには、[[http://docs.docker.jp/v17.06/engine/reference/commandline/commit.html|docker commit]] コマンドを使います。 $ docker commit php74 myphp74:2020-12-22 sha256:d743369242c56be71e47f1e7ad0f5b218ff8a61c923643fc475c6d01dbb23cda 保存したDockerイメージを [[http://docs.docker.jp/v17.06/engine/reference/commandline/images.html|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'' にアクセスして、''gd'' と ''memcached'' がインストールされているか確認して下さい。 [{{:docker:20:build:docker-20-build05.png?nolink}}] \\ ===== Dockerfile ===== これまでの項では、手動でDockerコンテナを作成しイメージとして保存しました。これら一連のDockerイメージの作成過程を自動化してくれるのが「Dockerfile」です。Dockerfile とは、Docker イメージを作成する時のコマンドを1つのファイルにまとめたもので、Docker コンテナの構成情報を記述するためのファイルです。 これまでの項で作成してものと全く同じDockerイメージを本項では Dockerfile を使って作成します。以下の作業は全てホストで行います。 \\ ==== 作業ディレクトリの準備 ==== ホームディレクトリ下に以下の作業ディレクトリを作成します: ~/docker/php7.4 このディレクトリの中にこれまでに作成した次のファイルを準備します。 * Dockerfile --- コンテナ構成ファイル * apache2.conf --- Apacheの設定ファイル * 000-default.conf --- Apacheのサイト構成ファイル * php.ini-development --- PHPの設定ファイル(開発用) * php.ini-production --- PHPの設定ファイル(本番用) * hello.html --- テスト用のhtml ファイル * info.php --- テスト用のphpファイル \\ ==== 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 * ''FROM'' --- イメージ構築の初期化を実行し、ベースイメージを設定します。Dockerfileは必ず''FROM''命令から始まります。 * ''COPY'' --- ホスト内のファイルやディレクトリをコンテナ内のファイルシステムに追加します。 * ''RUN'' --- 現在の最新イメージにおいて、コンテナ内でコマンドを実行します。コマンドが成功するとイメージは確定され、Dockerfile の次のステップで利用されます。 > 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 の詳細については、以下を参照して下さい: * [[https://docs.docker.jp/engine/reference/builder.html|Dockerfile リファレンス]] --- Docker日本語ドキュメント \\ ==== Dockerイメージの作成 ==== Dockerfileの準備が出来たら、[[https://docs.docker.jp/engine/reference/commandline/build.html|docker build]] コマンドを使って新しい Docker イメージを構築します。 $ docker build -t myphp74:2020-12-23 . * ''-t'' --- '名前:タグ' 形式でイメージの名前とタグ(オプション)を指定します。 * コマンドの最後の引数( ''.'' )はソースコードのパス(ここではカレントディレクトリ)を指定します。 [[https://docs.docker.jp/engine/reference/commandline/images.html|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 ... [[https://docs.docker.jp/engine/reference/commandline/history.html|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 11 days ago /bin/sh -c #(nop) EXPOSE 80 0B 11 days ago /bin/sh -c #(nop) WORKDIR /var/www/html 0B ... 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 に関して本章で説明するのは情報過多なので、改めて以下の章で説明することにします: * [[docker:20:hub|DockerHubの利用(Ship)]] \\