この記事のポイント
- Microsoft Execution ContainersをSDKでハンズオンしているよ
- ハンズオンを通して実装を深堀りしているよ
はじめに
この記事にはMicrosoft Build 2026で発表されたMicrosoft Execution Containers(以下、MXC)について書かれています。登場したばかりのツールということもあり、今後のアップデート次第では、このブログに書かれているハンズオンが機能しなくなる可能性もあります。
前回はMXCの中でもNative Binaryに関する説明でしたが、今回はSDKに関する説明になります。
Microsoft Execution Containers(MXC)とは
ハンズオン
では、実際にハンズオンしていきましょう。今回はmacOS上でMXCを実行します。
macOSの環境
- macOS
- Tahoe 26.5.1
- Visual Studio Code
- Version: 1.124.0
- node --version
- v20.19.5
- MXC SDK
- v0.6.1
前回は実行するためにRust/Cargoをインストールしていました。今回は不要ですが、参考程度に前提を共有しておきます。
- cargo
- 1.96.0 (30a34c682 2026-05-25)
ハンズオンのおおまかな流れ
- Setup
- npm run devの実行
- さまざまなスクリプトを試します
Setup
まずはリポジトリをクローンします。
gh repo clone ymd65536/MXCSDKDemo && cd MXCSDKDemo
git clone https://github.com/ymd65536/MXCSDKDemo.git && cd MXCSDKDemo
Node.jsをnvmでインストールします。インストール手順
最後にパッケージをインストールします。
npm install
これでセットアップは完了です。
今回やること
5つの使い方を例にSDKの特徴をチェックしていきます。
- 最初の一歩
- pythonのHello World
- ファイルシステムを試す
- 環境変数を追加/参照する
- ネットワーク機能を試す
最初は基本となるサンプルコードの実行、それからサンドボックス内でPythonを実行、ファイル・システム、環境変数、ネットワークの機能を確認します。
最初の一歩
まずはSDKのREADME.mdにあるソースコードを見てみましょう。
※pythonで実行するとcommand not foundになってしまうためpython3に修正しています。
このスクリプトを実行してみましょう。まずはsamples/firstに保存されているスクリプトをコピーします。
# samples/first
cp ./samples/first/index.ts ./src
npm run devで実行します。
npm run dev
実行結果
Spawning sandbox with config: {
"version": "0.7.0-alpha",
"containerId": "21d8081e",
"lifecycle": {
"destroyOnExit": true,
"preservePolicy": false
},
"process": {
"commandLine": "python3 --version;which python3;uname -m",
"timeout": 30000
},
"filesystem": {
"readwritePaths": [
"/var/folders/nk/26yk2_3d1dd382hvzshrs_3h0000gn/T/"
],
"readonlyPaths": [
~長いので省略~
],
"deniedPaths": []
},
"ui": {
"disable": true,
"clipboard": "none",
"injection": false
},
"network": {
"defaultPolicy": "block"
},
"containment": "seatbelt",
"seatbelt": {}
}
Python 3.11.15
/opt/homebrew/opt/python@3.11/libexec/bin/python3
arm64
exit: 0
このPythonバージョンはホストOSのPythonバージョンと一致するはずです。確認コマンドは以下のとおりです。
python --version
# Python 3.11.15
ここでNative Binaryを触ったときのことを思い出すとSDKではプラットフォームを意識することがないという点が挙げられます。
ソースコードを追ってみるとgetPlatformSupportというファンクションを使って自動判定していることがわかります。順番に追ってくとまずはgetPlatformSupportはPlatformSupportを返します。
このとき2つのPlatformSupportを返すようです。最初にcomputeSupportが実行されるようなのでこの実装を見てみましょう。※長いので一部省略
252行目から301行目にかけてプラットフォームの判定があります。これがまた奇妙な話なんですが、筆者としては先にWin32を判定して他のプラットフォームを判定しているかと思いきや結構変わった順番でした。※なんとWindowsの判定は最後!!
darwin => linux => win32という順番でプラットフォームを判定するようになっていました。
pythonのHello World
つぎにサンドボックス上でPythonを実行してみましょう。同様にスクリプトをコピーします。
cp ./samples/python_hello_world/index.ts ./src
npm run devで実行します。
npm run dev
Mon Jun 15 23:43:43 JST 2026
total 8
drwxr-xr-x 3 501 staff 96 Jun 15 21:04 .
drwxr-xr-x@ 18 501 staff 576 Jun 15 23:24 ..
-rw-r--r-- 1 501 staff 22 Jun 15 21:04 hello_world.py
Hello, World
Mon Jun 15 23:43:43 JST 2026
exit: 0
これでリポジトリにあるHello WorldのPythonスクリプトが動きました。
ファイルシステムを試す
つぎにサンドボックス上のファイルシステムを操作してみましょう。同様にスクリプトをコピーします。
cp ./samples/filesystem/index.ts ./src
npm run devで実行します。
npm run dev
実行結果ですが、今回は以下のコマンドを実行しているのでリポジトリのルートにsample.logというファイルができているはずです。
date;echo "# sample file ${userHome}" > sample.log;date
ファイルシステムの操作は3つの設定項目があり、許可/禁止どちらにしてもパスが格納されたリストを共有することでファイルシステムへのアクセスを制御できます。
- Read-write access
- 読み込み書き込み可
- Read-only access
- 読み込み可
- Blocked paths
- Sandboxシステムでブロック
環境変数を追加/参照する
次にサンドボックス上に環境変数を追加しましょう。Pythonが実行できるのでホストOS上の環境変数を共有しているように見えますが、起動されたサンドボックスは環境変数を持っていません。
どういうことなのか確認してみましょう。同様にスクリプトをコピーします。
cp ./samples/environ/index.ts ./src
npm run devで実行します。
npm run dev
実行結果
Mon Jun 15 23:56:44 JST 2026
MY_VAR=hello world
PWD=/Users/{ユーザー名}/Desktop/MXCSDKDemo
SHLVL=1
_=/usr/bin/env
hello world
Mon Jun 15 23:56:44 JST 2026
exit: 0
実行結果を見てみるとデフォルトの環境変数と追加した環境変数しかありません。これはつまり、サンドボックスが本当に独立した環境で動作していることを暗に示唆しています。
MY_VAR=hello world
PWD=/Users/{ユーザー名}/Desktop/MXCSDKDemo
SHLVL=1
_=/usr/bin/env
なお、ソースコード内ではconfig.process!.env = ["MY_VAR=hello world"];という1行で環境変数を定義できています。
ネットワーク機能を試す
最後にサンドボックスのネットワーク制御を試してみましょう。同様にスクリプトをコピーします。
cp ./samples/network/index.ts ./src
今回はローカルホストに簡易的なサーバーを構築して試します。ターミナルを新しく起動して以下のコマンドを実行します。
cd web && npm start
実行するとlocalhost:3000にサーバーが起動します。
ちなみに起動したサーバーの仕様は以下のとおりです。
| path | レスポンス |
|---|---|
/ |
{"message":"Hello from local Node.js JSON server","ok":true,"timestamp":"..."} |
/health |
{"status":"ok"} |
/not-found |
{"error":"Not Found","path":"/not-found"} |
もとのターミナルでnpm run devを実行します。
npm run dev
実行結果
Tue Jun 16 00:09:01 JST 2026
* Host localhost:3000 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
* Trying [::1]:3000...
* Connected to localhost (::1) port 3000
> GET /health HTTP/1.1
> Host: localhost:3000
> User-Agent: curl/8.7.1
> Accept: */*
>
* Request completely sent off
< HTTP/1.1 200 OK
< Content-Type: application/json; charset=utf-8
< Date: Mon, 15 Jun 2026 15:09:01 GMT
< Connection: keep-alive
< Keep-Alive: timeout=5
< Transfer-Encoding: chunked
<
* Connection #0 to host localhost left intact
{"status":"ok"}
Tue Jun 16 00:09:01 JST 2026
exit: 0
HTTP/1.1 200 OKと{"status":"ok"}というレスポンスが返ってくればOKです。
ソースコードで今回注目すべきところはもちろんnetworkという項目です。
const config = createConfigFromPolicy({
version: '0.7.0-alpha',
// サンドボックスからみて外向けの通信を有効にする設定
network: { allowOutbound: true },
});
なお、createConfigFromPolicyのnetworkはNetworkConfigによって定義されています。
ちなみにスキーマではallowOutboundという設定がないことに注意が必要かもしれません。
参考:mxc-config.schema.0.7.0-alpha.json#L120-L191
ハンズオンを通してSDKを知る
ハンズオンは以上です。ここからはREADME.mdをベースにMXCのSDKがどんなものか見ていきます。参考:README.md
MXC(SDK)特徴
SDKを触ってみて感じた特徴をまとめようと思います。
- Native Binaryのときより直感的でわかりやすく実装しやすい
- 実行はマイクロVM上だが、参照するプログラムはホストOS側のプログラムであり、環境変数も異なる
- ファイルシステムの設定はわりとアバウトでも許可できてしまう
-
/opt/homebrewという設定ではhomebrewよりしたのディレクトリは全許可判定
-
- ネットワークの設定ではホスト/IP/ポート番号レベルでブロックできる
- SDKの設定項目とNative Binaryの設定項目はひょっとすると名前が違うのでは?と思われるところがある
- ファイルシステムの設定には許可と禁止があるが、同じパスを設定に入れていると禁止が優先される
そして、やはりTypeScriptで実行できる点は魅力的です。というのもたとえば、Next.jsやReactなどから実行が可能であることです。APIとして作成すれば、オレオレサーバーレスも可能になるという点は刺さるポイントです。
ただし、ファイルシステムやネットワークの設定を誤るとホストOSを壊す可能性もあります。
(例:ファイルシステムで許可している範囲が広い、許可していないネットワークへアクセスできるなど)
まとめ
今回はMicrosoft Execution ContainersをSDKから触ってみました。
TypeScript製のSDKでマイクロVMを手軽に構築できる点は魅了的です。まだ可能性を探りきれていないですが、高速で任意のコマンドを実行するような用途ではとても役に立つものでした。
一方で前回のNative Binaryとどのように棲み分けて使ったら良いかという点やTypeScriptで書いた設定をjsonに落としてNative Binaryで使うといったことも考えられますが、試したことがないのでもしかすると難儀するかもしれません。
※createConfigFromPolicyで作成したconfigをJSON.stringifyで変換してconsole.logで表示することによりSDKで設定ファイルの生成が可能であることは検証できました。
まだ発展途上ですが、とても夢のあるSDKでした。今後もアップデートを見ていきたいと思います。
参考
- Microsoft Build 2026: Securing code, agents, and models across the development lifecycle
- microsoft/mxc
- Build 2026: 信頼できる開発プラットフォームとして、進化する Windows
- macOS Sandbox Container Backend
- Firecracker – サーバーレスコンピューティングのための軽量な仮想化機能
おまけ:トラブルシューティング
dyld[35322]: Library not loaded
次のようにdyld[35322]: Library not loadedというメッセージの出力がされる場合はSandboxの設定で読み込み先のパスがブロックされている可能性があります。
dyld[35322]: Library not loaded: /opt/homebrew/Cellar/python@3.13/3.13.13_1/Frameworks/Python.framework/Versions/3.13/Python
Referenced from: <393B5A9B-A55D-34F9-8B71-DA53A86CB8FB> /opt/homebrew/Cellar/python@3.13/3.13.13_1/Frameworks/Python.framework/Versions/3.13/bin/python3.13
Reason: tried: '/opt/homebrew/Cellar/python@3.13/3.13.13_1/Frameworks/Python.framework/Versions/3.13/Python' (file system sandbox blocked open()), '/System/Volumes/Preboot/Cryptexes/OS/opt/homebrew/Cellar/python@3.13/3.13.13_1/Frameworks/Python.framework/Versions/3.13/Python' (no such file), '/opt/homebrew/Cellar/python@3.13/3.13.13_1/Frameworks/Python.framework/Versions/3.13/Python' (file system sandbox blocked open())
/bin/sh: line 1: 35322 Abort trap: 6 python3 --version
解決方法としてはcreateConfigFromPolicyにて生成されるfilesystemプロパティでreadonlyPathsを追加してください。今回はhomebrewのパスが原因ですので/opt/homebrew/Cellar/python@3.13/3.13.13_1/Frameworks/Python.framework/Versions/3.13/Pythonを追加します。
なお、WindowsやLinuxでも同様にパスが追加されていないとブロックされます。
import {
spawnSandboxFromConfig, createConfigFromPolicy,
getAvailableToolsPolicy, getTemporaryFilesPolicy,
getPlatformSupport,
} from '@microsoft/mxc-sdk';
if (!getPlatformSupport().isSupported) {
throw new Error('MXC not available on this host');
}
const tools = getAvailableToolsPolicy(process.env);
const temp = getTemporaryFilesPolicy();
// ここでdirectories変数を作成し、homebrewのパスを追加する
const directories = tools.readonlyPaths;
directories.push('/opt/homebrew/Cellar/python@3.11/3.11.15_3/Frameworks/Python.framework/Versions/3.11/Python');
//あるいはhomebrewを丸ごと追加
// directories.push('/opt/homebrew/');
// directoriesをreadonlyPathsに追加する
const config = createConfigFromPolicy({
version: '0.7.0-alpha',
filesystem: {
readonlyPaths: directories,
readwritePaths: temp.readwritePaths,
},
network: { allowOutbound: false },
timeoutMs: 30_000,
});
config.process!.commandLine = 'python3 --version;which python3;uname -m';
console.log('Spawning sandbox with config:', JSON.stringify(config, null, 2));
const child = spawnSandboxFromConfig(config, { usePty: false });
child.stdout!.on('data', (d) => process.stdout.write(d));
child.on('close', (code) => console.log('exit:', code));