imagecontext.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. package dockerfile // import "github.com/docker/docker/builder/dockerfile"
  2. import (
  3. "context"
  4. "runtime"
  5. "github.com/containerd/containerd/platforms"
  6. "github.com/containerd/log"
  7. "github.com/docker/docker/api/types/backend"
  8. "github.com/docker/docker/builder"
  9. dockerimage "github.com/docker/docker/image"
  10. ocispec "github.com/opencontainers/image-spec/specs-go/v1"
  11. "github.com/pkg/errors"
  12. )
  13. type getAndMountFunc func(context.Context, string, bool, *ocispec.Platform) (builder.Image, builder.ROLayer, error)
  14. // imageSources mounts images and provides a cache for mounted images. It tracks
  15. // all images so they can be unmounted at the end of the build.
  16. type imageSources struct {
  17. byImageID map[string]*imageMount
  18. mounts []*imageMount
  19. getImage getAndMountFunc
  20. }
  21. func newImageSources(options builderOptions) *imageSources {
  22. getAndMount := func(ctx context.Context, idOrRef string, localOnly bool, platform *ocispec.Platform) (builder.Image, builder.ROLayer, error) {
  23. pullOption := backend.PullOptionNoPull
  24. if !localOnly {
  25. if options.Options.PullParent {
  26. pullOption = backend.PullOptionForcePull
  27. } else {
  28. pullOption = backend.PullOptionPreferLocal
  29. }
  30. }
  31. return options.Backend.GetImageAndReleasableLayer(ctx, idOrRef, backend.GetImageAndLayerOptions{
  32. PullOption: pullOption,
  33. AuthConfig: options.Options.AuthConfigs,
  34. Output: options.ProgressWriter.Output,
  35. Platform: platform,
  36. })
  37. }
  38. return &imageSources{
  39. byImageID: make(map[string]*imageMount),
  40. getImage: getAndMount,
  41. }
  42. }
  43. func (m *imageSources) Get(ctx context.Context, idOrRef string, localOnly bool, platform *ocispec.Platform) (*imageMount, error) {
  44. if im, ok := m.byImageID[idOrRef]; ok {
  45. return im, nil
  46. }
  47. image, layer, err := m.getImage(ctx, idOrRef, localOnly, platform)
  48. if err != nil {
  49. return nil, err
  50. }
  51. im := newImageMount(image, layer)
  52. m.Add(im, platform)
  53. return im, nil
  54. }
  55. func (m *imageSources) Unmount() (retErr error) {
  56. for _, im := range m.mounts {
  57. if err := im.unmount(); err != nil {
  58. log.G(context.TODO()).Error(err)
  59. retErr = err
  60. }
  61. }
  62. return
  63. }
  64. func (m *imageSources) Add(im *imageMount, platform *ocispec.Platform) {
  65. switch im.image {
  66. case nil:
  67. // Set the platform for scratch images
  68. if platform == nil {
  69. p := platforms.DefaultSpec()
  70. platform = &p
  71. }
  72. // Windows does not support scratch except for LCOW
  73. os := platform.OS
  74. if runtime.GOOS == "windows" {
  75. os = "linux"
  76. }
  77. im.image = &dockerimage.Image{V1Image: dockerimage.V1Image{
  78. OS: os,
  79. Architecture: platform.Architecture,
  80. Variant: platform.Variant,
  81. }}
  82. default:
  83. m.byImageID[im.image.ImageID()] = im
  84. }
  85. m.mounts = append(m.mounts, im)
  86. }
  87. // imageMount is a reference to an image that can be used as a builder.Source
  88. type imageMount struct {
  89. image builder.Image
  90. layer builder.ROLayer
  91. }
  92. func newImageMount(image builder.Image, layer builder.ROLayer) *imageMount {
  93. im := &imageMount{image: image, layer: layer}
  94. return im
  95. }
  96. func (im *imageMount) unmount() error {
  97. if im.layer == nil {
  98. return nil
  99. }
  100. if err := im.layer.Release(); err != nil {
  101. return errors.Wrapf(err, "failed to unmount previous build image %s", im.image.ImageID())
  102. }
  103. im.layer = nil
  104. return nil
  105. }
  106. func (im *imageMount) Image() builder.Image {
  107. return im.image
  108. }
  109. func (im *imageMount) NewRWLayer() (builder.RWLayer, error) {
  110. return im.layer.NewRWLayer()
  111. }
  112. func (im *imageMount) ImageID() string {
  113. return im.image.ImageID()
  114. }