redhat-developer / service-binding-operator

[Deprecated] The Service Binding Operator: Connecting Applications with Services, in Kubernetes
https://redhat-developer.github.io/service-binding-operator
Apache License 2.0
109 stars 91 forks source link

Feedback: support defining envVarPrefix per backing service #387

Closed navidsh closed 4 years ago

navidsh commented 4 years ago

Currently, it is only possible to define one envVarPrefix in the ServiceBindingRequest CR. And if multiple backing services are defined, they all get the same prefix. Being able to use different prefixes per backing service is important since different backing services might use the same name for the binding information.

https://github.com/redhat-developer/service-binding-operator/issues/356 has a similar discussion on how the SBR could look like to get around this.

ZhuangYuZY commented 4 years ago

@sbose78 What I understand, we plan to do following to support envVarPrefix for multiple backing service CRs. Is it correct, thank you.

backingServiceSelectors:
    - group: serving.knative.dev
      kind: Service
      resourceRef: demo-1
      version: v1beta1
      envVarPrefix: demo-1-prefix
    - group: serving.knative.dev
      kind: Service
      resourceRef: demo-2
      version: v1beta1
      envVarPrefix: demo-2-prefix
sbose78 commented 4 years ago

@ZhuangYuZY , roughly yes.

ZhuangYuZY commented 4 years ago

@sbose78 Do we have anyone working on this, I can get PR prepared. Thank you.

sbose78 commented 4 years ago

Go for it @ZhuangYuZY !

One thing to note, there might be a global env var prefix ( spec.envVarPrefix ) too. Maybe the combined prefix should be spec.envVarPrefix + "_" + spec.backingServiceSelectors[i].envVarPrefix ?

isutton commented 4 years ago

@sbose78 https://github.com/sbose78 What I understand, we plan to do following to support envVarPrefix for multiple backing service CRs. Is it correct, thank you.

backingServiceSelectors:

  • group: serving.knative.dev kind: Service resourceRef: demo-1 version: v1beta1 envVarPrefix: demo-1-prefix
  • group: serving.knative.dev kind: Service resourceRef: demo-2 version: v1beta1 envVarPrefix: demo-2-prefix

Ideally we should strive to require the interaction of the developer as little as possible by offering good enough defaults. In the case of multiple services, using at least kind and resourceRef is a wonderful start.

Building on your example, I see that each configuration value exposed in those resources would have the following prefix (already munged to look like an environment variable): SERVICEDEMO-1 and SERVICEDEMO-2 .

An interesting side effect of this approach is that it makes the service name meaningful in the context, since it becomes part of the contract between the application and a service; this becomes noticeable when an application requires, for example, a configuration value DATABASE_SALES_HOST, in which case a Database resource named sales is exposing the host value. In other words, just creating the right resource kind with the right name fulfills the contract without any intervention from the developer's side.

Thoughts?

sbose78 commented 4 years ago

Reducing the number of things the user has to specify is always helpful.

I wonder how common is it to have cases where people use multiple "services" of the same Kind ?

Otherwise, I'm happy if the prefix is auto-generated from just the Kind.

ZhuangYuZY commented 4 years ago

@isutton and @sbose78, Only kind is not enough for IBM Cloud Operator case. In IBM Cloud Operator, the backing service instances have same kind of Binding, different service instances(see example below, COS and virtual recognition has same kind).

Also kind+resourceRef as env prefix is not work from application experience. As your example DATABASE_SALES_HOST, if application wants to change database instance to other one SALES_BACKUP(e.g. switching to backup db when primary has problem), then if means application developer also needs to change application code to read from other envVar DATABASE_SALES_BACKUP_HOST. It is not good.

So I think envVarPrefix per backing service instance also valuable to address above cases.

apiVersion: apps.openshift.io/v1alpha1
kind: ServiceBindingRequest
metadata:
  name: helloworld-binding
spec:
  applicationSelector:
    resourceRef: helloworld
    group: serving.knative.dev
    version: v1
    resource: services
  backingServiceSelectors:
    - group: ibmcloud.ibm.com
      version: v1alpha1
      kind: Binding
      resourceRef: coligo-cos-service-credential
    - group: ibmcloud.ibm.com
      version: v1alpha1
      kind: Binding
      resourceRef: coligo-virtual-recogntion-service-credential
isutton commented 4 years ago

@isutton https://github.com/isutton and @sbose78 https://github.com/sbose78, Only kind is not enough for IBM Cloud Operator case. In IBM Cloud Operator, the backing service instances have some kind of Binding, different service instances(see example below, COS and virtual recognition has same kind).

Also kind+resourceRef as env prefix is not work from application experience. As your example DATABASE_SALES_HOST, if application wants to change database instance to other one SALES_BACKUP(e.g. switching to backup db when primary has problem), then if means application developer also needs to change application code to read from other envVar DATABASE_SALES_BACKUP_HOST. It is not good.

This is an interesting use case :)

I believe the application has authority over the configuration values it requires, including their names and format; in other words, the application establishes the contract the infrastructure should provide for its well functioning.

In this particular case, I believe a custom environment variable composed of DSNs that are extracted from the declared services (both sales and sales-backup database services) would be my preferred approach.

So I think envVarPrefix per backing service instance also valuable to address above cases.

apiVersion: apps.openshift.io/v1alpha1 kind: ServiceBindingRequest metadata: name: helloworld-binding spec: applicationSelector: resourceRef: helloworld group: serving.knative.dev version: v1 resource: services backingServiceSelectors:

  • group: ibmcloud.ibm.com version: v1alpha1 kind: Binding resourceRef: coligo-cos-service-credential
  • group: ibmcloud.ibm.com version: v1alpha1 kind: Binding resourceRef: coligo-virtual-recogntion-service-credential

Please correct me if I'm wrong, but it seems you're advocating in favour of envVarPrefix because the resource names are too long to be used in the template expression, in addition to resulting (in the example above) in really long environment variable names by default?

sbose78 commented 4 years ago

then if means application developer also needs to change application code to read from other envVar

Fair point.

I believe a custom environment variable composed of DSNs that are extracted from the declared services

While custom environment variable is a good escape hatch, I would uncomfortable if we didn't solve this use case :)

Maybe, we should just have id and also use that as an env var prefix ? After all both id and envVarPrefix gives us uniqueness?

ZhuangYuZY commented 4 years ago

I am also fine to have id and also use that as an envVarPrefix. Because both id and envVarPrefix give us uniqueness in my user cases. Thank you.

sbose78 commented 4 years ago

@isutton , I gave this a thought again :)

Therefore, in my opinion, we should proceed with making this API change.

isutton commented 4 years ago

@isutton https://github.com/isutton , I gave this a thought again :)

-

The discussion on the optional backing service-specific envVarPrefix is orthogonal to the id-related discussion. The id helps us refer to a backing service in customEnvVar.

Agreed. Although id's value might be used as envVarPrefix in the absence of the latter, as previously pointed out.

-

envVarPrefix helps us generate unique binding secret keys. Example, if service1 has a configmap field called certificate and service2 also has a field called certificate, the backing service-specific envVar prefix helps SBO generate a binding secret with unique secret field keys.

Agreed. The question here is whether envVarPrefix is optional or required. If optional, then we should have good enough defaults for envVarPrefix, probably by inferring it from the resource's GVK and name. If always required and its use-case enables more complex use cases (such as the logical grouping of configuration values from separate resources mentioned in another issue) then it could be possible to enforce this information through data hierarchy; one possible implementation would be change services type from []BackingServiceSelector to map[string][]BackingServiceSelector, thus using the key as envVarPrefix for all services in the value.

Regardless, it is important to decide on its semantics.

-

The name of the key in the binding secret should not be derived from the group/version/kind/resource . The user should be able to specify the exact prefix to ensure the user has control over the resulting name of the key in the binding secret.

Ok, its semantics are already defined, assuming the prefix will always be informed. The remarks regarding how this is going to be structured still applies.

To tackle the point the user has control over the resulting name of the key, the user might ensure the prefix, but still has no control whatsoever over the configuration values that are being exposed by the service resources; those being exposed either by the CRD author or amended by a cluster administrator. For example, an application is expecting the environment variable DATABASE_USER for its well functioning. The db1 Database resource is referenced by the binding, and it exposes "credentials" as per example, so if I understand it correctly, the automatically generated variable would be called DATABASE_CREDENTIALS_USER. It would still require a data mapping entry to compose the application's required configuration value before resorting to modify the application itself (which should be the last resort IMO).

ZhuangYuZY commented 4 years ago

Seems we have agreement on both id and envPrefix needed for multiple backing services cases. But open question about optional or mandatory, and related code logic.

For me, I will suggest both are optional. For id, as id is using in customEnvVar to reference backing service, if end user do not need customEnvVar, then not need id, if only one backing service, then no need id to define customEnvVar. Of course, customer could define id when needed. Same for envPrefix, if only one backing service, or multiple backing services but different env var name, then no need envPrefix, SBO will generate env variable from backing service directly without any prefix.

Of course, if same env var name in different backing service instances, it will have overwrite will happens. We can document clearly and suggest end user to define envPrefix to avoid overwrite.

Thank you.

Avni-Sharma commented 4 years ago

@isutton and @sbose78, Only kind is not enough for IBM Cloud Operator case. In IBM Cloud Operator, the backing service instances have same kind of Binding, different service instances(see example below, COS and virtual recognition has same kind).

Also kind+resourceRef as env prefix is not work from application experience. As your example DATABASE_SALES_HOST, if application wants to change database instance to other one SALES_BACKUP(e.g. switching to backup db when primary has problem), then if means application developer also needs to change application code to read from other envVar DATABASE_SALES_BACKUP_HOST. It is not good.

So I think envVarPrefix per backing service instance also valuable to address above cases.

apiVersion: apps.openshift.io/v1alpha1
kind: ServiceBindingRequest
metadata:
  name: helloworld-binding
spec:
  applicationSelector:
    resourceRef: helloworld
    group: serving.knative.dev
    version: v1
    resource: services
  backingServiceSelectors:
    - group: ibmcloud.ibm.com
      version: v1alpha1
      kind: Binding
      resourceRef: coligo-cos-service-credential
    - group: ibmcloud.ibm.com
      version: v1alpha1
      kind: Binding
      resourceRef: coligo-virtual-recogntion-service-credential

so when we have envVarPrefix shall we still have DBKIND in ENVARPREFIX_DBKIND_VALUE or only ENVARPREFIX_VALUE ? So by default, the action is DBKIND_VALUE and when the envarPrefix is mentioned then it is ENVARPREFIX_VALUE ?

sbose78 commented 4 years ago

Agreed. Both should be optional.

sbose78 commented 4 years ago

We shall not prefix our environment variables with DBKIND. Environment variables are not supposed to have the Kubernetes GVK's in it at all.

If envVarPrefix is available, we prefix it, example : MYPREFIX_HOST.

If not, the environment variable will remain as HOST.

There should be absolutely no GVK/configmap/secret substring in the name of the environment variable.

qibobo commented 4 years ago

@sbose78 @ZhuangYuZY @isutton So we will have id and envVarPrefix as optional in a backingServiceSelector.

For envVarPrefix, if the user does not set it, it can be empty.

But for id, it is used to identify a backing service. So to support multiple backing services, current Retriever.cache which is a map[string]interface{} can not work, we need to change it to a map[string]map[string]interface{}, while the key is the id and the value is info of the service identified by the id. So though user do not need to set an id, we still need to implicitly set an id as default key. How to define the default id? Your ideas? Is Group_Version_Kind_Name OK?

ZhuangYuZY commented 4 years ago

Group_Version_Kind_Name will be two long for using, e.g. like ibmcloud.ibm.com.v1alpha1.Binding.coligo-cos-service-credential.Status. I will suggest to using resourceRef as default if no id setting. It will cover 80% cases. Then using id for other 20%.

@sbose78 your though ?

isutton commented 4 years ago

We shall not prefix our environment variables with DBKIND. Environment variables are not supposed to have the Kubernetes GVK's in it at all.

If envVarPrefix is available, we prefix it, example : MYPREFIX_HOST.

If not, the environment variable will remain as HOST.

There should be absolutely no GVK/configmap/secret substring in the name of the environment variable.

I'm not sure about this. Having two behaviors to choose as default for the service prefix where a) expose properties from declared services without prefix; and b) prefix is generated from the resource type and name I find the latter less error prone from the user point of view.

What do you think about offering an opt-in mechanism, where the user explicitly declares they want the properties to be exposed without a prefix at all?

Exploring a little bit, this would reflect in the services definition as (for the lack of a better name) skipEnvPrefix:

services:
  - resourceRef: my-database
    group: postgres.io
    version: v1
    kind: Database
    skipEnvPrefix: false // do not skip by default
  ...

Assuming it exposes the host property, with this configuration the environment variable V1_POSTGRESIO_DATABASE_MYDATABASE_HOST be created, since there's no other information available. This default prefix format could be a service binding configuration specified as a go template expression, with the default behavior a template offering whatever we find reasonable by default.

Changing the services spec to:

services:
  - resourceRef: my-database
    group: postgres.io
    version: v1
    kind: Database
    skipEnvPrefix: true
    ...

Results in the environment variable HOST.

Changing again the services spec to:

services:
  - resourceRef: my-database
    group: postgres.io
    version: v1
    kind: Database
    envPrefix: MYDB
    skipEnvPrefix: false
    ...

Results in the environment variable MYDB_HOST.

Thoughts?

sbose78 commented 4 years ago

@isutton , I'm okay with the proposal to have skipEnvPrefix.

prefix is generated from the resource type and name I find the latter less error prone from the user point of view.

It's more of I am confused where the heck the other service's environment variables are :)

So we will have id and envVarPrefix as optional in a backingServiceSelector.

@qibobo , Let's move the id discussion to https://github.com/redhat-developer/service-binding-operator/issues/396 . I would like to explore a few options there.

isutton commented 4 years ago

What if we gave the authors the ability to expose the environment variables that'd be more useful for the users of their services directly? For example, in the example below the PostgreSQL CRD could define the binding/PG_HOST annotation, where its value is a path indicating the source in the CR:

annotations:
    binding/PG_HOST: status.connection.host

This would expose the PG_HOST environment variable by default, without any intervention from the service binding user to do so.

Some shortcuts for the data gathering can be offered; in the following example one could expose the data under the CR's status.connection field (in this example, a map[string]interface{} with host and port keys):

annotations:
    binding/PG: status.connection

This would result in PG_HOST and PG_PORT environment variables being available for the application to consume.

In the case status.connection contains more keys that should not be made available to applications, the author could specify the keys to be collected:

annotations:
    binding/PG: status.connection.{host,port}

Resulting once again in PG_HOST and PG_PORT environment variables.

The examples above are self referential, where they are shortcuts of fields in CRs of the CRD specifying those annotations and will be processed for each CR in the service binding scope.

To illustrate that, let's consider the following service binding services section:

services:
    - kind: Database
      group: postgres.io
      version: v1
      resourceRef: sales
    - kind: Database
      group: postgres.io
      version: v1
      resourceRef: analytics

It would then be expected that both services expose PG_HOST and PG_PORT with different contents, and the last one processed wins. Since resourceRef might contain long values, it can't be reliably used as prefix.

We've been discussing around having id, so let's play with that and assume we have it in place:

services:
    - kind: Database
      group: postgres.io
      version: v1
      resourceRef: sales
      id: sales
    - kind: Database
      group: postgres.io
      version: v1
      resourceRef: analytics
      id: analytics

To properly substitute the PG prefix for either SALES or ANALYTICS, a contract should be followed by the operator authors where they always prefix the configuration names and this prefix can be replaced if specified in the service binding request.

Having this contract in mind and using the id field as prefix, the resulting environments are SALES_HOST, SALES_PORT, ANALYTICS_HOST, ANALYTICS_PORT.

Using a similar approach, the operator authors could specify environment variables which values are templates to be executed by the service binding operator once all data has been retrieved from all services; in other words, this gives the authors ability to compose environment variables (and probably used as input of other mechanisms) using sets of similar resources such as Kafka resources, for example:

annotations:
    binding/KAFKA_HOST: .status.connection.host
    binding/KAFKA_HOSTS: "{{range .kafka}}{{.host}};{{end}}"

In the example above, the template engine context provides the .kafka slice containing all Kafka services collected by the service binding operator, and each element contains the host property.

Assuming now the following service binding services definition with made-up Kafka resources:

services:
    - kind: Kafka
      group: kafka
      version: v1
      resourceRef: kafka1
      id: kafka1
    - kind: Kafka
      group: kafka
      version: v1
      resourceRef: kafka2
      id: kafka2

The environment variables available to the applications are KAFKA1_HOST, KAFKA2_HOST and KAFKA_HOSTS.

I personally believe that this direction gives much more clarity, because it empowers the operator author to offer the best experience for the consumers of their services, exposing configuration values very efficiently and also removes a lot of the current SBO's responsibilities, by basically handling and interpreting data that could not otherwise be interpreted if not inside a runtime and persisting the results.

I'd like to hear your thoughts on this.

sbose78 commented 4 years ago

What if we gave the authors the ability to expose the environment variables that'd be more useful for the users of their services directly?

This is what I proposed this week as part of the new annotations' format

https://github.com/application-stacks/service-binding-specification/blob/master/annotations.md

“servicebinding.dev/uri: "path={.status.data.connectionURL}”

ExposesconnectionURL as uri.

This sounds similar to what you are recommending @isutton ?

isutton commented 4 years ago

What if we gave the authors the ability to expose the environment variables that'd be more useful for the users of their services directly?

This is what I proposed this week as part of the new annotations' format

https://github.com/application-stacks/service-binding-specification/blob/master/annotations.md

“servicebinding.dev/uri: "path={.status.data.connectionURL}”

ExposesconnectionURL as uri.

This sounds similar to what you are recommending @isutton ?

I agree with the end result.

This is much less about the format and more about the relationship between what is fed to what is spewed.

What is missing is a contract where the operator's authors expose their variables in such a way the service binding operator can effectively substitute it, as exposed in the examples.

In your example, I still think that the value on the left hand side is better represented as a unique value name the operator defines (PG_HOST in my example). And again, a contract is required if I want to not only prefix the environment variable (resulting in SALES_PG_HOST which is not useful if the application requires SALES_HOST at least).

If your application requires a HOST variable, then you can specify it in the custom environment variables section, or another mean such as skipEnvPrefix.

At least users would have sensible named environment variables being communicated from the authors directly to the users, which I believe is a pretty reasonable end goal.

sbose78 commented 4 years ago

Sorry, I didn't quite get you.

In your example, I still think that the value on the left hand side is better represented as a unique value name the operator defines (PG_HOST in my example).

If the operator author can never guarantee uniqueness because the "PG_HOST" doesn't take into account that another operator might have the same too, then in the context of this discussion, the need for an environment prefix at a backing service level is needed anyway?

If your application requires a HOST variable, then you can specify it in the custom environment variables section, or another mean such as skipEnvPrefix.

As per the schema being defined here https://github.com/application-stacks/service-binding-specification#service-binding-schema ,

Many services might expose host, and the consumer ( the one who creates the SBR ) could just prefix it and use?

isutton commented 4 years ago

Sorry, I didn't quite get you.

In your example, I still think that the value on the left hand side is better represented as a unique value name the operator defines (PG_HOST in my example).

If the operator author can never guarantee uniqueness because the "PG_HOST" doesn't take into account that another operator might have the same too, then in the context of this discussion, the need for an environment prefix at a backing service level is needed anyway?

If your application requires a HOST variable, then you can specify it in the custom environment variables section, or another mean such as skipEnvPrefix.

As per the schema being defined here https://github.com/application-stacks/service-binding-specification#service-binding-schema ,

Many services might expose host, and the consumer ( the one who creates the SBR ) could just prefix it and use?

Disclaimer: Please note that this answer doesn't discuss the service binding schema being proposed, but how the configuration values should be propagated from the operator to the application through service binding; this means to focus on the semantics rather than the encoding. Additionally, there are no distinction between environment variables and configuration values in this context, and as such there are no reference where the configuration value should be used (for example, exposed as an environment variable or a volume mount) since those are orthogonal of said value propagation.

I concur that the uniqueness can't be guaranteed by the operator author because it was never expected in the first case. There's no guarantee whatsoever an environment variable won't be overwritten until this data is persisted, pretty similar to what happens between the start of a shell process and the execution of a program within this shell.

On that sentiment, I believe we should encourage authors to consider contributing the environment variables their services provide (for example https://dev.mysql.com/doc/refman/8.0/en/environment-variables.html, https://www.postgresql.org/docs/9.3/libpq-envars.html) in the services' CRDs to be automatically exposed to the application by the service binding.

Before starting, observe the name encoded in the annotation name represents an environment variable being contributed to the service binding; this means that binding/PGHOST contributes the PGHOST environment variable, and binding/http_proxy would contribute the http_proxy environment variable.

Let's observe the following CRD annotations, where it states the configuration value PGHOST is going to be exported and contain the value of status.connection.host, and PGPORT the value of status.connection.host:

annotations:
    binding/PGHOST: status.connection.host
    binding/PGPORT: status.connection.port

This states the PGHOST and PGPORT environment variables will be contributed to the applications' environment variables by all CRs associated to the CRD containing the annotation.

If a legacy application requiring POSTGRES_HOST and POSTGRES_PORT is taken in account, the required environment variables won't be available to the application automatically, requiring a user's intervention to specify the proper values for each desired environment variable like in the example below:

services:
    - resourceRef: sales
      kind: Database
      group: postgres.io
      version: v1
customEnvVars:
    # The index function is used since groups are expected to contain dots, which are used as 
    # separators in Go template variable accessors.
    POSTGRES_HOST: "{{ index . "v1" "postgres.io" "Database" "sales" "status" "connection" "host" }}"
    POSTGRES_PORT: "{{ index . "v1" "postgres.io" "Database" "sales" "status" "connection" "port" }}"

This results in the following environment variables being available to the application:

PGHOST="sales1.local"
PGPORT="5432"
POSTGRES_HOST="sales1.local"
POSTGRES_PORT="5432"

Having access to the same data collected by the service binding operator, users themselves could create a configuration value containing all Database hosts like the example below, where all collected Postgres hosts are grouped under the POSTGRES_HOSTS environment variable.

customEnvVars:
    POSTGRES_HOSTS: "{{ range $k, $v := (index . "v1" "postgres.io" "Database") }}{{ $v.host }};{{ end }}"

This template expression results in the value sales1.local;, assuming the sales database status.connection.host contains the value sales1.local.

As a next step, and assuming this is a useful configuration to have enabled by default at the CRD level, this can be easily transferred back to the CRD like the example below, since both templates share the same customEnvVar context:

annotations:
    binding/PGHOST: status.connection.host
    binding/PGPORT: status.connection.port
    binding/PGHOSTS: "{{ range $k, $v := (index . "v1" "postgres.io" "Database") }}{{ $v.host }};{{ end }}"

This change now contributes the PGHOSTS variable to all services consuming the CRD.

Continuing the application evolution, let's consider the user has declared a new service in this existing service binding:

services:
    - resourceRef: sales
      kind: Database
      group: postgres.io
      version: v1
    - resourceRef: analytics
      kind: Database
      group: postgres.io
      version: v1
customEnvVars:
    POSTGRES_HOST: "{{ index . "v1" "postgres.io" "Database" "sales" "status" "connection" "host" }}"
    POSTGRES_PORT: "{{ index . "v1" "postgres.io" "Database" "sales" "status" "connection" "port" }}"

The following variables are available to applications declared in the service binding (assuming map keys are stable and ordered):

PGHOST="analytics1.local"
PGPORT="5432"
PGHOSTS="sales1.local;analytics1.local;"
PGDSN="sales1.local:5432"

This happens because all CRs contribute, through the annotations in CRDs, to the same environment variable at the end. For cases where different CRs are required to compose a logically unique resource (such as Kafka and KafkaUsers resources mentioned in the thread), this is handy because the authors of services split in different CRDs can contribute to grouped configuration values without user intervention.

Appending a prefix to the environment variables produced by a specific CR should be used to group those resources in different environment variables:

services:
    - resourceRef: sales
      kind: Database
      group: postgres.io
      version: v1
      envVarPrefix: sales
    - resourceRef: ANALYTICS
      kind: Database
      group: postgres.io
      version: v1
      envVarPrefix: ANALYTICS
customEnvVars:
    POSTGRES_HOST: "{{ index . "v1" "postgres.io" "Database" "sales" "status" "connection" "host" }}"
    POSTGRES_PORT: "{{ index . "v1" "postgres.io" "Database" "sales" "status" "connection" "port" }}"

The following environments are available to the applications (assuming map keys are stable and ordered):

ANALYTICS_PGHOST="analytics1.local"
ANALYTICS_PGPORT="5432"
ANALYTICS_PGDSN="analytics1.local:5432"
SALES_PGHOST="sales1.local"
SALES_PGPORT="5432"
SALES_PGDSN="sales1.local:5432"
PGHOSTS="sales1.local;analytics1.local;"

Let's play with a Kafka and KafkaUser service binding:

services:
    - resourceRef: kafka-cluster1
      kind: Kafka
      group: kafka.io
      version: v1alpha1
    - resourceRef: kafka-user1
      kind: KafkaUser
      group: kafka.io
      version: v1alpha1

The Kafka CRD contains the following annotations:

annotations:
    binding/KAFKA_HOST: status.connection.host # each Kafka CR will contribute this environment variable, last wins

And KafkaUser:

annotations:
    binding/KAFKA_USER: status.credentials.user # each KafkaUser CR will contribute this environment variable, last wins

The following environments are available to the application:

KAFKA_HOST="kafka1.local"
KAFKA_USER="isutton"

Adding a second Kafka service requires grouping, as seen before with the last wins scenarios discussed above:

services:
    - resourceRef: kafka-cluster1
      kind: Kafka
      group: kafka.io
      version: v1alpha1
      envVarPrefix: IN # <-
    - resourceRef: kafka-user1
      kind: KafkaUser
      group: kafka.io
      version: v1alpha1
      envVarPrefix: IN # <-
    - resourceRef: kafka-cluster2
      kind: Kafka
      group: kafka.io
      version: v1alpha1
      envVarPrefix: OUT # <-
    - resourceRef: kafka-user2
      kind: KafkaUser
      group: kafka.io
      version: v1alpha1
      envVarPrefix: OUT # <-

Resulting in the following variables available to the application:

IN_KAFKA_HOST="kafka1.local"
IN_KAFKA_USER="isutton"
OUT_KAFKA_HOST="kafka2.local"
OUT_KAFKA_USER="other-user"

What are your thoughts?

sbose78 commented 4 years ago

If I had to summarize,

sbose78 commented 4 years ago

Done in #428