1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

devcontainerでフロントとバックの環境を構築してコンテナ開発アレルギーを克服する

Last updated at Posted at 2024-10-28

はじめに

Docker開発が苦手!俺は業務ロジックを作りたい!しかしこの手の開発手法は当面なくなりそうにないので、とにかく仕事に近い感じのアレンジをしながら作ってみる。アレルギーを克服しろ!記事の量は最低限に!

最低限のファイル構成

こんな感じ(モノRepositoryはベストプラクティスではない。現場がそうだってだけ)

ファイル構成
docker_world
├─.devcontainer
│   ├─ devcontainer.json
│   └─ Dockerfile
├─.vscode
│   └─ launch.json
├─dev
│   └─ docker-compose.yml
├─src
│   ├─ main.py
│   └─tests
│       └─ test_main.py
├─ .gitignore
├─ README.md
├─ requirements.txt
└─ setup.sh

gitの設定

改行コードのLF統一

Git による改行コード管理が自動化され(ローカルでコミットされる際に CRLF を LF に自動変換します。)、リポジトリ内の改行コードをすべて LF で統一できるようになる。仕事でも環境面で大ハマリする筆頭だと思う

git config --global core.autocrlf input

whoami

whoami

※Dockerfileを試行錯誤するときは sleep infinity を使え

こうすると $PATH に追加すべきパスがなにかわかんねーってときにコンテナの世界にい続けたまま which uvicorn などで調査できる

事故ってた時期のDockerfileのかけら
  :
# uvicorn を起動コマンドとして設定
# CMD ["python", "uvicorn", "src.main:app", "--host", "0.0.0.0", "--port", "8000"]
CMD ["sleep", "infinity"]

※Dockerfileにおける WORKDIR を /workspace に統一する理由

/workspace 自体はルートに作った任意のディレクトリです

Dockerfile において WORKDIR/home/vscode など一般ユーザの「ホームディレクトリ」に設定していた時期があった。なぜかというとさくらのVPSでログインするとホームディレクトリでスタンバイされるから。

ホームディレクトリには 意外に多くの隠しファイル が生成される。

.cache/
.vscode-server/
.ssh/
.gitconfig
.bash_history

これらのファイルは環境依存の設定や一時的なデータであり、プロジェクトのコード管理には不要である。これらのファイルを .gitignore に追加するのは思考の妨げになる。

そこで

  • /workspaceWORKDIR に指定する 公式: WORKDIR
    • コンテナはホストOSとは独立した環境であるため、Linuxシステムに従ったディレクトリ配置をしなくてもよい
    • /workspace 配下にはプロジェクトに必要なファイルのみが存在するため、コンテナ内の環境をシンプルに保つことができる

以上の理由から、ホームディレクトリを直接 WORKDIR に設定するのは避けたほうが良い。

基本的な Docker-desktop の調査方法

Containers

logs

コンテナのログをみることができる
image.png

inspect

コンテナの環境変数を見ることができる
image.png

exec

コンテナのなかでコマンドを打って調査することができる
(使えるときとアップグレードしろって言われる時がある)

files

コンテナのファイルをツリーで見ることができる

Builds

ビルド中にエラーで落ちたときに途中経過を見ることができる
image.png
image.png

backend

なんべんもやり直してこの図を書いたよ... :sob:
コンテナの ライフタイム を意識すると、activateが2回ある理由などの解像度が深まる

.devcontainer\devcontainer.json

最初にハマりがちなのが、親ディレクトリに遡ることはできませんという仕様

Dockerfile 内では、親ディレクトリに遡ることはできません。これはセキュリティとコンテナの隔離を保つためです。具体的には、以下のような制限があります:

ビルドコンテキストの制限:

Dockerfile は、指定されたビルドコンテキスト内でのみファイルをコピーしたり、アクセスしたりできます。ビルドコマンドを実行する際に指定したディレクトリ(例えば、docker build -t myapp .. を指定した場合、そのディレクトリがビルドコンテキストになります)に制限されます。

.devcontainer\devcontainer.json
{
	"name": "FastAPI Dev Container",
	"build": {
		"dockerfile": "./Dockerfile",// TODO: のちほど 親ディレクトリの本番用 ../Dockerfile を利用 + features でセットアップする形にする
		"context": ".."  // 必要: buildの基準位置を示す
	},
	// "runArgs": ["--network=dev_network"],
	"containerEnv": {
		"SHELL": "/bin/bash"
	},
	"postCreateCommand": "/workspace/setup.sh",
	"workspaceFolder": "/workspace",  // 必要: セットアップ完了後に cd する
	"customizations": {
		"vscode": {
			"settings": {
				"python.defaultInterpreterPath": "/workspace/.venv/bin/python",  // 必要: セットアップ完了後に activate する
				"editor.defaultFormatter": "ms-python.black-formatter",
				"editor.formatOnSave":true,
				"editor.formatOnPaste": true
			},
			"extensions": [
				"ms-python.black-formatter",
				"ms-python.flake8",
				"humao.rest-client"
			]
		}
	}
}

.devcontainer\Dockerfile

わからないと大ハマリするのが linux のファイル構造。workspaces のなかには docker_world というフォルダがあって、どうやらここが host - コンテナ間 の窓口らしい

(.venv) vscode@01d3e9f0e986:/workspace$ ls -la /
total 100
drwxr-xr-x   1 root   root   4096 Mar  5 21:08 .
drwxr-xr-x   1 root   root   4096 Mar  5 21:08 ..
-rwxr-xr-x   1 root   root      0 Mar  5 21:08 .dockerenv
drwxr-xr-x   2 root   root   4096 Feb 24 09:00 bin
drwxr-xr-x   2 root   root   4096 Aug 15  2024 boot
  :
drwxr-xr-x   3 root   root   4096 Mar  5 21:08 vscode
drwxr-xr-x   1 vscode vscode 4096 Mar  5 21:08 workspace ←つくったディレクトリ
drwxr-xr-x   3 root   root   4096 Mar  5 21:08 workspaces
.devcontainer\Dockerfile
FROM python:3.12.9-slim-bullseye

# 共通変数
ARG WORKDIR=/workspace
ARG USER_NAME=vscode
ARG USER_UID=1000
ARG USER_GID=$USER_UID

ENV TZ=Asia/Tokyo

# `WORKDIR` で指定したカレントディレクトリは、ビルドセッション中のみ適用されます。
WORKDIR $WORKDIR

# チョンボしないで必要なものを $WORKDIR に転送しましょう
COPY ./.vscode $WORKDIR/.vscode
COPY ./setup.sh $WORKDIR
COPY ./requirements.txt $WORKDIR
COPY ./src $WORKDIR/src

# ユーザー作成
RUN groupadd --gid $USER_GID $USER_NAME \
    && useradd --uid $USER_UID --gid $USER_GID -m $USER_NAME

# 必要なパッケージをインストール
RUN apt-get update && apt-get install -y \
    bash curl git openssh-client zip

# 作業ディレクトリの所有者を設定
RUN chown -R $USER_NAME:$USER_NAME $WORKDIR

# ユーザー変更
USER $USER_NAME

# TODO: のちに本番用Dockerfileに移すと良い
#CMD ["uvicorn", "src.main:app", "--host", "0.0.0.0", "--port", "8000"]

.vscode\launch.json

F5 でサーバー起動と pytest が打てるようになる

.vscode\launch.json
{
    "version": "0.2.0",
    "configurations": [
      {
        "name": "Run Serve",
        "type": "debugpy",
        "request": "launch",
        "module": "uvicorn",
        "args": [
          "src.main:app",
          "--reload",
          "--port", "8000",
          "--host", "0.0.0.0",
        ],
      },
      {
        "name": "Run Tests",
        "type": "debugpy",
        "request": "launch",
        "module": "pytest",
        "args": ["-vv"]
      }
    ]
  }

dev\docker-compose.yml

(これは今回使っていない。バックエンドとフロントエンドを連動させるようなときに使う)

dev\docker-compose.yml
services:
  fastapi:
    build:
      context: .
      dockerfile: .devcontainer/Dockerfile
    volumes:
      - .:/workspace
    ports:
      - "8000:8000"

networks:
  default:
    name: dev_network

src\tests\test_main.py

src\tests\test_main.py
from src.main import reverse


def test_reverse():
    assert reverse("hello") == "olleh"
    assert reverse("") == ""
    assert reverse("123") == "321"
    assert reverse("あいう") == "ういあ"

src\main.py

src\main.py
from fastapi import FastAPI

app = FastAPI()


@app.get("/")
def read_root():
    return {"message": "Hello, FastAPI!"}


def reverse(text: str) -> str:
    """
    与えられた文字列を逆順にして返す。

    この関数はpytestのテスト用に作成されています。

    Args:
        text (str): 逆順にする文字列。

    Returns:
        str: 逆順になった文字列。
    """
    return text[::-1]

.gitignore

.gitignore
__pycache__/
.pytest_cache/
*.log
*.swp

.env
.venv/

requirements.txt

requirements.txt
fastapi==0.115.8
uvicorn==0.34.0
pytest==8.3.4

setup.sh

setup.sh
#!/bin/bash

# 共通変数
BASE_DIR="/workspace"
VENV_DIR="$BASE_DIR/.venv"

# 仮想環境の作成
if [ ! -d "$VENV_DIR" ]; then
    echo "仮想環境を作成中..."
    python -m venv $VENV_DIR
else
    echo "仮想環境は既に存在します。"
fi

# 仮想環境をアクティベート(現在のシェルセッション内でのみ有効)
source $VENV_DIR/bin/activate

# 仮想環境の確認
echo "現在のPython環境: $(which python)"

# 仮想環境が有効か確認
if [ "$VIRTUAL_ENV" != "" ]; then
    echo "仮想環境が有効です(\$VIRTUAL_ENV): $VIRTUAL_ENV"
else
    echo "仮想環境が有効ではありません。"
    exit 1
fi

# requirements.txt の内容をインストール
if [ -f "$BASE_DIR/requirements.txt" ]; then
    echo "requirements.txt からパッケージをインストール中..."
    pip install --upgrade pip
    pip install --no-cache-dir -r $BASE_DIR/requirements.txt
else
    echo "requirements.txt が見つかりませんでした。"
fi

echo "仮想環境のセットアップが完了しました。"

devcontainerを起動

左下のへんなマークを押して Reopen in Conteiner
image.png

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?