Skip to content
This repository was archived by the owner on Dec 9, 2024. It is now read-only.

Commit e704f53

Browse files
authored
Merge pull request #67 from andresmgot/singleIngress
Use just one Ingress Rule for service
2 parents b9e7ea9 + 001eb94 commit e704f53

File tree

15 files changed

+300
-212
lines changed

15 files changed

+300
-212
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ $ serverless deploy
5454
Serverless: Packaging service...
5555
Serverless: Excluding development dependencies...
5656
Serverless: Deploying function hello...
57-
Serverless: Function hello succesfully deployed
57+
Serverless: Function hello successfully deployed
5858
```
5959

6060
The function will be deployed to k8s via kubeless.
@@ -120,12 +120,12 @@ If you have a change in your function and you want to redeploy it you can run:
120120
```bash
121121
$ serverless deploy function -f hello
122122
Serverless: Redeploying hello...
123-
Serverless: Function hello succesfully deployed
123+
Serverless: Function hello successfully deployed
124124
```
125125

126126
Finally you can remove the function.
127127
```bash
128128
$ serverless remove
129129
Serverless: Removing function: hello...
130-
Serverless: Function hello succesfully deleted
130+
Serverless: Function hello successfully deleted
131131
```

examples/http-custom-path/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ Serverless: Packaging service...
1919
Serverless: Deploying function hello...
2020
Serverless: Deployed Ingress rule to map /hello
2121
Serverless: Waiting for function hello to be fully deployed. Pods status: {"waiting":{"reason":"PodInitializing"}}
22-
Serverless: Function hello succesfully deployed
22+
Serverless: Function hello successfully deployed
2323
```
2424

2525
As we can see in the logs an Ingress Rule has been deployed to run our function at `/hello`. If no host is specified, by default it will use `API_URL.nip.io` being `API_URL` the URL/IP of the Kubernetes IP. We can know the specific URL in which the function will be listening executing `serverless info`:
@@ -47,7 +47,7 @@ $ curl 192.168.99.100.nip.io/hello
4747
hello world
4848
```
4949

50-
## GCE and Firewall limitation
50+
## GKE and Firewall limitation
5151

5252
For some providers like Google you may need to add a firewall rule for allowing the traffic for the port 80 and 443 so you can connect to the IP the ingress controller provides.
5353

examples/multi-python/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ functions:
1515
$ npm install
1616
$ serverless deploy
1717
Serverless: Packaging service...
18-
Serverless: Function foo succesfully deployed
19-
Serverless: Function bar succesfully deployed
18+
Serverless: Function foo successfully deployed
19+
Serverless: Function bar successfully deployed
2020
```
2121

2222
You can invoke each function

examples/todo-app/backend/README.md

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,39 @@ Serverless: Deploying function update...
2121
Serverless: Deploying function read-one...
2222
Serverless: Deploying function create...
2323
Serverless: Deploying function read-all...
24-
Serverless: Function delete succesfully deployed
25-
Serverless: Function read-all succesfully deployed
26-
Serverless: Function update succesfully deployed
27-
Serverless: Function create succesfully deployed
28-
Serverless: Function read-one succesfully deployed
29-
```
24+
Serverless: Function delete successfully deployed
25+
Serverless: Function read-all successfully deployed
26+
Serverless: Function update successfully deployed
27+
Serverless: Function create successfully deployed
28+
Serverless: Function read-one successfully deployed
29+
```
30+
31+
# Running the Backend in GKE
32+
33+
In case your cluster is running on GCE you need to perform an additional step. If you check the Ingress rules that has been created:
34+
```
35+
$ kubectl get ingress
36+
NAME HOSTS ADDRESS PORTS AGE
37+
ingress-1505835652059 35.185.47.240.nip.io 35.196.212.24 80 18s
38+
```
39+
40+
There are two different possibilities, using `35.185.47.240.nip.io` or `35.196.212.24`. We will use the IP address (`35.196.212.24`) since it is accessible through HTTP. The hostname points to the Kubernetes API and it is only accessible through HTTPS and using the cluster certificate so it is not suitable for our application.
41+
42+
In any case we need to go to the [google console](https://console.cloud.google.com/) to enable HTTP traffic for the IP that we want to use.
43+
44+
On the left menu go to: `NETWORKING` -> `VPC Network` -> `Firewall rules` and select the Firewall rule that applies to all the Targets:
45+
<img src="./img/gce_firewall_rules.png" width="700">
46+
47+
Then click on EDIT and modify the `Source IP ranges` to make it accessible from outside of the cluster and click on `Save`:
48+
49+
<img src="./img/gce_firewall_rule_edit.png" width="700">
50+
51+
| Note: This will make the cluster accessible from anywhere to any port. You can create a more specific rule to only allow TCP traffic to the port 80
52+
53+
You should now be able to access the functions:
54+
```console
55+
$ curl 35.196.212.24/read-all
56+
[]
57+
```
58+
59+
This IP is the one that should be used as `API_URL` in the frontend.
177 KB
Loading
192 KB
Loading

lib/deploy.js

Lines changed: 27 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ const _ = require('lodash');
2020
const BbPromise = require('bluebird');
2121
const Api = require('kubernetes-client');
2222
const helpers = require('./helpers');
23+
const ingressHelper = require('./ingress');
2324
const moment = require('moment');
24-
const url = require('url');
2525

2626
function getFunctionDescription(
2727
funcName,
@@ -100,31 +100,6 @@ function getFunctionDescription(
100100
return funcs;
101101
}
102102

103-
function getIngressDescription(funcName, funcPath, funcHost) {
104-
return {
105-
kind: 'Ingress',
106-
metadata: {
107-
name: `ingress-${funcName}`,
108-
labels: { function: funcName },
109-
annotations: {
110-
'kubernetes.io/ingress.class': 'nginx',
111-
'ingress.kubernetes.io/rewrite-target': '/',
112-
},
113-
},
114-
spec: {
115-
rules: [{
116-
host: funcHost,
117-
http: {
118-
paths: [{
119-
path: funcPath,
120-
backend: { serviceName: funcName, servicePort: 8080 },
121-
}],
122-
},
123-
}],
124-
},
125-
};
126-
}
127-
128103
function waitForDeployment(funcName, requestMoment, namespace, options) {
129104
const opts = _.defaults({}, options, {
130105
verbose: false,
@@ -184,7 +159,7 @@ function waitForDeployment(funcName, requestMoment, namespace, options) {
184159
// so we should ensure that they are stable
185160
successfulCount++;
186161
if (successfulCount === 2) {
187-
opts.log(`Function ${funcName} succesfully deployed`);
162+
opts.log(`Function ${funcName} successfully deployed`);
188163
clearInterval(loop);
189164
resolve();
190165
}
@@ -272,57 +247,6 @@ function redeployFunctionAndWait(body, thirdPartyResources, options) {
272247
});
273248
}
274249

275-
function addIngressRuleIfNecessary(
276-
funcName,
277-
eventType,
278-
eventPath,
279-
eventHostname,
280-
namespace,
281-
options
282-
) {
283-
const opts = _.defaults({}, options, {
284-
verbose: false,
285-
log: console.log,
286-
});
287-
const config = helpers.loadKubeConfig();
288-
const extensions = new Api.Extensions(helpers.getConnectionOptions(
289-
config, { namespace })
290-
);
291-
const fpath = eventPath || '/';
292-
const hostname = eventHostname ||
293-
`${url.parse(helpers.getKubernetesAPIURL(config)).hostname}.nip.io`;
294-
return new BbPromise((resolve, reject) => {
295-
if (
296-
eventType === 'http' &&
297-
((!_.isEmpty(eventPath) && eventPath !== '/') || !_.isEmpty(eventHostname))
298-
) {
299-
// Found a path to deploy the function
300-
const absolutePath = _.startsWith(fpath, '/') ?
301-
fpath :
302-
`/${fpath}`;
303-
const ingressDef = getIngressDescription(funcName, absolutePath, hostname);
304-
extensions.ns.ingress.post({ body: ingressDef }, (err) => {
305-
if (err) {
306-
reject(
307-
`Unable to deploy the function ${funcName} in the given path. ` +
308-
`Received: ${err.message}`
309-
);
310-
} else {
311-
if (opts.verbose) {
312-
opts.log(`Deployed Ingress rule to map ${absolutePath}`);
313-
}
314-
resolve();
315-
}
316-
});
317-
} else {
318-
if (opts.verbose) {
319-
opts.log('Skipping ingress rule generation');
320-
}
321-
resolve();
322-
}
323-
});
324-
}
325-
326250
function deploy(functions, runtime, options) {
327251
const opts = _.defaults({}, options, {
328252
hostname: null,
@@ -345,8 +269,8 @@ function deploy(functions, runtime, options) {
345269
const thirdPartyResources = new Api.ThirdPartyResources(connectionOptions);
346270
thirdPartyResources.addResource('functions');
347271
const events = !_.isEmpty(description.events) ?
348-
description.events :
349-
[{ type: 'http', path: '/' }];
272+
description.events :
273+
[{ type: 'http', path: '/' }];
350274
_.each(events, event => {
351275
const funcs = getFunctionDescription(
352276
description.id,
@@ -400,38 +324,34 @@ function deploy(functions, runtime, options) {
400324
errors.push(deploymentErr);
401325
})
402326
.then((deployed) => {
403-
let p = null;
404-
if (!deployed || redeployed) {
405-
// If there were an error with the deployment
406-
// or the function is already deployed
407-
// don't try to add an ingress rule
408-
p = new BbPromise((r) => r());
409-
} else {
410-
p = addIngressRuleIfNecessary(
411-
description.id,
412-
event.type,
413-
event.path,
414-
event.hostname || opts.hostname,
415-
connectionOptions.namespace,
416-
{ verbose: opts.verbose, log: opts.log }
417-
);
418-
p.catch(ingressErr => {
419-
errors.push(ingressErr);
420-
});
421-
}
422-
p.then(() => {
423-
counter++;
424-
if (counter === _.keys(functions).length) {
425-
if (_.isEmpty(errors)) {
426-
resolve();
327+
counter++;
328+
if (counter === _.keys(functions).length) {
329+
if (_.isEmpty(errors)) {
330+
let p = null;
331+
if (!deployed || redeployed) {
332+
// If there were an error with the deployment
333+
// or the function is already deployed
334+
// don't try to add an ingress rule
335+
p = new BbPromise((r) => r());
427336
} else {
428-
reject(new Error(
337+
p = ingressHelper.addIngressRuleIfNecessary(functions, {
338+
verbose: opts.verbose,
339+
log: opts.log,
340+
hostname: opts.hostname,
341+
namespace: connectionOptions.namespace,
342+
});
343+
p.catch(ingressErr => {
344+
errors.push(ingressErr);
345+
});
346+
}
347+
p.then(resolve);
348+
} else {
349+
reject(new Error(
429350
'Found errors while deploying the given functions:\n' +
430351
`${errors.join('\n')}`
431352
));
432-
}
433353
}
434-
});
354+
}
435355
});
436356
});
437357
});

lib/get-info.js

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ const _ = require('lodash');
2020
const Api = require('kubernetes-client');
2121
const BbPromise = require('bluebird');
2222
const chalk = require('chalk');
23-
const helpers = require('../lib/helpers');
23+
const helpers = require('./helpers');
24+
const ingressHelper = require('./ingress');
2425

2526
function toMultipleWords(word) {
2627
return word.replace(/([A-Z])/, ' $1').replace(/^./, (l) => l.toUpperCase());
@@ -118,12 +119,16 @@ function info(functions, options) {
118119
opts.log(`Not found any information about the function "${f}"`);
119120
} else {
120121
const fIngress = _.find(ingressInfo.items, item => (
121-
item.metadata.labels && item.metadata.labels.function === f
122+
item.metadata.labels &&
123+
_.isEqual(item.metadata.labels, ingressHelper.getIngressRuleLabels(functions))
122124
));
123125
let url = null;
124126
if (fIngress) {
125-
url = `${fIngress.spec.rules[0].host || 'API_URL'}` +
126-
`${fIngress.spec.rules[0].http.paths[0].path}`;
127+
const rule = _.find(fIngress.spec.rules,
128+
r => _.some(r.http.paths, p => p.backend.serviceName === f)
129+
);
130+
const path = _.find(rule.http.paths, p => p.backend.serviceName === f).path;
131+
url = `${rule.host || 'API_URL'}${path}`;
127132
}
128133
const service = {
129134
name: functionService.metadata.name,

0 commit comments

Comments
 (0)