Skip to content

temerkhanov/edge-containers

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

21 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ECI Distribution

This repository contains a golang library and CLI for VM images, manage disk images, kernel, initrd and other bootable artifacts in OCI registries. It can build, push and pull those images.

It is inspired directly by ORAS and leverages it, but is opinionated to the ECI use case. As such, it uses elements of OCI Artifacts.

It can store the images in multiple formats:

  • artifacts (default): leverage full artifacts mime types, with each layer a different artifact
  • legacy: standard mime-types and configs, with each layer a different artifact
  • container: artifacts placed within a filesystem in an OCI container image, leveraging annotations to indicate where each artifact is

In all cases, annotations are used as well.

Because the container format uses a standard OCI container image, you can create it using standard docker tools as well. An example is shown below.

Usage

Pushing an ECI

To push an ECI to a registry, you need the following items in a directory:

  • a root disk image in any supported format: raw, vhd, vmdk, iso
  • a Linux kernel (optional)
  • a Linux initrd (optional)
  • additional disks (optional)
  • a config file, whose contents provide the desired OCI manifest config

Note: If you do not provide a config file, a default will be created, using the following information. It can be overridden via options; run with --help to see the options.

  • OS: current platform OS
  • Arch: current platform arch
  • Author: lfedge/edge-containers

You can push the image as follows:

eci push --root path/to/root.img:raw --kernel path/to/kernel --initrd path/to/initrd --disk path/to/disk1:iso --disk path/to/disk2:vmdk ... --config path/to/config lfedge/eci-nginx:ubuntu-1804-11715

The above uses the default artifacts format, which assumes that the registry fully supports Artifacts and will use specialized mime types.

If you wish to use one of the other formats, or do not have a choice as you are using a registry that does not yet support artifacts, select an alternate format with the --format flag.

For the legacy format:

eci push --format legacy --root path/to/root.img:raw --kernel path/to/kernel --initrd path/to/initrd --disk path/to/disk1:iso --disk path/to/disk2:vmdk ... --config path/to/config lfedge/eci-nginx:ubuntu-1804-11715

For the container format:

eci push --format container --root path/to/root.img:raw --kernel path/to/kernel --initrd path/to/initrd --disk path/to/disk1:iso --disk path/to/disk2:vmdk ... --config path/to/config lfedge/eci-nginx:ubuntu-1804-11715

The eci command will take care of setting the correct mime types and annotations on all of the objects.

Note that disks, both root and additional, must have the file name, following by a : and the disk type, so that consumers know how to interpret them, e.g. to send a disk file whose name is mydisk and is of type qcow2:

--disk mydisk:qcow2

Using Standard Docker

Standard docker tools do not support the artifacts or legacy format. However, you can build and push using the container format with standard docker tools. However, docker does not support adding annotations to the manifest, except using experimental tools.

To support standard docker tools, we support reading the annotations from the image labels, which are stored in the config that is generated by docker build.

To use standard docker tools, you need to do two things:

  1. Place the artifacts, such as disks or kernel, in your container image filesystem
  2. Add appropriate labels to the container image

The following Dockerfile is equivalent to the above:

FROM scratch
COPY path/to/root.img /root.img
COPY path/to/kernel /kernel
COPY path/to/initrd /initrd
COPY path/to/disk1 /disk1.iso
COPY path/to/disk2 /disk2.vmdk

Then run:

docker build -t lfedge/eci-nginx:ubuntu-1804-11715 --label "org.lfedge.eci.artifact.root"="/root.img" --label "org.lfedge.eci.artifact.kernel"="/kernel" --label "org.lfedge.eci.artifact.initrd"="/initrd" --label "org.lfedge.eci.artifact.disk-1"="/disk1.iso" --label "org.lfedge.eci.artifact.disk-2"="/disk2.vmdk" .

You can include the labels in the Dockerfile, which makes sense, by adding LABEL commands:

FROM scratch
COPY path/to/root.img /root.img
COPY path/to/kernel /kernel
COPY path/to/initrd /initrd
COPY path/to/disk1 /disk1.iso
COPY path/to/disk2 /disk2.vmdk

LABEL "org.lfedge.eci.artifact.root"="/root.img"
LABEL "org.lfedge.eci.artifact.kernel"="/kernel"
LABEL "org.lfedge.eci.artifact.initrd"="/initrd"
LABEL "org.lfedge.eci.artifact.disk-1"="/disk1.iso"
LABEL "org.lfedge.eci.artifact.disk-2"="/disk2.vmdk"

And then run:

docker build -t lfedge/eci-nginx:ubuntu-1804-11715 .

Note: if you use the container format, your config file needs to be in a specific format for docker to recognize it. This utility builds it for you, and it is recommended you accept the default. However, if you provide --config, you can override it. Use at your own risk.

Pulling an ECI

To pull an ECI, you simply need a registry where the components will be downloaded:

eci pull lf-edge/eci-nginx:ubuntu-1804-11715

The above will default to placing artifacts in the current directory. To place them in a different directory:

eci pull --dir foo/bar/ lf-edge/eci-nginx:ubuntu-1804-11715

The eci command knows how to read the manifest and annotations and determine how to extract the data.

Note that whatever format it is in, it can be pulled "as is" by docker, containerd, go-containerregistry, img or any other tool that knows how to pull OCI images.

Media Types and Annotations

The specific standard media types are at docs/mediatypes.md.

In addition to the types, eci always will add annotations to the layer and config in the manifest describing its purpose.

The specific standard annotations are at docs/annotations.md.

File Names

ECI is highly opinionated about the file names. No matter what names you pass to it, it will give the files particular names. These are listed in docs/filenames.md.

Sample Manifest

A sample manifest for an actual pushed image is below. This is a manifest on docker hub, so the media types are the legacy types, while the annotations provide the purpose.

{
  "schemaVersion": 2,
  "config": {
    "mediaType": "application/vnd.oci.image.config.v1+json",
    "digest": "sha256:ffb3941df4fe37f22165b124d66e966d93b3dbf2765b736818b57a4516aed94e",
    "size": 14,
    "annotations": {
      "org.lfedge.eci.mediaType": "application/vnd.lfedge.eci.config.v1+json",
      "org.opencontainers.image.title": "config.json"
    }
  },
  "layers": [
    {
      "mediaType": "application/vnd.oci.image.layer.v1.tar",
      "digest": "sha256:edeaaff3f1774ad2888673770c6d64097e391bc362d7d6fb34982ddf0efd18cb",
      "size": 4,
      "annotations": {
        "org.lfedge.eci.mediaType": "application/vnd.lfedge.eci.kernel.layer.v1+kernel",
        "org.lfedge.eci.role": "kernel",
        "org.opencontainers.image.title": "kernel"
      }
    },
    {
      "mediaType": "application/vnd.oci.image.layer.v1.tar",
      "digest": "sha256:da1464fd7ceaf38ff56043bc1774af4fb5cb83ef5358981d78de0b8be5a6fbcb",
      "size": 4,
      "annotations": {
        "org.lfedge.eci.mediaType": "application/vnd.lfedge.eci.initrd.layer.v1+cpio",
        "org.lfedge.eci.role": "initrd",
        "org.opencontainers.image.title": "initrd"
      }
    },
    {
      "mediaType": "application/vnd.oci.image.layer.v1.tar",
      "digest": "sha256:deb055d836e44a1dcf0317b0cacac2dbdd36301f82abf787f7849d3f5b916750",
      "size": 5,
      "annotations": {
        "org.lfedge.eci.mediaType": "application/vnd.lfedge.disk.layer.v1+raw",
        "org.lfedge.eci.role": "disk-root",
        "org.opencontainers.image.title": "disk-root-root.raw"
      }
    }
  ]
}

Differentiation Specification

How does the pull client - and anything else that might want to pull the artifacts - know what it has in hand? It could be one of:

  • a normal OCI container image
  • a normal OCI container image with VM artifacts inside
  • a legacy format image from this library/utility
  • an artifacts format image from this library/utility

The parsing process is as follows:

  1. Retrieve the manifest.
  2. If the layers have the special mediaType, it is an ECI in artifacts format.
  3. If the layers have the special annotations, it is an ECI in legacy format.
  4. If the manifest has the special annotations, it is an ECI in container format.
  5. If the config has the special labels, it is an ECI in container format.
  6. It is a regular OCI image.

Go Library

The go library is github.com/lf-edge/edge-containers/pkg/registry. Docs are available at godoc.org/github.com/lf-edge/edge-containers/pkg/registry.

Build

The eci tool can be built via make build, which will deposit the build artifact in dist/bin/eci-<os>-<arch>, e.g. dist/bin/eci-darwin-amd64 or dist/bin/eci-linux-arm64. To build it for alternate OSes or architectures, run:

make build OS=<target> ARCH=<target>

e.g.

make build OS=linux ARCH=amd64
make build OS=linux ARCH=amd64

About

Android has APKs, Docker has OCIs - Edge now has Edge Containers

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Go 92.7%
  • Makefile 7.3%