「自分のPCでは動くのに」をなくす技術
エンジニアなら誰もが一度は経験する悩みがあります。「ローカルでは動くのに本番環境で動かない」「チームメンバーのPCでは再現しない」「環境構築に丸1日かかった」——これらはすべて、実行環境の差異から生まれる問題です。
Dockerはこの問題を根本から解決するコンテナ技術です。「アプリケーションとその実行環境をひとつにパッケージングして、どこでも同じように動かす」という思想のもと、現代のWeb開発ではDockerは事実上の標準ツールになっています。転職市場でも「Docker経験あり」は多くのエンジニア求人で必須または歓迎スキルとして明記されており、理解の深さが選考の差別化ポイントになることも増えています。
この記事では、Dockerを「なんとなく使っている」状態から「仕組みを理解して使いこなせる」状態に引き上げるために必要な知識を、実務視点で整理します。
コンテナと仮想マシンの違いを正確に理解する
Dockerを語るうえで避けられない比較が「コンテナとVM(仮想マシン)の違い」です。この違いを正確に説明できるかどうかは、技術面接でも問われる頻出ポイントです。
VMは、ハイパーバイザーを介してホストOS上に独立したゲストOSを丸ごと立ち上げます。ゲストOSからミドルウェア・アプリまですべてを含むため、完全な隔離が実現できますが、起動に時間がかかり、リソース消費も大きくなります。
コンテナは、ホストOSのカーネルを共有しつつ、プロセス・ファイルシステム・ネットワークを名前空間(namespace)とcgroupsという仕組みで隔離します。ゲストOSを持たない分、起動が数秒以内と高速で、消費リソースも最小限で済みます。ただしカーネルを共有するため、Linuxコンテナを直接WindowsやmacOSのカーネル上で動かすことはできず、内部的にはLinux VMが間に挟まっています(Docker Desktopがこれを透過的に処理しています)。
Dockerの主要概念:イメージ・コンテナ・レジストリ
Dockerを使いこなすには、3つの概念を正確に区別して理解することが重要です。
イメージ(Image)は、コンテナの設計図です。読み取り専用のレイヤー構造を持っており、OSのベース層・ミドルウェア・アプリケーションコードといった構成要素が積み重なっています。イメージ自体は静的なファイルの集まりであり、これを元にコンテナを起動します。
コンテナ(Container)は、イメージを実行した「生きているプロセス」です。イメージに書き込み可能なレイヤーが追加された状態で動作し、停止・削除するとそのレイヤーは消えます。つまりコンテナは「使い捨て可能」であることが前提で、永続化が必要なデータはボリュームに書き出すという設計思想があります。
レジストリ(Registry)は、イメージを保存・配布するためのリポジトリです。Docker Hubが最も有名なパブリックレジストリで、nginx・postgres・node・pythonなどの公式イメージが公開されています。企業では、GitHub Container Registry・Amazon ECR・Google Artifact Registryなどのプライベートレジストリを使うことが一般的です。
Dockerfileの書き方と実務で意識するポイント
DockerfileはDockerイメージを定義するためのテキストファイルです。各行が「レイヤー」として積み重なり、最終的なイメージを形成します。
基本的なDockerfileの構造は、FROM(ベースイメージの指定)→WORKDIR(作業ディレクトリの設定)→COPY(ファイルのコピー)→RUN(コマンドの実行)→EXPOSE(ポートの公開)→CMD(起動コマンドの定義)という流れです。
実務で特に意識すべきポイントが2つあります。
①レイヤーのキャッシュを活用する
Dockerはビルド時、各レイヤーをキャッシュします。変更があったレイヤーとその下のレイヤーは再実行されますが、変更がなければキャッシュが使われます。そのため「変更頻度の低い処理を上に書き、変更頻度の高いコードのCOPYは後ろに書く」ことがビルド高速化のコツです。たとえばNode.jsの場合、package.jsonとpackage-lock.jsonだけを先にコピーしてnpm installを実行し、その後にソースコードをコピーする順番にすることで、依存パッケージが変わっていない場合のビルドが大幅に速くなります。
②マルチステージビルドでイメージを小さくする
本番環境に必要なのはビルドされたアプリだけであり、ビルドツールやテスト用ライブラリは不要です。マルチステージビルドを使うと、ビルド用のステージでコンパイル・バンドルを行い、その成果物だけを軽量な本番用イメージにコピーする構成が作れます。Goのバイナリアプリやフロントエンドのビルド成果物を配信するnginxイメージなど、最終イメージのサイズを大幅に削減できます。
Docker Composeで複数コンテナを管理する
本格的なWebアプリケーションは、アプリサーバー・データベース・キャッシュサーバーなど複数のサービスから構成されます。これらを個別のdocker runコマンドで管理するのは煩雑ですが、Docker Composeを使えばcompose.yaml(またはdocker-compose.yml)に構成を定義し、docker compose up一発でまとめて起動できます。
Docker Composeで特に活用したい機能として、depends_onによるサービス起動順序の制御、volumesによる永続ストレージのマウント、networksによるサービス間通信の隔離、environmentによる環境変数の注入があります。
開発環境での実践的なパターンとして、アプリのソースコードをホストからコンテナにボリュームマウントしつつ、コンテナ内でホットリロードを動かす構成が広く使われています。これにより「コードを変更→保存→ブラウザで即確認」という高速な開発サイクルが、誰のPCでも同じ環境で実現できます。
よく使うDockerコマンドと実務での使い方
| コマンド | 用途 |
|---|---|
docker build -t myapp . | カレントディレクトリのDockerfileからイメージをビルド |
docker run -p 8080:80 myapp | コンテナを起動しポートをマッピング |
docker ps | 起動中のコンテナ一覧を表示 |
docker exec -it <id> bash | 起動中のコンテナにシェルで入る |
docker logs -f <id> | コンテナのログをリアルタイム表示 |
docker compose up -d | Composeでサービスをバックグラウンド起動 |
docker compose down -v | コンテナ停止&ボリュームも削除 |
docker image prune -a | 未使用のイメージを一括削除 |
特にdocker exec -it <id> bashはデバッグ時の必須コマンドです。コンテナ内部に入ってファイルの状態・プロセス・環境変数を確認できます。本番環境のコンテナでは直接実行しないことが原則ですが、開発・検証環境では問題の特定に非常に有効です。
Dockerスキルが転職でどう評価されるか
「Docker使えます」と「Dockerfileを設計してチームの開発環境を整備しました」では評価が大きく異なります。特にマルチステージビルドの設計、Docker Composeによるローカル開発環境の整備、CI/CDパイプラインへのコンテナビルドの組み込みといった経験は、DevOps寄りのポジションやバックエンドエンジニアのシニアポジションで高く評価されます。
職務経歴書には「Dockerfileを最適化してイメージサイズを○○MBから○○MBに削減した」「Docker Composeでチーム全員の開発環境を統一し、環境起因のバグを削減した」といった具体的な成果を書けると、技術力のアピールとして非常に有効です。
まとめ
Dockerはコンテナとイメージの概念を正確に理解したうえで、Dockerfileの設計・レイヤーキャッシュの活用・マルチステージビルドを使いこなすことで、開発の生産性と本番環境の品質を同時に高めることができます。まずはローカルの個人プロジェクトにcompose.yamlを書いてみることから始め、次第にDockerfileを自分で書いて最適化する経験を積んでいきましょう。「環境依存の問題がゼロになった」という体験を一度得ると、Dockerなしの開発には戻れなくなるはずです。