Docker コンテナとサービス: ハンバーガーで理解する Docker の世界観

「ハンバーガーセットを一つください」の意味

前回、私たちは Dockerfile を使って自分だけの「Docker イメージ(Image)」を作った。これは、パンの上にパティを乗せ、レタスを重ねる順番が書かれた「絶対に変わらないレシピ」のようなものだ。

今度はそのレシピを使って、実際の商売、つまりサービス、を始める番だ。ところが Docker を使い始めると、ややこしい用語が次々に出てくる。Container、Service、Stack…どれも似て見えるが、いったい何が違うのだろう?

この概念をつかめないままだと、あとでデプロイスクリプトを書くときに「コンテナは起動したのに、なんでサービスが上がらないんだ?」と迷子になる。今日はこの系譜を整理するために、世界共通語である「ハンバーガーショップ」の比喩を持ってきた。

レシピ、Image、どおりにハンバーガー、Container、を作り、同じメニューを管理し、Service、セットとして売るのが Stack だ。

1. コンテナ(Container): 注文を受けて作られたハンバーガー

  • 定義: イメージを実行してメモリに載せた「実体」だ。
  • 特徴: お客さんにレシピの紙(イメージ)を渡すわけにはいかない。レシピどおりに調理された、できたての「ハンバーガー(コンテナ)」を渡さなければならない。
  • コマンド: docker run my-burger

もし私がサーバーを一台立ち上げたなら、それは「コンテナを一つ実行した」ということだ。

2. サービス(Service): 同じメニューの在庫管理

昼時になり、お客さんが一気に押し寄せてきた。ハンバーガーを一つずつ焼く速度では、とても追いつかない。そこで厨房の人手を増やして、「チーズバーガー」をあらかじめ 3 個ずつ作っておくことにした。こうなると私は、もはや「チーズバーガー 1 個」ではなく、「チーズバーガーのライン全体」、つまり Service を管理しなければならない。

  • 定義: 同じイメージから作られた「コンテナの集まり」。
  • 特徴: 「このメニューは常に在庫を 3 個キープせよ(Replicas=3)」といった「ポリシー」を与えられる。ハンバーガーを一つ落としても(エラー)、勝手に新しいものを焼いてくれる。
  • 目的: 「スケールアウト(Scale-out)」。トラフィックの分散と安定性。

3. スタック(Stack): セットメニュー、つまりフルパッケージ

ハンバーガーだけでは喉が詰まる。ポテト、DB、も必要だし、コーラ、Redis、も必要だ。これらが全部そろって初めて、「完璧な一食」、つまりアプリケーションになる。

  • 定義: 異なるサービス(Web、DB、キャッシュ)をひとまとめにした「最上位のグループ」。
  • 特徴: ハンバーガーとコーラは同じトレーに載っているほうが食べやすい(ネットワーク接続)。スタックとしてまとめると、これらが互いに通信できる専用の空間(Network)が生まれる。

問題点: 注文しているだけで息切れしそうだ

概念としては分かったが、実際に運用しようとすると頭が痛くなる。私たちが作ろうとしている Web サービス、つまり Stack、には普通、次のような構成要素が必要になる。

  1. Spring Boot (Burger): メインメニュー 2 個(冗長化)
  2. PostgreSQL (Fries): サイドメニュー 1 個
  3. Redis (Coke): ドリンク 1 杯

これを生の Docker コマンド、docker run、で起動するのは、カウンターでこんな注文をするようなものだ。

「すみません、『チーズバーガー(Spring)』をお願いします。ただしパティはミディアムウェルダンで、ピクルス抜き、ソースは多めで。あ、あと『ポテト(DB)』もお願いしますが、塩はなしで、ケチャップを 3 個つけてください。最後に『コーラ(Redis)』はゼロコーラで、氷は半分だけにしてください。そしてこの 3 つを『一つのトレー(Network)』に乗せてください」

# 実際にはこういうコマンドを毎回打たなければならない
$ docker run -d --name my-web -e PATTY=medium -e PICKLE=no -p 8080:8080 ...
$ docker run -d --name my-db -e SALT=no ...
$ docker run -d --name my-redis -e ICE=half ...

デプロイのたびに、この長い注文を一字一句間違えずに言えるだろうか? しかも順番を間違えて、ハンバーガーよりポテトのほうが遅く出てきたらどうする? お客さん、つまりユーザーは怒るはずだ。

救世主: Docker Compose – 「いつものください!」

そこで開発者たちは考えた。 「この複雑な注文内容を、あらかじめ『メニュー表、文書』に書いておいて、『1 番セットをください』とだけ言えるようにできないだろうか?」

そうして生まれたのが「Docker Compose」だ。docker-compose.yml というファイルに、自分たちだけの「カスタムセットメニュー」を定義しておけば、Docker が厨房に注文を通し、順番どおりにトレーへきれいに載せてくれる。

どれだけ複雑なカスタム注文でも、メニュー表に書いておけば「これをください」の一言で済む。

[Action] 自分だけのセットメニューを作る

言葉だけで終わらせず、実際にローカルにある Spring サーバーと DB を一発で立ち上げてみよう。やることは、プロジェクトのルートフォルダに docker-compose.yml を作り、下の内容を貼り付けるだけだ。

version: '3.8'

services:
  # 1. ポテト(DB)
  my-database:
    image: postgres:14
    environment:
      POSTGRES_PASSWORD: mysecretpassword
    ports:
      - "5432:5432"

  # 2. チーズバーガー(Web)
  my-web-server:
    image: my-spring-app:latest
    ports:
      - "8080:8080"
    depends_on:
      - my-database # "ポテトが先に揚がってからバーガーを出します" (順序保証)
    environment:
      DB_URL: jdbc:postgresql://my-database:5432/mydb

そしてターミナルで魔法の呪文を唱える。

# "1番セット(docker-compose.yml)一つください!"
$ docker-compose up -d

結果: Docker はこのメニュー表を読み、まず DB を起動し、DB の準備ができたら Spring サーバーを起動する。これこそが、IaC、Infrastructure as Code、つまり「インフラをコードで管理する」という考え方の始まりだ。これからは複雑なサーバー構成でも、「メニュー表ファイル」一つを共有するだけで済む。

おわりに: Works on My Machine? Works on ANY Machine!

このシリーズの始まりだった「自分の PC では動くんですが…」という言い訳は、もう通用しない。私たちは Linux、OS、を理解し、Docker、Container、で環境を隔離し、Docker Compose で複雑なサービスを一枚のファイルに定義できるようになった。

つまり、自分で書いた docker-compose.yml さえあれば、自分の PC でも、チーム長の PC でも、AWS サーバーでも、どこでもまったく同じハンバーガーセットを 1 分で用意できる。

私たちはもう「ただのコーダー」ではない。自分のコードだけでなく、そのコードが動く世界、環境、まで設計できる「エンジニア」になった。これで [Works on My Machine] シリーズを終える。

次のシリーズからは、この堅牢なインフラの上で、面倒なデプロイ作業を機械に任せる [The Pipeline: CI/CD 自動化] の世界へ進んでいこう。

コメントする