Add support for installing containers in images

This adds a stage called org.osbuild.skopeo that installs docker and
oci archive files into the container storage of the tree being
constructed.

The source can either be a file from another pipeline, for example one
created with the existing org.osbuild.oci-archive stage, or it can
be using the new org.osbuild.skopeo source and org.osbuild.containers
input, which will download an image from a registry and install that.

There is an optional option in the install stage that lets you
configure a custom storage location, which allows the use of the
additionalimagestores option in the container storage.conf
to use a read-only image stores (instead of /var/lib/container).

Note: skopeo fails to start if /etc/containers/policy.json is
not available, so we bind mount it from the build tree to the
buildroot if available.
This commit is contained in:
Alexander Larsson 2022-01-26 10:33:38 +01:00 committed by Christian Kellner
parent b6629de7b2
commit 46a228df38
5 changed files with 427 additions and 0 deletions

107
stages/org.osbuild.skopeo Executable file
View file

@ -0,0 +1,107 @@
#!/usr/bin/python3
"""
Install an container image into the container store.
This supports both oci archives and docker archives, and uses the containers
input (reading from a skopeo source or a file in a pipeline).
Buildhost commands used: `skopeo`.
"""
import os
import subprocess
import sys
import tempfile
import osbuild.api
SCHEMA_2 = r"""
"inputs": {
"type": "object",
"additionalProperties": false,
"required": ["images"],
"properties": {
"images": {
"type": "object",
"additionalProperties": true
}
}
},
"options": {
"additionalProperties": false,
"required": ["destination"],
"properties": {
"destination": {
"type": "object",
"additionalProperties": false,
"required": ["type"],
"properties": {
"type": {
"enum": ["containers-storage"]
},
"storage-path": {
"description": "Container storage location (default /var/lib/containers/storage).",
"type": "string"
},
"storage-driver": {
"description": "The container storage driver to use (default overlay).",
"type": "string"
}
}
}
}
}
"""
def parse_input(inputs):
images = inputs["images"]
archives = images["data"]["archives"]
res = []
for filename, data in archives.items():
filepath = os.path.join(images["path"], filename)
res.append((filepath, data))
return res
def main(inputs, output, options):
files = parse_input(inputs)
destination = options["destination"]
# The destination type is always containers-storage atm, so ignore "type"
storage_root = destination.get("storage-path", "/var/lib/containers/storage")
storage_driver = destination.get("storage-driver", "overlay")
for source, source_data in files:
container_format = source_data["format"]
image_name = source_data["name"]
# We can't have special characters like ":" in the source names because containers/image
# treats them special, like e.g. /some/path:tag, so we make a symlink to the real name
# and pass the symlink name to skopeo to make it work with anything
with tempfile.TemporaryDirectory() as tmpdir:
linkname = os.path.join(tmpdir, "image.tar")
os.symlink(source, linkname)
if container_format == "docker-archive":
source = f"docker-archive:{linkname}"
elif container_format == "oci-archive":
source = f"oci-archive:{linkname}"
else:
raise RuntimeError(f"Unknown container format {container_format}")
dest = f"containers-storage:[{storage_driver}@{output}{storage_root}+/run/containers/storage]{image_name}"
subprocess.run(["skopeo", "copy", source, dest],
check=True)
return 0
if __name__ == '__main__':
args = osbuild.api.arguments()
r = main(args["inputs"], args["tree"], args["options"])
sys.exit(r)