mirror of
https://github.com/kubernetes-sigs/kind.git
synced 2025-12-01 07:26:05 +07:00
switch to functional options for image builds
This commit is contained in:
@@ -24,8 +24,8 @@ import (
|
||||
)
|
||||
|
||||
type flags struct {
|
||||
Source string
|
||||
ImageName string
|
||||
Source string
|
||||
Image string
|
||||
}
|
||||
|
||||
// NewCommand returns a new cobra.Command for building the base image
|
||||
@@ -41,14 +41,16 @@ func NewCommand() *cobra.Command {
|
||||
},
|
||||
}
|
||||
cmd.Flags().StringVar(&flags.Source, "source", "", "path to the base image sources")
|
||||
cmd.Flags().StringVar(&flags.ImageName, "image", "kind-base", "name of the resulting image to be built")
|
||||
cmd.Flags().StringVar(&flags.Image, "image", "kind-base", "name of the resulting image to be built")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func run(flags *flags, cmd *cobra.Command, args []string) {
|
||||
// TODO(bentheelder): make this more configurable
|
||||
ctx := base.NewBuildContext(flags.ImageName)
|
||||
ctx.SourceDir = flags.Source
|
||||
ctx := base.NewBuildContext(
|
||||
base.WithImageTag(flags.Image),
|
||||
base.WithSourceDir(flags.Source),
|
||||
)
|
||||
err := ctx.Build()
|
||||
if err != nil {
|
||||
log.Fatalf("Build failed! %v", err)
|
||||
|
||||
@@ -50,7 +50,11 @@ func NewCommand() *cobra.Command {
|
||||
|
||||
func run(flags *flags, cmd *cobra.Command, args []string) {
|
||||
// TODO(bentheelder): make this more configurable
|
||||
ctx, err := node.NewBuildContext(flags.BuildType, flags.ImageName, flags.BaseImageName)
|
||||
ctx, err := node.NewBuildContext(
|
||||
node.WithMode(flags.BuildType),
|
||||
node.WithImageTag(flags.ImageName),
|
||||
node.WithBaseImage(flags.BaseImageName),
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatalf("Error creating build context: %v", err)
|
||||
}
|
||||
|
||||
@@ -28,23 +28,47 @@ import (
|
||||
"sigs.k8s.io/kind/pkg/fs"
|
||||
)
|
||||
|
||||
// DefaultImageName is the default name of the built base image
|
||||
const DefaultImageName = "kind-base"
|
||||
|
||||
// BuildContext is used to build the kind node base image, and contains
|
||||
// build configuration
|
||||
type BuildContext struct {
|
||||
SourceDir string
|
||||
ImageTag string
|
||||
GoCmd string
|
||||
Arch string
|
||||
sourceDir string
|
||||
imageTag string
|
||||
goCmd string
|
||||
arch string
|
||||
}
|
||||
|
||||
// Option is BuildContext configuration option supplied to NewBuildContext
|
||||
type Option func(*BuildContext)
|
||||
|
||||
// WithSourceDir configures a NewBuildContext to use the source dir `sourceDir`
|
||||
func WithSourceDir(sourceDir string) Option {
|
||||
return func(b *BuildContext) {
|
||||
b.sourceDir = sourceDir
|
||||
}
|
||||
}
|
||||
|
||||
// WithImageTag configures a NewBuildContext to tag the built image with `tag`
|
||||
func WithImageTag(tag string) Option {
|
||||
return func(b *BuildContext) {
|
||||
b.imageTag = tag
|
||||
}
|
||||
}
|
||||
|
||||
// NewBuildContext creates a new BuildContext with
|
||||
// default configuration
|
||||
func NewBuildContext(imageName string) *BuildContext {
|
||||
return &BuildContext{
|
||||
ImageTag: imageName,
|
||||
GoCmd: "go",
|
||||
Arch: "amd64",
|
||||
func NewBuildContext(options ...Option) *BuildContext {
|
||||
ctx := &BuildContext{
|
||||
imageTag: DefaultImageName,
|
||||
goCmd: "go",
|
||||
arch: "amd64",
|
||||
}
|
||||
for _, option := range options {
|
||||
option(ctx)
|
||||
}
|
||||
return ctx
|
||||
}
|
||||
|
||||
// Build builds the cluster node image, the sourcedir must be set on
|
||||
@@ -60,7 +84,7 @@ func (c *BuildContext) Build() (err error) {
|
||||
// populate with image sources
|
||||
// if SourceDir is unset, use the baked in sources
|
||||
buildDir := tmpDir
|
||||
if c.SourceDir == "" {
|
||||
if c.sourceDir == "" {
|
||||
// populate with image sources
|
||||
err = sources.RestoreAssets(buildDir, "images/base")
|
||||
if err != nil {
|
||||
@@ -69,7 +93,7 @@ func (c *BuildContext) Build() (err error) {
|
||||
buildDir = filepath.Join(buildDir, "images", "base")
|
||||
|
||||
} else {
|
||||
err = fs.CopyDir(c.SourceDir, buildDir)
|
||||
err = fs.CopyDir(c.sourceDir, buildDir)
|
||||
if err != nil {
|
||||
log.Errorf("failed to copy sources to build dir %v", err)
|
||||
return err
|
||||
@@ -93,9 +117,9 @@ func (c *BuildContext) buildEntrypoint(dir string) error {
|
||||
entrypointSrc := filepath.Join(dir, "entrypoint", "main.go")
|
||||
entrypointDest := filepath.Join(dir, "entrypoint", "entrypoint")
|
||||
|
||||
cmd := exec.Command(c.GoCmd, "build", "-o", entrypointDest, entrypointSrc)
|
||||
cmd := exec.Command(c.goCmd, "build", "-o", entrypointDest, entrypointSrc)
|
||||
// TODO(bentheelder): we may need to map between docker image arch and GOARCH
|
||||
cmd.Env = []string{"GOOS=linux", "GOARCH=" + c.Arch}
|
||||
cmd.Env = []string{"GOOS=linux", "GOARCH=" + c.arch}
|
||||
|
||||
// actually build
|
||||
log.Info("Building entrypoint binary ...")
|
||||
@@ -111,7 +135,7 @@ func (c *BuildContext) buildEntrypoint(dir string) error {
|
||||
|
||||
func (c *BuildContext) buildImage(dir string) error {
|
||||
// build the image, tagged as tagImageAs, using the our tempdir as the context
|
||||
cmd := exec.Command("docker", "build", "-t", c.ImageTag, dir)
|
||||
cmd := exec.Command("docker", "build", "-t", c.imageTag, dir)
|
||||
cmd.Debug = true
|
||||
cmd.InheritOutput = true
|
||||
|
||||
|
||||
@@ -31,38 +31,84 @@ import (
|
||||
"sigs.k8s.io/kind/pkg/fs"
|
||||
)
|
||||
|
||||
// DefaultTag is the default tag for the built image
|
||||
const DefaultTag = "kind-node"
|
||||
|
||||
// DefaultBaseImage is the default base image used
|
||||
const DefaultBaseImage = "kind-base"
|
||||
|
||||
// DefaultMode is the default kubernetes build mode for the built image
|
||||
// see pkg/build/kube.Bits
|
||||
const DefaultMode = "docker"
|
||||
|
||||
// Option is BuildContext configuration option supplied to NewBuildContext
|
||||
type Option func(*BuildContext)
|
||||
|
||||
// WithImageTag configures a NewBuildContext to tag the built image with `tag`
|
||||
func WithImageTag(tag string) Option {
|
||||
return func(b *BuildContext) {
|
||||
b.imageTag = tag
|
||||
}
|
||||
}
|
||||
|
||||
// WithBaseImage configures a NewBuildContext to use `image` as the base image
|
||||
func WithBaseImage(image string) Option {
|
||||
return func(b *BuildContext) {
|
||||
b.baseImage = image
|
||||
}
|
||||
}
|
||||
|
||||
// WithMode sets the kubernetes build mode for the build context
|
||||
func WithMode(mode string) Option {
|
||||
return func(b *BuildContext) {
|
||||
b.mode = mode
|
||||
}
|
||||
}
|
||||
|
||||
// BuildContext is used to build the kind node image, and contains
|
||||
// build configuration
|
||||
type BuildContext struct {
|
||||
ImageTag string
|
||||
Arch string
|
||||
BaseImage string
|
||||
KubeRoot string
|
||||
Bits kube.Bits
|
||||
// option fields
|
||||
mode string
|
||||
imageTag string
|
||||
arch string
|
||||
baseImage string
|
||||
// non-option fields
|
||||
kubeRoot string
|
||||
bits kube.Bits
|
||||
}
|
||||
|
||||
// NewBuildContext creates a new BuildContext with
|
||||
// default configuration
|
||||
func NewBuildContext(mode, imageName, baseImageName string) (ctx *BuildContext, err error) {
|
||||
kubeRoot := ""
|
||||
// NewBuildContext creates a new BuildContext with default configuration,
|
||||
// overridden by the options supplied in the order that they are supplied
|
||||
func NewBuildContext(options ...Option) (ctx *BuildContext, err error) {
|
||||
// default options
|
||||
ctx = &BuildContext{
|
||||
mode: DefaultMode,
|
||||
imageTag: DefaultTag,
|
||||
arch: "amd64",
|
||||
baseImage: DefaultBaseImage,
|
||||
}
|
||||
// apply user options
|
||||
for _, option := range options {
|
||||
option(ctx)
|
||||
}
|
||||
// lookup kuberoot unless mode == "apt",
|
||||
// apt should not fail on finding kube root as it does not use it
|
||||
if mode != "apt" {
|
||||
kubeRoot := ""
|
||||
if ctx.mode != "apt" {
|
||||
kubeRoot, err = kube.FindSource()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error finding kuberoot: %v", err)
|
||||
}
|
||||
}
|
||||
bits, err := kube.NewNamedBits(mode, kubeRoot)
|
||||
ctx.kubeRoot = kubeRoot
|
||||
// initialize bits
|
||||
bits, err := kube.NewNamedBits(ctx.mode, kubeRoot)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &BuildContext{
|
||||
ImageTag: imageName,
|
||||
Arch: "amd64",
|
||||
BaseImage: baseImageName,
|
||||
KubeRoot: kubeRoot,
|
||||
Bits: bits,
|
||||
}, nil
|
||||
ctx.bits = bits
|
||||
return ctx, nil
|
||||
}
|
||||
|
||||
// Build builds the cluster node image, the sourcedir must be set on
|
||||
@@ -70,7 +116,7 @@ func NewBuildContext(mode, imageName, baseImageName string) (ctx *BuildContext,
|
||||
func (c *BuildContext) Build() (err error) {
|
||||
// ensure kubernetes build is up to date first
|
||||
log.Infof("Starting to build Kubernetes")
|
||||
if err = c.Bits.Build(); err != nil {
|
||||
if err = c.bits.Build(); err != nil {
|
||||
log.Errorf("Failed to build Kubernetes: %v", err)
|
||||
return errors.Wrap(err, "failed to build kubernetes")
|
||||
}
|
||||
@@ -102,7 +148,7 @@ func (c *BuildContext) populateBits(buildDir string) error {
|
||||
}
|
||||
// copy all bits from their source path to where we will COPY them into
|
||||
// the dockerfile, see images/node/Dockerfile
|
||||
bitPaths := c.Bits.Paths()
|
||||
bitPaths := c.bits.Paths()
|
||||
for src, dest := range bitPaths {
|
||||
realDest := path.Join(bitsDir, dest)
|
||||
// NOTE: we use copy not copyfile because copy ensures the dest dir
|
||||
@@ -189,7 +235,7 @@ func (c *BuildContext) buildImage(dir string) error {
|
||||
basePath: "/kind/",
|
||||
containerID: containerID,
|
||||
}
|
||||
if err = c.Bits.Install(ic); err != nil {
|
||||
if err = c.bits.Install(ic); err != nil {
|
||||
log.Errorf("Image build Failed! %v", err)
|
||||
return err
|
||||
}
|
||||
@@ -203,7 +249,7 @@ func (c *BuildContext) buildImage(dir string) error {
|
||||
}
|
||||
|
||||
// Save the image changes to a new image
|
||||
cmd := exec.Command("docker", "commit", containerID, c.ImageTag)
|
||||
cmd := exec.Command("docker", "commit", containerID, c.imageTag)
|
||||
cmd.Debug = true
|
||||
cmd.InheritOutput = true
|
||||
if err = cmd.Run(); err != nil {
|
||||
@@ -222,7 +268,7 @@ func (c *BuildContext) createBuildContainer(buildDir string) (id string, err err
|
||||
// label the container to make them easier to track
|
||||
"--label", fmt.Sprintf("%s=%s", BuildContainerLabelKey, time.Now().Format(time.RFC3339Nano)),
|
||||
"-v", fmt.Sprintf("%s:/build", buildDir),
|
||||
c.BaseImage,
|
||||
c.baseImage,
|
||||
)
|
||||
cmd.Debug = true
|
||||
lines, err := cmd.CombinedOutputLines()
|
||||
|
||||
Reference in New Issue
Block a user