Skip to content

Commit

Permalink
code review comments and added documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
Priya Wadhwa committed Apr 30, 2019
1 parent f1fae32 commit 05a5ee8
Show file tree
Hide file tree
Showing 7 changed files with 120 additions and 19 deletions.
67 changes: 67 additions & 0 deletions docs/content/en/docs/how-tos/builders/_index.md
Expand Up @@ -15,6 +15,7 @@ Skaffold supports the following tools to build your image:
* [Bazel](https://bazel.build/) locally
* [Jib](https://github.com/GoogleContainerTools/jib) Maven and Gradle projects locally
* [Jib](https://github.com/GoogleContainerTools/jib) remotely with [Google Cloud Build](https://cloud.google.com/cloud-build/docs/)
* Custom build script run locally

The `build` section in the Skaffold configuration file, `skaffold.yaml`,
controls how artifacts are built. To use a specific tool for building
Expand Down Expand Up @@ -208,3 +209,69 @@ The following `build` section instructs Skaffold to build a
Docker image `gcr.io/k8s-skaffold/example` with Bazel:

{{% readfile file="samples/builders/bazel.yaml" %}}

## Custom Build Script Run Locally

Custom build scripts allow skaffold users the flexibility to build artifacts with any builder they desire.
Users can write a custom build script which must abide by the following contract for skaffold to work as expected:

### Contract between Skaffold and Custom Build Script

Skaffold will pass in the following environment variables to the custom build script:

| Environment Variable | Description | Expectation |
| ------------- |-------------| -----|
| $IMAGES | An array of fully qualified image names, separated by spaces. | The custom build script is expected to build an image and tag it with each image name in $IMAGES. Each image should also be pushed if `$PUSH_IMAGE=true`. |
| $PUSH_IMAGE | Set to true if each image in `$IMAGES` is expected to exist in a remote registry. Set to false if each image in `$IMAGES` is expected to exist locally. | The custom build script will push each image in `$IMAGES` if `$PUSH_IMAGE=true` |
| $BUILD_CONTEXT | An absolute path to the directory this artifact is meant to be built from. Specified by artifact `context` in the skaffold.yaml. | None. |
| Local environment variables | The current state of the local environment (e.g. `$HOST`, `$PATH)`. Determined by the golang [os.Environ](https://golang.org/pkg/os/#Environ) function.| None. |

As described above, the custom build script is expected to:

1. Build and tag each image in `$IMAGES`
2. Push each image in `$IMAGES` if `$PUSH_IMAGE=true`

Once the build script has finished executing, skaffold will try to obtain the digest of the newly built image from a remote registry (if `$PUSH_IMAGE=true`) or the local daemon (if `$PUSH_IMAGE=false`).
If skaffold fails to obtain the digest, it will error out.

#### Additional Environment Variables

Skaffold will pass in the following additional environment variables for the following builders:

##### Local builder
| Environment Variable | Description | Expectation |
| ------------- |-------------| -----|
| Docker daemon environment variables | Inform the custom builder of which docker daemon endpoint we are using. Allows custom build scripts to work with tools like Minikube.| None. |


### Configuration

To use a custom build script, add a `custom` field to each artifact in the `build` section of the skaffold.yaml.
Currently, this only works with the build type `local`. Supported schema for `custom` includes:


{{< schema root="CustomArtifact" >}}


`buildCommand` is *required* and points skaffold to the custom build script which will be executed to build the artifact.
`dependencies` tells the skaffold file watcher which files should be watched to trigger rebuilds and file syncs. Supported schema for `dependencies` includes:


{{< schema root="CustomDependencies" >}}

#### Custom Build Scripts and File Sync
Syncable files must be specified in the `paths` section of `dependencies` so that the skaffold file watcher knows to watch them.

#### Custom Build Scripts and Logging
STDOUT and STDERR from the custom build script will be redirected and displayed within skaffold logs.


### Example

The following `build` section instructs Skaffold to build an image `gcr.io/k8s-skaffold/example` with a custom build script `build.sh`:

{{% readfile file="samples/builders/custom.yaml" %}}

A sample `build.sh` file, which builds an image with bazel and docker:

{{% readfile file="samples/builders/build.sh" %}}
20 changes: 20 additions & 0 deletions docs/content/en/samples/builders/build.sh
@@ -0,0 +1,20 @@
#!/bin/bash

bazel build //:skaffold_example.tar
TAR_PATH=$(bazel info bazel-bin)
docker load -i $TAR_PATH/skaffold_example.tar


images=$(echo $IMAGES | tr " " "\n")

for image in $images
do
docker tag bazel:skaffold_example $image

if $PUSH_IMAGE
then
docker push $image
fi

done

10 changes: 10 additions & 0 deletions docs/content/en/samples/builders/custom.yaml
@@ -0,0 +1,10 @@
build:
artifacts:
- image: gcr.io/k8s-skaffold/example
custom:
buildCommand: ./build.sh
dependencies:
paths:
- .
ignore:
- README*
16 changes: 8 additions & 8 deletions docs/content/en/schemas/v1beta10.json
Expand Up @@ -581,8 +581,8 @@
},
"dependencies": {
"$ref": "#/definitions/CustomDependencies",
"description": "file dependencies that skaffold should watch for this artifact.",
"x-intellij-html-description": "file dependencies that skaffold should watch for this artifact."
"description": "file dependencies that skaffold should watch for both rebuilding and file syncing for this artifact.",
"x-intellij-html-description": "file dependencies that skaffold should watch for both rebuilding and file syncing for this artifact."
}
},
"preferredOrder": [
Expand All @@ -600,17 +600,17 @@
"type": "string"
},
"type": "array",
"description": "specifies the paths that should be ignored by the watcher. If a file exists in `paths` and in `ignore`, it will be ignored. Will only work in conjunction with `paths`.",
"x-intellij-html-description": "specifies the paths that should be ignored by the watcher. If a file exists in <code>paths</code> and in <code>ignore</code>, it will be ignored. Will only work in conjunction with <code>paths</code>.",
"description": "specifies the paths that should be ignored by skaffold's file watcher. If a file exists in both `paths` and in `ignore`, it will be ignored, and will be excluded from both rebuilds and file synchronization. Will only work in conjunction with `paths`.",
"x-intellij-html-description": "specifies the paths that should be ignored by skaffold's file watcher. If a file exists in both <code>paths</code> and in <code>ignore</code>, it will be ignored, and will be excluded from both rebuilds and file synchronization. Will only work in conjunction with <code>paths</code>.",
"default": "[]"
},
"paths": {
"items": {
"type": "string"
},
"type": "array",
"description": "should be set to the dependencies for this artifact if no Dockerfile exists.",
"x-intellij-html-description": "should be set to the dependencies for this artifact if no Dockerfile exists.",
"description": "should be set to the file dependencies for this artifact, so that the skaffold file watcher knows when to rebuild and perform file synchronization.",
"x-intellij-html-description": "should be set to the file dependencies for this artifact, so that the skaffold file watcher knows when to rebuild and perform file synchronization.",
"default": "[]"
}
},
Expand All @@ -619,8 +619,8 @@
"ignore"
],
"additionalProperties": false,
"description": "used to specify dependencies for an artifact built by a custom build script.",
"x-intellij-html-description": "used to specify dependencies for an artifact built by a custom build script."
"description": "*alpha* used to specify dependencies for an artifact built by a custom build script.",
"x-intellij-html-description": "<em>alpha</em> used to specify dependencies for an artifact built by a custom build script."
},
"DateTimeTagger": {
"properties": {
Expand Down
2 changes: 1 addition & 1 deletion hack/boilerplate/boilerplate.py
Expand Up @@ -24,7 +24,7 @@


SKIPPED_DIRS = ["Godeps", "third_party", ".git", "vendor", "examples", "testdata", "node_modules"]
SKIPPED_FILES = ["install_golint.sh", "skaffold.pb.go", "skaffold.pb.gw.go"]
SKIPPED_FILES = ["install_golint.sh", "skaffold.pb.go", "skaffold.pb.gw.go", "build.sh"]

parser = argparse.ArgumentParser()
parser.add_argument("filenames", help="list of files to check, all files if unspecified", nargs='*')
Expand Down
8 changes: 4 additions & 4 deletions pkg/skaffold/schema/latest/config.go
Expand Up @@ -561,15 +561,15 @@ type ArtifactType struct {
type CustomArtifact struct {
// BuildCommand is the command executed to build the image.
BuildCommand string `yaml:"buildCommand,omitempty"`
// Dependencies are the file dependencies that skaffold should watch for this artifact.
// Dependencies are the file dependencies that skaffold should watch for both rebuilding and file syncing for this artifact.
Dependencies *CustomDependencies `yaml:"dependencies,omitempty"`
}

// CustomDependencies is used to specify dependencies for an artifact built by a custom build script.
// CustomDependencies *alpha* is used to specify dependencies for an artifact built by a custom build script.
type CustomDependencies struct {
// Paths should be set to the dependencies for this artifact if no Dockerfile exists.
// Paths should be set to the file dependencies for this artifact, so that the skaffold file watcher knows when to rebuild and perform file synchronization.
Paths []string `yaml:"paths,omitempty" yamltags:"oneOf=dependency"`
// Ignore specifies the paths that should be ignored by the watcher. If a file exists in `paths` and in `ignore`, it will be ignored.
// Ignore specifies the paths that should be ignored by skaffold's file watcher. If a file exists in both `paths` and in `ignore`, it will be ignored, and will be excluded from both rebuilds and file synchronization.
// Will only work in conjunction with `paths`.
Ignore []string `yaml:"ignore,omitempty"`
}
Expand Down
16 changes: 10 additions & 6 deletions pkg/skaffold/schema/samples_test.go
Expand Up @@ -29,8 +29,11 @@ import (
)

const (
samplesRoot = "../../../docs/content/en/samples"
ignoredSample = "structureTest.yaml"
samplesRoot = "../../../docs/content/en/samples"
)

var (
ignoredSamples = []string{"structureTest.yaml", "build.sh"}
)

func TestParseSamples(t *testing.T) {
Expand All @@ -49,11 +52,12 @@ func TestParseSamples(t *testing.T) {
for _, path := range paths {
name := filepath.Base(path)

if name == ignoredSample {
continue
}

t.Run(name, func(t *testing.T) {
for _, is := range ignoredSamples {
if name == is {
t.Skip()
}
}
buf, err := ioutil.ReadFile(path)
testutil.CheckError(t, false, err)

Expand Down

0 comments on commit 05a5ee8

Please sign in to comment.