【2026-08-16 加筆】
この記事はDockerを触りはじめたときの記録です。その後仮想マシンの中身を実測した回などを経て、「Macで動かすDockerは、実は仮想マシンの上にいる」という点をきちんと書いておくべきだと感じたので、章として足しました。

Dockerって何?コンテナとはどういう概念か

スポンサーリンク

Dockerとは、アプリケーションをその実行環境ごとパッケージ化して動かせるツールです。このパッケージ化した単位のことをコンテナと呼びます。

コンテナを一言で表すなら「アプリと必要なものをまとめた小さな箱」です。輸送用のコンテナが中身を問わず船でも列車でも運べるように、Dockerのコンテナも環境を問わずどこでも同じように動かせます。

コンテナの中には、アプリのソースコードはもちろん、必要なライブラリ・設定ファイル・実行環境(Node.jsやPythonのバージョンなど)がすべて含まれています。開発PCでもサーバーでも、Dockerさえ入っていれば同じ動作を保証できる、というのが最大のメリットです😊

仮想マシンとの違いを比べてみる

「それって仮想マシンと何が違うの?」と思いますよね。私も最初はそう感じていました。整理するとこうなります。

項目 仮想マシン(VM) Dockerコンテナ
起動速度 数十秒〜数分 数秒
ディスク使用量 OSごと数GB〜十数GB 数百MB程度
OSの仮想化 ゲストOSを丸ごと起動 ホストOSのカーネルを共有
用途 完全なOS環境が必要な場面 アプリ実行環境の分離・配布
代表例 Parallels, UTM, VMware Docker Desktop

仮想マシンはOS全体をエミュレートするため重くなりがちですが、コンテナはホストのOSカーネルを共有するので軽量・高速です。「開発環境を素早く用意してすぐ作業に入りたい」という場面ではDockerが圧倒的に手軽でした。

実際にDockerをインストールして使ってみた

Mac上で試してみました。インストールはDocker公式サイトからDocker Desktopをダウンロードするだけです。

インストール後、ターミナルで動作確認します。

# バージョン確認
docker --version
# Docker version 26.1.1, build 4cf5afa

# 試しにhello-worldを動かす
docker run hello-world

docker run hello-world を実行すると、DockerHubからイメージを自動でダウンロードしてコンテナを起動してくれます。「Hello from Docker!」と表示されたら成功です。初回はイメージのダウンロードが走りますが、2回目以降はキャッシュが使われるので一瞬で起動します。

次に、Pythonの実行環境をコンテナとして立ち上げてみました。ローカルにPythonをインストールしていなくても動きます。

# Python 3.11のコンテナを対話モードで起動
docker run -it python:3.11 bash

# コンテナ内でPythonを実行
python3 -c "print('Hello from container!')"
# Hello from container!

コンテナを終了(exit)すればホスト環境は一切汚れません。「ちょっと試したいだけ」という場面で非常に便利でした😊

Dockerfileの基本的な書き方

毎回 docker run でコマンドを打つのではなく、Dockerfileというテキストファイルに環境の構成を記述しておくことで、同じ環境を何度でも再現できます。

以下はPythonアプリを動かすDockerfileの例です。

# ベースイメージを指定
FROM python:3.11-slim

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

# 依存パッケージをインストール
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# アプリのソースをコピー
COPY . .

# コンテナ起動時に実行するコマンド
CMD ["python3", "main.py"]

主要な命令を簡単にまとめます。

命令 役割
FROM ベースとなるイメージを指定
WORKDIR コンテナ内の作業ディレクトリを設定
COPY ホストのファイルをコンテナにコピー
RUN イメージビルド時にコマンドを実行
CMD コンテナ起動時に実行するコマンド

Dockerfileを作ったら、以下のコマンドでイメージをビルドしてコンテナを起動します。

# イメージをビルド(myappという名前をつける)
docker build -t myapp .

# コンテナを起動
docker run myapp

この手順を一度やってみると「なるほど、こういう仕組みか」とすんなり理解できました。

ParallelsやUTMとの使い分け

私はMac上でWindowsが必要な場面ではParallels、ARMのLinux環境が必要な場面ではUTMを使っています。Dockerはこれらとは競合するものではなく、用途が異なります。

実際の使い分けはこんな感じです。

  • Parallels / UTM:WindowsやLinuxのGUI環境が必要、ソフトウェアのフル動作確認をしたい、OSレベルの検証をしたい
  • Docker:開発用のPython・Node.js・データベース環境を素早く立てたい、チームで同じ環境を共有したい、本番環境と揃えたい

組み込み系の仕事をしていると、クロスコンパイル環境を用意する場面が多いのですが、そういう「特定バージョンのツールチェーンだけ入れた環境」を使い捨てで作れるDockerはかなり重宝しています。

【追記】MacのDockerは、実は仮想マシンの上で動いている

本文で「仮想マシンよりコンテナのほうが軽い」と書きました。これはLinux上では正しいのですが、MacとWindowsでは事情が違います。

コンテナは、ホストOSの中身(カーネル)を借りて動く仕組みです。だから起動が速く、消費するメモリも少なくて済みます。ただしこれは「借りられる中身が、そこにある」ことが前提です。Dockerのコンテナが借りたいのはLinuxの中身なので、macOSの上には借りるものがありません。

そこでMacでは、まずLinuxの仮想マシンを1つ立ち上げ、その中でコンテナを動かしています。

Linuxの場合 Linux(ホストOS) コンテナ 2段。中身を直接借りる macOSの場合 macOS(ホストOS) Linuxの仮想マシン コンテナ 3段。間に仮想マシンが挟まる

これを知っておくと、次のことが腑に落ちます。

  • Docker Desktop を起動した瞬間に、何もしていなくてもメモリを数GB持っていかれるのは、この仮想マシンのぶんです
  • ホスト側のフォルダをコンテナから読むと遅いのは、仮想マシンの境界をまたいでいるからです
  • コンテナ内の時刻やネットワークが、Macから見て少し違う挙動をするのも同じ理由です
それでも仮想マシンより手軽なのは変わらない
3段になっていても、立ち上げる仮想マシンは1つだけで、その上にコンテナをいくつも並べられます。用途ごとに仮想マシンを1台ずつ用意するのに比べれば、消費するものはずっと少なくて済みます。「軽い」の中身が、Macでは「1台を使い回せる」という意味になる、ということです。

【追記】Apple Siliconで踏みやすい罠 ── アーキテクチャの違い

Apple Silicon の Mac は ARM です。そのため、何も指定せずにイメージを取ってくるとARM版が落ちてきます。ところが世の中に出回っているイメージには、x86_64(Intel向け)しか用意されていないものがまだあります。

この場合、Dockerはエミュレーションで動かそうとします。動くことは動きますが、目に見えて遅くなります。

# いま動いているイメージがどちらなのかを確かめる
docker image inspect イメージ名 --format '{{.Architecture}}'
# arm64 と出れば本来の速度、amd64 ならエミュレーション

# どうしても x86_64 で動かしたいときは明示する
docker run --platform linux/amd64 イメージ名

ここも、仮想マシンの回で分かったことと同じ形をしています。「動いた」ことと「本来の経路で動いた」ことは別で、速度が出ないときはまず経路を確認する、というのが定石でした。

状況速度対処
arm64 のイメージがある本来の速度そのまま使う
amd64 しか無い目に見えて遅いarm64版の代替イメージを探す
自分でビルドする—--platform を明示して意図を固定する

【追記】仮想マシンとコンテナ、結局どう使い分けるか

本文の使い分けを、その後の経験を踏まえて整理し直します。判断の軸は「軽さ」ではなく、OSそのものが要るかどうかでした。

やりたいこと向いているもの理由
Linuxのビルド環境がほしいコンテナ必要なのは中身だけ。OSまるごとは要らない
同じ環境を人に渡したいコンテナ手順がファイル1つに収まる
Windowsのアプリを動かしたい仮想マシンWindowsという別のOSそのものが必要
GUIを操作したい仮想マシンコンテナは画面を持たない前提の作り
デバイスを直接つなぎたい場合によるUSBなどは仮想マシンのほうが素直なことが多い
3Dやゲームを動かしたい仮想マシン★ただしソフトによって描画の経路が別。要注意

組み込みの仕事で使う場面に限れば、ほとんどはコンテナで足ります。特定のバージョンのコンパイラを固定したい、という用途が多いからです。仮想マシンを立てるのは「Windows専用のツールを動かしたい」ときくらいでした。

まとめ

Dockerは仮想マシンほど重くなく、それでいて「どこでも同じ環境で動く」という確実性を持っています。最初は「コマンドが多くて難しそう」と感じていましたが、docker run と Dockerfile の基本さえ押さえれば思ったよりもハードルは低かったです。

仮想マシンをすべてDockerに置き換えるのではなく、「アプリの実行・開発環境はDocker、OSが必要な場面はParallels/UTM」という棲み分けが自分の環境にはしっくりきました。次は docker-compose を使って複数コンテナを組み合わせる構成にも挑戦してみたいと思っています。

それでは、今回はここまで。ありがとうございました😊