Manage CRDs w/ Skaffold - Configuring Which K8s Resources & Fields Skaffold Manages
Common Use Cases This Page Helps Resolve:
- Users who want skaffold to properly manage the rendering and deployment of their custom CRDs (as skaffold does with K8s objects like Pod, Deployment.apps, etc.)
- Additionally users w/ a CRD that uses a different field name for
image:
(eg:foo:
) and want skaffold to properly modify the value to instead have the image label for the image skaffold recently built
- Additionally users w/ a CRD that uses a different field name for
- Users who are seeing issues with skaffold’s default resource field overwriting for a given resource - eg: skaffold errors as it tries to mutate immutable config on re-deployment
Currently skaffold modifies the manifests it renders and deploys for the following functionality:
- status checking - done by mutating the manifest/K8s-Object by adding a label - skaffold/dev/run-id. Skaffold uses this run-id to identify … (TODO add doc link to run-id explanation)
- image label overwriting - done by mutating the manifest/K8s-Object by substituting the
image:$ORIGINAL_IMAGE_TAG
value(s) in a manifest withimage:$RECENT_SKAFFOLD_BUILT_IMAGE
Skaffold has by default the following resources set for management via field “labels:” and “image:” overwriting:
The below list is derived from the values defined here
- Pod
- DaemonSet.apps
- Deployment.apps
- ReplicaSet.apps
- StatefulSet.apps (with the exception of
.spec.volumeClaimTemplates.*.metadata.labels
field(s)) - CronJob.batch
- Job.batch
- DaemonSet.extensions
- Deployment.extensions
- ReplicaSet.extension
- Service.serving.knative.dev
- Fleet.agones.dev
- GameServer.agones.dev
- Rollout.argoproj.io
- Workflow.argoproj.io
- CronWorkflow.argoproj.io
- WorkflowTemplate.argoproj.io
- ClusterWorkflowTemplate.argoproj.io
- *.cnrm.cloud.google.com
This default overwriting modifies all JSON Paths for those GroupKinds of the form:
_* *.metadata.labels (skaffold appends a run-id
label to existing labels or adds a labels
field with a run-id
entry if it didn’t exist prior)_
_* *.image (changes image:
value to be the skaffold built image ONLY IF skaffold manages the original image:
value)_
The GroupKind’s that Skaffold manages (via resource field overwriting) are user configurable via the resourceSelector:
top level configuration. The resourceSelector
configuration allows users to modify and extend which resources and what fields of those resources skaffold modifies. Currently skaffold only supports label:
and .metadata.labels
related modifications.
(TODO add resourceSelector
schema overview and allowable inputs)
resourceSelector
spec (from pkg/skaffold/schema/latest/config.go
)
// ResourceSelector describes user defined filters describing how skaffold should treat objects/fields during rendering.
ResourceSelector ResourceSelectorConfig `yaml:"resourceSelector,omitempty"`
// ResourceSelectorConfig contains all the configuration needed by the deploy steps.
type ResourceSelectorConfig struct {
// Allow configures an allowlist for transforming manifests.
Allow []ResourceFilter `yaml:"allow,omitempty"`
// Deny configures an allowlist for transforming manifests.
Deny []ResourceFilter `yaml:"deny,omitempty"`
}
// ResourceFilter contains definition to filter which resource to transform.
type ResourceFilter struct {
// GroupKind is the compact format of a resource type.
GroupKind string `yaml:"groupKind" yamltags:"required"`
// Image is an optional slice of JSON-path-like paths of where to rewrite images.
Image []string `yaml:"image,omitempty"`
// Labels is an optional slide of JSON-path-like paths of where to add a labels block if missing.
Labels []string `yaml:"labels,omitempty"`
}
The values for Image
and Labels
support a JSON Path style string which designates a path to a field in the speified GroupKind. Additionally there is a special .*
value that can be used which means that skaffold will attempt to overwrite all relevant labels following the below rules:
- image: [".*"] -> replace all fields which follow
*.image:
where the value is an image that skaffold manages/builds - labels: [".*"] -> append-to or create a field named
*.metadata.labels
if a field*.metadata
is found
Some example use cases and motivations for the resourceSelector
are shown below:
- Skaffold Management of Custom CRD - The below snippet using
resourceSelector
allows a user to configure skaffold to manage a custom CRD (eg: CustomDeployment.skaffold.dev) they’ve created for their application in a skaffold.
Without this snippet, skaffold would apply the yaml but would not properly wait for child resources or replace the image:
values with skaffold built images
apiVersion: skaffold/v2beta28
kind: Config
build:
artifacts:
- image: my-image
context: my-image
deploy:
kubectl:
manifests:
- my-manifests-*
resourceSelector:
allow:
- groupKind: "CustomDeployment.skaffold.dev"
image: [".*"]
labels: [".*"]
Using the above configuation, skaffold will properly update the image:
… and .. allowing it to …
- Fix Issue With Skaffold Overwriting Immutable Field - The below snippet using
resourceSelector
shows a user configuring skaffold to change it’s behaviour to NOT overwrite a resource’s field to prevent K8s errors related to overwriting an immutable field: The below configuration is actually a part of skaffold’s default configuration, just made into a snippet to use as an example
apiVersion: skaffold/v2beta28
kind: Config
build:
artifacts:
- image: my-image
context: my-image
deploy:
kubectl:
manifests:
- k8-*
resourceSelector:
allow:
- groupKind: "StatefulSet.apps"
image: [".*"]
labels: [".*"]
deny:
- groupKind: "StatefulSet.apps"
labels: [".spec.volumeClaimTemplates.*.metadata.labels"]
- Allow
image:
Overwriting For Differently Named Image Field(s) - The below snippet usingresourceSelector
shows a user configuring skaffold to change it’s behaviour to overwrite a resource’sfoo:
field with skaffold built images. This allows skaffold to properly support the images skaffold builds this resources which usesfoo:
instead ofimage:
for an image value:
apiVersion: skaffold/v2beta28
kind: Config
build:
artifacts:
- image: my-image
context: my-image
deploy:
kubectl:
manifests:
- my-manifests-*
resourceSelector:
allow:
- groupKind: "CloudBuildTrigger.cloudbuild.cnrm.cloud.google.com"
image: [".*", ".spec.build.step.*.name"]
labels: [".*"]