Suite of the Docker and Kubernetes applications
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

627 lines
20 KiB

# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
Namespaces:
=: com.mirantis.docker.kubernetes
std: io.murano
res: io.murano.resources
sys: io.murano.system
docker: com.mirantis.docker
Name: KubernetesCluster
Extends: std:Application
Properties:
name:
Contract: $.string().notNull()
masterNode:
Contract: $.class(KubernetesMasterNode).notNull()
minionNodes:
Contract:
- $.class(KubernetesMinionNode).notNull()
- 1
nodeCount:
Contract: $.int().notNull().check($ > 0)
Usage: InOut
gatewayCount:
Contract: $.int().notNull().check($ > 0)
Usage: InOut
gatewayNodes:
Contract:
- $.class(KubernetesGatewayNode).notNull()
- 1
useFlannel:
Contract: $.bool().notNull()
Default: false
enableKubeDns:
Contract: $.bool().notNull()
Default: true
enableDashboard:
Contract: $.bool().notNull()
Default: true
dockerRegistry:
Contract: $.string()
dockerMirror:
Contract: $.string()
gcloudKey:
Contract: $.string()
serviceEndpoints:
Contract:
- port: $.int().notNull().check($ > 0)
address: $.string().notNull()
scope: $.string().notNull().check($ in list(public, cloud, internal, host))
portScope: $.string().notNull().check($ in list(public, cloud, internal, host))
containerPort: $.int().notNull().check($ > 0)
protocol: $.string().notNull().check($ in list(TCP, UDP))
applicationName: $.string().notNull()
podId: $.string().notNull()
serviceName: $.string()
Default: []
Usage: Out
Methods:
.init:
Body:
- $._environment: $.find(std:Environment).require()
isAvailable:
Body:
- Return: $.masterNode.isAvailable()
deploy:
Body:
- $.serviceEndpoints: $.getAttr(serviceEndpoints, list())
- If: not $.getAttr(deployed, false)
Then:
- $._environment.reporter.report($this, 'Creating VMs for Kubernetes cluster')
- $securityGroupIngress:
- ToPort: 4001
FromPort: 4001
IpProtocol: tcp
External: false
- ToPort: 7001
FromPort: 7001
IpProtocol: tcp
External: false
- ToPort: 10250
FromPort: 10250
IpProtocol: tcp
External: false
- ToPort: 8080
FromPort: 8080
IpProtocol: tcp
External: $.masterNode.instance.assignFloatingIp
- ToPort: 2380
FromPort: 2380
IpProtocol: tcp
External: false
- ToPort: 8285
FromPort: 8285
IpProtocol: udp
External: false
- $._environment.securityGroupManager.addGroupIngress($securityGroupIngress)
- $.setAttr(deployed, true)
- $prevNodeCount: $.getAttr(lastNodeCount, 0)
- $prevGatewayCount: $.getAttr(lastGatewayCount, 0)
- If: $prevNodeCount != $.nodeCount or $prevGatewayCount != $.gatewayCount
Then:
- $._environment.reporter.report($this, 'Setting up Kubernetes cluster')
- Parallel:
- $.masterNode.deployInstance()
- $.minionNodes.take($.nodeCount).pselect($.deployInstance())
- $.gatewayNodes.take($.gatewayCount).pselect($.deployInstance())
- $.masterNode.setupEtcd()
- $.minionNodes.skip($.nodeCount).select($.removeFromCluster())
- $.gatewayNodes.skip($.gatewayCount).select($.removeFromCluster())
- $.minionNodes.take($.nodeCount).select($.setupEtcd())
- $.gatewayNodes.take($.gatewayCount).select($.setupEtcd())
- $._deployContainersNetwork()
- $.masterNode.setupNode()
- Parallel:
- $.minionNodes.take($.nodeCount).pselect($.setupNode())
- $.gatewayNodes.take($.gatewayCount).pselect($.setupNode())
- If: $.enableKubeDns
Then:
$._deployDns()
- If: $.enableDashboard
Then:
- $._deployDashboard()
- If: $.gatewayCount > 0
Then:
- $msg: $.gatewayNodes.take($.gatewayCount).select('http://{0}:{1}'.format($.getIp(true), 9090)).join(', ')
- $._environment.reporter.report($this, 'Dashboard UI is available at {0}'.format($msg))
Else:
- $._environment.reporter.report($this, 'Dashboard UI is installed but is not accessible from outside')
- $._environment.stack.push()
- $._updateServicePublicIps()
- $.setAttr(lastNodeCount, $.nodeCount)
- $.setAttr(lastGatewayCount, $.gatewayCount)
- $._environment.reporter.report($this, 'Kubernetes cluster is up and running')
- $.setAttr(serviceEndpoints, $.serviceEndpoints)
getIp:
Body:
Return: $.masterNode.getIp()
_deployDashboard:
Body:
- If: not $.getAttr(uiDeployed, false)
Then:
- $securityGroupIngress:
- ToPort: 9090
FromPort: 9090
IpProtocol: tcp
External: $.masterNode.instance.assignFloatingIp
- $._environment.securityGroupManager.addGroupIngress($securityGroupIngress)
- $resources: new(sys:Resources)
- $template: $resources.yaml('DeployDashboard.template').bind(dict(ip => $.getIp()))
- $.masterNode.instance.agent.call($template, $resources)
- $.setAttr(uiDeployed, true)
_deployDns:
Body:
- If: not $.getAttr(dnsDeployed, false)
Then:
- $securityGroupIngress:
- ToPort: 8001
FromPort: 8001
IpProtocol: tcp
External: false
- ToPort: 10053
FromPort: 10053
IpProtocol: udp
External: false
- ToPort: 10053
FromPort: 10053
IpProtocol: tcp
External: false
- ToPort: 53
FromPort: 53
IpProtocol: udp
External: false
- ToPort: 53
FromPort: 53
IpProtocol: tcp
External: false
- $._environment.securityGroupManager.addGroupIngress($securityGroupIngress)
- $resources: new(sys:Resources)
- $template: $resources.yaml('DeployKubeDns.template')
- $.masterNode.instance.agent.call($template, $resources)
- $.setAttr(dnsDeployed, true)
_deployContainersNetwork:
Body:
- If: $.useFlannel
Then:
- $.masterNode.setupFlannel()
- Parallel:
- $.minionNodes.take($.nodeCount).pselect($.setupFlannel())
- $.gatewayNodes.take($.gatewayCount).pselect($.setupFlannel())
Else:
- Parallel:
- $.masterNode.setupCalico()
- $.minionNodes.take($.nodeCount).pselect($.setupCalico())
- $.gatewayNodes.take($.gatewayCount).pselect($.setupCalico())
createPod:
Arguments:
- definition:
Contract: {}
- isNew:
Contract: $.bool().notNull()
Default: true
Body:
- $.deploy()
- $resources: new(sys:Resources)
- $template: $resources.yaml('UpdatePod.template').bind(dict(
podDefinition => $definition,
isNew => $isNew
))
- $.masterNode.instance.agent.call($template, $resources)
createReplicationController:
Arguments:
- definition:
Contract: {}
- isNew:
Contract: $.bool().notNull()
Default: true
Body:
- $.deploy()
- $resources: new(sys:Resources)
- $template: $resources.yaml('UpdateReplicationController.template').bind(dict(
controllerDefinition => $definition,
isNew => $isNew
))
- $.masterNode.instance.agent.call($template, $resources)
deleteReplicationController:
Arguments:
- id:
Contract: $.string().notNull()
Body:
- $.deploy()
- $resources: new(sys:Resources)
- $template: $resources.yaml('DeleteReplicationController.template').bind(dict(rcId => $id))
- $.masterNode.instance.agent.call($template, $resources)
deletePods:
Arguments:
- labels:
Contract:
$.string().notNull(): $.string().notNull()
Body:
- $.deploy()
- $resources: new(sys:Resources)
- $template: $resources.yaml('DeletePods.template').bind(dict(labels => $labels))
- $.masterNode.instance.agent.call($template, $resources)
createService:
Arguments:
- applicationName:
Contract: $.string().notNull()
- applicationPorts:
Contract:
- $.class(docker:ApplicationPort)
- podId:
Contract: $.string().notNull()
Body:
- $.serviceEndpoints: $.getAttr(serviceEndpoints, list())
- $currentEndpoints: $.serviceEndpoints.where($.applicationName = $applicationName and $.podId = $podId and $.scope = internal)
- $serviceName: format('{0}-{1}', randomName(), $applicationName).substring(0, 24).toLower()
- $endpointMap: {}
- For: endpoint
In: $currentEndpoints
Do:
- $serviceName: $endpoint.serviceName
- $key: format('{0}-{1}', $endpoint.containerPort, $endpoint.protocol)
- $endpointMap[$key]: $endpoint
- $serviceChanged: len(list($applicationPorts.where($.scope != host))) != len($currentEndpoints)
- $servicePorts: []
- For: applicationPort
In: $applicationPorts.where($.scope != host)
Do:
- $key: format('{0}-{1}', $applicationPort.port, $applicationPort.protocol)
- $endpoint: $endpointMap.get($key)
- If: $endpoint != null
Then:
- $record:
- assignedPort: $endpoint.port
applicationPort: $applicationPort
Else:
- $port: $._findUnusedPort($applicationPort.port, $applicationPort.protocol)
- $record:
- assignedPort: $port
applicationPort: $applicationPort
- $serviceChanged: true
- $securityGroupIngress:
- ToPort: $port
FromPort: $port
IpProtocol: $applicationPort.protocol.toLower()
External: $applicationPort.scope = public
- $._environment.securityGroupManager.addGroupIngress($securityGroupIngress)
- $servicePorts: $servicePorts + $record
- If: $serviceChanged
Then:
- $serviceIp: $._createOrUpdateService(
name => $serviceName,
ports => $servicePorts,
podId => $podId,
isNew => len($currentEndpoints) = 0
)
- $._updateEndpoints(
ports => $servicePorts,
applicationName => $applicationName,
podId => $podId,
serviceName => $serviceName,
serviceIp => $serviceIp
)
- $._environment.stack.push()
- $.setAttr(serviceEndpoints, $.serviceEndpoints)
_createOrUpdateService:
Arguments:
- name:
Contract: $.string().notNull()
- ports:
Contract:
- assignedPort: $.int().notNull()
applicationPort: $.class(docker:ApplicationPort).notNull()
- podId:
Contract: $.string().notNull()
- isNew:
Contract: $.bool().notNull()
Body:
- $serviceDefinition:
apiVersion: v1
kind: Service
metadata:
labels:
name: $name
name: $name
spec:
ports: $ports.select(dict(
port => $.assignedPort,
targetPort => $.applicationPort.port,
protocol => $.applicationPort.protocol,
name => str($.assignedPort)
))
selector:
id: $podId
- If: $.gatewayCount = 0
Then:
- $serviceDefinition.spec.publicIPs: $.minionNodes.take($.nodeCount).select($.getIp())
- $resources: new(sys:Resources)
- $template: $resources.yaml('UpdateService.template').bind(dict(
serviceDefinition => $serviceDefinition,
isNew => $isNew
))
- Return: $.masterNode.instance.agent.call($template, $resources)
_updateEndpoints:
Arguments:
- ports:
Contract:
- assignedPort: $.int().notNull()
applicationPort: $.class(docker:ApplicationPort).notNull()
- applicationName:
Contract: $.string().notNull()
- podId:
Contract: $.string().notNull()
- serviceName:
Contract: $.string().notNull()
- serviceIp:
Contract: $.string().notNull()
Body:
- $.serviceEndpoints: $.serviceEndpoints.where($.applicationName != $applicationName or $.podId != $podId)
- For: port
In: $ports
Do:
- $newEndpoint:
port: $port.assignedPort
address: $serviceIp
scope: internal
portScope: $port.applicationPort.scope
applicationName: $applicationName
containerPort: $port.applicationPort.port
protocol: $port.applicationPort.protocol
podId: $podId
serviceName: $serviceName
- $.serviceEndpoints: $.serviceEndpoints + list($newEndpoint)
- If: $port.applicationPort.scope in list(public, cloud)
Then:
- If: $.gatewayCount > 0
Then:
- $nodes: $.gatewayNodes.take($.gatewayCount)
Else:
- $nodes: $.minionNodes.take($.nodeCount)
- For: t
In: $nodes
Do:
- $newEndpoint.address: $t.getIp()
- $newEndpoint.scope: cloud
- $.serviceEndpoints: $.serviceEndpoints + list($newEndpoint)
- If: $t.instance.floatingIpAddress != null and $port.applicationPort.scope = public
Then:
- $newEndpoint.address: $t.instance.floatingIpAddress
- $newEndpoint.scope: public
- $.serviceEndpoints: $.serviceEndpoints + list($newEndpoint)
- $newEndpoint:
port: $port.applicationPort.port
address: '127.0.0.1'
scope: host
portScope: $port.applicationPort.scope
containerPort: $port.applicationPort.port
protocol: $port.applicationPort.protocol
applicationName: $applicationName
podId: $podId
serviceName: null
- $.serviceEndpoints: $.serviceEndpoints + list($newEndpoint)
_updateServicePublicIps:
Body:
- $prevNodeCount: $.getAttr(lastNodeCount, 0)
- $prevGatewayCount: $.getAttr(lastGatewayCount, 0)
- $gatewayModeChanged: $prevGatewayCount != $.gatewayCount and $prevGatewayCount * $.gatewayCount = 0
- If: $prevGatewayCount > 0 and $.gatewayCount > 0
Then:
- Return:
- If: $prevGatewayCount = 0 and $.gatewayCount = 0 and $prevNodeCount = $.nodeCount
Then:
- Return:
- $serviceNameMap: {}
- For: endpoint
In: $.serviceEndpoints
Do:
- $serviceName: $endpoint.serviceName
- If: $serviceName != null
Then:
- $serviceNameMap[$serviceName]: true
- $uniqueServiceNames: $serviceNameMap.keys()
- If: len($uniqueServiceNames) > 0
Then:
- $publicIPs: $.minionNodes.take($.nodeCount).select($.getIp())
- $resources: new(sys:Resources)
- $template: $resources.yaml('PatchServices.template').bind(dict(
services => $uniqueServiceNames,
publicIPs => $publicIPs
))
- $.masterNode.instance.agent.call($template, $resources)
deleteServices:
Arguments:
- applicationName:
Contract: $.string().notNull()
- podId:
Contract: $.string().notNull()
Body:
- $.serviceEndpoints: $.getAttr(serviceEndpoints, list())
- $resources: new(sys:Resources)
- $services: $.serviceEndpoints.where($.scope = internal and $.podId = $podId).select($.serviceName)
- $template: $resources.yaml('DeleteServices.template').bind(dict(
services => $services
))
- $.masterNode.instance.agent.call($template, $resources)
- $.serviceEndpoints: $.serviceEndpoints.where($.podId != $podId)
- $.setAttr(serviceEndpoints, $.serviceEndpoints)
_findUnusedPort:
Arguments:
- initial:
Contract: $.int().notNull()
- protocol:
Contract: $.string().notNull()
Body:
- If: $initial != 22 and $._checkIfPortIsNotUsed($initial, $protocol)
Then:
Return: $initial
- $port: 1025
- While: not $._checkIfPortIsNotUsed($port, $protocol)
Do:
$port: $port + 1
- Return: $port
_checkIfPortIsNotUsed:
Arguments:
- port:
Contract: $.int().notNull()
- protocol:
Contract: $.string().notNull()
Body:
- Return: len(list($.serviceEndpoints.where($.port = $port).where($.protocol = $protocol))) = 0
scaleNodesUp:
Usage: Action
Body:
- If: $.nodeCount < len($.minionNodes)
Then:
- $._environment.reporter.report($this, 'Scaling up Kubernetes cluster')
- $.nodeCount: $.nodeCount + 1
- $.deploy()
Else:
- $._environment.reporter.report($this, 'The maximum number of nodes has been reached')
scaleNodesDown:
Usage: Action
Body:
- If: $.nodeCount > 1
Then:
- $._environment.reporter.report($this, 'Scaling Kubernetes cluster down')
- $.nodeCount: $.nodeCount - 1
- $.deploy()
Else:
- $._environment.reporter.report($this, 'At least one node must be in cluster')
scaleGatewaysUp:
Usage: Action
Body:
- If: $.gatewayCount < len($.gatewayNodes)
Then:
- $._environment.reporter.report($this, 'Adding new gateway node')
- $.gatewayCount: $.gatewayCount + 1
- $.deploy()
Else:
- $._environment.reporter.report($this, 'The maximum number of nodes has been reached')
scaleGatewaysDown:
Usage: Action
Body:
- If: $.gatewayCount > 1
Then:
- $._environment.reporter.report($this, 'Removing gateway node')
- $.gatewayCount: $.gatewayCount - 1
- $.deploy()
Else:
- $._environment.reporter.report($this, 'No gateway nodes that can be removed')
scaleRc:
Arguments:
- rcName:
Contract: $.string().notNull()
- newSize:
Contract: $.int().notNull()
Body:
- $resources: new(sys:Resources)
- $template: $resources.yaml('ScaleRc.template').bind(dict(
rcName => $rcName,
newSize => $newSize
))
- $.masterNode.instance.agent.call($template, $resources)
restartContainers:
Arguments:
- podName:
Contract: $.string().notNull()
Body:
- $.minionNodes.take($.nodeCount).pselect($.restartContainers(podName => $podName))