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:
parent
b6629de7b2
commit
46a228df38
5 changed files with 427 additions and 0 deletions
107
stages/org.osbuild.skopeo
Executable file
107
stages/org.osbuild.skopeo
Executable 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)
|
||||
Loading…
Add table
Add a link
Reference in a new issue