🐳

WWDC2025のContainerizationFrameworkでCodex CLI × Swift を安全かつ再現性高くビルドする

に公開

概要

macOS上で Codex CLI に swift build を実行させると、キャッシュの読み書きに /tmp ディレクトリなどへのアクセス権限がなく失敗することがあります。
簡単に解決するため、コンテナ上でCodexを実行しようと思います。
本記事では WWDC 2025 で発表された「Containerization Framework」 を利用し、Swift ネイティブなコンテナ環境で Codex CLI を安定稼働させる手順を紹介します。

Containerization Framework のインストール

GitHub Releases からインストーラを取得してセットアップします。

https://github.com/apple/container/releases/tag/0.1.0

リリース0.1.0

インストール完了

# インストーラ (.pkg) を実行後
$ container system start
Verifying apiserver is running...
Installing base container filesystem...
No default kernel configured.
Install the recommended default kernel ...? [Y/n]: Y
Installing kernel...

Docker イメージを用意する

Containerization Framework でもイメージは作成できますが、Docker でビルド → Docker Hub へ Push → Container で Pull する方が手軽です。
以下はswiftを実行するために作成したDockerfileです。

FROM ubuntu:noble

SHELL ["/bin/bash", "-c"]

# ================================
# apt
# ================================
RUN export DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true && \
    apt update && \
    apt install -y \
    curl \
    sudo \
    build-essential \
    make \
    locales \
    unzip \
    fontconfig \
    git \
    libncurses6 \
    libncurses-dev \
    binutils \
    unzip \
    gnupg2 \
    libc6-dev \
    libcurl4-openssl-dev \
    libedit2 \
    libgcc-13-dev \
    libpython3-dev \
    libsqlite3-0 \
    libstdc++-13-dev \
    libxml2-dev \
    libncurses-dev \
    libz3-dev \
    pkg-config \
    tzdata \
    zlib1g-dev \
    openssl \
    libssl-dev \
    && rm -r /var/lib/apt/lists/*

# ================================
# Swift Lover
# ================================
RUN echo 'swiftlover ALL=(ALL) NOPASSWD:ALL' | sudo tee /etc/sudoers.d/swiftlover
RUN useradd --user-group --create-home --system --skel /dev/null --home-dir /swiftlover swiftlover
USER swiftlover:swiftlover
WORKDIR /swiftlover

# ================================
# Homebrew
# ================================
RUN NONINTERACTIVE=1 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
RUN echo >> /swiftlover/.bashrc
RUN echo 'eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"' >> /swiftlover/.bashrc
RUN eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" && \
    brew install \
    vapor \
    codex \
    swift-format && \
    brew unlink swift

# ================================
# GitHub gh
# ================================
RUN (type -p wget >/dev/null || (sudo apt update && sudo apt-get install wget -y)) \
    && sudo mkdir -p -m 755 /etc/apt/keyrings \
    && out=$(mktemp) && wget -nv -O$out https://cli.github.com/packages/githubcli-archive-keyring.gpg \
    && cat $out | sudo tee /etc/apt/keyrings/githubcli-archive-keyring.gpg > /dev/null \
	&& sudo chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg \
	&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null \
	&& sudo apt update \
	&& sudo apt install gh -y

# ================================
# Setup Swift
# ================================
WORKDIR /swiftly
RUN NONINTERACTIVE=1 curl -O "https://download.swift.org/swiftly/linux/swiftly-$(uname -m).tar.gz" && \
    tar zxf "swiftly-$(uname -m).tar.gz" && \
    ./swiftly init --quiet-shell-followup && \
    . ${SWIFTLY_HOME_DIR:-~/.local/share/swiftly}/env.sh && \
    hash -r && \
    echo "source ${SWIFTLY_HOME_DIR:-~/.local/share/swiftly}/env.sh" >> /swiftlover/.bashrc

WORKDIR /swiftlover/workspace

# ================================
# Permission
# ================================
RUN sudo chown -R swiftlover:swiftlover /swiftly
RUN sudo chown -R swiftlover:swiftlover /swiftlover/workspace

ビルド & Push

$ docker build -t swift-codex:latest -f ./Dockerfile .
$ docker login -u lemonaderoom
$ docker tag swift-codex:latest lemonaderoom/swift-codex:latest
$ docker push lemonaderoom/swift-codex:latest

Containerization Framework で実行

$ container image pull lemonaderoom/swift-codex:latest

$ container run --rm -it \
    --volume "${HOME}/.codex":/swiftlover/.codex \
    --volume "$(pwd)":/swiftlover/workspace \
    --cpus 8 \
    --memory 16g \
    lemonaderoom/swift-codex bash
swiftlover@1fa98f9b-07c2-476f-9057-750f00fdfc55:~/workspace$ codex
╭──────────────────────────────────────────────────────────────╮
│ ● OpenAI Codex (research preview) v0.1.2505291658            │
╰──────────────────────────────────────────────────────────────╯
╭──────────────────────────────────────────────────────────────╮
│ localhost session: 612bce132c7b4a08b70676449d672dc5          │
│ ↳ workdir: ~/workspace                                       │
│ ↳ model: codex-mini-latest                                   │
│ ↳ provider: openai                                           │
│ ↳ approval: suggest                                          │
╰──────────────────────────────────────────────────────────────╯

パフォーマンス比較

環境 swift build (初回) swift build (2回目) swift test(初回)
macOS (ローカル) 92.0 s 5.7 s 48.4 s
Docker (Orbstack) 193.3 s 9.9 s 15.3 s
Containerization Framework 277.9 s 10.9 s 17.0 s

あとがき

  • あたり前ですがmacOSがbuild最速でした。なぜか初回testでは遅くなりましたが2回目以降のtestでは1.18s程度と速かったです。
  • Orbstackの性能がいいのか、コンテナ上の実行はcontainerよりdockerの方が速かったです
  • containerの方は感覚ではありますが初回build時にネットワークI/Oがネックになってしまっていそうでした

https://github.com/lemo-nade-room/swift-codex-docker

nextbeat Tech Blog

Discussion