demos --> examples

examples/ is pretty standard whereas demos/ isn't. So I just refactored that.

Signed-off-by: Ahmet Alp Balkan <ahmetb@google.com>
This commit is contained in:
Ahmet Alp Balkan
2018-05-25 10:07:46 -07:00
parent 4d111436aa
commit 7086e4f974
38 changed files with 38 additions and 38 deletions

31
examples/README.md Normal file
View File

@@ -0,0 +1,31 @@
# Examples
These examples assume that `kustomize` is on your `$PATH`.
They are covered by [pre-commit](../bin/pre-commit.sh)
tests, and should work with HEAD
<!-- @installkustomize @test -->
```
go get github.com/kubernetes-sigs/kustomize
```
* [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.
* [mySql](mySql/README.md) - Create a MySQL production
configuration from scratch.
* [springboot](springboot/README.md) - Create a Spring Boot
application production configuration from scratch.
* [configGeneration](configGeneration.md) -
Mixing configuration data from different owners
(e.g. devops/SRE and developers).
* [breakfast](breakfast.md) - Customize breakfast for
Alice and Bob.

124
examples/breakfast.md Normal file
View File

@@ -0,0 +1,124 @@
[kubernetes API object style]: https://kubernetes.io/docs/concepts/overview/working-with-objects/kubernetes-objects/#required-fields
[variant]: ../docs/glossary.md#variant
# Demo: configure breakfast
Define a place to work:
<!-- @makeWorkplace @test -->
```
DEMO_HOME=$(mktemp -d)
```
Make a place to put the base breakfast configuration:
<!-- @baseDir @test -->
```
mkdir -p $DEMO_HOME/breakfast/base
```
Make a `kustomization` to define what goes into
breakfast. This breakfast has coffee and pancakes:
<!-- @baseKustomization @test -->
```
cat <<EOF >$DEMO_HOME/breakfast/base/kustomization.yaml
resources:
- coffee.yaml
- pancakes.yaml
EOF
```
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 -->
```
cat <<EOF >$DEMO_HOME/breakfast/base/coffee.yaml
kind: Coffee
metadata:
name: morningCup
temperature: lukewarm
data:
greeting: "Good Morning!"
EOF
```
The `name` field merely distinguishes this instance of
coffee from others (if there were any).
Likewise, define _pancakes_:
<!-- @pancakes @test -->
```
cat <<EOF >$DEMO_HOME/breakfast/base/pancakes.yaml
kind: Pancakes
metadata:
name: comfort
stacksize: 3
topping: none
EOF
```
Make a custom [variant] of breakfast for Alice, who
likes her coffee hot:
<!-- @aliceOverlay @test -->
```
mkdir -p $DEMO_HOME/breakfast/overlays/alice
cat <<EOF >$DEMO_HOME/breakfast/overlays/alice/kustomization.yaml
commonLabels:
who: alice
bases:
- ../../base
patches:
- temperature.yaml
EOF
cat <<EOF >$DEMO_HOME/breakfast/overlays/alice/temperature.yaml
kind: Coffee
metadata:
name: morningCup
temperature: hot!
EOF
```
And likewise a [variant] for Bob, who wants _five_ pancakes, with strawberries:
<!-- @bobOverlay @test -->
```
mkdir -p $DEMO_HOME/breakfast/overlays/bob
cat <<EOF >$DEMO_HOME/breakfast/overlays/bob/kustomization.yaml
commonLabels:
who: bob
bases:
- ../../base
patches:
- topping.yaml
EOF
cat <<EOF >$DEMO_HOME/breakfast/overlays/bob/topping.yaml
kind: Pancakes
metadata:
name: comfort
stacksize: 5
topping: strawberries
EOF
```
One can now generate the configs for Alices breakfast:
<!-- @generateAlice @test -->
```
kustomize build $DEMO_HOME/breakfast/overlays/alice
```
Likewise for Bob:
<!-- @generateBob @test -->
```
kustomize build $DEMO_HOME/breakfast/overlays/bob
```

View File

@@ -0,0 +1,298 @@
[overlay]: ../docs/glossary.md#overlay
[target]: ../docs/glossary.md#target
# Demo: combining config data from devops and developers
Scenario: you have a Java-based server storefront in
production that various internal development teams
(signups, checkout, search, etc.) contribute to.
The server runs in different environments:
_development_, _testing_, _staging_ and _production_,
accepting configuration parameters from java property
files.
Using one big properties file for each environment is
difficult to manage. The files change frequently, and
have to be changed by devops exclusively because
1. the files must at least partially agree on certain
values that devops cares about and that developers
ignore and
1. because the production
properties contain sensitive data like production
database credentials.
## Property sharding
With some study, we notice that the properties are
separable into categories.
### Common properties
E.g. internationalization data, static data like
physical constants, location of external services, etc.
_Things that are the same regardless of environment._
Only one set of values is needed.
Place them in a file called
* `common.properties`
(relative location defined below).
### Plumbing properties
E.g. serving location of static content (HTML, CSS,
javascript), location of product and customer database
tables, ports expected by load balancers, log sinks,
etc.
_The different values for these properties are
precisely what sets the environments apart._
Devops or SRE will want full control over the values
used in production. Testing will have fixed
databases supporting testing. Developers will want
to do whatever they want to try scenarios under
development.
Places these values in
* `development/plumbing.properties`
* `staging/plumbing.properties`
* `production/plumbing.properties`
### Secret properties
E.g. location of actual user tables, database
credentials, decryption keys, etc.
_Things that are a subset of devops controls, that
nobody else has (or should want) access to._
Places these values in
* `development/secret.properties`
* `staging/secret.properties`
* `production/secret.properties`
[kubernetes secret]: https://kubernetes.io/docs/tasks/inject-data-application/distribute-credentials-secure/
and control access to them with (for example) unix file
owner and mode bits, or better yet, put them in
a server dedicated to storing password protected
secrets, and use a field called `secretGenerator`
in your _kustomization_ to create a kubernetes
secret holding them (not covering that here).
<!--
secretGenerator:
- name: app-tls
commands:
tls.crt: "cat tls.cert"
tls.key: "cat tls.key"
type: "kubernetes.io/tls"
EOF
-->
## A mixin approach to management
The way to create _n_ cluster environments that share
some common information is to create _n_ overlays of a
common base.
For the rest of this example, we'll do _n==2_, just
_development_ and _production_, since adding more
environments follows the same pattern.
A cluster environment is created by
running `kustomize build` on a [target] that happens to
be an [overlay].
[helloworld]: helloworld.md
The following example will do that, but will focus on
configMap construction, and not worry about how to
connect the configMaps to deployments (that is covered
in the [helloworld] example).
All files - including the shared property files
discussed above - will be created in a directory tree
that is consistent with the base vs overlay file layout
defined in the [helloworld] demo.
It will all live in this work directory:
<!-- @makeWorkplace @test -->
```
DEMO_HOME=$(mktemp -d)
```
### Create the base
<!-- kubectl create configmap BOB --dry-run -o yaml --from-file db. -->
Make a place to put the base configuration:
<!-- @baseDir @test -->
```
mkdir -p $DEMO_HOME/base
```
Make the data for the base. This direction by
definition should hold resources common to all
environments. Here we're only defining a java
properties file, and a `kustomization` file that
references it.
<!-- @baseKustomization @test -->
```
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
```
### Create and use the overlay for _development_
Make an abbreviation for the parent of the overlay
directories:
<!-- @overlays @test -->
```
OVERLAYS=$DEMO_HOME/overlays
```
Create the files that define the _development_ overlay:
<!-- @developmentFiles @test -->
```
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
bases:
- ../../base
namePrefix: dev-
configMapGenerator:
- name: my-configmap
behavior: merge
files:
- plumbing.properties
- secret.properties
EOF
```
One can now generate the configMaps for development:
<!-- @runDev @test -->
```
kustomize build $OVERLAYS/development
```
#### Check the ConfigMap name
The name of the generated `ConfigMap` is visible in this
output.
The name should be something like `dev-my-configmap-b5m75ck895`:
* `"dev-"` comes from the `namePrefix` field,
* `"my-configmap"` comes from the `configMapGenerator/name` field,
* `"-b5m75ck895"` comes from a deterministic hash that `kustomize`
computes from the contents of the configMap.
The hash suffix is critical. If the configMap content
changes, so does the configMap name, along with all
references to that name that appear in the YAML output
from `kustomize`.
The name change means deployments will do a rolling
restart to get new data if this YAML is applied to the
cluster using a command like
> ```
> kustomize build $OVERLAYS/development | kubectl apply -f -
> ```
A deployment has no means to automatically know when or
if a configMap in use by the deployment changes.
If one changes a configMap without changing its name
and all references to that name, one must imperatively
restart the cluster to pick up the change.
The best practice is to treat configMaps as immutable.
Instead of editing configMaps, modify your declarative
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.
### Create and use the overlay for _production_
Next, create the files for the _production_ overlay:
<!-- @productionFiles @test -->
```
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
bases:
- ../../base
namePrefix: prod-
configMapGenerator:
- name: my-configmap
behavior: merge
files:
- plumbing.properties
- secret.properties
EOF
```
One can now generate the configMaps for production:
<!-- @runProd @test -->
```
kustomize build $OVERLAYS/production
```
A CICD process could apply this directly to
the cluser using:
> ```
> kustomize build $OVERLAYS/production | kubectl apply -f -
> ```

View File

@@ -0,0 +1,430 @@
[base]: ../../docs/glossary.md#base
[config]: https://github.com/kinflate/example-hello
[gitops]: ../../docs/glossary.md#gitops
[hello]: https://github.com/monopole/hello
[kustomization]: ../../docs/glossary.md#kustomization
[original]: https://github.com/kinflate/example-hello
[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
Steps:
1. Clone an existing configuration as a [base].
1. Customize it.
1. Create two different [overlays] (_staging_ and _production_)
from the customized base.
1. Run kustomize and kubectl to deploy staging and production.
First define a place to work:
<!-- @makeWorkplace @test -->
```
DEMO_HOME=$(mktemp -d)
```
Alternatively, use
> ```
> DEMO_HOME=~/hello
> ```
## Establish the base
Let's run the [hello] service.
To use [overlays] to create [variants], we must
first establish a common [base].
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 -->
```
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"
```
Look at the directory:
<!-- @runTree @test -->
```
tree $DEMO_HOME
```
Expect something like:
> ```
> /tmp/tmp.IyYQQlHaJP
> └── base
> ├── configMap.yaml
> ├── deployment.yaml
> ├── kustomization.yaml
> └── service.yaml
> ```
One could immediately apply these resources to a
cluster:
> ```
> kubectl apply -f $DEMO_HOME/base
> ```
to instantiate the _hello_ service. `kubectl`
would only recognize the resource files.
### The Base Kustomization
The `base` directory has a [kustomization] file:
<!-- @showKustomization @test -->
```
more $BASE/kustomization.yaml
```
Optionally, run `kustomize` on the base to emit
customized resources to `stdout`:
<!-- @buildBase @test -->
```
kustomize build $BASE
```
### Customize the base
A first customization step could be to change the _app
label_ applied to all resources:
<!-- @addLabel @test -->
```
sed -i 's/app: hello/app: my-hello/' \
$BASE/kustomization.yaml
```
See the effect:
<!-- @checkLabel @test -->
```
kustomize build $BASE | grep -C 3 app:
```
## Create Overlays
Create a _staging_ and _production_ [overlay]:
* _Staging_ enables a risky feature not enabled in production.
* _Production_ has a higher replica count.
* Web server greetings from these cluster
[variants] will differ from each other.
<!-- @overlayDirectories @test -->
```
OVERLAYS=$DEMO_HOME/overlays
mkdir -p $OVERLAYS/staging
mkdir -p $OVERLAYS/production
```
#### Staging Kustomization
In the `staging` directory, make a kustomization
defining a new name prefix, and some different labels.
<!-- @makeStagingKustomization @test -->
```
cat <<'EOF' >$OVERLAYS/staging/kustomization.yaml
namePrefix: staging-
commonLabels:
variant: staging
org: acmeCorporation
commonAnnotations:
note: Hello, I am staging!
bases:
- ../../base
patches:
- map.yaml
EOF
```
#### Staging Patch
Add a configMap customization to change the server
greeting from _Good Morning!_ to _Have a pineapple!_
Also, enable the _risky_ flag.
<!-- @stagingMap @test -->
```
cat <<EOF >$OVERLAYS/staging/map.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: the-map
data:
altGreeting: "Have a pineapple!"
enableRisky: "true"
EOF
```
#### Production Kustomization
In the production directory, make a kustomization
with a different name prefix and labels.
<!-- @makeProductionKustomization @test -->
```
cat <<EOF >$OVERLAYS/production/kustomization.yaml
namePrefix: production-
commonLabels:
variant: production
org: acmeCorporation
commonAnnotations:
note: Hello, I am production!
bases:
- ../../base
patches:
- deployment.yaml
EOF
```
#### Production Patch
Make a production patch that increases the replica
count (because production takes more traffic).
<!-- @productionDeployment @test -->
```
cat <<EOF >$OVERLAYS/production/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: the-deployment
spec:
replicas: 10
EOF
```
## Compare overlays
`DEMO_HOME` now contains:
- a _base_ directory - a slightly customized clone
of the original configuration, and
- an _overlays_ directory, containing the kustomizations
and patches required to create distinct _staging_
and _production_ [variants] in a cluster.
Review the directory structure and differences:
<!-- @listFiles @test -->
```
tree $DEMO_HOME
```
Expecting something like:
> ```
> /tmp/tmp.IyYQQlHaJP1
> ├── base
> │   ├── configMap.yaml
> │   ├── deployment.yaml
> │   ├── kustomization.yaml
> │   └── service.yaml
> └── overlays
> ├── production
> │   ├── deployment.yaml
> │   └── kustomization.yaml
> └── staging
> ├── kustomization.yaml
> └── map.yaml
> ```
Compare the output directly
to see how _staging_ and _production_ differ:
<!-- @compareOutput -->
```
diff \
<(kustomize build $OVERLAYS/staging) \
<(kustomize build $OVERLAYS/production) |\
more
```
The first part of the difference output should look
something like
> ```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)
> ```
## Deploy
The individual resource sets are:
<!-- @buildStaging @test -->
```
kustomize build $OVERLAYS/staging
```
<!-- @buildProduction @test -->
```
kustomize build $OVERLAYS/production
```
To deploy, pipe the above commands to kubectl apply:
> ```
> kustomize build $OVERLAYS/staging |\
> kubectl apply -f -
> ```
> ```
> kustomize build $OVERLAYS/production |\
> kubectl apply -f -
> ```
## Rolling updates
### Review
The _hello-world_ deployment running in this cluster is
configured with data from a configMap.
The deployment refers to this map by name:
<!-- @showDeployment @test -->
```
grep -C 2 configMapKeyRef $DEMO_HOME/base/deployment.yaml
```
Changing the data held by a live configMap in a cluster
is considered bad practice. Deployments have no means
to know that the configMaps they refer to have
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
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.
### How this works with kustomize
The _staging_ [variant] here has a configMap [patch]:
<!-- @showMapPatch @test -->
```
cat $OVERLAYS/staging/map.yaml
```
This patch is by definition a named but not necessarily
complete resource spec intended to modify a complete
resource spec.
The resource it modifies is here:
<!-- @showMapBase @test -->
```
cat $DEMO_HOME/base/configMap.yaml
```
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 these names. To see the names
ultimately used in the cluster, just run kustomize:
<!-- @grepStagingName @test -->
```
kustomize build $OVERLAYS/staging |\
grep -B 8 -A 1 staging-the-map
```
The configMap name is prefixed by _staging-_, per the
`namePrefix` 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_:
<!-- @grepStagingHash @test -->
```
kustomize build $OVERLAYS/staging | grep hhhhkfmgmk
```
Now modify the map patch, to change the greeting
the server will use:
<!-- @changeMap @test -->
```
sed -i 's/pineapple/kiwi/' $OVERLAYS/staging/map.yaml
```
Run kustomize again to see the new names:
<!-- @grepStagingName @test -->
```
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
configMap name itself, and two in the deployment that
uses the map:
<!-- @countHashes @test -->
```
test 3 == \
$(kustomize build $OVERLAYS/staging | grep khk45ktkd9 | wc -l)
```
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
unused maps.
## Rollback
To rollback, one would undo whatever edits were made to
the configuation in source control, then rerun kustomize
on the reverted configuration and apply it to the
cluster.

View File

@@ -0,0 +1,7 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: the-map
data:
altGreeting: "Good Morning!"
enableRisky: "false"

View File

@@ -0,0 +1,30 @@
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

View File

@@ -0,0 +1,9 @@
# Example configuration for the webserver
# at https://github.com/monopole/hello
commonLabels:
app: hello
resources:
- deployment.yaml
- configMap.yaml
- service.yaml

View File

@@ -0,0 +1,12 @@
kind: Service
apiVersion: v1
metadata:
name: the-service
spec:
selector:
deployment: hello
type: LoadBalancer
ports:
- protocol: TCP
port: 8666
targetPort: 8080

84
examples/integration_tests.sh Executable file
View File

@@ -0,0 +1,84 @@
#!/bin/bash
# Copyright 2018 The Kubernetes Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# This script is run periodically by kubernetes
# test-infra.
#
# It uses kustomized configurations in a live cluster,
# to assure that the generated configs work as
# expected.
#
# This script assumes that the process running it has
# checked out the kubernetes-sigs/kustomize repo, and
# has cd'ed into it (i.e. the directory above "examples")
# before running it.
#
# At time of writing, its 'call point' was in
# https://github.com/kubernetes/test-infra/blob/master/jobs/config.json
function exitWith {
local msg=$1
echo >&2 ${msg}
exit 1
}
export -f exitWith
function expectCommand {
command -v $1 >/dev/null 2>&1 || \
{ exitWith "Expected $1 on PATH."; }
}
function setUpEnv {
local repo=$(git rev-parse --show-toplevel)
cd $repo
[[ $? -eq 0 ]] || "Failed to cd to $repo"
echo "pwd is " `pwd`
local expectedRepo=kubernetes-sigs/kustomize
if [[ `pwd` != */$expectedRepo ]]; then
exitWith "Script must be run from $expectedRepo"
fi
go install . || \
{ exitWith "Failed to install kustomize."; }
PATH=$GOPATH/bin:$PATH
expectCommand kustomize
expectCommand kubectl
}
function runTest {
local script=$1
shift
local args=$@
if [ ! -x "$script" ]; then
exitWith "Unable to run $script"
fi
$script "$args"
[[ $? -eq 0 ]] || exitWith "Failed: $script $args"
echo "$script passed."
}
setUpEnv
pushd examples
runTest ldap/integration_test.sh ldap/base
popd

281
examples/ldap/README.md Normal file
View File

@@ -0,0 +1,281 @@
[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
# Demo: LDAP with variants
Steps:
1. Clone an existing configuration as a [base].
1. Customize it.
1. Create two different [overlays] (_staging_ and _production_)
from the customized base.
1. Run kustomize and kubectl to deploy staging and production.
First define a place to work:
<!-- @makeWorkplace @test -->
```
DEMO_HOME=$(mktemp -d)
```
Alternatively, use
> ```
> DEMO_HOME=~/ldap
> ```
## Establish the base
To use [overlays] to create [variants], we must
first establish a common [base].
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 -->
```
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}"
```
Look at the directory:
<!-- @runTree @test -->
```
tree $DEMO_HOME
```
Expect something like:
> ```
> /tmp/tmp.IyYQQlHaJP
> └── base
> ├── deployment.yaml
> ├── env.startup.txt
> ├── kustomization.yaml
> └── service.yaml
> ```
One could immediately apply these resources to a
cluster:
> ```
> kubectl apply -f $DEMO_HOME/base
> ```
to instantiate the _ldap_ service. `kubectl`
would only recognize the resource files.
### The Base Kustomization
The `base` directory has a [kustomization] file:
<!-- @showKustomization @test -->
```
more $BASE/kustomization.yaml
```
Optionally, run `kustomize` on the base to emit
customized resources to `stdout`:
<!-- @buildBase @test -->
```
kustomize build $BASE
```
### Customize the base
A first customization step could be to set the name prefix to all resources:
<!-- @namePrefix @test -->
```
cd $BASE
kustomize edit set nameprefix "my-"
```
See the effect:
<!-- @checkNameprefix @test -->
```
kustomize build $BASE | grep -C 3 "my-"
```
## Create Overlays
Create a _staging_ and _production_ [overlay]:
* _Staging_ adds a configMap.
* _Production_ has a higher replica count and a persistent disk.
* [variants] will differ from each other.
<!-- @overlayDirectories @test -->
```
OVERLAYS=$DEMO_HOME/overlays
mkdir -p $OVERLAYS/staging
mkdir -p $OVERLAYS/production
```
#### Staging Kustomization
Download the staging customization and patch.
<!-- @downloadStagingKustomization @test -->
```
curl -s -o "$OVERLAYS/staging/#1" "$CONTENT/overlays/staging\
/{config.env,deployment.yaml,kustomization.yaml}"
```
The staging customization adds a configMap.
> ```cat $OVERLAYS/staging/kustomization.yaml
> (...truncated)
> configMapGenerator:
> - name: env-config
> files:
> - config.env
> ```
as well as 2 replica
> ```cat $OVERLAYS/staging/deployment.yaml
> apiVersion: apps/v1beta2
> kind: Deployment
> metadata:
> name: ldap
> spec:
> replicas: 2
> ```
#### Production Kustomization
Download the production customization and patch.
<!-- @downloadProductionKustomization @test -->
```
curl -s -o "$OVERLAYS/production/#1" "$CONTENT/overlays/production\
/{deployment.yaml,kustomization.yaml}"
```
The production customization adds 6 replica as well as a consistent disk.
> ```cat $OVERLAYS/production/deployment.yaml
> apiVersion: apps/v1beta2
> kind: Deployment
> metadata:
> name: ldap
> spec:
> replicas: 6
> template:
> spec:
> volumes:
> - name: ldap-data
> emptyDir: null
> gcePersistentDisk:
> pdName: ldap-persistent-storage
> ```
## Compare overlays
`DEMO_HOME` now contains:
- a _base_ directory - a slightly customized clone
of the original configuration, and
- an _overlays_ directory, containing the kustomizations
and patches required to create distinct _staging_
and _production_ [variants] in a cluster.
Review the directory structure and differences:
<!-- @listFiles @test -->
```
tree $DEMO_HOME
```
Expecting something like:
> ```
> /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
> ```
Compare the output directly
to see how _staging_ and _production_ differ:
<!-- @compareOutput -->
```
diff \
<(kustomize build $OVERLAYS/staging) \
<(kustomize build $OVERLAYS/production) |\
more
```
The difference output should look something like
> ```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)
> ```
## Deploy
The individual resource sets are:
<!-- @buildStaging @test -->
```
kustomize build $OVERLAYS/staging
```
<!-- @buildProduction @test -->
```
kustomize build $OVERLAYS/production
```
To deploy, pipe the above commands to kubectl apply:
> ```
> kustomize build $OVERLAYS/staging |\
> kubectl apply -f -
> ```
> ```
> kustomize build $OVERLAYS/production |\
> kubectl apply -f -
> ```

View File

@@ -0,0 +1,46 @@
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: ldap
labels:
app: ldap
spec:
replicas: 1
selector:
matchLabels:
app: ldap
template:
metadata:
labels:
app: ldap
spec:
containers:
- name: ldap
image: osixia/openldap:1.1.11
args: ["--copy-service"]
volumeMounts:
- name: ldap-data
mountPath: /var/lib/ldap
- name: ldap-config
mountPath: /etc/ldap/slapd.d
- name: ldap-certs
mountPath: /container/service/slapd/assets/certs
- name: configmap-volume
mountPath: /container/environment/01-custom
- name: container-run
mountPath: /container/run
ports:
- containerPort: 389
name: openldap
volumes:
- name: ldap-data
emptyDir: {}
- name: ldap-config
emptyDir: {}
- name: ldap-certs
emptyDir: {}
- name: "configmap-volume"
configMap:
name: "ldap-configmap"
- name: container-run
emptyDir: {}

View File

@@ -0,0 +1,61 @@
# This is the default image startup configuration file
# this file define environment variables used during the container **first start** in **startup files**.
# This file is deleted right after startup files are processed for the first time,
# after that all these values will not be available in the container environment.
# This helps to keep your container configuration secret.
# more information : https://github.com/osixia/docker-light-baseimage
# Required and used for new ldap server only
LDAP_ORGANISATION: Example Inc.
LDAP_DOMAIN: example.org
LDAP_BASE_DN: #if empty automatically set from LDAP_DOMAIN
LDAP_ADMIN_PASSWORD: admin
LDAP_CONFIG_PASSWORD: config
LDAP_READONLY_USER: false
LDAP_READONLY_USER_USERNAME: readonly
LDAP_READONLY_USER_PASSWORD: readonly
LDAP_RFC2307BIS_SCHEMA: false
# Backend
LDAP_BACKEND: hdb
# Tls
LDAP_TLS: true
LDAP_TLS_CRT_FILENAME: ldap.crt
LDAP_TLS_KEY_FILENAME: ldap.key
LDAP_TLS_CA_CRT_FILENAME: ca.crt
LDAP_TLS_ENFORCE: false
LDAP_TLS_CIPHER_SUITE: SECURE256:+SECURE128:-VERS-TLS-ALL:+VERS-TLS1.2:-RSA:-DHE-DSS:-CAMELLIA-128-CBC:-CAMELLIA-256-CBC
LDAP_TLS_VERIFY_CLIENT: demand
# Replication
LDAP_REPLICATION: false
# variables $LDAP_BASE_DN, $LDAP_ADMIN_PASSWORD, $LDAP_CONFIG_PASSWORD
# are automaticaly replaced at run time
# if you want to add replication to an existing ldap
# adapt LDAP_REPLICATION_CONFIG_SYNCPROV and LDAP_REPLICATION_DB_SYNCPROV to your configuration
# avoid using $LDAP_BASE_DN, $LDAP_ADMIN_PASSWORD and $LDAP_CONFIG_PASSWORD variables
LDAP_REPLICATION_CONFIG_SYNCPROV: binddn="cn=admin,cn=config" bindmethod=simple credentials=$LDAP_CONFIG_PASSWORD searchbase="cn=config" type=refreshAndPersist retry="60 +" timeout=1 starttls=critical
LDAP_REPLICATION_DB_SYNCPROV: binddn="cn=admin,$LDAP_BASE_DN" bindmethod=simple credentials=$LDAP_ADMIN_PASSWORD searchbase="$LDAP_BASE_DN" type=refreshAndPersist interval=00:00:00:10 retry="60 +" timeout=1 starttls=critical
LDAP_REPLICATION_HOSTS:
- ldap://ldap.example.org # The order must be the same on all ldap servers
- ldap://ldap2.example.org
# Do not change the ldap config
# - If set to true with an existing database, config will remain unchanged. Image tls and replication config will not be run.
# The container can be started with LDAP_ADMIN_PASSWORD and LDAP_CONFIG_PASSWORD empty or filled with fake data.
# - If set to true when bootstrapping a new database, bootstap ldif and schema will not be added and tls and replication config will not be run.
KEEP_EXISTING_CONFIG: false
# Remove config after setup
LDAP_REMOVE_CONFIG_AFTER_SETUP: true
# ssl-helper environment variables prefix
LDAP_SSL_HELPER_PREFIX: ldap # ssl-helper first search config from LDAP_SSL_HELPER_* variables, before SSL_HELPER_* variables.

View File

@@ -0,0 +1,7 @@
resources:
- deployment.yaml
- service.yaml
configMapGenerator:
- name: ldap-configmap
files:
- env.startup.txt

View File

@@ -0,0 +1,11 @@
apiVersion: v1
kind: Service
metadata:
labels:
app: ldap
name: ldap-service
spec:
ports:
- port: 389
selector:
app: ldap

136
examples/ldap/integration_test.sh Executable file
View File

@@ -0,0 +1,136 @@
#!/bin/bash
# Copyright 2018 The Kubernetes Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# ----------------------------------------------------
#
# This script tests the ldap kustomization demo
# against a real cluster.
#
# - deploy a ldap server by the output of kustomize
# - add a user
# - query a user
# - delete a user
#
# This script is a test that (passes|fails) if exit
# code is (0|1).
set -x
function configureCluster {
local tmpDir=$1
local target=$2
echo Kustomizing: \"$target\"
ls $target
kustomize build $target > $tmpDir/my.yaml
[[ $? -eq 0 ]] || { exitWith "Failed to kustomize build"; }
# Setting the namespace this way is a test-infra thing?
kubectl config set-context \
$(kubectl config current-context) --namespace=default
kubectl apply -f $tmpDir/my.yaml
[[ $? -eq 0 ]] || { exitWith "Failed to run kubectl apply"; }
sleep 20
}
function tearDownCluster {
local tmpDir=$1
kubectl delete -f $tmpDir/my.yaml
rm -rf $tmpDir
}
function getPodField {
echo $(kubectl get pods -l app=ldap -o jsonpath=$1)
}
function podExec {
kubectl exec $podName -c $containerName -- "$@"
}
function addUser {
local tmpDir=$1
local namespace=`getPodField '{.items[0].metadata.namespace}'`
[[ -z $namespace ]] && { exitWith "Unable to get namespace"; }
local myUserFile=$tmpDir/user.ldif
local podUserFile=/tmp/user.ldif
cat <<EOF >$myUserFile
dn: cn=The Postmaster,dc=example,dc=org
objectClass: organizationalRole
cn: The Postmaster
EOF
[[ -f $myUserFile ]] || \
{ exitWith "Failed to create $myUserFile"; }
kubectl cp $myUserFile \
$namespace/$podName:$podUserFile || \
{ exitWith "Failed to copy $myUserFile to pod $podName"; }
rm $myUserFile
podExec \
ldapadd \
-x \
-w admin \
-H ldap://localhost \
-D "cn=admin,dc=example,dc=org" \
-f $podUserFile
}
function getUserCount {
local result=$(\
podExec \
ldapsearch \
-x \
-w admin \
-H ldap://localhost \
-D "cn=admin,dc=example,dc=org" \
-b dc=example,dc=org \
)
return $(echo $result | grep "cn: The Postmaster" | wc -l)
}
function deleteAddedUser {
podExec \
ldapdelete \
-v \
-x \
-w admin \
-H ldap://localhost \
-D "cn=admin,dc=example,dc=org" \
"cn=The Postmaster,dc=example,dc=org"
}
tmpDir=$(mktemp -d)
configureCluster $tmpDir $1
podName=`getPodField '{.items[0].metadata.name}'`
[[ -z $podName ]] && { exitWith "Unable to get pod name"; }
containerName="ldap"
getUserCount; [[ $? -eq 0 ]] || { exitWith "Expected no users."; }
addUser $tmpDir || { exitWith "Failed to add a user"; }
getUserCount; [[ $? -eq 1 ]] || { exitWith "Couldn't find the new added user"; }
deleteAddedUser || { exitWith "Failed to delete the user"; }
getUserCount; [[ $? -eq 0 ]] || { exitWith "User has not been deleted."; }
tearDownCluster $tmpDir

View File

@@ -0,0 +1,13 @@
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: ldap
spec:
replicas: 6
template:
spec:
volumes:
- name: ldap-data
emptyDir: null
gcePersistentDisk:
pdName: ldap-persistent-storage

View File

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

View File

@@ -0,0 +1,2 @@
DB_USERNAME=admin
DB_PASSWORD=somepw

View File

@@ -0,0 +1,7 @@
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: ldap
spec:
replicas: 2

View File

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

203
examples/mySql/README.md Normal file
View File

@@ -0,0 +1,203 @@
# Demo: MySql
This example takes some off-the-shelf k8s resources
designed for MySQL, and customizes them to suit a
production scenario.
In the production environment we want:
- MySQL resource names to be prefixed by 'prod-'.
- MySQL resources to have 'env: prod' labels.
- MySQL to use persistent disk for storing data.
First make a place to work:
<!-- @makeDemoHome @test -->
```
DEMO_HOME=$(mktemp -d)
```
### Download resources
To keep this document shorter, the base resources
needed to run MySql on a k8s cluster are off in a
supplemental data directory rather than declared here
as HERE documents.
Download them:
<!-- @downloadResources @test -->
```
curl -s -o "$DEMO_HOME/#1.yaml" "https://raw.githubusercontent.com\
/kubernetes-sigs/kustomize\
/master/examples/mySql\
/{deployment,secret,service}.yaml"
```
### Initialize kustomization.yaml
The `kustomize` program gets its instructions from
a file called `kustomization.yaml`.
Start this file:
<!-- @kustomizeYaml @test -->
```
touch $DEMO_HOME/kustomization.yaml
```
### Add the resources
<!-- @addResources @test -->
```
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`'s resources section should contain:
> ```
> resources:
> - secret.yaml
> - service.yaml
> - deployment.yaml
> ```
### Name Customization
Arrange for the MySQL resources to begin with prefix
_prod-_ (since they are meant for the _production_
environment):
<!-- @customizeLabel @test -->
```
cd $DEMO_HOME
kustomize edit set nameprefix 'prod-'
cat kustomization.yaml
```
`kustomization.yaml` should have updated value of namePrefix field:
> ```
> namePrefix: prod-
> ```
This `namePrefix` directive adds _prod-_ to all
resource names.
<!-- @genNamePrefixConfig @test -->
```
kustomize build $DEMO_HOME
```
The output should contain:
> ```
> apiVersion: v1
> data:
> password: YWRtaW4=
> kind: Secret
> metadata:
> ....
> name: prod-mysql-pass-d2gtcm2t2k
> ---
> apiVersion: v1
> kind: Service
> metadata:
> ....
> name: prod-mysql
> spec:
> ....
> ---
> apiVersion: apps/v1beta2
> kind: Deployment
> metadata:
> ....
> name: prod-mysql
> spec:
> selector:
> ....
> ```
### Label Customization
We want resources in production environment to have
certain labels so that we can query them by label
selector.
`kustomize` does not have `edit set label` command to add
a label, but one can always edit `kustomization.yaml` directly:
<!-- @customizeLabels @test -->
```
sed -i 's/app: helloworld/app: prod/' \
$DEMO_HOME/kustomization.yaml
```
At this point, running `kustomize build` will
generate MySQL configs with name-prefix 'prod-' and
labels `env:prod`.
### Storage customization
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
resources.
<!-- @createPatchFile @test -->
```
cat <<'EOF' > $DEMO_HOME/persistent-disk.yaml
apiVersion: apps/v1beta2 # 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
```
Add the patch file to `kustomization.yaml`:
<!-- @specifyPatch @test -->
```
cat <<'EOF' >> $DEMO_HOME/kustomization.yaml
patches:
- persistent-disk.yaml
EOF
```
Lets break this down:
- In the first step, we created a YAML file named
`persistent-disk.yaml` to patch the resource defined
in deployment.yaml
- Then we added `persistent-disk.yaml` to list of
`patches` in `kustomization.yaml`. `kustomize build`
will apply this patch to the deployment resource with
the name `mysql` as defined in the patch.
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 -->
```
kustomize build $DEMO_HOME # | kubectl apply -f -
```

View File

@@ -0,0 +1,35 @@
apiVersion: apps/v1beta2 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
name: mysql
labels:
app: mysql
spec:
selector:
matchLabels:
app: mysql
strategy:
type: Recreate
template:
metadata:
labels:
app: mysql
spec:
containers:
- image: mysql:5.6
name: mysql
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-pass
key: password
ports:
- containerPort: 3306
name: mysql
volumeMounts:
- name: mysql-persistent-storage
mountPath: /var/lib/mysql
volumes:
- name: mysql-persistent-storage
emptyDir: {}

View File

@@ -0,0 +1,9 @@
apiVersion: v1
kind: Secret
metadata:
creationTimestamp: null
name: mysql-pass-d2gtcm2t2k
type: Opaque
data:
# Default password is "admin".
password: YWRtaW4=

View File

@@ -0,0 +1,11 @@
apiVersion: v1
kind: Service
metadata:
name: mysql
labels:
app: mysql
spec:
ports:
- port: 3306
selector:
app: mysql

View File

@@ -0,0 +1,307 @@
# Demo: SpringBoot
In this tutorial, you will learn - how to use `kustomize` to customize a basic Spring Boot application's
k8s configuration for production use cases.
In the production environment we want to customize the following:
- add application specific configuration for this Spring Boot application
- configure prod DB access configuration
- resource names to be prefixed by 'prod-'.
- resources to have 'env: prod' labels.
- JVM memory to be properly set.
- health check and readiness check.
First make a place to work:
<!-- @makeDemoHome @test -->
```
DEMO_HOME=$(mktemp -d)
```
### Download resources
To keep this document shorter, the base resources
needed to run springboot on a k8s cluster are off in a
supplemental data directory rather than declared here
as HERE documents.
Download them:
<!-- @downloadResources @test -->
```
CONTENT="https://raw.githubusercontent.com\
/kubernetes-sigs/kustomize\
/master/examples/springboot"
curl -s -o "$DEMO_HOME/#1.yaml" \
"$CONTENT/base/{deployment,service}.yaml"
```
### Initialize kustomization.yaml
The `kustomize` program gets its instructions from
a file called `kustomization.yaml`.
Start this file:
<!-- @kustomizeYaml @test -->
```
touch $DEMO_HOME/kustomization.yaml
```
### Add the resources
<!-- @addResources @test -->
```
cd $DEMO_HOME
kustomize edit add resource service.yaml
kustomize edit add resource deployment.yaml
cat kustomization.yaml
```
`kustomization.yaml`'s resources section should contain:
> ```
> resources:
> - service.yaml
> - deployment.yaml
> ```
### Add configMap generator
<!-- @addConfigMap @test -->
```
echo "app.name=Kustomize Demo" >$DEMO_HOME/application.properties
kustomize edit add configmap demo-configmap \
--from-file application.properties
cat kustomization.yaml
```
`kustomization.yaml`'s configMapGenerator section should contain:
> ```
> configMapGenerator:
> - files:
> - application.properties
> name: demo-configmap
> ```
### Customize configMap
We want to add database credentials for the prod environment. In general, these credentials can be put into the file `application.properties`.
However, for some cases, we want to keep the credentials in a different file and keep application specific configs in `application.properties`.
With this clear separation, the credentials and application specific things can be managed and maintained flexibly by different teams.
For example, application developers only tune the application configs in `application.properties` and operation teams or SREs
only care about the credentials.
For Spring Boot application, we can set an active profile through the environment variable `spring.profiles.active`. Then
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 -->
```
cat <<EOF >$DEMO_HOME/patch.yaml
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: sbdemo
spec:
template:
spec:
containers:
- name: sbdemo
env:
- name: spring.profiles.active
value: prod
EOF
kustomize edit add patch patch.yaml
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`'s configMapGenerator section should contain:
> ```
> configMapGenerator:
> - files:
> - application.properties
> - application-prod.properties
> name: demo-configmap
> ```
### Name Customization
Arrange for the resources to begin with prefix
_prod-_ (since they are meant for the _production_
environment):
<!-- @customizeLabel @test -->
```
cd $DEMO_HOME
kustomize edit set nameprefix 'prod-'
```
`kustomization.yaml` should have updated value of namePrefix field:
> ```
> namePrefix: prod-
> ```
This `namePrefix` directive adds _prod-_ to all
resource names, as can be seen by building the
resources:
<!-- @build1 @test -->
```
kustomize build $DEMO_HOME | grep prod-
```
### Label Customization
We want resources in production environment to have
certain labels so that we can query them by label
selector.
`kustomize` does not have `edit set label` command to
add a label, but one can always edit
`kustomization.yaml` directly:
<!-- @customizeLabels @test -->
```
cat <<EOF >>$DEMO_HOME/kustomization.yaml
commonLabels:
env: prod
EOF
```
Confirm that the resources now all have names prefixed
by `prod-` and the label tuple `env:prod`:
<!-- @build2 @test -->
```
kustomize build $DEMO_HOME | grep -C 3 env
```
### Download Patch for JVM memory
When a Spring Boot application is deployed in a k8s cluster, the JVM is running inside a container. We want to set memory limit for the container and make sure
the JVM is aware of that limit. In K8s deployment, we can set the resource limits for containers and inject these limits to
some environment variables by downward API. When the container starts to run, it can pick up the environment variables and
set JVM options accordingly.
Download the patch `memorylimit_patch.yaml`. It contains the memory limits setup.
<!-- @downloadPatch @test -->
```
curl -s -o "$DEMO_HOME/#1.yaml" \
"$CONTENT/overlays/production/{memorylimit_patch}.yaml"
cat $DEMO_HOME/memorylimit_patch.yaml
```
The output contains
> ```
> apiVersion: apps/v1beta2
> 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
> ```
### Download Patch for health check
We also want to add liveness check and readiness check in the production environment. Spring Boot application
has end points such as `/actuator/health` for this. We can customize the k8s deployment resource to talk to Spring Boot end point.
Download the patch `healthcheck_patch.yaml`. It contains the liveness probes and readyness probes.
<!-- @downloadPatch @test -->
```
curl -s -o "$DEMO_HOME/#1.yaml" \
"$CONTENT/overlays/production/{healthcheck_patch}.yaml"
cat $DEMO_HOME/healthcheck_patch.yaml
```
The output contains
> ```
> apiVersion: apps/v1beta2
> 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
> ```
### Add patches
Add these patches to the kustomization:
<!-- @addPatch @test -->
```
cd $DEMO_HOME
kustomize edit add patch memorylimit_patch.yaml
kustomize edit add patch healthcheck_patch.yaml
```
`kustomization.yaml` should have patches field:
> ```
> patches:
> - patch.yaml
> - memorylimit_patch.yaml
> - healthcheck_patch.yaml
> ```
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 -->
```
kustomize build $DEMO_HOME # | kubectl apply -f -
```

View File

@@ -0,0 +1,27 @@
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: sbdemo
labels:
app: sbdemo
spec:
selector:
matchLabels:
app: sbdemo
template:
metadata:
labels:
app: sbdemo
spec:
containers:
- name: sbdemo
image: jingfang/sbdemo
ports:
- containerPort: 8080
volumeMounts:
- name: demo-config
mountPath: /config
volumes:
- name: "demo-config"
configMap:
name: "demo-configmap"

View File

@@ -0,0 +1,12 @@
apiVersion: v1
kind: Service
metadata:
name: sbdemo
labels:
app: sbdemo
spec:
ports:
- port: 8080
selector:
app: sbdemo
type: LoadBalancer

View File

@@ -0,0 +1,5 @@
app.name=Staging Kinflate Demo
spring.jpa.hibernate.ddl-auto=update
spring.datasource.url=jdbc:mysql://<production_db_ip>:3306/db_example
spring.datasource.username=root
spring.datasource.password=admin

View File

@@ -0,0 +1,22 @@
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: sbdemo
spec:
replicas: 2
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

View File

@@ -0,0 +1,7 @@
bases:
- ../../base
patches:
- patch.yaml
- healthcheck_patch.yaml
- memorylimit_patch.yaml
namePrefix: production-

View File

@@ -0,0 +1,20 @@
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: sbdemo
spec:
replicas: 2
template:
spec:
containers:
- name: sbdemo
resources:
limits:
memory: 1250Mi
requests:
memory: 1250Mi
env:
- name: MEM_TOTAL_MB
valueFrom:
resourceFieldRef:
resource: limits.memory

View File

@@ -0,0 +1,13 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: demo-configmap
data:
application.properties: |
app.name=Staging Kinflate Demo
spring.jpa.hibernate.ddl-auto=update
spring.datasource.url=jdbc:mysql://<production_db_ip>:3306/db_example
spring.datasource.username=root
spring.datasource.password=admin
server.tomcat.max-threads=20
server.tomcat.min-spare-threads=3

View File

@@ -0,0 +1,5 @@
app.name=Staging Kinflate Demo
spring.jpa.hibernate.ddl-auto=update
spring.datasource.url=jdbc:mysql://<staging_db_ip>:3306/db_example
spring.datasource.username=root
spring.datasource.password=admin

View File

@@ -0,0 +1,11 @@
bases:
- ../../base
namePrefix: staging-
configMapGenerator:
- name: demo-configmap
behavior: merge
files:
- application.properties
literals:
- foo=bar
env: staging.env

View File

@@ -0,0 +1 @@
staging