Windows: Support non-base-layered images

Previously, Windows only supported running with a OS-managed base image.
With this change, Windows supports normal, Linux-like layered images, too.

Signed-off-by: John Starks <jostarks@microsoft.com>
This commit is contained in:
John Starks 2016-03-28 18:14:05 -07:00
parent fc352287c1
commit d45a26d7e2
6 changed files with 36 additions and 15 deletions

View File

@ -373,8 +373,7 @@ func restoreCustomImage(is image.Store, ls layer.Store, rs reference.Store) erro
} }
// layer is intentionally not released // layer is intentionally not released
rootFS := image.NewRootFS() rootFS := image.NewRootFSWithBaseLayer(filepath.Base(info.Path))
rootFS.BaseLayer = filepath.Base(info.Path)
// Create history for base layer // Create history for base layer
config, err := json.Marshal(&image.Image{ config, err := json.Marshal(&image.Image{

View File

@ -5,6 +5,7 @@ import (
"syscall" "syscall"
"github.com/docker/docker/container" "github.com/docker/docker/container"
"github.com/docker/docker/image"
"github.com/docker/docker/layer" "github.com/docker/docker/layer"
"github.com/docker/docker/libcontainerd" "github.com/docker/docker/libcontainerd"
"github.com/docker/docker/libcontainerd/windowsoci" "github.com/docker/docker/libcontainerd/windowsoci"
@ -88,9 +89,15 @@ func (daemon *Daemon) createSpec(c *container.Container) (*libcontainerd.Spec, e
// s.Windows.LayerPaths // s.Windows.LayerPaths
var layerPaths []string var layerPaths []string
if img.RootFS != nil && img.RootFS.Type == "layers+base" { if img.RootFS != nil && (img.RootFS.Type == image.TypeLayers || img.RootFS.Type == image.TypeLayersWithBase) {
// Get the layer path for each layer.
start := 1
if img.RootFS.Type == image.TypeLayersWithBase {
// Include an empty slice to get the base layer ID.
start = 0
}
max := len(img.RootFS.DiffIDs) max := len(img.RootFS.DiffIDs)
for i := 0; i <= max; i++ { for i := start; i <= max; i++ {
img.RootFS.DiffIDs = img.RootFS.DiffIDs[:i] img.RootFS.DiffIDs = img.RootFS.DiffIDs[:i]
path, err := layer.GetLayerPath(daemon.layerStore, img.RootFS.ChainID()) path, err := layer.GetLayerPath(daemon.layerStore, img.RootFS.ChainID())
if err != nil { if err != nil {

View File

@ -20,8 +20,9 @@ func detectBaseLayer(is image.Store, m *schema1.Manifest, rootFS *image.RootFS)
} }
// There must be an image that already references the baselayer. // There must be an image that already references the baselayer.
for _, img := range is.Map() { for _, img := range is.Map() {
if img.RootFS.BaseLayerID() == v1img.Parent { if img.RootFS.Type == image.TypeLayersWithBase && img.RootFS.BaseLayerID() == v1img.Parent {
rootFS.BaseLayer = img.RootFS.BaseLayer rootFS.BaseLayer = img.RootFS.BaseLayer
rootFS.Type = image.TypeLayersWithBase
return nil return nil
} }
} }

View File

@ -2,6 +2,14 @@ package image
import "github.com/docker/docker/layer" import "github.com/docker/docker/layer"
// TypeLayers is used for RootFS.Type for filesystems organized into layers.
const TypeLayers = "layers"
// NewRootFS returns empty RootFS struct
func NewRootFS() *RootFS {
return &RootFS{Type: TypeLayers}
}
// Append appends a new diffID to rootfs // Append appends a new diffID to rootfs
func (r *RootFS) Append(id layer.DiffID) { func (r *RootFS) Append(id layer.DiffID) {
r.DiffIDs = append(r.DiffIDs, id) r.DiffIDs = append(r.DiffIDs, id)

View File

@ -16,8 +16,3 @@ type RootFS struct {
func (r *RootFS) ChainID() layer.ChainID { func (r *RootFS) ChainID() layer.ChainID {
return layer.CreateChainID(r.DiffIDs) return layer.CreateChainID(r.DiffIDs)
} }
// NewRootFS returns empty RootFS struct
func NewRootFS() *RootFS {
return &RootFS{Type: "layers"}
}

View File

@ -10,6 +10,9 @@ import (
"github.com/docker/docker/layer" "github.com/docker/docker/layer"
) )
// TypeLayersWithBase is used for RootFS.Type for Windows filesystems that have layers and a centrally-stored base layer.
const TypeLayersWithBase = "layers+base"
// RootFS describes images root filesystem // RootFS describes images root filesystem
// This is currently a placeholder that only supports layers. In the future // This is currently a placeholder that only supports layers. In the future
// this can be made into an interface that supports different implementations. // this can be made into an interface that supports different implementations.
@ -21,17 +24,25 @@ type RootFS struct {
// BaseLayerID returns the 64 byte hex ID for the baselayer name. // BaseLayerID returns the 64 byte hex ID for the baselayer name.
func (r *RootFS) BaseLayerID() string { func (r *RootFS) BaseLayerID() string {
if r.Type != TypeLayersWithBase {
panic("tried to get base layer ID without a base layer")
}
baseID := sha512.Sum384([]byte(r.BaseLayer)) baseID := sha512.Sum384([]byte(r.BaseLayer))
return fmt.Sprintf("%x", baseID[:32]) return fmt.Sprintf("%x", baseID[:32])
} }
// ChainID returns the ChainID for the top layer in RootFS. // ChainID returns the ChainID for the top layer in RootFS.
func (r *RootFS) ChainID() layer.ChainID { func (r *RootFS) ChainID() layer.ChainID {
baseDiffID := digest.FromBytes([]byte(r.BaseLayerID())) ids := r.DiffIDs
return layer.CreateChainID(append([]layer.DiffID{layer.DiffID(baseDiffID)}, r.DiffIDs...)) if r.Type == TypeLayersWithBase {
// Add an extra ID for the base.
baseDiffID := layer.DiffID(digest.FromBytes([]byte(r.BaseLayerID())))
ids = append([]layer.DiffID{baseDiffID}, ids...)
}
return layer.CreateChainID(ids)
} }
// NewRootFS returns empty RootFS struct // NewRootFSWithBaseLayer returns a RootFS struct with a base layer
func NewRootFS() *RootFS { func NewRootFSWithBaseLayer(baseLayer string) *RootFS {
return &RootFS{Type: "layers+base"} return &RootFS{Type: TypeLayersWithBase, BaseLayer: baseLayer}
} }