0
0

Cloud Manager Reference Manual

Docs
Docs EInnovator Posted 13 May 20

Connectors and Bindings

Cloud Manager supports the twin mechanisms of connectors and bindings to simplify application configuration. Services expose one or more connectors, and applications bind to these connectors using bindings. Each binding specifies a set of related environment variables that are set at application deployment and restart time. The value of these variables is evaluated from the settings of the connector it binds to.

Configuration with Connector and Bindings

A deployment or service can expose one or more connectors, each defining a set of key-value pairs used to export connection information to applications. They are defined with a JSON specification, and typically include information, such as: credentials (username/password, key/secret), service location (host/IP), access URL, and other connection settings. When a connector is created it can be assigned an optional type and tags. This allows for the automatic generation of binging specs (see below).

Some examples of connectors include:

  • A database service may define several connectors one for each database (schema) and user pair that it manages.
  • A messaging-broker may define a single connnector for all app in a microservice architecture exchange messages. Multiple connector may also be define to access the broker with different permission level. If the broker supports virtual hosts, different connectors may be defined for each.
  • A connector may be defined for an external mail service definining host, port, protocol, credentials, and other options.

A binding is a collection of settings for environment variables whose values are resolved from the connector that it binds to. These settings constitute the specification (spec) of the binding, define as a JSON value.

A binding is matched with a connector by specifying a selector of the form service-name/connector-name. In Cloud Manager UI, the the service/connector of a binding can also selected via dropdown/combobox widgets.

It is preferred to make the actual settings in the binding spec depend on stack used to implement the application. This allows the app to be configured in a completely portable way — rather than requiring the app to be aware and pick-up platform specific settings.

When a binding is created, and the auto option provided, its specification is generated automatically. The type and/or tags of the matching connector, together with the stack of th app, is used determine which environment variable to set by the binding.

Deployment Connectors

To create a connector for a deployment with the Cloud Manager UI navigate to panel Environment > Connector of the deployment dashboard. Press button Add Connector.

The following information is specified for each connector:

  • Name — The name of the connector. Bindings use this name in their selector.
  • Type — An optional type designator. Used to hint how to generated binding specs automatically.
  • Tags — An optional comma separated list of tags. Similarly to the type, if is used to hint how to generated binding specs automatically.
  • Spec — The specification of connector as a JSON structure defining key--value pairs. When using the CLI, it can also be specified as a comma-separated list of key--value pairs.

Image depicts a the UI modal to create or edit a connector.

Connector can also be created with the CLI tool using command connector add. The option --spec provides a JSON specification for the connector.

Because entering the spec with JSON from the command-line tends to be a bit cumbersome (as double-quotes need to be escaped), it is often preferred to use a comma-separated list of settings. The option --spec defines the specification of the connection as JSON or a comma-separated list of key--value pairs. The option --type define the type of connector, and option --tag define a comma-separated list of tags. Both are used as optional hint to allow auto-generation of binding specifications.

ei connector add mysql superheros/root --type=mysql \
  --spec=password:^^mysql-credentials.password,username:root,uri:mysql://\${host}/superheros

In the example above, the connector spec defines several variables, including: password looked up from secret mysql-credentials (syntax prefix ^^ resolves a secret data item, and prefix ^ resolves a configmap data item), username defined as root, and uri referring to variable ${host} (set automatically to the IP of the service endpoint) and database superheros.

External Connectors

External connectors are used to connect to external services not running in the same cluster/space as the the binding applications. They are defined at the space level. This allow deployments running in the same space share the definitions.

Possible use cases for external connector, include:

  • A database running in a VM outside containers (for performance, security, or other reasons);
  • A message-broker provisioned in a service-broker marketplace and managed by a third-party;
  • A SMTP mail service managed by a CSP.

To create an external connector with Cloud Manager UI use panel Environment > (X)Connector of the space dashboard. Press button Add Connector.

External connector can also be created with the CLI tool using command connector create with option ‘-x’.

I define below a connector to an external SMTP service, named mailer, managed by AWS. The command connector add is used as before, but now the option -x is used to specify that it is an external connector. The connector is created in the scope of the current space. Alternatively, the option -n can be used to specify another space.

ei connector add mailer -x --type=mail --tags=smtp \
  --spec=host:email-smtp.us-east-1.amazonaws.com,port:587,from:web@acme.com,username:^^mail.key,password:^^mail.secret

The type mail and tag smtp are used to hint Cloud Manager how to create binding specs. For a Spring Boot application this sets SPRING_MAIL_* variables. Notice that the connector spec refers to a secret name mail, so we need to define it. Below, I use command secret create for this.

MAIL_KEY=XXXXX
MAIL_SECRET=YYYYY
ei secret create mail --encode --data=key:$MAIL_KEY,secret:$MAIL_SECRET

Defining Bindings

Stack-Aware Bindings

Table below, summarizes some of the stacks and services supported by Cloud Manager.

StackServiceService Type/TagsEnvironment variables
Spring BootMySQL|MariaDBmysqlSPRING_DATASOURCE_{URI|USERNAME|PASSWORD}
QuarkusMySQL|MariaDBmysqlQUARKUS_DATASOURCE_{URI|USERNAME|PASSWORD}

Note that we can use the connectors abstraction for any kind of service, and the binding abstraction for any stack. However, if the service-stack pair is currently not supported by Cloud Manager you will need to provide the spec of the binding manually. Alternatively, you can fallback to use plain environment variables settings.

TIP: If you find that there is currently no support for your preferred stack and service types in Cloud Manager, you can email <support@einnovator.org> to ask to be included in the next/future release.

You may also need to configure additional properties for a service beyond what the auto-generated binding spec provides. You can do this by modifying the binding spec (via the UI or CLI), or by complementing these settings with plain environment variables defined at the level of deployment or at the level of the Space*. For example, you have URL and credentials for a DB be defined in a stack-aware binding, and use a variable to define other connection settings.

Binding to an External Connector

To bind to an external service connector is similar to a deployment connector. Cloud Manager matches the selector of the binding with the connector name.

ei binding add superheros mailer 
ei superheros restart

A binding is a collection of settings for environment variables whose value are resolved from a connector. The appropriate environment variables to set depend on the stack used to implement the application. Below, I use command binding add to create a new binding for the app superheros. The selector mysql/superheros/root specifies that we are binding to the connector named superheros/root of service mysql.

ei binding add superheros mysql/superheros/root --auto
ei deploy restart supeheros

The option --auto ask for the binding specification to be generated automatically based on the stack of the app and the service type. Because we specified --stack=BOOT for the app early on, and the connector type is mysql, the environment variables to set are SPRING_DATASOURCE_*. The genereate binding spec is show below:

{"spring":{"datasource":{"url":"jdbc:${uri}","username":"${username}","password":"${password}"}}}

Once the app is restarted it will be running and fetching/storing data in the MySQL DB, rather than the embedded DB. You can confirm this my looking at the logs of the app (the table schema is auto-generated again), using the UI or with command ei deploy log superheros -l300.

Connecting to a Message-Broker

Message-brokers are ideal to implement asynchronous inter-process communication in microservice architectures. Below, I use RabbitMQ messaging-broker to illustrate how apps can easily be configured to send-receive messages with connectors and bindings.

Installing a Broker

RabbitMQ is most conveniently installed in a Kubernetes cluster using Helm charts. You can use helm command from your lapatop to perform the installation. Alternatively, you can use the command install of Cloud Manager CLI, has done before for MySQL.

Check that you have at least one solution for RabbitMQ in Cloud Manager marketplace by typing ei market rabbitmq. Confirm that it shown under a catalog of type HELM. If not, you can add a catalog known to have it, as follows:

ei catalog create bitami --type=helm --url=https://charts.bitnami.com/bitnami

To perform the installation with ei, assuming devops tools are installed in the cluster, type the command below.

ei install rabbitmq
ei ps

TIP: To use ei to install Helm charts, the devops tools image need to be running as a pod in the cluster. This can be done via the Cloud Manager UI in panel Cluster > Settings > Runtime > Devops Tools, or by specifying the option --tools when importing the cluster.

To create connectors to solutions installed from Helm charts you also need to make the solution managed by Cloud Manager. This is done with command deploy attach as shown below:

ei deploy attach rabbitmq

Defining Broker Connectors

Below, I use command connector add to create a connector the service rabbitmq with name default. The connector name default is somewhat special, as it can be omitted when defining bindings.

ei connector add rabbitmq default --type=amqp --spec=password:^^rabbitmq.rabbitmq-password,username:user,host:\${host}

The option --spec defines a comma-separated list of key-value pairs for the specification for the connector. Here, exporting the variables: password looked up from data in rabbitmq-password in secret rabbitmq, username defined as user, and host referring to built-in variable ${host}. The virtual host and ports are left unspecified, so they defaults are assumed. The option --type is an optional hint to allow auto-generation of binding specifications.

Binding to a Broker

Next, I create a binding for the app to connect to rabbitmq the service. The option --auto hints Cloud Manager to generate the specification automatically. Because the app stack in Spring Boot, the environment variables SPRING_RABBIT_ will be configured automatically.

ei binding add superheros rabbitmq --auto
ei deploy restart superheros

Command restart is used to restart the app and update the settings. Confirm that the environment variables are set automatically from the binding by inspeciting the deployment manifest. For this, you can use Cloud Manager UI panel Deployment > Instances > MetaData, command kubectl describe superheros, or command ei deploy manifest superheros.

Connecting to other Microservices

In addition to backing services, connectors and bindings can also be used to connect to other microservices, including: third-party reusable middleware services, such as a SSO Gateway or a Payments Gateway, and other custom services part of an overall architecture. Below, I illustrate these two scenarios by showing how to deploy and connect to EInnovator SSO Gateway, and discuss how to make the sample app API be accessible by other services.

Installing a SSO Gateway

To install EInnovator SSO Gateway I use the command install — the same procedure used before to install the backing services. The catalog name is einnovator and solution name einnovator-sso. The option --name is used to define a shorter name for the deployment.

ei install einnovator/einnovator-sso --name=sso

TIP: The EInnovator SSO Gateway will try to automatically bind to a AMQP service in the same space if you defined a connector named default, and tries to declare a queue and exchange. To prevent this run command ei connector rm sso amqp, or change the name of the RabbitMQ connector. You should also restart the SSO Gateway after this with command ei deploy restart sso.

Defining a SSO Connector

Command connector add is used to define a connector for the SSO Gateway named app. The type ei-sso is used to hint Cloud Manager on how to generate stack-aware bindings. The --spec option defines a comma-separated list of variables to export, including: the clientId and clientSecret, and the service URL from the implicit variable ${url}.

ei connector add sso app --type=ei-sso --spec=clientId:application,clientSecret:application\$123,url:\${url}

The specified clientId and clientSecret are default ones, setup automatically by the SSO Gateway for development purposes. For production environments, you should create new client app credentials for security reasons. (see below)

Without additional configuration, the implicit variable ${url} will take the value http://host-ip — where host-ip is the private IP address of the service. This is good enough if the connecting applications are using only the API of the SSO Gateway. For OAuth2 authentication with code grant or to use the UI, the SSO Gateway needs to accessible outside the cluster from a web-browser. The most convenient way to do this (although not the only one supported by Kubernetes), is to add a DNS route to the app. (see below)

Binding to the SSO Gateway

To bind the sample app to the SSO Gateway I use command binding add with option --auto. Cloud Manager will generate the binding spec to set the environment variables SSO_SERVER, SSO_CLIENTID, and SSO_CLIENTSECRET.

ei binding add superheros sso/app --auto
ei restart
ei connector refresh sso app
ei binding refresh superheros sso/app
ei restart superheros

Defining an API Connector

In addition to a UI, the sample app Superheros implements also a REST API for managing superhero resources with CRUD operations. To make this service API easily accessible by other services, we can define a default connector.

ei connector add superheros default --spec=url:\${url}

As was the case for the app connector of SSO Gateway, the implicit variable ${url} will take the value http://host-ip. To access the UI of the superheros app, and/or to access the API via a DNS host.domain, add one (or more) route(s) to the app.

ei route add superheros superheros
ei route add superheros heros

Client apps can then be configured to connect to the REST API (using the DNS route address) by defining a binding with a custom spec.

ei binding add myotherapp superheros --spec=superheros_server:\${url}

The variable superheros_server is some custom variable, assumed to be recognized by myotherapp.

Note: When service API is accessed via the private IP address (rather than a DNS host.domain), the connector-binding approach can be considered an overkill since Kubernetes exposes automatically this information in environment variables KUBERNETES_*_HOST. However, this requires the app to be modified to pickup this Kubernetes specific variables and detect that is running in a cluster rather than a (localhost) dev environment.

Comments and Discussion

Content