Add support for --manifest flags

This patch allows users to build a multi arch image with simple commands
using emulation software.

```
buildah bud --arch arm --manifest myimage /tmp/mysrc
buildah bud --arch amd64 --manifest myimage /tmp/mysrc
buildah bud --arch s390x --manifest myimage /tmp/mysrc
```

And something like this for buildah commit
```
build() {
	ctr=$(./bin/buildah from --arch $1 ubi8)
	./bin/buildah run $ctr dnf install -y iputils
	./bin/buildah commit --manifest ubi8ping $ctr
}
build arm
build amd64
build s390x
```

Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
This commit is contained in:
Daniel J Walsh 2020-12-30 07:16:24 -05:00
parent f01ddd6800
commit 7acdfe8e8d
No known key found for this signature in database
GPG Key ID: A2DF901DABE2C028
14 changed files with 121 additions and 12 deletions

View File

@ -330,6 +330,7 @@ func budCmd(c *cobra.Command, inputArgs []string, iopts budOptions) error {
Isolation: isolation,
Labels: iopts.Label,
Layers: layers,
Manifest: iopts.Manifest,
MaxPullPushRetries: maxPullPushRetries,
NamespaceOptions: namespaceOptions,
NoCache: iopts.NoCache,

View File

@ -27,6 +27,7 @@ type commitInputOptions struct {
disableCompression bool
format string
iidfile string
manifest string
omitTimestamp bool
timestamp int64
quiet bool
@ -73,6 +74,7 @@ func init() {
flags.StringVar(&opts.creds, "creds", "", "use `[username[:password]]` for accessing the registry")
flags.BoolVarP(&opts.disableCompression, "disable-compression", "D", true, "don't compress layers")
flags.StringVarP(&opts.format, "format", "f", defaultFormat(), "`format` of the image manifest and metadata")
flags.StringVar(&opts.manifest, "manifest", "", "create image with as part of the specified manifest list. Creates manifest if it does not exist")
flags.StringVar(&opts.iidfile, "iidfile", "", "Write the image ID to the file")
flags.BoolVar(&opts.omitTimestamp, "omit-timestamp", false, "set created timestamp to epoch 0 to allow for deterministic builds")
flags.Int64Var(&opts.timestamp, "timestamp", 0, "set created timestamp to epoch seconds to allow for deterministic builds, defaults to current time")
@ -175,6 +177,7 @@ func commitCmd(c *cobra.Command, args []string, iopts commitInputOptions) error
options := buildah.CommitOptions{
PreferredManifestType: format,
Manifest: iopts.manifest,
Compression: compress,
SignaturePolicyPath: iopts.signaturePolicy,
SystemContext: systemContext,

View File

@ -10,6 +10,7 @@ import (
"strings"
"time"
"github.com/containers/buildah/manifests"
"github.com/containers/buildah/pkg/blobcache"
"github.com/containers/buildah/util"
"github.com/containers/image/v5/docker"
@ -18,6 +19,7 @@ import (
"github.com/containers/image/v5/signature"
is "github.com/containers/image/v5/storage"
"github.com/containers/image/v5/transports"
"github.com/containers/image/v5/transports/alltransports"
"github.com/containers/image/v5/types"
encconfig "github.com/containers/ocicrypt/config"
"github.com/containers/storage"
@ -83,6 +85,8 @@ type CommitOptions struct {
OmitTimestamp bool
// SignBy is the fingerprint of a GPG key to use for signing the image.
SignBy string
// Manifest list to add the image to.
Manifest string
// MaxRetries is the maximum number of attempts we'll make to commit
// the image to an external registry if the first attempt fails.
MaxRetries int
@ -220,12 +224,59 @@ func checkRegistrySourcesAllows(forWhat string, dest types.ImageReference) (inse
return false, nil
}
func (b *Builder) addManifest(ctx context.Context, manifestName string, imageSpec string) error {
var create bool
systemContext := &types.SystemContext{}
var list manifests.List
_, listImage, err := util.FindImage(b.store, "", systemContext, manifestName)
if err != nil {
create = true
list = manifests.Create()
} else {
_, list, err = manifests.LoadFromImage(b.store, listImage.ID)
if err != nil {
return err
}
}
names, err := util.ExpandNames([]string{manifestName}, "", systemContext, b.store)
if err != nil {
return errors.Wrapf(err, "error encountered while expanding image name %q", manifestName)
}
ref, err := alltransports.ParseImageName(imageSpec)
if err != nil {
if ref, err = alltransports.ParseImageName(util.DefaultTransport + imageSpec); err != nil {
// check if the local image exists
if ref, _, err = util.FindImage(b.store, "", systemContext, imageSpec); err != nil {
return err
}
}
}
if _, err = list.Add(ctx, systemContext, ref, true); err != nil {
return err
}
var imageID string
if create {
imageID, err = list.SaveToImage(b.store, "", names, manifest.DockerV2ListMediaType)
} else {
imageID, err = list.SaveToImage(b.store, listImage.ID, nil, "")
}
if err == nil {
fmt.Printf("%s\n", imageID)
}
return err
}
// Commit writes the contents of the container, along with its updated
// configuration, to a new image in the specified location, and if we know how,
// add any additional tags that were specified. Returns the ID of the new image
// if commit was successful and the image destination was local.
func (b *Builder) Commit(ctx context.Context, dest types.ImageReference, options CommitOptions) (string, reference.Canonical, digest.Digest, error) {
var imgID string
var (
imgID string
)
// If we weren't given a name, build a destination reference using a
// temporary name that we'll remove later. The correct thing to do
@ -437,6 +488,11 @@ func (b *Builder) Commit(ctx context.Context, dest types.ImageReference, options
}
}
if options.Manifest != "" {
if err := b.addManifest(ctx, options.Manifest, imgID); err != nil {
return imgID, nil, "", err
}
}
return imgID, ref, manifestDigest, nil
}

View File

@ -324,6 +324,7 @@ return 1
-h
--disable-compression
-D
--manifest
--quiet
-q
--rm
@ -424,6 +425,7 @@ return 1
--ipc
--label
--loglevel
--manifest
-m
--memory
--memory-swap

View File

@ -355,6 +355,11 @@ Adjust the logging level up or down. Valid option values range from -2 to 3,
with 3 being roughly equivalent to using the global *--log-level=debug* option, and
values below 0 omitting even error messages which accompany fatal errors.
**--manifest** "manifest"
Name of the manifest list to which the image will be added. Creates the manifest list
if it does not exist. This option is useful for building multi architecture images.
**--memory**, **-m**=""
Memory limit (format: <number>[<unit>], where unit = b, k, m or g)
@ -519,7 +524,7 @@ When --timestamp is set, the created timestamp is always set to the time specifi
**--tls-verify** *bool-value*
Require HTTPS and verify certificates when talking to container registries (defaults to true). TLS verification cannot be used when talking to an insecure registry.
Require HTTPS and verification of certificates when talking to container registries (defaults to true). TLS verification cannot be used when talking to an insecure registry.
**--ulimit** *type*=*soft-limit*[:*hard-limit*]
@ -749,6 +754,12 @@ buildah bud --no-cache --rm=false -t imageName .
buildah bud --dns-search=example.com --dns=223.5.5.5 --dns-option=use-vc .
### Building an multi-architecture image using a --manifest option (Requires emulation software)
buildah bud --arch arm --manifest myimage /tmp/mysrc
buildah bud --arch amd64 --manifest myimage /tmp/mysrc
buildah bud --arch s390x --manifest myimage /tmp/mysrc
### Building an image using a URL
This will clone the specified GitHub repository from the URL and use it as context. The Containerfile or Dockerfile at the root of the repository is used as the context of the build. This only works if the GitHub repository is a dedicated repository.

View File

@ -65,6 +65,11 @@ environment variable. `export BUILDAH\_FORMAT=docker`
Write the image ID to the file.
**--manifest** "manifest"
Name of the manifest list to which the image will be added. Creates the manifest list
if it does not exist. This option is useful for building multi architecture images.
**--quiet**, **-q**
When writing the output image, suppress progress output.
@ -81,10 +86,6 @@ Sign the new image using the GPG key that matches the specified fingerprint.
Squash all of the new image's layers (including those inherited from a base image) into a single new layer.
**--tls-verify** *bool-value*
Require HTTPS and verify certificates when talking to container registries (defaults to true). TLS verification cannot be used when talking to an insecure registry.
**--timestamp** *seconds*
Set the create timestamp to seconds since epoch to allow for deterministic builds (defaults to current time).
@ -92,6 +93,10 @@ By default, the created timestamp is changed and written into the image manifest
causing the image's sha256 hash to be different even if the sources are exactly the same otherwise.
When --timestamp is set, the created timestamp is always set to the time specified and therefore not changed, allowing the image's sha256 to remain the same. All files committed to the layers of the image will be created with the timestamp.
**--tls-verify** *bool-value*
Require HTTPS and verification of certificates when talking to container registries (defaults to true). TLS verification cannot be used when talking to an insecure registry.
## EXAMPLE
This example saves an image based on the container.
@ -121,6 +126,20 @@ This example commits the container to the image on the local registry using cred
This example saves an image based on the container, but stores dates based on epoch time.
`buildah commit --timestamp=0 containerID newImageName`
### Building an multi-architecture image using a --manifest option (Requires emulation software)
```
#!/bin/sh
build() {
ctr=$(./bin/buildah from --arch $1 ubi8)
./bin/buildah run $ctr dnf install -y iputils
./bin/buildah commit --manifest ubi8ping $ctr
}
build arm
build amd64
build s390x
```
## ENVIRONMENT
**BUILD\_REGISTRY\_SOURCES**

View File

@ -53,6 +53,10 @@ Add a line to /etc/hosts. The format is hostname:ip. The **--add-host** option c
Set the ARCH of the image to be pulled to the provided value instead of using the architecture of the host. (Examples: aarch64, arm, i686, ppc64le, s390x, x86_64)
**--arch**="ARCH"
Set the ARCH of the image to be pulled to the provided value instead of using the architecture of the host.
**--authfile** *path*
Path of the authentication file. Default is ${XDG\_RUNTIME\_DIR}/containers/auth.json, which is set using `buildah login`.
@ -279,6 +283,10 @@ another process.
Set the OS of the image to be pulled instead of using the current operating system of the host.
**--os**="OS"
Set the OS of the image to be pulled to the provided value instead of using the current operating system of the host.
**--pid** *how*
Sets the configuration for PID namespaces when the container is subsequently
@ -341,7 +349,7 @@ If you omit the unit, the system uses bytes. If you omit the size entirely, the
**--tls-verify** *bool-value*
Require HTTPS and verify certificates when talking to container registries (defaults to true). TLS verification cannot be used when talking to an insecure registry.
Require HTTPS and verification of certificates when talking to container registries (defaults to true). TLS verification cannot be used when talking to an insecure registry.
**--ulimit** *type*=*soft-limit*[:*hard-limit*]

View File

@ -51,7 +51,7 @@ The default certificates directory is _/etc/containers/certs.d_.
**--tls-verify**
Require HTTPS and verify certificates when contacting registries (default: true). If explicitly set to true,
Require HTTPS and verification of certificates when talking to container registries (default: true). If explicitly set to true,
then TLS verification will be used. If set to false, then TLS verification will not be used. If not specified,
TLS verification will be used unless the target registry is listed as an insecure registry in registries.conf.
TLS verification cannot be used when talking to an insecure registry.

View File

@ -76,7 +76,7 @@ image. This option is rarely used.
**--tls-verify** *bool-value*
Require HTTPS and verify certificates when talking to container registries (defaults to true). TLS verification cannot be used when talking to an insecure registry.
Require HTTPS and verification of certificates when talking to container registries (defaults to true). TLS verification cannot be used when talking to an insecure registry.
**--variant**

View File

@ -65,7 +65,7 @@ Sign the pushed images using the GPG key that matches the specified fingerprint.
**--tls-verify** *bool-value*
Require HTTPS and verify certificates when talking to container registries (defaults to true). TLS verification cannot be used when talking to an insecure registry.
Require HTTPS and verification of certificates when talking to container registries (defaults to true). TLS verification cannot be used when talking to an insecure registry.
## EXAMPLE

View File

@ -78,6 +78,10 @@ If an image needs to be pulled from the registry, suppress progress output.
Set the OS of the image to be pulled instead of using the current operating system of the host.
**--os**="OS"
Set the OS of the image to be pulled to the provided value instead of using the current operating system of the host.
**--policy**=**always**|**missing**|**never**
Pull image policy. The default is **missing**.
@ -92,7 +96,7 @@ Don't copy signatures when pulling images.
**--tls-verify** *bool-value*
Require HTTPS and verify certificates when talking to container registries (defaults to true). TLS verification cannot be used when talking to an insecure registry.
Require HTTPS and verification of certificates when talking to container registries (defaults to true). TLS verification cannot be used when talking to an insecure registry.
**--variant**=""

View File

@ -92,7 +92,7 @@ Sign the pushed image using the GPG key that matches the specified fingerprint.
**--tls-verify** *bool-value*
Require HTTPS and verify certificates when talking to container registries (defaults to true). TLS verification cannot be used when talking to an insecure registry.
Require HTTPS and verification of certificates when talking to container registries (defaults to true). TLS verification cannot be used when talking to an insecure registry.
## EXAMPLE

View File

@ -58,6 +58,8 @@ type BuildOptions struct {
// IgnoreUnrecognizedInstructions tells us to just log instructions we
// don't recognize, and try to keep going.
IgnoreUnrecognizedInstructions bool
// Manifest Name to which the image will be added.
Manifest string
// Quiet tells us whether or not to announce steps as we go through them.
Quiet bool
// Isolation controls how Run() runs things.

View File

@ -67,6 +67,7 @@ type BudResults struct {
Label []string
Logfile string
Loglevel int
Manifest string
NoCache bool
Timestamp int64
Pull bool
@ -197,6 +198,7 @@ func GetBudFlags(flags *BudResults) pflag.FlagSet {
if err := fs.MarkHidden("log-rusage"); err != nil {
panic(fmt.Sprintf("error marking the log-rusage flag as hidden: %v", err))
}
fs.StringVar(&flags.Manifest, "manifest", "", "add the image to the specified manifest list. Creates manifest if it does not exist")
fs.BoolVar(&flags.NoCache, "no-cache", false, "Do not use existing cached images for the container build. Build from the start with a new set of cached layers.")
fs.String("os", runtime.GOOS, "set the OS to the provided value instead of the current operating system of the host")
fs.String("platform", parse.DefaultPlatform(), "set the OS/ARCH to the provided value instead of the current operating system and architecture of the host (for example `linux/arm`)")
@ -241,6 +243,7 @@ func GetBudFlagsCompletions() commonComp.FlagCompletions {
flagCompletion["label"] = commonComp.AutocompleteNone
flagCompletion["logfile"] = commonComp.AutocompleteDefault
flagCompletion["loglevel"] = commonComp.AutocompleteDefault
flagCompletion["manifest"] = commonComp.AutocompleteDefault
flagCompletion["os"] = commonComp.AutocompleteNone
flagCompletion["platform"] = commonComp.AutocompleteNone
flagCompletion["runtime-flag"] = commonComp.AutocompleteNone