OCI Standards (The Truce)

[!NOTE] This module explores the core principles of OCI Standards (The Truce), deriving solutions from first principles and hardware constraints to build world-class, production-ready expertise.

1. The Container Wars (2013-2015)

In the beginning, Docker was the only game in town. But as it grew, companies like CoreOS (creating rkt) and Google (Kubernetes) wanted standardization. They feared vendor lock-in.

The Open Container Initiative (OCI) was formed in 2015 to create open standards.

The Two Specs

  1. Image Spec: Defines the “shipping container”. What’s inside the tarball? (Manifest, Layers, Config).
  2. Runtime Spec: Defines the “crane”. How do you unpack and run it? (config.json, rootfs).

Because of OCI, you can build with Docker, push to Amazon ECR, and run with Kubernetes (CRI-O) or Podman.


2. Interactive: OCI Bundle Inspector

An OCI Bundle is just a directory with a config.json and a rootfs folder.

Directory Structure
📂 my-container-bundle/
📄 config.json
📂 rootfs/
📂 bin/
📄 sh
File Content: config.json
{
  "ociVersion": "1.0.2",
  "process": {
      "user": { "uid": 0, "gid": 0 },
      "args": ["sh"],
      "env": ["PATH=/usr/local/sbin..."],
      "cwd": "/"
  },
  "root": {
      "path": "rootfs",
      "readonly": true
  },
  "mounts": [
      {
          "destination": "/proc",
          "type": "proc",
          "source": "proc"
      }
  ],
  "linux": {
      "namespaces": [
          { "type": "pid" },
          { "type": "network" },
          { "type": "mount" }
      ]
  }
}
      

3. Code Examples

1. Go Implementation (OCI Runtime Spec)

This is the actual Go struct used by runc to parse config.json.

package main

import (
	"encoding/json"
	"fmt"
	"os"

	"github.com/opencontainers/runtime-spec/specs-go"
)

func main() {
	// 1. Create a minimal OCI Spec
	spec := specs.Spec{
		Version: specs.Version,
		Process: &specs.Process{
			Args: []string{"sh"},
			Env:  []string{"PATH=/bin"},
			Cwd:  "/",
		},
		Root: &specs.Root{
			Path: "rootfs",
			Readonly: true,
		},
		Linux: &specs.Linux{
			Namespaces: []specs.LinuxNamespace{
				{Type: specs.PIDNamespace},
				{Type: specs.NetworkNamespace},
			},
		},
	}

	// 2. Marshal to JSON (config.json)
	data, err := json.MarshalIndent(spec, "", "  ")
	if err != nil {
		panic(err)
	}

	// 3. Write config.json
	os.WriteFile("config.json", data, 0644)
	fmt.Println("Generated OCI config.json!")
}

2. Java Implementation (Parsing OCI)

Java tools can inspect OCI bundles (e.g., for security scanning) by parsing the standard JSON format.

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.File;
import java.io.IOException;

public class OciInspector {

    public static void main(String[] args) throws IOException {
        ObjectMapper mapper = new ObjectMapper();

        // 1. Read config.json
        JsonNode root = mapper.readTree(new File("config.json"));

        // 2. Inspect Process Args
        JsonNode argsNode = root.path("process").path("args");
        System.out.println("Container Command: " + argsNode.toString());

        // 3. Check for Privileged Mode (Security Check)
        // If namespaces are missing, it might be running on host!
        JsonNode namespaces = root.path("linux").path("namespaces");
        boolean hasPidNS = false;
        for (JsonNode ns : namespaces) {
            if (ns.get("type").asText().equals("pid")) {
                hasPidNS = true;
            }
        }

        if (!hasPidNS) {
            System.out.println("WARNING: Container shares Host PID namespace!");
        } else {
            System.out.println("PID Namespace isolation: Active");
        }
    }
}

[!TIP] Try it yourself:

  1. Run docker export $(docker create busybox) | tar -C rootfs -xvf -
  2. Run runc spec
  3. Run sudo runc run mycontainer You just ran a container without the Docker daemon!