ko beta
ko
enables fast, standardized, reproducible,
configuration-less, Docker-less, and multi-platform container image builds for
Go apps.
Skaffold embeds ko
as a library, so you do not need to download ko
to use the ko builder.
Benefits of the ko builder
Compared to …
-
the Cloud Native buildpacks builder, the ko builder is fast, doesn’t require Docker, and uses a default base image that has a small attack surface.
-
the Docker builder, the ko builder standardizes builds, avoiding artisanal snowflake
Dockerfile
s. It also doesn’t require the Docker daemon, so builds can run in environments where Docker isn’t available for security reasons. -
the Kaniko builder, the ko builder doesn’t need a Kubernetes cluster, and it avoids the previously-mentioned artisanal
Dockerfile
s. -
the Bazel builder, the ko builder doesn’t require users to adopt Bazel. However, we recommend the Bazel builder for users who already use Bazel for their Go apps.
-
the custom builder, the ko builder standardizes builds, as it doesn’t require running
ko
using custom shell scripts.
Configuring the ko builder
The ko builder default configuration is sufficient for many Go apps. To use
the ko builder with its default configuration, provide an empty map in the
ko
field, e.g.:
build:
artifacts:
- image: my-simple-go-app
ko: {}
Base image
ko
uses the
cgr.dev/chainguard/static
image as the default base image. This is a small image that provides a
minimal environment for Go binaries.
The default base image does not provide a shell, and it does not include
glibc
.
You can specify a different base image using the ko builder fromImage
config
field. For instance, if you want to use a base image that contains glibc
,
you can use this configuration:
ko:
fromImage: cgr.dev/chainguard/glibc-dynamic
If you run Skaffold in a Google Cloud VPC network with limited or no internet access, you can use a distroless base image from Google Container Registry, accessible via Private Google Access:
ko:
fromImage: gcr.io/distroless/static-debian11:nonroot
Multi-platform images
The ko builder supports building multi-platform images. The default platform
is linux/amd64
, but you can configure a list of platforms using the
artifact’s platforms
configuration field, e.g.:
build:
platforms: ["linux/amd64", "linux/arm64"]
artifacts:
- image: foo
ko: {}
You can also supply ["all"]
as the value of platforms
. all
means that the
ko builder builds images for all platforms supported by the base image.
Image labels
Use the labels
configuration field to add
image labels
(a.k.a. Dockerfile
LABEL
s),
For example, you can add labels based on the pre-defined annotations keys from the Open Container Initiative (OCI) Image Format Specification:
ko:
labels:
org.opencontainers.image.licenses: Apache-2.0
org.opencontainers.image.source: https://github.com/GoogleContainerTools/skaffold
The labels
section supports templating of values based on environment
variables, e.g.:
ko:
labels:
org.opencontainers.image.revision: "{{.GITHUB_SHA}}"
org.opencontainers.image.source: "{{.GITHUB_SERVER_URL}}/{{.GITHUB_REPOSITORY}}"
Build time environment variables
Use the env
configuration field to specify build-time environment variables.
Example:
ko:
env:
- GOCACHE=/workspace/.gocache
- GOPRIVATE=git.internal.example.com,source.developers.google.com
The env
field supports templating of values using environment variables, for
example:
ko:
env:
- GOPROXY={{.GOPROXY}}
Dependencies
The dependencies
section configures what files Skaffold should watch for
changes when in dev
mode.
paths
and ignore
are arrays that list file patterns to include and ignore.
Any patterns in ignore
will be ignored by the Skaffold file watcher, even if
they are also specified in paths
. ignore
is only used when paths
is not
empty.
Example:
ko:
dependencies:
paths:
- cmd
- go.mod
- pkg
ignore:
- vendor
If no dependencies
are specified, the default values are as follows:
ko:
dependencies:
paths: ["**/*.go"]
ignore: []
Build flags
Use the flags
configuration field to provide flag arguments to go build
,
e.g.:
ko:
flags:
- -mod=vendor
- -v
Use the ldflags
configuration field to provide linker flag arguments, e.g.:
ko:
ldflags:
- -s
- -w
The flags
and ldflags
fields support templating using environment
variables,
e.g.:
ko:
ldflags:
- -X main.version={{.VERSION}}
These templates are evaluated by Skaffold. Note that the syntax is slightly
different to
ko
’s template expansion,
specifically, there’s no .Env
prefix.
Source file locations
If your Go source files and go.mod
are not in the context
directory,
use the dir
configuration field to specify the path, relative to the
context
directory, e.g.:
ko:
dir: ./compat-go114
If your package main
is not in the context
directory (or in dir
if
specified), use the main
configuration field to specify the path or target,
e.g.:
ko:
main: ./cmd/foo
If your context
directory only contains one package main
directory, you
can use the ...
wildcard in the main
field value, e.g., ./...
.
Both dir
and main
default to .
.
Existing ko
users
Useful tips for existing ko
users:
-
Specify your destination image registry using Skaffold’s
default-repo
functionality. The ko builder does not read theKO_DOCKER_REPO
environment variable. -
Image naming follows the Skaffold image naming strategy. Skaffold removes the
ko://
prefix, if present, before determining the image name. -
If your image references use the
ko://
prefix and you are pushing the images to a registry, you must set the default repo. -
The ko builder supports reading base image configuration from the
.ko.yaml
file. If you already configure your base images using this file, you do not need to specify thefromImage
field for the artifact inskaffold.yaml
. -
The ko builder supports reading build configs from the
.ko.yaml
file ifskaffold.yaml
does not specify any of the build config fields (dir
,main
,env
,flags
, andldflags
). If you already specify these fields in.ko.yaml
, you do not need to repeat them inskaffold.yaml
. -
You can generate
skaffold.yaml
files by examining an existing code base, using the commandskaffold init --XXenableKoInit=true
. Select the Ko builder for your images when prompted.
ko
commands and workflows in Skaffold
Here are some examples of Skaffold equivalents of ko
commands and worflows.
Using vendored dependencies
If vendor your dependencies and your go.mod
specifies a Go version < 1.14,
you can pass -mod=vendor
to ko
using the GOFLAGS
environment variable:
GOFLAGS="-mod=vendor" ko publish .
To achieve the same using Skaffold’s ko builder, use the flags
field in
skaffold.yaml
:
ko:
flags:
- -mod=vendor
skaffold build
Capturing image name from stdout
If you want Skaffold to print out the full image name and digest (and nothing
else) to stdout
, similar to what ko build
does, use the
--quiet
and --output
flags.
These flags enable you to capture the full image references in an environment
variable or redirect to a file, e.g.:
skaffold build --quiet --output='{{range .Builds}}{{.Tag}}{{end}}' > out.txt
Note that Skaffold produces a JSON file with the image names if you run
skaffold build
with the --file-output
flag. You can then use this flag as
input to skaffold render
to render Kubernetes manifests. For details on how
to do this, see the next section.
Rendering Kubernetes manifests
When you use the Skaffold ko builder, Skaffold takes care of replacing the image placeholder name in your Kubernetes manifest files using its render functionality.
The ko builder supports image name placeholders that consist of the ko://
prefix, followed by the Go import path to the main package. This means that
Skaffold works with existing Kubernetes manifest files that use this image name
placeholder format. Note that Skaffold only replaces image references in fields
that have the name image
.
If you previously built images and rendered Kubernetes manifests using ko
,
e.g.:
ko resolve --filename k8s/*.yaml > out.yaml
You can instead use Skaffold’s
render
subcommand
with the --digest-source local
flag to build and render manifests:
skaffold render --digest-source local --offline --output out.yaml
Or you can perform the action as two steps: first build
the images, then
render
the manifests using the output file from the build
step:
skaffold build --file-output artifacts.json --push
skaffold render --build-artifacts artifacts.json --digest-source none --offline --output out.yaml
Specify the location of your Kubernetes manifests in skaffold.yaml
:
manifests:
rawYaml:
- k8s/*.yaml
To build images in parallel, consider setting the SKAFFOLD_BUILD_CONCURRENCY
environment variable value to 0
:
SKAFFOLD_BUILD_CONCURRENCY=0 skaffold [...]
You can also set the concurrency value in your skaffold.yaml
:
build:
local:
concurrency: 0
Advanced usage
Debugging
Cloud Code and
skaffold debug
can debug images built using ko
.
Images built using ko
are automatically identified as Go apps by the presence
of the
KO_DATA_PATH
environment variable.
Skaffold configures ko
to build with compiler optimizations and inlining
disabled (-gcflags='all=-N -l'
) when you run skaffold debug
or use
Cloud Code to
debug a Kubernetes application.
If you debug using VS Code and need to configure a “remote path” or “path on
remote container”, then this value should match your local path, typically
${workspaceFolder}
. The reason is that “remote path” in this case means the
path to your Go source code where it was compiled. The ko
builder currently
only supports local
builds, so the remote path will be same as the local path.
To learn more about how Skaffold debugs Go applications, read the Go section in the Debugging guide.
File sync
The ko
builder can
sync files to a running container
when you run skaffold dev
.
The sync feature for the ko
builder only works for
static assets bundled with the container image.
Use infer
mode to specify patterns for the files you want to sync. The
infer patterns are relative to the context
directory.
For instance, if your main package is in the context
directory, you can use
this configuration to sync all the static files bundled with the container
image:
sync:
infer:
- kodata/**/*
Note that the file sync feature requires the tar
command to be available in
the container. The default ko
builder base image does not include the tar
command. Use the fromImage
field in the ko
builder configuration in your
skaffold.yaml
file to specify a base image that contains the tar
command,
such as gcr.io/distroless/base-debian11:debug
.
You can use profiles with
activation by command to override the fromImage
value only when running
skaffold dev
, such as in this example:
profiles:
- name: sync
activation:
- command: dev
patches:
- op: add
path: /build/artifacts/0/ko/fromImage
value: gcr.io/distroless/base-debian11:debug
Remote builds
The ko
builder supports remote builds on Google Cloud Build. See the
example.
Using the custom
builder
If the ko builder doesn’t support your use of ko
, you can instead use the
custom
builder.
See the custom
builder
example.
build:
artifacts:
- image: ko://github.com/googlecontainertools/skaffold/examples/custom
custom:
buildCommand: ./build.sh
dependencies:
paths:
- "**/*.go"
- go.*
- .ko.yaml
If you need to use ko
via the custom builder rather than the ko builder,
please consider filing an
issue
that describes your use case.
Collecting coverage profiles from integration tests
Go 1.20 introduced support for collecting coverage profile data from running Go
application when running integration or end-to-end tests. To see how you can
use the ko
builder to configure this, see the tutorial
Go integration test coverage profiles.
SBOM synthesis and upload
The ko
CLI by default generates a software bill of materials (SBOM) and
uploads it to the image registry. The Skaffold ko builder does not generate
or upload SBOMs. If you need this feature, please
raise an issue.