mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-14 10:30:59 +00:00
Generalize configuration functions spec in RFC format.
As defined in `kustomize config docs-fn-spec`, configuration functions can be implemented using any toolchain and invoked using any container workflow orchestrator (e.g. Tekton, Cloud Build) or run directly using docker run. functions-impl describes using `kustomize config run` as an example orchestrator for invoking configuration functions.
This commit is contained in:
@@ -93,8 +93,13 @@ func NewConfigCommand(name string) *cobra.Command {
|
|||||||
})
|
})
|
||||||
root.AddCommand(&cobra.Command{
|
root.AddCommand(&cobra.Command{
|
||||||
Use: "docs-fn",
|
Use: "docs-fn",
|
||||||
Short: "[Alpha] Documentation for writing containerized functions run by run.",
|
Short: "[Alpha] Documentation for developing and invoking Configuration Functions.",
|
||||||
Long: api.ConfigFnLong,
|
Long: api.FunctionsImplLong,
|
||||||
|
})
|
||||||
|
root.AddCommand(&cobra.Command{
|
||||||
|
Use: "docs-fn-spec",
|
||||||
|
Short: "[Alpha] Documentation for Configuration Functions Specification.",
|
||||||
|
Long: api.FunctionsSpecLong,
|
||||||
})
|
})
|
||||||
root.AddCommand(&cobra.Command{
|
root.AddCommand(&cobra.Command{
|
||||||
Use: "docs-io-annotations",
|
Use: "docs-io-annotations",
|
||||||
|
|||||||
@@ -1,281 +0,0 @@
|
|||||||
# Configuration Functions API Semantics
|
|
||||||
|
|
||||||
Configuration Functions are functions packaged as executables in containers which enable
|
|
||||||
**shift-left practices**. They configure applications and infrastructure through
|
|
||||||
Kubernetes style Resource Configuration, but run locally pre-commit.
|
|
||||||
|
|
||||||
Configuration functions enable shift-left practices (client-side) through:
|
|
||||||
|
|
||||||
- Pre-commit / delivery validation and linting of configuration
|
|
||||||
- e.g. Fail if any containers don't have PodSecurityPolicy or CPU / Memory limits
|
|
||||||
- Implementation of abstractions as client actuated APIs (e.g. templating)
|
|
||||||
- e.g. Create a client-side *"CRD"* for generating configuration checked into git
|
|
||||||
- Aspect Orient configuration / Injection of cross-cutting configuration
|
|
||||||
- e.g. T-Shirt size containers by annotating Resources with `small`, `medium`, `large`
|
|
||||||
and inject the cpu and memory resources into containers accordingly.
|
|
||||||
- e.g. Inject `init` and `side-car` containers into Resources based off of Resource
|
|
||||||
Type, annotations, etc.
|
|
||||||
|
|
||||||
Performing these on the client rather than the server enables:
|
|
||||||
|
|
||||||
- Configuration to be reviewed prior to being sent to the API server
|
|
||||||
- Configuration to be validated as part of the CD pipeline
|
|
||||||
- Configuration for Resources to validated holistically rather than individually
|
|
||||||
per-Resource -- e.g. ensure the `Service.selector` and `Deployment.spec.template` labels
|
|
||||||
match.
|
|
||||||
- MutatingWebHooks are scoped to a single Resource instance at a time.
|
|
||||||
- Low-level tweaks to the output of high-level abstractions -- e.g. add an `init container`
|
|
||||||
to a client *"CRD"* Resource after it was generated.
|
|
||||||
- Composition and layering of multiple functions together
|
|
||||||
- Compose generation, injection, validation together
|
|
||||||
|
|
||||||
Configuration Functions are implemented as executable programs published in containers which:
|
|
||||||
|
|
||||||
- Accept as input (stdin):
|
|
||||||
- A list of Resource Configuration
|
|
||||||
- A Function Configuration (to configure the function itself)
|
|
||||||
- Emit as output (stdout + exit):
|
|
||||||
- A list of Resource Configuration
|
|
||||||
- An exit code for success / failure
|
|
||||||
|
|
||||||
### Function Specification
|
|
||||||
|
|
||||||
- Functions **SHOULD** be published as container images containing a `CMD` invoking an executable.
|
|
||||||
- Functions **MUST** accept input on STDIN a `ResourceList` containing the Resources and
|
|
||||||
`functionConfig`.
|
|
||||||
- Functions **MUST** emit output on STDOUT a `ResourceList` containing the modified
|
|
||||||
Resources.
|
|
||||||
- Functions **MUST** exit non-0 on failure, and exit 0 on success.
|
|
||||||
- Functions **MAY** emit output on STDERR with error messaging.
|
|
||||||
- Functions performing validation **SHOULD** exit failure and emit error messaging
|
|
||||||
on a validation failure.
|
|
||||||
- Functions generating Resources **SHOULD** retain non-conflicting changes on the
|
|
||||||
generated Resources -- e.g. 1. the function generates a Deployment, but doesn't
|
|
||||||
specify `cpu`, 2. the user sets the `cpu` on the generated Resource, 3. the
|
|
||||||
function should keep the `cpu` when regenerating the Resource a second time.
|
|
||||||
- Functions **SHOULD** be usable outside `kustomize config run` -- e.g. though pipeline
|
|
||||||
mechanisms such as Tekton.
|
|
||||||
|
|
||||||
#### Input Format
|
|
||||||
|
|
||||||
Functions must accept on STDIN:
|
|
||||||
|
|
||||||
`ResourceList`:
|
|
||||||
- contains `items` field, same as `List.items`
|
|
||||||
- contains `functionConfig` field -- a single item with the configuration for the function itself
|
|
||||||
|
|
||||||
Example `ResourceList` Input:
|
|
||||||
|
|
||||||
apiVersion: config.kubernetes.io/v1alpha1
|
|
||||||
kind: ResourceList
|
|
||||||
functionConfig:
|
|
||||||
apiVersion: example.com/v1beta1
|
|
||||||
kind: Nginx
|
|
||||||
metadata:
|
|
||||||
name: my-instance
|
|
||||||
annotations:
|
|
||||||
config.kubernetes.io/local-config: "true"
|
|
||||||
spec:
|
|
||||||
replicas: 5
|
|
||||||
items:
|
|
||||||
- apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: my-instance
|
|
||||||
spec:
|
|
||||||
replicas: 3
|
|
||||||
...
|
|
||||||
- apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: my-instance
|
|
||||||
spec:
|
|
||||||
...
|
|
||||||
|
|
||||||
#### Output Format
|
|
||||||
|
|
||||||
Functions must emit on STDOUT:
|
|
||||||
|
|
||||||
`ResourceList`:
|
|
||||||
- contains `items` field, same as `List.items`
|
|
||||||
|
|
||||||
Example `ResourceList` Output:
|
|
||||||
|
|
||||||
apiVersion: config.kubernetes.io/v1alpha1
|
|
||||||
kind: ResourceList
|
|
||||||
items:
|
|
||||||
- apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: my-instance
|
|
||||||
spec:
|
|
||||||
replicas: 5
|
|
||||||
...
|
|
||||||
- apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: my-instance
|
|
||||||
spec:
|
|
||||||
...
|
|
||||||
|
|
||||||
#### Container Environment
|
|
||||||
|
|
||||||
When run by `kustomize config run`, functions are run in containers with the
|
|
||||||
following environment:
|
|
||||||
|
|
||||||
- Network: `none`
|
|
||||||
- User: `nobody`
|
|
||||||
- Security Options: `no-new-privileges`
|
|
||||||
- Volumes: the volume containing the `functionConfig` yaml is mounted under `/local` as `ro`
|
|
||||||
|
|
||||||
### Example Function Implementation
|
|
||||||
|
|
||||||
Following is an example for implementing an nginx abstraction using a config
|
|
||||||
function.
|
|
||||||
|
|
||||||
#### `nginx-template.sh`
|
|
||||||
|
|
||||||
`nginx-template.sh` is a simple bash script which uses a *heredoc* as a templating solution
|
|
||||||
for generating Resources from the functionConfig input fields.
|
|
||||||
|
|
||||||
The script wraps itself using `config run wrap -- $0` which will:
|
|
||||||
|
|
||||||
1. Parse the `ResourceList.functionConfig` (provided to the container stdin) into env vars
|
|
||||||
2. Merge the stdout into the original list of Resources
|
|
||||||
3. Defaults filenames for newly generated Resources (if they are not set as annotations)
|
|
||||||
to `config/NAME_KIND.yaml`
|
|
||||||
4. Format the output
|
|
||||||
|
|
||||||
#!/bin/bash
|
|
||||||
# script must run wrapped by `kustomize config run wrap`
|
|
||||||
# for parsing input the functionConfig into env vars
|
|
||||||
if [ -z ${WRAPPED} ]; then
|
|
||||||
export WRAPPED=true
|
|
||||||
config run wrap -- $0
|
|
||||||
exit $?
|
|
||||||
fi
|
|
||||||
|
|
||||||
cat <<End-of-message
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: ${NAME}
|
|
||||||
labels:
|
|
||||||
app: nginx
|
|
||||||
instance: ${NAME}
|
|
||||||
spec:
|
|
||||||
ports:
|
|
||||||
- port: 80
|
|
||||||
targetPort: 80
|
|
||||||
name: http
|
|
||||||
selector:
|
|
||||||
app: nginx
|
|
||||||
instance: ${NAME}
|
|
||||||
---
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: ${NAME}
|
|
||||||
labels:
|
|
||||||
app: nginx
|
|
||||||
instance: ${NAME}
|
|
||||||
spec:
|
|
||||||
replicas: ${REPLICAS}
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
app: nginx
|
|
||||||
instance: ${NAME}
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
app: nginx
|
|
||||||
instance: ${NAME}
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- name: nginx
|
|
||||||
image: nginx:1.7.9
|
|
||||||
ports:
|
|
||||||
- containerPort: 80
|
|
||||||
End-of-message
|
|
||||||
|
|
||||||
#### `Dockerfile`
|
|
||||||
|
|
||||||
`Dockerfile` installs `kustomize config` and copies the script into the container image.
|
|
||||||
|
|
||||||
FROM golang:1.13-stretch
|
|
||||||
RUN go get sigs.k8s.io/kustomize/cmd/config
|
|
||||||
RUN mv /go/bin/config /usr/bin/config
|
|
||||||
COPY nginx-template.sh /usr/bin/nginx-template.sh
|
|
||||||
CMD ["nginx-template.sh]
|
|
||||||
|
|
||||||
### Example Function Usage
|
|
||||||
|
|
||||||
Following is an example of running the `kustomize config run` using the preceding API.
|
|
||||||
|
|
||||||
#### `nginx.yaml` (Input)
|
|
||||||
|
|
||||||
`dir/nginx.yaml` contains a reference to the Function. The contents of `nginx.yaml`
|
|
||||||
are passed to the Function through the `ResourceList.functionConfig` field.
|
|
||||||
|
|
||||||
apiVersion: example.com/v1beta1
|
|
||||||
kind: Nginx
|
|
||||||
metadata:
|
|
||||||
name: my-instance
|
|
||||||
annotations:
|
|
||||||
config.k8s.io/function: |
|
|
||||||
container:
|
|
||||||
image: gcr.io/example-functions/nginx-template:v1.0.0
|
|
||||||
config.kubernetes.io/local-config: "true"
|
|
||||||
spec:
|
|
||||||
replicas: 5
|
|
||||||
|
|
||||||
- `annotations.[config.k8s.io/function]`: the specification of how to run the function
|
|
||||||
- `annotations.[config.kubernetes.io/local-config]`: mark this as not a Resource that should
|
|
||||||
be applied
|
|
||||||
|
|
||||||
#### `kustomize config run dir/` (Output)
|
|
||||||
|
|
||||||
`dir/my-instance_deployment.yaml` contains the Deployment:
|
|
||||||
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: my-instance
|
|
||||||
labels:
|
|
||||||
app: nginx
|
|
||||||
instance: my-instance
|
|
||||||
spec:
|
|
||||||
replicas: 5
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
app: nginx
|
|
||||||
instance: my-instance
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
app: nginx
|
|
||||||
instance: my-instance
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- name: nginx
|
|
||||||
image: nginx:1.7.9
|
|
||||||
ports:
|
|
||||||
- containerPort: 80
|
|
||||||
|
|
||||||
`dir/my-instance_service.yaml` contains the Service:
|
|
||||||
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: my-instance
|
|
||||||
labels:
|
|
||||||
app: nginx
|
|
||||||
instance: my-instance
|
|
||||||
spec:
|
|
||||||
ports:
|
|
||||||
- port: 80
|
|
||||||
targetPort: 80
|
|
||||||
name: http
|
|
||||||
selector:
|
|
||||||
app: nginx
|
|
||||||
instance: my-instance
|
|
||||||
181
cmd/config/docs/api-conventions/functions-impl.md
Normal file
181
cmd/config/docs/api-conventions/functions-impl.md
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
# Running Configuration Functions using kustomize CLI
|
||||||
|
|
||||||
|
Configuration functions can be implemented using any toolchain and invoked using any
|
||||||
|
container workflow orchestrator including Tekton, Cloud Build, or run directly using `docker run`.
|
||||||
|
|
||||||
|
Run `config help docs-fn-spec` to see the Configuration Functions Specification.
|
||||||
|
|
||||||
|
`kustomize config run` is an example orchestrator for invoking Configuration Functions. This
|
||||||
|
document describes how to implement and invoke an example function.
|
||||||
|
|
||||||
|
## Example Function Implementation
|
||||||
|
|
||||||
|
Following is an example for implementing an nginx abstraction using a configuration
|
||||||
|
function.
|
||||||
|
|
||||||
|
### `nginx-template.sh`
|
||||||
|
|
||||||
|
`nginx-template.sh` is a simple bash script which uses a _heredoc_ as a templating solution
|
||||||
|
for generating Resources from the functionConfig input fields.
|
||||||
|
|
||||||
|
The script wraps itself using `config run wrap -- $0` which will:
|
||||||
|
|
||||||
|
1. Parse the `ResourceList.functionConfig` (provided to the container stdin) into env vars
|
||||||
|
2. Merge the stdout into the original list of Resources
|
||||||
|
3. Defaults filenames for newly generated Resources (if they are not set as annotations)
|
||||||
|
to `config/NAME_KIND.yaml`
|
||||||
|
4. Format the output
|
||||||
|
|
||||||
|
```bash
|
||||||
|
#!/bin/bash
|
||||||
|
# script must run wrapped by "kustomize config run wrap"
|
||||||
|
# for parsing input the functionConfig into env vars
|
||||||
|
if [ -z ${WRAPPED} ]; then
|
||||||
|
export WRAPPED=true
|
||||||
|
config run wrap -- $0
|
||||||
|
exit $?
|
||||||
|
fi
|
||||||
|
|
||||||
|
cat <<End-of-message
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: ${NAME}
|
||||||
|
labels:
|
||||||
|
app: nginx
|
||||||
|
instance: ${NAME}
|
||||||
|
spec:
|
||||||
|
ports:
|
||||||
|
- port: 80
|
||||||
|
targetPort: 80
|
||||||
|
name: http
|
||||||
|
selector:
|
||||||
|
app: nginx
|
||||||
|
instance: ${NAME}
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: ${NAME}
|
||||||
|
labels:
|
||||||
|
app: nginx
|
||||||
|
instance: ${NAME}
|
||||||
|
spec:
|
||||||
|
replicas: ${REPLICAS}
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: nginx
|
||||||
|
instance: ${NAME}
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: nginx
|
||||||
|
instance: ${NAME}
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: nginx
|
||||||
|
image: nginx:1.7.9
|
||||||
|
ports:
|
||||||
|
- containerPort: 80
|
||||||
|
End-of-message
|
||||||
|
```
|
||||||
|
|
||||||
|
### Dockerfile
|
||||||
|
|
||||||
|
`Dockerfile` installs `kustomize config` and copies the script into the container image.
|
||||||
|
|
||||||
|
```
|
||||||
|
FROM golang:1.13-stretch
|
||||||
|
RUN go get sigs.k8s.io/kustomize/cmd/config
|
||||||
|
RUN mv /go/bin/config /usr/bin/config
|
||||||
|
COPY nginx-template.sh /usr/bin/nginx-template.sh
|
||||||
|
CMD ["nginx-template.sh]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Example Function Usage
|
||||||
|
|
||||||
|
Following is an example of running the `kustomize config run` using the preceding API.
|
||||||
|
|
||||||
|
When run by `kustomize config run`, functions are run in containers with the
|
||||||
|
following environment:
|
||||||
|
|
||||||
|
- Network: `none`
|
||||||
|
- User: `nobody`
|
||||||
|
- Security Options: `no-new-privileges`
|
||||||
|
- Volumes: the volume containing the `functionConfig` yaml is mounted under `/local` as `ro`
|
||||||
|
|
||||||
|
### Input
|
||||||
|
|
||||||
|
`dir/nginx.yaml` contains a reference to the Function. The contents of `nginx.yaml`
|
||||||
|
are passed to the Function through the `ResourceList.functionConfig` field.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: example.com/v1beta1
|
||||||
|
kind: Nginx
|
||||||
|
metadata:
|
||||||
|
name: my-instance
|
||||||
|
annotations:
|
||||||
|
config.kubernetes.io/local-config: "true"
|
||||||
|
config.k8s.io/function: |
|
||||||
|
container:
|
||||||
|
image: gcr.io/example-functions/nginx-template:v1.0.0
|
||||||
|
spec:
|
||||||
|
replicas: 5
|
||||||
|
```
|
||||||
|
|
||||||
|
- `annotations[config.k8s.io/function].container.image`: the image to use for this API
|
||||||
|
- `annotations[config.kubernetes.io/local-config]`: mark this as not a Resource that should
|
||||||
|
be applied
|
||||||
|
|
||||||
|
### Output
|
||||||
|
|
||||||
|
The function is invoked using by runing `kustomize config run dir/`.
|
||||||
|
|
||||||
|
`dir/my-instance_deployment.yaml` contains the Deployment:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: my-instance
|
||||||
|
labels:
|
||||||
|
app: nginx
|
||||||
|
instance: my-instance
|
||||||
|
spec:
|
||||||
|
replicas: 5
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: nginx
|
||||||
|
instance: my-instance
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: nginx
|
||||||
|
instance: my-instance
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: nginx
|
||||||
|
image: nginx:1.7.9
|
||||||
|
ports:
|
||||||
|
- containerPort: 80
|
||||||
|
```
|
||||||
|
|
||||||
|
`dir/my-instance_service.yaml` contains the Service:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: my-instance
|
||||||
|
labels:
|
||||||
|
app: nginx
|
||||||
|
instance: my-instance
|
||||||
|
spec:
|
||||||
|
ports:
|
||||||
|
- port: 80
|
||||||
|
targetPort: 80
|
||||||
|
name: http
|
||||||
|
selector:
|
||||||
|
app: nginx
|
||||||
|
instance: my-instance
|
||||||
|
```
|
||||||
186
cmd/config/docs/api-conventions/functions-spec.md
Normal file
186
cmd/config/docs/api-conventions/functions-spec.md
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
# Configuration Functions Specification
|
||||||
|
|
||||||
|
This document specifies a standard for client-side functions that operate on
|
||||||
|
Kubernetes declarative configurations. This standard enables creating
|
||||||
|
small, interoperable, and language-independent executable programs packaged as
|
||||||
|
containers that can be chained together as part of a configuration management pipeline.
|
||||||
|
The end result of such a pipeline are fully rendered configurations that can then be
|
||||||
|
applied to a control plane (e.g. Using ‘kubectl apply’ for Kubernetes control plane).
|
||||||
|
As such, although this document references Kubernetes Resource Model and API conventions,
|
||||||
|
it is completely decoupled from Kuberentes API machinery and does not depend on any
|
||||||
|
in-cluster components.
|
||||||
|
|
||||||
|
This document references terms described in [Kubernetes API Conventions][1].
|
||||||
|
|
||||||
|
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD",
|
||||||
|
"SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be
|
||||||
|
interpreted as described in [RFC 2119][2].
|
||||||
|
|
||||||
|
## Use Cases
|
||||||
|
|
||||||
|
_Configuration functions_ enable shift-left practices (client-side) through:
|
||||||
|
|
||||||
|
- Pre-commit / delivery validation and linting of configuration
|
||||||
|
- e.g. Fail if any containers don't have PodSecurityPolicy or CPU / Memory limits
|
||||||
|
- Implementation of abstractions as client actuated APIs (e.g. templating)
|
||||||
|
- e.g. Create a client-side _"CRD"_ for generating configuration checked into git
|
||||||
|
- Aspect Orient configuration / Injection of cross-cutting configuration
|
||||||
|
- e.g. T-Shirt size containers by annotating Resources with `small`, `medium`, `large`
|
||||||
|
and inject the cpu and memory resources into containers accordingly.
|
||||||
|
- e.g. Inject `init` and `side-car` containers into Resources based off of Resource
|
||||||
|
Type, annotations, etc.
|
||||||
|
|
||||||
|
Performing these on the client rather than the server enables:
|
||||||
|
|
||||||
|
- Configuration to be reviewed prior to being sent to the API server
|
||||||
|
- Configuration to be validated as part of the CI?CD pipeline
|
||||||
|
- Configuration for Resources to validated holistically rather than individually
|
||||||
|
per-Resource
|
||||||
|
- e.g. ensure the `Service.selector` and `Deployment.spec.template` labels
|
||||||
|
match.
|
||||||
|
- e.g. MutatingWebHooks are scoped to a single Resource instance at a time.
|
||||||
|
- Low-level tweaks to the output of high-level abstractions
|
||||||
|
- e.g. add an `init container` to a client _"CRD"_ Resource after it was generated.
|
||||||
|
- Composition and layering of multiple functions together
|
||||||
|
- Compose generation, injection, validation together
|
||||||
|
|
||||||
|
## Spec
|
||||||
|
|
||||||
|
### Input Type
|
||||||
|
|
||||||
|
A function MUST accept as input a single [Kubernetes List type][3].
|
||||||
|
The `items` field in the input will contain a sequence of [Object types][3].
|
||||||
|
A function MAY not support [Simple types][3] and List types.
|
||||||
|
|
||||||
|
An example using `v1/ConfigMapList` as input:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMapList
|
||||||
|
items:
|
||||||
|
- apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: config1
|
||||||
|
data:
|
||||||
|
p1: v1
|
||||||
|
p2: v2
|
||||||
|
- apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: config2
|
||||||
|
```
|
||||||
|
|
||||||
|
An example using `v1/List` as input:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: v1
|
||||||
|
kind: List
|
||||||
|
items:
|
||||||
|
spec:
|
||||||
|
- apiVersion: foo-corp.com/v1
|
||||||
|
kind: FulfillmentCenter
|
||||||
|
metadata:
|
||||||
|
name: staging
|
||||||
|
address: "100 Main St."
|
||||||
|
- apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
name: namespace-reader
|
||||||
|
rules:
|
||||||
|
- resources:
|
||||||
|
- namespaces
|
||||||
|
apiGroups:
|
||||||
|
- ""
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- watch
|
||||||
|
- list
|
||||||
|
```
|
||||||
|
|
||||||
|
In addition, a function MUST accept as input a List of kind `ResourceList` where the
|
||||||
|
`functionConfig` field, if present, will contain the invocation-specific configuration passed to the function
|
||||||
|
by the orchestrator.
|
||||||
|
Functions MAY consider this field optional so that they can be triggered in an ad-hoc fashion.
|
||||||
|
|
||||||
|
An example using `config.kubernetes.io/v1beta1/ResourceList` as input:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: config.kubernetes.io/v1beta1
|
||||||
|
kind: ResourceList
|
||||||
|
functionConfig:
|
||||||
|
apiVersion: foo-corp.com/v1
|
||||||
|
kind: FulfillmentCenter
|
||||||
|
metadata:
|
||||||
|
name: staging
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
config.k8s.io/function: |
|
||||||
|
container:
|
||||||
|
image: gcr.io/example/foo:v1.0.0
|
||||||
|
spec:
|
||||||
|
address: "100 Main St."
|
||||||
|
items:
|
||||||
|
- apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
name: namespace-reader
|
||||||
|
rules:
|
||||||
|
- resources:
|
||||||
|
- namespaces
|
||||||
|
apiGroups:
|
||||||
|
- ""
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- watch
|
||||||
|
- list
|
||||||
|
```
|
||||||
|
|
||||||
|
Here `FulfillmentCenter` kind with name `staging` is passed as the invocation-specific configuration
|
||||||
|
to the function.
|
||||||
|
|
||||||
|
### Output Type
|
||||||
|
|
||||||
|
A function’s output MUST be the same as the input specification above
|
||||||
|
-- i.e. `ResourceList` or `List`.
|
||||||
|
This is necessary to enable chaining two or more functions together in a pipeline.
|
||||||
|
The serialization format of the output SHOULD match that of its input on each invocation
|
||||||
|
-- e.g. if the input was a `ResourceList`, the output should also be a `ResourceList`.
|
||||||
|
|
||||||
|
### Serialization Format
|
||||||
|
|
||||||
|
A function MUST support YAML as a serialization format for the input and output.
|
||||||
|
A function MUST use utf8 encoding (as YAML is a superset of JSON, JSON will also be supported
|
||||||
|
by any conforming function).
|
||||||
|
|
||||||
|
### Operations
|
||||||
|
|
||||||
|
A function MAY Create, Update, or Delete any number of items in the `items` field and output the
|
||||||
|
resultant list.
|
||||||
|
|
||||||
|
A function MAY modify annotations with prefix `config.kubernetes.io`, but must be careful about
|
||||||
|
doing so since they’re used for orchestration purposes and will likely impact subsequent functions
|
||||||
|
in the pipeline.
|
||||||
|
|
||||||
|
A function SHOULD preserve comments when input serialization format is YAML.
|
||||||
|
This allows for human authoring of configuration to coexist with changes made by functions.
|
||||||
|
|
||||||
|
### Containerization
|
||||||
|
|
||||||
|
A function MUST be implemented as a container.
|
||||||
|
|
||||||
|
A function container MUST be capable of running as a non-root user if it does not require
|
||||||
|
access to host filesystem or makes network calls.
|
||||||
|
|
||||||
|
### stdin/stdout/stderr and Exit Codes
|
||||||
|
|
||||||
|
A function MUST accept input from stdin and emit output to stdout.
|
||||||
|
|
||||||
|
Any error messages MUST be emitted to stderr.
|
||||||
|
|
||||||
|
An exit code of zero indicates function execution was successful.
|
||||||
|
A non-zero exit code indicates a failure.
|
||||||
|
|
||||||
|
[1]: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md
|
||||||
|
[2]: https://tools.ietf.org/html/rfc2119
|
||||||
|
[3]: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#types-kinds
|
||||||
@@ -4,288 +4,6 @@
|
|||||||
// Code generated by "mdtogo"; DO NOT EDIT.
|
// Code generated by "mdtogo"; DO NOT EDIT.
|
||||||
package api
|
package api
|
||||||
|
|
||||||
var ConfigFnLong = `# Configuration Functions API Semantics
|
|
||||||
|
|
||||||
Configuration Functions are functions packaged as executables in containers which enable
|
|
||||||
**shift-left practices**. They configure applications and infrastructure through
|
|
||||||
Kubernetes style Resource Configuration, but run locally pre-commit.
|
|
||||||
|
|
||||||
Configuration functions enable shift-left practices (client-side) through:
|
|
||||||
|
|
||||||
- Pre-commit / delivery validation and linting of configuration
|
|
||||||
- e.g. Fail if any containers don't have PodSecurityPolicy or CPU / Memory limits
|
|
||||||
- Implementation of abstractions as client actuated APIs (e.g. templating)
|
|
||||||
- e.g. Create a client-side *"CRD"* for generating configuration checked into git
|
|
||||||
- Aspect Orient configuration / Injection of cross-cutting configuration
|
|
||||||
- e.g. T-Shirt size containers by annotating Resources with ` + "`" + `small` + "`" + `, ` + "`" + `medium` + "`" + `, ` + "`" + `large` + "`" + `
|
|
||||||
and inject the cpu and memory resources into containers accordingly.
|
|
||||||
- e.g. Inject ` + "`" + `init` + "`" + ` and ` + "`" + `side-car` + "`" + ` containers into Resources based off of Resource
|
|
||||||
Type, annotations, etc.
|
|
||||||
|
|
||||||
Performing these on the client rather than the server enables:
|
|
||||||
|
|
||||||
- Configuration to be reviewed prior to being sent to the API server
|
|
||||||
- Configuration to be validated as part of the CD pipeline
|
|
||||||
- Configuration for Resources to validated holistically rather than individually
|
|
||||||
per-Resource -- e.g. ensure the ` + "`" + `Service.selector` + "`" + ` and ` + "`" + `Deployment.spec.template` + "`" + ` labels
|
|
||||||
match.
|
|
||||||
- MutatingWebHooks are scoped to a single Resource instance at a time.
|
|
||||||
- Low-level tweaks to the output of high-level abstractions -- e.g. add an ` + "`" + `init container` + "`" + `
|
|
||||||
to a client *"CRD"* Resource after it was generated.
|
|
||||||
- Composition and layering of multiple functions together
|
|
||||||
- Compose generation, injection, validation together
|
|
||||||
|
|
||||||
Configuration Functions are implemented as executable programs published in containers which:
|
|
||||||
|
|
||||||
- Accept as input (stdin):
|
|
||||||
- A list of Resource Configuration
|
|
||||||
- A Function Configuration (to configure the function itself)
|
|
||||||
- Emit as output (stdout + exit):
|
|
||||||
- A list of Resource Configuration
|
|
||||||
- An exit code for success / failure
|
|
||||||
|
|
||||||
### Function Specification
|
|
||||||
|
|
||||||
- Functions **SHOULD** be published as container images containing a ` + "`" + `CMD` + "`" + ` invoking an executable.
|
|
||||||
- Functions **MUST** accept input on STDIN a ` + "`" + `ResourceList` + "`" + ` containing the Resources and
|
|
||||||
` + "`" + `functionConfig` + "`" + `.
|
|
||||||
- Functions **MUST** emit output on STDOUT a ` + "`" + `ResourceList` + "`" + ` containing the modified
|
|
||||||
Resources.
|
|
||||||
- Functions **MUST** exit non-0 on failure, and exit 0 on success.
|
|
||||||
- Functions **MAY** emit output on STDERR with error messaging.
|
|
||||||
- Functions performing validation **SHOULD** exit failure and emit error messaging
|
|
||||||
on a validation failure.
|
|
||||||
- Functions generating Resources **SHOULD** retain non-conflicting changes on the
|
|
||||||
generated Resources -- e.g. 1. the function generates a Deployment, but doesn't
|
|
||||||
specify ` + "`" + `cpu` + "`" + `, 2. the user sets the ` + "`" + `cpu` + "`" + ` on the generated Resource, 3. the
|
|
||||||
function should keep the ` + "`" + `cpu` + "`" + ` when regenerating the Resource a second time.
|
|
||||||
- Functions **SHOULD** be usable outside ` + "`" + `kustomize config run` + "`" + ` -- e.g. though pipeline
|
|
||||||
mechanisms such as Tekton.
|
|
||||||
|
|
||||||
#### Input Format
|
|
||||||
|
|
||||||
Functions must accept on STDIN:
|
|
||||||
|
|
||||||
` + "`" + `ResourceList` + "`" + `:
|
|
||||||
- contains ` + "`" + `items` + "`" + ` field, same as ` + "`" + `List.items` + "`" + `
|
|
||||||
- contains ` + "`" + `functionConfig` + "`" + ` field -- a single item with the configuration for the function itself
|
|
||||||
|
|
||||||
Example ` + "`" + `ResourceList` + "`" + ` Input:
|
|
||||||
|
|
||||||
apiVersion: config.kubernetes.io/v1alpha1
|
|
||||||
kind: ResourceList
|
|
||||||
functionConfig:
|
|
||||||
apiVersion: example.com/v1beta1
|
|
||||||
kind: Nginx
|
|
||||||
metadata:
|
|
||||||
name: my-instance
|
|
||||||
annotations:
|
|
||||||
config.kubernetes.io/local-config: "true"
|
|
||||||
spec:
|
|
||||||
replicas: 5
|
|
||||||
items:
|
|
||||||
- apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: my-instance
|
|
||||||
spec:
|
|
||||||
replicas: 3
|
|
||||||
...
|
|
||||||
- apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: my-instance
|
|
||||||
spec:
|
|
||||||
...
|
|
||||||
|
|
||||||
#### Output Format
|
|
||||||
|
|
||||||
Functions must emit on STDOUT:
|
|
||||||
|
|
||||||
` + "`" + `ResourceList` + "`" + `:
|
|
||||||
- contains ` + "`" + `items` + "`" + ` field, same as ` + "`" + `List.items` + "`" + `
|
|
||||||
|
|
||||||
Example ` + "`" + `ResourceList` + "`" + ` Output:
|
|
||||||
|
|
||||||
apiVersion: config.kubernetes.io/v1alpha1
|
|
||||||
kind: ResourceList
|
|
||||||
items:
|
|
||||||
- apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: my-instance
|
|
||||||
spec:
|
|
||||||
replicas: 5
|
|
||||||
...
|
|
||||||
- apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: my-instance
|
|
||||||
spec:
|
|
||||||
...
|
|
||||||
|
|
||||||
#### Container Environment
|
|
||||||
|
|
||||||
When run by ` + "`" + `kustomize config run` + "`" + `, functions are run in containers with the
|
|
||||||
following environment:
|
|
||||||
|
|
||||||
- Network: ` + "`" + `none` + "`" + `
|
|
||||||
- User: ` + "`" + `nobody` + "`" + `
|
|
||||||
- Security Options: ` + "`" + `no-new-privileges` + "`" + `
|
|
||||||
- Volumes: the volume containing the ` + "`" + `functionConfig` + "`" + ` yaml is mounted under ` + "`" + `/local` + "`" + ` as ` + "`" + `ro` + "`" + `
|
|
||||||
|
|
||||||
### Example Function Implementation
|
|
||||||
|
|
||||||
Following is an example for implementing an nginx abstraction using a config
|
|
||||||
function.
|
|
||||||
|
|
||||||
#### ` + "`" + `nginx-template.sh` + "`" + `
|
|
||||||
|
|
||||||
` + "`" + `nginx-template.sh` + "`" + ` is a simple bash script which uses a *heredoc* as a templating solution
|
|
||||||
for generating Resources from the functionConfig input fields.
|
|
||||||
|
|
||||||
The script wraps itself using ` + "`" + `config run wrap -- $0` + "`" + ` which will:
|
|
||||||
|
|
||||||
1. Parse the ` + "`" + `ResourceList.functionConfig` + "`" + ` (provided to the container stdin) into env vars
|
|
||||||
2. Merge the stdout into the original list of Resources
|
|
||||||
3. Defaults filenames for newly generated Resources (if they are not set as annotations)
|
|
||||||
to ` + "`" + `config/NAME_KIND.yaml` + "`" + `
|
|
||||||
4. Format the output
|
|
||||||
|
|
||||||
#!/bin/bash
|
|
||||||
# script must run wrapped by ` + "`" + `kustomize config run wrap` + "`" + `
|
|
||||||
# for parsing input the functionConfig into env vars
|
|
||||||
if [ -z ${WRAPPED} ]; then
|
|
||||||
export WRAPPED=true
|
|
||||||
config run wrap -- $0
|
|
||||||
exit $?
|
|
||||||
fi
|
|
||||||
|
|
||||||
cat <<End-of-message
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: ${NAME}
|
|
||||||
labels:
|
|
||||||
app: nginx
|
|
||||||
instance: ${NAME}
|
|
||||||
spec:
|
|
||||||
ports:
|
|
||||||
- port: 80
|
|
||||||
targetPort: 80
|
|
||||||
name: http
|
|
||||||
selector:
|
|
||||||
app: nginx
|
|
||||||
instance: ${NAME}
|
|
||||||
---
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: ${NAME}
|
|
||||||
labels:
|
|
||||||
app: nginx
|
|
||||||
instance: ${NAME}
|
|
||||||
spec:
|
|
||||||
replicas: ${REPLICAS}
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
app: nginx
|
|
||||||
instance: ${NAME}
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
app: nginx
|
|
||||||
instance: ${NAME}
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- name: nginx
|
|
||||||
image: nginx:1.7.9
|
|
||||||
ports:
|
|
||||||
- containerPort: 80
|
|
||||||
End-of-message
|
|
||||||
|
|
||||||
#### ` + "`" + `Dockerfile` + "`" + `
|
|
||||||
|
|
||||||
` + "`" + `Dockerfile` + "`" + ` installs ` + "`" + `kustomize config` + "`" + ` and copies the script into the container image.
|
|
||||||
|
|
||||||
FROM golang:1.13-stretch
|
|
||||||
RUN go get sigs.k8s.io/kustomize/cmd/config
|
|
||||||
RUN mv /go/bin/config /usr/bin/config
|
|
||||||
COPY nginx-template.sh /usr/bin/nginx-template.sh
|
|
||||||
CMD ["nginx-template.sh]
|
|
||||||
|
|
||||||
### Example Function Usage
|
|
||||||
|
|
||||||
Following is an example of running the ` + "`" + `kustomize config run` + "`" + ` using the preceding API.
|
|
||||||
|
|
||||||
#### ` + "`" + `nginx.yaml` + "`" + ` (Input)
|
|
||||||
|
|
||||||
` + "`" + `dir/nginx.yaml` + "`" + ` contains a reference to the Function. The contents of ` + "`" + `nginx.yaml` + "`" + `
|
|
||||||
are passed to the Function through the ` + "`" + `ResourceList.functionConfig` + "`" + ` field.
|
|
||||||
|
|
||||||
apiVersion: example.com/v1beta1
|
|
||||||
kind: Nginx
|
|
||||||
metadata:
|
|
||||||
name: my-instance
|
|
||||||
annotations:
|
|
||||||
config.k8s.io/function: |
|
|
||||||
container:
|
|
||||||
image: gcr.io/example-functions/nginx-template:v1.0.0
|
|
||||||
config.kubernetes.io/local-config: "true"
|
|
||||||
spec:
|
|
||||||
replicas: 5
|
|
||||||
|
|
||||||
- ` + "`" + `annotations.[config.k8s.io/function]` + "`" + `: the specification of how to run the function
|
|
||||||
- ` + "`" + `annotations.[config.kubernetes.io/local-config]` + "`" + `: mark this as not a Resource that should
|
|
||||||
be applied
|
|
||||||
|
|
||||||
#### ` + "`" + `kustomize config run dir/` + "`" + ` (Output)
|
|
||||||
|
|
||||||
` + "`" + `dir/my-instance_deployment.yaml` + "`" + ` contains the Deployment:
|
|
||||||
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: my-instance
|
|
||||||
labels:
|
|
||||||
app: nginx
|
|
||||||
instance: my-instance
|
|
||||||
spec:
|
|
||||||
replicas: 5
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
app: nginx
|
|
||||||
instance: my-instance
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
app: nginx
|
|
||||||
instance: my-instance
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- name: nginx
|
|
||||||
image: nginx:1.7.9
|
|
||||||
ports:
|
|
||||||
- containerPort: 80
|
|
||||||
|
|
||||||
` + "`" + `dir/my-instance_service.yaml` + "`" + ` contains the Service:
|
|
||||||
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: my-instance
|
|
||||||
labels:
|
|
||||||
app: nginx
|
|
||||||
instance: my-instance
|
|
||||||
spec:
|
|
||||||
ports:
|
|
||||||
- port: 80
|
|
||||||
targetPort: 80
|
|
||||||
name: http
|
|
||||||
selector:
|
|
||||||
app: nginx
|
|
||||||
instance: my-instance`
|
|
||||||
|
|
||||||
var ConfigIoLong = `# Configuration IO API Semantics
|
var ConfigIoLong = `# Configuration IO API Semantics
|
||||||
|
|
||||||
Resource Configuration may be read / written from / to sources such as directories,
|
Resource Configuration may be read / written from / to sources such as directories,
|
||||||
@@ -346,6 +64,355 @@ Example:
|
|||||||
annotations:
|
annotations:
|
||||||
config.kubernetes.io/local-config: "true"`
|
config.kubernetes.io/local-config: "true"`
|
||||||
|
|
||||||
|
var FunctionsImplShort = `Following is an example for implementing an nginx abstraction using a configuration`
|
||||||
|
var FunctionsImplLong = `# Running Configuration Functions using kustomize CLI
|
||||||
|
|
||||||
|
Configuration functions can be implemented using any toolchain and invoked using any
|
||||||
|
container workflow orchestrator including Tekton, Cloud Build, or run directly using ` + "`" + `docker run` + "`" + `.
|
||||||
|
|
||||||
|
Run ` + "`" + `config help docs-fn-spec` + "`" + ` to see the Configuration Functions Specification.
|
||||||
|
|
||||||
|
` + "`" + `kustomize config run` + "`" + ` is an example orchestrator for invoking Configuration Functions. This
|
||||||
|
document describes how to implement and invoke an example function.
|
||||||
|
|
||||||
|
function.
|
||||||
|
|
||||||
|
### ` + "`" + `nginx-template.sh` + "`" + `
|
||||||
|
|
||||||
|
` + "`" + `nginx-template.sh` + "`" + ` is a simple bash script which uses a _heredoc_ as a templating solution
|
||||||
|
for generating Resources from the functionConfig input fields.
|
||||||
|
|
||||||
|
The script wraps itself using ` + "`" + `config run wrap -- $0` + "`" + ` which will:
|
||||||
|
|
||||||
|
1. Parse the ` + "`" + `ResourceList.functionConfig` + "`" + ` (provided to the container stdin) into env vars
|
||||||
|
2. Merge the stdout into the original list of Resources
|
||||||
|
3. Defaults filenames for newly generated Resources (if they are not set as annotations)
|
||||||
|
to ` + "`" + `config/NAME_KIND.yaml` + "`" + `
|
||||||
|
4. Format the output
|
||||||
|
|
||||||
|
#!/bin/bash
|
||||||
|
# script must run wrapped by "kustomize config run wrap"
|
||||||
|
# for parsing input the functionConfig into env vars
|
||||||
|
if [ -z ${WRAPPED} ]; then
|
||||||
|
export WRAPPED=true
|
||||||
|
config run wrap -- $0
|
||||||
|
exit $?
|
||||||
|
fi
|
||||||
|
|
||||||
|
cat <<End-of-message
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: ${NAME}
|
||||||
|
labels:
|
||||||
|
app: nginx
|
||||||
|
instance: ${NAME}
|
||||||
|
spec:
|
||||||
|
ports:
|
||||||
|
- port: 80
|
||||||
|
targetPort: 80
|
||||||
|
name: http
|
||||||
|
selector:
|
||||||
|
app: nginx
|
||||||
|
instance: ${NAME}
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: ${NAME}
|
||||||
|
labels:
|
||||||
|
app: nginx
|
||||||
|
instance: ${NAME}
|
||||||
|
spec:
|
||||||
|
replicas: ${REPLICAS}
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: nginx
|
||||||
|
instance: ${NAME}
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: nginx
|
||||||
|
instance: ${NAME}
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: nginx
|
||||||
|
image: nginx:1.7.9
|
||||||
|
ports:
|
||||||
|
- containerPort: 80
|
||||||
|
End-of-message
|
||||||
|
|
||||||
|
### Dockerfile
|
||||||
|
|
||||||
|
` + "`" + `Dockerfile` + "`" + ` installs ` + "`" + `kustomize config` + "`" + ` and copies the script into the container image.
|
||||||
|
|
||||||
|
FROM golang:1.13-stretch
|
||||||
|
RUN go get sigs.k8s.io/kustomize/cmd/config
|
||||||
|
RUN mv /go/bin/config /usr/bin/config
|
||||||
|
COPY nginx-template.sh /usr/bin/nginx-template.sh
|
||||||
|
CMD ["nginx-template.sh]
|
||||||
|
|
||||||
|
## Example Function Usage
|
||||||
|
|
||||||
|
Following is an example of running the ` + "`" + `kustomize config run` + "`" + ` using the preceding API.
|
||||||
|
|
||||||
|
When run by ` + "`" + `kustomize config run` + "`" + `, functions are run in containers with the
|
||||||
|
following environment:
|
||||||
|
|
||||||
|
- Network: ` + "`" + `none` + "`" + `
|
||||||
|
- User: ` + "`" + `nobody` + "`" + `
|
||||||
|
- Security Options: ` + "`" + `no-new-privileges` + "`" + `
|
||||||
|
- Volumes: the volume containing the ` + "`" + `functionConfig` + "`" + ` yaml is mounted under ` + "`" + `/local` + "`" + ` as ` + "`" + `ro` + "`" + `
|
||||||
|
|
||||||
|
### Input
|
||||||
|
|
||||||
|
` + "`" + `dir/nginx.yaml` + "`" + ` contains a reference to the Function. The contents of ` + "`" + `nginx.yaml` + "`" + `
|
||||||
|
are passed to the Function through the ` + "`" + `ResourceList.functionConfig` + "`" + ` field.
|
||||||
|
|
||||||
|
apiVersion: example.com/v1beta1
|
||||||
|
kind: Nginx
|
||||||
|
metadata:
|
||||||
|
name: my-instance
|
||||||
|
annotations:
|
||||||
|
config.kubernetes.io/local-config: "true"
|
||||||
|
config.k8s.io/function: |
|
||||||
|
container:
|
||||||
|
image: gcr.io/example-functions/nginx-template:v1.0.0
|
||||||
|
spec:
|
||||||
|
replicas: 5
|
||||||
|
|
||||||
|
- ` + "`" + `annotations[config.k8s.io/function].container.image` + "`" + `: the image to use for this API
|
||||||
|
- ` + "`" + `annotations[config.kubernetes.io/local-config]` + "`" + `: mark this as not a Resource that should
|
||||||
|
be applied
|
||||||
|
|
||||||
|
### Output
|
||||||
|
|
||||||
|
The function is invoked using by runing ` + "`" + `kustomize config run dir/` + "`" + `.
|
||||||
|
|
||||||
|
` + "`" + `dir/my-instance_deployment.yaml` + "`" + ` contains the Deployment:
|
||||||
|
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: my-instance
|
||||||
|
labels:
|
||||||
|
app: nginx
|
||||||
|
instance: my-instance
|
||||||
|
spec:
|
||||||
|
replicas: 5
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: nginx
|
||||||
|
instance: my-instance
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: nginx
|
||||||
|
instance: my-instance
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: nginx
|
||||||
|
image: nginx:1.7.9
|
||||||
|
ports:
|
||||||
|
- containerPort: 80
|
||||||
|
|
||||||
|
` + "`" + `dir/my-instance_service.yaml` + "`" + ` contains the Service:
|
||||||
|
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: my-instance
|
||||||
|
labels:
|
||||||
|
app: nginx
|
||||||
|
instance: my-instance
|
||||||
|
spec:
|
||||||
|
ports:
|
||||||
|
- port: 80
|
||||||
|
targetPort: 80
|
||||||
|
name: http
|
||||||
|
selector:
|
||||||
|
app: nginx
|
||||||
|
instance: my-instance`
|
||||||
|
|
||||||
|
var FunctionsSpecShort = `_Configuration functions_ enable shift-left practices (client-side) through:`
|
||||||
|
var FunctionsSpecLong = `# Configuration Functions Specification
|
||||||
|
|
||||||
|
This document specifies a standard for client-side functions that operate on
|
||||||
|
Kubernetes declarative configurations. This standard enables creating
|
||||||
|
small, interoperable, and language-independent executable programs packaged as
|
||||||
|
containers that can be chained together as part of a configuration management pipeline.
|
||||||
|
The end result of such a pipeline are fully rendered configurations that can then be
|
||||||
|
applied to a control plane (e.g. Using ‘kubectl apply’ for Kubernetes control plane).
|
||||||
|
As such, although this document references Kubernetes Resource Model and API conventions,
|
||||||
|
it is completely decoupled from Kuberentes API machinery and does not depend on any
|
||||||
|
in-cluster components.
|
||||||
|
|
||||||
|
This document references terms described in [Kubernetes API Conventions][1].
|
||||||
|
|
||||||
|
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD",
|
||||||
|
"SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be
|
||||||
|
interpreted as described in [RFC 2119][2].
|
||||||
|
|
||||||
|
|
||||||
|
- Pre-commit / delivery validation and linting of configuration
|
||||||
|
- e.g. Fail if any containers don't have PodSecurityPolicy or CPU / Memory limits
|
||||||
|
- Implementation of abstractions as client actuated APIs (e.g. templating)
|
||||||
|
- e.g. Create a client-side _"CRD"_ for generating configuration checked into git
|
||||||
|
- Aspect Orient configuration / Injection of cross-cutting configuration
|
||||||
|
- e.g. T-Shirt size containers by annotating Resources with ` + "`" + `small` + "`" + `, ` + "`" + `medium` + "`" + `, ` + "`" + `large` + "`" + `
|
||||||
|
and inject the cpu and memory resources into containers accordingly.
|
||||||
|
- e.g. Inject ` + "`" + `init` + "`" + ` and ` + "`" + `side-car` + "`" + ` containers into Resources based off of Resource
|
||||||
|
Type, annotations, etc.
|
||||||
|
|
||||||
|
Performing these on the client rather than the server enables:
|
||||||
|
|
||||||
|
- Configuration to be reviewed prior to being sent to the API server
|
||||||
|
- Configuration to be validated as part of the CI?CD pipeline
|
||||||
|
- Configuration for Resources to validated holistically rather than individually
|
||||||
|
per-Resource
|
||||||
|
- e.g. ensure the ` + "`" + `Service.selector` + "`" + ` and ` + "`" + `Deployment.spec.template` + "`" + ` labels
|
||||||
|
match.
|
||||||
|
- e.g. MutatingWebHooks are scoped to a single Resource instance at a time.
|
||||||
|
- Low-level tweaks to the output of high-level abstractions
|
||||||
|
- e.g. add an ` + "`" + `init container` + "`" + ` to a client _"CRD"_ Resource after it was generated.
|
||||||
|
- Composition and layering of multiple functions together
|
||||||
|
- Compose generation, injection, validation together
|
||||||
|
|
||||||
|
## Spec
|
||||||
|
|
||||||
|
### Input Type
|
||||||
|
|
||||||
|
A function MUST accept as input a single [Kubernetes List type][3].
|
||||||
|
The ` + "`" + `items` + "`" + ` field in the input will contain a sequence of [Object types][3].
|
||||||
|
A function MAY not support [Simple types][3] and List types.
|
||||||
|
|
||||||
|
An example using ` + "`" + `v1/ConfigMapList` + "`" + ` as input:
|
||||||
|
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMapList
|
||||||
|
items:
|
||||||
|
- apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: config1
|
||||||
|
data:
|
||||||
|
p1: v1
|
||||||
|
p2: v2
|
||||||
|
- apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: config2
|
||||||
|
|
||||||
|
An example using ` + "`" + `v1/List` + "`" + ` as input:
|
||||||
|
|
||||||
|
apiVersion: v1
|
||||||
|
kind: List
|
||||||
|
items:
|
||||||
|
spec:
|
||||||
|
- apiVersion: foo-corp.com/v1
|
||||||
|
kind: FulfillmentCenter
|
||||||
|
metadata:
|
||||||
|
name: staging
|
||||||
|
address: "100 Main St."
|
||||||
|
- apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
name: namespace-reader
|
||||||
|
rules:
|
||||||
|
- resources:
|
||||||
|
- namespaces
|
||||||
|
apiGroups:
|
||||||
|
- ""
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- watch
|
||||||
|
- list
|
||||||
|
|
||||||
|
In addition, a function MUST accept as input a List of kind ` + "`" + `ResourceList` + "`" + ` where the
|
||||||
|
` + "`" + `functionConfig` + "`" + ` field, if present, will contain the invocation-specific configuration passed to the function
|
||||||
|
by the orchestrator.
|
||||||
|
Functions MAY consider this field optional so that they can be triggered in an ad-hoc fashion.
|
||||||
|
|
||||||
|
An example using ` + "`" + `config.kubernetes.io/v1beta1/ResourceList` + "`" + ` as input:
|
||||||
|
|
||||||
|
apiVersion: config.kubernetes.io/v1beta1
|
||||||
|
kind: ResourceList
|
||||||
|
functionConfig:
|
||||||
|
apiVersion: foo-corp.com/v1
|
||||||
|
kind: FulfillmentCenter
|
||||||
|
metadata:
|
||||||
|
name: staging
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
config.k8s.io/function: |
|
||||||
|
container:
|
||||||
|
image: gcr.io/example/foo:v1.0.0
|
||||||
|
spec:
|
||||||
|
address: "100 Main St."
|
||||||
|
items:
|
||||||
|
- apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
name: namespace-reader
|
||||||
|
rules:
|
||||||
|
- resources:
|
||||||
|
- namespaces
|
||||||
|
apiGroups:
|
||||||
|
- ""
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- watch
|
||||||
|
- list
|
||||||
|
|
||||||
|
Here ` + "`" + `FulfillmentCenter` + "`" + ` kind with name ` + "`" + `staging` + "`" + ` is passed as the invocation-specific configuration
|
||||||
|
to the function.
|
||||||
|
|
||||||
|
### Output Type
|
||||||
|
|
||||||
|
A function’s output MUST be the same as the input specification above
|
||||||
|
-- i.e. ` + "`" + `ResourceList` + "`" + ` or ` + "`" + `List` + "`" + `.
|
||||||
|
This is necessary to enable chaining two or more functions together in a pipeline.
|
||||||
|
The serialization format of the output SHOULD match that of its input on each invocation
|
||||||
|
-- e.g. if the input was a ` + "`" + `ResourceList` + "`" + `, the output should also be a ` + "`" + `ResourceList` + "`" + `.
|
||||||
|
|
||||||
|
### Serialization Format
|
||||||
|
|
||||||
|
A function MUST support YAML as a serialization format for the input and output.
|
||||||
|
A function MUST use utf8 encoding (as YAML is a superset of JSON, JSON will also be supported
|
||||||
|
by any conforming function).
|
||||||
|
|
||||||
|
### Operations
|
||||||
|
|
||||||
|
A function MAY Create, Update, or Delete any number of items in the ` + "`" + `items` + "`" + ` field and output the
|
||||||
|
resultant list.
|
||||||
|
|
||||||
|
A function MAY modify annotations with prefix ` + "`" + `config.kubernetes.io` + "`" + `, but must be careful about
|
||||||
|
doing so since they’re used for orchestration purposes and will likely impact subsequent functions
|
||||||
|
in the pipeline.
|
||||||
|
|
||||||
|
A function SHOULD preserve comments when input serialization format is YAML.
|
||||||
|
This allows for human authoring of configuration to coexist with changes made by functions.
|
||||||
|
|
||||||
|
### Containerization
|
||||||
|
|
||||||
|
A function MUST be implemented as a container.
|
||||||
|
|
||||||
|
A function container MUST be capable of running as a non-root user if it does not require
|
||||||
|
access to host filesystem or makes network calls.
|
||||||
|
|
||||||
|
### stdin/stdout/stderr and Exit Codes
|
||||||
|
|
||||||
|
A function MUST accept input from stdin and emit output to stdout.
|
||||||
|
|
||||||
|
Any error messages MUST be emitted to stderr.
|
||||||
|
|
||||||
|
An exit code of zero indicates function execution was successful.
|
||||||
|
A non-zero exit code indicates a failure.
|
||||||
|
|
||||||
|
[1]: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md
|
||||||
|
[2]: https://tools.ietf.org/html/rfc2119
|
||||||
|
[3]: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#types-kinds`
|
||||||
|
|
||||||
var Merge2Long = `# Merge (2-way)
|
var Merge2Long = `# Merge (2-way)
|
||||||
|
|
||||||
2-way merges fields from a source to a destination, overriding the destination fields
|
2-way merges fields from a source to a destination, overriding the destination fields
|
||||||
|
|||||||
Reference in New Issue
Block a user