Kubernetes CRI CLI: crictl-shaped client, simulator server, proxy
0

Configure Feed

Select the types of activity you want to include in your feed.

OCaml 92.2%
Go 2.2%
Shell 1.4%
Dune 1.0%
Other 3.3%
22 1 0

Clone this repository

https://git.vm.fail/gazagnaire.org/ocaml-cri https://git.vm.fail/did:plc:dujeo4qsro7htliyzwzh5chl
ssh://git@git.recoil.org:2222/gazagnaire.org/ocaml-cri ssh://git@git.recoil.org:2222/did:plc:dujeo4qsro7htliyzwzh5chl

For self-hosted knots, clone URLs may differ based on your setup.


README.md

cri#

The Kubernetes Container Runtime Interface (CRI, runtime.v1) in pure OCaml: IO-free protobuf types and gRPC method definitions, a runtime backend boundary, an Eio server and daemon, an Eio client and CLI, and a body-aware gateway. The same definitions back the client, the server, and the proxy.

It is the gRPC/protobuf sibling of ocaml-docker: where Docker exposes a REST/JSON Engine API, CRI is gRPC over protobuf. The wire layer is built on nox-protobuf, nox-grpc and nox-grpc-eio; no protoc or external toolchain is needed.

Installation#

Install with opam:

$ opam install cri

If opam cannot find the package, it may not yet be released in the public opam-repository. Add the overlay repository, then install it:

$ opam repo add samoht https://tangled.org/gazagnaire.org/opam-overlay.git
$ opam update
$ opam install cri

Packages#

Package What it is
cri-api IO-free protobuf message types, nox-grpc method registry, and Cri.Runner backend interface/simulator for the full RuntimeService and ImageService (41 RPCs). No IO dependency.
cri-server Server.Make (B : Cri.Runner.BACKEND) over nox-grpc-eio and the Server.Proxy body-aware gateway.
cri-client An Eio gRPC client: one typed function per RPC.
cri The cri CLI: serve runs the in-memory simulator server, proxy runs the gateway, and the remaining subcommands are a crictl-shaped client (version, status, pods, ps, images, pull, runp, rmp).

The binary is named cri so it never shadows the upstream cri-tools crictl on PATH.

Library#

The cri library names every CRI message as a nox-protobuf codec and every RPC as a nox-grpc method:

# let path = Grpc.Method.path Cri.Service.run_pod_sandbox ;;
val path : string = "/runtime.v1.RuntimeService/RunPodSandbox"

Cri_server.Make builds a server over any backend; Make (Cri.Runner.Memory) is an in-memory CRI that speaks real gRPC:

module Server = Cri_server.Make (Cri.Runner.Memory)
let server = Server.v (Cri.Runner.Memory.v ())
(* Server.run ~sw ~net ~addr:(`Unix "/run/crid.sock") server *)

The proxy#

Cri_server.Proxy is a body-aware CRI gateway between a kubelet and an upstream runtime. Because every request is typed, policies inspect the body, not just the method path:

  • allow_all -- forward everything;
  • read_only -- deny mutating RPCs;
  • no_privileged -- deny privileged sandboxes and containers;
  • image_allowlist names -- deny images outside an allowlist.
crict-proxy --listen /run/crict-proxy.sock \
            --upstream /run/containerd/containerd.sock \
            --policy no_privileged --audit

CLI#

crictd  --socket /tmp/crid.sock                      # run the simulator daemon
crict   -r /tmp/crid.sock version                    # query it
crict   -r /tmp/crid.sock runp web                   # run a pod sandbox
crict   -r /tmp/crid.sock pods                        # list pod sandboxes

Testing#

dune test                       # codec round-trips, wire format, in-process e2e
CRI_LIVE=1 dune build @critest  # cri-tools `critest` conformance (needs critest)

The critest harness runs the official conformance suite against crictd (an API-shape smoke) or, with UPSTREAM=<sock>, through crict-proxy in front of a real runtime -- putting our codecs and proxy in the path of the authoritative suite.

Status#

The in-memory backend is an honest simulator: the pod/container/image lifecycle is bookkeeping, stats are zero, and exec/attach return a URL but stream no bytes -- no process is ever run. A real runc/VMM backend behind the same BACKEND boundary is the natural next step.