diff --git a/.drone.yml b/.drone.yml index 9bae0ad..9ffc9f4 100644 --- a/.drone.yml +++ b/.drone.yml @@ -1,7 +1,14 @@ kind: pipeline -type: docker +type: vm name: default +pool: + use: ubuntu + +platform: + os: linux + arch: amd64 + steps: - name: build image: golang:1.21 @@ -43,6 +50,23 @@ steps: exclude: - pull_request +- name: gar + image: plugins/docker + settings: + repo: plugins/kaniko-gar + auto_tag: true + auto_tag_suffix: linux-amd64 + daemon_off: false + dockerfile: docker/gar/Dockerfile.linux.amd64 + username: + from_secret: docker_username + password: + from_secret: docker_password + when: + event: + exclude: + - pull_request + - name: ecr image: plugins/docker settings: @@ -111,6 +135,22 @@ steps: exclude: - pull_request +- name: gar-kaniko-v1-9 + image: plugins/docker + settings: + repo: plugins/kaniko-gar + auto_tag: true + auto_tag_suffix: linux-amd64-kaniko1.9.1 + daemon_off: false + dockerfile: docker/gar/Dockerfile.linux.amd64.kaniko1.9.1 + username: + from_secret: docker_username + password: + from_secret: docker_password + when: + event: + exclude: + - pull_request - name: ecr-kaniko-v1-9 image: plugins/docker @@ -177,6 +217,23 @@ steps: exclude: - pull_request +- name: gar + image: plugins/docker + settings: + repo: plugins/kaniko-gar + auto_tag: true + auto_tag_suffix: linux-arm64 + daemon_off: false + dockerfile: docker/gar/Dockerfile.linux.arm64 + username: + from_secret: docker_username + password: + from_secret: docker_password + when: + event: + exclude: + - pull_request + - name: ecr image: plugins/docker settings: @@ -245,6 +302,22 @@ steps: exclude: - pull_request +- name: gar-kaniko-v1-9 + image: plugins/docker + settings: + repo: plugins/kaniko-gar + auto_tag: true + auto_tag_suffix: linux-arm64-kaniko1.9.1 + daemon_off: false + dockerfile: docker/gar/Dockerfile.linux.arm64.kaniko1.9.1 + username: + from_secret: docker_username + password: + from_secret: docker_password + when: + event: + exclude: + - pull_request - name: ecr-kaniko-v1-9 image: plugins/docker @@ -264,9 +337,12 @@ steps: - pull_request --- kind: pipeline -type: docker +type: vm name: notifications-docker +pool: + use: ubuntu + platform: os: linux arch: amd64 @@ -296,6 +372,18 @@ steps: username: from_secret: docker_username +- name: manifest-gar + pull: always + image: plugins/manifest + settings: + auto_tag: true + ignore_missing: true + password: + from_secret: docker_password + spec: docker/gar/manifest.tmpl + username: + from_secret: docker_username + - name: manifest-acr pull: always image: plugins/manifest @@ -331,9 +419,12 @@ depends_on: --- kind: pipeline -type: docker +type: vm name: notifications-docker-kaniko1-8 +pool: + use: ubuntu + platform: os: linux arch: amd64 @@ -363,6 +454,18 @@ steps: username: from_secret: docker_username +- name: manifest-gar + pull: always + image: plugins/manifest + settings: + auto_tag: false + ignore_missing: true + password: + from_secret: docker_password + spec: docker/gar/manifest-kaniko1.9.1.tmpl + username: + from_secret: docker_username + - name: manifest-ecr pull: always image: plugins/manifest diff --git a/cmd/kaniko-gar/main.go b/cmd/kaniko-gar/main.go new file mode 100644 index 0000000..93edd84 --- /dev/null +++ b/cmd/kaniko-gar/main.go @@ -0,0 +1,234 @@ +package main + +import ( + "fmt" + "io/ioutil" + "os" + + "github.com/joho/godotenv" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + "github.com/urfave/cli" + + kaniko "github.com/drone/drone-kaniko" + "github.com/drone/drone-kaniko/pkg/artifact" +) + +const ( + // GAR JSON key file path + garKeyPath string = "/kaniko/config.json" + garEnvVariable string = "GOOGLE_APPLICATION_CREDENTIALS" + + defaultDigestFile string = "/kaniko/digest-file" +) + +var ( + version = "unknown" +) + +func main() { + // Load env-file if it exists first + if env := os.Getenv("PLUGIN_ENV_FILE"); env != "" { + if err := godotenv.Load(env); err != nil { + logrus.Fatal(err) + } + } + + app := cli.NewApp() + app.Name = "kaniko gar plugin" + app.Usage = "kaniko gar plugin" + app.Action = run + app.Version = version + app.Flags = []cli.Flag{ + cli.StringFlag{ + Name: "dockerfile", + Usage: "build dockerfile", + Value: "Dockerfile", + EnvVar: "PLUGIN_DOCKERFILE", + }, + cli.StringFlag{ + Name: "context", + Usage: "build context", + Value: ".", + EnvVar: "PLUGIN_CONTEXT", + }, + cli.StringFlag{ + Name: "drone-commit-ref", + Usage: "git commit ref passed by Drone", + EnvVar: "DRONE_COMMIT_REF", + }, + cli.StringFlag{ + Name: "drone-repo-branch", + Usage: "git repository default branch passed by Drone", + EnvVar: "DRONE_REPO_BRANCH", + }, + cli.StringSliceFlag{ + Name: "tags", + Usage: "build tags", + Value: &cli.StringSlice{"latest"}, + EnvVar: "PLUGIN_TAGS", + FilePath: ".tags", + }, + cli.BoolFlag{ + Name: "expand-tag", + Usage: "enable for semver tagging", + EnvVar: "PLUGIN_EXPAND_TAG", + }, + cli.BoolFlag{ + Name: "auto-tag", + Usage: "enable auto generation of build tags", + EnvVar: "PLUGIN_AUTO_TAG", + }, + cli.StringFlag{ + Name: "auto-tag-suffix", + Usage: "the suffix of auto build tags", + EnvVar: "PLUGIN_AUTO_TAG_SUFFIX", + }, + cli.StringSliceFlag{ + Name: "args", + Usage: "build args", + EnvVar: "PLUGIN_BUILD_ARGS", + }, + cli.StringFlag{ + Name: "target", + Usage: "build target", + EnvVar: "PLUGIN_TARGET", + }, + cli.StringFlag{ + Name: "repo", + Usage: "gar repository", + EnvVar: "PLUGIN_REPO", + }, + cli.StringSliceFlag{ + Name: "custom-labels", + Usage: "additional k=v labels", + EnvVar: "PLUGIN_CUSTOM_LABELS", + }, + cli.StringFlag{ + Name: "registry", + Usage: "gar registry", + EnvVar: "PLUGIN_REGISTRY", + }, + cli.StringSliceFlag{ + Name: "registry-mirrors", + Usage: "docker registry mirrors", + EnvVar: "PLUGIN_REGISTRY_MIRRORS", + }, + cli.StringFlag{ + Name: "json-key", + Usage: "docker username", + EnvVar: "PLUGIN_JSON_KEY", + }, + cli.StringFlag{ + Name: "snapshot-mode", + Usage: "Specify one of full, redo or time as snapshot mode", + EnvVar: "PLUGIN_SNAPSHOT_MODE", + }, + cli.BoolFlag{ + Name: "enable-cache", + Usage: "Set this flag to opt into caching with kaniko", + EnvVar: "PLUGIN_ENABLE_CACHE", + }, + cli.StringFlag{ + Name: "cache-repo", + Usage: "Remote repository that will be used to store cached layers. Cache repo should be present in specified registry. enable-cache needs to be set to use this flag", + EnvVar: "PLUGIN_CACHE_REPO", + }, + cli.IntFlag{ + Name: "cache-ttl", + Usage: "Cache timeout in hours. Defaults to two weeks.", + EnvVar: "PLUGIN_CACHE_TTL", + }, + cli.StringFlag{ + Name: "artifact-file", + Usage: "Artifact file location that will be generated by the plugin. This file will include information of docker images that are uploaded by the plugin.", + EnvVar: "PLUGIN_ARTIFACT_FILE", + }, + cli.BoolFlag{ + Name: "no-push", + Usage: "Set this flag if you only want to build the image, without pushing to a registry", + EnvVar: "PLUGIN_NO_PUSH", + }, + cli.StringFlag{ + Name: "verbosity", + Usage: "Set this flag as --verbosity= to set the logging level for kaniko. Defaults to info.", + EnvVar: "PLUGIN_VERBOSITY", + }, + cli.StringFlag{ + Name: "platform", + Usage: "Allows to build with another default platform than the host, similarly to docker build --platform", + EnvVar: "PLUGIN_PLATFORM", + }, + cli.BoolFlag{ + Name: "skip-unused-stages", + Usage: "build only used stages", + EnvVar: "PLUGIN_SKIP_UNUSED_STAGES", + }, + } + + if err := app.Run(os.Args); err != nil { + logrus.Fatal(err) + } +} + +func run(c *cli.Context) error { + noPush := c.Bool("no-push") + jsonKey := c.String("json-key") + + // JSON key may not be set in the following cases: + // 1. Image does not need to be pushed to GAR. + // 2. Workload identity is set on GKE in which pod will inherit the credentials via service account. + if jsonKey != "" { + if err := setupGARAuth(jsonKey); err != nil { + return err + } + } + + plugin := kaniko.Plugin{ + Build: kaniko.Build{ + DroneCommitRef: c.String("drone-commit-ref"), + DroneRepoBranch: c.String("drone-repo-branch"), + Dockerfile: c.String("dockerfile"), + Context: c.String("context"), + Tags: c.StringSlice("tags"), + AutoTag: c.Bool("auto-tag"), + AutoTagSuffix: c.String("auto-tag-suffix"), + ExpandTag: c.Bool("expand-tag"), + Args: c.StringSlice("args"), + Target: c.String("target"), + Repo: fmt.Sprintf("%s/%s", c.String("registry"), c.String("repo")), + Mirrors: c.StringSlice("registry-mirrors"), + Labels: c.StringSlice("custom-labels"), + SnapshotMode: c.String("snapshot-mode"), + EnableCache: c.Bool("enable-cache"), + CacheRepo: fmt.Sprintf("%s/%s", c.String("registry"), c.String("cache-repo")), + CacheTTL: c.Int("cache-ttl"), + DigestFile: defaultDigestFile, + NoPush: noPush, + Verbosity: c.String("verbosity"), + Platform: c.String("platform"), + SkipUnusedStages: c.Bool("skip-unused-stages"), + }, + Artifact: kaniko.Artifact{ + Tags: c.StringSlice("tags"), + Repo: c.String("repo"), + Registry: c.String("registry"), + ArtifactFile: c.String("artifact-file"), + RegistryType: artifact.GAR, + }, + } + return plugin.Exec() +} + +func setupGARAuth(jsonKey string) error { + err := ioutil.WriteFile(garKeyPath, []byte(jsonKey), 0644) + if err != nil { + return errors.Wrap(err, "failed to write GAR JSON key") + } + + err = os.Setenv(garEnvVariable, garKeyPath) + if err != nil { + return errors.Wrap(err, fmt.Sprintf("failed to set %s environment variable", garEnvVariable)) + } + return nil +} diff --git a/docker/gar/Dockerfile.linux.amd64 b/docker/gar/Dockerfile.linux.amd64 new file mode 100644 index 0000000..79fb64a --- /dev/null +++ b/docker/gar/Dockerfile.linux.amd64 @@ -0,0 +1,5 @@ +FROM gcr.io/kaniko-project/executor:v1.9.1 + +ENV KANIKO_VERSION=1.9.1 +ADD release/linux/amd64/kaniko-gar /kaniko/ +ENTRYPOINT ["/kaniko/kaniko-gar"] diff --git a/docker/gar/Dockerfile.linux.amd64.kaniko1.9.1 b/docker/gar/Dockerfile.linux.amd64.kaniko1.9.1 new file mode 100644 index 0000000..79fb64a --- /dev/null +++ b/docker/gar/Dockerfile.linux.amd64.kaniko1.9.1 @@ -0,0 +1,5 @@ +FROM gcr.io/kaniko-project/executor:v1.9.1 + +ENV KANIKO_VERSION=1.9.1 +ADD release/linux/amd64/kaniko-gar /kaniko/ +ENTRYPOINT ["/kaniko/kaniko-gar"] diff --git a/docker/gar/Dockerfile.linux.arm64 b/docker/gar/Dockerfile.linux.arm64 new file mode 100644 index 0000000..32f0fb8 --- /dev/null +++ b/docker/gar/Dockerfile.linux.arm64 @@ -0,0 +1,8 @@ +FROM gcr.io/kaniko-project/executor:v1.9.1 + +ENV HOME /root +ENV USER root +ENV KANIKO_VERSION=1.9.1 + +ADD release/linux/arm64/kaniko-gar /kaniko/ +ENTRYPOINT ["/kaniko/kaniko-gar"] diff --git a/docker/gar/Dockerfile.linux.arm64.kaniko1.9.1 b/docker/gar/Dockerfile.linux.arm64.kaniko1.9.1 new file mode 100644 index 0000000..43f265a --- /dev/null +++ b/docker/gar/Dockerfile.linux.arm64.kaniko1.9.1 @@ -0,0 +1,5 @@ +FROM gcr.io/kaniko-project/executor:v1.9.1 + +ENV KANIKO_VERSION=1.9.1 +ADD release/linux/arm64/kaniko-gar /kaniko/ +ENTRYPOINT ["/kaniko/kaniko-gar"] diff --git a/docker/gar/manifest-kaniko1.9.1.tmpl b/docker/gar/manifest-kaniko1.9.1.tmpl new file mode 100644 index 0000000..f228982 --- /dev/null +++ b/docker/gar/manifest-kaniko1.9.1.tmpl @@ -0,0 +1,18 @@ +image: plugins/kaniko-gar:{{#if build.tag}}{{trimPrefix "v" build.tag}}-kaniko1.9.1{{else}}latest-kaniko1.9.1{{/if}} +{{#if build.tags}} +tags: +{{#each build.tags}} + - {{this}} +{{/each}} +{{/if}} +manifests: + - + image: plugins/kaniko-gar:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-amd64-kaniko1.9.1 + platform: + architecture: amd64 + os: linux + - + image: plugins/kaniko-gar:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-arm64-kaniko1.9.1 + platform: + architecture: arm64 + os: linux \ No newline at end of file diff --git a/docker/gar/manifest.tmpl b/docker/gar/manifest.tmpl new file mode 100644 index 0000000..ec08cbf --- /dev/null +++ b/docker/gar/manifest.tmpl @@ -0,0 +1,18 @@ +image: plugins/kaniko-gar:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}latest{{/if}} +{{#if build.tags}} +tags: +{{#each build.tags}} + - {{this}} +{{/each}} +{{/if}} +manifests: + - + image: plugins/kaniko-gar:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-amd64 + platform: + architecture: amd64 + os: linux + - + image: plugins/kaniko-gar:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-arm64 + platform: + architecture: arm64 + os: linux diff --git a/pkg/artifact/artifact.go b/pkg/artifact/artifact.go index 3e4ecf9..4db5161 100644 --- a/pkg/artifact/artifact.go +++ b/pkg/artifact/artifact.go @@ -20,6 +20,7 @@ const ( Docker RegistryTypeEnum = "Docker" ECR RegistryTypeEnum = "ECR" GCR RegistryTypeEnum = "GCR" + GAR RegistryTypeEnum = "GAR" ) type ( diff --git a/scripts/build.sh b/scripts/build.sh index c5a6a70..553b66a 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -14,13 +14,16 @@ GOOS=linux GOARCH=amd64 go build -o release/linux/amd64/kaniko-gcr ./cmd/kani GOOS=linux GOARCH=amd64 go build -o release/linux/amd64/kaniko-acr ./cmd/kaniko-acr GOOS=linux GOARCH=amd64 go build -o release/linux/amd64/kaniko-ecr ./cmd/kaniko-ecr GOOS=linux GOARCH=amd64 go build -o release/linux/amd64/kaniko-docker ./cmd/kaniko-docker +GOOS=linux GOARCH=amd64 go build -o release/linux/amd64/kaniko-gar ./cmd/kaniko-gar GOOS=linux GOARCH=arm64 go build -o release/linux/arm64/kaniko-gcr ./cmd/kaniko-gcr GOOS=linux GOARCH=arm64 go build -o release/linux/arm64/kaniko-acr ./cmd/kaniko-acr GOOS=linux GOARCH=arm64 go build -o release/linux/arm64/kaniko-ecr ./cmd/kaniko-ecr GOOS=linux GOARCH=arm64 go build -o release/linux/arm64/kaniko-docker ./cmd/kaniko-docker +GOOS=linux GOARCH=arm64 go build -o release/linux/arm64/kaniko-gar ./cmd/kaniko-gar GOOS=linux GOARCH=arm go build -o release/linux/arm/kaniko-gcr ./cmd/kaniko-gcr GOOS=linux GOARCH=arm go build -o release/linux/arm/kaniko-acr ./cmd/kaniko-acr GOOS=linux GOARCH=arm go build -o release/linux/arm/kaniko-ecr ./cmd/kaniko-ecr GOOS=linux GOARCH=arm go build -o release/linux/arm/kaniko-docker ./cmd/kaniko-docker +GOOS=linux GOARCH=arm go build -o release/linux/arm/kaniko-gar ./cmd/kaniko-gar diff --git a/scripts/docker.sh b/scripts/docker.sh index cd4b24a..bf1bdad 100755 --- a/scripts/docker.sh +++ b/scripts/docker.sh @@ -15,10 +15,12 @@ set -x # build the binary go build -o release/linux/amd64/kaniko-gcr ./cmd/kaniko-gcr +go build -o release/linux/amd64/kaniko-gar ./cmd/kaniko-gar go build -o release/linux/amd64/kaniko-ecr ./cmd/kaniko-ecr go build -o release/linux/amd64/kaniko-docker ./cmd/kaniko-docker # build the docker image docker build -f docker/gcr/Dockerfile.linux.amd64 -t plugins/kaniko-gcr . +docker build -f docker/gar/Dockerfile.linux.amd64 -t plugins/kaniko-gar . docker build -f docker/ecr/Dockerfile.linux.amd64 -t plugins/kaniko-ecr . docker build -f docker/docker/Dockerfile.linux.amd64 -t plugins/kaniko .