🐳

Dockerについてわかりやすくまとめてみました

2024/05/27に公開

Dockerとは

Dockerは、アプリケーションやサービスを環境から切り離して実行できるコンテナと呼ばれる軽量で独立した環境を利用して、アプリケーションの開発、配信、実行を簡素化するためのツールです。
https://www.docker.com/ja-jp/

Docker Desktopのインストール

下記を参考にOS上でDocker環境が使えるようにしてください。
https://zenn.dev/nenenemo/articles/deabf99a9ec00e

コンテナ(Container)

Dockerコンテナは、Dockerイメージから作成されるアプリケーションやサービスを実行するための独立した実行環境です。

イメージ(Image)

Dockerイメージは、コンテナを作成するための静的なファイルのセットです。これには、実行に必要なすべてのファイル、データ、および設定が含まれており、Dockerfileと呼ばれるテキストファイルを使用して定義されています。

また、イメージはDocker HubなどのDockerレジストリで共有して再利用することができます。

ボリューム(Volume)

Dockerボリュームは、Dockerコンテナにデータを永続化するための手段で、コンテナが停止または削除されてもデータが保持されます。

複数のウェブサーバーコンテナが同じボリュームを使用してデータにアクセスできるため、異なるコンテナ間でデータを共有することが可能です。

Dockerfile

コンテナイメージを管理するためのファイルで、ベースイメージの指定、必要なパッケージのインストール、ファイルのコピー、環境変数の設定など、イメージを構築するための手順が記述されています。

Dockerfile
# ベースイメージの選択
FROM node:18

# アプリケーションディレクトリを作成
# docker-compose.ymlのvolumesと同じパスにする
WORKDIR /app

# アプリケーションの依存ファイルをインストール
COPY package*.json ./

# 依存関係のインストール
RUN npm install

# アプリケーションのソースコードをコピー
COPY . .

# ポート3000を公開
EXPOSE 3000

# アプリケーションの起動
CMD ["npm", "run", "dev"]

RUN

Dockerイメージをビルドする過程で実行されるコマンドです。

主にソフトウェアのインストールや設定ファイルの編集など、イメージの構築に必要な手順を実行するために使用されます。RUNコマンドで実行された結果は、その時点でのイメージの一部として保存されます。

WORKDIR

Dockerコンテナ内での作業ディレクトリを設定

ENTRYPOINT

コンテナが起動する際に実行されるコマンドを設定

CMD

コンテナが実行された際にデフォルトで実行されるコマンドを指定

コンテナのデフォルトの実行コマンドを設定するために用いられ、Dockerfile内に一つだけ存在することができます。もし複数のCMDコマンドがある場合は、最後のCMDコマンドが有効になります。

docker-compose.yml

Docker Compose(docker-compose.yml)は、複数のDockerコンテナを定義し、管理するためのツールです。

このファイルでは、各サービスのイメージ、ポートマッピング、環境変数、ボリュームのマウントなど、コンテナの構成を定義しています。docker-composeコマンドを使用して、このファイルを読み込み、複数のコンテナを一度に起動、停止、管理することができます。

docker-compose.yml
version: '3.8'
services:
  app:
    container_name: app
    build: .
    volumes:
      - .:/app
    ports:
      - '3000:3000'
    env_file:
      - .env
    depends_on:
      - db
    platform: linux/amd64
    networks:
      - app-network
  db:
    image: mysql:8.0
    ports:
      - '3306:3306'
    environment:
      - MYSQL_ROOT_PASSWORD=password
      - MYSQL_DATABASE=test_db
    volumes:
      - db-data:/var/lib/mysql
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql
    platform: linux/amd64
    networks:
      - app-network

networks:
  app-network:
    driver: bridge

volumes:
  db-data:

version

ファイルの先頭で指定される部分であり、使用しているDocker Composeのファイルフォーマットのバージョンを示しています。
https://docs.docker.jp/compose/compose-file/compose-versioning.html

container_name

コンテナの名前を指定する

version

Docker Composeファイルのバージョンを指定します。

services

Docker Composeが管理する各サービス(コンテナ)が定義されます。
今回は、2つのコンテナ(appdb)を定義しています。

build

Dockerfileの場所を指定しています。

volumes

今回の.:/appという記述では、ホストマシンの現在のディレクトリ(.)をコンテナ内の/appディレクトリにマウントしています。

この設定により、ホストマシン上とコンテナ内の/appディレクトリの間でファイルの同期が行われるので、ホストマシン上のエディタでコードを編集した際にその変更をコンテナ内のアプリケーションに即座に反映することができます

ports

ホストとコンテナのポートのマッピングを指定しています。
今回は、ホストマシンのポート3000とコンテナ内のポート3000をマッピングしており、ホストマシンのポート3000にリクエストが送信されると、そのリクエストはDockerコンテナ内のポート3000に転送されます。

env_file

環境変数ファイルを指定しています。

environment

環境変数を設定しています。

depends_on

dbコンテナが起動してからapp`サービスが起動するように制御してます。

image

使用するDockerイメージを指定します。
今回は、MySQLの公式イメージmysql:5.7を使用しています。

platform

コンテナが実行されるプラットフォームを指定しています。

今回は、M1 Macを使用しているためlinux/amd64と記述しています。

networks

コンテナ間で通信するためのネットワークを定義しています。複数のコンテナが同じネットワークに接続されると、それらのコンテナ間で通信することができます。

今回は、app-networkという名前のネットワークを定義しており、appコンテナとdbコンテナが同じapp-networkネットワークに接続されているため、2つのコンテナは相互に通信することができます。

volumes

db-data:/var/lib/mysqlでは、データベースのデータを永続化するためのボリュームを設定しています。
今回は、db-dataという名前のボリュームを定義し、MySQLデータベースのデータがDockerボリュームに保存されるようにしています。

./init.sql:/docker-entrypoint-initdb.d/init.sqlでは、、初期化用のSQLファイルをマウントします。

restart: unless-stopped

コンテナが異常終了した場合に自動的に再起動されるように設定できます。ただし、手動で停止した場合は再起動されません。

データベースの初期化スクリプトの追加

init.sqlファイルをdocker-compose.ymlにパスを指定することで、Dockerコンテナが起動する際にinit.sqlファイルが自動的に実行され、データベースのセットアップが行われています。

プロジェクトのルートディレクトリに移動してinit.sqlファイルを作成してください。

touch init.sql

init.sqlの内容は次のようにします。

init.sql
SET CHARSET UTF8;

CREATE DATABASE IF NOT EXISTS test_db;
USE test_db;

CREATE TABLE IF NOT EXISTS users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    first_name VARCHAR(255) NOT NULL,
    last_name VARCHAR(255) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    deleted_at TIMESTAMP
);

INSERT INTO users (first_name, last_name) VALUES ('山田', '太郎'), ('山田', '花子');

MySQLデータベースに対して以下の操作を行っています。

SET CHARSET UTF8;

文字セットをUTF-8に変更することで、データベースが日本語のテキストを正しく扱えるようになります。

CREATE DATABASE IF NOT EXISTS test_db;

データベースが存在しない場合は、test_dbという名前のデータベースを作成します。test_dbのデータベースがすでに存在する場合は何もしません。

USE test_db;

以降の操作を実行するデータベースを選択しています。

CREATE TABLE IF NOT EXISTS users (...)

usersという名前のテーブルが存在しない場合は、新しいテーブルを作成します。

INSERT INTO users (first_name, last_name) VALUES ('山田', '太郎'), ('山田', '花子');

usersテーブルに新しいデータを挿入しています。

コマンド

Dockerイメージをビルド

Dockerは以前のビルドから生成されたキャッシュを使用してイメージをビルドします。このキャッシュ利用により、ビルドプロセスが速くなります。

例えば、Dockerfile のある命令が変更されていない場合、その命令の実行結果がキャッシュされていれば、再び実行する代わりにキャッシュから結果を取得し、時間とリソースの節約につながります。

docker-compose build

buildセクション(Dockerfileやベースイメージ)に設定変更があった場合には、再ビルドが必要です。

--no-cache

Dockerは一切のキャッシュを使用せずにイメージをビルドします。これにより、すべての命令がゼロから実行されるため、最新の状態で完全に新しいイメージを保証できます。

コンテナを起動

docker-compose.ymlファイルに基づいてサービスを起動しています。

docker-compose up

-d

バックグラウンドでコンテナを起動することができます。

--build

コンテナを起動する前にイメージをビルドします。

コンテナを停止

docker-compose down

ボリュームの一覧を確認

docker volume ls

ボリュームの削除

docker volume rm <ボリューム名>

Dockerコンテナの中に入る

docker exec -it <コンテナID> /bin/bash

/bin/のパスは省略することができるので、下記でも問題ないです。

docker exec -it <コンテナID> bash

コンテナ名を使ってコンテナに入る

docker-compose.ymlファイルがあるディレクトリに移動してから、

docker compose exec <コンテナ名> bash

Dockerコンテナから出る

exit

MySQLのイメージ

DockerでMySQLイメージを使う際、MYSQL_USERMYSQL_PASSWORD環境変数は通常の(非root)ユーザーを設定するために使います。これらの変数を使ってrootユーザーを設定することはできません。

MYSQL_ALLOW_EMPTY_PASSWORD

MySQLユーザー(通常はrootユーザー)がパスワード無しでログインできるかどうかを制御します。

値が1またはyesの場合は、MySQLサーバーのrootユーザーがパスワードなしでログインできるようになります。これにより、特に開発環境での設定やテストが容易になりますが、セキュリティリスクも伴います。

値が0またはnoの場合は、パスワードなしでのログインが不許可となります。この設定は本番環境で推奨されます。

OCI runtime exec failed: exec failed: unable to start container process: exec: "bin/bash": stat bin/bash: no such file or directory: unknown と表示される場合

bin/bashというパスのファイルが見つからない、または存在しないため実行できないということが示されています。ファイルが存在するか確認してください。

環境変数を変更した場合

コマンドを起動した後に.envファイルを追記した場合、その環境変数の変更は反映されません。

コンテナを停止し、再度コンテナを起動すると新しい環境変数が反映されます。

The requested image's platform (linux/amd64) does not match the detected host platform (linux/arm64/v8)

Dockerイメージのアーキテクチャがホストシステムのアーキテクチャと一致しないことを示しています。

下記の場合、MySQLのイメージはamd64プラットフォーム用に作られており、ホストマシンがarm64アーキテクチャであるため、不一致が起こっています。コンテナが実行されるプラットフォームを指定してください。

docker-compose.yml
version: '3.8'
services:
  app:
    build: .
    volumes:
      - .:/app
    ports:
      - '3000:3000'
    env_file:
      - .env
    depends_on:
      - db
    platform: linux/amd64 // 追加
    networks:
      - app-network
  db:
    image: mysql:8.0
    ports:
      - '3306:3306'
    environment:
      - MYSQL_ROOT_PASSWORD=password
      - MYSQL_DATABASE=test_db
    volumes:
      - db-data:/var/lib/mysql
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql
    platform: linux/amd64 // 追加
    networks:
      - app-network

networks:
  app-network:
    driver: bridge

volumes:
  db-data:

プラットフォームを指定した後、コンテナを再度起動してみてください。

entrypoint.sh

Dockerコンテナが起動する際に最初に実行されるスクリプトです。このスクリプトを使用することで、コンテナ起動時に特定のコマンドやスクリプトを実行することができます。

dockerディレクトリなどに作成します。
https://docs.docker.jp/engine/articles/dockerfile_best-practice.html#entrypoint

Dockerfile
COPY ./docker/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
ENTRYPOINT ["docker-entrypoint.sh"]
docker/docker-entrypoint.sh
#!/bin/sh

php artisan migrate --force

# PHP-FPMを起動
exec "$@"

終わりに

何かありましたらお気軽にコメント等いただけると助かります。
ここまでお読みいただきありがとうございます🎉

Discussion