Compare commits

...

14 Commits

Author SHA1 Message Date
vfebvre e1d9acb980 fix[README]: Added --role writer in token authentication creation
Cadoles/bouncer/pipeline/pr-develop Build started... Details
2024-03-26 14:04:07 +01:00
vfebvre f8be2c08d6 fix[README]: add identifier generation step 2024-03-26 14:04:07 +01:00
wpetit bc7422a50c feat: add configurable redis timeouts 2024-03-26 14:04:07 +01:00
wpetit 9d32551ec5 feat: generalize siege task 2024-03-26 14:04:07 +01:00
wpetit ded6d179c1 fix(k8s): redis configuration 2024-03-26 14:04:07 +01:00
Philippe Caseiro 6f4ee0ebd1 fix(skaffold): adding port-forward for testing 2024-03-26 14:04:07 +01:00
Philippe Caseiro 1375c9b317 fup 2024-03-26 14:04:05 +01:00
Philippe Caseiro 53a0d26a47 feat(pkg): adding archlinux package to gorelease 2024-03-26 13:49:58 +01:00
Philippe Caseiro 87354ef0d4 fix(doc): test command was incorrect 2024-03-26 13:49:58 +01:00
Philippe Caseiro 8560041598 fix(kustomization): adding correct labels to deployments 2024-03-26 13:49:58 +01:00
Philippe Caseiro 0611cc9f70 feat(k8s): adding kubernetes support
Now we can use skaffold and deploy bouncer in a kubernetes cluster

ref #10
2024-03-26 13:49:58 +01:00
wpetit 734ed64e8e feat: add basic k6 load testing script
Cadoles/bouncer/pipeline/head This commit looks good Details
2024-03-25 15:40:25 +01:00
wpetit c8fc143efa doc: add prometheus metrics documentation
Cadoles/bouncer/pipeline/head This commit looks good Details
2024-02-21 12:29:03 +01:00
wpetit f91c14e5d4 feat(admin): print default writer token to logs by default
Cadoles/bouncer/pipeline/head This commit looks good Details
2024-02-21 11:09:34 +01:00
38 changed files with 904 additions and 311 deletions

3
.gitignore vendored
View File

@ -7,4 +7,5 @@
/admin-key.json /admin-key.json
/.bouncer-token /.bouncer-token
/data /data
/out /out
.dockerconfigjson

View File

@ -1,37 +1,37 @@
project_name: bouncer project_name: bouncer
before: before:
hooks: hooks:
- go mod tidy - go mod tidy
- go generate ./... - go generate ./...
builds: builds:
- id: bouncer - id: bouncer
env: env:
- CGO_ENABLED=0 - CGO_ENABLED=0
ldflags: ldflags:
- -s - -s
- -w - -w
- -X 'main.GitRef={{ .Commit }}' - -X 'main.GitRef={{ .Commit }}'
- -X 'main.ProjectVersion={{ .Version }}' - -X 'main.ProjectVersion={{ .Version }}'
- -X 'main.BuildDate={{ .Date }}' - -X 'main.BuildDate={{ .Date }}'
- -X 'main.DefaultConfigPath=/etc/bouncer/config.yml' - -X 'main.DefaultConfigPath=/etc/bouncer/config.yml'
gcflags: gcflags:
- -trimpath="${PWD}" - -trimpath="${PWD}"
asmflags: asmflags:
- -trimpath="${PWD}" - -trimpath="${PWD}"
goos: goos:
- linux - linux
goarch: goarch:
- amd64 - amd64
- arm64 - arm64
- "386" - "386"
main: ./cmd/bouncer main: ./cmd/bouncer
archives: archives:
- id: bouncer - id: bouncer
builds: ["bouncer"] builds: ["bouncer"]
name_template: '{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ with .Arm }}v{{ . }}{{ end }}{{ with .Mips }}_{{ . }}{{ end }}{{ if not (eq .Amd64 "v1") }}{{ .Amd64 }}{{ end }}' name_template: '{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ with .Arm }}v{{ . }}{{ end }}{{ with .Mips }}_{{ . }}{{ end }}{{ if not (eq .Amd64 "v1") }}{{ .Amd64 }}{{ end }}'
files: files:
- README.md - README.md
- misc/packaging/common/config.yml - misc/packaging/common/config.yml
checksum: checksum:
name_template: 'checksums.txt' name_template: 'checksums.txt'
snapshot: snapshot:
@ -40,100 +40,109 @@ changelog:
sort: asc sort: asc
filters: filters:
exclude: exclude:
- '^docs:' - '^docs:'
- '^test:' - '^test:'
nfpms: nfpms:
- id: bouncer-bin - id: bouncer-bin
builds: builds:
- "bouncer" - "bouncer"
package_name: bouncer-bin package_name: bouncer-bin
homepage: https://forge.cadoles.com/Cadoles/bouncer homepage: https://forge.cadoles.com/Cadoles/bouncer
maintainer: Cadoles <contact@cadoles.com> maintainer: Cadoles <contact@cadoles.com>
description: |- description: |-
reverse proxy server with dynamic queuing management - binaries reverse proxy server with dynamic queuing management - binaries
license: AGPL-3.0 license: AGPL-3.0
formats: formats:
- apk - apk
- deb - deb
- rpm - rpm
contents: - archlinux
- src: misc/packaging/common/config.yml contents:
dst: /etc/bouncer/config.yml - src: misc/packaging/common/config.yml
type: config dst: /etc/bouncer/config.yml
- src: layers type: config
dst: /etc/bouncer/layers - src: layers
type: config dst: /etc/bouncer/layers
- id: bouncer-admin type: config
meta: true - id: bouncer-admin
package_name: bouncer-admin meta: true
homepage: https://forge.cadoles.com/Cadoles/bouncer package_name: bouncer-admin
maintainer: Cadoles <contact@cadoles.com> homepage: https://forge.cadoles.com/Cadoles/bouncer
dependencies: maintainer: Cadoles <contact@cadoles.com>
- bouncer-bin dependencies:
description: |- - bouncer-bin
reverse proxy server with dynamic queuing management - administration service description: |-
license: AGPL-3.0 reverse proxy server with dynamic queuing management - administration service
formats: license: AGPL-3.0
- apk formats:
- deb - apk
- rpm - deb
contents: - rpm
- src: misc/packaging/systemd/bouncer-admin.systemd.service - archlinux
dst: /usr/lib/systemd/system/bouncer-admin.service contents:
packager: deb - src: misc/packaging/systemd/bouncer-admin.systemd.service
- src: misc/packaging/systemd/bouncer-admin.systemd.service dst: /usr/lib/systemd/system/bouncer-admin.service
dst: /usr/lib/systemd/system/bouncer-admin.service packager: deb
packager: rpm - src: misc/packaging/systemd/bouncer-admin.systemd.service
- src: misc/packaging/openrc/bouncer-admin.openrc.sh dst: /usr/lib/systemd/system/bouncer-admin.service
dst: /etc/init.d/bouncer-admin packager: rpm
file_info: - src: misc/packaging/systemd/bouncer-admin.systemd.service
mode: 0755 dst: /usr/lib/systemd/system/bouncer-admin.service
packager: apk packager: archlinux
- dst: /usr/share/bouncer - src: misc/packaging/openrc/bouncer-admin.openrc.sh
type: dir dst: /etc/init.d/bouncer-admin
file_info: file_info:
mode: 0700 mode: 0755
- dst: /var/log/bouncer packager: apk
type: dir - dst: /usr/share/bouncer
file_info: type: dir
mode: 0700 file_info:
packager: apk mode: 0700
scripts: - dst: /var/log/bouncer
postinstall: "misc/packaging/common/postinstall-bouncer-admin.sh" type: dir
- id: bouncer-proxy file_info:
meta: true mode: 0700
dependencies: packager: apk
- bouncer-bin scripts:
package_name: bouncer-proxy postinstall: "misc/packaging/common/postinstall-bouncer-admin.sh"
homepage: https://forge.cadoles.com/Cadoles/bouncer - id: bouncer-proxy
maintainer: Cadoles <contact@cadoles.com> meta: true
description: |- dependencies:
reverse proxy server with dynamic queuing management - proxy service - bouncer-bin
license: AGPL-3.0 package_name: bouncer-proxy
formats: homepage: https://forge.cadoles.com/Cadoles/bouncer
- apk maintainer: Cadoles <contact@cadoles.com>
- deb description: |-
- rpm reverse proxy server with dynamic queuing management - proxy service
contents: license: AGPL-3.0
- src: misc/packaging/systemd/bouncer-proxy.systemd.service formats:
dst: /usr/lib/systemd/system/bouncer-proxy.service - apk
packager: deb - deb
- src: misc/packaging/systemd/bouncer-proxy.systemd.service - rpm
dst: /usr/lib/systemd/system/bouncer-proxy.service - archlinux
packager: rpm contents:
- src: misc/packaging/openrc/bouncer-proxy.openrc.sh - src: misc/packaging/systemd/bouncer-proxy.systemd.service
dst: /etc/init.d/bouncer-proxy dst: /usr/lib/systemd/system/bouncer-proxy.service
file_info: packager: deb
mode: 0755 - src: misc/packaging/systemd/bouncer-proxy.systemd.service
packager: apk dst: /usr/lib/systemd/system/bouncer-proxy.service
- dst: /usr/share/bouncer packager: rpm
type: dir - src: misc/packaging/systemd/bouncer-proxy.systemd.service
file_info: dst: /usr/lib/systemd/system/bouncer-proxy.service
mode: 0700 packager: archlinux
- dst: /var/log/bouncer - src: misc/packaging/openrc/bouncer-proxy.openrc.sh
type: dir dst: /etc/init.d/bouncer-proxy
file_info: file_info:
mode: 0700 mode: 0755
packager: apk packager: apk
scripts: - dst: /usr/share/bouncer
postinstall: "misc/packaging/common/postinstall-bouncer-proxy.sh" type: dir
file_info:
mode: 0700
- dst: /var/log/bouncer
type: dir
file_info:
mode: 0700
packager: apk
scripts:
postinstall: "misc/packaging/common/postinstall-bouncer-proxy.sh"

View File

@ -16,6 +16,9 @@ GOTEST_ARGS ?= -short
OPENWRT_DEVICE ?= 192.168.1.1 OPENWRT_DEVICE ?= 192.168.1.1
SIEGE_URLS_FILE ?= misc/siege/urls.txt
SIEGE_CONCURRENCY ?= 100
watch: tools/modd/bin/modd deps ## Watching updated files - live reload watch: tools/modd/bin/modd deps ## Watching updated files - live reload
( set -o allexport && source .env && set +o allexport && tools/modd/bin/modd ) ( set -o allexport && source .env && set +o allexport && tools/modd/bin/modd )
@ -105,7 +108,10 @@ grafterm: tools/grafterm/bin/grafterm
tools/grafterm/bin/grafterm -c ./misc/grafterm/dashboard.json -v job=bouncer-proxy -r 5s tools/grafterm/bin/grafterm -c ./misc/grafterm/dashboard.json -v job=bouncer-proxy -r 5s
siege: siege:
siege -i -c 100 -f ./misc/siege/urls.txt $(eval TMP := $(shell mktemp))
cat $(SIEGE_URLS_FILE) | envsubst > $(TMP)
siege -i -b -c $(SIEGE_CONCURRENCY) -f $(TMP)
rm -rf $(TMP)
tools/gitea-release/bin/gitea-release.sh: tools/gitea-release/bin/gitea-release.sh:
mkdir -p tools/gitea-release/bin mkdir -p tools/gitea-release/bin

View File

@ -6,9 +6,11 @@
## Exemples ## Exemples
- [(FR) - Exemple de déploiement multi-noeuds](../misc/docker-compose/README.md) - [(FR) - Exemple de déploiement multi-noeuds](../misc/docker-compose/README.md)
## Référence ## Référence
- [(FR) - Layers](./fr/references/layers/README.md) - [(FR) - Layers](./fr/references/layers/README.md)
- [(FR) - Métriques](./fr/references/metrics.md)
- [(FR) - Fichier de configuration](../misc/packaging/common/config.yml) - [(FR) - Fichier de configuration](../misc/packaging/common/config.yml)
- [(FR) - API d'administration](./fr/references/admin_api.md) - [(FR) - API d'administration](./fr/references/admin_api.md)

View File

@ -41,7 +41,7 @@
5. Tester que le CLI est en capacité d'interroger l'API d'administration 5. Tester que le CLI est en capacité d'interroger l'API d'administration
```bash ```bash
bouncer admin query proxy bouncer admin proxy query
``` ```
Un message équivalent à celui ci devrait s'afficher: Un message équivalent à celui ci devrait s'afficher:
@ -92,4 +92,4 @@
3. Ouvrir la page `https://<ip_serveur>:8080/` dans un navigateur. Le site Cadoles s'affiche ! 3. Ouvrir la page `https://<ip_serveur>:8080/` dans un navigateur. Le site Cadoles s'affiche !
**Bravo, vous avez créé votre premier proxy avec Bouncer !** **Bravo, vous avez créé votre premier proxy avec Bouncer !**

View File

@ -32,6 +32,10 @@ Ce layer permet de bloquer l'accès à un site (ou une section de celui ci) cibl
Voir le [fichier de configuration de référence](../../../../misc/packaging/common/config.yml), section `layers.circuitbreaker` pour voir les options permettant de personnaliser le chemin du répertoire contenant les templates. Voir le [fichier de configuration de référence](../../../../misc/packaging/common/config.yml), section `layers.circuitbreaker` pour voir les options permettant de personnaliser le chemin du répertoire contenant les templates.
### Schéma ## Schéma
Voir le [schéma JSON](../../../../internal/proxy/director/layer/circuitbreaker/layer-options.json). Voir le [schéma JSON](../../../../internal/proxy/director/layer/circuitbreaker/layer-options.json).
## Métriques
_Aucune [métrique Prometheus](../metrics.md) n'est exportée par ce layer._

View File

@ -30,6 +30,34 @@ Ce layer permet d'ajouter un mécanisme de file d'attente dynamique au proxy ass
Par exemple, si vous souhaitez limiter votre file à l'ensemble d'une section "`/blog`" d'un site, vous pouvez déclarer la valeur `["*/blog*"]`. Les autres URLs du site ne seront pas affectées par cette file d'attente. Par exemple, si vous souhaitez limiter votre file à l'ensemble d'une section "`/blog`" d'un site, vous pouvez déclarer la valeur `["*/blog*"]`. Les autres URLs du site ne seront pas affectées par cette file d'attente.
### Schéma ## Schéma
Voir le [schéma JSON](../../../../internal/proxy/director/layer/queue/schema/layer-options.json). Voir le [schéma JSON](../../../../internal/proxy/director/layer/queue/schema/layer-options.json).
## Métriques
Les [métriques Prometheus](../metrics.md) suivantes sont exposées par ce layer.
### `bouncer_layer_queue_capacity{layer=<layerName>,proxy=<proxyName>}`
- **Type:** `gauge`
- **Description**: Capacité maximale de la queue
- **Exemple**
```
# HELP bouncer_layer_queue_capacity Bouncer's queue layer capacity
# TYPE bouncer_layer_queue_capacity gauge
bouncer_layer_queue_capacity{layer="queue",proxy="cadoles"} 2
```
### `bouncer_layer_queue_sessions{layer=<layerName>,proxy=<proxyName>}`
- **Type:** `gauge`
- **Description**: Nombre courant de sessions ouvertes
- **Exemple**
```
# HELP bouncer_layer_queue_sessions Bouncer's queue layer current sessions
# TYPE bouncer_layer_queue_sessions gauge
bouncer_layer_queue_sessions{layer="queue",proxy="cadoles"} 3
```

View File

@ -0,0 +1,29 @@
# Métriques
Bouncer expose un certain nombre de métriques Prometheus sur le serveur proxy ainsi que sur le serveur d'administration. Ces métriques sont par défaut accessibles sur `/.bouncer/metrics`.
Il est possible de configurer le point d'entrée de ces métriques ainsi que d'ajouter une authentification de type `Basic Auth` [via la configuration](../../../misc/packaging/common/config.yml) (voir les clés `admin.metrics` et `proxy.metrics`).
Outre les métriques par défaut fournies par la librairie [Prometheus](https://prometheus.io/docs/guides/go-application/#instrumenting-a-go-application-for-prometheus), les serveurs Bouncer exposent également des métriques propres.
Chaque layer associé à un proxy peut également ses propres métriques spécifiques. [Voir la page de documentation](./layers/README.md) de chaque layer pour plus d'informations.
## Métriques spécifiques
### Serveur proxy
#### `bouncer_proxy_director_proxy_requests_total{proxy=<proxyName>}`
- **Type:** `counter`
- **Description**: Nombre total de requêtes ayant transité par le proxy
- **Exemple**
```
# HELP bouncer_proxy_director_proxy_requests_total Bouncer proxy total requests
# TYPE bouncer_proxy_director_proxy_requests_total counter
bouncer_proxy_director_proxy_requests_total{proxy="cadoles"} 64
```
### Serveur d'administration
_Pas de métrique supplémentaire._

View File

@ -5,15 +5,28 @@ import (
"strings" "strings"
"forge.cadoles.com/cadoles/bouncer/internal/admin" "forge.cadoles.com/cadoles/bouncer/internal/admin"
"forge.cadoles.com/cadoles/bouncer/internal/auth/jwt"
"forge.cadoles.com/cadoles/bouncer/internal/command/common" "forge.cadoles.com/cadoles/bouncer/internal/command/common"
"forge.cadoles.com/cadoles/bouncer/internal/jwk"
"forge.cadoles.com/cadoles/bouncer/internal/setup" "forge.cadoles.com/cadoles/bouncer/internal/setup"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"gitlab.com/wpetit/goweb/logger" "gitlab.com/wpetit/goweb/logger"
) )
const (
flagPrintDefaultToken = "print-default-token"
)
func RunCommand() *cli.Command { func RunCommand() *cli.Command {
flags := common.Flags() flags := append(
common.Flags(),
&cli.BoolFlag{
Name: flagPrintDefaultToken,
Usage: "Generate and print a default writer token in console at startup",
Value: true,
},
)
return &cli.Command{ return &cli.Command{
Name: "run", Name: "run",
@ -36,6 +49,22 @@ func RunCommand() *cli.Command {
defer flushSentry() defer flushSentry()
if printDefaultToken := ctx.Bool(flagPrintDefaultToken); printDefaultToken {
key, err := jwk.Generate(jwk.DefaultKeySize)
if err != nil {
return errors.Wrap(err, "could not generate default key")
}
token, err := jwt.GenerateToken(ctx.Context, key, string(conf.Admin.Auth.Issuer), "default-admin", jwt.Role(jwt.RoleWriter))
if err != nil {
return errors.WithStack(err)
}
logger.SetLevel(logger.LevelInfo)
logger.Info(ctx.Context, "default writer token", logger.F("token", token))
logger.SetLevel(logger.Level(conf.Logger.Level))
}
srv := admin.NewServer( srv := admin.NewServer(
admin.WithServerConfig(conf.Admin), admin.WithServerConfig(conf.Admin),
admin.WithRedisConfig(conf.Redis), admin.WithRedisConfig(conf.Redis),

View File

@ -1,5 +1,7 @@
package config package config
import "time"
const ( const (
RedisModeSimple = "simple" RedisModeSimple = "simple"
RedisModeSentinel = "sentinel" RedisModeSentinel = "sentinel"
@ -7,13 +9,19 @@ const (
) )
type RedisConfig struct { type RedisConfig struct {
Adresses InterpolatedStringSlice `yaml:"addresses"` Adresses InterpolatedStringSlice `yaml:"addresses"`
Master InterpolatedString `yaml:"master"` Master InterpolatedString `yaml:"master"`
ReadTimeout InterpolatedDuration `yaml:"readTimeout"`
WriteTimeout InterpolatedDuration `yaml:"writeTimeout"`
DialTimeout InterpolatedDuration `yaml:"dialTimeout"`
} }
func NewDefaultRedisConfig() RedisConfig { func NewDefaultRedisConfig() RedisConfig {
return RedisConfig{ return RedisConfig{
Adresses: InterpolatedStringSlice{"localhost:6379"}, Adresses: InterpolatedStringSlice{"localhost:6379"},
Master: "", Master: "",
ReadTimeout: InterpolatedDuration(30 * time.Second),
WriteTimeout: InterpolatedDuration(30 * time.Second),
DialTimeout: InterpolatedDuration(30 * time.Second),
} }
} }

View File

@ -4,7 +4,6 @@ import (
"crypto/rand" "crypto/rand"
"crypto/rsa" "crypto/rsa"
"encoding/json" "encoding/json"
"io/ioutil"
"os" "os"
"github.com/btcsuite/btcd/btcutil/base58" "github.com/btcsuite/btcd/btcutil/base58"
@ -56,7 +55,7 @@ func PublicKeySet(keys ...jwk.Key) (jwk.Set, error) {
} }
func LoadOrGenerate(path string, size int) (jwk.Key, error) { func LoadOrGenerate(path string, size int) (jwk.Key, error) {
data, err := ioutil.ReadFile(path) data, err := os.ReadFile(path)
if err != nil && !errors.Is(err, os.ErrNotExist) { if err != nil && !errors.Is(err, os.ErrNotExist) {
return nil, errors.WithStack(err) return nil, errors.WithStack(err)
} }
@ -72,7 +71,7 @@ func LoadOrGenerate(path string, size int) (jwk.Key, error) {
return nil, errors.WithStack(err) return nil, errors.WithStack(err)
} }
if err := ioutil.WriteFile(path, data, 0o640); err != nil { if err := os.WriteFile(path, data, 0o640); err != nil {
return nil, errors.WithStack(err) return nil, errors.WithStack(err)
} }
} }

View File

@ -10,11 +10,7 @@ import (
) )
func NewProxyRepository(ctx context.Context, conf config.RedisConfig) (store.ProxyRepository, error) { func NewProxyRepository(ctx context.Context, conf config.RedisConfig) (store.ProxyRepository, error) {
rdb := redis.NewUniversalClient(&redis.UniversalOptions{ rdb := newRedisClient(conf)
Addrs: conf.Adresses,
MasterName: string(conf.Master),
})
return redisStore.NewProxyRepository(rdb), nil return redisStore.NewProxyRepository(rdb), nil
} }

View File

@ -8,7 +8,6 @@ import (
"forge.cadoles.com/cadoles/bouncer/internal/proxy/director/layer/queue" "forge.cadoles.com/cadoles/bouncer/internal/proxy/director/layer/queue"
queueRedis "forge.cadoles.com/cadoles/bouncer/internal/proxy/director/layer/queue/redis" queueRedis "forge.cadoles.com/cadoles/bouncer/internal/proxy/director/layer/queue/redis"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/redis/go-redis/v9"
) )
func init() { func init() {
@ -36,10 +35,6 @@ func setupQueueLayer(conf *config.Config) (director.Layer, error) {
} }
func newQueueAdapter(redisConf config.RedisConfig) (queue.Adapter, error) { func newQueueAdapter(redisConf config.RedisConfig) (queue.Adapter, error) {
rdb := redis.NewUniversalClient(&redis.UniversalOptions{ rdb := newRedisClient(redisConf)
Addrs: redisConf.Adresses,
MasterName: string(redisConf.Master),
})
return queueRedis.NewAdapter(rdb, 2), nil return queueRedis.NewAdapter(rdb, 2), nil
} }

20
internal/setup/redis.go Normal file
View File

@ -0,0 +1,20 @@
package setup
import (
"time"
"forge.cadoles.com/cadoles/bouncer/internal/config"
"github.com/redis/go-redis/v9"
)
func newRedisClient(conf config.RedisConfig) redis.UniversalClient {
return redis.NewUniversalClient(&redis.UniversalOptions{
Addrs: conf.Adresses,
MasterName: string(conf.Master),
ReadTimeout: time.Duration(conf.ReadTimeout),
WriteTimeout: time.Duration(conf.WriteTimeout),
DialTimeout: time.Duration(conf.DialTimeout),
RouteByLatency: true,
ContextTimeoutEnabled: true,
})
}

View File

@ -0,0 +1,49 @@
FROM golang:1.20 AS BUILD
RUN apt-get update \
&& apt-get install -y make
ARG YQ_VERSION=4.34.1
RUN mkdir -p /usr/local/bin \
&& wget -O /usr/local/bin/yq https://github.com/mikefarah/yq/releases/download/v${YQ_VERSION}/yq_linux_amd64 \
&& chmod +x /usr/local/bin/yq
COPY . /src
WORKDIR /src
RUN make GORELEASER_ARGS='build --rm-dist --single-target --snapshot' goreleaser
# Patch config
RUN /src/dist/bouncer_linux_amd64_v1/bouncer -c '' config dump > /src/dist/bouncer_linux_amd64_v1/config.yml \
&& yq -i '.layers.queue.templateDir = "/usr/share/bouncer/layers/queue/templates"' /src/dist/bouncer_linux_amd64_v1/config.yml \
&& yq -i '.admin.auth.privateKey = "/etc/bouncer/admin-key.json"' /src/dist/bouncer_linux_amd64_v1/config.yml \
&& yq -i '.redis.adresses = ["redis:6379"]' /src/dist/bouncer_linux_amd64_v1/config.yml
FROM alpine:3.18 AS RUNTIME
ARG DUMB_INIT_VERSION=1.2.5
RUN apk add --no-cache ca-certificates
RUN mkdir -p /usr/local/bin \
&& wget -O /usr/local/bin/dumb-init https://github.com/Yelp/dumb-init/releases/download/v${DUMB_INIT_VERSION}/dumb-init_${DUMB_INIT_VERSION}_x86_64 \
&& chmod +x /usr/local/bin/dumb-init
ENTRYPOINT ["/usr/local/bin/dumb-init", "--"]
RUN mkdir -p /usr/local/bin /usr/share/bouncer/bin /etc/bouncer
COPY --from=BUILD /src/dist/bouncer_linux_amd64_v1/bouncer /usr/share/bouncer/bin/bouncer
COPY --from=BUILD /src/layers /usr/share/bouncer/layers
COPY --from=BUILD /src/dist/bouncer_linux_amd64_v1/config.yml /etc/bouncer/config.yml
RUN ln -s /usr/share/bouncer/bin/bouncer /usr/local/bin/bouncer
EXPOSE 8080
EXPOSE 8081
ENV BOUNCER_CONFIG=/etc/bouncer/config.yml
CMD ["bouncer"]

9
misc/k6/README.md Normal file
View File

@ -0,0 +1,9 @@
# K6 - Load Test
Very basic load testing script for [k6](https://k6.io/).
## How to run
```shell
k6 run cadoles-loadtest.js
```

View File

@ -0,0 +1,29 @@
import { check } from 'k6';
import { browser } from 'k6/experimental/browser';
export const options = {
scenarios: {
browser: {
vus: 10,
iterations: 100,
executor: 'shared-iterations',
options: {
browser: {
type: 'chromium',
},
},
},
}
};
export default async function () {
const page = browser.newPage();
try {
await page.goto('https://www.cadoles.com');
check(page, {
'Homepage loaded': p => p.locator('h1').textContent().trim() == 'La liberté est un choix',
});
} finally {
page.close();
}
}

66
misc/k8s/README.md Normal file
View File

@ -0,0 +1,66 @@
# Kubernetes
## Initialize your project
1. Generate the Docker configuration to enable image builds with Kaniko and communicate with reg.cadoles.com
```shell
docker login reg.cadoles.com
mkdir -p misc/k8s/kustomization/base/secrets/dockerconfig
docker --config misc/k8s/kustomization/base/secrets/dockerconfig login reg.cadoles.com
mv misc/k8s/kustomization/base/secrets/dockerconfig/config.json misc/k8s/kustomization/base/secrets/dockerconfig/.dockerconfigjson
mkdir -p misc/k8s/kustomization/overlays/dev/secrets/dockerconfig
cp misc/k8s/kustomization/base/secrets/dockerconfig/.dockerconfigjson misc/k8s/kustomization/overlays/dev/secrets/dockerconfig/.dockerconfigjson
```
## Getting started with Kind
1. Create your [Kind](https://kind.sigs.k8s.io/) cluster
```shell
kind create cluster --config misc/k8s/kind/bouncer-cluster.yaml
```
2. Deploy required operators
```shell
kubectl apply -k misc/k8s/kind/cluster --server-side
```
3. Deploy your Bouncer development environment
```shell
skaffold dev -p dev --cleanup=false --default-repo reg.cadoles.com/<YOUR_PERSONNAL_USER_NAME>
```
## Testing
1. Open shell in bouncer-admin pod
```shell
kubectl exec -it -n bouncer-dev bouncer-admin-<suffix> -- /bin/sh
```
2. Create an authentication token
```shell
bouncer --config /etc/bouncer/config.yml auth create-token --role writer --subject $(whoami) > .bouncer-token
```
3. Create a proxy and enable it
```shell
bouncer admin proxy create --proxy-to https://www.cadoles.com --proxy-name cadoles
bouncer admin proxy update --proxy-name cadoles --proxy-enabled=true
```
4. With you host web browser, open http://localhost:9000, you should see the Cadoles website.
## Benchmarking
You can use [`siege`](https://github.com/JoeDog/siege) to benchmark your instance with the Cadoles proxy.
```shell
BASE_URL=http://localhost:9000 make siege
```

View File

@ -0,0 +1,3 @@
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
name: bouncer-dev

View File

@ -0,0 +1,5 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- https://forge.cadoles.com/CadolesKube/c-kustom//base/redis?ref=develop

View File

@ -0,0 +1,10 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: bouncer
resources:
- ./resources/namespace.yaml
- ./resources/bouncer-server
- ./resources/bouncer-admin
- ./resources/redis

View File

@ -0,0 +1 @@
{"d":"JuBw5OsGv3rPgVczxUgtJ6iUQ41LQu4Xpu-t8IKI_z8r-BZBlbndxidPmRlGZASLGL3rhY4qw6_ScFxakrMpCreO1RMU0kqtz--N48BXFnW5tEgr1voyyKP__bPssQNn6PgkoyAd11es7MEKlBff_DtGrcSkVRgU0zDZB-vIU0aNEIZPNw0icbYqc1u_QQNPpBU9cw6P33WHhzvfCVAkZKRszwznhiPM08n1vjpiA7e1kQ8a6OC4IFZBvohkmpmyOq1g1OLRABQ83YPCjGjCAejO-jEWkbLksp6rAl_YYpCvfBAjFV76JuZq4eh5IU82LsSfi3PGYBkhxWuLY779XQ","dp":"gljHOQowGK7fVn2DJizWtgRIDJuKpKnoX2PWNJUbm2WZwcEPZalAkxn7Y-w_reLVJZuRpfKEUMS-Tn3-CwI1ZjCHPqMPTXcoG0Pe2E-Z88jOs9lW4XSOASiiM980VIvkV1xCxDJkN3NsDFQ9j9kRGnKuMnsucCW3AKaU917hXNU","dq":"mqY19JcEBDnzS70_XkAsOKqPzemOScax66b-4N6zrsgeLVlRjHffY9uCAgBWzlxOidRdQN8q23ZJB4fqsKB2w00Iw7Jxx94IoAKGjKDT5iB48Y_kdKLAwSHRTXsqA9GG3po_H_JpP_EqX4TDBYtqQZuBD_tACP9HbLYMi_V2YU8","e":"AQAB","kty":"RSA","n":"sam0X0BGcuFwX8z3Wde8cv2o_zl6A9ghpkT0tCjw8qH3GNWrbAqzncSWdHBzoChBgAbuTOVs-ixYC0KeUhwFdc8Ul-jmKJWFaS8kIr3y4EH62-vLgMuIKfaxbsyUG6KMkJfnftge1jPO4ccddNej9msxcqTxu37dcgstutwtd6QkS9p5RrNbDBc8-Z7SQ4TuxJfP8msXRnCPJ-I44yszGdQF1Np2DXakJHVn8PBrDh3iSFwORw8jxNS4oS0OlBl5aSc0t5XkkaNcSU2a50SKts290w54fl6MPJ1sLnnznLy4uu37-nrfEUvqRLDZL9B1F82RM1dtLIIiN4gnSrMlpQ","p":"wOmFPhAT_wXWzMuwtEdYIer3-CiOWxFKpFL09eEJkJ29MIUchEaoiJaUAghqPxM48llfOVaUaLbFVxmo5U3fyjNMaP-nHMUBwojutykMK-gC2R3J4bQgFWfKbGSL7M7UsextAvpq9iiOuR0LNE-xTfCgPIxHVdPZskO3yx0DkjM","q":"68OGRb0tLRjb_PpkGctcSjEz_vvcyjzxGL-fn4_h4GCw98Xrj6Y4rZ4lfWWRSeDohSvdd-ICSlxvxkQOIOcA0H7jyJcBC0KDs4hX5BRGJNDri3QX0ry4_F1ptAdbfiFgQGqCfMRCr7L60Tfd_6tLczvny7eEBKQNGdj6dLfhgMc","qi":"DFwixyxUDf0REPLLa8hOKieRL95_AH9rbYWzStBOdSjKWra5l0reD6a4bbvAYvl0e8qCcRI6S8Nzpz0BYm4sJL7poVOnjxqvBY3Q9Ppf4Mq8lW39pOCJcqOHIvvYHsMjTC5uwp7Yg2p0GvxuUibbyNL1PXf6WZ_szVP_oSMrCXA"}

View File

@ -0,0 +1,36 @@
admin:
http:
host: 127.0.0.1
port: 8081
cors:
allowedOrigins:
- http://localhost:3001
allowCredentials: true
allowMethods:
- POST
- GET
- PUT
- DELETE
allowedHeaders:
- Origin
- Accept
- Content-Type
- Authorization
- Sentry-Trace
debug: false
auth:
issuer: http://127.0.0.1:8081
privateKey: /etc/bouncer/admin-key.json
metrics:
enabled: true
endpoint: /.bouncer/metrics
basicAuth: null
redis:
addresses:
- rfs-bouncer-redis:${RFS_BOUNCER_REDIS_SERVICE_PORT}
master: mymaster
logger:
level: 2
format: human

View File

@ -0,0 +1,12 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ./resources/service.yaml
- ./resources/deployment.yaml
configMapGenerator:
- name: bouncer-admin-config
files:
- ./files/config.yml
- ./files/admin-key.json

View File

@ -0,0 +1,34 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: bouncer-admin
labels:
app: bouncer-admin
io.kompose.service: bouncer-admin
spec:
replicas: 3
selector:
matchLabels:
app: bouncer-admin
template:
metadata:
labels:
app: bouncer-admin
io.kompose.service: bouncer-admin
spec:
containers:
- name: bouncer-admin
image: reg.cadoles.com/cadoles/bouncer:v2024.2.5-1602626
command: ["bouncer", "--debug", "-c", "/etc/bouncer/config.yml", "server", "admin", "run"]
imagePullPolicy: Always
resources: {}
ports:
- name: bouncer-admin
containerPort: 8081
volumeMounts:
- mountPath: /etc/bouncer/
name: bouncer-admin-config
volumes:
- name: bouncer-admin-config
configMap:
name: bouncer-admin-config

View File

@ -0,0 +1,14 @@
apiVersion: v1
kind: Service
metadata:
labels:
io.kompose.service: bouncer-admin
name: bouncer-admin
spec:
type: ClusterIP
ports:
- name: bouncer-admin
port: 8081
targetPort: bouncer-admin
selector:
io.kompose.service: bouncer-admin

View File

@ -0,0 +1,22 @@
proxy:
http:
host: 0.0.0.0
port: 8080
metrics:
enabled: true
endpoint: /.bouncer/metrics
basicAuth: null
layers:
queue:
templateDir: /usr/share/bouncer/layers/queue/templates
defaultKeepAlive: 1m0s
redis:
addresses:
- rfs-bouncer-redis:${RFS_BOUNCER_REDIS_SERVICE_PORT}
master: mymaster
logger:
level: 2
format: human

View File

@ -0,0 +1,11 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ./resources/service.yaml
- ./resources/deployment.yaml
configMapGenerator:
- name: bouncer-server-config
files:
- ./files/config.yml

View File

@ -0,0 +1,34 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: bouncer-server
labels:
app: bouncer-server
io.kompose.service: bouncer-server
spec:
replicas: 3
selector:
matchLabels:
app: bouncer-server
template:
metadata:
labels:
app: bouncer-server
io.kompose.service: bouncer-server
spec:
containers:
- name: bouncer-server
image: reg.cadoles.com/cadoles/bouncer:v2024.2.5-1602626
command: ["bouncer", "-c", "/etc/bouncer/config.yml", "server", "proxy", "run"]
imagePullPolicy: Always
resources: {}
ports:
- name: bouncer-server
containerPort: 8080
volumeMounts:
- mountPath: /etc/bouncer/
name: bouncer-server-config
volumes:
- name: bouncer-server-config
configMap:
name: bouncer-server-config

View File

@ -0,0 +1,14 @@
apiVersion: v1
kind: Service
metadata:
labels:
io.kompose.service: bouncer-server
name: bouncer-server
spec:
type: ClusterIP
ports:
- name: bouncer-server
port: 8080
targetPort: bouncer-server
selector:
io.kompose.service: bouncer-server

View File

@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: bouncer

View File

@ -0,0 +1,15 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ./resources/redis-cluster.yaml
vars:
- name: REDIS_SERVICE_NAME
objref:
name: bouncer-redis
apiVersion: databases.spotahome.com/v1
kind: RedisFailover
fieldref:
fieldpath: metadata.name

View File

@ -0,0 +1,21 @@
apiVersion: databases.spotahome.com/v1
kind: RedisFailover
metadata:
name: bouncer-redis
spec:
sentinel:
replicas: 3
resources:
requests:
cpu: 100m
limits:
memory: 100Mi
redis:
replicas: 3
resources:
requests:
cpu: 100m
memory: 100Mi
limits:
cpu: 400m
memory: 500Mi

View File

@ -0,0 +1,18 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: bouncer-dev
resources:
- ../../base
secretGenerator:
- files:
- secrets/dockerconfig/.dockerconfigjson
name: regcred-dev
type: kubernetes.io/dockerconfigjson
patches:
- path: patches/add-registry-pull-secret.patch.yaml
target:
kind: Deployment
version: v1

View File

@ -0,0 +1,4 @@
- op: add
path: "/spec/template/spec/imagePullSecrets"
value:
- name: regcred-dev

View File

@ -1,176 +1,179 @@
# Configuration du service "admin" # Configuration du service "admin"
admin: admin:
http: http:
# Hôte d'écoute du service, # Hôte d'écoute du service,
# 0.0.0.0 pour écouter sur toutes les interfaces # 0.0.0.0 pour écouter sur toutes les interfaces
host: 127.0.0.1 host: 127.0.0.1
# Port d'écoute du service # Port d'écoute du service
port: 8081 port: 8081
# Utiliser les entêtes HTTP True-Client-IP, X-Real-IP ou X-Forwarded-For # Utiliser les entêtes HTTP True-Client-IP, X-Real-IP ou X-Forwarded-For
# pour le calcul de l'adresse distante à l'origine des requêtes # pour le calcul de l'adresse distante à l'origine des requêtes
useRealIP: true useRealIP: true
# Configuration CORS du service # Configuration CORS du service
# Uniquement nécessaire si un frontend web # Uniquement nécessaire si un frontend web
# est branché sur l'API d'administration. # est branché sur l'API d'administration.
cors: cors:
allowedOrigins: allowedOrigins:
- http://localhost:8081 - http://localhost:8081
allowCredentials: true allowCredentials: true
allowMethods: allowMethods:
- POST - POST
- GET - GET
- PUT - PUT
- DELETE - DELETE
allowedHeaders: allowedHeaders:
- Origin - Origin
- Accept - Accept
- Content-Type - Content-Type
- Authorization - Authorization
- Sentry-Trace - Sentry-Trace
debug: false debug: false
# Authentification JWT
auth:
# Origine du jeton JWT
issuer: http://127.0.0.1:8081
# Clé privée permettant de signer les jetons
# JWT générés pour l'usage de l'API d'administration.
privateKey: /etc/bouncer/admin-key.json
# Métriques Prometheus # Authentification JWT
metrics: auth:
# Activer ou désactiver la publication des métriques # Origine du jeton JWT
enabled: true issuer: http://127.0.0.1:8081
# Route de publication des métriques # Clé privée permettant de signer les jetons
endpoint: /.bouncer/metrics # JWT générés pour l'usage de l'API d'administration.
# Authentification "basic auth" sur la page privateKey: /etc/bouncer/admin-key.json
# de publication
# Mettre à null pour désactiver l'authentification # Métriques Prometheus
basicAuth: null metrics:
# Activer ou désactiver la publication des métriques
# Configuration de l'intégration Sentry enabled: true
# Voir https://pkg.go.dev/github.com/getsentry/sentry-go?utm_source=godoc#ClientOptions # Route de publication des métriques
sentry: endpoint: /.bouncer/metrics
dsn: "" # Authentification "basic auth" sur la page
debug: false # de publication
flushTimeout: 2s # Mettre à null pour désactiver l'authentification
attachStacktrace: true basicAuth: null
sampleRate: 1
enableTracing: true # Configuration de l'intégration Sentry
tracesSampleRate: 0.2 # Voir https://pkg.go.dev/github.com/getsentry/sentry-go?utm_source=godoc#ClientOptions
profilesSampleRate: 1 sentry:
ignoreErrors: [] dsn: ""
sendDefaultPII: false debug: false
serverName: "" flushTimeout: 2s
environment: "" attachStacktrace: true
maxBreadcrumbs: 0 sampleRate: 1
maxSpans: 1000 enableTracing: true
maxErrorDepth: 10 tracesSampleRate: 0.2
profilesSampleRate: 1
ignoreErrors: []
sendDefaultPII: false
serverName: ""
environment: ""
maxBreadcrumbs: 0
maxSpans: 1000
maxErrorDepth: 10
# Configuration du service "proxy" # Configuration du service "proxy"
proxy: proxy:
http: http:
# Hôte d'écoute du service, # Hôte d'écoute du service,
# 0.0.0.0 pour écouter sur toutes les interfaces # 0.0.0.0 pour écouter sur toutes les interfaces
host: 0.0.0.0 host: 0.0.0.0
# Port d'écoute du service # Port d'écoute du service
port: 8080 port: 8080
# Utiliser les entêtes HTTP True-Client-IP, X-Real-IP ou X-Forwarded-For # Utiliser les entêtes HTTP True-Client-IP, X-Real-IP ou X-Forwarded-For
# pour le calcul de l'adresse distante à l'origine des requêtes # pour le calcul de l'adresse distante à l'origine des requêtes
useRealIP: true useRealIP: true
# Métriques Prometheus
metrics:
# Activer ou désactiver la publication des métriques
enabled: true
# Route de publication des métriques
endpoint: /.bouncer/metrics
# Authentification "basic auth" sur la page
# de publication
# Mettre à null pour désactiver l'authentification
basicAuth:
credentials:
prom: etheus
# Configuration du transport HTTP(S) # Métriques Prometheus
# Voir https://pkg.go.dev/net/http#Transport metrics:
transport: # Activer ou désactiver la publication des métriques
forceAttemptHTTP2: true enabled: true
maxIdleConns: 100 # Route de publication des métriques
maxIdleConnsPerHost: 100 endpoint: /.bouncer/metrics
maxConnsPerHost: 100 # Authentification "basic auth" sur la page
idleConnTimeout: 1m30s # de publication
tlsHandshakeTimeout: 10s # Mettre à null pour désactiver l'authentification
expectContinueTimeout: 1s basicAuth:
disableKeepAlives: false credentials:
disableCompression: false prom: etheus
responseHeaderTimeout: 10s
writeBufferSize: 4096
readBufferSize: 4096
maxResponseHeaderBytes: 0
# Configuration de l'intégration Sentry # Configuration du transport HTTP(S)
# Voir https://pkg.go.dev/github.com/getsentry/sentry-go?utm_source=godoc#ClientOptions # Voir https://pkg.go.dev/net/http#Transport
sentry: transport:
dsn: "" forceAttemptHTTP2: true
debug: false maxIdleConns: 100
flushTimeout: 2s maxIdleConnsPerHost: 100
attachStacktrace: true maxConnsPerHost: 100
sampleRate: 1 idleConnTimeout: 1m30s
enableTracing: true tlsHandshakeTimeout: 10s
tracesSampleRate: 0.2 expectContinueTimeout: 1s
profilesSampleRate: 1 disableKeepAlives: false
ignoreErrors: [] disableCompression: false
sendDefaultPII: false responseHeaderTimeout: 10s
serverName: "" writeBufferSize: 4096
environment: "" readBufferSize: 4096
maxBreadcrumbs: 0 maxResponseHeaderBytes: 0
maxSpans: 1000
maxErrorDepth: 10
# Configuration des connexions TCP # Configuration de l'intégration Sentry
# Voir https://pkg.go.dev/net#Dialer # Voir https://pkg.go.dev/github.com/getsentry/sentry-go?utm_source=godoc#ClientOptions
dial: sentry:
timeout: 30s dsn: ""
keepAlive: 30s debug: false
fallbackDelay: 300ms flushTimeout: 2s
dualStack: true attachStacktrace: true
sampleRate: 1
enableTracing: true
tracesSampleRate: 0.2
profilesSampleRate: 1
ignoreErrors: []
sendDefaultPII: false
serverName: ""
environment: ""
maxBreadcrumbs: 0
maxSpans: 1000
maxErrorDepth: 10
# Configuration des connexions TCP
# Voir https://pkg.go.dev/net#Dialer
dial:
timeout: 30s
keepAlive: 30s
fallbackDelay: 300ms
dualStack: true
# Configuration du client Redis # Configuration du client Redis
# #
# Les modes "standalone", "sentinel" et "cluster" de Redis sont supportés: # Les modes "standalone", "sentinel" et "cluster" de Redis sont supportés:
# - Mode "standalone": renseigner une seule entrée dans redis.addresses; # - Mode "standalone": renseigner une seule entrée dans redis.addresses;
# - Mode "sentinel": renseigner une adresse dans redis.master et une ou plusieurs adresses dans redis.addresses; # - Mode "sentinel": renseigner le nom du master sentinel dans redis.master et une ou plusieurs adresses dans redis.addresses;
# - Mode "cluster": renseigner plusieurs adresses dans redis.addresses et laisser redis.master vide. # - Mode "cluster": renseigner plusieurs adresses dans redis.addresses et laisser redis.master vide.
redis: redis:
addresses: addresses:
- localhost:6379 - localhost:6379
master: "" master: ""
writeTimeout: 30s
readTimeout: 30s
dialTimeout: 30s
# Configuration des logs # Configuration des logs
logger: logger:
# Niveau de verbosité # Niveau de verbosité
# 0 - DEBUG # 0 - DEBUG
# 1 - INFO # 1 - INFO
# 2 - WARNING # 2 - WARNING
# 3 - ERROR # 3 - ERROR
# 4 - FATAL # 4 - FATAL
level: 1 level: 2
# Format des logs, "human" ou "json" # Format des logs, "human" ou "json"
format: human format: human
# Configuration des différents layers # Configuration des différents layers
layers: layers:
# Configuration du layer "queue" # Configuration du layer "queue"
queue: queue:
# Répertoire contenant les templates # Répertoire contenant les templates
templateDir: "/etc/bouncer/layers/queue/templates" templateDir: "/etc/bouncer/layers/queue/templates"
# Temps de vie par défaut d'une session # Temps de vie par défaut d'une session
defaultKeepAlive: 1m defaultKeepAlive: 1m
# Configuration du layer "circuitbreaker" # Configuration du layer "circuitbreaker"
circuitbreaker: circuitbreaker:
# Répertoire contenant les templates # Répertoire contenant les templates
templateDir: "/etc/bouncer/layers/circuitbreaker/templates" templateDir: "/etc/bouncer/layers/circuitbreaker/templates"

View File

@ -1,6 +1,6 @@
http://localhost:8080/blog/ ${BASE_URL}/blog/
http://localhost:8080/services/ ${BASE_URL}/services/
http://localhost:8080/ ${BASE_URL}
http://localhost:8080/recrutement/ ${BASE_URL}/recrutement/
http://localhost:8080/faq/ ${BASE_URL}/faq/
http://localhost:8080/societe/histoire/ ${BASE_URL}/societe/histoire/

53
skaffold.yaml Normal file
View File

@ -0,0 +1,53 @@
apiVersion: skaffold/v3
kind: Config
metadata:
name: bouncer
manifests:
kustomize:
paths:
- misc/k8s/kustomization/base
profiles:
- name: dev
manifests:
kustomize:
paths:
- misc/k8s/kustomization/overlays/dev
activation:
- command: dev
build:
local:
push: true
tagPolicy:
sha256: {}
artifacts:
- image: reg.cadoles.com/cadoles/bouncer
context: .
sync:
infer:
- cmd/**
- internal/**
- layers/**
- misc/**
docker:
dockerfile: Dockerfile
deploy:
statusCheckDeadlineSeconds: 600
portForward:
- resourceType: service
resourceName: bouncer-admin
namespace: bouncer-dev
port: 8081
localPort: 9999
- resourceType: service
resourceName: bouncer-server
namespace: bouncer-dev
port: 8080
localPort: 9000 # *Optional*