Skip to content
This repository was archived by the owner on May 6, 2020. It is now read-only.

Commit 726a587

Browse files
krisnovamboersma
authored andcommitted
feat(ingress): Feature work for experimental native ingress
Adding ingress support to controller Adding changes to chart to support feature Adding ingress rules for controller API, and SSH on TCP 2222 Adding ingress support in general Requires deis/workflow#732 Requires deis/builder#495 Requires deis/router#316 Technically a non breaking change, as the user must opt-in to the feature
1 parent 70e99f4 commit 726a587

File tree

6 files changed

+119
-1
lines changed

6 files changed

+119
-1
lines changed

charts/controller/templates/controller-deployment.yaml

+5
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,11 @@ spec:
5858
# NOTE(bacongobbler): use deis/registry_proxy to work around Docker --insecure-registry requirements
5959
- name: "DEIS_REGISTRY_SERVICE_HOST"
6060
value: "127.0.0.1"
61+
# Environmental variable value for $EXPERIMENTAL_NATIVE_INGRESS
62+
- name: "EXPERIMENTAL_NATIVE_INGRESS"
63+
value: "{{ .Values.global.experimental_native_ingress }}"
64+
- name: "EXPERIMENTAL_NATIVE_INGRESS_HOSTNAME"
65+
value: "{{ .Values.platform_domain }}"
6166
- name: "K8S_API_VERIFY_TLS"
6267
value: "{{ .Values.k8s_api_verify_tls }}"
6368
- name: "DEIS_REGISTRY_SERVICE_PORT"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{{ if .Values.global.experimental_native_ingress }}
2+
apiVersion: extensions/v1beta1
3+
kind: Ingress
4+
metadata:
5+
namespace: "deis"
6+
name: "controller-api-server-ingress-http"
7+
labels:
8+
app: "controller"
9+
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
10+
release: "{{ .Release.Name }}"
11+
heritage: "{{ .Release.Service }}"
12+
spec:
13+
rules:
14+
- host: deis.{{ .Values.platform_domain }}
15+
http:
16+
paths:
17+
- path: /
18+
backend:
19+
serviceName: deis-controller
20+
servicePort: 80
21+
{{- end }}

charts/controller/values.yaml

+10
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ deploy_hook_urls: ""
1414
registration_mode: "admin_only"
1515
# Option to disable ssl verification to connect to k8s api server
1616
k8s_api_verify_tls: "true"
17+
# The public resolvable hostname to build your cluster with.
18+
#
19+
# This will be the hostname that is used to build endpoints such as "deis.$HOSTNAME"
20+
platform_domain: ""
1721

1822
global:
1923
# Set the storage backend
@@ -45,3 +49,9 @@ global:
4549
host_port: 5555
4650
# Prefix for the imagepull secret created when using private registry
4751
secret_prefix: "private-registry"
52+
# Experimental feature to toggle using kubernetes ingress instead of the Deis router.
53+
#
54+
# Valid values are:
55+
# - true: The deis controller will now create Kubernetes ingress rules for each app, and ingress rules will automatically be created for the controller itself.
56+
# - false: The default mode, and the default behavior of Deis workflow.
57+
experimental_native_ingress: false

rootfs/api/models/app.py

+13-1
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ def create(self, *args, **kwargs): # noqa
191191

192192
# create required minimum resources in k8s for the application
193193
namespace = self.id
194+
ingress = self.id
194195
service = self.id
195196
quota_name = '{}-quota'.format(self.id)
196197
try:
@@ -200,7 +201,6 @@ def create(self, *args, **kwargs): # noqa
200201
self._scheduler.ns.get(namespace)
201202
except KubeException:
202203
self._scheduler.ns.create(namespace)
203-
204204
if settings.KUBERNETES_NAMESPACE_DEFAULT_QUOTA_SPEC != '':
205205
quota_spec = json.loads(settings.KUBERNETES_NAMESPACE_DEFAULT_QUOTA_SPEC)
206206
self.log('creating Quota {} for namespace {}'.format(quota_name, namespace),
@@ -224,6 +224,18 @@ def create(self, *args, **kwargs): # noqa
224224

225225
raise ServiceUnavailable('Kubernetes resources could not be created') from e
226226

227+
try:
228+
# In order to create an ingress, we must first have a namespace.
229+
if settings.EXPERIMENTAL_NATIVE_INGRESS:
230+
try:
231+
self._scheduler.ingress.get(ingress)
232+
except KubeException:
233+
self.log("creating Ingress {}".format(namespace), level=logging.INFO)
234+
self._scheduler.ingress.create(ingress,
235+
namespace,
236+
settings.EXPERIMENTAL_NATIVE_INGRESS_HOSTNAME)
237+
except KubeException as e:
238+
raise ServiceUnavailable('Could not create Ingress in Kubernetes') from e
227239
try:
228240
self.appsettings_set.latest()
229241
except AppSettings.DoesNotExist:

rootfs/api/settings/production.py

+4
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,10 @@
260260
SECRET_KEY = os.environ.get('DEIS_SECRET_KEY', random_secret)
261261
BUILDER_KEY = os.environ.get('DEIS_BUILDER_KEY', random_secret)
262262

263+
# experimental native ingress
264+
EXPERIMENTAL_NATIVE_INGRESS = bool(os.environ.get('EXPERIMENTAL_NATIVE_INGRESS', 0))
265+
EXPERIMENTAL_NATIVE_INGRESS_HOSTNAME = os.environ.get('EXPERIMENTAL_NATIVE_INGRESS_HOSTNAME', '')
266+
263267
# k8s image policies
264268
SLUGRUNNER_IMAGE = os.environ.get('SLUGRUNNER_IMAGE_NAME', 'quay.io/deisci/slugrunner:canary') # noqa
265269
IMAGE_PULL_POLICY = os.environ.get('IMAGE_PULL_POLICY', "IfNotPresent") # noqa

rootfs/scheduler/resources/ingress.py

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
from scheduler.exceptions import KubeHTTPException
2+
from scheduler.resources import Resource
3+
4+
5+
class Ingress(Resource):
6+
short_name = 'ingress'
7+
8+
def get(self, name=None, **kwargs):
9+
"""
10+
Fetch a single Ingress or a list of Ingresses
11+
"""
12+
if name is not None:
13+
url = "/apis/extensions/v1beta1/namespaces/%s/ingresses/%s" % (name, name)
14+
message = 'get Ingress ' + name
15+
else:
16+
url = "/apis/extensions/v1beta1/namespaces/%s/ingresses" % name
17+
message = 'get Ingresses'
18+
19+
response = self.http_get(url, params=self.query_params(**kwargs))
20+
if self.unhealthy(response.status_code):
21+
raise KubeHTTPException(response, message)
22+
23+
return response
24+
25+
def create(self, ingress, namespace, hostname):
26+
url = "/apis/extensions/v1beta1/namespaces/%s/ingresses" % namespace
27+
28+
if hostname == "":
29+
raise KubeHTTPException("empty hostname value")
30+
31+
data = {
32+
"kind": "Ingress",
33+
"apiVersion": "extensions/v1beta1",
34+
"metadata": {
35+
"name": ingress
36+
},
37+
"spec": {
38+
"rules": [
39+
{"host": ingress + "." + hostname,
40+
"http": {
41+
"paths": [
42+
{"path": "/",
43+
"backend": {
44+
"serviceName": ingress,
45+
"servicePort": 80
46+
}}
47+
]
48+
}
49+
}
50+
]
51+
}
52+
}
53+
response = self.http_post(url, json=data)
54+
55+
if not response.status_code == 201:
56+
raise KubeHTTPException(response, "create Ingress {}".format(namespace))
57+
58+
return response
59+
60+
def delete(self, namespace, ingress):
61+
url = self.api("/namespaces/{}/ingresses/{}", namespace, ingress)
62+
response = self.http_delete(url)
63+
if self.unhealthy(response.status_code):
64+
raise KubeHTTPException(response, 'delete Ingress "{}"', namespace)
65+
66+
return response

0 commit comments

Comments
 (0)