まずarm64、必要なときにamd64
MシリーズMacではarm64 Linuxカーネル上でLinuxコンテナを実行します。マルチアーキテクチャイメージ(postgres、redis、node、pythonなど多くの公式イメージ)をpullすると、Dockerが自動でarm64版を選び、ネイティブの速度で動きます。
古い社内イメージ、ベンダーツール、Intelノートパソコンやプラットフォーム指定なしのCIランナーで作ったイメージなど、amd64版しかないものもあります。その場合は明示的に指定します。
services:
legacy-tool:
image: example/amd64-only-tool:1.4
platform: linux/amd64 OxcartはAppleのx86-64変換技術Rosettaでamd64イメージを実行します。Buildxでamd64イメージをビルドしてロードし、エンジンでローカル実行することもできます。docker run --rm --platform linux/amd64 alpine uname -mでコンテナの実際のアーキテクチャを確認でき、x86_64と表示されます。
| 状況 | 対応 |
|---|---|
| イメージにarm64版がある | 対応不要。Composeがarm64版をpullします。 |
| イメージがamd64専用 | サービスにplatform: linux/amd64を追加します。 |
| amd64サーバーにデプロイする | pushするイメージはdocker buildx build --platform linux/amd64でビルドします。スタックが対応していれば、ローカル作業はarm64のままで構いません。 |
| "exec format error" | バイナリとコンテナのアーキテクチャが一致していません。プラットフォームを指定するか、arm64向けに再ビルドします。 |
一通りの例
Postgresデータベース、現在のフォルダーからビルドしてデータベースの正常性を待つAPI、プロファイルで有効にするamd64専用ツールの例です。
services:
db:
image: postgres:17-alpine
environment:
POSTGRES_PASSWORD: dev
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 2s
timeout: 3s
retries: 15
api:
build: .
init: true
environment:
DATABASE_URL: postgres://postgres:dev@db:5432/postgres
ports:
- "127.0.0.1:8080:8080"
depends_on:
db:
condition: service_healthy
legacy-tool:
image: example/amd64-only-tool:1.4
platform: linux/amd64
profiles: ["tools"]
volumes:
pgdata: 各設定の役割:
healthcheckは、Postgresが起動しただけでなく、実際に接続を受け付けるようになったことをComposeに伝えます。depends_on: condition: service_healthyは、そのチェックが通るまでAPIを待機させます。init: trueは小さなinitをPID 1として実行し、プロセスにシグナルを届け、ゾンビプロセスを回収します。これによりdocker stopはタイムアウトを待たずに正常終了します。127.0.0.1:8080:8080はMacのループバックだけにAPIを公開します。アドレスを指定しないと、MacのすべてのIPv4アドレスで待ち受け、同じネットワーク上のほかのマシンからもアクセスできます。pgdataは名前付きボリュームです。データはdocker compose down後も残り、down -vでのみ削除されます。
AppleシリコンでComposeスタックを動かす
- ツールを確認します。
docker compose versionとdocker context showを実行します。OxcartはDocker Compose 5.6.0、docker CLI 29.9.0、Buildx 0.38.0を同梱し、コンテキスト名はoxcartです。 - composeファイルを書きます。 アプリが待つ必要のあるすべてのサービスに
healthcheckを設定し、依存する側はdepends_on: condition: service_healthyで待機させます。 - 起動して正常性を待ちます。
docker compose up -d --build --waitを実行します。すべてのサービスが稼働して正常になるとコマンドが戻り、そうでないサービスがあれば失敗します。 - ポートを確認します。
docker compose psを実行するか、OxcartのPorts画面を開きます。各公開ポートが準備完了、待機中、失敗のどれかを理由とともに表示します。 - 変更を繰り返します。 コードを編集して
docker compose up -d --build apiを実行します。変更のないビルドステップはキャッシュから取得されます。 - 片付けます。
docker compose downでコンテナを停止・削除します。名前付きボリュームも削除するならdocker compose down -vを実行します。
再ビルドを高速に
ComposeはBuildxとBuildKitを通じてビルドします。Dockerfileでは依存関係のインストールをCOPY . .より前に置くと、コード変更時にその上のキャッシュ済みレイヤーをすべて再利用できます。Oxcartでは、ベンチマークプロジェクトのキャッシュありビルドは121 ms、ローカルコンテキストを使うキャッシュなしビルドは341 msで、どちらもテストした3つのランタイムの中で最速でした。短い反復作業の差が積み重なります。docker run --rmは42 ms、20コンテナの停止・削除は77 msでした。
Oxcart 0.1.2は2026-10-10に同梱のdocker 29.9クライアントで測定しました。他のランタイムは同日のそれ以前に、同じMacと測定ハーネスを使い、docker 29.4で測定しました。Apple M5 Max、各8 CPU・12 GiB、ランタイムを1つずつ実行。
ポート、Mac、ほかのサービス
- ポートの構文はDockerと同じです。TCPとUDP、一時ポート(
"127.0.0.1::8080")、IPv4とIPv6で待ち受ける"[::]:8080:80"に対応します。TCPとUDPは同じホストポート番号を共有できます。 - コンテナからMacへ:
host.docker.internalを使うと、コンテナやビルドステップからTCPでMacの127.0.0.1にバインドされたサービスにアクセスできます。 - ローカルレジストリ:レジストリコンテナをポート5000で公開すると、
docker push localhost:5000/appでアクセスできます。 - サイドカー:
network_mode: service:apiはコンテナを別のサービスのネットワーク名前空間に入れ、そのサービスのlocalhostを共有させます。
VPN、DNS、ファイアウォール、ネットワーク経路の保護については、Macのコンテナネットワークをご覧ください。
名前付きボリュームとバインドマウント
データベースやビルドで頻繁に書き込むものには名前付きボリュームを使います。node_modules、パッケージキャッシュ、データベースファイルなどです。データはエンジン自身のストレージ内に保存されます。Oxcartの名前付きボリュームでは、小さなファイルの作成・stat・読み取り・削除を1,000回行う処理が17.8 msで完了し、テストした3つのランタイムの中で最速でした。
Macで編集するソースコードにはバインドマウントを使います。Oxcartは既定でホームフォルダー、/private/tmp、/private/var/foldersを読み書き可能でコンテナと共有します。Macでの編集はコンテナに、コンテナでの変更はMacに反映されます。ただし、Macで行ったファイル変更はコンテナ内でinotifyイベントを発生させません。コンテナ内のファイル監視でエディタの変更を検出する必要がある場合は、ポーリングを使ってください。
トラブルシューティング
| 症状 | 原因 | 対処 |
|---|---|---|
exec format error | arm64コンテナ内のamd64バイナリ、またはその逆 | platform: linux/amd64を指定、またはarm64向けに再ビルド |
| "no matching manifest for linux/arm64" | イメージにarm64版がない | platform: linux/amd64 |
| "address already in use" | 別のプロセスやコンテナがホストポートを使用中 | ホストポートを変更するか、OxcartのPorts画面で使用者を確認 |
| 公開ポートで接続が拒否される | コンテナ内のサーバーが127.0.0.1で待ち受けている、またはまだ待ち受けていない | 0.0.0.0で待ち受け、ヘルスチェックを追加して--waitを使う |
| データベースの準備前にアプリが起動する | 条件のないdepends_onは起動だけを待つ | condition: service_healthyとhealthcheckを組み合わせる |
docker stopで10 s待たされる | PID 1がSIGTERMを無視する | init: trueを使うか、アプリでSIGTERMを処理する |
よくある質問
Docker ComposeはAppleシリコンMacで使えますか?
はい。Composeはarm64でネイティブ実行でき、多くの公式イメージにarm64版があります。OxcartはDocker Compose 5.6.0を同梱し、複数サービス、ヘルスチェックによる依存関係、up --wait、build、down、サービス名DNS、init: true、network_mode: service:の互換性を確認しています。
MシリーズMacでamd64(x86-64)イメージを実行するには?
サービスにplatform: linux/amd64を設定するか、docker runに--platform linux/amd64を渡します。OxcartはRosetta経由でamd64イメージを実行します。arm64ネイティブイメージがあれば優先し、arm64ビルドのないイメージにamd64を使ってください。
「exec format error」とは何ですか?
コンテナの実行アーキテクチャとは異なるCPU向けにビルドされたバイナリを実行しようとしています。通常は、イメージや内部のバイナリがamd64専用です。そのサービスにplatform: linux/amd64を追加するか、arm64向けにイメージを再ビルドしてください。
コンテナが動いているのに「connection refused」と出るのはなぜですか?
最も多い原因は、コンテナ内のサーバーが127.0.0.1で待ち受けていることです。公開ポートはループバックではなくコンテナのネットワークインターフェースに届くため、サーバーは0.0.0.0で待ち受ける必要があります。OxcartのPorts画面は、この状態を明示します。
別のサービスの準備ができるまで待たせるには?
依存先にhealthcheckを追加し、依存する側にdepends_on: { db: { condition: service_healthy } }を設定します。するとdocker compose up --waitは、すべてのサービスが正常になってから戻ります。
コンテナからMac上のサーバーにアクセスできますか?
はい。host.docker.internalを使います。Oxcartでは、コンテナやビルドからTCPでMacの127.0.0.1にバインドされたサービスにアクセスできます。
データベースには名前付きボリュームとバインドマウントのどちらを使うべきですか?
データベースのデータには、エンジン自身のストレージ内に保存する名前付きボリュームを使います。Macで編集するソースコードにはバインドマウントを使います。Oxcartの名前付きボリュームでは、小さなファイルの作成・stat・読み取り・削除を1,000回行う処理が17.8 msでした。
出典と測定方法
- 互換性:Oxcartで検証済みの連携(docker CLI、ヘルスチェックによる依存関係を使うCompose、
up --wait、init: true、network_mode: service:、Buildx、Rosetta経由のamd64)。 - 速度の数値:Oxcart 0.1.2、2026-10-10、Apple M5 Max、8 CPU・12 GiB、ウォームアップ後5回測定の中央値。他のランタイムは同日のそれ以前に、同じMacと測定ハーネスでdocker 29.4クライアントを使って測定しました。
- 同梱ツール:docker 29.9.0、Docker Compose 5.6.0、Buildx 0.38.0。