Docker超入門ガイド
0. はじめに
今回は,私の所属している技大祭実行委員会情報局(NUTMEG)でよく使用されている Docker についてブログを書こうと思います.
dockerって便利ですよね.
コマンド打って待ってればアプリが立ち上がるし,失敗してもコマンドを打ち直せば元通り.
とってもありがたいdockerですが,なんとなく使っていませんか?
こんなことを言っていますが,僕もdockerはなんとなく使っていました.
今回のブログを通して,dockerについて,少しでも理解が深まると嬉しいです.
そもそも何でdockerについて学ぶの?
プログラムファイルを他の人に渡したら動かない…
こんな経験をしたことはありませんか?
――そんな “It works on my machine” 問題を解決するのが Docker です.
Docker をお弁当🍱に例えると,「中身(アプリ)と必要な道具(ライブラリ) を全部詰めて,どこに持って行っても同じ味を再現できるもの」となります.
今回の記事を通して,Docker を直感的に理解し,自分で環境構築ができるようになりましょう.
1. Docker 基礎編
1.1 Docker とは
Docker は,アプリをまるごと コンテナ という箱に入れて配布できる技術 です.
VM(仮想マシン)のように OS ごとコピーするのではなく,ホスト OS のカーネルを共有しながら必要最小限のライブラリだけをまとめます.
例え話: 旅行用スーツケース ✈️
* 従来の VM = 引っ越しトラック(家具まるごと)
* Docker コンテナ = スーツケース(旅先で必要な物だけ)
必要な荷物をコンパクトにまとめるイメージ
1.2 Docker が必要な理由
従来の困りごと | Docker でどう変わる? |
---|---|
ライブラリのバージョン違いで アプリが起動しない |
イメージにライブラリを固定するので再現性◎ |
複数のプロジェクトで Python のバージョンが衝突 |
コンテナごとに Python 3.8 / 3.12 など共存可能 |
本番環境だけで発生するバグ | 本番と同じイメージをローカルで動かせる |
1.3 Docker の仕組み
┌────────────┐
│ Dockerfile │ ← 料理のレシピ(テキスト)
└─────┬──────┘
build
┌───────────┐
│ Image │ ← レシピから作った冷凍弁当 (静的)
└─────┬─────┘
run
┌───────────┐
│ Container │ ← チンして温めたお弁当 (動的)
└───────────┘
イメージは色々なものが配布されています.
配布されているものをそのまま使ってもいいし,アレンジすることもできます.
2. Docker Compose 基礎編
2.1 Docker Compose とは
複数のコンテナを指揮する指揮者 (Compose) です.
コンテナ同士の接続設定や起動順序を1つのファイル(YAML)で管理することができます.
例え話 : オーケストラ 🎻
それぞれの楽器(コンテナ)を,指揮者(docker‑compose)がテンポ良く演奏させるイメージ
2.2 Compose が必要な理由
- Web サーバ + データベースなど,セット運用 が当たり前
- 手動で
docker run
を 2 回 3 回… は面倒 & ミスが出る
2.3 Compose の仕組み
version: 'バージョン番号'
services:
コンテナ名:
build: dockerfileの場所
ports:
- "ホスト側:コンテナ側"
depends_on:
- コンテナ名 // 起動の順番(ここに書かれたものの後に起動する)
volumes:
- 共有したいディレクトリ:作業ディレクトリ
tty: true // コマンド実行終了後にも落ちないようになる
コンテナの情報を複数記述することで,1つのYAMLとして管理できます.
YAMLは.pngとか.txtみたいなものだと思ってください.
要するに1つのファイルで全てのコンテナを管理できるということです.
2.4 最小 YAML を書く
以下の 2 ファイルを空ディレクトリに置いて体験してみましょう.
Dockerfile
FROM nginx:alpine
docker-compose.yml
version: '3'
services:
web:
build: .
ports:
- "8080:80"
ターミナル
# 起動
$ docker compose up -d
# 起動確認
$ curl http://localhost:8080
or
http://localhost:8080 にアクセス
「buildしてrunするんじゃないの?」と思った方,いらっしゃると思います.
気になって仕方がないという方は,付録2を参照してください.
とりあえず流れだけ知りたいという方は,このまま読み進めてください.
2.5 基本操作
コマンド | 意味 |
---|---|
docker compose up -d |
バックグラウンド起動 |
docker compose logs -f |
リアルタイムログを見る |
docker compose down |
停止 & ネットワーク片づけ |
片づけも指揮者任せ: down 1 発でコンテナ・ネットワークをクリーンにできます.
3. 実践ハンズオン:環境構築
今回はハンズオン形式で,Next.js+Go API+MySQLの環境を構築してみましょう.
完成図
[ブラウザ :3000] │ HTTP [Next.js (front) コンテナ] ──> :3000 │ REST [Go (back) コンテナ] ────────> :8080 │ SQL/TCP [MySQL コンテナ] ───────────> :3306
Web フロントエンド(Next.js)→ API サーバ(Go)→ データベース(MySQL)の三層を,Docker Compose で一括起動します.
3.1 プロジェクト構成
my-app/
├── front/ # Next.js アプリ
├── back/ # Go API サーバ
│ └── main.go
├── docker/ # 各種 Dockerfile
│ ├── Dockerfile.front
│ ├── Dockerfile.back
│ └── Dockerfile.db
└── docker-compose.yml
ポイントは 「コードと Dockerfile を分ける」 ことです.
ディレクトリが増えますが,初学者でも「どのイメージが何をするのか」がわかりやすいです.
3.2 docker‑compose.yml を書く
version: "3.8"
services:
front:
build:
context: ./front # プロジェクトルートのpath
dockerfile: ../docker/Dockerfile.front
ports:
- "3000:3000"
depends_on:
- back
volumes:
- ./front:/app
tty: true
back:
build:
context: ./back
dockerfile: ../docker/Dockerfile.back
ports:
- "8080:8080"
depends_on:
- db
volumes:
- ./back:/app
tty: true
db:
build:
context: .
dockerfile: ./docker/Dockerfile.db
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: rootpass
MYSQL_DATABASE: develop
MYSQL_USER: user
MYSQL_PASSWORD: password
volumes:
- db-data:/var/lib/mysql
tty: true
volumes:
db-data:
-
depends_on
で起動順制御:db → back → front の順番で安心.- あくまで起動順序の保証であり,起動に成功したら次に進むわけではない.
-
volumes
でソースをマウントするとホットリロードが効きます.- 要するに,ディレクトリの中身が共有されるということです.
-
db-data
は永続ボリュームで,データベースを再起動しても中身が残ります.- Dockerfileやイメージは基本的にはデータを保持しません.
3.3 Dockerfileを書く
Dockerfile.front — Next.js
FROM node:20
WORKDIR /app
Dockerfile.back — Go API
FROM golang:1.21
WORKDIR /app
Dockerfile.db — MySQL
FROM mysql:8.0
後で色々編集しますが,最初はベースイメージだけです.
道具もなしに設計図は作れません.
3.4 プログラムを書く
package main
import (
"net/http"
"fmt"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello, world!")
})
server := http.Server{
Addr: ":8080",
Handler: nil,
}
server.ListenAndServe()
}
package main
でエラーが起こりますが,無視してください.
3.5 ビルドする
# イメージをビルド
$ docker compose build
設計図を基にイメージを作成します.
3.6 コンテナ内に入る
1ステップずつ実行したい場合
$ docker compose run --rm コンテナ名 sh
コマンド実行
$ exit
一度で終わらせたい場合
$ docker compose exec コンテナ名 コマンド
ただし,後者はコンテナが起動していないと使えません.
3.7 コマンドの実行(一度で終わる方を採用)
$ docker compose exec front npx create-next-app .
リポジトリの作成手順は省略します.
$ docker compose exec back go mod init github.com/ユーザ名/my-app/back
$ docker compose exec back go get github.com/gin-gonic/gin
go.sum
が生成できれば何をインストールしてもいいです.
go.sum
があるならインストールしなくてもいいです.
3.8 Dockefileの修正
必要なライブラリなどをインストールできたので,イメージファイルの設計図(Dockerfile)を編集します.
Dockerfile.front
FROM node:20
WORKDIR /app
# 依存関係を先にコピーする
COPY ./package*.json ./
RUN npm install
# アプリ本体を後からコピー
COPY . .
CMD ["npm", "run", "dev"]
-
npm run dev
は Next.js の開発サーバ.
Dockerfile.back
FROM golang:1.21
WORKDIR /app
COPY ./go.mod ./go.sum ./
RUN go mod download
COPY . .
CMD ["go", "run", "main.go"]
3.9 動作確認
-
ブラウザで http://localhost:3000 を開き,Next.js が表示されることを確認.
-
API サーバにリクエスト:
$ curl http://localhost:8080 # => Hello, world!
-
MySQL に接続:
$ docker compose exec db mysql -u root -p -h localhost -P 3306 => mysql>
MySQL クライアントが起動されていれば成功です.
最後に
今回はdockerとdocker-composeについてまとめてみました.
これから学習し始めるという方は,意味がわからない箇所がいくつかあったと思います.
ですが,開発において,dockerは欠かせないツールです.
dockerについて勉強しようと思った時に,このブログを見返していただけると幸いです.
付録1. 用語リスト
用語 | 一行説明 |
---|---|
Image | コンテナの起動元となる静的テンプレート |
Container | Image から起動した実行中プロセス |
Dockerfile | Image を作るレシピファイル |
Volume | ホストと共有するストレージ領域 |
Network (bridge) | デフォルトの仮想 LAN |
Compose | 複数コンテナの定義・管理ツール |
付録2. build・run・upの違いについて
1. 基本の違い
コマンド | 何をする? | どういう時使う? |
---|---|---|
docker compose up |
コンテナ作成+起動 | 普段の開発やアプリ起動 |
docker compose build |
イメージだけ作成 | Dockerfile更新後,ビルドのみしたい時 |
docker compose run |
一時的なコンテナで コマンド実行 |
テストやデバッグ,シェル操作したい時 |
2. それぞれの役割と使い方
2.1 docker compose up
- サービス(コンテナ)の作成と起動をまとめて行う
- イメージがなければ自動でbuildする(イメージがあればbuildしない)
- 全サービスをまとめて起動&ネットワークもセットアップ
- ログの確認や停止管理も一括で可能
docker compose up
2.2 docker compose build
- イメージのビルドだけを行う
- サービスの起動はしない
- Dockerfileや依存パッケージ変更後に使う
docker compose build
2.3 docker compose run
- 一時的なコンテナを作ってコマンド実行
- サービス全体は起動せず,単発で動かす
- テスト・デバッグ・シェル操作などに便利
- 実行完了後,コンテナは自動で消える(オプションで残すことも可能)
docker compose run app bash
3. up = build + run ではない理由
3.1 upは「必要な場合だけ」buildする
- buildは必ずイメージを新しく作るが,upは「なければbuildする」だけ(毎回ではない)
3.2 upは全サービスの起動・管理をする
- runは一部のサービスだけ一時的に動かす
- upはネットワーク・依存関係も全部面倒を見る
3.3 runは一時的、upは常駐
- runはコマンドを実行して,終わったらコンテナが消える
- upはサービスとして起動し続ける(コンテナとして残る)
3.4 upは依存関係も管理
- upはdepends_onで書かれた依存サービスも起動する
- runは指定したサービスだけ(必要ならオプションで他も起動できる)
4. イメージしやすい例え
- up:家の全部屋の電気を一気につける(必要なら新しい電球にしてからつける)
- build:電球だけ新しくする
- run:一部屋だけ一時的に電気をつけてすぐ消す
5. まとめ
- upは「ビルド&全サービスのまとめ起動&管理」
- buildは「イメージの作成だけ」
- runは「一時的なコマンド実行だけ」
付録3. COPY とマウント (volumes) の違い
“宅配便と共有フォルダ”
操作 | 実行タイミング | 例え話 |
---|---|---|
COPY イメージ内にファイルを封入 |
イメージビルド時 | 宅配便で荷物を箱に詰めて送る |
volumes ホストのフォルダをコンテナに共有 |
コンテナ起動時 | クラウド共有フォルダ |
- ローカル開発では volumes でホットリロードしたい.
- CI/CD 本番環境ではホストのフォルダが無いため COPY が必須.
- 両方書くと,開発でも本番でも動くイメージになります.
COPY . .
が必要な理由
付録4. CI/CD パイプラインや Docker Hub などで構築される本番環境では
-
ビルドされた Docker イメージ だけが本番サーバーに送られる
-
本番サーバーでは,そのイメージを元に コンテナが起動されるだけ である
-
本番サーバーには ホスト側のソースコードファイルが存在しない ため,
volumes
で.tsx
などを「マウントする先」がない
よって,COPY . .
が必要になる
Discussion