mirror of
https://github.com/kernelkit/infix.git
synced 2026-07-29 20:23:01 +02:00
container: optimize startup of preexisting containers
This commit adds metadata to track loaded OCI archives to allow skipping 'delete + load' of OCI images when restarting either the container or the system as a whole. The sha256 of all loaded OCI archives is stored in a sidecar file in our downloads directory. Then we verify the checksum of the OCI archives against their same-named sidecar to determine if the OCI archive is already loaded or not. Additionally, the instance using the image is labled with metadata to detect changes in the container configuration. This in turn allow skipping the delete + create phase also of the instance. Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
@@ -230,6 +230,18 @@ load_archive()
|
||||
err 1 "failed tagging image as $tag"
|
||||
fi
|
||||
|
||||
# Save archive SHA256 to sidecar file for local archives to enable optimization
|
||||
if [ -f "$file" ]; then
|
||||
img_sha256=$(sha256sum "$file" | cut -f1 -d' ')
|
||||
archive_basename=$(basename "$file")
|
||||
sha_file="$DOWNLOADS/${archive_basename}.sha256"
|
||||
|
||||
mkdir -p "$DOWNLOADS"
|
||||
|
||||
echo "$img_sha256" > "$sha_file"
|
||||
log "Saved archive checksum to $sha_file"
|
||||
fi
|
||||
|
||||
# Clean up after ourselves
|
||||
if [ -n "$extracted" ]; then
|
||||
log "Cleaning up extracted $dir"
|
||||
@@ -295,6 +307,20 @@ create()
|
||||
args="$args --network=none"
|
||||
fi
|
||||
|
||||
# Add optimization labels for meta-sha256 and config checksum
|
||||
script="/run/containers/${name}.sh"
|
||||
if [ -f "$script" ]; then
|
||||
# Extract meta-sha256 from script if present
|
||||
meta_sha=$(awk '/^# meta-sha256:/ {print $3}' "$script" 2>/dev/null)
|
||||
if [ -n "$meta_sha" ]; then
|
||||
args="$args --label meta-sha256=$meta_sha"
|
||||
fi
|
||||
|
||||
# Add config checksum label
|
||||
config_sha=$(sha256sum "$script" | cut -f1 -d' ')
|
||||
args="$args --label config-sha256=$config_sha"
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC2048
|
||||
log "podman create --name $name --conmon-pidfile=$pidfile $args $image $*"
|
||||
if podman create --name "$name" --conmon-pidfile="$pidfile" $args "$image" $*; then
|
||||
@@ -785,6 +811,78 @@ case $cmd in
|
||||
script=/run/containers/${name}.sh
|
||||
[ -x "$script" ] || err 1 "setup: $script does not exist or is not executable."
|
||||
|
||||
# Early exit optimization: check if container is already up-to-date
|
||||
meta_sha=$(awk '/^# meta-sha256:/ {print $3}' "$script" 2>/dev/null)
|
||||
if [ -n "$meta_sha" ]; then
|
||||
# Local image optimization: check if archive SHA matches stored sidecar file
|
||||
# Extract the image path from the script
|
||||
img=$(awk '/^# meta-image:/ {print $3}' "$script" 2>/dev/null)
|
||||
if [ -n "$img" ]; then
|
||||
# Determine the archive file path
|
||||
case "$img" in
|
||||
oci-archive:*)
|
||||
archive_path="${img#oci-archive:}"
|
||||
;;
|
||||
*)
|
||||
archive_path="$img"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Handle relative paths - check BUILTIN and DOWNLOADS
|
||||
if [ ! -e "$archive_path" ]; then
|
||||
if [ -e "$DOWNLOADS/$(basename "$archive_path")" ]; then
|
||||
archive_path="$DOWNLOADS/$(basename "$archive_path")"
|
||||
elif [ -e "$BUILTIN/$(basename "$archive_path")" ]; then
|
||||
archive_path="$BUILTIN/$(basename "$archive_path")"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check if the archive exists and compare SHA with sidecar file
|
||||
if [ -f "$archive_path" ]; then
|
||||
archive_basename=$(basename "$archive_path")
|
||||
sha_file="$DOWNLOADS/${archive_basename}.sha256"
|
||||
|
||||
# Check if sidecar file exists
|
||||
if [ -f "$sha_file" ]; then
|
||||
stored_sha=$(cat "$sha_file" 2>/dev/null)
|
||||
current_sha=$(sha256sum "$archive_path" | cut -f1 -d' ')
|
||||
|
||||
# If SHA matches, check container instance
|
||||
if [ "$stored_sha" = "$current_sha" ]; then
|
||||
if podman container exists "$name"; then
|
||||
# Check if container has matching labels
|
||||
config_sha=$(sha256sum "$script" | cut -f1 -d' ')
|
||||
container_meta=$(podman inspect "$name" --format '{{index .Config.Labels "meta-sha256"}}' 2>/dev/null)
|
||||
container_config=$(podman inspect "$name" --format '{{index .Config.Labels "config-sha256"}}' 2>/dev/null)
|
||||
|
||||
if [ "$container_meta" = "$meta_sha" ] && [ "$container_config" = "$config_sha" ]; then
|
||||
log "Container $name is up-to-date (archive and config unchanged), skipping setup"
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
else
|
||||
# Archive changed (e.g., rootfs upgrade) - need to reload
|
||||
log "Archive SHA changed, will reload image and recreate container"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
else
|
||||
# Remote image optimization: check config-sha256 only
|
||||
if podman container exists "$name"; then
|
||||
# Get current config checksum from script
|
||||
config_sha=$(sha256sum "$script" | cut -f1 -d' ')
|
||||
|
||||
# Get container's stored config checksum
|
||||
container_config=$(podman inspect "$name" --format '{{index .Config.Labels "config-sha256"}}' 2>/dev/null)
|
||||
|
||||
if [ -n "$container_config" ] && [ "$container_config" = "$config_sha" ]; then
|
||||
log "Container $name config unchanged, skipping setup"
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Save our PID in case we get stuck here and someone wants to
|
||||
# stop us, e.g., due to reconfiguration or reboot.
|
||||
pidfile=$(pidfn "${name}")
|
||||
|
||||
@@ -22,6 +22,30 @@
|
||||
|
||||
#define _PATH_CONT "/run/containers"
|
||||
|
||||
/*
|
||||
* Check if image is a local archive and return the offset to the file path.
|
||||
* Returns 0 if not a recognized local archive format.
|
||||
*/
|
||||
static int archive_offset(const char *image)
|
||||
{
|
||||
static const struct {
|
||||
const char *prefix;
|
||||
int offset;
|
||||
} prefixes[] = {
|
||||
{ "docker-archive:", 15 },
|
||||
{ "oci-archive:", 12 },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
int i;
|
||||
|
||||
for (i = 0; prefixes[i].prefix; i++) {
|
||||
if (!strncmp(image, prefixes[i].prefix, prefixes[i].offset))
|
||||
return prefixes[i].offset;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a setup/create/upgrade script and instantiate a new instance
|
||||
* that Finit will start when all networking and other dependencies are
|
||||
@@ -37,6 +61,7 @@ static int add(const char *name, struct lyd_node *cif)
|
||||
struct lyd_node *node, *nets, *caps;
|
||||
char script[strlen(name) + 5];
|
||||
FILE *fp, *ap;
|
||||
int offset;
|
||||
|
||||
snprintf(script, sizeof(script), "%s.sh", name);
|
||||
fp = fopenf("w", "%s/%s", _PATH_CONT, script);
|
||||
@@ -58,9 +83,26 @@ static int add(const char *name, struct lyd_node *cif)
|
||||
image = lydx_get_cattr(cif, "image");
|
||||
fprintf(fp, "#!/bin/sh\n"
|
||||
"# meta-name: %s\n"
|
||||
"# meta-image: %s\n"
|
||||
"container --quiet delete %s >/dev/null\n"
|
||||
"container --quiet", name, image, name);
|
||||
"# meta-image: %s\n", name, image);
|
||||
|
||||
offset = archive_offset(image);
|
||||
if (offset) {
|
||||
const char *path = image + offset;
|
||||
char sha256[65] = { 0 };
|
||||
FILE *pp;
|
||||
|
||||
pp = popenf("r", "sha256sum %s | cut -f1 -d' '", path);
|
||||
if (pp) {
|
||||
if (fgets(sha256, sizeof(sha256), pp)) {
|
||||
chomp(sha256);
|
||||
fprintf(fp, "# meta-sha256: %s\n", sha256);
|
||||
}
|
||||
pclose(pp);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(fp, "container --quiet delete %s >/dev/null\n"
|
||||
"container --quiet", name);
|
||||
|
||||
LYX_LIST_FOR_EACH(lyd_child(cif), node, "dns")
|
||||
fprintf(fp, " --dns %s", lyd_get_value(node));
|
||||
|
||||
Reference in New Issue
Block a user