mirror of
https://github.com/home-assistant/operating-system.git
synced 2025-07-24 13:36:31 +00:00
Use skopeo and DIND to download container images (#1561)
* Use skopeo to download container images Separate container download from image build. This will allow to share the downloaded images between multiple builds. We won't store the Supervisor container with the version tag, just with the latest tag. This allows to simplify the procedure a bit. It seems there is no downside to this approach. * Use official Docker in Docker images to build data partition Instead of building our own Debian based image let's use the official Docker in Docker image. This avoids building an image for the hassio data partition and speeds up build as well. This calls mount commands using sudo to mount the data partition as part of the buildroot build now. This is not much different from before as mount has been called as root inside the container, essentially equates to the same "isolation" level. * Use image digest as part of the file name The landing page has no version information in the tag. To avoid potentially source caching issues, use the digest as part of the file name.
This commit is contained in:
parent
693507aaca
commit
762f098c14
@ -46,6 +46,11 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
vim \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
skopeo \
|
||||
jq \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Init entry
|
||||
COPY scripts/entry.sh /usr/sbin/
|
||||
ENTRYPOINT ["/usr/sbin/entry.sh"]
|
||||
|
@ -1,23 +0,0 @@
|
||||
FROM debian:buster
|
||||
|
||||
# Set shell
|
||||
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
|
||||
|
||||
# Docker
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
apt-transport-https \
|
||||
ca-certificates \
|
||||
curl \
|
||||
jq \
|
||||
gpg-agent \
|
||||
gpg \
|
||||
dirmngr \
|
||||
software-properties-common \
|
||||
&& curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add - \
|
||||
&& add-apt-repository "deb https://download.docker.com/linux/debian $(lsb_release -cs) stable" \
|
||||
&& apt-get update && apt-get install -y --no-install-recommends \
|
||||
docker-ce docker-ce-cli containerd.io \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY hostapp.sh /usr/bin/
|
||||
ENTRYPOINT ["/usr/bin/hostapp.sh"]
|
@ -1,104 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
ARCH=
|
||||
MACHINE=
|
||||
DATA_IMG="/export/data.ext4"
|
||||
VERSION_URL="https://version.home-assistant.io/stable.json"
|
||||
APPARMOR_URL="https://version.home-assistant.io/apparmor.txt"
|
||||
|
||||
# Parse
|
||||
while [[ $# -gt 0 ]]; do
|
||||
key=$1
|
||||
case $key in
|
||||
--arch)
|
||||
ARCH=$2
|
||||
shift
|
||||
;;
|
||||
--machine)
|
||||
MACHINE=$2
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
VERSION_JSON="$(curl -s ${VERSION_URL})"
|
||||
|
||||
SUPERVISOR=$(echo "${VERSION_JSON}" | jq -e -r --arg arch "${ARCH}" '.images.supervisor | sub("{arch}"; $arch)')
|
||||
DNS=$(echo "${VERSION_JSON}" | jq -e -r --arg arch "${ARCH}" '.images.dns | sub("{arch}"; $arch)')
|
||||
AUDIO=$(echo "${VERSION_JSON}" | jq -e -r --arg arch "${ARCH}" '.images.audio | sub("{arch}"; $arch)')
|
||||
CLI=$(echo "${VERSION_JSON}" | jq -e -r --arg arch "${ARCH}" '.images.cli | sub("{arch}"; $arch)')
|
||||
MULTICAST=$(echo "${VERSION_JSON}" | jq -e -r --arg arch "${ARCH}" '.images.multicast | sub("{arch}"; $arch)')
|
||||
OBSERVER=$(echo "${VERSION_JSON}" | jq -e -r --arg arch "${ARCH}" '.images.observer | sub("{arch}"; $arch)')
|
||||
LANDINGPAGE=$(echo "${VERSION_JSON}" | jq -e -r --arg machine "${MACHINE}" '.images.core | sub("{machine}"; $machine)'):landingpage
|
||||
|
||||
SUPERVISOR_VERSION=$(echo "${VERSION_JSON}" | jq -e -r '.supervisor')
|
||||
DNS_VERSION=$(echo "${VERSION_JSON}" | jq -e -r '.dns')
|
||||
CLI_VERSION=$(echo "${VERSION_JSON}" | jq -e -r '.cli')
|
||||
AUDIO_VERSION=$(echo "${VERSION_JSON}" | jq -e -r '.audio')
|
||||
MULTICAST_VERSION=$(echo "${VERSION_JSON}" | jq -e -r '.multicast')
|
||||
OBSERVER_VERSION=$(echo "${VERSION_JSON}" | jq -e -r '.observer')
|
||||
|
||||
# Make image
|
||||
truncate --size="1G" "${DATA_IMG}"
|
||||
mkfs.ext4 -L "hassos-data" -E lazy_itable_init=0,lazy_journal_init=0 ${DATA_IMG}
|
||||
|
||||
# Setup local user
|
||||
if [ "${BUILDER_UID:0}" -ne 0 ] && [ "${BUILDER_GID:0}" -ne 0 ]; then
|
||||
groupadd -g "${BUILDER_GID}" builder
|
||||
useradd -m -u "${BUILDER_UID}" -g "${BUILDER_GID}" -G docker builder
|
||||
chown builder:builder ${DATA_IMG}
|
||||
fi
|
||||
|
||||
# Mount / init file structs
|
||||
mkdir -p /mnt/data/
|
||||
mount -o loop ${DATA_IMG} /mnt/data
|
||||
mkdir -p /mnt/data/docker
|
||||
|
||||
# Run dockerd
|
||||
dockerd -s overlay2 -g /mnt/data/docker &
|
||||
DOCKER_PID=$!
|
||||
|
||||
DOCKER_COUNT=0
|
||||
until docker info >/dev/null 2>&1; do
|
||||
if [ ${DOCKER_COUNT} -gt 30 ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
sleep 1
|
||||
DOCKER_COUNT=$((DOCKER_COUNT + 1))
|
||||
done
|
||||
|
||||
# Install supervisor
|
||||
docker pull "${SUPERVISOR}:${SUPERVISOR_VERSION}"
|
||||
|
||||
# Need match with the tag used by OS
|
||||
docker tag "${SUPERVISOR}:${SUPERVISOR_VERSION}" "homeassistant/${ARCH}-hassio-supervisor:latest"
|
||||
|
||||
# Install Plugins
|
||||
docker pull "${CLI}:${CLI_VERSION}"
|
||||
docker pull "${DNS}:${DNS_VERSION}"
|
||||
docker pull "${AUDIO}:${AUDIO_VERSION}"
|
||||
docker pull "${MULTICAST}:${MULTICAST_VERSION}"
|
||||
docker pull "${OBSERVER}:${OBSERVER_VERSION}"
|
||||
|
||||
# Install landing page
|
||||
docker pull "${LANDINGPAGE}"
|
||||
|
||||
# Setup AppArmor
|
||||
mkdir -p "/mnt/data/supervisor/apparmor"
|
||||
curl -sL -o "/mnt/data/supervisor/apparmor/hassio-supervisor" "${APPARMOR_URL}"
|
||||
|
||||
# Finish
|
||||
kill $DOCKER_PID && wait $DOCKER_PID
|
||||
|
||||
# Unmount resource
|
||||
if ! umount /mnt/data; then
|
||||
umount -f /mnt/data || echo "umount force fails!"
|
||||
fi
|
||||
|
||||
exit 0
|
32
buildroot-external/package/hassio/create-data-partition.sh
Executable file
32
buildroot-external/package/hassio/create-data-partition.sh
Executable file
@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
build_dir=$1
|
||||
dst_dir=$2
|
||||
|
||||
data_img="${dst_dir}/data.ext4"
|
||||
|
||||
# Make image
|
||||
rm -f "${data_img}"
|
||||
truncate --size="1280M" "${data_img}"
|
||||
mkfs.ext4 -L "hassos-data" -E lazy_itable_init=0,lazy_journal_init=0 "${data_img}"
|
||||
|
||||
# Mount / init file structs
|
||||
mkdir -p "${build_dir}/data/"
|
||||
sudo mount -o loop,discard "${data_img}" "${build_dir}/data/"
|
||||
|
||||
# Use official Docker in Docker images
|
||||
# Ideally we use the same version as Buildroot is using in case the
|
||||
# overlayfs2 storage format changes
|
||||
container=$(docker run --privileged -e DOCKER_TLS_CERTDIR="" \
|
||||
-v "${build_dir}/data/":/data \
|
||||
-v "${build_dir}/data/docker/":/var/lib/docker \
|
||||
-v "${build_dir}":/build \
|
||||
-d docker:20.10-dind --storage-driver overlay2)
|
||||
|
||||
docker exec "${container}" sh /build/dind-import-containers.sh
|
||||
|
||||
docker stop "${container}"
|
||||
|
||||
# Unmount data image
|
||||
sudo umount "${build_dir}/data/"
|
19
buildroot-external/package/hassio/dind-import-containers.sh
Executable file
19
buildroot-external/package/hassio/dind-import-containers.sh
Executable file
@ -0,0 +1,19 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
APPARMOR_URL="https://version.home-assistant.io/apparmor.txt"
|
||||
|
||||
# Install supervisor
|
||||
for image in /build/images/*.tar; do
|
||||
docker load --input "${image}"
|
||||
done
|
||||
|
||||
# Tag the Supervisor how the OS expects it to be tagged
|
||||
supervisor=$(docker images --filter "label=io.hass.type=supervisor" --quiet)
|
||||
arch=$(docker inspect --format '{{ index .Config.Labels "io.hass.arch" }}' "${supervisor}")
|
||||
docker tag "${supervisor}" "homeassistant/${arch}-hassio-supervisor:latest"
|
||||
|
||||
# Setup AppArmor
|
||||
mkdir -p "/data/supervisor/apparmor"
|
||||
wget -O "/data/supervisor/apparmor/hassio-supervisor" "${APPARMOR_URL}"
|
||||
|
38
buildroot-external/package/hassio/fetch-container-image.sh
Executable file
38
buildroot-external/package/hassio/fetch-container-image.sh
Executable file
@ -0,0 +1,38 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
arch=$1
|
||||
machine=$2
|
||||
version_json=$3
|
||||
image_json_name=$4
|
||||
dl_dir=$5
|
||||
dst_dir=$6
|
||||
|
||||
set -e
|
||||
|
||||
image_name=$(jq -e -r --arg image_json_name "${image_json_name}" \
|
||||
--arg arch "${arch}" --arg machine "${machine}" \
|
||||
'.images[$image_json_name] | sub("{arch}"; $arch) | sub("{machine}"; $machine)' \
|
||||
< "${version_json}")
|
||||
image_tag=$(jq -e -r --arg image_json_name "${image_json_name}" \
|
||||
'.[$image_json_name]' < "${version_json}")
|
||||
full_image_name="${image_name}:${image_tag}"
|
||||
|
||||
image_digest=$(skopeo inspect "docker://${full_image_name}" | jq -r '.Digest')
|
||||
|
||||
# Cleanup image name file name use
|
||||
image_file_name="${full_image_name//[:\/]/_}@${image_digest//[:\/]/_}"
|
||||
image_file_path="${dl_dir}/${image_file_name}.tar"
|
||||
dst_image_file_path="${dst_dir}/${image_file_name}.tar"
|
||||
|
||||
if [ -f "${image_file_path}" ]
|
||||
then
|
||||
echo "Skipping download of existing image: ${full_image_name} (digest ${image_digest})"
|
||||
cp "${image_file_path}" "${dst_image_file_path}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Use digest here to avoid race conditions of any sort...
|
||||
echo "Fetching image: ${full_image_name}"
|
||||
skopeo copy "docker://${image_name}@${image_digest}" "docker-archive:${image_file_path}:${full_image_name}"
|
||||
|
||||
cp "${image_file_path}" "${dst_image_file_path}"
|
@ -9,18 +9,27 @@ HASSIO_LICENSE = Apache License 2.0
|
||||
HASSIO_LICENSE_FILES = $(BR2_EXTERNAL_HASSOS_PATH)/../LICENSE
|
||||
HASSIO_SITE = $(BR2_EXTERNAL_HASSOS_PATH)/package/hassio
|
||||
HASSIO_SITE_METHOD = local
|
||||
HASSIO_VERSION_URL = "https://version.home-assistant.io/stable.json"
|
||||
|
||||
HASSIO_CONTAINER_IMAGES_ARCH = supervisor dns audio cli multicast observer core
|
||||
|
||||
define HASSIO_CONFIGURE_CMDS
|
||||
# Deploy only landing page for "core" by setting version to "landingpage"
|
||||
curl -s $(HASSIO_VERSION_URL) | jq '.core = "landingpage"' > $(@D)/stable.json
|
||||
|
||||
$(Q)mkdir -p $(@D)/images
|
||||
$(Q)mkdir -p $(HASSIO_DL_DIR)
|
||||
$(foreach image,$(HASSIO_CONTAINER_IMAGES_ARCH),\
|
||||
$(BR2_EXTERNAL_HASSOS_PATH)/package/hassio/fetch-container-image.sh \
|
||||
$(BR2_PACKAGE_HASSIO_ARCH) $(BR2_PACKAGE_HASSIO_MACHINE) $(@D)/stable.json $(image) "$(HASSIO_DL_DIR)" "$(@D)/images"
|
||||
)
|
||||
|
||||
define HASSIO_BUILD_CMDS
|
||||
docker build --tag hassos-hostapps $(@D)/builder
|
||||
endef
|
||||
|
||||
define HASSIO_INSTALL_TARGET_CMDS
|
||||
docker run --rm --privileged \
|
||||
-e BUILDER_UID="$(shell id -u)" -e BUILDER_GID="$(shell id -g)" \
|
||||
-v $(BINARIES_DIR):/export \
|
||||
hassos-hostapps \
|
||||
--arch $(BR2_PACKAGE_HASSIO_ARCH) \
|
||||
--machine $(BR2_PACKAGE_HASSIO_MACHINE)
|
||||
HASSIO_INSTALL_IMAGES = YES
|
||||
|
||||
define HASSIO_INSTALL_IMAGES_CMDS
|
||||
$(BR2_EXTERNAL_HASSOS_PATH)/package/hassio/create-data-partition.sh "$(@D)" "$(BINARIES_DIR)"
|
||||
endef
|
||||
|
||||
$(eval $(generic-package))
|
||||
|
@ -15,7 +15,7 @@ BOOTSTATE_SIZE=8M
|
||||
SYSTEM_SIZE=256M
|
||||
KERNEL_SIZE=24M
|
||||
OVERLAY_SIZE=96M
|
||||
DATA_SIZE=1G
|
||||
DATA_SIZE=1280M
|
||||
|
||||
|
||||
function size2sectors() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user