🛠️

OCI コンテナランタイム仕様に登場する bundle を作って試す

2020/11/07に公開

概要

OCIコンテナランタイム仕様 に登場する bundle を理解するために、簡単な bundle のサンプルを作り、コンテナランタイム runc を用いて動作を見てみた。

試作したリポジトリは下記。(ほとんど何もないですが)
https://github.com/nokute78/container-runtime-bundle-example

bundleとは

OCIの定めるコンテナランタイム仕様に登場する、コンテナのもととなるもの。
仕様によると、コンテナ生成(create)をする際に与える必要がある。

https://github.com/opencontainers/runtime-spec/blob/master/runtime.md#create
create <container-id> <path-to-bundle>

bundleについてはこちらに記載がある。
https://github.com/opencontainers/runtime-spec/blob/master/bundle.md

bundleの内容はシンプルで、下記二つを単一ディレクトリ以下に置いたもののことらしい。

  1. config.json
  2. コンテナのルートファイルシステム

簡単なbundleの作成

bundleを作成してみる。今回はルートファイルシステム作成の簡単化のため、動作に特別なライブラリが不要なgolangを使用した。
また、config.json のひな型生成と bundle の動作確認のため、runcを用いた。

環境

Ubuntu 18.04.5
runc 1.0.0-rc10
go1.15.3 linux/amd64

インストール

golang, runcともに apt でパッケージを取得できる。

bundle と rootfs ディレクトリの作成

まず、config.jsonとrootfsを置くためのディレクトリを作成する。

mkdir -p bundle/rootfs

実行ファイルの作成

golangで helloworld プログラムを作成する。

package main

func main() {
	println("hello world")
}

この時点で下記のような構成になる。

$ go build hello.go
$ ls -F 
bundle/  hello*  hello.go

出来上がった実行ファイルを bundle/rootfs 以下に配置する。

mv hello bundle/rootfs

config.jsonの作成

runc コマンドには config.json のひな形を作成するオプションspecがあるようなので、これを利用した。
先ほどの bundleディレクトリ直下に config.json を配置する。

$ runc spec
$ ls -F 
bundle/  config.json  hello.go
$ mv config.json bundle

config.json については、下記二点を修正した。

  1. process.terminalfalse にする
  2. process.args を 実行ファイル名にした

1つ目の修正がない場合、runc 実行時に tty のエラーがでた。

$ sudo runc create sample
ERRO[0000] cannot allocate tty if runc will detach without setting console socket 
cannot allocate tty if runc will detach without setting console socket

最終的な diff は下記。

--- config_orig.json	2020-11-07 08:32:48.861478283 +0900
+++ config.json	2020-11-07 08:33:00.861671773 +0900
@@ -1,13 +1,13 @@
 {
 	"ociVersion": "1.0.1-dev",
 	"process": {
-		"terminal": true,
+		"terminal": false,
 		"user": {
 			"uid": 0,
 			"gid": 0
 		},
 		"args": [
-			"sh"
+			"/hello"
 		],
 		"env": [
 			"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",

最終的なディレクトリ構成

ここまでの作業によって、下記のような配置になる。

.
├── bundle
│   ├── config.json
│   └── rootfs
│       └── hello
└── hello.go

runc によるテスト

出来上がったbundleの動作を試すため、runc create および runc start を行う。

まずはコンテナを生成する。下記はtestというコンテナを生成する例。-bオプションでbundleのパスを指定する。

sudo runc create test -b bundle/

成功した場合、runc listでコンテナが生成されていることを確認できる。

$ sudo runc list
ID          PID         STATUS      BUNDLE                                           CREATED                          OWNER
test        10449       created     /home/taka/git/container-bundle-example/bundle   2020-11-06T23:38:06.028602922Z   root

作成されたコンテナを実行し、helloworldが出力されることを確認する。

$ sudo runc start test
hello world

なお、実行済みコンテナはdeleteコマンドで消去する。

sudo runc delete test

その他

Linux上ではrunc create した際に rootfs 以下に proc, sys, dev が生成されるようだ。

参考

https://danishpraka.sh/2020/07/24/introduction-to-runc.html
https://github.com/opencontainers/runc/issues/1580 ttyのエラーについて

Discussion