🔖

VS Code の Dev Container で複数のコンテナを起動する

2024/03/18に公開

ふだんは VS Code エディタの Dev Container を利用して開発環境を構築しています。通常は一つのコンテナだけを利用していますが、グラフデータベースのNeo4jを利用したかったので、開発用に利用するPython環境のコンテナとNeo4jのDockerイメージを利用したコンテナの二つを立ちあげてみました。この記事は、そのときの設定のメモです。

概要

VS Code エディタの Dev Container は、開発環境をコンテナ内に閉じ込めることができるため、OSの環境を気にせずいじれますし、Dockerfiledevcontainer.jsonなどの設定ファイルを通じて、手軽に同一環境を構築できる点で、とても重宝しています。

特定の言語やフレームワークのみの開発であれば、単一のコンテナ上に開発環境を構築すればよいのですが、データベースの動作確認などに公式のDockerイメージを使いたいというような場合には、複数のコンテナを立ち上げることになります。

今回は、ナレッジグラフでRAGを構築することを目的に、以下の2つのコンテナを Dev Container で立ち上げてみました。

  • Python + Langchain 開発環境(Pythonベースイメージにpipで必要なパッケージをインストール)
  • Neo4jデータベース(Neo4j公式のDockerイメージそのまま)

docker-composeを利用して2つのコンテナを立ち上げ、Python側のコンテナからNeo4jデータベースのコンテナにアクセスさせることを目的とします。

※ナレッジグラフでRAGを動作させてみた結果については、別の記事で報告する予定です。

前提条件

今回は、Windows10上に以下のソフトウェアがインストールされていて、Dev Container を利用していることが前提となります。

  • VS Code エディタ 1.87.2
  • Docker desktop 4.28.0

VS Code エディタでの Dev Container の開発環境の構築方法については、以下の記事が参考になります。

https://zenn.dev/karaage0703/books/80b6999d429abc8051bb/viewer/6ebae8

各種設定

それでは、各種の設定を紹介していきます。

ファイルの配置

VS Code ワークスペースからみたファイルの配置は以下のとおりです。

(VS Code Workspace)
├─.devcontainer/
│  |  devcontainer.json
|
├─app/
│  │  Dockerfile
│  │  requirements.txt
|
├─neo4j/
|
| docker-compose.yml

appディレクトリはPython+Langchainコンテナ用、neo4jディレクトリはNeo4jデータベース用です。Python+Langchainの開発環境用コンテナは、Dockerfileで構成を定義します。また、Dockerfile内で読み込むPythonのパッケージリストを記載したrequirements.txtも配置します。

appコンテナのDockerfile

Python+Langchainの開発環境のコンテナの構成を定義するDockerfileの内容は以下のとおりです。

Dockerfile
FROM python:3.11

COPY requirements.txt /tmp/pip-tmp/
RUN pip3 install -r /tmp/pip-tmp/requirements.txt \
   && rm -rf /tmp/pip-tmp

# Workspace
RUN mkdir -p /workspace

Pythonの公式Dockerイメージをベースに、requirements.txtに記載したパッケージをインストールしているだけです。

requirements.txtは以下のとおりです。

requirements.txt
langchain
langchain-community
langchain-openai
langchain-experimental
neo4j
wikipedia
tiktoken
python-dotenv

必要なパッケージがあれば、ここに追加してコンテナをRebuildすればOKです。Rebuildの方法はあとで説明します。

docker-compose.yml

複数のコンテナを立ち上げるために、Docker Compose を利用します。Docker Compose は以下のようなツールです。

Compose とは、複数のコンテナを定義し実行する Docker アプリケーションのためのツールです。Compose は YAML ファイルを使い、アプリケーションのサービスを設定します。コマンドを1つ実行するだけで、設定内容に基づいた全てのサービスを生成・起動します。

(出典)Docker Compose 概要(Docker公式)

複数のコンテナを立ち上げる際の構成や設定をYAML形式で簡易に記述できるツールです。設定はdocker-compose.ymlというファイルに記述します。VS Code の Dev Container からも、docker-compose.ymlファイルを指定して起動することができます。

docker-compose.ymlの内容は以下のとおりです。

docker-compose.yml
version: '3'
services:
  app:
    build:
      context: ./app
      dockerfile: Dockerfile
    depends_on:
      - neo4j
    container_name: app_container
    volumes:
      - .:/workspace
    environment:
      - NEO4J_URI=bolt://neo4j:7687
      - NEO4J_USER=neo4j
      - NEO4J_PASSWORD=neo4jpassword
    tty: true
    command: sleep infinity

  neo4j:
    image: neo4j:latest
    container_name: neo4j_container
    ports:
      - "7474:7474" # HTTP
      - "7687:7687" # Bolt
    environment:
      - NEO4J_AUTH=neo4j/neo4jpassword
      - NEO4JLABS_PLUGINS=["apoc"]
    volumes:
      - ./neo4j/data:/data
      - ./neo4j/logs:/logs
      - ./neo4j/import:/var/lib/neo4j/import
      - ./neo4j/plugins:/plugins

servicesにあるappneo4jのセクションが、それぞれPython+Langchain用コンテナとNeo4jデータベース用コンテナの設定になります。

以下、ポイントを説明します。

app:
  build:
    context: ./app
    dockerfile: Dockerfile

buildのところは、コンテナをどのように構成するかを記述します。contextに(docker-compose.ymlファイルがあるディレクトリからみた)ディレクトリ名を、dockerfileにDockerfileのファイル名を設定します。上の設定では、./app/Dockerfileを利用してコンテナを構築することを示しています。

app:
...
  volumes:
    - .:/workspace

volumesは、ホストのディレクトリ(今回の場合はWindows10側の作業ディレクトリ)を、コンテナ内の指定されたディレクトリにマウントするための設定です。

ホスト側のカレントディレクトリ(docker-compose.ymlがあるVS Code ワークスペースのルートディレクトリ)が、appコンテナの/workspaceディレクトリにマウントされ、コンテナ側からホストにあるソースファイル等にアクセスすることができるようになります。

app:
...
  environment:
    - NEO4J_URI=bolt://neo4j:7687
    - NEO4J_USER=neo4j
    - NEO4J_PASSWORD=neo4jpassword

environmentには、コンテナ内で参照できる環境変数を設定します。Python+Langchain側のコンテナから、Neo4jコンテナにアクセスするためのURLやUSER名、パスワードなどを設定しています。

NEO4J_URIbolt://neo4j:7687となっています。ホスト名がneo4jとなっていますが、Docker Compose では、docker-compose.ymlで設定したサービス名(appneop4j)で、そのコンテナにアクセスできるよう名前解決がされます。

次は、Neo4jデータベース用のコンテナの設定についてです。

neo4j:
  image: neo4j:latest

Neo4j公式のDockerイメージをそのまま使うため、imageにイメージ名を設定しています。これで、Docker Hubからこのイメージをダウンロードして起動してくれます。

neo4j:
...
  ports:
    - "7474:7474" # HTTP
    - "7687:7687" # Bolt

portsは、ホスト側のポート番号とコンテナ側のポート番号のマッピングを記述します。ホスト側の7474番にアクセスすると、Neo4jデータベースコンテナの7474番ポートに転送されます。

ちなみに、Neo4jの7474番ポートにブラウザでアクセスすると、GUIベースでNeo4jデータベースの内容を確認できます。

neo4j:
...
  volumes:
    - ./neo4j/data:/data
    - ./neo4j/logs:/logs
    - ./neo4j/import:/var/lib/neo4j/import
    - ./neo4j/plugins:/plugins

volumesappコンテナのほうで説明したものと同じです。Neo4j公式イメージでは、/dataディレクトリにデータベースが、/logディレクトリにログが保存されるようになっています。データベースを永続化するために、ホスト側のフォルダ./neo4j/*をマウントしています。

devcontainer.json

Dev Container の設定ファイルdevcontainer.jsonは以下のとおりです。

devcontainer.json
{
	"name": "Neo4j and Python + Langchain Development",
	"dockerComposeFile": "../docker-compose.yml",
	"service": "app",
	"workspaceFolder": "/workspace",
	"customizations": {
		"vscode": {
			"extensions": [
				"ms-python.isort",
				"ms-python.vscode-pylance",
				"eeyore.yapf",
				"ms-python.python",
				"njpwerner.autodocstring"
			]
		}
	}
}

dockerComposeFileに、先ほど作成したdocker-compose.ymlを設定します。この設定により、このdevcontainer.jsonファイルがあるフォルダで VS Code エディタを立ち上げると、docker-compose.ymlを読み込んで、appneo4jの2つのコンテナを起動します。

serviceには、docker-compose.ymlファイル内で定義されたサービスのうち、VS Codeで使用するサービスを指定します。appコンテナは、Pythonでの開発環境のメインとなるコンテナですので、ここではappを指定しています。

"customizations": { "vscode": { "extensions": [...] } }では、VS Codeの拡張機能を指定しています。ここはふだん利用しているものを指定しておけばよいでしょう。上の例では、Pythonのフォーマッタなどを指定しています。

Dev Container の起動

それでは、上記の設定ファイルをもとに、Dev Container を起動してみましょう。ワークスペースとなるフォルダを VS Code で開くと、エディタの右下に以下のようなメッセージが表示されます。

VS Code の「コンテナ-で再度開く」のメッセージ

「コンテナーで再度開く」をクリックすると、上記の設定ファイルをもとに、コンテナを起動してくれます。始めて起動するときは、コンテナイメージをダウンロードしたり、Dockerfileをもとにコンテナを構成したりする作業が始まるため、起動するまでに少し時間がかかります。

WindowsのDocker Desktopで、コンテナが正常に起動しているかを確認してみましょう。Docker Desktopの左側の"Containers"を選択して、動作しているコンテナを確認しましょう。

Docker Desktop のコンテナの状態表示

app_containerneo4j_containerの2つがRunningと表示されていて、正常に動作していることがわかります。このコンテナの名前は、docker-compose.ymlcontainer_nameで設定したものです。何も設定しないと、数字やアルファベットの羅列になり、何のコンテナかがわかりずらくなってしまうので、設定しておいた方が良いでしょう。

VS Codeが開発コンテナ-で起動していることを示す表示

VS Code エディタの左下の表示が「開発コンテナ-: <開発コンテナ名>」となっていることも確認しておきましょう。この表示が出ているときは、コンテナ内の開発環境でVS Codeが起動していることになります。

Neo4jのGUI

Neo4jデータベースのコンテナにもアクセスしてみましょう。ホスト側のWindowsのブラウザから、localhost:7474にアクセスすると、上のような画面が表示されます。設定したユーザ名とパスワードを入力すれば、グラフデータベースの中身を確認できる画面へ移動できます。

ホスト側のWindowsからアクセスできるのは、docker-compose.ymlportsで、ホスト側とコンテナのポート番号のマッピング(転送設定)をしてあるためです。開発環境のappコンテナからは、neo4jというホスト名でアクセスできます。

コンテナの再構成(Rebuild)

コンテナの構成ファイルとなるDockerfiledocker-compose.ymlなどを変更した場合には、コンテナの再構成が必要となります。

VS Code エディタをいったん閉じて、再度開くと、再構成後のコンテナイメージで起動するはずです。コンテナイメージはキャッシュされていて、必要なものだけをダウンロード、あるいは、再構成しますので、初回起動時ほどは時間がかからないはずです。

ただ、たまにうまく再構成できない場合もあります。そのような場合は、VS Code のコマンドパレットからDev Containers: Rebuild Container Without Cacheを実行すると、キャッシュを利用せずに、一からコンテナイメージを作り直してくれます。

まとめ

VS Code の Dev Container で、複数のコンテナを動作させてみました。

ポイントとなるのは Docker Compose の設定ファイルとなるdocker-compose.ymlです。YAMLで簡潔に記述できますし、内容もそれほど難しいものではありません。docker-compose.ymlの書き方さえマスターしてしまえば、2つといわず、3つでも4つでもコンテナを立ち上げることができます。

なお、今回は、メインの開発環境のコンテナapp+データベースのコンテナneo4jという構成で、データベース側のコンテナはほどんといじる必要はありません。そのため、VS Code エディタ上からは、メインのappコンテナのターミナルやファイルだけを操作できる構成としています。

複数のコンテナのターミナルやファイルにアクセスする必要がある場合は、もう少し工夫する必要があります。例えば、以下の記事が参考になります。

https://qiita.com/fumiyakk/items/960f7ae32cce40c9d83d

Discussion