Merge pull request #453 from monopole/configmapdemp
configmapgenerator example
This commit is contained in:
commit
35a269810a
|
|
@ -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
|
||||||
|
defintion 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 -
|
||||||
|
> ```
|
||||||
Loading…
Reference in New Issue