🐳

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 動作確認

  1. ブラウザで http://localhost:3000 を開き,Next.js が表示されることを確認.

  2. API サーバにリクエスト:

    $ curl http://localhost:8080
    # => Hello, world!
    
  3. 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 が必須.
  • 両方書くと,開発でも本番でも動くイメージになります.

付録4. COPY . . が必要な理由

CI/CD パイプラインや Docker Hub などで構築される本番環境では

  1. ビルドされた Docker イメージ だけが本番サーバーに送られる

  2. 本番サーバーでは,そのイメージを元に コンテナが起動されるだけ である

  3. 本番サーバーには ホスト側のソースコードファイルが存在しない ため,

    volumes.tsx などを「マウントする先」がない

よって,COPY . . が必要になる

GitHubで編集を提案

Discussion