Docker Swarmにcompose.ymlをそのまま持ち込めるか|docker stack deployで効くdeployキーと無視されるbuildの扱い

宮崎智広 この記事の監修:宮崎智広(Linux実務・教育歴20年以上・受講者3,100名超)
HOMELinux技術 リナックスマスター.JP(Linuxマスター.JP)Docker > Docker Swarmにcompose.ymlをそのまま持ち込めるか|docker stack deployで効くdeployキーと無視されるbuildの扱い
「Docker ComposeでAPIサーバーを動かしているが、本番環境でDocker Swarmを使うことになった。compose.ymlをそのまま渡せば動くのか?」

こう尋ねるエンジニアをセミナーでもよく見かける。手元のPCではdocker compose upで問題なく動作していても、docker stack deployに切り替えた瞬間に「buildキーは無視される」「depends_onが機能しない」という壁にぶつかる。

この記事では、compose.ymlをDocker Swarmへ持ち込む際の互換性を体系的に整理し、docker stack deployで有効なdeployキーと無視されるキーの違い・対処法をコマンド実例付きで解説します。Rocky Linux 9.4 / Ubuntu 24.04 LTSで動作確認済みです。

この記事のポイント

・docker stack deployはdeployブロック(replicas・placement・restart_policy)を読み取りSwarmサービスを構成する
・build・depends_on・restartキーはdocker stack deployでは完全に無視される
・buildを使っているサービスは「ビルド→レジストリpush→image:書き換え」の3ステップで対応する
・depends_onの代替はhealthcheck + deploy.restart_policy.condition: on-failureで吸収できる


「このままじゃマズい」と感じていませんか?
参考書を開く気力もない、同年代に取り残される不安——
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

Docker SwarmとDocker Compose、何が根本的に違うのか

docker compose upとdocker stack deployは、どちらもcompose.yml(またはdocker-compose.yml)を読む点では同じに見える。しかし内部の動作モデルは大きく異なる。

docker compose upはシングルホスト上でコンテナを起動するツールだ。compose.ymlに書かれたほぼすべてのキー(build、depends_on、restart、container_name、links等)を処理する。

一方、docker stack deployはDocker Swarmクラスターに対してサービスを宣言的にデプロイするコマンドだ。複数ノードにまたがるため、「1台のPCでしか意味をなさないキー」は設計上サポートされない。具体的には以下の違いがある。

項目 docker compose up docker stack deploy
実行環境 シングルホスト Swarmクラスター(マルチノード可)
build:キー 有効(その場でビルド) 無視される(事前にpush必須)
depends_on:キー 有効(起動順序を制御) 無視される(同時起動)
deploy:キー 基本的に無視 有効(replicas・placementなど)
restart:キー 有効 無視(deploy.restart_policyを使う)
container_name:キー 有効 無視(Swarmが管理)

compose.ymlをSwarm対応に調整してdocker stack deployで展開する基本手順

実際にcompose.ymlをSwarmに持ち込む手順を順を追って説明する。

1. Docker Swarmを初期化する

まだSwarmを起動していない場合は、マネージャーノードで以下を実行する。

$ docker swarm init --advertise-addr 192.168.1.10 Swarm initialized: current node (abc123xyz) is now a manager. To add a worker to this swarm, run the following command: docker swarm join --token SWMTKN-1-xxx 192.168.1.10:2377

--advertise-addrには、ほかのノードからアクセスできるIPアドレスを指定する。シングルノードでの動作確認であれば、docker swarm initだけでも構わない。

2. compose.ymlをSwarm対応に調整する

既存のcompose.ymlがある場合、Swarmで無視されるキーを取り除き、deployブロックを追加する。以下はWordPressとMySQLの構成例だ。

修正前(docker compose up向け):

services: db: image: mysql:8.0 restart: always # ← Swarmでは無視される container_name: wp_db # ← Swarmでは無視される environment: MYSQL_ROOT_PASSWORD: secret MYSQL_DATABASE: wordpress wordpress: build: . # ← Swarmでは無視される(事前にpush必須) depends_on: - db # ← Swarmでは無視される ports: - "80:80" environment: WORDPRESS_DB_HOST: db:3306

修正後(docker stack deploy向け):

services: db: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: secret MYSQL_DATABASE: wordpress deploy: replicas: 1 restart_policy: condition: on-failure max_attempts: 3 placement: constraints: - node.role == manager wordpress: image: myrepo/wordpress:latest # ← buildの代わりにpush済みイメージを指定 ports: - "80:80" environment: WORDPRESS_DB_HOST: db:3306 deploy: replicas: 2 restart_policy: condition: on-failure update_config: parallelism: 1 delay: 10s networks: default: driver: overlay

3. docker stack deployを実行する

# スタック名を "myapp" として展開する $ docker stack deploy -c compose.yml myapp Creating network myapp_default Creating service myapp_db Creating service myapp_wordpress

-cオプションでcompose.ymlのパスを指定し、その後ろにスタック名(ここでは myapp)を付ける。スタック名はすべてのサービス名・ネットワーク名のプレフィックスになる。

4. デプロイ状態を確認する

# サービス一覧を確認する $ docker service ls ID NAME MODE REPLICAS IMAGE a1b2c3d4e5f6 myapp_db replicated 1/1 mysql:8.0 f6e5d4c3b2a1 myapp_wordpress replicated 2/2 myrepo/wordpress:latest # 特定サービスのタスク(コンテナ)状態を確認する $ docker service ps myapp_wordpress ID NAME IMAGE NODE DESIRED STATE CURRENT STATE x1y2z3a4b5c6 myapp_wordpress.1 myrepo/wordpress:latest node01 Running Running 2 minutes ago c6b5a4z3y2x1 myapp_wordpress.2 myrepo/wordpress:latest node02 Running Running 2 minutes ago

REPLICAS列が「2/2」と表示されれば、目標レプリカ数に達して正常稼働している。「0/2」や「1/2」のまま止まっている場合はトラブルシュートセクションを参照してほしい。

docker stack deployで有効なdeployキー一覧

deployブロック配下のキーは、docker stack deployで初めて意味を持つ。主要なキーを実例付きで整理する。

replicas(レプリカ数)

deploy: replicas: 3 # サービスを3コンテナで動かす

placement(配置制約)

どのノードにコンテナを配置するかを制御する。node.role、node.labels、node.hostnameなどが使える。

deploy: placement: constraints: - node.role == worker # ワーカーノードにのみ配置 - node.labels.region == tokyo # ラベルで絞り込む場合

ノードラベルは以下で付与する。

$ docker node update --label-add region=tokyo node01

update_config(ローリングアップデート設定)

deploy: update_config: parallelism: 1 # 同時に更新するコンテナ数 delay: 10s # 各バッチ間の待機時間 failure_action: rollback # 失敗したら自動ロールバック order: start-first # 新コンテナを先に起動してから旧コンテナを停止

restart_policy(再起動ポリシー)

deploy: restart_policy: condition: on-failure # 失敗時のみ再起動(any / none も指定可能) delay: 5s # 再起動前の待機時間 max_attempts: 3 # 最大再起動回数(超えたらタスクを停止) window: 120s # max_attemptsをカウントする時間窓

resources(CPUとメモリの制限・予約)

deploy: resources: limits: cpus: '0.50' # CPUの上限(コア数の割合) memory: 512M # メモリの上限 reservations: cpus: '0.25' # スケジューリング時に確保するCPU memory: 256M # スケジューリング時に確保するメモリ

mode(replicated vs global)

deploy: mode: global # 全ノードに1コンテナずつ配置(監視エージェントなどに使う) # mode: replicated # デフォルト。replicasで数を指定

docker stack deployで無視されるキー(要注意)

以下のキーはdocker compose upでは有効だが、docker stack deployでは完全に無視される。エラーにはならないため、うっかり残したまま展開しても気づきにくい点に注意が必要だ。

build:Swarmはイメージをビルドしない。image:でレジストリ上のイメージを指定する必要がある
depends_on:Swarmはサービスの起動順序を制御しない。すべてのサービスがほぼ同時に起動される
restart:deploy.restart_policyで代替する(restart: alwaysとは設定方法が異なる)
container_name:Swarmはコンテナ名を「スタック名_サービス名.タスク番号」形式で自動管理する
links:レガシー機能のため非サポート。overlayネットワーク上ではサービス名でDNS解決できる
network_mode: host:Swarmのopenポートでは使えない。ホストネットワークが必要な場合は別途検討が必要

buildキーを使っている場合の対処法

compose.ymlにbuild:が含まれているサービスをSwarmで動かすには、「ビルド→レジストリへpush→image:に書き換え」の3ステップが必要だ。

1. イメージをビルドしてタグを付ける

# カレントディレクトリのDockerfileを使ってビルドする $ docker build -t myrepo/myapp:v1.0 . # Docker Hubに送る場合は事前にログインしておく $ docker login

2. レジストリにpushする

$ docker push myrepo/myapp:v1.0 The push refers to repository [docker.io/myrepo/myapp] v1.0: digest: sha256:abc123... size: 1234

プライベートレジストリを使う場合は、Swarmの全ノードがそのレジストリにアクセスできる状態にしておく必要がある。認証情報はdocker login後に~/.docker/config.jsonに保存されるが、マルチノード構成では各ノードへのログインか、Docker Secretsを使った認証情報の共有が必要になる。

3. compose.ymlのbuild:をimage:に書き換える

# 修正前 services: app: build: . ports: - "8080:8080" # 修正後 services: app: image: myrepo/myapp:v1.0 # pushしたイメージを指定 ports: - "8080:8080" deploy: replicas: 2

CI/CD環境ではビルド→タグ付け→pushをパイプラインに組み込み、compose.yml内のimage:タグをCI側で動的に書き換えてからdocker stack deployを実行するパターンが一般的だ。

トラブルシュート|よくあるエラーと対処

サービスが「Preparing」から進まない

docker service psを実行してCURRENT STATE列を確認する。「Preparing」が続く場合はイメージのpullに失敗している可能性が高い。

$ docker service ps myapp_wordpress --no-trunc ID NAME IMAGE NODE DESIRED CURRENT STATE ERROR xxx myapp_wordpress.1 myrepo/wordpress:latest node02 Running Preparing 3 min "No such image: myrepo/wordpress:latest"

ERROR列に「No such image」が出ている場合、node02からそのレジストリにアクセスできないか、イメージがpushされていない。node02上で直接docker pull myrepo/wordpress:latestを試し、エラー内容を確認する。

「no suitable node」エラーが出る

placementのconstraintsが厳しすぎて、条件に合うノードが存在しない場合に発生する。

# ノードの状態とラベルを確認する $ docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS abc123 * node01 Ready Active Leader def456 node02 Ready Active # ノードに付いているラベルを確認する $ docker node inspect node02 --pretty | grep -A 5 Labels Labels: - region=osaka

compose.yml側でconstraintsにnode.labels.region == tokyoと書いているのに、実際のノードにそのラベルが付いていない場合に起きる。docker node updateでラベルを追加するか、constraintsの条件を修正する。

depends_onが効かずDB接続エラーが出る

Swarmではdepends_onが無視されるため、DBが完全に起動する前にアプリが接続を試みてエラーになることがある。対処法は2つある。

・アプリ側で接続リトライロジックを実装する(最も根本的な解決策)
・deploy.restart_policy.condition: on-failureを設定し、DB起動完了後にアプリが自動再起動するのを待つ

deploy: restart_policy: condition: on-failure max_attempts: 5 # 最大5回リトライする間にDBが起動するのを待つ delay: 5s

スタックの更新(再デプロイ)方法

設定変更後は同じコマンドを再実行するだけでよい。Swarmはdiff差分を適用し、変更のあったサービスのみをローリングアップデートする。

# 同じコマンドで再実行すると差分が適用される $ docker stack deploy -c compose.yml myapp Updating service myapp_wordpress (id: f6e5d4c3b2a1) # スタックを完全に削除する場合 $ docker stack rm myapp

本記事のまとめ

docker stack deployとcompose.ymlの互換性の早見表です。

キー docker stack deployでの扱い 代替手段
deploy.replicas 有効
deploy.placement 有効
deploy.update_config 有効
deploy.restart_policy 有効
deploy.resources 有効
build 無視される ビルド後にimage:でpush済みイメージを指定
depends_on 無視される アプリ側リトライ + restart_policy.condition: on-failure
restart 無視される deploy.restart_policyに移行
container_name 無視される Swarmが「スタック名_サービス名.N」形式で自動付与
ポイントをまとめます。

・compose.ymlをSwarmに持ち込む際は、buildをimage:に、restartをdeploy.restart_policyに置き換えるのが最初の作業になる
・deployブロック(replicas・placement・update_config・restart_policy・resources)はdocker stack deployで初めて有効になる
・depends_onの代替はアプリ側リトライとrestart_policy.on-failureの組み合わせで対応する
・サービスが「Preparing」から進まない場合はdocker service ps --no-truncでイメージpullのエラーを確認する
現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、20年以上の運用経験を持つ現役エンジニアがDockerの基礎からSwarmによる本番運用まで体系的に教えます。
Docker実践講座の詳細を見る >>

無料メルマガで学習を続ける

Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。

登録無料・いつでも解除できます

暗記不要・1時間後にはサーバーが動く

3,100名以上が実践した「型」を無料で公開中

プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。

姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

Linux無料マニュアル(図解60P) 名前とメールで30秒登録
宮崎 智広

この記事を書いた人

宮崎 智広(みやざき ともひろ)

株式会社イーネットマーキュリー代表。現役のLinuxサーバー管理者として20年以上の実務経験を持ち、これまでに累計3,100名以上のエンジニアを指導してきたLinux教育のプロフェッショナル。「現場で本当に使える技術」を体系的に伝えることをモットーに、実践型のLinuxセミナーの開催や無料マニュアルの配布を通じてLinux人材の育成に取り組んでいる。

趣味は、キャンプにカメラ、トラウト釣り。好きな食べ物は、ラーメンにお酒。休肝日が作れない、酒量を減らせないのが悩み。最近、ドラマ「フライトエンジェル」を観て涙腺が崩壊しました。