The code section
The code section puts together the rest of a component’s specification to instruct how to actually run the code for an instance of the component.
The code section is essentially, a set of specifications for how to run a container. A component’s code may consist of more than one image, each of which should be ran within its own container.
Containers within the code section are organized as a dictionary of #Container
structures:
code: [nm=string]: #Container & {name: nm}
Where each field in code
is the name of the container to be created when an instance of the
component is run, and the #Container
structure must contain itself a name
field whose
value is that of the key leading to that structure,
#Container: {
name: string
size: #ContainerSize
image: #Image
entrypoint?: [...string]
cmd?: [...string]
user?: {
userid: uint16
groupid: uint16
}
mapping: #Mapping
}
#Image: {
hub: #Hub | * {name: "registry.hub.docker.com", secret: ""}
tag: string
digest?: string
}
#Hub: {
name: string
secret: string
}
Note that, as we mentioned earlier, code for a component must be encapsulated
by docker images, which are referenced within the #Container
structure.
We can use a tag to refer to an image, and, currently, providing the
digest is optional. This will change in future revisions, as Kumori Platform enphasizes
reproducibility of results, and referring to the code by tag is very weak, as such
tags provide no guarantee of immutability of the code behind the tag, besides being fully dependent
on the hub from which the image is retrieved.
|
A hub to retrieve an image must be provided (there is a suitable default, though). In the future, this may be optional, relying on registered hubs, or default hubs. The Hub in itself is not a defining characteristic of the image itself, nor of the component. |
The secret
referred to within a hub description must be registered in the platform.
As other resources referenced from within the code
section, what actually gets placed
in the image secret is the path into the resource configuration contianing that secret.
Size
As before the size of a component instance has a global part and a per-container part.
Mappings
An important part of the code
section is the mapping subsection. Its definition is here:
#Mapping: {
filesystem: [...#FileMap | #FolderMap]
env: #EnvMap
}
#EnvMap: {
[string]: {[#DataResourceKey]: string} | {parameter: string} | {value: string}
}
#FileMap: {
path: string
mode: uint16 | *0o644
data: {[#DataResourceKey]: string} | {parameter: string} | {value: string}
format: *"text" | "json" | "yaml"
}
#FolderMap: {
path: string
{{tree: [...#FileMap | #FolderMap]} | volume: string}
}
From the definition we see that there are filesystem and environment mappings. The environment mapping is organized as a dictionary of environment variables, whose values will be made available to the container on execution.
In the specification, values for environment variables can be provided in several ways:
-
As the data value of resources made available through the configuration, where the string provided must correspond to a path in the
resource
part of the config leading to a resource of the kind specified by the#DataResourceKey
provided -
With an arbitrary string value (
value: string
) which may come from the configuration through standard CUE references. -
As a reference to a parameter (
parameter: string
), where the string must be a path into theparameter
section of the config. The value injected will be the value of the parameter as a string.
Values for environment variable mappings must resolve to string |
Filesystem mappings
Filesystem mappings are organizad as an array of mappings. Each element of the array may map a file or, potentially, a tree of folders and files.
File Maps
Mapping a file is simple: its path within the container must be specified. In addition, we can provide a mode for the file (useful to inject executable scripts when adapting third party images).
In addition to the path, we need to provide the data. Data for a file map can come from the same sources as data for an environment variable (see above).
In addition, a format field completes the specification for a file map. By default it assumes data
value should be interpreted as a raw string and be left as is within the resulting
text file, without marshalling it.
It is an error to specify a `text`format for a non-string data value. |
If format is json
, or yaml
, then data is marshalled to either of those two formats, and
the result of that is placed within the file.
Folder maps
Folder maps seem a bit more complex, but they are also quite simple to understand.
A folder map, like a file map, must provide a path. The simplest folder map then, interprets
that path as the path of a folder where to mount either a Volatile or a Persistent Volume.
In such a case, the string provided for the volume is actually a path into the
resource
section of the config. This approach allows us to share the same volume accross multiple
containers.
If, however, a tree
field is specified, then the path provided is still
treated as a folder path, however no mounting is produced on that path, serving only
to recursively define further mappings withint the folder (either file or folder
maps).
As mentioned, volumes can be shared among the containers of a component. |
When references to the config are used outside a value: ` field, the strings must match
a path within the respective part of the config (either `parameter or resource ). The values
to be inserted into the file/env variable will be provided by the platform at deployment.
|