Message ID | 20210827205430.39745-3-matthew.weber@collins.com |
---|---|
State | Accepted |
Headers | show |
Series | Add support for OCI rootfs images | expand |
On 27/08/2021 22:54, Matthew Weber via buildroot wrote: > From: Sergio Prado <sergio.prado@e-labworks.com> > > Add support to generate OCI (Open Container Initiative) images. > > An OCI image consists of a manifest, an image index (optional), a set of > filesystem layers, and a configuration. The complete specification is > available in the link below: > > https://github.com/opencontainers/image-spec/blob/master/spec.md > > The image is generated with the host tool sloci-image, and config > options can be used to configure image parameters. > > By default, the image is generated in a directory called rootfs-oci: > > $ cd output/images > $ ls rootfs-oci/ > blobs index.json oci-layout > > Optionally, the image can be packed into a tar archive. > > The image can be pushed to a registry using containers tools like > skopeo: > > $ skopeo copy --dest-creds <user>:<pass> oci:rootfs-oci:<tag> \ > docker://<user>/<image>[:tag] > > And then we can pull/run the container image with tools like docker: > > $ docker run -it <user>/<image>[:tag] > > Signed-off-by: Sergio Prado <sergio.prado@e-labworks.com> > Signed-off-by: Matthew Weber <matthew.weber@collins.com> [snip] > + > +config BR2_TARGET_ROOTFS_OCI_ENTRYPOINT > + string "entrypoint" > + default "sh" > + help > + Command to execute when the container starts. > + > +config BR2_TARGET_ROOTFS_OCI_ENTRYPOINT_ARGS > + string "entrypoint arguments" > + help > + Default arguments to the entrypoint of the container. > + > +config BR2_TARGET_ROOTFS_OCI_WORKDIR > + string "working directory" > + help > + Working directory of the entrypoint process in the > + container. > + > +config BR2_TARGET_ROOTFS_OCI_UID > + string "username or UID" > + default "0" > + help > + The username or UID of user the process run as. > + > +config BR2_TARGET_ROOTFS_OCI_ENV_VARS > + string "environment variables" > + help > + Default environment variables for the container. I've added here that variable assignments are space separated. > + > +config BR2_TARGET_ROOTFS_OCI_PORTS > + string "ports" > + help > + Default set of ports to expose from a container running > + this image in the following format: > + > + <port>/tcp, <port>/udp, <port> (same as <port>/tcp). > + > +config BR2_TARGET_ROOTFS_OCI_LABELS > + string "labels" > + help > + Metadata in the format KEY=VALUE for the container compliant > + with OCI annotation rules. If KEY starts with a dot, it will > + be prefixed with "org.opencontainers.image" > + (e.g. .url -> org.opencontainers.image.url). > + > +config BR2_TARGET_ROOTFS_OCI_ARCHIVE > + bool "pack oci image into a tar archive" > + default n default n is not needed. > + help > + Select whether the image should be packed into a TAR archive. > + > +endif > diff --git a/fs/oci/oci.mk b/fs/oci/oci.mk > new file mode 100644 > index 0000000000..09c3e88069 > --- /dev/null > +++ b/fs/oci/oci.mk > @@ -0,0 +1,99 @@ > +################################################################################ > +# > +# Build the oci image > +# > +################################################################################ > + > +ROOTFS_OCI_IMAGE_NAME = rootfs-oci > + > +ROOTFS_OCI_DEPENDENCIES = host-sloci-image > + > +# architecture > +OCI_SLOCI_IMAGE_OPTS = --arch $(BR2_ARCH) That's unlikely to be correct... For example, the typical 32-bit Intel target is i686 in Buildroot, not 386 as expected by OCI. The specification says it has to correspond to GOARCH - and we have that, in GO_GOARCH. So I replaced it with that. Ideally, the Config.in option should also depend on BR2_PACKAGE_HOST_GO_TARGET_ARCH_SUPPORTS. Unfortunately, that symbol includes a dependency on BR2_PACKAGE_HOST_GO_BOOTSTRAP_ARCH_SUPPORTS, which is not needed here. I decided that no sane person would try to build an OCI image for an architecture which doesn't support containers, so I left it as is. > +# architecture variant (typically used only for arm) > +ifeq ($(BR2_ARM_CPU_HAS_ARM),y) > +ifeq ($(BR2_ARM_CPU_ARMV5),y) > +OCI_SLOCI_IMAGE_OPTS += --arch-variant v5 > +else ifeq ($(BR2_ARM_CPU_ARMV6),y) > +OCI_SLOCI_IMAGE_OPTS += --arch-variant v6 > +else ifeq ($(BR2_ARM_CPU_ARMV7A),y) > +OCI_SLOCI_IMAGE_OPTS += --arch-variant v7 > +else ifeq ($(BR2_ARM_CPU_ARMV8A),y) > +OCI_SLOCI_IMAGE_OPTS += --arch-variant v8 Same here, I replaced all that with OCI_SLOCI_IMAGE_OPTS += $(and $(GO_GOARM),--arch-variant $(GO_GOARM)) > +endif > +endif > + > +# entrypoint > +OCI_ENTRYPOINT = $(call qstrip,$(BR2_TARGET_ROOTFS_OCI_ENTRYPOINT)) > +ifneq ($(OCI_ENTRYPOINT),) > +OCI_SLOCI_IMAGE_OPTS += --entrypoint $(OCI_ENTRYPOINT) For consistency, I've added quotes around all options. It's a string so it may contain spaces. > +endif > + > +# entrypoint arguments > +OCI_ENTRYPOINT_ARGS = $(call qstrip,$(BR2_TARGET_ROOTFS_OCI_ENTRYPOINT_ARGS)) > +ifneq ($(OCI_ENTRYPOINT_ARGS),) > +OCI_SLOCI_IMAGE_OPTS += --cmd "$(OCI_ENTRYPOINT_ARGS)" > +endif > + > +# author > +OCI_AUTHOR = $(call qstrip,$(BR2_TARGET_ROOTFS_OCI_AUTHOR)) > +ifneq ($(OCI_AUTHOR),) > +OCI_SLOCI_IMAGE_OPTS += --author "$(OCI_AUTHOR)" > +endif > + > +# username or UID > +OCI_UID = $(call qstrip,$(BR2_TARGET_ROOTFS_OCI_UID)) > +ifneq ($(OCI_UID),) > +OCI_SLOCI_IMAGE_OPTS += --user $(OCI_UID) > +endif > + > +# labels > +OCI_LABELS = $(call qstrip,$(BR2_TARGET_ROOTFS_OCI_LABELS)) > +ifneq ($(OCI_LABELS),) > +OCI_SLOCI_IMAGE_OPTS += \ > + $(foreach label,$(OCI_LABELS),--label $(label)) > +endif > + > +# environment variables > +OCI_ENV_VARS = $(call qstrip,$(BR2_TARGET_ROOTFS_OCI_ENV_VARS)) > +ifneq ($(OCI_ENV_VARS),) > +OCI_SLOCI_IMAGE_OPTS += \ > + $(foreach var,$(OCI_ENV_VARS),--env $(var)) > +endif > + > +# working directory > +OCI_WORKDIR = $(call qstrip,$(BR2_TARGET_ROOTFS_OCI_WORKDIR)) > +ifneq ($(OCI_WORKDIR),) > +OCI_SLOCI_IMAGE_OPTS += --working-dir $(OCI_WORKDIR) > +endif > + > +# ports > +OCI_PORTS = $(call qstrip,$(BR2_TARGET_ROOTFS_OCI_PORTS)) > +ifneq ($(OCI_PORTS),) > +OCI_SLOCI_IMAGE_OPTS += \ > + $(foreach port,$(OCI_PORTS),--port $(port)) > +endif > + > +# tag > +OCI_TAG = $(call qstrip,$(BR2_TARGET_ROOTFS_OCI_TAG)) > +ifeq ($(OCI_TAG),) > +# we need a tag, so if it is empty, it is safe to override here > +# check-package OverriddenVariable > +OCI_TAG = latest > +endif This can also be simplified to OCI_TAG = $(or $(call qstrip,$(BR2_TARGET_ROOTFS_OCI_TAG)),latest) > + > +# enable tar archive > +ifeq ($(BR2_TARGET_ROOTFS_OCI_ARCHIVE),y) > +OCI_SLOCI_IMAGE_OPTS += --tar > +endif > + > +define ROOTFS_OCI_CMD > + (cd $(BINARIES_DIR); \ > + rm -rf $(ROOTFS_OCI_IMAGE_NAME)* > + $(HOST_DIR)/bin/sloci-image $(OCI_SLOCI_IMAGE_OPTS) $(TARGET_DIR) \ > + $(ROOTFS_OCI_IMAGE_NAME):$(OCI_TAG) > + ) The iamge name is just a file name, so the cd is not needed. I just added $(BINARIES_DIR)/ in front and get the same result. I've also removed the ROOTFS_OCI_IMAGE_NAME, it serves no purpose IMHO. And i've removed the wildcard after the rm -rf. Only the directory needs to be removed; if there's a tarball, it will simply be overwritten. Applied to master with all those fixed. Regards, Arnout > +endef > + > +$(eval $(rootfs)) >
>>>>> "Matthew" == Matthew Weber via buildroot <buildroot@busybox.net> writes: > From: Sergio Prado <sergio.prado@e-labworks.com> > Add support to generate OCI (Open Container Initiative) images. > An OCI image consists of a manifest, an image index (optional), a set of > filesystem layers, and a configuration. The complete specification is > available in the link below: Out of interest, what is the functional difference between this and just doing docker import output/build/rootfs.tar <my-tag>?
On 11/09/2021 15:29, Peter Korsgaard wrote: >>>>>> "Matthew" == Matthew Weber via buildroot <buildroot@busybox.net> writes: > > > From: Sergio Prado <sergio.prado@e-labworks.com> > > Add support to generate OCI (Open Container Initiative) images. > > > An OCI image consists of a manifest, an image index (optional), a set of > > filesystem layers, and a configuration. The complete specification is > > available in the link below: > > Out of interest, what is the functional difference between this and just > doing docker import output/build/rootfs.tar <my-tag>? "import" just creates a filesystem. An OCI image also has an entrypoint, an environment, exposed ports, and a bunch of metadata. Regards, Arnout
>>>>> "Arnout" == Arnout Vandecappelle <arnout@mind.be> writes: > On 11/09/2021 15:29, Peter Korsgaard wrote: >>>>>>> "Matthew" == Matthew Weber via buildroot <buildroot@busybox.net> writes: >> >> > From: Sergio Prado <sergio.prado@e-labworks.com> >> > Add support to generate OCI (Open Container Initiative) images. >> >> > An OCI image consists of a manifest, an image index (optional), a set of >> > filesystem layers, and a configuration. The complete specification is >> > available in the link below: >> >> Out of interest, what is the functional difference between this and just >> doing docker import output/build/rootfs.tar <my-tag>? > "import" just creates a filesystem. An OCI image also has an entrypoint, an > environment, exposed ports, and a bunch of metadata. Ok. I guess you can do most if not all of those with the --change option to docker import though: https://docs.docker.com/engine/reference/commandline/import/
diff --git a/fs/Config.in b/fs/Config.in index 37a2aa21f8..eee5e26bb2 100644 --- a/fs/Config.in +++ b/fs/Config.in @@ -11,6 +11,7 @@ source "fs/f2fs/Config.in" source "fs/initramfs/Config.in" source "fs/iso9660/Config.in" source "fs/jffs2/Config.in" +source "fs/oci/Config.in" source "fs/romfs/Config.in" source "fs/squashfs/Config.in" source "fs/tar/Config.in" diff --git a/fs/oci/Config.in b/fs/oci/Config.in new file mode 100644 index 0000000000..dd7112ea8a --- /dev/null +++ b/fs/oci/Config.in @@ -0,0 +1,88 @@ +config BR2_TARGET_ROOTFS_OCI + bool "oci image" + help + Build an OCI (Open Container Initiative) image. + + By default, the image is generated in a directory called + rootfs-oci: + + $ cd output/images + $ ls rootfs-oci/ + blobs index.json oci-layout + + You can push the image to a registry. Example using skopeo: + + $ skopeo copy --dest-creds <user>:<pass> \ + oci:rootfs-oci:<tag> docker://<user>/<image>[:tag] + + And pull/run it with docker: + + $ docker run -it <user>/<image>[:tag] + +if BR2_TARGET_ROOTFS_OCI + +config BR2_TARGET_ROOTFS_OCI_AUTHOR + string "author name and/or email address" + default "Buildroot" + help + Name and/or email address of the person which created the + image. + +config BR2_TARGET_ROOTFS_OCI_TAG + string "image tag" + default "latest" + help + Tag to be used in the container image. If empty, 'latest' will + be used by default. + +config BR2_TARGET_ROOTFS_OCI_ENTRYPOINT + string "entrypoint" + default "sh" + help + Command to execute when the container starts. + +config BR2_TARGET_ROOTFS_OCI_ENTRYPOINT_ARGS + string "entrypoint arguments" + help + Default arguments to the entrypoint of the container. + +config BR2_TARGET_ROOTFS_OCI_WORKDIR + string "working directory" + help + Working directory of the entrypoint process in the + container. + +config BR2_TARGET_ROOTFS_OCI_UID + string "username or UID" + default "0" + help + The username or UID of user the process run as. + +config BR2_TARGET_ROOTFS_OCI_ENV_VARS + string "environment variables" + help + Default environment variables for the container. + +config BR2_TARGET_ROOTFS_OCI_PORTS + string "ports" + help + Default set of ports to expose from a container running + this image in the following format: + + <port>/tcp, <port>/udp, <port> (same as <port>/tcp). + +config BR2_TARGET_ROOTFS_OCI_LABELS + string "labels" + help + Metadata in the format KEY=VALUE for the container compliant + with OCI annotation rules. If KEY starts with a dot, it will + be prefixed with "org.opencontainers.image" + (e.g. .url -> org.opencontainers.image.url). + +config BR2_TARGET_ROOTFS_OCI_ARCHIVE + bool "pack oci image into a tar archive" + default n + help + Select whether the image should be packed into a TAR archive. + +endif diff --git a/fs/oci/oci.mk b/fs/oci/oci.mk new file mode 100644 index 0000000000..09c3e88069 --- /dev/null +++ b/fs/oci/oci.mk @@ -0,0 +1,99 @@ +################################################################################ +# +# Build the oci image +# +################################################################################ + +ROOTFS_OCI_IMAGE_NAME = rootfs-oci + +ROOTFS_OCI_DEPENDENCIES = host-sloci-image + +# architecture +OCI_SLOCI_IMAGE_OPTS = --arch $(BR2_ARCH) + +# architecture variant (typically used only for arm) +ifeq ($(BR2_ARM_CPU_HAS_ARM),y) +ifeq ($(BR2_ARM_CPU_ARMV5),y) +OCI_SLOCI_IMAGE_OPTS += --arch-variant v5 +else ifeq ($(BR2_ARM_CPU_ARMV6),y) +OCI_SLOCI_IMAGE_OPTS += --arch-variant v6 +else ifeq ($(BR2_ARM_CPU_ARMV7A),y) +OCI_SLOCI_IMAGE_OPTS += --arch-variant v7 +else ifeq ($(BR2_ARM_CPU_ARMV8A),y) +OCI_SLOCI_IMAGE_OPTS += --arch-variant v8 +endif +endif + +# entrypoint +OCI_ENTRYPOINT = $(call qstrip,$(BR2_TARGET_ROOTFS_OCI_ENTRYPOINT)) +ifneq ($(OCI_ENTRYPOINT),) +OCI_SLOCI_IMAGE_OPTS += --entrypoint $(OCI_ENTRYPOINT) +endif + +# entrypoint arguments +OCI_ENTRYPOINT_ARGS = $(call qstrip,$(BR2_TARGET_ROOTFS_OCI_ENTRYPOINT_ARGS)) +ifneq ($(OCI_ENTRYPOINT_ARGS),) +OCI_SLOCI_IMAGE_OPTS += --cmd "$(OCI_ENTRYPOINT_ARGS)" +endif + +# author +OCI_AUTHOR = $(call qstrip,$(BR2_TARGET_ROOTFS_OCI_AUTHOR)) +ifneq ($(OCI_AUTHOR),) +OCI_SLOCI_IMAGE_OPTS += --author "$(OCI_AUTHOR)" +endif + +# username or UID +OCI_UID = $(call qstrip,$(BR2_TARGET_ROOTFS_OCI_UID)) +ifneq ($(OCI_UID),) +OCI_SLOCI_IMAGE_OPTS += --user $(OCI_UID) +endif + +# labels +OCI_LABELS = $(call qstrip,$(BR2_TARGET_ROOTFS_OCI_LABELS)) +ifneq ($(OCI_LABELS),) +OCI_SLOCI_IMAGE_OPTS += \ + $(foreach label,$(OCI_LABELS),--label $(label)) +endif + +# environment variables +OCI_ENV_VARS = $(call qstrip,$(BR2_TARGET_ROOTFS_OCI_ENV_VARS)) +ifneq ($(OCI_ENV_VARS),) +OCI_SLOCI_IMAGE_OPTS += \ + $(foreach var,$(OCI_ENV_VARS),--env $(var)) +endif + +# working directory +OCI_WORKDIR = $(call qstrip,$(BR2_TARGET_ROOTFS_OCI_WORKDIR)) +ifneq ($(OCI_WORKDIR),) +OCI_SLOCI_IMAGE_OPTS += --working-dir $(OCI_WORKDIR) +endif + +# ports +OCI_PORTS = $(call qstrip,$(BR2_TARGET_ROOTFS_OCI_PORTS)) +ifneq ($(OCI_PORTS),) +OCI_SLOCI_IMAGE_OPTS += \ + $(foreach port,$(OCI_PORTS),--port $(port)) +endif + +# tag +OCI_TAG = $(call qstrip,$(BR2_TARGET_ROOTFS_OCI_TAG)) +ifeq ($(OCI_TAG),) +# we need a tag, so if it is empty, it is safe to override here +# check-package OverriddenVariable +OCI_TAG = latest +endif + +# enable tar archive +ifeq ($(BR2_TARGET_ROOTFS_OCI_ARCHIVE),y) +OCI_SLOCI_IMAGE_OPTS += --tar +endif + +define ROOTFS_OCI_CMD + (cd $(BINARIES_DIR); \ + rm -rf $(ROOTFS_OCI_IMAGE_NAME)* + $(HOST_DIR)/bin/sloci-image $(OCI_SLOCI_IMAGE_OPTS) $(TARGET_DIR) \ + $(ROOTFS_OCI_IMAGE_NAME):$(OCI_TAG) + ) +endef + +$(eval $(rootfs))