# ocinoco - Build <ins>**OCI**</ins> Image with <ins>**no**</ins> <ins>**co**</ins>ntainer
> [!WARNING]
> このプロジェクトは開発中です.製品環境で利用する場合は十分に検証してください.
> 開発者は利用したことによる損害などについて一切の責任を負いません.
## モチベーション
OCI イメージ (Docker イメージとも呼ばれます) をビルドするときは,通常 BuildKit などのツールキットを利用し,
ビルド用のコンテナを起動した上で行われます.再現可能なビルドをするためには優れた仕組みですが,その代わりに時間がかかります.
ビルドにかかる時間の内訳を以下に示します (CI 上で実行することを想定します):
1. BuildKit のセットアップ
2. ベースイメージおよびキャッシュのダウンロード
3. ビルド用コンテナの起動
4. ビルド (`pnpm install`, `tsc` など)
5. コンテナから OCI イメージを作成
6. レジストリへのプッシュ
特に,スクリプト言語 (JavaScript, TypeScript, Python, Ruby などです) で書かれたアプリケーションをビルドする場合,
4 のビルド工程よりもその他の工程が占める割合が大きくなりがちです.
**ocinoco** は,これらの工程のほとんどを排除します:
1. ビルド (`pnpm install`, `tsc` など)
2. ベースイメージとファイルシステムから OCI イメージを作成
3. レジストリへのプッシュ
後述する仕組みから分かるように,ocinoco ではベースイメージをダウンロードする必要すらありません.
ビルド済みのベースイメージと必要なファイルさえあれば, **数秒で OCI イメージを作成できます**.
## 仕組み
OCI イメージは複数の **レイヤ** で構成されます.ファイル・ディレクトリの差分をレイヤとして積み重ねて複数をまとめることで,
最終的なコンテナ上のファイルシステムを表します.
一般によくあるイメージのレイヤ構造を次に示します (簡略化しています):
| 3 | アプリケーションのコード |
| 2 | 言語ランタイムなど |
| 1 | ミドルウェア |
アプリケーションをビルドする際に構築する必要があるものは,一般に一番上のレイヤのみです.
したがって,イメージをビルドする作業は,一番上のレイヤを新規作成してベースイメージに結合する作業と言い換えられます.
レイヤは,レジストリにおいても独立して存在します (blob といいます).レイヤを追加したイメージを作成する場合は,
新しいレイヤの blob と変更したマニフェストをアップロードすることで実現できます.
以上の前提をもとに,ocinoco は,ファイルシステム上に存在するアプリケーションコードのファイル群を OCI 準拠のレイヤに変換してレジストリにプッシュすることで,
必要な工程を極限まで削減したビルド手段を提供します.
## インストール
現時点では,crates.io でのみ配布しています.
npm での配布も予定しています.
```shell
cargo install ocinoco
```
## 使い方
> [!IMPORTANT]
> ビルドに使う環境がイメージのランタイム環境 (platform) と一致していることを確認してください.
> 例えば,一部の npm パッケージはネイティブバイナリをインストール時に解決するため,
> ランタイムと異なる環境でビルドすると動作しなくなる場合があります.
### OCI イメージを作成する
`build` コマンドは,指定したディレクトリから `tar.zst` 形式の OCI レイヤを作成し,既存のベースイメージにそのレイヤを追加した
OCI イメージを作成します.
```shell
ocinoco build ./dist \
--from ghcr.io/example/base:latest \
--tag ghcr.io/example/app:latest
```
デフォルトではレジストリへのプッシュは行いません.作成したイメージをプッシュする場合は `--push` を指定します.
```shell
ocinoco build ./dist \
--from ghcr.io/example/base:latest \
--tag ghcr.io/example/app:latest \
--push
```
> [!NOTE]
> 指定されたベースイメージは既にレジストリ上に存在している必要があります.
アーカイブ内の配置先や所有者を指定する場合は,次のようにします.
```shell
ocinoco build ./dist \
--from ghcr.io/example/base:latest \
--tag ghcr.io/example/app:latest \
--root-dir /app \
--uid 1000 \
--gid 1000
```
### tar.zst アーカイブを作成する
`pack` コマンドは,指定したディレクトリを OCI レイヤと同じ `tar.zst` 形式のアーカイブとして出力します.
レジストリへの接続や OCI マニフェストの作成は行いません.
```shell
ocinoco pack ./dist ./layer.tzst
```
アーカイブ内の配置先や所有者を指定する場合は,次のようにします.
```shell
ocinoco pack ./dist ./layer.tzst \
--root-dir /app \
--uid 1000 \
--gid 1000
```