Table of Contents generated with DocToc
Composable Operator
Composable is an overlay operator that can wrap any resource (native Kubernetes or CRD instance) and allows it to be
dynamically configurable. Any field of the underlying resource can be specified with a reference to any field of other
Kubernetes objects.
The Composable Operator enables the complete declarative executable specification of collections of inter-dependent resources.
Installation Composable
To install the latest release of Composable, run the following script:
curl -sL https://raw.githubusercontent.com/IBM/composable/master/hack/install-composable.sh | bash
Composable will be installed in the composable-operator
namespace
Removing Composable
To remove Composable, run the following script:
curl -sL https://raw.githubusercontent.com/IBM/composable/master/hack/uninstall-composable.sh | bash
Examples
Here we provide several examples of Composable usage, of course its possible usage is not restricted by the provided use
cases. More other can be added later.
File with all examples can be found in samples
An example when a Kubernetes ConfigMap
created based on a Kubernetes Service
Let's assume that we have a Kubernetes Service
, which is part of another deployment, but we would like to create an automatic
binding of our deployment objects with this Service
. With help of Composable
we can automatically create a ConfigMap
with a Service
parameter(s), e.g. the port number, whose name is http
The Service
yaml file might looks like:
apiVersion: v1
kind: Service
metadata:
name: myservice
namespace: default
spec:
sessionAffinity: None
type: ClusterIP
selector:
app: MyApp
ports:
- name: http
protocol: TCP
port: 80
targetPort: 9376
The following file contains the Composable
definition:
apiVersion: ibmcloud.ibm.com/v1alpha1
kind: Composable
metadata:
name: to-cm
spec:
template:
apiVersion: "v1"
kind: ConfigMap
metadata:
name: myconfigmap
data:
servicePort:
getValueFrom:
kind: Service
name: myservice
namespace: default
path: '{.spec.ports[?(@.name=="http")].port}}'
format-transformers:
- ToString
You can see the detail explanation of the getValueForm
fields below, but the purpose of the object is to create a
ConfigMap
named myconfigmap
and set servicePort
to be equal to the port named http
in the Service
object named
myservice
in the default
namespace.
A Composable and a created object (myconfigmap
) will be in teh same namespace, but input objects can be in any namespaces.
An example of Service.ibmcloud.ibm.com
Composable-operator project works tightly with 2 other related projects: (SolSA - Solution Service Architecture)[https://github.com/IBM/solsa]
and (cloud-operators)[https://github.com/IBM/cloud-operators]. The samples directory has 3 different
examples of creation/configuration of Service.ibmcloud.ibm.com
from the cloud-opertors
project.
Here is one of them
apiVersion: ibmcloud.ibm.com/v1alpha1
kind: Composable
metadata:
name: comp
spec:
template:
apiVersion: ibmcloud.ibm.com/v1alpha1
kind: Service
metadata:
name: mymessagehub
spec:
instancename: mymessagehub
service: Event Streams
plan:
getValueFrom:
kind: Secret
name: mysecret
path: '{.data.plan}'
format-transformers:
- "Base64ToString"
In this example, the field plan
of the Service.ibmcloud
instance is specified by referring to a secret. When the composable operator is created, its controller tries to read the secret and obtains the data needed for this field. If the secret is available, it then creates the Service.ibmcloud
resource with the proper configuration. If the secret does not exist, the Composable controller keeps re-trying until it becomes available.
Here is another example:
apiVersion: ibmcloud.ibm.com/v1alpha1
kind: Composable
metadata:
name: comp
spec:
template:
apiVersion: ibmcloud.ibm.com/v1alpha1
kind: Service
metadata:
name:
getValueFrom:
kind: ConfigMap
name: myconfigmap
namespace: default
path: {.data.name}
spec:
instancename:
getValueFrom:
kind: ConfigMap
name: myconfigmap
namespace: default
path: {.data.name}
service: Event Streams
plan:
getValueFrom:
kind: Secret
name: mysecret
namespace: default
path: {.data.planKey}
In this example, the name of the underlying Service.ibmcloud
instance is obtained from a configmap
and the same
name is used for the field instancename
. This allows flexibility in defining configurations, and promotes the reuse
of yamls by alleviating hard-wired information.
Moreover, it can be used to configure with data that is computed dynamically as a result of the deployment of some other
resource.
The getValueFrom
element can point to any K8s and its extensions object. The kind of the object is defined by thekind
element; the object name is defined by the name
elements, and finally, the path to the data is defined by the value of
the path
element, which is a string with dots as a delimiter.
getValueFrom elements
The getValueFrom
element should be a single child of the parent element and can contain the following sub-fileds:
Filed |
Is required |
Format/Type |
Comments |
kind |
Yes |
String |
Kind of the input object |
group |
No |
String |
Defines a K8s Api group of teh checking object. Helps to resolve conflicts, when the same Kind defined in several groups |
name |
Yes |
String |
Name of the input object |
namespace |
No |
String |
Namespace of the input object, if isn't defined, the ns of the Composable operator will be checked |
path |
Yes |
String |
The jsonpath formatted path to the checked filed |
format-transformers |
No |
Array of predefined strings |
Used for value type transformation, see Format transformers |
Sometimes, types of an input value and expected output value are not compatable, in order to resolve this issue,
Composable
supports several predefined transformers. They can be defined as a string array, so output of the a previous
transformer's will be input to next one.
When you define a Composable
object, it is your responsibility to put in a correct order the transformers.
Currently Composable
supports the following transformers:
Transformer |
Transformation |
ToString |
returns a native string representation of any object |
ArrayToCSString |
returns a comma-separated string from array's values |
Base64ToString |
decodes a base64 encoded string |
StringToBase64 |
encodes a string to base64 |
StringToInt |
transforms a string to an integer |
StringToFloat |
transforms a string to a float |
StringToBool |
transforms a string to boolean |
JsonToObject |
transforms a JSON string to an object |
ObjectToJson |
transforms an object to a JSON string |
The data transformation roles are:
- If there is no data transformers - original data format will be used, include complex structures such as maps or arrays.
- Transformers from the format-transformers array executed one after another according to their order. Which allows
creation of data transformation pipelines. For example, the following snippet defines transformation from a base64
encoded string to a plain string and after that to integer. This transformation can be useful to retrieve data from Secrets.
format-transformers:
- Base64ToString
- StringToInt
Namespaces
The getValueFrom
definition includes the destination namespace
, the specified namespace is used
to look up the referenced object. Otherwise, the namespace
of the Composable
object is checked.
The template object should be created in the same namespaces
as the Composable
object. Therefore, we recommend do not
define namespace
in the template. If the namespace field is defined and its value does not equal to the Composable
object namespace, no objects will be created, and Composable
object status will contain an error.
Deletion
When the Composable object is deleted, the underlying object is deleted as well.
If the user deletes the underlying object manually, it is automatically recreated`.
Field path discovery
We use a jsonpath
parser from go-client
to define path to the resolving files. Here some examples:
{.data.key-name}
- returns a path to the key named key-name
from a ConfigMap
or from a Secret
{.spec.ports[?(@.name==“http”)].port}}
- takes port value from a port named http
from the ports
array
Limitations
Due to
issue #72220, jsonpath
doesn't support regular expressions
in json-path