# 20250605_Dcoker超入門ガイド (例:20210901_LT会を開催しました) ###### tags: `ブログ記事` - [ ] 公開(ブログ公開担当者がいじるやつ) 太字斜体で書いてある内容を埋めて行ってください. 文章,画像は太字斜体の下の行に入れてください. 最初に書く時はREADMEを読んだら読むといいと思います. <br> ## 表示されない情報 ***書いた人の名前(自己紹介文と同じ名前)*** { つっきー } ***記事の簡単な説明(検索した時にタイトルの下に出てくる文章)*** { こんにちは!今回はNUTMEGのメンター制度について詳しく解説します! メンティーになる新入生の方や、これからメンターになる在校生の方はぜひチェックしてみてください! } <br> ## 表示される部分 ***サムネイル画像*** { } ***カテゴリ*** 以下の中から該当しそうなカテゴリを選択してください ※一つだけ選択してください - [ ] 対外活動 - [x] 活動の様子 - [ ] メンバーの趣味 - [ ] 実務訓練体験記 - [ ] NUTMEG Advent Calendar 2023 ***タグ*** 以下の中から該当しそうなカテゴリを選択してください.当てはまる物がない場合は適宜追加してください. 言語 - [ ] HTML - [ ] CSS - [ ] Python - [ ] Go - [ ] Ruby - [ ] JavaScript - [ ] TypeScript - [ ] Dart - [ ] Rust - [ ] Kotlin - [ ] Swift フレームワーク・ライブラリ - [ ] Ruby on rails - [ ] Vue.js - [ ] Nuxt.js - [ ] React.js - [ ] Next.js - [ ] Gin - [ ] Flluter ツール - [ ] GitHub - [ ] ターミナル - [ ] WSL - [ ] Ubuntu - [x] Docker - [ ] Raspberry Pi - [ ] Figma 分野 - [ ] チームづくり - [ ] フロントエンド - [ ] バックエンド - [ ] インフラ - [ ] Web-design - [ ] API関係 --- ***以下に本文を記載してください*** # 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 の仕組み  ```yaml version: 'バージョン番号' services: コンテナ名: build: dockerfileの場所 ports: - "ホスト側:コンテナ側" depends_on: - コンテナ名 // 起動の順番(ここに書かれたものの後に起動する) volumes: - 共有したいディレクトリ:作業ディレクトリ tty: true // コマンド実行終了後にも落ちないようになる ``` コンテナの情報を複数記述することで,1つのYAMLとして管理できます. YAMLは.pngとか.txtみたいなものだと思ってください. 要するに1つのファイルで全てのコンテナを管理できるということです. ## 2.4 最小 YAML を書く  以下の 2 ファイルを空ディレクトリに置いて体験してみましょう. **Dockerfile** ```dockerfile FROM nginx:alpine ``` **docker-compose.yml** ```yaml version: '3' services: web: build: . ports: - "8080:80" ``` **ターミナル** ```bash # 起動 $ 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 を書く ```yaml 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** ```dockerfile FROM node:20 WORKDIR /app ``` **Dockerfile.back — Go API** ```dockerfile FROM golang:1.21 WORKDIR /app ``` **Dockerfile.db — MySQL** ```dockerfile FROM mysql:8.0 ``` 後で色々編集しますが,最初はベースイメージだけです. 道具もなしに設計図は作れません. ## 3.4 プログラムを書く ```go 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 ビルドする ```bash # イメージをビルド $ docker compose build ``` 設計図を基にイメージを作成します. ## 3.6 コンテナ内に入る 1ステップずつ実行したい場合 ```fish $ docker compose run --rm コンテナ名 sh コマンド実行 $ exit ``` 一度で終わらせたい場合 ```fish $ docker compose exec コンテナ名 コマンド ``` ただし,後者はコンテナが起動していないと使えません. ## 3.7 コマンドの実行(一度で終わる方を採用) ```fish $ docker compose exec front npx create-next-app . ``` リポジトリの作成手順は省略します. ```fish $ 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** ```dockerfile FROM node:20 WORKDIR /app # 依存関係を先にコピーする COPY ./package*.json ./ RUN npm install # アプリ本体を後からコピー COPY . . CMD ["npm", "run", "dev"] ``` * `npm run dev` は Next.js の開発サーバ. **Dockerfile.back** ```dockerfile 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](http://localhost:3000) を開き,Next.js が表示されることを確認. 2. API サーバにリクエスト: ```bash $ curl http://localhost:8080 # => Hello, world! ``` 3. MySQL に接続: ```fish $ docker compose exec db mysql -u root -p -h localhost -P 3306 => mysql> ``` MySQL クライアントが起動されていれば成功です. # 最後に 今回はdockerとdocker-composeについてまとめてみました. 新入生の皆さんは意味がわからない箇所がいくつかあったと思います. ですが,NUTMEGで活動していく中で,dockerは欠かせないツールです. dockerについて勉強しようと思った時に,このブログを見返していただけると幸いです. P.S. AIにブログを書かせると半日で完成することは内緒だよ. --- # 付録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しない) * 全サービスをまとめて起動&ネットワークもセットアップ * ログの確認や停止管理も一括で可能 ```sh docker compose up ``` --- ### 2.2 docker compose build * **イメージのビルドだけ**を行う * サービスの起動はしない * Dockerfileや依存パッケージ変更後に使う ```sh docker compose build ``` --- ### 2.3 docker compose run * **一時的なコンテナを作ってコマンド実行** * サービス全体は起動せず,**単発**で動かす * テスト・デバッグ・シェル操作などに便利 * **実行完了後**,コンテナは自動で消える(オプションで残すことも可能) ```sh 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 . .` が必要になる ---