ほぼ備忘録です。
単一コンテナを単純に動かしたいときにもCompose
ささっとローカルに環境を作りたい場合、コンテナは重宝しますよね。
私はPodman派なのですが、podman runでコンテナを動かすことが多いです。ただ、パラメータを多く配置すると見づらいときもあります。
ビルドされたイメージを利用するだけなら、Composeだと定義内容を把握しやすいという利点があります。
Composeは複数のコンテナを1つのアプリケーションとして動作させることを想定している技術ですが、単一コンテナの場合にも可読性、可搬性というメリットはあります。
ただPodmanだとcomposeをどう使おうか悩むところもあるかと思うので、手順などをまとめておきます。
この記事では、podman desktopおよびpodmanがインストールされた環境を想定しています。動作検証はWindows11で実施しています。
Composeとは
「コンテナは単一機能だけ載せましょう」という共通認識があります。ただ多くのアプリケーションはDBとWebアプリなど複数の機能で構成されるため、コンテナも複数起動する必要があります。常にワンセットで使うコンテナを1つずつ起動するのは面倒なので「ワンセットで管理できるようにしました」という技術です。
コンテナの他、ボリュームやネットワークの定義もまとめることができます。
Dockerから派生して登場したComposeですが、現在はオープンソースとして仕様が管理されています。
定義ファイルをもとに起動する
compose.ymlというファイルでどのように実行するかを管理します。
mariadbコンテナの起動を、runコマンドで起動する場合とcompose.ymlで指定する場合にて比較してみます。
podman run -d --name my-mariadb -p 3306:3306 -e MARIADB_ROOT_PASSWORD=secret_root_pw -e MARIADB_DATABASE=myapp_db -e MARIADB_USER=app_user -e MARIADB_PASSWORD=app_password -v ./mariadb-data:/var/lib/mysql:Z mariadb:latest
services:
db:
image: mariadb:latest
container_name: my-mariadb
ports:
- "3306:3306"
environment:
MARIADB_ROOT_PASSWORD: secret_root_pw
MARIADB_DATABASE: myapp_db
MARIADB_USER: app_user
MARIADB_PASSWORD: app_password
volumes:
./mariadb-data:/var/lib/mysql:Z
composeのほうが文字数は多いし、ymlを書いてから実行するという2段階が必要ですが
、見やすさは圧倒的に上でしょう。細かいミスも減ると思います。
1回だけ実行するのであればrunコマンドでよいですが、隣の人とシェアしたり継続的に使ったりする場合にはcomposeを使うと仕様が伝わりやすいでしょう。
この例は1コンテナだけの指定ですが、複数コンテナを指定できるところがcomposeの本来の使い方です。
実装
Docker向けの「DockerCompose」というプロダクトがcompose仕様のオリジナルとしてリリースされています。これは内部でDockerコマンドを呼び出します。
Podman向けの互換製品として「PodmanCompose」があり、こちらはPodmanコマンドを呼び出します。
Podmanではどちらの実装を使うべきか
DockerComposeがおすすめ
一見するとPodmanComposeのほうが妥当ですが、DockerComposeとの互換性に少し課題もあるようです。
Podmanのオプションで「Dockerコマンドのエイリアスとして使う」という指定が可能なので、この指定を行ったうえでDockerComposeを使うほうが無難であるといえます。
Podman自体にもcomposeというラッパーコマンドがあり、これが呼び出されたらDockerComposeまたはPodmanComposeを呼び出すことになっています。もし端末に両方ともインストールされている場合は、DockerComposeを優先する仕様になっています。
この仕様からも、DockerComposeが無難と読み取れます。
Docker Composeを使う
インストール
Windowsでは次のコマンドでインストール可能です。
winget install Docker.DockerCompose
コマンド
compose.ymlがあるフォルダで次のコマンドを使用します。
| 機能 | コマンド |
|---|---|
| 起動/再起動 | docker-compose up -d |
| 停止(コンテナ削除) | docker-compose down |
| 停止(ボリュームを同時削除) | docker-compose down -v |
| 停止(pullイメージを同時削除) | docker-compose down --rmi all |
Composeは Docker/Podmanのコンテナ実行を宣言的に制御するプロダクトであり、主体はコンテナです。そのため、起動後はPodmanのコマンドをそのまま使用できます。
ハイフン無しでも起動できる
DockerとPodmanには、composeというラッパーコマンドがあり、
docker compose
と呼び出すと、内部でdocker-composeを呼び出します。
Podman環境でdocker composeを呼び出すと、エイリアスによりpodman composeというコマンドが呼び出されるのですが、podmanからDockerComposeを呼び出す形になり次のメッセージが出力されます。
煩わしい場合、次のコマンドでユーザー環境変数を追加することでメッセージの出力を抑制できます。そもそもハイフン付きで起動すれば発生しませんが...
setx PODMAN_COMPOSE_WARNING_LOGS false
Podman Desktopでの状況確認
Containersのセクションで、Composeとその配下のコンテナという形で表示されます。
開発者向けCompose.ymlのサンプル
定義内容の詳細はここでは割愛しますが、各種環境の例を配置しておきます。
リレーショナルDB
開発でのRDB利用には必須となる「初期セットアップ」「SQLクライアントツール」の2要素を含めています。
RDBの起動とともにテーブルの初期構築やテストデータを投入できます。
compose.ymlと同階層にinitフォルダを作成し、そのなかにSQLファイルを置いておきます。
ファイル名昇順で参照し、ファイルに記載されたSQLが実行されます。
.
├── compose.yaml
└── init/
├── 01_create_tables.sql
└── 02_insert_test_records.sql
PostgreSQL
services:
db:
image: postgres:16-alpine
container_name: pg01
ports:
- "5432:5432"
environment:
POSTGRES_USER: usr01
POSTGRES_PASSWORD: pwd01
POSTGRES_DB: db01
TZ: "Asia/Tokyo"
volumes:
- ./init:/docker-entrypoint-initdb.d:Z
- pg01-data:/var/lib/postgresql/data
volumes:
pg01-data:
MariaDB
services:
db:
image: mariadb:latest
container_name: maria01
environment:
MYSQL_ROOT_PASSWORD: rootpwd
MYSQL_DATABASE: db01
MYSQL_USER: usr01
MYSQL_PASSWORD: pwd01
ports:
- "3306:3306"
volumes:
- ./init:/docker-entrypoint-initdb.d:Z
- maria01-data:/var/lib/mysql
volumes:
maria01-data:
IBM Db2
Db2は起動に5分くらい時間がかかるため、ログを確認しながら気長に待ちましょう。起動した後の接続ユーザーはdb2inst1になります。
また、Db2は残念ながらinitdbの仕組みに対応していません。
services:
db:
image: icr.io/db2_community/db2
container_name: db2-01
privileged: true
environment:
- LICENSE=accept
- DB2INST1_PASSWORD=db2inst1pwd
- DBNAME=db01
- ARCHIVE_LOGS=false
ports:
- "50000:50000"
volumes:
- db2-01-data:/database
volumes:
db2-01-data:
インテグレーション
IBM MQ
IBMのキューを使用した非同期メッセージングのための製品です。
開発者向けには、キューマネージャーに対するメッセージ送信のスタブとしての利用が考えられます。
services:
ibm-mq:
image: icr.io/ibm-messaging/mq:latest
container_name: mq01
environment:
- LICENSE=accept
- MQ_QMGR_NAME=QM1
- MQ_ADMIN_USER=admin
- MQ_ADMIN_PASSWORD=passw0rd
- MQ_APP_USER=app
- MQ_APP_PASSWORD=apppwd
ports:
- "1414:1414"
- "9443:9443"
volumes:
- mq01-data:/mnt/mqm
volumes:
mq01-data:
MQの利用にあたっては次の記事も参考にしてみてください。
Mailpit
別記事にて紹介した開発環境用に利用できるSMTPサーバーです。
別記事側ではOpenShift上でチーム利用する想定でしたが、こちらは開発者個人向けになります。
services:
mailpit:
image: axllent/mailpit
container_name: mlpt01
ports:
- "8025:8025"
- "1025:1025"
environment:
MP_MAX_MESSAGES: 5000
OpenShiftに載せるためのyml定義と比較すると、両者の違いについて理解が進むかもしれません。
余談ですが、compose.ymlを元にOpenShiftへ移行したい場合にはKomposeというツールが役に立ちます。次のようなコマンドでcompose.ymlをdeployment用のymlに変換できます。
kompose convert -f compose.yml
WireMock
APIモックツールで、レスポンスの柔軟性が高く使いやすい印象です。
services:
wiremock:
image: wiremock/wiremock:latest
container_name: wmock
ports:
- "8080:8080"
volumes:
- ./mappings:/home/wiremock/mappings
- ./__files:/home/wiremock/__files
entrypoint: ["/docker-entrypoint.sh", "--global-response-templating", "--disable-gzip", "--verbose"]
次のようなフォルダ構成で、モック動作のレスポンスデータを格納します。
.
├── compose.yaml
├── mappings/ ※APIモック定義のフォルダ
└── __files/ ※レスポンスデータなど
mappingsフォルダに次のようなJSONファイルを配置することで動作します。
{
"request": {
"method": "GET",
"url": "/api/hello"
},
"response": {
"status": 200,
"headers": {
"Content-Type": "application/json"
},
"jsonBody": {
"totalSize": 1,
"done": true,
"records": [
{
"message": "Hello Compose!"
}
]
}
}
}
ユーティリティなど
Cloud Beaver
SQLクライアントツールである「DBeaver」のブラウザ版です。
compose上に定義したユーザーでログインした後、コネクション定義を行う必要があります。データベースのホスト名は「db」で対象のコンテナを認識できます。「Save credentials for all users with access」のチェックも忘れずに。
services:
cloudbeaver:
image: dbeaver/cloudbeaver:latest
container_name: beaver01
network_mode: "host"
volumes:
- cb01-data:/opt/cloudbeaver/workspace
environment:
CB_SERVER_NAME: "LocalBeaver"
CB_SERVER_URL: "http://localhost:8978"
CB_ADMIN_NAME: "cbadmin"
CB_ADMIN_PASSWORD: "cbadminPwd0"
volumes:
cb01-data:
次のようにRDB定義とセットで1ファイルにまとめることもできます。この場合RDBと同一ネットワークに配置されるため、ホストネットワークとシェアする必要はありません。
こちらのほうがcomposeの本来的な使い方ですね。
services:
db:
(必要なDBの定義を記載する)
cloudbeaver:
image: dbeaver/cloudbeaver:latest
container_name: beaver01
ports:
- "8978:8978"
volumes:
- cb01-data:/opt/cloudbeaver/workspace
environment:
CB_SERVER_NAME: "LocalBeaver"
CB_SERVER_URL: "http://localhost:8978"
CB_ADMIN_NAME: "cbadmin"
CB_ADMIN_PASSWORD: "cbadminPwd0"
depends_on:
- db
volumes:
(DBのボリューム指定)
cb01-data:
Keycloak
認証認可の製品です。開発者のローカルでの利用シーンは、認証関連の実装をクイックに行う場合などが考えられますね。
services:
keycloak:
image: quay.io/keycloak/keycloak:latest
container_name: keycloak01
command: start-dev # 開発モード(HTTPS不要、H2 DB使用)
environment:
KEYCLOAK_ADMIN: admin
KEYCLOAK_ADMIN_PASSWORD: admin
ports:
- "8080:8080"
Ollama
ローカルでLLMを動かすためのツールです。ollama自体にGUIが搭載されるようになりましたが、ここでは実績の多く多機能なopen-webuiを使用します。
services:
ollama:
image: ollama/ollama:latest
container_name: olm01
volumes:
- ollama_data:/root/.ollama
ports:
- "11434:11434"
open-webui:
image: ghcr.io/open-webui/open-webui:main
container_name: owu01
ports:
- "3000:8080"
environment:
- OLLAMA_BASE_URL=http://ollama:11434
volumes:
- open-webui_data:/app/backend/data
depends_on:
- ollama
volumes:
ollama_data:
open-webui_data:
使用するモデルは、OllamaのラインナップからOpen WebUI上で指定してD/L可能です。
ministral-3(8b)を指定して動作することを確認しました。「最初の映画ゴジラは昭和何年に公開されましたか?」という質問に1分くらいで回答しています。
Ollamaをコンテナではなくローカルインストールすることで、GPUの性能を活用できる場合もあるようです。この場合、Open WebUIからOllamaが参照できるようにネットワーク設定は修正する必要があります。
LiteLLM
様々なLLM(大規模言語モデル)サービスのAPIを、OpenAI形式(ChatGPTのAPI形式)に統一してくれるオープンソースのプロキシサーバーです。
IBMのwatsonx.aiが直接利用できるAIエージェントなどのツールは増えていますが、未対応の場合もあります。そんなとき、ローカルでLiteLLMをコンテナ起動してここからwatsonx.aiに接続することで対応可能です。
ファイルは次のように配置します。
.
├── compose.yml
├── config.yaml ※プロキシ設定(モデルの定義)
└── .env ※APIキーなどの機密情報
services:
litellm:
image: ghcr.io/berriai/litellm:main-latest
container_name: litellm
ports:
- "4000:4000"
volumes:
- ./config.yaml:/app/config.yaml
command: [ "--config", "/app/config.yaml" ]
env_file:
- .env
次の2ファイルはwatsonx.aiと接続するためのサンプルです。
watsonx.aiでは複数のLLMを使い分けることができます。複数のLLMを定義するにはモデルリストの項目をコピーしてmodelを変更してください。modelに指定する値はwatsonx/(モデルID)になります。
model_list:
- model_name: gpt-oss-120b
litellm_params:
model: watsonx/openai/gpt-oss-120b
api_key: os.environ/WATSONX_API_KEY
url: os.environ/WATSONX_URL
project_id: os.environ/WATSONX_PROJECT_ID
APIキーなどの機密情報はコードに直書きせず、環境変数ファイルで管理します。
LITELLM_MASTER_KEY=XXX(AIツールからLiteLLMに接続するためのキーを任意に指定)
WATSONX_API_KEY=XXX(watsonx.aiのAPIキー)
WATSONX_PROJECT_ID=YYY(watsonx.aiのプロジェクト)
WATSONX_URL=https://ZZZ(watsonx.aiの接続先URL)
その他
AWS開発者はLocalStackなどもよく使われると思います。
Composeの本来の目的である複数サービスの組合せについては、次のサイトにて多くのパターンが提供されています。
おわりに
これらの定義をシェアすることで、チーム内での開発環境構築も捗るのではないでしょうか。
この考え方の延長として、本番運用に適した安定稼働コンテナ稼働環境として発展したといえるのが、k8sやOpenShiftになるかと思います。
ローカル環境でOpenShiftまで導入する必要は小さいですが、Composeに慣れるとk8sやOpenShiftへの移行もスムーズに進むと思います。コンテナネイティブの世界にひとつずつ近づくよう体験していきましょう。