Skip to content

Commit 522d77a

Browse files
Add optional embedding of container images (#239)
## Description <!--- Please describe what this PR is going to change --> This adds the optional capability to embed container images into hook-docker. This helps use cases where images already existing in the DinD cache is needed. Air gap envs, latency constrained/concerned envs, etc. Just FYI, with this change but without embedding any images the final 6.6 kernel initramfs is 171 MB. The v0.9.0 initramfs is 178.9 MB ## Why is this needed <!--- Link to issue you have raised --> Fixes: # ## How Has This Been Tested? <!--- Please describe in detail how you tested your changes. --> <!--- Include details of your testing environment, and the tests you ran to --> <!--- see how your change affects other areas of the code, etc. --> ## How are existing users impacted? What migration steps/scripts do we need? <!--- Fixes a bug, unblocks installation, removes a component of the stack etc --> <!--- Requires a DB migration script, etc. --> ## Checklist: I have: - [ ] updated the documentation and/or roadmap (if required) - [ ] added unit or e2e tests - [ ] provided instructions on how to upgrade
2 parents 526b4a3 + 78f2850 commit 522d77a

File tree

17 files changed

+236
-29
lines changed

17 files changed

+236
-29
lines changed

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,10 @@ cache/
1212
*.swp
1313
.idea
1414
kernel/Dockerfile.autogen.*
15+
images/hook-embedded/images/*
16+
!images/hook-embedded/images/.keep
17+
images/hook-embedded/images.txt
18+
images/hook-embedded/docker/*
19+
!images/hook-embedded/docker/.keep
20+
images/hook-embedded/images_tar/*
21+
!images/hook-embedded/images_tar/.keep

README.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,9 +160,21 @@ The `gha-matrix` CLI command prepares a set of JSON outputs for GitHub Actions m
160160
- `DOCKER_ARCH` is used by the `linuxkit-containers` command to build the containers for the specified architecture.
161161
- `DO_PUSH`: `yes` or `no`, will push the built containers to the OCI registry; defaults to `no`.
162162

163+
### Embedding container images into the DinD (docker-in-docker), also known as [hook-docker](images/hook-docker/), container
164+
165+
For use cases where having container images already available in Docker is needed, the following steps can be taken to embed container images into hook-docker (DinD):
166+
167+
> Note: This is optional and no container images will be embedded by default.
168+
169+
> Note: This will increase the overall size of HookOS. As HookOS is an in memory OS, make sure that the size increase works for the machines you are provisioning.
170+
171+
1. Create a file named `images.txt` in the [images/hook-embedded/](images/hook-embedded/) directory.
172+
1. Populate this `images.txt` file with the list of images to be embedded. See [images/hook-embedded/images.txt.example](images/hook-embedded/images.txt.example) for details on the required file format.
173+
1. Change directories to [images/hook-embedded/](images/hook-embedded/) and run [`pull-images.sh`](images/hook-embedded/pull-images.sh) script when building amd64 images and run [`pull-images.sh arm64`](images/hook-embedded/pull-images.sh) when building arm64 images. Read the comments at the top of the script for more details.
174+
1. Change directories to the root of the HookOS repository and run `sudo ./build.sh build ...` to build the HookOS kernel and ramdisk. FYI, `sudo` is needed as DIND changes file ownerships to root.
175+
163176
### Build system TO-DO list
164177

165-
- [ ] Update to Linuxkit 1.2.0 and new linuxkit pkgs; this might lead into the containerd vs dind;
166178
- [ ] `make debug` functionality (sshd enabled) was lost in the Makefile -> bash transition;
167179

168180
[formats]: https://github.com/linuxkit/linuxkit/blob/master/README.md#booting-and-testing

bash/hook-lk-containers.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ function build_all_hook_linuxkit_containers() {
1313
build_hook_linuxkit_container hook-mdev HOOK_CONTAINER_MDEV_IMAGE
1414
build_hook_linuxkit_container hook-containerd HOOK_CONTAINER_CONTAINERD_IMAGE
1515
build_hook_linuxkit_container hook-runc HOOK_CONTAINER_RUNC_IMAGE
16+
build_hook_linuxkit_container hook-embedded HOOK_CONTAINER_EMBEDDED_IMAGE
1617
}
1718

1819
function build_hook_linuxkit_container() {

bash/linuxkit.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@ function linuxkit_build() {
7070
HOOK_CONTAINER_MDEV_IMAGE="${HOOK_CONTAINER_MDEV_IMAGE}" \
7171
HOOK_CONTAINER_CONTAINERD_IMAGE="${HOOK_CONTAINER_CONTAINERD_IMAGE}" \
7272
HOOK_CONTAINER_RUNC_IMAGE="${HOOK_CONTAINER_RUNC_IMAGE}" \
73-
envsubst '$HOOK_VERSION $HOOK_KERNEL_IMAGE $HOOK_KERNEL_ID $HOOK_KERNEL_VERSION $HOOK_CONTAINER_IP_IMAGE $HOOK_CONTAINER_BOOTKIT_IMAGE $HOOK_CONTAINER_DOCKER_IMAGE $HOOK_CONTAINER_MDEV_IMAGE $HOOK_CONTAINER_CONTAINERD_IMAGE $HOOK_CONTAINER_RUNC_IMAGE' \
73+
HOOK_CONTAINER_EMBEDDED_IMAGE="${HOOK_CONTAINER_EMBEDDED_IMAGE}" \
74+
envsubst '$HOOK_VERSION $HOOK_KERNEL_IMAGE $HOOK_KERNEL_ID $HOOK_KERNEL_VERSION $HOOK_CONTAINER_IP_IMAGE $HOOK_CONTAINER_BOOTKIT_IMAGE $HOOK_CONTAINER_DOCKER_IMAGE $HOOK_CONTAINER_MDEV_IMAGE $HOOK_CONTAINER_CONTAINERD_IMAGE $HOOK_CONTAINER_RUNC_IMAGE $HOOK_CONTAINER_EMBEDDED_IMAGE' \
7475
> "hook.${inventory_id}.yaml"
7576

7677
declare -g linuxkit_bin=""

build.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ declare -g HOOK_LK_CONTAINERS_OCI_BASE="${HOOK_LK_CONTAINERS_OCI_BASE:-"quay.io/
2929
declare -g SKOPEO_IMAGE="${SKOPEO_IMAGE:-"quay.io/skopeo/stable:latest"}"
3030

3131
# See https://github.com/linuxkit/linuxkit/releases
32-
declare -g -r LINUXKIT_VERSION_DEFAULT="1.2.0" # LinuxKit version to use by default; each flavor can set its own too
32+
declare -g -r LINUXKIT_VERSION_DEFAULT="1.5.0" # LinuxKit version to use by default; each flavor can set its own too
3333

3434
# Directory to use for storing downloaded artifacts: LinuxKit binary, shellcheck binary, etc.
3535
declare -g -r CACHE_DIR="${CACHE_DIR:-"cache"}"

images/hook-bootkit/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM golang:1.21-alpine as dev
1+
FROM golang:1.22.6-alpine AS dev
22
COPY . /src/
33
WORKDIR /src
44
RUN go mod download

images/hook-bootkit/go.mod

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
module github.com/tinkerbell/hook/hook-bootkit
22

3-
go 1.17
3+
go 1.22
4+
5+
toolchain go1.22.6
46

57
require (
68
github.com/cenkalti/backoff/v4 v4.3.0

images/hook-bootkit/main.go

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ import (
1515
"time"
1616

1717
"github.com/cenkalti/backoff/v4"
18-
"github.com/docker/docker/api/types"
1918
"github.com/docker/docker/api/types/container"
19+
"github.com/docker/docker/api/types/image"
2020
"github.com/docker/docker/api/types/mount"
2121
"github.com/docker/docker/api/types/registry"
2222
"github.com/docker/docker/client"
@@ -127,13 +127,22 @@ func run(ctx context.Context, log logr.Logger) error {
127127

128128
authStr := base64.URLEncoding.EncodeToString(encodedJSON)
129129

130-
pullOpts := types.ImagePullOptions{
130+
pullOpts := image.PullOptions{
131131
RegistryAuth: authStr,
132132
}
133133
var out io.ReadCloser
134134
imagePullOperation := func() error {
135+
// with embedded images, the tink worker could potentially already exist
136+
// in the local Docker image cache. And the image name could be something
137+
// unreachable via the network (for example: 127.0.0.1/embedded/tink-worker).
138+
// Because of this we check if the image already exists and don't return an
139+
// error if the image does not exist and the pull fails.
140+
var imageExists bool
141+
if _, _, err := cli.ImageInspectWithRaw(ctx, imageName); err == nil {
142+
imageExists = true
143+
}
135144
out, err = cli.ImagePull(ctx, imageName, pullOpts)
136-
if err != nil {
145+
if err != nil && !imageExists {
137146
log.Error(err, "image pull failure", "imageName", imageName)
138147
return err
139148
}
@@ -143,18 +152,20 @@ func run(ctx context.Context, log logr.Logger) error {
143152
return err
144153
}
145154

146-
buf := bufio.NewScanner(out)
147-
for buf.Scan() {
148-
structured := make(map[string]interface{})
149-
if err := json.Unmarshal(buf.Bytes(), &structured); err != nil {
150-
log.Info("image pull logs", "output", buf.Text())
151-
} else {
152-
log.Info("image pull logs", "logs", structured)
153-
}
155+
if out != nil {
156+
buf := bufio.NewScanner(out)
157+
for buf.Scan() {
158+
structured := make(map[string]interface{})
159+
if err := json.Unmarshal(buf.Bytes(), &structured); err != nil {
160+
log.Info("image pull logs", "output", buf.Text())
161+
} else {
162+
log.Info("image pull logs", "logs", structured)
163+
}
154164

155-
}
156-
if err := out.Close(); err != nil {
157-
log.Error(err, "closing image pull logs failed")
165+
}
166+
if err := out.Close(); err != nil {
167+
log.Error(err, "closing image pull logs failed")
168+
}
158169
}
159170

160171
log.Info("Removing any existing tink-worker container")

images/hook-docker/Dockerfile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM golang:1.20-alpine as dev
1+
FROM golang:1.20-alpine AS dev
22
COPY . /src/
33
WORKDIR /src
44
RUN CGO_ENABLED=0 go build -a -ldflags '-s -w -extldflags "-static"' -o /hook-docker
@@ -13,4 +13,5 @@ RUN strip /usr/local/bin/docker /usr/local/bin/dockerd /usr/local/bin/docker-pro
1313
# Purge binutils package after stripping
1414
RUN apk del binutils
1515
COPY --from=dev /hook-docker .
16+
1617
ENTRYPOINT ["/hook-docker"]

images/hook-embedded/Dockerfile

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
FROM scratch
2+
ENTRYPOINT []
3+
WORKDIR /
4+
COPY ./images/ /etc/embedded-images/
5+
# the name 001 is important as that is the order in which the scripts are executed
6+
# we need this mounting to happen before the other init.d scripts run so that
7+
# the mount points are available to them.
8+
COPY ./images-mount.sh /etc/init.d/001-images-mount.sh
9+
CMD []

0 commit comments

Comments
 (0)