[初心者向け] Dockerで簡単なWebコンテナとDBコンテナを作ってみよう

# [初心者向け] Dockerで簡単なWebコンテナとDBコンテナを作ってみよう
## 前置き
最近Dockerに触れる機会があったので、復習がてら簡単なWebコンテナとDBコンテナを作成して
コンテナ間で通信するまでの手順をまとめたいと思います。初心者向けの内容となっています。
Dockerは知っている前提です。

### 環境
- Windows10 Home
- Docker Desktop
  - インストールは[こちら](https://docs.docker.jp/docker-for-windows/install.html)から

### 構成
- docker-compose利用
- DBコンテナ
  - OS:alpine
  - postgresql11
- Webコンテナ
  - OS:centos7
  - apache2.4
  - php7.4

DBコンテナはDocker-hubに公開されているpostgres公式のイメージを使ってサクッと作ります。  
一方Webコンテナは必要なパッケージを選んで作る形でやってみます。

## docker-composeとは
docker-composeは、複数のDockerコンテナを操作するためのツール(コマンド)です。
docker-composeはDocker Desktopに含まれているため、別途インストールする必要はありません。
docker-composeはdocker-compose.ymlというファイルに複数のDockerコンテナの定義を記述しておき、
`docker-compose build`(Dockerイメージの作成)や`docker-compose up -d`(Dockerコンテナの起動)
といったコマンドで複数のDockerイメージ・コンテナを操作することができます。

早速必要なファイルを作成していきます。

```
作業ディレクトリ
|docker-compose.yml
|-db
|   Dockerfile
|-web
    Dockerfile
```

## DBコンテナ
### Dockerfile作成
```db/Dockerfile
FROM postgres:11-alpine
ENV LANG ja_JP.utf8
```
DBコンテナ用のDockerfileはこれだけです。
### Dockerfile内容
- FROM: ベースとなるイメージを指定します。
  - ここでは、公開されている[postgres公式のイメージ](https://hub.docker.com/layers/postgres/library/postgres/11-alpine/images/sha256-44e838f01f20c87179dec4f076881f6bef4704959363ac490e2541d05c1c97b9?context=explore)を取得して使用することを示します。

## Webコンテナ
### Dockerfile作成
```web/Dockefile
FROM centos:7

RUN yum update -y
RUN yum install -y httpd
RUN yum install -y vim
RUN yum install -y epel-release && \
    yum install -y http://rpms.remirepo.net/enterprise/remi-release-7.rpm && \
    yum install -y --enablerepo=remi,remi-php74 php php-pdo php-pgsql

RUN systemctl enable httpd
```
### Dockerfile内容
- RUN: ビルド時に実行したいコマンドを記載します。
  - ここでは、主に必要なapache httpdとphp7をインストールしています。(おまけでvim)
- RUN以降の書き方について
  - 上記ではRUNのあとにyumコマンド1つだけのものと、&&で複数つなげているものがあります。
    &&でつなげることでイメージのレイヤ数を抑えることができ、こちらが推奨されているようです。
    このあたりの話は下記が参考になります。
    - [Dockerfile を書くベスト・プラクティス — Docker\-docs\-ja 17\.06\.Beta ドキュメント](https://docs.docker.jp/engine/userguide/eng-image/dockerfile_best-practice.html#run)
    - [Dockerイメージの理解を目指すチュートリアル \- Qiita](https://qiita.com/zembutsu/items/24558f9d0d254e33088f)

## docker-composeファイル作成
```docker-compose.yml
version: "3"

services:
  web:
    build:
      context: ./web
      dockerfile: Dockerfile
    container_name: web
    volumes:
      - ./html:/var/www/html
    ports:
        - "80:80"
    privileged: true
    command: /sbin/init
    networks:
      app_net:
        ipv4_address: 172.30.0.2
  db:
    build:
      context: ./db
      dockerfile: Dockerfile
    container_name: db
    ports:
        - "5432:5432"
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
    networks:
      app_net:
        ipv4_address: 172.30.0.3
networks:
  app_net:
    name: app_net
    driver: bridge
    ipam:
     driver: default
     config:
       - subnet: 172.30.0.0/24
```
### docker-composeファイル内容
主なものを記載します。

- services
  - 起動するコンテナ群の定義。上記の例だと、webとdbという2つを定義していることになります。
- build
  - そのコンテナを構築する際のオプション定義。
  - context  
    - Dockerファイルのあるディレクトリパスを指定。
- volumes
  - dockerを実行しているホストとコンテナをつなぐ設定。
    ここでは、ホスト上のhtmlディレクトリとコンテナ上の/var/www/htmlがリンクするイメージです。
    ちなみにディレクトリではなく、ファイルを指定することも可能。
- ports
  - 公開するポートを指定。":"の左側がホスト上のポート、右側がコンテナ上のポートです。
    ここでは同じポート番号にしています。ホスト上からlocalhost:80でコンテナ上の80に接続できます。
- privileged
  - これはdocker run時に指定するprivilegedオプションにあたります。privilegedオプションについては
    systemctlコマンドで`Failed to get D-Bus connection: Operation not permitted`が出てサービスを
    起動できないことへの対処で設定しており、説明は割愛します。
    - 参考:[CentOS7のDockerコンテナでsystemctlを使えるようにする \- Qiita](https://qiita.com/mikene_koko/items/4c71c969f55e3fe24190)
- command
  - docker-compose upした時に実行したいコマンド

## docker-composeコマンドでbuild～コンテナ起動
build

```bash
# build
$ docker-compose build
# コンテナ起動
$ docker-compose up -d
```

## dbコンテナでテスト用テーブル作成

```bash
# dbコンテナに入る
$ docker-compose exec db /bin/bash
```

以下コンテナ内で作業

```bash
# テストテーブル作成
$ psql -U postgres -c 'create table test (name text)'
# テストデータ作成
$ psql -U postgres -c "insert into test (name) values ('hello'),('world')"
# 一旦コンテナから抜ける
$ exit
```

## webコンテナでテスト用スクリプト作成

```bash
# webコンテナに入る
$ docker-compose exec web /bin/bash
```

以下コンテナ内で作業

```bash
$ cd /var/www/html
$ vi test.php
```

```php:test.php
<?php

$dsn = 'pgsql:dbname=postgres host=172.30.0.3 port=5432';
$user = 'postgres';
$password = 'postgres';

try{
    $dbh = new PDO($dsn, $user, $password);
    $sql = 'select * from test';
    foreach ($dbh->query($sql) as $row) {
        echo $row['name'] . ' ';
    }
}catch (PDOException $e){
    echo $e->getMessage() . PHP_EOL;
    die();
}
```

## 動作確認
http://localhost/test.php へアクセスしてhello worldと表示されれば成功です。

## dockerファイル共有
上記の環境を整え済みのdockerファイルを共有しておきますので、お試し下さい。  
※dbコンテナのテストデータは入っていないため、上記参考にデータ作成して下さい。

```bash
$ git clone https://github.com/jcong7495/docker_simple_web_db.git
```