VS CodeとDev Container(docker-compose.yml対応)

Posted by johtani on Friday, July 21, 2023

目次

前回の記事で、VS Code+Dev Containerを導入しました。 残課題として「マルチコンテナ化」があるという話もしました。今回はDev Containerのdocker-compose.yml対応をした話をメモとして残しておきます。 実際、VS Code + Dev Containerに移行した後に、Esを起動してアプリからつなげるというのがうまくいかないというのがあったので対応がんばりました。。。

Dev Containerのdocker compose設定

この記事ではすでにdocker-compose.ymlが存在している状態の話をします。 変更する前は、devcontainer.jsonでベースのコンテナイメージの指定、マウントの設定などを行っていましたが、docker-compose.ymlにいくつかを移動しないといけません。 対応した時の作業の流れは以下のような感じです。

  1. ワークスペース用のDockerfileの作成
  2. docker-compose.ymlにワークスペース用のサービスを追加
  3. devcontainer.jsonをdokcer-compose.ymlを利用する形に書き換え
  4. アプリでの接続文字列をlocalhostからdocker-compose.ymlのサービス名に変更

参考:対応した時のコミットです。差分などはこちらをごらんください。

devcontainerのリポジトリにPython+PostgreSQLのサンプルが公開されており、こちらを参考にしながら作業をしました。

1. Dockerfileの作成

docker-compose.ymlだけでも完結するのかもしれないですが、いろいろやりたいことも出てくるかもしれないので別のファイルに切り出しました。 といっても、コンテナのイメージはdevcontainer.jsonに記述していたものを使っています。

ARG VARIANT=3.11-bookworm
FROM mcr.microsoft.com/devcontainers/python:${VARIANT}

ENV PYTHONUNBUFFERED 1
ENV TZ Asia/Tokyo

TZはdevcontainer.jsonで指定していたものを、こちらに移行した形になります。 PYTHONUNBUFFEREDは参考にしたDockerfileの記載です。標準出力・エラーをバッファリングしない指定になっています。

2. dokcer-compose.ymlにサービス追加

backendという名前のサービスをdevcontainer(VS Code)から接続するコンテナのサービス名にしています。

services:
  backend:
    build:
      context: .
      dockerfile: .devcontainer/Dockerfile
    init: true
    environment:
      - TZ=Asia/Tokyo
    command: sleep infinity
    volumes:
      - .:/workspace/search-research:cached
      - venv-search-research-backend:/workspace/search-research/.venv
...
volumes:
  venv-search-research-backend:

1.で作成したDockerfileを利用します。docker-compose.ymlファイル自体は、プロジェクトのルートディレクトリに配置していますが、Dockerfileは.devcontainerディレクトリに入れたため、contextdockerfileはこのような指定になっています。

initは、devcontainer.jsonで指定していた"runArgs": ["--init"],の設定になります。

commandの部分は、コンテナが起動したままにしておくための設定です。

volumesでは2つのボリュームに関しての指定があります。 1つ目の/workspace...は、VS Codeがコンテナにプロジェクトをマウントする場所の指定です。 devcontainer.jsonだけを利用していた場合は意識していませんでしたが、/workspace/プロジェクト名というディレクトリにプロジェクトがマウントされていました。 docker-compose.ymlを利用する場合は、明示的に指定が必要です。 2つ目のvenv-....venvのディレクトリをコンテナの中だけのものにする設定を移植したものになります。 前回の記事ではコンテナIDをボリューム名に含めていましたが、こちらのほうがわかりやすいかと思い、プロジェクトの名前とサービス名をつけるようにしてみました。 Dev Containerで起動した場合はsearch-research_venv-search-research-backendという名前がついています(最初の部分はDev Containerがつけてるのかな?)

3. dovcontainer.jsonの変更

devcountainer.jsonから呼び出すものの準備ができたので、devcontainer.jsonを書き換えます。 公式のドキュメントとしてDocker Compose向けのプロパティが紹介されています。 変更したものは次のような形です。

{
  "name": "search-research",
  "dockerComposeFile": "../docker-compose.yml",
  "service": "backend",
  "workspaceFolder": "/workspace/search-research",
  "postCreateCommand": "/bin/sh ./.devcontainer/postCreateCommand.sh",
  "customizations": {
...
  • dockerComposeFile : 利用するdocker-compose.ymlのファイルパス
  • service:VS Codeが利用するワークスペース用のサービス名
  • workspaceFoldeer:VS Codeがコンテナに接続したときに開くフォルダのパス

を指定します。これで、VS Codeでこのプロジェクトを開いた時に、Dev Containerがdocker-compose.ymlを使ってコンテナの起動(ビルドとか)を行ってくれます。

4. アプリの接続文字列の書き換え

こちらはおまけです。 PythonのアプリからElasticsearchに接続するときの文字列として、Dev Container化の前は、http://localhost:9200と指定をしていました。 Elasticsearch用のサービス(es)で、ポートフォワードをしていたためです。

アプリ側もコンテナ化したので、Docker Composeが名前の解決をしてくれるので、http://es:9200という接続文字列で接続ができるようになりました。

ということで、ここまでで、VS Codeでプロジェクトを開くと、2つのコンテナ(backendes)が起動してVS Code上でPythonアプリからEsへの接続ができるようになりました。

追加の変更

参考のプルリクでは、上記まででしたがさらにいくつかの変更をそのあとやっています。

  • 起動するサービスの指定(開発だけするときはEsを起動したくない)
  • GPUをコンテナから利用できるように
    • devcontainer.jsonfeaturesnvidia-cudaを指定し、docker-compose.ymlでnvidiaのドライバーなどを設定することで対応しました。
    • nvidiaが公開しているcuda対応のコンテナイメージでもよかったのですが、こちらのほうが楽そうだったという理由です。featuresとコンテナのビルド、postCreateCommandの順序などはもうちょっと勉強しないといけない気がしています。

これらの対応はこちらのコミットで対応しています。

GPUの対応は、私個人の環境はこれでいいのですが、複数の人がこのリポジトリを使う場合はどうやって切り替えたりするんだろう?という疑問が残っています。。。 今回はrinna/japanese-clipのモデルを使って、テキストからベクトルを生成する部分の処理のためにGPUを使いたいというモチベーションがあり、コンテナでもGPUを使えるようにしています(CPUだと時間がすごくかかる。。。)。

サービス起動の新たな問題点

runServicesで起動するサービス名を指定したのはよかったのですが、Elasticsearchのサービスを起動して、データ登録や検索の確認を行おうと思った時に、EsのコンテナをVS Codeだけで起動する方法がまだわかっていません。。。 一度コンテナをビルドした後なら、「Remote Explorer」でOther Containerというくくりで表示され、右クリックで起動や停止ができそうなのだけど、新規サービスをdocker-compose.ymlに追加した場合は、自分でターミナルなどでコンテナのビルドをしないといけないかもしれないです。もうちょっと調べてみないとなぁ。

副次的な効果

Docker Compose対応をしたことで、前回の記事での疑問点のうち、「コンテナ名」「VolumeのID」については懸念点がなくなりました。

「コンテナ名」は、docker-compose.ymlのサービス名がコンテナ起動時に名前として利用されるため、Docker Desktopで見た時などの探しにくさはなくなりました。 ただ、「イメージ名」については、いまだに2つできています。「-uid」がつかないものの代わりに、search-research-backendというイメージが作られています。 ただし、実際に利用されるのは前回の記事に書いたようなvsc-search-research-bf04371c017c8d2f1dd5ad2529841b02e9ea1d1aaa4354c19edf53cef3f0c13b-uidという名前のイメージです。

「VolumeのID」については、docker-compose.ymlのファイルで自分で名前をつけるようにしたので、コンテナのIDが利用されなくなったという次第です。 代わりに、プロジェクト名である「search-research」という名前を直接記述しているので、変数などで置き換えたほうがいいのかも?という気がしています。

まとめ

ということで、複数のコンテナを利用するプロジェクトでVS Code+Dev Container対応ができそうだということがわかりました。 ついでに、GPU対応もできたのでこれで、やっと他の検索エンジン対応などができる気がしています。 (その前にpre-commitを保存時にチェックする形に変更かなぁ) やりたいことからちょっとずつ外れている気もするけれど、新しいことを調べるのは楽しいですね。


comments powered by Disqus

See Also by Hugo


Related by prelims-cli