Skip to content

Commit

Permalink
docs: add demo
Browse files Browse the repository at this point in the history
  • Loading branch information
andydunstall committed May 4, 2024
1 parent dcc8b14 commit 405aa31
Show file tree
Hide file tree
Showing 10 changed files with 240 additions and 59 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
pico
!pico/

build/
bin/

coverage.out
9 changes: 7 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ all: pico

.PHONY: pico
pico:
mkdir -p build
go build -o build/pico main.go
mkdir -p bin
go build -o bin/pico main.go

.PHONY: unit-test
unit-test:
Expand All @@ -31,3 +31,8 @@ lint:
coverage:
go test ./... -coverprofile=coverage.out
go tool cover -html=coverage.out

.PHONY: image
image:
docker build . -f build/Dockerfile -t pico:$(shell git rev-parse HEAD)
docker tag pico:$(shell git rev-parse HEAD) pico:latest
40 changes: 2 additions & 38 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,48 +107,12 @@ Run the Pico agent with `pico agent`.

## Getting Started

This section describes how to run both the Pico server and agent locally to
register and endpoint. In production you'd host the server remotely as a
cluster, though this is still useful to demo Pico.

This example registers an endpoint `my-endpoint` and forwards requests to
`localhost:3000`. To see the requests being forwarded, start a simple file
server at `localhost:3000` with `python3 -m http.server 3000`.

Pico has a single binary that can be built with `make pico`, which is output to
`build/pico` (requires Go 1.21 or later).

### Setup

Start the Pico server with `pico server`. This listens for proxy requests on
port `8000` and upstream connections on `8001`.

Next start the Pico agent and register the above endpoint with
`pico agent –endpoints my-endpoint/localhost:3000`. This creates an outbound
connection to the Pico server that registers to receive requests for the given
endpoints.

You can inspect the status of the server using the `pico status` CLI. Such as
use `pico status proxy endpoints` to view the list of endpoints registered on
the server.

### Request

As described above, when sending a request to Pico you can identify the
endpoint ID using either the `Host` header or the `x-pico-agent`.

Therefore to send a request to the upstream endpoint use:
```
# x-pico-endpoint
curl http://localhost:8000 -H "x-pico-endpoint: my-endpoint"
# Host
curl --connect-to my-endpoint.example.com:8000:localhost:8000 http://my-endpoint.example.com:8000
```
See [Getting Started](./docs/getting-started.md).

## Docs

See [docs](./docs) for details on deploying and managing Pico:
- [Getting Started](./docs/getting-started.md)
- [Configure](./docs/deploy/configure.md)
- [Kubernetes](./docs/deploy/kubernetes.md)
- [Observability](./docs/deploy/observability.md)
Expand Down
17 changes: 0 additions & 17 deletions dev/Dockerfile

This file was deleted.

54 changes: 54 additions & 0 deletions docs/demo/config/nginx.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
events {
worker_connections 1024;
}

http {
upstream backend-proxy {
server pico-1:8000 max_fails=1 fail_timeout=1s;
server pico-2:8000 max_fails=1 fail_timeout=1s;
server pico-3:8000 max_fails=1 fail_timeout=1s backup;
}

server {
listen 8000;
access_log /dev/null;
location / {
proxy_pass http://backend-proxy;
# Retain the original Host header.
proxy_set_header Host $host;
}
}

upstream backend-upstream {
server pico-1:8001 max_fails=1 fail_timeout=1s;
server pico-2:8001 max_fails=1 fail_timeout=1s;
server pico-3:8001 max_fails=1 fail_timeout=1s backup;
}

server {
listen 8001;
access_log /dev/null;
location / {
proxy_pass http://backend-upstream;
# Enable WebSockets.
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
}
}

upstream backend-admin {
server pico-1:8002 max_fails=1 fail_timeout=1s;
server pico-2:8002 max_fails=1 fail_timeout=1s;
server pico-3:8002 max_fails=1 fail_timeout=1s backup;
}

server {
listen 8002;
access_log /dev/null;
location / {
proxy_pass http://backend-admin;
}
}
}
5 changes: 5 additions & 0 deletions docs/demo/config/pico.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
cluster:
join:
- pico-1
- pico-2
- pico-3
18 changes: 18 additions & 0 deletions docs/demo/config/prometheus.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
global:
scrape_interval: 5s
external_labels:
cluster: demo
namespace: demo

scrape_configs:
- job_name: demo/pico
static_configs:
- targets: ["pico-1:8002"]
labels:
pod: "pico-1"
- targets: ["pico-2:8002"]
labels:
pod: "pico-2"
- targets: ["pico-3:8002"]
labels:
pod: "pico-3"
77 changes: 77 additions & 0 deletions docs/demo/docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
version: "3.4"
services:
pico-1:
image: pico:latest
command:
- server
- --config.path
- /etc/pico.yaml
- --cluster.node-id-prefix
- pico-1-
hostname: pico-1
volumes:
- ./config/pico.yaml:/etc/pico.yaml

pico-2:
image: pico:latest
command:
- server
- --config.path
- /etc/pico.yaml
- --cluster.node-id-prefix
- pico-2-
hostname: pico-2
volumes:
- ./config/pico.yaml:/etc/pico.yaml

pico-3:
image: pico:latest
command:
- server
- --config.path
- /etc/pico.yaml
- --cluster.node-id-prefix
- pico-3-
hostname: pico-3
volumes:
- ./config/pico.yaml:/etc/pico.yaml

load-balancer:
image: nginx:latest
volumes:
- ./config/nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
- "pico-1"
- "pico-2"
- "pico-3"
ports:
- 8000:8000
- 8001:8001
- 8002:8002

prometheus:
image: prom/prometheus:latest
command:
- --config.file=/etc/prometheus/prometheus.yml
- --log.level=error
volumes:
- ./config/prometheus.yaml:/etc/prometheus/prometheus.yml
depends_on:
- "pico-1"
- "pico-2"
- "pico-3"
ports:
- 9090:9090

grafana:
image: grafana/grafana:latest
environment:
- GF_LOG_MODE=console
- GF_LOG_LEVEL=critical
ports:
- 3000:3000

networks:
pico-network:
driver: bridge
name: pico-network
75 changes: 75 additions & 0 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Getting Started

This example uses `docker-compose` to deploy three Pico server nodes behind
a load balancer, then registers endpoints to forward requests to a local HTTP
server.

## Server

Start by cloning Pico and building the Pico Docker image:
```shell
git clone [email protected]:andydunstall/pico.git
make pico
make image
```

This will build the Pico binary at `bin/pico` and Docker image `pico:latest`.

Next start the Pico server cluster:
```shell
cd docs/demo
docker compose up
```

This creates a cluster of three server nodes and a load balancer that exposes
the Pico ports. It will also start Prometheus and Grafana to inspect the Pico
metrics. The following ports are exposed:
- Pico proxy (`http://localhost:8000`): Forwards proxy requests to registered
endpoints
- Pico upstream (`http://localhost:8001`): Accepts connections from upstream
endpoints
- Pico admin (`http://localhost:8002`): Accepts admin connections for metrics,
the status API, and health checks
- Prometheus (`http://localhost:9090`)
- Grafana (`http://localhost:3000`)

To verify Pico has started correctly, run `pico status netmap nodes` which
queries the Pico admin API for the set of known Pico nodes.

## Agent

The Pico agent is a lightweight proxy that runs alongside your upstream
services. It connects to the Pico server and registers endpoints, then forwards
incoming requests to your services.

Create a simple HTTP server to forward requests to, such as
`python3 -m http.server 4000` so serve the files in the local directory on port
`4000`.

Then run the Pico agent and register endpoint `my-endpoint` using:
```shell
pico agent --endpoints my-endpoint/localhost:4000
```

See `pico agent -h` for the available options.

You can verify the endpoint has connected, again run `pico status netmap nodes`
and you'll see one of the Pico server nodes reporting endpoint `my-endpoint`
has an active connection.

### Request

As described above, when sending a request to Pico you can identify the
endpoint ID using either the `Host` header or the `x-pico-agent`.

Therefore to send a request to the registered endpoint, `my-endpoint`, use:
```shell
# x-pico-endpoint
curl http://localhost:8000 -H "x-pico-endpoint: my-endpoint"

# Host
curl --connect-to my-endpoint.example.com:8000:localhost:8000 http://my-endpoint.example.com:8000
```

This request will be load balanced among the Pico servers, then forwarded to
the endpoint registered above.
2 changes: 1 addition & 1 deletion server/netmap/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ func (n *Node) Copy() *Node {
}

func GenerateNodeID() string {
b := make([]byte, 6)
b := make([]byte, 7)
for i := range b {
n, err := rand.Int(rand.Reader, big.NewInt(int64(len(alphaNumericChars))))
if err != nil {
Expand Down

0 comments on commit 405aa31

Please sign in to comment.