Docker触ってみる

ソフトウェアをコンテナ化するためのプラットフォームのDockerを使ってみます。

|用語 |意味|
|:-----------|:------------|
| Dockerコンテナ	| アプリケーションとその依存関係を一つのパッケージとして隔離した実行環境 |
| Dockerイメージ	| コンテナの設計図で、必要なソフトウェアやライブラリ、設定が含まれた静的なファイル群 |

# 準備

Windows環境でやっていきます。

Docker Desktopのインストール
https://www.docker.com/get-started/
「Download Docker Desktop」を押してダウンロード、インストールしてください




## Ubuntu
OSです。

Dockerイメージが公開されているDocker Hubを開きます。

Ubuntuを検索
https://hub.docker.com/_/ubuntu

ubuntu:24.04のイメージを使ってみます。
これはubuntuのDockerイメージで24.04というtagがついているものを使うという意味です。
「:latest」というタグは最新版という意味で、pullする時期によって指すバージョンが変わってしまうので、自分でも後で使うかもしれない場合や、他人と共有したりする目的で使うのは避けましょう。


https://hub.docker.com/layers/library/ubuntu/24.04/images/sha256-3afff29dffbc200d202546dc6c4f614edc3b109691e7ab4aa23d02b42ba86790

コンテナを起動すると、元にしたDockerイメージに設定されているデフォルトコマンドが実行されるので、確認しておきます。
デフォルトコマンド:```CMD ["/bin/bash"]```

### ファイル構成

```:directory
project/
　└ compose.yaml
```

Dockerコンテナを複数連携させて管理するための設定ファイルであるcompose.yamlを作成します。


```yaml:compose.yaml
services: # コンテナとして実行するサービスを定義するセクションの開始を意味する
  ubuntu: # サービス名の指定(任意の文字列)　Docker内部のネットワーク名や依存関係の指定に使用
    image: ubuntu:24.04 #タグ名まで含めたDockerイメージの指定
    container_name: ubuntu #コンテナ名の指定(任意の文字列)　docker psで表示される名前
    stdin_open: true # 標準入力を開いたままにする
    tty: true # 仮想端末を有効にする
```    
デフォルトコマンドでbashが指定されていても、stdin_openとttyの設定をしないとbashで操作できないため記載が必要です。
container_nameを省略するとコンテナ名は「Docker Compose が実行されるディレクトリの名前_サービス名_番号」になります


### コンテナを起動

作成したcompose.yamlを元にしてコンテナを起動します

```:terminal
# コンテナを起動
docker compose up

# コンテナをバックグラウンドで起動(-d は "detached" の略で、コンテナをバックグラウンドで起動するオプション)　※基本はこれを使う
docker compose up -d

# イージをビルドし直す時
docker compose up -d --build
 
# キャッシュなしで再ビルド
docker compose build --no-cache 

# コンテナを停止
docker compose down  
``` 
初回コンテナ起動時は使用するDockerイメージがローカルに存在しないのでダウンロードが始まります。

```:terminal
//起動しているコンテナの確認
docker ps
```

|CONTAINER ID|IMAGE|COMMAND|CREATED|STATUS|PORTS|NAMES|
|:-----------|:------------|:------------|:------------|:------------|:------------|:------------|
|e632506d7889|ubuntu:24.04|"/bin/bash"|17 seconds ago|Up 16 seconds||ubuntu|

Docker DesiktopのContainersタブでも確認できます

### 使ってみる
#### bashに接続
```:terminal
//ubuntuコンテナ内でbashシェルを実行する
//docker exec -it コンテナ名 bash 
docker exec -it ubuntu bash 

//bashの入力待ちになるのでコマンドを試してみる
//bashの終了はexit+Enterキー
``` 



## Fedra
OSです。
イメージはfedora:42を使います。

https://hub.docker.com/layers/library/fedora/42/images/sha256-19fcecbd14f2c1e887cbeb974295f5fc0e7b81e2df133e4f1b47a6f65cd11737

デフォルトコマンド:```CMD ["/bin/bash"]```

### ファイル構成

```:directory
project/
　└ compose.yaml
```


```yaml:compose.yaml
services:
  app:
    image: fedora:42
    container_name: fedra
    stdin_open: true  # インタラクティブシェルを有効化（オプション）
    tty: true         # 仮想端末を使用（オプション）
```

コンテナ起動

```:terminal
docker compose up -d
```

### 使ってみる

#### Fedraコンテナ内でbashシェルを実行する

```:terminal
//docker exec -it コンテナ名 /bin/bash
docker exec -it fedra /bin/bash
　
//bashの入力待ちになるのでコマンドを試してみる
//bashの終了はexit+Enterキー
```



## Apache
ウェブサーバーです。
イメージはhttpd:2.4.63を使います。

https://hub.docker.com/layers/library/httpd/2.4.63/images/sha256-7403dba12dd0cd4787ecb367c1eed248e0177f7613767acfc4e6a4906a85da7d


デフォルトコマンド:```CMD ["httpd-foreground"]```

### ファイル構成

```:directory
project/
　├ compose.yaml
  └ html/
     └ index.html
```



```yaml:compose.yaml
services:
  apache:
    image: httpd:2.4.63
    container_name: apache
    ports:
      - "8080:80" #ホストのポート 8080をコンテナのポート80にマッピング
  volumes:
      - ./html:/usr/local/apache2/htdocs/ #プロジェクト/htmlディレクトリをコンテナの/usr/local/apache2/htdocs/ にマッピング
```

```html:html/index.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  HTML
</body>
</html>
```

コンテナ起動

```:terminal
//コンテナを起動
docker-compose up -d
```

 
### 使ってみる
http://localhost:8080 でhtml/index.htmlの内容が表示されます



## nginx
Webサーバーです。
イメージはnginx:1.26.3を使います。
https://hub.docker.com/layers/library/nginx/1.26.3/images/sha256-b1f9004dc208f2c78aa60798f37f37efaf03c0b1df61020e25f36c3894b83651

デフォルトコマンド:```CMD ["nginx" "-g" "daemon off;"]```

### ファイル構成

```:directory
project/
　├ compose.yaml
  ├ html/
  │  └ index.html
  └  nginx
  　　└ default.conf
```



```yaml:compose.yaml
services:
  nginx:
    image: nginx:1.26.3
    container_name: nginx
    ports:
      - "8080:80"
    volumes:
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf
      - ./html:/usr/share/nginx/html
```


```:nginx/default.conf
server {
    listen 80;
    server_name localhost;

    root /usr/share/nginx/html;
    index index.html index.htm;

    location / {
        try_files $uri $uri/ =404;
    }
}
```

```html:html/index.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  HTML
</body>
</html>
```
コンテナ起動
```:terminal
docker-compose up -d
```

### 使ってみる
http://localhost:8080 でindex.htmlの内容が表示されます




## mySQL
RDBMSです。
イメージはmysql:9.0.1を使います

https://hub.docker.com/layers/library/mysql/9.0.1/images/sha256-0cf8b60f74e235c4dd4beb762b10ec6da3dce30265f5f1d40c2c11fa7872ebd9

デフォルトコマンド:```CMD ["mysqld"]```

### ファイル構成

```:directory
project/
　├ compose.yaml
  ├ .env
  ├ html/
  │  └ index.html
  └ nginx
  　 └ default.conf
```



```yaml:compose.yaml
services:
  mysql:
    image: mysql:9.0.1  
    container_name: mysql
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}  
      MYSQL_DATABASE: ${MYSQL_DATABASE}   
    ports:
      - "3306:3306"  # ホストとコンテナ間のポートマッピング
    volumes:
      - mysql_data:/var/lib/mysql  # データの永続化
 
volumes:
  mysql_data:
```



```:.env
MYSQL_ROOT_PASSWORD=example  # MySQLのrootパスワード
MYSQL_DATABASE=mydatabase   # 初期データベース名
```
コンテナ起動
```:terminal
docker-compose up -d
```

### 使ってみる
mySQLにログイン
```:terminal
//docker exec -it mySQLのコンテナ名 mysql -u root -p
docker exec -it mysql mysql -u root -p

//下記が表示されるのでcompose.yamlで指定したrootユーザーのパスワードexampleを入力してEnter
Enter password: 

//mySQLの入力待ちになる

//データベースの一覧表示
SHOW DATABASES;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mydatabase         |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
 5 rows in set (0.02 sec)
 
 
SHOW VARIABLES LIKE '%version%';
+-----------------------------+------------------------------+
| Variable_name               | Value                        |
+-----------------------------+------------------------------+
| admin_tls_version           | TLSv1.2,TLSv1.3              |
| explain_json_format_version | 1                            |
| immediate_server_version    | 999999                       |
| innodb_version              | 9.0.1                        |
| original_server_version     | 999999                       |
| protocol_version            | 10                           |
| replica_type_conversions    |                              |
| slave_type_conversions      |                              |
| tls_version                 | TLSv1.2,TLSv1.3              |
| version                     | 9.0.1                        |
| version_comment             | MySQL Community Server - GPL |
| version_compile_machine     | x86_64                       |
| version_compile_os          | Linux                        |
| version_compile_zlib        | 1.2.13                       |
+-----------------------------+------------------------------+
14 rows in set (0.01 sec)

//mySQLから出るにはexit+Enterキー
 ```
 
 
 

## PHP
 サーバーサイドのスクリプト言語です。
イメージはphp:8.4-fpmを使います。

https://hub.docker.com/layers/library/php/8.4-fpm/images/sha256-d1707c3b288547fad075dddbb04bb5fc47a57ec21f5ea373c591bbcba0f7047a


デフォルトコマンド:```CMD ["php-fpm"]```


### ファイル構成
PHPだけでWebサーバーがないとWebページが表示できないのでnginxも一緒に起動します。
(apacheが同梱されているPHPのDockerイメージもあります)



```:directory
project/
　├ compose.yaml
  ├ html/
  │  └ index.php
  └ nginx/
  　　└ default.conf
```


```yaml:compose.yaml
services:
  nginx:
    image: nginx:1.26.3
    container_name: nginx
    ports:
      - "8080:80"
    volumes:
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf # default.confをコンテナにマウント
    depends_on:
      - php
  php:
    image: php:8.4-fpm
    container_name: php-fpm
    volumes:
      - ./html:/var/www/html # phpコンテナの/var/www/htmlにホストマシンのcompose.yamlと同じ階層にあるhtmlフォルダをマウント
```

```php:html/index.php
<?php
phpinfo();
?>
```

```:nginx/default.conf
server {
    listen 80;
    server_name localhost;

    root /var/www/html;

    index index.php index.html;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_pass php-fpm:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
}
```

コンテナ起動
```:terminal
docker-compose up -d
```


### 使ってみる
http://localhost:8080 を開くとindex.phpの内容が表示されます




## mySQLとphpMyAdmin
phpMyAdminはMySQLデータベースを管理するためのウェブベースのツールです
イメージはphpmyadmin/phpmyadmin:5.2.2を使います

https://hub.docker.com/layers/phpmyadmin/phpmyadmin/5.2.2/images/sha256-95e01f723b5e55fabf16d0473f1df2354c4c6352b35902b51d6a6245e074aee4


デフォルトコマンド:```CMD ["apache2-foreground"]```
### ファイル構成

```:directory
project/
  ├ compose.yaml
  ├ .env
  └ mysql/
  　　└ my.cnf
```



```yaml:compose.yaml
services:
  phpmyadmin:
    image: phpmyadmin/phpmyadmin:5.2.2 # phpmyadmin/phpmyadmin:5.2.2であることに注意
    container_name: phpmyadmin
    ports:
      - "8081:80"  # ホストのポート8081をコンテナの80ポートにマッピング
    environment:
      PMA_HOST:  ${PMA_HOST}    
      PMA_PORT:  3306
      MYSQL_ROOT_PASSWORD:  ${MYSQL_ROOT_PASSWORD}   
    restart: always  # 常に再起動

  mysql:
    image: mysql:9.0.1
    container_name: mysql
    environment:
      MYSQL_ROOT_PASSWORD:  ${MYSQL_ROOT_PASSWORD}   
    volumes:
      - mysql-data:/var/lib/mysql  # データ永続化のためボリュームを使用
      - ./mysql/my.cnf:/etc/mysql/my.cnf  # my.cnf をコンテナにマウント
    ports:
      - "3306:3306"  # MySQLのポートをホストに公開
    restart: always  # 常に再起動
 
volumes:
  mysql-data: # mysql-dataという名前のデータボリュームを作成
    driver: local # ボリュームをホストマシンのファイルシステムに格納(省略可能)
``` 


```:.env
PMA_HOST: mysql  # MySQLのサービス名(コンテナ名ではなく)
MYSQL_ROOT_PASSWORD: example  # MySQLのrootパスワード
```

```:mysql/my.cnf
[mysql]
default-character-set = utf8mb4

[mysqld]
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
default-time-zone = 'Asia/Tokyo'
```


コンテナ起動

```:terminal
docker-compose up -d
```
### 使ってみる
#### phpMyAdmin
GUIでデータベースを操作できます
http://localhost:8081 でphpMyAdminにアクセス


|項目|値|
|---|---|
|ユーザー名|root|
|パスワード|example|

#### mySQL

※Windows環境で、phpMyAdminから入れた日本語が???になってしまう場合の対応
my.cnfを右クリック→プロパティで「読み取り専用」にチェックしてください


###### ログイン
```:terminal
docker exec -it mysql mysql -u root -p
//パスワードを聞かれるので上で設定したものを入力してEnterキー
//mySQLの入力待ちになる

//データベースの一覧表示でphpMyAdminでの操作が反映されていることを確認する
SHOW DATABASES;
```  
(mysqlで日本語を入力すると消えるのは、後半で対応します。)



##### bashにログイン
```:terminal
docker exec -it mysql bash
```






## PHPとnginxとmySQLとphpMyAdmin


### ファイル構成

```:directory
project/
  ├ compose.yaml
  ├ .env
  ├ html/
  │  └ index.php
  ├  mysql
  │  └  my.cnf
  └  nginx/
  　　└ default.conf
```


```yaml:compose.yaml
services:
  nginx:
    image: nginx:1.26.3
    container_name: nginx
    ports:
      - "8080:80"
    volumes:
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf
    depends_on:
       - php
  php:
    image: php:8.4-fpm
    container_name: php-fpm

    command:
      - bash
      - -c
      - |
          apt-get update && apt-get install -y libmariadb-dev && docker-php-ext-install mysqli && php-fpm
    volumes:
      - ./html:/var/www/html
    environment:
      MYSQL_HOST: mysql  # MySQLのホスト名としてサービス名(mysql)を設定
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_PORT: 3306
      MYSQL_DATABASE: ${MYSQL_DATABASE}
    depends_on:
      - mysql


  phpmyadmin:
    image: phpmyadmin/phpmyadmin:5.2.2
    container_name: phpmyadmin
    ports:
      - "8081:80"  # ホストのポート8081をコンテナの80ポートにマッピング
    environment:
      PMA_HOST: ${PMA_HOST}
      PMA_PORT: 3306 
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}  # MySQLのrootパスワード
    restart: always  # 常に再起動
 
  mysql:
    image: mysql:9.0.1
    container_name: mysql
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}  # MySQLのrootパスワード
      MYSQL_DATABASE: ${MYSQL_DATABASE}   
    volumes:
      - mysql-data:/var/lib/mysql  # データ永続化のためボリュームを使用
      - ./mysql/my.cnf:/etc/mysql/my.cnf  # my.cnfをコンテナにマウント
    ports:
      - "3306:3306"  # MySQLのポートをホストに公開
    restart: always  # 常に再起動
 
volumes:
  mysql-data:
    driver: local
```

```:.env
MYSQL_ROOT_PASSWORD=example  # MySQLのrootパスワード
MYSQL_HOST=mysql # MySQLのホスト名（サービス名に合わせる）
PMA_HOST=mysql # MySQLのホスト名（サービス名に合わせる）
MYSQL_DATABASE=mydatabase # MySQLの初期データベース名
```

```:nginx\default.conf
server {
  listen 80;
    server_name localhost;

    root /var/www/html;

    index index.php index.html;

    location / {
      try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
      include fastcgi_params;
      fastcgi_pass php-fpm:9000;
      fastcgi_index index.php;
      fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
  }
}
```

```:mysql\my.cnf
[mysql]
default-character-set = utf8mb4

[mysqld]
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
default-time-zone = 'Asia/Tokyo'
```

```php:html/index.php
<?php
$servername = getenv('MYSQL_HOST');  // MySQLのホスト名（phpコンテナ内のサービス名）
$username = 'root';
$password = getenv('MYSQL_ROOT_PASSWORD');  // rootパスワード
$dbname = getenv('MYSQL_DATABASE');  // テスト用のデータベース名
$port = getenv('MYSQL_PORT');  // ポート番号（環境変数から取得）

// MySQLに接続
$conn = new mysqli($servername, $username, $password, $dbname, $port);  // データベースを指定して接続

if ($conn->connect_error) {
    die("Connection failed: " . $conn->connect_error);
}

// データベースに接続成功
echo "データベース'$dbname'への接続に成功しました。";

// 接続を閉じる
$conn->close();
?>
``` 

コンテナ起動
```:terminal
docker-compose up -d
```


### 使ってみる

http://localhost:8080 で index.phpを表示
http://localhost:8081 を開くとphpMyAdminにアクセス

## Dockerfileの使用
これまでcompose.yamlで頑張ってきましたが、それぞれのコンテナの元になるイメージ自体の変更をするためにDockerfileを使っていきます。


## MySQL(Dockerfile使用版)

|変更箇所|内容|
|---|---|
|compose.yamlの変更|mysqlがimagesだったのをbuildオプションに変更してmysql/Dockerfileを参照するように変更|
|mysql/Dockerfileの追加|日本語ロケールの指定<br>初期化SQLスクリプトの追加|
|mysql/init.sqlの追加|データベースとユーザーを作成するSQL|


### ファイル構成

```:directory
project/
  ├ compose.yaml
  ├ .env
  ├ html/
  │  └ index.php
  ├  mysql/
  │  ├ Dockerfile
  │  ├ init.sql
  │  └ my.cnf
  └  nginx/
  　　└ default.conf
```


```yaml:compose.yaml
services:
  nginx:
    image: nginx:1.26.3
    container_name: nginx
    ports:
      - "8080:80"
    volumes:
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf
    depends_on:
       - php
  php:
    image: php:8.4-fpm
    container_name: php-fpm

    command:
      - bash
      - -c
      - |
          apt-get update && apt-get install -y libmariadb-dev && docker-php-ext-install mysqli && php-fpm
   volumes:
      - ./html:/var/www/html
    environment:
      MYSQL_HOST: mysql  # MySQLのホスト名としてサービス名（mysql）を設定
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_PORT: 3306
    depends_on:
      - mysql


  phpmyadmin:
    image: phpmyadmin/phpmyadmin:5.2.2
    container_name: phpmyadmin
    ports:
      - "8081:80"  # ホストのポート8081をコンテナの80ポートにマッピング
    environment:
      PMA_HOST: ${PMA_HOST}
      PMA_PORT: 3306 
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
    restart: always  # 常に再起動
 
  mysql:
    build:
      context: ./mysql  # mysql フォルダにある Dockerfile を使う
    container_name: mysql
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
    volumes:
      - mysql-data:/var/lib/mysql  # データ永続化のためボリュームを使用
      - ./mysql/my.cnf:/etc/mysql/my.cnf  # my.cnf をコンテナにマウント
    ports:
      - "3306:3306"  # MySQLのポートをホストに公開
    restart: always  # 常に再起動
 
volumes:
  mysql-data:
    driver: local
```

```:.env
MYSQL_ROOT_PASSWORD=example  # MySQLのrootパスワード
MYSQL_HOST=mysql # MySQLのホスト名（サービス名に合わせる）
PMA_HOST=mysql # MySQLのホスト名（サービス名に合わせる）
```

```php:html/index.php
<?php
$servername = getenv('MYSQL_HOST');  // MySQLのホスト名（phpコンテナ内のサービス名）
$username = 'root';
$password = getenv('MYSQL_ROOT_PASSWORD');  // rootパスワード
$dbname = getenv('MYSQL_DATABASE');  // テスト用のデータベース名
$port = getenv('MYSQL_PORT');  // ポート番号（環境変数から取得）

// MySQLに接続
$conn = new mysqli($servername, $username, $password, $dbname, $port);  // データベースを指定して接続

if ($conn->connect_error) {
    die("Connection failed: " . $conn->connect_error);
}

// データベースに接続成功
echo "データベース'$dbname'への接続に成功しました。";

// 接続を閉じる
$conn->close();
?>
```


```Dockerfile:mysql/Dockerfile
FROM mysql:9.0.1

# microdnf を使って bash と locales をインストール
RUN microdnf install -y bash glibc-langpack-ja

# ロケールの設定
ENV LANG ja_JP.UTF-8

# 初期化用SQLをコピー
COPY ./init.sql /docker-entrypoint-initdb.d/
```


```:mysql/my.cnf
[mysql]
default-character-set = utf8mb4

[mysqld]
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
default-time-zone = 'Asia/Tokyo'
```



```:mysql/init.sql
-- 初期データベースの作成
CREATE DATABASE IF NOT EXISTS mydatabase CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

-- ユーザーの作成と権限の付与
CREATE USER IF NOT EXISTS 'myuser'@'%' IDENTIFIED BY 'mypassword';
GRANT ALL PRIVILEGES ON mydatabase.* TO 'myuser'@'%';

-- 権限の反映
FLUSH PRIVILEGES;
``` 

```:nginx/default.conf
server {
  listen 80;
    server_name localhost;

    root /var/www/html;

    index index.php index.html;

    location / {
      try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
      include fastcgi_params;
      fastcgi_pass php-fpm:9000;
      fastcgi_index index.php;
      fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
  }
}
```


コンテナを起動
```:terminal
docker-compose up -d
```
### 使ってみる

http://localhost:8080 でindex.phpを表示
http://localhost:8081 でphpMyAdminにアクセス


## PHP(Dockerfile使用版)

|変更箇所|内容|
|---|---|
|compose.yamlの変更|phpがimagesだったのをbuild オプションに変更してphp/Dockerfileを参照するように変更<br>拡張機能の追加をphp/Dockerfileに移動|
|php/Dockerfileの追加|拡張機能の追加 <br>php.iniをコンテナ内の適切な場所にコピー|
|php/php.iniの追加|PHPの設定|

### ファイル構成


```:directory
project/
  ├ compose.yaml
  ├ .env
  ├ html/
  │  └ index.php
  ├  mysql
  │  ├ Dockerfile
  │  ├ init.sql
  │  └ my.cnf
  ├  php/
  │  ├ Dockerfile
  │  └ php.ini
  └  nginx/
  　　└ default.conf
```



```yaml:compose.yaml
services:
  nginx:
    image: nginx:1.26.3
    container_name: nginx
    ports:
      - "8080:80"
    volumes:
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf
    depends_on:
      - php
  php:
    build:
      context: ./php  # 新しく作成したphpフォルダ内のDockerfileを使用
    container_name: php-fpm
    volumes:
      - ./html:/var/www/html
    environment:
      MYSQL_HOST: mysql  # MySQLのホスト名としてサービス名（mysql）を設定
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_PORT: 3306
    depends_on:
      - mysql
 
  phpmyadmin:
    image: phpmyadmin/phpmyadmin:5.2.2
    container_name: phpmyadmin
    ports:
      - "8081:80"  # ホストのポート8081をコンテナの80ポートにマッピング
    environment:
      PMA_HOST: ${PMA_HOST}
      PMA_PORT: 3306 
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
    restart: always  # 常に再起動
  
  mysql:
    build:
      context: ./mysql  # mysql フォルダにある Dockerfile を使う
    container_name: mysql
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
    volumes:
      - mysql-data:/var/lib/mysql  # データ永続化のためボリュームを使用
      - ./mysql/my.cnf:/etc/mysql/my.cnf  # my.cnf をコンテナにマウント
    ports:
      - "3306:3306"  # MySQLのポートをホストに公開
    restart: always  # 常に再起動
  
volumes:
  mysql-data:
    driver: local
```

```Dockerfile:php/Dockerfile
FROM php:8.4-fpm

# 必要なパッケージをインストール
RUN apt-get update && apt-get install -y \
    # MySQL/MariaDBとの接続をサポートするライブラリ（mysqli用）
    libmariadb-dev \
    # PNG画像の操作をサポート
    libpng-dev \
    # JPEG画像の操作をサポート
    libjpeg-dev \
    # FreeTypeライブラリ（フォントレンダリングのためのライブラリ）
    libfreetype6-dev \
    # 圧縮ライブラリ（画像やファイル圧縮に使用）
    zlib1g-dev \
    # XML処理用のライブラリ
    libxml2-dev \
    # 国際化機能（多言語対応、地域設定など）
    libicu-dev \
    # mbstringで必要なライブラリ
    libonig-dev \
    # ZIPファイル操作に必要なライブラリ
    libzip-dev \
    # Gitのインストール（ソースコード管理などに使用）
    git \
    # PHP拡張モジュールのインストール
    && docker-php-ext-install \
    # 画像処理ライブラリ（画像の生成・加工が可能）
    gd \
    # マルチバイト文字列操作をサポート（日本語や中国語など）
    mbstring \
    # 高精度な数値計算（大きな整数や小数を扱う）
    bcmath \
    # ZIPファイルの圧縮・解凍
    zip \
    # SOAP Webサービスクライアントを提供（XMLベースのWebサービスとの通信）
    soap \
    # 国際化対応（多言語やロケールに関連する処理）
    intl \
    # mysqli拡張をインストール（MySQL/MariaDBとの接続）
    mysqli \
    # PECLで追加の拡張をインストール
    && pecl install xdebug \
    # インストールした拡張を有効化
    && docker-php-ext-enable xdebug
```

```ini:php/php.ini
[PHP]
; 基本的な設定
max_execution_time = 30
memory_limit = 256M

; エラーレポートの設定
display_errors = On
error_reporting = E_ALL

; xdebugの設定
[xdebug]
zend_extension=xdebug.so
xdebug.mode=debug
xdebug.start_with_request=yes
xdebug.client_host=host.docker.internal
xdebug.client_port=9003
xdebug.log_level=0
xdebug.log=/tmp/xdebug.log

; PHPの文字エンコーディング設定
default_charset = "UTF-8"
```
 


```:.env
MYSQL_ROOT_PASSWORD=example  # MySQLのrootパスワード
MYSQL_HOST=mysql # MySQLのホスト名（サービス名に合わせる）
PMA_HOST=mysql # MySQLのホスト名（サービス名に合わせる）
```

```php:html/index.php
<?php
$servername = getenv('MYSQL_HOST');  // MySQLのホスト名（phpコンテナ内のサービス名）
$username = 'root';
$password = getenv('MYSQL_ROOT_PASSWORD');  // rootパスワード
$dbname = 'mydatabase';  // init.sqlで作成するデータベース名
$port = getenv('MYSQL_PORT');  // ポート番号（環境変数から取得）

// MySQLに接続
$conn = new mysqli($servername, $username, $password, $dbname, $port);  // データベースを指定して接続
 
if ($conn->connect_error) {
    die("Connection failed: " . $conn->connect_error);
}
 
// データベースに接続成功
echo "データベース'$dbname'への接続に成功しました。";

// 接続を閉じる
$conn->close();
?>
``` 
 


```Dockerfile:mysql/Dockerfile
FROM mysql:9.0.1

# microdnf を使って bash と locales をインストール
RUN microdnf install -y bash glibc-langpack-ja

# ロケールの設定
ENV LANG ja_JP.UTF-8

# 初期化用SQLをコピー
COPY ./init.sql /docker-entrypoint-initdb.d/
```


```:mysql/my.cnf
[mysql]
default-character-set = utf8mb4

[mysqld]
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
default-time-zone = 'Asia/Tokyo'
```



```sql:mysql/init.sql
 -- 初期データベースの作成
CREATE DATABASE IF NOT EXISTS mydatabase CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

-- ユーザーの作成と権限の付与
CREATE USER IF NOT EXISTS 'myuser'@'%' IDENTIFIED BY 'mypassword';
GRANT ALL PRIVILEGES ON mydatabase.* TO 'myuser'@'%';

-- 権限の反映
FLUSH PRIVILEGES;
``` 

```:nginx/default.conf
server {
  listen 80;
    server_name localhost;

    root /var/www/html;

    index index.php index.html;

    location / {
      try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
      include fastcgi_params;
      fastcgi_pass php-fpm:9000;
      fastcgi_index index.php;
      fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
  }
}
```


コンテナを起動
```:terminal
docker-compose up -d
```

php/Dockerfileで指定したパッケージがインストールされているかの確認
```:terminal
docker-compose exec php php -m
```

### 使ってみる

http://localhost:8080 でindex.phpの内容を表示
http://localhost:8081 でphpMyAdminにアクセス


# Dockerfileで指定できる主な命令

|命令|内容|
|:---|:---|
|FROM|ベースとなるイメージを指定Dockerfileの最初に記述|
| ADD|ローカルにあるファイルやディレクトリ、URL、tarアーカイブファイルなどをコンテナ内にコピー(COPY の方が推奨)|
| COPY|ローカルのファイルやディレクトリをコンテナ内にコピー|
| RUN|コンテナ内でコマンドを実行|
|CMD|コンテナが起動した際に実行されるデフォルトのコマンドを指定|
|ENTRYPOINT|コンテナが起動する際に実行されるコマンドを指定 (CMDとの違い)コンテナを実行する際に指定するコマンドを変更不可|
|ONBUILD|親イメージがビルドされる際に実行する命令を指定|
|EXPOSE|コンテナがリッスンするネットワークポートを指定|
|VOLUME|コンテナにマウントするボリュームを指定|
|ENV|環境変数を設定|
|WORKDIR|作業ディレクトリを設定|
|SHELL|RUN コマンドの実行時に使うシェルを変更|
|LABEL|イメージにメタデータを付与|
|USER|コンテナ内で実行するユーザーを指定|
|ARG|ビルド時に渡される変数を定義|
|STOPSIGNAL|コンテナの停止に使用するシグナルを指定|
|HEALTHCHECK|コンテナのヘルスチェックを設定|

## イメージに不要なものを含めない

### .dockerignore
Dockerイメージをビルドする時に、どのファイルやディレクトリを無視するかを指定できます

#### Dockerfile用.dockerignore
主にビルドに関連しないファイルを無視します
例：依存関係、IDE 設定、ログ、一時ファイルなど

```:.dockerignore
# バージョン管理のディレクトリ（Git）
.git/

# IDEの設定ファイル（VSCode、IntelliJ等）
.vscode/
.idea/

# Node.js の依存関係（再インストール可能）
node_modules/

# PHP の依存関係（再インストール可能）
vendor/

# 一時ファイルやバックアップファイル
tmp/
temp/
*~
*.bak

# ログファイル（不要）
*.log

# コンパイル済みのバイナリや中間ファイル（例: Pythonのバイトコード）
*.pyc
*.pyo
``` 

#### compose.yaml用.dockerignore
開発用の設定ファイルや開発環境専用ファイルを無視します
例：.env ファイル、docker-compose.override.yaml など

```.dockerignore
# .env ファイル（環境設定や機密情報が含まれているため）
.env

# Node.js の依存関係（再インストール可能）
node_modules/

# PHP の依存関係（再インストール可能）
vendor/

# 開発環境用のオーバーライド設定
docker-compose.override.yaml

# IDEの設定ファイル（VSCode、IntelliJ等）
.vscode/
.idea/

# Git リポジトリ関連ファイル
.git/

# ログファイル（不要）
*.log

# 一時ファイルやバックアップファイル
tmp/
temp/
*~

# README やドキュメントファイル（ビルドには不要）
*.md
```

### マルチステージビルド
今回は扱いませんが、Dockerfileをマルチステージビルドに対応した記述に変更することで、不要なものを取り除き、イメージの軽量化、セキュリティ向上、ビルド速度の向上、柔軟性の確保ができます

## 問題があるときの調査方法



### コンテナの詳細の確認
```:terminal
docker container inspect コンテナ名
```


### イメージの詳細の確認

```:terminal
docker image inspect イメージ名:タグ
```

### ボリュームの詳細の確認

```:terminal
docker volume inspect ボリューム名
```


### ネットワークの詳細の確認
```:terminal
docker network inspect ネットワーク名
```

### コンテナ情報の表示 

```:terminal
//停止中のコンテナも含めて、すべてのコンテナの情報を表示
docker compose ps -a:

//特定のサービスのコンテナの状態を表示
docker compose ps サービス名: 
``` 

### コンテナの中を調べる

```:terminal
docker exec -it コンテナ名 bash

cat ファイル名
```

### ログの確認

```:terminal
//単一のコンテナのログを表示
docker logs コンテナ名

//compose.yamlで定義されたコンテナのログを表示
docker-compose logs コンテナ名
```


### Gordonに聞く
(Docker Desktopバージョン4.38以降が必要)
DockerのAIエージェントであるGordonに助けてもらうことができます
デフォルトでは無効になっているため、設定メニューから有効化する必要があります
(設定画面のFeatures in developmentでEnable Docker AIにチェックを入れてApply & restart
Containers、Imagesなどの上にAsk Gordonが追加されます)