diff --git a/src/cmd/moby/build.go b/src/cmd/moby/build.go index 7bf2449d0..3f67799d6 100644 --- a/src/cmd/moby/build.go +++ b/src/cmd/moby/build.go @@ -12,10 +12,6 @@ import ( "github.com/docker/moby/src/initrd" ) -const ( - docker2tar = "mobylinux/docker2tar:82a3f11f70b2959c7100dd6e184b511ebfc65908@sha256:e4fd36febc108477a2e5316d263ac257527779409891c7ac10d455a162df05c1" -) - func untarKernel(buf *bytes.Buffer, bzimageName, ktarName string) (*bytes.Buffer, *bytes.Buffer, error) { tr := tar.NewReader(buf) @@ -112,7 +108,7 @@ func build(name string, args []string) { containers = append(containers, ktar) // convert init image to tarball - init, err := dockerRun("-v", "/var/run/docker.sock:/var/run/docker.sock", docker2tar, m.Init) + init, err := imageExtract(m.Init) if err != nil { log.Fatalf("Failed to build init tarball: %v", err) } diff --git a/src/cmd/moby/image.go b/src/cmd/moby/image.go new file mode 100644 index 000000000..c0531a872 --- /dev/null +++ b/src/cmd/moby/image.go @@ -0,0 +1,213 @@ +package main + +import ( + "archive/tar" + "bytes" + "errors" + "fmt" + "io" + "io/ioutil" + "os/exec" + "strings" +) + +// This uses Docker to convert a Docker image into a tarball. It would be an improvement if we +// used the containerd libraries to do this instead locally direct from a local image +// cache as it would be much simpler. + +func dockerCreate(image string) (string, error) { + docker, err := exec.LookPath("docker") + if err != nil { + return "", errors.New("Docker does not seem to be installed") + } + // we do not ever run the container, so /dev/null is used as command + args := []string{"create", image, "/dev/null"} + cmd := exec.Command(docker, args...) + + stderrPipe, err := cmd.StderrPipe() + if err != nil { + return "", err + } + + stdoutPipe, err := cmd.StdoutPipe() + if err != nil { + return "", err + } + + err = cmd.Start() + if err != nil { + return "", err + } + + stdout, err := ioutil.ReadAll(stdoutPipe) + if err != nil { + return "", err + } + + stderr, err := ioutil.ReadAll(stderrPipe) + if err != nil { + return "", err + } + + err = cmd.Wait() + if err != nil { + return "", fmt.Errorf("%s: %s", err, stderr) + } + + container := strings.TrimSpace(string(stdout)) + return container, nil +} + +func dockerExport(container string) ([]byte, error) { + docker, err := exec.LookPath("docker") + if err != nil { + return []byte{}, errors.New("Docker does not seem to be installed") + } + args := []string{"export", container} + cmd := exec.Command(docker, args...) + + stderrPipe, err := cmd.StderrPipe() + if err != nil { + return []byte{}, err + } + + stdoutPipe, err := cmd.StdoutPipe() + if err != nil { + return []byte{}, err + } + + err = cmd.Start() + if err != nil { + return []byte{}, err + } + + stdout, err := ioutil.ReadAll(stdoutPipe) + if err != nil { + return []byte{}, err + } + + stderr, err := ioutil.ReadAll(stderrPipe) + if err != nil { + return []byte{}, err + } + + err = cmd.Wait() + if err != nil { + return []byte{}, fmt.Errorf("%s: %s", err, stderr) + } + + return stdout, nil +} + +func dockerRm(container string) error { + docker, err := exec.LookPath("docker") + if err != nil { + return errors.New("Docker does not seem to be installed") + } + args := []string{"rm", container} + cmd := exec.Command(docker, args...) + + stderrPipe, err := cmd.StderrPipe() + if err != nil { + return err + } + + stdoutPipe, err := cmd.StdoutPipe() + if err != nil { + return err + } + + err = cmd.Start() + if err != nil { + return err + } + + _, err = ioutil.ReadAll(stdoutPipe) + if err != nil { + return err + } + + stderr, err := ioutil.ReadAll(stderrPipe) + if err != nil { + return err + } + + err = cmd.Wait() + if err != nil { + return fmt.Errorf("%s: %s", err, stderr) + } + + return nil +} + +var exclude = map[string]bool{ + ".dockerenv": true, + "Dockerfile": true, + "dev/console": true, + "dev/pts": true, + "dev/shm": true, +} + +var replace = map[string]string{ + "etc/hosts": `127.0.0.1 localhost +::1 localhost ip6-localhost ip6-loopback +fe00::0 ip6-localnet +ff00::0 ip6-mcastprefix +ff02::1 ip6-allnodes +ff02::2 ip6-allrouters +`, + "etc/resolv.conf": `nameserver 8.8.8.8 +nameserver 8.8.4.4 +nameserver 2001:4860:4860::8888 +nameserver 2001:4860:4860::8844 +`, + "etc/hostname": "moby", +} + +func imageExtract(image string) ([]byte, error) { + container, err := dockerCreate(image) + if err != nil { + return []byte{}, fmt.Errorf("Failed to docker create image %s: %v", image, err) + } + contents, err := dockerExport(container) + if err != nil { + return []byte{}, fmt.Errorf("Failed to docker export container from container %s: %v", container, err) + } + err = dockerRm(container) + if err != nil { + return []byte{}, fmt.Errorf("Failed to docker rm container %s: %v", container, err) + } + + // now we need to filter out some files from the resulting tar archive + out := new(bytes.Buffer) + tw := tar.NewWriter(out) + + r := bytes.NewReader(contents) + tr := tar.NewReader(r) + + for { + hdr, err := tr.Next() + if err == io.EOF { + break + } + if err != nil { + return []byte{}, err + } + if exclude[hdr.Name] { + io.Copy(ioutil.Discard, tr) + } else if replace[hdr.Name] != "" { + hdr.Size = int64(len(replace[hdr.Name])) + tw.WriteHeader(hdr) + buf := bytes.NewBufferString(replace[hdr.Name]) + io.Copy(tw, buf) + } else { + tw.WriteHeader(hdr) + io.Copy(tw, tr) + } + } + err = tw.Close() + if err != nil { + return []byte{}, err + } + return out.Bytes(), nil +}