mirror of
https://github.com/linuxkit/linuxkit.git
synced 2025-07-20 09:39:08 +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"
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
@ -108,7 +109,7 @@ func build(name string, args []string) {
|
||||
containers = append(containers, ktar)
|
||||
|
||||
// convert init image to tarball
|
||||
init, err := imageExtract(m.Init)
|
||||
init, err := ImageExtract(m.Init, "")
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to build init tarball: %v", err)
|
||||
}
|
||||
@ -116,20 +117,29 @@ func build(name string, args []string) {
|
||||
containers = append(containers, buffer)
|
||||
|
||||
for i, image := range m.System {
|
||||
args := ConfigToRun(i, "system", &image)
|
||||
out, err := dockerRun(args...)
|
||||
config, err := ConfigToOCI(&image)
|
||||
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)
|
||||
containers = append(containers, buffer)
|
||||
}
|
||||
|
||||
for i, image := range m.Daemon {
|
||||
args := ConfigToRun(i, "daemon", &image)
|
||||
out, err := dockerRun(args...)
|
||||
for _, image := range m.Daemon {
|
||||
config, err := ConfigToOCI(&image)
|
||||
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)
|
||||
containers = append(containers, buffer)
|
||||
|
@ -50,7 +50,7 @@ type MobyImage struct {
|
||||
ReadOnly bool `yaml:"read_only"`
|
||||
}
|
||||
|
||||
const riddler = "mobylinux/riddler:c23ab4b6e2a2a4ebd4dd51a059cef7f270da72cb@sha256:7e7744b2f554518411633200db98e599782b120e323348495f43f540de26f7b6"
|
||||
const riddler = "mobylinux/riddler:2b4051422b155f659019f9e3fef8cca04e153f5c@sha256:f4bb0c39f1e5c636ed52ebd3ed8ec447ca6c0dc554ffb5784cbeff423ac70d34"
|
||||
|
||||
// NewConfig parses a config file
|
||||
func NewConfig(config []byte) (*Moby, error) {
|
||||
@ -64,11 +64,10 @@ func NewConfig(config []byte) (*Moby, error) {
|
||||
return &m, nil
|
||||
}
|
||||
|
||||
// ConfigToRun converts a config to a series of arguments for docker run
|
||||
func ConfigToRun(order int, path string, image *MobyImage) []string {
|
||||
// ConfigToOCI converts a config specification to an OCI config file
|
||||
func ConfigToOCI(image *MobyImage) (string, error) {
|
||||
// riddler arguments
|
||||
so := fmt.Sprintf("%03d", order)
|
||||
args := []string{"-v", "/var/run/docker.sock:/var/run/docker.sock", riddler, image.Image, "/containers/" + path + "/" + so + "-" + image.Name}
|
||||
args := []string{"-v", "/var/run/docker.sock:/var/run/docker.sock", riddler, image.Image}
|
||||
// docker arguments
|
||||
args = append(args, "--cap-drop", "all")
|
||||
for _, cap := range image.Capabilities {
|
||||
@ -107,7 +106,12 @@ func ConfigToRun(order int, path string, image *MobyImage) []string {
|
||||
// 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) {
|
||||
|
@ -164,23 +164,69 @@ nameserver 2001:4860:4860::8844
|
||||
"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)
|
||||
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)
|
||||
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)
|
||||
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
|
||||
out := new(bytes.Buffer)
|
||||
tw := tar.NewWriter(out)
|
||||
|
||||
r := bytes.NewReader(contents)
|
||||
tr := tar.NewReader(r)
|
||||
@ -191,21 +237,58 @@ func imageExtract(image string) ([]byte, error) {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
return err
|
||||
}
|
||||
if exclude[hdr.Name] {
|
||||
io.Copy(ioutil.Discard, tr)
|
||||
} 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)
|
||||
buf := bytes.NewBufferString(replace[hdr.Name])
|
||||
buf := bytes.NewBufferString(contents)
|
||||
io.Copy(tw, buf)
|
||||
io.Copy(ioutil.Discard, tr)
|
||||
} else {
|
||||
hdr.Name = prefix + hdr.Name
|
||||
tw.WriteHeader(hdr)
|
||||
io.Copy(tw, tr)
|
||||
}
|
||||
}
|
||||
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 {
|
||||
return []byte{}, err
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user