drone-kaniko/kaniko.go

244 lines
8.2 KiB
Go
Raw Normal View History

2020-11-16 19:11:59 +01:00
package kaniko
2020-11-16 18:37:13 +01:00
import (
"fmt"
"io/ioutil"
2020-11-16 18:37:13 +01:00
"os"
"os/exec"
"strings"
"github.com/drone/drone-kaniko/pkg/artifact"
Port the auto tag feature from docker plugin (#36) * Port the auto tag feature from https://plugins.drone.io/drone-plugins/drone-docker The logic is forked from https://github.com/drone-plugins/drone-docker code base with necessary modification. I've tested it e2e for DockerHub on my Drone server via this plugin image https://hub.docker.com/repository/docker/15cm/drone-kaniko, for both tag pushes and commit pushes. With this change the .drone.yml in this repo should work as intended. Other changes: - Rename the existing "auto tag" flags/code to "expand tag" for a less misleading naming. - ATTENTION: make a breaking change to set default value of "--tags" to empty. Rationale is to expect most users to use the auto tagging feature. When power users want to specify tags, they should always explicitly set tags instead of being surprised by the default "latest" tag. * Change how --auto-tag flag works with other flags The --auto-tag has to be a breaking change. This commit limit the breaking impact to the users who enable the flag. Behaviors of flag combination after this commit: * --auto-tag=false: No changes. * --auto-tag=false,--expand-tag=true,tags=1.0.0: * Old behavior: Should not happen. --expand-tag didn't exist. * New Behavior: Build with [1,1.0,1.0.0] tags. * --auto-tag=true * Old behavior: Build with the "latest" tag. * New behavior: Build with auto detected tags. Abort if auto detection failed. * --auto-tag=true,tags=latest: same as "--auto-tag=true". * --auto-tag=true,tags=1.0.0: * Old behavior: Build with [1,1.0,1.0.0] tags. * New behavior: Abort the build with an error message. * --auto-tag=true,--expand-tag=true,tags=1.0.0: Abort the build with an error message. Also added a test for the integration of the BUILD struct and the tagger package, which is used by kaniko.go. * Update readme to note that expand-tag and auto-tag don't support artifacts
2022-02-10 08:36:14 +01:00
"github.com/drone/drone-kaniko/pkg/tagger"
"golang.org/x/mod/semver"
2020-11-16 18:37:13 +01:00
)
type (
// Build defines Docker build parameters.
Build struct {
DroneCommitRef string // Drone git commit reference
DroneRepoBranch string // Drone repo branch
Dockerfile string // Docker build Dockerfile
Context string // Docker build context
Tags []string // Docker build tags
AutoTag bool // Set this to auto detect tags from git commits and semver-tagged labels
AutoTagSuffix string // Suffix to append to the auto detect tags
ExpandTag bool // Set this to expand the `Tags` into semver-tagged labels
Args []string // Docker build args
Target string // Docker build target
Repo string // Docker build repository
Mirrors []string // Docker repository mirrors
Labels []string // Label map
SkipTlsVerify bool // Docker skip tls certificate verify for registry
SnapshotMode string // Kaniko snapshot mode
EnableCache bool // Whether to enable kaniko cache
CacheRepo string // Remote repository that will be used to store cached layers
CacheTTL int // Cache timeout in hours
DigestFile string // Digest file location
NoPush bool // Set this flag if you only want to build the image, without pushing to a registry
Verbosity string // Log level
Platform string // Allows to build with another default platform than the host, similarly to docker build --platform
SkipUnusedStages bool // Build only used stages
}
// Artifact defines content of artifact file
Artifact struct {
Tags []string // Docker artifact tags
Repo string // Docker artifact repository
Registry string // Docker artifact registry
RegistryType artifact.RegistryTypeEnum // Rocker artifact registry type
ArtifactFile string // Artifact file location
2020-11-16 18:37:13 +01:00
}
// Plugin defines the Docker plugin parameters.
Plugin struct {
Build Build // Docker build configuration
Artifact Artifact // Artifact file content
2020-11-16 18:37:13 +01:00
}
)
Port the auto tag feature from docker plugin (#36) * Port the auto tag feature from https://plugins.drone.io/drone-plugins/drone-docker The logic is forked from https://github.com/drone-plugins/drone-docker code base with necessary modification. I've tested it e2e for DockerHub on my Drone server via this plugin image https://hub.docker.com/repository/docker/15cm/drone-kaniko, for both tag pushes and commit pushes. With this change the .drone.yml in this repo should work as intended. Other changes: - Rename the existing "auto tag" flags/code to "expand tag" for a less misleading naming. - ATTENTION: make a breaking change to set default value of "--tags" to empty. Rationale is to expect most users to use the auto tagging feature. When power users want to specify tags, they should always explicitly set tags instead of being surprised by the default "latest" tag. * Change how --auto-tag flag works with other flags The --auto-tag has to be a breaking change. This commit limit the breaking impact to the users who enable the flag. Behaviors of flag combination after this commit: * --auto-tag=false: No changes. * --auto-tag=false,--expand-tag=true,tags=1.0.0: * Old behavior: Should not happen. --expand-tag didn't exist. * New Behavior: Build with [1,1.0,1.0.0] tags. * --auto-tag=true * Old behavior: Build with the "latest" tag. * New behavior: Build with auto detected tags. Abort if auto detection failed. * --auto-tag=true,tags=latest: same as "--auto-tag=true". * --auto-tag=true,tags=1.0.0: * Old behavior: Build with [1,1.0,1.0.0] tags. * New behavior: Abort the build with an error message. * --auto-tag=true,--expand-tag=true,tags=1.0.0: Abort the build with an error message. Also added a test for the integration of the BUILD struct and the tagger package, which is used by kaniko.go. * Update readme to note that expand-tag and auto-tag don't support artifacts
2022-02-10 08:36:14 +01:00
// labelsForTag returns the labels to use for the given tag, subject to the value of ExpandTag.
//
// Build information (e.g. +linux_amd64) is carried through to all labels.
// Pre-release information (e.g. -rc1) suppresses major and major+minor auto-labels.
func (b Build) labelsForTag(tag string) (labels []string) {
// We strip "v" off of the beginning of semantic versions, as they are not used in docker tags
const VersionPrefix = "v"
// Semantic Versions don't allow underscores, so replace them with dashes.
// https://semver.org/
semverTag := strings.ReplaceAll(tag, "_", "-")
// Allow tags of the form "1.2.3" as well as "v1.2.3" to avoid confusion.
if withV := VersionPrefix + semverTag; !semver.IsValid(semverTag) && semver.IsValid(withV) {
semverTag = withV
}
Port the auto tag feature from docker plugin (#36) * Port the auto tag feature from https://plugins.drone.io/drone-plugins/drone-docker The logic is forked from https://github.com/drone-plugins/drone-docker code base with necessary modification. I've tested it e2e for DockerHub on my Drone server via this plugin image https://hub.docker.com/repository/docker/15cm/drone-kaniko, for both tag pushes and commit pushes. With this change the .drone.yml in this repo should work as intended. Other changes: - Rename the existing "auto tag" flags/code to "expand tag" for a less misleading naming. - ATTENTION: make a breaking change to set default value of "--tags" to empty. Rationale is to expect most users to use the auto tagging feature. When power users want to specify tags, they should always explicitly set tags instead of being surprised by the default "latest" tag. * Change how --auto-tag flag works with other flags The --auto-tag has to be a breaking change. This commit limit the breaking impact to the users who enable the flag. Behaviors of flag combination after this commit: * --auto-tag=false: No changes. * --auto-tag=false,--expand-tag=true,tags=1.0.0: * Old behavior: Should not happen. --expand-tag didn't exist. * New Behavior: Build with [1,1.0,1.0.0] tags. * --auto-tag=true * Old behavior: Build with the "latest" tag. * New behavior: Build with auto detected tags. Abort if auto detection failed. * --auto-tag=true,tags=latest: same as "--auto-tag=true". * --auto-tag=true,tags=1.0.0: * Old behavior: Build with [1,1.0,1.0.0] tags. * New behavior: Abort the build with an error message. * --auto-tag=true,--expand-tag=true,tags=1.0.0: Abort the build with an error message. Also added a test for the integration of the BUILD struct and the tagger package, which is used by kaniko.go. * Update readme to note that expand-tag and auto-tag don't support artifacts
2022-02-10 08:36:14 +01:00
// Pass through tags if expand-tag is not set, or if the tag is not a semantic version
if !b.ExpandTag || !semver.IsValid(semverTag) {
return []string{tag}
}
tag = semverTag
// If the version is pre-release, only the full release should be tagged, not the major/minor versions.
if semver.Prerelease(tag) != "" {
return []string{
strings.TrimPrefix(tag, VersionPrefix),
}
}
// tagFor carries any build information from the semantic version through to major and minor tags.
labelFor := func(base string) string {
return strings.TrimPrefix(base, VersionPrefix) + semver.Build(tag)
}
return []string{
labelFor(semver.Major(tag)),
labelFor(semver.MajorMinor(tag)),
labelFor(semver.Canonical(tag)),
}
}
Port the auto tag feature from docker plugin (#36) * Port the auto tag feature from https://plugins.drone.io/drone-plugins/drone-docker The logic is forked from https://github.com/drone-plugins/drone-docker code base with necessary modification. I've tested it e2e for DockerHub on my Drone server via this plugin image https://hub.docker.com/repository/docker/15cm/drone-kaniko, for both tag pushes and commit pushes. With this change the .drone.yml in this repo should work as intended. Other changes: - Rename the existing "auto tag" flags/code to "expand tag" for a less misleading naming. - ATTENTION: make a breaking change to set default value of "--tags" to empty. Rationale is to expect most users to use the auto tagging feature. When power users want to specify tags, they should always explicitly set tags instead of being surprised by the default "latest" tag. * Change how --auto-tag flag works with other flags The --auto-tag has to be a breaking change. This commit limit the breaking impact to the users who enable the flag. Behaviors of flag combination after this commit: * --auto-tag=false: No changes. * --auto-tag=false,--expand-tag=true,tags=1.0.0: * Old behavior: Should not happen. --expand-tag didn't exist. * New Behavior: Build with [1,1.0,1.0.0] tags. * --auto-tag=true * Old behavior: Build with the "latest" tag. * New behavior: Build with auto detected tags. Abort if auto detection failed. * --auto-tag=true,tags=latest: same as "--auto-tag=true". * --auto-tag=true,tags=1.0.0: * Old behavior: Build with [1,1.0,1.0.0] tags. * New behavior: Abort the build with an error message. * --auto-tag=true,--expand-tag=true,tags=1.0.0: Abort the build with an error message. Also added a test for the integration of the BUILD struct and the tagger package, which is used by kaniko.go. * Update readme to note that expand-tag and auto-tag don't support artifacts
2022-02-10 08:36:14 +01:00
// Returns the auto detected tags. See the AutoTag section of
// https://plugins.drone.io/drone-plugins/drone-docker/ for more info.
func (b Build) AutoTags() (tags []string, err error) {
if len(b.Tags) > 1 || len(b.Tags) == 1 && b.Tags[0] != "latest" {
err = fmt.Errorf("The auto-tag flag does not work with user provided tags %s", b.Tags)
return
}
// We have tried the best to prevent enabling auto-tag and passing in
// user specified at the same time. Starts to auto detect tags.
// Note: passing in a "latest" tag with auto-tag enabled won't trigger the
// early returns above, because we cannot tell if the tag is provided by
2022-02-10 14:06:36 +01:00
// the default value or by the users.
Port the auto tag feature from docker plugin (#36) * Port the auto tag feature from https://plugins.drone.io/drone-plugins/drone-docker The logic is forked from https://github.com/drone-plugins/drone-docker code base with necessary modification. I've tested it e2e for DockerHub on my Drone server via this plugin image https://hub.docker.com/repository/docker/15cm/drone-kaniko, for both tag pushes and commit pushes. With this change the .drone.yml in this repo should work as intended. Other changes: - Rename the existing "auto tag" flags/code to "expand tag" for a less misleading naming. - ATTENTION: make a breaking change to set default value of "--tags" to empty. Rationale is to expect most users to use the auto tagging feature. When power users want to specify tags, they should always explicitly set tags instead of being surprised by the default "latest" tag. * Change how --auto-tag flag works with other flags The --auto-tag has to be a breaking change. This commit limit the breaking impact to the users who enable the flag. Behaviors of flag combination after this commit: * --auto-tag=false: No changes. * --auto-tag=false,--expand-tag=true,tags=1.0.0: * Old behavior: Should not happen. --expand-tag didn't exist. * New Behavior: Build with [1,1.0,1.0.0] tags. * --auto-tag=true * Old behavior: Build with the "latest" tag. * New behavior: Build with auto detected tags. Abort if auto detection failed. * --auto-tag=true,tags=latest: same as "--auto-tag=true". * --auto-tag=true,tags=1.0.0: * Old behavior: Build with [1,1.0,1.0.0] tags. * New behavior: Abort the build with an error message. * --auto-tag=true,--expand-tag=true,tags=1.0.0: Abort the build with an error message. Also added a test for the integration of the BUILD struct and the tagger package, which is used by kaniko.go. * Update readme to note that expand-tag and auto-tag don't support artifacts
2022-02-10 08:36:14 +01:00
commitRef := b.DroneCommitRef
if !tagger.UseAutoTag(commitRef, b.DroneRepoBranch) {
err = fmt.Errorf("Could not auto detect the tag. Skipping automated docker build for commit %s", commitRef)
return
}
tags, err = tagger.AutoTagsSuffix(commitRef, b.AutoTagSuffix)
if err != nil {
err = fmt.Errorf("Invalid semantic version when auto detecting the tag. Skipping automated docker build for %s.", commitRef)
}
return
}
2020-11-16 18:37:13 +01:00
// Exec executes the plugin step
func (p Plugin) Exec() error {
if !p.Build.NoPush && p.Build.Repo == "" {
2020-11-16 18:37:13 +01:00
return fmt.Errorf("repository name to publish image must be specified")
}
if _, err := os.Stat(p.Build.Dockerfile); os.IsNotExist(err) {
return fmt.Errorf("dockerfile does not exist at path: %s", p.Build.Dockerfile)
}
Port the auto tag feature from docker plugin (#36) * Port the auto tag feature from https://plugins.drone.io/drone-plugins/drone-docker The logic is forked from https://github.com/drone-plugins/drone-docker code base with necessary modification. I've tested it e2e for DockerHub on my Drone server via this plugin image https://hub.docker.com/repository/docker/15cm/drone-kaniko, for both tag pushes and commit pushes. With this change the .drone.yml in this repo should work as intended. Other changes: - Rename the existing "auto tag" flags/code to "expand tag" for a less misleading naming. - ATTENTION: make a breaking change to set default value of "--tags" to empty. Rationale is to expect most users to use the auto tagging feature. When power users want to specify tags, they should always explicitly set tags instead of being surprised by the default "latest" tag. * Change how --auto-tag flag works with other flags The --auto-tag has to be a breaking change. This commit limit the breaking impact to the users who enable the flag. Behaviors of flag combination after this commit: * --auto-tag=false: No changes. * --auto-tag=false,--expand-tag=true,tags=1.0.0: * Old behavior: Should not happen. --expand-tag didn't exist. * New Behavior: Build with [1,1.0,1.0.0] tags. * --auto-tag=true * Old behavior: Build with the "latest" tag. * New behavior: Build with auto detected tags. Abort if auto detection failed. * --auto-tag=true,tags=latest: same as "--auto-tag=true". * --auto-tag=true,tags=1.0.0: * Old behavior: Build with [1,1.0,1.0.0] tags. * New behavior: Abort the build with an error message. * --auto-tag=true,--expand-tag=true,tags=1.0.0: Abort the build with an error message. Also added a test for the integration of the BUILD struct and the tagger package, which is used by kaniko.go. * Update readme to note that expand-tag and auto-tag don't support artifacts
2022-02-10 08:36:14 +01:00
var tags = p.Build.Tags
if p.Build.AutoTag && p.Build.ExpandTag {
return fmt.Errorf("The auto-tag flag conflicts with the expand-tag flag")
}
if p.Build.AutoTag {
var err error
tags, err = p.Build.AutoTags()
if err != nil {
return err
}
}
2020-11-16 18:37:13 +01:00
cmdArgs := []string{
fmt.Sprintf("--dockerfile=%s", p.Build.Dockerfile),
fmt.Sprintf("--context=dir://%s", p.Build.Context),
}
// Set the destination repository
if !p.Build.NoPush {
Port the auto tag feature from docker plugin (#36) * Port the auto tag feature from https://plugins.drone.io/drone-plugins/drone-docker The logic is forked from https://github.com/drone-plugins/drone-docker code base with necessary modification. I've tested it e2e for DockerHub on my Drone server via this plugin image https://hub.docker.com/repository/docker/15cm/drone-kaniko, for both tag pushes and commit pushes. With this change the .drone.yml in this repo should work as intended. Other changes: - Rename the existing "auto tag" flags/code to "expand tag" for a less misleading naming. - ATTENTION: make a breaking change to set default value of "--tags" to empty. Rationale is to expect most users to use the auto tagging feature. When power users want to specify tags, they should always explicitly set tags instead of being surprised by the default "latest" tag. * Change how --auto-tag flag works with other flags The --auto-tag has to be a breaking change. This commit limit the breaking impact to the users who enable the flag. Behaviors of flag combination after this commit: * --auto-tag=false: No changes. * --auto-tag=false,--expand-tag=true,tags=1.0.0: * Old behavior: Should not happen. --expand-tag didn't exist. * New Behavior: Build with [1,1.0,1.0.0] tags. * --auto-tag=true * Old behavior: Build with the "latest" tag. * New behavior: Build with auto detected tags. Abort if auto detection failed. * --auto-tag=true,tags=latest: same as "--auto-tag=true". * --auto-tag=true,tags=1.0.0: * Old behavior: Build with [1,1.0,1.0.0] tags. * New behavior: Abort the build with an error message. * --auto-tag=true,--expand-tag=true,tags=1.0.0: Abort the build with an error message. Also added a test for the integration of the BUILD struct and the tagger package, which is used by kaniko.go. * Update readme to note that expand-tag and auto-tag don't support artifacts
2022-02-10 08:36:14 +01:00
for _, tag := range tags {
for _, label := range p.Build.labelsForTag(tag) {
cmdArgs = append(cmdArgs, fmt.Sprintf("--destination=%s:%s", p.Build.Repo, label))
}
}
2020-11-16 18:37:13 +01:00
}
// Set the build arguments
for _, arg := range p.Build.Args {
cmdArgs = append(cmdArgs, fmt.Sprintf("--build-arg=%s", arg))
}
// Set the labels
for _, label := range p.Build.Labels {
2021-01-18 16:42:53 +01:00
cmdArgs = append(cmdArgs, fmt.Sprintf("--label=%s", label))
2020-11-16 18:37:13 +01:00
}
2022-03-15 07:15:57 +01:00
// Set repository mirrors
for _, mirror := range p.Build.Mirrors {
cmdArgs = append(cmdArgs, fmt.Sprintf("--registry-mirror=%s", mirror))
}
2020-11-16 18:37:13 +01:00
if p.Build.Target != "" {
cmdArgs = append(cmdArgs, fmt.Sprintf("--target=%s", p.Build.Target))
}
if p.Build.SkipTlsVerify {
cmdArgs = append(cmdArgs, "--skip-tls-verify=true")
}
2021-03-02 16:45:44 +01:00
if p.Build.SnapshotMode != "" {
cmdArgs = append(cmdArgs, fmt.Sprintf("--snapshotMode=%s", p.Build.SnapshotMode))
}
if p.Build.EnableCache {
cmdArgs = append(cmdArgs, "--cache=true")
if p.Build.CacheRepo != "" {
cmdArgs = append(cmdArgs, fmt.Sprintf("--cache-repo=%s", p.Build.CacheRepo))
}
}
if p.Build.CacheTTL != 0 {
cmdArgs = append(cmdArgs, fmt.Sprintf("--cache-ttl=%dh", p.Build.CacheTTL))
}
if p.Build.DigestFile != "" {
cmdArgs = append(cmdArgs, fmt.Sprintf("--digest-file=%s", p.Build.DigestFile))
}
2021-04-29 17:23:43 +02:00
if p.Build.NoPush {
cmdArgs = append(cmdArgs, "--no-push")
2021-04-29 17:23:43 +02:00
}
if p.Build.Verbosity != "" {
cmdArgs = append(cmdArgs, fmt.Sprintf("--verbosity=%s", p.Build.Verbosity))
}
2021-12-01 12:40:28 +01:00
if p.Build.Platform != "" {
cmdArgs = append(cmdArgs, fmt.Sprintf("--customPlatform=%s", p.Build.Platform))
}
if p.Build.SkipUnusedStages {
cmdArgs = append(cmdArgs, "--skip-unused-stages")
}
2020-11-16 18:37:13 +01:00
cmd := exec.Command("/kaniko/executor", cmdArgs...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
trace(cmd)
err := cmd.Run()
if err != nil {
return err
}
if p.Build.DigestFile != "" && p.Artifact.ArtifactFile != "" {
content, err := ioutil.ReadFile(p.Build.DigestFile)
if err != nil {
fmt.Fprintf(os.Stderr, "failed to read digest file contents at path: %s with error: %s\n", p.Build.DigestFile, err)
}
err = artifact.WritePluginArtifactFile(p.Artifact.RegistryType, p.Artifact.ArtifactFile, p.Artifact.Registry, p.Artifact.Repo, string(content), p.Artifact.Tags)
if err != nil {
fmt.Fprintf(os.Stderr, "failed to write plugin artifact file at path: %s with error: %s\n", p.Artifact.ArtifactFile, err)
}
}
return nil
2020-11-16 18:37:13 +01:00
}
// trace writes each command to stdout with the command wrapped in an xml
// tag so that it can be extracted and displayed in the logs.
func trace(cmd *exec.Cmd) {
fmt.Fprintf(os.Stdout, "+ %s\n", strings.Join(cmd.Args, " "))
}