Merge branch 'master' into config-map-consistency

This commit is contained in:
Timo Furrer
2021-09-27 09:16:42 +02:00
committed by GitHub
17503 changed files with 1144155 additions and 1881486 deletions

View File

@@ -1,38 +1,78 @@
English | [简体中文](zh/README.md)
# Examples
These examples assume that `kustomize` is on your `$PATH`.
To run these examples, your `$PATH` must contain `kustomize`.
See the [installation instructions](../docs/INSTALL.md).
They are covered by [pre-commit](../bin/pre-commit.sh)
tests, and should work with HEAD
These examples are [tested](../hack/testExamplesAgainstKustomize.sh)
to work with the latest _released_ version of kustomize.
<!-- @installkustomize @test -->
```
go get github.com/kubernetes-sigs/kustomize
```
Basic Usage
* [hello world](helloWorld/README.md) - Deploy multiple
* [valueAdd](valueAdd.md) -
Add a simple string value easily to various fields, including
fields that happen to hold file paths.
* [configGenerations](configGeneration.md) -
Rolling update when ConfigMapGenerator changes.
* [combineConfigs](combineConfigs.md) -
Mixing configuration data from different owners
(e.g. devops/SRE and developers).
* [generatorOptions](generatorOptions.md) -
Modifying behavior of all ConfigMap and Secret generators.
* [vars](wordpress/README.md) - Injecting k8s runtime data into
container arguments (e.g. to point wordpress to a SQL service) by vars.
* [image names and tags](image.md) - Updating image names and tags without applying a patch.
* [remote target](remoteBuild.md) - Building a kustomization from a github URL
* [json patch](jsonpatch.md) - Apply a json patch in a kustomization
* [patch multiple objects](patchMultipleObjects.md) - Apply a patch to multiple objects
Advanced Usage
- generator plugins:
* [last mile helm](chart.md) - Make last mile modifications to
a helm chart.
* [secret generation](secretGeneratorPlugin.md) - Generating secrets from a plugin.
* [remote sources](goGetterGeneratorPlugin.md) - Generating from remote sources.
- transformer plugins:
* [validation transformer](validationTransformer/README.md) -
validate resources through a transformer
- customize builtin transformer configurations
* [transformer configs](transformerconfigs/README.md) - Customize transformer configurations
Multi Variant Examples
* [hello world](helloWorld/README.md) - Deploy multiple
(differently configured) variants of a simple Hello
World server.
* [LDAP](ldap/README.md) - Deploy multiple
(differently configured) variants of a LDAP server.
* [LDAP](ldap/README.md) - Deploy multiple
(differently configured) variants of a LDAP server.
* [mySql](mySql/README.md) - Create a MySQL production
configuration from scratch.
* [springboot](springboot/README.md) - Create a Spring Boot
* [springboot](springboot/README.md) - Create a Spring Boot
application production configuration from scratch.
* [combineConfigs](combineConfigs.md) -
Mixing configuration data from different owners
(e.g. devops/SRE and developers).
* [configGenerations](configGeneration.md) -
Rolling update when ConfigMapGenerator changes
* [mySql](mySql/README.md) - Create a MySQL production
configuration from scratch.
* [breakfast](breakfast.md) - Customize breakfast for
Alice and Bob.
* [container args](wordpress/README.md) - Injecting k8s runtime data into container arguments (e.g. to point wordpress to a SQL service).
* [image tags](imageTags.md) - Updating image tags without applying a patch.
* [breakfast](breakfast.md) - Customize breakfast for
Alice and Bob.
* [multibases](multibases/README.md) - Composing three variants (dev, staging, production) with a common base.
* [components](components.md) - Compose three variants (community, enterprise, dev) with a common base, by reusing configuration between them.

View File

@@ -0,0 +1,152 @@
[kind]: https://github.com/kubernetes-sigs/kind
# Demo: Multiple Deployments
This demo helps you to multiple services on same kubenetes cluster using kustomize.
Steps:
1. Create the resources files for wordpress service.
2. Create the resources files for mysql service.
3. Spin-up kubernetes cluster on local using [kind].
4. Deploy the wordpress app using kustomize and verify the status.
5. Deploy the mysql app using kustomize on same "kind" cluster and verify the status.
6. Add and remove a resource to mysql service and verify prune.
First define a place to work:
<!-- @makeWorkplace @testE2EAgainstLatestRelease -->
```
DEMO_HOME=$(mktemp -d)
```
Alternatively, use
> ```
> DEMO_HOME=~/hello
> ```
## Establish the base
<!-- @createBase @testE2EAgainstLatestRelease -->
```
BASE=$DEMO_HOME/base
mkdir -p $BASE
OUTPUT=$DEMO_HOME/output
mkdir -p $OUTPUT
mkdir $BASE/wordpress
mkdir $BASE/mysql
curl -s -o "$BASE/wordpress/#1.yaml" "https://raw.githubusercontent.com\
/kubernetes-sigs/kustomize\
/master/examples/wordpress/wordpress\
/{deployment,kustomization,service}.yaml"
curl -s -o "$BASE/mysql/#1.yaml" "https://raw.githubusercontent.com\
/kubernetes-sigs/kustomize\
/master/examples/wordpress/mysql\
/{secret,deployment,kustomization,service}.yaml"
```
Create a `grouping.yaml` resource. By this, you are defining the grouping of the current directory, `mysql`. Kustomize uses the unique label in this file to track any future state changes made to this directory. Make sure the label key is `kustomize.config.k8s.io/inventory-id` and give any unique label value and DO NOT change it in future.
<!-- @createGroupingYaml @testE2EAgainstLatestRelease-->
```
cat <<EOF >$BASE/mysql/grouping.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: inventory-map
labels:
kustomize.config.k8s.io/inventory-id: mysql-app
EOF
```
Delete any existing kind cluster and create a new one. By default the name of the cluster is "kind"
<!-- @deleteAndCreateKindCluster @testE2EAgainstLatestRelease -->
```
kind delete cluster
kind create cluster
```
Let's run the wordpress and mysql services.
<!-- @RunWordpressAndMysql @testE2EAgainstLatestRelease -->
```
export KUSTOMIZE_ENABLE_ALPHA_COMMANDS=true
kustomize resources apply $BASE/mysql --status;
status=$(mktemp);
kustomize status fetch $BASE/mysql > $OUTPUT/status
test 1 == \
$(grep "mysql" $OUTPUT/status | grep "Deployment is available. Replicas: 1" | wc -l); \
echo $?
test 1 == \
$(grep "mysql-pass" $OUTPUT/status | grep "Resource is always ready" | wc -l); \
echo $?
test 1 == \
$(grep "mysql" $OUTPUT/status | grep "Service is ready" | wc -l); \
echo $?
kustomize resources apply $BASE/wordpress --status;
status=$(mktemp);
kustomize status fetch $BASE/wordpress > $OUTPUT/status
test 1 == \
$(grep "wordpress" $OUTPUT/status | grep "Deployment is available. Replicas: 1" | wc -l); \
echo $?
test 1 == \
$(grep "wordpress" $OUTPUT/status | grep "Service is ready" | wc -l); \
echo $?
```
Let's replace the secret resource from mysql service and verify prune and addition of resource.
<!-- @ReplaceResourceInMysql @testE2EAgainstLatestRelease -->
```
cat <<EOF >$BASE/mysql/secret2.yaml
apiVersion: v1
kind: Secret
metadata:
name: mysql-pass2
type: Opaque
data:
# Default password is "admin".
password: YWRtaW5=
EOF
rm $BASE/mysql/secret.yaml
sed -i.bak 's/secret/secret2/' \
$BASE/mysql/kustomization.yaml
sed -i.bak 's/mysql-pass/mysql-pass2/' \
$BASE/mysql/deployment.yaml
kustomize resources apply $BASE/mysql --status;
status=$(mktemp);
kustomize status fetch $BASE/mysql > $OUTPUT/status
test 1 == \
$(grep "mysql" $OUTPUT/status | grep "Deployment is available. Replicas: 1" | wc -l); \
echo $?
test 1 == \
$(grep "mysql-pass2" $OUTPUT/status | grep "Resource is always ready" | wc -l); \
echo $?
test 1 == \
$(grep "mysql" $OUTPUT/status | grep "Service is ready" | wc -l); \
echo $?
```
Clean-up the cluster
<!-- @deleteKindCluster @testE2EAgainstLatestRelease -->
```
kind delete cluster
```

View File

@@ -0,0 +1,240 @@
[hello]: https://github.com/monopole/hello
[kind]: https://github.com/kubernetes-sigs/kind
[helloWorld]: https://github.com/kubernetes-sigs/kustomize/tree/master/examples/helloWorld
# Demo: hello app
This demo helps you to deploy an example hello app end-to-end using kustomize.
Steps:
1. Create the resources files.
2. Kustomize them.
3. Spin-up kubernetes cluster on local using [kind].
4. Deploy the app using kustomize and verify the status.
First define a place to work:
<!-- @makeWorkplace @testE2EAgainstLatestRelease-->
```
DEMO_HOME=$(mktemp -d)
```
Alternatively, use
> ```
> DEMO_HOME=~/hello
> ```
## Establish the base
Let's run the [hello] service.
<!-- @createBase @testE2EAgainstLatestRelease-->
```
BASE=$DEMO_HOME/base
mkdir -p $BASE
OUTPUT=$DEMO_HOME/output
mkdir -p $OUTPUT
```
Now lets add a simple config map resource to the `base`
<!-- @createConfigMapYaml @testE2EAgainstLatestRelease-->
```
cat <<EOF >$BASE/configMap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: the-map
data:
altGreeting: "Good Morning!"
enableRisky: "false"
EOF
```
Create `deployment.yaml` with any image and with desired number of replicas
<!-- @createDeploymentYaml @testE2EAgainstLatestRelease-->
```
cat <<EOF >$BASE/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: the-deployment
spec:
replicas: 3
template:
metadata:
labels:
deployment: hello
spec:
containers:
- name: the-container
image: monopole/hello:1
command: ["/hello",
"--port=8080",
"--enableRiskyFeature=\$(ENABLE_RISKY)"]
ports:
- containerPort: 8080
env:
- name: ALT_GREETING
valueFrom:
configMapKeyRef:
name: the-map
key: altGreeting
- name: ENABLE_RISKY
valueFrom:
configMapKeyRef:
name: the-map
key: enableRisky
EOF
```
Create `service.yaml` pointing to the deployment created above
<!-- @createServiceYaml @testE2EAgainstLatestRelease-->
```
cat <<EOF >$BASE/service.yaml
kind: Service
apiVersion: v1
metadata:
name: the-service
spec:
selector:
deployment: hello
type: LoadBalancer
ports:
- protocol: TCP
port: 8666
targetPort: 8080
EOF
```
Create a `grouping.yaml` resource. By this, you are defining the grouping of the current directory, `base`. Kustomize uses the unique label in this file to track any future state changes made to this directory. Make sure the label key is `kustomize.config.k8s.io/inventory-id` and give any unique label value and DO NOT change it in future.
<!-- @createGroupingYaml @testE2EAgainstLatestRelease-->
```
cat <<EOF >$BASE/grouping.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: inventory-map
labels:
kustomize.config.k8s.io/inventory-id: hello-app
EOF
```
Now, create `kustomization.yaml` add all your resources.
<!-- @createKustomizationYaml @testE2EAgainstLatestRelease-->
```
cat <<EOF >$BASE/kustomization.yaml
commonLabels:
app: hello
resources:
- deployment.yaml
- service.yaml
- configMap.yaml
- grouping.yaml
EOF
```
### The Base Kustomization
The `base` directory has a kustomization file:
<!-- @showKustomization @testE2EAgainstLatestRelease -->
```
more $BASE/kustomization.yaml
```
### Customize the base
A simple customization step could be to change the _app
label_ applied to all resources:
<!-- @addLabel @testE2EAgainstLatestRelease -->
```
sed -i.bak 's/app: hello/app: my-hello/' \
$BASE/kustomization.yaml
```
The following requires installation of [kind].
Delete any existing kind cluster and create a new one. By default the name of the cluster is "kind"
<!-- @deleteAndCreateKindCluster @testE2EAgainstLatestRelease -->
```
kind delete cluster
kind create cluster
```
Use the kustomize binary in MYGOBIN to apply a deployment, fetch the status and verify the status.
<!-- @runHelloApp @testE2EAgainstLatestRelease -->
```
export KUSTOMIZE_ENABLE_ALPHA_COMMANDS=true
kustomize resources apply $BASE --status;
kustomize status fetch $BASE > $OUTPUT/status
test 1 == \
$(grep "the-deployment" $OUTPUT/status | grep "Deployment is available. Replicas: 3" | wc -l); \
echo $?
test 1 == \
$(grep "the-map" $OUTPUT/status | grep "Resource is always ready" | wc -l); \
echo $?
test 1 == \
$(grep "the-service" $OUTPUT/status | grep "Service is ready" | wc -l); \
echo $?
```
Now let's replace the configMap with configMap2 apply the config, fetch and verify the status. This should delete the-map from deployment and add the-map2.
<!-- @replaceConfigMapInHello @testE2EAgainstLatestRelease -->
```
cat <<EOF >$BASE/configMap2.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: the-map2
data:
altGreeting: "Good Evening!"
enableRisky: "false"
EOF
rm $BASE/configMap.yaml
sed -i.bak 's/configMap/configMap2/' \
$BASE/kustomization.yaml
sed -i.bak 's/the-map/the-map2/' \
$BASE/deployment.yaml
kustomize resources apply $BASE --status;
status=$(mktemp);
kustomize status fetch $BASE > $OUTPUT/status
test 1 == \
$(grep "the-deployment" $OUTPUT/status | grep "Deployment is available. Replicas: 3" | wc -l); \
echo $?
test 1 == \
$(grep "the-map2" $OUTPUT/status | grep "Resource is always ready" | wc -l); \
echo $?
test 1 == \
$(grep "the-service" $OUTPUT/status | grep "Service is ready" | wc -l); \
echo $?
```
Clean-up the cluster
<!-- @deleteKindCluster @testE2EAgainstLatestRelease -->
```
kind delete cluster
```
### Next Exercise
Create overlays as described in the [helloWorld] section and verify the results.

View File

@@ -6,14 +6,14 @@
Define a place to work:
<!-- @makeWorkplace @test -->
<!-- @makeWorkplace @testAgainstLatestRelease -->
```
DEMO_HOME=$(mktemp -d)
```
Make a place to put the base breakfast configuration:
<!-- @baseDir @test -->
<!-- @baseDir @testAgainstLatestRelease -->
```
mkdir -p $DEMO_HOME/breakfast/base
```
@@ -21,7 +21,7 @@ mkdir -p $DEMO_HOME/breakfast/base
Make a `kustomization` to define what goes into
breakfast. This breakfast has coffee and pancakes:
<!-- @baseKustomization @test -->
<!-- @baseKustomization @testAgainstLatestRelease -->
```
cat <<EOF >$DEMO_HOME/breakfast/base/kustomization.yaml
resources:
@@ -34,7 +34,7 @@ Here's a _coffee_ type. Give it a `kind` and `metdata/name` field
to conform to [kubernetes API object style]; no other
file or definition is needed:
<!-- @coffee @test -->
<!-- @coffee @testAgainstLatestRelease -->
```
cat <<EOF >$DEMO_HOME/breakfast/base/coffee.yaml
kind: Coffee
@@ -50,7 +50,7 @@ The `name` field merely distinguishes this instance of
coffee from others (if there were any).
Likewise, define _pancakes_:
<!-- @pancakes @test -->
<!-- @pancakes @testAgainstLatestRelease -->
```
cat <<EOF >$DEMO_HOME/breakfast/base/pancakes.yaml
kind: Pancakes
@@ -64,16 +64,16 @@ EOF
Make a custom [variant] of breakfast for Alice, who
likes her coffee hot:
<!-- @aliceOverlay @test -->
<!-- @aliceOverlay @testAgainstLatestRelease -->
```
mkdir -p $DEMO_HOME/breakfast/overlays/alice
cat <<EOF >$DEMO_HOME/breakfast/overlays/alice/kustomization.yaml
commonLabels:
who: alice
bases:
resources:
- ../../base
patches:
patchesStrategicMerge:
- temperature.yaml
EOF
@@ -87,16 +87,16 @@ EOF
And likewise a [variant] for Bob, who wants _five_ pancakes, with strawberries:
<!-- @bobOverlay @test -->
<!-- @bobOverlay @testAgainstLatestRelease -->
```
mkdir -p $DEMO_HOME/breakfast/overlays/bob
cat <<EOF >$DEMO_HOME/breakfast/overlays/bob/kustomization.yaml
commonLabels:
who: bob
bases:
resources:
- ../../base
patches:
patchesStrategicMerge:
- topping.yaml
EOF
@@ -111,14 +111,14 @@ EOF
One can now generate the configs for Alices breakfast:
<!-- @generateAlice @test -->
<!-- @generateAlice @testAgainstLatestRelease -->
```
kustomize build $DEMO_HOME/breakfast/overlays/alice
```
Likewise for Bob:
<!-- @generateBob @test -->
<!-- @generateBob @testAgainstLatestRelease -->
```
kustomize build $DEMO_HOME/breakfast/overlays/bob
```

370
examples/chart.md Normal file
View File

@@ -0,0 +1,370 @@
# kustomization of a helm chart
[`helm`]: https://helm.sh
[last mile]: https://testingclouds.wordpress.com/2018/07/20/844/
[artifact hub]: https://artifacthub.io
[_minecraft_]: https://artifacthub.io/packages/helm/minecraft-server-charts/minecraft
[plugin]: ../docs/plugins
[built]: https://kubectl.docs.kubernetes.io/references/kustomize/kustomization
Kustomize is [built] from _generators_ and
_transformers_; the former make kubernetes YAML, the
latter transform said YAML.
Kustomize, via the `helmCharts` field, has the ability to
use the [`helm`] command line program in a subprocess to
inflate a helm chart, generating YAML as part of (or as the
entirety of) a kustomize base.
This YAML can then be modified either in the base directly
(transformers always run _after_ generators), or via
a kustomize overlay.
Either approach can be viewed as [last mile] modification
of the chart output before applying it to a cluster.
The example below arbitrarily uses the
[_minecraft_] chart pulled from the [artifact hub]
chart repository.
## Preparation
This example defines the `helm` command as
<!-- @defineHelmCommand @testHelm -->
```
helmCommand=${MYGOBIN:-~/go/bin}/helmV3
```
This value is needed for testing this example in CI/CD.
A user doesn't need this if their binary is called
`helm` and is on their shell's `PATH`.
Make a place to work:
<!-- @makeWorkplace @testHelm -->
```
DEMO_HOME=$(mktemp -d)
mkdir -p $DEMO_HOME/base $DEMO_HOME/dev $DEMO_HOME/prod
```
## Define some variants
Define a kustomization representing your _development_
variant.
This could involve any number of kustomizations (see
other examples), but in this case just add the name
prefix '`dev-`' to all resources:
<!-- @writeKustDev @testHelm -->
```
cat <<'EOF' >$DEMO_HOME/dev/kustomization.yaml
namePrefix: dev-
resources:
- ../base
EOF
```
Likewise define a _production_ variant, with a name
prefix '`prod-`':
<!-- @writeKustProd @testHelm -->
```
cat <<'EOF' >$DEMO_HOME/prod/kustomization.yaml
namePrefix: prod-
resources:
- ../base
EOF
```
These two variants refer to a common base.
Define this base the usual way by creating a
`kustomization` file:
<!-- @writeKustBase @testHelm -->
```
cat <<'EOF' >$DEMO_HOME/base/kustomization.yaml
helmCharts:
- name: minecraft
includeCRDs: false
valuesInline:
minecraftServer:
eula: true
difficulty: hard
rcon:
enabled: true
releaseName: moria
version: 3.1.3
repo: https://itzg.github.io/minecraft-server-charts
EOF
```
The only thing in this particular file is a `helmCharts`
field, specifying a single chart.
The `valuesInline` field overrides some native chart values.
The `includeCRDs` field instructs Helm to generate
`CustomResourceDefinitions`.
See [the Helm documentation](https://helm.sh/docs/chart_best_practices/custom_resource_definitions/) for details.
Check the directory layout:
<!-- @tree -->
```
tree $DEMO_HOME
```
Expect something like:
> ```
> /tmp/whatever
> ├── base
> │ └── kustomization.yaml
> ├── dev
> │ └── kustomization.yaml
> └── prod
> └── kustomization.yaml
> ```
### Helm related flags
Attempt to build the `base`:
<!-- @checkFailure @testHelm -->
```
cmd="kustomize build --helm-command $helmCommand $DEMO_HOME/base"
if ($cmd); then
echo "Build should fail!" && false # Force test to fail.
else
echo "Build failed because no --enable-helm flag (desired outcome)."
fi
```
This `build` fails and complains about a missing
`--enable-helm` flag.
The flag `--enable-helm` exists to have the user
acknowledge that kustomize is running an external program as
part of the `build` step. It's like the
`--enable-plugins` flag, but with a helm focus.
The flag `--helm-command` has a default value (`helm` of
course) so it's not suitable as an enablement flag. A user
with `helm` on their `PATH` need not awkwardly specify
`'--helm-command helm'`.
Given the above, define a helper function to run `kustomize` with the
flags required for `helm` use in this demo:
<!-- @defineKustomizeIt @testHelm -->
```
function kustomizeIt {
kustomize build \
--enable-helm \
--helm-command $helmCommand \
$DEMO_HOME/$1
}
```
### Build the base and the variants
Now build the `base`:
<!-- @showBase @testHelm -->
```
kustomizeIt base
```
This works, and you see an inflated chart complete
with a `Secret`, `Service`, `Deployment`, etc.
As a side effect of this build, kustomize pulled the chart
and placed it in the `charts` subdirectory of the base.
Take a look:
<!-- @tree -->
```
tree $DEMO_HOME
```
If the chart had already been there, kustomize would
not have tried to pull it.
To change the location of the charts, use this
in your kustomization file:
> ```
> helmGlobals:
> chartHome: charts
> ```
Change `charts` as desired, but it's best to keep it
in (or below) the same directory as the `kustomization.yaml` file.
If it's outside the kustomization root, the `build` command will
fail unless given the flag `'--load-restrictor=none'` to
disable file loading restrictions.
Now build the two variants `dev` and `prod`
and compare their differences:
<!-- @doCompare -->
```
diff <(kustomizeIt dev) <(kustomizeIt prod) | more
```
This shows so-called _last mile hydration_ of two variants
made from a common base that happens to be generated from a
helm chart.
## How does the pull work?
The command kustomize used to download the chart
is something like
> ```
> $helmCommand pull \
> --untar \
> --untardir $DEMO_HOME/base/charts \
> --repo https://itzg.github.io/minecraft-server-charts \
> --version 3.1.3 \
> minecraft
> ```
The first use of kustomize above (when the `base` was
expanded) fetched the chart and placed it in the `charts`
directory next to the `kustomization.yaml` file.
This chart was reused, _not_ re-fetched, with the variant
expansions `prod` and `dev`.
If a chart exists, kustomize will not overwrite it (so to
suppress a pull, simply assure the chart is already in your
kustomization root). kustomize won't check dates or version
numbers or do anything that smells like cache management.
> kustomize is a YAML manipulator. It's not a manager
> of a cache of things downloaded from the internet.
## The pull happens once.
To show that the locally stored chart is being re-used, modify
its _values_ file.
First make note of the password encoded in the production
inflation:
<!-- @checkPassword @testHelm -->
```
test 1 == $(kustomizeIt prod | grep -c "rcon-password: Q0hBTkdFTUUh")
```
The above command succeeds if the value of the generated
password is as shown (`Q0hBTkdFTUUh`).
Now change the password in the local values file:
<!-- @valueChange @testHelm -->
```
values=$DEMO_HOME/base/charts/minecraft/values.yaml
grep CHANGEME $values
sed -i 's/CHANGEME/SOMETHING_ELSE/' $values
grep SOMETHING_ELSE $values
```
Run the build, and confirm that the same `rcon-password`
field in the output has a new value, confirming that the
chart used was a _local_ chart, not a chart freshly
downloaded from the internet:
<!-- @checkPassword2 @testHelm -->
```
test 1 == $(kustomizeIt prod | grep -c "rcon-password: U09NRVRISU5HX0VMU0Uh")
```
Finally, clean up:
<!-- @showBase @testHelm -->
```
rm -r $DEMO_HOME
```
## Performance
To recap, the helm-related kustomization fields make
kustomize run
> ```
> helm pull ...
> helm template ...
> ```
_as a convenience for the user_ to generate YAML from a helm chart.
Helm's `pull` command downloads the chart. Helm's `template`
command inflates the chart template, spitting the inflated
template to stdout (where kustomize captures it) rather than
immediately sending it to a cluster as `helm install`
would.
To improve performance, a user can retain the chart after
the first pull, and commit the chart to their configuration
repository (below the `kustomization.yaml` file that refers
to it). kustomize only tries to pull the chart if it's not
already there.
To further improve performance, a user can inflate the
chart themselves at the command line, e.g.
> ```
> helm template {releaseName} \
> --values {valuesFile} \
> --version {version} \
> --repo {repo} \
> {chartName} > {chartName}.yaml
> ```
then commit the resulting `{chartName}.yaml` file to a git
repo as a configuration base, mentioning that file as a
`resource` in a `kustomization.yaml` file, e.g.
> ```
> resources:
> - minecraft_v3.1.3_Chart.yaml
> ```
The user should choose when or if to refresh their local
copy of the chart's inflation. kustomize would have no
awareness that the YAML was generated by helm, and kustomize
wouldn't run `helm` during the `build`. This is analogous
to `Go` module vendoring.
### But it's not really about performance.
Although the `helm` related fields discussed above are handy
for experimentation and development, it's best to avoid them
in production.
The same argument applies to using _remote_ git URL's in
other kustomization fields. Handy for experimentation,
but ill-advised in production.
It's irresponsible to depend on a remote configuration
that's _not under your control_. Annoying enablement flags
like `'--enable-helm'` are intended to _remind_ one of a
risk, but offer zero protection from risk. Further, they
are useless are reminders, since __annoying things are
immediately scripted away and forgotten__, as was done above
in the `kustomizeIt` shell function.
## Best practice
Don't use remote configuration that you don't control in
production.
Maintain a _local, inflated fork_ of a remote configuration,
and have a human rebase / reinflate that fork from time to
time to capture upstream changes.

View File

@@ -92,9 +92,9 @@ secret holding them (not covering that here).
<!--
secretGenerator:
- name: app-tls
commands:
tls.crt: "cat tls.cert"
tls.key: "cat tls.key"
files:
tls.crt=tls.cert
tls.key=tls.key
type: "kubernetes.io/tls"
EOF
-->
@@ -128,7 +128,7 @@ defined in the [helloworld] demo.
It will all live in this work directory:
<!-- @makeWorkplace @test -->
<!-- @makeWorkplace @testAgainstLatestRelease -->
```
DEMO_HOME=$(mktemp -d)
```
@@ -139,7 +139,7 @@ DEMO_HOME=$(mktemp -d)
Make a place to put the base configuration:
<!-- @baseDir @test -->
<!-- @baseDir @testAgainstLatestRelease -->
```
mkdir -p $DEMO_HOME/base
```
@@ -150,7 +150,7 @@ environments. Here we're only defining a java
properties file, and a `kustomization` file that
references it.
<!-- @baseKustomization @test -->
<!-- @baseKustomization @testAgainstLatestRelease -->
```
cat <<EOF >$DEMO_HOME/base/common.properties
color=blue
@@ -171,14 +171,14 @@ EOF
Make an abbreviation for the parent of the overlay
directories:
<!-- @overlays @test -->
<!-- @overlays @testAgainstLatestRelease -->
```
OVERLAYS=$DEMO_HOME/overlays
```
Create the files that define the _development_ overlay:
<!-- @developmentFiles @test -->
<!-- @developmentFiles @testAgainstLatestRelease -->
```
mkdir -p $OVERLAYS/development
@@ -191,9 +191,10 @@ dbpassword=mothersMaidenName
EOF
cat <<EOF >$OVERLAYS/development/kustomization.yaml
bases:
resources:
- ../../base
namePrefix: dev-
nameSuffix: -v1
configMapGenerator:
- name: my-configmap
behavior: merge
@@ -205,7 +206,7 @@ EOF
One can now generate the configMaps for development:
<!-- @runDev @test -->
<!-- @runDev @testAgainstLatestRelease -->
```
kustomize build $OVERLAYS/development
```
@@ -215,11 +216,12 @@ kustomize build $OVERLAYS/development
The name of the generated `ConfigMap` is visible in this
output.
The name should be something like `dev-my-configmap-b5m75ck895`:
The name should be something like `dev-my-configmap-v1-2gccmccgd5`:
* `"dev-"` comes from the `namePrefix` field,
* `"my-configmap"` comes from the `configMapGenerator/name` field,
* `"-b5m75ck895"` comes from a deterministic hash that `kustomize`
* `"-v1"` comes from the `nameSuffix` field,
* `"-2gccmccgd5"` comes from a deterministic hash that `kustomize`
computes from the contents of the configMap.
The hash suffix is critical. If the configMap content
@@ -249,8 +251,15 @@ specification of the cluster's desired state to
point deployments to _new_ configMaps with _new_ names.
`kustomize` makes this easy with its
`configMapGenerator` directive and associated naming
controls. A GC process in the k8s master eventually
deletes unused configMaps.
controls.
To remove outdated configMaps add a label
to your resource, for example, kustomize-cleanup="true",
and then you can use `kustomize` to prune old resources^
> ```
> kustomize build | kubectl apply --prune -f- -l kustomize-cleanup="true"
> ```
### Create and use the overlay for _production_
@@ -258,7 +267,7 @@ deletes unused configMaps.
Next, create the files for the _production_ overlay:
<!-- @productionFiles @test -->
<!-- @productionFiles @testAgainstLatestRelease -->
```
mkdir -p $OVERLAYS/production
@@ -271,7 +280,7 @@ dbpassword=thisShouldProbablyBeInASecretInstead
EOF
cat <<EOF >$OVERLAYS/production/kustomization.yaml
bases:
resources:
- ../../base
namePrefix: prod-
configMapGenerator:
@@ -285,13 +294,13 @@ EOF
One can now generate the configMaps for production:
<!-- @runProd @test -->
<!-- @runProd @testAgainstLatestRelease -->
```
kustomize build $OVERLAYS/production
```
A CICD process could apply this directly to
the cluser using:
the cluster using:
> ```
> kustomize build $OVERLAYS/production | kubectl apply -f -

794
examples/components.md Normal file
View File

@@ -0,0 +1,794 @@
# Demo: Components
For more details regarding this feature you can read the
[Kustomize Components KEP](https://github.com/kubernetes/enhancements/blob/master/keps/sig-cli/1802-kustomize-components/README.md).
_This example requires Kustomize ``v3.7.0`` or newer_
Suppose you've written a very simple Web application:
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: example
spec:
template:
spec:
containers:
- name: example
image: example:1.0
```
You want to deploy a **community** edition of this application as SaaS, so you
add support for persistence (e.g. an external database), and bot detection
(e.g. Google reCAPTCHA).
You've now attracted **enterprise** customers who want to deploy it
on-premises, so you add LDAP support, and disable Google reCAPTCHA. At the same
time, the **devs** need to be able to test parts of the application, so they
want to deploy it with some features enabled and others not.
Here's a matrix with the deployments of this application and the features
enabled for each one:
| | External DB | LDAP | reCAPTCHA |
|------------|:------------------:|:------------------:|:------------------:|
| Community | :heavy_check_mark: | | :heavy_check_mark: |
| Enterprise | :heavy_check_mark: | :heavy_check_mark: | |
| Dev | :white_check_mark: | :white_check_mark: | :white_check_mark: |
So, you want to make it easy to deploy your application in any of the above
three environments. This seems like a work for [variants], so you try to create
three overlays; a `community/`, an `enterprise/` and a `dev/` overlay, that each
provides the appropriate features for their audience, i.e., public, customers and
developers, respectfully.
## Variants example
Here's the common and most simplistic approach to solve this problem. As we will
soon see, this approach does not scale well in more complex scenarios. However,
it will help you get a better grasp of the problem we are about to tackle and
demonstrate where there is room for improvement.
First, define a place to work:
```shell
DEMO_HOME=$(mktemp -d)
```
Define a common **base** that has a `Deployment` and a simple `ConfigMap`, that
is mounted on the application's container.
```shell
BASE=$DEMO_HOME/base
mkdir $BASE
cat <<EOF >$BASE/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
configMapGenerator:
- name: conf
literals:
- main.conf=|
color=cornflower_blue
log_level=info
EOF
cat <<EOF >$BASE/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: example
spec:
template:
spec:
containers:
- name: example
image: example:1.0
volumeMounts:
- name: conf
mountPath: /etc/config
volumes:
- name: conf
configMap:
name: conf
EOF
```
Define a **community** overlay that:
- generates `Secrets` for external DB's password and reCAPTCHA's keys
- patches the `ConfigMap` of the common base with configurations for external DB
and reCAPTCHA
- patches the `Deployment` of the common base to mount the generated `Secrets`
for external DB and reCAPTCHA
```shell
COMMUNITY=$DEMO_HOME/overlays/community
mkdir -p $COMMUNITY
cat <<EOF >$COMMUNITY/kustomization.yaml
kind: Kustomization
resources:
- ../../base
secretGenerator:
- name: dbpass
files:
- dbpass.txt
- name: recaptcha
files:
- site_key.txt
- secret_key.txt
patchesStrategicMerge:
- configmap.yaml
patchesJson6902:
- target:
group: apps
version: v1
kind: Deployment
name: example
path: deployment.yaml
EOF
cat <<EOF >$COMMUNITY/deployment.yaml
- op: add
path: /spec/template/spec/volumes/0
value:
name: dbpass
secret:
secretName: dbpass
- op: add
path: /spec/template/spec/containers/0/volumeMounts/0
value:
mountPath: /var/run/secrets/db/
name: dbpass
- op: add
path: /spec/template/spec/volumes/0
value:
name: recaptcha
secret:
secretName: recaptcha
- op: add
path: /spec/template/spec/containers/0/volumeMounts/0
value:
mountPath: /var/run/secrets/recaptcha/
name: recaptcha
EOF
cat <<EOF >$COMMUNITY/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: conf
data:
db.conf: |
endpoint=127.0.0.1:1234
name=app
user=admin
pass=/var/run/secrets/db/dbpass.txt
recaptcha.conf: |
enabled=true
site_key=/var/run/secrets/recaptcha/site_key.txt
secret_key=/var/run/secrets/recaptcha/secret_key.txt
EOF
```
Create local input files for external DB's password and reCAPTCHA's keys:
```shell
cat <<EOF >$COMMUNITY/dbpass.txt
dbpass
EOF
cat <<EOF >$COMMUNITY/site_key.txt
sitekey
EOF
cat <<EOF >$COMMUNITY/secret_key.txt
secretkey
EOF
```
Define a **enterprise** overlay that:
- generates `Secrets` for LDAP's password and external DB's password
- patches the `ConfigMap` of the common base with configurations for LDAP and
external DB
- patches the `Deployment` of the common base to mount the generated `Secrets`
for LDAP and external DB
```shell
ENTERPRISE=$DEMO_HOME/overlays/enterprise
mkdir -p $ENTERPRISE
cat <<EOF >$ENTERPRISE/kustomization.yaml
kind: Kustomization
resources:
- ../../base
secretGenerator:
- name: ldappass
files:
- ldappass.txt
- name: dbpass
files:
- dbpass.txt
patchesStrategicMerge:
- configmap.yaml
patchesJson6902:
- target:
group: apps
version: v1
kind: Deployment
name: example
path: deployment.yaml
EOF
cat <<EOF >$ENTERPRISE/deployment.yaml
- op: add
path: /spec/template/spec/volumes/0
value:
name: dbpass
secret:
secretName: dbpass
- op: add
path: /spec/template/spec/containers/0/volumeMounts/0
value:
mountPath: /var/run/secrets/db/
name: dbpass
- op: add
path: /spec/template/spec/volumes/0
value:
name: ldappass
secret:
secretName: ldappass
- op: add
path: /spec/template/spec/containers/0/volumeMounts/0
value:
mountPath: /var/run/secrets/ldap/
name: ldappass
EOF
cat <<EOF >$ENTERPRISE/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: conf
data:
db.conf: |
endpoint=127.0.0.1:1234
name=app
user=admin
pass=/var/run/secrets/db/dbpass.txt
ldap.conf: |
endpoint=ldap://ldap.example.com
bindDN=cn=admin,dc=example,dc=com
pass=/var/run/secrets/ldap/ldappass.txt
EOF
```
Create local input files for LDAP's password and external DB's password:
```shell
cat <<EOF >$ENTERPRISE/ldappass.txt
ldappass
EOF
cat <<EOF >$ENTERPRISE/dbpass.txt
dbpass
EOF
```
Define a **dev** overlay that supports all three features(ExternalDB, LDAP,
reCAPTCHA) and conditionally enables some or all of them. In this example, we
define a dev overlay that supports all the features, but has disabled the LDAP
support, by doing the following::
- generates `Secrets` for external DB's password and reCAPTCHA's keys
- patches the `ConfigMap` of the common base with configurations for external DB
and reCAPTCHA
- patches the `Deployment` of the common base to mount the generated `Secrets`
for external DB and reCAPTCHA
```shell
DEV=$DEMO_HOME/overlays/dev
mkdir -p $DEV
cat <<EOF >$DEV/kustomization.yaml
kind: Kustomization
resources:
- ../../base
secretGenerator:
# - name: ldappass <-- Commenting to disable LDAP support
# files:
# - ldappass.txt
- name: dbpass
files:
- dbpass.txt
- name: recaptcha
files:
- site_key.txt
- secret_key.txt
patchesStrategicMerge:
- configmap.yaml
patchesJson6902:
- target:
group: apps
version: v1
kind: Deployment
name: example
path: deployment.yaml
EOF
cat <<EOF >$DEV/deployment.yaml
- op: add
path: /spec/template/spec/volumes/0
value:
name: dbpass
secret:
secretName: dbpass
- op: add
path: /spec/template/spec/containers/0/volumeMounts/0
value:
mountPath: /var/run/secrets/db/
name: dbpass
# - op: add <-- Commenting to disable LDAP support
# path: /spec/template/spec/volumes/0
# value:
# name: ldappass
# secret:
# secretName: ldappass
# - op: add
# path: /spec/template/spec/containers/0/volumeMounts/0
# value:
# mountPath: /var/run/secrets/ldap/
# name: ldappass
- op: add
path: /spec/template/spec/volumes/0
value:
name: recaptcha
secret:
secretName: recaptcha
- op: add
path: /spec/template/spec/containers/0/volumeMounts/0
value:
mountPath: /var/run/secrets/recaptcha/
name: recaptcha
EOF
cat <<EOF >$DEV/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: conf
data:
db.conf: |
endpoint=127.0.0.1:1234
name=app
user=admin
pass=/var/run/secrets/db/dbpass.txt
# ldap.conf: | <-- Commenting to disable LDAP support
# endpoint=ldap://ldap.example.com
# bindDN=cn=admin,dc=example,dc=com
# pass=/var/run/secrets/ldap/ldappass.txt
recaptcha.conf: |
enabled=true
site_key=/var/run/secrets/recaptcha/site_key.txt
secret_key=/var/run/secrets/recaptcha/secret_key.txt
EOF
```
Create local input files for external DB's password and reCAPTCHA's keys:
```shell
cat <<EOF >$DEV/dbpass.txt
dbpass
EOF
cat <<EOF >$DEV/site_key.txt
sitekey
EOF
cat <<EOF >$DEV/secret_key.txt
secretkey
EOF
```
The above commands result in the following structure:
```shell
├── base
│ ├── deployment.yaml
│ └── kustomization.yaml
└── overlays
├── community
│ ├── configmap.yaml
│ ├── dbpass.txt
│ ├── deployment.yaml
│ ├── kustomization.yaml
│ ├── secret_key.txt
│ └── site_key.txt
├── dev
│ ├── configmap.yaml <-- Refers to multiple features and might contain comments
│ ├── dbpass.txt
│ ├── deployment.yaml <-- Refers to multiple features and might contain comments
│ ├── kustomization.yaml <-- Refers to multiple features and might contain comments
│ ├── secret_key.txt
│ └── site_key.txt
└── enterprise
├── configmap.yaml
├── dbpass.txt
├── deployment.yaml
├── kustomization.yaml
└── ldappass.txt
```
The main issues observed with this solution are:
1. Since some features are repeated in the `community/`, `enterprise/` and
`dev/` overlays, one needs to manually define patches with content that is
partially identical to patches of different overlays, that also enable this
feature.
2. The `dev/` overlay is dynamic, i.e., supports multiple optional features. To
enable/disable any single feature one needs to uncomment/comment many lines
of YAML which is cumbersome and hard to maintain. Alternatively, one needs
to maintain a multitude of overlays and track all possible combinations of
features.
3. Overlays that combine more than one features define patches for resources
whose content is not dedicated to a single feature. That is, there is no
semantic isolation per feature, everything gets mixed into a single,
multi-feature, resource-specific patch.
The variants approach may solve this simple example but it won't scale in the
long run, as the number of features and deployments grow. What if you have `N`
opt-in features and `M` real-world deployment scenarios that ship with `0-N` of
these features?
Ideally, you want to move each feature under a separate, reusable overlay and
enable them on-demand per deployment, i.e., in kustomization files of top-level
overlays. Enter components.
## Components example
Here's an alternative and more [DRY] approach that solves this issue by using a
Kustomize feature called "components". Each opt-in feature gets packaged as a
component, so that it can be referred to from higher-level overlays.
First, define a place to work:
```shell
DEMO_HOME=$(mktemp -d)
```
Define a common **base** that has a `Deployment` and a simple `ConfigMap`, that
is mounted on the application's container.
```shell
BASE=$DEMO_HOME/base
mkdir $BASE
cat <<EOF >$BASE/kustomization.yaml
resources:
- deployment.yaml
configMapGenerator:
- name: conf
literals:
- main.conf=|
color=cornflower_blue
log_level=info
EOF
cat <<EOF >$BASE/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: example
spec:
template:
spec:
containers:
- name: example
image: example:1.0
volumeMounts:
- name: conf
mountPath: /etc/config
volumes:
- name: conf
configMap:
name: conf
EOF
```
Define an `external_db` component, using `kind: Component`, that creates a
`Secret` for the DB password and a new entry in the `ConfigMap`:
```shell
EXT_DB=$DEMO_HOME/components/external_db
mkdir -p $EXT_DB
cat <<EOF >$EXT_DB/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1alpha1 # <-- Component notation
kind: Component
secretGenerator:
- name: dbpass
files:
- dbpass.txt
patchesStrategicMerge:
- configmap.yaml
patchesJson6902:
- target:
group: apps
version: v1
kind: Deployment
name: example
path: deployment.yaml
EOF
cat <<EOF >$EXT_DB/deployment.yaml
- op: add
path: /spec/template/spec/volumes/0
value:
name: dbpass
secret:
secretName: dbpass
- op: add
path: /spec/template/spec/containers/0/volumeMounts/0
value:
mountPath: /var/run/secrets/db/
name: dbpass
EOF
cat <<EOF >$EXT_DB/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: conf
data:
db.conf: |
endpoint=127.0.0.1:1234
name=app
user=admin
pass=/var/run/secrets/db/dbpass.txt
EOF
```
Define an `ldap` component, that creates a `Secret` for the LDAP password
and a new entry in the `ConfigMap`:
```shell
LDAP=$DEMO_HOME/components/ldap
mkdir -p $LDAP
cat <<EOF >$LDAP/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1alpha1
kind: Component
secretGenerator:
- name: ldappass
files:
- ldappass.txt
patchesStrategicMerge:
- configmap.yaml
patchesJson6902:
- target:
group: apps
version: v1
kind: Deployment
name: example
path: deployment.yaml
EOF
cat <<EOF >$LDAP/deployment.yaml
- op: add
path: /spec/template/spec/volumes/0
value:
name: ldappass
secret:
secretName: ldappass
- op: add
path: /spec/template/spec/containers/0/volumeMounts/0
value:
mountPath: /var/run/secrets/ldap/
name: ldappass
EOF
cat <<EOF >$LDAP/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: conf
data:
ldap.conf: |
endpoint=ldap://ldap.example.com
bindDN=cn=admin,dc=example,dc=com
pass=/var/run/secrets/ldap/ldappass.txt
EOF
```
Define a `recaptcha` component, that creates a `Secret` for the reCAPTCHA
site/secret keys and a new entry in the `ConfigMap`:
```shell
RECAPTCHA=$DEMO_HOME/components/recaptcha
mkdir -p $RECAPTCHA
cat <<EOF >$RECAPTCHA/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1alpha1
kind: Component
secretGenerator:
- name: recaptcha
files:
- site_key.txt
- secret_key.txt
# Updating the ConfigMap works with generators as well.
configMapGenerator:
- name: conf
behavior: merge
literals:
- recaptcha.conf=|
enabled=true
site_key=/var/run/secrets/recaptcha/site_key.txt
secret_key=/var/run/secrets/recaptcha/secret_key.txt
patchesJson6902:
- target:
group: apps
version: v1
kind: Deployment
name: example
path: deployment.yaml
EOF
cat <<EOF >$RECAPTCHA/deployment.yaml
- op: add
path: /spec/template/spec/volumes/0
value:
name: recaptcha
secret:
secretName: recaptcha
- op: add
path: /spec/template/spec/containers/0/volumeMounts/0
value:
mountPath: /var/run/secrets/recaptcha/
name: recaptcha
EOF
```
Define a `community` variant, that bundles the external DB and reCAPTCHA
components:
```shell
COMMUNITY=$DEMO_HOME/overlays/community
mkdir -p $COMMUNITY
cat <<EOF >$COMMUNITY/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
components:
- ../../components/external_db
- ../../components/recaptcha
EOF
```
Define an `enterprise` overlay, that bundles the external DB and LDAP
components:
```shell
ENTERPRISE=$DEMO_HOME/overlays/enterprise
mkdir -p $ENTERPRISE
cat <<EOF >$ENTERPRISE/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
components:
- ../../components/external_db
- ../../components/ldap
EOF
```
Define a `dev` overlay, that points to all the components and has LDAP
disabled:
```shell
DEV=$DEMO_HOME/overlays/dev
mkdir -p $DEV
cat <<EOF >$DEV/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
components:
- ../../components/external_db
#- ../../components/ldap
- ../../components/recaptcha
EOF
```
Now the workspace has following directories:
```shell
├── base
│ ├── deployment.yaml
│ └── kustomization.yaml
├── components
│ ├── external_db
│ │ ├── configmap.yaml
│ │ ├── dbpass.txt
│ │ ├── deployment.yaml
│ │ └── kustomization.yaml
│ ├── ldap
│ │ ├── configmap.yaml
│ │ ├── deployment.yaml
│ │ ├── kustomization.yaml
│ │ └── ldappass.txt
│ └── recaptcha
│ ├── deployment.yaml
│ ├── kustomization.yaml
│ ├── secret_key.txt
│ └── site_key.txt
└── overlays
├── community
│ └── kustomization.yaml
├── dev
│ └── kustomization.yaml
└── enterprise
└── kustomization.yaml
```
With this structure, you can create the YAML files for each deployment as
follows:
```shell
kustomize build overlays/community
kustomize build overlays/enterprise
kustomize build overlays/dev
```
## Takeaway
At the end of the day, Kustomize components provide a more flexible way to
enable/disable features and configurations for applications directly from the
kustomization file. This results in more readable, concise and intuitive
overlays.
[variants]: multibases/README.md
[DRY principle]: https://en.wikipedia.org/wiki/Don%27t_repeat_yourself

View File

@@ -1,22 +1,24 @@
[patch]: ../../docs/glossary.md#patch
[resource]: ../../docs/glossary.md#resource
[variant]: ../../docs/glossary.md#variant
[patch]: ../docs/glossary.md#patch
[resource]: ../docs/glossary.md#resource
[variant]: ../docs/glossary.md#variant
## ConfigMap generation and rolling updates
Kustomize provides two ways of adding ConfigMap in one `kustomization`, either by declaring ConfigMap as a [resource] or declaring ConfigMap from a ConfigMapGenerator. The formats inside `kustomization.yaml` are
Kustomize provides two ways of adding ConfigMap in one `kustomization`, either by declaring ConfigMap as a [resource] or declaring ConfigMap from a ConfigMapGenerator. The formats inside `kustomization.yaml` are
> ```
> # declare ConfigMap as a resource
> resources:
> - configmap.yaml
>
>
> # declare ConfigMap from a ConfigMapGenerator
> configMapGenerator:
> - name: a-configmap
> files:
> # configfile is used as key
> - configs/configfile
> - configs/another_configfile
> # configkey is used as key
> - configkey=configs/another_configfile
> ```
The ConfigMaps declared as [resource] are treated the same way as other resources. Kustomize doesn't append any hash to the ConfigMap name. The ConfigMap declared from a ConfigMapGenerator is treated differently. A hash is appended to the name and any change in the ConfigMap will trigger a rolling update.
@@ -26,7 +28,7 @@ In this demo, the same [hello_world](helloWorld/README.md) is used while the Con
### Establish base and staging
Establish the base with a `configMapGenerator`:
<!-- @establishBase @test -->
<!-- @establishBase @testAgainstLatestRelease -->
```
DEMO_HOME=$(mktemp -d)
@@ -44,30 +46,33 @@ commonLabels:
resources:
- deployment.yaml
- service.yaml
configMapGenerator:
- name: the-map
literals:
- altGreeting=Good Morning!
configMapGenerator:
- name: the-map
literals:
- altGreeting=Good Morning!
- enableRisky="false"
EOF
```
Establish the staging with a patch applied to the ConfigMap
<!-- @establishStaging @test -->
<!-- @establishStaging @testAgainstLatestRelease -->
```
OVERLAYS=$DEMO_HOME/overlays
mkdir -p $OVERLAYS/staging
cat <<'EOF' >$OVERLAYS/staging/kustomization.yaml
namePrefix: staging-
nameSuffix: -v1
commonLabels:
variant: staging
org: acmeCorporation
commonAnnotations:
note: Hello, I am staging!
bases:
resources:
- ../../base
patches:
patchesStrategicMerge:
- map.yaml
EOF
@@ -89,8 +94,8 @@ configured with data from a ConfigMap.
The deployment refers to this map by name:
<!-- @showDeployment @testAgainstLatestRelease -->
<!-- @showDeployment @test -->
```
grep -C 2 configMapKeyRef $BASE/deployment.yaml
```
@@ -103,20 +108,21 @@ changed, so such updates have no effect.
The recommended way to change a deployment's
configuration is to
1. create a new ConfigMap with a new name,
1. patch the _deployment_, modifying the name value of
1. create a new ConfigMap with a new name,
1. patch the _deployment_, modifying the name value of
the appropriate `configMapKeyRef` field.
This latter change initiates rolling update to the pods
in the deployment. The older ConfigMap, when no longer
referenced by any other resource, is eventually garbage
collected.
in the deployment. The older ConfigMap, when no longer
referenced by any other resource, is eventually [garbage
collected](/../../issues/242).
### How this works with kustomize
The _staging_ [variant] here has a ConfigMap [patch]:
<!-- @showMapPatch @test -->
<!-- @showMapPatch @testAgainstLatestRelease -->
```
cat $OVERLAYS/staging/map.yaml
```
@@ -127,7 +133,8 @@ resource spec.
The ConfigMap it modifies is declared from a `configMapGenerator`.
<!-- @showMapBase @test -->
<!-- @showMapBase @testAgainstLatestRelease -->
```
grep -C 4 configMapGenerator $BASE/kustomization.yaml
```
@@ -136,11 +143,12 @@ For a patch to work, the names in the `metadata/name`
fields must match.
However, the name values specified in the file are
_not_ what gets used in the cluster. By design,
kustomize modifies names of ConfigMaps declared from ConfigMapGenerator. To see the names
_not_ what gets used in the cluster. By design,
kustomize modifies names of ConfigMaps declared from ConfigMapGenerator. To see the names
ultimately used in the cluster, just run kustomize:
<!-- @grepStagingName @test -->
<!-- @grepStagingName @testAgainstLatestRelease -->
```
kustomize build $OVERLAYS/staging |\
grep -B 8 -A 1 staging-the-map
@@ -150,21 +158,27 @@ The ConfigMap name is prefixed by _staging-_, per the
`namePrefix` field in
`$OVERLAYS/staging/kustomization.yaml`.
The ConfigMap name is suffixed by _-v1_, per the
`nameSuffix` field in
`$OVERLAYS/staging/kustomization.yaml`.
The suffix to the ConfigMap name is generated from a
hash of the maps content - in this case the name suffix
is _hhhhkfmgmk_:
is _5276h4th55_:
<!-- @grepStagingHash @testAgainstLatestRelease -->
<!-- @grepStagingHash @test -->
```
kustomize build $OVERLAYS/staging | grep hhhhkfmgmk
kustomize build $OVERLAYS/staging | grep 5276h4th55
```
Now modify the map patch, to change the greeting
the server will use:
<!-- @changeMap @test -->
<!-- @changeMap @testAgainstLatestRelease -->
```
sed -i 's/pineapple/kiwi/' $OVERLAYS/staging/map.yaml
sed -i.bak 's/pineapple/kiwi/' $OVERLAYS/staging/map.yaml
```
See the new greeting:
@@ -176,28 +190,30 @@ kustomize build $OVERLAYS/staging |\
Run kustomize again to see the new ConfigMap names:
<!-- @grepStagingName @test -->
<!-- @grepStagingName @testAgainstLatestRelease -->
```
kustomize build $OVERLAYS/staging |\
grep -B 8 -A 1 staging-the-map
```
Confirm that the change in ConfigMap content resulted
in three new names ending in _khk45ktkd9_ - one in the
in three new names ending in _c2g8fcbf88_ - one in the
ConfigMap name itself, and two in the deployment that
uses the map:
<!-- @countHashes @test -->
<!-- @countHashes @testAgainstLatestRelease -->
```
test 3 == \
$(kustomize build $OVERLAYS/staging | grep khk45ktkd9 | wc -l); \
$(kustomize build $OVERLAYS/staging | grep c2g8fcbf88 | wc -l); \
echo $?
```
Applying these resources to the cluster will result in
a rolling update of the deployments pods, retargetting
them from the _hhhhkfmgmk_ maps to the _khk45ktkd9_
maps. The system will later garbage collect the
them from the _5276h4th55_ maps to the _c2g8fcbf88_
maps. The system will later garbage collect the
unused maps.
## Rollback

View File

@@ -0,0 +1,333 @@
[builtin operations]: ../docs/plugins/builtins.md
[builtin plugins]: ../docs/plugins/builtins.md
[plugins]: ../docs/plugins
[plugin]: ../docs/plugins
[fields]: ../docs/fields.md
[fields in a kustomization file]: ../docs/fields.md
[TransformerConfig]: ../api/internal/plugins/builtinconfig/transformerconfig.go
[kustomization]: ../docs/glossary.md#kustomization
# Customizing kustomize
The [fields in a kustomization file] allow the user to
specify which resource files to use as input, how to
_generate_ new resources, and how to _transform_ those
resources - add labels, patch them, etc.
These fields are simple (low argument count) directives.
For example, the `commonAnnotations` field demands only a
list of _name:value_ pairs.
If using a field triggers behavior that pleases the user,
everyone's happy.
If not, the user can ask for new behavior to be implemented
in kustomize proper (and wait), or the user can write a
transformer or generator [plugin]. This latter option
generally means writing code; a Go plugin, a Go binary,
a C++ binary, a `bash` script - something.
There's a third option. If one merely wants to tweak
behavior that already exists in kustomize, one may be able
to do so by just writing some YAML.
## Configure the builtin plugins
All of kustomize's [builtin operations] are implemented
and usable as plugins.
Using the fields is convenient and brief, but necessarily
specifies only part of the entire plugin specification. The
unspecified part is defaulted to what are hopefully
generally appealing values.
If, instead, one invokes the plugins directly using the
`transformers` or `generators` field, one can (indeed
_must_) specify the entire plugin configuration.
## Example: field vs plugin
Define a place to work:
<!-- @makeWorkplace @testAgainstLatestRelease -->
```
DEMO_HOME=$(mktemp -d)
```
### Using the `commonLabels` and `commonAnnotations` fields
In this simple example, we'll use just two resources: a deployment and a service.
Define them:
<!-- @makeRes1 @testAgainstLatestRelease -->
```
cat <<EOF >$DEMO_HOME/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment
spec:
replicas: 10
template:
spec:
containers:
- name: the-container
image: monopole/hello:1
EOF
```
<!-- @makeRes2 @testAgainstLatestRelease -->
```
cat <<EOF >$DEMO_HOME/service.yaml
apiVersion: v1
kind: Service
metadata:
name: service
spec:
type: LoadBalancer
ports:
- protocol: TCP
port: 8666
targetPort: 8080
EOF
```
Now make a kustomization file that causes them
to be read and transformed:
<!-- @makeKustomization @testAgainstLatestRelease -->
```
cat <<'EOF' >$DEMO_HOME/kustomization.yaml
namePrefix: hello-
commonLabels:
app: hello
commonAnnotations:
area: "51"
greeting: Take me to your leader
resources:
- deployment.yaml
- service.yaml
EOF
```
And run kustomize:
<!-- @checkLabel @testAgainstLatestRelease -->
```
kustomize build $DEMO_HOME
```
The output will be something like
> ```
> apiVersion: v1
> kind: Service
> metadata:
> annotations:
> area: "51"
> greeting: Take me to your leader
> labels:
> app: hello
> name: hello-service
> spec:
> ports:
> - port: 8666
> protocol: TCP
> targetPort: 8080
> selector:
> app: hello
> type: LoadBalancer
> ---
> apiVersion: apps/v1
> kind: Deployment
> metadata:
> annotations:
> area: "51"
> greeting: Take me to your leader
> labels:
> app: hello
> name: hello-deployment
> spec:
> replicas: 10
> selector:
> matchLabels:
> app: hello
> template:
> metadata:
> annotations:
> area: "51"
> greeting: Take me to your leader
> labels:
> app: hello
> spec:
> containers:
> - image: monopole/hello:1
> name: the-container
> ```
Let's say we are unhappy with this result.
We only want the annotations
to be applied down in the pod templates,
and don't want to see them in the metadata
for Service or Deployment.
We like that the label _app: hello_ ended up in
- Service `spec.selector`
- Deployment `spec.selector.matchLabels`
- Deployment `spec.template.metadata.labels`
as this binds the Service (load balancer) to the pods,
and the Deployment itself to its own pods -
but we again don't care to see these labels in
the metadata for the Service and the Deployment.
### Configuring the builtin plugins instead
To fine tune this, invoke the same transformations
using the plugin approach.
Change the kustomization file:
<!-- @makeKustomization @testAgainstLatestRelease -->
```
cat <<'EOF' >$DEMO_HOME/kustomization.yaml
namePrefix: hello-
transformers:
- myAnnotator.yaml
- myLabeller.yaml
resources:
- deployment.yaml
- service.yaml
EOF
```
Then make the two plugin configuration files
(`myAnnotator.yaml`, `myLabeller.yaml`)
referred to by the `transformers` field above.
For details about the fields to specify, see
the documentation for the [builtin plugins].
<!-- @makeAnnotatorPluginConfig @testAgainstLatestRelease -->
```
cat <<EOF >$DEMO_HOME/myAnnotator.yaml
apiVersion: builtin
kind: AnnotationsTransformer
metadata:
name: notImportantHere
annotations:
area: 51
greeting: take me to your leader
fieldSpecs:
- kind: Deployment
path: spec/template/metadata/annotations
create: true
EOF
```
<!-- @makeLabelPluginConfig @testAgainstLatestRelease -->
```
cat <<EOF >$DEMO_HOME/myLabeller.yaml
apiVersion: builtin
kind: LabelTransformer
metadata:
name: notImportantHere
labels:
app: hello
fieldSpecs:
- kind: Service
path: spec/selector
create: true
- kind: Deployment
path: spec/selector/matchLabels
create: true
- kind: Deployment
path: spec/template/metadata/labels
create: true
EOF
```
Finally, run kustomize again:
<!-- @checkLabel @testAgainstLatestRelease -->
```
kustomize build $DEMO_HOME
```
The output should resemble the following,
with fewer labels and annotations.
> ```
> apiVersion: v1
> kind: Service
> metadata:
> name: hello-service
> spec:
> ports:
> - port: 8666
> protocol: TCP
> targetPort: 8080
> selector:
> app: hello
> type: LoadBalancer
> ---
> apiVersion: apps/v1
> kind: Deployment
> metadata:
> name: hello-deployment
> spec:
> replicas: 10
> selector:
> matchLabels:
> app: hello
> template:
> metadata:
> annotations:
> area: "51"
> greeting: take me to your leader
> labels:
> app: hello
> spec:
> containers:
> - image: monopole/hello:1
> name: the-container
> ```
## The old way to do this
The original (and still functional) way to customize
kustomize is to specify a `configurations` field in the
kustomization file.
This field, normally omitted because it overrides hardcoded
data, accepts a list of file path arguments. The files, in
turn, specify which fields in which k8s objects should be
affected by particular builtin transformations. It's a
global configuration cutting across transformations, and
doesn't effect generators at all.
At `build` time, the configuration files are unmarshalled
into one instance of [TransformerConfig]. This
object, _plus_ the field values for `namePrefix`, etc. are
fed into the transformation code to build the output.
The best way to write these custom configuration files is to
generate the files from the hardcoded values built into
kustomize via these commands:
> ```
> mkdir /tmp/junk
> kustomize config save -d /tmp/junk
> ```
One can then edit those file or files, and specify the
resulting edited files in a `configurations:`
field in a kustomization file used in a `build`.
Using plugins _completely ignores_ both hard coded
tranformer configuration, and any configuration loaded by
the `configuration` field.

View File

@@ -0,0 +1,244 @@
# Using a Custom OpenAPI schema
For more details regarding this feature you can read the
[Kustomize OpenAPI Features KEP](https://github.com/kubernetes/enhancements/tree/master/keps/sig-cli/2206-openapi-features-in-kustomize).
A kustomization file supports adding your own
OpenAPI schema to define merge keys and patch
strategy.
Make a place to work:
<!-- @placeToWork @testAgainstLatestRelease -->
```
DEMO_HOME=$(mktemp -d)
```
We'll be editing our own [custom resource](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/).
<!-- @customOpenAPI @testAgainstLatestRelease -->
```
cat <<EOF >$DEMO_HOME/my_resource.yaml
apiVersion: example.com/v1alpha1
kind: MyResource
metadata:
name: service
spec:
template:
spec:
containers:
- name: server
image: server
command: example
ports:
- name: grpc
protocol: TCP
containerPort: 8080
EOF
```
This resource has an image field. Let's change its value from server
to nginx with a patch.
Kustomize gets its merge key information from the OpenAPI data
provided by the kubernetes API server. It doesn't have information
about custom resources, so we will have to provide our own
schema file.
Note: CRDs support declarative validation using an OpenAPI v3 schema.
See https://book.kubebuilder.io/reference/generating-crd.html#validation.
You can get an OpenAPI document like this by fetching the OpenAPI
document from your locally favored cluster with the command
`kustomize openapi fetch`. Kustomize will use the OpenAPI extensions
`x-kubernetes-patch-merge-key` and `x-kubernetes-patch-strategy` to
perform a strategic merge. `x-kubernetes-patch-strategy` should be set
to "merge", and you can set your merge key to whatever you like. Below,
our custom resource inherits merge keys from `PodTemplateSpec`.
<!-- @addCustomSchema @testAgainstLatestRelease -->
```
cat <<EOF >>$DEMO_HOME/mycr_schema.json
{
"definitions": {
"v1alpha1.MyResource": {
"properties": {
"apiVersion": {
"type": "string"
},
"kind": {
"type": "string"
},
"metadata": {
"type": "object"
},
"spec": {
"properties": {
"template": {
"\$ref": "#/definitions/io.k8s.api.core.v1.PodTemplateSpec"
}
},
"type": "object"
},
"status": {
"properties": {
"success": {
"type": "boolean"
}
},
"type": "object"
}
},
"type": "object",
"x-kubernetes-group-version-kind": [
{
"group": "example.com",
"kind": "MyResource",
"version": "v1alpha1"
}
]
},
"io.k8s.api.core.v1.PodTemplateSpec": {
"properties": {
"metadata": {
"\$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta"
},
"spec": {
"\$ref": "#/definitions/io.k8s.api.core.v1.PodSpec"
}
},
"type": "object"
},
"io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta": {
"properties": {
"name": {
"type": "string"
}
},
"type": "object"
},
"io.k8s.api.core.v1.PodSpec": {
"properties": {
"containers": {
"items": {
"\$ref": "#/definitions/io.k8s.api.core.v1.Container"
},
"type": "array",
"x-kubernetes-patch-merge-key": "name",
"x-kubernetes-patch-strategy": "merge"
}
},
"type": "object"
},
"io.k8s.api.core.v1.Container": {
"properties": {
"command": {
"items": {
"type": "string"
},
"type": "array"
},
"image": {
"type": "string"
},
"name": {
"type": "string"
},
"ports": {
"items": {
"\$ref": "#/definitions/io.k8s.api.core.v1.ContainerPort"
},
"type": "array",
"x-kubernetes-list-map-keys": [
"containerPort",
"protocol"
],
"x-kubernetes-list-type": "map",
"x-kubernetes-patch-merge-key": "containerPort",
"x-kubernetes-patch-strategy": "merge"
}
},
"type": "object"
},
"io.k8s.api.core.v1.ContainerPort": {
"properties": {
"containerPort": {
"format": "int32",
"type": "integer"
},
"name": {
"type": "string"
},
"protocol": {
"type": "string"
}
},
"type": "object"
}
}
}
EOF
```
We'll of course need a `kustomization` file
referring to the custom resource, and containing our patch:
<!-- @openAPIkustomization @testAgainstLatestRelease -->
```
cat <<EOF >$DEMO_HOME/kustomization.yaml
resources:
- my_resource.yaml
openapi:
path: mycr_schema.json
patchesStrategicMerge:
- |-
apiVersion: example.com/v1alpha1
kind: MyResource
metadata:
name: service
spec:
template:
spec:
containers:
- name: server
image: nginx
EOF
```
Define the expected output:
<!-- @expected @testAgainstLatestRelease -->
```
cat <<EOF >$DEMO_HOME/out_expected.yaml
apiVersion: example.com/v1alpha1
kind: MyResource
metadata:
name: service
spec:
template:
spec:
containers:
- command: example
image: nginx
name: server
ports:
- containerPort: 8080
name: grpc
protocol: TCP
EOF
```
Run the build:
<!-- @runExample @testAgainstLatestRelease -->
```
kustomize build $DEMO_HOME >$DEMO_HOME/out_actual.yaml
```
Confirm they match:
<!-- @diffShouldBeEmpty @testAgainstLatestRelease -->
```
diff $DEMO_HOME/out_actual.yaml $DEMO_HOME/out_expected.yaml
```

View File

@@ -0,0 +1,60 @@
# Generator Options
Kustomize provides options to modify the behavior of ConfigMap and Secret generators. These options include
- disable appending a content hash suffix to the names of generated resources
- adding labels to generated resources
- adding annotations to generated resources
This demo shows how to use these options. First create a workspace.
```
DEMO_HOME=$(mktemp -d)
```
Create a kustomization and add a ConfigMap generator to it.
<!-- @createCMGenerator @testAgainstLatestRelease -->
```
cat > $DEMO_HOME/kustomization.yaml << EOF
configMapGenerator:
- name: my-configmap
literals:
- foo=bar
- baz=qux
EOF
```
Add following generatorOptions
<!-- @addGeneratorOptions @testAgainstLatestRelease -->
```
cat >> $DEMO_HOME/kustomization.yaml << EOF
generatorOptions:
disableNameSuffixHash: true
labels:
kustomize.generated.resource: somevalue
annotations:
annotations.only.for.generated: othervalue
EOF
```
Run `kustomize build` and make sure that the generated ConfigMap
- doesn't have name suffix
<!-- @verify @testAgainstLatestRelease -->
```
test 1 == \
$(kustomize build $DEMO_HOME | grep "name: my-configmap$" | wc -l); \
echo $?
```
- has label `kustomize.generated.resource: somevalue`
```
test 1 == \
$(kustomize build $DEMO_HOME | grep -A 1 "labels" | grep "kustomize.generated.resource" | wc -l); \
echo $?
```
- has annotation `annotations.only.for.generated: othervalue`
```
test 1 == \
$(kustomize build $DEMO_HOME | grep -A 1 "annotations" | grep "annotations.only.for.generated" | wc -l); \
echo $?
```

View File

@@ -0,0 +1,132 @@
# Remote Sources
Kustomize supports building a [remote target], but the URLs are limited to common [Git repository specs].
To extend the supported format, Kustomize has a [plugin] system that allows one to integrate third-party tools such as [hashicorp/go-getter] to "download things from a string URL using a variety of protocols", extract the content and generated resources as part of kustomize build.
[remote target]: /examples/remoteBuild.md
[Git repository specs]: /api/internal/git/repospec_test.go
[plugin]: /docs/plugins
[hashicorp/go-getter]: https://github.com/hashicorp/go-getter
## Make a place to work
<!-- @makeWorkplace @test -->
```sh
DEMO_HOME=$(mktemp -d)
mkdir -p $DEMO_HOME/base
```
## Use a remote kustomize layer
Define a kustomization representing your _local_ variant (aka environment).
This could involve any number of kustomizations (see other examples), but in this case just add the name prefix `my-` to all resources:
<!-- @writeKustLocal @test -->
```sh
cat <<'EOF' >$DEMO_HOME/kustomization.yaml
namePrefix: my-
resources:
- base/
EOF
```
It refer a remote base defined as below:
<!-- @writeKustLocal @test -->
```sh
cat <<'EOF' >$DEMO_HOME/base/kustomization.yaml
generators:
- goGetter.yaml
EOF
```
The base refers to a generator configuration file called `goGetter.yaml`.
This file lets one specify the source URL, and other things like sub path in the package, defaulting to base directory, and command to run under the path, defaulting to `kustomize build`.
Create the config file `goGetter.yaml`, specifying the arbitrarily chosen name _example_:
<!-- @writeGeneratorConfig @test -->
```sh
cat <<'EOF' >$DEMO_HOME/base/goGetter.yaml
apiVersion: someteam.example.com/v1
kind: GoGetter
metadata:
name: example
url: github.com/kustless/kustomize-examples.git
EOF
```
Because this particular YAML file is listed in the `generators:` stanza of a kustomization file, it is treated as the binding between a generator plugin - identified by the _apiVersion_ and _kind_ fields - and other fields that configure the plugin.
Download the plugin to your `DEMO_HOME` and make it executable:
<!-- @installPlugin @test -->
```sh
plugin=plugin/someteam.example.com/v1/gogetter/GoGetter
curl -s --create-dirs -o \
"$DEMO_HOME/kustomize/$plugin" \
"https://raw.githubusercontent.com/\
kubernetes-sigs/kustomize/master/$plugin"
chmod a+x $DEMO_HOME/kustomize/$plugin
```
Define a helper function to run kustomize with the correct environment and flags for plugins:
<!-- @defineKustomizeIt @test -->
```sh
function kustomizeIt {
XDG_CONFIG_HOME=$DEMO_HOME \
kustomize build --enable_alpha_plugins \
$DEMO_HOME/$1
}
```
Finally, build the local variant. Notice that all
resource names now have the `my-` prefix:
<!-- @doLocal @test -->
```sh
clear
kustomizeIt
```
Compare local variant to remote base:
<!-- @doCompare @test-->
```sh
diff <(kustomizeIt) <(kustomizeIt base) | more
...
< name: my-remote-cm
---
> name: remote-cm
```
To see the unmodified but extracted sources, run kustomize on the base. Every invocation here is re-downloading and re-building the package.
<!-- @showBase @test -->
```sh
kustomizeIt base
```
## Use non-kustomize remote sources
Sometimes the remote sources does not include `kustomization.yaml`. To use that in the plugin, set command to override the default build.
<!-- @setCommand @test -->
```sh
echo "command: cat resources.yaml" >>$DEMO_HOME/base/goGetter.yaml
```
Finally, built it
<!-- @finalLocal @test -->
```sh
kustomizeIt
```
and observe the output includes raw `resources.yaml` instead of building result of remote `kustomization.yaml`.

View File

@@ -1,9 +1,9 @@
[base]: ../../docs/glossary.md#base
[config]: https://github.com/kinflate/example-hello
[config]: https://github.com/kubernetes-sigs/kustomize/tree/master/examples/helloWorld
[gitops]: ../../docs/glossary.md#gitops
[hello]: https://github.com/monopole/hello
[kustomization]: ../../docs/glossary.md#kustomization
[original]: https://github.com/kinflate/example-hello
[original]: https://github.com/kubernetes-sigs/kustomize/tree/master/examples/helloWorld
[overlay]: ../../docs/glossary.md#overlay
[overlays]: ../../docs/glossary.md#overlay
[patch]: ../../docs/glossary.md#patch
@@ -22,7 +22,7 @@ Steps:
First define a place to work:
<!-- @makeWorkplace @test -->
<!-- @makeWorkplace @testAgainstLatestRelease -->
```
DEMO_HOME=$(mktemp -d)
```
@@ -44,7 +44,7 @@ To keep this document shorter, the base resources are
off in a supplemental data directory rather than
declared here as HERE documents. Download them:
<!-- @downloadBase @test -->
<!-- @downloadBase @testAgainstLatestRelease -->
```
BASE=$DEMO_HOME/base
mkdir -p $BASE
@@ -57,7 +57,7 @@ curl -s -o "$BASE/#1.yaml" "https://raw.githubusercontent.com\
Look at the directory:
<!-- @runTree @test -->
<!-- @runTree -->
```
tree $DEMO_HOME
```
@@ -78,7 +78,7 @@ One could immediately apply these resources to a
cluster:
> ```
> kubectl apply -f $DEMO_HOME/base
> kubectl apply -k $DEMO_HOME/base
> ```
to instantiate the _hello_ service. `kubectl`
@@ -88,7 +88,7 @@ would only recognize the resource files.
The `base` directory has a [kustomization] file:
<!-- @showKustomization @test -->
<!-- @showKustomization @testAgainstLatestRelease -->
```
more $BASE/kustomization.yaml
```
@@ -96,7 +96,7 @@ more $BASE/kustomization.yaml
Optionally, run `kustomize` on the base to emit
customized resources to `stdout`:
<!-- @buildBase @test -->
<!-- @buildBase @testAgainstLatestRelease -->
```
kustomize build $BASE
```
@@ -106,20 +106,14 @@ kustomize build $BASE
A first customization step could be to change the _app
label_ applied to all resources:
<!-- @addLabel @test -->
<!-- @addLabel @testAgainstLatestRelease -->
```
sed -i 's/app: hello/app: my-hello/' \
sed -i.bak 's/app: hello/app: my-hello/' \
$BASE/kustomization.yaml
```
On a Mac, use:
```
sed -i '' $pattern $file
```
to get in-place editing.
See the effect:
<!-- @checkLabel @test -->
<!-- @checkLabel @testAgainstLatestRelease -->
```
kustomize build $BASE | grep -C 3 app:
```
@@ -133,7 +127,7 @@ Create a _staging_ and _production_ [overlay]:
* Web server greetings from these cluster
[variants] will differ from each other.
<!-- @overlayDirectories @test -->
<!-- @overlayDirectories @testAgainstLatestRelease -->
```
OVERLAYS=$DEMO_HOME/overlays
mkdir -p $OVERLAYS/staging
@@ -145,7 +139,7 @@ mkdir -p $OVERLAYS/production
In the `staging` directory, make a kustomization
defining a new name prefix, and some different labels.
<!-- @makeStagingKustomization @test -->
<!-- @makeStagingKustomization @testAgainstLatestRelease -->
```
cat <<'EOF' >$OVERLAYS/staging/kustomization.yaml
namePrefix: staging-
@@ -156,7 +150,7 @@ commonAnnotations:
note: Hello, I am staging!
bases:
- ../../base
patches:
patchesStrategicMerge:
- map.yaml
EOF
```
@@ -168,7 +162,7 @@ greeting from _Good Morning!_ to _Have a pineapple!_
Also, enable the _risky_ flag.
<!-- @stagingMap @test -->
<!-- @stagingMap @testAgainstLatestRelease -->
```
cat <<EOF >$OVERLAYS/staging/map.yaml
apiVersion: v1
@@ -186,7 +180,7 @@ EOF
In the production directory, make a kustomization
with a different name prefix and labels.
<!-- @makeProductionKustomization @test -->
<!-- @makeProductionKustomization @testAgainstLatestRelease -->
```
cat <<EOF >$OVERLAYS/production/kustomization.yaml
namePrefix: production-
@@ -197,7 +191,7 @@ commonAnnotations:
note: Hello, I am production!
bases:
- ../../base
patches:
patchesStrategicMerge:
- deployment.yaml
EOF
```
@@ -208,7 +202,7 @@ EOF
Make a production patch that increases the replica
count (because production takes more traffic).
<!-- @productionDeployment @test -->
<!-- @productionDeployment @testAgainstLatestRelease -->
```
cat <<EOF >$OVERLAYS/production/deployment.yaml
apiVersion: apps/v1
@@ -234,7 +228,7 @@ EOF
Review the directory structure and differences:
<!-- @listFiles @test -->
<!-- @listFiles -->
```
tree $DEMO_HOME
```
@@ -294,12 +288,12 @@ something like
The individual resource sets are:
<!-- @buildStaging @test -->
<!-- @buildStaging @testAgainstLatestRelease -->
```
kustomize build $OVERLAYS/staging
```
<!-- @buildProduction @test -->
<!-- @buildProduction @testAgainstLatestRelease -->
```
kustomize build $OVERLAYS/production
```

View File

@@ -4,6 +4,9 @@ metadata:
name: the-deployment
spec:
replicas: 3
selector:
matchLabels:
deployment: hello
template:
metadata:
labels:

View File

@@ -1,3 +1,8 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
metadata:
name: arbitrary
# Example configuration for the webserver
# at https://github.com/monopole/hello
commonLabels:

View File

@@ -1,16 +1,16 @@
# Demo: change image tags
# Demo: change image names and tags
Define a place to work:
<!-- @makeWorkplace @test -->
<!-- @makeWorkplace @testAgainstLatestRelease -->
```
DEMO_HOME=$(mktemp -d)
```
Make a `kustomization` containing a pod resource
<!-- @createKustomization @test -->
<!-- @createKustomization @testAgainstLatestRelease -->
```
cat <<EOF >$DEMO_HOME/kustomization.yaml
resources:
@@ -20,7 +20,7 @@ EOF
Declare the pod resource
<!-- @createDeployment @test -->
<!-- @createDeployment @testAgainstLatestRelease -->
```
cat <<EOF >$DEMO_HOME/pod.yaml
apiVersion: v1
@@ -42,34 +42,35 @@ EOF
```
The `myapp-pod` resource declares an initContainer and a container, both use the image `busybox:1.29.0`.
The tag `1.29.0` can be changed by adding `imageTags` in `kustomization.yaml`.
The image `busybox` and tag `1.29.0` can be changed by adding `images` in `kustomization.yaml`.
Add `imageTags`:
<!-- @addImageTags @test -->
Add `images`:
<!-- @addImages @testAgainstLatestRelease -->
```
cd $DEMO_HOME
kustomize edit set imagetag busybox:1.29.1
kustomize edit set image busybox=alpine:3.6
```
The `kustomization.yaml` will be added following `imageTags`.
The following `images` will be added to `kustomization.yaml`:
> ```
> imageTags:
> images:
> - name: busybox
> newTag: 1.29.1
> newName: alpine
> newTag: 3.6
> ```
Now build this `kustomization`
<!-- @kustomizeBuild @test -->
<!-- @kustomizeBuild @testAgainstLatestRelease -->
```
kustomize build $DEMO_HOME
```
Confirm that this replaces _both_ busybox tags:
Confirm that this replaces _both_ busybox images and tags for `alpine:3.6`:
<!-- @confirmTags @test -->
<!-- @confirmImages @testAgainstLatestRelease -->
```
test 2 == \
$(kustomize build $DEMO_HOME | grep busybox:1.29.1 | wc -l); \
test 2 = \
$(kustomize build $DEMO_HOME | grep alpine:3.6 | wc -l); \
echo $?
```

265
examples/inlinePatch.md Normal file
View File

@@ -0,0 +1,265 @@
[Strategic Merge Patch]: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-api-machinery/strategic-merge-patch.md
[JSON Patch]: https://tools.ietf.org/html/rfc6902
# Demo: Inline Patch
A kustomization file supports patching in three ways:
- patchesStrategicMerge: A list of patch files where each file is parsed as a [Strategic Merge Patch].
- patchesJSON6902: A list of patches and associated targets, where each file is parsed as a [JSON Patch] and can only be applied to one target resource.
- patches: A list of patches and their associated targets. The patch can be applied to multiple objects. It auto detects whether the patch is a [Strategic Merge Patch] or [JSON Patch].
Since 3.2.0, all three support inline patch, where the patch content is put inside the kustomization file as a single string. With this feature, no separate patch files need to be created.
Make a base kustomization containing a Deployment resource.
<!-- @createKustomization @test -->
```
DEMO_HOME=$(mktemp -d)
BASE=$DEMO_HOME/base
mkdir $BASE
cat <<EOF >$BASE/kustomization.yaml
resources:
- deployments.yaml
EOF
cat <<EOF >$BASE/deployments.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy
spec:
template:
metadata:
labels:
foo: bar
spec:
containers:
- name: nginx
image: nginx
args:
- one
- two
EOF
```
## Inline Patch for PatchesStrategicMerge
Create an overlay and add an inline patch in `patchesStrategicMerge` field to the kustomization file
to change the image from `nginx` to `nginx:latest`.
<!-- @addSMPatch @test -->
```
SMP_OVERLAY=$DEMO_HOME/smp
mkdir $SMP_OVERLAY
cat <<EOF >$SMP_OVERLAY/kustomization.yaml
resources:
- ../base
patchesStrategicMerge:
- |-
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy
spec:
template:
spec:
containers:
- name: nginx
image: nginx:latest
EOF
```
Running `kustomize build $SMP_OVERLAY`, in the output confirm that image is updated successfully.
<!-- @confirmSMPatch @test -->
```
test 1 == \
$(kustomize build $SMP_OVERLAY | grep "image: nginx:latest" | wc -l); \
echo $?
```
The output is
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy
spec:
template:
metadata:
labels:
foo: bar
spec:
containers:
- name: nginx
image: nginx:latest
args:
- one
- two
```
`$patch: delete` and `$patch: replace` also work in the inline patch. Change the inline patch to delete the container `nginx`.
<!-- @addDeleteSMPatch @test -->
```
cat <<EOF >$SMP_OVERLAY/kustomization.yaml
resources:
- ../base
patchesStrategicMerge:
- |-
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy
spec:
template:
spec:
containers:
- name: nginx
$patch: delete
EOF
```
Running `kustomize build $SMP_OVERLAY`, in the output confirm that the `nginx` container has been deleted.
<!-- @confirmDeleteSMPatch @test -->
```
test 0 == \
$(kustomize build $SMP_OVERLAY | grep "image: nginx" | wc -l); \
echo $?
```
The output is
```
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy
spec:
template:
metadata:
labels:
foo: bar
spec:
containers: []
```
## Inline Patch for PatchesJson6902
Create an overlay and add an inline patch in `patchesJSON6902` field to the kustomization file
to change the image from `nginx` to `nginx:latest`.
<!-- @addJSONPatch @test -->
```
JSON_OVERLAY=$DEMO_HOME/json
mkdir $JSON_OVERLAY
cat <<EOF >$JSON_OVERLAY/kustomization.yaml
resources:
- ../base
patchesJSON6902:
- target:
group: apps
version: v1
kind: Deployment
name: deploy
patch: |-
- op: replace
path: /spec/template/spec/containers/0/image
value: nginx:latest
EOF
```
Running `kustomize build $JSON_OVERLAY`, in the output confirm that image is updated successfully.
<!-- @confirmJSONPatch @test -->
```
test 1 == \
$(kustomize build $JSON_OVERLAY | grep "image: nginx:latest" | wc -l); \
echo $?
```
The output is
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy
spec:
template:
metadata:
labels:
foo: bar
spec:
containers:
- name: nginx
image: nginx:latest
args:
- one
- two
```
## Inline Patch for Patches
Create an overlay and add an inline patch in `patches` field to the kustomization file
to change the image from `nginx` to `nginx:latest`.
<!-- @addPatch @test -->
```
PATCH_OVERLAY=$DEMO_HOME/patch
mkdir $PATCH_OVERLAY
cat <<EOF > $PATCH_OVERLAY/kustomization.yaml
resources:
- ../base
patches:
- target:
kind: Deployment
name: deploy
patch: |-
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy
spec:
template:
spec:
containers:
- name: nginx
image: nginx:latest
EOF
```
Running `kustomize build $PATCH_OVERLAY`, in the output confirm that image is updated successfully.
<!-- @confirmPatch @test -->
```
test 1 == \
$(kustomize build $PATCH_OVERLAY | grep "image: nginx:latest" | wc -l); \
echo $?
```
The output is
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy
spec:
template:
metadata:
labels:
foo: bar
spec:
containers:
- name: nginx
image: nginx:latest
args:
- one
- two
```

View File

@@ -28,7 +28,7 @@
# before running it.
#
# At time of writing, its 'call point' was in
# https://github.com/kubernetes/test-infra/blob/master/jobs/config.json
# https://github.com/kubernetes/test-infra/blob/master/config/jobs/kubernetes-sigs/kustomize/kustomize-config.yaml
function exitWith {
local msg=$1
@@ -48,12 +48,12 @@ function setUpEnv {
[[ $? -eq 0 ]] || "Failed to cd to $repo"
echo "pwd is " `pwd`
local expectedRepo=kubernetes-sigs/kustomize
local expectedRepo=sigs.k8s.io/kustomize
if [[ `pwd` != */$expectedRepo ]]; then
exitWith "Script must be run from $expectedRepo"
fi
go install . || \
GO111MODULE=on go install ./cmd/kustomize || \
{ exitWith "Failed to install kustomize."; }
PATH=$GOPATH/bin:$PATH

201
examples/jsonpatch.md Normal file
View File

@@ -0,0 +1,201 @@
# JSON Patching
[JSON patches]: https://tools.ietf.org/html/rfc6902
[JSON patch]: https://tools.ietf.org/html/rfc6902
A kustomization file supports customizing
resources via [JSON patches].
Make a place to work:
<!-- @placeToWork @testAgainstLatestRelease -->
```
DEMO_HOME=$(mktemp -d)
```
We'll be editting an `Ingress` object:
<!-- @ingress @testAgainstLatestRelease -->
```
cat <<EOF >$DEMO_HOME/ingress.yaml
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: my-ingress
spec:
rules:
- host: foo.bar.com
http:
paths:
- path: /
backend:
serviceName: homepage
servicePort: 8888
- path: /api
backend:
serviceName: my-api
servicePort: 7701
- path: /test
backend:
serviceName: hello
servicePort: 7702
EOF
```
The edits we want to make are:
- change the value of `host` to _foo.bar.io_
- change the port for `'/'` from _8888_ to _80_
- insert an entirely new serving path `/healthz`
at a particular point in the `paths` list,
rather than at the end or the beginning.
Here's the patch file to do that:
<!-- @addJsonPatch @testAgainstLatestRelease -->
```
cat <<EOF >$DEMO_HOME/ingress_patch.json
[
{"op": "replace",
"path": "/spec/rules/0/host",
"value": "foo.bar.io"},
{"op": "replace",
"path": "/spec/rules/0/http/paths/0/backend/servicePort",
"value": 80},
{"op": "add",
"path": "/spec/rules/0/http/paths/1",
"value": { "path": "/healthz", "backend": {"servicePort":7700} }}
]
EOF
```
We'll of course need a `kustomization` file
referring to the `Ingress`:
<!-- @kustomization @testAgainstLatestRelease -->
```
cat <<EOF >$DEMO_HOME/kustomization.yaml
resources:
- ingress.yaml
EOF
```
To this same `kustomization` file, add a
`patches` field refering to
the patch file we just made and
target it to the `Ingress` object:
<!-- @applyJsonPatch @testAgainstLatestRelease -->
```
cat <<EOF >>$DEMO_HOME/kustomization.yaml
patches:
- path: ingress_patch.json
target:
group: networking.k8s.io
version: v1beta1
kind: Ingress
name: my-ingress
EOF
```
Define the expected output:
<!-- @expected @testAgainstLatestRelease -->
```
cat <<EOF >$DEMO_HOME/out_expected.yaml
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: my-ingress
spec:
rules:
- host: foo.bar.io
http:
paths:
- backend:
serviceName: homepage
servicePort: 80
path: /
- backend:
servicePort: 7700
path: /healthz
- backend:
serviceName: my-api
servicePort: 7701
path: /api
- backend:
serviceName: hello
servicePort: 7702
path: /test
EOF
```
Run the build:
<!-- @runIt @testAgainstLatestRelease -->
```
kustomize build $DEMO_HOME >$DEMO_HOME/out_actual.yaml
```
Confirm they match:
<!-- @diffShouldExitZero @testAgainstLatestRelease -->
```
diff $DEMO_HOME/out_actual.yaml $DEMO_HOME/out_expected.yaml
```
If you prefer YAML to JSON, the patch can be expressed
in YAML format (nevertheless following [JSON patch] rules):
<!-- @writeYamlPatch @testAgainstLatestRelease -->
```
cat <<EOF >$DEMO_HOME/ingress_patch.yaml
- op: add
path: /spec/rules/0/http/paths/-
value:
path: '/canada'
backend:
serviceName: hoser
servicePort: 7703
EOF
```
Now add this to the list of patches in the `kustomization` file:
<!-- @addYamlPatch @testAgainstLatestRelease -->
```
cat <<EOF >>$DEMO_HOME/kustomization.yaml
- path: ingress_patch.yaml
target:
group: networking.k8s.io
version: v1beta1
kind: Ingress
name: my-ingress
EOF
```
We expect the following at the end of the output:
<!-- @expected @testAgainstLatestRelease -->
```
cat <<EOF >$DEMO_HOME/out_expected.yaml
- backend:
serviceName: hello
servicePort: 7702
path: /test
- backend:
serviceName: hoser
servicePort: 7703
path: /canada
EOF
```
Try it:
<!-- @runIt @testAgainstLatestRelease -->
```
kustomize build $DEMO_HOME | tail -n 8 |\
diff $DEMO_HOME/out_expected.yaml -
```
To see how to apply one JSON patch to many resources,
see the [multi-patch](patchMultipleObjects.md) demo.

View File

@@ -18,7 +18,7 @@ Steps:
First define a place to work:
<!-- @makeWorkplace @test -->
<!-- @makeWorkplace @testAgainstLatestRelease -->
```
DEMO_HOME=$(mktemp -d)
```
@@ -38,7 +38,7 @@ To keep this document shorter, the base resources are
off in a supplemental data directory rather than
declared here as HERE documents. Download them:
<!-- @downloadBase @test -->
<!-- @downloadBase @testAgainstLatestRelease -->
```
BASE=$DEMO_HOME/base
mkdir -p $BASE
@@ -53,7 +53,7 @@ curl -s -o "$BASE/#1" "$CONTENT/base\
Look at the directory:
<!-- @runTree @test -->
<!-- @runTree -->
```
tree $DEMO_HOME
```
@@ -84,7 +84,7 @@ would only recognize the resource files.
The `base` directory has a [kustomization] file:
<!-- @showKustomization @test -->
<!-- @showKustomization @testAgainstLatestRelease -->
```
more $BASE/kustomization.yaml
```
@@ -92,7 +92,7 @@ more $BASE/kustomization.yaml
Optionally, run `kustomize` on the base to emit
customized resources to `stdout`:
<!-- @buildBase @test -->
<!-- @buildBase @testAgainstLatestRelease -->
```
kustomize build $BASE
```
@@ -101,14 +101,14 @@ kustomize build $BASE
A first customization step could be to set the name prefix to all resources:
<!-- @namePrefix @test -->
<!-- @namePrefix @testAgainstLatestRelease -->
```
cd $BASE
kustomize edit set nameprefix "my-"
```
See the effect:
<!-- @checkNameprefix @test -->
<!-- @checkNameprefix @testAgainstLatestRelease -->
```
kustomize build $BASE | grep -C 3 "my-"
```
@@ -121,7 +121,7 @@ Create a _staging_ and _production_ [overlay]:
* _Production_ has a higher replica count and a persistent disk.
* [variants] will differ from each other.
<!-- @overlayDirectories @test -->
<!-- @overlayDirectories @testAgainstLatestRelease -->
```
OVERLAYS=$DEMO_HOME/overlays
mkdir -p $OVERLAYS/staging
@@ -132,7 +132,7 @@ mkdir -p $OVERLAYS/production
Download the staging customization and patch.
<!-- @downloadStagingKustomization @test -->
<!-- @downloadStagingKustomization @testAgainstLatestRelease -->
```
curl -s -o "$OVERLAYS/staging/#1" "$CONTENT/overlays/staging\
/{config.env,deployment.yaml,kustomization.yaml}"
@@ -148,7 +148,7 @@ The staging customization adds a configMap.
> ```
as well as 2 replica
> ```cat $OVERLAYS/staging/deployment.yaml
> apiVersion: apps/v1beta2
> apiVersion: apps/v1
> kind: Deployment
> metadata:
> name: ldap
@@ -159,7 +159,7 @@ as well as 2 replica
#### Production Kustomization
Download the production customization and patch.
<!-- @downloadProductionKustomization @test -->
<!-- @downloadProductionKustomization @testAgainstLatestRelease -->
```
curl -s -o "$OVERLAYS/production/#1" "$CONTENT/overlays/production\
/{deployment.yaml,kustomization.yaml}"
@@ -167,7 +167,7 @@ curl -s -o "$OVERLAYS/production/#1" "$CONTENT/overlays/production\
The production customization adds 6 replica as well as a consistent disk.
> ```cat $OVERLAYS/production/deployment.yaml
> apiVersion: apps/v1beta2
> apiVersion: apps/v1
> kind: Deployment
> metadata:
> name: ldap
@@ -196,7 +196,7 @@ The production customization adds 6 replica as well as a consistent disk.
Review the directory structure and differences:
<!-- @listFiles @test -->
<!-- @listFiles -->
```
tree $DEMO_HOME
```
@@ -258,12 +258,12 @@ The difference output should look something like
The individual resource sets are:
<!-- @buildStaging @test -->
<!-- @buildStaging @testAgainstLatestRelease -->
```
kustomize build $OVERLAYS/staging
```
<!-- @buildProduction @test -->
<!-- @buildProduction @testAgainstLatestRelease -->
```
kustomize build $OVERLAYS/production
```

View File

@@ -1,4 +1,4 @@
apiVersion: apps/v1beta2
apiVersion: apps/v1
kind: Deployment
metadata:
name: ldap

View File

@@ -1,4 +1,4 @@
apiVersion: apps/v1beta2
apiVersion: apps/v1
kind: Deployment
metadata:
name: ldap

View File

@@ -1,5 +1,5 @@
bases:
resources:
- ../../base
patches:
patchesStrategicMerge:
- deployment.yaml
namePrefix: production-

View File

@@ -1,5 +1,5 @@
apiVersion: apps/v1beta2
apiVersion: apps/v1
kind: Deployment
metadata:
name: ldap

View File

@@ -1,9 +1,9 @@
bases:
- ../../base
patches:
- deployment.yaml
nameprefix: staging-
resources:
- ../../base
patchesStrategicMerge:
- deployment.yaml
namePrefix: staging-
configMapGenerator:
- name: env-config
files:
- config.env
- name: env-config
files:
- config.env

25
examples/loadHttp.md Normal file
View File

@@ -0,0 +1,25 @@
# load file from http
Resource and patch files could be loaded from http
<!-- @loadHttp -->
```sh
DEMO_HOME=$(mktemp -d)
cat <<EOF >$DEMO_HOME/kustomization.yaml
resources:
- https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/examples/helloWorld/configMap.yaml
EOF
```
<!-- @loadHttp -->
```sh
test 1 == \
$(kustomize build $DEMO_HOME | grep "Good Morning!" | wc -l); \
echo $?
```
Kustomize will try loading resource as a file either from local or http. If it
fails, try to load it as a directory or git repository.
Http load applies to patches as well. See full example in [loadHttp](loadHttp/).

View File

@@ -0,0 +1,15 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/examples/wordpress/wordpress/deployment.yaml
- https://github.com/knative/serving/releases/download/v0.12.0/serving.yaml # redirects to s3
patches:
- https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/examples/wordpress/patch.yaml
patchesStrategicMerge:
- |-
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: custom-metrics-auth-reader
namespace: kube-system
$patch: delete

View File

@@ -0,0 +1,137 @@
# Demo: multibases with a common base
`kustomize` encourages defining multiple variants -
e.g. dev, staging and prod,
as overlays on a common base.
It's possible to create an additional overlay to
compose these variants together - just declare the
overlays as the bases of a new kustomization.
This is also a means to apply a common label or
annotation across the variants, if for some reason
the base isn't under your control. It also allows
one to define a left-most namePrefix across the
variants - something that cannot be
done by modifying the common base.
The following demonstrates this using a base
that is just a single pod.
Define a place to work:
<!-- @makeWorkplace @testAgainstLatestRelease -->
```
DEMO_HOME=$(mktemp -d)
```
Define a common base:
<!-- @makeBase @testAgainstLatestRelease -->
```
BASE=$DEMO_HOME/base
mkdir $BASE
cat <<EOF >$BASE/kustomization.yaml
resources:
- pod.yaml
EOF
cat <<EOF >$BASE/pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
spec:
containers:
- name: nginx
image: nginx:1.7.9
EOF
```
Define a dev variant overlaying base:
<!-- @makeDev @testAgainstLatestRelease -->
```
DEV=$DEMO_HOME/dev
mkdir $DEV
cat <<EOF >$DEV/kustomization.yaml
resources:
- ./../base
namePrefix: dev-
EOF
```
Define a staging variant overlaying base:
<!-- @makeStaging @testAgainstLatestRelease -->
```
STAG=$DEMO_HOME/staging
mkdir $STAG
cat <<EOF >$STAG/kustomization.yaml
resources:
- ./../base
namePrefix: stag-
EOF
```
Define a production variant overlaying base:
<!-- @makeProd @testAgainstLatestRelease -->
```
PROD=$DEMO_HOME/production
mkdir $PROD
cat <<EOF >$PROD/kustomization.yaml
resources:
- ./../base
namePrefix: prod-
EOF
```
Then define a _Kustomization_ composing three variants together:
<!-- @makeTopLayer @testAgainstLatestRelease -->
```
cat <<EOF >$DEMO_HOME/kustomization.yaml
resources:
- ./dev
- ./staging
- ./production
namePrefix: cluster-a-
EOF
```
Now the workspace has following directories
> ```
> .
> ├── base
> │   ├── kustomization.yaml
> │   └── pod.yaml
> ├── dev
> │   └── kustomization.yaml
> ├── kustomization.yaml
> ├── production
> │   └── kustomization.yaml
> └── staging
> └── kustomization.yaml
> ```
Confirm that the `kustomize build` output contains three pod objects from dev, staging and production variants.
<!-- @confirmVariants @testAgainstLatestRelease -->
```
test 1 == \
$(kustomize build $DEMO_HOME | grep cluster-a-dev-myapp-pod | wc -l); \
echo $?
test 1 == \
$(kustomize build $DEMO_HOME | grep cluster-a-stag-myapp-pod | wc -l); \
echo $?
test 1 == \
$(kustomize build $DEMO_HOME | grep cluster-a-prod-myapp-pod | wc -l); \
echo $?
```
Similarly to adding different `namePrefix` in different variants, one can also add different `namespace` and compose those variants in
one _kustomization_. For more details, take a look at [multi-namespaces](multi-namespace.md).

View File

@@ -0,0 +1,2 @@
resources:
- pod.yaml

View File

@@ -0,0 +1,10 @@
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
spec:
containers:
- name: nginx
image: nginx:1.7.9

View File

@@ -0,0 +1,3 @@
resources:
- ../base
namePrefix: dev-

View File

@@ -0,0 +1,5 @@
resources:
- dev
- staging
- production
namePrefix: cluster-a-

View File

@@ -0,0 +1,115 @@
# Demo: multi namespaces with a common base
`kustomize` supports defining multiple variants with different namespace, as overlays on a common base.
It's possible to create an additional overlay to compose these variants
together - just declare the overlays as the bases of a new kustomization. The
following demonstrates this using a base that's just one pod.
Define a place to work:
<!-- @makeWorkplace @testAgainstLatestRelease -->
```
DEMO_HOME=$(mktemp -d)
```
Define a common base:
<!-- @makeBase @testAgainstLatestRelease -->
```
BASE=$DEMO_HOME/base
mkdir $BASE
cat <<EOF >$BASE/kustomization.yaml
resources:
- pod.yaml
EOF
cat <<EOF >$BASE/pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
spec:
containers:
- name: nginx
image: nginx:1.7.9
EOF
```
Define a variant in namespace-a overlaying base:
<!-- @makeNamespaceA @testAgainstLatestRelease -->
```
NSA=$DEMO_HOME/namespace-a
mkdir $NSA
cat <<EOF >$NSA/kustomization.yaml
resources:
- namespace.yaml
- ../base
namespace: namespace-a
EOF
cat <<EOF >$NSA/namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: namespace-a
EOF
```
Define a variant in namespace-b overlaying base:
<!-- @makeNamespaceB @testAgainstLatestRelease -->
```
NSB=$DEMO_HOME/namespace-b
mkdir $NSB
cat <<EOF >$NSB/kustomization.yaml
resources:
- namespace.yaml
- ../base
namespace: namespace-b
EOF
cat <<EOF >$NSB/namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: namespace-b
EOF
```
Then define a _Kustomization_ composing two variants together:
<!-- @makeTopLayer @testAgainstLatestRelease -->
```
cat <<EOF >$DEMO_HOME/kustomization.yaml
resources:
- namespace-a
- namespace-b
EOF
```
Now the workspace has following directories
> ```
> .
> ├── base
> │   ├── kustomization.yaml
> │   └── pod.yaml
> ├── kustomization.yaml
> ├── namespace-a
> │   ├── kustomization.yaml
> │   └── namespace.yaml
> └── namespace-b
> ├── kustomization.yaml
> └── namespace.yaml
> ```
Confirm that the `kustomize build` output contains two pod objects from namespace-a and namespace-b.
<!-- @confirmVariants @testAgainstLatestRelease -->
```
test 2 == \
$(kustomize build $DEMO_HOME| grep -B 4 "namespace: namespace-[ab]" | grep "name: myapp-pod" | wc -l); \
echo $?
```

View File

@@ -0,0 +1,3 @@
resources:
- ../base
namePrefix: prod-

View File

@@ -0,0 +1,3 @@
resources:
- ../base
namePrefix: staging-

View File

@@ -11,7 +11,7 @@ In the production environment we want:
- MySQL to use persistent disk for storing data.
First make a place to work:
<!-- @makeDemoHome @test -->
<!-- @makeDemoHome @testAgainstLatestRelease -->
```
DEMO_HOME=$(mktemp -d)
```
@@ -25,7 +25,7 @@ as HERE documents.
Download them:
<!-- @downloadResources @test -->
<!-- @downloadResources @testAgainstLatestRelease -->
```
curl -s -o "$DEMO_HOME/#1.yaml" "https://raw.githubusercontent.com\
/kubernetes-sigs/kustomize\
@@ -40,14 +40,14 @@ a file called `kustomization.yaml`.
Start this file:
<!-- @kustomizeYaml @test -->
<!-- @kustomizeYaml @testAgainstLatestRelease -->
```
touch $DEMO_HOME/kustomization.yaml
```
### Add the resources
<!-- @addResources @test -->
<!-- @addResources @testAgainstLatestRelease -->
```
cd $DEMO_HOME
@@ -73,7 +73,7 @@ Arrange for the MySQL resources to begin with prefix
_prod-_ (since they are meant for the _production_
environment):
<!-- @customizeLabel @test -->
<!-- @customizeLabel @testAgainstLatestRelease -->
```
cd $DEMO_HOME
@@ -91,7 +91,7 @@ cat kustomization.yaml
This `namePrefix` directive adds _prod-_ to all
resource names.
<!-- @genNamePrefixConfig @test -->
<!-- @genNamePrefixConfig @testAgainstLatestRelease -->
```
kustomize build $DEMO_HOME
```
@@ -115,7 +115,7 @@ The output should contain:
> spec:
> ....
> ---
> apiVersion: apps/v1beta2
> apiVersion: apps/v1
> kind: Deployment
> metadata:
> ....
@@ -134,9 +134,9 @@ selector.
`kustomize` does not have `edit set label` command to add
a label, but one can always edit `kustomization.yaml` directly:
<!-- @customizeLabels @test -->
<!-- @customizeLabels @testAgainstLatestRelease -->
```
sed -i 's/app: helloworld/app: prod/' \
sed -i.bak 's/app: helloworld/app: prod/' \
$DEMO_HOME/kustomization.yaml
```
@@ -150,13 +150,13 @@ Off the shelf MySQL uses `emptyDir` type volume, which
gets wiped away if the MySQL Pod is recreated, and that
is certainly not desirable for production
environment. So we want to use Persistent Disk in
production. kustomize lets you apply `patches` to the
production. kustomize lets you apply `patchesStrategicMerge` to the
resources.
<!-- @createPatchFile @test -->
<!-- @createPatchFile @testAgainstLatestRelease -->
```
cat <<'EOF' > $DEMO_HOME/persistent-disk.yaml
apiVersion: apps/v1beta2 # for versions before 1.9.0 use apps/v1beta2
apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
name: mysql
@@ -173,14 +173,16 @@ EOF
Add the patch file to `kustomization.yaml`:
<!-- @specifyPatch @test -->
<!-- @specifyPatch @testAgainstLatestRelease -->
```
cat <<'EOF' >> $DEMO_HOME/kustomization.yaml
patches:
patchesStrategicMerge:
- persistent-disk.yaml
EOF
```
A `mysql-persistent-storage` persistent disk needs to exist for it to run successfully.
Lets break this down:
- In the first step, we created a YAML file named
@@ -188,7 +190,7 @@ Lets break this down:
in deployment.yaml
- Then we added `persistent-disk.yaml` to list of
`patches` in `kustomization.yaml`. `kustomize build`
`patchesStrategicMerge` in `kustomization.yaml`. `kustomize build`
will apply this patch to the deployment resource with
the name `mysql` as defined in the patch.
@@ -197,7 +199,7 @@ The output of the following command can now be applied
to the cluster (i.e. piped to `kubectl apply`) to
create the production environment.
<!-- @finalInflation @test -->
<!-- @finalInflation @testAgainstLatestRelease -->
```
kustomize build $DEMO_HOME # | kubectl apply -f -
```

View File

@@ -1,4 +1,4 @@
apiVersion: apps/v1beta2 # for versions before 1.9.0 use apps/v1beta2
apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
name: mysql

View File

@@ -2,7 +2,7 @@ apiVersion: v1
kind: Secret
metadata:
creationTimestamp: null
name: mysql-pass-d2gtcm2t2k
name: mysql-pass
type: Opaque
data:
# Default password is "admin".

View File

@@ -0,0 +1,218 @@
# Patching multiple resources at once.
kustomize supports patching via either a
[strategic merge patch] (wherein you
partially re-specify the thing you want to
modify, with in-place changes) or a
[JSON patch] (wherein you specify specific
operation/target/value tuples in a particular
syntax).
A kustomize file lets one specify many
patches. Each patch must be associated with
a _target selector_:
[strategic merge patch]: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-api-machinery/strategic-merge-patch.md
[json patch]: jsonpatch.md
> ```yaml
> patches:
> - path: <relative path to file containing patch>
> target:
> group: <optional group>
> version: <optional version>
> kind: <optional kind>
> name: <optional name>
> namespace: <optional namespace>
> labelSelector: <optional label selector>
> annotationSelector: <optional annotation selector>
> ```
E.g. select resources with _name_ matching `foo*`:
> ```yaml
> target:
> name: foo*
> ```
Select all resources of _kind_ `Deployment`:
> ```yaml
> target:
> kind: Deployment
> ```
[label/annotation selector rules]: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors
Using multiple fields just makes the target
more specific. The following selects only
Deployments that also have the _label_ `app=hello`
(full [label/annotation selector rules]):
> ```yaml
> target:
> kind: Deployment
> labelSelector: app=hello
> ```
### Demo
The example below shows how to inject a
sidecar container for multiple Deployment
resources.
Make a place to work:
<!-- @demoHome @testAgainstLatestRelease -->
```
DEMO_HOME=$(mktemp -d)
```
Make a file describing two Deployments:
<!-- @createDeployments @testAgainstLatestRelease -->
```
cat <<EOF >$DEMO_HOME/deployments.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy1
spec:
template:
metadata:
labels:
old-label: old-value
spec:
containers:
- name: nginx
image: nginx
args:
- one
- two
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy2
spec:
template:
metadata:
labels:
key: value
spec:
containers:
- name: busybox
image: busybox
EOF
```
Declare a [strategic merge patch] file
to inject a sidecar container:
<!-- @definePatch @testAgainstLatestRelease -->
```
cat <<EOF >$DEMO_HOME/patch.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: not-important
spec:
template:
spec:
containers:
- name: istio-proxy
image: docker.io/istio/proxyv2
args:
- proxy
- sidecar
EOF
```
Finally, define a kustomization file
that specifies both a `patches` and `resources`
entry:
<!-- @createKustomization @testAgainstLatestRelease -->
```
cat <<EOF >$DEMO_HOME/kustomization.yaml
resources:
- deployments.yaml
patches:
- path: patch.yaml
target:
kind: Deployment
EOF
```
The expected result is:
<!-- @definedExpectedOutput @testAgainstLatestRelease -->
```
cat <<EOF >$DEMO_HOME/out_expected.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy1
spec:
template:
metadata:
labels:
old-label: old-value
spec:
containers:
- args:
- proxy
- sidecar
image: docker.io/istio/proxyv2
name: istio-proxy
- args:
- one
- two
image: nginx
name: nginx
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy2
spec:
template:
metadata:
labels:
key: value
spec:
containers:
- args:
- proxy
- sidecar
image: docker.io/istio/proxyv2
name: istio-proxy
- image: busybox
name: busybox
EOF
```
Run the build:
<!-- @runIt @testAgainstLatestRelease -->
```
kustomize build $DEMO_HOME >$DEMO_HOME/out_actual.yaml
```
Confirm expectations:
<!-- @diffShouldExitZero @testAgainstLatestRelease -->
```
diff $DEMO_HOME/out_actual.yaml $DEMO_HOME/out_expected.yaml
```
To see how to do this with JSON patches,
try the [JSON patch] demo.

98
examples/remoteBuild.md Normal file
View File

@@ -0,0 +1,98 @@
# remote targets
`kustomize build` can be run on a URL.
A [lite version of go-getter module](https://github.com/yujunz/go-getter) is
leveraged to get remote content, then running `kustomize build` against the
desired directory in the local copy.
To try this immediately, run a build against the kustomization
in the [multibases](multibases/README.md) example. There's
one pod in the output:
<!-- @remoteOverlayBuild @testAgainstLatestRelease -->
```
target="github.com/kubernetes-sigs/kustomize/examples/multibases/dev/?ref=v1.0.6"
test 1 == \
$(kustomize build $target | grep dev-myapp-pod | wc -l); \
echo $?
```
Run against the overlay in that example to get three pods
(the overlay combines the dev, staging and prod bases for
someone who wants to send them all at the same time):
<!-- @remoteBuild @testAgainstLatestRelease -->
```
target="https://github.com/kubernetes-sigs/kustomize/examples/multibases?ref=v1.0.6"
test 3 == \
$(kustomize build $target | grep cluster-a-.*-myapp-pod | wc -l); \
echo $?
```
The URL can be an archive
<!-- @remoteBuild -->
```
target="https://github.com/kustless/kustomize-examples/archive/master.zip//kustomize-examples-master"
test 1 == \
$(kustomize build $target | grep remote-cm | wc -l); \
echo $?
```
Note the kustomize root path inside archive must be appended after `//`.
A base can be a URL:
<!-- @createOverlay @testAgainstLatestRelease -->
```
DEMO_HOME=$(mktemp -d)
cat <<EOF >$DEMO_HOME/kustomization.yaml
resources:
- github.com/kubernetes-sigs/kustomize/examples/multibases?ref=v1.0.6
namePrefix: remote-
EOF
```
Build this to confirm that all three pods from the base
have the `remote-` prefix.
<!-- @remoteBases @testAgainstLatestRelease -->
```
test 3 == \
$(kustomize build $DEMO_HOME | grep remote-.*-myapp-pod | wc -l); \
echo $?
```
## URL format
The url should follow
[hashicorp/go-getter URL format](https://github.com/hashicorp/go-getter#url-format).
Note that using `//` in the url will only copy the directory specified by the path
after `//`, which means some relative paths, like `../xxx`, may not work. Using `/` to copy
entire repo. For more details please see [go-getter documentation](https://github.com/hashicorp/go-getter#subdirectories).
Note that S3 and GCS are NOT supported to avoid introducing massive dependency.
Here are some example urls
<!-- @createOverlay @testAgainstLatestRelease -->
```
DEMO_HOME=$(mktemp -d)
cat <<'EOF' >$DEMO_HOME/kustomization.yaml
resources:
# a repo with a root level kustomization.yaml
- github.com/Liujingfang1/mysql
# a repo with a root level kustomization.yaml on branch test
- github.com/Liujingfang1/mysql?ref=test
# a subdirectory in a repo on branch repoUrl2
- github.com/Liujingfang1/kustomize/examples/helloWorld?ref=repoUrl2
# a subdirectory in a repo on commit `7050a45134e9848fca214ad7e7007e96e5042c03`
- github.com/Liujingfang1/kustomize/examples/helloWorld?ref=7050a45134e9848fca214ad7e7007e96e5042c03
# a subdirectory in a remote archive
- https://github.com/kustless/kustomize-examples/archive/master.zip//kustomize-examples-master
EOF
```

67
examples/replicas.md Normal file
View File

@@ -0,0 +1,67 @@
# Demo: change replicas
Define a place to work:
<!-- @makeWorkplace @testAgainstLatestRelease -->
```
DEMO_HOME=$(mktemp -d)
```
Make a `kustomization` containing a deployment resource with replicas
<!-- @createKustomization @testAgainstLatestRelease -->
```
cat <<EOF >$DEMO_HOME/kustomization.yaml
resources:
- deployment.yaml
replicas:
- name: myapp
count: 3
EOF
```
Declare the deployment resource
<!-- @createDeployment @testAgainstLatestRelease -->
```
cat <<EOF >$DEMO_HOME/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: myapp
name: myapp
spec:
replicas: 1
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: myapp-container
image: busybox:1.29.0
EOF
```
The `myapp` resource declares an deployment managing a pod running a busybox container.
Now build this `kustomization`
<!-- @kustomizeBuild @testAgainstLatestRelease -->
```
kustomize build $DEMO_HOME
```
Confirm that this replaces replicas for myapp:
<!-- @confirmImages @testAgainstLatestRelease -->
```
test 3 = \
$(kustomize build $DEMO_HOME | grep replicas | awk '{print $2}'); \
echo $?
```

View File

@@ -0,0 +1,221 @@
[ConfigMaps]: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.18/#configmap-v1-core
[ELF]: https://en.wikipedia.org/wiki/Executable_and_Linkable_Format
[Go plugin]: https://golang.org/pkg/plugin
[Secrets]: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.18/#secret-v1-core
[base64]: https://tools.ietf.org/html/rfc4648#section-4
[configuration directory]: https://wiki.archlinux.org/index.php/XDG_Base_Directory#Specification
[grpc]: https://grpc.io
[tag]: /../../releases
[v2.0.3]: /../../releases/tag/v2.0.3
[`exec.Command`]: https://golang.org/pkg/os/exec/#Command
# Generating Secrets
## What's a Secret?
Kubernetes [ConfigMaps] and [Secrets] are both
key:value maps, but the latter is intended to
signal that its values have a sensitive nature -
e.g. pass phrases or ssh keys.
Kubernetes developers work in various ways to hide
the information in a Secret more carefully than
the information held by ConfigMaps, Deployments,
etc.
## Make a place to work
<!-- @establishBase @testAgainstLatestRelease -->
```
DEMO_HOME=$(mktemp -d)
```
## Secret values from local files
kustomize has three different (builtin) ways to
generate a secret from local files:
* get them from so-called _env_ files (`NAME=VALUE`, one per line),
* consume the entire contents of a file to make one secret value,
* get literal values from the kustomization file itself.
Here's an example combining all three methods:
Make an env file with some short secrets:
<!-- @makeEnvFile @testAgainstLatestRelease -->
```
cat <<'EOF' >$DEMO_HOME/foo.env
ROUTER_PASSWORD=admin
DB_PASSWORD=iloveyou
EOF
```
Make a text file with a long secret:
<!-- @makeLongSecretFile @testAgainstLatestRelease -->
```
cat <<'EOF' >$DEMO_HOME/longsecret.txt
Lorem ipsum dolor sit amet,
consectetur adipiscing elit,
sed do eiusmod tempor incididunt
ut labore et dolore magna aliqua.
EOF
```
And make a kustomization file referring to the
above and _additionally_ defining some literal KV
pairs in line:
<!-- @makeKustomization1 @testAgainstLatestRelease -->
```
cat <<'EOF' >$DEMO_HOME/kustomization.yaml
secretGenerator:
- name: mysecrets
envs:
- foo.env
files:
- longsecret.txt
literals:
- FRUIT=apple
- VEGETABLE=carrot
EOF
```
Now generate the Secret:
<!-- @build1 @testAgainstLatestRelease -->
```
result=$(kustomize build $DEMO_HOME)
echo "$result"
# Spot check the result:
test 1 == $(echo "$result" | grep -c "FRUIT: YXBwbGU=")
```
This emits something like
> ```
> apiVersion: v1
> kind: Secret
> metadata:
> name: mysecrets-hfb5df789h
> type: Opaque
> data:
> FRUIT: YXBwbGU=
> VEGETABLE: Y2Fycm90
> ROUTER_PASSWORD: YWRtaW4=
> DB_PASSWORD: aWxvdmV5b3U=
> longsecret.txt: TG9yZW0gaXBzdW0gZG9sb3Igc2l0I... (elided)
> ```
The name of the resource is the prefix `mysecrets`
(as specfied in the kustomization file), followed
by a hash of its contents.
Use your favorite base64 decoder to confirm the raw
versions of any of these values.
The problem that these three approaches share is
that the purported secrets must live on disk.
This adds additional security questions - who can
see the files, who installs them, who deletes
them, etc.
## Secret values from anywhere
A general alternative is to enshrine secret
value generation in a [plugin](../docs/plugins).
The values can then come in via, say, an
authenticated and authorized RPC to a password
vault service.
[sgp]: ../plugin/someteam.example.com/v1/secretsfromdatabase
Here's a [secret generator plugin][sgp]
that pretends to pull the values of a map
from a database.
Download it
<!-- @copyPlugin @testAgainstLatestRelease -->
```
repo=https://raw.githubusercontent.com/kubernetes-sigs/kustomize
pPath=plugin/someteam.example.com/v1/secretsfromdatabase
dir=$DEMO_HOME/kustomize/$pPath
mkdir -p $dir
curl -s -o $dir/SecretsFromDatabase.go \
${repo}/master/$pPath/SecretsFromDatabase.go
```
Compile it
<!-- @compilePlugin @xtest -->
```
go build -buildmode plugin \
-o $dir/SecretsFromDatabase.so \
$dir/SecretsFromDatabase.go
```
Create a configuration file for it:
<!-- @makeConfiguration @testAgainstLatestRelease -->
```
cat <<'EOF' >$DEMO_HOME/secretFromDb.yaml
apiVersion: someteam.example.com/v1
kind: SecretsFromDatabase
metadata:
name: mySecretGenerator
name: forbiddenValues
namespace: production
keys:
- ROCKET
- VEGETABLE
EOF
```
Create a new kustomization file
referencing this plugin:
<!-- @makeKustomization2 @testAgainstLatestRelease -->
```
cat <<'EOF' >$DEMO_HOME/kustomization.yaml
generators:
- secretFromDb.yaml
EOF
```
Finally, generate the secret, setting
`XDG_CONFIG_HOME` so that the plugin
can be found under `$DEMO_HOME`:
<!-- @build2 @xtest -->
```
result=$( \
XDG_CONFIG_HOME=$DEMO_HOME \
kustomize build --enable_alpha_plugins $DEMO_HOME )
echo "$result"
# Spot check the result:
test 1 == $(echo "$result" | grep -c "FRUIT: YXBwbGU=")
```
This should emit something like:
> ```
> apiVersion: v1
> kind: Secret
> metadata:
> name: mysecrets-bdt27dbkd6
> type: Opaque
> data:
> FRUIT: YXBwbGU=
> VEGETABLE: Y2Fycm90
> ```
i.e. a subset of the same values as above.

View File

@@ -13,7 +13,7 @@ In the production environment we want to customize the following:
- health check and readiness check.
First make a place to work:
<!-- @makeDemoHome @test -->
<!-- @makeDemoHome @testAgainstLatestRelease -->
```
DEMO_HOME=$(mktemp -d)
```
@@ -27,7 +27,7 @@ as HERE documents.
Download them:
<!-- @downloadResources @test -->
<!-- @downloadResources @testAgainstLatestRelease -->
```
CONTENT="https://raw.githubusercontent.com\
/kubernetes-sigs/kustomize\
@@ -44,14 +44,14 @@ a file called `kustomization.yaml`.
Start this file:
<!-- @kustomizeYaml @test -->
<!-- @kustomizeYaml @testAgainstLatestRelease -->
```
touch $DEMO_HOME/kustomization.yaml
```
### Add the resources
<!-- @addResources @test -->
<!-- @addResources @testAgainstLatestRelease -->
```
cd $DEMO_HOME
@@ -71,7 +71,7 @@ cat kustomization.yaml
### Add configMap generator
<!-- @addConfigMap @test -->
<!-- @addConfigMap @testAgainstLatestRelease -->
```
echo "app.name=Kustomize Demo" >$DEMO_HOME/application.properties
@@ -102,10 +102,10 @@ For Spring Boot application, we can set an active profile through the environmen
the application will pick up an extra `application-<profile>.properties` file. With this, we can customize the configMap in two
steps. Add an environment variable through the patch and add a file to the configMap.
<!-- @customizeConfigMap @test -->
<!-- @customizeConfigMap @testAgainstLatestRelease -->
```
cat <<EOF >$DEMO_HOME/patch.yaml
apiVersion: apps/v1beta2
apiVersion: apps/v1
kind: Deployment
metadata:
name: sbdemo
@@ -119,7 +119,7 @@ spec:
value: prod
EOF
kustomize edit add patch patch.yaml
kustomize edit add patch --path patch.yaml --name sbdemo --kind Deployment --group apps --version v1
cat <<EOF >$DEMO_HOME/application-prod.properties
spring.jpa.hibernate.ddl-auto=update
@@ -149,7 +149,7 @@ Arrange for the resources to begin with prefix
_prod-_ (since they are meant for the _production_
environment):
<!-- @customizeLabel @test -->
<!-- @customizeLabel @testAgainstLatestRelease -->
```
cd $DEMO_HOME
kustomize edit set nameprefix 'prod-'
@@ -165,7 +165,7 @@ This `namePrefix` directive adds _prod-_ to all
resource names, as can be seen by building the
resources:
<!-- @build1 @test -->
<!-- @build1 @testAgainstLatestRelease -->
```
kustomize build $DEMO_HOME | grep prod-
```
@@ -180,7 +180,7 @@ selector.
add a label, but one can always edit
`kustomization.yaml` directly:
<!-- @customizeLabels @test -->
<!-- @customizeLabels @testAgainstLatestRelease -->
```
cat <<EOF >>$DEMO_HOME/kustomization.yaml
commonLabels:
@@ -191,7 +191,7 @@ EOF
Confirm that the resources now all have names prefixed
by `prod-` and the label tuple `env:prod`:
<!-- @build2 @test -->
<!-- @build2 @testAgainstLatestRelease -->
```
kustomize build $DEMO_HOME | grep -C 3 env
```
@@ -205,7 +205,7 @@ set JVM options accordingly.
Download the patch `memorylimit_patch.yaml`. It contains the memory limits setup.
<!-- @downloadPatch @test -->
<!-- @downloadPatch @testAgainstLatestRelease -->
```
curl -s -o "$DEMO_HOME/#1.yaml" \
"$CONTENT/overlays/production/{memorylimit_patch}.yaml"
@@ -216,7 +216,7 @@ cat $DEMO_HOME/memorylimit_patch.yaml
The output contains
> ```
> apiVersion: apps/v1beta2
> apiVersion: apps/v1
> kind: Deployment
> metadata:
> name: sbdemo
@@ -243,7 +243,7 @@ has end points such as `/actuator/health` for this. We can customize the k8s dep
Download the patch `healthcheck_patch.yaml`. It contains the liveness probes and readyness probes.
<!-- @downloadPatch @test -->
<!-- @downloadPatch @testAgainstLatestRelease -->
```
curl -s -o "$DEMO_HOME/#1.yaml" \
"$CONTENT/overlays/production/{healthcheck_patch}.yaml"
@@ -254,7 +254,7 @@ cat $DEMO_HOME/healthcheck_patch.yaml
The output contains
> ```
> apiVersion: apps/v1beta2
> apiVersion: apps/v1
> kind: Deployment
> metadata:
> name: sbdemo
@@ -281,27 +281,42 @@ The output contains
Add these patches to the kustomization:
<!-- @addPatch @test -->
<!-- @addPatch @testAgainstLatestRelease -->
```
cd $DEMO_HOME
kustomize edit add patch memorylimit_patch.yaml
kustomize edit add patch healthcheck_patch.yaml
kustomize edit add patch --path memorylimit_patch.yaml --name sbdemo --kind Deployment --group apps --version v1
kustomize edit add patch --path healthcheck_patch.yaml --name sbdemo --kind Deployment --group apps --version v1
```
`kustomization.yaml` should have patches field:
> ```
> patches:
> - patch.yaml
> - memorylimit_patch.yaml
> - healthcheck_patch.yaml
> - path: patch.yaml
> target:
> group: apps
> version: v1
> kind: Deployment
> name: sbdemo
> - path: memorylimit_patch.yaml
> target:
> group: apps
> version: v1
> kind: Deployment
> name: sbdemo
> - path: healthcheck_patch.yaml
> target:
> group: apps
> version: v1
> kind: Deployment
> name: sbdemo
> ```
The output of the following command can now be applied
to the cluster (i.e. piped to `kubectl apply`) to
create the production environment.
<!-- @finalBuild @test -->
<!-- @finalBuild @testAgainstLatestRelease -->
```
kustomize build $DEMO_HOME # | kubectl apply -f -
kustomize build $DEMO_HOME # | kubectl apply -f -
```

View File

@@ -1,4 +1,4 @@
apiVersion: apps/v1beta2
apiVersion: apps/v1
kind: Deployment
metadata:
name: sbdemo

View File

@@ -1,4 +1,4 @@
apiVersion: apps/v1beta2
apiVersion: apps/v1
kind: Deployment
metadata:
name: sbdemo

View File

@@ -1,6 +1,6 @@
bases:
resources:
- ../../base
patches:
patchesStrategicMerge:
- patch.yaml
- healthcheck_patch.yaml
- memorylimit_patch.yaml

View File

@@ -1,4 +1,4 @@
apiVersion: apps/v1beta2
apiVersion: apps/v1
kind: Deployment
metadata:
name: sbdemo

View File

@@ -1,4 +1,4 @@
bases:
resources:
- ../../base
namePrefix: staging-
configMapGenerator:

View File

@@ -0,0 +1,180 @@
# Transformer Configurations
Kustomize creates new resources by applying a series of transformations to an original
set of resources. Kustomize provides the following default transformers:
- annotations
- images
- labels
- name reference
- namespace
- prefix/suffix
- variable reference
A `fieldSpec` list, in a transformer's configuration, determines which resource types and which fields
within those types the transformer can modify.
## FieldSpec
FieldSpec is a type that represents a path to a field in one kind of resource.
```yaml
group: some-group
version: some-version
kind: some-kind
path: path/to/the/field
create: false
```
If `create` is set to `true`, the transformer creates the path to the field in the resource if the path is not already found. This is most useful for label and annotation transformers, where the path for labels or annotations may not be set before the transformation.
## Images transformer
The default images transformer updates the specified image key values found in paths that include
`containers` and `initcontainers` sub-paths.
If found, the `image` key value is customized by the values set in the `newName`, `newTag`, and `digest` fields.
The `name` field should match the `image` key value in a resource.
Example kustomization.yaml:
```yaml
images:
- name: postgres
newName: my-registry/my-postgres
newTag: v1
- name: nginx
newTag: 1.8.0
- name: my-demo-app
newName: my-app
- name: alpine
digest: sha256:25a0d4
```
Image transformer configurations can be customized by creating a list of `images` containing the `path` and `kind` fields.
The images transformation tutorial shows how to specify the default images transformer and customize the [images transformer configuration](images/README.md).
## Prefix/suffix transformer
The prefix/suffix transformer adds a prefix/suffix to the `metadata/name` field for all resources. Here is the default prefix transformer configuration:
```yaml
namePrefix:
- path: metadata/name
```
Example kustomization.yaml:
```yaml
namePrefix:
alices-
nameSuffix:
-v2
```
## Labels transformer
The labels transformer adds labels to the `metadata/labels` field for all resources. It also adds labels to the `spec/selector` field in all Service resources as well as the `spec/selector/matchLabels` field in all Deployment resources.
Example:
```yaml
commonLabels:
- path: metadata/labels
create: true
- path: spec/selector
create: true
version: v1
kind: Service
- path: spec/selector/matchLabels
create: true
kind: Deployment
```
Example kustomization.yaml:
```yaml
commonLabels:
someName: someValue
owner: alice
app: bingo
```
## Annotations transformer
The annotations transformer adds annotations to the `metadata/annotations` field for all resources.
Annotations are also added to `spec/template/metadata/annotations` for Deployment,
ReplicaSet, DaemonSet, StatefulSet, Job, and CronJob resources, and `spec/jobTemplate/spec/template/metadata/annotations`
for CronJob resources.
Example kustomization.yaml
```yaml
commonAnnotations:
oncallPager: 800-555-1212
```
## Name reference transformer
Name reference transformer's configuration is different from all other transformers. It contains a list of `nameReferences`, which represent all of the possible fields that a type could be used as a reference in other types of resources. A `nameReference` contains a type such as ConfigMap as well as a list of `fieldSpecs` where ConfigMap is referenced in other resources. Here is an example:
```yaml
kind: ConfigMap
version: v1
fieldSpecs:
- kind: Pod
version: v1
path: spec/volumes/configMap/name
- kind: Deployment
path: spec/template/spec/volumes/configMap/name
- kind: Job
path: spec/template/spec/volumes/configMap/name
```
Name reference transformer's configuration contains a list of `nameReferences` for resources such as ConfigMap, Secret, Service, Role, and ServiceAccount. Here is an example configuration:
```yaml
nameReference:
- kind: ConfigMap
version: v1
fieldSpecs:
- path: spec/volumes/configMap/name
version: v1
kind: Pod
- path: spec/containers/env/valueFrom/configMapKeyRef/name
version: v1
kind: Pod
# ...
- kind: Secret
version: v1
fieldSpecs:
- path: spec/volumes/secret/secretName
version: v1
kind: Pod
- path: spec/containers/env/valueFrom/secretKeyRef/name
version: v1
kind: Pod
```
## Customizing transformer configurations
In addition to the default transformers, you can create custom transformer configurations.
This tutorial shows how to create custom transformer configurations:
- [support a CRD type](crd/README.md)
- add extra fields for variable substitution
- add extra fields for name reference
## Supporting escape characters in CRD path
```yaml
metadata:
annotations:
foo.k8s.io/bar: baz
```
Kustomize supports escaping special characters in path, e.g `metadata/annotations/foo.k8s.io\/bar`

View File

@@ -0,0 +1,139 @@
## Supporting Custom Resources (defined by a CRD)
This tutorial shows how to add transformer configurations to support a custom resource.
Create a workspace by
<!-- @createws @testAgainstLatestRelease -->
```
DEMO_HOME=$(mktemp -d)
```
### Adding a custom resource
Consider a CRD of kind `MyKind` with fields
- `.spec.secretRef.name` reference a Secret
- `.spec.beeRef.name` reference an instance of CRD `Bee`
- `.spec.containers.command` as the list of container commands
- `.spec.selectors` as the label selectors
Add the following file to configure the transformers for the above fields
<!-- @addConfig @testAgainstLatestRelease -->
```
mkdir $DEMO_HOME/kustomizeconfig
cat > $DEMO_HOME/kustomizeconfig/mykind.yaml << EOF
commonLabels:
- path: spec/selectors
create: true
kind: MyKind
nameReference:
- kind: Bee
fieldSpecs:
- path: spec/beeRef/name
kind: MyKind
- kind: Secret
fieldSpecs:
- path: spec/secretRef/name
kind: MyKind
varReference:
- path: spec/containers/command
kind: MyKind
- path: spec/beeRef/action
kind: MyKind
EOF
```
### Apply config
Create a file with some resources that
includes an instance of `MyKind`:
<!-- @createResource @testAgainstLatestRelease -->
```
cat > $DEMO_HOME/resources.yaml << EOF
apiVersion: v1
kind: Secret
metadata:
name: crdsecret
data:
PATH: YmJiYmJiYmIK
---
apiVersion: v1beta1
kind: Bee
metadata:
name: bee
spec:
action: fly
---
apiVersion: jingfang.example.com/v1beta1
kind: MyKind
metadata:
name: mykind
spec:
secretRef:
name: crdsecret
beeRef:
name: bee
action: \$(BEE_ACTION)
containers:
- command:
- "echo"
- "\$(BEE_ACTION)"
image: myapp
EOF
```
Create a kustomization referring to it:
<!-- @createKustomization @testAgainstLatestRelease -->
```
cat > $DEMO_HOME/kustomization.yaml << EOF
resources:
- resources.yaml
namePrefix: test-
commonLabels:
foo: bar
vars:
- name: BEE_ACTION
objref:
kind: Bee
name: bee
apiVersion: v1beta1
fieldref:
fieldpath: spec.action
EOF
```
Use the customized transformer configurations by specifying them
in the kustomization file:
<!-- @addTransformerConfigs @testAgainstLatestRelease -->
```
cat >> $DEMO_HOME/kustomization.yaml << EOF
configurations:
- kustomizeconfig/mykind.yaml
EOF
```
Run `kustomize build` and verify that the namereference is correctly resolved.
<!-- @build @testAgainstLatestRelease -->
```
test 2 == \
$(kustomize build $DEMO_HOME | grep -A 2 ".*Ref" | grep "test-" | wc -l); \
echo $?
```
Run `kustomize build` and verify that the vars correctly resolved.
<!-- @verify @testAgainstLatestRelease -->
```
test 0 == \
$(kustomize build $DEMO_HOME | grep "BEE_ACTION" | wc -l); \
echo $?
```

View File

@@ -0,0 +1,16 @@
resources:
- resources.yaml
namePrefix: test-
commonLabels:
foo: bar
vars:
- name: BEE_ACTION
objref:
kind: Bee
name: bee
apiVersion: v1beta1
fieldref:
fieldpath: spec.action

View File

@@ -0,0 +1,29 @@
apiVersion: v1
kind: Secret
metadata:
name: crdsecret
data:
PATH: YmJiYmJiYmIK
---
apiVersion: v1beta1
kind: Bee
metadata:
name: bee
spec:
action: fly
---
apiVersion: jingfang.example.com/v1beta1
kind: MyKind
metadata:
name: mykind
spec:
secretRef:
name: crdsecret
beeRef:
name: bee
action: $(BEE_ACTION)
containers:
- command:
- "echo"
- "$(BEE_ACTION)"
image: myapp

View File

@@ -0,0 +1,128 @@
## Images transformations
This tutorial shows how to modify images in resources, and create a custom images transformer configuration.
Create a workspace by
<!-- @createws @testAgainstLatestRelease -->
```
DEMO_HOME=$(mktemp -d)
```
### Adding a custom resource
Consider a Custom Resource Definition(CRD) of kind `MyKind` with field
- `.spec.runLatest.container.image` referencing an image
Add the following file to configure the images transformer for the CRD:
<!-- @addConfig @testAgainstLatestRelease -->
```
mkdir $DEMO_HOME/kustomizeconfig
cat > $DEMO_HOME/kustomizeconfig/mykind.yaml << EOF
images:
- path: spec/runLatest/container/image
kind: MyKind
EOF
```
### Apply config
Create a file with some resources that includes an instance of `MyKind`:
<!-- @createResource @testAgainstLatestRelease -->
```
cat > $DEMO_HOME/resources.yaml << EOF
apiVersion: config/v1
kind: MyKind
metadata:
name: testSvc
spec:
runLatest:
container:
image: crd-image
containers:
- image: docker
name: ecosystem
- image: my-mysql
name: testing-1
---
group: apps
apiVersion: v1
kind: Deployment
metadata:
name: deploy1
spec:
template:
spec:
initContainers:
- name: nginx2
image: my-app
- name: init-alpine
image: alpine:1.8.0
EOF
```
Create a kustomization.yaml referring to it:
<!-- @createKustomization @testAgainstLatestRelease -->
```
cat > $DEMO_HOME/kustomization.yaml << EOF
resources:
- resources.yaml
images:
- name: crd-image
newName: new-crd-image
newTag: new-v1-tag
- name: my-app
newName: new-app-1
newTag: MYNEWTAG-1
- name: my-mysql
newName: prod-mysql
newTag: v3
- name: docker
newName: my-docker2
digest: sha256:25a0d4
EOF
```
Use the customized transformer configurations by specifying them
in the kustomization file:
<!-- @addTransformerConfigs @testAgainstLatestRelease -->
```
cat >> $DEMO_HOME/kustomization.yaml << EOF
configurations:
- kustomizeconfig/mykind.yaml
EOF
```
Run `kustomize build` and verify that the images have been updated.
<!-- @build @testAgainstLatestRelease -->
```
test 1 == \
$(kustomize build $DEMO_HOME | grep -A 2 ".*image" | grep "new-crd-image:new-v1-tag" | wc -l); \
echo $?
```
<!-- @build @testAgainstLatestRelease -->
```
test 1 == \
$(kustomize build $DEMO_HOME | grep -A 2 ".*image" | grep "new-app-1:MYNEWTAG-1" | wc -l); \
echo $?
```
<!-- @build @testAgainstLatestRelease -->
```
test 1 == \
$(kustomize build $DEMO_HOME | grep -A 2 ".*image" | grep "my-docker2@sha" | wc -l); \
echo $?
```
<!-- @build @testAgainstLatestRelease -->
```
test 1 == \
$(kustomize build $DEMO_HOME | grep -A 2 ".*image" | grep "prod-mysql:v3" | wc -l); \
echo $?
```

View File

@@ -0,0 +1,19 @@
resources:
- resources.yaml
configurations:
- kustomizeconfig/mykind.yaml
images:
- name: crd-image
newName: new-crd-image
newTag: new-v1-tag
- name: my-app
newName: new-app-1
newTag: MYNEWTAG-1
- name: my-mysql
newName: prod-mysql
newTag: v3
- name: docker
newName: my-docker2
digest: sha256:25a0d4

View File

@@ -0,0 +1,3 @@
images:
- path: spec/runLatest/container/image
kind: MyKind

View File

@@ -0,0 +1,27 @@
apiVersion: config/v1
kind: MyKind
metadata:
name: testSvc
spec:
runLatest:
container:
image: crd-image
containers:
- image: docker
name: ecosystem
- image: my-mysql
name: testing-1
---
group: apps
apiVersion: v1
kind: Deployment
metadata:
name: deploy1
spec:
template:
spec:
initContainers:
- name: nginx2
image: my-app
- name: init-alpine
image: alpine:1.8.0

View File

@@ -0,0 +1,221 @@
# a transformer plugin performing validation
[base]: ../../docs/glossary.md#base
[kubeval]: https://github.com/instrumenta/kubeval
[plugin]: ../../docs/plugins
kustomize doesn't validate either its input or
output beyond the validation provided by the
marshalling/unmarshalling packages it depends on.
Another tool, [kubeval], goes beyond this to do
k8s aware validation. Here's a usage example:
```shell
$ kubeval my-invalid-rc.yaml
The document my-invalid-rc.yaml contains an invalid ReplicationController
--> spec.replicas: Invalid type. Expected: integer, given: string
```
One can write a Kustomize transformer [plugin] to
run [kubeval] against the resources that have been
loaded by Kustomize.
Make a place to work:
<!-- @makeWorkplace @kubevalTest -->
```
DEMO_HOME=$(mktemp -d)
mkdir -p $DEMO_HOME/valid
mkdir -p $DEMO_HOME/invalid
PLUGINDIR=$DEMO_HOME/kustomize/plugin/someteam.example.com/v1/validator
mkdir -p $PLUGINDIR
```
## write a transformer plugin
Download the [kubeval] binary depending on the operating system
and add it to $PATH.
<!-- @downloadKubeval @kubevalTest -->
```
OS=`uname | sed -e 's/Linux/linux/' -e 's/Darwin/darwin/'`
wget https://github.com/instrumenta/kubeval/releases/download/0.9.2/kubeval-${OS}-amd64.tar.gz
tar xf kubeval-${OS}-amd64.tar.gz
export PATH=$PATH:`pwd`
```
Kustomize has the following assumption of a transformer plugin:
- The resources are passed to the transformer plugin from stdin.
- The configuration file for the transformer plugin is passed in
as the first argument.
- The working directory of the plugin is the kustomization
directory where it is used as a transformer.
- The transformed resources are written to stdout by the plugin.
- If the return code of the transformer plugin is non zero,
Kustomize regards there is an error during the transformation.
A transformer plugin for the validation can be written as a
bash script, which execute the [kubeval] binary and return proper
output and exit code.
<!-- @writePlugin @kubevalTest -->
```
cat <<'EOF' > $PLUGINDIR/Validator
#!/bin/bash
if ! [ -x "$(command -v kubeval)" ]; then
echo "Error: kubeval is not installed."
exit 1
fi
temp_file=$(mktemp)
output_file=$(mktemp)
cat - > $temp_file
kubeval $temp_file > $output_file
if [ $? -eq 0 ]; then
cat $temp_file
rm $temp_file $output_file
exit 0
fi
cat $output_file
rm $temp_file $output_file
exit 1
EOF
chmod +x $PLUGINDIR/Validator
```
## use the transformer plugin
Define a kustomization containing a valid ConfigMap
and the transformer plugin.
<!-- @writeKustomization @kubevalTest -->
```
cat <<'EOF' >$DEMO_HOME/valid/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: cm
data:
foo: bar
EOF
cat <<'EOF' >$DEMO_HOME/valid/validation.yaml
apiVersion: someteam.example.com/v1
kind: Validator
metadata:
name: notImportantHere
EOF
cat <<'EOF' >$DEMO_HOME/valid/kustomization.yaml
resources:
- configmap.yaml
transformers:
- validation.yaml
EOF
```
Define a kustomization containing an invalid ConfigMap
and the transformer plugin.
<!-- @writeKustomization @kubevalTest -->
```
cat <<'EOF' >$DEMO_HOME/invalid/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: cm
data:
- foo: bar
EOF
cat <<'EOF' >$DEMO_HOME/invalid/validation.yaml
apiVersion: someteam.example.com/v1
kind: Validator
metadata:
name: notImportantHere
EOF
cat <<'EOF' >$DEMO_HOME/invalid/kustomization.yaml
resources:
- configmap.yaml
transformers:
- validation.yaml
EOF
```
The directory structure is as the following:
```
/tmp/tmp.fAYMfLZJs4
├── invalid
│   ├── configmap.yaml
│   ├── kustomization.yaml
│   └── validation.yaml
├── kustomize
│   └── plugin
│   └── someteam.example.com
│   └── v1
│   ├── kubeval
│   └── Validator
└── valid
├── configmap.yaml
├── kustomization.yaml
└── validation.yaml
```
Define a helper function to run kustomize with the
correct environment and flags for plugins:
<!-- @defineKustomizeBd @kubevalTest -->
```
function kustomizeBd {
XDG_CONFIG_HOME=$DEMO_HOME \
kustomize build \
--enable_alpha_plugins \
$DEMO_HOME/$1
}
```
Build the valid variant
<!-- @buildValid @kubevalTest -->
```
kustomizeBd valid
```
The output contains a ConfigMap as
```yaml
apiVersion: v1
data:
foo: bar
kind: ConfigMap
metadata:
name: cm
```
Build the invalid variant
```
kustomizeBd invalid
```
The output is an error as
```shell
data: Invalid type. Expected: object, given: array
```
## cleanup
<!-- @cleanup @kubevalTest -->
```shell
rm -rf $DEMO_HOME
```

View File

@@ -0,0 +1,6 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: cm
data:
- foo: bar

View File

@@ -0,0 +1,6 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: cm
data:
foo: bar

224
examples/validatorPlugin.md Normal file
View File

@@ -0,0 +1,224 @@
# Examples for Validator Plugin
Previously, Kustomize suggested to used a transformer plugin to [perform validation](https://github.com/kubernetes-sigs/kustomize/tree/master/examples/validationTransformer). Now we introduce a new type of plugin: validator. As the name says, validator is used to validate the result YAML output. It works in the same way with *transformers* but cannot *modify* the input YAML content. Let's take a look at how it works.
## Make a Place to Work
<!-- @makeWorkplace @validatorPlugin -->
```
DEMO_HOME=$(mktemp -d)
mkdir -p $DEMO_HOME/valid
PLUGINDIR=$DEMO_HOME/kustomize/plugin/someteam.example.com/v1/validator
mkdir -p $PLUGINDIR
```
## Write a Validator Plugin
Kustomize has the following assumption of a validator plugin:
- The resources are passed to the validator plugin from stdin.
- The configuration file for the validator plugin is passed in
as the first argument.
- The working directory of the plugin is the kustomization
directory where it is used as a validator.
- The validated resources are written to stdout by the plugin. Or the validator can print nothing to the stdout if there is no need to change the input.
- Validator can **only** add a label named `validated-by` (case-sensitive) to the **top-level** resources. If there is any other modification in the validator, Kustomize will throw an error.
- If the return code of the transformer plugin is non zero,
Kustomize regards there is an error during the validation.
You can use either exec plugin or Go plugin as a validator. Here we use a bash script as an exec plugin.
<!-- @writePlugin @validatorPlugin -->
```bash
cat <<'EOF' > $PLUGINDIR/Validator
#!/bin/bash
# Do whatever you want here. In this example we
# just print out the input
cat
EOF
chmod +x $PLUGINDIR/Validator
```
## Use the Validator Plugin
Define a kustomization containing a valid ConfigMap
and the transformer plugin.
<!-- @writeKustomization @validatorPlugin -->
```bash
cat <<'EOF' >$DEMO_HOME/valid/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: cm
data:
foo: bar
EOF
cat <<'EOF' >$DEMO_HOME/valid/validator.yaml
apiVersion: someteam.example.com/v1
kind: Validator
metadata:
name: notImportantHere
EOF
cat <<'EOF' >$DEMO_HOME/valid/kustomization.yaml
resources:
- configmap.yaml
validators:
- validator.yaml
EOF
```
The directory structure is as the following:
```
/tmp/tmp.69tTCuXuYc
├── kustomize
│   └── plugin
│   └── someteam.example.com
│   └── v1
│   └── validator
│   └── Validator
└── valid
├── configmap.yaml
├── kustomization.yaml
└── validator.yaml
```
Define a helper function to run kustomize with the
correct environment and flags for plugins:
<!-- @defineKustomizeBd @validatorPlugin -->
```bash
function kustomizeBd {
XDG_CONFIG_HOME=$DEMO_HOME \
kustomize build \
--enable_alpha_plugins \
$DEMO_HOME/$1
}
```
Build the valid variant
<!-- @buildValid @validatorPlugin -->
```bash
kustomizeBd valid
```
The output contains a ConfigMap as
```yaml
apiVersion: v1
data:
foo: bar
kind: ConfigMap
metadata:
name: cm
```
### Validator Failure
Now lets try a failed validator
```bash
cat <<'EOF' > $PLUGINDIR/Validator
#!/bin/bash
# Non-zero indicates a failed validation
>&2 echo "Validation failed"
exit 1
EOF
chmod +x $PLUGINDIR/Validator
```
Build the valid variant
```bash
kustomizeBd valid
```
The output contains the error information that is printed to stderr
by validator.
```
Validation failed
Error: failure in plugin configured via /tmp/kust-plugin-config-369137659; exit status 1: exit status 1
```
### Input Modification
Typically a validator shouldn't modify the content to be validated. If it does, Kustomize will complain about it.
```bash
cat <<'EOF' > $PLUGINDIR/Validator
#!/bin/bash
# Modify the input content
sed 's/bar/baz/g'
EOF
chmod +x $PLUGINDIR/Validator
```
Then build
```
kustomizeBd valid
```
The error output will indicate you where is modified by the validator
```
Error: validator shouldn't modify the resource map: kunstruct not equal:
-- {"apiVersion":"v1","data":{"foo":"bar"},"kind":"ConfigMap","metadata":{"name":"cm"}}{nsfx:false,beh:unspecified},
-- {"apiVersion":"v1","data":{"foo":"baz"},"kind":"ConfigMap","metadata":{"name":"cm"}}{nsfx:false,beh:unspecified}
--
&resource.Resource{Kunstructured:(*kunstruct.UnstructAdapter)(0xc000118408), originalName:"cm", originalNs:"", options:(*types.GenArgs)(0xc00059e5e8), refBy:[]resid.ResId(nil), refVarNames:[]string(nil), namePrefixes:[]string{""}, nameSuffixes:[]string{""}}
------
&resource.Resource{Kunstructured:(*kunstruct.UnstructAdapter)(0xc000118510), originalName:"cm", originalNs:"", options:(*types.GenArgs)(0xc00059e5e8), refBy:[]resid.ResId(nil), refVarNames:[]string(nil), namePrefixes:[]string{""}, nameSuffixes:[]string{""}}
```
There is an exception that the validator can add a `validated-by` label to the **top** level resources.
<!-- @validatedByLabel @validatorPlugin -->
```bash
cat <<'EOF' > $PLUGINDIR/Validator
#!/usr/bin/bash
sed 's/^ name: cm$/ name: cm\n labels:\n validated-by: whatever/'
EOF
chmod +x $PLUGINDIR/Validator
```
Then build
<!-- @validatedByLabelBuild @validatorPlugin -->
```
kustomizeBd valid
```
The output will be
```yaml
apiVersion: v1
data:
foo: bar
kind: ConfigMap
metadata:
labels:
validated-by: whatever
name: cm
```
## cleanup
<!-- @cleanup @validatorPlugin -->
```
rm -rf $DEMO_HOME
```

405
examples/valueAdd.md Normal file
View File

@@ -0,0 +1,405 @@
# Simple addition of one string value
[DRY]: https://en.wikipedia.org/wiki/Don%27t_repeat_yourself
Suppose you have several distinct cloud _projects_
(on GCP or AWS or whatever) named:
* cat-111
* dog-222
* fox-333
These might be project names within the company,
cloud billing identifiers, or both.
Further suppose
* You want to deploy these projects to different
k8s namespaces, named after the projects.
* You need to specify the project name
in various resource subfields.
* You want to name the configuration
directories using the project name.
Additionally you might want to deploy the
projects one at a time, or all at once.
Ideally, you'll want to avoid specifying
the project name in more than one place
(i.e. you want to stay [DRY]).
Here's a possible layout:
> ```
> ├── all
> │ └── kustomization.yaml
>
> ├── bases
> │ └── iam-iap-tunnel
> │ ├── kustomization.yaml
> │ └── policymembers.yaml
>
> └── projects
> ├── cat-111
> │ └── kustomization.yaml
> ├── dog-222
> │ └── kustomization.yaml
> └── fox-333
> └── kustomization.yaml
> ```
This layout allows each project to be
individually buildable:
> ```
> kustomize build projects/cat-111
> kustomize build projects/dog-222
> kustomize build projects/fox-333
> ```
or collectively buildable:
> ```
> kustomize build all
> ```
-----
Make a place to work:
<!-- @makePlaceToWork @testAgainstLatestRelease -->
```
DEMO_HOME=$(mktemp -d)
```
<!-- @defineLayout @testAgainstLatestRelease -->
```
mkdir -p $DEMO_HOME/bases/iam-iap-tunnel
mkdir -p $DEMO_HOME/transformers/setProject
mkdir -p $DEMO_HOME/projects/cat-111
mkdir -p $DEMO_HOME/projects/dog-222
mkdir -p $DEMO_HOME/projects/fox-333
```
To ground this example with a common problem,
assume a set of engineers:
* red@example.com
* blue@example.com
* yellow@example.com
who need particular access to one or more projects.
Define an instance of `IAMCustomRole`:
<!-- @customRole @testAgainstLatestRelease -->
```
cat <<'EOF' >$DEMO_HOME/bases/iam-iap-tunnel/customroles.yaml
apiVersion: iam.cnrm.cloud.google.com/v1beta1
kind: IAMCustomRole
metadata:
name: engineer
spec:
title: Colorful Engineer
permissions:
- iap.tunnelInstances.accessViaIAP
stage: GA
EOF
```
Define corresponding instances of `IAMPolicyMember`.
The values in the `resourceRef/external` fields in these instances
are only partially complete. kustomize will add projectIds to
these below.
The boilerplate in these instances could be eliminated
by making a _custom generator_, but that's for
different tutorial, and with only three instances here
it's not worth it the effort.
<!-- @policyMembers @testAgainstLatestRelease -->
```
cat <<'EOF' >$DEMO_HOME/bases/iam-iap-tunnel/policymembers.yaml
apiVersion: iam.cnrm.cloud.google.com/v1beta1
kind: IAMPolicyMember
metadata:
name: iap-tunnel-red
spec:
member: user:red@example.com
role: roles/engineer
resourceRef:
apiVersion: resourcemanager.cnrm.cloud.google.com/v1beta1
kind: Project
external: projects
---
apiVersion: iam.cnrm.cloud.google.com/v1beta1
kind: IAMPolicyMember
metadata:
name: iap-tunnel-blue
spec:
member: user:blue@example.com
role: roles/engineer
resourceRef:
apiVersion: resourcemanager.cnrm.cloud.google.com/v1beta1
kind: Project
external: projects
---
apiVersion: iam.cnrm.cloud.google.com/v1beta1
kind: IAMPolicyMember
metadata:
name: iap-tunnel-yellow
spec:
member: user:yellow@example.com
role: roles/engineer
resourceRef:
apiVersion: resourcemanager.cnrm.cloud.google.com/v1beta1
kind: Project
external: projects
EOF
```
Make a base that combines these:
<!-- @makeBase @testAgainstLatestRelease -->
```
cat <<'EOF' >$DEMO_HOME/bases/iam-iap-tunnel/kustomization.yaml
resources:
- customroles.yaml
- policymembers.yaml
EOF
```
Make a transformer configuration file.
The transformer used is called `AddValueTransformer`. It's
intended to implement the 'add' operation of
[IETF RFC 6902 JSON]. The add operation is simple declaration
of what value to add, and a powerful syntax for specifying where
to add the value. The value can, for example, be inserted
into an existing field holding a file path as either a prefix,
a postfix, or some change
in the middle (e.g. `/volume/data` becomes `/volume/projectId/data`).
[IETF RFC 6902 JSON]: https://tools.ietf.org/html/rfc6902
At the time of writing, this transformer has no dedicated keyword
in the kustomization file to hold it's config. This means
the config must live in its own file:
<!-- @defineSetProjectTransformer @testAgainstLatestRelease -->
```
cat <<'EOF' >$DEMO_HOME/transformers/setProject/setProject.yaml
apiVersion: builtin
kind: ValueAddTransformer
metadata:
name: dirNameAdd
# Omitting the 'value:' field means that the current
# kustomization root directory name will be used as
# the value.
# value: not specified!
targets:
- fieldPath: metadata/namespace
- selector:
kind: IAMPolicyMember
fieldPath: spec/resourceRef/external
filePathPosition: 2
EOF
```
This file defined both the value to insert, and a list of places to
insert it. It's saying 1) _take the name of the directory I am in_ and
2) use the name as a namespace on all objects in scope, and 3) add that
name to the 2nd position in the file path found in the `spec/resourceRef/external`
field of all `IAMPolicyMember` instances.
To be used, this transformer config file must be referenced
from some kustomization file's `transformers:` field.
This field can contain a path directly to the transformer config file,
or a path to an encapsulating kustomization root. The latter approach
allows any number of transformers to be loaded as a group from a local
or remote location.
Here an example of the latter case that uses a kustomization file to
list pointers to transformer configs, although in this case it
references only one transformer config.
<!-- @makeTransformerDir @testAgainstLatestRelease -->
```
cat <<'EOF' >$DEMO_HOME/transformers/setProject/kustomization.yaml
resources:
- setProject.yaml
EOF
```
Now make the _cat_, _dog_ and _fox_ _variants_.
These are the targets that one could
independently apply to a cluster.
<!-- @defineCat @testAgainstLatestRelease -->
```
cat <<'EOF' >$DEMO_HOME/projects/cat-111/kustomization.yaml
resources:
- ../../bases/iam-iap-tunnel
transformers:
- ../../transformers/setProject
EOF
```
<!-- @defineDog @testAgainstLatestRelease -->
```
cat <<'EOF' >$DEMO_HOME/projects/dog-222/kustomization.yaml
resources:
- ../../bases/iam-iap-tunnel
transformers:
- ../../transformers/setProject
EOF
```
<!-- @defineFox @testAgainstLatestRelease -->
```
cat <<'EOF' >$DEMO_HOME/projects/fox-333/kustomization.yaml
resources:
- ../../bases/iam-iap-tunnel
transformers:
- ../../transformers/setProject
EOF
```
Then, optionally, a target to deploy all the projects at once:
<!-- @defineAllTarget @testAgainstLatestRelease -->
```
mkdir -p $DEMO_HOME/all
cat <<'EOF' >$DEMO_HOME/all/kustomization.yaml
resources:
- ../projects/cat-111
- ../projects/dog-222
- ../projects/fox-333
EOF
```
The layout is now:
<!-- @showLayout -->
```
tree $DEMO_HOME
```
It should look like:
> ```
> /tmp/someTmpDir
> ├── all
> │   └── kustomization.yaml
> ├── bases
> │   └── iam-iap-tunnel
> │   ├── customroles.yaml
> │   ├── kustomization.yaml
> │   └── policymembers.yaml
> ├── projects
> │   ├── cat-111
> │   │   └── kustomization.yaml
> │   ├── dog-222
> │   │   └── kustomization.yaml
> │   └── fox-333
> │   └── kustomization.yaml
> └── transformers
> └── setProject
> ├── kustomization.yaml
> └── setProject.yaml
> ```
The expected output from building the dog project
is as follows:
<!-- @definedExpectedOutput @testAgainstLatestRelease -->
```
cat <<EOF >$DEMO_HOME/out_expected.yaml
apiVersion: iam.cnrm.cloud.google.com/v1beta1
kind: IAMCustomRole
metadata:
name: engineer
namespace: dog-222
spec:
permissions:
- iap.tunnelInstances.accessViaIAP
stage: GA
title: Colorful Engineer
---
apiVersion: iam.cnrm.cloud.google.com/v1beta1
kind: IAMPolicyMember
metadata:
name: iap-tunnel-blue
namespace: dog-222
spec:
member: user:blue@example.com
resourceRef:
apiVersion: resourcemanager.cnrm.cloud.google.com/v1beta1
external: projects/dog-222
kind: Project
role: roles/engineer
---
apiVersion: iam.cnrm.cloud.google.com/v1beta1
kind: IAMPolicyMember
metadata:
name: iap-tunnel-red
namespace: dog-222
spec:
member: user:red@example.com
resourceRef:
apiVersion: resourcemanager.cnrm.cloud.google.com/v1beta1
external: projects/dog-222
kind: Project
role: roles/engineer
---
apiVersion: iam.cnrm.cloud.google.com/v1beta1
kind: IAMPolicyMember
metadata:
name: iap-tunnel-yellow
namespace: dog-222
spec:
member: user:yellow@example.com
resourceRef:
apiVersion: resourcemanager.cnrm.cloud.google.com/v1beta1
external: projects/dog-222
kind: Project
role: roles/engineer
EOF
```
In this output, the namespace of all instances is the
project name `dog-222`, and the project name also appears
in the resourceRef field of the `IAMPolicyMember` instances.
This project name only appears in the project _directory name_,
achieving our [DRY] goal.
Run the build:
<!-- @runIt @testAgainstLatestRelease -->
```
kustomize build $DEMO_HOME/projects/dog-222 >$DEMO_HOME/out_actual.yaml
```
and confirm that the actual output matches the expected output:
<!-- @diffShouldExitZero @testAgainstLatestRelease -->
```
diff $DEMO_HOME/out_actual.yaml $DEMO_HOME/out_expected.yaml
```
Build all the projects at once like this:
<!-- @buildAll @testAgainstLatestRelease -->
```
kustomize build $DEMO_HOME/all
```

View File

@@ -1,6 +1,6 @@
# Demo: Injecting k8s runtime data into containers
In this tutorial, you will learn how to use `kustomize` to declare a variable reference and substitute it in container's command.
In this tutorial, you will learn how to use `kustomize` to declare a variable reference and substitute it in container's command. Note that, the substitution is not for arbitrary fields, it is only applicable to container env, args and command.
To run WordPress, it's necessary to
@@ -8,7 +8,7 @@ To run WordPress, it's necessary to
- access the service name of MySQL database from WordPress container
First make a place to work:
<!-- @makeDemoHome @test -->
<!-- @makeDemoHome @testAgainstLatestRelease -->
```
DEMO_HOME=$(mktemp -d)
MYSQL_HOME=$DEMO_HOME/mysql
@@ -21,7 +21,7 @@ mkdir -p $WORDPRESS_HOME
Download the resources and `kustomization.yaml` for WordPress.
<!-- @downloadResources @test -->
<!-- @downloadResources @testAgainstLatestRelease -->
```
CONTENT="https://raw.githubusercontent.com\
/kubernetes-sigs/kustomize\
@@ -33,7 +33,7 @@ curl -s -o "$WORDPRESS_HOME/#1.yaml" \
Download the resources and `kustomization.yaml` for MySQL.
<!-- @downloadResources @test -->
<!-- @downloadResources @testAgainstLatestRelease -->
```
CONTENT="https://raw.githubusercontent.com\
/kubernetes-sigs/kustomize\
@@ -44,15 +44,19 @@ curl -s -o "$MYSQL_HOME/#1.yaml" \
```
### Create kustomization.yaml
Create a new kustomization with two bases:
<!-- @createKustomization @test -->
Create a new kustomization with two bases,
`wordpress` and `mysql`:
<!-- @createKustomization @testAgainstLatestRelease -->
```
cat <<EOF >$DEMO_HOME/kustomization.yaml
bases:
- wordpress
- mysql
resources:
- wordpress
- mysql
namePrefix: demo-
patchesStrategicMerge:
- patch.yaml
EOF
```
@@ -61,18 +65,18 @@ In the new kustomization, apply a patch for wordpress deployment. The patch does
- Add an initial container to show the mysql service name
- Add environment variable that allow wordpress to find the mysql database
<!-- @downloadPatch @test -->
<!-- @downloadPatch @testAgainstLatestRelease -->
```
CONTENT="https://raw.githubusercontent.com\
/kubernetes-sigs/kustomize\
/master/examples/patch.yaml"
/master/examples/wordpress"
curl -s -o "$DEMO_HOME/#1.yaml" \
"$CONTENT/{patch}.yaml"
```
The patch has following content
> ```
> apiVersion: apps/v1beta2
> apiVersion: apps/v1
> kind: Deployment
> metadata:
> name: wordpress
@@ -82,9 +86,8 @@ The patch has following content
> initContainers:
> - name: init-command
> image: debian
> command:
> - "echo $(WORDPRESS_SERVICE)"
> - "echo $(MYSQL_SERVICE)"
> command: ["/bin/sh"]
> args: ["-c", "echo $(WORDPRESS_SERVICE); echo $(MYSQL_SERVICE)"]
> containers:
> - name: wordpress
> env:
@@ -101,7 +104,7 @@ $(WORDPRESS_SERVICE) and $(MYSQL_SERVICE).
### Bind the Variables to k8s Object Fields
<!-- @addVarRef @test -->
<!-- @addVarRef @testAgainstLatestRelease -->
```
cat <<EOF >>$DEMO_HOME/kustomization.yaml
vars:
@@ -124,7 +127,7 @@ EOF
### Substitution
Confirm the variable substitution:
<!-- @kustomizeBuild @test -->
<!-- @kustomizeBuild @testAgainstLatestRelease -->
```
kustomize build $DEMO_HOME
```
@@ -134,11 +137,13 @@ Expect this in the output:
> ```
> (truncated)
> ...
> initContainers:
> - command:
> - echo demo-wordpress
> - echo demo-mysql
> image: debian
> name: init-command
> initContainers:
> - args:
> - -c
> - echo demo-wordpress; echo demo-mysql
> command:
> - /bin/sh
> image: debian
> name: init-command
>
> ```
> ```

View File

@@ -1,19 +1,19 @@
bases:
- wordpress
- mysql
patches:
- patch.yaml
resources:
- wordpress
- mysql
patchesStrategicMerge:
- patch.yaml
namePrefix: demo-
vars:
- name: WORDPRESS_SERVICE
objref:
kind: Service
name: wordpress
apiVersion: v1
- name: MYSQL_SERVICE
objref:
kind: Service
name: mysql
apiVersion: v1
- name: WORDPRESS_SERVICE
objref:
kind: Service
name: wordpress
apiVersion: v1
- name: MYSQL_SERVICE
objref:
kind: Service
name: mysql
apiVersion: v1

View File

@@ -1,4 +1,4 @@
apiVersion: apps/v1beta2 # for versions before 1.9.0 use apps/v1beta2
apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
name: mysql

View File

@@ -1,4 +1,4 @@
apiVersion: apps/v1beta2
apiVersion: apps/v1
kind: Deployment
metadata:
name: wordpress
@@ -8,9 +8,8 @@ spec:
initContainers:
- name: init-command
image: debian
command:
- "echo $(WORDPRESS_SERVICE)"
- "echo $(MYSQL_SERVICE)"
command: ["/bin/sh"]
args: ["-c", "echo $(WORDPRESS_SERVICE); echo $(MYSQL_SERVICE)"]
containers:
- name: wordpress
env:

View File

@@ -1,4 +1,4 @@
apiVersion: apps/v1beta2 # for versions before 1.9.0 use apps/v1beta2
apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
name: wordpress

61
examples/zh/README.md Normal file
View File

@@ -0,0 +1,61 @@
[English](../README.md) | 简体中文
# 示例
这些示例默认 `kustomize` 在您的 `$PATH` 中。
这些示例通过了 [pre-commit](../../hack/testExamplesAgainstKustomize.sh) 测试,并且应该与 HEAD 一起使用。
```
go get sigs.k8s.io/kustomize/v3/cmd/kustomize
```
基本用法
* [configGenerations](configGeneration.md) - 当 ConfigMapGenerator 修改时进行滚动更新。
* [combineConfigs](combineConfigs.md) - 融合来自不同用户的配置数据(例如来自 devops/SRE 和 developers
* [generatorOptions](generatorOptions.md) -修改所有 ConfigMapGenerator 和 SecretGenerator 的行为。
* [vars](vars.md) - 通过 vars 将一个资源的数据注入另一个资源的容器参数 (例如,为 wordpress 指定 SQL 服务)。
* [image names and tags](image.md) - 在不使用 patch 的情况下更新镜像名称和标签。
* [remote target](remoteBuild.md) - 通过 github URL 来构建 kustomization 。
* [json patch](jsonpatch.md) -在 kustomization 中应用 json patch 。
* [patch multiple objects](patchMultipleObjects.md) - 通过一个patch来修改多个资源。
高级用法
- generator 插件:
* [last mile helm](chart.md) - 对 helm chart 进行 last mile 修改。
* [secret generation](secretGeneratorPlugin.md) - 生成 Secret。
- transformer 插件:
* [validation transformer](validationTransformer.md) - 通过 transformer 验证资源。
- 定制内建 transformer 配置
* [transformer configs](transformerconfigs.md) - 自定义 transformer 配置。
多 Variant 示例
* [hello world](helloWorld.md) - 部署多个不同配置的 Hello World 服务。
* [LDAP](ldap.md) - 部署多个配置不同的 LDAP 服务。
* [springboot](springboot.md) - 从头开始创建一个 Spring Boot 项目的生产配置。
* [mySql](mysql.md) - 从头开始创建一个 MySQL 的生产配置。
* [breakfast](breakfast.md) - 给 Alice 和 Bob 定制一顿早餐 :)
* [multibases](multibases.md) - 使用相同的 base 生成三个 variantsdevstagingproduction
>声明:部分文档可能稍微滞后于英文版本,同步工作持续进行中

118
examples/zh/breakfast.md Normal file
View File

@@ -0,0 +1,118 @@
[kubernetes API 对象样式]: https://kubernetes.io/docs/concepts/overview/working-with-objects/kubernetes-objects/#required-fields
[variant]: ../../docs/glossary.md#variant
# 示例:早餐配置
定义一个工作空间:
<!-- @makeWorkplace @testAgainstLatestRelease -->
```
DEMO_HOME=$(mktemp -d)
```
创建目录用于存放早餐的 base 配置:
<!-- @baseDir @testAgainstLatestRelease -->
```
mkdir -p $DEMO_HOME/breakfast/base
```
创建一个 `kustomization` 来定义早餐所需的食物。包含咖啡和薄煎饼:
<!-- @baseKustomization @testAgainstLatestRelease -->
```
cat <<EOF >$DEMO_HOME/breakfast/base/kustomization.yaml
resources:
- coffee.yaml
- pancakes.yaml
EOF
```
这里有一个 _coffee_ 类型。定义`kind``metdata/name` 字段以符合 [kubernetes API 对象样式],不需要其他文件或定义:
<!-- @coffee @testAgainstLatestRelease -->
```
cat <<EOF >$DEMO_HOME/breakfast/base/coffee.yaml
kind: Coffee
metadata:
name: morningCup
temperature: lukewarm
data:
greeting: "Good Morning!"
EOF
```
`name` 字段仅将这种咖啡实例与其他实例(如果有的话)区分开
同样,定义 _pancakes_
<!-- @pancakes @testAgainstLatestRelease -->
```
cat <<EOF >$DEMO_HOME/breakfast/base/pancakes.yaml
kind: Pancakes
metadata:
name: comfort
stacksize: 3
topping: none
EOF
```
为喜欢热咖啡的 Alice 定制她的早餐:
<!-- @aliceOverlay @testAgainstLatestRelease -->
```
mkdir -p $DEMO_HOME/breakfast/overlays/alice
cat <<EOF >$DEMO_HOME/breakfast/overlays/alice/kustomization.yaml
commonLabels:
who: alice
resources:
- ../../base
patchesStrategicMerge:
- temperature.yaml
EOF
cat <<EOF >$DEMO_HOME/breakfast/overlays/alice/temperature.yaml
kind: Coffee
metadata:
name: morningCup
temperature: hot!
EOF
```
同样的Bob 想要 _5_ 块薄煎饼和草莓:
<!-- @bobOverlay @testAgainstLatestRelease -->
```
mkdir -p $DEMO_HOME/breakfast/overlays/bob
cat <<EOF >$DEMO_HOME/breakfast/overlays/bob/kustomization.yaml
commonLabels:
who: bob
resources:
- ../../base
patchesStrategicMerge:
- topping.yaml
EOF
cat <<EOF >$DEMO_HOME/breakfast/overlays/bob/topping.yaml
kind: Pancakes
metadata:
name: comfort
stacksize: 5
topping: strawberries
EOF
```
现在,可以为 Alice 的早餐生成配置了:
<!-- @generateAlice @testAgainstLatestRelease -->
```
kustomize build $DEMO_HOME/breakfast/overlays/alice
```
同样的,也为 Bob 的早餐生成配置:
<!-- @generateBob @testAgainstLatestRelease -->
```
kustomize build $DEMO_HOME/breakfast/overlays/bob
```

215
examples/zh/chart.md Normal file
View File

@@ -0,0 +1,215 @@
# 使用 kustomize 对 helm charts 进行修改
[last mile]: https://testingclouds.wordpress.com/2018/07/20/844/
[stable chart]: https://github.com/helm/charts/tree/master/stable
[Helm charts]: https://github.com/helm/charts
[_minecraft_]: https://github.com/helm/charts/tree/master/stable/minecraft
[插件]: ../../docs/plugins
kustomize 并不会读取 [Helm charts] ,但可以使用 generator 来访问 [Helm charts] 。
使用 [last mile] 模式来结合 kustomize 和 helm ,使用一个 inflated chart 作为基础,然后使用 kustomize 在部署到集群的途中进行修改。
以下示例中使用的 generator 仅适用于 [stable chart] 仓库中的 chart。该示例虽然使用 [_minecraft_] ,但可以应用于任何 chart。
假设 `helm` 已在你的 `$PATH` 中,建立一个工作空间:
<!-- @makeWorkplace @test -->
```bash
DEMO_HOME=$(mktemp -d)
mkdir -p $DEMO_HOME/base
mkdir -p $DEMO_HOME/dev
mkdir -p $DEMO_HOME/prod
```
## 使用远程 chart
定义 _development_ variant环境
这可能涉及许多 kustomizations参见其他示例但在本示例中`dev-` 名称前缀添加到所有资源:
<!-- @writeKustDev @test -->
```bash
cat <<'EOF' >$DEMO_HOME/dev/kustomization.yaml
namePrefix: dev-
resources:
- ../base
EOF
```
同上,使用 `namePrefix: prod-` 定义生产 variant
<!-- @writeKustProd @test -->
```bash
cat <<'EOF' >$DEMO_HOME/prod/kustomization.yaml
namePrefix: prod-
resources:
- ../base
EOF
```
这两个 variants 指向同一个 base。
定义这个 base
<!-- @writeKustDev @test -->
```bash
cat <<'EOF' >$DEMO_HOME/base/kustomization.yaml
generators:
- chartInflator.yaml
EOF
```
base 指向一个名为 `chartInflator.yaml` 的生成配置文件。
此文件允许指定 [stable chart] 的名称及其他内容,例如 values 文件的路径,默认为 `values.yaml`
创建配置文件 `chartInflator.yaml`,指定 chart 名称为 _minecraft_
<!-- @writeGeneratorConfig @test -->
```bash
cat <<'EOF' >$DEMO_HOME/base/chartInflator.yaml
apiVersion: someteam.example.com/v1
kind: ChartInflator
metadata:
name: notImportantHere
chartName: minecraft
EOF
```
因为这个特定的 YAML 文件列在 kustomization文件的 `generators:` 字段中,所以它被视为生成器插件(由 _apiVersion__kind_ 字段标识)与配置插件的其他字段之间的绑定。
将插件下载到 `DEMO_HOME` 并赋予其执行权限:
<!-- @installPlugin @test -->
```bash
plugin=plugin/someteam.example.com/v1/chartinflator/ChartInflator
curl -s --create-dirs -o \
"$DEMO_HOME/kustomize/$plugin" \
"https://raw.githubusercontent.com/\
kubernetes-sigs/kustomize/master/$plugin"
chmod a+x $DEMO_HOME/kustomize/$plugin
```
检查目录布局:
<!-- @tree -->
```bash
tree $DEMO_HOME
```
将会得倒类似的目录及文件:
> ```bash
> /tmp/whatever
> ├── base
> │   ├── chartInflator.yaml
> │   └── kustomization.yaml
> ├── dev
> │   └── kustomization.yaml
> ├── kustomize
> │   └── plugin
> │   └── someteam.example.com
> │   └── v1
> │   └── chartinflator
> │   └── ChartInflator
> └── prod
> └── kustomization.yaml
> ```
运行 kustomize 定义一个 helper function 来传入正确的环境和常见标志:
<!-- @defineKustomizeIt @test -->
```
function kustomizeIt {
XDG_CONFIG_HOME=$DEMO_HOME \
kustomize build --enable_alpha_plugins \
$DEMO_HOME/$1
}
```
最终构建 `prod` variant。这里要注意的是所有资源名称现在都具有 `prod-` 前缀:
<!-- @doProd @test -->
```bash
clear
kustomizeIt prod
```
比较 `dev``prod`
<!-- @doCompare -->
```bash
diff <(kustomizeIt dev) <(kustomizeIt prod) | more
```
在 base上 运行 kustomize 查看未修改但已展开的 chart。
这里的每次调用都是重新下载并重新展开 chart。
<!-- @showBase @test -->
```bash
kustomizeIt base
```
## 使用本地 chart
上面的示例由于未在配置中指定本地 chart 的主目录所以kustomize会取得远程chart的副本并存在临时目录中。
要禁止 fetch请明确指定 `charHome` 并确保chart 已经被保存在该目录下
要进行演示,并且不会干扰您现有的 helm 环境,请执行以下操作:
<!-- @helmInit @test -->
```bash
helmHome=$DEMO_HOME/dothelm
chartHome=$DEMO_HOME/base/charts
function doHelm {
helm --home $helmHome $@
}
# 在新位置创建 helm 配置文件。
# 初始化命令比较复杂
doHelm init --client-only >& /dev/null
```
现在下载 chart 可以再次使用的 [_minecraft_] (也可以使用其他的 chart
<!-- @fetchChart @test -->
```bash
doHelm fetch --untar \
--untardir $chartHome \
stable/minecraft
```
使用 tree 查看更多信息helm 配置数据和完整的 chart 副本:
<!-- @tree -->
```bash
tree $DEMO_HOME
```
`chartHome` 字段添加到生成器的配置文件中,以便可以查找本地 chart
<!-- @modifyGenConfig @test -->
```bash
echo "chartHome: $chartHome" >>$DEMO_HOME/base/chartInflator.yaml
```
更改 values 文件,用来展示本地 chart 的更改:
<!-- @valueChange @test -->
```
sed -i 's/CHANGEME!/SOMETHINGELSE/' $chartHome/minecraft/values.yaml
sed -i 's/LoadBalancer/NodePort/' $chartHome/minecraft/values.yaml
```
最后进行构建:
<!-- @finalProd @test -->
```bash
kustomizeIt prod
```
观察结果中 `LoadBalancer` 变为 `NodePort`,并且加密的密码也有所不同。

View File

@@ -0,0 +1,230 @@
[overlay]: ../docs/glossary.md#overlay
[target]: ../docs/glossary.md#target
# 示例devops和开发配合管理配置数据
场景:在生产环境中有一个基于 Java 由多个内部团队(注册、结账和搜索等)共同开发的商店服务。
这个服务在不同的环境中运行_development_、 _testing__staging__production_,从 Java 的 properties 文件中读取配置。
为每个环境维护一个大的 properties 文件是很困难的。这个文件需要频繁的修改,并且这些修改都需要由 devops 工程师来进行,因为:
1. 这个文件包含 devops 工程师需要知道,而开发人员不必知道的值
2. 比如生产环境的 properties 包含敏感数据,比如生产数据库的登录凭据。
## Property sharding
通过一些研究,我们注意到属性可以分为不同的类别。
### Property sharding
例如:国际化数据、物理常量,外部服务位置等静态数据。
_这些无论哪个环境,都一样的配置。_
这些都只需要一组配置。将这组配置放在一个文件中:
* `common.properties`
### Plumbing properties
例如静态资源HTML、CSS、JavaScript的位置产品和用户的数据表负载均衡的端口日志收集等。
_这些属性的不同,恰恰是环境的不同之处。_
DevOps 或 SRE 工程师需要完全控制生产环境中的这些配置;测试需要调整数据库来支持测试;而开发则希望尝试开发中遇到的各种不同的情景。
将这些值放入
* `development/plumbing.properties`
* `staging/plumbing.properties`
* `production/plumbing.properties`
### Secret properties
例如:用户表的位置、数据库凭证、解密密钥等。
_这些需要 devops 工程师控制,其他人没有访问权限。_
将这些值放入
* `development/secret.properties`
* `staging/secret.properties`
* `production/secret.properties`
[kubernetes secret]: https://kubernetes.io/docs/tasks/inject-data-application/distribute-credentials-secure/
例如使用 unix 文件权限和模式来限制访问控制,或者使用更好的方法-使用专门用于存储密码的服务,并且使用 kustomize 中的 `secretGenerator` 字段在 Kubernetes 中创建 secret 来存储密码。
<!--
secretGenerator:
- name: app-tls
files:
tls.crt=tls.cert
tls.key=tls.key
type: "kubernetes.io/tls"
EOF
-->
## 混合管理方法
基于相同的 base 创建 _n_ 个 overlays 来创建 _n_ 个集群环境的方法。
在本例的其余部分,我们将使用 _n==2_,这里只使用 _development__production_ ,可以使用相同的方法来增加更多的环境。
运行 `kustomize build` 基于 [overlay] 的 [target] 来创建集群环境。
[helloworld]: helloWorld.md
以下示例将执行此操作,但将侧重于 configMap 构建,而不用担心如何将 configMaps 关联到 Deployment[helloworld] 示例中介绍的)。
所有文件(包括共享 property 文件)都将在目录树中创建,目录中包含 base 和 overlay 文件的目录,这些都与 [helloworld] 中演示的一致。
它将全部存在于此工作目录中:
<!-- @makeWorkplace @test -->
```bash
DEMO_HOME=$(mktemp -d)
```
### 创建 base
<!-- kubectl create configmap BOB --dry-run -o yaml --from-file db. -->
创建放置 base 配置的路径:
<!-- @baseDir @test -->
```bash
mkdir -p $DEMO_HOME/base
```
向 base 中的插入数据base 中应该包含所有环境共有的资源,这里我们只定义一个 java properties 文件,以及一个引用他们的 `kustomization` 文件。
<!-- @baseKustomization @test -->
```bash
cat <<EOF >$DEMO_HOME/base/common.properties
color=blue
height=10m
EOF
cat <<EOF >$DEMO_HOME/base/kustomization.yaml
configMapGenerator:
- name: my-configmap
files:
- common.properties
EOF
```
### 创建并使用 overlay 用于 _开发_
创建一个 overlays 目录:
<!-- @overlays @test -->
```bash
OVERLAYS=$DEMO_HOME/overlays
```
创建 _development_ overlay
<!-- @developmentFiles @test -->
```bash
mkdir -p $OVERLAYS/development
cat <<EOF >$OVERLAYS/development/plumbing.properties
port=30000
EOF
cat <<EOF >$OVERLAYS/development/secret.properties
dbpassword=mothersMaidenName
EOF
cat <<EOF >$OVERLAYS/development/kustomization.yaml
resources:
- ../../base
namePrefix: dev-
nameSuffix: -v1
configMapGenerator:
- name: my-configmap
behavior: merge
files:
- plumbing.properties
- secret.properties
EOF
```
现在可以生成开发使用的 configMaps
<!-- @runDev @test -->
```bash
kustomize build $OVERLAYS/development
```
#### 检查 ConfigMap 名称
可以在输出中看到生成的 `ConfigMap` 名称。
名称应该是这样的:`dev-my-configmap-v1-2gccmccgd5`
* `"dev-"` 来自 `namePrefix` 字段
* `"my-configmap"` 来自 `configMapGenerator/name` 字段
* `"-v1"` 来自 `nameSuffix` 字段
* `"-2gccmccgd5"` 为哈希值,是 `kustomize` 根据 configMap 的内容计算的
哈希后缀很关键,如果 configMap 内容发生变化, configMap 的名称也会发生变化,以及从 `kustomize` 出现在 YAML 输出中的对该名称的所有引用。
名称更改意味着如果使用类似命令将此 YAML 应用于群集,则 Deployment 将执行滚动更新重启以获取新数据。
> ```bash
> kustomize build $OVERLAYS/development | kubectl apply -f -
> ```
Deployment 无法自动检测 ConfigMap 是否发生改变。
如果更改 configMap 的数据, 而不更改其名称以及对该名称的所有引用, 则必须重新启动Deployment中的那些Pods以获取更改。
最佳的做法就是将 configMap 视为不变的。
不去编辑 configMap ,而是使用 __ 的名称的 __ configMap并在 Deployment 中引用新的 configMap 。而 `kustomize` 使用 `configMapGenerator` 指令和相关的命名控件使这很容易。
### 创建并且使用 overlay 用于 _生产_
接下来创建 _production_ overlay 的文件:
<!-- @productionFiles @test -->
```bash
mkdir -p $OVERLAYS/production
cat <<EOF >$OVERLAYS/production/plumbing.properties
port=8080
EOF
cat <<EOF >$OVERLAYS/production/secret.properties
dbpassword=thisShouldProbablyBeInASecretInstead
EOF
cat <<EOF >$OVERLAYS/production/kustomization.yaml
resources:
- ../../base
namePrefix: prod-
configMapGenerator:
- name: my-configmap
behavior: merge
files:
- plumbing.properties
- secret.properties
EOF
```
现在可以生成用于生产的 configMap
<!-- @runProd @test -->
```bash
kustomize build $OVERLAYS/production
```
可以直接在 CI/CD 流程中执行如下命令,将应用部署到集群:
> ```bash
> kustomize build $OVERLAYS/production | kubectl apply -f -
> ```

View File

@@ -0,0 +1,197 @@
[patch]: ../../docs/glossary.md#patch
[resource]: ../../docs/glossary.md#resource
[variant]: ../../docs/glossary.md#variant
## ConfigMap 的生成和滚动更新
kustomize 提供了两种添加 ConfigMap 的方法:
- 将 ConfigMap 声明为 [resource]
- 通过 ConfigMapGenerator 声明 ConfigMap
`kustomization.yaml` 中,这两种方法的格式分别如下:
> ```
> # 将 ConfigMap 声明为 resource
> resources:
> - configmap.yaml
>
> # 在 ConfigMapGenerator 中声明 ConfigMap
> configMapGenerator:
> - name: a-configmap
> files:
> - configs/configfile
> - configs/another_configfile
> ```
声明为 [resource] 的 ConfigMaps 的处理方式与其他 resource 相同Kustomize 不会在为 ConfigMap 的名称添加哈希后缀。而在 ConfigMapGenerator 中声明 ConfigMap 的处理方式则与之前不同默认将为名称添加哈希后缀ConfigMap 中的任何更改都将触发滚动更新。
在 [hello_world](helloWorld.md) 示例中,使用 ConfigmapGenerator 来替换将 ConfigMap 声明为 [resource] 的方法。由此生成的 ConfigMap 中的更改将导致哈希值更改和滚动更新。
### 建立 base 和 staging
使用 configMapGenerator 建立 base
<!-- @establishBase @testAgainstLatestRelease -->
```
DEMO_HOME=$(mktemp -d)
BASE=$DEMO_HOME/base
mkdir -p $BASE
curl -s -o "$BASE/#1.yaml" "https://raw.githubusercontent.com\
/kubernetes-sigs/kustomize\
/master/examples/helloWorld\
/{deployment,service}.yaml"
cat <<'EOF' >$BASE/kustomization.yaml
commonLabels:
app: hello
resources:
- deployment.yaml
- service.yaml
configMapGenerator:
- name: the-map
literals:
- altGreeting=Good Morning!
- enableRisky="false"
EOF
```
通过应用 ConfigMap patch 的方式建立 staging
<!-- @establishStaging @testAgainstLatestRelease -->
```
OVERLAYS=$DEMO_HOME/overlays
mkdir -p $OVERLAYS/staging
cat <<'EOF' >$OVERLAYS/staging/kustomization.yaml
namePrefix: staging-
nameSuffix: -v1
commonLabels:
variant: staging
org: acmeCorporation
commonAnnotations:
note: Hello, I am staging!
resources:
- ../../base
patchesStrategicMerge:
- map.yaml
EOF
cat <<EOF >$OVERLAYS/staging/map.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: the-map
data:
altGreeting: "Have a pineapple!"
enableRisky: "true"
EOF
```
### Review
在集群中运行的 _hello-world_ 的 deployment 配置了来自 configMap 的数据。
deployment 按照名称引用此 ConfigMap
<!-- @showDeployment @testAgainstLatestRelease -->
```
grep -C 2 configMapKeyRef $BASE/deployment.yaml
```
当 ConfigMap 中的数据需要更新时,更改群集中的实时 ConfigMap 的数据并不是一个好的做法。 由于 Deployment 无法知道其引用的 ConfigMap 已更改,这类更新是无效。
更改 Deployment 配置的推荐方法是:
1. 使用新名称创建一个新的 configMap
2. 为*deployment* 添加 patch修改相应 `configMapKeyRef` 字段的名称值。
后一种更改会启动对 deployment 中的 pod 的滚动更新。旧的 configMap 在不再被任何其他资源引用时最终会被[垃圾回收](/../../issues/242)。
### 如何使用 kustomize
_staging_ 的 [variant] 包含一个 configMap 的 [patch]
<!-- @showMapPatch @testAgainstLatestRelease -->
```
cat $OVERLAYS/staging/map.yaml
```
根据定义,此 patch 是一个命名但不一定是完整的资源规范,旨在修改完整的资源规范。
在 ConfigMapGenerator 中声明 ConfigMap 的修改。
<!-- @showMapBase @testAgainstLatestRelease -->
```
grep -C 4 configMapGenerator $BASE/kustomization.yaml
```
要使这个 patch 正常工作,`metadata/name` 字段中的名称必须匹配。
但是文件中指定的名称值不是群集中使用的名称值。根据设计kustomize 修改从 ConfigMapGenerator 声明的 ConfigMaps 的名称。要查看最终在群集中使用的名称,只需运行 kustomize
<!-- @grepStagingName @testAgainstLatestRelease -->
```
kustomize build $OVERLAYS/staging |\
grep -B 8 -A 1 staging-the-map
```
根据 `$OVERLAYS/staging/kustomization.yaml` 中的 `namePrefix` 字段configMap 名称以 _staging-_ 为前缀。
根据 `$OVERLAYS/staging/kustomization.yaml` 中的 `nameSuffix` 字段configMap 名称以 _-v1_ 为后缀。
configMap 名称的后缀是由 map 内容的哈希生成的 - 在这种情况下,名称后缀是 _5276h4th55_
<!-- @grepStagingHash @testAgainstLatestRelease -->
```
kustomize build $OVERLAYS/staging | grep 5276h4th55
```
现在修改 map patch ,更改该服务将使用的问候消息:
<!-- @changeMap @testAgainstLatestRelease -->
```
sed -i.bak 's/pineapple/kiwi/' $OVERLAYS/staging/map.yaml
```
查看新的问候消息:
```
kustomize build $OVERLAYS/staging |\
grep -B 2 -A 3 kiwi
```
再次运行 kustomize 查看新的 configMap 名称:
<!-- @grepStagingName @testAgainstLatestRelease -->
```
kustomize build $OVERLAYS/staging |\
grep -B 8 -A 1 staging-the-map
```
确认 configMap 内容的更改将会生成以 _c2g8fcbf88_ 结尾的三个新名称 - 一个在 configMap 的名称中,另两个在使用 ConfigMap 的 deployment 中:
<!-- @countHashes @testAgainstLatestRelease -->
```
test 3 == \
$(kustomize build $OVERLAYS/staging | grep c2g8fcbf88 | wc -l); \
echo $?
```
将这些资源应用于群集将导致 deployment pod 的滚动更新,将它们从 _5276h4th55_ map 重新定位到 _c2g8fcbf88_ map 。系统稍后将垃圾收集未使用的 map。
## 回滚
回滚,可以撤消对源码配置所做的任何编辑,然后在还原的配置上重新运行 kustomize 并将其应用于群集。

View File

@@ -0,0 +1,60 @@
# Generator Options
Kustomize 提供了修改 ConfigMapGenerator 和 SecretGenerator 行为的选项,这些选项包括:
- 不再将基于内容生成的哈希后缀添加到资源名称后
- 为生成的资源添加 labels
- 为生成的资源添加 annotations
这个示例将展示如何运用这些选项,首先创建一个工作空间:
```bash
DEMO_HOME=$(mktemp -d)
```
创建 kustomization 并且为其添加一个 ConfigMapGenerator
<!-- @createCMGenerator @test -->
```bash
cat > $DEMO_HOME/kustomization.yaml << EOF
configMapGenerator:
- name: my-configmap
literals:
- foo=bar
- baz=qux
EOF
```
添加如下 generatorOptions
<!-- @addGeneratorOptions @test -->
```bash
cat >> $DEMO_HOME/kustomization.yaml << EOF
generatorOptions:
disableNameSuffixHash: true
labels:
kustomize.generated.resource: somevalue
annotations:
annotations.only.for.generated: othervalue
EOF
```
运行 `kustomize build` 并且确定生成的 ConfigMap 。
- 确定没有名称后缀
<!-- @verify @test -->
```
test 1 == \
$(kustomize build $DEMO_HOME | grep "name: my-configmap$" | wc -l); \
echo $?
```
- 确定 label `kustomize.generated.resource: somevalue`
```
test 1 == \
$(kustomize build $DEMO_HOME | grep -A 1 "labels" | grep "kustomize.generated.resource" | wc -l); \
echo $?
```
- 确定 annotation `annotations.only.for.generated: othervalue`
```
test 1 == \
$(kustomize build $DEMO_HOME | grep -A 1 "annotations" | grep "annotations.only.for.generated" | wc -l); \
echo $?
```

301
examples/zh/helloWorld.md Normal file
View File

@@ -0,0 +1,301 @@
[base]: ../../docs/glossary.md#base
[config]: https://github.com/kubernetes-sigs/kustomize/tree/master/examples/helloWorld
[gitops]: ../../docs/glossary.md#gitops
[hello]: https://github.com/monopole/hello
[kustomization]: ../../docs/glossary.md#kustomization
[original]: https://github.com/kubernetes-sigs/kustomize/tree/master/examples/helloWorld
[overlay]: ../../docs/glossary.md#overlay
[overlays]: ../../docs/glossary.md#overlay
[patch]: ../../docs/glossary.md#patch
[variant]: ../../docs/glossary.md#variant
[variants]: ../../docs/glossary.md#variant
# Demo: hello world with variants
步骤:
1. 下载 [base] 配置。
2. 进行定制。
3. 基于定制后的 base 新建2个不同的 [overlays] (_staging_ 和 _production_)。
4. 运行 kustomize 和 kubectl 来部署 staging 和 production 。
首先创建一个工作空间:
<!-- @makeWorkplace @testAgainstLatestRelease -->
```
DEMO_HOME=$(mktemp -d)
```
或者:
> ```
> DEMO_HOME=~/hello
> ```
## 创建 base
如果要使用 [overlays] 创建 [variants] ,必须先创建一个共同的 [base] 。
为了使本文档保持简洁base 的资源位于补充目录中,并不在此处,请按照下面的方法下载它们:
<!-- @downloadBase @testAgainstLatestRelease -->
```
BASE=$DEMO_HOME/base
mkdir -p $BASE
curl -s -o "$BASE/#1.yaml" "https://raw.githubusercontent.com\
/kubernetes-sigs/kustomize\
/master/examples/helloWorld\
/{configMap,deployment,kustomization,service}.yaml"
```
观察该目录:
<!-- @runTree -->
```
tree $DEMO_HOME
```
可以看到:
> ```
> /tmp/tmp.IyYQQlHaJP
> └── base
> ├── configMap.yaml
> ├── deployment.yaml
> ├── kustomization.yaml
> └── service.yaml
> ```
这些 resources 可以立即在 k8s 集群中部署:
> ```
> kubectl apply -f $DEMO_HOME/base
> ```
实例化 _hello_ 服务, `kubectl` 只能识别 resources 文件。
### The Base Kustomization
`base` 目录中包含一个 [kustomization] 文件:
<!-- @showKustomization @testAgainstLatestRelease -->
```
more $BASE/kustomization.yaml
```
(可选)在 base 目录上运行 `kustomize` 将定制过的 resources 打印到标准输出:
<!-- @buildBase @testAgainstLatestRelease -->
```
kustomize build $BASE
```
### 定制 base
定制 _app label_ 并应用于所有的 resources
<!-- @addLabel @testAgainstLatestRelease -->
```
sed -i.bak 's/app: hello/app: my-hello/' \
$BASE/kustomization.yaml
```
查看效果:
<!-- @checkLabel @testAgainstLatestRelease -->
```
kustomize build $BASE | grep -C 3 app:
```
## 创建 Overlays
创建包含 _staging__production_ 的 [overlay]
* _Staging_ 包含生产环境中无法应用的带有风险的功能。
* _Production_ 包含更多的副本数。
* 来自这些集群 [variants] 的问候消息将与来自其他集群的不同。
<!-- @overlayDirectories @testAgainstLatestRelease -->
```
OVERLAYS=$DEMO_HOME/overlays
mkdir -p $OVERLAYS/staging
mkdir -p $OVERLAYS/production
```
#### Staging Kustomization
`staging` 目录中创建一个 kustomization 文件,用来定义一个新的名称前缀和一些不同的 labels 。
<!-- @makeStagingKustomization @testAgainstLatestRelease -->
```
cat <<'EOF' >$OVERLAYS/staging/kustomization.yaml
namePrefix: staging-
commonLabels:
variant: staging
org: acmeCorporation
commonAnnotations:
note: Hello, I am staging!
resources:
- ../../base
patchesStrategicMerge:
- map.yaml
EOF
```
#### Staging Patch
新增一个自定义的 configMap 将问候消息从 _Good Morning!_ 改为 _Have a pineapple!_
同时,将 _risky_ 标记设置为 true 。
<!-- @stagingMap @testAgainstLatestRelease -->
```
cat <<EOF >$OVERLAYS/staging/map.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: the-map
data:
altGreeting: "Have a pineapple!"
enableRisky: "true"
EOF
```
#### Production Kustomization
`production` 目录中创建一个 kustomization 文件,用来定义一个新的名称前缀和 labels 。
<!-- @makeProductionKustomization @testAgainstLatestRelease -->
```
cat <<EOF >$OVERLAYS/production/kustomization.yaml
namePrefix: production-
commonLabels:
variant: production
org: acmeCorporation
commonAnnotations:
note: Hello, I am production!
resources:
- ../../base
patchesStrategicMerge:
- deployment.yaml
EOF
```
#### Production Patch
因为生产环境需要处理更多的流量,新建一个 production patch 来增加副本数。
<!-- @productionDeployment @testAgainstLatestRelease -->
```
cat <<EOF >$OVERLAYS/production/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: the-deployment
spec:
replicas: 10
EOF
```
## 比较 overlays
`DEMO_HOME` 现在包含:
- _base_ 目录:对拉取到的源配置进行了简单定制
- _overlays_ 目录:包含在集群中创建不同 _staging__production_ [variants] 的 kustomizations 和 patches 。
查看目录结构和差异:
<!-- @listFiles -->
```
tree $DEMO_HOME
```
可以看到:
> ```
> /tmp/tmp.IyYQQlHaJP1
> ├── base
> │   ├── configMap.yaml
> │   ├── deployment.yaml
> │   ├── kustomization.yaml
> │   └── service.yaml
> └── overlays
> ├── production
> │   ├── deployment.yaml
> │   └── kustomization.yaml
> └── staging
> ├── kustomization.yaml
> └── map.yaml
> ```
直接比较 _staging__production_ 输出的不同:
<!-- @compareOutput -->
```
diff \
<(kustomize build $OVERLAYS/staging) \
<(kustomize build $OVERLAYS/production) |\
more
```
部分比较输出:
> ```diff
> < altGreeting: Have a pineapple!
> < enableRisky: "true"
> ---
> > altGreeting: Good Morning!
> > enableRisky: "false"
> 8c8
> < note: Hello, I am staging!
> ---
> > note: Hello, I am production!
> 11c11
> < variant: staging
> ---
> > variant: production
> 13c13
> (...truncated)
> ```
## 部署
输出不同 _overlys_ 的配置:
<!-- @buildStaging @testAgainstLatestRelease -->
```
kustomize build $OVERLAYS/staging
```
<!-- @buildProduction @testAgainstLatestRelease -->
```
kustomize build $OVERLAYS/production
```
将上述命令传递给 kubectl 进行部署:
> ```
> kustomize build $OVERLAYS/staging |\
> kubectl apply -f -
> ```
> ```
> kustomize build $OVERLAYS/production |\
> kubectl apply -f -
> ```
也可使用 `kubectl` (v1.14.0 以上版本)
> ```
> kubectl apply -k $OVERLAYS/staging
> ```
> ```
> kubectl apply -k $OVERLAYS/production
> ```

74
examples/zh/image.md Normal file
View File

@@ -0,0 +1,74 @@
# 示例: 改变镜像名称和标签
首先构建一个工作空间:
<!-- @makeWorkplace @testAgainstLatestRelease -->
```bash
DEMO_HOME=$(mktemp -d)
```
创建包含pod资源的 `kustomization`
<!-- @testAgainstLatestRelease to @test -->
```bash
cat <<EOF >$DEMO_HOME/kustomization.yaml
resources:
- pod.yaml
EOF
```
创建 pod 资源pod.yaml
<!-- @createDeployment @test -->
```bash
cat <<EOF >$DEMO_HOME/pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
spec:
containers:
- name: myapp-container
image: busybox:1.29.0
command: ['sh', '-c', 'echo The app is running! && sleep 3600']
initContainers:
- name: init-mydb
image: busybox:1.29.0
command: ['sh', '-c', 'until nslookup mydb; do echo waiting for mydb; sleep 2; done;']
EOF
```
`myapp-pod` 包含一个init容器和一个普通容器两者都使用 `busybox1.29.0` 镜像。
`kustomization.yaml` 中添加 `images` 字段来更改镜像 `busybox` 和标签 `1.29.0`
- 通过 `kustomize` 添加 `images`
<!-- @addImages @test -->
```bash
cd $DEMO_HOME
kustomize edit set image busybox=alpine:3.6
```
- 将`images`字段将被添加到`kustomization.yaml`
> ```yaml
> images:
> - name: busybox
> newName: alpine
> newTag: 3.6
> ```
构建 `kustomization`
<!-- @kustomizeBuild @testAgainstLatestRelease -->
```bash
kustomize build $DEMO_HOME
```
确认`busybox`镜像和标签是否被替换为`alpine3.6`
<!-- @confirmImages @testAgainstLatestRelease -->
```
test 2 = \
$(kustomize build $DEMO_HOME | grep alpine:3.6 | wc -l); \
echo $?
```

124
examples/zh/jsonpatch.md Normal file
View File

@@ -0,0 +1,124 @@
# 示例: 应用 json patchjson补丁
kustomization文件支持通过[JSON patches](https://tools.ietf.org/html/rfc6902)来修改已有的资源.
下面的例子将会使用这个功能对`Ingress`加以修改.
首先,创建一个包含`ingress``kustomization`文件.
<!-- @createIngress @testAgainstLatestRelease -->
```bash
DEMO_HOME=$(mktemp -d)
cat <<EOF >$DEMO_HOME/kustomization.yaml
resources:
- ingress.yaml
EOF
cat <<EOF >$DEMO_HOME/ingress.yaml
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: my-ingress
spec:
rules:
- host: foo.bar.com
http:
paths:
- backend:
serviceName: my-api
servicePort: 80
EOF
```
定义一个JSON patch文件以更新`Ingress`对象的2个字段:
- 把 host 从 `foo.bar.com` 改为 `foo.bar.io`
- 把 servicePort 从 `80` 改为 `8080`
<!-- @addJsonPatch @testAgainstLatestRelease -->
```bash
cat <<EOF >$DEMO_HOME/ingress_patch.json
[
{"op": "replace", "path": "/spec/rules/0/host", "value": "foo.bar.io"},
{"op": "replace", "path": "/spec/rules/0/http/paths/0/backend/servicePort", "value": 8080}
]
EOF
```
JSON patch 也可以写成 YAML 的格式.该例子顺便展示了“添加”操作:
<!-- @addYamlPatch @testAgainstLatestRelease -->
```bash
cat <<EOF >$DEMO_HOME/ingress_patch.yaml
- op: replace
path: /spec/rules/0/host
value: foo.bar.io
- op: add
path: /spec/rules/0/http/paths/-
value:
path: '/test'
backend:
serviceName: my-test
servicePort: 8081
EOF
```
在kustomization.yaml文件中增加 _patchesJson6902_ 字段,以应用该补丁
<!-- @applyJsonPatch @testAgainstLatestRelease -->
```bash
cat <<EOF >>$DEMO_HOME/kustomization.yaml
patchesJson6902:
- target:
group: networking.k8s.io
version: v1beta1
kind: Ingress
name: my-ingress
path: ingress_patch.json
EOF
```
运行 `kustomize build $DEMO_HOME`, 在输出那里确认 host 已经被正确更新.
<!-- @confirmHost @testAgainstLatestRelease -->
```bash
test 1 == \
$(kustomize build $DEMO_HOME | grep "host: foo.bar.io" | wc -l); \
echo $?
```
运行 `kustomize build $DEMO_HOME`, 在输出那里确认 servicePort 已经被正确更新.
<!-- @confirmServicePort @testAgainstLatestRelease -->
```bash
test 1 == \
$(kustomize build $DEMO_HOME | grep "servicePort: 8080" | wc -l); \
echo $?
```
如果 patch 是YAML格式的就能正确解析:
<!-- @applyYamlPatch @testAgainstLatestRelease -->
```bash
cat <<EOF >>$DEMO_HOME/kustomization.yaml
patchesJson6902:
- target:
group: networking.k8s.io
version: v1beta1
kind: Ingress
name: my-ingress
path: ingress_patch.yaml
EOF
```
运行 `kustomize build $DEMO_HOME`, 在输出那里确认有 `/test` 这个路径.
<!-- @confirmYamlPatch @testAgainstLatestRelease -->
```bash
test 1 == \
$(kustomize build $DEMO_HOME | grep "path: /test" | wc -l); \
echo $?
```

269
examples/zh/ldap.md Normal file
View File

@@ -0,0 +1,269 @@
[base]: ../../docs/glossary.md#base
[gitops]: ../../docs/glossary.md#gitops
[kustomization]: ../../docs/glossary.md#kustomization
[overlay]: ../../docs/glossary.md#overlay
[overlays]: ../../docs/glossary.md#overlay
[variant]: ../../docs/glossary.md#variant
[variants]: ../../docs/glossary.md#variant
# 示例LDAP 服务
步骤:
1. 拉取已经存在的 [base] 配置
2. 进行配置
3. 基于 [base] 创建2个不同的 [overlays] (_staging_ 和 _production_)
4. 运行 kustomize 或 kubectl 部署 staging 和 production
首先创建一个工作空间:
<!-- @makeWorkplace @testAgainstLatestRelease -->
```
DEMO_HOME=$(mktemp -d)
```
或者
> ```
> DEMO_HOME=~/ldap
> ```
## 创建 base
要使用 [overlays] 创建 [variant],首先需要创建一个 [base]。
为了保证文档的精简,基础资源都在补充目录中,如果需要请下载它们:
<!-- @downloadBase @testAgainstLatestRelease -->
```
BASE=$DEMO_HOME/base
mkdir -p $BASE
CONTENT="https://raw.githubusercontent.com\
/kubernetes-sigs/kustomize\
/master/examples/ldap"
curl -s -o "$BASE/#1" "$CONTENT/base\
/{deployment.yaml,kustomization.yaml,service.yaml,env.startup.txt}"
```
检查这个目录:
<!-- @runTree -->
```
tree $DEMO_HOME
```
将会看到如下文件:
> ```
> /tmp/tmp.IyYQQlHaJP
> └── base
> ├── deployment.yaml
> ├── env.startup.txt
> ├── kustomization.yaml
> └── service.yaml
> ```
这些资源可以由 kubectl 立刻部署到集群上来实例化 _ldap_ 服务:
> ```
> kubectl apply -f $DEMO_HOME/base
> ```
注意 `kubectl -f` 只能识别 k8s 资源文件。
### The Base Kustomization
`base` 目录包含一个 [kustomization] 文件:
<!-- @showKustomization @testAgainstLatestRelease -->
```
more $BASE/kustomization.yaml
```
(可选)在 base 上运行 `kustomize`,并将结果打印到标准输出:
<!-- @buildBase @testAgainstLatestRelease -->
```
kustomize build $BASE
```
### Customize the base
为所有资源设置名称前缀:
<!-- @namePrefix @testAgainstLatestRelease -->
```
cd $BASE
kustomize edit set nameprefix "my-"
```
查看变化:
<!-- @checkNameprefix @testAgainstLatestRelease -->
```
kustomize build $BASE | grep -C 3 "my-"
```
## 创建 Overlays
创建 _staging__production_ 的 [overlay]:
*_Staging_ 新增一个 ConfigMap
*_Production_ 添加持久化存储盘和更多的副本数
* 现实两个 [variants] 的不同之处
<!-- @overlayDirectories @testAgainstLatestRelease -->
```
OVERLAYS=$DEMO_HOME/overlays
mkdir -p $OVERLAYS/staging
mkdir -p $OVERLAYS/production
```
#### Staging Kustomization
下载 staging 配置
<!-- @downloadStagingKustomization @testAgainstLatestRelease -->
```
curl -s -o "$OVERLAYS/staging/#1" "$CONTENT/overlays/staging\
/{config.env,deployment.yaml,kustomization.yaml}"
```
在 staging 配置中增加一个 ConfigMap
> ```cat $OVERLAYS/staging/kustomization.yaml
> (...truncated)
> configMapGenerator:
> - name: env-config
> files:
> - config.env
> ```
和2个副本
> ```cat $OVERLAYS/staging/deployment.yaml
> apiVersion: apps/v1
> kind: Deployment
> metadata:
> name: ldap
> spec:
> replicas: 2
> ```
#### Production Kustomization
下载 production 配置
<!-- @downloadProductionKustomization @testAgainstLatestRelease -->
```
curl -s -o "$OVERLAYS/production/#1" "$CONTENT/overlays/production\
/{deployment.yaml,kustomization.yaml}"
```
在 production 的配置中增加为6副本和存储盘
> ```cat $OVERLAYS/production/deployment.yaml
> apiVersion: apps/v1
> kind: Deployment
> metadata:
> name: ldap
> spec:
> replicas: 6
> template:
> spec:
> volumes:
> - name: ldap-data
> emptyDir: null
> gcePersistentDisk:
> pdName: ldap-persistent-storage
> ```
## 比较 overlays
`DEMO_HOME` 现在包括:
* 一个 _base_ 目录:对拉取原始配置进行少量的定制
* 一个 _overlays_ 目录:其中包含在集群中创建不同的 _staging__production_ [variants] 所需的 kustomizations 文件和 patche 文件
查看目录结构和差异:
<!-- @listFiles -->
```
tree $DEMO_HOME
```
将会得到类似的内容:
> ```
> /tmp/tmp.IyYQQlHaJP1
> ├── base
> │   ├── deployment.yaml
> │   ├── env.startup.txt
> │   ├── kustomization.yaml
> │   └── service.yaml
> └── overlays
> ├── production
> │   ├── deployment.yaml
> │   └── kustomization.yaml
> └── staging
> ├── config.env
> ├── deployment.yaml
> └── kustomization.yaml
> ```
直接对输出内容进行比较,以查看 _staging__production_ 的不同之处:
<!-- @compareOutput -->
```
diff \
<(kustomize build $OVERLAYS/staging) \
<(kustomize build $OVERLAYS/production) |\
more
```
输出的差异内容
> ```diff
> (...truncated)
> < name: staging-my-ldap-configmap-kftftt474h
> ---
> > name: production-my-ldap-configmap-k27f7hkg4f
> 85c75
> < name: staging-my-ldap-service
> ---
> > name: production-my-ldap-service
> 97c87
> < name: staging-my-ldap
> ---
> > name: production-my-ldap
> 99c89
> < replicas: 2
> ---
> > replicas: 6
> (...truncated)
> ```
## 部署
查看各个资源集:
<!-- @buildStaging @testAgainstLatestRelease -->
```
kustomize build $OVERLAYS/staging
```
<!-- @buildProduction @testAgainstLatestRelease -->
```
kustomize build $OVERLAYS/production
```
将上述命令通过管道传递给 kubectl 以进行部署:
> ```
> kustomize build $OVERLAYS/staging |\
> kubectl apply -f -
> ```
> ```
> kustomize build $OVERLAYS/production |\
> kubectl apply -f -
> ```

View File

@@ -0,0 +1,113 @@
# 示例:使用通用的 base 应用多 namespace
`kustomize` 支持基于同一base具有不同 namespace 的多个 variants。
只需将 overlay 作为新的 kustomization 的 base就可以创建一个额外的 overlay 将这些 variants 组合在一起。下面使用一个 pod 作为 base 来进行演示。
创建一个工作空间:
<!-- @makeWorkplace @testAgainstLatestRelease -->
```
DEMO_HOME=$(mktemp -d)
```
定义一个通用的 base
<!-- @makeBase @testAgainstLatestRelease -->
```
BASE=$DEMO_HOME/base
mkdir $BASE
cat <<EOF >$BASE/kustomization.yaml
resources:
- pod.yaml
EOF
cat <<EOF >$BASE/pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
spec:
containers:
- name: nginx
image: nginx:1.7.9
EOF
```
定义 namespace-a 的 variant
<!-- @makeNamespaceA @testAgainstLatestRelease -->
```
NSA=$DEMO_HOME/namespace-a
mkdir $NSA
cat <<EOF >$NSA/kustomization.yaml
resources:
- namespace.yaml
- ../base
namespace: namespace-a
EOF
cat <<EOF >$NSA/namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: namespace-a
EOF
```
定义 namespace-b 的 variant
<!-- @makeNamespaceB @testAgainstLatestRelease -->
```
NSB=$DEMO_HOME/namespace-b
mkdir $NSB
cat <<EOF >$NSB/kustomization.yaml
resources:
- namespace.yaml
- ../base
namespace: namespace-b
EOF
cat <<EOF >$NSB/namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: namespace-b
EOF
```
然后定义一个 _Kustomization_,将两个 variants 组合在一起:
<!-- @makeTopLayer @testAgainstLatestRelease -->
```
cat <<EOF >$DEMO_HOME/kustomization.yaml
resources:
- namespace-a
- namespace-b
EOF
```
现在工作空间有如下目录:
> ```
> .
> ├── base
> │   ├── kustomization.yaml
> │   └── pod.yaml
> ├── kustomization.yaml
> ├── namespace-a
> │   ├── kustomization.yaml
> │   └── namespace.yaml
> └── namespace-b
> ├── kustomization.yaml
> └── namespace.yaml
> ```
输出两个 namespace 的 pod 对象,分别在 namespace-a 和 namespace-b。
<!-- @confirmVariants @testAgainstLatestRelease -->
```
test 2 == \
$(kustomize build $DEMO_HOME| grep -B 4 "namespace: namespace-[ab]" | grep "name: myapp-pod" | wc -l); \
echo $?
```

127
examples/zh/multibases.md Normal file
View File

@@ -0,0 +1,127 @@
# 示例:多 Overlay 使用相同 base
`kustomize` 鼓励定义多个 variants例如在通用的 base 上使用 dev、staging 和 prod overlay。
可以创建其他 overlay 来将这些 variants 组合在一起:只需将 overlay 声明为新 kustomization 的 base 即可。
如果 base 由于某种原因无法控制,将多个 variants 组合在一起也可以为他们添加通用的 label 或 annotation。
下面使用一个 pod 作为 base 来进行演示。
首先创建一个工作空间:
<!-- @makeWorkplace @testAgainstLatestRelease -->
```
DEMO_HOME=$(mktemp -d)
```
定义一个通用的 base
<!-- @makeBase @testAgainstLatestRelease -->
```
BASE=$DEMO_HOME/base
mkdir $BASE
cat <<EOF >$BASE/kustomization.yaml
resources:
- pod.yaml
EOF
cat <<EOF >$BASE/pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
spec:
containers:
- name: nginx
image: nginx:1.7.9
EOF
```
定义 dev variant
<!-- @makeDev @testAgainstLatestRelease -->
```
DEV=$DEMO_HOME/dev
mkdir $DEV
cat <<EOF >$DEV/kustomization.yaml
resources:
- ./../base
namePrefix: dev-
EOF
```
定义 staging variant
<!-- @makeStaging @testAgainstLatestRelease -->
```
STAG=$DEMO_HOME/staging
mkdir $STAG
cat <<EOF >$STAG/kustomization.yaml
resources:
- ./../base
namePrefix: stag-
EOF
```
定义 production variant
<!-- @makeProd @testAgainstLatestRelease -->
```
PROD=$DEMO_HOME/production
mkdir $PROD
cat <<EOF >$PROD/kustomization.yaml
resources:
- ./../base
namePrefix: prod-
EOF
```
然后定义一个 _Kustomization_,将三个 variants 组合在一起:
<!-- @makeTopLayer @testAgainstLatestRelease -->
```
cat <<EOF >$DEMO_HOME/kustomization.yaml
resources:
- ./dev
- ./staging
- ./production
namePrefix: cluster-a-
EOF
```
现在工作空间有如下目录:
> ```
> .
> ├── base
> │   ├── kustomization.yaml
> │   └── pod.yaml
> ├── dev
> │   └── kustomization.yaml
> ├── kustomization.yaml
> ├── production
> │   └── kustomization.yaml
> └── staging
> └── kustomization.yaml
> ```
输出包含三个 pod 对象,分别来自 dev、staging 和 production variants。
<!-- @confirmVariants @testAgainstLatestRelease -->
```
test 1 == \
$(kustomize build $DEMO_HOME | grep cluster-a-dev-myapp-pod | wc -l); \
echo $?
test 1 == \
$(kustomize build $DEMO_HOME | grep cluster-a-stag-myapp-pod | wc -l); \
echo $?
test 1 == \
$(kustomize build $DEMO_HOME | grep cluster-a-prod-myapp-pod | wc -l); \
echo $?
```
与在不同的 variants 中添加不同的 `namePrefix` 类似,也可以添加不同的 `namespace` 并在一个 _kustomization_ 中组成这些 variants。更多的详细信息请查看[multi-namespaces](multi-namespace.md)。

171
examples/zh/mysql.md Normal file
View File

@@ -0,0 +1,171 @@
# 示例MySql
本示例采用现成的专为 MySql 设计的 k8s 资源,并对其进行定制使其适合生产环境。
在生产环境中,我们希望:
- 以 'prod-' 为前缀的 MySQL 资源
- MySQL 资源具有 'env: prod' label
- 使用持久化磁盘来存储 MySQL 数据
首先创建一个工作空间:
<!-- @makeDemoHome @testAgainstLatestRelease -->
```
DEMO_HOME=$(mktemp -d)
```
### 下载资源
为了保证文档的精简,基础资源都在补充目录中,如果需要请下载它们:
<!-- @downloadResources @testAgainstLatestRelease -->
```
curl -s -o "$DEMO_HOME/#1.yaml" "https://raw.githubusercontent.com\
/kubernetes-sigs/kustomize\
/master/examples/mySql\
/{deployment,secret,service}.yaml"
```
### 初始化 kustomization.yaml
`kustomize` 会从 `kustomization.yaml` 文件中获取指令,创建这个文件:
<!-- @kustomizeYaml @testAgainstLatestRelease -->
```
touch $DEMO_HOME/kustomization.yaml
```
### 添加资源
<!-- @addResources @testAgainstLatestRelease -->
```
cd $DEMO_HOME
kustomize edit add resource secret.yaml
kustomize edit add resource service.yaml
kustomize edit add resource deployment.yaml
cat kustomization.yaml
```
执行上面的命令后,`kustomization.yaml` 的 resources 字段如下:
> ```
> resources:
> - secret.yaml
> - service.yaml
> - deployment.yaml
> ```
### 定制名称
为 MySQL 资源添加 _prod-_ 前缀(这些资源将用于生产环境):
<!-- @customizeLabel @testAgainstLatestRelease -->
```
cd $DEMO_HOME
kustomize edit set nameprefix 'prod-'
cat kustomization.yaml
```
执行上面的命令后,`kustomization.yaml` 的 namePrefix 字段将会被更新:
> ```
> namePrefix: prod-
> ```
`namePrefix` 将在所有资源的名称前添加 _prod-_ 的前缀,可以通过如下命令查看:
<!-- @genNamePrefixConfig @testAgainstLatestRelease -->
```
kustomize build $DEMO_HOME
```
输出内容:
> ```
> apiVersion: v1
> data:
> password: YWRtaW4=
> kind: Secret
> metadata:
> ....
> name: prod-mysql-pass-d2gtcm2t2k
> ---
> apiVersion: v1
> kind: Service
> metadata:
> ....
> name: prod-mysql
> spec:
> ....
> ---
> apiVersion: apps/v1
> kind: Deployment
> metadata:
> ....
> name: prod-mysql
> spec:
> selector:
> ....
> ```
### 定制 Label
我们希望生产环境的资源包含某些 Label这样我们就可以通过 label selector 来查询到这些资源。
`kustomize` 没有 `edit set label` 命令来添加 label但是可以通过编辑 `kustomization.yaml` 文件来实现:
<!-- @customizeLabels @testAgainstLatestRelease -->
```
sed -i.bak 's/app: helloworld/app: prod/' \
$DEMO_HOME/kustomization.yaml
```
这时,执行 `kustomize build` 命令将会生成包含 `prod-` 前缀和 `env:prod` label 的 MySQL 配置。
### 存储定制
现成的 MySQL 使用 `emptyDir` 类型的 volume如果 MySQL Pod 被重新部署,则该类型的 volume 将会消失,这是不能应用于生产环境的,因此在生产环境中我们需要使用持久化磁盘。在 kustomize 中可以使用`patchesStrategicMerge` 来应用资源。
<!-- @createPatchFile @testAgainstLatestRelease -->
```
cat <<'EOF' > $DEMO_HOME/persistent-disk.yaml
apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
name: mysql
spec:
template:
spec:
volumes:
- name: mysql-persistent-storage
emptyDir: null
gcePersistentDisk:
pdName: mysql-persistent-storage
EOF
```
将 patch 文件添加到 `kustomization.yaml` 中:
<!-- @specifyPatch @testAgainstLatestRelease -->
```
cat <<'EOF' >> $DEMO_HOME/kustomization.yaml
patchesStrategicMerge:
- persistent-disk.yaml
EOF
```
`mysql-persistent-storage` 必须存在一个持久化磁盘才能使其成功运行,分为两步:
1. 创建一个名为 `persistent-disk.yaml` 的 YAML 文件,用于修改 deployment.yaml 的定义。
2.`kustomization.yaml` 中添加 `persistent-disk.yaml``patchesStrategicMerge` 列表中。运行 `kustomize build` 将 patch 应用于 Deployment 资源。
现在就可以将完整的配置输出并在集群中部署(将结果通过管道输出给 `kubectl apply`在生产环境创建MySQL 应用。
<!-- @finalInflation @testAgainstLatestRelease -->
```
kustomize build $DEMO_HOME # | kubectl apply -f -
```

View File

@@ -0,0 +1,186 @@
[Strategic Merge Patch]: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-api-machinery/strategic-merge-patch.md
[JSON patches]: https://tools.ietf.org/html/rfc6902
[label selector]: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors
# 示例:通过一个 patch 来修改多个资源
kustomization.yaml 支持通过 [Strategic Merge Patch] 和 [JSON patch] 来自定义资源。自 3.1.0 起,一个 patch 可以修改多个资源。
这可以通过指定 patch 和它所修改的 target 来完成,如下所示:
```yaml
patches:
- path: <PatchFile>
target:
group: <Group>
version: <Version>
kind: <Kind>
name: <Name>
namespace: <Namespace>
labelSelector: <LabelSelector>
annotationSelector: <AnnotationSelector>
```
`labelSelector``annotationSelector` 都应遵循 [label selector] 中的约定。Kustomize 选择匹配`target`中所有字段的目标来应用 patch 。
下面的示例展示了如何为所有部署资源注入 sidecar 容器。
创建一个包含 Deployment 资源的 `kustomization`
<!-- @createDeployment @test -->
```bash
DEMO_HOME=$(mktemp -d)
cat <<EOF >$DEMO_HOME/kustomization.yaml
resources:
- deployments.yaml
EOF
cat <<EOF >$DEMO_HOME/deployments.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy1
spec:
template:
metadata:
labels:
old-label: old-value
spec:
containers:
- name: nginx
image: nginx
args:
- one
- two
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy2
spec:
template:
metadata:
labels:
key: value
spec:
containers:
- name: busybox
image: busybox
EOF
```
声明 [Strategic Merge Patch] 文件以注入 sidecar 容器:
<!-- @addPatch @test -->
```bash
cat <<EOF >$DEMO_HOME/patch.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: not-important
spec:
template:
spec:
containers:
- name: istio-proxy
image: docker.io/istio/proxyv2
args:
- proxy
- sidecar
EOF
```
在 kustomization.yaml 中添加 _patches_ 字段
<!-- @applyPatch @testAgainstLatestRelease -->
```bash
cat <<EOF >>$DEMO_HOME/kustomization.yaml
patches:
- path: patch.yaml
target:
kind: Deployment
EOF
```
运行 `kustomize build $DEMO_HOME`,可以在输出中确认两个 Deployment 资源都已正确应用。
<!-- @confirmPatch @test -->
```bash
test 2 == \
$(kustomize build $DEMO_HOME | grep "image: docker.io/istio/proxyv2" | wc -l); \
echo $?
```
输出如下:
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy1
spec:
template:
metadata:
labels:
old-label: old-value
spec:
containers:
- args:
- proxy
- sidecar
image: docker.io/istio/proxyv2
name: istio-proxy
- args:
- one
- two
image: nginx
name: nginx
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy2
spec:
template:
metadata:
labels:
key: value
spec:
containers:
- args:
- proxy
- sidecar
image: docker.io/istio/proxyv2
name: istio-proxy
- image: busybox
name: busybox
```
## Target 选择
- 选择名称与 `name*` 匹配的资源
```yaml
target:
name: name*
```
- 选择所有 Deployment 资源
```yaml
target:
kind: Deployment
```
- 选择 label 与 `app=hello` 匹配的资源
```yaml
target:
labelSelector: app=hello
```
- 选择 annotation 与 `app=hello` 匹配的资源
```yaml
target:
annotationSelector: app=hello
```
- 选择所有 label 与 `app=hello` 匹配的 Deployment 资源
```yaml
target:
kind: Deployment
labelSelector: app=hello
```

View File

@@ -0,0 +1,68 @@
# remote targets
`kustomize build` 可以将 URL 作为参数传入并运行.
运行效果与如下操作相同:
如果想要要立即尝试此操作,可以按照 [multibases](../multibases/README.md) 示例运行 kustomization 运行构建。然后查看输出中的pod
<!-- @remoteOverlayBuild @test -->
```bash
target="github.com/kubernetes-sigs/kustomize/examples/multibases/dev/?ref=v1.0.6"
test 1 == \
$(kustomize build $target | grep dev-myapp-pod | wc -l); \
echo $?
```
在该示例中运行 overlay 将获得三个 pod在此 overlay 结合了dev、staging 和 prod 的 bases以便同时将它们全部发送给所有人
<!-- @remoteBuild @test -->
```bash
target="https://github.com/kubernetes-sigs/kustomize/examples/multibases?ref=v1.0.6"
test 3 == \
$(kustomize build $target | grep cluster-a-.*-myapp-pod | wc -l); \
echo $?
```
将 URL 作为 base
<!-- @createOverlay @test -->
```bash
DEMO_HOME=$(mktemp -d)
cat <<EOF >$DEMO_HOME/kustomization.yaml
resources:
- github.com/kubernetes-sigs/kustomize/examples/multibases?ref=v1.0.6
namePrefix: remote-
EOF
```
构建该 base 以确定所有的三个 pod 都有 `remote-` 前缀。
<!-- @remoteBases @testAgainstLatestRelease -->
```bash
test 3 == \
$(kustomize build $DEMO_HOME | grep remote-.*-myapp-pod | wc -l); \
echo $?
```
## URL format
URL 需要遵循 [hashicorp/go-getter URL 格式](https://github.com/hashicorp/go-getter#url-format) 。下面是一些遵循此约定的 Github repos 示例url。
- kustomization.yaml 在根目录
`github.com/Liujingfang1/mysql`
- kustomization.yaml 在 test 分支的根目录
`github.com/Liujingfang1/mysql?ref=test`
- kustomization.yaml 在 v1.0.6 版本的子目录
`github.com/kubernetes-sigs/kustomize/examples/multibases?ref=v1.0.6`
- kustomization.yaml repoUrl2 分支的子目录
`github.com/Liujingfang1/kustomize/examples/helloWorld?ref=repoUrl2`
- kustomization.yaml commit `7050a45134e9848fca214ad7e7007e96e5042c03` 的子目录
`github.com/Liujingfang1/kustomize/examples/helloWorld?ref=7050a45134e9848fca214ad7e7007e96e5042c03`

View File

@@ -0,0 +1,193 @@
[ConfigMaps]: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.18/#configmap-v1-core
[ELF]: https://en.wikipedia.org/wiki/Executable_and_Linkable_Format
[Go plugin]: https://golang.org/pkg/plugin
[Secrets]: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.18/#secret-v1-core
[base64]: https://tools.ietf.org/html/rfc4648#section-4
[configuration directory]: https://wiki.archlinux.org/index.php/XDG_Base_Directory#Specification
[grpc]: https://grpc.io
[tag]: /../../releases
[v2.0.3]: /../../releases/tag/v2.0.3
[`exec.Command`]: https://golang.org/pkg/os/exec/#Command
# 生成 Secrets
## Secret 是什么?
Kubernetes 的 [ConfigMaps] 和 [Secrets] 都是key:value map但 [Secrets] 的内容更为敏感,比如:密码或者 ssh 秘钥。
Kubernetes 开发者以各种方式工作Secrets 保存的信息相比 ConfigMaps,Deployments 等的配置信息需要更谨慎的隐藏。
## 创建一个工作空间
<!-- @establishBase @test -->
```bash
DEMO_HOME=$(mktemp -d)
```
## 来自本地文件的 Secret
kustomize 可以通过三种不同的方式生成来自本地文件的 Secret 。
*_env_ 文件中获取(`NAME = VALUE`,每行一个)
* 使用文件内容来生成一个 secret
* 从 kustomization.yaml 文件获取 secret
这里有一个示例结合所有的三种方式:
创建一个包含一些短密码的 env 文件:
<!-- @makeEnvFile @test -->
```bash
cat <<'EOF' >$DEMO_HOME/foo.env
ROUTER_PASSWORD=admin
DB_PASSWORD=iloveyou
EOF
```
创建一个长密码的文本文件:
<!-- @makeLongSecretFile @test -->
```bash
cat <<'EOF' >$DEMO_HOME/longsecret.txt
Lorem ipsum dolor sit amet,
consectetur adipiscing elit,
sed do eiusmod tempor incididunt
ut labore et dolore magna aliqua.
EOF
```
创建一个kustomization.yaml 文件, 其中包含引用上面文件的 secretGenerator, 并且另外定义一些文字 KV 对:
<!-- @makeKustomization1 @test -->
```bash
cat <<'EOF' >$DEMO_HOME/kustomization.yaml
secretGenerator:
- name: mysecrets
envs:
- foo.env
files:
- longsecret.txt
literals:
- FRUIT=apple
- VEGETABLE=carrot
EOF
```
生成 Secret
<!-- @build1 @test -->
```bash
result=$(kustomize build $DEMO_HOME)
echo "$result"
# Spot check the result:
test 1 == $(echo "$result" | grep -c "FRUIT: YXBwbGU=")
```
将会得到类似的内容:
> ```yaml
> apiVersion: v1
> kind: Secret
> metadata:
> name: mysecrets-hfb5df789h
> type: Opaque
> data:
> FRUIT: YXBwbGU=
> VEGETABLE: Y2Fycm90
> ROUTER_PASSWORD: YWRtaW4=
> DB_PASSWORD: aWxvdmV5b3U=
> longsecret.txt: TG9yZW0gaXBzdW0gZG9sb3Igc2l0I... (elided)
> ```
资源名称的前缀为 `mysecrets`(在 kustomization.yaml 中指定),后跟其内容的哈希值。
使用 base64 解码器确认这些值的原始版本。
这三种方法共同的问题是创建 Secret 所使用的敏感数据必须保存磁盘上。
这会增加额外的安全问题:对本地存储的敏感文件的查看、安装和删除权限的控制等。
## 来自任何地方的 Secret
一般的替代方案是在[generator](../../docs/plugins)中生成 secrets 。
然后,这些值可以通过经过身份验证和授权的 RPC 进入密码保险库服务。
[sgp]: ../../plugin/someteam.example.com/v1/secretsfromdatabase
这里有一个[secret 生成器][sgp],它模拟从数据库中拉取 map 中的值。
下载
<!-- @copyPlugin @test -->
```bash
repo=https://raw.githubusercontent.com/kubernetes-sigs/kustomize
pPath=plugin/someteam.example.com/v1/secretsfromdatabase
dir=$DEMO_HOME/kustomize/$pPath
mkdir -p $dir
curl -s -o $dir/SecretsFromDatabase.go \
${repo}/master/$pPath/SecretsFromDatabase.go
```
运行 kustomize build 生成结果
<!-- @compilePlugin @xtest -->
```bash
go build -buildmode plugin \
-o $dir/SecretsFromDatabase.so \
$dir/SecretsFromDatabase.go
```
创建一个配置文件:
<!-- @makeConfiguration @test -->
```bash
cat <<'EOF' >$DEMO_HOME/secretFromDb.yaml
apiVersion: someteam.example.com/v1
kind: SecretsFromDatabase
metadata:
name: mySecretGenerator
name: forbiddenValues
namespace: production
keys:
- ROCKET
- VEGETABLE
EOF
```
创建一个引用此生成器的新 kustomization.yaml 文件:
<!-- @makeKustomization2 @test -->
```bash
cat <<'EOF' >$DEMO_HOME/kustomization.yaml
generators:
- secretFromDb.yaml
EOF
```
最终生成 secret ,设置 `XDG_CONFIG_HOME` 以便可以在 `$DEMO_HOME` 中找到该生成器:
<!-- @build2 @xtest -->
```bash
result=$( \
XDG_CONFIG_HOME=$DEMO_HOME \
kustomize build --enable_alpha_plugins $DEMO_HOME )
echo "$result"
# Spot check the result:
test 1 == $(echo "$result" | grep -c "FRUIT: YXBwbGU=")
```
将会得到类似的内容:
> ```yaml
> apiVersion: v1
> kind: Secret
> metadata:
> name: mysecrets-bdt27dbkd6
> type: Opaque
> data:
> FRUIT: YXBwbGU=
> VEGETABLE: Y2Fycm90
> ```

296
examples/zh/springboot.md Normal file
View File

@@ -0,0 +1,296 @@
# 示例SpringBoot
在本教程中,您将学会如何使用 `kustomize` 定制一个运行 Spring Boot 应用的 k8s 配置。
在生产环境中,我们需要定制如下内容:
- 为 Spring Boot 应用添加特定配置
- 配置数据库连接
- 以 'prod-' 前缀命名资源
- 资源具有 'env: prod' label
- 设置合适的 JVM 内存
- 健康检查和就绪检查
首先创建一个工作空间:
<!-- @makeDemoHome @testAgainstLatestRelease -->
```
DEMO_HOME=$(mktemp -d)
```
### 下载资源
为了保证文档的精简,基础资源都在补充目录中,如果需要请下载它们:
<!-- @downloadResources @testAgainstLatestRelease -->
```
CONTENT="https://raw.githubusercontent.com\
/kubernetes-sigs/kustomize\
/master/examples/springboot"
curl -s -o "$DEMO_HOME/#1.yaml" \
"$CONTENT/base/{deployment,service}.yaml"
```
### 初始化 kustomization.yaml
`kustomize` 会从 `kustomization.yaml` 文件中获取指令,创建这个文件:
<!-- @kustomizeYaml @testAgainstLatestRelease -->
```
touch $DEMO_HOME/kustomization.yaml
```
### 添加资源
<!-- @addResources @testAgainstLatestRelease -->
```
cd $DEMO_HOME
kustomize edit add resource service.yaml
kustomize edit add resource deployment.yaml
cat kustomization.yaml
```
执行上面的命令后,`kustomization.yaml` 的 resources 字段如下:
> ```
> resources:
> - service.yaml
> - deployment.yaml
> ```
### 添加 configMap 生成器
<!-- @addConfigMap @testAgainstLatestRelease -->
```
echo "app.name=Kustomize Demo" >$DEMO_HOME/application.properties
kustomize edit add configmap demo-configmap \
--from-file application.properties
cat kustomization.yaml
```
执行上面的命令后,`kustomization.yaml` 的 configMapGenerator 字段如下:
> ```
> configMapGenerator:
> - files:
> - application.properties
> name: demo-configmap
> ```
### 定制 configMap
我们将为生产环境添加数据库连接凭证。通常这些凭据被存放在 `application.properties` 中,然而在有些时候,我们希望将这些凭证保存在其他文件中,而将应用的其他配置保存在 `application.properties` 中。通过这种清晰的分离,这些凭证和应用配置可由不同的团队管理和维护。例如,应用开发人员可以在 `application.properties` 中调整应用程序的配置,而数据库的连接凭证则由运维或 SRE 团队管理和维护。
对于 Spring Boot 应用,我们可以通过环境变量动态的设置 `spring.profiles.active`,然后应用将获取一个额外的 `application-<profile>.properties` 文件,我们可以分为两步定制这个 ConfigMap
1. 通过 patch 添加一个环境变量
2. 将文件添加到 ConfigMap 中
<!-- @customizeConfigMap -->
```
cat <<EOF >$DEMO_HOME/patch.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: sbdemo
spec:
template:
spec:
containers:
- name: sbdemo
env:
- name: spring.profiles.active
value: prod
EOF
kustomize edit add patch --path patch.yaml --name sbdemo --kind Deployment --group apps --version v1
cat <<EOF >$DEMO_HOME/application-prod.properties
spring.jpa.hibernate.ddl-auto=update
spring.datasource.url=jdbc:mysql://<prod_database_host>:3306/db_example
spring.datasource.username=root
spring.datasource.password=admin
EOF
kustomize edit add configmap \
demo-configmap --from-file application-prod.properties
cat kustomization.yaml
```
执行上面的命令后,`kustomization.yaml` 的 configMapGenerator 字段如下:
> ```
> configMapGenerator:
> - files:
> - application.properties
> - application-prod.properties
> name: demo-configmap
> ```
### 定制名称
为资源添加 _prod-_ 前缀(这些资源将用于生产环境):
<!-- @customizeLabel @testAgainstLatestRelease -->
```
cd $DEMO_HOME
kustomize edit set nameprefix 'prod-'
```
执行上面的命令后,`kustomization.yaml` 的 namePrefix 字段将会被更新:
> ```
> namePrefix: prod-
> ```
`namePrefix` 将在所有资源的名称前添加 _prod-_ 的前缀,可以通过如下命令查看:
<!-- @build1 @testAgainstLatestRelease -->
```
kustomize build $DEMO_HOME | grep prod-
```
### 定制 Label
我们希望生产环境的资源包含某些 Label这样我们就可以通过 label selector 来查询到这些资源。
`kustomize` 没有 `edit set label` 命令来添加 label但是可以通过编辑 `kustomization.yaml` 文件来实现:
<!-- @customizeLabels @testAgainstLatestRelease -->
```
cat <<EOF >>$DEMO_HOME/kustomization.yaml
commonLabels:
env: prod
EOF
```
现在所有资源都包含 `prod-` 前缀和 `env:prod` label可以通过下面的命令来查看
<!-- @build2 @testAgainstLatestRelease -->
```
kustomize build $DEMO_HOME | grep -C 3 env
```
### 下载调整 JVM 内存的 Patch
当 Spring Boot 应用部署在 k8s 集群中时JVM 会运行在容器中。我们要为容器设置内存限制,并确保 JVM 知道容器的内存限制。在 k8s 的 Deployment 中,我们可以设置资源容器的资源限制,并将限制注入到一些环境变量中,当容器启动时,其可以获取环境变量并设置相应的 JVM 选项。
下载 `memorylimit_patch.yaml` 其包含内存限制设置的 patch
<!-- @downloadPatch @testAgainstLatestRelease -->
```
curl -s -o "$DEMO_HOME/#1.yaml" \
"$CONTENT/overlays/production/{memorylimit_patch}.yaml"
cat $DEMO_HOME/memorylimit_patch.yaml
```
输出内容
> ```
> apiVersion: apps/v1
> kind: Deployment
> metadata:
> name: sbdemo
> spec:
> template:
> spec:
> containers:
> - name: sbdemo
> resources:
> limits:
> memory: 1250Mi
> requests:
> memory: 1250Mi
> env:
> - name: MEM_TOTAL_MB
> valueFrom:
> resourceFieldRef:
> resource: limits.memory
> ```
### 下载健康检查的 Patch
我们还可以在生产环境中添加健康检查和就绪检查Spring Boot 应用都具有类似 `/actuator/health` 的接口用于健康检查,我们可以定制 k8s 的 Deployment 资源来进行健康检查和就绪检查。
下载 `memorylimit_patch.yaml` 其包含存活和就绪探针的 patch
<!-- @downloadPatch @testAgainstLatestRelease -->
```
curl -s -o "$DEMO_HOME/#1.yaml" \
"$CONTENT/overlays/production/{healthcheck_patch}.yaml"
cat $DEMO_HOME/healthcheck_patch.yaml
```
输出内容
> ```
> apiVersion: apps/v1
> kind: Deployment
> metadata:
> name: sbdemo
> spec:
> template:
> spec:
> containers:
> - name: sbdemo
> livenessProbe:
> httpGet:
> path: /actuator/health
> port: 8080
> initialDelaySeconds: 10
> periodSeconds: 3
> readinessProbe:
> initialDelaySeconds: 20
> periodSeconds: 10
> httpGet:
> path: /actuator/info
> port: 8080
> ```
### 添加 patches
将这些 patch 添加到 `kustomization.yaml` 中:
<!-- @addPatch -->
```
cd $DEMO_HOME
kustomize edit add patch --path memorylimit_patch.yaml --name sbdemo --kind Deployment --group apps --version v1
kustomize edit add patch --path healthcheck_patch.yaml --name sbdemo --kind Deployment --group apps --version v1
```
执行上面的命令后,`kustomization.yaml` 的 patches 字段如下:
> ```
> patches:
> - path: patch.yaml
> target:
> group: apps
> version: v1
> kind: Deployment
> name: sbdemo
> - path: memorylimit_patch.yaml
> target:
> group: apps
> version: v1
> kind: Deployment
> name: sbdemo
> - path: healthcheck_patch.yaml
> target:
> group: apps
> version: v1
> kind: Deployment
> name: sbdemo
> ```
现在就可以将完整的配置输出并在集群中部署(将结果通过管道输出给 `kubectl apply`),在生产环境创建 Spring Boot 应用。
<!-- @finalBuild @testAgainstLatestRelease -->
```
kustomize build $DEMO_HOME # | kubectl apply -f -
```

View File

@@ -0,0 +1,171 @@
# 自定义 transformer 配置
Kustomize 通过对原始资源集进行一系列转换来创建新资源。Kustomize 提供以下默认的 transformers
- annotations
- images
- labels
- name reference
- namespace
- prefix/suffix
- variable reference
transformer 配置的 `fieldSpec` 列表,用来确定哪些资源类型和这些类型的 transformer 可以修改哪些字段。
## FieldSpec
FieldSpec 是一种表示资源中字段路径的类型。
```yaml
group: some-group
version: some-version
kind: some-kind
path: path/to/the/field
create: false
```
如果 `create` 设置为 `true`,表示如果尚未找到该路径,则 transformer 将在资源中创建该路径。这对于 label 和 annotation 转换器最有用,因为在转换之前可能未设置 label 或 annotation 的路径。
## Images transformer
默认的 images transformer 会更新包含 `containers``initcontainers` 子路径的路径中找到的指定镜像的键值 。如果找到,则更新 `image``newName``newTag``digest` 等字段。该 `name` 字段应与 `image` 资源中的键值匹配。
kustomization.yaml 示例:
```yaml
images:
- name: postgres
newName: my-registry/my-postgres
newTag: v1
- name: nginx
newTag: 1.8.0
- name: my-demo-app
newName: my-app
- name: alpine
digest: sha256:25a0d4
```
可以通过创建 `images` 包含 `path``kind` 字段的列表来自定义镜像 transformer 配置。[镜像 transformer 教程](image.md) 展示了如何指定默认镜像 transformer 和自定义镜像 transformer 配置。
## Prefix/suffix transformer
prefix/suffix transformer 为所有资源的 `metadata/name` 字段添加前缀/后缀。默认的 prefix transformer 配置如下:
```yaml
namePrefix:
- path: metadata/name
```
kustomization.yaml 示例:
```yaml
namePrefix:
alices-
nameSuffix:
-v2
```
## Labels transformer
labels transformer 将 labels 添加到所有资源的 `metadata/labels` 字段。它还将 labels 添加到 `spec/selector``spec/selector/matchLabels` 字段以及所有 Deployment 资源中的字段。
示例:
```yaml
commonLabels:
- path: metadata/labels
create: true
- path: spec/selector
create: true
version: v1
kind: Service
- path: spec/selector/matchLabels
create: true
kind: Deployment
```
kustomization.yaml 示例:
```yaml
commonLabels:
someName: someValue
owner: alice
app: bingo
```
## Annotations transformer
annotations transformer 可以:
- 将 annotations 添加到所有资源的 `metadata/annotations` 字段
- 将 annotations 添加到DeploymentReplicaSetDaemonSetStatefulSetJob 和 CronJob 等资源的 `spec/template/metadata/annotations`
- 将 annotations 添加到CronJob 资源的 `spec/jobTemplate/spec/template/metadata/annotations`字段。
kustomization.yaml 示例:
```yaml
commonAnnotations:
oncallPager: 800-555-1212
```
## Name reference transformer
Name reference transformer 的配置不同于其他所有的 transformer。`nameReferences` 列表代表一种可以用作其他类型资源中的引用的所有可能字段。一个 `nameReference` 包含一个类型如 ConfigMap 以及 `fieldSpecs` 列表,其中 `ConfigMap` 其他资源被引用。下面是一个例子:
```yaml
kind: ConfigMap
version: v1
fieldSpecs:
- kind: Pod
version: v1
path: spec/volumes/configMap/name
- kind: Deployment
path: spec/template/spec/volumes/configMap/name
- kind: Job
path: spec/template/spec/volumes/configMap/name
```
Name reference transformer 的配置为 `nameReferences` 列表包含 ConfigMapSecretServiceRole和ServiceAccount等资源。下面是一个示例配置
```yaml
nameReference:
- kind: ConfigMap
version: v1
fieldSpecs:
- path: spec/volumes/configMap/name
version: v1
kind: Pod
- path: spec/containers/env/valueFrom/configMapKeyRef/name
version: v1
kind: Pod
# ...
- kind: Secret
version: v1
fieldSpecs:
- path: spec/volumes/secret/secretName
version: v1
kind: Pod
- path: spec/containers/env/valueFrom/secretKeyRef/name
version: v1
kind: Pod
```
## Customizing transformer configurations
除默认 transformers 外,您还可以创建自定义的 transformers 配置。通过调用将默认的 transformers 配置保存到本地目录`kustomize config save -d`,然后修改和使用这些配置。本教程显示了如何创建自定义 transformers 配置:
- [support a CRD type](../transformerconfigs/crd/README.md)
- 添加额外的字段以进行变量替换
- 添加额外的字段以供名称参考
## Supporting escape characters in CRD path
```yaml
metadata:
annotations:
foo.k8s.io/bar: baz
```
Kustomize 支持在路径中转义特殊字符,例如: `metadata/annotations/foo.k8s.io\/bar`

View File

@@ -0,0 +1,207 @@
# 通过 transformer 验证资源
[kubeval]: https://github.com/instrumenta/kubeval
[插件]: ../../docs/plugins
kustomize 不会验证其输入或输出是否符合资源要求。
而另一个工具 [kubeval] 提供了验证 k8s 资源的功能,例如:
```shell
$ kubeval my-invalid-rc.yaml
The document my-invalid-rc.yaml contains an invalid ReplicationController
--> spec.replicas: Invalid type. Expected: integer, given: string
```
可以创建一个 Kustomize transformer [插件] 通过运行 [kubeval] 来进行验证资源。
创建一个工作空间:
<!-- @makeWorkplace @test -->
```bash
DEMO_HOME=$(mktemp -d)
mkdir -p $DEMO_HOME/valid
mkdir -p $DEMO_HOME/invalid
PLUGINDIR=$DEMO_HOME/kustomize/plugin/someteam.example.com/v1/validator
mkdir -p $PLUGINDIR
```
## 创建 transformer 插件
根据操作系统下载 [kubeval] 的二进制文件并将其添加到 $PATH。
<!-- @downloadKubeval @test -->
```bash
OS=`uname | sed -e 's/Linux/linux/' -e 's/Darwin/darwin/'`
wget https://github.com/instrumenta/kubeval/releases/download/0.9.2/kubeval-${OS}-amd64.tar.gz
tar xf kubeval-${OS}-amd64.tar.gz
export PATH=$PATH:`pwd`
```
transformer 插件将执行逻辑如下:
- 从 stdin 中读取资源并传递到 transformer 插件。
- transformer 插件的配置文件作为第一个参数传入。
- transformer 插件的工作目录是 kustomization 所在目录。
- 转换后的资源由插件写入 stdout 。
- transformer 返回值为0则转化成功如果 transformer 插件的返回值不为0则 kustomize 认为转化期间存在错误。
我们可以写一个 bash 脚本作为用于验证资源的 transformer 插件,该脚本执行 [kubeval] 二进制文件并返回正确的输出和退出码。
<!-- @writePlugin @test -->
```bash
cat <<'EOF' > $PLUGINDIR/Validator
#!/bin/bash
if ! [ -x "$(command -v kubeval)" ]; then
echo "Error: kubeval is not installed."
exit 1
fi
temp_file=$(mktemp)
output_file=$(mktemp)
cat - > $temp_file
kubeval $temp_file > $output_file
if [ $? -eq 0 ]; then
cat $temp_file
rm $temp_file $output_file
exit 0
fi
cat $output_file
rm $temp_file $output_file
exit 1
EOF
chmod +x $PLUGINDIR/Validator
```
## 使用 transformer 插件
创建一个包含有效 ConfigMap 和 transformer 插件的 Kustomization。
<!-- @writeKustomization @test -->
```bash
cat <<'EOF' >$DEMO_HOME/valid/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: cm
data:
foo: bar
EOF
cat <<'EOF' >$DEMO_HOME/valid/validation.yaml
apiVersion: someteam.example.com/v1
kind: Validator
metadata:
name: notImportantHere
EOF
cat <<'EOF' >$DEMO_HOME/valid/kustomization.yaml
resources:
- configmap.yaml
transformers:
- validation.yaml
EOF
```
创建一个包含无效 ConfigMap 和 transformer 插件的 Kustomization。
<!-- @writeKustomization @test -->
```bash
cat <<'EOF' >$DEMO_HOME/invalid/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: cm
data:
- foo: bar
EOF
# ConfigMap 的 data 字段需要传入的数据类型为 object这里传入一个 array
cat <<'EOF' >$DEMO_HOME/invalid/validation.yaml
apiVersion: someteam.example.com/v1
kind: Validator
metadata:
name: notImportantHere
EOF
cat <<'EOF' >$DEMO_HOME/invalid/kustomization.yaml
resources:
- configmap.yaml
transformers:
- validation.yaml
EOF
```
目录结构如下:
```bash
/tmp/tmp.fAYMfLZJs4
├── invalid
│   ├── configmap.yaml
│   ├── kustomization.yaml
│   └── validation.yaml
├── kustomize
│   └── plugin
│   └── someteam.example.com
│   └── v1
│   ├── kubeval
│   └── Validator
└── valid
├── configmap.yaml
├── kustomization.yaml
└── validation.yaml
```
定义一个 helper 函数在正确的的环境和插件标记运行 kustomize 。
<!-- @defineKustomizeBd @test -->
```bash
function kustomizeBd {
XDG_CONFIG_HOME=$DEMO_HOME \
kustomize build \
--enable_alpha_plugins \
$DEMO_HOME/$1
}
```
构建有效的 variant
<!-- @buildValid @test -->
```bash
kustomizeBd valid
```
输出的 ConfigMap 内容为:
```yaml
apiVersion: v1
data:
foo: bar
kind: ConfigMap
metadata:
name: cm
```
构建无效的 variant
```bash
kustomizeBd invalid
```
可以查看到输出错误日志为:
```shell
data: Invalid type. Expected: object, given: array
```
## 清理
<!-- @cleanup @test -->
```shell
rm -rf $DEMO_HOME
```

149
examples/zh/vars.md Normal file
View File

@@ -0,0 +1,149 @@
# 示例: 将 k8s runtime 数据注入容器
本教程将会介绍如何声明变量以及如何在容器中的命令使用变量。要注意的是变量的查找和替换并不适用于任意字段默认仅适用于容器的envargs和command。
运行WordPress以下是必须的
- WordPress 连接 MySQL 数据库
- MySQL 服务可以被 WordPress 容器访问
首先构建一个工作空间:
<!-- @makeDemoHome @test -->
```bash
DEMO_HOME=$(mktemp -d)
MYSQL_HOME=$DEMO_HOME/mysql
mkdir -p $MYSQL_HOME
WORDPRESS_HOME=$DEMO_HOME/wordpress
mkdir -p $WORDPRESS_HOME
```
### 下载 resources
下载 WordPress 的 resources 和 `kustomization.yaml`
<!-- @downloadResources @test -->
```bash
CONTENT="https://raw.githubusercontent.com\
/kubernetes-sigs/kustomize\
/master/examples/wordpress/wordpress"
curl -s -o "$WORDPRESS_HOME/#1.yaml" \
"$CONTENT/{deployment,service,kustomization}.yaml"
```
下载 MySQL 的 resources 和 `kustomization.yaml`
<!-- @downloadResources @test -->
```bash
CONTENT="https://raw.githubusercontent.com\
/kubernetes-sigs/kustomize\
/master/examples/wordpress/mysql"
curl -s -o "$MYSQL_HOME/#1.yaml" \
"$CONTENT/{deployment,service,secret,kustomization}.yaml"
```
### 创建 kustomization.yaml
基于 `wordpress``mysql` 的两个 bases 创建一个新的 `kustomization.yaml`
<!-- @createKustomization @test -->
```bash
cat <<EOF >$DEMO_HOME/kustomization.yaml
resources:
- wordpress
- mysql
namePrefix: demo-
patchesStrategicMerge:
- patch.yaml
EOF
```
### 下载 WordPress 的 patchs
在新的 kustomization 中应用 WordPress Deployment 的 patch ,该 patch 包含:
- 添加初始容器来显示mysql的服务名称
- 添加允许 wordpress 查找到 mysql 数据库的环境变量
<!-- @downloadPatch @test -->
```bash
CONTENT="https://raw.githubusercontent.com\
/kubernetes-sigs/kustomize\
/master/examples/wordpress"
curl -s -o "$DEMO_HOME/#1.yaml" \
"$CONTENT/{patch}.yaml"
```
该 patch 内容如下:
> ```yaml
> apiVersion: apps/v1
> kind: Deployment
> metadata:
> name: wordpress
> spec:
> template:
> spec:
> initContainers:
> - name: init-command
> image: debian
> command: ["/bin/sh"]
> args: ["-c", "echo $(WORDPRESS_SERVICE); echo $(MYSQL_SERVICE)"]
> containers:
> - name: wordpress
> env:
> - name: WORDPRESS_DB_HOST
> value: $(MYSQL_SERVICE)
> - name: WORDPRESS_DB_PASSWORD
> valueFrom:
> secretKeyRef:
> name: mysql-pass
> key: password
> ```
初始化容器的命令需要依赖于k8s资源对象字段的信息由占位符变量 $(WORDPRESS_SERVICE) 和 $(MYSQL_SERVICE) 表示。
### 将变量绑定到k8s对象字段
<!-- @addVarRef @test -->
```bash
cat <<EOF >>$DEMO_HOME/kustomization.yaml
vars:
- name: WORDPRESS_SERVICE
objref:
kind: Service
name: wordpress
apiVersion: v1
fieldref:
fieldpath: metadata.name
- name: MYSQL_SERVICE
objref:
kind: Service
name: mysql
apiVersion: v1
EOF
```
`WORDPRESS_SERVICE` 来自 `wordpress` 服务的 `metadata.name` 字段。如果不指定 `fieldref` ,则使用默认的 `metadata.name` 。因此 `MYSQL_SERVICE` 来自 `mysql` 服务的 `metadata.name` 字段。
### 替换
运行命令查看替换结果:
<!-- @kustomizeBuild @test -->
```bash
kustomize build $DEMO_HOME
```
预期的输出为:
> ```yaml
> (truncated)
> ...
> initContainers:
> - args:
> - -c
> - echo demo-wordpress; echo demo-mysql
> command:
> - /bin/sh
> image: debian
> name: init-command
>
> ```