mirror of
https://github.com/linuxkit/linuxkit.git
synced 2025-07-21 18:11:35 +00:00
Use Go code to extract rootfs from system containers
- this removes the use of riddler to extract the rootfs, use code we were using for rootfs. riddler now just geenrates the config, next stage is to generate this ourselves - change the naming of the daemons so no longer include number as we do not guarantee ordering as they start up simultaneously Signed-off-by: Justin Cormack <justin.cormack@docker.com>
This commit is contained in:
parent
a2049a0da9
commit
dd4ee77a23
@ -4,6 +4,7 @@ import (
|
|||||||
"archive/tar"
|
"archive/tar"
|
||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
@ -108,7 +109,7 @@ func build(name string, args []string) {
|
|||||||
containers = append(containers, ktar)
|
containers = append(containers, ktar)
|
||||||
|
|
||||||
// convert init image to tarball
|
// convert init image to tarball
|
||||||
init, err := imageExtract(m.Init)
|
init, err := ImageExtract(m.Init, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Failed to build init tarball: %v", err)
|
log.Fatalf("Failed to build init tarball: %v", err)
|
||||||
}
|
}
|
||||||
@ -116,20 +117,29 @@ func build(name string, args []string) {
|
|||||||
containers = append(containers, buffer)
|
containers = append(containers, buffer)
|
||||||
|
|
||||||
for i, image := range m.System {
|
for i, image := range m.System {
|
||||||
args := ConfigToRun(i, "system", &image)
|
config, err := ConfigToOCI(&image)
|
||||||
out, err := dockerRun(args...)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Failed to build container tarball: %v", err)
|
log.Fatalf("Failed to run riddler to get config.json for %s: %v", image.Image, err)
|
||||||
|
}
|
||||||
|
so := fmt.Sprintf("%03d", i)
|
||||||
|
path := "containers/system/" + so + "-" + image.Name
|
||||||
|
out, err := ImageBundle(path, image.Image, config)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to extract root filesystem for %s: %v", image.Image, err)
|
||||||
}
|
}
|
||||||
buffer := bytes.NewBuffer(out)
|
buffer := bytes.NewBuffer(out)
|
||||||
containers = append(containers, buffer)
|
containers = append(containers, buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, image := range m.Daemon {
|
for _, image := range m.Daemon {
|
||||||
args := ConfigToRun(i, "daemon", &image)
|
config, err := ConfigToOCI(&image)
|
||||||
out, err := dockerRun(args...)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Failed to build container tarball: %v", err)
|
log.Fatalf("Failed to run riddler to get config.json for %s: %v", image.Image, err)
|
||||||
|
}
|
||||||
|
path := "containers/daemon/" + image.Name
|
||||||
|
out, err := ImageBundle(path, image.Image, config)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to extract root filesystem for %s: %v", image.Image, err)
|
||||||
}
|
}
|
||||||
buffer := bytes.NewBuffer(out)
|
buffer := bytes.NewBuffer(out)
|
||||||
containers = append(containers, buffer)
|
containers = append(containers, buffer)
|
||||||
|
@ -50,7 +50,7 @@ type MobyImage struct {
|
|||||||
ReadOnly bool `yaml:"read_only"`
|
ReadOnly bool `yaml:"read_only"`
|
||||||
}
|
}
|
||||||
|
|
||||||
const riddler = "mobylinux/riddler:c23ab4b6e2a2a4ebd4dd51a059cef7f270da72cb@sha256:7e7744b2f554518411633200db98e599782b120e323348495f43f540de26f7b6"
|
const riddler = "mobylinux/riddler:2b4051422b155f659019f9e3fef8cca04e153f5c@sha256:f4bb0c39f1e5c636ed52ebd3ed8ec447ca6c0dc554ffb5784cbeff423ac70d34"
|
||||||
|
|
||||||
// NewConfig parses a config file
|
// NewConfig parses a config file
|
||||||
func NewConfig(config []byte) (*Moby, error) {
|
func NewConfig(config []byte) (*Moby, error) {
|
||||||
@ -64,11 +64,10 @@ func NewConfig(config []byte) (*Moby, error) {
|
|||||||
return &m, nil
|
return &m, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConfigToRun converts a config to a series of arguments for docker run
|
// ConfigToOCI converts a config specification to an OCI config file
|
||||||
func ConfigToRun(order int, path string, image *MobyImage) []string {
|
func ConfigToOCI(image *MobyImage) (string, error) {
|
||||||
// riddler arguments
|
// riddler arguments
|
||||||
so := fmt.Sprintf("%03d", order)
|
args := []string{"-v", "/var/run/docker.sock:/var/run/docker.sock", riddler, image.Image}
|
||||||
args := []string{"-v", "/var/run/docker.sock:/var/run/docker.sock", riddler, image.Image, "/containers/" + path + "/" + so + "-" + image.Name}
|
|
||||||
// docker arguments
|
// docker arguments
|
||||||
args = append(args, "--cap-drop", "all")
|
args = append(args, "--cap-drop", "all")
|
||||||
for _, cap := range image.Capabilities {
|
for _, cap := range image.Capabilities {
|
||||||
@ -107,7 +106,12 @@ func ConfigToRun(order int, path string, image *MobyImage) []string {
|
|||||||
// command
|
// command
|
||||||
args = append(args, image.Command...)
|
args = append(args, image.Command...)
|
||||||
|
|
||||||
return args
|
config, err := dockerRun(args...)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("Failed to run riddler to get config.json: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(config), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func filesystem(m *Moby) (*bytes.Buffer, error) {
|
func filesystem(m *Moby) (*bytes.Buffer, error) {
|
||||||
|
@ -164,23 +164,69 @@ nameserver 2001:4860:4860::8844
|
|||||||
"etc/hostname": "moby",
|
"etc/hostname": "moby",
|
||||||
}
|
}
|
||||||
|
|
||||||
func imageExtract(image string) ([]byte, error) {
|
// ImageExtract extracts the filesystem from an image and returns a tarball with the files prefixed by the given path
|
||||||
|
func ImageExtract(image, prefix string) ([]byte, error) {
|
||||||
|
out := new(bytes.Buffer)
|
||||||
|
tw := tar.NewWriter(out)
|
||||||
|
err := tarPrefix(prefix, tw)
|
||||||
|
if err != nil {
|
||||||
|
return []byte{}, err
|
||||||
|
}
|
||||||
|
err = imageTar(image, prefix, tw)
|
||||||
|
if err != nil {
|
||||||
|
return []byte{}, err
|
||||||
|
}
|
||||||
|
err = tw.Close()
|
||||||
|
if err != nil {
|
||||||
|
return []byte{}, err
|
||||||
|
}
|
||||||
|
return out.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// tarPrefix creates the leading directories for a path
|
||||||
|
func tarPrefix(path string, tw *tar.Writer) error {
|
||||||
|
if path == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if path[len(path)-1] != byte('/') {
|
||||||
|
return fmt.Errorf("path does not end with /: %s", path)
|
||||||
|
}
|
||||||
|
path = path[:len(path)-1]
|
||||||
|
if path[0] == byte('/') {
|
||||||
|
return fmt.Errorf("path should be relative: %s", path)
|
||||||
|
}
|
||||||
|
mkdir := ""
|
||||||
|
for _, dir := range strings.Split(path, "/") {
|
||||||
|
mkdir = mkdir + dir
|
||||||
|
hdr := &tar.Header{
|
||||||
|
Name: mkdir,
|
||||||
|
Mode: 0755,
|
||||||
|
Typeflag: tar.TypeDir,
|
||||||
|
}
|
||||||
|
tw.WriteHeader(hdr)
|
||||||
|
mkdir = mkdir + "/"
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func imageTar(image, prefix string, tw *tar.Writer) error {
|
||||||
|
if prefix != "" && prefix[len(prefix)-1] != byte('/') {
|
||||||
|
return fmt.Errorf("prefix does not end with /: %s", prefix)
|
||||||
|
}
|
||||||
container, err := dockerCreate(image)
|
container, err := dockerCreate(image)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []byte{}, fmt.Errorf("Failed to docker create image %s: %v", image, err)
|
return fmt.Errorf("Failed to docker create image %s: %v", image, err)
|
||||||
}
|
}
|
||||||
contents, err := dockerExport(container)
|
contents, err := dockerExport(container)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []byte{}, fmt.Errorf("Failed to docker export container from container %s: %v", container, err)
|
return fmt.Errorf("Failed to docker export container from container %s: %v", container, err)
|
||||||
}
|
}
|
||||||
err = dockerRm(container)
|
err = dockerRm(container)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []byte{}, fmt.Errorf("Failed to docker rm container %s: %v", container, err)
|
return fmt.Errorf("Failed to docker rm container %s: %v", container, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// now we need to filter out some files from the resulting tar archive
|
// 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)
|
r := bytes.NewReader(contents)
|
||||||
tr := tar.NewReader(r)
|
tr := tar.NewReader(r)
|
||||||
@ -191,21 +237,58 @@ func imageExtract(image string) ([]byte, error) {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []byte{}, err
|
return err
|
||||||
}
|
}
|
||||||
if exclude[hdr.Name] {
|
if exclude[hdr.Name] {
|
||||||
io.Copy(ioutil.Discard, tr)
|
io.Copy(ioutil.Discard, tr)
|
||||||
} else if replace[hdr.Name] != "" {
|
} else if replace[hdr.Name] != "" {
|
||||||
hdr.Size = int64(len(replace[hdr.Name]))
|
contents := replace[hdr.Name]
|
||||||
|
hdr.Size = int64(len(contents))
|
||||||
|
hdr.Name = prefix + hdr.Name
|
||||||
tw.WriteHeader(hdr)
|
tw.WriteHeader(hdr)
|
||||||
buf := bytes.NewBufferString(replace[hdr.Name])
|
buf := bytes.NewBufferString(contents)
|
||||||
io.Copy(tw, buf)
|
io.Copy(tw, buf)
|
||||||
|
io.Copy(ioutil.Discard, tr)
|
||||||
} else {
|
} else {
|
||||||
|
hdr.Name = prefix + hdr.Name
|
||||||
tw.WriteHeader(hdr)
|
tw.WriteHeader(hdr)
|
||||||
io.Copy(tw, tr)
|
io.Copy(tw, tr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err = tw.Close()
|
err = tw.Close()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImageBundle produces an OCI bundle at the given path in a tarball, given an image and a config.json
|
||||||
|
func ImageBundle(path, image, config string) ([]byte, error) {
|
||||||
|
out := new(bytes.Buffer)
|
||||||
|
tw := tar.NewWriter(out)
|
||||||
|
err := tarPrefix(path+"/rootfs/", tw)
|
||||||
|
if err != nil {
|
||||||
|
return []byte{}, err
|
||||||
|
}
|
||||||
|
hdr := &tar.Header{
|
||||||
|
Name: path + "/" + "config.json",
|
||||||
|
Mode: 0644,
|
||||||
|
Size: int64(len(config)),
|
||||||
|
}
|
||||||
|
err = tw.WriteHeader(hdr)
|
||||||
|
if err != nil {
|
||||||
|
return []byte{}, err
|
||||||
|
}
|
||||||
|
buf := bytes.NewBufferString(config)
|
||||||
|
_, err = io.Copy(tw, buf)
|
||||||
|
if err != nil {
|
||||||
|
return []byte{}, err
|
||||||
|
}
|
||||||
|
err = imageTar(image, path+"/rootfs/", tw)
|
||||||
|
if err != nil {
|
||||||
|
return []byte{}, err
|
||||||
|
}
|
||||||
|
err = tw.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []byte{}, err
|
return []byte{}, err
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user