diff --git a/doc/source/user/index.rst b/doc/source/user/index.rst index 478043bde8..2f28375700 100644 --- a/doc/source/user/index.rst +++ b/doc/source/user/index.rst @@ -357,6 +357,10 @@ the table are linked to more details elsewhere in the user guide. +---------------------------------------+--------------------+---------------+ | `cert_manager_api`_ | see below | false | +---------------------------------------+--------------------+---------------+ +| `ingress_controller`_ | see below | "" | ++---------------------------------------+--------------------+---------------+ +| `ingress_controller_role`_ | see below | "ingress" | ++---------------------------------------+--------------------+---------------+ Cluster ------- @@ -1164,6 +1168,29 @@ service is deleted. Refer to the `Kubernetes External Load Balancer`_ section for more details. +Ingress Controller +------------------ + +In addition to the LoadBalancer described above, Kubernetes can also +be configured with an Ingress Controller. Ingress can provide load +balancing, SSL termination and name-based virtual hosting. + +Magnum allows selecting one of multiple controller options via the +'ingress_controller' label. Check the Kubernetes documentation to define +your own Ingress resources. + +_`ingress_controller` + This label sets the Ingress Controller to be used. Currently only traefik + is supported. The default is '', meaning no Ingress Controller configured. + +_`ingress_controller_role` + This label defines the role nodes should have to run an instance of the + Ingress Controller. This gives operators full control on which nodes should + be running an instance of the controller, and should be set in multiple nodes + for availability. Default is 'ingress'. An example of setting this in a + Kubernetes node would be:: + + kubectl label node role=ingress Swarm ===== diff --git a/magnum/drivers/common/templates/kubernetes/fragments/enable-ingress-controller b/magnum/drivers/common/templates/kubernetes/fragments/enable-ingress-controller new file mode 100644 index 0000000000..52b8cf88b8 --- /dev/null +++ b/magnum/drivers/common/templates/kubernetes/fragments/enable-ingress-controller @@ -0,0 +1,23 @@ +#!/bin/bash + +# Enables the specified ingress controller. +# +# Currently there is only support for traefik. +. /etc/sysconfig/heat-params + +function writeFile { + # $1 is filename + # $2 is file content + + [ -f ${1} ] || { + echo "Writing File: $1" + mkdir -p $(dirname ${1}) + cat << EOF > ${1} +$2 +EOF + } +} + +if [ "$(echo $INGRESS_CONTROLLER | tr '[:upper:]' '[:lower:]')" = "traefik" ]; then + $enable-ingress-traefik +fi diff --git a/magnum/drivers/common/templates/kubernetes/fragments/enable-ingress-traefik b/magnum/drivers/common/templates/kubernetes/fragments/enable-ingress-traefik new file mode 100644 index 0000000000..675092152c --- /dev/null +++ b/magnum/drivers/common/templates/kubernetes/fragments/enable-ingress-traefik @@ -0,0 +1,147 @@ +INGRESS_TRAEFIK_MANIFEST=/srv/magnum/kubernetes/ingress-traefik.yaml +INGRESS_TRAEFIK_MANIFEST_CONTENT=$(cat < + ingress controller backend to use + default: "" + + ingress_controller_role: + type: string + description: > + node role where the ingress controller backend should run + default: "ingress" + resources: ###################################################################### @@ -617,6 +629,8 @@ resources: calico_kube_controllers_tag: {get_param: calico_kube_controllers_tag} calico_ipv4pool: {get_param: calico_ipv4pool} pods_network_cidr: {get_param: pods_network_cidr} + ingress_controller: {get_param: ingress_controller} + ingress_controller_role: {get_param: ingress_controller_role} ###################################################################### # diff --git a/magnum/drivers/k8s_fedora_atomic_v1/templates/kubemaster.yaml b/magnum/drivers/k8s_fedora_atomic_v1/templates/kubemaster.yaml index 7068eaf168..97b026b0a6 100644 --- a/magnum/drivers/k8s_fedora_atomic_v1/templates/kubemaster.yaml +++ b/magnum/drivers/k8s_fedora_atomic_v1/templates/kubemaster.yaml @@ -307,6 +307,16 @@ parameters: type: string description: Configure the IP pool/range from which pod IPs will be chosen + ingress_controller: + type: string + description: > + ingress controller backend to use + + ingress_controller_role: + type: string + description: > + node role where the ingress controller should run + resources: master_wait_handle: @@ -401,6 +411,8 @@ resources: "$CALICO_CNI_TAG": {get_param: calico_cni_tag} "$CALICO_KUBE_CONTROLLERS_TAG": {get_param: calico_kube_controllers_tag} "$CALICO_IPV4POOL": {get_param: calico_ipv4pool} + "$INGRESS_CONTROLLER": {get_param: ingress_controller} + "$INGRESS_CONTROLLER_ROLE": {get_param: ingress_controller_role} install_openstack_ca: type: OS::Heat::SoftwareConfig @@ -578,6 +590,24 @@ resources: server: {get_resource: kube-master} actions: ['CREATE'] + enable_ingress_controller: + type: OS::Heat::SoftwareConfig + properties: + group: script + config: + str_replace: + params: + $enable-ingress-traefik: {get_file: ../../common/templates/kubernetes/fragments/enable-ingress-traefik} + template: {get_file: ../../common/templates/kubernetes/fragments/enable-ingress-controller} + + enable_ingress_controller_deployment: + type: OS::Heat::SoftwareDeployment + properties: + signal_transport: HEAT_SIGNAL + config: {get_resource: enable_ingress_controller} + server: {get_resource: kube-master} + actions: ['CREATE'] + ###################################################################### # # a single kubernetes master. diff --git a/magnum/tests/unit/conductor/handlers/test_k8s_cluster_conductor.py b/magnum/tests/unit/conductor/handlers/test_k8s_cluster_conductor.py index 10ff10d6f6..126bc65225 100644 --- a/magnum/tests/unit/conductor/handlers/test_k8s_cluster_conductor.py +++ b/magnum/tests/unit/conductor/handlers/test_k8s_cluster_conductor.py @@ -98,7 +98,9 @@ class TestClusterConductorWithK8s(base.TestCase): 'kube_dashboard_enabled': 'True', 'docker_volume_type': 'lvmdriver-1', 'availability_zone': 'az_1', - 'cert_manager_api': 'False'}, + 'cert_manager_api': 'False', + 'ingress_controller': 'i-controller', + 'ingress_controller_role': 'i-controller-role'}, 'master_flavor_id': 'master_flavor_id', 'flavor_id': 'flavor_id', } @@ -179,7 +181,9 @@ class TestClusterConductorWithK8s(base.TestCase): 'docker_volume_type': 'lvmdriver-1', 'etcd_volume_size': None, 'availability_zone': 'az_1', - 'cert_manager_api': 'False'}, + 'cert_manager_api': 'False', + 'ingress_controller': 'i-controller', + 'ingress_controller_role': 'i-controller-role'}, 'http_proxy': 'http_proxy', 'https_proxy': 'https_proxy', 'no_proxy': 'no_proxy', @@ -237,6 +241,8 @@ class TestClusterConductorWithK8s(base.TestCase): "nodes_affinity_policy": "soft-anti-affinity", 'availability_zone': 'az_1', 'cert_manager_api': 'False', + 'ingress_controller': 'i-controller', + 'ingress_controller_role': 'i-controller-role', } if missing_attr is not None: expected.pop(mapping[missing_attr], None) @@ -336,6 +342,8 @@ class TestClusterConductorWithK8s(base.TestCase): "nodes_affinity_policy": "soft-anti-affinity", 'availability_zone': 'az_1', 'cert_manager_api': 'False', + 'ingress_controller': 'i-controller', + 'ingress_controller_role': 'i-controller-role', } self.assertEqual(expected, definition) @@ -422,6 +430,8 @@ class TestClusterConductorWithK8s(base.TestCase): "nodes_affinity_policy": "soft-anti-affinity", 'availability_zone': 'az_1', 'cert_manager_api': 'False', + 'ingress_controller': 'i-controller', + 'ingress_controller_role': 'i-controller-role', } self.assertEqual(expected, definition) self.assertEqual( @@ -501,6 +511,8 @@ class TestClusterConductorWithK8s(base.TestCase): 'verify_ca': True, 'openstack_ca': '', 'cert_manager_api': 'False', + 'ingress_controller': 'i-controller', + 'ingress_controller_role': 'i-controller-role', } self.assertEqual(expected, definition) self.assertEqual( @@ -575,6 +587,8 @@ class TestClusterConductorWithK8s(base.TestCase): 'verify_ca': True, 'openstack_ca': '', 'cert_manager_api': 'False', + 'ingress_controller': 'i-controller', + 'ingress_controller_role': 'i-controller-role', } self.assertEqual(expected, definition) self.assertEqual( @@ -750,6 +764,8 @@ class TestClusterConductorWithK8s(base.TestCase): "nodes_affinity_policy": "soft-anti-affinity", 'availability_zone': 'az_1', 'cert_manager_api': 'False', + 'ingress_controller': 'i-controller', + 'ingress_controller_role': 'i-controller-role', } self.assertEqual(expected, definition) self.assertEqual( diff --git a/magnum/tests/unit/drivers/test_template_definition.py b/magnum/tests/unit/drivers/test_template_definition.py index 8ee5fb0060..a92d03b9ed 100644 --- a/magnum/tests/unit/drivers/test_template_definition.py +++ b/magnum/tests/unit/drivers/test_template_definition.py @@ -290,6 +290,10 @@ class AtomicK8sTemplateDefinitionTestCase(BaseTemplateDefinitionTestCase): pods_network_cidr = flannel_cidr elif mock_cluster_template.network_driver == 'calico': pods_network_cidr = calico_ipv4pool + ingress_controller = mock_cluster.labels.get( + 'ingress_controller') + ingress_controller_role = mock_cluster.labels.get( + 'ingress_controller_role') k8s_def = k8sa_tdef.AtomicK8sTemplateDefinition() @@ -324,8 +328,9 @@ class AtomicK8sTemplateDefinitionTestCase(BaseTemplateDefinitionTestCase): 'calico_cni_tag': calico_cni_tag, 'calico_kube_controllers_tag': calico_kube_controllers_tag, 'calico_ipv4pool': calico_ipv4pool, - 'pods_network_cidr': pods_network_cidr - }} + 'pods_network_cidr': pods_network_cidr, + 'ingress_controller': ingress_controller, + 'ingress_controller_role': ingress_controller_role}} mock_get_params.assert_called_once_with(mock_context, mock_cluster_template, mock_cluster, @@ -402,6 +407,10 @@ class AtomicK8sTemplateDefinitionTestCase(BaseTemplateDefinitionTestCase): pods_network_cidr = flannel_cidr elif mock_cluster_template.network_driver == 'calico': pods_network_cidr = calico_ipv4pool + ingress_controller = mock_cluster.labels.get( + 'ingress_controller') + ingress_controller_role = mock_cluster.labels.get( + 'ingress_controller_role') k8s_def = k8sa_tdef.AtomicK8sTemplateDefinition() @@ -438,8 +447,9 @@ class AtomicK8sTemplateDefinitionTestCase(BaseTemplateDefinitionTestCase): 'calico_cni_tag': calico_cni_tag, 'calico_kube_controllers_tag': calico_kube_controllers_tag, 'calico_ipv4pool': calico_ipv4pool, - 'pods_network_cidr': pods_network_cidr - }} + 'pods_network_cidr': pods_network_cidr, + 'ingress_controller': ingress_controller, + 'ingress_controller_role': ingress_controller_role}} mock_get_params.assert_called_once_with(mock_context, mock_cluster_template, mock_cluster, diff --git a/releasenotes/notes/ingress-controller-552ea956ceabdd25.yaml b/releasenotes/notes/ingress-controller-552ea956ceabdd25.yaml new file mode 100644 index 0000000000..72ef0bc4b4 --- /dev/null +++ b/releasenotes/notes/ingress-controller-552ea956ceabdd25.yaml @@ -0,0 +1,8 @@ +--- +features: + - | + Add new labels 'ingress_controller' and 'ingress_controller_role' enabling + the deployment of a Kubernetes Ingress Controller backend for clusters. + Default for 'ingress_controller' is '' (meaning no controller deployed), + with possible values being 'traefik'. + Default for 'ingress_controller_role' is 'ingress'.