Skip to content

Commit

Permalink
docker-import and docker-export
Browse files Browse the repository at this point in the history
Signed-off-by: Flynn <[email protected]>
  • Loading branch information
Flynn authored and kflynn committed Jul 8, 2022
1 parent f10470c commit 48208a9
Show file tree
Hide file tree
Showing 4 changed files with 242 additions and 19 deletions.
2 changes: 2 additions & 0 deletions build-aux/tools.mk
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ go-mod-tidy/tools/%:
#
tools/copy-ifchanged = $(tools.bindir)/copy-ifchanged
tools/devversion = $(tools.bindir)/devversion
tools/docker-import = $(tools.bindir)/docker-import
tools/docker-promote = $(tools.bindir)/docker-promote
tools/move-ifchanged = $(tools.bindir)/move-ifchanged
tools/tap-driver = $(tools.bindir)/tap-driver
Expand Down Expand Up @@ -77,6 +78,7 @@ $(tools.main-gomod): $(tools.bindir)/%: $(tools.srcdir)/%/pin.go $(OSS_HOME)/go.
# Local Go sources
# ================
#
tools/docker-export = $(tools.bindir)/docker-export
tools/dsum = $(tools.bindir)/dsum
tools/filter-yaml = $(tools.bindir)/filter-yaml
tools/fix-crds = $(tools.bindir)/fix-crds
Expand Down
36 changes: 17 additions & 19 deletions builder/builder.mk
Original file line number Diff line number Diff line change
Expand Up @@ -308,30 +308,28 @@ push-dev: docker/$(LCNAME).docker.tag.local
docker push '$(DEV_REGISTRY)/$(LCNAME):$(patsubst v%,%,$(VERSION))'
.PHONY: push-dev

export-docker: docker/$(LCNAME).docker.tag.local
docker-export: images $(tools/docker-export)
@if [ -z "$$VERSION_FILE" ]; then printf '$(RED)$@: VERSION_FILE is not set$(END)\n'; exit 1; fi;
@if [ -z "$$EXPORT_FILE" ]; then printf '$(RED)$@: EXPORT_FILE is not set$(END)\n'; exit 1; fi;
@printf '$(CYN)==> $(GRN)exporting $(BLU)%s$(GRN) as $(BLU)%s$(GRN)...$(END)\n' '$(LCNAME)' "$$EXPORT_FILE"
docker save $$(cat docker/$(LCNAME).docker) -o "$$EXPORT_FILE"
.PHONY: export-docker
@printf '$(CYN)==> $(GRN)exporting Docker build state as $(BLU)%s$(GRN)...$(END)\n' "$$EXPORT_FILE"
$(tools/docker-export)
@set -ex -o pipefail ; { \
cd docker ;\
echo "$(VERSION)" > "$$VERSION_FILE" ;\
tar cf "$$EXPORT_FILE" images.tar images.sh ;\
}
.PHONY: docker-export

import-docker:
docker-import: $(tools/docker-import)
@if [ -z "$$IMPORT_FILE" ]; then printf '$(RED)$@: IMPORT_FILE is not set$(END)\n'; exit 1; fi;
@{ set -e ; \
# repotags=$$(bsdtar -xzO -f "$$IMPORT_FILE" manifest.json | jq '.[0].RepoTags[0]') ;\
hash=$$(bsdtar -xzO -f "$$IMPORT_FILE" manifest.json | jq '.[0].Config' | tr -d '"' | sed -e 's/\.json$$//') ;\
test -n "$$hash" ;\
imgid="sha256:$$hash" ;\
imgtag="$(BUILDER_NAME).local/$(LCNAME)" ;\
@set -ex -o pipefail ; { \
printf '$(CYN)==> $(GRN)importing $(BLU)%s$(GRN) as $(BLU)%s$(GRN)...$(END)\n' "$$IMPORT_FILE" "$$imgid" ;\
docker load -i "$$IMPORT_FILE" ;\
printf '$(CYN)==> $(GRN)tagging as $(BLU)%s$(GRN)...$(END)\n' "$$imgtag" ;\
docker tag "$$imgid" "$$imgtag" ;\
printf '$(CYN)==> $(GRN)stamping $(BLU)%s$(GRN)...$(END)\n' "$$imgtag" ;\
echo "$$imgid" > docker/$(LCNAME).docker ;\
( echo "$$imgid" ; echo "$$imgtag" ) > docker/$(LCNAME).docker.tag.local ;\
cp docker/$(LCNAME).docker docker/.$(LCNAME).docker.stamp ;\
cd docker ;\
tar xf "$$IMPORT_FILE" ;\
$(tools/docker-import) ;\
rm -f images.sh images.tar ;\
}
.PHONY: import-docker
.PHONY: docker-import

export KUBECONFIG_ERR=$(RED)ERROR: please set the $(BLU)DEV_KUBECONFIG$(RED) make/env variable to the cluster\n you would like to use for development. Note this cluster must have access\n to $(BLU)DEV_REGISTRY$(RED) (currently $(BLD)$(DEV_REGISTRY)$(END)$(RED))$(END)
export KUBECTL_ERR=$(RED)ERROR: preflight kubectl check failed$(END)
Expand Down
150 changes: 150 additions & 0 deletions tools/src/docker-export/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
package main

import (
"encoding/json"
"fmt"
"io"
"os"
"os/exec"
"path/filepath"
"sort"
"strings"
)

type DockerInspect struct {
Id string
RepoTags []string
RepoDigests []string
}

func sort_u(in []string) []string {
set := make(map[string]struct{}, len(in))
for _, item := range in {
set[item] = struct{}{}
}
out := make([]string, 0, len(set))
for item := range set {
out = append(out, item)
}
sort.Strings(out)
return out
}

func Main() error {
// 1. Get the "docker inspect" for all images
bs, err := exec.Command("docker", "image", "ls", "--filter=dangling=false", "--format={{ .ID }}").Output()
if err != nil {
return err
}
ids := sort_u(strings.Split(strings.TrimSpace(string(bs)), "\n"))
bs, err = exec.Command("docker", append([]string{"image", "inspect"}, ids...)...).Output()
if err != nil {
return err
}
var infos []DockerInspect
if err := json.Unmarshal(bs, &infos); err != nil {
return err
}

// 2. Decide what to do with each image
workspacePull := make(map[string]struct{}) // pull these images from remote registries...
workspaceTag := make(map[string]string) // ... then tag them with these names
workspaceLoad := make(map[string]struct{}) // store these images locally with 'docker image save'/'docker image load'

for _, info := range infos {
b, _ := json.Marshal(info)
fmt.Printf("- check %s: %s\n", info.Id, b)
if len(info.RepoDigests) > 0 {
repoDigest := info.RepoDigests[0]
fmt.Printf(" - pull %s\n", repoDigest)
workspacePull[repoDigest] = struct{}{}
for _, tag := range info.RepoTags {
fmt.Printf(" - tag %s\n", tag)
workspaceTag[tag] = info.Id
}
} else {
for _, tag := range info.RepoTags {
fmt.Printf(" - load %s\n", tag)
workspaceLoad[tag] = struct{}{}
}
}
}

// 3. Record and do those things

// Write the pull/tag steps to a file
err = func() error {
var lines []string
for pull := range workspacePull {
lines = append(lines, fmt.Sprintf("docker image pull %s\n", pull))
}
for tag, id := range workspaceTag {
lines = append(lines, fmt.Sprintf("docker image tag %s %s\n", id, tag))
}
sort.Strings(lines) // NB: relying on "pull" sorting before "tag"

lines = append([]string{
"#!/usr/bin/env bash\n",
"set -ex\n",
}, lines...)

restoreSh, err := os.OpenFile("docker/images.sh", os.O_CREATE|os.O_WRONLY, 0777)
if err != nil {
return err
}
defer restoreSh.Close()
for _, line := range lines {
if _, err := io.WriteString(restoreSh, line); err != nil {
return err
}
}

return nil
}()
if err != nil {
return err
}

// Run 'docker image save'
err = func() error {
localImages := make([]string, 0, len(workspaceLoad))
for image := range workspaceLoad {
fmt.Printf("- save %s\n", image)
localImages = append(localImages, image)
}
sort.Strings(localImages)

fmt.Printf("local images:\n")
for _, image := range localImages {
fmt.Printf("- %s\n", image)
}

restoreTar, err := os.OpenFile("docker/images.tar", os.O_CREATE|os.O_WRONLY, 0666)
if err != nil {
return err
}
defer restoreTar.Close()

cmd := exec.Command("docker", append([]string{"image", "save"}, localImages...)...)
cmd.Stdout = restoreTar
cmd.Stderr = os.Stderr

if err := cmd.Run(); err != nil {
return err
}

return nil
}()
if err != nil {
return err
}

return nil
}

func main() {
if err := Main(); err != nil {
fmt.Fprintf(os.Stderr, "%s: error: %v\n", filepath.Base(os.Args[0]), err)
os.Exit(1)
}
}
73 changes: 73 additions & 0 deletions tools/src/docker-import.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#!/usr/bin/env bash
set -ex

# Load the images
docker image load < docker/images.tar
./docker/images.sh

stamp_docker () {
tag="$1"
stamp_base="$2"

hash=$(docker image inspect --format='{{ .Id }}' "$tag")

for stamp_file in ".$stamp_base.docker.stamp" "$stamp_base.docker" "$stamp_base.docker.tag.local"; do
echo "Stamping $tag as docker/$stamp_file"
echo "$hash" > "docker/$stamp_file"
# sleep 1
done

tag_file="docker/$stamp_base.docker.tag.local"
echo "Adding tag to $tag_file"
echo "$tag" >> "$tag_file"
}

stamp_image () {
tag="$1"
stamp_base="$2"

hash=$(docker image inspect --format='{{ .Id }}' "$tag")

for tarfile in "docker/$stamp_base.img.tar" "docker/.$stamp_base.img.tar.stamp"; do
echo "Copying $tag to $tarfile"
docker save "$tag" > "$tarfile"
done
}

# ORDER MATTERS HERE
stamp_image frolvlad/alpine-glibc:alpine-3.15 base # This MUST be frolvlad, not emissary.local/base
stamp_image emissary.local/kat-client kat-client
stamp_image emissary.local/kat-server kat-server

stamp_docker emissary.local/base-envoy base-envoy
stamp_docker emissary.local/base-python base-python
stamp_docker emissary.local/base-pip base-pip
stamp_docker emissary.local/base base
stamp_docker emissary.local/emissary emissary
stamp_docker emissary.local/kat-client kat-client
stamp_docker emissary.local/kat-server kat-server

# # Resume the build container
# if [[ -z "$DEV_REGISTRY" ]]; then
# export DEV_REGISTRY=127.0.0.1:31000
# export BASE_REGISTRY=docker.io/datawiredev
# fi
# rm -f docker/container.txt docker/container.txt.stamp
# make docker/container.txt
# docker run \
# --rm \
# --volume=/var/run/docker.sock:/var/run/docker.sock \
# --user=root \
# --entrypoint=rsync $(cat docker/snapshot.docker) \
# -a -xx --exclude=/etc/{resolv.conf,hostname,hosts} --delete \
# --blocking-io -e 'docker exec -i --user=root' / "$(cat docker/container.txt):/"
# docker exec "$(cat docker/container.txt)" rm -f /buildroot/image.dirty
# # Load the cache volume
# docker run \
# --rm \
# --volumes-from=$(cat docker/container.txt) \
# --volume="$PWD/docker":/mnt \
# --user=root \
# --workdir=/home/dw \
# --entrypoint=tar $(cat docker/snapshot.docker) -xf /mnt/volume.tar
# rm -f docker/volume.tar

0 comments on commit 48208a9

Please sign in to comment.