feat: merge service repository into Sablier

Add plugins folder to integrate with multiple reverse proxies

The project is now released as 'Sablier'
This commit is contained in:
Alexis Couvreur
2022-09-30 14:37:18 +00:00
parent ad4e9ffb8c
commit 551a146d94
41 changed files with 185 additions and 469 deletions

View File

@@ -23,8 +23,8 @@ jobs:
with:
# list of Docker images to use as base name for tags
images: |
ghcr.io/acouvreur/traefik-ondemand-service
acouvreur/traefik-ondemand-service
ghcr.io/acouvreur/sablier
acouvreur/sablier
# generate Docker tags based on the following events/attributes
tags: |
type=schedule

23
.github/workflows/plugins.yml vendored Normal file
View File

@@ -0,0 +1,23 @@
name: Build Sablier plugins
on:
- pull_request
jobs:
traefik:
name: Build Sablier for Traefik middleware
runs-on: ubuntu-latest
steps:
- name: Set up Go 1.18
uses: actions/setup-go@v2
with:
go-version: 1.18
- name: Checkout code
uses: actions/checkout@v2
- name: Build
run: cd plugins/traefik && go build -v .
- name: Test
run: cd plugins/traefik && go test -v ./...

2
.gitignore vendored
View File

@@ -1,2 +0,0 @@
vendor
traefik-ondemand-service

View File

@@ -1,12 +1,12 @@
displayName: Containers On Demand
type: middleware
import: github.com/acouvreur/traefik-ondemand-plugin
import: github.com/acouvreur/sablier/plugins/traefik
summary: 'Start your containers/services on the first request they recieve, and shut them down after a specified duration after the last request they received. Kubernetes, Docker classic and docker swarm compatible.'
summary: 'Start your containers/services on the first request they receive, and shut them down after a specified duration after the last request they received. Kubernetes, Docker classic and docker swarm compatible.'
testData:
serviceUrl: http://ondemand:10000
name: TRAEFIK_HACKATHON_whoami
serviceUrl: http://sablier:10000
name: whoami
timeout: 1m

View File

@@ -3,16 +3,16 @@ FROM golang:1.18-alpine AS build
ENV CGO_ENABLED=0
ENV PORT 10000
COPY . /go/src/ondemand-service
WORKDIR /go/src/ondemand-service
COPY . /go/src/sablier
WORKDIR /go/src/sablier
ARG TARGETOS
ARG TARGETARCH
RUN GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -buildvcs=false -o /go/bin/ondemand-service
RUN GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -buildvcs=false -o /go/bin/sablier
FROM alpine
EXPOSE 10000
COPY --from=build /go/bin/ondemand-service /go/bin/ondemand-service
COPY --from=build /go/bin/sablier /go/bin/sablier
ENTRYPOINT [ "/go/bin/ondemand-service" ]
ENTRYPOINT [ "/go/bin/sablier" ]
CMD [ "--swarmMode=true" ]

View File

@@ -1,4 +1,4 @@
# Kubernetes traefik-ondemand-service Howto
# Kubernetes sablier Howto
# Traefik parameters
@@ -6,8 +6,8 @@ Its important to set allowEmptyServices to true, otherwhise the scale up will
not work because traefik cannot find the service if it was scaled down to zero.
- "--pilot.token=xxxx"
- "--experimental.plugins.traefik-ondemand-plugin.modulename=github.com/acouvreur/traefik-ondemand-plugin"
- "--experimental.plugins.traefik-ondemand-plugin.version=v0.1.1"
- "--experimental.plugins.sablier.modulename=github.com/acouvreur/sablier/plugins/traefik"
- "--experimental.plugins.sablier.version=v0.1.1"
- "--providers.kubernetesingress.allowEmptyServices=true"
If you are using the traefik helm chart its also important to set:
@@ -18,30 +18,30 @@ not work because traefik cannot find the service if it was scaled down to zero.
# Deployment
In this example we will deploy the traefik-ondemand-service into the namespace kube-system
In this example we will deploy the sablier into the namespace kube-system
apiVersion: apps/v1
kind: Deployment
metadata:
name: traefik-ondemand-service
name: sablier
namespace: kube-system
labels:
app: traefik-ondemand-service
app: sablier
spec:
replicas: 1
selector:
matchLabels:
app: traefik-ondemand-service
app: sablier
template:
metadata:
labels:
app: traefik-ondemand-service
app: sablier
spec:
serviceAccountName: traefik-ondemand-service
serviceAccount: traefik-ondemand-service
serviceAccountName: sablier
serviceAccount: sablier
containers:
- name: traefik-ondemand-service
image: gchr.io/acouvreur/traefik-ondemand-service
- name: sablier
image: gchr.io/acouvreur/sablier
args: ["--swarmMode=false", "--kubernetesMode=true"]
ports:
- containerPort: 10000
@@ -49,28 +49,28 @@ In this example we will deploy the traefik-ondemand-service into the namespace k
apiVersion: v1
kind: Service
metadata:
name: traefik-ondemand-service
name: sablier
namespace: kube-system
spec:
selector:
app: traefik-ondemand-service
app: sablier
ports:
- protocol: TCP
port: 10000
targetPort: 10000
We have to create RBAC to allow the traefik-ondemand-service to access the kubernetes API and get/update/patch the deployment resource
We have to create RBAC to allow the sablier to access the kubernetes API and get/update/patch the deployment resource
apiVersion: v1
kind: ServiceAccount
metadata:
name: traefik-ondemand-service
name: sablier
namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: traefik-ondemand-service
name: sablier
namespace: kube-system
rules:
- apiGroups:
@@ -88,15 +88,15 @@ We have to create RBAC to allow the traefik-ondemand-service to access the kuber
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: traefik-ondemand-service
name: sablier
namespace: kube-system
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: traefik-ondemand-service
name: sablier
subjects:
- kind: ServiceAccount
name: traefik-ondemand-service
name: sablier
namespace: kube-system
## Creating a Middleware
@@ -111,9 +111,9 @@ First we need to create a traefik middleware for that:
namespace: kube-system
spec:
plugin:
traefik-ondemand-plugin:
sablier:
name: deployment_codeserverns_code-server_1
serviceUrl: 'http://traefik-ondemand-service:10000'
serviceUrl: 'http://sablier:10000'
timeout: 10m
The format of the `name:` section is `<KIND>_<NAMESPACE>_<NAME>_<REPLICACOUNT>` where `_` is the delimiter.

View File

@@ -8,6 +8,6 @@ version = draft
release: $(PLATFORMS)
$(PLATFORMS):
GOOS=$(os) GOARCH=$(arch) go build -o 'traefik-ondemand-service_$(version)_$(os)-$(arch)' .
GOOS=$(os) GOARCH=$(arch) go build -o 'sablier_$(version)_$(os)-$(arch)' .
.PHONY: release $(PLATFORMS)

View File

@@ -1,41 +1,33 @@
<h1 align="center">
<img src="https://blog.alterway.fr/images/traefik.logo.png" alt="Traefik Ondemand Plugin" width="200">
<br>Traefik Ondemand Service<br>
</h1>
# Sablier ![Github Actions](https://img.shields.io/github/workflow/status/acouvreur/sablier/Build?style=flat-square) ![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)
<h4 align="center">Traefik Ondemand Service for <a href="https://github.com/acouvreur/traefik-ondemand-plugin">traefik-ondemand-plugin</a> to control containers and services.</h4>
## Getting started
<p align="center">
<a href="https://github.com/acouvreur/traefik-ondemand-service/actions">
<img src="https://img.shields.io/github/workflow/status/acouvreur/traefik-ondemand-service/Build?style=flat-square" alt="Github Actions">
</a>
<a href="https://goreportcard.com/report/github.com/acouvreur/traefik-ondemand-service">
<img src="https://goreportcard.com/badge/github.com/acouvreur/traefik-ondemand-service?style=flat-square">
</a>
<img src="https://img.shields.io/github/go-mod/go-version/acouvreur/traefik-ondemand-service?style=flat-square">
<a href="https://github.com/acouvreur/traefik-ondemand-service/releases">
<img src="https://img.shields.io/github/release/acouvreur/traefik-ondemand-service/all.svg?style=flat-square">
</a>
<a href="https://github.com/acouvreur/traefik-ondemand-service/releases">
<img src="https://img.shields.io/docker/image-size/acouvreur/traefik-ondemand-service?style=flat-square">
</a>
</p>
```bash
docker run -d --name nginx nginx
docker stop nginx
docker run -v /var/run/docker.sock:/var/run/docker.sock -p 10000:10000 ghcr.io/acouvreur/sablier:latest --swarmode=false
curl 'http://localhost:10000/?name=nginx&timeout=1m'
```
## Plugins
## Features
- Support for Docker containers
- Support for Docker swarm mode, scale services
- Support for Kubernetes Deployments and Statefulsets
- Support for **Docker** containers
- Support for **Docker Swarm mode**, scale services
- Support for **Kubernetes** Deployments and Statefulsets
- Start your container/service on the first request
- Automatic **scale to zero** after configured timeout upon last request the service received
- Dynamic loading page (cloudflare or grafana cloud style)
- Automatic scale to zero after configured timeout upon last request the service received
- Support container/service healthcheck and will not redirect until service is healthy
- Customize dynamic and loading pages
## Usage
`docker run -v /var/run/docker.sock:/var/run/docker.sock -p 10000:10000 ghcr.io/acouvreur/sablier:latest --swarmode=true`
### CLI
`./traefik-ondemand-service --swarmMode=true --kubernetesMode=false`
`./sablier --swarmMode=true --kubernetesMode=false`
| Argument | Value | Description |
| ---------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
@@ -45,14 +37,14 @@
### Docker
- Docker Hub `acouvreur/traefik-ondemand-service`
- Ghcr `ghcr.io/acouvreur/traefik-ondemand-service`
- Docker Hub `acouvreur/sablier`
- Ghcr `ghcr.io/acouvreur/sablier`
`docker run -v /var/run/docker.sock:/var/run/docker.sock -p 10000:10000 ghcr.io/acouvreur/traefik-ondemand-service:latest --swarmode=true`
`docker run -v /var/run/docker.sock:/var/run/docker.sock -p 10000:10000 ghcr.io/acouvreur/sablier:latest --swarmode=true`
### Kubernetes
see <a href="https://github.com/acouvreur/traefik-ondemand-service/blob/main/KUBERNETES.md">KUBERNETES.md</a>
see <a href="https://github.com/acouvreur/sablier/blob/main/KUBERNETES.md">KUBERNETES.md</a>
### API

View File

@@ -1,8 +1,8 @@
version: "3.9"
services:
ondemand:
image: gchr.io/acouvreur/traefik-ondemand-service:latest
sablier:
image: gchr.io/acouvreur/sablier:latest
command:
- --swarmMode=true
volumes:

2
go.mod
View File

@@ -1,4 +1,4 @@
module github.com/acouvreur/traefik-ondemand-service
module github.com/acouvreur/sablier
go 1.18

View File

@@ -10,8 +10,8 @@ import (
"time"
"github.com/acouvreur/tinykv"
"github.com/acouvreur/traefik-ondemand-service/pkg/scaler"
"github.com/acouvreur/traefik-ondemand-service/pkg/storage"
"github.com/acouvreur/sablier/pkg/scaler"
"github.com/acouvreur/sablier/pkg/storage"
"github.com/docker/docker/client"
log "github.com/sirupsen/logrus"
"k8s.io/client-go/kubernetes"

View File

@@ -5,7 +5,7 @@ import (
"errors"
"testing"
"github.com/acouvreur/traefik-ondemand-service/pkg/scaler/mocks"
"github.com/acouvreur/sablier/pkg/scaler/mocks"
"github.com/docker/docker/api/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"

View File

@@ -126,7 +126,7 @@ func (scaler *DockerSwarmScaler) isServiceRunningFor(service *swarm.Service, dur
return false
}
// Getting 503 first time a workload is woken up https://github.com/acouvreur/traefik-ondemand-service/issues/24
// Getting 503 first time a workload is woken up https://github.com/acouvreur/sablier/issues/24
// Let the service be up for a given duration
for _, task := range tasks {
if time.Since(task.Status.Timestamp) < (time.Second * 5) {

View File

@@ -6,7 +6,7 @@ import (
"testing"
"time"
"github.com/acouvreur/traefik-ondemand-service/pkg/scaler/mocks"
"github.com/acouvreur/sablier/pkg/scaler/mocks"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/client"

View File

@@ -1,25 +0,0 @@
name: Build
on:
push:
pull_request:
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- name: Set up Go 1.17
uses: actions/setup-go@v2
with:
go-version: ^1.17
- name: Check out code into the Go module directory
uses: actions/checkout@v2
- name: Build
run: go build -v .
- name: Test
run: go test -v ./...

View File

@@ -1,26 +0,0 @@
name: Release
on:
push:
branches:
- main
- beta
jobs:
release:
name: Release
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v1
with:
node-version: '14.17'
- name: Release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: npx semantic-release

View File

@@ -1,201 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -1,33 +1,7 @@
# Traefik Ondemand Plugin
# Traefik Sablier Plugin
Traefik middleware to start containers on demand.
![Github Actions](https://img.shields.io/github/workflow/status/acouvreur/traefik-ondemand-plugin/Build?style=flat-square)
![Go Report](https://goreportcard.com/badge/github.com/acouvreur/traefik-ondemand-plugin?style=flat-square)
![Go Version](https://img.shields.io/github/go-mod/go-version/acouvreur/traefik-ondemand-plugin?style=flat-square)
![Latest Release](https://img.shields.io/github/release/acouvreur/traefik-ondemand-plugin/all.svg?style=flat-square)
- [Traefik Ondemand Plugin](#traefik-ondemand-plugin)
- [Features](#features)
- [Usage](#usage)
- [Plugin configuration](#plugin-configuration)
- [Strategies](#strategies)
- [Custom loading/error pages](#custom-loadingerror-pages)
- [Traefik-Ondemand-Service](#traefik-ondemand-service)
- [Examples](#examples)
- [Development](#development)
- [Authors](#authors)
## Features
- Support for **Docker** containers
- Support for **Docker swarm** mode, scale services
- Support for **Kubernetes** Deployments and Statefulsets
- Start your container/service on the first request
- Automatic **scale to zero** after configured timeout upon last request the service received
- Dynamic loading page (cloudflare or grafana cloud style)
- Customize dynamic and loading pages
![Demo](./img/ondemand.gif)
## Usage
@@ -42,8 +16,8 @@ _Serve an HTML page that self reload._
```yml
testData:
serviceUrl: http://ondemand:10000
name: TRAEFIK_HACKATHON_whoami
serviceUrl: http://sablier:10000
name: whoami
timeout: 1m
waitui: true
```
@@ -58,8 +32,8 @@ The timeout is set by `blockdelay`.
```yml
testData:
serviceUrl: http://ondemand:10000
name: TRAEFIK_HACKATHON_whoami
serviceUrl: http://sablier:10000
name: whoami
timeout: 1m
waitui: false
blockdelay: 1m
@@ -83,30 +57,30 @@ You must include `<meta http-equiv="refresh" content="5" />` inside your html pa
```yml
testData:
serviceUrl: http://ondemand:10000
name: TRAEFIK_HACKATHON_whoami
serviceUrl: http://sablier:10000
name: whoami
timeout: 1m
waitui: false
blockdelay: 1m
loadingpage: /etc/traefik/plugins/traefik-ondemand-plugin/custompages/loading.html
errorpage: /etc/traefik/plugins/traefik-ondemand-plugin/custompages/error.html
loadingpage: /etc/traefik/plugins/sablier/custompages/loading.html
errorpage: /etc/traefik/plugins/sablier/custompages/error.html
```
| Parameter | Type | Default | Required | Example | Description |
| ------------- | --------------- | ------- | -------- | ----------------------------------------------------------------------- | ------------------------------------------------------------------------------------- |
| `serviceUrl` | `string` | empty | yes | `http://ondemand:10000` | The docker container name, or the swarm service name |
| `name` | `string` | empty | yes (except if `names` is set) | `TRAEFIK_HACKATHON_whoami` | The container/service/kubernetes resource to be stopped (docker ps docker service ls) |
| `names` | `[]string` | [] | yes (except if `name` is set) | `[TRAEFIK_HACKATHON_whoami-1, TRAEFIK_HACKATHON_whoami-2]` | The containers/services to be stopped (docker ps docker service ls) |
| `serviceUrl` | `string` | empty | yes | `http://sablier:10000` | The docker container name, or the swarm service name |
| `name` | `string` | empty | yes (except if `names` is set) | `whoami` | The container/service/kubernetes resource to be stopped (docker ps docker service ls) |
| `names` | `[]string` | [] | yes (except if `name` is set) | `[whoami-1, whoami-2]` | The containers/services to be stopped (docker ps docker service ls) |
| `timeout` | `time.Duration` | `1m` | no | `1m30s` | The duration after which the container/service will be scaled down to 0 |
| `waitui` | `bool` | `true` | no | `true` | Serves a self-refreshing html page when the service is scaled down to 0 |
| `displayname` | `string` | `the middleware name` | no | `My App` | Serves a self-refreshing html page when the service is scaled down to 0 |
| `blockdelay` | `time.Duration` | `1m` | no | `1m30s` | When `waitui` is `false`, wait for the service to be scaled up before `blockdelay` |
| `loadingpage` | `string` | empty | no | `/etc/traefik/plugins/traefik-ondemand-plugin/custompages/loading.html` | The path in the traefik container for the **loading** page template |
| `errorpage` | `string` | empty | no | `/etc/traefik/plugins/traefik-ondemand-plugin/custompages/error.html` | The path in the traefik container for the **error** page template |
| `loadingpage` | `string` | empty | no | `/etc/traefik/plugins/sablier/custompages/loading.html` | The path in the traefik container for the **loading** page template |
| `errorpage` | `string` | empty | no | `/etc/traefik/plugins/sablier/custompages/error.html` | The path in the traefik container for the **error** page template |
### Traefik-Ondemand-Service
### sablier
The [traefik-ondemand-service](https://github.com/acouvreur/traefik-ondemand-service) must be used to bypass [Yaegi](https://github.com/traefik/yaegi) limitations.
The [sablier](https://github.com/acouvreur/sablier) must be used to bypass [Yaegi](https://github.com/traefik/yaegi) limitations.
Yaegi is the interpreter used by Traefik to load plugin and run them at runtime.
@@ -122,12 +96,4 @@ The docker library that interacts with the docker deamon uses `unsafe` which mus
## Development
`export TRAEFIK_PILOT_TOKEN=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`
`docker stack deploy -c docker-compose.yml TRAEFIK_HACKATHON`
## Authors
[Alexis Couvreur](https://www.linkedin.com/in/alexis-couvreur/) (left)
[Alexandre Hiltcher](https://www.linkedin.com/in/alexandre-hiltcher/) (middle)
[Matthias Schneider](https://www.linkedin.com/in/matthias-schneider-18831baa/) (right)
![Alexandre, Alexis and Matthias](./img/gophers-traefik.png)
`docker stack deploy -c docker-compose.yml DEV`

View File

@@ -10,7 +10,7 @@ services:
volumes:
- './traefik_dev.yml:/etc/traefik/traefik-template.yml'
- '/var/run/docker.sock:/var/run/docker.sock'
- '.:/plugins-local/src/github.com/acouvreur/traefik-ondemand-plugin'
- '.:/plugins-local/src/github.com/acouvreur/sablier/plugins/traefik'
environment:
- TRAEFIK_PILOT_TOKEN
deploy:
@@ -18,8 +18,8 @@ services:
- traefik.enable=true
- traefik.http.services.traefik.loadbalancer.server.port=8080
ondemand:
image: ghcr.io/acouvreur/traefik-ondemand-service:1.7
sablier:
image: ghcr.io/acouvreur/sablier:feature-merge-repositories
command:
- --swarmMode=true
volumes:
@@ -34,9 +34,9 @@ services:
# If you do not use the swarm load balancer, traefik will evict the service from its pool
# as soon as the service is 0/0. If you do not set that, fallback to dynamic-config.yml file usage.
- traefik.docker.lbswarm=true
- traefik.http.middlewares.ondemand_whoami.plugin.traefik-ondemand-plugin.name=TRAEFIK_HACKATHON_whoami
- traefik.http.middlewares.ondemand_whoami.plugin.traefik-ondemand-plugin.serviceurl=http://ondemand:10000
- traefik.http.middlewares.ondemand_whoami.plugin.traefik-ondemand-plugin.timeout=1m
- traefik.http.middlewares.ondemand_whoami.plugin.sablier.name=whoami
- traefik.http.middlewares.ondemand_whoami.plugin.sablier://sablier:10000
- traefik.http.middlewares.ondemand_whoami.plugin.sablier
- traefik.http.routers.whoami.middlewares=ondemand_whoami@docker
- traefik.http.routers.whoami.rule=PathPrefix(`/whoami`)
- traefik.http.services.whoami.loadbalancer.server.port=80
@@ -56,10 +56,10 @@ services:
# If you do not use the swarm load balancer, traefik will evict the service from its pool
# as soon as the service is 0/0. If you do not set that, fallback to dynamic-config.yml file usage.
- traefik.docker.lbswarm=true
- traefik.http.middlewares.ondemand_nginx.plugin.traefik-ondemand-plugin.name=TRAEFIK_HACKATHON_nginx
- traefik.http.middlewares.ondemand_nginx.plugin.traefik-ondemand-plugin.serviceurl=http://ondemand:10000
- traefik.http.middlewares.ondemand_nginx.plugin.traefik-ondemand-plugin.timeout=5m
- traefik.http.middlewares.ondemand_nginx.plugin.traefik-ondemand-plugin.waitui=false
- traefik.http.middlewares.ondemand_nginx.plugin.sablier.name=nginx
- traefik.http.middlewares.ondemand_nginx.plugin.sablier.serviceurl=http://sablier:10000
- traefik.http.middlewares.ondemand_nginx.plugin.sablier.timeout=5m
- traefik.http.middlewares.ondemand_nginx.plugin.sablier.waitui=false
- traefik.http.routers.nginx.middlewares=ondemand_nginx@docker
- traefik.http.routers.nginx.rule=PathPrefix(`/nginx`)
- traefik.http.services.nginx.loadbalancer.server.port=80

View File

@@ -2,8 +2,8 @@
## Run the demo
1. `git clone git@github.com:acouvreur/traefik-ondemand-plugin.git`
2. `cd traefik-ondemand-plugin/examples/docker_classic`
1. `git clone git@github.com:acouvreur/sablier.git`
2. `cd sablier/plugins/traefik/examples/docker_classic`
3. `export TRAEFIK_PILOT_TOKEN=...`
4. `docker-compose up`

View File

@@ -7,8 +7,8 @@ services:
- --api=true
- --api.insecure=true
- --pilot.token=$TRAEFIK_PILOT_TOKEN
- --experimental.plugins.traefik-ondemand-plugin.moduleName=github.com/acouvreur/traefik-ondemand-plugin
- --experimental.plugins.traefik-ondemand-plugin.version=v1.2.0
- --experimental.plugins.sablier.moduleName=github.com/acouvreur/sablier/plugins/traefik
- --experimental.plugins.sablier.version=v1.2.0
- --providers.docker=true
- --providers.file.filename=/etc/traefik/dynamic-config.yml
- --entrypoints.http.address=:80
@@ -23,17 +23,17 @@ services:
labels:
- traefik.enable=true
ondemand:
image: ghcr.io/acouvreur/traefik-ondemand-service:1
sablier:
image: ghcr.io/acouvreur/sablier:1
command:
- --swarmMode=false
volumes:
- '/var/run/docker.sock:/var/run/docker.sock'
labels:
- traefik.enable=true
- traefik.http.middlewares.ondemand.plugin.traefik-ondemand-plugin.name=docker_classic_whoami_1
- traefik.http.middlewares.ondemand.plugin.traefik-ondemand-plugin.serviceUrl=http://ondemand:10000
- traefik.http.middlewares.ondemand.plugin.traefik-ondemand-plugin.timeout=1m
- traefik.http.middlewares.ondemand.plugin.sablier.name=docker_classic_whoami_1
- traefik.http.middlewares.ondemand.plugin.sablier.serviceUrl=http://sablier:10000
- traefik.http.middlewares.ondemand.plugin.sablier.timeout=1m
- traefik.http.services.ondemand.loadbalancer.server.port=10000
whoami:

View File

@@ -2,8 +2,8 @@
## Run the demo
1. `git clone git@github.com:acouvreur/traefik-ondemand-plugin.git`
2. `cd traefik-ondemand-plugin/examples/docker_swarm`
1. `git clone git@github.com:acouvreur/sablier.git`
2. `cd sablier/plugins/traefik/examples/docker_swarm`
3. `docker swarm init`
4. `export TRAEFIK_PILOT_TOKEN=...`
5. `docker stack deploy -c docker-stack.yml DOCKER_SWARM`

View File

@@ -7,8 +7,8 @@ services:
- --api=true
- --api.insecure=true
- --pilot.token=$TRAEFIK_PILOT_TOKEN
- --experimental.plugins.traefik-ondemand-plugin.moduleName=github.com/acouvreur/traefik-ondemand-plugin
- --experimental.plugins.traefik-ondemand-plugin.version=v1.2.0
- --experimental.plugins.sablier.moduleName=github.com/acouvreur/sablier/plugins/traefik
- --experimental.plugins.sablier.version=v1.2.0
- --providers.docker=true
- --providers.docker.swarmmode=true
- --providers.file.filename=/etc/traefik/dynamic-config.yml
@@ -21,8 +21,8 @@ services:
volumes:
- '/var/run/docker.sock:/var/run/docker.sock'
ondemand:
image: ghcr.io/acouvreur/traefik-ondemand-service:1
sablier:
image: ghcr.io/acouvreur/sablier:1
command:
- --swarmMode=true
volumes:
@@ -30,9 +30,9 @@ services:
deploy:
labels:
- traefik.enable=true
- traefik.http.middlewares.ondemand.plugin.traefik-ondemand-plugin.name=DOCKER_SWARM_nginx
- traefik.http.middlewares.ondemand.plugin.traefik-ondemand-plugin.serviceUrl=http://ondemand:10000
- traefik.http.middlewares.ondemand.plugin.traefik-ondemand-plugin.timeout=1m
- traefik.http.middlewares.ondemand.plugin.sablier.name=DOCKER_SWARM_nginx
- traefik.http.middlewares.ondemand.plugin.sablier.serviceUrl=http://sablier:10000
- traefik.http.middlewares.ondemand.plugin.sablier.timeout=1m
- traefik.http.services.ondemand.loadbalancer.server.port=10000
nginx:

View File

@@ -4,8 +4,8 @@
# you need docker-compose, kubectl and helm (v3) installed
1. `git clone git@github.com:acouvreur/traefik-ondemand-plugin.git`
2. `cd traefik-ondemand-plugin/examples/kubernetes`
1. `git clone git@github.com:acouvreur/sablier.git`
2. `cd sablier/plugins/traefik/examples/kubernetes`
3. `docker-compose up`
4. Wait 1 minute
5. `export KUBECONFIG=./kubeconfig.yaml`

View File

@@ -1,25 +1,25 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: traefik-ondemand-service
name: sablier
namespace: kube-system
labels:
app: traefik-ondemand-service
app: sablier
spec:
replicas: 1
selector:
matchLabels:
app: traefik-ondemand-service
app: sablier
template:
metadata:
labels:
app: traefik-ondemand-service
app: sablier
spec:
serviceAccountName: traefik-ondemand-service
serviceAccount: traefik-ondemand-service
serviceAccountName: sablier
serviceAccount: sablier
containers:
- name: traefik-ondemand-service
image: ghcr.io/acouvreur/traefik-ondemand-service:1
- name: sablier
image: ghcr.io/acouvreur/sablier:1
args: ["--swarmMode=false", "--kubernetesMode=true"]
ports:
- containerPort: 10000
@@ -27,11 +27,11 @@ spec:
apiVersion: v1
kind: Service
metadata:
name: traefik-ondemand-service
name: sablier
namespace: kube-system
spec:
selector:
app: traefik-ondemand-service
app: sablier
ports:
- protocol: TCP
port: 10000
@@ -40,13 +40,13 @@ spec:
apiVersion: v1
kind: ServiceAccount
metadata:
name: traefik-ondemand-service
name: sablier
namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: traefik-ondemand-service
name: sablier
namespace: kube-system
rules:
- apiGroups:
@@ -62,15 +62,15 @@ rules:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: traefik-ondemand-service
name: sablier
namespace: kube-system
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: traefik-ondemand-service
name: sablier
subjects:
- kind: ServiceAccount
name: traefik-ondemand-service
name: sablier
namespace: kube-system
---
apiVersion: traefik.containo.us/v1alpha1
@@ -80,7 +80,7 @@ metadata:
namespace: default
spec:
plugin:
traefik-ondemand-plugin:
sablier:
name: deployment_default_whoami_1
serviceUrl: 'http://traefik-ondemand-service:10000'
serviceUrl: 'http://sablier:10000'
timeout: 1m

View File

@@ -1,8 +1,8 @@
# traefik helm values
additionalArguments:
- "--pilot.token=XXXXX_YOURTOKEN_XXXXXXXXXXXXXXXX"
- "--experimental.plugins.traefik-ondemand-plugin.modulename=github.com/acouvreur/traefik-ondemand-plugin"
- "--experimental.plugins.traefik-ondemand-plugin.version=v1.2.0"
- "--experimental.plugins.sablier.modulename=github.com/acouvreur/sablier/plugins/traefik"
- "--experimental.plugins.sablier.version=v1.2.0"
- "--providers.kubernetesingress.allowEmptyServices=true"
experimental:

View File

@@ -2,8 +2,8 @@
## Run the demo
1. `git clone git@github.com:acouvreur/traefik-ondemand-plugin.git`
2. `cd traefik-ondemand-plugin/examples/multiple_containers`
1. `git clone git@github.com:acouvreur/sablier.git`
2. `cd sablier/plugins/traefik/examples/multiple_containers`
3. `docker swarm init`
4. `export TRAEFIK_PILOT_TOKEN=...`
5. `docker stack deploy -c docker-stack.yml DOCKER_SWARM`
@@ -21,4 +21,4 @@ Due to Traefik plugin, the interface is to provide a config and a `ServeHTTP` re
This function has no access to the Traefik configuration, thus no way to determine the container/service associated to the request.
See https://github.com/acouvreur/traefik-ondemand-plugin/issues/8#issuecomment-931940533.
See https://github.com/acouvreur/sablier/issues/8#issuecomment-931940533.

View File

@@ -7,8 +7,8 @@ services:
- --api=true
- --api.insecure=true
- --pilot.token=$TRAEFIK_PILOT_TOKEN
- --experimental.plugins.traefik-ondemand-plugin.moduleName=github.com/acouvreur/traefik-ondemand-plugin
- --experimental.plugins.traefik-ondemand-plugin.version=v1.2.0
- --experimental.plugins.sablier.moduleName=github.com/acouvreur/sablier/plugins/traefik
- --experimental.plugins.sablier.version=v1.2.0
- --providers.docker=true
- --providers.docker.swarmmode=true
- --providers.file.filename=/etc/traefik/dynamic-config.yml
@@ -21,8 +21,8 @@ services:
volumes:
- '/var/run/docker.sock:/var/run/docker.sock'
ondemand:
image: ghcr.io/acouvreur/traefik-ondemand-service:1
sablier:
image: ghcr.io/acouvreur/sablier:1
command:
- --swarmMode=true
volumes:
@@ -30,12 +30,12 @@ services:
deploy:
labels:
- traefik.enable=true
- traefik.http.middlewares.ondemand-nginx.plugin.traefik-ondemand-plugin.name=DOCKER_SWARM_nginx
- traefik.http.middlewares.ondemand-nginx.plugin.traefik-ondemand-plugin.serviceUrl=http://ondemand:10000
- traefik.http.middlewares.ondemand-nginx.plugin.traefik-ondemand-plugin.timeout=5m
- traefik.http.middlewares.ondemand-whoami.plugin.traefik-ondemand-plugin.name=DOCKER_SWARM_whoami
- traefik.http.middlewares.ondemand-whoami.plugin.traefik-ondemand-plugin.serviceUrl=http://ondemand:10000
- traefik.http.middlewares.ondemand-whoami.plugin.traefik-ondemand-plugin.timeout=1m
- traefik.http.middlewares.ondemand-nginx.plugin.sablier.name=DOCKER_SWARM_nginx
- traefik.http.middlewares.ondemand-nginx.plugin.sablier.serviceUrl=http://sablier:10000
- traefik.http.middlewares.ondemand-nginx.plugin.sablier.timeout=5m
- traefik.http.middlewares.ondemand-whoami.plugin.sablier.name=DOCKER_SWARM_whoami
- traefik.http.middlewares.ondemand-whoami.plugin.sablier.serviceUrl=http://sablier:10000
- traefik.http.middlewares.ondemand-whoami.plugin.sablier.timeout=1m
- traefik.http.services.ondemand.loadbalancer.server.port=10000
nginx:

View File

@@ -1,6 +1,6 @@
module github.com/acouvreur/traefik-ondemand-plugin
module github.com/acouvreur/sablier/plugins/traefik
go 1.17
go 1.18
require github.com/stretchr/testify v1.6.1

Binary file not shown.

Before

Width:  |  Height:  |  Size: 184 KiB

View File

@@ -1,4 +1,4 @@
package traefik_ondemand_plugin
package traefik
import (
"context"
@@ -6,7 +6,7 @@ import (
"net/http"
"time"
"github.com/acouvreur/traefik-ondemand-plugin/pkg/strategy"
"github.com/acouvreur/sablier/plugins/traefik/pkg/strategy"
)
// Config the plugin configuration

View File

@@ -1,4 +1,4 @@
package traefik_ondemand_plugin
package traefik
import (
"context"

View File

@@ -164,8 +164,8 @@ var errorPage = `<!doctype html>
</section>
<footer class="footer text">
<a href="https://github.com/acouvreur/traefik-ondemand-plugin"
target="_blank">acouvreur/traefik-ondemand-plugin</a>
<a href="https://github.com/acouvreur/sablier"
target="_blank">acouvreur/sablier</a>
</footer>
</body>

View File

@@ -156,8 +156,8 @@
</section>
<footer class="footer text">
<a href="https://github.com/acouvreur/traefik-ondemand-plugin"
target="_blank">acouvreur/traefik-ondemand-plugin</a>
<a href="https://github.com/acouvreur/sablier"
target="_blank">acouvreur/sablier</a>
</footer>
</body>

View File

@@ -240,8 +240,8 @@ var loadingPage = `<!doctype html>
</section>
<footer class="footer text">
<a href="https://github.com/acouvreur/traefik-ondemand-plugin"
target="_blank">acouvreur/traefik-ondemand-plugin</a>
<a href="https://github.com/acouvreur/sablier"
target="_blank">acouvreur/sablier</a>
</footer>
</body>

View File

@@ -228,8 +228,8 @@
</section>
<footer class="footer text">
<a href="https://github.com/acouvreur/traefik-ondemand-plugin"
target="_blank">acouvreur/traefik-ondemand-plugin</a>
<a href="https://github.com/acouvreur/sablier"
target="_blank">acouvreur/sablier</a>
</footer>
</body>

View File

@@ -5,7 +5,7 @@ import (
"net/http"
"time"
"github.com/acouvreur/traefik-ondemand-plugin/pkg/pages"
"github.com/acouvreur/sablier/plugins/traefik/pkg/pages"
)
type DynamicStrategy struct {

View File

@@ -1,11 +0,0 @@
module.exports = {
"branches": [
{ "name": "main" },
{ "name": "beta", "channel": "beta", "prerelease": "beta" },
],
"plugins": [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
"@semantic-release/github"
]
}

View File

@@ -7,8 +7,8 @@ api:
experimental:
plugins:
traefik-ondemand-plugin:
moduleName: "github.com/acouvreur/traefik-ondemand-plugin"
sablier:
moduleName: "github.com/acouvreur/sablier/plugins/traefik"
version: "v0.1.1"
entryPoints:

View File

@@ -7,8 +7,8 @@ api:
experimental:
localPlugins:
traefik-ondemand-plugin:
moduleName: github.com/acouvreur/traefik-ondemand-plugin
sablier:
moduleName: github.com/acouvreur/sablier/plugins/traefik
entryPoints:
http:

View File

@@ -11,7 +11,7 @@ module.exports = {
}],
["@semantic-release/github", {
"assets": [
"traefik-ondemand-service*"
"sablier*"
]
}]
]