feat: specify create time for image built with buildpacks (#1685)

* specify the image created time

* add build-timestamp config

* fix trailing white space
This commit is contained in:
Will Li 2023-04-28 15:14:51 +08:00 committed by GitHub
parent 46076a581d
commit cd0dbfd300
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 51 additions and 22 deletions

View File

@ -27,6 +27,7 @@ NAME
SYNOPSIS SYNOPSIS
{{rootCmdUse}} build [-r|--registry] [--builder] [--builder-image] [--push] {{rootCmdUse}} build [-r|--registry] [--builder] [--builder-image] [--push]
[--platform] [-p|--path] [-c|--confirm] [-v|--verbose] [--platform] [-p|--path] [-c|--confirm] [-v|--verbose]
[--build-timestamp]
DESCRIPTION DESCRIPTION
@ -64,7 +65,7 @@ EXAMPLES
`, `,
SuggestFor: []string{"biuld", "buidl", "built"}, SuggestFor: []string{"biuld", "buidl", "built"},
PreRunE: bindEnv("image", "path", "builder", "registry", "confirm", "push", "builder-image", "platform", "verbose"), PreRunE: bindEnv("image", "path", "builder", "registry", "confirm", "push", "builder-image", "platform", "verbose", "build-timestamp"),
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return runBuild(cmd, args, newClient) return runBuild(cmd, args, newClient)
}, },
@ -105,6 +106,7 @@ EXAMPLES
"Specify a custom builder image for use by the builder other than its default. ($FUNC_BUILDER_IMAGE)") "Specify a custom builder image for use by the builder other than its default. ($FUNC_BUILDER_IMAGE)")
cmd.Flags().StringP("image", "i", f.Image, cmd.Flags().StringP("image", "i", f.Image,
"Full image name in the form [registry]/[namespace]/[name]:[tag] (optional). This option takes precedence over --registry ($FUNC_IMAGE)") "Full image name in the form [registry]/[namespace]/[name]:[tag] (optional). This option takes precedence over --registry ($FUNC_IMAGE)")
cmd.Flags().BoolP("build-timestamp", "", false, "Use the actual time as the created time for the docker image. This is only useful for buildpacks builder.")
// Static Flags: // Static Flags:
// Options which have static defaults only (not globally configurable nor // Options which have static defaults only (not globally configurable nor
@ -171,7 +173,9 @@ func runBuild(cmd *cobra.Command, _ []string, newClient ClientFactory) (err erro
if f.Build.Builder == builders.Pack { if f.Build.Builder == builders.Pack {
builder = buildpacks.NewBuilder( builder = buildpacks.NewBuilder(
buildpacks.WithName(builders.Pack), buildpacks.WithName(builders.Pack),
buildpacks.WithVerbose(cfg.Verbose)) buildpacks.WithVerbose(cfg.Verbose),
buildpacks.WithTimestamp(cfg.WithTimestamp),
)
} else if f.Build.Builder == builders.S2I { } else if f.Build.Builder == builders.S2I {
builder = s2i.NewBuilder( builder = s2i.NewBuilder(
s2i.WithName(builders.S2I), s2i.WithName(builders.S2I),
@ -220,6 +224,10 @@ type buildConfig struct {
// Push the resulting image to the registry after building. // Push the resulting image to the registry after building.
Push bool Push bool
// Build with the current timestamp as the created time for docker image.
// This is only useful for buildpacks builder.
WithTimestamp bool
} }
// newBuildConfig gathers options into a single build request. // newBuildConfig gathers options into a single build request.
@ -231,11 +239,12 @@ func newBuildConfig() buildConfig {
Registry: registry(), // deferred defaulting Registry: registry(), // deferred defaulting
Verbose: viper.GetBool("verbose"), Verbose: viper.GetBool("verbose"),
}, },
BuilderImage: viper.GetString("builder-image"), BuilderImage: viper.GetString("builder-image"),
Image: viper.GetString("image"), Image: viper.GetString("image"),
Path: viper.GetString("path"), Path: viper.GetString("path"),
Platform: viper.GetString("platform"), Platform: viper.GetString("platform"),
Push: viper.GetBool("push"), Push: viper.GetBool("push"),
WithTimestamp: viper.GetBool("build-timestamp"),
} }
} }

View File

@ -32,7 +32,7 @@ SYNOPSIS
{{rootCmdUse}} deploy [-R|--remote] [-r|--registry] [-i|--image] [-n|--namespace] {{rootCmdUse}} deploy [-R|--remote] [-r|--registry] [-i|--image] [-n|--namespace]
[-e|env] [-g|--git-url] [-t|git-branch] [-d|--git-dir] [-e|env] [-g|--git-url] [-t|git-branch] [-d|--git-dir]
[-b|--build] [--builder] [--builder-image] [-p|--push] [-b|--build] [--builder] [--builder-image] [-p|--push]
[--platform] [-c|--confirm] [-v|--verbose] [--platform] [-c|--confirm] [-v|--verbose] [--build-timestamp]
DESCRIPTION DESCRIPTION
@ -116,7 +116,7 @@ EXAMPLES
`, `,
SuggestFor: []string{"delpoy", "deplyo"}, SuggestFor: []string{"delpoy", "deplyo"},
PreRunE: bindEnv("confirm", "env", "git-url", "git-branch", "git-dir", "remote", "build", "builder", "builder-image", "image", "registry", "push", "platform", "namespace", "path", "verbose", "pvc-size"), PreRunE: bindEnv("confirm", "env", "git-url", "git-branch", "git-dir", "remote", "build", "builder", "builder-image", "image", "registry", "push", "platform", "namespace", "path", "verbose", "pvc-size", "build-timestamp"),
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return runDeploy(cmd, newClient) return runDeploy(cmd, newClient)
}, },
@ -178,6 +178,7 @@ EXAMPLES
"Push the function image to registry before deploying. ($FUNC_PUSH)") "Push the function image to registry before deploying. ($FUNC_PUSH)")
cmd.Flags().String("platform", "", cmd.Flags().String("platform", "",
"Optionally specify a specific platform to build for (e.g. linux/amd64). ($FUNC_PLATFORM)") "Optionally specify a specific platform to build for (e.g. linux/amd64). ($FUNC_PLATFORM)")
cmd.Flags().BoolP("build-timestamp", "", false, "Use the actual time as the created time for the docker image. This is only useful for buildpacks builder.")
// Oft-shared flags: // Oft-shared flags:
addConfirmFlag(cmd, cfg.Confirm) addConfirmFlag(cmd, cfg.Confirm)
@ -240,7 +241,9 @@ func runDeploy(cmd *cobra.Command, newClient ClientFactory) (err error) {
if f.Build.Builder == builders.Pack { if f.Build.Builder == builders.Pack {
builder = buildpacks.NewBuilder( builder = buildpacks.NewBuilder(
buildpacks.WithName(builders.Pack), buildpacks.WithName(builders.Pack),
buildpacks.WithVerbose(cfg.Verbose)) buildpacks.WithVerbose(cfg.Verbose),
buildpacks.WithTimestamp(cfg.WithTimestamp),
)
} else if f.Build.Builder == builders.S2I { } else if f.Build.Builder == builders.S2I {
builder = s2i.NewBuilder( builder = s2i.NewBuilder(
s2i.WithName(builders.S2I), s2i.WithName(builders.S2I),
@ -374,21 +377,26 @@ type deployConfig struct {
// PVCSize configures the PVC size used by the pipeline if --remote flag is set. // PVCSize configures the PVC size used by the pipeline if --remote flag is set.
PVCSize string PVCSize string
// Build with the current timestamp as the created time for docker image.
// This is only useful for buildpacks builder.
WithTimestamp bool
} }
// newDeployConfig creates a buildConfig populated from command flags and // newDeployConfig creates a buildConfig populated from command flags and
// environment variables; in that precedence. // environment variables; in that precedence.
func newDeployConfig(cmd *cobra.Command) (c deployConfig) { func newDeployConfig(cmd *cobra.Command) (c deployConfig) {
c = deployConfig{ c = deployConfig{
buildConfig: newBuildConfig(), buildConfig: newBuildConfig(),
Build: viper.GetString("build"), Build: viper.GetString("build"),
Env: viper.GetStringSlice("env"), Env: viper.GetStringSlice("env"),
GitBranch: viper.GetString("git-branch"), GitBranch: viper.GetString("git-branch"),
GitDir: viper.GetString("git-dir"), GitDir: viper.GetString("git-dir"),
GitURL: viper.GetString("git-url"), GitURL: viper.GetString("git-url"),
Namespace: viper.GetString("namespace"), Namespace: viper.GetString("namespace"),
Remote: viper.GetBool("remote"), Remote: viper.GetBool("remote"),
PVCSize: viper.GetString("pvc-size"), PVCSize: viper.GetString("pvc-size"),
WithTimestamp: viper.GetBool("build-timestamp"),
} }
// NOTE: .Env should be viper.GetStringSlice, but this returns unparsed // NOTE: .Env should be viper.GetStringSlice, but this returns unparsed
// results and appears to be an open issue since 2017: // results and appears to be an open issue since 2017:

View File

@ -7,6 +7,7 @@ import (
"io" "io"
"runtime" "runtime"
"strings" "strings"
"time"
"github.com/Masterminds/semver" "github.com/Masterminds/semver"
pack "github.com/buildpacks/pack/pkg/client" pack "github.com/buildpacks/pack/pkg/client"
@ -50,9 +51,10 @@ type Builder struct {
name string name string
verbose bool verbose bool
// in non-verbose mode contains std[err,out], so it can be printed on error // in non-verbose mode contains std[err,out], so it can be printed on error
outBuff bytes.Buffer outBuff bytes.Buffer
logger logging.Logger logger logging.Logger
impl Impl impl Impl
withTimestamp bool
} }
// Impl allows for the underlying implementation to be mocked for tests. // Impl allows for the underlying implementation to be mocked for tests.
@ -97,6 +99,12 @@ func WithImpl(i Impl) Option {
} }
} }
func WithTimestamp(v bool) Option {
return func(b *Builder) {
b.withTimestamp = v
}
}
var DefaultLifecycleImage = "quay.io/boson/lifecycle@sha256:f53fea9ec9188b92cab0b8a298ff852d76a6c2aaf56f968a08637e13de0e0c59" var DefaultLifecycleImage = "quay.io/boson/lifecycle@sha256:f53fea9ec9188b92cab0b8a298ff852d76a6c2aaf56f968a08637e13de0e0c59"
// Build the Function at path. // Build the Function at path.
@ -119,6 +127,10 @@ func (b *Builder) Build(ctx context.Context, f fn.Function) (err error) {
Volumes []string Volumes []string
}{Network: "", Volumes: nil}, }{Network: "", Volumes: nil},
} }
if b.withTimestamp {
now := time.Now()
opts.CreationTime = &now
}
if opts.Env, err = fn.Interpolate(f.Build.BuildEnvs); err != nil { if opts.Env, err = fn.Interpolate(f.Build.BuildEnvs); err != nil {
return err return err
} }