From 87fd5a0c2153b37742039956e2e9b3d58d1df92a Mon Sep 17 00:00:00 2001 From: Jessica Yuen <im.jessicayuen@gmail.com> Date: Tue, 9 Jan 2018 12:56:05 -0800 Subject: [PATCH] Design proposal: explicit environment metadata Proposal for explicit environment metadata; allowing environment metadata (such as namespace, server URI) to be reference-able at the component and prototype manifest level. Signed-off-by: Jessica Yuen <im.jessicayuen@gmail.com> --- .../explicit-environment-metadata.md | 147 ++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 design/proposals/explicit-environment-metadata.md diff --git a/design/proposals/explicit-environment-metadata.md b/design/proposals/explicit-environment-metadata.md new file mode 100644 index 00000000..2055c39f --- /dev/null +++ b/design/proposals/explicit-environment-metadata.md @@ -0,0 +1,147 @@ +# Explicit Environment Metadata + +Status: Pending + +Version: Alpha + +## Abstract + +We want to introduce functionality to enable the use of environment metadata (ex: cluster namespace, Server URI) in prototype and component manifest files. + +## Motivation + +* Environments have configured metadata, such as the cluster’s namespace or server URI. Users [have requested](https://github.com/ksonnet/ksonnet/issues/222) that these fields be referenceable in both prototypes and component files. + +Example: + +Consider the following [nginx prototype](https://github.com/ksonnet/parts/blob/9d78d6bb445d530d5b927656d2293d4f12654608/incubator/nginx/examples/nginx.jsonnet) where the namespace is currently hardcoded: + +```jsonnet +local k = import 'k.libsonnet'; +local nginx = import '../nginx.libsonnet'; + +local namespace = "dev-alex"; +local appName = "nginx-app"; + +k.core.v1.list.new([ + nginx.parts.deployment.withServerBlock(namespace, appName), + nginx.parts.service(namespace, appName), + nginx.parts.serverBlockConfigMap(namespace, appName), +]) +``` + +This example does not lend well to the ksonnet desired model where components are environment agnostic; meaning a component should not need information on which environment the resulting Kubernetes Objects will be deployed to. Yet, it is unavoidable that these component / prototype configurations may need to reference a namespace, server URI, or other metadata. + +## Goals + +* Encourage behavior for component and prototype manifests to be environment-agnostic. + Example: It is encouraged to write `nginx.parts.service(env.namespace, appName)`, but not `local namespace = "foo"` or `if (env.namespace == "foo") ... else ...`. +* Component and prototype manifests should be able to refer to environment metadata fields, such as the environment namespace in the form of `env.namespace`. +* Environment fields should be evaluated at run-time depending on which environment the user is trying to deploy to. + Example: If the user had a `prod` environment configured to the namespace `prod-ns`, running `ks apply prod` should evaluate `env.namespace` to the value `prod-ns`. +* Produce a second version of existing prototypes without hard-coded namespace values. + +## Non Goals + +* Access to a specific environment's metadata. + Example: There should not be access to an attribute like `env.prod.namespace`. The evaluation of `env.namespace` should happen on `apply`, `diff`, or other ks functionalities that operate on an environment. +* This proposal does not suggest to reveal the environment metadata as a part of the `ks param` operations. Environment metadata will remain discrete from component parameters. Meaning, users are currently able to discover differences in component parameters through the use of the ksonnet CLI. Running `ks param diff <env-one> <env-two>` will output differences in component parameters, such as replica count, between the two environments, however will not output differences in environment metadata such as the namespace. + +## Proposal + +### Fundamentals + +The change will behave similarly to how parameters operate in component and prototype manifests. + +Components created on the `generate` command will introduce the following line to the top of the component manifest [1]: + +`local env = std.extVar("__ksonnet/env");` + +Namespace, Server URI, and other environment metadata attributes can then be accessed using `env.namespace` and `env.server`, respectively. + +For example, the components generated from the nginx prototype in the Motivation section above may appear as: + +```jsonnet +local env = std.extVar("__ksonnet/env"); + +local k = import 'k.libsonnet'; +local nginx = import '../nginx.libsonnet'; + +local appName = "nginx-app"; + +k.core.v1.list.new([ + nginx.parts.deployment.withServerBlock(env.namespace, appName), + nginx.parts.service(env.namespace, appName), + nginx.parts.serverBlockConfigMap(env.namespace, appName), +]) +``` + +The corresponding prototype manifest would appear as: + +```jsonnet +local k = import 'k.libsonnet'; +local nginx = import '../nginx.libsonnet'; + +local appName = "nginx-app"; + +k.core.v1.list.new([ + nginx.parts.deployment.withServerBlock(import 'env://namespace', appName), + nginx.parts.service(import 'env://namespace', appName), + nginx.parts.serverBlockConfigMap(import 'env://namespace', appName), +]) +``` + +ksonnet would translate `import 'env://namespace'` prototype snippets to `env.namespace` during the `generate` command. + +Note: This proposal does not prevent users from writing such things as: + +```jsonnet +if env.namespace == "foo" then + ... +else + ... +``` + +However, this is similar to type checking in Java using `instanceof`. It is not encouraged, but not disallowed. This can be discouraged through tutorials and documentation of proper use cases. + +[1] On commands where ksonnet interacts with the server (`apply <env>`, `delete <env>`, etc.), the `std.ExtVar("__ksonnet/env")` line will import the correct environment attributes; determined by ksonnet at run-time based on the environment the user specified in the command. + +### Version 2 Core Prototypes + +A version 2 of the existing system prototypes and prototypes in the [incubator registry](https://github.com/ksonnet/parts/tree/master/incubator) will need to be provided. + +These version 2 prototypes will remove any hard-coded namespace or other environment metadata values to use the proposal from the Fundamentals section above. + +The prototypes need to be versioned to support backwards compatibility. Ex: a user running ksonnet 0.8.0 would not be able to use version 2 prototypes. + +## Backwards Compatibility + +This change will not break compatibility with previous ksonnet versions for existing prototypes and components. However, if a user is running a ksonnet version <= 0.8.0 and attempts to use a newer prototype or component manifest (that contain the above changes), an error will occur. + +Existing component and prototype manifests are also able to use the new features. + +If existing components wish to use the `env.namespace` attribute, it can do so by adding the following line to the top of the manifest: + +`local env = std.extVar("__ksonnet/env");` + +If existing prototypes wish to use the the namespace attribute, it can do so using the key-phrase `import 'env://namespace'` in place of where it expects the attribute. This is similar to how prototype parameters are currently imported. ksonnet will translate `import 'env://namespace'` to `env.namespace` when a component is generated from the prototype. + +## Alternatives Considered + +## Environment metadata as parameters + +As opposed to `env.namespace`, environment metadata can be added to the existing params model, i.e. `params.global.namespace`. + +The following would be added to the `param.libsonnet` files: + +```jsonnet +{ + global:: { + namespace:: std.extVar("__ksonnet/env/namespace"), + }, +} +``` + +The primary reason we are considering the proposal's approach in-place of this alternative is that this alternative introduces multiple areas of mutability. Meaning, it would be possible to set namespaces in both an environment's `spec.json` file and in the `param.libsonnet` files. In the event of conflicts, it is not immediately obvious which file's attribute should be prioritized. + +Advantages of this alternative involve being able to vary namespaces across components within the same environment. It also emables the user to display environment metadata in `ks param diff` or `ks param list`. However, this approach also comes with the disadvantage of muddying the definition of an environment (that currently has strongly defined metadata). Environment differences and metadata is still visible through the `ks env list` command. -- GitLab