Warning
Container Cubby is still in development, and may be subject to frequent and unannounced breaking changes.
Container Cubby is a container registry that aims to implement the OCI Distribution Specification while avoiding complex features and dependencies. It is single-tenant, and stores all container data as files in a local directory.
Pre-built images are available from cubby.no (Which, of course, runs Container Cubby ✨).
podman pull cubby.no/rosvik/container-cubby:mainpodman run -d --name container-cubby -p 8602:8602 \
-v ./data:/data \
-e AUTH_MODE=write_only \
-e USERNAME=admin \
-e PASSWORD=hunter2 \
cubby.no/rosvik/container-cubby:mainInstall rust, then execute the following to create and run an optimized binary:
cargo build --release && ./target/release/container-cubby| Variable | Description | Default |
|---|---|---|
HOST |
The host to bind to. | localhost |
PORT |
The port to bind to. | 8602 |
DATA_DIR |
The directory to store the container data in. | ./data |
USERNAME |
The username to use for authentication. | |
PASSWORD |
The password to use for authentication. | |
AUTH_MODE |
The authentication mode to use. none, write_only or read_write. |
Required |
PRUNE_CRON |
A cron expression that sets the schedule for pruning the database. | Disabled |
See .env.example for a starting point.
Container Cubby implements the following authentication modes:
none: No authentication is required for reading or writing. Not recommended if the registry is publicly accessible.write_only: Authentication is required for writing, but not for reading.read_write: Authentication is required for both reading and writing.
The only type of authentication that is supported is basic auth for a single user/password pair. If no username or password is provided, the registry will be set to read-only mode.
To avoid bloating the database with unused data, Container Cubby can be configured to delete untagged images. Images that are less than 24 hours old are not deleted to avoid issues with ongoing uploads.
Pruning is disabled by default. It is enabled by setting PRUNE_CRON as a cron expression. The following example will prune the database every day at midnight UTC:
# sec, min, hour, day of month, month, day of week
PRUNE_CRON="0 0 0 * * *"Container Cubby stores all container data in a local directory. The location of this directory can be set by the DATA_DIR environment variable.
This is implemented using:
- directories to represent namespaces.
- E.g. containers under the
rosvik/container-cubbynamespace are stored in<DATA_DIR>/containers/rosvik/container-cubby/.
- E.g. containers under the
- files to store manifest and blob data.
- Manifests are stored as
sha256:<manifest hash>.jsonin namespace folders. - Blobs are stored in the
<DATA_DIR>/blobsfolder.
- Manifests are stored as
- symbolic links to represent relations between files.
- Tags are represented as symlinks to manifest files.
- Instead of storing blobs per namespace, the namespace directories contains symlinks to the blob directory. This way, when two namespaces refers to blobs with the same hash, only one blob file is stored.
- extended attributes to store file metadata.
- The
user.mime_typeextended attribute is used to store the media type of manifests.
- The
As an example, if the image rosvik/container-cubby:latest is created as one manifest which points to two blobs with hashes sha256:abcdef123456 and sha256:123456abcdef, then the following files will be created:
<DATA_DIR>/
├── containers/
│ └── rosvik/
│ └── container-cubby/
│ ├── latest.json [SYMLINK]
│ ├── sha256:<manifest hash>.json
│ ├── sha256:abcdef123456.blob [SYMLINK]
│ └── sha256:123456abcdef.blob [SYMLINK]
└── blobs/
├── 12/
│ └── 3456abcdef.blob
└── ab/
└── cdef123456.blob
Here, latest.json is a symlink to sha256:<manifest hash>.json, and sha256:abcdef123456.blob is a symlink to blobs/ab/cdef123456.blob.
Note
Since symlinks and extended attributes are OS-specific features, Container Cubby is not guaranteed to work on all operating systems. It is periodically tested and expected to work on MacOS, Debian, Ubuntu and Arch Linux. To verify that your OS is supported, run cargo test and check that all tests pass.
Due to the use of symlinks and extended attributes, some caveats apply when you want to move or backup the data directory. For example, the cp command doesn't preserve extended attributes, and the --archive parameter should be used to preserve both symlinks and extended attributes.
cp --archive data/ data-backup/You can read more about this on ArchWiki under Extended Attributes > Preserving extended attributes.
The endpoints as defined by the OCI Distribution Spec, and the project's current progress is as follows:
| ID | Method | API Endpoint | Implemented |
|---|---|---|---|
| end-1 | GET | /v2/ |
✅ |
| end-2 | GET/HEAD | /v2/<name>/blobs/<digest> |
✅ |
| end-3 | GET/HEAD | /v2/<name>/manifests/<reference> |
✅ |
| end-4a | POST | /v2/<name>/blobs/uploads/ |
✅ |
| end-4b | POST | /v2/<name>/blobs/uploads/?digest=<digest> |
✅ |
| end-5 | PATCH | /v2/<name>/blobs/uploads/<reference> |
✅ |
| end-6 | PUT | /v2/<name>/blobs/uploads/<reference>?digest=<digest> |
✅ |
| end-7a | PUT | /v2/<name>/manifests/<reference> |
✅ |
| end-7b | PUT | /v2/<name>/manifests/<digest>?tag=1&tag=2&tag=3 |
✅ |
| end-8a | GET | /v2/<name>/tags/list |
✅ |
| end-8b | GET | /v2/<name>/tags/list?n=<integer>&last=<tagname> |
✅ |
| end-9 | DELETE | /v2/<name>/manifests/<reference> |
✅ |
| end-10 | DELETE | /v2/<name>/blobs/<digest> |
✅ |
| end-11 | POST | /v2/<name>/blobs/uploads/?mount=<digest>&from=<other_name> |
✅ |
| end-12a | GET | /v2/<name>/referrers/<digest> |
❌ |
| end-12b | GET | /v2/<name>/referrers/<digest>?artifactType=<artifactType> |
❌ |
| end-13 | GET | /v2/<name>/blobs/uploads/<reference> |
✅ |
| end-14 | DELETE | /v2/<name>/blobs/uploads/<reference> |
❌ |
The referrers endpoints (end-12a and end-12b) are not implemented, mostly due to there not being an obvious way to support it without slowly reading all manifests per namespace on disk. See this issue for progress on this when/if a solution is being looked into.
This means the registry is not fully conformant with v1.1 of the spec. Conformance with v1.0 should be quite good, but see my fork of the spec conformance test suite for some nitpicks: rosvik/oci-distribution-spec
That being said, there are plenty of details around pulling and pushing images that tools rely on that are not covered by the spec. So as a secondary goal, Container Cubby will try to support Podman, Skopeo, Docker CLI and Containerization.
If you find any issues with these tools or spec compliance, feel free to open an issue!
Contributions are very welcome! If you notice any bugs or have suggestions, please feel free to open an issue or make a PR.