Webの実行環境はコンテナ化が進み、productionに合わせて開発環境もコンテナ化するケースが主流になりました。
コンテナ化のメリットには、次のようなものがあります。
- 実行環境を再利用できる
- セットアップ・プロセスがコードになる
これらは、自ら構築した環境を復元したり別のインフラに移すことが圧倒的に手軽になると同時に、環境を含めて検証済のパッケージが増える、カスタマイズの自由度が増えるというメリットもあります。
kubernetes vs docker
結論から言えば、コンテナを採用するとなったときに、今となってはdockerを採用する理由は弱いと言えます。
production競争で、kubernetesが圧倒的に勝ったからです。 dockerはコンテナ実装の着手が早かったことと、Mac開発環境のデスクトップパッケージが普及した点で知名度があります。実際に使われている、という点も含めて、開発環境はdockerというイメージがあるかもしれません。
kubernetesとdockerの違いは、主にセットアップコード(manifest)の非互換性です。
kubernetes向けのYAMLマニフェストを書くとproductionとdevelopment環境の両方で動作し得ます。
productionがkubernetesなのであれば、開発環境もkubernetesをまず評価した方が良いでしょう。
docker-compose上に構築すると環境の乖離が進み、Day 1から負債化するシナリオがあります。
k8sベースの代替選択肢はいくつかありますが、 k3s がほぼproduction機能を持っています。
docker -> kubernetes の連続性
マニフェストの違いは避けられませんが、コンテナ構成になること自体は旧来のベアメタルと比べれば kubernetes 移行のステップにはなります。
マルチホスト構成の獲得
dockerでは1コンテナ=1サービスという構成を指向していることもあり、たとえばApache+PHPとMySQLの2コンテナ構成をとることが多くなります。
1台の開発機(たとえばノートPC)で複数のOSを立ち上げることは従来のVMでは無駄が多かったのですが、コンテナではオーバーヘッドが少ないため特に問題なく複数のOS環境を構築できます。
本番環境でも開発機上のWebサーバーとDBMSの接続設定をある程度活用できるため、ネットワーク構成上は処理容量の上限を相当かせぐことが可能になります。
このようにdockerでひとまずアプリケーションが動作する環境を作っておけば、先々アクセスが増えて環境を移行するケースが発生しても短期間で構築しやすいというメリットを得られます。
パブリッククラウドへのシームレスな移行
RailsやPHPといったWebアプリケーションフレームワークを利用して開発したサービスでは、アプリケーションそのもののコード開発と別に、一定のOS環境依存が発生します。
kubernetesとdockerのコンテナイメージは互換性があるため、コンテナ起動の基礎的な動作はkubernetesに移行してもある程度同じです。
dockerでコンテナイメージやその構築手順を確立しておけば、パブリッククラウド移行でも活用できます。
またクラウドサービスは、ネットワークレイヤの拡張機能が豊富にあります。この部分は各サービス独自の部分が多いため、けっきょくのところ開発環境をk8sで運用しても追加のセットアップは必要になるでしょう。。
Docker Composeの概要
必要なツールのセットアップは各OS用のDockerをインストールするだけでひと通り揃いますが、インストール後はとくにガイドがなく各自で環境を設計する必要があります。
ここからはdockerベースの実装を概観します。docker-compose.ymlの文法とdocker...のコマンド群が全体的にkubernetesとパラレルワールドになっています。
基層の仕様は共有している部分がありますが、開発者に接触するインターフェースはまったく別です。
Docker Composeで複数コンテナを構築する
多くのWebサービスは、RDBMS(MySQL・PostgreSQLなど)、Webサーバー(Apache・nginxなど)、アプリサーバー(PHP・ruby・python・Javaなど)の3層構造になっています。
そのため、Webサービス向けのDocker開発環境も、複数のコンテナ間で通信する構成を作ります。
基本的な設定は docker-compose.yml に記載します。コンテナ群を一括操作するdocker-composeコマンドは、カレントディレクトリからこのファイルを探して参照します。
複数のプロジェクトを作成する際は、別のディレクトリにdocker-compose.ymlを作成しカレントディレクトリを移動するだけで、環境を手軽に切り替えられます。
docker-compose.ymlの設定例
Webサービス向けのコンテナ設定例は、以下のような記述になります。YAML形式の設定ファイルはインデント幅(スペースの数)も意味を持つので注意してください。
version: '2'
services:
app:
image: php:7.0-apache
ports:
- "80:80"
- "443:443"
depends_on:
- "mysql"
environment:
DB_NAME: somepj_dev
DB_HOST: somepj_mysql_1
volumes:
- $DOCKER_PATH/somepj:/var/www/html/
mysql:
image: mysql:5.7
ports:
- "3306:3306"
volumes:
- $DOCKER_PATH/somepj-data/:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: some-root-password
networks:
default:
external:
name: somepjnet
この作例では、PHP環境の例として、appとmysqlという2つのコンテナを設定しています。PHPの公式イメージにはApache上で動作するPHP環境があるため、Web+AppとDBMSの2層構造をとっています。
複数コンテナの構成で重要なのは、appサーバーからmysqlサーバーに接続する部分を理解することです。
dockerは内部ネットワークを定義することで、コンテナ間をホスト名で接続できます。
内部ネットワークの定義は、先ほどの設定後半networksブロックの部分で指定しています。
指定するネットワーク(この例ではsomepjnet)はコンテナ起動前に一度
$ docker network create somepjnet
といったコマンドで作成しておく必要があります( dockerのネットワーク設定 で解説)。
この設定により、各コンテナは somepj_app_1, somepj_mysql_1 といった名前で動作します(コンテナ起動後であれば、docker container lsコマンドで確認できます)。
名称はアンダースコアで区切られており「カレントディレクトリ名_コンテナ名_コンテナ番号」というルールになっています。
ホスト名が決まれば、フレームワークごとのDB設定ファイルに somepj_mysql_1 などを指定すれば接続できるはずです(Dockerの手順ではなく、各Webフレームワークの手順です)。
先ほどの設定例では、environmentディレクティブを利用して、環境変数DB_HOSTにこのホストを指定しています。環境変数を介した設定のメリットは、コンテナの設定で起動時に接続先を切り替えられることです。
その他、各ディレクティブの詳細については、公式ドキュメントを参照してください。
volumeを利用してコードをPC上で編集
今回のケースでは、アプリケーションのソースコードをappホストのvolumesディレクトリで参照しています。
/var/www/html はphp:7.0-apacheイメージのドキュメントルートになっているため、ドキュメントルート以下のファイルを直接編集できるのと同じ効果があります。
PHPの場合はファイルの変更により、そのままアプリの挙動が変わるためPC上のファイルを変更してブラウザを更新すれば新しいコード部分を即時確認できます。
(portsディレクティブで80:80と443:443を指定しているため、http://localhost/でアクセスできます。httpsもアクセス可能ですが、証明書設定を完結できないためエラーになるでしょう)
docker-composeの変数指定について
先ほどのdocker-compose.ymlに記載した$DOCKER_PATHは、同じディレクトリにある.envファイルで設定した変数を参照しています。
.envは以下のように、シェルスクリプトと同様の形式で変数を定義できます。
DOCKER_PATH=/home/some_user/docker
dockerの設定では、volumeを通じてPC上のファイルを直接利用したいケースが多々あります。このようにトップディレクトリを変数化しておくことで、複数のユーザー間で開発コンテナ設定を共有するケースでも各自の置き場所を設定するだけで動作する環境を作れます。
なお、docker-composeには env_file という機能もありますが、これはコンテナ上の環境変数をコンテナ間で共通指定する機能で目的は異なります。
関連するセットアップ
docker-composeをセットアップすることで、複数コンテナを相互に通信可能な状態で一括起動できます。
ここまでの段階では、まだDBデータが空の状態であるためデータロードする必要があります。論理バックアップからのリストアなど、コンテナ上のDBMS手順については『 Dockerでデータベースを実運用 』を参照してください。