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
├── .gitignore
├── frontend
│   ├── .devcontainer
│   │   ├── devcontainer.json
│   │   └── Dockerfile
│   ├── src
│   │   └── pages
│   │       └── index.tsx
│   ├── package.json
│   └── README.md
└── backend
    ├── .devcontainer
    │   ├── devcontainer.json
    │   ├── Dockerfile
    │   └── setup.sh
    ├── src
    │   ├── tests
    │   │   └── test_main.py
    │   └── main.py
    ├── .gitignore
    ├── docker-compose.yml
    ├── README.md
    └── requirements.txt

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 に統一する理由

Dockerfile において WORKDIR/home/vscode など一般ユーザの「ホームディレクトリ」に設定していた時期があった。

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

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

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

解決策:

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

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

(※要見直し)

frontend

File - Open Folder で frontend のフォルダを開く

devcontainer.json(新規)

frontend/.devcontainer/devcontainer.json
{
  "name": "Node.js Dev Container",
  "dockerFile": "./Dockerfile",
  "postCreateCommand": "npm i"
}

Dockerfile(新規)

ENVとRUNのapt-getのとこはpythonやnextjsでもかまわずコピペでやってる

frontend/.devcontainer/Dockerfile
FROM node:latest

ENV TZ=Asia/Tokyo
RUN apt-get update && apt-get install -y \
    bash curl git openssh-client zip \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

package.json(新規)

このセットはたしかNext.jsをすっぴんセットアップしてできあがるやつだったような気がする。ご自由にどうぞ

frontend/package.json
{
  "name": "next.js",
  "version": "1.0.0",
  "description": "Your project description",
  "main": "index.js",
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start"
  },
  "dependencies": {
    "next": "13.2.4",
    "react": "18.2.0",
    "react-dom": "18.2.0"
  },
  "devDependencies": {
    "@types/node": "22.7.4",
    "@types/react": "18.3.11",
    "typescript": "5.6.2"
  }
}

devcontainerを起動

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

devcontainerを起動したときの処理の流れは

  1. devcontainer が dockerFile をビルドする
  2. 終わったら postCreateCommand を実行する
{
  "name": "Node.js Dev Container",
  "dockerFile": "./Dockerfile",
  "postCreateCommand": "npm i"
}

ハマりがちなのが、親ディレクトリに遡ることはできませんという仕様。pip installDockerfile のなかでやろうとしたときに、大概この仕様で大ハマリする

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

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

COPYコマンドの制約: COPYやADDコマンドで親ディレクトリやそれ以外のディレクトリからファイルをコピーすることはできません。例えば、COPY ../file.txt /app/のように親ディレクトリを指定すると、エラーが発生します。

index.tsx

src/pages/index.tsx
import type { NextPage } from 'next'

const Home: NextPage = () => {
  return (
    <div>
      <h1>Hello World</h1>
    </div>
  )
}

export default Home

README.md

README.md
## サーバ起動
# npm run dev

サーバ起動

console
# npm run dev

image.png

backend

.devcontainer/devcontainer.json

backend/.devcontainer/devcontainer.json
{
	"name": "FastAPI Dev Container",
	"dockerComposeFile": "../docker-compose.yml",
	"service": "fastapi",
	"postCreateCommand": "/workspace/.devcontainer/setup.sh",
	"workspaceFolder": "/workspace",
	"containerEnv": {
		"SHELL": "/bin/bash"
	},
	"customizations": {
		"vscode": {
			"settings": {
				"editor.defaultFormatter": "ms-python.black-formatter",
				"editor.formatOnSave":true,
				"editor.formatOnPaste": true
			},
			"extensions": [
				"ms-python.black-formatter",
				"ms-python.flake8",
				"humao.rest-client"
			]
		}
	}
}

docker-compose.yml

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

networks:
  default:
    name: dev_network

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

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

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

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

COPYコマンドの制約

COPYADD コマンドで親ディレクトリやそれ以外のディレクトリからファイルをコピーすることはできません。例えば、COPY ../file.txt /app/ のように親ディレクトリを指定すると、エラーが発生します。

.devcontainer/Dockerfile

backend/.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

# ユーザー作成
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 \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

# 作業ディレクトリを設定
WORKDIR $WORKDIR

# ユーザー変更
USER $USER_NAME

# 確認: ここでsleepしないとコンテナが終わってしまう
#CMD ["uvicorn", "src.main:app", "--host", "0.0.0.0", "--port", "8000"]
CMD ["sleep", "infinity"]

.devcontainer/setup.sh

backend/.devcontainer/setup.sh
#!/bin/bash

# 共通変数
WORKDIR="/workspace"
VENV_DIR="$WORKDIR/.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 "$WORKDIR/requirements.txt" ]; then
    echo "requirements.txt からパッケージをインストール中..."
    pip install --upgrade pip
    pip install --no-cache-dir -r $WORKDIR/requirements.txt
else
    echo "requirements.txt が見つかりませんでした。"
fi

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

requirements.txt

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

.gitignore

backend/.gitignore
__pycache__/
*.log
*.swp

.env
.venv/

src/main.py

backend/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]

src/tests/test_main.py

backend/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("あいう") == "ういあ"

.vscode/launch.json

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

backend/.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"]
      }
    ]
  }

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?