Visual Studio Codeの拡張機能Remote - Containersを使用して,Dev ContainerでDocker Composeを使いPostgresデータベースを起動して,Pythonから操作してみます.
環境
MacOSからUbuntu ServerのDocker engineにリモート接続してVScodeで操作します.
% docker version Client: Cloud integration: v1.0.22 Version: 20.10.13 API version: 1.41 Go version: go1.16.15 Built: Thu Mar 10 14:08:44 2022 OS/Arch: darwin/amd64 Context: default Experimental: true Server: Docker Engine - Community Engine: Version: 20.10.14 API version: 1.41 (minimum version 1.12) Go version: go1.16.15 Built: Thu Mar 24 01:45:53 2022 OS/Arch: linux/amd64 Experimental: false containerd: Version: 1.5.11 runc: Version: 1.0.3 docker-init: Version: 0.19.0
ソースコード
.devcontainer/devcontainer.json
{ "name": "Python3 and Postgres", "dockerComposeFile": "docker-compose.yml", "service": "workspace", "settings": {}, "extensions": [ "ms-azuretools.vscode-docker", "ms-python.python" ], "remoteUser": "vscode", "postCreateCommand": "pip install --user -r requirements.txt" }
dockerComposeFile
を指定して,デフォルトのDockerfileを使用するのではなく,docker-compose.ymlに切り替えます.
VScodeが接続するコンテナをservice
で指定します.
.devcontainer/docker-compose.yml
version: "3" services: workspace: build: context: .. dockerfile: .devcontainer/Dockerfile command: sleep infinity volumes: - pysample-bashhistory:/commandhistory postgres: image: postgres:12 restart: unless-stopped volumes: - postgres-data:/var/lib/postgresql/data ports: - "5432" environment: POSTGRES_USER: postgres POSTGRES_DB: postgres POSTGRES_PASSWORD: postgres volumes: postgres-data: pysample-bashhistory:
workspace
はVSCodeが接続する対象となるコンテナですので,起動したら終了しないようにしたり,各種開発用のパッケージをインストールしたりします.
workspace
のdockerfileの相対パスが一見まどろっこしいですが,プロジェクトの任意のファイルにアクセスできるよう,contextはプロジェクトのルートディレクトリに設定しておくべきです.
postgres
は初期パスワードの設定が必須なので,環境変数で指定します*1.
pysample-bashhistory
はbashの履歴を保存するための名前付きボリュームです.
.devcontainer/Dockerfile
FROM mcr.microsoft.com/vscode/devcontainers/python:3.9-bullseye ARG USERNAME=vscode RUN SNIPPET="export PROMPT_COMMAND='history -a' && export HISTFILE=/commandhistory/.bash_history" \ && mkdir /commandhistory \ && touch /commandhistory/.bash_history \ && chown -R $USERNAME /commandhistory \ && echo $SNIPPET >> "/home/$USERNAME/.bashrc"
Dev Container用の各種コンテナイメージはマイクロソフト社が公開してくれていますので,利用します*2.
pysample-bashhistory
にbashの履歴を保存するよう設定しておきます.
requirements.txt
psycopg2
PythonでPostgresを使用するためにpsycopg2をインストールします.
main.py
import psycopg2 connection = psycopg2.connect( host="postgres", port="5432", dbname="postgres", user="postgres", password="postgres", ) cursor = connection.cursor() cursor.execute("SELECT version();") record = cursor.fetchone()[0] print(f"You are connected to {record}")
これをターミナルから実行すると,以下のような出力が得られました.
vscode ➜ /workspaces/pysample (master) $ python main.py You are connected to PostgreSQL 12.10 (Debian 12.10-1.pgdg110+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 10.2.1-6) 10.2.1 20210110, 64-bit
docker-compose.ymlのnetwork_modeの設定
network_modeを設定すればlocalhostで別のコンテナにアクセスできるようになると記載されています*3.これを設定しなくても,Docker Composeの機能としてサービス名でアクセスできます*4.上記のソースコードではhost=postgresを指定してアクセスしています.
Docker from DockerやDocker in Dockerとの比較
複数のコンテナを扱う方法として,Docker from DockerやDocker in Dockerが存在しますが,ややこしいマウントを設定したり,キャッシュが効かなかったりするなど,いずれもデメリットがあります.Dev ContainerでDocker Composeを使用する上記の方法は,Docker Composeで複数のコンテナを起動して,そのうちの1個のコンテナをDev ContainerとしてVSCodeから操作するだけですので,とてもシンプルな構成です*5.
non-rootユーザー
mcr.microsoft.com/vscode/devcontainers/python
がnon-rootユーザーに設定されているので追加の操作は不要みたいです*6.
参考
- https://github.com/microsoft/vscode-dev-containers/tree/main/container-templates/docker-compose
- https://github.com/microsoft/vscode-dev-containers/tree/main/containers/python-3-postgres
- https://code.visualstudio.com/remote/advancedcontainers/persist-bash-history
- https://code.visualstudio.com/remote/advancedcontainers/add-nonroot-user
*2:https://mcr.microsoft.com/v2/_catalog
*3:https://github.com/microsoft/vscode-dev-containers/tree/main/containers/python-3-postgres#adding-another-service
*4:https://docs.docker.com/compose/networking/
*5:https://code.visualstudio.com/docs/remote/containers
*6:https://github.com/microsoft/vscode-dev-containers/blob/main/containers/python-3/.devcontainer/base.Dockerfile