Skip to content

Commit

Permalink
Stub out tests and provide new example deployment for Compose and Triton
Browse files Browse the repository at this point in the history
  • Loading branch information
tgross committed Feb 6, 2017
1 parent 91c4d41 commit ea37c45
Show file tree
Hide file tree
Showing 21 changed files with 551 additions and 35 deletions.
6 changes: 3 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# credentials
_env*

# macos frustration
.DS_Store

# generated content
ExampleFile
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "test/testing"]
path = test/testing
url = https://github.com/autopilotpattern/testing.git
32 changes: 3 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,39 +12,13 @@ The goal of this project is to create an Nginx image that can be reused across e

### Running in your own project

Consult https://github.com/autopilotpattern/wordpress for example usage.

### Hello world example

1. [Get a Joyent account](https://my.joyent.com/landing/signup/) and [add your SSH key](https://docs.joyent.com/public-cloud/getting-started).
1. Install the [Docker Toolbox](https://docs.docker.com/installation/mac/) (including `docker` and `docker-compose`) on your laptop or other environment, as well as the [Joyent Triton CLI](https://www.joyent.com/blog/introducing-the-triton-command-line-tool) (`triton` replaces our old `sdc-*` CLI tools).
1. [Configure Docker and Docker Compose for use with Joyent.](https://docs.joyent.com/public-cloud/api-access/docker)

Check that everything is configured correctly by running `./setup.sh`. This will check that your environment is setup correctly and will create an `_env` file that includes injecting an environment variable for the Consul hostname into the Nginx and App containers so we can take advantage of [Triton Container Name Service (CNS)](https://www.joyent.com/blog/introducing-triton-container-name-service).

Start everything:

```bash
docker-compose -p nginx up -d
```

The Nginx server will register with the Consul server named in the `_env` file. You can see its status there in the Consul web UI. On a Mac, you can open your browser to that with the following command:

```bash
open "http://$(triton ip nginx_consul_1):8500/ui"
```

You can open the demo app that Nginx is proxying by opening a browser to the Nginx instance IP:

```bash
open "http://$(triton ip nginx_nginx_1)/example"
```
Consult https://github.com/autopilotpattern/wordpress for example usage, or see the examples in the examples directory for deploying to Joyent's Triton Cloud or via Docker Compose.

### Configuring LetsEncrypt (ACME)

Setting the `ACME_DOMAIN` environment variable will enable LetsEncrypt within the image. The image will automatically acquire certificates for the given domain, and renew them over time. If you scale to multiple instances of Nginx, they will elect a leader who will be responsible for renewing the certificates. Any challenge response tokens as well as acquired certificates will be replicated to all Nginx instances.
Setting the `ACME_DOMAIN` environment variable will enable LetsEncrypt within the image. The image will automatically acquire certificates for the given domain, and renew them over time. If you scale to multiple instances of Nginx, they will elect a leader who will be responsible for renewing the certificates. Any challenge response tokens as well as acquired certificates will be replicated to all Nginx instances.

By default, this process will use the LetsEncrypt staging endpoint, so as not to impact your api limits. When ready for production, you must also set the `ACME_ENV` environment variable to `production`.
By default, this process will use the LetsEncrypt staging endpoint, so as not to impact your api limits. When ready for production, you must also set the `ACME_ENV` environment variable to `production`.

You must ensure the domain resolves to your Nginx containers so that they can respond to the ACME http challenges. Triton users may [refer to this document](https://docs.joyent.com/public-cloud/network/cns/faq#can-i-use-my-own-domain-name-with-triton-cns) for more information on how to insure your domain resolves to your Triton containers.

Expand Down
6 changes: 3 additions & 3 deletions bin/generate-config
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,21 @@ if [ -f ${CERT_DIR}/fullchain.pem -a -f ${CERT_DIR}/privkey.pem ]; then
export SSL_READY="true"
fi

# Generate a conf.d config file for every corresponding cond.d Consul template
# Generate a conf.d config file for every corresponding conf.d Consul template
for f in $(ls -1 /etc/nginx/templates/conf.d/)
do
consul-template \
-once \
-dedup \
-consul ${CONSUL}:8500 \
-consul-addr "${CONSUL}:8500" \
-template "/etc/nginx/templates/conf.d/${f}:/etc/nginx/conf.d/${f}"
done

# Render Nginx configuration template using values from Consul
consul-template \
-once \
-dedup \
-consul ${CONSUL}:8500 \
-consul-addr "${CONSUL}:8500" \
-template "/etc/nginx/templates/health.conf:/etc/nginx/health.conf" \
-template "/etc/nginx/templates/ssl.conf:/etc/nginx/ssl.conf" \
-template "/etc/nginx/templates/nginx.conf:/etc/nginx/nginx.conf"
4 changes: 4 additions & 0 deletions examples/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
FROM autopilotpattern/nginx:latest

COPY examples/example.conf /etc/nginx/templates/conf.d/site.conf
COPY examples/containerpilot.json /etc/containerpilot.json
24 changes: 24 additions & 0 deletions examples/backend/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
FROM mhart/alpine-node:latest

RUN apk update && \
apk add curl

# Install ContainerPilot
ENV CONTAINERPILOT_VERSION 2.4.1
RUN export CP_SHA1=198d96c8d7bfafb1ab6df96653c29701510b833c \
&& curl -Lso /tmp/containerpilot.tar.gz \
"https://github.com/joyent/containerpilot/releases/download/${CONTAINERPILOT_VERSION}/containerpilot-${CONTAINERPILOT_VERSION}.tar.gz" \
&& echo "${CP_SHA1} /tmp/containerpilot.tar.gz" | sha1sum -c \
&& tar zxf /tmp/containerpilot.tar.gz -C /bin \
&& rm /tmp/containerpilot.tar.gz

# COPY ContainerPilot configuration
COPY examples/backend/containerpilot.json /etc/containerpilot.json
ENV CONTAINERPILOT=file:///etc/containerpilot.json


# Install our application
COPY examples/backend/index.js /opt/hello/

EXPOSE 3001
CMD ["/bin/containerpilot", "node", "/opt/hello/index.js"]
Empty file added examples/backend/README.md
Empty file.
12 changes: 12 additions & 0 deletions examples/backend/containerpilot.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"consul": "consul:8500",
"services": [
{
"name": "backend",
"port": 3001,
"health": "/usr/bin/curl -o /dev/null --fail -s http://localhost:3001/",
"poll": 3,
"ttl": 10
}
]
}
15 changes: 15 additions & 0 deletions examples/backend/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
'use strict';

// Load modules

const Http = require('http');


const server = module.exports = Http.createServer((req, res) => {
res.writeHead(200);
res.end('Hello World\n');
});

server.listen(3001, () => {
console.log(`Hello server listening on port ${server.address().port}`);
});
17 changes: 17 additions & 0 deletions examples/backend/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "hello",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "lab -c"
},
"keywords": [],
"author": "",
"license": "MPL-V2",
"devDependencies": {
"code": "3.x.x",
"lab": "11.x.x",
"wreck": "9.x.x"
}
}
19 changes: 19 additions & 0 deletions examples/compose/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
### Hello world example

Install the [Docker Toolbox](https://docs.docker.com/installation/mac/) (including `docker` and `docker-compose`) on your laptop or other environment. Then start everything:

```bash
docker-compose -p nginx up -d
```

The Nginx server will register with the Consul server. You can see its status there in the Consul web UI. If you're using Docker for Mac, you can open your browser to that with the following command:

```bash
open "http://localhost:8500/ui"
```

You can view the demo backend running behind Nginx by opening a browser to the Nginx instance:

```bash
open "http://localhost:8080/example"
```
50 changes: 50 additions & 0 deletions examples/compose/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
version: '2.1'

services:
nginx:
image: autopilotpattern/nginx-example:${TAG:-latest}
mem_limit: 128m
restart: always
environment:
- CONSUL_AGENT=1
- CONSUL=consul
links:
- consul:consul
ports:
- "8080:80"
network_mode: bridge


backend:
image: autopilotpattern/nginx-backend:${TAG:-latest}
mem_limit: 128m
restart: always
environment:
- CONSUL=consul
links:
- consul:consul
ports:
- "3001:3001"
network_mode: bridge


consul:
image: autopilotpattern/consul:0.7.2-r0.8
command: >
/usr/local/bin/containerpilot
/bin/consul agent -server
-bootstrap-expect 1
-config-dir=/etc/consul
-ui-dir /ui
restart: always
mem_limit: 128m
ports:
- "8500:8500"
expose:
- 53
- 8300
- 8301
- 8302
- 8400
- 8500
network_mode: bridge
96 changes: 96 additions & 0 deletions examples/containerpilot.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
{
"consul": "{{ if .CONSUL_AGENT }}localhost{{ else }}{{ if .CONSUL }}{{ .CONSUL }}{{ else }}consul{{ end }}{{ end }}:8500",
"preStart": "generate-config",
"services": [
{
"name": "nginx",
"port": 80,
"health": "health-check http",
"poll": 10,
"ttl": 25,
"interfaces": ["eth0"]
},
{
"name": "nginx-public",
"port": 80,
"health": "health-check http",
"poll": 10,
"ttl": 25,
"interfaces": ["eth1", "eth0"]
}{{ if .ACME_DOMAIN }},
{
"name": "nginx-ssl",
"port": 443,
"health": "acme init && health-check https",
"poll": 10,
"ttl": 25,
"interfaces": ["eth0"]
},
{
"name": "nginx-public-ssl",
"port": 443,
"health": "health-check https",
"poll": 10,
"ttl": 25,
"interfaces": ["eth0"]
},
{
"name": "nginx-public-ssl",
"port": 443,
"health": "/usr/bin/curl --insecure --fail --silent --show-error --output /dev/null --header \"HOST: {{ .ACME_DOMAIN }}\" https://localhost/nginx-health",
"poll": 10,
"ttl": 25,
"interfaces": ["eth1", "eth0"]
}{{ end }}
],
"coprocesses": [{{ if .CONSUL_AGENT }}
{
"command": ["consul", "agent",
"-data-dir=/var/lib/consul",
"-config-dir=/etc/consul",
"-rejoin",
"-retry-join", "{{ if .CONSUL }}{{ .CONSUL }}{{ else }}consul{{ end }}",
"-retry-max", "10",
"-retry-interval", "10s"],
"restarts": "unlimited"
}{{ end }}
{{ if and .CONSUL_AGENT .ACME_DOMAIN }},{{ end }}
{{ if .ACME_DOMAIN }}
{
"command": ["acme", "watch"],
"restarts": "unlimited"
}{{ end }}],
"backends": [
{
"name": "backend",
"poll": 7,
"onChange": "reload"
}
],
"telemetry": {
"port": 9090,
"sensors": [
{
"name": "nginx_connections_unhandled_total",
"help": "Number of accepted connnections that were not handled",
"type": "gauge",
"poll": 5,
"check": ["sensor", "unhandled"]
},
{
"name": "nginx_connections_load",
"help": "Ratio of active connections (less waiting) to the maximum worker connections",
"type": "gauge",
"poll": 5,
"check": ["sensor", "connections_load"]
}
]
},
"tasks": [{{ if .ACME_DOMAIN }}
{
"name": "acme-checkin",
"command": [ "acme", "checkin" ],
"frequency": "1h",
"timeout": "10s"
}{{ end }}]
}
50 changes: 50 additions & 0 deletions examples/example.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
{{ $acme_domain := env "ACME_DOMAIN" }}
{{ $ssl_ready := env "SSL_READY" }}

# If we're listening on https, define an http listener that redirects everything to https
{{ if eq $ssl_ready "true" }}
server {
server_name _;
listen 80;

include /etc/nginx/health.conf;

location / {
return 301 https://$host$request_uri;
}
}
{{ end }}


{{ if service "backend" }}
upstream backend {
{{ range service "backend" }}
server {{ .Address }}:{{ .Port }};
{{ end }}
least_conn;
}{{ end }}


server {
server_name _;
# Listen on port 80 unless we have certificates installed, then listen on 443
listen {{ if ne $ssl_ready "true" }}80{{ else }}443 ssl{{ end }};

include /etc/nginx/health.conf;

location /.well-known/acme-challenge {
alias /var/www/acme/challenge;
}

location / {
{{ if service "backend" }}
proxy_pass http://backend;
proxy_redirect off;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
{{ else }}
return 503;
{{ end }}
}
}
Loading

0 comments on commit ea37c45

Please sign in to comment.