Closed8

開発環境構築ツール「devbox」を試す

kun432kun432

2024/10のTechnology RaderでTrialになってた。

https://www.thoughtworks.com/radar/tools/summary/devbox

今のところ、自分の場合:

  • 環境閉じ込めたい場合はDocker。devcontainerで使うことも多い。
  • Pythonだけならmise+venv。最初、mise+uvにしてたんだけど、いつのまにかPythonバージョンがおかしくなってしまうようになったので、 uvはやめた。 自分が正しくuvを理解していないのもあるが、miseだけで困ってない。
  • VMが欲しいときはmultipassだけどかなり頻度が少ない

って感じで困ってはいないけど、Dockerfileとかdocker-compose.yaml書くのがめんどくさいなと思うときはあるので、devboxを試してみる。

kun432kun432

GitHubレポジトリ
https://github.com/jetify-com/devbox

Devbox

瞬時に、簡単で予測可能な開発環境

これは何?

Devboxは、開発用に隔離されたシェルを簡単に作成できるコマンドラインツールです。まず、開発環境に必要なパッケージのリストを定義し、その定義に基づいてDevboxがアプリケーション専用の隔離された環境を作成します。

実際のところ、Devboxはyarnのようなパッケージマネージャーと似た動作をしますが、管理するパッケージはオペレーティングシステムレベルのものです(通常、brewapt-getでインストールするようなものです)。Devboxを使うと、Nixパッケージレジストリから40万以上のパッケージバージョンをインストールすることができます。

DevboxはもともとJetifyによって開発され、内部ではnixが使用されています。

利点

チーム全員に一貫したシェル環境

プロジェクトで必要なツールのリストをdevbox.jsonファイルで宣言し、devbox shellを実行するだけ。プロジェクトに取り組むすべてのメンバーが、同じバージョンのツールを使用できるシェル環境を手に入れます。

ラップトップを汚さずに新しいツールを試せる

Devboxが作成する開発環境は、ラップトップ上の他のすべてのものから隔離されています。試してみたいツールがあるけど、ラップトップを汚したくない?そんな時は、そのツールをDevboxのシェルに追加して、不要になったら削除すればOK。ラップトップは常にクリーンなままです。

スピードを犠牲にしない

Devboxは、ラップトップ上に仮想化の余計なレイヤーを追加せず、ファイルシステムやコマンドの速度を落とさずに隔離された環境を作成します。プロジェクトの出荷準備が整ったら、それをコンテナに変換できますが、その時まで速度は維持されます。

バージョンの競合にさようなら

複数のプロジェクトで、同じバイナリの異なるバージョンが必要ですか?ラップトップに競合するバージョンをインストールする代わりに、プロジェクトごとに隔離された環境を作成し、各プロジェクトで必要なバージョンを自由に使用できます。

環境を持ち運べる

Devboxの開発環境はポータブルです。環境を一度だけ正確に宣言し、その単一の定義を以下のように複数の方法で活用できます:

  • ローカルでdevbox shellを使ってシェルを作成
  • VSCodeで使用するdevcontainer
  • 開発と同じツールを使って本番イメージを作成できるDockerfile
  • ローカル環境をそのまま反映したクラウド上のリモート開発環境

ライセンスはApache-2.0

kun432kun432

インストール

https://www.jetify.com/docs/devbox/installing_devbox/

ローカルのMacでやってみる。

インストールはリモートのスクリプトを実行する形式。自分はこのタイプ、何をやるのかがわからないので、あまり好きではない。一旦中身を見てみる。

$ curl -fsSL https://get.jetify.com/devbox
インストールスクリプトの中身
#!/bin/bash
#
# Install script
#
# Downloads and installs a binary from the given url.

set -euo pipefail

# ========================
# Customize install script
# ========================

# This script is published at get.jetify.com/devbox so users can install via:
# curl -fsSL https://get.jetify.com/devbox | bash

readonly INSTALL_DIR="/usr/local/bin"
readonly BIN="devbox"
readonly DOWNLOAD_URL="https://releases.jetify.com/devbox"

readonly TITLE="Devbox 📦 by Jetify"
readonly DESCRIPTION=$(
	cat <<EOF
  Instant, easy and predictable development environments.

  This script downloads and installs the latest devbox binary.
EOF
)
readonly DOCS_URL="https://github.com/jetify-com/devbox"
readonly COMMUNITY_URL="https://discord.gg/jetify"

# ====================
# flags.sh
# ====================
FORCE="${FORCE:-0}"

parse_flags() {
	while [ "$#" -gt 0 ]; do
		case "$1" in
		-f | --force)
			FORCE=1
			shift 1
			;;
		*)
			error "Unknown option: $1"
			exit 1
			;;
		esac
	done
}

# ====================
# format.sh
# ====================

readonly BOLD="$(tput bold 2>/dev/null || echo '')"
readonly GREY="$(tput setaf 8 2>/dev/null || echo '')"
readonly UNDERLINE="$(tput smul 2>/dev/null || echo '')"
readonly RED="$(tput setaf 1 2>/dev/null || echo '')"
readonly GREEN="$(tput setaf 2 2>/dev/null || echo '')"
readonly YELLOW="$(tput setaf 3 2>/dev/null || echo '')"
readonly BLUE="$(tput setaf 4 2>/dev/null || echo '')"
readonly MAGENTA="$(tput setaf 5 2>/dev/null || echo '')"
readonly CYAN="$(tput setaf 6 2>/dev/null || echo '')"
readonly NO_COLOR="$(tput sgr0 2>/dev/null || echo '')"
readonly CLEAR_LAST_MSG="\033[1F\033[0K"

title() {
	local -r text="$*"
	printf "%s\n" "${BOLD}${MAGENTA}${text}${NO_COLOR}"
}

header() {
	local -r text="$*"
	printf "%s\n" "${BOLD}${text}${NO_COLOR}"
}

plain() {
	local -r text="$*"
	printf "%s\n" "${text}"
}

info() {
	local -r text="$*"
	printf "%s\n" "${BOLD}${GREY}${NO_COLOR} ${text}"
}

warn() {
	local -r text="$*"
	printf "%s\n" "${YELLOW}! $*${NO_COLOR}"
}

error() {
	local -r text="$*"
	printf "%s\n" "${RED}${text}${NO_COLOR}" >&2
}

success() {
	local -r text="$*"
	printf "%s\n" "${GREEN}${NO_COLOR} ${text}"
}

start_task() {
	local -r text="$*"
	printf "%s\n" "${BOLD}${GREY}${NO_COLOR} ${text}..."
}

end_task() {
	local -r text="$*"
	printf "${CLEAR_LAST_MSG}%s\n" "${GREEN}${NO_COLOR} ${text}... [DONE]"
}

fail_task() {
	local -r text="$*"
	printf "${CLEAR_LAST_MSG}%s\n" "${RED}${text}... [FAILED]${NO_COLOR}" >&2
}

confirm() {
	if [ ${FORCE-} -ne 1 ]; then
		printf "%s " "${MAGENTA}?${NO_COLOR} $* ${BOLD}[Y/n]${NO_COLOR}"
		set +e
		read -r yn </dev/tty
		rc=$?
		set -e
		if [ $rc -ne 0 ]; then
			error "Error reading from prompt (re-run with '-f' flag to auto select Yes if running in a script)"
			exit 1
		fi
		if [ "$yn" != "y" ] && [ "$yn" != "Y" ] && [ "$yn" != "yes" ] && [ "$yn" != "" ]; then
			error 'Aborting (please answer "yes" to continue)'
			exit 1
		fi
	fi
}

delay() {
	sleep 0.3
}

# =========
# util.sh
# =========
has() {
	command -v "$1" 1>/dev/null 2>&1
}

download() {
	local -r url="$1"
	local -r file="$2"
	local cmd=""

	if has curl; then
		cmd="curl --fail --silent --location --output $file $url"
	elif has wget; then
		cmd="wget --quiet --output-document=$file $url"
	elif has fetch; then
		cmd="fetch --quiet --output=$file $url"
	else
		error "No program to download files found. Please install one of: curl, wget, fetch"
		error "Exiting..."
		return 1
	fi

	if [[ ${3:-} == "--fail" ]]; then
		$cmd && return 0 || rc=$?
		error "Command failed (exit code $rc): ${BLUE}${cmd}${NO_COLOR}"
		exit $rc
	fi

	$cmd && return 0 || rc=$?
	return $rc
}

# ==============
# Implementation
# ==============
intro_msg() {
	title "${TITLE}"
	plain "${DESCRIPTION}"
	printf "\n"
	header "Confirm Installation Details"
	plain "  Location:     ${GREEN}${INSTALL_DIR}/${BIN}${NO_COLOR}"
	plain "  Download URL: ${UNDERLINE}${BLUE}${DOWNLOAD_URL}${NO_COLOR}"
	printf "\n"
}

install_flow() {
	confirm "Install ${GREEN}${BIN}${NO_COLOR} to ${GREEN}${INSTALL_DIR}${NO_COLOR} (requires sudo)?"
	printf "\n"
	header "Downloading and Installing"

	start_task "Downloading ${BIN} binary"
	local -r tmp_file=$(mktemp)
	download "${DOWNLOAD_URL}" "${tmp_file}" --fail
	delay
	end_task "Downloading ${BIN} binary"

	start_task "Installing in ${INSTALL_DIR}/${BIN} (requires sudo)"
	chmod +x "${tmp_file}"
	$(command -v sudo || true) bash -c "mkdir -p ${INSTALL_DIR} && mv ${tmp_file} ${INSTALL_DIR}/${BIN}"
	delay
	end_task "Installing in ${INSTALL_DIR}/${BIN}"
	delay

	success "${BOLD}Successfully installed ${GREEN}${BIN}${NO_COLOR}${BOLD}${NO_COLOR} 🚀"
	delay
	printf "\n"
}

next_steps_msg() {
	header "Next Steps"
	plain "  1. ${BOLD}Learn how to use ${BIN}${NO_COLOR}"
	plain "     ${GREY}Run ${CYAN}${BIN} help${GREY} or read the docs at ${UNDERLINE}${BLUE}${DOCS_URL}${NO_COLOR}"
	plain "  2. ${BOLD}Get help and give feedback${NO_COLOR}"
	plain "     ${GREY}Join our community at ${UNDERLINE}${BLUE}${COMMUNITY_URL}${NO_COLOR}"
}

main() {
	parse_flags "$@"
	intro_msg
	install_flow
	next_steps_msg
}

main "$@"

見た感じバイナリをダウンロードして配置する程度。問題なさそうなのでインストール。

$ curl -fsSL https://get.jetify.com/devbox | bash

/usr/local/bin以下に配置されるみたい。インストールするか聞かれるので"Y"。

Devbox 📦 by Jetify
  Instant, easy and predictable development environments.

  This script downloads and installs the latest devbox binary.

Confirm Installation Details
  Location:     /usr/local/bin/devbox
  Download URL: https://releases.jetify.com/devbox

? Install devbox to /usr/local/bin (requires sudo)? [Y/n] Y

sudoで確認が求められるのでパスワードを入力。

Downloading and Installing
✓ Downloading devbox binary... [DONE]
→ Installing in /usr/local/bin/devbox (requires sudo)...
Password:

インストール完了

 Installing in /usr/local/bin/devbox... [DONE]
✓ Successfully installed devbox 🚀

Next Steps
  1. Learn how to use devbox
     Run devbox help or read the docs at https://github.com/jetify-com/devbox
  2. Get help and give feedback
     Join our community at https://discord.gg/jetify

バージョンを確認してみる。

$ devbox version
✓ Downloading version 0.13.5... [DONE]
✓ Verifying checksum... [DONE]
✓ Unpacking binary... [DONE]

0.13.5

Usage

$ devbox help
Instant, easy, predictable development environments

Usage:
  devbox [flags]
  devbox [command]

Available Commands:
  add         Add a new package to your devbox
  auth        Devbox auth commands
  cache       Collection of commands to interact with nix cache
  completion  Generate the autocompletion script for the specified shell
  create      Initialize a directory as a devbox project using a template
  generate    Generate supporting files for your project
  global      Manage global devbox packages
  help        Help about any command
  info        Display package info
  init        Initialize a directory as a devbox project
  install     Install all packages mentioned in devbox.json
  list        List installed packages
  rm          Remove a package from your devbox
  run         Run a script or command in a shell with access to your packages
  search      Search for nix packages
  secrets     Interact with devbox secrets in jetify cloud.
  services    Interact with devbox services.
  shell       Start a new shell with access to your packages
  shellenv    Print shell commands that create a Devbox Environment in the shell
  update      Update packages in your devbox
  version     Print version information

Flags:
  -h, --help    help for devbox
  -q, --quiet   suppresses logs

Use "devbox [command] --help" for more information about a command.
kun432kun432

開発環境の作成

https://www.jetify.com/docs/devbox/quickstart/

開発環境を作成してみる。

適当なディレクトリを作成。

$ mkdir devbox-test && cd devbox-test

devbox initで環境の初期設定。

$ devbox init

ディレクトリ内にdevbox.jsonが作成される。コード管理する場合はこのファイルも含めればよいみたい。

$ ls
devbox.json
devbox.json
{
    "$schema": "https://raw.githubusercontent.com/jetify-com/devbox/0.13.5/.schema/devbox.schema.json",
    "packages": [],
    "shell": {
      "init_hook": [
        "echo 'Welcome to devbox!' > /dev/null"
      ],
      "scripts": {
        "test": [
          "echo \"Error: no test specified\" && exit 1"
        ]
      }
    }
  }

この環境にパッケージをインストールする。パッケージはdevbox searchで検索できる。試しにpythonのパッケージを検索してみる。

$ devbox search python3
Found 40+ results for "python3":

* python  (3.13.0, 3.13.0rc3, 3.13.0rc2, 3.13.0rc1, 3.13.0b4, 3.13.0b3, 3.13.0b2, 3.13.0b1, 3.13.0a6, 3.13.0a5 ...)
* gnatcoll-python3  (24.0.0, 23.0.0, 22.0.0, 21.0.0)
* python310Packages.avro-python3  (1.10.2)
* python310Packages.mecab-python3  (1.0.8, 1.0.7, 1.0.6, 1.0.5, 1.0.4)
* python310Packages.python3-application  (3.0.6, 3.0.4, 3.0.3)
* python310Packages.python3-eventlib  (0.3.0)
* python310Packages.python3-gnutls  (3.1.9)
* python310Packages.python3-openid  (3.2.0)
* python310Packages.python3-saml  (1.15.0, 1.14.0, 1.12.0)
* python311Packages.avro-python3  (1.10.2)

Warning: Showing top 10 results and truncated versions. Use --show-all to show all.

Node.jsだとこんな感じ。

$ devbox search nodejs
Found 3+ results for "nodejs":

* nodejs  (22.9.0, 22.8.0, 22.6.0, 22.5.1, 22.4.1, 22.3.0, 22.2.0, 22.0.0, 21.7.3, 21.7.2 ...)
* nodejs-slim  (22.9.0, 22.8.0, 22.6.0, 22.5.1, 22.4.1, 22.3.0, 22.2.0, 22.0.0, 21.7.3, 21.7.2 ...)
* nodejs_latest  (19.7.0, 19.1.0, 19.0.1, 18.4.0, 18.3.0, 18.2.0, 18.1.0, 18.0.0, 16.14.2, 16.14.0 ...)

Warning: Showing top 10 results and truncated versions. Use --show-all to show all.

少しインフラ的なものを試してみる。

$ devbox search postgres
Found 25+ results for "postgres":

* postgres-lsp  (0-unstable-2024-03-24, 2024-01-11, 2023-10-20, 2023-09-21, 2023-08-23, 2023-08-08)
* gnatcoll-postgres  (24.0.0, 23.0.0, 22.0.0, 21.0.0)
* prometheus-postgres-exporter  (0.15.0, 0.14.0, 0.13.2, 0.13.1, 0.13.0, 0.12.1, 0.12.0, 0.11.1, 0.11.0, 0.10.1 ...)
* postgresql  (16.4, 15.7, 15.6, 15.5, 15.4, 14.9, 14.8, 14.7, 14.6, 14.5 ...)
* postgresql95  (9.5.25, 9.5.24, 9.5.23, 9.5.22, 9.5.21)
* postgresql96  (9.6.24, 9.6.23, 9.6.22, 9.6.21, 9.6.20, 9.6.19, 9.6.18, 9.6.17)
* postgresqlTestHook
* postgrest  (12.0.2)
* postgresql_10  (10.22, 10.21, 10.20, 10.19, 10.18, 10.17, 10.16, 10.15, 10.14, 10.13 ...)
* postgresql_11  (11.21, 11.20, 11.19, 11.18, 11.17, 11.16, 11.15, 11.14, 11.13, 11.12 ...)

Warning: Showing top 10 results and truncated versions. Use --show-all to show all.

ライブラリよりなものも。

$ devbox search openai
Found 28+ results for "openai":

* openai  (1.51.0, 1.50.2, 1.47.1, 1.46.0, 1.45.1, 1.44.0, 1.43.0, 1.42.0, 1.40.8, 1.39.0 ...)
* openai-full  (0.28.1, 0.28.0, 0.27.8, 0.27.7, 0.27.6v2, 0.27.5, 0.27.4, 0.27.2, 0.27.1, 0.27.0)
* openai-whisper  (20240930, 20240927, 20231117, 20230918, 20230314, 20230124, 2022-09-30, 2022-09-23)
* openai-triton-llvm  (17.0.0-c5dede880d17, 14.0.6-f28c006a5895)
* openai-whisper-cpp  (1.7.0, 1.6.2, 1.5.4, 1.5.2, 1.4.2, 1.4.0, 1.2.1, 1.2.0, 1.0.4)
* python310Packages.openai  (1.6.1, 1.6.0, 1.5.0, 1.3.7, 0.28.1, 0.28.0, 0.27.9, 0.27.8, 0.27.7, 0.27.6v2 ...)
* python311Packages.openai  (1.51.0, 1.50.2, 1.47.1, 1.46.0, 1.45.1, 1.44.0, 1.43.0, 1.42.0, 1.40.8, 1.39.0 ...)
* python312Packages.openai  (1.51.0, 1.50.2, 1.47.1, 1.46.0, 1.45.1, 1.44.0, 1.43.0, 1.42.0, 1.40.8, 1.39.0 ...)
* python38Packages.openai  (0.11.5, 0.11.4)
* python39Packages.openai  (0.25.0, 0.24.0, 0.23.1, 0.23.0, 0.22.1, 0.22.0, 0.20.0, 0.19.0, 0.18.1, 0.18.0 ...)

Warning: Showing top 10 results and truncated versions. Use --show-all to show all.

なるほど、いろいろあるけど、これがnixパッケージというやつなのかな?ちょっとまだよくわからないけど、とりあえずまずはpython-3.11をインストールしてみる。パッケージ追加はdevbox add

$ devbox add python@3.11

Nixがないのでインストールする。

Nix is not installed. Devbox will attempt to install it.

Press enter to continue or ctrl-c to exit.
Nixインストール時のメッセージ
Switching to the Multi-user Installer
Welcome to the Multi-User Nix Installation

This installation tool will set up your computer with the Nix package
manager. This will happen in a few stages:

1. Make sure your computer doesn't already have Nix. If it does, I
   will show you instructions on how to clean up your old install.

2. Show you what I am going to install and where. Then I will ask
   if you are ready to continue.

3. Create the system users (uids [351..382]) and groups (gid 350)
   that the Nix daemon uses to run builds. To create system users
   in a different range, exit and run this tool again with
   NIX_FIRST_BUILD_UID set.

4. Perform the basic installation of the Nix files daemon.

5. Configure your shell to import special Nix Profile files, so you
   can use Nix.

6. Start the Nix daemon.

Would you like to see a more detailed list of what I will do?
No TTY, assuming you would say yes :)

I will:

 - make sure your computer doesn't already have Nix files
   (if it does, I will tell you how to clean them up.)
 - create local users (see the list above for the users I'll make)
 - create a local group (nixbld)
 - install Nix in /nix
 - create a configuration file in /etc/nix
 - set up the "default profile" by creating some Nix-related files in
   /var/root
 - back up /etc/bashrc to /etc/bashrc.backup-before-nix
 - update /etc/bashrc to include some Nix configuration
 - back up /etc/zshrc to /etc/zshrc.backup-before-nix
 - update /etc/zshrc to include some Nix configuration
 - create a Nix volume and a LaunchDaemon to mount it
 - create a LaunchDaemon (at /Library/LaunchDaemons/org.nixos.nix-daemon.plist) for nix-daemon

Ready to continue?
No TTY, assuming you would say yes :)

---- let's talk about sudo -----------------------------------------------------
This script is going to call sudo a lot. Normally, it would show you
exactly what commands it is running and why. However, the script is
run in a headless fashion, like this:

  $ curl -L https://nixos.org/nix/install | sh

or maybe in a CI pipeline. Because of that, I'm going to skip the
verbose output in the interest of brevity.

If you would like to
see the output, try like this:

  $ curl -L -o install-nix https://nixos.org/nix/install
  $ sh ./install-nix


~~> Fixing any leftover Nix volume state
Before I try to install, I'll check for any existing Nix volume config
and ask for your permission to remove it (so that the installer can
start fresh). I'll also ask for permission to fix any issues I spot.

~~> Checking for artifacts of previous installs
Before I try to install, I'll check for signs Nix already is or has
been installed on this system.

---- Nix config report ---------------------------------------------------------
        Temp Dir:	/var/folders/5z/mnlc5_7x5dv8r528s4sg1h2r0000gn/T/tmp.70NujKP1Do
        Nix Root:	/nix
     Build Users:	32
  Build Group ID:	350
Build Group Name:	nixbld

build users:
    Username:	UID
     _nixbld1:	351
     _nixbld2:	352
     _nixbld3:	353
     _nixbld4:	354
     _nixbld5:	355
     _nixbld6:	356
     _nixbld7:	357
     _nixbld8:	358
     _nixbld9:	359
     _nixbld10:	360
     _nixbld11:	361
     _nixbld12:	362
     _nixbld13:	363
     _nixbld14:	364
     _nixbld15:	365
     _nixbld16:	366
     _nixbld17:	367
     _nixbld18:	368
     _nixbld19:	369
     _nixbld20:	370
     _nixbld21:	371
     _nixbld22:	372
     _nixbld23:	373
     _nixbld24:	374
     _nixbld25:	375
     _nixbld26:	376
     _nixbld27:	377
     _nixbld28:	378
     _nixbld29:	379
     _nixbld30:	380
     _nixbld31:	381
     _nixbld32:	382

Ready to continue?
No TTY, assuming you would say yes :)

---- Preparing a Nix volume ----------------------------------------------------
    Nix traditionally stores its data in the root directory /nix, but
    macOS now (starting in 10.15 Catalina) has a read-only root directory.
    To support Nix, I will create a volume and configure macOS to mount it
    at /nix.

インストール時のメッセージを見ると、なかなかにシステムのコアな部分に絡む様子。ちょっとビビるけど、進めてみる。パスワードを入力

~~> Configuring /etc/synthetic.conf to make a mount-point at /nix
Password:

またここから色々と出力されるのだが、最終的に以下のように表示されればOKっぽい。

Nix installed successfully. Devbox is ready to use!

でそのままpythonパッケージもインストールされる。


Info: Adding package "python@3.11" to devbox.json
Info: Installing the following packages to the nix store: python@3.11

python NOTES:
Python in Devbox works best when used with a virtual environment (venv, virtualenv, etc.). Devbox will automatically create a virtual environment using `venv` for python3 projects, so you can install packages with pip as normal.
To activate the environment, run `. $VENV_DIR/bin/activate` or add it to the init_hook of your devbox.json
To change where your virtual environment is created, modify the $VENV_DIR environment variable in your init_hook

This plugin creates the following helper files:
* /Users/kun432/work/devbox-test/.devbox/virtenv/python/bin/venvShellHook.sh

This plugin sets the following environment variables:
* VENV_DIR=/Users/kun432/work/devbox-test/.venv
* UV_PYTHON=/Users/kun432/work/devbox-test/.devbox/nix/profile/default/bin/python

To show this information, run `devbox info python`

やっと完了。devbox.jsonが更新され、pythonがパッケージに追加される。

devbox.json
{
  "$schema":  "https://raw.githubusercontent.com/jetify-com/devbox/0.13.5/.schema/devbox.schema.json",
  "packages": ["python@3.11"],
  "shell": {
    "init_hook": [
      "echo 'Welcome to devbox!' > /dev/null"
    ],
    "scripts": {
      "test": [
        "echo \"Error: no test specified\" && exit 1"
      ]
    }
  }
}

また、ディレクトリ内に環境が作成されている模様。

$ tree -a
.
├── .devbox
│   └── virtenv
│       ├── bin
│       │   └── venvShellHook.sh -> /Users/kun432/work/devbox-test/.devbox/virtenv/python/bin/venvShellHook.sh
│       └── python
│           └── bin
│               └── venvShellHook.sh
├── devbox.json
└── devbox.lock

他にもパッケージを追加することができるが、一旦これで。あとpythonパッケージインストール時にvenv周りの出力が出ていたけども、そちらも後回しで。

ではこの開発環境に入る前に、現在のpythonを確認しておく。

$ which python
/Users/kun432/.pyenv/shims/python

$ python --version
Python 3.11.9

では開発環境に入る。devbox shellを実行。

$ devbox shell

初回は何やらいろいろ処理するので時間がかかるみたい。

Info: Ensuring packages are installed.
⢿ Computing the Devbox environment...

新しいシェルが立ち上がった。ちょいちょいwarning的なものが出てくるけど、これは自分の環境依存。

Starting a devbox shell...
bash: export: `BASH_FUNC_show_virtual_env%%=() {  if [ -n "VIRTUAL_ENV_PROMPT" ]; then echo "$VIRTUAL_ENV_PROMPT"; fi}': not a valid identifier
Virtual environment directory doesn't exist. Creating new one...

The default interactive shell is now zsh.
To update your account to use zsh, please run `chsh -s /bin/zsh`.
For more details, please visit https://support.apple.com/kb/HT208050.
(devbox) bash-3.2$

devbox開発環境のpythonを確認してみると、環境内のものになっている。

(devbox) bash-3.2$ which python
/Users/kun432/work/devbox-test/.devbox/nix/profile/default/bin/python

(devbox) bash-3.2$ python --version
Python 3.11.10

ただし、pipはグローバルのものを見てしまってる。

$ which pip
/Users/kun432/.pyenv/shims/pip

pipは.venv内にあるのでactivateされていないのだろうと思う。

(devbox) bash-3.2$ find . -type f -name "pip"
./.venv/bin/pip

なるほど。.venv内にもpythonはあるけど、devboxが用意したpythonへのシンボリックリンクになってる。やはりactivateが必要だと思う。

(devbox) bash-3.2$ ls -lt .venv/bin/python
lrwxr-xr-x 1 kun432 staff 69 10 26 00:16 .venv/bin/python -> /Users/kun432/work/devbox-test/.devbox/nix/profile/default/bin/python

上のpipを見てても分かる通り、グローバルな環境のものは普通に見える

(devbox) bash-3.2$ git config --get user.email
kun432@users.noreply.github.com

開発環境から抜けると元に戻っているのがわかる。

(devbox) bash-3.2$ exit

$ which python
/Users/kun432/.pyenv/shims/python
kun432kun432

pythonの場合

以下にいろいろな環境についての例がある。

https://www.jetify.com/docs/devbox/devbox_examples/

で、pythonの場合。

https://www.jetify.com/docs/devbox/devbox_examples/languages/python/

なるほど、init_hookというのがあるのでここでactivateさせれば良さそう。あと、デフォルトだと.venvは.devbox/virtenv/python/.venvになるとあるが、自分の環境だと作業ディレクトリ直下だった。

とりあえず以下のようにdevbox.jsonを修正

devbox.json
{
  "$schema":  "https://raw.githubusercontent.com/jetify-com/devbox/0.13.5/.schema/devbox.schema.json",
  "packages": ["python@3.11"],
  "env": {
    "VENV_DIR": ".venv"
  },
  "shell": {
    "init_hook": [
      ". $VENV_DIR/bin/activate"
    ],
    "scripts": {
      "test": [
        "echo \"Error: no test specified\" && exit 1"
      ]
    }
  }
}

再度devbox環境に入ってみる。

$ devbox shell

環境の確認が行われる。

Info: Ensuring packages are installed.
✓ Computed the Devbox environment.

シェルプロンプトを見る限りはactivateされてるように思える。

(.venv) (devbox) bash-3.2$

確認

(.venv) (devbox) bash-3.2$ which python
/Users/kun432/work/devbox-test/.venv/bin/python

(.venv) (devbox) bash-3.2$ which pip
/Users/kun432/work/devbox-test/.venv/bin/pip

いけてそう。

とりあえずpythonについては大体使い方や設定がわかったけど、他のパッケージを使う場合はそれぞれの固有の設定はありそうなので、個別に見ていく必要は当然ありそう。

kun432kun432

devboxをグローバルなパッケージマネージャにすることもできるみたい。

https://www.jetify.com/docs/devbox/devbox_global/

今のところ自分はMacではHomebrewでBrewfileをレポジトリ管理しているし、Ubuntuサーバは基本的にOSが提供するパッケージを使いたいと思っている。今の状況に特に不満もないのであえて変えようとは思わないけど、別の環境が用意できたら一度試してみたい。

kun432kun432

あと、devboxについて書かれた記事を見ていると、どうやらdevbox環境からDevcontainerやDockerの設定ファイルを生成したり、あとはREADMEなんかも出力できるみたい。

https://www.jetify.com/docs/devbox/cli_reference/devbox_generate/

参考

https://zenn.dev/shimarisu_121/articles/12cbe01ee9fbe8

https://zenn.dev/rsi_dev/articles/ceafde722868f9

とりあえずREADMEを試してみる。

 $ devbox generate readme

こんな感じのREADME.mdが出力される

README.md
<!-- gen-readme start - generated by https://github.com/jetify-com/devbox/ -->
## Getting Started
This project uses [devbox](https://github.com/jetify-com/devbox) to manage its development environment.

Install devbox:
```sh
curl -fsSL https://get.jetpack.io/devbox | bash
```

Start the devbox shell:
```sh
devbox shell
```

Run a script in the devbox environment:
```sh
devbox run <script>
```
## Scripts
Scripts are custom commands that can be run using this project's environment. This project has the following scripts:

* [test](#devbox-run-test)

## Environment

```sh
UV_PYTHON="/Users/kun432/work/devbox-test/.devbox/nix/profile/default/bin/python"
VENV_DIR=".venv"
```

## Shell Init Hook
The Shell Init Hook is a script that runs whenever the devbox environment is instantiated. It runs
on `devbox shell` and on `devbox run`.
```sh
/Users/kun432/work/devbox-test/.devbox/virtenv/python/bin/venvShellHook.sh
. $VENV_DIR/bin/activate
```

## Packages

* [python@3.11](https://www.nixhub.io/packages/python)

## Script Details

### devbox run test
```sh
echo "Error: no test specified" && exit 1
```
&ensp;



<!-- gen-readme end -->

あと、Devcontainerの設定ファイルも出力してみる。

$ devbox generate devcontainer
$ tree .devcontainer
.devcontainer
├── Dockerfile
└── devcontainer.json
.devcontainer/devcontainer.json
{
  "name": "Devbox Remote Container",
  "build": {
    "dockerfile": "./Dockerfile",
    "context": ".."
  },
  "customizations": {
    "vscode": {
      "settings": {},
      "extensions": [
        "jetpack-io.devbox"
      ]
    }
  },
  "remoteUser": "devbox"
}
.devcontainer/Dockerfile
$ cat .devcontainer/Dockerfile
FROM jetpackio/devbox:latest

# Installing your devbox project
WORKDIR /code
USER root:root
RUN mkdir -p /code && chown ${DEVBOX_USER}:${DEVBOX_USER} /code
USER ${DEVBOX_USER}:${DEVBOX_USER}
COPY --chown=${DEVBOX_USER}:${DEVBOX_USER} devbox.json devbox.json
COPY --chown=${DEVBOX_USER}:${DEVBOX_USER} devbox.lock devbox.lock



RUN devbox run -- echo "Installed Packages."

RUN devbox shellenv --init-hook >> ~/.profile

なるほど、このあたりをレポジトリに入れとけばセットアップ手順なんかも全部共有されると。これは便利かも。

kun432kun432

まとめ

Nixは名前だけしか聞いたことがなくて、ちょっとややこしそう、という印象しかなかったけど、devboxを使う限りはあまり意識しなくて良さそう。ちょっとNixインストール時のメッセージにはビビるところもあったけども、今のところ自分の環境でも特に問題は起きてない。

とりあえずもう少し使い続けないと良さはわからないと思うけど、現時点では印象は悪くない。個人的にはまだDockerのほうが安心感はあるけど(完全に隔離されるし)、その分多少の手間はかかるので、ライトに環境用意したい場合に使ってみてもいいかなという印象。

このスクラップは11日前にクローズされました