Skip to the content.

Dev Container 開発環境

.devcontainer/ 以下は、Dev Container(VS Code の Dev Containers 拡張、または Dev Container CLI)で開くための開発環境定義です。 アプリ自体は docs/dev_note.md と同じく docker compose up --build で起動し(Dev Container を使う/使わないで手順を揃える)、その 開発シェル(エディタ・AI CLI・tmux) を Dev Container として提供します。 Claude Code / Codex / GitHub Copilot CLI といった AI コーディング支援 CLI もあらかじめ組み込まれています。 また、ターミナルベースで開発できるよう tmux の設定(コンテナ内の tmux.conf、および Mac のホストから接続するためのスクリプト)も含まれています。

概要

前提条件

起動方法

VS Code で開く

  1. クローンした OpenFisca-Japan のディレクトリを VS Code で開く。
  2. コマンドパレット(F1)から Dev Containers: Reopen in Container を実行する。
  3. 初回はイメージのビルドと postCreateCommand の実行が走るため数分かかる。完了後、コンテナ内のターミナルで開発できる。

Dev Container CLI で起動

VS Code を使わずコンテナだけ起動したい場合に利用する。

# リポジトリのルートで実行
devcontainer up --workspace-folder .

# 起動済みコンテナ内でコマンドを実行する例
devcontainer exec --workspace-folder . bash

ファイル構成

.devcontainer/ 以下の各ファイルの役割は次の通り。

ファイル 役割
devcontainer.json Dev Container の本体設定(ビルド方法・ポート・マウント・環境変数・VS Code 拡張/設定・features)。
Dockerfile ベースイメージと OS パッケージ・Python ツールのインストール、非 root ユーザー user の作成、make install && make build によるバックエンドのセットアップ。
post-create.sh コンテナ作成時(初回)に一度だけ実行。AI CLI のディレクトリ準備、Claude Code・Codex CLI と gh copilot のインストール、tmux 設定のシンボリックリンク作成。
post-start.sh コンテナ起動のたびに実行。永続化ボリュームがリセットされた場合に備え、AI CLI のディレクトリ権限を再設定。
prepare-agent-dirs.sh post-create.sh / post-start.sh から共通で呼ばれ、~/.claude ~/.codex ~/.copilot ~/.config/git の作成・所有権・権限を整える。
tmux.conf コンテナ内 tmux の設定。post-create.sh により ~/.tmux.conf へリンクされる。tmux セッション内では DOCKER_CONFIG を専用ディレクトリに切り替え、Dev Containers の docker 認証ヘルパー(VS Code 接続時のみ有効)を回避する。
devcontainer-lock.json features で参照する各 feature のバージョン・ダイジェストの固定(ロックファイル)。

同梱ツール

Dockerfile および features により以下がインストールされる。

主要な設定のポイント

ポート公開(docker compose)

ポート 用途
30000 フロントエンド(Vite 開発サーバー、dashboard サービス)
50000 バックエンド(OpenFisca API、openfisca サービス)
8080 Swagger UI(swagger-ui サービス)

アプリは docs/dev_note.md と同様に docker compose up --build で起動する(Dev Container を使う場合も使わない場合も手順は同じ)。Dev Container 内から実行しても、ホストの Docker ソケット経由(docker-from-docker)で ホストの Docker デーモン上に兄弟コンテナとして起動 するため、ポートは Dev Container ではなく ホスト(Mac)側に公開 される。

コンテナの常駐と停止(shutdownAction)

このコンテナは 一度起動すると常駐 し、停止はユーザーが明示的に行う 運用です。

マウント・永続化ボリューム(mounts)

ロケール・git 設定(containerEnv)

コンテナ内ユーザー(remoteUser)

VS Code のカスタマイズ(customizations.vscode)

tmux でホストから接続する(Mac)

VS Code を使わず、Mac のホストターミナルから Dev Container を起動してコンテナ内の tmux セッションへ接続したい場合は、以下のスクリプトを使います。

このスクリプトは各自のローカル環境(Node の bin パスなど)に依存する個人用途のものなので、リポジトリでは管理していません。下記の内容を Mac 上の任意の場所(例: ~/bin/connect-devcontainer-tmux.sh)に保存して使ってください。 保存したら、スクリプト冒頭の設定変数(===== 各自の環境に合わせて編集する設定 ===== の部分)を自分の環境に合わせて直接書き換えてください。<username> は自分の Mac のユーザー名に読み替えます。

#!/usr/bin/env bash
set -euo pipefail

# ===== 各自の環境に合わせて編集する設定(以下の値はサンプル。自分の環境に合わせて変更する)=====
# コンテナ内のワークスペースのパス(通常は変更不要)
container_workspace_dir="/workspaces/OpenFisca-Japan"
# ローカル(Mac)上の OpenFisca-Japan リポジトリのパス
workspace_dir="$HOME/workspaces/openfisca-japan-workspace/OpenFisca-Japan"
# 対象コンテナ(vsc-<prefix>...)を特定するためのプレフィックス
container_prefix="openfisca-japan"
# アタッチする tmux セッション名
tmux_session_name="openfisca-japan"
# Mac で使っている Node / Dev Container CLI の bin ディレクトリ(<username> は自分のユーザー名に)
node_bin_dir="/Users/<username>/.local/share/mise/installs/node/24/bin"

# ===== PATH の準備 =====
# Node / Homebrew の bin を PATH の先頭に追加(node_bin_dir は存在する場合のみ)
extra_paths="/opt/homebrew/bin:/usr/local/bin"
[ -d "$node_bin_dir" ] && extra_paths="$node_bin_dir:$extra_paths"
export PATH="$extra_paths:$PATH"

# ===== ヘルパー関数 =====
# エラーメッセージを標準エラーに出して終了する
die() {
  echo "$@" >&2
  exit 1
}

# 指定したコマンドが無ければメッセージを出して終了する
require_command() {
  command -v "$1" >/dev/null 2>&1 || die "$2"
}

# 起動中のコンテナから、イメージ名が vsc-<prefix>... のものを1つ探す
find_container() {
  docker ps --format '\t' \
    | awk -v prefix="$container_prefix" '$2 ~ ("^vsc-" prefix) {print $1; exit}'
}

# ===== 事前チェック =====
# ローカルに OpenFisca-Japan リポジトリ(devcontainer.json)が存在するか
if [ ! -f "$workspace_dir/.devcontainer/devcontainer.json" ]; then
  echo "devcontainer.json が見つかりません: $workspace_dir" >&2
  die "workspace_dir にローカルの OpenFisca-Japan リポジトリのパスを設定してください。"
fi

# 必要なコマンドと Docker の起動状態を確認
require_command devcontainer "Dev Container CLI がありません。実行: npm install -g @devcontainers/cli"
require_command docker "docker コマンドがありません。先に Docker Desktop をインストールしてください。"
docker info >/dev/null 2>&1 || die "Docker Desktop が起動していません。"

# ===== コンテナの起動(未起動なら up)=====
container_name="$(find_container)"

# 見つからなければ devcontainer up で起動して、もう一度探す
if [ -z "$container_name" ]; then
  echo "$container_prefix の Dev Container を起動しています..." >&2
  devcontainer up --workspace-folder "$workspace_dir" >/dev/null
  container_name="$(find_container)"
fi

# それでも見つからなければ失敗
[ -n "$container_name" ] || die "$container_prefix の Dev Container を起動できませんでした。"

# ===== 実行ユーザーと HOME =====
# devcontainer の remoteUser=user 前提(user が居なければ以降の docker exec が失敗して終了する)
exec_user="user"
exec_home="/home/user"

# 解決したユーザー・HOME でコンテナ内コマンドを実行するヘルパー
dexec() {
  docker exec -u "$exec_user" -e HOME="$exec_home" "$container_name" "$@"
}

# ===== Git の safe.directory をグローバル設定に登録(未登録時のみ)=====
if ! dexec git config --global --get-all safe.directory 2>/dev/null \
  | grep -Fx "$container_workspace_dir" >/dev/null; then
  dexec git config --global --add safe.directory "$container_workspace_dir" >/dev/null
fi

# ===== コンテナに入り tmux セッションへアタッチ =====
# Backspace(^H/^?)の不一致は /etc/inputrc 側の二重バインドで吸収するため、
# ここで stty erase を無理に固定しない(ホストによって送る文字が違い、固定すると逆に合わない場合がある)。
# -it: 対話端末を割り当て / --detach-keys=ctrl-]: コンテナからデタッチするキー
# LOCAL_WORKSPACE_FOLDER: docker-from-docker で `docker compose` のバインドマウント元に
#   ホスト側の実パスが必要なため注入する(workspace_dir はホスト上のリポジトリパス)。
exec docker exec -it \
  -u "$exec_user" \
  --detach-keys="ctrl-]" \
  -e HOME="$exec_home" \
  -e TERM="${TERM:-xterm-256color}" \
  -e LOCAL_WORKSPACE_FOLDER="$workspace_dir" \
  -w "$container_workspace_dir" "$container_name" \
  bash -lc 'tmux source-file "$HOME/.tmux.conf" 2>/dev/null || true; exec tmux -u new-session -A -s "'"$tmux_session_name"'"'

保存したら実行権限を付けて起動します(保存先は例です。各自のパスに読み替えてください)。

chmod +x ~/bin/connect-devcontainer-tmux.sh
~/bin/connect-devcontainer-tmux.sh

このスクリプトの動作は次の通りです。

  1. ローカルの OpenFisca-Japan リポジトリと Docker Desktop / Dev Container CLI の存在を確認する(Preflight checks)。
  2. 対象の Dev Container が未起動なら devcontainer up で起動する(Locate (or start) the devcontainer)。
  3. コンテナ内の git config --global safe.directory を(未登録時のみ)設定する。
  4. コンテナへ入り、tmux セッション(既定名 openfisca-japan)へアタッチ(無ければ新規作成)する。

スクリプト冒頭(===== 各自の環境に合わせて編集する設定 =====)で書き換える変数は次の通りです。

変数 例 説明
workspace_dir $HOME/workspaces/openfisca-japan-workspace/OpenFisca-Japan ローカル(Mac)の OpenFisca-Japan リポジトリのパス
container_workspace_dir /workspaces/OpenFisca-Japan コンテナ内のワークスペースパス(通常は変更不要)
container_prefix openfisca-japan 対象コンテナ(vsc-<prefix>...)を特定するプレフィックス
tmux_session_name openfisca-japan アタッチする tmux セッション名
node_bin_dir /Users/<username>/.local/share/mise/installs/node/24/bin PATH の先頭に追加する Node/Dev Container CLI の bin ディレクトリ(存在する場合のみ追加)

リモートから SSH で接続する(Tailscale)

外出先などのリモート端末から、常時起動しておいた Mac 上の Dev Container の tmux セッションへ、ssh ofj-tmux の一発で接続するための設定です。

[リモート端末] --(Tailscale)--> [Mac(Amphetamine で常時起動)]
                                  └─ ssh 実行時に connect-devcontainer-tmux.sh を起動
                                       └─ Dev Container 内の tmux セッションへアタッチ

回線が切れても tmux セッションはコンテナ内に残るため、再度 ssh ofj-tmux で作業を再開できます。

1. Mac 側(ホスト)の準備

2. リモート端末(クライアント)の準備

3. 接続する

ssh ofj-tmux

補足・トラブルシューティング

トラブルシューティング