Skip to content

Commit

Permalink
Merge pull request #983 from priyawadhwa/localdir
Browse files Browse the repository at this point in the history
 Add localdir buildcontext to kaniko builder
  • Loading branch information
dgageot authored Oct 10, 2018
2 parents a78735d + a87a459 commit dd7f219
Show file tree
Hide file tree
Showing 14 changed files with 421 additions and 73 deletions.
5 changes: 4 additions & 1 deletion examples/annotated-skaffold.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -96,13 +96,16 @@ build:
# dockerImage: gcr.io/cloud-builders/docker

# Docker artifacts can be built on a Kubernetes cluster with Kaniko.
# Sources will be sent to a GCS bucket whose name is provided.
# Exactly one buildContext must be specified to use kaniko
# If localDir is specified, skaffold will mount sources directly via a emptyDir volume
# If gcsBucket is specified, skaffold will send sources to the GCS bucket provided
# Kaniko also needs access to a service account to push the final image.
# See https://github.com/GoogleContainerTools/kaniko#running-kaniko-in-a-kubernetes-cluster
#
# kaniko:
# buildContext:
# gcsBucket: k8s-skaffold
# localDir: {}
# pullSecret: /a/secret/path/serviceaccount.json
# namespace: default
# timeout: 20m
Expand Down
6 changes: 6 additions & 0 deletions integration/examples/kaniko-local/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
FROM gcr.io/google-appengine/golang

WORKDIR /go/src/github.com/GoogleCloudPlatform/skaffold
CMD ["./app"]
COPY main.go .
RUN go build -o app main.go
34 changes: 34 additions & 0 deletions integration/examples/kaniko-local/README.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
=== Example: kaniko-local
:icons: font

This is an example demonstrating

* *building* a single go file app and with a single stage `Dockerfile` using https://github.com/GoogleContainerTools/kaniko[kaniko] to build on a K8S cluster directly from a local build context
* *tagging* using the default tagPolicy (`gitCommit`)
* *deploying* a single container pod using `kubectl`
ifndef::env-github[]
==== Example files
link:{github-repo-tree}/examples/kaniko[see on Github icon:github[]]

[source,yaml, indent=3, title=skaffold.yaml]
----
include::skaffold.yaml[]
----

[source,go, indent=3, title=main.go, syntax=go]
----
include::main.go[]
----

[source,docker, indent=3, title=Dockerfile]
----
include::Dockerfile[]
----

[source,yaml, indent=3, title=k8s-pod.yaml]
----
include::k8s-pod.yaml[]
----

endif::[]
8 changes: 8 additions & 0 deletions integration/examples/kaniko-local/k8s-pod.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
apiVersion: v1
kind: Pod
metadata:
name: getting-started-kaniko
spec:
containers:
- name: getting-started
image: gcr.io/k8s-skaffold/skaffold-example
13 changes: 13 additions & 0 deletions integration/examples/kaniko-local/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package main

import (
"fmt"
"time"
)

func main() {
for {
fmt.Println("Hello world!")
time.Sleep(time.Second * 1)
}
}
14 changes: 14 additions & 0 deletions integration/examples/kaniko-local/skaffold.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
apiVersion: skaffold/v1alpha4
kind: Config
build:
artifacts:
- image: gcr.io/k8s-skaffold/skaffold-example
kaniko:
buildContext:
localDir: {}
pullSecretName: e2esecret
namespace: default
deploy:
kubectl:
manifests:
- k8s-*
7 changes: 7 additions & 0 deletions integration/run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,13 @@ func TestRun(t *testing.T) {
dir: "examples/kaniko",
remoteOnly: true,
},
{
description: "kaniko local example",
args: []string{"run"},
pods: []string{"getting-started-kaniko"},
dir: "examples/kaniko-local",
remoteOnly: true,
},
{
description: "helm example",
args: []string{"run"},
Expand Down
82 changes: 16 additions & 66 deletions pkg/skaffold/build/kaniko/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ import (
"sync/atomic"
"time"

cstorage "cloud.google.com/go/storage"
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/build/kaniko/sources"
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/constants"

"github.com/GoogleContainerTools/skaffold/pkg/skaffold/docker"
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/gcp"
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/kubernetes"
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest"
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/util"
Expand All @@ -38,28 +38,18 @@ import (
corev1 "k8s.io/client-go/kubernetes/typed/core/v1"
)

const kanikoContainerName = "kaniko"

func runKaniko(ctx context.Context, out io.Writer, artifact *latest.Artifact, cfg *latest.KanikoBuild) (string, error) {
initialTag := util.RandomID()
dockerfilePath := artifact.DockerArtifact.DockerfilePath

bucket := cfg.BuildContext.GCSBucket
if bucket == "" {
guessedProjectID, err := gcp.ExtractProjectID(artifact.ImageName)
if err != nil {
return "", errors.Wrap(err, "extracting projectID from image name")
}

bucket = guessedProjectID
s, err := sources.Retrieve(cfg)
if err != nil {
return "", errors.Wrap(err, "retrieving build context")
}
logrus.Debugln("Upload sources to", bucket, "GCS bucket")

tarName := fmt.Sprintf("context-%s.tar.gz", initialTag)
if err := docker.UploadContextToGCS(ctx, artifact.Workspace, artifact.DockerArtifact, bucket, tarName); err != nil {
return "", errors.Wrap(err, "uploading sources to GCS")
context, err := s.Setup(ctx, artifact, cfg, initialTag)
if err != nil {
return "", errors.Wrap(err, "setting up build context")
}
defer gcsDelete(ctx, bucket, tarName)
defer s.Cleanup(ctx, cfg)
dockerfilePath := artifact.DockerArtifact.DockerfilePath

client, err := kubernetes.GetClientset()
if err != nil {
Expand All @@ -70,49 +60,19 @@ func runKaniko(ctx context.Context, out io.Writer, artifact *latest.Artifact, cf
imageDst := fmt.Sprintf("%s:%s", artifact.ImageName, initialTag)
args := []string{
fmt.Sprintf("--dockerfile=%s", dockerfilePath),
fmt.Sprintf("--context=gs://%s/%s", bucket, tarName),
fmt.Sprintf("--context=%s", context),
fmt.Sprintf("--destination=%s", imageDst),
fmt.Sprintf("-v=%s", logrus.GetLevel().String()),
}
args = append(args, docker.GetBuildArgs(artifact.DockerArtifact)...)

logrus.Debug("Creating pod")
p, err := pods.Create(&v1.Pod{
ObjectMeta: metav1.ObjectMeta{
GenerateName: "kaniko",
Labels: map[string]string{"skaffold-kaniko": "skaffold-kaniko"},
Namespace: cfg.Namespace,
},
Spec: v1.PodSpec{
Containers: []v1.Container{{
Name: kanikoContainerName,
Image: cfg.Image,
ImagePullPolicy: v1.PullIfNotPresent,
Args: args,
VolumeMounts: []v1.VolumeMount{{
Name: constants.DefaultKanikoSecretName,
MountPath: "/secret",
}},
Env: []v1.EnvVar{{
Name: "GOOGLE_APPLICATION_CREDENTIALS",
Value: "/secret/kaniko-secret",
}},
}},
Volumes: []v1.Volume{{
Name: constants.DefaultKanikoSecretName,
VolumeSource: v1.VolumeSource{
Secret: &v1.SecretVolumeSource{
SecretName: cfg.PullSecretName,
},
},
}},
RestartPolicy: v1.RestartPolicyNever,
},
})
p, err := pods.Create(s.Pod(cfg, args))
if err != nil {
return "", errors.Wrap(err, "creating kaniko pod")
}

if err := s.ModifyPod(p); err != nil {
return "", errors.Wrap(err, "modifying kaniko pod")
}
waitForLogs := streamLogs(out, p.Name, pods)

defer func() {
Expand Down Expand Up @@ -148,7 +108,7 @@ func streamLogs(out io.Writer, name string, pods corev1.PodInterface) func() {
for atomic.LoadInt32(&retry) == 1 {
r, err := pods.GetLogs(name, &v1.PodLogOptions{
Follow: true,
Container: kanikoContainerName,
Container: constants.DefaultKanikoContainerName,
}).Stream()
if err == nil {
io.Copy(out, r)
Expand All @@ -165,13 +125,3 @@ func streamLogs(out io.Writer, name string, pods corev1.PodInterface) func() {
wg.Wait()
}
}

func gcsDelete(ctx context.Context, bucket, path string) error {
c, err := cstorage.NewClient(ctx)
if err != nil {
return err
}
defer c.Close()

return c.Bucket(bucket).Object(path).Delete(ctx)
}
75 changes: 75 additions & 0 deletions pkg/skaffold/build/kaniko/sources/gcs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
Copyright 2018 The Skaffold Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package sources

import (
"context"
"fmt"

cstorage "cloud.google.com/go/storage"
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/docker"
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/gcp"
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
v1 "k8s.io/api/core/v1"
)

type GCSBucket struct {
tarName string
}

// Setup uploads the context to the provided GCS bucket
func (g *GCSBucket) Setup(ctx context.Context, artifact *latest.Artifact, cfg *latest.KanikoBuild, initialTag string) (string, error) {
bucket := cfg.BuildContext.GCSBucket
if bucket == "" {
guessedProjectID, err := gcp.ExtractProjectID(artifact.ImageName)
if err != nil {
return "", errors.Wrap(err, "extracting projectID from image name")
}

bucket = guessedProjectID
}
logrus.Debugln("Upload sources to", bucket, "GCS bucket")

g.tarName = fmt.Sprintf("context-%s.tar.gz", initialTag)
if err := docker.UploadContextToGCS(ctx, artifact.Workspace, artifact.DockerArtifact, bucket, g.tarName); err != nil {
return "", errors.Wrap(err, "uploading sources to GCS")
}
context := fmt.Sprintf("gs://%s/%s", cfg.BuildContext.GCSBucket, g.tarName)
return context, nil
}

// Pod returns the pod template for this builder
func (g *GCSBucket) Pod(cfg *latest.KanikoBuild, args []string) *v1.Pod {
return podTemplate(cfg, args)
}

// ModifyPod does nothing here, since we just need to let kaniko run to completion
func (g *GCSBucket) ModifyPod(p *v1.Pod) error {
return nil
}

// Cleanup deletes the tarball from the GCS bucket
func (g *GCSBucket) Cleanup(ctx context.Context, cfg *latest.KanikoBuild) error {
c, err := cstorage.NewClient(ctx)
if err != nil {
return err
}
defer c.Close()
return c.Bucket(cfg.BuildContext.GCSBucket).Object(g.tarName).Delete(ctx)
}
Loading

0 comments on commit dd7f219

Please sign in to comment.