Compare commits

...
11 Commits
Author SHA1 Message Date
Ara Sadoyan 0831ffb801 Merge pull request #53 from sergelogvinov/chart
feat: add aralez helm chart
2026-09-09 19:08:06 +02:00
Ara Sadoyan 5d55e2b120 configs 2026-09-09 19:01:38 +02:00
Ara Sadoyan b3c614e592 configs 2026-09-09 18:54:25 +02:00
Ara Sadoyan b22bb2fe16 Config files update, cleanup 2026-09-09 18:52:32 +02:00
Ara Sadoyan e6204a2b1d version change 2026-09-09 18:43:49 +02:00
Ara Sadoyan 6a78acd486 version change 2026-09-09 18:43:28 +02:00
Ara Sadoyan 1a2485b87a Implemented EndpointSlices #55 2026-09-09 18:42:41 +02:00
Ara Sadoyan 3329c34a09 working on #55 2026-09-09 15:39:28 +02:00
Serge 6df63f69cd feat: add aralez helm chart
Add basic Aralez deployment configuration, Helm chart linting workflow,
and Dependabot configuration.
2026-09-06 11:33:16 +02:00
Ara Sadoyan 4a4f3e6187 fixed closed #52 2026-09-04 16:24:49 +02:00
Ara Sadoyan 31f513cc2a hcl examples 2026-09-01 12:53:42 +02:00
43 changed files with 1260 additions and 282 deletions
+9
View File
@@ -0,0 +1,9 @@
helm-extra-args: --timeout 300s
check-version-increment: true
debug: true
chart-dirs:
- charts
validate-maintainers: true
namespace: default
release-label: test
target-branch: main
+23
View File
@@ -0,0 +1,23 @@
---
# See https://docs.github.com/en/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
commit-message:
prefix: "chore:"
open-pull-requests-limit: 8
rebase-strategy: disabled
schedule:
interval: "monthly"
day: "monday"
time: "10:00"
timezone: "UTC"
cooldown:
default-days: 7
groups:
actions:
patterns:
- "actions/*"
- "helm/*"
+28
View File
@@ -0,0 +1,28 @@
name: Helm chart check
on:
pull_request:
branches:
- main
paths:
- "charts/**"
jobs:
helm-lint:
name: Helm chart check
timeout-minutes: 5
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Install chart-testing tools
id: lint
uses: helm/chart-testing-action@6ec842c01de15ebb84c8627d2744a0c2f2755c9f # v2.8.0
- name: Run helm chart linter
run: ct --config .github/ct.yml lint
- name: Run helm template
run: helm lint charts/aralez
Generated
+58 -45
View File
@@ -138,7 +138,7 @@ checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3"
[[package]]
name = "aralez"
version = "0.93.2"
version = "0.93.4"
dependencies = [
"ahash",
"arc-swap",
@@ -156,6 +156,7 @@ dependencies = [
"jsonwebtoken",
"k8s-openapi",
"kube",
"lazy_static",
"libc",
"log",
"log4rs",
@@ -183,7 +184,7 @@ dependencies = [
"subtle",
"tokio",
"tokio-native-tls",
"tower-http 0.7.0",
"tower-http 0.7.1",
"urlencoding",
"x509-parser",
]
@@ -284,9 +285,9 @@ dependencies = [
[[package]]
name = "async-trait"
version = "0.1.91"
version = "0.1.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae36dc4177970ef04fde5178d3e2429882def40e57a451f919c098f72baa6cec"
checksum = "82f6aeea286b8eb4dd3431a1be1b59d290ace00f5bfd8e2a159bc2a05e2c1667"
dependencies = [
"proc-macro2",
"quote",
@@ -307,9 +308,9 @@ checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
[[package]]
name = "aws-lc-rs"
version = "1.17.1"
version = "1.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4342d8937fc7e5dd9b1c60292261c0670c882a2cd1719cfc11b1af41731e32ad"
checksum = "b281d307588d634de920874890732659e2e7672f72b5e10e81badc1a8a83621e"
dependencies = [
"aws-lc-sys",
"untrusted 0.7.1",
@@ -318,9 +319,9 @@ dependencies = [
[[package]]
name = "aws-lc-sys"
version = "0.42.0"
version = "0.45.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d9ceb1da931507a12f4fccea479dccd00da1943e1b4ae72d8e502d707361444"
checksum = "9bff6c3b54fad79a2e60b8102caf565819711497c1f5f092f49508e2f5c31b27"
dependencies = [
"cc",
"cmake",
@@ -1338,9 +1339,9 @@ checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
[[package]]
name = "futures"
version = "0.3.32"
version = "0.3.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d"
checksum = "9a31d2a3fbaaeb2af2368bbdd904aa8e812d3c04a1ee10d3171f52d556e5d0a3"
dependencies = [
"futures-channel",
"futures-core",
@@ -1353,9 +1354,9 @@ dependencies = [
[[package]]
name = "futures-channel"
version = "0.3.32"
version = "0.3.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d"
checksum = "b1f9e3d69d39e4862ffed03ed071a76f9a13ba1d9109d355b0f0aa6b15e393c4"
dependencies = [
"futures-core",
"futures-sink",
@@ -1363,15 +1364,15 @@ dependencies = [
[[package]]
name = "futures-core"
version = "0.3.32"
version = "0.3.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d"
checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e"
[[package]]
name = "futures-executor"
version = "0.3.32"
version = "0.3.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d"
checksum = "031b47cf1a3c6cc8bc2fc76cd437f521619387907d469316e7c0bc278f1f5432"
dependencies = [
"futures-core",
"futures-task",
@@ -1380,38 +1381,38 @@ dependencies = [
[[package]]
name = "futures-io"
version = "0.3.32"
version = "0.3.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718"
checksum = "53c0fa8157de1303bfffdaa1cc2a673bfffb60102f76b0ef4441659124373fed"
[[package]]
name = "futures-macro"
version = "0.3.32"
version = "0.3.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b"
checksum = "9fb9654ba8355388abeb8dcb4fc62f511300867002afc858860463bdd9fe0c44"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.118",
"syn 3.0.3",
]
[[package]]
name = "futures-sink"
version = "0.3.32"
version = "0.3.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893"
checksum = "1944426bf7d03f1d14f708785e4b33efd750b36d48a157b836b3efc15ede8e1d"
[[package]]
name = "futures-task"
version = "0.3.32"
version = "0.3.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393"
checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd"
[[package]]
name = "futures-util"
version = "0.3.32"
version = "0.3.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6"
checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc"
dependencies = [
"futures-channel",
"futures-core",
@@ -1638,9 +1639,9 @@ dependencies = [
[[package]]
name = "http-body-util"
version = "0.1.4"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e9f41fd6a08e4d4ec69df65976da761afd5ad5e58a9d4acb46bd1c953a9e3ff2"
checksum = "23169fe34a5fbcdd3f3862e78fb9b6fccd5f02a6dc6f732547005d45631ce71c"
dependencies = [
"bytes",
"futures-core",
@@ -1684,9 +1685,9 @@ dependencies = [
[[package]]
name = "hyper"
version = "1.11.0"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d22053281f852e11534f5198498373cbb59295120a20771d90f7ed1897490a72"
checksum = "27b501faa50e7a26c3d3560ca625132f4078a17771f4810baf70475ae48cbe43"
dependencies = [
"atomic-waker",
"bytes",
@@ -2019,7 +2020,7 @@ dependencies = [
"js-sys",
"p256",
"p384",
"pem",
"pem 3.0.6",
"rand 0.8.7",
"rsa",
"serde",
@@ -2096,7 +2097,7 @@ dependencies = [
"jsonpath-rust",
"k8s-openapi",
"kube-core",
"pem",
"pem 3.0.6",
"rustls",
"rustls-platform-verifier",
"secrecy",
@@ -2239,9 +2240,9 @@ dependencies = [
[[package]]
name = "log"
version = "0.4.33"
version = "0.4.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad"
checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6"
dependencies = [
"serde_core",
]
@@ -2373,9 +2374,9 @@ checksum = "9bb517913cfcfb9eeda59f36020269075a152701a01606c612f547e4890be399"
[[package]]
name = "moka"
version = "0.12.15"
version = "0.12.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "957228ad12042ee839f93c8f257b62b4c0ab5eaae1d4fa60de53b27c9d7c5046"
checksum = "4293f18e7567a1caf3c584855554377025c65e0aa445344d04171f5ad63d19b9"
dependencies = [
"crossbeam-channel",
"crossbeam-epoch",
@@ -2505,16 +2506,18 @@ dependencies = [
[[package]]
name = "noyalib"
version = "0.0.18"
version = "0.0.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccc67d13e91577493ff12d930fcdc92a342b46e2299210089d90d2caed837f60"
checksum = "190b855ac3a2a1ff710c203db23da6aec67f4317af6e226960d40f181ceeccac"
dependencies = [
"hashbrown 0.17.1",
"indexmap 2.14.0",
"itoa",
"libm",
"memchr",
"rustc-hash",
"ryu",
"serde",
"serde_core",
"serde_ignored",
"smallvec",
]
@@ -2760,6 +2763,16 @@ dependencies = [
"serde_core",
]
[[package]]
name = "pem"
version = "4.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d354a98a3d1251555de99e8fdd8afda05573c31b82f59063a7b0a29b5527f120"
dependencies = [
"base64 0.23.1",
"serde_core",
]
[[package]]
name = "pem-rfc7468"
version = "0.7.0"
@@ -3357,12 +3370,12 @@ checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69"
[[package]]
name = "rcgen"
version = "0.14.8"
version = "0.14.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57f6d249aad744e274e682777a50283a225a32705394ee6d5fcc01efa25e4055"
checksum = "8774e05a7d0de114588e6a28fe7e71694b82614ed569d86d8b389dfbc98b8ad8"
dependencies = [
"aws-lc-rs",
"pem",
"pem 4.0.0",
"ring",
"rustls-pki-types",
"time",
@@ -4356,9 +4369,9 @@ dependencies = [
[[package]]
name = "tower-http"
version = "0.7.0"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b11f75e912b0c2be01b63d8cf8057b8c3f97cf34abb3d431a3a4c8675498e233"
checksum = "08a05a66a4fdd61cbbe0a1d755ffe0ca6aba159dd4820936a0ff8a8278245b9c"
dependencies = [
"bitflags 2.13.0",
"bytes",
+11 -10
View File
@@ -1,6 +1,6 @@
[package]
name = "aralez"
version = "0.93.2"
version = "0.93.4"
edition = "2021"
license = "Apache-2.0"
description = "Reverse proxy built on top of Cloudflare's Pingora"
@@ -23,12 +23,12 @@ pingora-http = "0.8.1"
pingora-limits = "0.8.1"
pingora-cache = "0.8.1"
dashmap = "7.0.0-rc2"
async-trait = "0.1.91"
log = "0.4.33"
async-trait = "0.1.92"
log = "0.4.34"
notify = "9.0.0-rc.4"
axum = { version = "0.8.9" }
serde = { version = "1.0.229", features = ["derive"] }
noyalib = { version = "0.0.18", features = ["compat-serde-yaml"] }
noyalib = { version = "0.0.32", features = ["compat-serde-yaml"] }
rand = "0.10.2"
base64 = "0.23.1"
jsonwebtoken = { version = "11.0.0", default-features = false, features = ["use_pem", "rust_crypto"] }
@@ -39,26 +39,27 @@ arc-swap = "1.9.2"
prometheus = "0.14.0"
x509-parser = "0.18.1"
rustls-pemfile = "2.2.0"
tower-http = { version = "0.7.0", features = ["fs"] }
tower-http = { version = "0.7.1", features = ["fs"] }
privdrop = "0.5.6"
serde_json = "1.0.151"
subtle = "2.6.1"
moka = { version = "0.12.15", features = ["sync"] }
moka = { version = "0.12.16", features = ["sync"] }
ahash = "0.8.12"
instant-acme = "0.8.5"
rcgen = "0.14.8"
rcgen = "0.14.10"
log4rs = { version = "1.4.0", features = ["rolling_file_appender", "compound_policy", "size_trigger", "fixed_window_roller", "gzip"] }
mimalloc = { version = "0.1.52", default-features = false }
signal-hook = "0.4.4"
sd-notify = "0.5.0"
libc = "0.2.186"
tokio-native-tls = "0.3.1"
hyper = "1.11.0"
hyper = "1.11.1"
hyper-util = "0.1.20"
http-body-util = "0.1.4"
http-body-util = "0.1.5"
bytes = "1.12.1"
rustls = { version = "0.23", default-features = false, features = ["ring"] }
kube = { version = "4.2.0", features = ["runtime", "client", "derive"] }
k8s-openapi = { version = "0.28.0", features = ["v1_32"] }
futures = "0.3"
futures = "0.3.34"
lazy_static = "1.5.0"
+23
View File
@@ -0,0 +1,23 @@
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*.orig
*~
# Various IDEs
.project
.idea/
*.tmproj
.vscode/
+18
View File
@@ -0,0 +1,18 @@
# yaml-language-server: $schema=https://json.schemastore.org/chart.json
apiVersion: v2
name: aralez
description: Ingress controller for Kubernetes
type: application
home: https://github.com/sadoyan/aralez/charts
sources:
- https://github.com/sadoyan/helm-charts/tree/main/charts/aralez
keywords:
- ingress-controller
- aralez
maintainers: []
#
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.0.1
#
# renovate: datasource=docker depName=ghcr.io/sadoyan/aralez
appVersion: 0.93.3
+17
View File
@@ -0,0 +1,17 @@
{{ template "chart.header" . }}
{{ template "chart.deprecationWarning" . }}
{{ template "chart.badgesSection" . }}
{{ template "chart.description" . }}
{{ template "chart.homepageLine" . }}
{{ template "chart.maintainersSection" . }}
{{ template "chart.sourcesSection" . }}
{{ template "chart.requirementsSection" . }}
{{ template "chart.valuesSection" . }}
+18
View File
@@ -0,0 +1,18 @@
ingressClass: aralez
ingressClassResource:
enabled: true
# hostNetwork: true
# hostPort:
# ports:
# http: 8080
# https: 8443
priorityClassName: system-cluster-critical
env: []
args: []
useDaemonSet: true
terminationGracePeriodSeconds: 120
View File
+104
View File
@@ -0,0 +1,104 @@
{{/*
Expand the name of the chart.
*/}}
{{- define "aralez.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "aralez.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}
{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "aralez.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Common labels
*/}}
{{- define "aralez.labels" -}}
helm.sh/chart: {{ include "aralez.chart" . }}
{{ include "aralez.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- with .Values.podLabels }}
{{ toYaml . }}
{{- end }}
{{- end }}
{{/*
Selector labels
*/}}
{{- define "aralez.selectorLabels" -}}
app.kubernetes.io/name: {{ include "aralez.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/*
Return a podAffinity/podAntiAffinity definition
*/}}
{{- define "affinities.pods" -}}
{{- if eq .Values.podAntiAffinityPreset "soft" }}
{{- include "affinities.pods.soft" . -}}
{{- else if eq .Values.podAntiAffinityPreset "hard" }}
{{- include "affinities.pods.hard" . -}}
{{- end -}}
{{- end -}}
{{/*
Return a soft podAntiAffinity definition
*/}}
{{- define "affinities.pods.soft" -}}
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- podAffinityTerm:
labelSelector:
matchLabels: {{- (include "aralez.selectorLabels" .) | nindent 12 }}
namespaces:
- {{ .Release.Namespace | quote }}
topologyKey: kubernetes.io/hostname
weight: 1
{{- end -}}
{{/*
Return a hard podAntiAffinity definition
*/}}
{{- define "affinities.pods.hard" -}}
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels: {{- (include "aralez.selectorLabels" .) | nindent 10 }}
namespaces:
- {{ .Release.Namespace | quote }}
topologyKey: kubernetes.io/hostname
{{- end -}}
{{/*
Create the name of the service account to use
*/}}
{{- define "aralez.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "aralez.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}
+21
View File
@@ -0,0 +1,21 @@
{{- $ca := genCA .Chart.Name 3650 }}
{{- $server := genSignedCert "server" (list "127.0.0.1") nil 3650 $ca }}
apiVersion: v1
kind: Secret
metadata:
name: {{ include "aralez.fullname" . }}-tls
labels:
{{- include "aralez.labels" . | nindent 4 }}
type: kubernetes.io/tls
data:
{{- $secretName := printf "%s-tls" (include "aralez.fullname" .) }}
{{- $secretData := (lookup "v1" "Secret" .Release.Namespace $secretName).data }}
{{- if and $secretData (hasKey $secretData "ca.crt") }}
ca.crt: {{ get $secretData "ca.crt" }}
tls.crt: {{ get $secretData "tls.crt" }}
tls.key: {{ get $secretData "tls.key" }}
{{- else }}
ca.crt: {{ $ca.Cert | b64enc }}
tls.crt: {{ $server.Cert | b64enc }}
tls.key: {{ $server.Key | b64enc }}
{{- end }}
+28
View File
@@ -0,0 +1,28 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "aralez.fullname" . }}
labels:
{{- include "aralez.labels" . | nindent 4 }}
data:
aralez.yaml: |
daemon: false
upstreams_conf: /etc/aralez/upstreams.yaml
proxy_configs: /etc/aralez-proxy
proxy_address_http: "0.0.0.0:{{ .Values.hostPort.ports.http }}"
proxy_address_tls: "0.0.0.0:{{ .Values.hostPort.ports.https }}"
config_api_enabled: false
config_address: "0.0.0.0:3000"
upgrade_sock: /tmp/aralez.sock
pid_file: /tmp/aralez.pid
log_level: debug
hc_method: HEAD
hc_interval: 5
upstreams.yaml: |
provider: "kubernetes"
sticky_sessions: 172000
kubernetes: {}
{{- with .Values.upstreams }}
{{- toYaml . | nindent 4 }}
{{- end }}
+130
View File
@@ -0,0 +1,130 @@
apiVersion: apps/v1
{{- if .Values.useDaemonSet }}
kind: DaemonSet
{{- else }}
kind: Deployment
{{- end }}
metadata:
name: {{ include "aralez.fullname" . }}
labels:
{{- include "aralez.labels" . | nindent 4 }}
spec:
{{- if not (or .Values.autoscaling.enabled .Values.useDaemonSet) }}
replicas: {{ .Values.replicaCount }}
{{- end }}
{{- if not .Values.useDaemonSet }}
strategy:
type: {{ .Values.updateStrategy.type }}
{{- else }}
updateStrategy:
type: {{ .Values.updateStrategy.type }}
{{- end }}
selector:
matchLabels:
{{- include "aralez.selectorLabels" . | nindent 6 }}
template:
metadata:
{{- with .Values.podAnnotations }}
annotations:
{{- toYaml . | nindent 8 }}
{{- end }}
labels:
{{- include "aralez.labels" . | nindent 8 }}
{{- with .Values.podLabels }}
{{- toYaml . | nindent 8 }}
{{- end }}
annotations:
{{- if .Values.upstreams }}
checksum/upstreams: {{ toJson .Values.upstreams | sha256sum }}
{{- end }}
spec:
enableServiceLinks: false
{{- if and .Values.hostNetwork .Values.useDaemonSet }}
hostNetwork: {{ .Values.hostNetwork }}
dnsPolicy: "ClusterFirstWithHostNet"
{{- end }}
{{- if .Values.priorityClassName }}
priorityClassName: {{ .Values.priorityClassName }}
{{- end }}
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
serviceAccountName: {{ include "aralez.serviceAccountName" . }}
securityContext:
{{- toYaml .Values.podSecurityContext | nindent 8 }}
{{- if .Values.terminationGracePeriodSeconds }}
terminationGracePeriodSeconds: {{ .Values.terminationGracePeriodSeconds }}
{{- end }}
containers:
- name: {{ .Chart.Name }}
securityContext:
{{- toYaml .Values.securityContext | nindent 12 }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
command: ["aralez"]
args:
- --conf=/etc/aralez/aralez.yaml
{{- range $value := .Values.args }}
- {{ $value }}
{{- end }}
env:
{{- with .Values.env }}
{{- . | toYaml | nindent 12 }}
{{- end }}
ports:
{{- if .Values.hostPort.ports.http }}
- name: http
containerPort: {{ .Values.hostPort.ports.http }}
protocol: TCP
{{- end }}
{{- if .Values.hostPort.ports.https }}
- name: https
containerPort: {{ .Values.hostPort.ports.https }}
protocol: TCP
{{- end }}
# readinessProbe:
# httpGet:
# path: /status
# port: 3000
# initialDelaySeconds: 30
# timeoutSeconds: 5
resources:
{{- toYaml .Values.resources | nindent 12 }}
volumeMounts:
- name: config
mountPath: /etc/aralez
- name: tlscerts
mountPath: /etc/aralez-proxy/certificates
{{- with .Values.volumeMounts }}
{{- toYaml . | nindent 12 }}
{{- end }}
volumes:
- name: config
configMap:
name: {{ include "aralez.fullname" . }}
- name: tlscerts
secret:
secretName: {{ include "aralez.fullname" . }}-tls
defaultMode: 256
items:
- key: tls.crt
path: tls.crt
- key: tls.key
path: tls.key
{{- with .Values.volumes }}
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
affinity:
{{- include "affinities.pods" . | nindent 8 }}
{{- with .Values.affinity }}
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
+24
View File
@@ -0,0 +1,24 @@
{{- if and .Values.autoscaling.enabled (not .Values.useDaemonSet) }}
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: {{ include "aralez.fullname" . }}
labels:
{{- include "aralez.labels" . | nindent 4 }}
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: {{ include "aralez.fullname" . }}
minReplicas: {{ .Values.autoscaling.minReplicas }}
maxReplicas: {{ .Values.autoscaling.maxReplicas }}
metrics:
{{- if .Values.autoscaling.targetCPUUtilizationPercentage }}
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
{{- end }}
{{- end }}
+10
View File
@@ -0,0 +1,10 @@
{{- if .Values.ingressClassResource.enabled -}}
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
labels:
{{- include "aralez.labels" . | nindent 4 }}
name: {{ .Values.ingressClass }}
spec:
controller: {{ .Values.ingressClassResource.controllerValue }}
{{- end }}
+41
View File
@@ -0,0 +1,41 @@
apiVersion: v1
kind: Service
metadata:
name: {{ include "aralez.fullname" . }}
labels:
{{- include "aralez.labels" . | nindent 4 }}
{{- with .Values.service.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
type: {{ .Values.service.type }}
{{- if eq .Values.service.type "NodePort" }}
externalTrafficPolicy: Local
{{- end }}
{{- with .Values.service.ipFamilies }}
ipFamilies:
{{- toYaml . | nindent 4 }}
{{- end }}
ipFamilyPolicy: {{ if eq (len .Values.service.ipFamilies) 2 }}PreferDualStack{{ else }}SingleStack{{ end }}
ports:
{{- if .Values.hostPort.ports.http }}
- port: 80
targetPort: http
protocol: TCP
name: http
{{- if .Values.hostPort.enabled }}
nodePort: {{ .Values.hostPort.ports.http }}
{{- end }}
{{- end }}
{{- if .Values.hostPort.ports.https }}
- port: 443
targetPort: https
protocol: TCP
name: https
{{- if .Values.hostPort.enabled }}
nodePort: {{ .Values.hostPort.ports.https }}
{{- end }}
{{- end }}
selector:
{{- include "aralez.selectorLabels" . | nindent 4 }}
@@ -0,0 +1,52 @@
{{- if .Values.serviceAccount.create -}}
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ include "aralez.serviceAccountName" . }}
labels:
{{- include "aralez.labels" . | nindent 4 }}
{{- with .Values.serviceAccount.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
automountServiceAccountToken: true
{{- end }}
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: {{ include "aralez.fullname" . }}
labels:
{{- include "aralez.labels" . | nindent 4 }}
rules:
- apiGroups: ["networking.k8s.io"]
resources: ["ingresses", "ingressclasses"]
verbs: ["get", "list", "watch"]
- apiGroups: ["networking.k8s.io"]
resources: ["ingresses/status"]
verbs: ["get", "update", "patch"]
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["nodes", "services", "endpoints"]
verbs: ["get", "list", "watch"]
- apiGroups: ["discovery.k8s.io"]
resources: ["endpointslices"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: {{ include "aralez.fullname" . }}
labels:
{{- include "aralez.labels" . | nindent 4 }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: {{ include "aralez.fullname" . }}
subjects:
- kind: ServiceAccount
name: {{ include "aralez.serviceAccountName" . }}
namespace: {{ .Release.Namespace }}
+164
View File
@@ -0,0 +1,164 @@
# Default values for aralez.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
replicaCount: 1
image:
repository: ghcr.io/sadoyan/aralez
pullPolicy: IfNotPresent
# Overrides the image tag whose default is the chart appVersion.
tag: ""
imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""
# -- Environment variables
env: []
# -- Aralez arguments
args: []
# -- Aralez upstreams file body
# refs: https://aralez.rs/docs/kubernetes/
upstreams:
rate_limit: 500000
x4xx_limit: 100000
to_https: true
server_headers:
- "X-Forwarded-Proto:https"
- "X-Forwarded-Port:443"
serviceAccount:
# Specifies whether a service account should be created
create: true
# Annotations to add to the service account
annotations: {}
# The name of the service account to use.
# If not set and create is true, a name is generated using the fullname template
name: ""
# -- Annotations for pod.
# ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/
podAnnotations: {}
# cluster-autoscaler.kubernetes.io/safe-to-evict: "false"
# -- Extra labels for pod.
# ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/
podLabels: {}
# -- Pod Security Context.
# ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod
podSecurityContext:
runAsNonRoot: true
runAsUser: 9999
runAsGroup: 9999
fsGroup: 9999
fsGroupChangePolicy: "OnRootMismatch"
# -- Container Security Context.
# ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod
securityContext:
seccompProfile:
type: RuntimeDefault
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
# -- Pod host network
# Use it only for performance reason
hostNetwork: false
# -- Service node port
# refs: https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport
hostPort:
enabled: false
ports:
http: 8080
https: 8443
ingressClass: aralez
ingressClassResource:
enabled: true
controllerValue: aralez.proxy/ingress-controller
# -- Bitwarden service parameters
# ref: https://kubernetes.io/docs/user-guide/services/
service:
# -- service type
type: ClusterIP
annotations: {}
# -- IP families for service
# possible values: IPv4, IPv6
# ref: https://kubernetes.io/docs/concepts/services-networking/dual-stack/
ipFamilies: [IPv4]
# -- Resource requests and limits.
# ref: https://kubernetes.io/docs/user-guide/compute-resources/
resources:
limits:
cpu: 1
memory: 512Mi
requests:
cpu: 100m
memory: 128Mi
# -- Horizontal and Vertical pod autoscaler.
# ref: https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/
autoscaling:
enabled: false
minReplicas: 1
maxReplicas: 10
targetCPUUtilizationPercentage: 80
# -- Use a daemonset instead of a deployment
useDaemonSet: false
# -- The time in seconds that is allowed for a Aralez instance to gracefully shutdown
# ref: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks
terminationGracePeriodSeconds: 120
## updateStrategy for PostgreSQL StatefulSet and its slaves StatefulSets
## ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#update-strategies
updateStrategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
# -- Priority Class Name
# ref: https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#priorityclass
priorityClassName: ""
# Additional volumes on the output Deployment definition.
volumes: []
# - name: foo
# secret:
# secretName: mysecret
# optional: false
# Additional volumeMounts on the output Deployment definition.
volumeMounts: []
# - name: foo
# mountPath: "/etc/foo"
# readOnly: true
# -- Node labels for pod assignment.
# ref: https://kubernetes.io/docs/user-guide/node-selection/
nodeSelector: {}
# -- Tolerations for pod assignment.
# ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/
tolerations: []
# -- Pod Anti Affinity
# soft/hard
podAntiAffinityPreset: soft
# -- Affinity for pod assignment.
# ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity
affinity: {}
@@ -1,9 +0,0 @@
apiVersion: v1
kind: Secret
metadata:
name: aralez-tls
type: kubernetes.io/tls
data:
tls.crt: <base64-cert>
tls.key: <base64-key>
+8
View File
@@ -0,0 +1,8 @@
# 1. Define the IngressClass so Kubernetes knows "aralez" is a valid controller
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
name: aralez
namespace: upstreams
spec:
controller: aralez.proxy/ingress-controller
+76
View File
@@ -0,0 +1,76 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: aralez
namespace: aralez
labels:
app.kubernetes.io/name: aralez
app.kubernetes.io/component: ingress-controller
spec:
replicas: 1
selector:
matchLabels:
app: aralez
template:
metadata:
labels:
app: aralez
spec:
serviceAccountName: aralez-sa
containers:
- name: aralez
#image: sadoyan/aralez:latest
image: nginx:latest
imagePullPolicy: IfNotPresent
env:
- name: ARALEZ_SERVICE_NAME
value: "aralez-service"
- name: ARALEZ_SERVICE_NAMESPACE
value: "aralez"
- name: ARALEZ_EXTERNAL_IP # Only for bare metal deployment, remove this in Cloud.
value: "192.168.10.10" # Only for bare metal deployment, remove this in Cloud.
ports:
- name: http
containerPort: 80
- name: https
containerPort: 443
readinessProbe:
tcpSocket:
port: 80
initialDelaySeconds: 3
periodSeconds: 5
livenessProbe:
tcpSocket:
port: 80
initialDelaySeconds: 10
periodSeconds: 10
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "1"
memory: "512Mi"
volumeMounts:
- name: main-config
mountPath: /etc/aralez/main.yaml
subPath: main.yaml
readOnly: true
- name: upstreams-config
mountPath: /etc/aralez/upstreams.yml
subPath: upstreams.yml
readOnly: true
- name: tls-certs
mountPath: /etc/aralez/certificates
readOnly: true
volumes:
- name: main-config
configMap:
name: aralez-main-config
- name: upstreams-config
configMap:
name: aralez-upstreams-config
- name: tls-certs
secret:
secretName: aralez-tls
@@ -1,43 +0,0 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: aralez
spec:
replicas: 1
selector:
matchLabels:
app: aralez
template:
metadata:
labels:
app: aralez
spec:
serviceAccountName: aralez-sa
containers:
- name: aralez
image: sadoyan/aralez:latest
ports:
- containerPort: 80
- containerPort: 443
volumeMounts:
- name: main-config
mountPath: /etc/aralez/main.yaml
subPath: main.yaml
readOnly: true
- name: upstreams-config
mountPath: /etc/aralez/upstreams.yml
subPath: upstreams.yml
readOnly: true
- name: tls-certs
mountPath: /etc/aralez/certificates
readOnly: true
volumes:
- name: main-config
configMap:
name: aralez-main-config
- name: upstreams-config
configMap:
name: aralez-upstreams-config
- name: tls-certs
secret:
secretName: aralez-tls
@@ -1,14 +0,0 @@
# The file under watch and hot reload, changes are applied immediately, no need to restart or reload.
provider: "kubernetes" # "file" "consul" "kubernetes"
sticky_sessions: 172000
to_https: false
rate_limit: 500000
x4xx_limit: 100000
server_headers:
- "X-Forwarded-Proto:https"
- "X-Forwarded-Port:443"
client_headers:
- "X-Global-Client:Yooooooo"
kubernetes:
servers:
- "127.0.0.1:6443" # Gets KUBERNETES_SERVICE_HOST : KUBERNETES_SERVICE_PORT_HTTPS env variables.
+17
View File
@@ -0,0 +1,17 @@
apiVersion: v1
kind: Service
metadata:
name: aralez-service
namespace: aralez
spec:
type: NodePort
selector:
app: aralez
ports:
- name: http
port: 80
targetPort: 80
- name: https
port: 443
targetPort: 443
+9
View File
@@ -0,0 +1,9 @@
apiVersion: v1
kind: Secret
metadata:
name: aralez-tls
namespace: aralez
type: kubernetes.io/tls
data:
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUY3ekNDQTllZ0F3SUJBZ0lVUm12YytSU25LS01HNXVaV1JNS3NtS2dwU1drd0RRWUpLb1pJaHZjTkFRRUwKQlFBd2dZWXhDekFKQmdOVkJBWVRBbGhZTVJJd0VBWURWUVFJREFsVGRHRjBaVTVoYldVeEVUQVBCZ05WQkFjTQpDRU5wZEhsT1lXMWxNUlF3RWdZRFZRUUtEQXREYjIxd1lXNTVUbUZ0WlRFYk1Ca0dBMVVFQ3d3U1EyOXRjR0Z1CmVWTmxZM1JwYjI1T1lXMWxNUjB3R3dZRFZRUUREQlJEYjIxdGIyNU9ZVzFsVDNKSWIzTjBibUZ0WlRBZUZ3MHkKTmpBNE1UZ3hOREkwTVRKYUZ3MHpOakE0TVRVeE5ESTBNVEphTUlHR01Rc3dDUVlEVlFRR0V3SllXREVTTUJBRwpBMVVFQ0F3SlUzUmhkR1ZPWVcxbE1SRXdEd1lEVlFRSERBaERhWFI1VG1GdFpURVVNQklHQTFVRUNnd0xRMjl0CmNHRnVlVTVoYldVeEd6QVpCZ05WQkFzTUVrTnZiWEJoYm5sVFpXTjBhVzl1VG1GdFpURWRNQnNHQTFVRUF3d1UKUTI5dGJXOXVUbUZ0WlU5eVNHOXpkRzVoYldVd2dnSWlNQTBHQ1NxR1NJYjNEUUVCQVFVQUE0SUNEd0F3Z2dJSwpBb0lDQVFEQklZejBUNDRnVnZWdTBPMlA3NEV3NzE1c3FDekZuWHhTRDE4RnNCRHE2L1NadW1qYmpvTXBjWFZhCkVVQVQwMXpxRW9JZm5waHY3VExNWmtNNmZ6WTFNVGdOcXVqeHVXUGNVMTBES2VQa0Y1K1RPbWdoUUE1ODRCV1gKcmZrMlp5NXpGT012ODZUZXFCOGRyUVh2SWpHNTZhMW5DMFMwSFlnTnJ6R2srVXdrNWpDZTlaYURnc3Q5VlkrcApRYlZyUVdwR2V6RDl3WVE2bU41MkRGRERYbnp6WUVwRWVVekwwNkpNSlE5M2d5ZDVtbWd4aWlpbU1QMS9UTG5BClo2cWlYQ05UVGQvMERiL2tVWW9tK1hkTm11em83Qm1qaDY4ZzVTYUtYWkJXM25BQnhoaUVkZHoyaUViTGx2UFIKcXltcjVzazgyYlZQTWlWUC82alFLaTk0anBxVDc4ZVZZRG81dmhyMDQvczhVZk9xWVBEY0NLTGFzOEpBdTRvUwpoTnRjYm5GbGJjOG1Qcm00bnY2NlhKUUpIV1cwU1Rqc1pZWVRTRTllM3lMV2JqRlpUQTBIb3lQV1dDS1ZXSS82CnExa09IcnhJWitzOStHajB3aUJhdUpsbWk2by9oZE5qWUhsY2sxbnFTM2l6UXZ2WFpuSWtwTWkrU2pQRzhBZ0MKdEFqSWVPNlFOZVFFM3p3d3ZJb09tRnVTMC8zWkJFSkZuaWdxV0xuKzRidnV4eTNReW5JWHNsY250dDRXbjdMTAp0MWZtMTU3a2x6TUNHeHBWVXFqT1FwVnVuVnVmMDdURHdWbGxxek96TXlxZWdYSHlYODJxVlV2czdidCtpZFdOCngrdks1RUtrQUhidU9QV3lGRkJJci91aE93OWZsOEUxR1ZUYzg1OG5pM0NrWWtGeEpRSURBUUFCbzFNd1VUQWQKQmdOVkhRNEVGZ1FVQkFya1htNXZ2dDhmNVRGdkI0YmJNVS9EcEc4d0h3WURWUjBqQkJnd0ZvQVVCQXJrWG01dgp2dDhmNVRGdkI0YmJNVS9EcEc4d0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBTkJna3Foa2lHOXcwQkFRc0ZBQU9DCkFnRUFYdGJ3TVpkOElrTkxwWGFHeTRleGR6OVN0dVpjYnBhWjVWeURTdTJBdFZERm1BeXNSM0hHaEhWend5a0cKOGtibGdQQ3B3OEhWeGdMd0xmNHFuTWhvdUNHQ3ZiMVd2UjM5VW45NmVOWFA5cHFDTWhRTzFMU0JCSy80UllsUwp4ajhyRlBub3p5OHdFTzRwR1VaejN3LzJIdXgyTGovVHIxRXY5cklsa0hMZ3plazc1clpHTUIxUHhsRU1zUGNsCmtGY3NacGZ5TE5LM0FydUMzbmVGbldSODh5UHFVU3FwVEJ1OVRubjZUQ002TXVEZHlaRTZXYVlGU01zNzBJOU8KN3c5SkdreDc0UlAraTBQeUZUOFNhbUdncTUxWmtrUFZnK3ZZSUhTbGszdGlxZFN0MEYzMnVNaHNDZXZCcVUzQQp2M3lUOW9UUlpRZE9XKzQySDZjVTJ4Q2FCTVBRdnpaZWRtYno1eTNpS1NjMDBQUy8vMDI4YjIzbHpGQVZjbURHCnlOaUcraUJUVkRydHgwZC9qdGhqdzV4cllqNFBnNXl6emM2R3hkaC9VWGpUN1dqSUpweThnR3V2MHhMWVNQTDYKMmROUkYyVDl1TDQ0Z1J2K09ndTRRaHNacGg3WWxNZVp0aVpoT1IvTC8yUWdnZDMrNEhpeXBNNFpiWkUrMVg2TQoyNEtVdG5wZU53dE0wR1huU01aY2dkUm5LMWg0WDQ2T1lMYW9vSTdERkhSUWJSclJQSWl1eXZ2NXpPQzF5NTFFCm9rY0tvMVREQThRcXVHMlBRay9kMEZ0LzNiOEJoOHJCcTR1V3lKWHYyYTJJUmt1Q05MN0Myck5Rem92ekF0aW4KZnB5ejVKb1NHc1dUSVhSYlNucnpocWxFeUJCRGxQQ3AxTW1zM2xzZkFROThIQmM9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUpRUUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQ1Nzd2dna25BZ0VBQW9JQ0FRREJJWXowVDQ0Z1Z2VnUKME8yUDc0RXc3MTVzcUN6Rm5YeFNEMThGc0JEcTYvU1p1bWpiam9NcGNYVmFFVUFUMDF6cUVvSWZucGh2N1RMTQpaa002ZnpZMU1UZ05xdWp4dVdQY1UxMERLZVBrRjUrVE9tZ2hRQTU4NEJXWHJmazJaeTV6Rk9Ndjg2VGVxQjhkCnJRWHZJakc1NmExbkMwUzBIWWdOcnpHaytVd2s1akNlOVphRGdzdDlWWStwUWJWclFXcEdlekQ5d1lRNm1ONTIKREZERFhuenpZRXBFZVV6TDA2Sk1KUTkzZ3lkNW1tZ3hpaWltTVAxL1RMbkFaNnFpWENOVFRkLzBEYi9rVVlvbQorWGRObXV6bzdCbWpoNjhnNVNhS1haQlczbkFCeGhpRWRkejJpRWJMbHZQUnF5bXI1c2s4MmJWUE1pVlAvNmpRCktpOTRqcHFUNzhlVllEbzV2aHIwNC9zOFVmT3FZUERjQ0tMYXM4SkF1NG9TaE50Y2JuRmxiYzhtUHJtNG52NjYKWEpRSkhXVzBTVGpzWllZVFNFOWUzeUxXYmpGWlRBMEhveVBXV0NLVldJLzZxMWtPSHJ4SVorczkrR2owd2lCYQp1SmxtaTZvL2hkTmpZSGxjazFucVMzaXpRdnZYWm5Ja3BNaStTalBHOEFnQ3RBakllTzZRTmVRRTN6d3d2SW9PCm1GdVMwLzNaQkVKRm5pZ3FXTG4rNGJ2dXh5M1F5bklYc2xjbnR0NFduN0xMdDFmbTE1N2tsek1DR3hwVlVxak8KUXBWdW5WdWYwN1REd1ZsbHF6T3pNeXFlZ1hIeVg4MnFWVXZzN2J0K2lkV054K3ZLNUVLa0FIYnVPUFd5RkZCSQpyL3VoT3c5Zmw4RTFHVlRjODU4bmkzQ2tZa0Z4SlFJREFRQUJBb0lDQUNjaHhDeXdmZXpCa2VOTlJBVlpFd1UyClN4eWJDczlUdEovdjYySDhwY0RqNUdETnEzZHBMZHhVMStGVEEzZkE2TitvdG1MdndKVlZLMmpOQTZ3em9Ha3cKdXRuU0duYjRDR3JaSFV5SnpWb25DemRLcTFTcFpRWWFaV1doWTVDSllaa0J6M0trM0hBZEFva0J5T1VHT2FzZwoxUGkvQ01HeUJpSTNzRWhzRnVpWEY1enR4L3lIb1BHWlI0MlUrY3hzcWJyME5SNEZldVJnbXhxeUxoOFg0eHR4CkZEdEJsTFRzQWNPSjh0TlZhTWN6NlE2NG5ybmx6VWRnNVhZOXl3NHd1eHVpK05DN2hIa2ZxRzF6T0tBcDF2enUKOGRiM3BCMTNNTkx5V0UreHJHSS9vREllcTVIc1ZPUGxoeXVoa2NUNTh5WjRPa3Q4cnFEQi9aT0lLS3cxd000RQp1S1h3VnhmMEZzZ09pSjhCME1iY1g4OTdEdUJrV29DeHorbVlwVzByTW9EWTlhcEI3ZllZZkN2ZVJXVWt3RmJnCkdhWDZPRndwWkU5cHBOOXR4YUpKYVgrdXowT3ZySWh4c1FPamtSdTA1cXl5NjcvTG04aFpoRkVMMm1PMjBOUGMKVWpVUHpoenF1M3NHaHltR01Kb21aa3VQR1FyYnlYR2lSVjl2dWhWSHlVa3EyWXJ5ZTJpeEpUMWgreDFBZXJHbgo2ZzQxWFA5UzVTNDUzTU8wUVFDcVQ2aG9ZUnBpbUxkYlpmZjJOTmt1ZFFINS9UVjZqTGN0SjZua212ZDVTbGhPCm9YSHdkcW9jVlkrUEVZZHRyVzE5OGxhVG9JVFZQZFBBOHdwL0pmb2pGK0hSM1owQmlBMUFsWjhzL0RsM0xLWVoKb2xHUUVnQ3kwQ2xVazFZa0FiYzFBb0lCQVFEZnNiZWlwOTNrNitjSGJHdTk2eE53b1RHMEdWVnkzWDBzeVhWSAppSERvdnpTNGtzY0c0SEpteHc2S2N0ZDR5eEIvaDRuZHZ2VkV0M3RqTFQ3VGxqOTlhNWJVaTZOS3ZyNll0ZGsxCk50elFTaXJjeG81M3dNUlRSeFVNZnVPQW1Ia3VKWXduZWVFMHcxdnRBZloyR0RnVTBGbGZicThkRFc2TlFZQ0gKS01wNUtWNnJyenE2Y1g1cGNWcWRZckp6Y2REbk5YeXUyUXBDT3FSZFhFQ3RnYmxWdmF6UTh2c0t0K3Awd1NpcgpCdmFqY3c1YW1iZ2x4Zm1uWWhNY2ZkWjRqR3NrVVJmWE5JMGZUcHRwMEdNVlFYZEFkL3BScThjKzljQU1LY3p6Ck9OL0NzVjVpbHpjUDBJZzB0bU50a0tVV3dKTGRKbkp1Z1Vud200SFFtUzJWNUUwL0FvSUJBUURkQmQ4Y0NUbUgKYmJUbmVjcHJnNkd4ZUN3aW95dnVkZVJZS2NCcGdvcW5uUVdEMm9LQmVDWC9HL1lJNVIwcWxLdXZBRlEvWEd3ZAp3N1pwYlZsbUcvQTBBRjNQeW5MMlFHSWhDN1Z6cHNrSFRPOU5VOTJjS0Fhd2Erbk9nZVJSbzBhOEhucGJpcktmCjlEdzkvcjhxTWVmdzhRS3JmMDVwMEVjVVJlTTR2WlJ1cGs5bVZac0x0QmxIMjhEYXE4YnJBYlNXUjNKN1RsZEkKMHZaZE9Cd0xxWkZVTWVOR09rUjN6azAvWDNXOWVIT3RmTkZYQzU3N1Bvby9vTDNobERDcnVXalZodkM0dUttdQpLTU5CMTM2ZnFuanZ6QXcrVTdMbkhHYTlQSHp5aUhFN1B3TVNiSGlBcXpFNXdBaDlLOWJGdEttUE0wN1FudTNSClBWMVlDNk1tMGxTYkFvSUJBQkFRRU9Hck1ESGFCckx2eENUVkZvWkY3TzNEeS9EOW1wbDJ0ZWMzRXZTRGxtT1MKbHB3VnplRTNkZ0hYRVVYcFB2d0pYWXNBeFZmejNQWllMMlMrS3p6MFZ0WllXSmRyYndCRVBwNmxtK0dSRWRiYwpveXBTTzBiSG1lbFZ5enhXdG96cndVNnNYOUdNSGJPOUtsZDhrYnBjNDY0SW9xWnhhbmpXTlVaL1ZWcXg3OHhnClB0VlloUDFKV0hwb3RldTRSb256dTBwSzU0T3Q5bE9GNWxjUE02SEdodnhTRmxqRXNCOUdKNGR3YnBGNkY1UEYKNmdVOFhCcjYzZWh6Mk15N09JNVpERjgxdE5TRXJvQkFxSHpFUUszdWI1a2h2cUwwdnArZytNaVdVdXNHRllMNgozTWRUOEJQbzdPYlhOaU9XSEhXbzV4cXNTZ1R2QmJsVzVvRVc3YjBDZ2dFQWZFOWRHT3VuUzZCTWF4UjQ0TmQ4CkRkREZJZ1ljSTFaelE1TFlBWC9HZEZkQVR0U0xLajVsUUlKOWNxdEtLRFRPQ3ZOb2J1cVFkSDByRDBqTlN6elQKY0t2MEYzYUtDaTVVQXJvUEtDamFVQnpaU3Vpc2I3T2piMzZDVmYrQVp0b3FZb3ZSemNMSWpHWlZxNWluOUJkMQptSEkxU2plajVxZWFFckRzQjNHNUZqSzczWmF3U1hqVjd6Q04yMjlaeGJ1RDBqSUZGWTBPVW9zMHZXRmRoTUd1ClYyaG5wNHdHRGt3ZDdsTEdhZlpoT1daR1oyckYxQkZzdURTMEZ6ZTkyQmZEK3JTV2w0NWxBT3MwUnNmcEUreFIKY0syWEJVY1dEQjVST29YVzBLSWs3V21YVkxsbFhSanI2c3N5K3hPNURDRjhiR296SGVzRlh2WGdsakNWWnJSTgptUUtDQVFCQ044M21FMllMVWtlUTUrWVVoS1kyYktQcS9GVnA2NWNPVXZ2R2RCNGxQUTlDU01xWUc0SHR5VFJUCmdzaEdvdjRrYk5NQ2JsdnlkWkttU1RKZk16bnJhdlYrbDVJekRFZWpEUXQrUzMxdWh5OXdiMVlIaFBRNStXZ2sKbnVMcUhzWE9WKzZuWmdyMzJvUVFxeVdlTjFkUW1XTUVoYWVOVVlwamxpTFNlUm55UjVNazBCbm55clJEZGV2NQpLekpyZmdYZG5CSGdJY3M4VmxoWXZoYlFDQmpNT2FIcXp1dXJ3M21VSVJxNlNWWVR5eHprZElEM2tna0VxbDdrCnEwL3RBbkhrNHZIS1JhSU1nSmdGOVVBRG50MHVpTFdVcTZBbCsyRU5sQW16VGhmQlAxOUVPSlFuNC85L0tnOXEKTXV3ZGxLSTl5MWRpQlBmdk00R3RIcGlYaEZnVQotLS0tLUVORCBQUklWQVRFIEtFWS0tLS0tCg==
+73
View File
@@ -0,0 +1,73 @@
# Define your Ingress resource targeting Aralez
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: api-service-v2
namespace: upstreams
annotations:
# Custom annotations parsed by Aralez
aralez.rs/rate_limit: "100"
aralez.rs/x4xx_limit: "20"
aralez.rs/client_headers: '["X-Proxy-From:Aralezzzzzzzzzzz", "X-Hopar-From:Hopaaaaaaaaaaaar"]'
aralez.rs/server_headers: '["X-Proxy-Version:Aralez", "X-Po-From:Kung Fu Panda"]'
spec:
ingressClassName: aralez # Matches the IngressClass metadata.name above
rules:
- host: api-service-v2.blabla.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api-service-v2
port:
number: 80
---
# Define your Ingress resource targeting Aralez
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: wss-service-v2
namespace: upstreams
annotations:
# Custom annotations parsed by Aralez
aralez.rs/rate_limit: "50"
aralez.rs/x4xx_limit: "10"
aralez.rs/client_headers: '["X-Hors-Arev:Naturi", "X-Grand-Master:Oogway"]'
aralez.rs/server_headers: '["X-Mors-Arev:Hastat", "X-Shifu-Master:Shifu"]'
spec:
ingressClassName: aralez # Matches the IngressClass metadata.name above
rules:
- host: wss-service-v2.blabla.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: svc-nginx
port:
number: 80
---
# Define your Ingress resource targeting Aralez
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: joj-service-v2
namespace: upstreams
spec:
ingressClassName: aralez # Matches the IngressClass metadata.name above
rules:
- host: joj-service-v2.blabla.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: svc-nginx
port:
number: 80
@@ -2,6 +2,7 @@ apiVersion: apps/v1
kind: Deployment
metadata:
name: svc-nginx
namespace: upstreams
labels:
app: svc-nginx
spec:
-24
View File
@@ -1,24 +0,0 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: wss-service-v2
namespace: default
annotations:
# These custom annotations are parsed by Aralez
aralez.rs/rate_limit: "50"
aralez.rs/x4xx_limit: "10"
aralez.rs/client_headers: '["X-Some-Client:Some Custom Header", "X-Example-Client:An Example Header"]'
aralez.rs/server_headers: '["X-Some-Server:Some Custom Header", "X-Example-Server:An Example Header"]'
spec:
ingressClassName: aralez # Matches the IngressClass metadata
rules:
- host: wss-service-v2.blabla.com
http:
paths:
- path: /ws
pathType: Prefix
backend:
service:
name: svc-nginx
port:
number: 80
@@ -2,6 +2,7 @@ apiVersion: v1
kind: Service
metadata:
name: svc-nginx
namespace: upstreams
spec:
selector:
app: svc-nginx
+12
View File
@@ -0,0 +1,12 @@
apiVersion: v1
kind: Service
metadata:
name: api-service-v2
namespace: upstreams
spec:
selector:
app: svc-nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
+40
View File
@@ -0,0 +1,40 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: aralez-sa
namespace: aralez
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: aralez-role
rules:
# Watch Ingresses and IngressClasses across all namespaces
- apiGroups: ["networking.k8s.io"]
resources: ["ingresses", "ingressclasses"]
verbs: ["get", "list", "watch"]
# Update Ingress status (for setting load balancer IPs)
- apiGroups: ["networking.k8s.io"]
resources: ["ingresses/status"]
verbs: ["update", "patch"]
# Watch Services and Endpoints across all namespaces
- apiGroups: [""]
resources: ["services", "endpoints"]
verbs: ["get", "list", "watch"]
# Watch EndpointSlices across all namespaces
- apiGroups: ["discovery.k8s.io"]
resources: ["endpointslices"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: aralez-ingress
subjects:
- kind: ServiceAccount
name: aralez-sa
namespace: aralez # <--- MUST match where Aralez is deployed
roleRef:
kind: ClusterRole
name: aralez-role
apiGroup: rbac.authorization.k8s.io
+16
View File
@@ -0,0 +1,16 @@
provider: "kubernetes"
to_https: false
sticky_sessions: 86000
rate_limit: 100
x4xx_limit: 100
headers:
- "Access-Control-Allow-Origin:*"
- "Access-Control-Allow-Methods:POST, GET, OPTIONS"
- "Access-Control-Max-Age:86400"
- "Strict-Transport-Security:max-age=31536000; includeSubDomains; preload"
kubernetes:
services:
- hostname: "svc-nginx"
upstream: "svc-nginx"
path: "/"
tokenpath: "/var/run/secrets/kubernetes.io/serviceaccount/token"
+25 -16
View File
@@ -1,6 +1,6 @@
use crate::utils::consul::ConsulService;
use crate::utils::kuberconsul::match_path;
use crate::utils::kubernetes::KubeEndpoints;
use crate::utils::kubernetes::KubeEndpointSliceList;
use crate::utils::structs::{GlobalServiceMapping, InnerMap};
use ahash::HashMap;
use dashmap::DashMap;
@@ -36,7 +36,9 @@ pub struct ConsulServicesInternal {
#[serde(rename = "aralez.to_https")]
pub to_https: Option<bool>,
}
pub type ConsulServices = HashMap<String, ConsulServicesInternal>;
pub async fn for_consul_list(url: &str, token: Option<String>) -> Option<ConsulServices> {
if let Some(data) = getfromapi(url, token, "consul").await {
let yo = parse_services(data);
@@ -75,6 +77,7 @@ fn parse_services(json: Vec<u8>) -> Result<ConsulServices, serde_json::Error> {
})
.collect())
}
pub async fn for_consul(url: &str, token: Option<String>, conf: &GlobalServiceMapping) -> Option<DashMap<Arc<str>, (Vec<Arc<InnerMap>>, AtomicUsize)>> {
if let Some(data) = getfromapi(url, token, "consul").await {
let endpoints: Vec<ConsulService> = serde_json::from_slice(&data).ok()?;
@@ -103,18 +106,29 @@ pub async fn for_consul(url: &str, token: Option<String>, conf: &GlobalServiceMa
pub async fn for_kuber(url: &str, token: &str, conf: &GlobalServiceMapping) -> Option<DashMap<Arc<str>, (Vec<Arc<InnerMap>>, AtomicUsize)>> {
if let Some(data) = getfromapi(url, Some(token.to_string()), "kubernetes").await {
let endpoints: KubeEndpoints = serde_json::from_slice(&data).ok()?;
let slice_list: KubeEndpointSliceList = serde_json::from_slice(&data).ok()?;
let upstreams: DashMap<Arc<str>, (Vec<Arc<InnerMap>>, AtomicUsize)> = DashMap::new();
let mut inner_vec = Vec::new();
if let Some(subsets) = endpoints.subsets {
for subset in subsets {
if let (Some(addresses), Some(ports)) = (subset.addresses, subset.ports) {
for addr in addresses {
for port in &ports {
for slice in slice_list.items {
let ports = match &slice.ports {
Some(p) if !p.is_empty() => p,
_ => continue,
};
for ep in &slice.endpoints {
let is_ready = ep.conditions.as_ref().and_then(|c| c.ready).unwrap_or(true);
if !is_ready {
continue;
}
for addr in &ep.addresses {
for port in ports {
if let Some(port_num) = port.port {
let to_add = Arc::from(InnerMap {
address: Arc::from(addr.ip.as_str()),
port: port.port,
address: Arc::from(addr.as_str()),
port: port_num,
is_ssl: false,
is_http2: false,
to_https: conf.to_https.unwrap_or(false),
@@ -130,6 +144,7 @@ pub async fn for_kuber(url: &str, token: &str, conf: &GlobalServiceMapping) -> O
}
}
}
if !inner_vec.is_empty() {
match_path(conf, &upstreams, inner_vec);
return Some(upstreams);
@@ -137,6 +152,7 @@ pub async fn for_kuber(url: &str, token: &str, conf: &GlobalServiceMapping) -> O
}
None
}
pub async fn getfromapi(url: &str, token: Option<String>, provider: &str) -> Option<Vec<u8>> {
let (host, port, path, is_tls) = parse_url(&url).ok()?;
@@ -226,10 +242,3 @@ fn parse_url(url: &str) -> Result<(&str, u16, &str, bool), &'static str> {
Ok((host, port, uri, is_https))
}
// fn base64_decode(encoded: &str) -> Option<String> {
// let decoded_bytes = general_purpose::STANDARD.decode(encoded).unwrap_or_default();
// let decoded: Result<HashMap<String, String>, serde_json::Error> = serde_json::from_slice(&decoded_bytes);
// println!("Decoded: {:?}", decoded);
// None
// }
+28 -22
View File
@@ -7,8 +7,6 @@ use dashmap::DashMap;
use log::error;
use rand::RngExt;
use std::env;
use std::fs;
use std::path::Path;
use std::sync::Arc;
use crate::utils::kuberconsul::{clone_compare, list_to_upstreams, ServiceDiscovery};
@@ -17,25 +15,40 @@ use rustls::crypto::CryptoProvider;
use tokio::sync::mpsc::Sender;
#[derive(Debug, serde::Deserialize)]
pub struct KubeEndpoints {
pub subsets: Option<Vec<KubeSubset>>,
#[serde(rename_all = "camelCase")]
pub struct KubeEndpointSliceList {
#[serde(default)]
pub items: Vec<KubeEndpointSlice>,
}
#[derive(Debug, serde::Deserialize)]
pub struct KubeSubset {
pub addresses: Option<Vec<KubeAddress>>,
#[serde(rename_all = "camelCase")]
pub struct KubeEndpointSlice {
pub ports: Option<Vec<KubePort>>,
#[serde(default)]
pub endpoints: Vec<KubeEndpoint>,
}
#[derive(Debug, serde::Deserialize)]
pub struct KubeAddress {
pub ip: String,
#[serde(rename_all = "camelCase")]
pub struct KubeEndpoint {
#[serde(default)]
pub addresses: Vec<String>,
pub conditions: Option<KubeConditions>,
}
#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct KubeConditions {
pub ready: Option<bool>,
}
#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct KubePort {
pub port: u16,
pub port: Option<u16>,
}
pub struct KubernetesDiscovery;
#[async_trait]
@@ -54,7 +67,6 @@ impl ServiceDiscovery for KubernetesDiscovery {
let num = if end > 0 { rand::rng().random_range(0..end) } else { 0 };
let server = servers.get(num).unwrap().to_string();
let path = kuber.tokenpath.unwrap_or_else(|| "/var/run/secrets/kubernetes.io/serviceaccount/token".to_string());
let namespace = get_current_namespace().unwrap_or_else(|| "default".to_string());
let token = crate::utils::kuberconsul::read_token(path.as_str()).await;
if CryptoProvider::get_default().is_none() {
@@ -86,7 +98,6 @@ impl ServiceDiscovery for KubernetesDiscovery {
to_https: None,
redirect_to: None,
authorization: None,
// sticky_sessions: update.sticky_sessions,
rate_limit: update.rate_limit,
x4xx_limit: update.x4xx_limit,
client_headers: None,
@@ -129,7 +140,12 @@ impl ServiceDiscovery for KubernetesDiscovery {
sheader_list.insert(Arc::from(path_key), server_headers_list);
config.server_headers.insert(host_key.clone(), sheader_list);
}
let url = format!("https://{}/api/v1/namespaces/{}/endpoints/{}", server, namespace, update.service_name);
let url = format!(
"https://{}/apis/discovery.k8s.io/v1/namespaces/{}/endpointslices?labelSelector=kubernetes.io%2Fservice-name%3D{}",
server, update.namespace, update.service_name
);
let list = httpclient::for_kuber(&url, &token, &service).await;
if list.is_none() {
@@ -145,13 +161,3 @@ impl ServiceDiscovery for KubernetesDiscovery {
}
}
}
fn get_current_namespace() -> Option<String> {
let ns_path = "/var/run/secrets/kubernetes.io/serviceaccount/namespace";
if Path::new(ns_path).exists() {
if let Ok(contents) = fs::read_to_string(ns_path) {
return Some(contents.trim().to_string());
}
}
env::var("POD_NAMESPACE").ok()
}
+89 -81
View File
@@ -1,3 +1,4 @@
use dashmap::DashMap;
use futures::StreamExt;
use hyper::Uri;
use k8s_openapi::api::core::v1::{Node, Service};
@@ -11,17 +12,18 @@ use kube::{
};
use log::{error, info};
use serde_json::json;
use std::sync::Arc;
use std::time::Duration;
use tokio::sync::mpsc;
pub struct AralezRouteUpdate {
pub host: String,
pub path: String,
pub namespace: String,
pub service_name: String,
pub is_deleted: bool,
pub rate_limit: Option<isize>,
pub x4xx_limit: Option<u32>,
pub sticky_sessions: Option<u64>,
pub client_headers: Option<Vec<String>>,
pub server_headers: Option<Vec<String>>,
}
@@ -30,11 +32,14 @@ pub struct AralezRouteUpdate {
struct AralezAnnotation {
rate_limit: Option<isize>,
x4xx_limit: Option<u32>,
sticky_sessions: Option<u64>,
pub client_headers: Option<Vec<String>>,
pub server_headers: Option<Vec<String>>,
namespace: String,
client_headers: Option<Vec<String>>,
server_headers: Option<Vec<String>>,
}
lazy_static::lazy_static! {
static ref PATCHED_INGRESSES: Arc<DashMap<String, String>> = Arc::new(DashMap::new());
}
pub async fn start_ingress_watcher_with_config(
api_server: &str,
token: &str,
@@ -82,53 +87,59 @@ async fn process_ingress_change(client: &Client, ing: &Ingress, target_class: &s
if !is_deleted {
if let (Some(name), Some(ns)) = (ing.metadata.name.as_deref(), ing.metadata.namespace.as_deref()) {
let svc_name = std::env::var("ARALEZ_SERVICE_NAME").unwrap_or_else(|_| "aralez-service".to_string());
let external_ip = match discover_controller_ip(&client, ns, &svc_name).await {
Some(ip) => ip,
None => discover_node_ip(&client)
.await
.unwrap_or_else(|| std::env::var("ARALEZ_EXTERNAL_IP").unwrap_or_else(|_| "127.0.0.1".to_string())),
};
let client_clone = client.clone();
let name_clone = name.to_string();
let ns_clone = ns.to_string();
let status = ing.status.clone();
tokio::spawn(async move {
patch_ingress_status_address(&client_clone, &ns_clone, &name_clone, status.as_ref(), &external_ip).await;
});
let key = format!("{}/{}", ns, name);
let external_ip = resolve_external_ip(client).await;
let status_already_correct = ing
.status
.as_ref()
.and_then(|s| s.load_balancer.as_ref())
.and_then(|lb| lb.ingress.as_ref())
.map(|list| list.iter().any(|i| i.ip.as_deref() == Some(&external_ip)))
.unwrap_or(false);
if status_already_correct {
PATCHED_INGRESSES.insert(key, external_ip);
} else {
PATCHED_INGRESSES.insert(key.clone(), external_ip.clone());
let client_clone = client.clone();
let name_clone = name.to_string();
let ns_clone = ns.to_string();
let key_clone = key.clone();
tokio::spawn(async move {
if let Err(e) = patch_ingress_status_address(&client_clone, &ns_clone, &name_clone, &external_ip).await {
error!("Failed to patch ingress status address {}/{}: {}", &ns_clone, &name_clone, e);
PATCHED_INGRESSES.remove(&key_clone);
}
});
}
}
} else {
if let (Some(name), Some(ns)) = (ing.metadata.name.as_deref(), ing.metadata.namespace.as_deref()) {
PATCHED_INGRESSES.remove(&format!("{}/{}", ns, name));
}
}
if let Some(rules) = &spec.rules {
for rule in rules {
let host = match &rule.host {
Some(h) => h.clone(),
None => "*".to_string(),
};
let host = rule.host.clone().unwrap_or_else(|| "*".to_string());
if let Some(http) = &rule.http {
for path_entry in &http.paths {
let path = path_entry.path.clone().unwrap_or_else(|| "/".to_string());
if let Some(service) = &path_entry.backend.service {
let service_name = service.name.clone();
let mut update = AralezRouteUpdate {
let annot = parse_ingress_config(ing);
let update = AralezRouteUpdate {
host: host.clone(),
path,
service_name,
is_deleted,
rate_limit: None,
x4xx_limit: None,
sticky_sessions: None,
client_headers: None,
server_headers: None,
rate_limit: annot.rate_limit,
x4xx_limit: annot.x4xx_limit,
client_headers: annot.client_headers,
server_headers: annot.server_headers,
namespace: annot.namespace,
};
if let Some(annot) = parse_ingress_config(ing) {
update.rate_limit = annot.rate_limit;
update.x4xx_limit = annot.x4xx_limit;
update.sticky_sessions = annot.sticky_sessions;
update.client_headers = annot.client_headers;
update.server_headers = annot.server_headers;
}
if let Err(e) = tx.send(update).await {
error!("Failed to send route update to channel: {:?}", e);
}
@@ -160,54 +171,26 @@ pub async fn create_custom_k8s_client(api_server_url: &str, bearer_token: &str,
Ok(client)
}
fn parse_ingress_config(ing: &Ingress) -> Option<AralezAnnotation> {
if let Some(annotations) = &ing.metadata.annotations {
let mut clh: Option<Vec<String>> = None;
let mut srh: Option<Vec<String>> = None;
fn parse_ingress_config(ing: &Ingress) -> AralezAnnotation {
let namespace = ing.metadata.namespace.clone().unwrap_or_else(|| "default".to_string());
let annotations = ing.metadata.annotations.as_ref();
if let Some(ch) = annotations.get("aralez.rs/client_headers") {
let data: Vec<String> = serde_json::from_str(ch).unwrap_or_default();
clh = Some(data);
}
if let Some(sh) = annotations.get("aralez.rs/server_headers") {
let data: Vec<String> = serde_json::from_str(sh).unwrap_or_default();
srh = Some(data);
};
let client_headers = annotations.and_then(|a| a.get("aralez.rs/client_headers")).and_then(|ch| serde_json::from_str(ch).ok());
let annots = AralezAnnotation {
rate_limit: annotations.get("aralez.rs/rate_limit").and_then(|v| v.parse().ok()),
x4xx_limit: annotations.get("aralez.rs/x4xx_limit").and_then(|v| v.parse().ok()),
sticky_sessions: annotations.get("aralez.rs/sticky_sessions").and_then(|v| v.parse().ok()),
client_headers: clh,
server_headers: srh,
};
return Some(annots);
let server_headers = annotations.and_then(|a| a.get("aralez.rs/server_headers")).and_then(|sh| serde_json::from_str(sh).ok());
AralezAnnotation {
rate_limit: annotations.and_then(|a| a.get("aralez.rs/rate_limit")).and_then(|v| v.parse().ok()),
x4xx_limit: annotations.and_then(|a| a.get("aralez.rs/x4xx_limit")).and_then(|v| v.parse().ok()),
client_headers,
server_headers,
namespace,
}
None
}
pub async fn patch_ingress_status_address(
client: &Client,
namespace: &str,
name: &str,
current_status: Option<&k8s_openapi::api::networking::v1::IngressStatus>,
external_ip: &str,
) {
if let Some(status) = current_status {
if let Some(lb) = &status.load_balancer {
if let Some(ing_list) = &lb.ingress {
if ing_list.iter().any(|i| i.ip.as_deref() == Some(external_ip)) {
return;
}
}
}
}
pub async fn patch_ingress_status_address(client: &Client, namespace: &str, name: &str, external_ip: &str) -> Result<(), kube::Error> {
let ingresses: Api<Ingress> = Api::namespaced(client.clone(), namespace);
let patch = json!({
"apiVersion": "networking.k8s.io/v1",
"kind": "Ingress",
"status": {
"loadBalancer": {
"ingress": [
@@ -218,12 +201,17 @@ pub async fn patch_ingress_status_address(
}
}
});
let params = PatchParams::default();
let params = PatchParams::apply("aralez-ingress-controller").force();
match ingresses.patch_status(name, &params, &Patch::Apply(patch)).await {
Ok(_) => info!("Patched Ingress {}/{} ADDRESS to {}", namespace, name, external_ip),
Err(e) => error!("Failed to patch status for Ingress {}/{}: {:?}", namespace, name, e),
match ingresses.patch_status(name, &params, &Patch::Strategic(patch)).await {
Ok(_) => {
info!("Successfully patched Ingress {}/{} ADDRESS to {}", namespace, name, external_ip);
Ok(())
}
Err(e) => {
error!("Failed to patch status for Ingress {}/{}: {:?}", namespace, name, e);
Err(e)
}
}
}
@@ -269,3 +257,23 @@ pub async fn discover_controller_ip(client: &Client, namespace: &str, service_na
}
None
}
pub async fn resolve_external_ip(client: &Client) -> String {
if let Ok(ip) = std::env::var("ARALEZ_EXTERNAL_IP") {
let trimmed = ip.trim();
if !trimmed.is_empty() {
return trimmed.to_string();
}
}
let svc_name = std::env::var("ARALEZ_SERVICE_NAME").unwrap_or_else(|_| "aralez-service".to_string());
let svc_ns = std::env::var("ARALEZ_SERVICE_NAMESPACE").unwrap_or_else(|_| "aralez".to_string());
if let Some(ip) = discover_controller_ip(client, &svc_ns, &svc_name).await {
return ip;
}
if let Some(ip) = discover_node_ip(client).await {
return ip;
}
"127.0.0.1".to_string()
}
+82 -15
View File
@@ -47,28 +47,83 @@ pub static REQUESTS_BY_UPSTREAM: LazyLock<IntCounterVec> =
pub static REQUESTS_BY_VERSION: LazyLock<IntCounterVec> =
LazyLock::new(|| register_int_counter_vec!("aralez_requests_by_version_total", "Number of requests by HTTP versions", &["version"]).unwrap());
pub static HTTP_11_COUNT: LazyLock<IntCounter> = LazyLock::new(|| REQUESTS_BY_VERSION.with_label_values(&["HTTP/1.1"]));
pub static HTTP_20_COUNT: LazyLock<IntCounter> = LazyLock::new(|| REQUESTS_BY_VERSION.with_label_values(&["HTTP/2.0"]));
pub static HTTP_30_COUNT: LazyLock<IntCounter> = LazyLock::new(|| REQUESTS_BY_VERSION.with_label_values(&["HTTP/3.0"]));
pub static HTTP_10_COUNT: LazyLock<IntCounter> = LazyLock::new(|| REQUESTS_BY_VERSION.with_label_values(&["HTTP/1.0"]));
pub static HTTP_UNK_COUNT: LazyLock<IntCounter> = LazyLock::new(|| REQUESTS_BY_VERSION.with_label_values(&["Unknown"]));
pub static METHOD_GET: LazyLock<IntCounter> = LazyLock::new(|| REQUESTS_BY_METHOD.with_label_values(&["GET"]));
pub static METHOD_POST: LazyLock<IntCounter> = LazyLock::new(|| REQUESTS_BY_METHOD.with_label_values(&["POST"]));
pub static METHOD_PUT: LazyLock<IntCounter> = LazyLock::new(|| REQUESTS_BY_METHOD.with_label_values(&["PUT"]));
pub static METHOD_DELETE: LazyLock<IntCounter> = LazyLock::new(|| REQUESTS_BY_METHOD.with_label_values(&["DELETE"]));
pub static METHOD_HEAD: LazyLock<IntCounter> = LazyLock::new(|| REQUESTS_BY_METHOD.with_label_values(&["HEAD"]));
pub static METHOD_OPTIONS: LazyLock<IntCounter> = LazyLock::new(|| REQUESTS_BY_METHOD.with_label_values(&["OPTIONS"]));
pub static METHOD_PATCH: LazyLock<IntCounter> = LazyLock::new(|| REQUESTS_BY_METHOD.with_label_values(&["PATCH"]));
pub static METHOD_OTHER: LazyLock<IntCounter> = LazyLock::new(|| REQUESTS_BY_METHOD.with_label_values(&["OTHER"]));
pub static STATUS_100: LazyLock<IntCounter> = LazyLock::new(|| RESPONSE_CODES.with_label_values(&["100"]));
pub static STATUS_101: LazyLock<IntCounter> = LazyLock::new(|| RESPONSE_CODES.with_label_values(&["101"]));
pub static STATUS_200: LazyLock<IntCounter> = LazyLock::new(|| RESPONSE_CODES.with_label_values(&["200"]));
pub static STATUS_204: LazyLock<IntCounter> = LazyLock::new(|| RESPONSE_CODES.with_label_values(&["204"]));
pub static STATUS_301: LazyLock<IntCounter> = LazyLock::new(|| RESPONSE_CODES.with_label_values(&["301"]));
pub static STATUS_302: LazyLock<IntCounter> = LazyLock::new(|| RESPONSE_CODES.with_label_values(&["302"]));
pub static STATUS_304: LazyLock<IntCounter> = LazyLock::new(|| RESPONSE_CODES.with_label_values(&["304"]));
pub static STATUS_400: LazyLock<IntCounter> = LazyLock::new(|| RESPONSE_CODES.with_label_values(&["400"]));
pub static STATUS_403: LazyLock<IntCounter> = LazyLock::new(|| RESPONSE_CODES.with_label_values(&["403"]));
pub static STATUS_404: LazyLock<IntCounter> = LazyLock::new(|| RESPONSE_CODES.with_label_values(&["404"]));
pub static STATUS_500: LazyLock<IntCounter> = LazyLock::new(|| RESPONSE_CODES.with_label_values(&["500"]));
pub static STATUS_501: LazyLock<IntCounter> = LazyLock::new(|| RESPONSE_CODES.with_label_values(&["501"]));
pub static STATUS_502: LazyLock<IntCounter> = LazyLock::new(|| RESPONSE_CODES.with_label_values(&["502"]));
pub static STATUS_503: LazyLock<IntCounter> = LazyLock::new(|| RESPONSE_CODES.with_label_values(&["503"]));
pub fn calc_metrics(metric_types: &MetricTypes) {
REQUEST_COUNT.inc();
let version_str = match metric_types.version {
Version::HTTP_11 => "HTTP/1.1",
Version::HTTP_2 => "HTTP/2.0",
Version::HTTP_3 => "HTTP/3.0",
Version::HTTP_10 => "HTTP/1.0",
_ => "Unknown",
match metric_types.version {
Version::HTTP_11 => HTTP_11_COUNT.inc(),
Version::HTTP_2 => HTTP_20_COUNT.inc(),
Version::HTTP_3 => HTTP_30_COUNT.inc(),
Version::HTTP_10 => HTTP_10_COUNT.inc(),
_ => HTTP_UNK_COUNT.inc(),
};
REQUESTS_BY_VERSION.with_label_values(&[version_str]).inc();
RESPONSE_CODES.with_label_values(&[metric_types.code.unwrap_or(StatusCode::GONE).as_str()]).inc();
REQUESTS_BY_METHOD.with_label_values(&[metric_types.method.as_str()]).inc();
match metric_types.method.as_str() {
"GET" => METHOD_GET.inc(),
"POST" => METHOD_POST.inc(),
"PUT" => METHOD_PUT.inc(),
"DELETE" => METHOD_DELETE.inc(),
"HEAD" => METHOD_HEAD.inc(),
"OPTIONS" => METHOD_OPTIONS.inc(),
"PATCH" => METHOD_PATCH.inc(),
_ => METHOD_OTHER.inc(),
}
let code = metric_types.code.unwrap_or(StatusCode::GONE);
match code.as_u16() {
100 => STATUS_100.inc(),
101 => STATUS_101.inc(),
200 => STATUS_200.inc(),
204 => STATUS_204.inc(),
301 => STATUS_301.inc(),
302 => STATUS_302.inc(),
304 => STATUS_304.inc(),
400 => STATUS_400.inc(),
403 => STATUS_403.inc(),
404 => STATUS_404.inc(),
500 => STATUS_500.inc(),
501 => STATUS_501.inc(),
502 => STATUS_502.inc(),
503 => STATUS_503.inc(),
_ => RESPONSE_CODES.with_label_values(&[code.as_str()]).inc(), // Fallback for rare status codes
}
REQUESTS_BY_UPSTREAM.with_label_values(&[metric_types.upstream.as_ref()]).inc();
RESPONSE_LATENCY.observe(metric_types.latency.as_secs_f64());
if let Some(eviction) = EVICTION.get() {
CACHE_SIZE_BYTES.set(eviction.total_size() as i64);
CACHE_ITEMS.set(eviction.total_items() as i64);
CACHE_EVICTED_BYTES.set(eviction.evicted_size() as i64);
CACHE_EVICTED_ITEMS.set(eviction.evicted_items() as i64);
}
// if let Some(eviction) = EVICTION.get() {
// CACHE_SIZE_BYTES.set(eviction.total_size() as i64);
// CACHE_ITEMS.set(eviction.total_items() as i64);
// CACHE_EVICTED_BYTES.set(eviction.evicted_size() as i64);
// CACHE_EVICTED_ITEMS.set(eviction.evicted_items() as i64);
// }
}
pub(crate) fn get_memory_usage() -> usize {
@@ -87,3 +142,15 @@ pub(crate) fn get_memory_usage() -> usize {
pub fn get_open_files() -> usize {
std::fs::read_dir("/proc/self/fd").map(|dir| dir.count()).unwrap_or(0)
}
pub async fn calc_cache_metrics() {
loop {
if let Some(eviction) = EVICTION.get() {
CACHE_SIZE_BYTES.set(eviction.total_size() as i64);
CACHE_ITEMS.set(eviction.total_items() as i64);
CACHE_EVICTED_BYTES.set(eviction.evicted_size() as i64);
CACHE_EVICTED_ITEMS.set(eviction.evicted_items() as i64);
}
tokio::time::sleep(std::time::Duration::from_secs(5)).await;
}
}
+2
View File
@@ -1,5 +1,6 @@
use crate::tls::acme::order::refresh_order;
use crate::utils::discovery::{APIUpstreamProvider, ConsulProvider, Discovery, FromFileProvider, KubernetesProvider};
use crate::utils::metrics::calc_cache_metrics;
use crate::utils::parceyaml::load_configuration;
use crate::utils::structs::Configuration;
use crate::utils::tools::*;
@@ -76,6 +77,7 @@ impl BackgroundService for LB {
drop(tokio::spawn(async move {
healthcheck::hc2(uu, ff, im, (&*hc_method.to_string(), hc_interval.to_string().parse().unwrap())).await
}));
drop(tokio::spawn(async move { calc_cache_metrics().await }));
drop(tokio::spawn(async move { refresh_order(certdir, confdir).await }));
init_logging(self.config.access_log.clone());
loop {
+2 -3
View File
@@ -1,4 +1,3 @@
// use rustls::crypto::ring::default_provider;
use crate::tls::grades;
use crate::tls::load;
use crate::tls::load::CertificateConfig;
@@ -18,6 +17,7 @@ use pingora_core::prelude::{background_service, Opt};
use pingora_core::protocols::TcpKeepalive;
use pingora_core::server::Server;
use privdrop::reexports::libc::SIGQUIT;
use rustls::crypto::ring::default_provider;
use sd_notify::NotifyState;
use signal_hook::{
consts::{SIGINT, SIGTERM},
@@ -27,9 +27,8 @@ use std::sync::mpsc::{channel, Receiver, Sender};
use std::sync::Arc;
use std::time::Duration;
use std::{fs, thread};
pub fn run() {
// default_provider().install_default().expect("Failed to install rustls crypto provider");
default_provider().install_default().expect("Failed to install RusTLS crypto provider");
let parameters = Opt::parse_args();
let file = parameters.conf.clone().unwrap();
let maincfg = crate::utils::parceyaml::parce_main_config(file.as_str());