From d1452385cca6574e0f0bfa8c120e39bef89f2852 Mon Sep 17 00:00:00 2001 From: Avi Deitcher Date: Tue, 6 Dec 2022 16:57:04 +0100 Subject: [PATCH] unify apk installed db for base layer (#3879) --- src/cmd/linuxkit/moby/apk_tarwriter.go | 86 ++++++++++++++++++++++++++ src/cmd/linuxkit/moby/build.go | 6 +- 2 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 src/cmd/linuxkit/moby/apk_tarwriter.go diff --git a/src/cmd/linuxkit/moby/apk_tarwriter.go b/src/cmd/linuxkit/moby/apk_tarwriter.go new file mode 100644 index 000000000..45691fae5 --- /dev/null +++ b/src/cmd/linuxkit/moby/apk_tarwriter.go @@ -0,0 +1,86 @@ +package moby + +import ( + "archive/tar" + "bytes" +) + +// apkTarWriter apk-aware tar writer that consolidates installed database, so that +// it can be called multiple times and will do the union of all such databases, +// rather than overwriting the previous one. +const apkInstalledPath = "lib/apk/db/installed" + +type apkTarWriter struct { + *tar.Writer + dbs [][]byte + current *bytes.Buffer +} + +func newAPKTarWriter(w *tar.Writer) *apkTarWriter { + return &apkTarWriter{ + Writer: w, + } +} + +func (a *apkTarWriter) WriteHeader(hdr *tar.Header) error { + if a.current != nil { + a.dbs = append(a.dbs, a.current.Bytes()) + a.current = nil + } + if hdr.Name == apkInstalledPath { + a.current = new(bytes.Buffer) + } + return a.Writer.WriteHeader(hdr) +} +func (a *apkTarWriter) Write(b []byte) (int, error) { + if a.current != nil { + a.current.Write(b) + } + return a.Writer.Write(b) +} + +func (a *apkTarWriter) Close() error { + // before closing, write out the union of all the databases + if a.current != nil { + a.dbs = append(a.dbs, a.current.Bytes()) + a.current = nil + } + if err := a.WriteAPKDB(); err != nil { + return err + } + return a.Writer.Close() +} + +func (a *apkTarWriter) WriteAPKDB() error { + if len(a.dbs) > 1 { + // consolidate the databases + // calculate the size of the new database + var size int + for _, db := range a.dbs { + size += len(db) + size += 2 // 2 trailing newlines for each db + } + hdr := &tar.Header{ + Name: apkInstalledPath, + Mode: 0o644, + Uid: 0, + Gid: 0, + Typeflag: tar.TypeReg, + Size: int64(size), + } + if err := a.Writer.WriteHeader(hdr); err != nil { + return err + } + for _, db := range a.dbs { + if _, err := a.Writer.Write(db); err != nil { + return err + } + if _, err := a.Writer.Write([]byte{'\n', '\n'}); err != nil { + return err + } + } + } + // once complete, clear the databases + a.dbs = nil + return nil +} diff --git a/src/cmd/linuxkit/moby/build.go b/src/cmd/linuxkit/moby/build.go index 29403a55d..e0c3b8bd4 100644 --- a/src/cmd/linuxkit/moby/build.go +++ b/src/cmd/linuxkit/moby/build.go @@ -168,13 +168,17 @@ func Build(m Moby, w io.Writer, opts BuildOpts) error { if len(m.Init) != 0 { log.Infof("Add init containers:") } + apkTar := newAPKTarWriter(iw) for _, ii := range m.initRefs { log.Infof("Process init image: %s", ii) - err := ImageTar(ii, "", iw, resolvconfSymlink, opts) + err := ImageTar(ii, "", apkTar, resolvconfSymlink, opts) if err != nil { return fmt.Errorf("Failed to build init tarball from %s: %v", ii, err) } } + if err := apkTar.WriteAPKDB(); err != nil { + return err + } if len(m.Onboot) != 0 { log.Infof("Add onboot containers:")