feat(plugin): add proxywasm plugin (#284)

* feat(plugin): add `proxywasm` plugin

The `proxywasm` plugin is a WASM Filter following the ProxyWasm ABI Specification using the proxywasm go sdk

This allows extensibility with any reverse proxy who implements the ProxyWasm ABI Specification.

The current WASM Filter was successfully tested with APISIX, Envoy, Nginx with ngx_wasm_module from Kong and Istio.

Fixes #145
This commit is contained in:
Alexis Couvreur
2024-06-28 13:22:06 -04:00
parent 54bc622b45
commit 3891027e23
57 changed files with 2164 additions and 2891 deletions

View File

@@ -1,7 +1,5 @@
![Latest Build](https://img.shields.io/github/actions/workflow/status/acouvreur/sablier/build.yml?style=flat-square&branch=main)![Go Report](https://goreportcard.com/badge/github.com/acouvreur/sablier?style=flat-square) ![Go Version](https://img.shields.io/github/go-mod/go-version/acouvreur/sablier?style=flat-square) ![Latest Release](https://img.shields.io/github/release/acouvreur/sablier/all.svg?style=flat-square)
*This website is still a work in progress and is based on the **beta** branch version*
# Sablier - Scale to Zero
Sablier is a **free** and **open-source** software that can scale your workloads on demand.
@@ -19,7 +17,7 @@ Which allows you to start your containers on demand and shut them down automatic
## Glossary
I'll use these terms in order to be provider agnostic.
I'll use these terms in order to be provider-agnostic.
- **Session**: A Session is a set of **instances**
- **Instance**: An instance is either a docker container, docker swarm service, kubernetes deployment or kubernetes statefulset

View File

@@ -8,14 +8,18 @@
- [Versioning](/versioning)
- **Providers**
- [Overview](/providers/overview)
- [Docker](/providers/docker)
- [Docker Swarm](/providers/docker_swarm)
- [Kubernetes](/providers/kubernetes)
- [<img src="assets/img/docker.svg" height=24px width=24px />Docker](/providers/docker)
- [<img src="assets/img/docker_swarm.png" height=24px width=24px />Docker Swarm](/providers/docker_swarm)
- [<img src="assets/img/kubernetes.png" height=24px width=24px />Kubernetes](/providers/kubernetes)
- **Reverse Proxy Plugins**
- [Overview](/plugins/overview)
- [Traefik](/plugins/traefik)
- [Nginx](/plugins/nginx)
- [Caddy](/plugins/caddy)
- [<img src="assets/img/apacheapisix.png" height=24px width=24px />Apache APISIX](/plugins/apacheapisix)
- [<img src="assets/img/caddy.png" height=24px width=24px />Caddy](/plugins/caddy)
- [<img src="assets/img/envoy.png" height=24px width=24px />Envoy](/plugins/envoy)
- [<img src="assets/img/istio.png" height=24px width=24px />Istio](/plugins/istio)
- [<img src="assets/img/nginx.svg" height=24px width=24px />Nginx (NJS)](/plugins/nginx)
- [<img src="assets/img/nginx.svg" height=24px width=24px />Nginx (ProxyWasm)](/plugins/nginx_proxywasm)
- [<img src="assets/img/traefik.png" height=24px /> Traefik](/plugins/traefik)
- **Guides**
- [Overview](/guides/overview)
- [VSCode Server with Traefik and Kubernetes](/guides/code-server-traefik-kubernetes.md)

Binary file not shown.

After

Width:  |  Height:  |  Size: 238 KiB

BIN
docs/assets/img/caddy.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

BIN
docs/assets/img/envoy.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

BIN
docs/assets/img/istio.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 KiB

View File

@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg width="800px" height="800px" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg"><title>file_type_nginx</title><path d="M15.948,2h.065a10.418,10.418,0,0,1,.972.528Q22.414,5.65,27.843,8.774a.792.792,0,0,1,.414.788c-.008,4.389,0,8.777-.005,13.164a.813.813,0,0,1-.356.507q-5.773,3.324-11.547,6.644a.587.587,0,0,1-.657.037Q9.912,26.6,4.143,23.274a.7.7,0,0,1-.4-.666q0-6.582,0-13.163a.693.693,0,0,1,.387-.67Q9.552,5.657,14.974,2.535c.322-.184.638-.379.974-.535" style="fill:#019639"/><path d="M8.767,10.538q0,5.429,0,10.859a1.509,1.509,0,0,0,.427,1.087,1.647,1.647,0,0,0,2.06.206,1.564,1.564,0,0,0,.685-1.293c0-2.62-.005-5.24,0-7.86q3.583,4.29,7.181,8.568a2.833,2.833,0,0,0,2.6.782,1.561,1.561,0,0,0,1.251-1.371q.008-5.541,0-11.081a1.582,1.582,0,0,0-3.152,0c0,2.662-.016,5.321,0,7.982-2.346-2.766-4.663-5.556-7-8.332A2.817,2.817,0,0,0,10.17,9.033,1.579,1.579,0,0,0,8.767,10.538Z" style="fill:#fff"/></svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

BIN
docs/assets/img/traefik.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 258 KiB

View File

@@ -0,0 +1,33 @@
# Apache APISIX Plugin
The Apache APISIX Plugin is a WASM Plugin written with the Proxy Wasm SDK.
## Provider compatibility grid
| Provider | Dynamic | Blocking |
|-----------------------------------------|:-------:|:--------:|
| [Docker](/providers/docker) | ✅ | ✅ |
| [Docker Swarm](/providers/docker_swarm) | ❓ | ❓ |
| [Kubernetes](/providers/kubernetes) | ❓ | ❓ |
## Install the plugin to Apache APISIX
```yaml
wasm:
plugins:
- name: proxywasm_sablier_plugin
priority: 7997
file: /wasm/sablierproxywasm.wasm # Downloaded WASM Filter path
```
## Configuration
You can have the following configuration:
```yaml
routes:
- uri: "/"
plugins:
proxywasm_sablier_plugin:
conf: '{ "sablier_url": "sablier:10000", "group": ["my-group"], "session_duration": "1m", "dynamic": { "display_name": "Dynamic Whoami" } }'
```

48
docs/plugins/envoy.md Normal file
View File

@@ -0,0 +1,48 @@
# Envoy Plugin
The Envoy Plugin is a WASM Plugin written with the Proxy Wasm SDK.
## Provider compatibility grid
| Provider | Dynamic | Blocking |
|-----------------------------------------|:-------:|:--------:|
| [Docker](/providers/docker) | ✅ | ✅ |
| [Docker Swarm](/providers/docker_swarm) | ❓ | ❓ |
| [Kubernetes](/providers/kubernetes) | ❓ | ❓ |
## Configuration
You can have the following configuration:
```yaml
http_filters:
- name: sablier-wasm-whoami-dynamic
disabled: true
typed_config:
"@type": type.googleapis.com/udpa.type.v1.TypedStruct
type_url: type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm
value:
config:
name: "sablier-wasm-whoami-dynamic"
root_id: "sablier-wasm-whoami-dynamic"
configuration:
"@type": "type.googleapis.com/google.protobuf.StringValue"
value: |
{
"sablier_url": "sablier:10000",
"cluster": "sablier",
"names": ["docker_classic_e2e-whoami-1"],
"session_duration": "1m",
"dynamic": {
"display_name": "Dynamic Whoami",
"theme": "hacker-terminal"
}
}
vm_config:
runtime: "envoy.wasm.runtime.v8"
vm_id: "vm.sablier.sablier-wasm-whoami-dynamic"
code:
local:
filename: "/etc/sablierproxywasm.wasm"
configuration: { }
```

45
docs/plugins/istio.md Normal file
View File

@@ -0,0 +1,45 @@
# Istio Plugin
The Istio Plugin is a WASM Plugin written with the Proxy Wasm SDK.
## Provider compatibility grid
| Provider | Dynamic | Blocking |
|-----------------------------------------|:-------:|:--------:|
| [Docker](/providers/docker) | ❌ | ❌ |
| [Docker Swarm](/providers/docker_swarm) | ❌ | ❌ |
| [Kubernetes](/providers/kubernetes) | ✅ | ✅ |
## Configuration
You can have the following configuration:
!> This only works for ingress gateways.
!> Attaching this filter to a side-car would not work because the side-car itself gets shutdown on scaling to zero.
```yaml
apiVersion: extensions.istio.io/v1alpha1
kind: WasmPlugin
metadata:
name: sablier-wasm-whoami-dynamic
namespace: istio-system
spec:
selector:
matchLabels:
istio: ingressgateway
url: file:///opt/filters/sablierproxywasm.wasm/..data/sablierproxywasm.wasm
# Use https://istio.io/latest/docs/reference/config/proxy_extensions/wasm-plugin/#WasmPlugin-TrafficSelector
# To specify which service to apply this filter only
phase: UNSPECIFIED_PHASE
pluginConfig:
{
"sablier_url": "sablier.sablier-system.svc.cluster.local",
"cluster": "outbound|10000||sablier.sablier-system.svc.cluster.local",
"names": [ "deployment_default_whoami_1" ],
"session_duration": "1m",
"dynamic": {
"display_name": "Dynamic Whoami",
"theme": "hacker-terminal"
}
}
```

View File

@@ -0,0 +1,79 @@
# Nginx Plugin
The Nginx Plugin is a WASM Plugin written with the Proxy Wasm SDK.
## Provider compatibility grid
| Provider | Dynamic | Blocking |
|-----------------------------------------|:-------:|:--------:|
| [Docker](/providers/docker) | ✅ | ✅ |
| [Docker Swarm](/providers/docker_swarm) | ❓ | ❓ |
| [Kubernetes](/providers/kubernetes) | ❓ | ❓ |
# Install ngx_wasm_module
Install https://github.com/Kong/ngx_wasm_module.
Example for a Dockerfile:
```dockerfile
FROM ubuntu:22.04
RUN apt update && apt install libatomic1
ADD https://github.com/Kong/ngx_wasm_module/releases/download/prerelease-0.3.0/wasmx-prerelease-0.3.0-v8-x86_64-ubuntu22.04.tar.gz wasmx.tar.gz
RUN mkdir /etc/nginx
RUN tar -xvf wasmx.tar.gz
RUN mv /wasmx-prerelease-0.3.0-v8-x86_64-ubuntu22.04/* /etc/nginx/
WORKDIR /etc/nginx
CMD [ "./nginx", "-g", "daemon off;" ]
```
## Configuration
```nginx
# nginx.conf
events {}
# nginx master process gets a default 'main' VM
# a new top-level configuration block receives all configuration for this main VM
wasm {
module proxywasm_sablier_plugin /wasm/sablierproxywasm.wasm;
}
http {
access_log /dev/stdout;
# internal docker resolver, see /etc/resolv.conf on proxy container
# needed for docker name resolution
resolver 127.0.0.11 valid=1s ipv6=off;
server {
listen 8080;
location /dynamic {
proxy_wasm proxywasm_sablier_plugin '{ "sablier_url": "sablier:10000", "names": ["docker_classic_e2e-whoami-1"], "session_duration": "1m", "dynamic": { "display_name": "Dynamic Whoami", "theme": "hacker-terminal" } }';
# force dns resolution by using a variable
# because container will be restarted and change ip a lot of times
set $proxy_pass_host whoami:80$request_uri;
proxy_pass http://$proxy_pass_host;
proxy_set_header Host localhost:8080; # e2e test compliance
}
location /blocking {
wasm_socket_read_timeout 60s; # Blocking hangs the request
proxy_wasm proxywasm_sablier_plugin '{ "sablier_url": "sablier:10000", "names": ["docker_classic_e2e-whoami-1"], "session_duration": "1m", "blocking": { "timeout": "30s" } }';
# force dns resolution by using a variable
# because container will be restarted and change ip a lot of times
set $proxy_pass_host whoami:80$request_uri;
proxy_pass http://$proxy_pass_host;
proxy_set_header Host localhost:8080; # e2e test compliance
}
}
}
```

View File

@@ -12,11 +12,24 @@ It leverages the API calls to plugin integration to catch in-flight requests to
## Available Reverse Proxies
| Reverse Proxy | Docker | Docker Swarm mode | Kubernetes | Podman |
| ---------------------------- | :----: | :---------------: | :--------: | :-------------------------------------------------------: |
| [Traefik](/plugins/traefik) | ✅ | ✅ | ✅ | [See #70](https://github.com/acouvreur/sablier/issues/70) |
| [Nginx](/plugins/nginx) | ✅ | ✅ | ❌ |
| [Caddy](/plugins/caddy) | ✅ | | |
| Reverse Proxy | Docker | Docker Swarm mode | Kubernetes |
|-------------------------------------------------|:------:|:-----------------:|:----------:|
| [Apache APISIX](/plugins/apacheapisix) | ✅ | ✅ | ✅ |
| [Caddy](/plugins/caddy) | ✅ | ✅ | ❌ |
| [Envoy](/plugins/envoy) | ✅ | | |
| [Istio](plugins/istio) | ❌ | ❌ | ⚠️ |
| [Nginx (NJS Module)](/plugins/nginx_njs) | ✅ | ✅ | ✅ |
| [Nginx (WASM Module)](/plugins/nginx_proxywasm) | ✅ | ❓ | ❓ |
| [Traefik](/plugins/traefik) | ✅ | ✅ | ✅ |
| [ProxyWasm](/plugins/proxywasm) | ✅ | ✅ | ✅ |
> ✅ **Fully compatible**
>
> ⚠️ **Partially compatible**
>
> ❓ **Should be compatible (but not tested)**
>
> ❌ **Not compatible**
*Your Reverse Proxy is not on the list? [Open an issue to request the missing reverse proxy integration here!](https://github.com/acouvreur/sablier/issues/new?assignees=&labels=enhancement%2C+reverse-proxy&projects=&template=reverse-proxy-integration-request.md&title=Add+%60%5BREVERSE+PROXY%5D%60+reverse+proxy+integration)*

View File

@@ -13,7 +13,7 @@ A Provider typically have the following capabilities:
## Available providers
| Provider | Name | Details |
| --------------------------------------- | ------------------------- | ---------------------------------------------------------------- |
|-----------------------------------------|---------------------------|------------------------------------------------------------------|
| [Docker](/providers/docker) | `docker` | Stop and start **containers** on demand |
| [Docker Swarm](/providers/docker_swarm) | `docker_swarm` or `swarm` | Scale down to zero and up **services** on demand |
| [Kubernetes](/providers/kubernetes) | `kubernetes` | Scale down and up **deployments** and **statefulsets** on demand |