DockerとKubernetesで学ぶコンテナ技術:環境差異の悪夢から脱出し、インフラを支配する方法

目次

「私の環境では動いたんです」という言い訳が通用しない夜

エンジニアとして働いていると、一生忘れられないトラウマのような夜がいくつかあります。
私にとってのそれは、あるWebサービスのリリース前夜でした。

開発環境(自分のMacBook)では完璧に動いていたんです。テストも全部パスした。自信満々でステージング環境(検証用サーバー)にコードをデプロイしました。
ところが、画面には無慈悲な「500 Internal Server Error」。
ログを見ると、ライブラリのバージョンが微妙に違うとか、OSの環境変数が足りないとか、そんな些細な食い違いが原因で、アプリは起動すらしませんでした。

「私の環境では動いたんですけど…」

震える声でそう報告した時、先輩エンジニアが放った言葉が胸に刺さりました。
「ユーザーはお前のMacBookを使ってるわけじゃないんだよ」

その通りです。ぐうの音も出ません。
OSの違い、インストールされているソフトの違い、設定ファイルの書き忘れ。開発環境と本番環境の「ズレ」は、いつの時代もエンジニアを苦しめる最大の敵でした。このズレをなくすために、手順書を作り、仮想マシンをコピーし、それでもミスは起きる。

そんな絶望的な戦いに終止符を打ったのが、「Docker」という技術でした。
そして、そのDockerが増えすぎた時に指揮を執る「Kubernetes」の登場。

これらは単なる流行りのツールではありません。インフラ構築の概念を根底から覆した革命です。
かつてサーバーエンジニアが徹夜で行っていた作業を、コード数行で終わらせる魔法の杖。
もしあなたが「インフラは難しそうだから避けている」のだとしたら、それはあまりにも勿体ない。なぜなら、これらを使えるようになるだけで、あなたのエンジニアとしての市場価値は倍増するからです。

環境差異の悪夢にうなされていた私が、DockerとKubernetesを使いこなし、インフラを自在に操れるようになるまでの道のりを、実体験と現場のノウハウを交えて解説します。
黒い画面(ターミナル)への恐怖心を捨てて、一緒にコンテナの海へ漕ぎ出しましょう。

深夜のオフィスで、開発環境と本番環境の挙動の違いに頭を抱え、複数のモニターを見比べながら冷や汗をかいているエンジニアの線画イラスト

なぜ今、仮想マシンではなく「コンテナ」なのか

Dockerの話をする前に、少しだけ時計の針を戻しましょう。
昔は、1つの物理サーバーに1つのOSを入れて、その上でアプリを動かしていました。でもそれだと、サーバーのスペックが余ってしまってもったいない。
そこで登場したのが「仮想マシン(VM)」です。VMwareやVirtualBoxといったソフトを使って、1つのPCの中に「仮想的なPC」を何台も作る技術です。

これで効率は上がりました。しかし、VMには弱点がありました。
「重い」んです。
仮想マシンは、OS(WindowsやLinux)を丸ごと立ち上げるので、起動に数分かかります。メモリも数GB食います。「ちょっとアプリをテストしたい」だけなのに、PC全体の動作が重くなる。

そこで天才たちは考えました。
「OSを丸ごと立ち上げる必要なくない? アプリを動かすのに必要な『部品』だけをパッケージにして、OSの上で軽く動かせばいいじゃないか」

これが「コンテナ技術」の正体です。
コンテナは、ホストOS(あなたのPCのOS)のカーネルという核となる部分を共有しつつ、プロセスだけを隔離します。
だから、起動は一瞬。メモリ消費も極少。
まるで、重たい引越し荷物を全部トラックに積む(VM)のではなく、必要最低限の着替えだけをバックパックに詰めて移動する(コンテナ)ような身軽さです。

このコンテナ技術を、誰でも簡単に使えるようにしたツールがDockerです。
Dockerを使えば、「アプリ本体」と「それを動かすための環境(ライブラリや設定)」をひとまとめにした「コンテナ」を作ることができます。
このコンテナは、MacでもWindowsでもLinuxでも、Dockerさえ入っていれば「全く同じ挙動」をします。

「私の環境では動いた」という言い訳は、この世から消滅しました。
Dockerコンテナの中で動いたなら、それは世界中のどこでも動くのです。

Docker入門 ~お弁当箱につめる技術~

Dockerの概念は、「お弁当箱」で考えると分かりやすいです。
アプリ(おかず)と、実行環境(ご飯や調味料)を、一つの箱(イメージ)に詰め込む。
食べる時(実行する時)は、その箱を開けるだけで、どこでも同じ味が楽しめる。

Dockerの3つの基本要素

  1. Dockerfile(レシピ)
    「どのおかずを、どうやって調理して詰めるか」を書いた設計図です。テキストファイルです。
  2. Image(冷凍弁当)
    Dockerfileを元に作られた、コンテナのひな形です。これは変更できません(Read Only)。冷凍保存されたお弁当のようなものです。
  3. Container(解凍したお弁当)
    Imageを実行して、実際に動いている状態です。ここでアプリが動きます。食べ終わったら捨てられます(使い捨て)。

【実践】Hello Worldを動かしてみる

理屈はこれくらいにして、実際に手を動かしましょう。
まずはDocker Desktopを公式サイトからインストールしてください。クジラのアイコンが目印です。

ターミナル(またはコマンドプロンプト)を開き、以下のコマンドを打ち込みます。

docker run hello-world

これだけです。
画面に「Hello from Docker!」というメッセージが表示されたら成功です。
裏側ではこんなことが起きています。

  1. PC内に「hello-world」というImageがあるか探す。
  2. なければ、Docker Hub(クラウド上の巨大な冷蔵庫)からImageをダウンロードする。
  3. ImageからContainerを作成し、実行する。
  4. メッセージを表示して、Containerを終了する。

この間、わずか数秒。VMならOSの起動だけで数分待たされるところです。

自分でDockerfileを書いてみる

次は、自分でレシピを書いてみましょう。Pythonを使って簡単なWebサーバーを立ててみます。
適当なフォルダを作り、Dockerfile という名前(拡張子なし)のファイルを作成します。

# ベースとなるImage(Pythonが入ったLinux)を指定
FROM python:3.9-slim

# 作業ディレクトリを作成
WORKDIR /app

# カレントディレクトリのファイルをコンテナ内にコピー
COPY . .

# Pythonで簡易Webサーバーを立ち上げるコマンド
CMD ["python", "-m", "http.server", "8000"]

そして、同じフォルダに index.html を作ります。中身は <h1>Hello Docker!</h1> とかでOKです。

ターミナルでそのフォルダに移動し、ビルド(お弁当作り)をします。

docker build -t my-web-server .

-t はタグ(名前)をつけるオプションです。最後の . は「今のフォルダのDockerfileを使ってね」という意味です。
ビルドが終わったら、実行(ランチタイム)です。

docker run -p 8080:8000 my-web-server

-p 8080:8000 は「PCの8080番ポートへのアクセスを、コンテナの8000番ポートに転送してね」という意味です。コンテナは隔離された空間なので、こうして穴を開けてあげないと外からアクセスできません。

ブラウザで localhost:8080 にアクセスしてみてください。
あなたが作ったHTMLが表示されましたか?
おめでとうございます。あなたは今、自分だけの環境をコンテナに閉じ込め、それを動かすことに成功しました。このコンテナは、あなたの友人のPCでも、AWS上のサーバーでも、全く同じように動きます。

PC画面上でDockerのコマンドを入力し、ブラウザに「Hello Docker!」が表示された瞬間を見て、その手軽さに驚きと喜びを感じているエンジニアの線画イラスト

Docker Composeで「定食」を作る

Web開発では、Webサーバーだけで完結することは稀です。データベース(MySQLなど)やキャッシュサーバー(Redisなど)が必要です。
これら複数のコンテナを一つ一つ docker run コマンドで立ち上げるのは面倒ですよね。配線(ネットワーク設定)も大変です。

そこで登場するのが、Docker Composeです。
これは「複数のコンテナの構成をまとめて書いた注文書」です。お弁当単品ではなく、「定食」を注文するイメージです。

docker-compose.yml というファイルに構成を書きます。

version: '3.8'
services:
  web:
    build: .
    ports:
      - "8080:8000"
  db:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: password

そして、魔法のコマンドを唱えます。

docker-compose up

これ一発で、Webサーバーとデータベースが同時に立ち上がり、自動的に通信できる状態で繋がります。
開発現場では、この docker-compose.yml をGitで共有します。新しく入ったメンバーは、リポジトリをクローンして docker-compose up を叩くだけ。それだけで全員と同じ開発環境が手に入るのです。
「環境構築で3日かかった」なんて話は、もはや過去の笑い話になりました。

コンテナの反乱とKubernetesの登場

Dockerのおかげで、アプリの開発と配布は劇的に楽になりました。
しかし、運用フェーズに入ると新たな問題が発生します。本番環境では、アクセス負荷に耐えるために、同じアプリのコンテナを10個、100個と並べて動かすことがあります。

「100個のコンテナをどうやって管理する?」
「1個がエラーで落ちたら、誰が再起動する?」
「アクセスの少ない夜中は減らして、昼間は増やしたい」

これを人間が手動でやるのは不可能です。ターミナルを100個開いて監視しますか? 無理ですよね。
コンテナが増えすぎて制御不能になる。これが「コンテナの反乱」です。

この無秩序なコンテナの群れを統率し、指揮を執るためにGoogleが生み出したのが、Kubernetes(クーべネティス / k8s)です。
Kubernetesは、コンテナオーケストレーションツールと呼ばれます。その名の通り、コンテナという個々の演奏者を指揮し、全体として美しい音楽(サービス)を奏でさせる「指揮者」です。

Kubernetesがやってくれること

K8sは非常に賢い指揮者です。

  • 死活監視と自己修復(Self-healing): 「あ、トランペット(コンテナA)が倒れた! すぐに代わりの奏者を連れてこい!」と、落ちたコンテナを勝手に再起動してくれます。
  • スケーリング(Auto-scaling): 「観客(アクセス)が増えてきたぞ! バイオリン(コンテナB)を倍に増やせ!」と、自動でコンテナ数を増減させます。
  • ローリングアップデート: 「演奏を止めるな! 曲の途中で一人ずつ新しい楽譜(新バージョン)に切り替えろ!」と、サービスを停止させずにアプリを更新します。

人間が夜中に起きて対応していたことを、全部自動でやってくれるのです。神のようなツールですが、その分、学習コストはDockerの比ではありません。

無数のコンテナ(箱)が散乱して収拾がつかない状況の中、指揮棒を持ったKubernetesのキャラクターが現れて、整然と隊列を組ませているイメージの線画イラスト

Kubernetes実践 ~指揮者への指示書~

K8sを学ぶには、実際にクラスタ(演奏団)を作ってみるのが一番です。
クラウド(AWSのEKSやGoogleのGKE)を使うとお金がかかるので、今回はローカル環境で動くMinikubeDocker DesktopのKubernetes機能を使いましょう。Docker Desktopの設定で「Enable Kubernetes」にチェックを入れるだけでOKです。

マニフェストファイル(YAML)の地獄と天国

K8sへの指示は、すべてYAML形式のテキストファイルで行います。これを「マニフェスト」と呼びます。
正直、このYAMLを書くのが最初は苦痛です。インデントが一つずれただけで動かない。
でも、これを書けばインフラが「コード」として残る(Infrastructure as Code)ので、再現性が完璧になります。

基本的な構成要素を見てみましょう。

  1. Pod(ポッド): K8sの最小単位。コンテナが1つ以上入ったカプセルです。
  2. Deployment(デプロイメント): 「Podを何個維持するか」を管理する監督です。「常に3個起動しておけ」と指示すると、1個死んでもすぐに補充してくれます。
  3. Service(サービス): 外部からのアクセスをPodに振り分ける受付係(ロードバランサー)です。

簡単なマニフェスト(deployment.yaml)を書いてみます。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  replicas: 3 # 3つのコピー(レプリカ)を作る
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80

これを保存して、以下のコマンドを叩きます。

kubectl apply -f deployment.yaml

kubectl(クーべコントロール)は、指揮者に指示を伝えるための専用トランシーバーです。
apply すると、K8sは「了解。NginxのPodを3つ起動します」と言って、裏でよしなにやってくれます。

確認してみましょう。

kubectl get pods

NAME の欄に、my-nginx-xxxxx という名前のPodが3つ並んでいるはずです。
ここで試しに、そのうちの1つを無理やり削除(kubectl delete pod ...)してみてください。
すぐにもう一度 get pods をすると、新しいPodが勝手に起動しているのが分かります。
これが「自己修復」の力です。感動しませんか? 私は初めてこれを見た時、「これで夜ぐっすり眠れる!」と涙が出そうになりました。

現場で求められるK8sスキル

基礎は分かりましたが、実際の現場ではもっと複雑なことをやります。
副業や転職で評価されるポイントを紹介します。

CI/CDとの連携

コードをGitHubにプッシュしたら、自動的にDockerイメージがビルドされ、K8s環境にデプロイされる。
この「CI/CDパイプライン」を構築できるエンジニアは最強です。
GitHub Actionsなどのツールと組み合わせて、「人間がサーバーに入ってコマンドを叩く」という作業をゼロにする。これが現代のインフラエンジニアの理想形です。

マイクロサービスアーキテクチャ

巨大な一つのアプリ(モノリス)ではなく、機能ごとに小さなアプリ(マイクロサービス)に分割して、それぞれをコンテナで動かす手法です。
「ユーザー管理サービス」と「商品管理サービス」を別のチームが別の言語で開発し、K8s上で連携させる。
K8sは、こうしたマイクロサービスの基盤としてデファクトスタンダードになっています。

監視とログ

コンテナは使い捨てなので、ログをコンテナの中に保存してしまうと、再起動した時に消えてしまいます。
DatadogやPrometheusといった監視ツールを導入し、ログを外部に転送して可視化するスキルも必須です。K8sが勝手に再起動してくれるのは良いですが、「なぜ落ちたのか」を知る術がないと改善できないからです。

複数のモニターに表示された複雑なYAMLファイルと格闘しつつ、CI/CDパイプラインが正常に動作して緑色のチェックマークがついたのを確認して安堵するエンジニアの線画イラスト

FAQ:初心者が抱えるモヤモヤ

Q. DockerとKubernetes、どっちから勉強すべき?
A. 間違いなくDockerです。 K8sはDockerコンテナを管理するためのツールなので、コンテナの仕組み(Dockerfileの書き方など)を理解していないと、K8sの概念は理解できません。まずDockerでアプリを作れるようになってから、K8sに進んでください。

Q. 個人開発の小規模アプリにK8sは必要?
A. 正直、オーバースペックです。 K8sは維持費も高いし(マネージドサービスを使うと月数千円~数万円)、学習コストも高い。個人開発なら、Docker Composeで十分か、あるいはPaaS(HerokuやRender、Vercel)を使った方が幸せになれます。K8sは「大規模なシステムを安定運用するため」の技術だと割り切りましょう。ただ、学習用として触っておく価値は絶大です。

Q. 学習にお金はかかる?
A. 基本は無料です。Docker Desktopも個人利用なら無料ですし、Minikubeを使えば自分のPC内でK8sを動かせます。AWS等のクラウドでK8s(EKSなど)を使うと課金されるので注意してください。

インフラを支配するものが、開発を制する

ここまで、DockerとKubernetesについて、駆け足で解説してきました。
お弁当箱の話から始まって、最後はオーケストラの指揮者へ。インフラ技術の進化の速さには目を見張るものがあります。

私がまだ新人だった頃、サーバー構築といえば、重たい物理サーバーをラックに運び、ケーブルを繋ぎ、OSのディスクを入れてインストールする…という肉体労働でした。失敗すれば最初からやり直し。環境の違いに泣かされ、休日の呼び出しに怯える日々。

それが今や、たった数行のテキストファイル(DockerfileやYAML)で、インフラ全体を定義できる時代になりました。
コマンド一つでサーバーが立ち上がり、勝手に復旧し、スケールする。
これは、エンジニアが「インフラの保守」という守りの業務から解放され、「サービスの価値を高める」という攻めの業務に集中できるようになったことを意味します。

DockerとKubernetesを学ぶということは、単に新しいツールの使い方を覚えることではありません。
「どんな環境でも動く」という安心感と、「大規模なシステムでも操れる」という自信を手に入れることです。

最初はYAMLのインデント地獄にイライラするかもしれません。概念が抽象的すぎて頭が痛くなるかもしれません。
でも、その壁を乗り越えた先には、自分の指先一つで数千のコンテナを自在に操る、全能感あふれる世界が待っています。

さあ、ターミナルを開きましょう。
まずは docker run hello-world から。
その小さな一歩が、あなたのエンジニアとしてのキャリアを、大きく、そして堅牢なものに変えていくはずです。

PC画面上に、Kubernetesのダッシュボードが表示され、全てのPodが正常に稼働している(All Systems Go)状態を確認し、コーヒーを片手に頼もしい表情でモニターを見つめるエンジニアの線画イラスト

あなたの構築したインフラの上で、世界を変えるサービスが動き出す日を、心から楽しみにしています。
エラーが出たら、ログを読みましょう。答えは必ずそこにあります。
Happy Containerizing!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いたエンジニア

松本 大介のアバター 松本 大介 クラウドインフラエンジニア

クラウドインフラの専門家で、大規模構成の最適化が得意。頼れる兄貴肌で、若手の育成にも積極的。普段は落ち着いているが、技術の話になると熱く語る一面も。釣りとドライブが趣味で、休日はよく地方へ出かけてリフレッシュしている。

目次