mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-07-17 09:49:13 +00:00
Merge pull request #1850 from pwittrock/workspace
cmd/config: Add examples and tutorials for config functions
This commit is contained in:
@@ -14,6 +14,7 @@ func GetRunFnRunner(name string) *RunFnRunner {
|
|||||||
r := &RunFnRunner{}
|
r := &RunFnRunner{}
|
||||||
c := &cobra.Command{
|
c := &cobra.Command{
|
||||||
Use: "run-fns DIR",
|
Use: "run-fns DIR",
|
||||||
|
Aliases: []string{"run"},
|
||||||
Short: commands.RunFnsShort,
|
Short: commands.RunFnsShort,
|
||||||
Long: commands.RunFnsLong,
|
Long: commands.RunFnsLong,
|
||||||
Example: commands.RunFnsExamples,
|
Example: commands.RunFnsExamples,
|
||||||
|
|||||||
@@ -278,3 +278,186 @@ var ConfigurationBasicsLong = `
|
|||||||
│ ├── name: web
|
│ ├── name: web
|
||||||
│ └── image: <YOUR-CONTAINER>
|
│ └── image: <YOUR-CONTAINER>
|
||||||
...`
|
...`
|
||||||
|
|
||||||
|
var FunctionBasicsShort = `### Synopsis`
|
||||||
|
var FunctionBasicsLong = `
|
||||||
|
` + "`" + `kustomize config` + "`" + ` enables encapsulating function for manipulating Resource
|
||||||
|
configuration inside containers, which are run using ` + "`" + `run-fns` + "`" + `.
|
||||||
|
|
||||||
|
First fetch the kustomize repository, which contains a collection of example
|
||||||
|
functions
|
||||||
|
|
||||||
|
git clone https://github.com/kubernetes-sigs/kustomize
|
||||||
|
cd kustomize/functions/examples/
|
||||||
|
|
||||||
|
### Templating -- CockroachDB
|
||||||
|
|
||||||
|
This section demonstrates how to leverage templating based solutions from
|
||||||
|
` + "`" + `kustomize config` + "`" + `. The templating function is implemented as a ` + "`" + `bash` + "`" + ` script
|
||||||
|
using a ` + "`" + `heredoc` + "`" + `.
|
||||||
|
|
||||||
|
#### 1: Generate the Resources
|
||||||
|
|
||||||
|
` + "`" + `cd` + "`" + ` into the ` + "`" + `kustomize/functions/examples/template-heredoc-cockroachdb/` + "`" + `
|
||||||
|
directory, and invoke ` + "`" + `run-fns` + "`" + ` on the ` + "`" + `local-resource/` + "`" + ` directory.
|
||||||
|
|
||||||
|
cd template-heredoc-cockroachdb/
|
||||||
|
|
||||||
|
# view the Resources
|
||||||
|
kustomize config tree local-resource/ --name --image --replicas
|
||||||
|
|
||||||
|
# run the function
|
||||||
|
kustomize config run-fns local-resource/
|
||||||
|
|
||||||
|
# view the generated Resources
|
||||||
|
kustomize config tree local-resource/ --name --image --replicas
|
||||||
|
|
||||||
|
` + "`" + `run-fns` + "`" + ` generated the directory ` + "`" + ` local-resource/config` + "`" + ` containing the generated
|
||||||
|
Resources.
|
||||||
|
|
||||||
|
#### 2. Modify the Generated Resources
|
||||||
|
|
||||||
|
- modify the generated Resources by adding an annotation, sidecar container, etc.
|
||||||
|
- modify the ` + "`" + `local-resources/example-use.yaml` + "`" + ` by changing the replicas
|
||||||
|
|
||||||
|
re-run ` + "`" + `run-fns` + "`" + `. this will apply the updated replicas to the generated Resources,
|
||||||
|
but keep the fields that you manually added to the generated Resource configuration.
|
||||||
|
|
||||||
|
|
||||||
|
# run the function
|
||||||
|
kustomize config run-fns local-resource/
|
||||||
|
|
||||||
|
` + "`" + `run-fns` + "`" + ` facilitates a non-destructive *smart templating* approach that allows templating
|
||||||
|
to be composed with manual modifications directly to the template output, as well as
|
||||||
|
composition with other functions which may appy validation or injection of values.
|
||||||
|
|
||||||
|
#### 3. Function Implementation
|
||||||
|
|
||||||
|
the function implementation is located under the ` + "`" + `image/` + "`" + ` directory as a ` + "`" + `Dockerfile` + "`" + `
|
||||||
|
and a ` + "`" + `bash` + "`" + ` script.
|
||||||
|
|
||||||
|
### Templating -- Nginx
|
||||||
|
|
||||||
|
The steps in this section are identical to the CockroachDB templating example,
|
||||||
|
but the function implementation is very different, and implemented as a ` + "`" + `go` + "`" + `
|
||||||
|
program rather than a ` + "`" + `bash` + "`" + ` script.
|
||||||
|
|
||||||
|
#### 1: Generate the Resources
|
||||||
|
|
||||||
|
` + "`" + `cd` + "`" + ` into the ` + "`" + `kustomize/functions/examples/template-go-nginx/` + "`" + `
|
||||||
|
directory, and invoke ` + "`" + `run-fns` + "`" + ` on the ` + "`" + `local-resource/` + "`" + ` directory.
|
||||||
|
|
||||||
|
cd template-go-nginx/
|
||||||
|
|
||||||
|
# view the Resources
|
||||||
|
kustomize config tree local-resource/ --name --image --replicas
|
||||||
|
|
||||||
|
# run the function
|
||||||
|
kustomize config run-fns local-resource/
|
||||||
|
|
||||||
|
# view the generated Resources
|
||||||
|
kustomize config tree local-resource/ --name --image --replicas
|
||||||
|
|
||||||
|
` + "`" + `run-fns` + "`" + ` generated the directory ` + "`" + ` local-resource/config` + "`" + ` containing the generated
|
||||||
|
Resources. this time it put the configuration in a single file rather than multiple
|
||||||
|
files. The mapping of Resources to files is controlled by the function itself through
|
||||||
|
annotations on the generated Resources.
|
||||||
|
|
||||||
|
#### 2. Modify the Generated Resources
|
||||||
|
|
||||||
|
- modify the generated Resources by adding an annotation, sidecar container, etc.
|
||||||
|
- modify the ` + "`" + `local-resources/example-use.yaml` + "`" + ` by changing the replicas
|
||||||
|
|
||||||
|
re-run ` + "`" + `run-fns` + "`" + `. this will apply the updated replicas to the generated Resources,
|
||||||
|
but keep the fields that you manually added to the generated Resource configuration.
|
||||||
|
|
||||||
|
# run the function
|
||||||
|
kustomize config run-fns local-resource/
|
||||||
|
|
||||||
|
Just like in the preceding section, the function is implemented using a non-destructive
|
||||||
|
approach which merges the generated Resources into previously generated instances.
|
||||||
|
|
||||||
|
#### 3. Function Implementation
|
||||||
|
|
||||||
|
the function implementation is located under the ` + "`" + `image/` + "`" + ` directory as a ` + "`" + `Dockerfile` + "`" + `
|
||||||
|
and a ` + "`" + `go` + "`" + ` program.
|
||||||
|
|
||||||
|
### Validation -- resource reservations
|
||||||
|
|
||||||
|
This section uses ` + "`" + `run-fns` + "`" + ` to perform validation rather than generate Resources.
|
||||||
|
|
||||||
|
#### 1: Run the Validator
|
||||||
|
|
||||||
|
` + "`" + `cd` + "`" + ` into the ` + "`" + `kustomize/functions/examples/validator-resource-requests` + "`" + `
|
||||||
|
directory, and invoke ` + "`" + `run-fns` + "`" + ` on the ` + "`" + `local-resource/` + "`" + ` directory.
|
||||||
|
|
||||||
|
# run the function
|
||||||
|
kustomize config run-fns local-resource/
|
||||||
|
cpu-requests missing for a container in Deployment nginx (example-use.yaml [1])
|
||||||
|
Error: exit status 1
|
||||||
|
Usage:
|
||||||
|
...
|
||||||
|
|
||||||
|
#### 2: Fix the validation issue
|
||||||
|
|
||||||
|
The command will fail complaining that the nginx Deployment is missing ` + "`" + `cpu-requests` + "`" + `,
|
||||||
|
and print the name of the file + Resource index. Edit the file and uncomment the resources,
|
||||||
|
then re-run the functions.
|
||||||
|
|
||||||
|
kustomize config run-fns local-resource/
|
||||||
|
|
||||||
|
The validation now passes.
|
||||||
|
|
||||||
|
### Injection -- resource reservations
|
||||||
|
|
||||||
|
This section uses ` + "`" + `run-fns` + "`" + ` to perform injection of field values based off annotations
|
||||||
|
on the Resource.
|
||||||
|
|
||||||
|
#### 1: Run the Injector
|
||||||
|
|
||||||
|
` + "`" + `cd` + "`" + ` into the ` + "`" + `kustomize/functions/examples/inject-tshirt-sizes` + "`" + `
|
||||||
|
directory, and invoke ` + "`" + `run-fns` + "`" + ` on the ` + "`" + `local-resource/` + "`" + ` directory.
|
||||||
|
|
||||||
|
# print the resources
|
||||||
|
kustomize config tree local-resource --resources --name
|
||||||
|
local-resource
|
||||||
|
├── [example-use.yaml] Validator
|
||||||
|
└── [example-use.yaml] Deployment nginx
|
||||||
|
└── spec.template.spec.containers
|
||||||
|
└── 0
|
||||||
|
└── name: nginx
|
||||||
|
|
||||||
|
# run the functions
|
||||||
|
kustomize config run-fns local-resource/
|
||||||
|
|
||||||
|
# print the new resources
|
||||||
|
kustomize config tree local-resource --resources --name
|
||||||
|
├── [example-use.yaml] Validator
|
||||||
|
└── [example-use.yaml] Deployment nginx
|
||||||
|
└── spec.template.spec.containers
|
||||||
|
└── 0
|
||||||
|
├── name: nginx
|
||||||
|
└── resources: {requests: {cpu: 4, memory: 1GiB}}
|
||||||
|
|
||||||
|
#### 2: Change the tshirt-size
|
||||||
|
|
||||||
|
Change the ` + "`" + `tshirt-size` + "`" + ` annotation from ` + "`" + `medium` + "`" + ` to ` + "`" + `small` + "`" + ` and re-run the functions.
|
||||||
|
|
||||||
|
kustomize config run-fns local-resource/
|
||||||
|
kustomize config tree local-resource/
|
||||||
|
local-resource
|
||||||
|
├── [example-use.yaml] Validator
|
||||||
|
└── [example-use.yaml] Deployment nginx
|
||||||
|
└── spec.template.spec.containers
|
||||||
|
└── 0
|
||||||
|
├── name: nginx
|
||||||
|
└── resources: {requests: {cpu: 200m, memory: 50MiB}}
|
||||||
|
|
||||||
|
The function has applied the reservations for the new tshirt-size
|
||||||
|
|
||||||
|
### Function Composition
|
||||||
|
|
||||||
|
Functions may be composed together. Try putting the Injection (tshirt-size) and
|
||||||
|
Validation functions together in the same .yaml file (separated by ` + "`" + `---` + "`" + `). Run
|
||||||
|
` + "`" + `run-fns` + "`" + ` and observe that the first function in the file is applied to the Resources,
|
||||||
|
and then the second function in the file is applied.`
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ func NewConfigCommand(name string) *cobra.Command {
|
|||||||
})
|
})
|
||||||
root.AddCommand(&cobra.Command{
|
root.AddCommand(&cobra.Command{
|
||||||
Use: "docs-fn",
|
Use: "docs-fn",
|
||||||
Short: "[Alpha] Documentation for writing containerized functions run by run-fns.",
|
Short: "[Alpha] Documentation for writing containerized functions run by run.",
|
||||||
Long: api.ConfigFnLong,
|
Long: api.ConfigFnLong,
|
||||||
})
|
})
|
||||||
root.AddCommand(&cobra.Command{
|
root.AddCommand(&cobra.Command{
|
||||||
@@ -87,10 +87,16 @@ func NewConfigCommand(name string) *cobra.Command {
|
|||||||
})
|
})
|
||||||
|
|
||||||
root.AddCommand(&cobra.Command{
|
root.AddCommand(&cobra.Command{
|
||||||
Use: "tutorials-basics",
|
Use: "tutorials-command-basics",
|
||||||
Short: "[Alpha] Tutorials for using basic config commands.",
|
Short: "[Alpha] Tutorials for using basic config commands.",
|
||||||
Long: tutorials.ConfigurationBasicsLong,
|
Long: tutorials.ConfigurationBasicsLong,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
root.AddCommand(&cobra.Command{
|
||||||
|
Use: "tutorials-function-basics",
|
||||||
|
Short: "[Alpha] Tutorials for using functions.",
|
||||||
|
Long: tutorials.FunctionBasicsLong,
|
||||||
|
})
|
||||||
|
|
||||||
return root
|
return root
|
||||||
}
|
}
|
||||||
|
|||||||
184
cmd/config/docs/tutorials/function-basics.md
Normal file
184
cmd/config/docs/tutorials/function-basics.md
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
## Function Basics
|
||||||
|
|
||||||
|
### Synopsis
|
||||||
|
|
||||||
|
`kustomize config` enables encapsulating function for manipulating Resource
|
||||||
|
configuration inside containers, which are run using `run-fns`.
|
||||||
|
|
||||||
|
First fetch the kustomize repository, which contains a collection of example
|
||||||
|
functions
|
||||||
|
|
||||||
|
git clone https://github.com/kubernetes-sigs/kustomize
|
||||||
|
cd kustomize/functions/examples/
|
||||||
|
|
||||||
|
### Templating -- CockroachDB
|
||||||
|
|
||||||
|
This section demonstrates how to leverage templating based solutions from
|
||||||
|
`kustomize config`. The templating function is implemented as a `bash` script
|
||||||
|
using a `heredoc`.
|
||||||
|
|
||||||
|
#### 1: Generate the Resources
|
||||||
|
|
||||||
|
`cd` into the `kustomize/functions/examples/template-heredoc-cockroachdb/`
|
||||||
|
directory, and invoke `run-fns` on the `local-resource/` directory.
|
||||||
|
|
||||||
|
cd template-heredoc-cockroachdb/
|
||||||
|
|
||||||
|
# view the Resources
|
||||||
|
kustomize config tree local-resource/ --name --image --replicas
|
||||||
|
|
||||||
|
# run the function
|
||||||
|
kustomize config run-fns local-resource/
|
||||||
|
|
||||||
|
# view the generated Resources
|
||||||
|
kustomize config tree local-resource/ --name --image --replicas
|
||||||
|
|
||||||
|
`run-fns` generated the directory ` local-resource/config` containing the generated
|
||||||
|
Resources.
|
||||||
|
|
||||||
|
#### 2. Modify the Generated Resources
|
||||||
|
|
||||||
|
- modify the generated Resources by adding an annotation, sidecar container, etc.
|
||||||
|
- modify the `local-resources/example-use.yaml` by changing the replicas
|
||||||
|
|
||||||
|
re-run `run-fns`. this will apply the updated replicas to the generated Resources,
|
||||||
|
but keep the fields that you manually added to the generated Resource configuration.
|
||||||
|
|
||||||
|
|
||||||
|
# run the function
|
||||||
|
kustomize config run-fns local-resource/
|
||||||
|
|
||||||
|
`run-fns` facilitates a non-destructive *smart templating* approach that allows templating
|
||||||
|
to be composed with manual modifications directly to the template output, as well as
|
||||||
|
composition with other functions which may appy validation or injection of values.
|
||||||
|
|
||||||
|
#### 3. Function Implementation
|
||||||
|
|
||||||
|
the function implementation is located under the `image/` directory as a `Dockerfile`
|
||||||
|
and a `bash` script.
|
||||||
|
|
||||||
|
### Templating -- Nginx
|
||||||
|
|
||||||
|
The steps in this section are identical to the CockroachDB templating example,
|
||||||
|
but the function implementation is very different, and implemented as a `go`
|
||||||
|
program rather than a `bash` script.
|
||||||
|
|
||||||
|
#### 1: Generate the Resources
|
||||||
|
|
||||||
|
`cd` into the `kustomize/functions/examples/template-go-nginx/`
|
||||||
|
directory, and invoke `run-fns` on the `local-resource/` directory.
|
||||||
|
|
||||||
|
cd template-go-nginx/
|
||||||
|
|
||||||
|
# view the Resources
|
||||||
|
kustomize config tree local-resource/ --name --image --replicas
|
||||||
|
|
||||||
|
# run the function
|
||||||
|
kustomize config run-fns local-resource/
|
||||||
|
|
||||||
|
# view the generated Resources
|
||||||
|
kustomize config tree local-resource/ --name --image --replicas
|
||||||
|
|
||||||
|
`run-fns` generated the directory ` local-resource/config` containing the generated
|
||||||
|
Resources. this time it put the configuration in a single file rather than multiple
|
||||||
|
files. The mapping of Resources to files is controlled by the function itself through
|
||||||
|
annotations on the generated Resources.
|
||||||
|
|
||||||
|
#### 2. Modify the Generated Resources
|
||||||
|
|
||||||
|
- modify the generated Resources by adding an annotation, sidecar container, etc.
|
||||||
|
- modify the `local-resources/example-use.yaml` by changing the replicas
|
||||||
|
|
||||||
|
re-run `run-fns`. this will apply the updated replicas to the generated Resources,
|
||||||
|
but keep the fields that you manually added to the generated Resource configuration.
|
||||||
|
|
||||||
|
# run the function
|
||||||
|
kustomize config run-fns local-resource/
|
||||||
|
|
||||||
|
Just like in the preceding section, the function is implemented using a non-destructive
|
||||||
|
approach which merges the generated Resources into previously generated instances.
|
||||||
|
|
||||||
|
#### 3. Function Implementation
|
||||||
|
|
||||||
|
the function implementation is located under the `image/` directory as a `Dockerfile`
|
||||||
|
and a `go` program.
|
||||||
|
|
||||||
|
### Validation -- resource reservations
|
||||||
|
|
||||||
|
This section uses `run-fns` to perform validation rather than generate Resources.
|
||||||
|
|
||||||
|
#### 1: Run the Validator
|
||||||
|
|
||||||
|
`cd` into the `kustomize/functions/examples/validator-resource-requests`
|
||||||
|
directory, and invoke `run-fns` on the `local-resource/` directory.
|
||||||
|
|
||||||
|
# run the function
|
||||||
|
kustomize config run-fns local-resource/
|
||||||
|
cpu-requests missing for a container in Deployment nginx (example-use.yaml [1])
|
||||||
|
Error: exit status 1
|
||||||
|
Usage:
|
||||||
|
...
|
||||||
|
|
||||||
|
#### 2: Fix the validation issue
|
||||||
|
|
||||||
|
The command will fail complaining that the nginx Deployment is missing `cpu-requests`,
|
||||||
|
and print the name of the file + Resource index. Edit the file and uncomment the resources,
|
||||||
|
then re-run the functions.
|
||||||
|
|
||||||
|
kustomize config run-fns local-resource/
|
||||||
|
|
||||||
|
The validation now passes.
|
||||||
|
|
||||||
|
### Injection -- resource reservations
|
||||||
|
|
||||||
|
This section uses `run-fns` to perform injection of field values based off annotations
|
||||||
|
on the Resource.
|
||||||
|
|
||||||
|
#### 1: Run the Injector
|
||||||
|
|
||||||
|
`cd` into the `kustomize/functions/examples/inject-tshirt-sizes`
|
||||||
|
directory, and invoke `run-fns` on the `local-resource/` directory.
|
||||||
|
|
||||||
|
# print the resources
|
||||||
|
kustomize config tree local-resource --resources --name
|
||||||
|
local-resource
|
||||||
|
├── [example-use.yaml] Validator
|
||||||
|
└── [example-use.yaml] Deployment nginx
|
||||||
|
└── spec.template.spec.containers
|
||||||
|
└── 0
|
||||||
|
└── name: nginx
|
||||||
|
|
||||||
|
# run the functions
|
||||||
|
kustomize config run-fns local-resource/
|
||||||
|
|
||||||
|
# print the new resources
|
||||||
|
kustomize config tree local-resource --resources --name
|
||||||
|
├── [example-use.yaml] Validator
|
||||||
|
└── [example-use.yaml] Deployment nginx
|
||||||
|
└── spec.template.spec.containers
|
||||||
|
└── 0
|
||||||
|
├── name: nginx
|
||||||
|
└── resources: {requests: {cpu: 4, memory: 1GiB}}
|
||||||
|
|
||||||
|
#### 2: Change the tshirt-size
|
||||||
|
|
||||||
|
Change the `tshirt-size` annotation from `medium` to `small` and re-run the functions.
|
||||||
|
|
||||||
|
kustomize config run-fns local-resource/
|
||||||
|
kustomize config tree local-resource/
|
||||||
|
local-resource
|
||||||
|
├── [example-use.yaml] Validator
|
||||||
|
└── [example-use.yaml] Deployment nginx
|
||||||
|
└── spec.template.spec.containers
|
||||||
|
└── 0
|
||||||
|
├── name: nginx
|
||||||
|
└── resources: {requests: {cpu: 200m, memory: 50MiB}}
|
||||||
|
|
||||||
|
The function has applied the reservations for the new tshirt-size
|
||||||
|
|
||||||
|
### Function Composition
|
||||||
|
|
||||||
|
Functions may be composed together. Try putting the Injection (tshirt-size) and
|
||||||
|
Validation functions together in the same .yaml file (separated by `---`). Run
|
||||||
|
`run-fns` and observe that the first function in the file is applied to the Resources,
|
||||||
|
and then the second function in the file is applied.
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
Copyright {{.Year}} {{.Holder}}
|
||||||
|
SPDX-License-Identifier: Apache-2.0
|
||||||
42
functions/examples/injection-tshirt-sizes/Makefile
Normal file
42
functions/examples/injection-tshirt-sizes/Makefile
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
# Copyright 2019 The Kubernetes Authors.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
.PHONY: generate license fix vet fmt test build tidy image
|
||||||
|
|
||||||
|
GOBIN := $(shell go env GOPATH)/bin
|
||||||
|
|
||||||
|
build:
|
||||||
|
(cd image && go build -v -o $(GOBIN)/config-function .)
|
||||||
|
|
||||||
|
all: generate license build fix vet fmt test lint tidy
|
||||||
|
|
||||||
|
fix:
|
||||||
|
(cd image && go fix ./...)
|
||||||
|
|
||||||
|
fmt:
|
||||||
|
(cd image && go fmt ./...)
|
||||||
|
|
||||||
|
generate:
|
||||||
|
(which $(GOBIN)/mdtogo || go get sigs.k8s.io/kustomize/cmd/mdtogo)
|
||||||
|
(cd image && GOBIN=$(GOBIN) go generate ./...)
|
||||||
|
|
||||||
|
license:
|
||||||
|
(which $(GOPATH)/bin/addlicense || go get github.com/google/addlicense)
|
||||||
|
$(GOPATH)/bin/addlicense -y 2019 -c "The Kubernetes Authors." -f LICENSE_TEMPLATE .
|
||||||
|
|
||||||
|
tidy:
|
||||||
|
(cd image && go mod tidy)
|
||||||
|
|
||||||
|
lint:
|
||||||
|
(which $(GOBIN)/golangci-lint || go get github.com/golangci/golangci-lint/cmd/golangci-lint@v1.19.1)
|
||||||
|
(cd image && $(GOBIN)/golangci-lint run ./...)
|
||||||
|
|
||||||
|
test:
|
||||||
|
(cd image && go test -cover ./...)
|
||||||
|
|
||||||
|
vet:
|
||||||
|
(cd image && go vet ./...)
|
||||||
|
|
||||||
|
image:
|
||||||
|
docker build image -t gcr.io/kustomize-functions/example-tshirt:v0.1.0
|
||||||
|
docker push gcr.io/kustomize-functions/example-tshirt:v0.1.0
|
||||||
35
functions/examples/injection-tshirt-sizes/README.md
Normal file
35
functions/examples/injection-tshirt-sizes/README.md
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
# Injection
|
||||||
|
|
||||||
|
This is an example of implementing an injection function.
|
||||||
|
|
||||||
|
This example is written in `go` and uses the `kyaml` libraries for parsing the
|
||||||
|
input and writing the output. Writing in `go` is not a requirement.
|
||||||
|
|
||||||
|
## Function implementation
|
||||||
|
|
||||||
|
The function is implemented as an [image](image), and built using `make image`.
|
||||||
|
|
||||||
|
The template is implemented as a go program, which reads a collection of input
|
||||||
|
Resource configuration, and looks for invalid configuration.
|
||||||
|
|
||||||
|
## Function invocation
|
||||||
|
|
||||||
|
The function is invoked by authoring a [local Resource](local-resource)
|
||||||
|
with `metadata.configFn` and running:
|
||||||
|
|
||||||
|
kustomize config run-fns local-resources/
|
||||||
|
|
||||||
|
This exists non-zero if there is an error.
|
||||||
|
|
||||||
|
## Running the Example
|
||||||
|
|
||||||
|
Run the validator with:
|
||||||
|
|
||||||
|
kustomize config run-fns local-resource/
|
||||||
|
|
||||||
|
This will add resource reservations to the Deployment. Change the `tshirt-size`
|
||||||
|
annotation from `medium` to `small` and rerun:
|
||||||
|
|
||||||
|
kustomize config run-fns local-resource/
|
||||||
|
|
||||||
|
Observe that the reservations have changed.
|
||||||
15
functions/examples/injection-tshirt-sizes/image/Dockerfile
Normal file
15
functions/examples/injection-tshirt-sizes/image/Dockerfile
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# Copyright 2019 The Kubernetes Authors.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
FROM golang:1.13-stretch
|
||||||
|
ENV CGO_ENABLED=0
|
||||||
|
WORKDIR /go/src/
|
||||||
|
COPY go.mod .
|
||||||
|
COPY go.sum .
|
||||||
|
RUN go mod download
|
||||||
|
COPY main.go .
|
||||||
|
RUN go build -v -o /usr/local/bin/config-function ./
|
||||||
|
|
||||||
|
FROM alpine:latest
|
||||||
|
COPY --from=0 /usr/local/bin/config-function /usr/local/bin/config-function
|
||||||
|
CMD ["config-function"]
|
||||||
5
functions/examples/injection-tshirt-sizes/image/go.mod
Normal file
5
functions/examples/injection-tshirt-sizes/image/go.mod
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
module sigs.k8s.io/kustomize/functions/examples/injection-tshirt-sizes
|
||||||
|
|
||||||
|
go 1.13
|
||||||
|
|
||||||
|
require sigs.k8s.io/kustomize/kyaml v0.0.0-20191126155111-73fb32c85ad4
|
||||||
27
functions/examples/injection-tshirt-sizes/image/go.sum
Normal file
27
functions/examples/injection-tshirt-sizes/image/go.sum
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
|
||||||
|
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
||||||
|
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||||
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
|
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||||
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||||
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
|
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca h1:1CFlNzQhALwjS9mBAUkycX616GzgsuYUOCHA5+HSlXI=
|
||||||
|
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
||||||
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20191026110619-0b21df46bc1d h1:LCPbGQ34PMrwad11aMZ+dbz5SAsq/0ySjRwQ8I9Qwd8=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20191026110619-0b21df46bc1d/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
sigs.k8s.io/kustomize/kyaml v0.0.0-20191126155111-73fb32c85ad4 h1:QfQuib3Xi0uyHUi/R5MgWmDScb5iy/+LjoaGIdpmMpE=
|
||||||
|
sigs.k8s.io/kustomize/kyaml v0.0.0-20191126155111-73fb32c85ad4/go.mod h1:rywm/rcR5LmCBghz9956tE45OdUPChFoXVVs+WmhMTI=
|
||||||
116
functions/examples/injection-tshirt-sizes/image/main.go
Normal file
116
functions/examples/injection-tshirt-sizes/image/main.go
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
// Copyright 2019 The Kubernetes Authors.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
// Package main implements an injection function for resource reservations and
|
||||||
|
// is run with `kustomize config run-fns -- DIR/`.
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
rw := &kio.ByteReadWriter{Reader: os.Stdin, Writer: os.Stdout, KeepReaderAnnotations: true}
|
||||||
|
p := kio.Pipeline{
|
||||||
|
Inputs: []kio.Reader{rw}, // read the inputs into a slice
|
||||||
|
Filters: []kio.Filter{filter{}}, // run the inject into the inputs
|
||||||
|
Outputs: []kio.Writer{rw}} // copy the inputs to the output
|
||||||
|
if err := p.Execute(); err != nil {
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// filter implements kio.Filter
|
||||||
|
type filter struct{}
|
||||||
|
|
||||||
|
// Filter injects cpu and memory resource reservations into containers for
|
||||||
|
// Resources containing the `tshirt-size` annotation.
|
||||||
|
func (filter) Filter(in []*yaml.RNode) ([]*yaml.RNode, error) {
|
||||||
|
// inject the resource reservations into each Resource
|
||||||
|
for _, r := range in {
|
||||||
|
if err := inject(r); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return in, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// cpuSizes is the mapping from tshirt-size to cpu reservation quantity
|
||||||
|
var cpuSizes = map[string]string{
|
||||||
|
"small": "200m",
|
||||||
|
"medium": "4",
|
||||||
|
"large": "16",
|
||||||
|
}
|
||||||
|
|
||||||
|
// memorySizes is the mapping from tshirt-size to memory reservation quantity
|
||||||
|
var memorySizes = map[string]string{
|
||||||
|
"small": "50MiB",
|
||||||
|
"medium": "1GiB",
|
||||||
|
"large": "32GiB",
|
||||||
|
}
|
||||||
|
|
||||||
|
// inject sets the cpu and memory reservations on all containers for Resources annotated
|
||||||
|
// with `tshirt-size: small|medium|large`
|
||||||
|
func inject(r *yaml.RNode) error {
|
||||||
|
// lookup the containers field
|
||||||
|
containers, err := r.Pipe(yaml.Lookup("spec", "template", "spec", "containers"))
|
||||||
|
if err != nil {
|
||||||
|
s, _ := r.String()
|
||||||
|
return fmt.Errorf("%v: %s", err, s)
|
||||||
|
}
|
||||||
|
if containers == nil {
|
||||||
|
// doesn't have containers, skip the Resource
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for the tshirt-size annotations
|
||||||
|
meta, err := r.GetMeta()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var memorySize, cpuSize string
|
||||||
|
if size, found := meta.Annotations["tshirt-size"]; !found {
|
||||||
|
// not a tshirt-sized Resource, ignore it
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
// lookup the memory and cpu quantities based on the tshirt size
|
||||||
|
memorySize = memorySizes[size]
|
||||||
|
cpuSize = cpuSizes[size]
|
||||||
|
if memorySize == "" || cpuSize == "" {
|
||||||
|
return fmt.Errorf("unsupported tshirt-size: " + size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// visit each container and apply the cpu and memory reservations
|
||||||
|
return containers.VisitElements(func(node *yaml.RNode) error {
|
||||||
|
// set cpu
|
||||||
|
err := node.PipeE(
|
||||||
|
// lookup resources.requests.cpu, creating the field as a
|
||||||
|
// ScalarNode if it doesn't exist
|
||||||
|
yaml.LookupCreate(yaml.ScalarNode, "resources", "requests", "cpu"),
|
||||||
|
// set the field value to the cpuSize
|
||||||
|
yaml.Set(yaml.NewScalarRNode(cpuSize)))
|
||||||
|
if err != nil {
|
||||||
|
s, _ := r.String()
|
||||||
|
return fmt.Errorf("%v: %s", err, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// set memory
|
||||||
|
err = node.PipeE(
|
||||||
|
// lookup resources.requests.memory, creating the field as a
|
||||||
|
// ScalarNode if it doesn't exist
|
||||||
|
yaml.LookupCreate(yaml.ScalarNode, "resources", "requests", "memory"),
|
||||||
|
// set the field value to the memorySize
|
||||||
|
yaml.Set(yaml.NewScalarRNode(memorySize)))
|
||||||
|
if err != nil {
|
||||||
|
s, _ := r.String()
|
||||||
|
return fmt.Errorf("%v: %s", err, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
# Copyright 2019 The Kubernetes Authors.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
apiVersion: examples.config.kubernetes.io/v1beta1
|
||||||
|
kind: Validator
|
||||||
|
metadata:
|
||||||
|
configFn:
|
||||||
|
container:
|
||||||
|
image: gcr.io/kustomize-functions/example-tshirt:v0.1.0
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: nginx
|
||||||
|
labels:
|
||||||
|
app: nginx
|
||||||
|
annotations:
|
||||||
|
tshirt-size: small # this injects the resource reservations
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: nginx
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: nginx
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: nginx
|
||||||
|
image: nginx
|
||||||
2
functions/examples/template-go-nginx/LICENSE_TEMPLATE
Normal file
2
functions/examples/template-go-nginx/LICENSE_TEMPLATE
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
Copyright {{.Year}} {{.Holder}}
|
||||||
|
SPDX-License-Identifier: Apache-2.0
|
||||||
42
functions/examples/template-go-nginx/Makefile
Normal file
42
functions/examples/template-go-nginx/Makefile
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
# Copyright 2019 The Kubernetes Authors.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
.PHONY: generate license fix vet fmt test build tidy image
|
||||||
|
|
||||||
|
GOBIN := $(shell go env GOPATH)/bin
|
||||||
|
|
||||||
|
build:
|
||||||
|
(cd image && go build -v -o $(GOBIN)/config-function .)
|
||||||
|
|
||||||
|
all: generate license build fix vet fmt test lint tidy
|
||||||
|
|
||||||
|
fix:
|
||||||
|
(cd image && go fix ./...)
|
||||||
|
|
||||||
|
fmt:
|
||||||
|
(cd image && go fmt ./...)
|
||||||
|
|
||||||
|
generate:
|
||||||
|
(which $(GOBIN)/mdtogo || go get sigs.k8s.io/kustomize/cmd/mdtogo)
|
||||||
|
(cd image && GOBIN=$(GOBIN) go generate ./...)
|
||||||
|
|
||||||
|
license:
|
||||||
|
(which $(GOPATH)/bin/addlicense || go get github.com/google/addlicense)
|
||||||
|
$(GOPATH)/bin/addlicense -y 2019 -c "The Kubernetes Authors." -f LICENSE_TEMPLATE .
|
||||||
|
|
||||||
|
tidy:
|
||||||
|
(cd image && go mod tidy)
|
||||||
|
|
||||||
|
lint:
|
||||||
|
(which $(GOBIN)/golangci-lint || go get github.com/golangci/golangci-lint/cmd/golangci-lint@v1.19.1)
|
||||||
|
(cd image && $(GOBIN)/golangci-lint run ./...)
|
||||||
|
|
||||||
|
test:
|
||||||
|
(cd image && go test -cover ./...)
|
||||||
|
|
||||||
|
vet:
|
||||||
|
(cd image && go vet ./...)
|
||||||
|
|
||||||
|
image:
|
||||||
|
docker build image -t gcr.io/kustomize-functions/example-nginx:v0.1.0
|
||||||
|
docker push gcr.io/kustomize-functions/example-nginx:v0.1.0
|
||||||
55
functions/examples/template-go-nginx/README.md
Normal file
55
functions/examples/template-go-nginx/README.md
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
# Template GoTemplate
|
||||||
|
|
||||||
|
This is an example of implementing a template function using a `go` template.
|
||||||
|
|
||||||
|
This example uses a more sophisticated approach for building abstractions.
|
||||||
|
|
||||||
|
## Function implementation
|
||||||
|
|
||||||
|
The function is implemented as an [image](image), and built using `make image`.
|
||||||
|
|
||||||
|
The template is implemented as a go program with a `go` template. It parses the
|
||||||
|
functionConfig into a `go` struct and uses the `kyaml` module for parsing the
|
||||||
|
function input, and writing the function output.
|
||||||
|
|
||||||
|
1. read the inputs (stdin)
|
||||||
|
2. apply filters
|
||||||
|
- (custom filter) generate the nginx Deployment and Service from go templates using the
|
||||||
|
functionConfig as the template input.
|
||||||
|
- merge the generated Deployment and Service with the input Deployment and Service if
|
||||||
|
present
|
||||||
|
- set filenames on the Resources (`NAME.yaml`)
|
||||||
|
- format the Resources
|
||||||
|
3. write the outputs (stdout)
|
||||||
|
|
||||||
|
## Function invocation
|
||||||
|
|
||||||
|
The function is invoked by authoring a [local Resource](local-resource)
|
||||||
|
with `metadata.configFn` and running:
|
||||||
|
|
||||||
|
kustomize config run-fns local-resources/
|
||||||
|
|
||||||
|
This generates the `local-resources/config` directory containing the template output.
|
||||||
|
|
||||||
|
- the template output may be modified by adding fields -- such as initContainers,
|
||||||
|
sidecarConatiners, cpu resource limits, etc -- and these fields will be retained
|
||||||
|
when re-running `run-fns`
|
||||||
|
- the function input `example-use.yaml` may be changed and rerunning `run-fns` will update
|
||||||
|
only the parts changed in the template output.
|
||||||
|
|
||||||
|
## Running the Example
|
||||||
|
|
||||||
|
Run the config with:
|
||||||
|
|
||||||
|
kustomize config run-fns local-resource/
|
||||||
|
|
||||||
|
This will create the directory
|
||||||
|
|
||||||
|
local-resource/config
|
||||||
|
|
||||||
|
Add an annotation to the StatefulSet Resource and change the replica count of the
|
||||||
|
`kind: Nginx` Resource in `example-use.yaml`. Rerun the template:
|
||||||
|
|
||||||
|
kustomize config run-fns local-resource/
|
||||||
|
|
||||||
|
The replica count should be updated, but your annotation should remain.
|
||||||
15
functions/examples/template-go-nginx/image/Dockerfile
Normal file
15
functions/examples/template-go-nginx/image/Dockerfile
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# Copyright 2019 The Kubernetes Authors.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
FROM golang:1.13-stretch
|
||||||
|
ENV CGO_ENABLED=0
|
||||||
|
WORKDIR /go/src/
|
||||||
|
COPY go.mod .
|
||||||
|
COPY go.sum .
|
||||||
|
RUN go mod download
|
||||||
|
COPY main.go .
|
||||||
|
RUN go build -v -o /usr/local/bin/config-function ./
|
||||||
|
|
||||||
|
FROM alpine:latest
|
||||||
|
COPY --from=0 /usr/local/bin/config-function /usr/local/bin/config-function
|
||||||
|
CMD ["config-function"]
|
||||||
5
functions/examples/template-go-nginx/image/go.mod
Normal file
5
functions/examples/template-go-nginx/image/go.mod
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
module sigs.k8s.io/kustomize/functions/examples/template-go-nginx
|
||||||
|
|
||||||
|
go 1.12
|
||||||
|
|
||||||
|
require sigs.k8s.io/kustomize/kyaml v0.0.0-20191126203124-d1b33e746881
|
||||||
27
functions/examples/template-go-nginx/image/go.sum
Normal file
27
functions/examples/template-go-nginx/image/go.sum
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
|
||||||
|
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
||||||
|
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||||
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
|
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||||
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||||
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
|
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca h1:1CFlNzQhALwjS9mBAUkycX616GzgsuYUOCHA5+HSlXI=
|
||||||
|
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
||||||
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20191026110619-0b21df46bc1d h1:LCPbGQ34PMrwad11aMZ+dbz5SAsq/0ySjRwQ8I9Qwd8=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20191026110619-0b21df46bc1d/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
sigs.k8s.io/kustomize/kyaml v0.0.0-20191126203124-d1b33e746881 h1:dmMlmv+TXMSAtCf6Za1GKNAjCssKtgnVkAYRiKdnjIY=
|
||||||
|
sigs.k8s.io/kustomize/kyaml v0.0.0-20191126203124-d1b33e746881/go.mod h1:rywm/rcR5LmCBghz9956tE45OdUPChFoXVVs+WmhMTI=
|
||||||
169
functions/examples/template-go-nginx/image/main.go
Normal file
169
functions/examples/template-go-nginx/image/main.go
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
// Copyright 2019 The Kubernetes Authors.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
|
"text/template"
|
||||||
|
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/kio/filters"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
rw := &kio.ByteReadWriter{
|
||||||
|
Reader: os.Stdin,
|
||||||
|
Writer: os.Stdout,
|
||||||
|
KeepReaderAnnotations: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := kio.Pipeline{
|
||||||
|
Inputs: []kio.Reader{rw},
|
||||||
|
Filters: []kio.Filter{
|
||||||
|
&filter{rw: rw}, // generate the Resources from the template
|
||||||
|
filters.MergeFilter{}, // merge the generated template
|
||||||
|
// set Resource filenames
|
||||||
|
&filters.FileSetter{FilenamePattern: filepath.Join("config", "%n.yaml")},
|
||||||
|
filters.FormatFilter{}, // format the output
|
||||||
|
},
|
||||||
|
Outputs: []kio.Writer{rw},
|
||||||
|
}.Execute()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "%v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// define the input API schema as a struct
|
||||||
|
type API struct {
|
||||||
|
Metadata struct {
|
||||||
|
// Name is the Deployment Resource and Container name
|
||||||
|
Name string `yaml:"name"`
|
||||||
|
} `yaml:"metadata"`
|
||||||
|
|
||||||
|
Spec struct {
|
||||||
|
// Replicas is the number of Deployment replicas
|
||||||
|
// Defaults to the REPLICAS env var, or 1
|
||||||
|
Replicas *int `yaml:"replicas"`
|
||||||
|
} `yaml:"spec"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// filter implements kio.Filter
|
||||||
|
type filter struct {
|
||||||
|
rw *kio.ByteReadWriter
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter checks each input and ensures that all containers have cpu and memory
|
||||||
|
// reservations set, otherwise it returns an error.
|
||||||
|
func (f *filter) Filter(in []*yaml.RNode) ([]*yaml.RNode, error) {
|
||||||
|
api := f.parseAPI()
|
||||||
|
|
||||||
|
// execute the service template
|
||||||
|
buff := &bytes.Buffer{}
|
||||||
|
t := template.Must(template.New("nginx-service").Parse(serviceTemplate))
|
||||||
|
if err := t.Execute(buff, api); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
s, err := yaml.Parse(buff.String())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// execute the deployment template
|
||||||
|
buff = &bytes.Buffer{}
|
||||||
|
t = template.Must(template.New("nginx-deployment").Parse(deploymentTemplate))
|
||||||
|
if err := t.Execute(buff, api); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
d, err := yaml.Parse(buff.String())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// add the template generated Resources to the output -- these will get merged by the next
|
||||||
|
// filter
|
||||||
|
in = append(in, s, d)
|
||||||
|
return in, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseAPI parses the functionConfig into an API struct, and validates the input
|
||||||
|
func (f *filter) parseAPI() API {
|
||||||
|
// parse the input function config -- TODO: simplify this
|
||||||
|
var api API
|
||||||
|
if err := yaml.Unmarshal([]byte(f.rw.FunctionConfig.MustString()), &api); err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "%v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default functionConfig values from environment variables if they are not set
|
||||||
|
// in the functionConfig
|
||||||
|
r := os.Getenv("REPLICAS")
|
||||||
|
if r != "" && api.Spec.Replicas == nil {
|
||||||
|
replicas, err := strconv.Atoi(r)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "%v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
api.Spec.Replicas = &replicas
|
||||||
|
}
|
||||||
|
if api.Spec.Replicas == nil {
|
||||||
|
r := 1
|
||||||
|
api.Spec.Replicas = &r
|
||||||
|
}
|
||||||
|
if api.Metadata.Name == "" {
|
||||||
|
fmt.Fprintf(os.Stderr, "must specify metadata.name\n")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return api
|
||||||
|
}
|
||||||
|
|
||||||
|
var serviceTemplate = `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: {{ .Metadata.Name }}
|
||||||
|
labels:
|
||||||
|
app: nginx
|
||||||
|
instance: {{ .Metadata.Name }}
|
||||||
|
spec:
|
||||||
|
ports:
|
||||||
|
- port: 80
|
||||||
|
targetPort: 80
|
||||||
|
name: http
|
||||||
|
selector:
|
||||||
|
app: nginx
|
||||||
|
instance: {{ .Metadata.Name }}
|
||||||
|
`
|
||||||
|
|
||||||
|
var deploymentTemplate = `apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: {{ .Metadata.Name }}
|
||||||
|
labels:
|
||||||
|
app: nginx
|
||||||
|
instance: {{ .Metadata.Name }}
|
||||||
|
spec:
|
||||||
|
replicas: {{ .Spec.Replicas }}
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: nginx
|
||||||
|
instance: {{ .Metadata.Name }}
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: nginx
|
||||||
|
instance: {{ .Metadata.Name }}
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: nginx
|
||||||
|
image: nginx:1.7.9
|
||||||
|
ports:
|
||||||
|
- containerPort: 80
|
||||||
|
`
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# Copyright 2019 The Kubernetes Authors.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
apiVersion: examples.config.kubernetes.io/v1beta1 # call `kustomize config run-fns` on a directory containing this file
|
||||||
|
kind: Nginx
|
||||||
|
metadata:
|
||||||
|
name: demo
|
||||||
|
configFn:
|
||||||
|
container:
|
||||||
|
image: gcr.io/kustomize-functions/example-nginx:v0.1.0
|
||||||
|
spec:
|
||||||
|
replicas: 4
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
Copyright {{.Year}} {{.Holder}}
|
||||||
|
SPDX-License-Identifier: Apache-2.0
|
||||||
12
functions/examples/template-heredoc-cockroachdb/Makefile
Normal file
12
functions/examples/template-heredoc-cockroachdb/Makefile
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# Copyright 2019 The Kubernetes Authors.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
.PHONY: license image
|
||||||
|
|
||||||
|
license:
|
||||||
|
(which $(GOPATH)/bin/addlicense || go get github.com/google/addlicense)
|
||||||
|
$(GOPATH)/bin/addlicense -y 2019 -c "The Kubernetes Authors." -f LICENSE_TEMPLATE .
|
||||||
|
|
||||||
|
image:
|
||||||
|
docker build image -t gcr.io/kustomize-functions/example-cockroachdb:v0.1.0
|
||||||
|
docker push gcr.io/kustomize-functions/example-cockroachdb:v0.1.0
|
||||||
50
functions/examples/template-heredoc-cockroachdb/README.md
Normal file
50
functions/examples/template-heredoc-cockroachdb/README.md
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
# Template HereDoc
|
||||||
|
|
||||||
|
This is an example of implementing a template function using a heredoc.
|
||||||
|
|
||||||
|
This example uses the simplest approach for building abstractions.
|
||||||
|
|
||||||
|
## Function implementation
|
||||||
|
|
||||||
|
The function is implemented as an [image](image), and built using `make image`.
|
||||||
|
|
||||||
|
The template is implemented as a heredoc, which substitutes environment variables
|
||||||
|
into a static string.
|
||||||
|
|
||||||
|
This simple implementation uses `kustomize config run-fns wrap --` to perform the
|
||||||
|
heavy lifting of implementing the function interface.
|
||||||
|
|
||||||
|
- parse functionConfig from stdin into environment variables
|
||||||
|
- merge script output with items from stdin
|
||||||
|
|
||||||
|
## Function invocation
|
||||||
|
|
||||||
|
The function is invoked by authoring a [local Resource](local-resource)
|
||||||
|
with `metadata.configFn` and running:
|
||||||
|
|
||||||
|
kustomize config run-fns local-resources/
|
||||||
|
|
||||||
|
This generates the `local-resources/config` directory containing the template output.
|
||||||
|
|
||||||
|
- the template output may be modified by adding fields -- such as initContainers,
|
||||||
|
sidecarConatiners, cpu resource limits, etc -- and these fields will be retained
|
||||||
|
when re-running `run-fns`
|
||||||
|
- the function input `example-use.yaml` may be changed and rerunning `run-fns` will update
|
||||||
|
only the parts changed in the template output.
|
||||||
|
|
||||||
|
## Running the Example
|
||||||
|
|
||||||
|
Run the config with:
|
||||||
|
|
||||||
|
kustomize config run-fns local-resource/
|
||||||
|
|
||||||
|
This will create the directory
|
||||||
|
|
||||||
|
local-resource/config
|
||||||
|
|
||||||
|
Add an annotation to the StatefulSet Resource and change the replica count of the
|
||||||
|
`kind: CockroachDB` Resource in `example-use.yaml`. Rerun the template:
|
||||||
|
|
||||||
|
kustomize config run-fns local-resource/
|
||||||
|
|
||||||
|
The replica count should be updated, but your annotation should remain.
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# Copyright 2019 The Kubernetes Authors.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
FROM golang:1.13-stretch
|
||||||
|
ENV CGO_ENABLED=0
|
||||||
|
RUN go get -v sigs.k8s.io/kustomize/kustomize
|
||||||
|
|
||||||
|
FROM alpine:latest
|
||||||
|
RUN apk add --no-cache bash
|
||||||
|
COPY --from=0 /go/bin/kustomize /usr/local/bin
|
||||||
|
COPY cockroachdb-template.sh /usr/local/bin/config-function
|
||||||
|
CMD ["config-function"]
|
||||||
204
functions/examples/template-heredoc-cockroachdb/image/cockroachdb-template.sh
Executable file
204
functions/examples/template-heredoc-cockroachdb/image/cockroachdb-template.sh
Executable file
@@ -0,0 +1,204 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Copyright 2019 The Kubernetes Authors.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
|
||||||
|
# use `kustomize config run-fns wrap` to parse the container stdin into
|
||||||
|
# environment variables, and to merge the template output into the
|
||||||
|
# input Resources.
|
||||||
|
if [ -z ${WRAPPED} ]; then
|
||||||
|
export WRAPPED=true
|
||||||
|
kustomize config run-fns wrap -- $0
|
||||||
|
exit $?
|
||||||
|
fi
|
||||||
|
|
||||||
|
# this is the template for a cockroachdb instance
|
||||||
|
# environment variables are parsed from the input functionConfig by
|
||||||
|
# `kustomize config run-fns wrap`
|
||||||
|
cat <<End-of-message
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
# This service is meant to be used by clients of the database. It exposes a ClusterIP that will
|
||||||
|
# automatically load balance connections to the different database pods.
|
||||||
|
name: ${NAME}-public
|
||||||
|
labels:
|
||||||
|
app: cockroachdb
|
||||||
|
name: ${NAME}
|
||||||
|
spec:
|
||||||
|
ports:
|
||||||
|
# The main port, served by gRPC, serves Postgres-flavor SQL, internode
|
||||||
|
# traffic and the cli.
|
||||||
|
- port: 26257
|
||||||
|
targetPort: 26257
|
||||||
|
name: grpc
|
||||||
|
# The secondary port serves the UI as well as health and debug endpoints.
|
||||||
|
- port: 8080
|
||||||
|
targetPort: 8080
|
||||||
|
name: http
|
||||||
|
selector:
|
||||||
|
app: cockroachdb
|
||||||
|
name: ${NAME}
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
# This service only exists to create DNS entries for each pod in the stateful
|
||||||
|
# set such that they can resolve each other's IP addresses. It does not
|
||||||
|
# create a load-balanced ClusterIP and should not be used directly by clients
|
||||||
|
# in most circumstances.
|
||||||
|
name: ${NAME}
|
||||||
|
labels:
|
||||||
|
app: cockroachdb
|
||||||
|
name: ${NAME}
|
||||||
|
annotations:
|
||||||
|
# This is needed to make the peer-finder work properly and to help avoid
|
||||||
|
# edge cases where instance 0 comes up after losing its data and needs to
|
||||||
|
# decide whether it should create a new cluster or try to join an existing
|
||||||
|
# one. If it creates a new cluster when it should have joined an existing
|
||||||
|
# one, we'd end up with two separate clusters listening at the same service
|
||||||
|
# endpoint, which would be very bad.
|
||||||
|
service.alpha.kubernetes.io/tolerate-unready-endpoints: "true"
|
||||||
|
# Enable automatic monitoring of all instances when Prometheus is running in the cluster.
|
||||||
|
prometheus.io/scrape: "true"
|
||||||
|
prometheus.io/path: "_status/vars"
|
||||||
|
prometheus.io/port: "8080"
|
||||||
|
spec:
|
||||||
|
ports:
|
||||||
|
- port: 26257
|
||||||
|
targetPort: 26257
|
||||||
|
name: grpc
|
||||||
|
- port: 8080
|
||||||
|
targetPort: 8080
|
||||||
|
name: http
|
||||||
|
clusterIP: None
|
||||||
|
selector:
|
||||||
|
app: cockroachdb
|
||||||
|
name: ${NAME}
|
||||||
|
---
|
||||||
|
apiVersion: policy/v1beta1
|
||||||
|
kind: PodDisruptionBudget
|
||||||
|
metadata:
|
||||||
|
name: ${NAME}-budget
|
||||||
|
labels:
|
||||||
|
app: cockroachdb
|
||||||
|
name: ${NAME}
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: cockroachdb
|
||||||
|
name: ${NAME}
|
||||||
|
minAvailable: 67%
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1 # for k8s versions before 1.9.0 use apps/v1beta2 and before 1.8.0 use extensions/v1beta1
|
||||||
|
kind: StatefulSet
|
||||||
|
metadata:
|
||||||
|
name: ${NAME}
|
||||||
|
labels:
|
||||||
|
app: cockroachdb
|
||||||
|
name: ${NAME}
|
||||||
|
spec:
|
||||||
|
serviceName: ${NAME}
|
||||||
|
replicas: ${REPLICAS}
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: cockroachdb
|
||||||
|
name: ${NAME}
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: cockroachdb
|
||||||
|
name: ${NAME}
|
||||||
|
spec:
|
||||||
|
# Init containers are run only once in the lifetime of a pod, before
|
||||||
|
# it's started up for the first time. It has to exit successfully
|
||||||
|
# before the pod's main containers are allowed to start.
|
||||||
|
# This particular init container does a DNS lookup for other pods in
|
||||||
|
# the set to help determine whether or not a cluster already exists.
|
||||||
|
# If any other pods exist, it creates a file in the cockroach-data
|
||||||
|
# directory to pass that information along to the primary container that
|
||||||
|
# has to decide what command-line flags to use when starting CockroachDB.
|
||||||
|
# This only matters when a pod's persistent volume is empty - if it has
|
||||||
|
# data from a previous execution, that data will always be used.
|
||||||
|
#
|
||||||
|
# If your Kubernetes cluster uses a custom DNS domain, you will have
|
||||||
|
# to add an additional arg to this pod: "-domain=<your-custom-domain>"
|
||||||
|
initContainers:
|
||||||
|
- name: bootstrap
|
||||||
|
image: cockroachdb/cockroach-k8s-init:0.1
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
args:
|
||||||
|
- "-on-start=/on-start.sh"
|
||||||
|
- "-service=cockroachdb"
|
||||||
|
env:
|
||||||
|
- name: POD_NAMESPACE
|
||||||
|
valueFrom:
|
||||||
|
fieldRef:
|
||||||
|
fieldPath: metadata.namespace
|
||||||
|
volumeMounts:
|
||||||
|
- name: datadir
|
||||||
|
mountPath: "/cockroach/cockroach-data"
|
||||||
|
affinity:
|
||||||
|
podAntiAffinity:
|
||||||
|
preferredDuringSchedulingIgnoredDuringExecution:
|
||||||
|
- weight: 100
|
||||||
|
podAffinityTerm:
|
||||||
|
labelSelector:
|
||||||
|
matchExpressions:
|
||||||
|
- key: app
|
||||||
|
operator: In
|
||||||
|
values:
|
||||||
|
- cockroachdb
|
||||||
|
topologyKey: kubernetes.io/hostname
|
||||||
|
containers:
|
||||||
|
- name: ${NAME}
|
||||||
|
image: cockroachdb/cockroach:v1.1.0
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
ports:
|
||||||
|
- containerPort: 26257
|
||||||
|
name: grpc
|
||||||
|
- containerPort: 8080
|
||||||
|
name: http
|
||||||
|
volumeMounts:
|
||||||
|
- name: datadir
|
||||||
|
mountPath: /cockroach/cockroach-data
|
||||||
|
command:
|
||||||
|
- "/bin/bash"
|
||||||
|
- "-ecx"
|
||||||
|
- |
|
||||||
|
# The use of qualified \`hostname -f\` is crucial:
|
||||||
|
# Other nodes aren't able to look up the unqualified hostname.
|
||||||
|
CRARGS=("start" "--logtostderr" "--insecure" "--host" "\$(hostname -f)" "--http-host" "0.0.0.0")
|
||||||
|
# We only want to initialize a new cluster (by omitting the join flag)
|
||||||
|
# if we're sure that we're the first node (i.e. index 0) and that
|
||||||
|
# there aren't any other nodes running as part of the cluster that
|
||||||
|
# this is supposed to be a part of (which indicates that a cluster
|
||||||
|
# already exists and we should make sure not to create a new one).
|
||||||
|
# It's fine to run without --join on a restart if there aren't any
|
||||||
|
# other nodes.
|
||||||
|
if [ ! "\$(hostname)" == "cockroachdb-0" ] || \
|
||||||
|
[ -e "/cockroach/cockroach-data/cluster_exists_marker" ]
|
||||||
|
then
|
||||||
|
# We don't join cockroachdb in order to avoid a node attempting
|
||||||
|
# to join itself, which currently doesn't work
|
||||||
|
# (https://github.com/cockroachdb/cockroach/issues/9625).
|
||||||
|
CRARGS+=("--join" "cockroachdb-public")
|
||||||
|
fi
|
||||||
|
exec /cockroach/cockroach \${CRARGS[*]}
|
||||||
|
# No pre-stop hook is required, a SIGTERM plus some time is all that's
|
||||||
|
# needed for graceful shutdown of a node.
|
||||||
|
terminationGracePeriodSeconds: 60
|
||||||
|
volumes:
|
||||||
|
- name: datadir
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: datadir
|
||||||
|
volumeClaimTemplates:
|
||||||
|
- metadata:
|
||||||
|
name: datadir
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- "ReadWriteOnce"
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 1Gi
|
||||||
|
End-of-message
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
# Copyright 2019 The Kubernetes Authors.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
# call `kustomize config run-fns` on a directory containing this file
|
||||||
|
apiVersion: examples.config.kubernetes.io/v1beta1
|
||||||
|
kind: CockroachDB
|
||||||
|
metadata:
|
||||||
|
name: demo
|
||||||
|
configFn:
|
||||||
|
container:
|
||||||
|
image: gcr.io/kustomize-functions/example-cockroachdb:v0.1.0
|
||||||
|
spec:
|
||||||
|
replicas: 3
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
Copyright {{.Year}} {{.Holder}}
|
||||||
|
SPDX-License-Identifier: Apache-2.0
|
||||||
42
functions/examples/validator-resource-requests/Makefile
Normal file
42
functions/examples/validator-resource-requests/Makefile
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
# Copyright 2019 The Kubernetes Authors.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
.PHONY: generate license fix vet fmt test build tidy image
|
||||||
|
|
||||||
|
GOBIN := $(shell go env GOPATH)/bin
|
||||||
|
|
||||||
|
build:
|
||||||
|
(cd image && go build -v -o $(GOBIN)/config-function .)
|
||||||
|
|
||||||
|
all: generate license build fix vet fmt test lint tidy
|
||||||
|
|
||||||
|
fix:
|
||||||
|
(cd image && go fix ./...)
|
||||||
|
|
||||||
|
fmt:
|
||||||
|
(cd image && go fmt ./...)
|
||||||
|
|
||||||
|
generate:
|
||||||
|
(which $(GOBIN)/mdtogo || go get sigs.k8s.io/kustomize/cmd/mdtogo)
|
||||||
|
(cd image && GOBIN=$(GOBIN) go generate ./...)
|
||||||
|
|
||||||
|
license:
|
||||||
|
(which $(GOPATH)/bin/addlicense || go get github.com/google/addlicense)
|
||||||
|
$(GOPATH)/bin/addlicense -y 2019 -c "The Kubernetes Authors." -f LICENSE_TEMPLATE .
|
||||||
|
|
||||||
|
tidy:
|
||||||
|
(cd image && go mod tidy)
|
||||||
|
|
||||||
|
lint:
|
||||||
|
(which $(GOBIN)/golangci-lint || go get github.com/golangci/golangci-lint/cmd/golangci-lint@v1.19.1)
|
||||||
|
(cd image && $(GOBIN)/golangci-lint run ./...)
|
||||||
|
|
||||||
|
test:
|
||||||
|
(cd image && go test -cover ./...)
|
||||||
|
|
||||||
|
vet:
|
||||||
|
(cd image && go vet ./...)
|
||||||
|
|
||||||
|
image:
|
||||||
|
docker build image -t gcr.io/kustomize-functions/example-validator:v0.1.0
|
||||||
|
docker push gcr.io/kustomize-functions/example-validator:v0.1.0
|
||||||
38
functions/examples/validator-resource-requests/README.md
Normal file
38
functions/examples/validator-resource-requests/README.md
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
# Validation
|
||||||
|
|
||||||
|
This is an example of implementing a validation function.
|
||||||
|
|
||||||
|
This example is written in `go` and uses the `kyaml` libraries for parsing the
|
||||||
|
input and writing the output. Writing in `go` is not a requirement.
|
||||||
|
|
||||||
|
## Function implementation
|
||||||
|
|
||||||
|
The function is implemented as an [image](image), and built using `make image`.
|
||||||
|
|
||||||
|
The template is implemented as a go program, which reads a collection of input
|
||||||
|
Resource configuration, and looks for invalid configuration.
|
||||||
|
|
||||||
|
## Function invocation
|
||||||
|
|
||||||
|
The function is invoked by authoring a [local Resource](local-resource)
|
||||||
|
with `metadata.configFn` and running:
|
||||||
|
|
||||||
|
kustomize config run-fns local-resources/
|
||||||
|
|
||||||
|
This exists non-zero if there is an error.
|
||||||
|
|
||||||
|
## Running the Example
|
||||||
|
|
||||||
|
Run the validator with:
|
||||||
|
|
||||||
|
kustomize config run-fns local-resource/
|
||||||
|
|
||||||
|
This will return an error:
|
||||||
|
|
||||||
|
cpu-requests missing for container nginx
|
||||||
|
|
||||||
|
Now uncomment the resource reservations and run again:
|
||||||
|
|
||||||
|
kustomize config run-fns local-resource/
|
||||||
|
|
||||||
|
This will return success
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
# Copyright 2019 The Kubernetes Authors.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
FROM golang:1.13-stretch
|
||||||
|
ENV CGO_ENABLED=0
|
||||||
|
WORKDIR /go/src/
|
||||||
|
COPY go.mod .
|
||||||
|
COPY go.sum .
|
||||||
|
RUN go mod download
|
||||||
|
COPY main.go .
|
||||||
|
RUN go build -v -o /usr/local/bin/config-function ./
|
||||||
|
|
||||||
|
FROM alpine:latest
|
||||||
|
COPY --from=0 /usr/local/bin/config-function /usr/local/bin/config-function
|
||||||
|
CMD ["config-function"]
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
module sigs.k8s.io/kustomize/functions/examples/validator-resource-requests
|
||||||
|
|
||||||
|
go 1.13
|
||||||
|
|
||||||
|
require sigs.k8s.io/kustomize/kyaml v0.0.0-20191126155111-73fb32c85ad4
|
||||||
27
functions/examples/validator-resource-requests/image/go.sum
Normal file
27
functions/examples/validator-resource-requests/image/go.sum
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
|
||||||
|
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
||||||
|
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||||
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
|
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||||
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||||
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
|
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca h1:1CFlNzQhALwjS9mBAUkycX616GzgsuYUOCHA5+HSlXI=
|
||||||
|
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
||||||
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20191026110619-0b21df46bc1d h1:LCPbGQ34PMrwad11aMZ+dbz5SAsq/0ySjRwQ8I9Qwd8=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20191026110619-0b21df46bc1d/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
sigs.k8s.io/kustomize/kyaml v0.0.0-20191126155111-73fb32c85ad4 h1:QfQuib3Xi0uyHUi/R5MgWmDScb5iy/+LjoaGIdpmMpE=
|
||||||
|
sigs.k8s.io/kustomize/kyaml v0.0.0-20191126155111-73fb32c85ad4/go.mod h1:rywm/rcR5LmCBghz9956tE45OdUPChFoXVVs+WmhMTI=
|
||||||
94
functions/examples/validator-resource-requests/image/main.go
Normal file
94
functions/examples/validator-resource-requests/image/main.go
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
// Copyright 2019 The Kubernetes Authors.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
// Package main implements a validator function run by `kustomize config run-fns`
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/kio/kioutil"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
rw := &kio.ByteReadWriter{Reader: os.Stdin, Writer: os.Stdout, KeepReaderAnnotations: true}
|
||||||
|
p := kio.Pipeline{
|
||||||
|
Inputs: []kio.Reader{rw}, // read the inputs into a slice
|
||||||
|
Filters: []kio.Filter{filter{}}, // run the filter against the inputs
|
||||||
|
Outputs: []kio.Writer{rw}} // copy the inputs to the output
|
||||||
|
if err := p.Execute(); err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "%v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// filter implements kio.Filter
|
||||||
|
type filter struct{}
|
||||||
|
|
||||||
|
// Filter checks each input and ensures that all containers have cpu and memory
|
||||||
|
// reservations set, otherwise it returns an error.
|
||||||
|
func (filter) Filter(in []*yaml.RNode) ([]*yaml.RNode, error) {
|
||||||
|
// validate each Resource
|
||||||
|
for _, r := range in {
|
||||||
|
if err := validate(r); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return in, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func validate(r *yaml.RNode) error {
|
||||||
|
meta, err := r.GetMeta()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// lookup the containers field in the Resource
|
||||||
|
containers, err := r.Pipe(yaml.Lookup("spec", "template", "spec", "containers"))
|
||||||
|
if err != nil {
|
||||||
|
s, _ := r.String()
|
||||||
|
return fmt.Errorf("%v: %s", err, s)
|
||||||
|
}
|
||||||
|
if containers == nil {
|
||||||
|
// doesn't have containers, ignore it
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// visit each container in the list and validate
|
||||||
|
return containers.VisitElements(func(node *yaml.RNode) error {
|
||||||
|
|
||||||
|
// check cpu is non-nil
|
||||||
|
f, err := node.Pipe(yaml.Lookup("resources", "requests", "cpu"))
|
||||||
|
if err != nil {
|
||||||
|
s, _ := r.String()
|
||||||
|
return fmt.Errorf("%v: %s", err, s)
|
||||||
|
}
|
||||||
|
if f == nil {
|
||||||
|
return fmt.Errorf(
|
||||||
|
"cpu-requests missing for a container in %s %s (%s [%s])",
|
||||||
|
meta.Kind, meta.Name,
|
||||||
|
meta.Annotations[kioutil.PathAnnotation],
|
||||||
|
meta.Annotations[kioutil.IndexAnnotation])
|
||||||
|
}
|
||||||
|
|
||||||
|
// check memory is non-nil
|
||||||
|
f, err = node.Pipe(yaml.Lookup("resources", "requests", "memory"))
|
||||||
|
if err != nil {
|
||||||
|
s, _ := r.String()
|
||||||
|
return fmt.Errorf("%v: %s", err, s)
|
||||||
|
}
|
||||||
|
if f == nil {
|
||||||
|
return fmt.Errorf(
|
||||||
|
"memory-requests missing for a container in %s in %s (%s [%s])",
|
||||||
|
meta.Kind, meta.Name,
|
||||||
|
meta.Annotations[kioutil.PathAnnotation],
|
||||||
|
meta.Annotations[kioutil.IndexAnnotation])
|
||||||
|
}
|
||||||
|
|
||||||
|
// container is valid
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
# Copyright 2019 The Kubernetes Authors.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
apiVersion: examples.config.kubernetes.io/v1beta1
|
||||||
|
kind: Validator
|
||||||
|
metadata:
|
||||||
|
configFn:
|
||||||
|
container:
|
||||||
|
image: gcr.io/kustomize-functions/example-validator:v0.1.0
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1 # this should fail validation
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: nginx
|
||||||
|
labels:
|
||||||
|
app: nginx
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: nginx
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: nginx
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: nginx
|
||||||
|
image: nginx
|
||||||
|
# uncomment these to pass validation
|
||||||
|
# resources:
|
||||||
|
# requests:
|
||||||
|
# cpu: 100m
|
||||||
|
# memory: 300MiB
|
||||||
Reference in New Issue
Block a user