NTT DATA TECH
👨‍💻

VSCode/Dev Containersで安心・安全なCodex CLI環境お手軽作成

に公開

はじめに

記事の取り組みの背景

Codex CLIなどを使っていて次のような悩みはありませんか?

  • 万一の事故でsandbox外のファイルを壊しちゃったり、漏洩しちゃうのは怖い。
  • 別マシンで使えば安全だけど、普段使っているPCでより安全、かつお手軽に使いたい。

この記事は、そういった悩みを解決するために、Dev Containersを使ってコンテナ環境でお手軽にCodex CLIを使える環境を作った際の手順とサンプル設定の紹介記事です。

環境イメージ図

この記事で紹介している手順でできること

  • ホストのどのフォルダを見せるかを作業フォルダ単位で絞れるので、WSL 直使いより事故範囲を小さくできる。
    • /mnt/c/とか見えない。
  • 副次効果
    • WSL内でcodexを使うより、ホストとのファイルのやり取りが簡単になる。
      • 普段のパスでアクセスできる。(\\wsl.localhostとかじゃなく)
    • 環境を簡単に再構築できる。
      • とりあえずお試しでいろいろライブラリとか入れても、すぐ戻せる。

記事で紹介しないこと

  • WSLの導入手順
  • VS Codeの導入手順
  • Dev Containersの仕組み

導入手順サマリ

  1. 作業フォルダに以下の構成でファイル(サンプルは後述)を作る。
  2. Dev Containers: Reopen in Container(コンテナで再度開く)を選ぶ
    以上
作業フォルダ/
├─ .devcontainer/
│  ├─ devcontainer.json
│  └─ Dockerfile
└─ certs/
  └─ zscaler.cer # Zscaler導入環境のみ

前提

  • Podman Desktopを導入していること
    • 公式サイトからインストーラーをダウンロードして実行すればOK
    • 個人PCなど、ライセンス条件を気にする必要がない場合はDocker DesktopでもOK
  • 拡張機能Dev Containers(ms-vscode-remote.remote-containers)を導入していること
  • VS Codeの設定を開く。
    • テキストボックス(図中:赤丸で囲った箇所)に docker pathと入れる。
    • Dev> Containers: Docker Pathpodmanに変更する。(図中:赤線の箇所)
      設定画面

手順詳細

  • 筆者環境ではゼロトラスト基盤としてクラウドプロキシZscalerを用いてます。
  • Zscalerの導入有無による手順の違い、設定例を記載しています。
  • 環境に合わせて利用ください。
  1. 作業用フォルダを作成する
  2. リポジトリルートに.devcontainerフォルダを作成する
  3. .devcontainerフォルダに、設定ファイルのサンプルをコピーする
    • devcontainer.json
    • Dockerfile
  4. Zscaler導入環境の場合の追加手順
    1. Windowsキー + Rを押して「certmgr.msc」と入力し、Enterを押します。
    2. 「信頼されたルート証明機関 > 証明書」を選択します。
    3. 一覧から「Zscaler」またはそれに類似する名前の証明書を探します。
    4. 証明書を右クリックし、「すべてのタスク > エクスポート」を選択します。
    5. 「次へ」をクリックし、保存先にリポジトリルートの下のcerts/zscaler.cerを指定する。
      • この Dockerfile は、certs/zscaler.cerというファイル名で証明書を参照します
      • ファイル名を変更せず、この名前に合わせて配置してください

設定ファイル(サンプル)

devcontainer.json

  • Dev Containersのドキュメント
  • ポイントは2つあります。(詳細後述)
    1. 文字化け防止 LANG,LC_ALLの設定
    2. アクセス権限ずれの防止 : userns=keep-idを設定
      • Docker Desktopを使う場合は、この設定を削除ください。
      • 本オプションは、Podman Desktop固有です。Docker Desktopに直接対応するオプションはありません。もし、Docker Desktopで上手くいかない場合は、Podman Desktopでお試しください。
{
    "name": "Codex CLI Dev Environment",
    "build": {
        "dockerfile": "Dockerfile",
        "context": ".."
    },
    "remoteEnv": {
        "PATH": "/home/vscode/.local/npm/bin:${containerEnv:PATH}",
        "LANG": "C.UTF-8",
        "LC_ALL": "C.UTF-8"
    },
    "customizations": {
        "vscode": {
            "extensions": [
                "ms-python.python",
                "dbaeumer.vscode-eslint"
            ]
        }
    },
    "remoteUser": "vscode",
    "runArgs": [
        "--userns=keep-id"
    ]
}

文字化け防止

コンテナを起動するとLANG=en_US.UTF-8という設定になっており、lsコマンドなどでファイル名が文字化けしていた。
上記を回避するために、LANG,LC_ALLdevcontainer.jsonで設定して回避した。

そもそものデフォルト設定がLANG=en_US.UTF-8になる理由は追っていません。

アクセス権限ずれの防止(userns=keep-idの設定理由)

この設定を入れずに環境を作ったところ、以下の状態だった。

  • マウントしたフォルダのファイルや、サブフォルダがコンテナ内では root:root 所有に見えてしまった。
  • sudo chown -R vscode:vscode ... を実行しても、所有者が変わらない/変わったように見えない
  • VS Code 上では編集できるが、ターミナル操作やツール実行で権限エラーになった。
  • 自宅用PCでは起きなかったため、何らかの環境依存があると思われます。

(参考) Podman Desktop(rootless)では user namespace が有効になり、ホスト(podman machine / WSL / VM)上の通常ユーザの UID が、コンテナ内の root(UID 0)に対応して見える状態だった

cat /proc/self/uid_map

# 例(問題が起きていたときの出力例):
#          0       1000          1  # ← コンテナ内 UID 0(root)が、ホスト側 UID 1000 に対応して見えている
#          1     524288      65536

Dockerfile

Zscaler導入環境用と、Zscaler未導入環境の2バージョンを用意しています。自身の環境に合うものを利用してください。

Zscaler導入版
  • 前提
    • この Dockerfile は、デフォルトではリポジトリルートの certs/zscaler.cerARG ZSCALER_CERT_FILE=certs/zscaler.cer として参照します。
    • 証明書ファイルは、Dockerfile の期待どおり certs/zscaler.cer という名前に合わせて配置してください。
作業フォルダ/
├─ .devcontainer/
│  ├─ devcontainer.json
│  └─ Dockerfile
└─ certs/
  └─ zscaler.cer
Dockerfileサンプル(Zscaler導入環境用)
  • 主なポイント:
    • ベースは ubuntu:24.04
    • ca-certificates を更新し、各種ツールが OS の CA バンドルを見るように環境変数を設定
    • Node.js 20 を導入し、@openai/codex をグローバルインストール
    • vscode ユーザを用意し、sudo をパスワード無しで実行できるように設定
    • WORKDIR /workspaces(Dev Containers で一般的な配置)
# ベースイメージ
FROM ubuntu:24.04

# apt の対話プロンプトを抑止
ENV DEBIAN_FRONTEND=noninteractive

# Zscaler の証明書ファイルをビルド時引数で指定
# 例: certs/zscaler.cer
ARG ZSCALER_CERT_FILE=certs/zscaler.cer

# update-ca-certificates が認識する配置先
# 拡張子は .crt にしておく
ENV ZSCALER_CERT_DST=/usr/local/share/ca-certificates/zscaler.crt

# 各種ツールが OS の CA バンドルを参照するように設定
# 注意: NODE_OPTIONS=--use-system-ca は Node.js 20 系で起動失敗したため入れない
ENV SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt \
    REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt \
    CURL_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt \
    GIT_SSL_CAINFO=/etc/ssl/certs/ca-certificates.crt \
    NODE_EXTRA_CA_CERTS=/etc/ssl/certs/ca-certificates.crt \
    NPM_CONFIG_CAFILE=/etc/ssl/certs/ca-certificates.crt \
    PIP_CERT=/etc/ssl/certs/ca-certificates.crt

# Zscaler 証明書をコンテナ内にコピー
# 注意: ビルドコンテキスト内に certs/zscaler.cer が必要
COPY ${ZSCALER_CERT_FILE} ${ZSCALER_CERT_DST}

# 基本ツールをインストール
RUN apt-get update && apt-get install -y --no-install-recommends \
    ca-certificates \
    curl \
    git \
    python3 \
    python3-pip \
    build-essential \
    sudo \
    gnupg \
    bubblewrap \
    && update-ca-certificates \
    && git config --system http.sslCAInfo /etc/ssl/certs/ca-certificates.crt \
    && mkdir -p /etc/pip \
    && printf '%s\n' '[global]' 'cert = /etc/ssl/certs/ca-certificates.crt' > /etc/pip/pip.conf \
    && chmod 644 /etc/pip/pip.conf \
    && test -s /etc/ssl/certs/ca-certificates.crt \
    && rm -rf /var/lib/apt/lists/*

# Node.js 20 をインストール
RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
    && apt-get update \
    && apt-get install -y --no-install-recommends nodejs \
    && rm -rf /var/lib/apt/lists/*

# npm の CA 設定
RUN npm config set cafile /etc/ssl/certs/ca-certificates.crt --global \
    && npm config set strict-ssl true --global

# VS Code 用の非特権ユーザー作成
ARG USERNAME=vscode
RUN if id -u ubuntu > /dev/null 2>&1; then \
        usermod -l ${USERNAME} ubuntu && \
        groupmod -n ${USERNAME} ubuntu && \
        usermod -d /home/${USERNAME} -m ${USERNAME}; \
    fi \
    && echo ${USERNAME} ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/${USERNAME} \
    && chmod 0440 /etc/sudoers.d/${USERNAME} \
    && mkdir -p /home/${USERNAME}/.local/npm /home/${USERNAME}/.npm \
    && chown -R ${USERNAME}:${USERNAME} /home/${USERNAME}

# npm のグローバルインストール先をユーザー領域に固定
ENV HOME=/home/${USERNAME}
ENV NPM_CONFIG_PREFIX=${HOME}/.local/npm
ENV PATH=${HOME}/.local/npm/bin:${PATH}

USER ${USERNAME}

# Codex CLI をユーザー領域へインストール
RUN npm install -g @openai/codex

# Dev Containers では /workspaces が扱いやすい
WORKDIR /workspaces
Zscaler未導入環境
Dockerfileサンプル(Zscaler未導入環境)
# ベースイメージ
FROM ubuntu:24.04

# apt の対話プロンプトを抑止
ENV DEBIAN_FRONTEND=noninteractive

# 基本ツールをインストール
RUN apt-get update && apt-get install -y --no-install-recommends \
    ca-certificates \
    curl \
    git \
    python3 \
    python3-pip \
    build-essential \
    sudo \
    gnupg \
    bubblewrap \
    && rm -rf /var/lib/apt/lists/*

# Node.js 20 をインストール
RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
    && apt-get update \
    && apt-get install -y --no-install-recommends nodejs \
    && rm -rf /var/lib/apt/lists/*

# VS Code 用の非特権ユーザー作成
ARG USERNAME=vscode
RUN if id -u ubuntu > /dev/null 2>&1; then \
        usermod -l ${USERNAME} ubuntu && \
        groupmod -n ${USERNAME} ubuntu && \
        usermod -d /home/${USERNAME} -m ${USERNAME}; \
    fi \
    && echo ${USERNAME} ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/${USERNAME} \
    && chmod 0440 /etc/sudoers.d/${USERNAME} \
    && mkdir -p /home/${USERNAME}/.local/npm /home/${USERNAME}/.npm \
    && chown -R ${USERNAME}:${USERNAME} /home/${USERNAME}

# npm のグローバルインストール先をユーザー領域に固定
ENV HOME=/home/${USERNAME}
ENV NPM_CONFIG_PREFIX=${HOME}/.local/npm
ENV PATH=${HOME}/.local/npm/bin:${PATH}

USER ${USERNAME}

# Codex CLI をユーザー領域へインストール
RUN npm install -g @openai/codex

# Dev Containers では /workspaces が扱いやすい
WORKDIR /workspaces
NTT DATA TECH
NTT DATA TECH
設定によりコメント欄が無効化されています