Feature: Scheduler Labels Others - sonchang/cattle GitHub Wiki
Overview
Why?
From the standpoint of building/deploying/scaling an application consisting of a bunch of micro-services, we want to allow users fine grained control over the deployment of the containers running these micro-services. Often these containers have very specific deployment requirements in order to inter-operate with each other (for example, port requirements, volume requirements, etc...)
Considerations
-
Handle existing container dependencies
- Port conflicts
- Shared volumes: --volumes-from=dependency
- Links: --link=dependency:alias
- Shared network stack: --net=container:dependency
-
Try to be compatible with docker swarm's specifications for filtering
-
Try to provide capabilities somewhat equivalent to fleet and kubernetes
Rancher labels for affinity rules
io.rancher.scheduler.constraint:XYZ{ne}ABC
io.rancher.scheduler.constraint:XYZ{eq~}DEF
Labels:
-
io.rancher.scheduler.affinity:container=foo (where foo is name of container or uuid)
-
io.rancher.scheduler.affinity:container_ne=foo,bar
-
io.rancher.scheduler.affinity:container_soft=foo,bar
-
io.rancher.scheduler.affinity:container_soft_ne=foo,bar
-
io.rancher.scheduler.affinity:host_label=XYZ=ABC (where XYZ and ABC are key/value pairs for a host label)
-
io.rancher.scheduler.affinity:host_label_ne=XYZ=ABC
-
io.rancher.scheduler.affinity:host_label_soft=XYZ=ABC,AAA=BBB
-
io.rancher.scheduler.affinity:host_label_soft_ne=XYZ=ABC
-
io.rancher.scheduler.affinity:container_label=XYZ=ABC (where XYZ and ABC are key/value pairs for a container label)
-
io.rancher.scheduler.affinity:container_label_ne=XYZ=ABC
-
io.rancher.scheduler.affinity:container_label_soft=XYZ=ABC
-
io.rancher.scheduler.affinity:container_label_soft_ne=XYZ=ABC
We'll continue to support swarm's environment variables as well for specifying affinity rules
-
Container constraints (where 'foo' is name of container or 'uuid'):
- affinity:container==foo (goes to a host having 'foo')
- affinity:container!=foo (goes to a host that does not have 'foo')
- affinity:container==~foo
- affinity:container!=~foo
-
Host constraints:
- constraint:label_key==bar (goes to host with label_key=bar)
- constraint:label_key!=bar
- constraint:label_key==~bar
- constraint:label_key!=~bar
-
Rancher environment variables
- affinity:container_label:key==value (goes to a host having container with label: label_key=bar)
- affinity:container_label:key!=value
- affinity:container_label:key==~value
- affinity:container_label:key!=~value
Service scenarios
TODO: Most likely these rules will actually use ==~ instead of == (and !=~ instead of !=) to avoid falling into a case where no allocation is found
Service rule: A: affinity:container==B (where A=3, B=1)
- A1: affinity:container==B
- A2: affinity:container==B
- A3: affinity:container==B
Service rule: A: affinity:container==B (where A=3, B=2)
- I guess cycle through however many B's are available. Likewise, if B's scale is larger than A's:
- A1: affinity:container==B1
- A2: affinity:container==B2
- A3: affinity:container==B1
Service rule: A: affinity:container!=A (where scale of A is 3)
- Initially A1 lands on any:
- A1: affinity:container!=A1
- A1: affinity:container!=A2
- A1: affinity:container!=A3
- A2 shouldn't land on A1
- A2: affinity:container!=A1
- A2: affinity:container!=A2
- A2: affinity:container!=A3
- A3 shouldn't land on A1 or A2
- A3: affinity:container!=A1
- A3: affinity:container!=A2
- A3: affinity:container!=A3
Service rule: A: affinity:container!=B (where A=3, B=2)
- A1: affinity:container!=B1
- A1: affinity:container!=B2
- A2: affinity:container!=B1
- A2: affinity:container!=B2
- A3: affinity:container!=B1
- A3: affinity:container!=B2
Functional design
Labels/tagging versus clustering
Question: Should we use cattle's existing clustering framework for labeling?
I don't think we should do this for multiple reasons:
- Currently, a cluster is also considered as a host. This means it has an entirely different deployment mechanism for containers. We choose one specific 'host' or 'cluster' to deploy to. On the other hand, with labeling, there's much greater flexibility in terms of how the label is treated including wildcarding or regular expressions. Also, treating a cluster as a label is limiting the labeling to just hosts as opposed to including containers.
- Labels are currently publicly exposed within docker. Similarly, clusters are publicly exposed within cattle. Intermixing the two would cause much confusion.
Ultimately, labeling/tagging should be an entirely different axis from clustering.
Environment variable definition
Swarm type constraints
-e constraint:{label_key==label_value}
where label_key can be a custom value or one of the following standard ones sourced from docker info : storagedriver, executiondriver, kernelversion, operatingsystem
Note: Currently the labels above only apply to host/docker daemon labels. So we'll have cattle's scheduler do the same except act on our own host labels
-e affinity:container=={other_container_name or id}
-e affinity:image={image_name or id}
*Note: Soft affinities is specified using '~' * Note: globbing support?
Additional research: Docker GET /exec/(id)/json returns info that is gathered by the docker info command. However, how do we obtain this info without first deploying a container?
Potentially phase 2: Support for go regular expressions
Fleet / systemd considerations
Option Name | Description |
---|---|
MachineID |
Require the unit be scheduled to the machine identified by the given string. |
MachineOf |
Limit eligible machines to the one that hosts a specific unit. |
MachineMetadata |
Limit eligible machines to those with this specific metadata. |
Conflicts |
Prevent a unit from being collocated with other units using glob-matching on the other unit names. |
Global |
Schedule this unit on all agents in the cluster. A unit is considered invalid if options other than MachineMetadata are provided alongside Global=true . |
- MachineID: accomplished via matching of tag/label of host
- MachineOf: accomplished via matching of tag/label of container
- MachineMetadata: accomplished via matching of tag/label of hosts all having same tag/label
- Conflicts: Negative matches of above
Kubernetes type scheduling
Labels support (same as swarm's)
Question: Are there additional capabilities that label variable substitutions provide that can't be accomplished by glob-matching / regex
Implementation
##New models
-
'label' with fields 'name', 'type'
- 'name': name of the label
- 'type': TBD whether we should keep this or not
-
'instancelabelmap'
-
'hostlabelmap'
-
labels for images?
Basically, allows you associate label(s) to instances or hosts.
Public API
'container': New actions 'addlabel', 'removelabel'
'host': New actions 'addlabel', 'removelabel'
'label': Simplified process lifecycle: create/remove
Appendix
Sample host information:
{
"fields": {
"reportedUuid": "fb605b0b-f213-412f-bed6-234a89a0e2fe",
"type": "host",
"physicalHostUuid": "7cb89135-6030-48ec-a009-aad41844ee3e",
"info": {
"osInfo": {
"versionDescription": "trusty",
"kernelVersion": "3.18.5-tinycore64",
"distribution": "Ubuntu",
"version": "14.04",
"dockerVersion": "Docker version 1.5.0, build a8a31ef"
},
"cpuInfo": {
"count": 8,
"cpuCoresPercentages": [
0.21,
0.565,
0.904,
0.347,
0.826,
1.27,
0.065,
0.289
],
"loadAvg": [
0.02,
0.08,
0.07
],
"mhz": 2210.338,
"modelName": "Intel(R) Core(TM) i7-4770HQ CPU @ 2.20GHz"
},
"memoryInfo": {
"memTotal": 2007.906,
"swapTotal": 1434.145,
"cached": 185.699,
"swapCached": 0.0,
"swapFree": 1434.145,
"memAvailable": 1635.586,
"memFree": 1678.313,
"inactive": 119.238,
"active": 156.703,
"buffers": 34.305
},
"diskInfo": {
"mountPoints": {
"/dev/sda1": {
"total": 18603.41,
"free": 12721.297,
"used": 5882.113,
"percentUsed": 31.62
}
}
}
}
}
}
Sample Kubernetes replication controller config:
id: nginx-controller
apiVersion: v1beta1
kind: ReplicationController
desiredState:
replicas: 2
# replicaSelector identifies the set of Pods that this
# replicaController is responsible for managing
replicaSelector:
name: nginx
# podTemplate defines the 'cookie cutter' used for creating
# new pods when necessary
podTemplate:
desiredState:
manifest:
version: v1beta1
id: nginx
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
# Important: these labels need to match the selector above
# The api server enforces this constraint.
labels:
name: nginx
References
https://github.com/GoogleCloudPlatform/kubernetes/blob/master/examples/walkthrough/k8s201.md