Skip to content

Commit

Permalink
docs(examples): add Ambassador example
Browse files Browse the repository at this point in the history
  • Loading branch information
eysi09 committed Mar 1, 2019
1 parent 1b6548f commit 7fd2a18
Show file tree
Hide file tree
Showing 15 changed files with 330 additions and 0 deletions.
113 changes: 113 additions & 0 deletions examples/ambassador/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# Ambassador example project

This example project demonstrates how to use the [Ambassador API Gateway](https://www.getambassador.io/) instead of the default Nginx ingress controller. Ambassador is an open source, Kubernetes-Native, API Gateway built on the [Envoy Proxy](https://www.envoyproxy.io/). Services are configured via [annotations](https://docs.garden.io/reference/module-types/container#module-services-annotations) which Ambassador reads to configure its Envoy Proxy.

Even though we chose Ambassador for this project, the same principles apply to e.g. [Traefik](https://traefik.io/), which also supports configuring route mappings via service annotations.

The project is based on our [simple-project example](https://github.com/garden-io/garden/tree/v0.9.0-docfix.2/examples/simple-project) and installs Ambassador via the [Helm module type](https://docs.garden.io/reference/module-types/helm). To learn more about using Helm charts with Garden, take a look at our [Helm user guide](https://docs.garden.io/using-garden/using-helm-charts).

## Usage

This project doesn't require any specific set up and can be deployed in a single step with the `deploy` command:

```sh
garden deploy
```

Since we're letting Ambassador handle our ingresses, we don't define any in our `garden.yml` config files. Therefore, the `call` command won't work with this set up. Instead, we can use `curl` to check on our services.

To find the external IP for the Ambassador service, run:

```sh
kubectl get svc ambassador --namespace=custom-ingress-controller
```

It should return something like:

```sh
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ambassador LoadBalancer 10.102.14.233 localhost 8080:30634/TCP,443:30614/TCP 120m
```

Now we can call our services with:


```sh
curl localhost:8080/node-service/hello-node
```

which should return

```sh
Hello from Node service!
```

## Notes on configuration

### Project configuration

If you've looked at our other examples, the project configuration should look familiar with the exception of the `setupIngressController` key:

```yaml
project:
name: custom-ingress-controller
environments:
- name: local
providers:
- name: local-kubernetes
setupIngressController: false
```
The `setupIngressController` key is specific to the `local-kubernetes` plugin. Setting it to `false` disables the default Nginx ingress controller.

### Ambassador configuration

We've configured the Ambassador service to listen on port `8080` since the default Nginx ingress controller might occupy the default port (`80`) if we're running other Garden projects. Here's the relevant configuration from `ambassador/garden.yml`:

```yaml
module:
description: Ambassador API Gateway
type: helm
name: ambassador
chart: stable/ambassador
values:
service:
annotations:
getambassador.io/config: |
---
apiVersion: ambassador/v1
kind: Module
name: ambassador
config:
service_port: 8080 # Set port since the default ingress already occupies the default port
http:
port: 8080 # Set port since the default ingress already occupies the default port
```

### Module configuration

The module configuration is the same as for the `simple-project` example with the exception of annotations. Below is the configuration for our `go-service`:

```yaml
module:
name: go-service
description: Go service container
type: container
services:
- name: go-service
ports:
- name: http
containerPort: 8080
# Maps service:80 -> container:8080
servicePort: 80
annotations:
getambassador.io/config: |
---
apiVersion: ambassador/v1
kind: Mapping
name: go-service_mapping
prefix: /go-service/
service: go-service:80
```

Please refer to the [official Ambassador docs](https://www.getambassador.io/reference/mappings/) for more information on how to configure route mappings.
17 changes: 17 additions & 0 deletions examples/ambassador/ambassador/garden.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
module:
description: Ambassador API Gateway
type: helm
name: ambassador
chart: stable/ambassador
values:
service:
annotations:
getambassador.io/config: |
---
apiVersion: ambassador/v1
kind: Module
name: ambassador
config:
service_port: 8080 # Set port since the default ingress already occupies the default port
http:
port: 8080 # Set port since the default ingress already occupies the default port
7 changes: 7 additions & 0 deletions examples/ambassador/garden.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
project:
name: ambassador
environments:
- name: local
providers:
- name: local-kubernetes
setupIngressController: false
4 changes: 4 additions & 0 deletions examples/ambassador/go-service/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
node_modules
Dockerfile
garden.yml
app.yaml
27 changes: 27 additions & 0 deletions examples/ambassador/go-service/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so

# Folders
_obj
_test

# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out

*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*

_testmain.go

*.exe
*.test
*.prof

.vscode/settings.json
webserver/*server*
14 changes: 14 additions & 0 deletions examples/ambassador/go-service/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
FROM golang:1.8.3-alpine
MAINTAINER Aurelien PERRIER <a.perrier89@gmail.com>

ENV webserver_path /go/src/github.com/perriea/webserver/
ENV PATH $PATH:$webserver_path

WORKDIR $webserver_path
COPY webserver/ .

RUN go build .

ENTRYPOINT ./webserver

EXPOSE 8080
19 changes: 19 additions & 0 deletions examples/ambassador/go-service/garden.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
module:
name: go-service
description: Go service container
type: container
services:
- name: go-service
ports:
- name: http
containerPort: 8080
# Maps service:80 -> container:8080
servicePort: 80
annotations:
getambassador.io/config: |
---
apiVersion: ambassador/v1
kind: Mapping
name: go-service_mapping
prefix: /go-service/
service: go-service:80
17 changes: 17 additions & 0 deletions examples/ambassador/go-service/webserver/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package main

import (
"fmt"
"net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Hello from Go!")
}

func main() {
http.HandleFunc("/hello-go", handler)
fmt.Println("Server running...")

http.ListenAndServe(":8080", nil)
}
4 changes: 4 additions & 0 deletions examples/ambassador/node-service/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
node_modules
Dockerfile
garden.yml
app.yaml
12 changes: 12 additions & 0 deletions examples/ambassador/node-service/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
FROM node:9-alpine

ENV PORT=8080
EXPOSE ${PORT}
WORKDIR /app

ADD package.json /app
RUN npm install

ADD . /app

CMD ["npm", "start"]
28 changes: 28 additions & 0 deletions examples/ambassador/node-service/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
const express = require('express');
const request = require('request-promise')
const app = express();

// Unless configured otherwise, the hostname is simply the service name
const goServiceEndpoint = `http://go-service/hello-go`;

app.get('/hello-node', (req, res) => res.send('Hello from Node service!'));

app.get('/call-go-service', (req, res) => {
// Query the go-service and return the response
request.get(goServiceEndpoint)
.then(message => {
message = `Go says: '${message}'`
res.json({
message,
})
})
.catch(err => {
res.statusCode = 500
res.json({
error: err,
message: "Unable to reach service at " + goServiceEndpoint,
})
});
});

module.exports = { app }
26 changes: 26 additions & 0 deletions examples/ambassador/node-service/garden.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
module:
name: node-service
description: Node service container
type: container
services:
- name: node-service
ports:
- name: http
containerPort: 8080
annotations:
getambassador.io/config: |
---
apiVersion: ambassador/v1
kind: Mapping
name: node-service_mapping
prefix: /node-service/
service: node-service:8080
dependencies:
- go-service
tests:
- name: unit
args: [npm, test]
- name: integ
args: [npm, run, integ]
dependencies:
- go-service
3 changes: 3 additions & 0 deletions examples/ambassador/node-service/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const { app } = require('./app');

app.listen(process.env.PORT, '0.0.0.0', () => console.log('Node service started'));
22 changes: 22 additions & 0 deletions examples/ambassador/node-service/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"name": "node-service",
"version": "1.0.0",
"description": "Simple Node.js docker service",
"main": "main.js",
"scripts": {
"start": "node main.js",
"test": "echo OK",
"integ": "node_modules/mocha/bin/mocha test/integ.js"
},
"author": "garden.io <info@garden.io>",
"license": "ISC",
"dependencies": {
"express": "^4.16.2",
"request": "^2.83.0",
"request-promise": "^4.2.2"
},
"devDependencies": {
"mocha": "^5.1.1",
"supertest": "^3.0.0"
}
}
17 changes: 17 additions & 0 deletions examples/ambassador/node-service/test/integ.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
const supertest = require("supertest")
const { app } = require("../app")

describe('GET /call-go-service', () => {
const agent = supertest.agent(app)

it('should respond with a message from go-service', (done) => {
agent
.get("/call-go-service")
.expect(200, { message: "Go says: 'Hello from Go!'" })
.end((err) => {
if (err) return done(err)
done()
})
})
})

0 comments on commit 7fd2a18

Please sign in to comment.