Dockerを使うことになった際に役立ちそうな知識
はじめに
本記事は社内勉強会でDockerの使い方をテーマに取り扱った内容を書き起こしたものです。
参画しているプロジェクトでDockerを使用しているため使い方を知りたい、もしくはDockerを使用することになったがイマイチ使い方、学び方がわからない、といった方の助けになれば幸いです。
この記事で取り扱う内容
Dockerの機能や仕組みについて簡単に解説します。
また複数のコンテナイメージを用いてWebアプリケーションを実現する方法を説明します。
Dockerとは何か
公式の日本語訳では下記のように記載されています。
アプリケーションの構築、共有、実行を加速
Dcokerを使うと、開発者は面倒な環境構成や管理を行わずに、どこでもアプリケーションを構築、共有、実行、検証できるようになります。
本来は「アプリケーションの構築、共有、実行を提供する製品群の総称」という意味になります。
一方、開発現場ではコンテナ型の仮想化技術によって上記が実現されていることから、「Docker」という単語がコンテナ型の仮想化技術そのものを指して使われることも多いと感じます。
したがって「Docker」のという単語は文脈に応じて細かな意味が異なることに注意していただくと良さそうです。
Dockerの仕組み
上図はDockerがアプリケーションを構築、共有、実行する仕組みを簡単に表現したものです。
Container
Linuxカーネルの機能を利用し、ホスト上でも隔離された状態でアプリケーションを実行する環境です。
コンテナ内の出来事はホストや他のコンテナには影響を与えません。
Container Image
コンテナを構築するためのベースとなる情報です。
コンテナイメージはDocker Hub等のイメージレジストリから取得できます。
また Dockerfile を使用しコンテナイメージの作成も可能です。
現在は Open Container Initiative (OCI)という仕様で共通化されているため、OCI仕様のコンテナイメージは下記のようなDocker以外のコンテナランタイムでも動作します。
Image Registry
Docker Hub等のコンテナイメージを保存・管理・共有するための中央集約型の場所です。
Dockerfile
コンテナイメージを構築するためテキストファイルです。
Virtual Network
コンテナが他のコンテナや外部サービスとの通信するために接続するネットワークです。
ネットワークの作成、削除、接続はコマンドで操作でき、複数のコンテナを同じネットワークに接続させることで、IPアドレスを使用せずにコンテナ名で名前解決ができるようなります。
Filesystem
コンテナは隔離された環境であるため、コンテナを削除するとコンテナ内で生成されたデータも一緒に削除されます。
データベースなどデータの永続化が必要なアプリケーションをコンテナとして動作させる際はホスト上のファイルシステムを対象のコンテナにマウントすることでデータの永続化を実現します。
マウントには下記3種があります。
ボリューム(volume)
Dockerによって管理されているボリュームをコンテナにマウントする。
バインド マウント(bind mount)
ホスト上の任意のファイルやディレクトリをコンテナにマウントする。
tmpfs マウント
メモリ領域をコンテナにマウントする。
データはメモリに書き込まれるためコンテナを削除した際はホスト、コンテナのどちらにもデータは残らない。
コンテナを動かしてみよう
Dockerをインストールした端末を使用しコンテナの動作を確認します。
ここでは皆さんのお家にもあるRaspberry Piで動作を確認しました。
デモの概要
上図のようにnginx、MySQL、Webアプリケーションのコンテナを使用し簡単なWebアプリケーションをDockerを使用して構築します。
nginx、MySQLのコンテナはDockerHubで公開されているコンテナイメージを使用します。
またWebアプリケーションコンテナはPythonのコンテナイメージをベースに新たにコンテナイメージを作成します。
確認環境(Raspberry Pi 5)
Software | Version |
---|---|
OS | Debian GNU/Linux 12 (bookworm) aarch64 |
Docker version | 28.2.2, build e6534b4 |
Docker Compose version | v2.36.2 |
MySQL | MySQL Ver 15.1 Distrib 10.11.11-MariaDB, for debian-linux-gnu (aarch64) using EditLine wrapper |
使用したコンテナイメージ
本記事ではDocker Hubから取得したコンテナイメージを使用しています。
Docker Hubの制限[1] が気になる場合などは Amazon ECR Public Galleryからでも同等のイメージを取得し使用できます。
Image | Tag |
---|---|
mysql |
8.4.5 |
python |
3.13.5-slim-bookworm |
nginx |
1.28.0-bookworm |
ディレクトリ構成
動作を確認した際のディレクトリ構成です。
基本的に下記ディレクトリ構成のルートで作業をします。
.
├── app
│ ├── Dockerfile
│ ├── requirements.txt
│ └── src
│ ├── __init__.py
│ ├── db.py
│ ├── main.py
│ ├── models.py
│ └── templates
│ └── index.html
├── compose.yaml
├── db
│ └── initdb.d
│ └── 001_create_table.sql
└── nginx
└── default.conf
デモプロジェクト
下記にデモ用のプロジェクトを作成しましたのでご活用ください。
コンテナイメージを取得してみる
Docker Hub等のイメージレジストリからコンテナをPullします。
docker pull <イメージ名>:<タグ>
とすることで指定したタグのイメージを取得できます。
タグ名を省略した場合は latest
のイメージが取得されます。
# Registry から Container Image を Pull する
# タグ名指定なし(latest)
$ docker pull mysql
# タグ名を指定
$ docker pull mysql:8.4.5
# ローカル内のイメージを確認する
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mysql 8.4.5 bf4c7f45ae54 2 months ago 779MB
mysql latest cd7958658f92 2 months ago 877MB
コンテナイメージを作ってみる
デモプロジェクトのDockerfileを使用し新たにコンテナイメージを作成します。
参考までにデモプロジェクトのDockerfileで実施している内容を各命令ごとにコメントを記載します。
また詳細な命令の内容やベストプラクティスについてはDockerfile referenceを参照してください。
# build時の引数と初期値を設定(Dockerfile内で利用可)
ARG IMAGE_TAG=3.13.5-slim-bookworm
# ベースとなるPythonイメージを指定(タグ名はARGで設定された値)
FROM python:${IMAGE_TAG}
# 環境変数と初期値を設定(コンテナ起動時に上書き可)
ENV DB_HOST=db \
DB_PORT=3306
# 以降の命令の作業ディレクトリを指定
WORKDIR /src
# ホスト上の`requirements.txt`を`/src`ディレクトリにコピー
COPY requirements.txt .
# 新しいレイヤー上でコマンドを実行
# ここでは`app`ユーザーの追加、`requirements.txt`をもとにPythonパッケージをインストール、`/src`ディレクトリの所有者を`app`ユーザーへ変更
RUN useradd --home-dir /src --uid 1000 app \
&& pip install --no-cache-dir -r requirements.txt \
&& chown -R app:app /src
# 以降の命令の実行者を`app`ユーザーへ変更
USER app
# ホスト上の`src`ディレクトリを`app/`ディレクトリとしてコピー
COPY ./src/ ./app
# tcp/8000で接続を受け付ける(実際に公開はしない)
EXPOSE 8000
# コンテナ起動時のデフォルトコマンドを指定
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
# デモプロジェクトを使用している場合は `app` ディレクトリへ移動します
$ cd app
# build-argとtagを指定しコンテナイメージをbuild
$ docker build --build-arg IMAGE_TAG=3.13.5-slim-bookworm --tag demo-app:0.1.0 .
# コンテナイメージの確認
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
demo-app 0.1.0 1a860224795a 5 hours ago 210MB
python 3.13.5-slim-bookworm e07b767bb2b3 2 weeks ago 146MB
nginx 1.28.0-bookworm e55a872cbf1b 2 months ago 198MB
mysql 8.4.5 bf4c7f45ae54 2 months ago 779MB
コンテナを起動してみる
docker run
コマンドでコンテナのもととなるイメージを指定しコンテナを起動します。
docker run
コマンドは docker pull
、docker create
、 docker start
コマンドの動作を含みます。
-
-d
: デタッチドモード、コンテナをバックグラウンドで実行 -
--name
: コンテナに名前を設定 -
-e
: 起動するコンテナ内の環境変数を設定
コンテナ内で利用する環境変数はコンテナイメージによって異なります。
詳しくはコンテナイメージの提供元の情報を確認してください。
参考: mysql
# コンテナを作って起動(イメージがなければPull)
# docker pull & docker create & docker start
$ docker run -d \
--name db001 \
-e MYSQL_ROOT_PASSWORD=password \
-e MYSQL_DATABASE=database \
mysql:8.4.5
コンテナを操作してみる
続いてコンテナを起動してみるで起動したコンテナを操作します。
# 起動中のコンテナで任意のコマンドを実行する
$ docker exec db001 touch container.txt
# 起動中のコンテナに /bin/bash を指定しで接続する
$ docker exec -it db001 /bin/bash
# コンテナから抜ける(コンテナ内で実行)
$ exit
# 起動中のコンテナ内のファイルをカレントディレクトリにコピーする
$ docker cp db001:/container.txt .
# コンテナの状況を確認(停止中のコンテナも表示する場合は `docker ps -a` )
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9c1176f18c10 mysql:8.4.5 "docker-entrypoint.s…" 12 minutes ago Up 12 minutes 3306/tcp, 33060/tcp db001
# コンテナで出力されたログを確認する
$ docker logs db001
# コンテナを停止する
$ docker stop db001
# コンテナを削除する
$ docker rm db001
コンテナをサービスとして利用してみる
コンテナをホスト上で稼働するサービスとして公開するため、コンテナを起動してみるで紹介した docker run
コマンドを下記のように変更し、コンテナを起動します。
追記した下記の -p
フラグはホスト側の tcp/33066
ポートにコンテナ側の tcp/3306
ポートを割り当てる意味となります。
なお、Dockerのバージョンが27以下の場合は意図せずホストの外部にもポートを公開する場合[2]もあるため取り扱いにはご注意ください。
# tcp/33066ポートを使用してコンテナを起動する
$ docker run -d \
- --name db001 \
+ --name db002 \
-e MYSQL_ROOT_PASSWORD=password \
-e MYSQL_DATABASE=database \
+ -p 33066:3306 \
mysql:8.4.5
ホストからコンテナとして起動したMySQLが利用できるかの確認
(MySQLクライアントよりMySQLコンテナに割り当てたポートへ接続できるか確認)
# ホストからMySQLクライアントで接続してみる
# Welcome to the MariaDB monitor... が出力されれば接続OK
$ mysql -P 33066 -u root -p database
Enter password: # MYSQL_ROOT_PASSWORDに設定した値を入力
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MySQL connection id is 19
Server version: 8.4.5 MySQL Community Server - GPL
コンテナのデータを永続化してみる
ボリュームを作成し、コンテナにマウントすることでコンテナ内のデータを永続化します。
MySQLコンテナでは初回実行時に /docker-entrypoint-initdb.d
内の .sql
ファイルなどを実行する機能があります。
ここでは db_data01
ボリュームを作成し、データベースのデータが格納される /var/lib/mysql
にマウントします。
またコンテナ作成時にデモ用のテーブルを作成するため、DDLを記載したsqlファイルを格納したディレクトリを /docker-entrypoint-initdb.d
にbindマウントします。
--mount
フラグの記載は -v
フラグを使用しすると下記のように省略も可能です。
-v db_data01:/var/lib/mysql
-v ./initdb.d:/docker-entrypoint.initdb.d:ro
-- デモ用テーブルを作成
CREATE TABLE `database`.demo_table (
id BIGINT auto_increment NOT NULL COMMENT 'Primary Key',
created_at DATETIME DEFAULT NULL COMMENT '作成日時',
updated_at DATETIME DEFAULT NULL COMMENT '更新日時',
value varchar(100) NULL COMMENT '値',
CONSTRAINT demo_table_pk PRIMARY KEY (id)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'demo_table';
# db_data01ボリュームを作成する
$ docker volume create db_data01
# 作成したボリュームを確認
$ docker volume ls
DRIVER VOLUME NAME
local db_data01
# 作成したとホスト側のディレクトリをマウントし、コンテナを起動
$ docker run -d \
--name db003 \
-e MYSQL_ROOT_PASSWORD=password \
-e MYSQL_DATABASE=database \
-p 33067:3306 \
--mount type=volume,source=db_data01,target=/var/lib/mysql \
--mount type=bind,source=./db/initdb.d,target=/docker-entrypoint-initdb.d,readonly \
mysql:8.4.5
# MySQLに接続し、データを挿入する
$ mysql -P 33067 -u root -p database
# ...省略...
MySQL [database]> insert into demo_table (created_at, updated_at, value) values (current_timestamp(), current_timestamp(), 'test data01');
Query OK, 1 row affected (0.009 sec)
MySQL [database]> select * from demo_table;
+----+---------------------+---------------------+-------------+
| id | created_at | updated_at | value |
+----+---------------------+---------------------+-------------+
| 1 | 2025-06-22 14:37:01 | 2025-06-22 14:37:01 | test data01 |
+----+---------------------+---------------------+-------------+
MySQL [database]>quit
Bye
# db003 コンテナを停止&削除
$ docker stop db003 && docker rm db003
続いてデータの永続化ができているか確認します。
新たに db_data01
ボリュームをマウントしたMySQLコンテナを起動し、
db003
コンテナで登録したデータが取得できれば成功です。
# `db_data01` ボリュームをマウントした `db004` コンテナを起動
$ docker run -d \
--name db004 \
-e MYSQL_ROOT_PASSWORD=password \
-e MYSQL_DATABASE=database \
-p 33068:3306 \
--mount type=volume,source=db_data01,target=/var/lib/mysql \
mysql:8.4.5
$ mysql -P 33068 -u root -p database
# ...省略...
# `db003` コンテナで登録したデータが取得できるか確認
MySQL [database]> select * from demo_table;
+----+---------------------+---------------------+-------------+
| id | created_at | updated_at | value |
+----+---------------------+---------------------+-------------+
| 1 | 2025-06-22 14:37:01 | 2025-06-22 14:37:01 | test data01 |
+----+---------------------+---------------------+-------------+
複数のコンテナを連携してみる
デモの概要の図のような構成するためコンテナ同士を連携します。
docker network create
コマンドで demo-nw01
ネットワークを作成し、コンテナのデータを永続化してみるで作成した db004
コンテナを接続します。
(db004
コンテナは停止させずに demo-nw01
ネットワークへ参加させます)
# Networkを作成
$ docker network create --driver bridge demo-nw01
# 作成したネットワークを確認
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
b7ee6c7b42bd bridge bridge local
2b0cea38706e demo-nw01 bridge local
ef0245f590b6 host host local
6aef57c9dc4d none null local
# 実行中のコンテナを作成したネットワークに追加
$ docker network connect demo-nw01 db004
続いてコンテナイメージを作ってみるで作成したコンテナイメージとnginxのコンテナイメージをベースに demo-nw01
ネットワークへ参加させたコンテナを起動します。
# コンテナ起動時に作成したネットワークに参加
# demo-webコンテナ
$ docker run -d \
--name app \
-e DB_HOST=db004 \
-e DB_USER=root \
-e DB_PASSWORD=password \
-e DB_SCHEMA=database \
--net demo-nw01 \
demo-app:0.1.0
# Nginxコンテナ
$ docker run -d \
--name nx01 \
-p 80:80 \
-v ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro \
--net demo-nw01 \
nginx:1.28.0-bookworm
最後にブラウザより http://localhost/ へアクセスし下記が表示されれば成功です。
Docker Composeを使用する
Docker Composeは、複数のコンテナからなるアプリケーションを定義し、実行するためのツールです。
これまでは様々なコマンドを使用し複数のコンテナの起動、操作を実現しましたが非常に複雑で手間のかかる作業でした。
Docker Composeでは yaml
ファイルに複数のコンテナの設定を記載することで、 docker compose
コマンドを通じ全てのコンテナ起動・管理ができるようになります。
他に下記のような便利な機能もあります。
-
yaml
ファイル内で.env
ファイルに記載した変数が利用できる - コンテナが同一のネットワークの場合は
yaml
に記載したサービス名で名前解決できる
また yaml
ファイルのファイル名はデフォルトで下記に対応しています。
プロジェクトによってファイル名が異なっても正常に動作するためご安心ください。
compose.yml
compose.yaml
docker-compose.yml
docker-compose.yaml
実際にDocker Composeを使用して複数のコンテナを連携してみると同じ構成を実現します。
一部、ポートやコンテナ名が干渉してしまうため、複数のコンテナを連携してみるで使用したコンテナが起動中の場合は一度、停止&削除してから実施してください。
Docker Composeは docker compose <command>
の形式でコマンド入力することによりコンテナを操作できます。
Docker Composeの詳細な使用方法については公式ドキュメントなどを参照してください。
参考までにデモプロジェクトのcompose.yamlにコメントを記載します。
(.env.sample
ファイルは .env
にリネームしてご利用ください)
# 起動するサービス(コンテナ)の定義
services:
# `db` というサービス名でMySQLコンテナを定義
db:
# コンテナイメージを指定
image: 'mysql:8.4.5'
# コンテナの環境変数を設定(設定値は`.env`に記載の内容を設定)
environment:
MYSQL_ROOT_PASSWORD: '${DEMO_DB_PASSWORD}'
MYSQL_DATABASE: '${DEMO_DB_DATABASE}'
# tcp/3306で接続を受け付ける
expose:
- '3306'
# マウント設定
volumes:
# ボリュームをマウント
- type: 'volume'
source: 'db_data02'
target: '/var/lib/mysql'
# バインド マウント
- type: 'bind'
source: './db/initdb.d'
target: '/docker-entrypoint-initdb.d'
read_only: true
# 参加するネットワークを設定
networks:
- 'demo-nw02'
# `app` というサービス名でWebアプリケーションコンテナを定義
app:
# コンテナイメージの指定(コンテナイメージの指定時は`--tag` に相当)
image: 'demo-app:0.1.0'
# コンテナイメージのbuild時の設定
build:
context: './app'
args:
IMAGE_TAG: '3.13.5-slim-bookworm'
environment:
DB_USER: '${DEMO_DB_USER}'
DB_PASSWORD: '${DEMO_DB_PASSWORD}'
DB_SCHEMA: '${DEMO_DB_DATABASE}'
expose:
- '8000'
networks:
- 'demo-nw02'
# `db` サービスの起動待ってからサービスを起動する
depends_on:
- 'db'
# `nginx` というサービス名でNginxコンテナを定義
nginx:
image: nginx:1.28.0-bookworm
# ホスト側のtcp/80ポートに Nginxコンテナのtcp/80ポートを割り当てる
ports:
- "80:80"
volumes:
- './nginx/default.conf:/etc/nginx/conf.d/default.conf:ro'
networks:
- 'demo-nw02'
depends_on:
- 'app'
# volumeの定義(`docker volume create db_data02` に相当)
volumes:
db_data02:
name: 'db_data02'
# networkの定義(`docker network create --driver bridge demo-nw02` に相当)
networks:
demo-nw02:
driver: 'bridge'
# コンテナをbuildし、バックグラウンドでコンテナを起動する(buildが不要な場合は `--build` を削除)
$ docker compose up -d --build
# コンテナの状態を確認する
$ docker compose stats
# サービス名を指定してログを確認する
$ docker compose logs app
# コンテナを停止&削除する
$ docker compose down
docker compose up
を実行後、複数のコンテナを連携してみると同様にブラウザから http://localhost/ へアクセスした際に画面が表示されれば成功です。
Dockerを業務で使用する際に気をつけたいこと
最後に業務でDockerを使用する際の注意点です。
一部のツールの利用に有料ライセンスが必要
Docker DesktopやDocker Hubを制限なく業務で利用するには有料ライセンスが必要になります。[3]
参画したプロジェクトでライセンスが付与されていない場合は下記のような代替手段をご検討ください。
Docker Desktopの代替
- WSL(Windows)
- Rancher Desktop
Docker Hubの代替
不要なポートは使用しない
コンテナをサービスとして利用してみるでも紹介した通り、Dockerを利用する環境によっては意図せずホスト側のポートを解放している場合[2:1]があります。
起動したコンテナなどに脆弱性がある場合、意図せずホスト側のポートも開けてしまうと悪用されてしまう可能性があります。
不必要にポート開けないよう設定の見直しや使用してないコンテナは停止するなど運用方法をご検討ください。
Docker Engine v28: デフォルトでコンテナネットワークを強化する
Container imageに秘密情報を書き込まない
コンテナイメージを作成する際、データベースの接続情報など秘密情報を書き込まないように注意が必要です。
万が一、コンテナイメージに秘密情報を書き込んだままDocker Hubなどで公開してしまうと秘密情報も一緒に公開されてしまいます。
.env
などで秘密情報を管理していてもDockerfileの COPY
命令で他のソースコードに紛れてイメージに含まれてしまう可能性もあります。
.dockerignore
などを活用しコンテナイメージに必要以上の情報が混入しないようご検討ください。
コンテナに必要以上の権限を与えない
Dockerでは下記のような特徴もあります。
- Dockerデーモンはデフォルト設定ではrootユーザーとして実行される
-
--privileged
フラグを付与し起動したコンテナはホスト上のプロセスとほぼ同じ権限を持つ
以上のことからコンテナの起動方法次第でホスト側のファイルを操作するなど、意図せずホストに影響を与える場合もあるため注意が必要です。
rootユーザーの権限が不要であればDockerをRootless modeで実行する、コンテナ起動時に必要な権限のみ付与するなどの対応で万が一、コンテナがホストに与える悪影響を抑止できます。
CPUアーキテクチャの違いでイメージが使えないこともある
コンテナイメージはCPUアーキテクチャの種類(x86, arm64など)によって同じアプリケーションでも使用するコンテナイメージが異なります。
MySQL、Pythonなど複数のCPUアーキテクチャに合わせたコンテナイメージが公開されてるため通常利用には影響はありませんが、
コンテナイメージを作成し配布する場合などは注意が必要です。
CPUアーキテクチャが異なるコンテナイメージの作成が必要な場合はDocker Buildxを利用することでマルチアーキテクチャイメージを簡単にビルドできます。
Discussion