- OS
-
Windows、macOS、Linux
- ブランド
-
ドッカー
私が知っている開発者は皆、同じサイクルを経験しています。新しいプロジェクトを開始すると、データベースが必要になります。そのため、PostgreSQL または MySQL をダウンロードして設定を完了し、5 分後に設定したパスワードを忘れてしまいます。数か月後、そのデータベースの別のバージョンが必要な別のプロジェクトを開始したり、おそらく Redis が必要になったりすると、ホスト マシンは突然、一度インストールして忘れていたサービスの墓場となります。
この問題を解決する方法はたくさんあります (正直に言うと多すぎます) が、個人のローカル開発環境の場合、最もシンプルで保守しやすい解決策は、すべてを 1 つの Docker Compose ファイルに入れることです。
ほとんどの開発環境で必要なサービス
Web アプリケーションの作業に座るとき、ほぼ常に必要となるサービスがいくつかあります。正確な要件がプロジェクトごとに異なる場合でも、ほとんどの開発者は同様のツール セットに依存しています。データを保存するデータベースが必要です。通常は PostgreSQL です。キャッシュやセッション管理のために Redis のようなキーバリューストアが必要になることがよくあります。バックグラウンド ジョブやイベント駆動型アーキテクチャに関連するものに取り組んでいる場合は、RabbitMQ のようなメッセージ ブローカーが必要です。また、開発中に電子メールの機能をテストするには、送信電子メールをキャッチして、実際に送信するのではなく Web インターフェイスに表示する MailHog のようなものが必要です。
これらすべてのサービスを一緒に実行する Docker Compose ファイルを構築します。このファイルはポータブル開発ツールボックスになります。プロジェクト間でコピーしたり、バージョンを調整したりすることで、毎回一貫した環境を得ることができます。
まず、プロジェクト用に新しいディレクトリを作成し、そのディレクトリ内に docker-compose.yml という名前のファイルを作成します。これは標準名であり、docker compose コマンドがデフォルトで検索するものです。
1. データベースから始める
PostgreSQL から始めましょう。 PostgreSQL の基本的なサービス定義は次のとおりです。
services:
postgres:
image: postgres:18.2
container_name: local_postgres
ports:
- "5432:5432"
environment:
POSTGRES_USER: myuser
POSTGRES_PASSWORD: mypassword
POSTGRES_DB: myapp_dev
volumes:
- postgres_data:/var/lib/postgresql/data
restart: unless-stopped
この小さなブロックでは多くのことが行われているので、各行について説明しましょう。サービス ブロックには、実行するすべてのコンテナーをリストします。各サービスには名前があり、この場合は postgres です。
イメージ行は、Docker Hub からどのイメージをプルするかを Docker に指示します。に固定しました postgres:18.2。 タグなしで postgres を使用すると、最新のタグが取得されます。これは、PostgreSQL の新しいメジャー バージョンがリリースされると、環境が予期せず変更される可能性があることを意味します (機能が壊れることがよくあります)。
Container_name はオプションですが、役に立ちます。コンテナの固定名を設定します。これがないと、Docker は postgres_1234abcd のようなランダムな名前を生成します。予測可能な名前を付けると、必要に応じて、その特定のコンテナーに対して docker コマンドを実行しやすくなります。
NAS を購入する前に Docker を学習する必要があります (方法はこちら)
Docker を使用すると、NAS を独自のアプリをホストし、自宅を自動化できる独自のクラウドに変えることができます。
ポート行は、ホスト マシン上のポートをコンテナ内のポートにマップします。形式は「ホスト:コンテナ」です。 PostgreSQL はデフォルトでコンテナ内のポート 5432 をリッスンします。これをホスト上の同じポートにマッピングすると、PostgreSQL をネイティブにインストールしたかのように、ラップトップで実行されている任意のツールから localhost:5432 を使用してデータベースに接続できます。
環境セクションでは、コンテナー内の環境変数を設定します。 PostgreSQL イメージは、これらの特定の変数を検索して、デフォルトのユーザー、パスワード、およびデータベースを構成します。ここではデモのためだけに単純な値を使用しました。
コンテナーはデフォルトでは一時的なものであるため、ボリューム セクションは重要です。コンテナを削除すると、データも削除されます (ゴミ箱やごみ箱はなくなり、永久に削除されます)。 postgres_data: /var/lib/postgresql/data この行は、という名前のボリュームを作成します postgres_data そして、それを PostgreSQL がデータ ファイルを保存するコンテナ内のパスにマウントします。つまり、データベースはコンテナーの再起動やコンテナーの削除にも耐えることができます。ファイルの下部でボリュームを定義します。
ついに、 再起動: 停止しない限り コンテナがクラッシュした場合は自動的に再起動するが、手動で停止した場合は再起動しないように Docker に指示します。
2.Redisの追加
次に、Redis を追加しましょう。 Redis は PostgreSQL に比べてシンプルです。複雑なユーザー システムは必要なく、セットアップに環境変数も必要ありません。
redis:
image: redis:8.6.1
container_name: local_redis
ports:
- "6379:6379"
volumes:
- redis_data:/data
command: redis-server --appendonly yes
restart: unless-stopped
3. RabbitMQ の統合
RabbitMQ には管理 UI があるため、もう少し複雑です。ブラウザでその UI にアクセスしたいと考えています。
rabbitmq:
image: rabbitmq:4.2-management-alpine
container_name: local_rabbitmq
ports:
- "5672:5672"
- "15672:15672"
environment:
RABBITMQ_DEFAULT_USER: guest
RABBITMQ_DEFAULT_PASS: guest
volumes:
- rabbitmq_data:/var/lib/rabbitmq
restart: unless-stopped
現時点では 2 つのポートがマッピングされています。 ポート5672 アプリケーションがメッセージの送受信のために RabbitMQ に接続するために使用するメイン AMQP ポートです。 ポート15672 Web 管理インターフェイスの HTTP ポートです。ブラウザを開いて、 http://ローカルホスト:15672 デフォルトの認証情報 guest/guest でログインして、キュー、交換、メッセージを表示します。
4. MailHog でメールをキャッチする
MailHog は、偽の SMTP サーバーを実行し、そこに送信されたメッセージをキャプチャするツールです。キャプチャされた電子メールを表示するための Web インターフェイスが提供されます。これは、実際のユーザーに誤ってスパムを送信することなく、登録フロー、パスワードのリセット、通知メールをテストするのに非常に役立ちます。
mailhog:
image: minidocks/mailhog
container_name: local_mailhog
ports:
- "1025:1025"
- "8025:8025"
restart: unless-stopped
あなたの根底にあるのは、 docker-compose.yml ファイルでは、使用した名前付きボリュームを宣言する必要があります。
volumes:
postgres_data:
redis_data:
rabbitmq_data:
これにより、Docker にこれらのボリュームを作成して管理するように指示されます。 Docker は実際のデータをホスト ファイル システムのどこかに保存しますが、場所を知る必要はありません。
5. すべてをまとめる
# Local Dev Toolbox
services:
postgres:
image: postgres:18.2
container_name: local_postgres
ports:
- "5432:5432"
environment:
POSTGRES_USER: myuser
POSTGRES_PASSWORD: mypassword
POSTGRES_DB: myapp_dev
volumes:
- postgres_data:/var/lib/postgresql/data
restart: unless-stopped
redis:
image: redis:8.6.1
container_name: local_redis
ports:
- "6379:6379"
volumes:
- redis_data:/data
command: redis-server --appendonly yes
restart: unless-stopped
rabbitmq:
image: rabbitmq:4.2-management-alpine
container_name: local_rabbitmq
ports:
- "5672:5672"
- "15672:15672"
environment:
RABBITMQ_DEFAULT_USER: guest
RABBITMQ_DEFAULT_PASS: guest
volumes:
- rabbitmq_data:/var/lib/rabbitmq
restart: unless-stopped
mailhog:
image: minidocks/mailhog
container_name: local_mailhog
ports:
- "1025:1025"
- "8025:8025"
restart: unless-stopped
volumes:
postgres_data:
redis_data:
rabbitmq_data:
そのファイルをプロジェクト ディレクトリに保存します。
ツールボックスを実行する
1. docker-compose.yml ファイルが含まれるディレクトリでターミナルを開きます。すべてを開始するには、次を実行します。
docker compose up -d
-d フラグはコンテナーをデタッチ モードで実行します。つまり、コンテナーはバックグラウンドで実行され、ターミナル プロンプトが戻ります。
2. 何が実行されているかを確認するには、次を使用します。
docker compose ps
これにより、各コンテナのステータス、マップ先のポート、およびコンテナの実行時間が表示されます。
3. その日の作業が終了したら、サービスを破棄せずに停止できます。
docker compose stop
これによりコンテナは停止しますが、コンテナとそのデータ ボリュームはそのまま残ります。後で docker compose start または docker compose up を使用して再度開始できます。
4. コンテナーを完全に削除しても、データ ボリュームは保持したい場合は、次を使用します。
docker compose down
5. ボリュームとその内部のすべてのデータを含むすべてを削除するには、 -v フラグ:
docker compose down -v
Docker Compose の代替手段
システムにサービスを直接インストールする
Compose ファイルはローカル開発ツールボックスを構築する唯一の方法ですか?もちろん違います。 Linux ディストリビューションが無数にあるのと同様に、開発スタックを作成する方法もたくさんあります。
最も伝統的なアプローチは、すべてをオペレーティング システムに直接インストールすることです。パッケージ マネージャーから PostgreSQL をインストールし、サービスを有効にして次に進みます。広い意味では、次のようなものをインストールすることも ビルド必須 Debian ベースのシステムでは、すでに開発スタックの始まりです。ソフトウェアをローカルでコンパイルして実行できるように、コンパイラ、ヘッダー、およびコア ツールをベース OS に取り込みます。
これは単純な場合にはうまく機能しますが、プロジェクトが分岐し始めると事態は混乱します。 1 つのアプリケーションが PostgreSQL 18 を必要とし、別のアプリケーションが PostgreSQL 16 に依存している場合、異なるポート上で複数のインスタンスをやりくりするか、異なるバージョンを再インストールする必要があります。これらをネイティブ システム サービスとして管理するのは面倒になります。後でそれらを削除しても、期待したほどクリーンになることはほとんどなく、構成ファイルはシステム全体に分散したままになる傾向があります。
asdf などのバージョン マネージャー
asdf などのツールは言語ランタイムの管理に最適で、Python、Node.js、または Ruby の異なるバージョン間の切り替えを非常にスムーズにします。アプリケーション コードの場合、これは実際の問題を解決します。
ただし、データベース、メッセージ ブローカー、メール サーバーは、そのモデルにうまく適合しません。これらは、シムと交換する軽量のランタイム バイナリではありません。永続的なデータ ディレクトリ、バックグラウンド プロセス、およびシステム リソースが必要です。これらを手動でコンパイルすることもできますが、それは迅速で再現可能なセットアップを実現するという目標を達成できません。
Ansible やタスクファイルなどの自動化ツール
もう 1 つのオプションは、自動化フレームワークとタスク ランナーを使用することです。 Ansible などのツールは、サーバーのプロビジョニングに非常に強力です。同様に、Task などのタスク ランナーを使用すると、複雑なコマンド シーケンスを調整することもできます。
ただし、ローカル開発マシンの場合、PostgreSQL、Redis、RabbitMQ がインストールされ、適切に構成されていることを確認する Playbook を作成することは、問題に不釣り合いに感じる可能性があります。
これらの Docker コンテナを毎日実行し、残りは削除しました
一部の自己ホスト型アプリは生涯アップグレードされます。その他はメンテナンス用マグネットです。これは、私が残したコンテナと、放棄したコンテナの短いリストです。
Docker を直接実行する場合
Compose に最も近い技術的な代替手段は、生の docker run コマンドを使用することです。単一のサービスの場合、これはクリーンで効率的です。 1 つのコマンドでコンテナーを起動し、ポートをマップすれば完了です。
サービスが追加されると、複雑さは急速に増加します。ポート マッピング、永続データ用の名前付きボリューム、資格情報の環境変数、再起動ポリシー、カスタム ネットワークはすべて手動で指定する必要があります。サービスが相互に通信する必要があると、すべてのフラグを覚えておくとエラーが発生しやすくなります。正直に言うと、そんな長いコマンドを覚えられる人は誰もいません。
3 つまたは 4 つのコンテナーを使用した後、多くの開発者は最終的に長いコマンドをドキュメントからコピーするか、シェル スクリプトにラップすることになります (そこにいて、完了しました)。この段階では、スクリプトは docker-compose.yml ファイルの手書きの読みにくいバージョンに似ています。
Compose が依然として実用的な理由
Docker Compose は、これらの長くて命令的な docker run 呼び出しを、構造化された宣言型構成に変換します。すべてのサービスは単一のファイルで定義され、コンテナ間のネットワークが自動的に作成されます。 Compose の場合でも、ネットワークは複雑になる可能性がありますが、それは別の日の話です。ほとんどの場合、それに対処する必要はないからです。
Compose の本当の利点は、独占性だけではなく、それがもたらす明確さと再現性です。ほとんどのローカル開発スタックでは、Compose ファイルは、実験するすべてのプロジェクトに合わせてベース オペレーティング システムを永続的に形成することなく、シンプルさと制御の間の実質的なバランスをとります。
このトリックで Docker の更新を最適化する
まだ Docker コンテナを手動で更新していますか?
コンテナ化された開発環境が時間を大幅に節約する理由
Docker Compose ファイルを使用してローカル開発ボックスを作成すると、ネイティブ サービスのインストール、構成、トラブルシューティングに費やす時間を節約できます。プロジェクトが終了したら、プロジェクト ディレクトリを削除してコンテナを停止すると、システムに痕跡が残りません。私は、Compose が客観的にすべてのケースにおいて最良の選択肢であると言っているわけではありません。ただし、セットアップの容易さと時間効率の点では、ローカル環境を整理し始めたばかりの開発者にとってはこれに勝るものはありません。経験が増え、要件がより専門化するにつれて、好みも進化する傾向があります。
時間が経つにつれて、私自身のワークフローも変化してきました。私は、特定のプロジェクト、特にデーモンレスでホスト システムとより緊密に統合されたエクスペリエンスを好むプロジェクトでは、徐々に asdf や Podman Pods などのツールに移行してきました。ただし、中心となる考え方は同じです。つまり、関連サービスをグループ化し、それらを基本オペレーティング システムから分離し、スタック全体を再現可能にするというものです。
Windows、macOS、Linux
ドッカー