initial commit
All checks were successful
Build and Publish TechDocs / build-and-publish (push) Successful in 1m15s

Change-Id: I2e2564a72b6be9af536235fc3795fd788fd9257b
This commit is contained in:
Scaffolder
2026-04-15 15:41:22 +00:00
commit b6460c4ea3
180 changed files with 12299 additions and 0 deletions

67
.circleci/config.yml Normal file
View File

@@ -0,0 +1,67 @@
version: 2
jobs:
lint-scripts:
docker:
- image: koalaman/shellcheck-alpine
steps:
- checkout
- run:
command: |
shellcheck -x .circleci/install_charts.sh
shellcheck -x .circleci/install_tools.sh
shellcheck -x .circleci/release.sh
lint-charts:
docker:
- image: quay.io/helmpack/chart-testing:latest
steps:
- checkout
- run:
command: |
ct lint --all --validate-maintainers=false --config .circleci/ct.yaml
install-charts:
machine: true
steps:
- checkout
- run:
no_output_timeout: 20m
command: .circleci/install_charts.sh
release-charts:
machine: true
steps:
- checkout
- add_ssh_keys:
fingerprints:
- "7f:84:3b:70:a1:c8:63:8e:dc:5f:51:51:b8:f4:7c:76"
- run:
command: |
echo "export GIT_REPOSITORY_URL=$CIRCLE_REPOSITORY_URL" >> $BASH_ENV
echo "export GIT_USERNAME=$CIRCLE_PROJECT_USERNAME" >> $BASH_ENV
.circleci/install_tools.sh
.circleci/release.sh
workflows:
version: 2
lint-test-release:
jobs:
- lint-scripts:
filters:
branches:
ignore: gh-pages
- lint-charts:
filters:
branches:
ignore: gh-pages
- install-charts:
requires:
- lint-charts
filters:
branches:
ignore: gh-pages
- release-charts:
requires:
- lint-charts
- install-charts
filters:
tags:
ignore: /.*/
branches:
only: main

1
.circleci/ct.yaml Normal file
View File

@@ -0,0 +1 @@
chart-dirs: .

126
.circleci/install_charts.sh Executable file
View File

@@ -0,0 +1,126 @@
#!/bin/bash
set -o errexit
set -o nounset
set -o pipefail
readonly CT_VERSION=latest
readonly KIND_VERSION=v0.31.0
readonly CLUSTER_NAME=chart-testing
readonly REPO_ROOT="${REPO_ROOT:-$(git rev-parse --show-toplevel)}"
readonly KEDA_VERSION=2.19.0
find_latest_tag() {
if ! git describe --tags --abbrev=0 2>/dev/null; then
git rev-list --max-parents=0 --first-parent HEAD
fi
}
create_ct_container() {
echo "Starting Chart Testing container"
docker run --rm --interactive --detach --network host --name ct \
--volume "$(pwd)/.circleci/ct.yaml:/etc/ct/ct.yaml" \
--volume "$(pwd):/workdir" \
--workdir /workdir \
"quay.io/helmpack/chart-testing:${CT_VERSION}" \
cat
}
cleanup() {
echo "Removing ct container"
docker kill ct >/dev/null 2>&1 || true
}
docker_exec() {
docker exec --interactive --tty ct "$@"
}
create_kind_cluster() {
echo "Installing kind"
curl -sSLo kind "https://github.com/kubernetes-sigs/kind/releases/download/${KIND_VERSION}/kind-linux-amd64"
chmod +x kind
sudo mv kind /usr/local/bin/kind
echo "Creating cluster"
kind create cluster --name "${CLUSTER_NAME}" --wait 5m -q
echo "Copying kubeconfig to container"
local kubeconfig
kubeconfig="$(pwd)/kube-config"
kind get kubeconfig --name "${CLUSTER_NAME}" | tee "${kubeconfig}"
docker_exec mkdir -p /root/.kube
docker cp "${kubeconfig}" ct:/root/.kube/config
docker_exec kubectl cluster-info
docker_exec kubectl get nodes
}
install_local_path_provisioner() {
docker_exec kubectl delete storageclass standard
docker_exec kubectl apply -f "https://raw.githubusercontent.com/rancher/local-path-provisioner/master/deploy/local-path-storage.yaml"
}
install_keda() {
docker_exec kubectl apply -f "https://github.com/kedacore/keda/releases/download/v${KEDA_VERSION}/keda-${KEDA_VERSION}-core.yaml" || true
}
install_charts() {
docker_exec ct install --all
echo
}
main() {
pushd "${REPO_ROOT}" >/dev/null
echo "Fetching tags"
git fetch --tags
local latest_tag
latest_tag=$(find_latest_tag)
local latest_tag_rev
latest_tag_rev=$(git rev-parse --verify "${latest_tag}")
echo "${latest_tag_rev} ${latest_tag} (latest tag)"
local head_rev
head_rev=$(git rev-parse --verify HEAD)
echo "${head_rev} HEAD"
if [[ "${latest_tag_rev}" == "${head_rev}" ]]; then
echo "No code changes. Nothing to release."
exit
fi
echo "Identifying changed charts since tag ${latest_tag}"
local changed_charts=()
readarray -t changed_charts <<< "$(git diff --find-renames --name-only "${latest_tag_rev}" | grep '\.yaml$' | cut -d '/' -f 1 | sort -u)"
if [[ -n "${changed_charts[*]}" ]]; then
local changes_pending=no
for chart in "${changed_charts[@]}"; do
if [[ -f "${chart}/Chart.yaml" ]]; then
changes_pending=yes
break
fi
done
if [[ "${changes_pending}" == "yes" ]]; then
create_ct_container
trap cleanup EXIT
create_kind_cluster
install_local_path_provisioner
install_keda
install_charts
else
echo "Nothing to do. No chart changes detected."
fi
else
echo "Nothing to do. No chart changes detected."
fi
popd >/dev/null
}
main

33
.circleci/install_tools.sh Executable file
View File

@@ -0,0 +1,33 @@
#!/bin/bash
set -o errexit
readonly HELM_VERSION=3.19.4
readonly CHART_RELEASER_VERSION=1.8.1
install_helm() {
echo "Installing Helm"
curl -sSLO "https://get.helm.sh/helm-v${HELM_VERSION}-linux-amd64.tar.gz"
sudo mkdir -p "/usr/local/helm-v${HELM_VERSION}"
sudo tar -xzf "helm-v${HELM_VERSION}-linux-amd64.tar.gz" -C "/usr/local/helm-v${HELM_VERSION}"
sudo ln -s "/usr/local/helm-v${HELM_VERSION}/linux-amd64/helm" /usr/local/bin/helm
sudo chmod +x /usr/local/helm-v${HELM_VERSION}/linux-amd64/helm
rm -f "helm-v${HELM_VERSION}-linux-amd64.tar.gz"
}
install_cr() {
echo "Installing Chart Releaser"
curl -sSLO "https://github.com/helm/chart-releaser/releases/download/v${CHART_RELEASER_VERSION}/chart-releaser_${CHART_RELEASER_VERSION}_linux_amd64.tar.gz"
sudo mkdir -p "/usr/local/chart-releaser-v${CHART_RELEASER_VERSION}"
sudo tar -xzf "chart-releaser_${CHART_RELEASER_VERSION}_linux_amd64.tar.gz" -C "/usr/local/chart-releaser-v${CHART_RELEASER_VERSION}"
sudo ln -s "/usr/local/chart-releaser-v${CHART_RELEASER_VERSION}/cr" /usr/local/bin/cr
sudo chmod +x "/usr/local/chart-releaser-v${CHART_RELEASER_VERSION}/cr"
rm -f "chart-releaser_${CHART_RELEASER_VERSION}_linux_amd64.tar.gz"
}
main() {
install_helm
install_cr
}
main

105
.circleci/release.sh Executable file
View File

@@ -0,0 +1,105 @@
#!/bin/bash
set -o nounset
: "${CR_TOKEN:?Environment variable CR_TOKEN must be set}"
: "${GIT_REPOSITORY_URL:?Environment variable GIT_REPOSITORY_URL must be set}"
: "${GIT_USERNAME:?Environment variable GIT_USERNAME must be set}"
: "${GIT_EMAIL:?Environment variable GIT_EMAIL must be set}"
readonly OWNER=haproxytech
readonly GIT_REPO=helm-charts
readonly PACKAGE_PATH=.deploy
readonly CHARTS_URL=https://haproxytech.github.io/helm-charts
readonly REPO_ROOT="${REPO_ROOT:-$(git rev-parse --show-toplevel)}"
find_latest_tag() {
if ! git describe --tags --abbrev=0 2>/dev/null; then
git rev-list --max-parents=0 --first-parent HEAD
fi
}
package_chart() {
local chart="$1"
helm dependency build "${chart}"
helm package "${chart}" --destination "${PACKAGE_PATH}"
}
release_charts() {
echo "Upload Helm chart packages to GitHub"
cr upload -o "${OWNER}" -r "${GIT_REPO}" -p "${PACKAGE_PATH}"
echo "Upload Helm chart packages to GHCR OCI"
echo "${HELM_GH_TOKEN}" | helm registry login ghcr.io --username "${OWNER}" --password-stdin
for chart in "${PACKAGE_PATH}"/*.tgz; do
helm push "${chart}" "oci://ghcr.io/${OWNER}/${GIT_REPO}"
done
}
update_index() {
echo "Generating Helm chart index"
git config user.email "${GIT_EMAIL}"
git config user.name "${GIT_USERNAME}"
git checkout gh-pages
cr index -i index.yaml -o "${OWNER}" -r "${GIT_REPO}" -c "${CHARTS_URL}" -p "${PACKAGE_PATH}"
git add index.yaml
git commit --message="Update index.yaml" --signoff
git push "${GIT_REPOSITORY_URL}" gh-pages
}
main() {
pushd "${REPO_ROOT}" >/dev/null || exit 1
echo "Fetching tags"
git fetch --tags
local latest_tag
latest_tag=$(find_latest_tag)
local latest_tag_rev
latest_tag_rev=$(git rev-parse --verify "${latest_tag}")
echo "${latest_tag_rev} ${latest_tag} (latest tag)"
local head_rev
head_rev=$(git rev-parse --verify HEAD)
echo "${head_rev} HEAD"
if [[ "${latest_tag_rev}" == "${head_rev}" ]]; then
echo "No code changes. Nothing to release."
exit
fi
mkdir -p "${PACKAGE_PATH}"
echo "Identifying changed charts since tag ${latest_tag}"
local changed_charts=()
readarray -t changed_charts <<< "$(git diff --find-renames --name-only "${latest_tag_rev}" | grep 'Chart.yaml$' | cut -d '/' -f 1 | sort -u)"
if [[ -n "${changed_charts[*]}" ]]; then
local release_pending=no
for chart in "${changed_charts[@]}"; do
if [[ -f "${chart}/Chart.yaml" ]]; then
release_pending=yes
echo "Packaging chart ${chart}"
package_chart "${chart}"
fi
done
if [[ "${release_pending}" == "yes" ]]; then
release_charts
update_index
else
echo "Nothing to do. No chart changes detected."
fi
else
echo "Nothing to do. No chart changes detected."
fi
popd >/dev/null || exit 1
}
main

View File

@@ -0,0 +1,84 @@
name: Build and Push to ACR
on:
push:
branches: [ dev ]
workflow_dispatch: {}
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
AZURE_FEDERATED_TOKEN_FILE: /var/run/secrets/azure/tokens/azure-identity-token
jobs:
build:
name: Build and Push
runs-on: ubuntu-latest
if: >-
github.ref != 'refs/heads/main' && (
github.event_name == 'workflow_dispatch' ||
(github.event_name == 'push' && github.event.before != '0000000000000000000000000000000000000000')
)
permissions:
contents: read
id-token: write
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install Azure CLI
run: |
command -v az &>/dev/null || curl -sL https://aka.ms/InstallAzureCLIDeb | bash
- name: Install Docker CLI
run: |
command -v docker &>/dev/null || (apt-get update -qq && apt-get install -y docker.io)
docker --version
- name: Azure login (OIDC)
run: |
az login \
--service-principal \
--username "$AZURE_CLIENT_ID" \
--tenant "$AZURE_TENANT_ID" \
--federated-token "$(cat $AZURE_FEDERATED_TOKEN_FILE)"
echo "✓ Azure login successful"
- name: Get ACR details
run: |
ACR_NAME=$(az acr list --query "[0].name" -o tsv)
ACR_NAME="${ACR_NAME:-bstagecjotdevacr}"
echo "ACR_NAME=$ACR_NAME" >> $GITHUB_ENV
echo "ACR_LOGIN_SERVER=${ACR_NAME}.azurecr.io" >> $GITHUB_ENV
echo "✓ Using ACR: ${ACR_NAME}.azurecr.io"
- name: ACR Login
run: |
ACR_TOKEN=$(az acr login --name "$ACR_NAME" --expose-token --output tsv --query accessToken)
docker login "$ACR_LOGIN_SERVER" \
--username 00000000-0000-0000-0000-000000000000 \
--password "$ACR_TOKEN"
echo "✓ ACR login successful"
- name: Build and Push Docker image
run: |
IMAGE_TAG="${{ gitea.sha }}"
IMAGE_FULL="${ACR_LOGIN_SERVER}/haproxy-unified:${IMAGE_TAG}"
IMAGE_LATEST="${ACR_LOGIN_SERVER}/haproxy-unified:latest"
docker build -t "$IMAGE_FULL" -t "$IMAGE_LATEST" .
docker push "$IMAGE_FULL"
docker push "$IMAGE_LATEST"
echo "IMAGE_FULL=$IMAGE_FULL" >> $GITHUB_ENV
echo "✓ Pushed: $IMAGE_FULL"
- name: Build Summary
run: |
echo "### ✅ Build Successful" >> $GITHUB_STEP_SUMMARY
echo "| | |" >> $GITHUB_STEP_SUMMARY
echo "|---|---|" >> $GITHUB_STEP_SUMMARY
echo "| **Service** | haproxy-unified |" >> $GITHUB_STEP_SUMMARY
echo "| **Commit** | ${{ gitea.sha }} |" >> $GITHUB_STEP_SUMMARY
echo "| **Image** | $IMAGE_FULL |" >> $GITHUB_STEP_SUMMARY

View File

@@ -0,0 +1,138 @@
name: Integration Test
on:
pull_request:
branches: [ "main" ]
workflow_dispatch: {}
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
# ── Job 1: Platform Conformance ───────────────────────────────────────────
platform-check:
name: Platform Conformance
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Validate catalog-info.yaml
run: |
if [ ! -f catalog-info.yaml ]; then
echo "✗ catalog-info.yaml not found"
exit 1
fi
python3 -c "import yaml; list(yaml.safe_load_all(open('catalog-info.yaml')))" 2>/dev/null \
|| (pip install pyyaml -q && python3 -c "import yaml; list(yaml.safe_load_all(open('catalog-info.yaml')))")
echo "✓ catalog-info.yaml is valid YAML"
- name: Check platform files
run: |
ERRORS=0
for f in catalog-info.yaml; do
if [ ! -f "$f" ]; then
echo "✗ Missing: $f"
ERRORS=$((ERRORS+1))
else
echo "✓ Found: $f"
fi
done
if [ $ERRORS -gt 0 ]; then exit 1; fi
# ── Job 2: Unit Tests + Container Smoke ───────────────────────────────────
smoke-test:
name: Unit Tests + Container Smoke
runs-on: ubuntu-latest
needs: platform-check
timeout-minutes: 20
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Free disk space
run: |
docker system prune -f 2>/dev/null || true
df -h / 2>/dev/null || true
- name: Install Docker CLI
run: command -v docker &>/dev/null || (apt-get update -qq && apt-get install -y docker.io)
- name: Build container image
run: |
if [ -f Dockerfile ]; then
docker build -t ci-image:test .
else
echo "No Dockerfile found — skipping container smoke test"
echo "SKIP_SMOKE=true" >> $GITHUB_ENV
fi
- name: Start service and wait for health
if: env.SKIP_SMOKE != 'true'
run: |
CONTAINER_NAME="ci-${GITHUB_RUN_ID}"
PORT="${CONTAINER_PORT:-8080}"
HEALTH_PATH="${HEALTH_ENDPOINT:-/health}"
echo "CONTAINER_NAME=${CONTAINER_NAME}" >> $GITHUB_ENV
echo "CONTAINER_PORT=${PORT}" >> $GITHUB_ENV
echo "HEALTH_PATH=${HEALTH_PATH}" >> $GITHUB_ENV
docker run -d --name "${CONTAINER_NAME}" -e OTEL_SDK_DISABLED=true ci-image:test
for i in $(seq 1 10); do
CONTAINER_IP=$(docker inspect "${CONTAINER_NAME}" --format '{{.NetworkSettings.IPAddress}}' 2>/dev/null)
[ -n "${CONTAINER_IP}" ] && break
sleep 1
done
echo "CONTAINER_IP=${CONTAINER_IP}" >> $GITHUB_ENV
echo "Waiting for ${HEALTH_PATH} on ${CONTAINER_IP}:${PORT} (up to 180s)..."
DEADLINE=$(($(date +%s) + 180))
while true; do
if curl -sf "http://${CONTAINER_IP}:${PORT}${HEALTH_PATH}" >/dev/null 2>&1; then
break
fi
if [ $(date +%s) -ge $DEADLINE ]; then
echo "Timeout waiting for health check"
docker logs "${CONTAINER_NAME}" 2>&1 | tail -30
exit 1
fi
if ! docker ps --filter "name=${CONTAINER_NAME}" --format '{{.Status}}' | grep -q Up; then
echo "Container exited:"
docker logs "${CONTAINER_NAME}" 2>&1 | tail -30
exit 1
fi
echo " still waiting..."; sleep 3
done
echo "✓ Service healthy at ${CONTAINER_IP}:${PORT}${HEALTH_PATH}"
- name: Validate health response
if: env.SKIP_SMOKE != 'true'
run: |
curl -sf "http://${CONTAINER_IP}:${CONTAINER_PORT}${HEALTH_PATH}" > /tmp/health.json
echo "Health response:"
cat /tmp/health.json
echo ""
echo "✓ Container smoke test: PASSED"
- name: Cleanup
if: always()
run: docker rm -f "ci-${GITHUB_RUN_ID}" 2>/dev/null || true
- name: Post commit status
if: always()
env:
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
JOB_STATUS: ${{ job.status }}
run: |
STATE=$([[ "$JOB_STATUS" == "success" ]] && echo "success" || echo "failure")
DESC=$([[ "$STATE" == "success" ]] && echo "All checks passed" || echo "Some checks failed")
curl -sf -X POST \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/json" \
"${GITHUB_SERVER_URL}/api/v1/repos/${GITHUB_REPOSITORY}/statuses/${GITHUB_SHA}" \
-d "{\"state\":\"${STATE}\",\"context\":\"Integration Test / Unit Tests + Container Smoke (workflow_dispatch)\",\"description\":\"${DESC}\"}" \
|| true

View File

@@ -0,0 +1,149 @@
name: Security Scanning
on:
pull_request:
branches: [ "main" ]
workflow_dispatch: {}
env:
TRIVY_VERSION: "0.51.1"
GITLEAKS_VERSION: "8.18.4"
COMPONENT_ID: haproxy-unified
jobs:
# ─────────────────────────────────────────────
# 1. FILESYSTEM & DEPENDENCY SCAN
# Trivy auto-detects lockfiles (pom.xml,
# package-lock.json, go.sum, requirements.txt, etc.)
# and scans for vulns, secrets, and misconfigs.
# ─────────────────────────────────────────────
trivy-scan:
name: Trivy — Filesystem & Dependency Scan
runs-on: ubuntu-latest
steps:
- name: Checkout source
uses: actions/checkout@v4
- name: Install Trivy
run: |
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh \
| sh -s -- -b /usr/local/bin v
- name: Run Trivy filesystem scan
run: |
trivy fs \
--exit-code 0 \
--severity HIGH,CRITICAL \
--format sarif \
--output trivy-results.sarif \
--scanners vuln,secret,misconfig \
--dependency-tree \
.
- name: Upload SARIF report
uses: actions/upload-artifact@v4
if: always()
with:
name: trivy-sarif
path: trivy-results.sarif
retention-days: 30
- name: Print human-readable summary
run: |
trivy fs \
--exit-code 0 \
--severity MEDIUM,HIGH,CRITICAL \
--format table \
--scanners vuln,secret,misconfig \
.
- name: Enforce quality gate (CRITICAL fails build)
run: |
trivy fs \
--exit-code 1 \
--severity CRITICAL \
--scanners vuln,misconfig \
.
# ─────────────────────────────────────────────
# 2. SECRET SCAN — detect leaked credentials
# across full git history.
# ─────────────────────────────────────────────
gitleaks-scan:
name: Gitleaks — Secret Scan
runs-on: ubuntu-latest
steps:
- name: Checkout source (full history)
uses: actions/checkout@v4
with:
fetch-depth: 0
# Install Gitleaks binary directly — the GitHub Action
# relies on GITHUB_TOKEN which is unavailable on Gitea Act runners.
- name: Install Gitleaks
run: |
curl -sSfL "https://github.com/gitleaks/gitleaks/releases/download/v/gitleaks__linux_x64.tar.gz" \
| tar -xz -C /usr/local/bin gitleaks
- name: Run Gitleaks
run: |
gitleaks detect \
--source . \
--report-format sarif \
--report-path gitleaks-results.sarif \
--exit-code 1 \
--log-level warn
- name: Upload SARIF report
uses: actions/upload-artifact@v4
if: always()
with:
name: gitleaks-sarif
path: gitleaks-results.sarif
retention-days: 30
# ─────────────────────────────────────────────
# 3. SUMMARY — aggregate all SARIF reports
# ─────────────────────────────────────────────
security-summary:
name: Security Summary
needs:
- trivy-scan
- gitleaks-scan
runs-on: ubuntu-latest
if: always()
steps:
- name: Download all SARIF artefacts
uses: actions/download-artifact@v4
with:
pattern: "*-sarif"
merge-multiple: true
path: sarif-reports/
- name: List collected reports
run: ls -lh sarif-reports/
- name: Generate summary
run: |
echo "## Security Scan Results — " >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Report | Size |" >> $GITHUB_STEP_SUMMARY
echo "|--------|------|" >> $GITHUB_STEP_SUMMARY
for f in sarif-reports/*.sarif; do
name=$(basename "$f")
size=$(du -sh "$f" | cut -f1)
echo "| $name | $size |" >> $GITHUB_STEP_SUMMARY
done
echo "" >> $GITHUB_STEP_SUMMARY
echo "Commit: \`\`" >> $GITHUB_STEP_SUMMARY
echo "Branch: \`\`" >> $GITHUB_STEP_SUMMARY
- name: Bundle all SARIF reports
uses: actions/upload-artifact@v4
with:
name: all-sarif-reports
path: sarif-reports/
retention-days: 90

View File

@@ -0,0 +1,108 @@
name: Build and Publish TechDocs
on:
push:
branches: [main]
paths:
- "docs/**"
- "mkdocs.yml"
- "catalog-info.yaml"
workflow_dispatch: {}
env:
TECHDOCS_AZURE_BLOB_CONTAINER_NAME:
AZURE_FEDERATED_TOKEN_FILE: /var/run/secrets/azure/tokens/azure-identity-token
AZURE_ACCOUNT_NAME: "bstagecjotdevsttechdocs"
ENTITY_NAMESPACE: default
ENTITY_KIND: component
ENTITY_NAME: haproxy-unified
jobs:
build-and-publish:
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 1
- name: read and set output
id: read_env
run: |
echo "$AZURE_FEDERATED_TOKEN_FILE"
env | grep AZURE
echo "$(cat $AZURE_FEDERATED_TOKEN_FILE)"
# act-based Gitea runners run as root — sudo is not available.
# apt-get is called directly; works whether root or not.
- name: Bootstrap pip
run: |
python3 --version
if python3 -m pip --version 2>/dev/null; then
echo "pip already available"
elif python3 -m ensurepip --version 2>/dev/null; then
python3 -m ensurepip --upgrade
else
apt-get update -qq
apt-get install -y python3-pip
fi
python3 -m pip install --upgrade pip
python3 -m pip --version
- name: Install dependencies
run: |
python3 -m pip install --upgrade pip
python3 -m pip install \
mkdocs-techdocs-core==1.* \
mkdocs-git-revision-date-localized-plugin \
mkdocs-awesome-pages-plugin
npm install -g @techdocs/cli
npm cache clean --force
# mkdocs has no dry-run flag — build into a temp dir to validate config
# and catch any broken links or missing pages early.
- name: Validate MkDocs config
run: mkdocs build --strict --site-dir /tmp/mkdocs-validate
- name: Build TechDocs site
run: |
techdocs-cli generate \
--source-dir . \
--output-dir ./site \
--no-docker \
--verbose
# act runners don't include az by default — install via Microsoft's
# official script which works on Debian/Ubuntu without sudo.
- name: Install Azure CLI
run: |
if command -v az &>/dev/null; then
echo "Azure CLI already installed: $(az version --query '"azure-cli"' -o tsv)"
else
curl -sL https://aka.ms/InstallAzureCLIDeb | bash
fi
- name: Azure login (OIDC)
run: |
az login \
--service-principal \
--username "$AZURE_CLIENT_ID" \
--tenant "$AZURE_TENANT_ID" \
--federated-token "$(cat $AZURE_FEDERATED_TOKEN_FILE)"
echo "✓ Azure login successful"
- name: Publish TechDocs site
run: |
echo "$AZURE_ACCOUNT_NAME"
echo "$ENTITY_NAMESPACE"
echo "$ENTITY_KIND"
echo "$ENTITY_NAME"
techdocs-cli publish \
--publisher-type azureBlobStorage \
--storage-name "techdocs" \
--azureAccountName "$AZURE_ACCOUNT_NAME" \
--entity "$ENTITY_NAMESPACE/$ENTITY_KIND/$ENTITY_NAME"

22
.github/workflows/inactive.yml vendored Normal file
View File

@@ -0,0 +1,22 @@
name: Close inactive issues
on:
schedule:
- cron: "30 1 * * *"
jobs:
close-issues:
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- uses: actions/stale@v9
with:
days-before-issue-stale: 30
days-before-issue-close: 30
stale-issue-label: "stale"
stale-issue-message: "This issue is stale because it has been open for 30 days with no activity."
close-issue-message: "This issue was closed because it has been inactive for 30 days since being marked as stale."
days-before-pr-stale: -1
days-before-pr-close: -1
repo-token: ${{ secrets.GITHUB_TOKEN }}

34
.gitignore vendored Normal file
View File

@@ -0,0 +1,34 @@
# General files
*.tgz
.project
.deploy
# MacOS
._*
.DS_Store
# JetBrains
.idea/
*.iml
# VSC
.vscode
# Emacs
*~
\#*\#
.\#*
# Vim
[._]*.s[a-w][a-z]
[._]s[a-w][a-z]
*.un~
Session.vim
.netrwhist
# ct config files (auto-downloaded by test/ct-test.sh)
test/chart_schema.yaml
test/lintconf.yaml
# TODO
TODO

3
.pages Normal file
View File

@@ -0,0 +1,3 @@
nav:
- docs
- ...

254
CLAUDE.md Normal file
View File

@@ -0,0 +1,254 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Commands
### Linting and Template Validation (no cluster needed)
```bash
# Test all charts
./test/local-test.sh
# Test a single chart
./test/local-test.sh haproxy-unified-gateway
./test/local-test.sh kubernetes-ingress
# Helm lint a chart directly
helm lint kubernetes-ingress/
helm lint haproxy-unified-gateway/ -f haproxy-unified-gateway/ci/deployment-default-values.yaml
# Render templates to stdout
helm template test-release kubernetes-ingress/
helm template test-release haproxy-unified-gateway/ --set controller.kind=DaemonSet
helm template test-release haproxy-unified-gateway/ --api-versions monitoring.coreos.com/v1
```
### Chart-testing (ct) — matches CircleCI
```bash
# Lint all charts
./test/ct-test.sh lint
# Lint a single chart
./test/ct-test.sh lint haproxy-unified-gateway
# Install (creates a Kind cluster automatically)
./test/ct-test.sh install haproxy-unified-gateway
# Keep the Kind cluster after install tests
KIND_KEEP_CLUSTER=1 ./test/ct-test.sh install
```
### Integration Tests (real Kind cluster)
```bash
# Test all charts
./test/integration-test.sh
# Test a single chart
./test/integration-test.sh haproxy-unified-gateway
# Run a specific test scenario (defaults, daemonset, hpa, pdb, metrics-port, monitoring, hugconf-cleanup, ci)
TEST_FILTER=monitoring ./test/integration-test.sh haproxy-unified-gateway
# Keep namespaces after failure for debugging
KEEP_NS=1 ./test/integration-test.sh
```
## Contribution Requirements
- All commits require a `Signed-off-by` line (DCO): `git commit -s -m "message"`
- Any change to a chart requires a chart **version bump** in `Chart.yaml` following semver
- Submit changes to multiple charts in **separate PRs**
## Project Structure
This repo contains Helm charts for HAProxy products:
- `kubernetes-ingress/` - HAProxy Kubernetes Ingress Controller chart (mature, feature-rich)
- `haproxy/` - HAProxy community chart
- `haproxy-unified-gateway/` - HAProxy Unified Gateway (HUG) chart
## kubernetes-ingress Chart
- **Chart version**: follows its own semver (currently 1.49.x)
- **Image**: `haproxytech/kubernetes-ingress`
- **Supports**: Deployment + DaemonSet modes, IngressClass, Gateway API, HPA, KEDA, ServiceMonitor/PodMonitor, PDB, proxy service (fetch sync mode), ConfigMap-based HAProxy config, publish-service, default TLS cert generation
- **Templates**: 25 files in `templates/`
- **CI tests**: 38 test value files in `ci/`
- **Kubernetes**: >=1.23
- **Maintainer**: Dinko Korunic
## haproxy-unified-gateway Chart
- **Chart version**: 0.1.0 (appVersion 0.9.1)
- **Image**: `haproxytech/haproxy-unified-gateway`
- **Purpose**: Kubernetes Gateway API controller powered by HAProxy
- **Kubernetes**: >=1.26
- **Binary**: `/usr/local/sbin/hug` inside the container
- **Entry point**: `/start.sh`
- **Key flag**: `--hugconf-crd=<namespace>/<name>` for HugConf CRD reference
### Templates
| Template | Purpose |
|---|---|
| `_helpers.tpl` | Name, labels, image, serviceAccount, hugconfCrd, serviceMonitorName, podMonitorName helpers |
| `controller-deployment.yaml` | Deployment (when controller.kind=Deployment) |
| `controller-daemonset.yaml` | DaemonSet with hostNetwork/hostPort support (when controller.kind=DaemonSet) |
| `controller-service.yaml` | NodePort Service (HTTP 31080, HTTPS 31443, Stats 31024) |
| `controller-serviceaccount.yaml` | ServiceAccount |
| `clusterrole.yaml` | RBAC: Gateway API resources, HUG CRDs (gate.v3.haproxy.org incl. globals/defaults), core K8s resources, auth/authz for kube-rbac metrics |
| `clusterrolebinding.yaml` | ClusterRoleBinding |
| `controller-hugconf.yaml` | HugConf CR (logging, globalRef, defaultsRef configuration) — post-install hook (weight 5) |
| `controller-hugconf-cleanup.yaml` | Pre-delete hook Job that deletes the HugConf CR on `helm uninstall` |
| `controller-crdjob.yaml` | Helm hook Job: installs HUG CRDs (`--job-check-crd`) — post-install hook (weight 0) |
| `controller-crdjob-rbac.yaml` | SA + ClusterRole + Binding for CRD/GWAPI jobs |
| `controller-gwapijob.yaml` | Helm hook Job: installs Gateway API CRDs (`--job-gwapi=VERSION`) |
| `controller-hpa.yaml` | HPA (disabled by default, mutually exclusive with KEDA) |
| `controller-keda.yaml` | KEDA ScaledObject (disabled by default, Deployment only) |
| `controller-servicemonitor.yaml` | ServiceMonitor for Prometheus Operator (disabled by default, gated behind `.Capabilities.APIVersions`) |
| `controller-podmonitor.yaml` | PodMonitor for Prometheus Operator (disabled by default, gated behind `.Capabilities.APIVersions`) |
| `controller-service-metrics.yaml` | ClusterIP metrics Service with stat + metrics ports (created when serviceMonitor is enabled) |
| `controller-poddisruptionbudget.yaml` | PDB (disabled by default) |
| `controller-podsecuritypolicy.yaml` | PSP (disabled by default, K8s <1.25 only) |
| `controller-role.yaml` | Role for PSP usage |
| `controller-rolebinding.yaml` | RoleBinding for PSP Role |
| `namespace.yaml` | Optional namespace creation (pre-install hook) |
| `NOTES.txt` | Post-install instructions |
### Values Structure
- `rbac.create` - RBAC resources
- `namespace.create` - optional namespace
- `serviceAccount` - create, name, annotations
- `controller` - kind (Deployment/DaemonSet), image, replicaCount, hugconfCrd, metricsAuth, extraArgs, containerPort, resources, securityContext, probes, scheduling (nodeSelector/tolerations/affinity/topologySpreadConstraints), extraEnvs/Volumes/Containers, daemonset (useHostNetwork/useHostPort/hostPorts/hostIP), service config (incl. metrics service), serviceMonitor, podMonitor, autoscaling, keda (ScaledObject), PDB
- `hugconf` - create, name, logging (defaultLevel, categoryLevelList), globalRef, defaultsRef
- `crdjob` - enabled, podAnnotations, ttl, scheduling, resources, image override
- `gwapijob` - enabled, version (Gateway API CRD version), same options as crdjob
### Metrics
HUG exposes two separate metrics endpoints:
| Port | Name | Source | Default |
|---|---|---|---|
| 31024 | `stat` | HAProxy stats (via `--stats-port`) | Always exposed |
| 31060 | `metrics` | Controller metrics (via `--controller-port`) | Always exposed |
- `controller.metricsAuth` controls `--metrics-auth` flag; default is `kube-rbac`
- Supported values: `none`, `kube-rbac`, `basic`
- When `kube-rbac`: controller serves HTTPS, validates bearer tokens via TokenReview API
- When `none`: plain HTTP, no authentication
- ClusterRole includes `tokenreviews` and `subjectaccessreviews` for kube-rbac auth
- The metrics Service (`controller-service-metrics.yaml`) exposes both `stat` and `metrics` ports, created only when ServiceMonitor is enabled
### What HUG chart intentionally does NOT have (compared to kubernetes-ingress)
- No IngressClass
- No ConfigMap-based HAProxy configuration
- No proxy service / fetch sync mode
- No publish-service
- No default TLS cert generation
### HUG Source Project
Source code lives at: `/home/zlatko/src/gitlab.int.haproxy.com/zbratkovic/unified-k8s-gateway`
Key paths in source:
- `cmd/controller/main.go` - controller entry point
- `hug/configuration/configuration.go` - CLI flags definition
- `build/Dockerfile` - container image build
- `api/definition/` - CRD definitions
- `example/dev-init/` - example Gateway/HTTPRoute manifests
- `documentation/metrics*.md` - metrics documentation
### HUG Controller Flags
All flags (for `extraArgs`):
| Flag | Default | Description |
|---|---|---|
| `--hugconf-crd` | | `namespace/name` of the HugConf CRD |
| `--controller-name` | `gate.haproxy.org/hug` | `spec.controllerName` GatewayClass selector |
| `--ipv4-bind-address` | | IPv4 address to bind to |
| `--ipv6-bind-address` | | IPv6 address to bind to |
| `--log-type` | `json` | Log output type (`text` or `json`) |
| `--job-gwapi` | | Install Gateway API experimental CRDs for given version (e.g. `1.3.0`) and exit |
| `--namespaces` | | Comma-separated list of namespaces to monitor |
| `--stats-port` | `1024` | Port for HAProxy stats |
| `--controller-port` | `31060` | Port for controller metrics (prometheus) |
| `--sync-period` | `0` | Period for HAProxy config computation (e.g. `5s`, `1m`) |
| `--startup-sync-period` | `0` | Startup period for HAProxy config computation |
| `--cache-resync-period` | `0` | Controller-runtime manager cache SyncPeriod (default: 10 hours) |
| `--add-stats-port` | `true` | Add stats port bind to existing stats frontend |
| `--force-restart-haproxy` | `false` | Force HAProxy restart at controller startup |
| `--leader-election-enabled` | `false` | Enable leader election |
| `--with-s6-overlay` | `false` | Use s6 overlay to start/stop/restart HAProxy |
| `--with-pebble` | `false` | Use pebble to start/stop/restart HAProxy |
| `--disable-ipv4` | `false` | Disable IPv4 support |
| `--disable-ipv6` | `false` | Disable IPv6 support |
| `--job-check-crd` | `false` | Run CRD refresh job and exit |
| `-e` / `--external` | `false` | Use as external controller (out of k8s cluster) |
| `--external-config-dir` | | Path to HAProxy configuration directory |
| `--external-haproxy-binary` | | Path to HAProxy binary |
| `--external-runtime-dir` | | Path to HAProxy runtime directory |
| `--external-state-dir` | | Path to HAProxy state directory |
| `--external-aux-dir` | | Path to HAProxy aux directory |
| `--metrics-auth` | `none` | Metrics endpoint auth mode: `none`, `kube-rbac`, `basic` |
| `--metrics-basic-auth-user` | | Basic auth username (when `--metrics-auth=basic`) |
| `--metrics-basic-auth-password` | | Basic auth password (when `--metrics-auth=basic`) |
| `-t` | `false` | Simulate running HAProxy (test mode) |
Note: The HUG binary default for `--metrics-auth` is `none`, but the Helm chart overrides this to `kube-rbac` via `controller.metricsAuth`.
## CI Values Files
23 test value files in `haproxy-unified-gateway/ci/`:
- 8 DaemonSet variants (default, customnodeport, extraargs, extraenvs, extraports, hostport, serviceannotation, strategy)
- 15 Deployment variants (default, customnodeport, disabled-jobs, extraargs, extraenvs, extraports, hpa, hugconf, keda, keda-advanced, metrics-none, pdb, podmonitor, servicemonitor, strategy)
Naming convention: `<mode>-<feature>-values.yaml`
## Testing
Three test scripts in `test/`:
| Script | Purpose |
|---|---|
| `test/local-test.sh` | Offline lint + template validation (no cluster needed) |
| `test/integration-test.sh` | Deploy to a real Kind cluster and verify resources |
| `test/ct-test.sh` | Wrapper around `ct` (chart-testing), matches CircleCI pipeline |
### local-test.sh
Tests: Chart.yaml metadata, helm lint, helm template, Deployment vs DaemonSet switching, HugConf cleanup hooks, metrics port rendering + `--metrics-auth` flag, ServiceMonitor/PodMonitor rendering, all ci/ values files.
### integration-test.sh
Tests on a real Kind cluster: default install, DaemonSet mode, HPA, PDB, metrics port (container port 31060, `--metrics-auth=kube-rbac` arg), ServiceMonitor/PodMonitor with metrics Service port verification, HugConf cleanup on uninstall, all ci/ values files.
`TEST_FILTER` values: `defaults`, `daemonset`, `hpa`, `pdb`, `metrics-port`, `monitoring`, `hugconf-cleanup`, `ci`
### ct-test.sh
Runs `ct lint` and `ct install` locally, same as CircleCI. Auto-downloads `chart_schema.yaml` and `lintconf.yaml` from the ct release on first run (files are gitignored).
Modes: `lint`, `install`, `all`
### CircleCI Pipeline
`.circleci/config.yml` workflow: `lint-scripts` (shellcheck) -> `lint-charts` (ct lint) -> `install-charts` (ct install on Kind) -> `release-charts` (helm package + push to GitHub Releases, GHCR OCI, update gh-pages index).
## Conventions
- Template names prefixed with `controller-` for controller-specific resources
- All templates use `include "<chart>.fullname"` for resource naming
- All templates use `include "<chart>.namespace"` for namespace
- Helm hooks used for CRD installation jobs (post-install, pre-upgrade)
- ArgoCD hook annotations included alongside Helm hooks
- HugConf CR is a post-install hook (weight 5) that runs after the CRD job (weight 0)
- HugConf cleanup is a pre-delete hook Job
- Security context: non-root (UID 1000), CAP_NET_BIND_SERVICE, seccomp RuntimeDefault
- ServiceMonitor/PodMonitor gated behind `.Capabilities.APIVersions "monitoring.coreos.com/v1"`

89
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,89 @@
# Contributing Guidelines
Contributions are welcome via GitHub pull requests.
This document outlines the process to help get your contribution accepted.
## Sign off Your Work
The Developer Certificate of Origin (DCO) is a lightweight way for contributors to certify that they wrote or otherwise have the right to submit the code they are contributing to the project.
Here is the full text of the [DCO](http://developercertificate.org/):
```
Developer Certificate of Origin
Version 1.1
Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
1 Letterman Drive
Suite D4700
San Francisco, CA, 94129
Everyone is permitted to copy and distribute verbatim copies of this
license document, but changing it is not allowed.
Developer's Certificate of Origin 1.1
By making a contribution to this project, I certify that:
(a) The contribution was created in whole or in part by me and I
have the right to submit it under the open source license
indicated in the file; or
(b) The contribution is based upon previous work that, to the best
of my knowledge, is covered under an appropriate open source
license and I have the right under that license to submit that
work with modifications, whether created in whole or in part
by me, under the same open source license (unless I am
permitted to submit under a different license), as indicated
in the file; or
(c) The contribution was provided directly to me by some other
person who certified (a), (b) or (c) and I have not modified
it.
(d) I understand and agree that this project and the contribution
are public and that a record of the contribution (including all
personal information I submit with it, including my sign-off) is
maintained indefinitely and may be redistributed consistent with
this project or the open source license(s) involved.
```
Contributors must sign-off that they adhere to these requirements by adding a `Signed-off-by` line to commit messages.
```
This is my commit message
Signed-off-by: Random J Developer <random@developer.example.org>
```
Git has a `-s` command line option to append this automatically to your commit message:
```console
$ git commit -s -m 'This is my commit message'
```
## How to Contribute
1. Fork this repository, develop, and test your changes.
1. Remember to sign off your commits as described above.
1. Submit a pull request.
**_NOTE_**: In order to make testing and merging of PRs easier, please submit changes to multiple charts in separate PRs.
### Technical Requirements
- Must pass linting and installing with the [chart-testing](https://github.com/helm/chart-testing) tool
- Must follow [best practices](https://helm.sh/docs/chart_best_practices/) and [review guidelines](https://github.com/helm/charts/blob/master/REVIEW_GUIDELINES.md)
### Documentation Requirements
- A chart's `README.md` must include configuration options
- A chart's `NOTES.txt` must include relevant post-installation information
### Merge Approval and Release Process
- Must pass DCO check
- Must pass CI jobs for linting and installing changed charts
- Any change to a chart requires a version bump following [semver](https://semver.org/) principles
Once changes have been merged, the release job will automatically run to package and release changed charts.

176
LICENSE Normal file
View File

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

51
README.md Normal file
View File

@@ -0,0 +1,51 @@
# ![HAProxy](https://github.com/haproxytech/kubernetes-ingress/raw/master/assets/images/haproxy-weblogo-210x49.png "HAProxy")
## HAProxy Helm Charts
![GitHub](https://img.shields.io/github/license/haproxytech/helm-charts)
[![CircleCI](https://circleci.com/gh/haproxytech/helm-charts/tree/main.svg?style=svg)](https://circleci.com/gh/haproxytech/helm-charts/tree/main)
[![Artifact Hub](https://img.shields.io/endpoint?url=https://artifacthub.io/badge/repository/haproxytech)](https://artifacthub.io/packages/search?repo=haproxytech)
This repository hosts official [HAProxy Technologies](https://www.haproxy.com/) Helm Charts for deploying [HAProxy Load Balancer](https://github.com/haproxy/haproxy) and [Ingress controller](https://github.com/haproxytech/kubernetes-ingress) on [Kubernetes](https://kubernetes.io/).
### Changelogs
Changelog for **Helm charts** in this repository are maintained automatically at ArtifactHub separately for [HAProxy](https://artifacthub.io/packages/helm/haproxytech/haproxy?modal=changelog) and [Ingress controller](https://artifacthub.io/packages/helm/haproxytech/kubernetes-ingress?modal=changelog)
Changelog for the packaged projects are available separately for [HAProxy](https://github.com/haproxy/haproxy/blob/master/CHANGELOG) and [HAProxy Technologies Ingress controller](https://github.com/haproxytech/kubernetes-ingress/releases/), with release notes and other documentation available at their respective project pages.
## Before you begin
### Setup a Kubernetes Cluster
The quickest way to setup a Kubernetes cluster is with [Azure Kubernetes Service](https://azure.microsoft.com/en-us/services/kubernetes-service/), [AWS Elastic Kubernetes Service](https://aws.amazon.com/eks/) or [Google Kubernetes Engine](https://cloud.google.com/kubernetes-engine/) using their respective quick-start guides.
For setting up Kubernetes on other cloud platforms or bare-metal servers refer to the Kubernetes [getting started guide](http://kubernetes.io/docs/getting-started-guides/).
### Install Helm
Get the latest [Helm release](https://github.com/helm/helm#install).
### Add Helm chart repo
Once you have Helm installed, add the repo as follows:
```console
helm repo add haproxytech https://haproxytech.github.io/helm-charts
helm repo update
```
HAProxy Helm charts can be also found on [ArtifactHub](https://artifacthub.io/packages/search?repo=haproxytech).
## Search and install charts
```console
helm search repo haproxytech/
helm install my-release haproxytech/<chart>
```
**_NOTE_**: For instructions on how to install a chart follow instructions in its `README.md`.
## Contributing
We welcome all contributions. Please refer to [guidelines](CONTRIBUTING.md) on how to make a contribution.

101
catalog-info.yaml Normal file
View File

@@ -0,0 +1,101 @@
# ─── System: groups all per-service Components for this application ───
apiVersion: backstage.io/v1alpha1
kind: System
metadata:
name: haproxy-unified
description: "haproxy-unified — deployed via ArgoCD into demo-apps"
labels:
backstage.io/environment: "dev"
app.kubernetes.io/managed-by: "backstage"
tags:
- deployment
- argocd
annotations:
argocd/app-name: "haproxy-unified"
argocd/app-namespace: "argocd"
argocd/instance-name: ""
backstage.io/techdocs-ref: dir:.
backstage.io/source-location: "url:https://gitea.kyndemo.live/validate/haproxy-unified/src/branch/main"
backstage.io/kubernetes-namespace: "demo-apps"
backstage.io/kubernetes-label-selector: "app.kubernetes.io/managed-by=backstage"
gitea.kyndemo.live/repo-slug: "validate/haproxy-unified"
links:
- url: https://haproxy-unified.kyndemo.live
title: Live Application
icon: web
- url: https://gitea.kyndemo.live/validate/haproxy-unified
title: Repository
icon: github
- url: https://argocd.kyndemo.live/applications/haproxy-unified
title: ArgoCD App
icon: dashboard
spec:
owner: "platform-engineering"
domain: platform
dependsOn:
- component:default/argocd-service
- resource:default/k6-operator
# ─── Primary Component (always present, matches component_id) ───────
---
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: haproxy-unified
description: "haproxy-unified — deployed via ArgoCD into demo-apps"
labels:
backstage.io/environment: "dev"
app.kubernetes.io/managed-by: "backstage"
tags:
- deployment
- argocd
- load-testing
- k6
annotations:
argocd/app-name: "haproxy-unified"
argocd/app-namespace: "argocd"
argocd/instance-name: ""
backstage.io/techdocs-ref: dir:.
backstage.io/source-location: "url:https://gitea.kyndemo.live/validate/haproxy-unified/src/branch/main"
backstage.io/kubernetes-namespace: "demo-apps"
backstage.io/kubernetes-label-selector: "app=haproxy-unified"
gitea.kyndemo.live/repo-slug: "validate/haproxy-unified"
k6/enabled: "true"
k6/test-configmap: "k6-test-haproxy-unified"
k6/test-namespace: "demo-apps"
k6/target-service: "frontend"
links:
- url: https://haproxy-unified.kyndemo.live
title: Live Application
icon: web
- url: https://gitea.kyndemo.live/validate/haproxy-unified
title: Repository
icon: github
- url: https://argocd.kyndemo.live/applications/haproxy-unified
title: ArgoCD App
icon: dashboard
spec:
type: service
owner: "platform-engineering"
lifecycle: experimental
system: haproxy-unified
dependsOn:
- component:default/argocd-service
- resource:default/k6-operator
# ─── Per-service Components (from Watcher discovery) ─────────────────

65
docs/index.md Normal file
View File

@@ -0,0 +1,65 @@
# haproxy-unified
Deployed from **custom** via the Backstage Hello Demo template.
| Property | Value |
|---|---|
| **Environment** | `dev` |
| **Namespace** | `demo-apps` |
| **ArgoCD Project** | `` |
| **Branch** | `main` |
| **Observability** | Disabled |
## Quick Links
- **Repository**: [https://gitea.kyndemo.live/validate/haproxy-unified](https://gitea.kyndemo.live/validate/haproxy-unified)
- **ArgoCD**: [https://argocd.kyndemo.live/applications/haproxy-unified](https://argocd.kyndemo.live/applications/haproxy-unified)
- **Live App**: [https://haproxy-unified.kyndemo.live](https://haproxy-unified.kyndemo.live)
## Architecture
This service was scaffolded using the **Application Migration Factory** Backstage template.
**Deployment flow:**
1. Source cloned from `custom`
2. Catalog entity and CI workflows overlaid by Backstage
4. ArgoCD Application created targeting the `demo-apps` namespace
5. ArgoCD continuously syncs from the `main` branch
**ArgoCD sync path:** `kubernetes-manifests`
## Development Workflow
```bash
git clone https://gitea.kyndemo.live/validate/haproxy-unified.git
cd haproxy-unified
# make changes, then:
git add . && git commit -m "your change" && git push origin main
```
ArgoCD monitors the repository and automatically syncs changes to the `demo-apps` namespace.
## Rollback
To roll back to a previous version:
1. Open the [ArgoCD UI](https://argocd.kyndemo.live/applications/haproxy-unified)
2. Click **History and Rollback**
3. Select the desired revision and click **Rollback**
Alternatively, revert the commit in Git and push — ArgoCD will auto-sync the rollback.
## SLOs and Monitoring
Define your service level objectives here once the service is stable:
| SLI | Target | Dashboard |
|---|---|---|
| Availability | 99.9% | [Grafana](https://grafana.kyndemo.live) |
| Latency (p99) | < 500ms | [Grafana](https://grafana.kyndemo.live) |
| Error rate | < 1% | [Grafana](https://grafana.kyndemo.live) |

View File

@@ -0,0 +1,21 @@
# Patterns to ignore when building packages.
.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/

View File

@@ -0,0 +1,39 @@
# Copyright 2026 HAProxy Technologies LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
apiVersion: v2
name: haproxy-unified-gateway
description: A Helm chart for HAProxy Unified Gateway - Kubernetes Gateway API Controller
type: application
version: 1.0.0
appVersion: 1.0.1
kubeVersion: ">=1.26.0-0"
keywords:
- haproxy
- gateway-api
- gateway
- load-balancer
home: https://github.com/haproxytech/helm-charts/tree/main/haproxy-unified-gateway
sources:
- https://github.com/haproxytech/haproxy-unified-gateway
icon: https://raw.githubusercontent.com/haproxytech/helm-charts/main/kubernetes-ingress/chart-icon.png
maintainers:
- name: Zlatko Bratkovic
email: zbratkovic@haproxy.com
- name: Dinko Korunic
email: dkorunic@haproxy.com
annotations:
artifacthub.io/license: Apache-2.0
artifacthub.io/changes: |-
- Use HAProxy Unified Gateway 1.0.1 version for base image

View File

@@ -0,0 +1,495 @@
# ![HAProxy](https://github.com/haproxytech/kubernetes-ingress/raw/master/assets/images/haproxy-weblogo-210x49.png "HAProxy")
## HAProxy Unified Gateway
A Kubernetes Gateway API controller powered by HAProxy. HAProxy Unified Gateway (HUG) implements the [Gateway API](https://gateway-api.sigs.k8s.io/) specification to provide advanced traffic management capabilities.
## Introduction
This chart bootstraps a HAProxy Unified Gateway deployment/daemonset on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager.
### Prerequisites
- Kubernetes 1.26+
- Helm 3.6+ (recommended 3.7+)
## Before you begin
### Setting up a Kubernetes Cluster
The quickest way to setup a Kubernetes cluster is with [Azure Kubernetes Service](https://azure.microsoft.com/en-us/services/kubernetes-service/), [AWS Elastic Kubernetes Service](https://aws.amazon.com/eks/) or [Google Kubernetes Engine](https://cloud.google.com/kubernetes-engine/) using their respective quick-start guides.
For setting up Kubernetes on other cloud platforms or bare-metal servers refer to the Kubernetes [getting started guide](http://kubernetes.io/docs/getting-started-guides/).
### Install Helm
Get the latest [Helm release](https://github.com/helm/helm#install).
### Adding Helm chart repo
Once you have Helm installed, add the haproxytech Chart Repository as follows:
```console
helm repo add haproxytech https://haproxytech.github.io/helm-charts
helm repo update
```
## Installing the chart
To install the chart with Helm v3 as _my-release_ deployment:
```console
helm install my-release haproxytech/haproxy-unified-gateway
```
### Installing with unique name
To auto-generate controller and its resources names when installing, use the following:
```console
helm install haproxytech/haproxy-unified-gateway \
--generate-name
```
### Installing from a private registry
To install the chart using a private registry for controller into a separate namespace _prod_.
**_NOTE_**: Helm v3 requires namespace to be precreated (eg. with `kubectl create namespace prod`)
```console
helm install my-release haproxytech/haproxy-unified-gateway \
--namespace prod \
--set controller.image.tag=SOMETAG \
--set controller.imagePullSecrets[0].name=my-pull-secret
```
### Using values from YAML file
As opposed to using many `--set` invocations, much simpler approach is to define value overrides in a separate YAML file and specify them when invoking Helm:
_myhug.yaml_:
```yaml
controller:
kind: DaemonSet
service:
type: LoadBalancer
annotations:
service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled: "true"
service.beta.kubernetes.io/aws-load-balancer-internal: 0.0.0.0/0
```
And invoking Helm becomes:
```console
helm install my-release -f myhug.yaml haproxytech/haproxy-unified-gateway
```
### Installing as DaemonSet
Default controller mode is [Deployment](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/), but it is possible to use [DaemonSet](https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/) as well:
```console
helm install my-release haproxytech/haproxy-unified-gateway \
--set controller.kind=DaemonSet
```
### Installing with host networking (DaemonSet)
When using DaemonSet mode, you can enable host networking and host ports:
```console
helm install my-release haproxytech/haproxy-unified-gateway \
--set controller.kind=DaemonSet \
--set controller.daemonset.useHostNetwork=true \
--set controller.dnsPolicy=ClusterFirstWithHostNet
```
### Installing with service annotations
On some environments like EKS and GKE there might be a need to pass service annotations. Syntax can become a little tedious however:
```console
helm install my-release haproxytech/haproxy-unified-gateway \
--set controller.service.type=LoadBalancer \
--set controller.service.annotations."service\.beta\.kubernetes\.io/aws-load-balancer-internal"="0.0.0.0/0" \
--set controller.service.annotations."service\.beta\.kubernetes\.io/aws-load-balancer-cross-zone-load-balancing-enabled"="true"
```
**_NOTE_**: With helm `--set` it is needed to put quotes and escape dots in the annotation key and commas in the value string.
### Installing with Horizontal Pod Autoscaler (HPA)
[HPA](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/) automatically scales number of replicas in Deployment and adjusts replica count for the controller:
```console
helm install my-release haproxytech/haproxy-unified-gateway \
--set controller.autoscaling.enabled=true
```
### Enabling Prometheus monitoring
HUG exposes two separate metrics endpoints:
- **`stat`** (port 31024) — HAProxy native metrics (`haproxy_*` prefix): connections, request rates, backend health, latency, error codes
- **`metrics`** (port 31060) — HUG controller metrics (`hug_*` prefix): event batch processing, config generation, cert/map operations, HAProxy reloads
The chart supports both [ServiceMonitor](https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/user-guides/getting-started.md) and [PodMonitor](https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/design.md#podmonitor) for Prometheus Operator integration. These are mutually exclusive — enable only one. By default, both endpoints are scraped.
**Note:** Requires Prometheus Operator installed in the cluster. The `monitoring.coreos.com/v1` API must be available.
#### Metrics authentication
The controller metrics endpoint (`metrics` port) supports three authentication modes via `controller.metricsAuth`:
| Mode | Default | Protocol | Description |
| --- | --- | --- | --- |
| `kube-rbac` | **yes** | HTTPS | Kubernetes TokenReview/SubjectAccessReview — Prometheus authenticates with its ServiceAccount token |
| `none` | | HTTP | No authentication |
| `basic` | | HTTPS | HTTP Basic Authentication with username/password |
#### Default setup (kube-rbac)
By default the chart uses `kube-rbac` authentication. The controller serves metrics over HTTPS and validates bearer tokens via the Kubernetes API. To set it up:
**Step 1.** Create a ClusterRole that grants access to the `/metrics` endpoint and bind it to the Prometheus ServiceAccount:
```yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: hug-metrics-reader
rules:
- nonResourceURLs: ["/metrics"]
verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: hug-metrics-reader
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: hug-metrics-reader
subjects:
- kind: ServiceAccount
name: prometheus # adjust to your Prometheus SA name
namespace: monitoring # adjust to your Prometheus namespace
```
**Step 2.** Enable the ServiceMonitor (or PodMonitor). The default endpoints are pre-configured for kube-rbac — `stat` uses plain HTTP, `metrics` uses HTTPS with the Prometheus pod's ServiceAccount token:
```yaml
controller:
serviceMonitor:
enabled: true
extraLabels:
release: prometheus # match your Prometheus serviceMonitorSelector
```
That's it. The default `values.yaml` endpoints already include the correct HTTPS + bearer token configuration for the `metrics` port:
```yaml
# Default endpoints (already set in values.yaml):
endpoints:
- port: stat
path: /metrics
scheme: http
interval: 30s
- port: metrics
path: /metrics
scheme: https
interval: 30s
tlsConfig:
insecureSkipVerify: true
bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
```
#### Using no authentication
To disable metrics authentication:
```yaml
controller:
metricsAuth: none
serviceMonitor:
enabled: true
endpoints:
- port: stat
path: /metrics
scheme: http
interval: 30s
- port: metrics
path: /metrics
scheme: http
interval: 30s
```
#### Using basic authentication
```yaml
controller:
metricsAuth: basic
extraArgs:
- --metrics-basic-auth-user=prometheus
- --metrics-basic-auth-password=secret
serviceMonitor:
enabled: true
endpoints:
- port: stat
path: /metrics
scheme: http
interval: 30s
- port: metrics
path: /metrics
scheme: https
interval: 30s
tlsConfig:
insecureSkipVerify: true
basicAuth:
username:
name: hug-metrics-basic-auth
key: username
password:
name: hug-metrics-basic-auth
key: password
```
#### Using PodMonitor instead of ServiceMonitor
PodMonitor scrapes pods directly without creating an extra metrics Service. Replace `serviceMonitor` with `podMonitor` in any of the examples above:
```yaml
controller:
podMonitor:
enabled: true
extraLabels:
release: prometheus
```
### Configuring HugConf
The chart creates a HugConf custom resource for controller configuration. You can customize logging, and optionally reference Global and Defaults custom resources:
```yaml
hugconf:
logging:
defaultLevel: Debug
categoryLevelList:
- category: "gate"
level: "Debug"
- category: "k8s"
level: "Info"
# Reference a Global CR for HAProxy global section customization
globalRef:
group: gate.v3.haproxy.org
kind: Global
name: global
# Reference a Defaults CR for HAProxy defaults section customization
defaultsRef:
group: gate.v3.haproxy.org
kind: Defaults
name: haproxytech
```
The Global and Defaults CRDs are automatically installed by the CRD job. When a `globalRef` or `defaultsRef` is set, the controller uses the referenced CR to configure the HAProxy global/defaults sections. When removed, built-in defaults are restored.
### Adding extra ports
By default the chart exposes four container ports: `http` (31080), `https` (31443), `stat` (31024) and `metrics` (31060). Additional ports can be added in two places:
1. **`controller.containerPort`** — exposes the port on the container (pod spec)
2. **`controller.service.extraPorts`** — exposes the port on the Service
#### Using `--set` flags
To add a container port only (e.g. for a sidecar or internal use):
```console
helm install my-release haproxytech/haproxy-unified-gateway \
--set controller.containerPort.custom=8080
```
To also expose it on the Service:
```console
helm install my-release haproxytech/haproxy-unified-gateway \
--set controller.containerPort.custom=8080 \
--set controller.service.extraPorts[0].name=custom \
--set controller.service.extraPorts[0].port=8080 \
--set controller.service.extraPorts[0].targetPort=8080 \
--set controller.service.extraPorts[0].protocol=TCP
```
#### Using a values file
For multiple extra ports, a values file is cleaner:
```yaml
controller:
containerPort:
http: 31080
https: 31443
stat: 31024
custom: 8080
grpc: 9090
service:
extraPorts:
- name: custom
port: 8080
targetPort: 8080
protocol: TCP
- name: grpc
port: 9090
targetPort: 9090
protocol: TCP
```
#### DaemonSet with host ports
For DaemonSet mode with host ports, also add matching entries in `controller.daemonset.hostPorts`:
```yaml
controller:
kind: DaemonSet
containerPort:
http: 31080
https: 31443
stat: 31024
custom: 8080
daemonset:
useHostPort: true
hostPorts:
http: 80
https: 443
stat: 1024
custom: 8080
service:
extraPorts:
- name: custom
port: 8080
targetPort: 8080
protocol: TCP
```
### Passing extra arguments
Additional controller flags can be passed via `extraArgs`:
```yaml
controller:
extraArgs:
- --controller-name=gate.haproxy.org/hug
- --namespaces=default,production
- --leader-election-enabled
```
#### Available controller flags
| Flag | Default | Description |
| --- | --- | --- |
| `--controller-name` | `gate.haproxy.org/hug` | `spec.controllerName` GatewayClass selector |
| `--namespaces` | | Comma-separated list of namespaces to monitor |
| `--ipv4-bind-address` | | IPv4 address to bind to |
| `--ipv6-bind-address` | | IPv6 address to bind to |
| `--disable-ipv4` | `false` | Disable IPv4 support |
| `--disable-ipv6` | `false` | Disable IPv6 support |
| `--stats-port` | `1024` | Port for HAProxy stats |
| `--controller-port` | `31060` | Port for controller metrics (prometheus) |
| `--log-type` | `json` | Log output type (`text` or `json`) |
| `--sync-period` | `0` | Period at which the controller computes HAProxy configuration (e.g. `5s`, `1m`) |
| `--startup-sync-period` | `0` | Startup period for HAProxy config computation |
| `--cache-resync-period` | `0` | Controller-runtime manager cache SyncPeriod (defaults to 10 hours if not set) |
| `--leader-election-enabled` | `false` | Enable leader election |
| `--add-stats-port` | `true` | Add stats port bind to existing stats frontend |
| `--metrics-auth` | `none` | Metrics endpoint auth mode: `none`, `kube-rbac`, `basic` |
| `--metrics-basic-auth-user` | | Basic auth username (when `--metrics-auth=basic`) |
| `--metrics-basic-auth-password` | | Basic auth password (when `--metrics-auth=basic`) |
**Note:** The `--hugconf-crd` flag is set automatically by the chart via the `hugconfCrd` helper. The `--job-check-crd` and `--job-gwapi` flags are used internally by the CRD/Gateway API installation jobs.
### Installing with KEDA autoscaling
[KEDA](https://keda.sh/) provides event-driven autoscaling. It is mutually exclusive with HPA — when KEDA is enabled, HPA is automatically disabled even if `autoscaling.enabled` is set to `true`.
```yaml
controller:
keda:
enabled: true
minReplicas: 2
maxReplicas: 20
pollingInterval: 30
cooldownPeriod: 300
restoreToOriginalReplicaCount: false
scaledObject:
annotations: {}
triggers:
- type: prometheus
metadata:
serverAddress: http://<prometheus-host>:9090
metricName: haproxy_process_idle_time_percent
threshold: '50'
query: avg(100-avg_over_time(haproxy_process_idle_time_percent{job="haproxy-unified-gateway"}[2m]))
```
Optional advanced configuration:
```yaml
controller:
keda:
enabled: true
# ...triggers, minReplicas, maxReplicas...
fallback:
failureThreshold: 3
replicas: 5
horizontalPodAutoscalerConfig:
behavior:
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Pods
value: 1
periodSeconds: 300
```
### Disabling CRD/Gateway API installation jobs
By default, the chart includes Helm hook jobs that install HUG CRDs and Gateway API CRDs. To disable them:
```console
helm install my-release haproxytech/haproxy-unified-gateway \
--set crdjob.enabled=false \
--set gwapijob.enabled=false
```
## Upgrading the chart
To upgrade the _my-release_ deployment:
```console
helm upgrade my-release haproxytech/haproxy-unified-gateway
```
## Uninstalling the chart
To uninstall/delete the _my-release_ deployment:
```console
helm delete my-release
```
## Debugging
It is possible to generate a set of YAML files for testing/debugging:
```console
helm install my-release haproxytech/haproxy-unified-gateway \
--debug \
--dry-run
```
## Contributing
We welcome all contributions. Please refer to [guidelines](../CONTRIBUTING.md) on how to make a contribution.

View File

@@ -0,0 +1,12 @@
controller:
kind: DaemonSet
service:
type: NodePort
http:
port: 8080
targetPort: 8080
nodePort: 30080
https:
port: 8443
targetPort: 8443
nodePort: 30443

View File

@@ -0,0 +1,2 @@
controller:
kind: DaemonSet

View File

@@ -0,0 +1,5 @@
controller:
kind: DaemonSet
extraArgs:
- --controller-name=gate.haproxy.org/hug
- --namespaces=default

View File

@@ -0,0 +1,7 @@
controller:
kind: DaemonSet
extraEnvs:
- name: TEST_STR1
value: foo
- name: TEST_STR2
value: baz

View File

@@ -0,0 +1,21 @@
## Test: DaemonSet with extra container and service ports, including host ports
controller:
kind: DaemonSet
containerPort:
http: 31080
https: 31443
stat: 31024
custom: 8080
daemonset:
useHostPort: true
hostPorts:
http: 80
https: 443
stat: 1024
custom: 8080
service:
extraPorts:
- name: custom
port: 8080
targetPort: 8080
protocol: TCP

View File

@@ -0,0 +1,8 @@
controller:
kind: DaemonSet
daemonset:
useHostPort: true
hostPorts:
http: 80
https: 443
stat: 1024

View File

@@ -0,0 +1,5 @@
controller:
kind: DaemonSet
service:
annotations:
service.beta.kubernetes.io/aws-load-balancer-internal: 0.0.0.0/0

View File

@@ -0,0 +1,7 @@
controller:
kind: DaemonSet
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 0
maxSurge: 1

View File

@@ -0,0 +1,11 @@
controller:
service:
type: NodePort
http:
port: 8080
targetPort: 8080
nodePort: 30080
https:
port: 8443
targetPort: 8443
nodePort: 30443

View File

@@ -0,0 +1 @@
#

View File

@@ -0,0 +1,4 @@
crdjob:
enabled: false
gwapijob:
enabled: false

View File

@@ -0,0 +1,4 @@
controller:
extraArgs:
- --controller-name=gate.haproxy.org/hug
- --namespaces=default

View File

@@ -0,0 +1,6 @@
controller:
extraEnvs:
- name: TEST_STR1
value: foo
- name: TEST_STR2
value: baz

View File

@@ -0,0 +1,14 @@
## Test: Deployment with extra container and service ports
controller:
kind: Deployment
containerPort:
http: 31080
https: 31443
stat: 31024
custom: 8080
service:
extraPorts:
- name: custom
port: 8080
targetPort: 8080
protocol: TCP

View File

@@ -0,0 +1,6 @@
controller:
autoscaling:
enabled: true
minReplicas: 1
maxReplicas: 5
targetCPUUtilizationPercentage: 80

View File

@@ -0,0 +1,8 @@
hugconf:
logging:
defaultLevel: Debug
categoryLevelList:
- category: "gate"
level: "Debug"
- category: "k8s"
level: "Info"

View File

@@ -0,0 +1,34 @@
controller:
keda:
enabled: true
minReplicas: 1
maxReplicas: 10
pollingInterval: 15
cooldownPeriod: 600
restoreToOriginalReplicaCount: true
scaledObject:
annotations: {}
fallback:
failureThreshold: 3
replicas: 5
horizontalPodAutoscalerConfig:
behavior:
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Pods
value: 1
periodSeconds: 300
triggers:
- type: prometheus
metadata:
serverAddress: http://prometheus:9090
metricName: haproxy_process_idle_time_percent
threshold: '50'
query: avg(100-avg_over_time(haproxy_process_idle_time_percent{job="haproxy-unified-gateway"}[2m]))
# HPA should be ignored when KEDA is enabled
autoscaling:
enabled: true
minReplicas: 1
maxReplicas: 5
targetCPUUtilizationPercentage: 80

View File

@@ -0,0 +1,18 @@
controller:
keda:
enabled: true
minReplicas: 2
maxReplicas: 20
pollingInterval: 30
cooldownPeriod: 300
restoreToOriginalReplicaCount: false
scaledObject:
annotations:
test-annotation: "test-value"
triggers:
- type: prometheus
metadata:
serverAddress: http://prometheus:9090
metricName: haproxy_process_idle_time_percent
threshold: '50'
query: avg(100-avg_over_time(haproxy_process_idle_time_percent{job="haproxy-unified-gateway"}[2m]))

View File

@@ -0,0 +1,14 @@
## Test: Deployment with metricsAuth=none (plain HTTP controller metrics)
controller:
metricsAuth: none
serviceMonitor:
enabled: true
endpoints:
- port: stat
path: /metrics
scheme: http
interval: 30s
- port: metrics
path: /metrics
scheme: http
interval: 30s

View File

@@ -0,0 +1,5 @@
controller:
replicaCount: 2
podDisruptionBudget:
enabled: true
minAvailable: 1

View File

@@ -0,0 +1,10 @@
controller:
podMonitor:
enabled: true
extraLabels:
release: prometheus
endpoints:
- port: stat
path: /metrics
scheme: http
interval: 30s

View File

@@ -0,0 +1,18 @@
## Test: Deployment with ServiceMonitor (both stat and controller metrics endpoints)
controller:
serviceMonitor:
enabled: true
extraLabels:
release: prometheus
endpoints:
- port: stat
path: /metrics
scheme: http
interval: 30s
- port: metrics
path: /metrics
scheme: https
interval: 30s
tlsConfig:
insecureSkipVerify: true
bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token

View File

@@ -0,0 +1,6 @@
controller:
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 0
maxSurge: 1

View File

@@ -0,0 +1,51 @@
{{/*
Copyright 2026 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
HAProxy Unified Gateway has been installed.
{{- if .Values.controller.service.enabled }}
The controller is exposed via a {{ .Values.controller.service.type }} Service:
- HTTP: {{ .Values.controller.service.http.port }}
- HTTPS: {{ .Values.controller.service.https.port }}
- Stats: {{ .Values.controller.service.stat.port }}
{{- if eq .Values.controller.service.type "NodePort" }}
Access the gateway using your node IP and the configured NodePort:
export NODE_IP=$(kubectl get nodes -o jsonpath='{.items[0].status.addresses[?(@.type=="ExternalIP")].address}')
echo "HTTP: http://$NODE_IP:{{ .Values.controller.service.http.nodePort }}"
echo "HTTPS: https://$NODE_IP:{{ .Values.controller.service.https.nodePort }}"
{{- else if eq .Values.controller.service.type "LoadBalancer" }}
It may take a few minutes for the LoadBalancer IP to be available.
Watch the status with:
kubectl get svc {{ include "haproxy-unified-gateway.fullname" . }} -n {{ include "haproxy-unified-gateway.namespace" . }} -w
{{- end }}
{{- end }}
{{- if .Values.crdjob.enabled }}
A post-install/pre-upgrade Job will install/update the HUG CRDs automatically.
{{- end }}
{{- if .Values.gwapijob.enabled }}
A post-install/pre-upgrade Job will install Gateway API CRDs (v{{ .Values.gwapijob.version }}).
{{- end }}
To check the controller status:
kubectl get pods -n {{ include "haproxy-unified-gateway.namespace" . }} -l "{{ include "haproxy-unified-gateway.selectorLabels" . | replace "\n" "," }}"
For more information, visit: https://github.com/haproxytech/haproxy-unified-gateway

View File

@@ -0,0 +1,174 @@
{{/*
Copyright 2026 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{/*
Expand the name of the chart.
*/}}
{{- define "haproxy-unified-gateway.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Create a default fully qualified app name.
*/}}
{{- define "haproxy-unified-gateway.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 "haproxy-unified-gateway.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Namespace to use.
*/}}
{{- define "haproxy-unified-gateway.namespace" -}}
{{- default .Release.Namespace .Values.namespaceOverride }}
{{- end }}
{{/*
Selector labels.
*/}}
{{- define "haproxy-unified-gateway.selectorLabels" -}}
app.kubernetes.io/name: {{ include "haproxy-unified-gateway.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/*
Helm chart metadata labels.
*/}}
{{- define "haproxy-unified-gateway.helmChartLabels" -}}
helm.sh/chart: {{ include "haproxy-unified-gateway.chart" . }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{/*
Common labels (selector + chart metadata).
*/}}
{{- define "haproxy-unified-gateway.labels" -}}
{{ include "haproxy-unified-gateway.selectorLabels" . }}
{{ include "haproxy-unified-gateway.helmChartLabels" . }}
{{- end }}
{{/*
ServiceAccount name.
*/}}
{{- define "haproxy-unified-gateway.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "haproxy-unified-gateway.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}
{{/*
Controller image.
*/}}
{{- define "haproxy-unified-gateway.image" -}}
{{- $tag := default .Chart.AppVersion .Values.controller.image.tag -}}
{{- printf "%s:%s" .Values.controller.image.repository $tag }}
{{- end }}
{{/*
CRD Job ServiceAccount/RBAC name.
*/}}
{{- define "haproxy-unified-gateway.crdjob.saName" -}}
{{- printf "%s-crdjob" (include "haproxy-unified-gateway.fullname" .) | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Metrics Service name.
*/}}
{{- define "haproxy-unified-gateway.metricsServiceName" -}}
{{- printf "%s-metrics" (include "haproxy-unified-gateway.fullname" .) | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
HugConf cleanup Job name.
*/}}
{{- define "haproxy-unified-gateway.hugconfCleanup.fullname" -}}
{{- printf "%s-hugconf-cleanup" (include "haproxy-unified-gateway.fullname" .) | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
CRD Job labels.
*/}}
{{- define "haproxy-unified-gateway.crdjobLabels" -}}
{{ include "haproxy-unified-gateway.helmChartLabels" . }}
app.kubernetes.io/name: {{ include "haproxy-unified-gateway.name" . }}-crdjob
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/*
CRD Job fullname (includes revision for uniqueness).
*/}}
{{- define "haproxy-unified-gateway.crdjob.fullname" -}}
{{- printf "%s-crdjob-%d" (include "haproxy-unified-gateway.fullname" .) .Release.Revision | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Gateway API Job labels.
*/}}
{{- define "haproxy-unified-gateway.gwapijobLabels" -}}
{{ include "haproxy-unified-gateway.helmChartLabels" . }}
app.kubernetes.io/name: {{ include "haproxy-unified-gateway.name" . }}-gwapijob
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/*
Gateway API Job fullname (includes revision for uniqueness).
*/}}
{{- define "haproxy-unified-gateway.gwapijob.fullname" -}}
{{- printf "%s-gwapijob-%d" (include "haproxy-unified-gateway.fullname" .) .Release.Revision | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
ServiceMonitor name.
*/}}
{{- define "haproxy-unified-gateway.serviceMonitorName" -}}
{{- default (include "haproxy-unified-gateway.fullname" .) .Values.controller.serviceMonitor.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
PodMonitor name.
*/}}
{{- define "haproxy-unified-gateway.podMonitorName" -}}
{{- default (include "haproxy-unified-gateway.fullname" .) .Values.controller.podMonitor.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
HugConf CRD reference path (namespace/name).
*/}}
{{- define "haproxy-unified-gateway.hugconfCrd" -}}
{{- if .Values.controller.hugconfCrd }}
{{- .Values.controller.hugconfCrd }}
{{- else }}
{{- printf "%s/%s" (include "haproxy-unified-gateway.namespace" .) .Values.hugconf.name }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,138 @@
{{/*
Copyright 2026 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if .Values.rbac.create }}
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: {{ include "haproxy-unified-gateway.fullname" . }}
labels:
{{- include "haproxy-unified-gateway.labels" . | nindent 4 }}
rules:
- apiGroups:
- "apiextensions.k8s.io"
resources:
- customresourcedefinitions
verbs:
- get
- list
- watch
- update
- apiGroups:
- ""
resources:
- configmaps
- endpoints
- nodes
- pods
- services
- namespaces
- events
- serviceaccounts
verbs:
- get
- list
- watch
- create
- patch
- update
- apiGroups:
- ""
resources:
- secrets
verbs:
- get
- list
- watch
- create
- patch
- update
- apiGroups:
- "discovery.k8s.io"
resources:
- endpointslices
verbs:
- get
- list
- watch
- apiGroups:
- "apps"
resources:
- replicasets
- deployments
- daemonsets
verbs:
- get
- list
- apiGroups:
- gateway.networking.k8s.io
resources:
- gatewayclasses
- gateways
- httproutes
- referencegrants
- grpcroutes
- tlsroutes
verbs:
- list
- watch
- apiGroups:
- gateway.networking.k8s.io
resources:
- gatewayclasses/status
- gateways/status
- httproutes/status
- referencegrants/status
- grpcroutes/status
- tlsroutes/status
verbs:
- get
- update
- patch
- apiGroups:
- coordination.k8s.io
resources:
- leases
verbs:
- create
- get
- update
- apiGroups:
- gate.v3.haproxy.org
resources:
- huggates
- hugconfs
- backends
- globals
- defaults
verbs:
- get
- list
- watch
# Required for kube-rbac metrics auth (TokenReview + SubjectAccessReview)
- apiGroups:
- authentication.k8s.io
resources:
- tokenreviews
verbs:
- create
- apiGroups:
- authorization.k8s.io
resources:
- subjectaccessreviews
verbs:
- create
{{- end }}

View File

@@ -0,0 +1,32 @@
{{/*
Copyright 2026 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if .Values.rbac.create }}
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: {{ include "haproxy-unified-gateway.fullname" . }}
labels:
{{- include "haproxy-unified-gateway.labels" . | nindent 4 }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: {{ include "haproxy-unified-gateway.fullname" . }}
subjects:
- kind: ServiceAccount
name: {{ include "haproxy-unified-gateway.serviceAccountName" . }}
namespace: {{ include "haproxy-unified-gateway.namespace" . }}
{{- end }}

View File

@@ -0,0 +1,72 @@
{{/*
Copyright 2026 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if or .Values.crdjob.enabled .Values.gwapijob.enabled }}
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ include "haproxy-unified-gateway.crdjob.saName" . }}
namespace: {{ include "haproxy-unified-gateway.namespace" . }}
labels:
{{- include "haproxy-unified-gateway.crdjobLabels" . | nindent 4 }}
annotations:
"helm.sh/hook": post-install,pre-upgrade
"helm.sh/hook-weight": "-5"
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: {{ include "haproxy-unified-gateway.crdjob.saName" . }}
labels:
{{- include "haproxy-unified-gateway.crdjobLabels" . | nindent 4 }}
annotations:
"helm.sh/hook": post-install,pre-upgrade
"helm.sh/hook-weight": "-5"
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
rules:
- apiGroups:
- "apiextensions.k8s.io"
resources:
- customresourcedefinitions
verbs:
- get
- list
- watch
- create
- update
- patch
- delete
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: {{ include "haproxy-unified-gateway.crdjob.saName" . }}
labels:
{{- include "haproxy-unified-gateway.crdjobLabels" . | nindent 4 }}
annotations:
"helm.sh/hook": post-install,pre-upgrade
"helm.sh/hook-weight": "-5"
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: {{ include "haproxy-unified-gateway.crdjob.saName" . }}
subjects:
- kind: ServiceAccount
name: {{ include "haproxy-unified-gateway.crdjob.saName" . }}
namespace: {{ include "haproxy-unified-gateway.namespace" . }}
{{- end }}

View File

@@ -0,0 +1,96 @@
{{/*
Copyright 2026 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if .Values.crdjob.enabled }}
apiVersion: batch/v1
kind: Job
metadata:
name: {{ include "haproxy-unified-gateway.crdjob.fullname" . }}
namespace: {{ include "haproxy-unified-gateway.namespace" . }}
labels:
{{- include "haproxy-unified-gateway.crdjobLabels" . | nindent 4 }}
annotations:
"helm.sh/hook": post-install,pre-upgrade
"helm.sh/hook-weight": "0"
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
"argocd.argoproj.io/hook": PostSync
{{- with .Values.crdjob.podAnnotations }}
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- with .Values.crdjob.ttlSecondsAfterFinished }}
ttlSecondsAfterFinished: {{ . }}
{{- end }}
template:
metadata:
labels:
{{- include "haproxy-unified-gateway.crdjobLabels" . | nindent 8 }}
{{- with .Values.crdjob.podAnnotations }}
annotations:
{{- toYaml . | nindent 8 }}
{{- end }}
spec:
serviceAccountName: {{ include "haproxy-unified-gateway.crdjob.saName" . }}
restartPolicy: Never
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
seccompProfile:
type: RuntimeDefault
{{- with .Values.controller.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
containers:
- name: crdjob
{{- if .Values.crdjob.image.repository }}
image: {{ printf "%s:%s" .Values.crdjob.image.repository (default .Chart.AppVersion .Values.crdjob.image.tag) }}
{{- else }}
image: {{ include "haproxy-unified-gateway.image" . }}
{{- end }}
imagePullPolicy: {{ .Values.controller.image.pullPolicy }}
securityContext:
allowPrivilegeEscalation: false
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
capabilities:
drop:
- ALL
seccompProfile:
type: RuntimeDefault
command:
- /usr/local/sbin/hug
- --job-check-crd
{{- with .Values.crdjob.resources }}
resources:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.crdjob.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.crdjob.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.crdjob.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
backoffLimit: 0
{{- end }}

View File

@@ -0,0 +1,185 @@
{{/*
Copyright 2026 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if eq .Values.controller.kind "DaemonSet" }}
{{- $useHostNetwork := .Values.controller.daemonset.useHostNetwork -}}
{{- $useHostPort := .Values.controller.daemonset.useHostPort -}}
{{- $hostPorts := .Values.controller.daemonset.hostPorts -}}
{{- $hostIP := .Values.controller.daemonset.hostIP -}}
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: {{ include "haproxy-unified-gateway.fullname" . }}
namespace: {{ include "haproxy-unified-gateway.namespace" . }}
labels:
{{- include "haproxy-unified-gateway.labels" . | nindent 4 }}
{{- with .Values.controller.extraLabels }}
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
selector:
matchLabels:
{{- include "haproxy-unified-gateway.selectorLabels" . | nindent 6 }}
{{- with .Values.controller.strategy }}
updateStrategy:
{{- toYaml . | nindent 4 }}
{{- end }}
template:
metadata:
labels:
{{- include "haproxy-unified-gateway.selectorLabels" . | nindent 8 }}
{{- with .Values.controller.podLabels }}
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.controller.podAnnotations }}
annotations:
{{- toYaml . | nindent 8 }}
{{- end }}
spec:
serviceAccountName: {{ include "haproxy-unified-gateway.serviceAccountName" . }}
{{- with .Values.controller.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- if .Values.controller.unprivileged }}
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
{{- end }}
{{- with .Values.controller.podSecurityContext }}
securityContext:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.controller.priorityClassName }}
priorityClassName: {{ . }}
{{- end }}
{{- if $useHostNetwork }}
hostNetwork: true
{{- end }}
{{- with .Values.controller.dnsPolicy }}
dnsPolicy: {{ . }}
{{- end }}
{{- with .Values.controller.dnsConfig }}
dnsConfig:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.controller.initContainers }}
initContainers:
{{- toYaml . | nindent 8 }}
{{- end }}
containers:
- name: {{ include "haproxy-unified-gateway.name" . }}
image: {{ include "haproxy-unified-gateway.image" . }}
imagePullPolicy: {{ .Values.controller.image.pullPolicy }}
args:
{{- if or .Values.hugconf.create .Values.controller.hugconfCrd }}
- --hugconf-crd={{ include "haproxy-unified-gateway.hugconfCrd" . }}
{{- end }}
{{- with .Values.controller.metricsAuth }}
- --metrics-auth={{ . }}
{{- end }}
{{- range .Values.controller.extraArgs }}
- {{ . }}
{{- end }}
ports:
{{- range $key, $value := .Values.controller.containerPort }}
- name: {{ $key }}
containerPort: {{ $value }}
protocol: TCP
{{- if and $useHostPort (index $hostPorts $key) }}
hostPort: {{ index $hostPorts $key }}
{{- end }}
{{- if $hostIP }}
hostIP: {{ $hostIP }}
{{- end }}
{{- end }}
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
{{- with .Values.controller.extraEnvs }}
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.controller.livenessProbe }}
livenessProbe:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.controller.readinessProbe }}
readinessProbe:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.controller.startupProbe }}
startupProbe:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.controller.resources }}
resources:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- if .Values.controller.unprivileged }}
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
allowPrivilegeEscalation: {{ .Values.controller.allowPrivilegeEscalation }}
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
{{- with .Values.controller.seccompProfile }}
seccompProfile:
{{- toYaml . | nindent 14 }}
{{- end }}
{{- end }}
{{- with .Values.controller.extraVolumeMounts }}
volumeMounts:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.controller.extraContainers }}
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.controller.extraVolumes }}
volumes:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.controller.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.controller.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.controller.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.controller.topologySpreadConstraints }}
topologySpreadConstraints:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,175 @@
{{/*
Copyright 2026 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if eq .Values.controller.kind "Deployment" }}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "haproxy-unified-gateway.fullname" . }}
namespace: {{ include "haproxy-unified-gateway.namespace" . }}
labels:
{{- include "haproxy-unified-gateway.labels" . | nindent 4 }}
{{- with .Values.controller.extraLabels }}
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- if not .Values.controller.autoscaling.enabled }}
replicas: {{ .Values.controller.replicaCount }}
{{- end }}
selector:
matchLabels:
{{- include "haproxy-unified-gateway.selectorLabels" . | nindent 6 }}
{{- with .Values.controller.strategy }}
strategy:
{{- toYaml . | nindent 4 }}
{{- end }}
template:
metadata:
labels:
{{- include "haproxy-unified-gateway.selectorLabels" . | nindent 8 }}
{{- with .Values.controller.podLabels }}
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.controller.podAnnotations }}
annotations:
{{- toYaml . | nindent 8 }}
{{- end }}
spec:
serviceAccountName: {{ include "haproxy-unified-gateway.serviceAccountName" . }}
{{- with .Values.controller.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- if .Values.controller.unprivileged }}
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
{{- end }}
{{- with .Values.controller.podSecurityContext }}
securityContext:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.controller.priorityClassName }}
priorityClassName: {{ . }}
{{- end }}
{{- with .Values.controller.dnsPolicy }}
dnsPolicy: {{ . }}
{{- end }}
{{- with .Values.controller.dnsConfig }}
dnsConfig:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.controller.initContainers }}
initContainers:
{{- toYaml . | nindent 8 }}
{{- end }}
containers:
- name: {{ include "haproxy-unified-gateway.name" . }}
image: {{ include "haproxy-unified-gateway.image" . }}
imagePullPolicy: {{ .Values.controller.image.pullPolicy }}
args:
{{- if or .Values.hugconf.create .Values.controller.hugconfCrd }}
- --hugconf-crd={{ include "haproxy-unified-gateway.hugconfCrd" . }}
{{- end }}
{{- with .Values.controller.metricsAuth }}
- --metrics-auth={{ . }}
{{- end }}
{{- range .Values.controller.extraArgs }}
- {{ . }}
{{- end }}
ports:
{{- range $key, $value := .Values.controller.containerPort }}
- name: {{ $key }}
containerPort: {{ $value }}
protocol: TCP
{{- end }}
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
{{- with .Values.controller.extraEnvs }}
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.controller.livenessProbe }}
livenessProbe:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.controller.readinessProbe }}
readinessProbe:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.controller.startupProbe }}
startupProbe:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.controller.resources }}
resources:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- if .Values.controller.unprivileged }}
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
allowPrivilegeEscalation: {{ .Values.controller.allowPrivilegeEscalation }}
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
{{- with .Values.controller.seccompProfile }}
seccompProfile:
{{- toYaml . | nindent 14 }}
{{- end }}
{{- end }}
{{- with .Values.controller.extraVolumeMounts }}
volumeMounts:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.controller.extraContainers }}
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.controller.extraVolumes }}
volumes:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.controller.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.controller.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.controller.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.controller.topologySpreadConstraints }}
topologySpreadConstraints:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,96 @@
{{/*
Copyright 2026 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if .Values.gwapijob.enabled }}
apiVersion: batch/v1
kind: Job
metadata:
name: {{ include "haproxy-unified-gateway.gwapijob.fullname" . }}
namespace: {{ include "haproxy-unified-gateway.namespace" . }}
labels:
{{- include "haproxy-unified-gateway.gwapijobLabels" . | nindent 4 }}
annotations:
"helm.sh/hook": post-install,pre-upgrade
"helm.sh/hook-weight": "0"
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
"argocd.argoproj.io/hook": PostSync
{{- with .Values.gwapijob.podAnnotations }}
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- with .Values.gwapijob.ttlSecondsAfterFinished }}
ttlSecondsAfterFinished: {{ . }}
{{- end }}
template:
metadata:
labels:
{{- include "haproxy-unified-gateway.gwapijobLabels" . | nindent 8 }}
{{- with .Values.gwapijob.podAnnotations }}
annotations:
{{- toYaml . | nindent 8 }}
{{- end }}
spec:
serviceAccountName: {{ include "haproxy-unified-gateway.crdjob.saName" . }}
restartPolicy: Never
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
seccompProfile:
type: RuntimeDefault
{{- with .Values.controller.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
containers:
- name: gwapijob
{{- if .Values.gwapijob.image.repository }}
image: {{ printf "%s:%s" .Values.gwapijob.image.repository (default .Chart.AppVersion .Values.gwapijob.image.tag) }}
{{- else }}
image: {{ include "haproxy-unified-gateway.image" . }}
{{- end }}
imagePullPolicy: {{ .Values.controller.image.pullPolicy }}
securityContext:
allowPrivilegeEscalation: false
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
capabilities:
drop:
- ALL
seccompProfile:
type: RuntimeDefault
command:
- /usr/local/sbin/hug
- --job-gwapi={{ .Values.gwapijob.version }}
{{- with .Values.gwapijob.resources }}
resources:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.gwapijob.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.gwapijob.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.gwapijob.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
backoffLimit: 0
{{- end }}

View File

@@ -0,0 +1,53 @@
{{/*
Copyright 2026 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if and .Values.controller.autoscaling.enabled (not .Values.controller.keda.enabled) }}
{{- if semverCompare ">=1.23-0" .Capabilities.KubeVersion.GitVersion }}
apiVersion: autoscaling/v2
{{- else }}
apiVersion: autoscaling/v2beta2
{{- end }}
kind: HorizontalPodAutoscaler
metadata:
name: {{ include "haproxy-unified-gateway.fullname" . }}
namespace: {{ include "haproxy-unified-gateway.namespace" . }}
labels:
{{- include "haproxy-unified-gateway.labels" . | nindent 4 }}
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: {{ include "haproxy-unified-gateway.fullname" . }}
minReplicas: {{ .Values.controller.autoscaling.minReplicas }}
maxReplicas: {{ .Values.controller.autoscaling.maxReplicas }}
metrics:
{{- if .Values.controller.autoscaling.targetCPUUtilizationPercentage }}
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: {{ .Values.controller.autoscaling.targetCPUUtilizationPercentage }}
{{- end }}
{{- if .Values.controller.autoscaling.targetMemoryUtilizationPercentage }}
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: {{ .Values.controller.autoscaling.targetMemoryUtilizationPercentage }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,125 @@
{{/*
Copyright 2026 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if .Values.hugconf.create }}
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ include "haproxy-unified-gateway.hugconfCleanup.fullname" . }}
namespace: {{ include "haproxy-unified-gateway.namespace" . }}
labels:
{{- include "haproxy-unified-gateway.labels" . | nindent 4 }}
annotations:
"helm.sh/hook": pre-delete
"helm.sh/hook-weight": "-5"
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: {{ include "haproxy-unified-gateway.hugconfCleanup.fullname" . }}
labels:
{{- include "haproxy-unified-gateway.labels" . | nindent 4 }}
annotations:
"helm.sh/hook": pre-delete
"helm.sh/hook-weight": "-5"
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
rules:
- apiGroups:
- "gate.v3.haproxy.org"
resources:
- hugconfs
verbs:
- get
- delete
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: {{ include "haproxy-unified-gateway.hugconfCleanup.fullname" . }}
labels:
{{- include "haproxy-unified-gateway.labels" . | nindent 4 }}
annotations:
"helm.sh/hook": pre-delete
"helm.sh/hook-weight": "-5"
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: {{ include "haproxy-unified-gateway.hugconfCleanup.fullname" . }}
subjects:
- kind: ServiceAccount
name: {{ include "haproxy-unified-gateway.hugconfCleanup.fullname" . }}
namespace: {{ include "haproxy-unified-gateway.namespace" . }}
---
apiVersion: batch/v1
kind: Job
metadata:
name: {{ include "haproxy-unified-gateway.hugconfCleanup.fullname" . }}
namespace: {{ include "haproxy-unified-gateway.namespace" . }}
labels:
{{- include "haproxy-unified-gateway.labels" . | nindent 4 }}
annotations:
"helm.sh/hook": pre-delete
"helm.sh/hook-weight": "0"
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
spec:
ttlSecondsAfterFinished: 60
template:
metadata:
labels:
{{- include "haproxy-unified-gateway.labels" . | nindent 8 }}
spec:
serviceAccountName: {{ include "haproxy-unified-gateway.hugconfCleanup.fullname" . }}
restartPolicy: Never
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
seccompProfile:
type: RuntimeDefault
{{- with .Values.controller.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
containers:
- name: hugconf-cleanup
image: {{ include "haproxy-unified-gateway.image" . }}
imagePullPolicy: {{ .Values.controller.image.pullPolicy }}
securityContext:
allowPrivilegeEscalation: false
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
capabilities:
drop:
- ALL
seccompProfile:
type: RuntimeDefault
command:
- /bin/sh
- -c
- |
APISERVER="https://kubernetes.default.svc"
TOKEN="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)"
CACERT="/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"
wget --header="Authorization: Bearer ${TOKEN}" \
--ca-certificate="${CACERT}" \
--method=DELETE \
-q -O /dev/null \
"${APISERVER}/apis/gate.v3.haproxy.org/v3/namespaces/{{ include "haproxy-unified-gateway.namespace" . }}/hugconfs/{{ .Values.hugconf.name }}" 2>/dev/null || true
backoffLimit: 1
{{- end }}

View File

@@ -0,0 +1,45 @@
{{/*
Copyright 2026 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if .Values.hugconf.create }}
apiVersion: gate.v3.haproxy.org/v3
kind: HugConf
metadata:
name: {{ .Values.hugconf.name }}
namespace: {{ include "haproxy-unified-gateway.namespace" . }}
labels:
{{- include "haproxy-unified-gateway.labels" . | nindent 4 }}
annotations:
"helm.sh/hook": post-install,pre-upgrade
"helm.sh/hook-weight": "5"
"helm.sh/hook-delete-policy": before-hook-creation
"argocd.argoproj.io/hook": PostSync
spec:
logging:
defaultLevel: {{ .Values.hugconf.logging.defaultLevel | quote }}
{{- with .Values.hugconf.logging.categoryLevelList }}
categoryLevelList:
{{- toYaml . | nindent 6 }}
{{- end }}
{{- with .Values.hugconf.globalRef }}
globalRef:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.hugconf.defaultsRef }}
defaultsRef:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,57 @@
{{/*
Copyright 2026 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if and (eq .Values.controller.kind "Deployment") .Values.controller.keda.enabled }}
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: {{ include "haproxy-unified-gateway.fullname" . }}
namespace: {{ include "haproxy-unified-gateway.namespace" . }}
labels:
{{- include "haproxy-unified-gateway.labels" . | nindent 4 }}
{{- if .Values.controller.keda.scaledObject.annotations }}
annotations: {{ toYaml .Values.controller.keda.scaledObject.annotations | nindent 4 }}
{{- end }}
spec:
scaleTargetRef:
name: {{ include "haproxy-unified-gateway.fullname" . }}
pollingInterval: {{ .Values.controller.keda.pollingInterval }}
cooldownPeriod: {{ .Values.controller.keda.cooldownPeriod }}
minReplicaCount: {{ .Values.controller.keda.minReplicas }}
maxReplicaCount: {{ .Values.controller.keda.maxReplicas }}
triggers:
{{- with .Values.controller.keda.triggers }}
{{ toYaml . | indent 2 }}
{{ end }}
{{- with .Values.controller.keda.fallback }}
fallback:
{{ toYaml . | indent 4 }}
{{- end }}
advanced:
restoreToOriginalReplicaCount: {{ .Values.controller.keda.restoreToOriginalReplicaCount }}
{{- if .Values.controller.keda.horizontalPodAutoscalerConfig }}
horizontalPodAutoscalerConfig:
{{- if .Values.controller.keda.horizontalPodAutoscalerConfig.name }}
name: {{ .Values.controller.keda.horizontalPodAutoscalerConfig.name }}
{{- end }}
{{- if .Values.controller.keda.horizontalPodAutoscalerConfig.behavior }}
behavior:
{{ with .Values.controller.keda.horizontalPodAutoscalerConfig.behavior -}}
{{ toYaml . | indent 8 }}
{{ end }}
{{- end }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,35 @@
{{/*
Copyright 2026 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if .Values.controller.podDisruptionBudget.enabled }}
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: {{ include "haproxy-unified-gateway.fullname" . }}
namespace: {{ include "haproxy-unified-gateway.namespace" . }}
labels:
{{- include "haproxy-unified-gateway.labels" . | nindent 4 }}
spec:
selector:
matchLabels:
{{- include "haproxy-unified-gateway.selectorLabels" . | nindent 6 }}
{{- if .Values.controller.podDisruptionBudget.minAvailable }}
minAvailable: {{ .Values.controller.podDisruptionBudget.minAvailable }}
{{- end }}
{{- if .Values.controller.podDisruptionBudget.maxUnavailable }}
maxUnavailable: {{ .Values.controller.podDisruptionBudget.maxUnavailable }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,37 @@
{{/*
Copyright 2026 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if and (.Capabilities.APIVersions.Has "monitoring.coreos.com/v1") .Values.controller.podMonitor.enabled }}
apiVersion: monitoring.coreos.com/v1
kind: PodMonitor
metadata:
name: {{ include "haproxy-unified-gateway.podMonitorName" . }}
namespace: {{ include "haproxy-unified-gateway.namespace" . }}
labels:
{{- include "haproxy-unified-gateway.labels" . | nindent 4 }}
{{- with .Values.controller.podMonitor.extraLabels }}
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
podMetricsEndpoints:
{{- toYaml .Values.controller.podMonitor.endpoints | nindent 4 }}
namespaceSelector:
matchNames:
- {{ include "haproxy-unified-gateway.namespace" . }}
selector:
matchLabels:
{{- include "haproxy-unified-gateway.selectorLabels" . | nindent 6 }}
{{- end }}

View File

@@ -0,0 +1,81 @@
{{/*
Copyright 2026 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if (semverCompare "<1.25.0-0" .Capabilities.KubeVersion.Version) }}
{{- if and .Values.rbac.create .Values.podSecurityPolicy.enabled }}
{{- $useHostNetwork := false }}
{{- $useHostPort := false }}
{{- if eq .Values.controller.kind "DaemonSet" }}
{{- $useHostNetwork = .Values.controller.daemonset.useHostNetwork }}
{{- $useHostPort = .Values.controller.daemonset.useHostPort }}
{{- end }}
{{- if or (.Capabilities.APIVersions.Has "policy/v1/PodSecurityPolicy") (semverCompare ">=1.21.0-0" .Capabilities.KubeVersion.Version) }}
apiVersion: policy/v1
{{- else }}
apiVersion: policy/v1beta1
{{- end }}
kind: PodSecurityPolicy
metadata:
{{- if .Values.podSecurityPolicy.annotations }}
annotations:
{{ toYaml .Values.podSecurityPolicy.annotations | indent 4 }}
{{- end }}
labels:
{{- include "haproxy-unified-gateway.labels" . | nindent 4 }}
name: {{ include "haproxy-unified-gateway.fullname" . }}
annotations:
seccomp.security.alpha.kubernetes.io/allowedProfileNames: 'docker/default,runtime/default'
apparmor.security.beta.kubernetes.io/allowedProfileNames: 'runtime/default'
seccomp.security.alpha.kubernetes.io/defaultProfileName: 'runtime/default'
apparmor.security.beta.kubernetes.io/defaultProfileName: 'runtime/default'
spec:
allowPrivilegeEscalation: {{ .Values.controller.allowPrivilegeEscalation }}
allowedCapabilities:
- NET_BIND_SERVICE
defaultAllowPrivilegeEscalation: false
fsGroup:
rule: MustRunAs
ranges:
- max: 65535
min: 1
hostIPC: false
{{- if $useHostNetwork }}
hostNetwork: true
{{- end }}
{{- if or $useHostPort $useHostNetwork }}
hostPorts:
{{- range $key, $value := .Values.controller.containerPort }}
- min: {{ $value }}
max: {{ $value }}
{{- end }}
{{- end }}
hostPID: false
privileged: false
runAsUser:
rule: RunAsAny
seLinux:
rule: RunAsAny
supplementalGroups:
rule: MustRunAs
ranges:
- max: 65535
min: 1
volumes:
- configMap
- downwardAPI
- secret
{{- end }}
{{- end }}

View File

@@ -0,0 +1,34 @@
{{/*
Copyright 2026 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if and .Values.rbac.create .Values.podSecurityPolicy.enabled -}}
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: {{ include "haproxy-unified-gateway.fullname" . }}
namespace: {{ include "haproxy-unified-gateway.namespace" . }}
labels:
{{- include "haproxy-unified-gateway.labels" . | nindent 4 }}
rules:
- apiGroups:
- "policy"
resources:
- podsecuritypolicies
verbs:
- use
resourceNames:
- {{ include "haproxy-unified-gateway.fullname" . }}
{{- end -}}

View File

@@ -0,0 +1,33 @@
{{/*
Copyright 2026 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if and .Values.rbac.create .Values.podSecurityPolicy.enabled -}}
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: {{ include "haproxy-unified-gateway.fullname" . }}
namespace: {{ include "haproxy-unified-gateway.namespace" . }}
labels:
{{- include "haproxy-unified-gateway.labels" . | nindent 4 }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: {{ include "haproxy-unified-gateway.fullname" . }}
subjects:
- kind: ServiceAccount
name: {{ include "haproxy-unified-gateway.serviceAccountName" . }}
namespace: {{ include "haproxy-unified-gateway.namespace" . }}
{{- end -}}

View File

@@ -0,0 +1,45 @@
{{/*
Copyright 2026 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if and .Values.controller.serviceMonitor.enabled .Values.controller.service.enabled }}
apiVersion: v1
kind: Service
metadata:
name: {{ include "haproxy-unified-gateway.metricsServiceName" . }}
namespace: {{ include "haproxy-unified-gateway.namespace" . }}
labels:
{{- include "haproxy-unified-gateway.labels" . | nindent 4 }}
{{- with .Values.controller.service.metrics.labels }}
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.controller.service.metrics.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
type: {{ .Values.controller.service.metrics.type }}
selector:
{{- include "haproxy-unified-gateway.selectorLabels" . | nindent 4 }}
ports:
- name: stat
port: {{ .Values.controller.service.stat.port }}
targetPort: {{ .Values.controller.service.stat.targetPort }}
protocol: TCP
- name: metrics
port: {{ index .Values.controller.service "controller-metrics" "port" }}
targetPort: {{ index .Values.controller.service "controller-metrics" "targetPort" }}
protocol: TCP
{{- end }}

View File

@@ -0,0 +1,64 @@
{{/*
Copyright 2026 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if .Values.controller.service.enabled }}
apiVersion: v1
kind: Service
metadata:
name: {{ include "haproxy-unified-gateway.fullname" . }}
namespace: {{ include "haproxy-unified-gateway.namespace" . }}
labels:
{{- include "haproxy-unified-gateway.labels" . | nindent 4 }}
{{- with .Values.controller.service.labels }}
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.controller.service.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
type: {{ .Values.controller.service.type }}
{{- with .Values.controller.service.externalTrafficPolicy }}
externalTrafficPolicy: {{ . }}
{{- end }}
selector:
{{- include "haproxy-unified-gateway.selectorLabels" . | nindent 4 }}
ports:
- name: http
port: {{ .Values.controller.service.http.port }}
targetPort: {{ .Values.controller.service.http.targetPort }}
protocol: TCP
{{- if and (eq .Values.controller.service.type "NodePort") .Values.controller.service.http.nodePort }}
nodePort: {{ .Values.controller.service.http.nodePort }}
{{- end }}
- name: https
port: {{ .Values.controller.service.https.port }}
targetPort: {{ .Values.controller.service.https.targetPort }}
protocol: TCP
{{- if and (eq .Values.controller.service.type "NodePort") .Values.controller.service.https.nodePort }}
nodePort: {{ .Values.controller.service.https.nodePort }}
{{- end }}
- name: stat
port: {{ .Values.controller.service.stat.port }}
targetPort: {{ .Values.controller.service.stat.targetPort }}
protocol: TCP
{{- if and (eq .Values.controller.service.type "NodePort") .Values.controller.service.stat.nodePort }}
nodePort: {{ .Values.controller.service.stat.nodePort }}
{{- end }}
{{- with .Values.controller.service.extraPorts }}
{{- toYaml . | nindent 4 }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,29 @@
{{/*
Copyright 2026 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if .Values.serviceAccount.create }}
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ include "haproxy-unified-gateway.serviceAccountName" . }}
namespace: {{ include "haproxy-unified-gateway.namespace" . }}
labels:
{{- include "haproxy-unified-gateway.labels" . | nindent 4 }}
{{- with .Values.serviceAccount.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,37 @@
{{/*
Copyright 2026 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if and (.Capabilities.APIVersions.Has "monitoring.coreos.com/v1") .Values.controller.serviceMonitor.enabled }}
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: {{ include "haproxy-unified-gateway.serviceMonitorName" . }}
namespace: {{ include "haproxy-unified-gateway.namespace" . }}
labels:
{{- include "haproxy-unified-gateway.labels" . | nindent 4 }}
{{- with .Values.controller.serviceMonitor.extraLabels }}
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
endpoints:
{{- toYaml .Values.controller.serviceMonitor.endpoints | nindent 4 }}
namespaceSelector:
matchNames:
- {{ include "haproxy-unified-gateway.namespace" . }}
selector:
matchLabels:
{{- include "haproxy-unified-gateway.selectorLabels" . | nindent 6 }}
{{- end }}

View File

@@ -0,0 +1,27 @@
{{/*
Copyright 2026 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if .Values.namespace.create }}
apiVersion: v1
kind: Namespace
metadata:
name: {{ include "haproxy-unified-gateway.namespace" . }}
labels:
{{- include "haproxy-unified-gateway.labels" . | nindent 4 }}
annotations:
"helm.sh/hook": pre-install
"helm.sh/hook-weight": "-1"
{{- end }}

View File

@@ -0,0 +1,389 @@
# Copyright 2026 HAProxy Technologies LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
## HAProxy Unified Gateway Helm Chart - values.yaml
# -- PodSecurityPolicy configuration (deprecated in K8s 1.21, removed in 1.25)
podSecurityPolicy:
## Specify pod annotations
## ref: https://kubernetes.io/docs/concepts/policy/pod-security-policy/#apparmor
## ref: https://kubernetes.io/docs/concepts/policy/pod-security-policy/#seccomp
## ref: https://kubernetes.io/docs/concepts/policy/pod-security-policy/#sysctl
annotations: {}
# apparmor.security.beta.kubernetes.io/allowedProfileNames: runtime/default
# apparmor.security.beta.kubernetes.io/defaultProfileName: runtime/default
# seccomp.security.alpha.kubernetes.io/allowedProfileNames: runtime/default
# seccomp.security.alpha.kubernetes.io/defaultProfileName: runtime/default
enabled: false
# -- Create RBAC resources
rbac:
create: true
# -- Create a namespace (uses Helm pre-install hook)
namespace:
create: false
# -- ServiceAccount configuration
serviceAccount:
# -- Create a ServiceAccount
create: true
# -- ServiceAccount name (generated if not set)
name: ""
# -- Annotations to add to the ServiceAccount
annotations: {}
# -- Controller configuration
controller:
# -- Controller name
name: controller
# -- Container image configuration
image:
repository: docker.io/haproxytech/haproxy-unified-gateway
tag: "" # defaults to appVersion
pullPolicy: IfNotPresent
# -- Image pull secrets
imagePullSecrets: []
# -- Deployment or DaemonSet pod mode
# ref: https://kubernetes.io/docs/concepts/workloads/controllers/deployment/
# ref: https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/
kind: Deployment # can be 'Deployment' or 'DaemonSet'
# -- Number of replicas (only for Deployment mode)
replicaCount: 1
# -- HugConf CRD reference (namespace/name)
# If empty, defaults to "<release-namespace>/hugconf"
hugconfCrd: ""
# -- Metrics authentication mode for the controller metrics endpoint (port 31060)
# Supported values: "none", "kube-rbac", "basic"
# - none: HTTP, no authentication
# - kube-rbac: HTTPS with Kubernetes TokenReview/SubjectAccessReview
# - basic: HTTPS with HTTP Basic Authentication (set credentials via extraArgs)
metricsAuth: kube-rbac
# -- Extra arguments to pass to the controller
extraArgs: []
# -- Container ports
containerPort:
http: 31080
https: 31443
stat: 31024
metrics: 31060
# -- Resource requests and limits
resources:
limits:
memory: 2560Mi
requests:
memory: 2048Mi
## Running container without root privileges
## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/
unprivileged: true
## Privilege escalation
## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/
allowPrivilegeEscalation: false
## Restricts container syscalls
## ref: https://kubernetes.io/docs/tutorials/security/seccomp/
## Supported types: RuntimeDefault, Localhost, Unconfined
## Set to empty ({}) to disable seccomp profile
seccompProfile:
type: RuntimeDefault
# localhostProfile: my-profiles/profile.json # only for type: Localhost
# -- Pod-level security context
podSecurityContext: {}
# -- Liveness probe configuration
livenessProbe: {}
# -- Readiness probe configuration
readinessProbe: {}
# -- Startup probe configuration
startupProbe: {}
# -- Node selector for pod scheduling
nodeSelector: {}
# -- Tolerations for pod scheduling
tolerations: []
# -- Affinity rules for pod scheduling
affinity: {}
# -- Topology spread constraints
topologySpreadConstraints: []
# -- Extra environment variables
extraEnvs: []
# -- Extra volume mounts
extraVolumeMounts: []
# -- Extra volumes
extraVolumes: []
# -- Extra init containers
initContainers: []
# -- Extra sidecar containers
extraContainers: []
# -- Pod annotations
podAnnotations: {}
# -- Pod labels
podLabels: {}
# -- Extra labels for the Deployment
extraLabels: {}
# -- Update strategy
strategy:
type: RollingUpdate
# -- Priority class name
priorityClassName: ""
# -- DNS policy
dnsPolicy: ""
# -- DNS config
dnsConfig: {}
# -- DaemonSet-specific configuration (only used when kind is 'DaemonSet')
daemonset:
useHostNetwork: false # also modify dnsPolicy accordingly
useHostPort: false
hostIP: null
hostPorts:
http: 80
https: 443
stat: 1024
metrics: 31060
# -- Service configuration
service:
# -- Enable the Service
enabled: true
# -- Service type
type: NodePort
# -- Service annotations
annotations: {}
# -- Service labels
labels: {}
# -- External traffic policy
externalTrafficPolicy: ""
# -- HTTP port configuration
http:
port: 31080
targetPort: 31080
nodePort: 31080
# -- HTTPS port configuration
https:
port: 31443
targetPort: 31443
nodePort: 31443
# -- Stats port configuration
stat:
port: 31024
targetPort: 31024
nodePort: ""
# -- Extra ports to expose
extraPorts: []
# -- Controller metrics port configuration (hug_* prometheus metrics)
controller-metrics:
port: 31060
targetPort: 31060
# -- Metrics service configuration (created when serviceMonitor is enabled)
metrics:
type: ClusterIP
annotations: {}
labels: {}
# -- ServiceMonitor configuration (requires Prometheus Operator)
## ref: https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/user-guides/getting-started.md
## Note: requires Prometheus Operator to be able to work, for example:
## helm install prometheus prometheus-community/kube-prometheus-stack \
## --set prometheus.prometheusSpec.podMonitorSelectorNilUsesHelmValues=false \
## --set prometheus.prometheusSpec.serviceMonitorSelectorNilUsesHelmValues=false
serviceMonitor:
# -- Enable ServiceMonitor (should not be enabled together with podMonitor)
enabled: false
# -- Extra labels for ServiceMonitor target discovery
extraLabels: {}
# -- ServiceMonitor endpoints configuration
endpoints:
- port: stat
path: /metrics
scheme: http
interval: 30s
- port: metrics
path: /metrics
scheme: https
interval: 30s
tlsConfig:
insecureSkipVerify: true
bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
# -- PodMonitor configuration (requires Prometheus Operator)
## ref: https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/user-guides/getting-started.md
podMonitor:
# -- Enable PodMonitor (should not be enabled together with serviceMonitor)
enabled: false
# -- Extra labels for PodMonitor target discovery
extraLabels: {}
# -- PodMonitor endpoints configuration
endpoints:
- port: stat
path: /metrics
scheme: http
interval: 30s
- port: metrics
path: /metrics
scheme: https
interval: 30s
tlsConfig:
insecureSkipVerify: true
bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
# -- HorizontalPodAutoscaler configuration
autoscaling:
enabled: false
minReplicas: 1
maxReplicas: 10
targetCPUUtilizationPercentage: 80
# targetMemoryUtilizationPercentage: 80
# -- KEDA ScaledObject configuration (mutually exclusive with autoscaling)
keda:
enabled: false
minReplicas: 2
maxReplicas: 20
pollingInterval: 30
cooldownPeriod: 300
restoreToOriginalReplicaCount: false
# fallback:
# failureThreshold: 3
# replicas: 11
scaledObject:
annotations: {}
horizontalPodAutoscalerConfig: {}
# name: ""
# behavior:
# scaleDown:
# stabilizationWindowSeconds: 300
# policies:
# - type: Pods
# value: 1
# periodSeconds: 300
triggers: []
# - type: prometheus
# metadata:
# serverAddress: http://<prometheus-host>:9090
# metricName: haproxy_process_idle_time_percent
# threshold: '50'
# query: avg(100-avg_over_time(haproxy_process_idle_time_percent{job="haproxy-unified-gateway"}[2m]))
# -- PodDisruptionBudget configuration
podDisruptionBudget:
enabled: false
# minAvailable: 1
# maxUnavailable: 1
# -- HugConf custom resource configuration
hugconf:
# -- Create a HugConf resource
create: true
# -- HugConf name
name: hugconf
# -- Logging configuration
logging:
# -- Default log level
defaultLevel: Info
# -- Per-category log level overrides
categoryLevelList:
- category: "k8s"
level: "Error"
- category: "gate"
level: "Info"
- category: "status"
level: "Info"
- category: "batch"
level: "Error"
- category: "app"
level: "Info"
- category: "certs-storage"
level: "Info"
# -- Global configuration reference (group, kind, name, namespace)
globalRef: {}
# group: gate.v3.haproxy.org
# kind: Global
# name: global
# namespace: haproxy-unified-gateway
# -- Defaults configuration reference (group, kind, name, namespace)
defaultsRef: {}
# group: gate.v3.haproxy.org
# kind: Defaults
# name: haproxytech
# namespace: haproxy-unified-gateway
# -- CRD Job configuration
crdjob:
# -- Enable the CRD installation Job (Helm hook)
enabled: true
# -- Additional pod annotations
podAnnotations: {}
# -- TTL for completed jobs (seconds)
ttlSecondsAfterFinished: 60
# -- Node selector
nodeSelector: {}
# -- Tolerations
tolerations: []
# -- Affinity
affinity: {}
# -- Resources for CRD job
resources: {}
# -- Image override (defaults to controller image)
image: {}
# -- Gateway API Job configuration
gwapijob:
# -- Enable the Gateway API CRD installation Job (Helm hook)
enabled: true
# -- Gateway API version to install
version: "1.3.0"
# -- Additional pod annotations
podAnnotations: {}
# -- TTL for completed jobs (seconds)
ttlSecondsAfterFinished: 60
# -- Node selector
nodeSelector: {}
# -- Tolerations
tolerations: []
# -- Affinity
affinity: {}
# -- Resources for Gateway API job
resources: {}
# -- Image override (defaults to controller image)
image: {}

23
haproxy/.helmignore Normal file
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/

35
haproxy/Chart.yaml Normal file
View File

@@ -0,0 +1,35 @@
# Copyright 2020 HAProxy Technologies LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
apiVersion: v2
name: haproxy
description: A Helm chart for HAProxy on Kubernetes
type: application
version: 1.28.1
appVersion: 3.3.6
kubeVersion: ">=1.17.0-0"
keywords:
- haproxy
home: https://github.com/haproxytech/helm-charts/tree/main/haproxy
sources:
- http://www.haproxy.org/
icon: https://raw.githubusercontent.com/haproxytech/helm-charts/main/haproxy/chart-icon.png
maintainers:
- name: Dinko Korunic
email: dkorunic@haproxy.com
engine: gotpl
annotations:
artifacthub.io/changes: |
- Update base image to HAProxy 3.3.6
- Fix newline issue with YAML normalisation (#344)

378
haproxy/README.md Normal file
View File

@@ -0,0 +1,378 @@
# ![HAProxy](https://github.com/haproxytech/kubernetes-ingress/raw/master/assets/images/haproxy-weblogo-210x49.png "HAProxy")
## HAProxy Helm Chart
## Introduction
This chart bootstraps an HAProxy load balancer as deployment/daemonset on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager. As oposed to [HAProxy Kubernetes Ingress Controller](https://github.com/haproxytech/helm-charts/tree/main/kubernetes-ingress) Chart, HAProxy is installed as a regular application and not as an Ingress Controller.
### Prerequisites
- Kubernetes 1.17+ (recommended 1.20+)
- Helm 3.6+ (recommended 3.7+)
## Before you begin
### Setup a Kubernetes Cluster
The quickest way to setup a Kubernetes cluster is with [Azure Kubernetes Service](https://azure.microsoft.com/en-us/services/kubernetes-service/), [AWS Elastic Kubernetes Service](https://aws.amazon.com/eks/) or [Google Kubernetes Engine](https://cloud.google.com/kubernetes-engine/) using their respective quick-start guides.
For setting up Kubernetes on other cloud platforms or bare-metal servers refer to the Kubernetes [getting started guide](http://kubernetes.io/docs/getting-started-guides/).
### Install Helm
Get the latest [Helm release](https://github.com/helm/helm#install).
### Add Helm chart repo
Once you have Helm installed, add the haproxytech Chat Repository as follows:
```console
helm repo add haproxytech https://haproxytech.github.io/helm-charts
helm repo update
```
Alternatively if you want to proceed with just OCI-based repository, skip this step and follow the installation with OCI.
## Install the chart
To install the chart with Helm v3 as _my-release_ deployment:
```console
helm install my-release haproxytech/haproxy
```
**_NOTE_**: To install the chart with Helm v2 (legacy Helm) the syntax requires adding deployment name to `--name` parameter:
```console
helm install haproxytech/haproxy \
--name my-release
```
Alternatively also have OCI-based repository available for simplified access:
```console
helm install oci://ghcr.io/haproxytech/helm-charts/haproxy --version 1.24.0
```
### Installing with unique name
To auto-generate resource names when installing, use the following:
```console
helm install haproxytech/haproxy \
--generate-name
```
### Installing from a private registry
To install the chart using a private registry for HAProxy (for instance to use a HAProxy Enterprise image) into a separate namespace _prod_.
**_NOTE_**: Helm v3 requires namespace to be precreated (eg. with `kubectl create namespace prod`)
```console
helm install my-haproxy haproxytech/haproxy \
--namespace prod \
--set image.tag=latest \
--set image.repository=myregistry.domain.com/imagename \
--set imageCredentials.registry=myregistry.domain.com \
--set imageCredentials.username=MYUSERNAME \
--set imageCredentials.password=MYPASSWORD
```
Alternatively, use a pre-configured (existing) imagePullSecret in the same namespace:
```console
helm install my-ingress haproxytech/haproxy \
--namespace prod \
--set image.tag=SOMETAG \
--set existingImagePullSecret name-of-existing-image-pull-secret
```
**_NOTE_**: Enterprise images using S6 overlay need default CMD arguments disabled (more about YAML configuration file for Helm can be found in a separate paragraph below):
```yaml
args:
enabled: false
```
### Installing as DaemonSet
Default image mode is [Deployment](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/), but it is possible to use [DaemonSet](https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/) as well:
```console
helm install my-haproxy2 haproxytech/haproxy \
--set kind=DaemonSet
```
**_NOTE_**: With helm `--set` it is needed to put quotes and escape dots in the annotation key and commas in the value string.
### Installing with Horizontal Pod Autoscaler
[HPA](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/) automatically scales number of replicas in Deployment or Replication Controller and adjusts replica count. Therefore we want to unset default replicaCount by setting corresponding key value to null and enable autoscaling:
```console
helm install my-haproxy3 haproxytech/haproxy \
--set kind=Deployment \
--set replicaCount=null \
--set autoscaling.enabled=true \
--set autoscaling.targetCPUUtilizationPercentage=80
```
**_NOTE_**: Make sure to look into other tunable values for HPA documented in [values.yaml](values.yaml).
### Installing with service annotations
On some environments like EKS and GKE there might be a need to pass service annotations. Syntax can become a little tedious however:
```console
helm install my-haproxy4 haproxytech/haproxy \
--set kind=DaemonSet \
--set service.type=LoadBalancer \
--set service.annotations."service\.beta\.kubernetes\.io/aws-load-balancer-internal"="0.0.0.0/0" \
--set service.annotations."service\.beta\.kubernetes\.io/aws-load-balancer-cross-zone-load-balancing-enabled"="true"
```
**_NOTE_**: With helm `--set` it is needed to put quotes and escape dots in the annotation key and commas in the value string.
### Using values from YAML file
As opposed to using many `--set` invocations, much simpler approach is to define value overrides in a separate YAML file and specify them when invoking Helm.
The `config` block can also support using helm templates to populate dynamic values, e.g. `{{ .Release.Name }}`.
_mylb.yaml_:
```yaml
kind: DaemonSet
config: |
global
log stdout format raw local0
daemon
maxconn 1024
defaults
log global
timeout client 60s
timeout connect 60s
timeout server {{ .Values.global.serverTimeout }}
frontend fe_main
bind :80
default_backend be_main
backend be_main
server web1 10.0.0.1:8080 check
server web2 {{ .Release.Name }}-web:8080 check
service:
type: LoadBalancer
annotations:
service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled: "true"
service.beta.kubernetes.io/aws-load-balancer-internal: 0.0.0.0/0
```
And invoking Helm becomes (compare to the previous example):
```console
helm install my-haproxy5 -f mylb.yml haproxytech/haproxy
```
### Using secrets in additional volume mounts
In order to e.g. support SSL certificates, you can mount additional volumes from secrets:
_mylb.yaml_:
```yaml
service:
type: LoadBalancer
config: |
global
log stdout format raw local0
daemon
maxconn 1024
defaults
log global
timeout client 60s
timeout connect 60s
timeout server 60s
frontend fe_main
mode http
bind :80
bind :443 ssl crt /usr/local/etc/ssl/tls.crt
http-request redirect scheme https code 301 unless { ssl_fc }
default_backend be_main
backend be_main
mode http
server web1 10.0.0.1:8080 check
mountedSecrets:
- volumeName: ssl-certificate
secretName: star-example-com
mountPath: /usr/local/etc/ssl
```
The above example assumes that there is a certificate in key `tls.crt` of a secret called `star-example-com`.
### Using additional volumes and volumeMounts
In order to load data from other sources (e.g. to preload something inside an init-container) you can mount additional volumes to the container:
```yaml
extraVolumes:
- name: tls
emptyDir: {}
- name: tmp
emptyDir:
medium: Memory
extraVolumeMounts:
- name: tls
mountPath: /etc/tls
- name: tmp
mountPath: /tmp
```
### Using additional environment variables
In order to expose extra data (e.g. node and pod IP addresses) to haproxy, you can populate extra environment variables on the container:
```yaml
extraEnvs:
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
```
### Automatic configuration reloading
In some cases, configuration changes are frequent and constantly restarting HAProxy is not optimal. For those cases the HAProxy hot-reload feature
can be used.
In master-worker mode, sending a USR2 signal to the HAProxy process will trigger a configuration reload.
```yaml
config: |
global
log stdout format raw local0
master-worker
daemon
maxconn 1024
defaults
log global
timeout client 60s
timeout connect 60s
timeout server 60s
frontend fe_main
mode http
bind :80
http-request redirect scheme https code 301 unless { ssl_fc }
default_backend be_main
backend be_main
mode http
server web1 10.0.0.1:8080 check
```
Make sure you are not specifying subPath for any of your volumeMounts so that Kubernetes will automatically update the volumes created from
ConfigMaps.
And finally, use some sidecar container which will be delivering the signal to the process. The shareProcessNamespace Pod property is required
for the sidecars to be able to access other containers' processes.
```yaml
shareProcessNamespace:
enabled: true
sidecarContainers:
- name: reflex
image: acim/go-reflex:1.17.3
command: ["reflex", "-d", "fancy"]
workingDir: /usr/local/etc/haproxy
args:
- -svr
- "..data"
- --
- bash
- -c
- 'pkill -SIGUSR2 "haproxy|hapee-lb"'
volumeMounts:
- name: haproxy-config
mountPath: /usr/local/etc/haproxy
resources:
limits:
memory: 128Mi
requests:
cpu: 50m
memory: 64Mi
```
## Installing as non-root with binding to privileged ports
To be able to bind to privileged ports such as tcp/80 and tcp/443 without root privileges (UID and GID are set to 1000 in the example, as HAProxy Docker image has UID/GID of 1000 reserved for HAProxy), there is a special workaround required as `NET_BIND_SERVICE` capability is [not propagated](https://github.com/kubernetes/kubernetes/issues/56374), so we need to use `initContainers` feature as well:
```yaml
kind: DaemonSet
containerPorts:
http: 80
https: 443
stat: 1024
daemonset:
useHostNetwork: true
useHostPort: true
hostPorts:
http: 80
https: 443
stat: 1024
config: |
global
log stdout format raw local0
maxconn 1024
defaults
log global
timeout client 60s
timeout connect 60s
timeout server 60s
frontend fe_main
bind :80
default_backend be_main
backend be_main
server web1 127.0.0.1:8080 check
securityContext:
enabled: true
runAsUser: 1000
runAsGroup: 1000
initContainers:
- name: sysctl
image: "busybox:musl"
command:
- /bin/sh
- -c
- sysctl -w net.ipv4.ip_unprivileged_port_start=0
securityContext:
privileged: true
```
## Upgrading the chart
To upgrade the _my-release_ deployment:
```console
helm upgrade my-release haproxytech/haproxy
```
## Uninstalling the chart
To uninstall/delete the _my-release_ deployment:
```console
helm delete my-release
```
## Debugging
It is possible to generate a set of YAML files for testing/debugging:
```console
helm install my-release haproxytech/haproxy \
--debug \
--dry-run
```
## Contributing
We welcome all contributions. Please refer to [guidelines](../CONTRIBUTING.md) on how to make a contribution.

BIN
haproxy/chart-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -0,0 +1,2 @@
kind: DaemonSet
replicaCount: 2

View File

@@ -0,0 +1,13 @@
kind: DaemonSet
containerPorts:
http: 8080
https: 8443
stat: 8024
daemonset:
useHostNetwork: true
useHostPort: true
hostPorts:
http: 8080
https: 8443
stat: 8024
dnsPolicy: ClusterFirstWithHostNet

View File

@@ -0,0 +1,3 @@
kind: DaemonSet
ingress:
enabled: true

View File

@@ -0,0 +1,4 @@
kind: DaemonSet
service:
ipFamilies: [IPv4]
ipFamilyPolicy: SingleStack

View File

@@ -0,0 +1,26 @@
kind: DaemonSet
replicaCount: 2
livenessProbe:
failureThreshold: 3
successThreshold: 1
initialDelaySeconds: 0
timeoutSeconds: 1
tcpSocket:
port: 80
periodSeconds: 10
readinessProbe:
failureThreshold: 3
successThreshold: 1
initialDelaySeconds: 0
timeoutSeconds: 1
tcpSocket:
port: 80
periodSeconds: 10
startupProbe:
failureThreshold: 20
successThreshold: 1
initialDelaySeconds: 0
timeoutSeconds: 1
tcpSocket:
port: 80
periodSeconds: 1

View File

@@ -0,0 +1 @@
kind: Deployment

View File

@@ -0,0 +1,18 @@
config: |
global
log stdout format raw local0
daemon
maxconn 1024
defaults
log global
timeout client 60s
timeout connect 60s
timeout server 60s
frontend fe_main
bind :80
default_backend be_main
backend be_main
server web1 10.0.0.1:8080 check

View File

@@ -0,0 +1,19 @@
kind: Deployment
replicaCount: null
autoscaling:
enabled: true
minReplicas: 1
maxReplicas: 5
targetCPUUtilizationPercentage: 80
behavior:
scaleUp:
policies:
- type: Percent
value: 900
periodSeconds: 60
scaleDown:
stabilizationWindowSeconds: 600
policies:
- type: Pods
value: 1
periodSeconds: 600

View File

@@ -0,0 +1,3 @@
kind: Deployment
ingress:
enabled: true

View File

@@ -0,0 +1,4 @@
kind: Deployment
service:
ipFamilies: [IPv4]
ipFamilyPolicy: SingleStack

View File

@@ -0,0 +1,25 @@
kind: Deployment
livenessProbe:
failureThreshold: 3
successThreshold: 1
initialDelaySeconds: 0
timeoutSeconds: 1
tcpSocket:
port: 80
periodSeconds: 10
readinessProbe:
failureThreshold: 3
successThreshold: 1
initialDelaySeconds: 0
timeoutSeconds: 1
tcpSocket:
port: 80
periodSeconds: 10
startupProbe:
failureThreshold: 20
successThreshold: 1
initialDelaySeconds: 0
timeoutSeconds: 1
tcpSocket:
port: 80
periodSeconds: 1

View File

@@ -0,0 +1,58 @@
HAProxy has been has been successfully installed. This Chart is used to run HAProxy as a regular application,
as opposed to HAProxy Ingress Controller Chart.
Controller image deployed is: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}".
Your HAProxy app is of a "{{ .Values.kind }}" kind.
Service ports mapped are:
{{- $nodePorts := .Values.service.nodePorts }}
{{- $servicePortType := .Values.service.type }}
{{- if eq .Values.kind "Deployment" }}
{{- range $key, $value := .Values.containerPorts }}
- name: {{ $key }}
containerPort: {{ $value }}
protocol: TCP
{{- if and (hasKey $nodePorts $key) (eq $servicePortType "NodePort") }}
nodePort: {{ get $nodePorts $key }}
{{- end }}
{{- end }}
{{- end }}
{{- if eq .Values.kind "DaemonSet" }}
{{- $hostPorts := .Values.daemonset.hostPorts -}}
{{- $useHostPort := .Values.daemonset.useHostPort -}}
{{- range $key, $value := .Values.containerPorts }}
- name: {{ $key }}
containerPort: {{ $value }}
protocol: TCP
{{- if $useHostPort }}
hostPort: {{ index $hostPorts $key | default $value }}
{{- end }}
{{- if and (hasKey $nodePorts $key) (eq $servicePortType "NodePort") }}
nodePort: {{ get $nodePorts $key }}
{{- end }}
{{- end }}
{{- end }}
To be able to bind to privileged ports as non-root, the following is required:
securityContext:
enabled: true
runAsUser: 1000
runAsGroup: 1000
initContainers:
- name: sysctl
image: "busybox:musl"
command:
- /bin/sh
- -c
- sysctl -w net.ipv4.ip_unprivileged_port_start=0
securityContext:
privileged: true
Node IP can be found with:
$ kubectl --namespace {{ template "haproxy.namespace" . }} get nodes -o jsonpath="{.items[0].status.addresses[1].address}"
For more examples and up to date documentation, please visit:
* Helm chart documentation: https://github.com/haproxytech/helm-charts/tree/main/haproxy
* HAProxy Alpine Docker container documentation: https://github.com/haproxytech/haproxy-docker-alpine
* HAProxy documentation: https://www.haproxy.org/download/2.7/doc/configuration.txt

View File

@@ -0,0 +1,105 @@
{{/*
Copyright 2020 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{/*
Expand the name of the chart.
*/}}
{{- define "haproxy.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Allow the release namespace to be overridden for multi-namespace deployments in combined charts
*/}}
{{- define "haproxy.namespace" -}}
{{- if .Values.namespaceOverride -}}
{{- .Values.namespaceOverride -}}
{{- else -}}
{{- .Release.Namespace -}}
{{- end -}}
{{- 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 "haproxy.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 "haproxy.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Common labels
*/}}
{{- define "haproxy.labels" -}}
helm.sh/chart: {{ include "haproxy.chart" . }}
{{ include "haproxy.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{/*
Selector labels
*/}}
{{- define "haproxy.selectorLabels" -}}
app.kubernetes.io/name: {{ include "haproxy.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/*
Create the name of the service account to use
*/}}
{{- define "haproxy.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "haproxy.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}
{{/*
Create includes name
*/}}
{{- define "haproxy.includes" -}}
{{- printf "%s-%s" (include "haproxy.fullname" .) "includes" | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Encode an imagePullSecret string.
*/}}
{{- define "haproxy.imagePullSecret" }}
{{- printf "{\"auths\": {\"%s\": {\"auth\": \"%s\"}}}" .Values.imageCredentials.registry (printf "%s:%s" .Values.imageCredentials.username .Values.imageCredentials.password | b64enc) | b64enc }}
{{- end }}
{{/* vim: set filetype=mustache: */}}

View File

@@ -0,0 +1,41 @@
{{/*
Copyright 2020 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if .Values.config }}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "haproxy.fullname" . }}
namespace: {{ include "haproxy.namespace" . }}
labels:
{{- include "haproxy.labels" . | nindent 4 }}
data:
{{ .Values.configMount.subPath | default "haproxy.cfg" }}: |+
{{ tpl .Values.config . | nindent 4 }}
{{- end }}
{{- if .Values.includes }}
---
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "haproxy.includes" . }}
namespace: {{ include "haproxy.namespace" . }}
data:
{{- range $key, $val := .Values.includes }}
{{ $key }}: | {{ $val | nindent 4 }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,193 @@
{{/*
Copyright 2020 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if eq .Values.kind "DaemonSet" }}
{{- $useHostNetwork := .Values.daemonset.useHostNetwork -}}
{{- $useHostPort := .Values.daemonset.useHostPort -}}
{{- $hostPorts := .Values.daemonset.hostPorts -}}
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: {{ include "haproxy.fullname" . }}
namespace: {{ include "haproxy.namespace" . }}
labels:
{{- include "haproxy.labels" . | nindent 4 }}
spec:
minReadySeconds: {{ .Values.minReadySeconds }}
updateStrategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
selector:
matchLabels:
{{- include "haproxy.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "haproxy.selectorLabels" . | nindent 8 }}
{{- if .Values.podLabels }}
{{ toYaml .Values.podLabels | indent 8 }}
{{- end }}
annotations:
{{- if .Values.checksumConfigMap.enabled }}
checksum/environment: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
{{- end }}
{{- if .Values.podAnnotations }}
{{ tpl (toYaml .Values.podAnnotations) . | indent 8 }}
{{- end }}
spec:
{{- if .Values.shareProcessNamespace.enabled }}
shareProcessNamespace: true
{{- end }}
serviceAccountName: {{ include "haproxy.serviceAccountName" . }}
{{- if hasKey .Values.serviceAccount "automountServiceAccountToken" }}
automountServiceAccountToken: {{ .Values.serviceAccount.automountServiceAccountToken }}
{{- end }}
terminationGracePeriodSeconds: {{ .Values.terminationGracePeriodSeconds }}
{{- if $useHostNetwork }}
hostNetwork: true
{{- end }}
securityContext:
{{- toYaml .Values.podSecurityContext | nindent 8 }}
{{- if .Values.dnsConfig }}
dnsConfig:
{{ toYaml .Values.dnsConfig | indent 8 }}
{{- end }}
dnsPolicy: {{ .Values.dnsPolicy }}
{{- if .Values.imageCredentials.registry }}
imagePullSecrets:
- name: {{ include "haproxy.fullname" . }}
{{- else if .Values.existingImagePullSecret }}
imagePullSecrets:
- name: {{ .Values.existingImagePullSecret }}
{{- end }}
{{- if .Values.priorityClassName }}
priorityClassName: {{ .Values.priorityClassName }}
{{- end }}
volumes:
- name: haproxy-config
configMap:
name: {{ include "haproxy.fullname" . }}
{{- if .Values.includes }}
- name: includes
projected:
sources:
- configMap:
name: {{ include "haproxy.includes" . }}
{{- end }}
{{- range $mountedSecret := .Values.mountedSecrets }}
- name: {{ $mountedSecret.volumeName }}
secret:
secretName: {{ $mountedSecret.secretName }}
{{- end }}
{{- with.Values.extraVolumes }}
{{- toYaml . | nindent 8 }}
{{- end }}
containers:
{{- with.Values.sidecarContainers }}
{{- toYaml . | nindent 8 }}
{{- end }}
- name: {{ .Chart.Name }}
{{- if .Values.securityContext.enabled }}
securityContext: {{- omit .Values.securityContext "enabled" | toYaml | nindent 12 }}
{{- end }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
{{- if .Values.args.enabled }}
args:
{{- range .Values.args.defaults }}
- {{ . }}
{{- end }}
{{- range .Values.args.extraArgs }}
- {{ . }}
{{- end }}
{{- end }}
ports:
{{- range $key, $value := .Values.containerPorts }}
- name: {{ $key }}
containerPort: {{ $value }}
protocol: TCP
{{- if and $useHostPort (index $hostPorts $key) }}
hostPort: {{ index $hostPorts $key }}
{{- end }}
{{- end }}
{{- with .Values.rawContainerPorts }}
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.livenessProbe }}
livenessProbe:
{{- toYaml . | trim | nindent 12 }}
{{- end }}
{{- with .Values.readinessProbe }}
readinessProbe:
{{- toYaml . | trim | nindent 12 }}
{{- end }}
{{- with .Values.startupProbe }}
startupProbe:
{{- toYaml . | trim | nindent 12 }}
{{- end }}
{{- with .Values.extraEnvs }}
env:
{{- toYaml . | trim | nindent 12 }}
{{- end }}
{{- with .Values.extraEnvFrom }}
envFrom:
{{- toYaml . | trim | nindent 12 }}
{{- end }}
resources:
{{- toYaml .Values.resources | nindent 12 }}
{{- if .Values.lifecycle }}
lifecycle:
{{- if eq "string" (printf "%T" .Values.lifecycle) }}
{{ tpl .Values.lifecycle . | indent 12 }}
{{- else }}
{{ toYaml .Values.lifecycle | indent 12 }}
{{- end }}
{{- end }}
volumeMounts:
- name: haproxy-config
mountPath: {{ .Values.configMount.mountPath }}
{{- if .Values.configMount.subPath }}
subPath: {{ .Values.configMount.subPath }}
{{- end }}
{{- if .Values.includes }}
- name: includes
mountPath: {{ .Values.includesMountPath }}
{{- end }}
{{- with.Values.extraVolumeMounts }}
{{- toYaml . | nindent 12 }}
{{- end }}
{{- range $mountedSecret := .Values.mountedSecrets }}
- name: {{ $mountedSecret.volumeName }}
mountPath: {{ $mountedSecret.mountPath }}
{{- end }}
{{- with.Values.initContainers }}
initContainers:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,198 @@
{{/*
Copyright 2020 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if eq .Values.kind "Deployment" }}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "haproxy.fullname" . }}
namespace: {{ include "haproxy.namespace" . }}
labels:
{{- include "haproxy.labels" . | nindent 4 }}
{{- if .Values.deploymentLabels }}
{{ tpl (toYaml .Values.deploymentLabels) . | indent 4 }}
{{- end }}
annotations:
{{- if .Values.deploymentAnnotations }}
{{ tpl (toYaml .Values.deploymentAnnotations) . | indent 4 }}
{{- end }}
spec:
minReadySeconds: {{ .Values.minReadySeconds }}
{{- if and (not .Values.autoscaling.enabled) (not .Values.keda.enabled) }}
replicas: {{ .Values.replicaCount }}
{{- end }}
selector:
matchLabels:
{{- include "haproxy.selectorLabels" . | nindent 6 }}
{{- with .Values.strategy }}
strategy:
{{- toYaml . | nindent 4 }}
{{- end }}
template:
metadata:
labels:
{{- include "haproxy.selectorLabels" . | nindent 8 }}
{{- if .Values.podLabels }}
{{ toYaml .Values.podLabels | indent 8 }}
{{- end }}
annotations:
{{- if .Values.checksumConfigMap.enabled }}
checksum/environment: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
{{- end }}
{{- if .Values.podAnnotations }}
{{ tpl (toYaml .Values.podAnnotations) . | indent 8 }}
{{- end }}
spec:
{{- if .Values.shareProcessNamespace.enabled }}
shareProcessNamespace: true
{{- end }}
serviceAccountName: {{ include "haproxy.serviceAccountName" . }}
{{- if hasKey .Values.serviceAccount "automountServiceAccountToken" }}
automountServiceAccountToken: {{ .Values.serviceAccount.automountServiceAccountToken }}
{{- end }}
terminationGracePeriodSeconds: {{ .Values.terminationGracePeriodSeconds }}
securityContext:
{{- toYaml .Values.podSecurityContext | nindent 8 }}
{{- with .Values.topologySpreadConstraints }}
topologySpreadConstraints:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- if .Values.dnsConfig }}
dnsConfig:
{{ toYaml .Values.dnsConfig | indent 8 }}
{{- end }}
dnsPolicy: {{ .Values.dnsPolicy }}
{{- if .Values.imageCredentials.registry }}
imagePullSecrets:
- name: {{ include "haproxy.fullname" . }}
{{- else if .Values.existingImagePullSecret }}
imagePullSecrets:
- name: {{ .Values.existingImagePullSecret }}
{{- end }}
{{- if .Values.priorityClassName }}
priorityClassName: {{ .Values.priorityClassName }}
{{- end }}
volumes:
- name: haproxy-config
configMap:
name: {{ include "haproxy.fullname" . }}
{{- if .Values.includes }}
- name: includes
projected:
sources:
- configMap:
name: {{ include "haproxy.includes" . }}
{{- end }}
{{- range $mountedSecret := .Values.mountedSecrets }}
- name: {{ $mountedSecret.volumeName }}
secret:
secretName: {{ $mountedSecret.secretName }}
{{- end }}
{{- with.Values.extraVolumes }}
{{- toYaml . | nindent 8 }}
{{- end }}
containers:
{{- with.Values.sidecarContainers }}
{{- toYaml . | nindent 8 }}
{{- end }}
- name: {{ .Chart.Name }}
{{- if .Values.securityContext.enabled }}
securityContext: {{- omit .Values.securityContext "enabled" | toYaml | nindent 12 }}
{{- end }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
{{- if .Values.args.enabled }}
args:
{{- range .Values.args.defaults }}
- {{ . }}
{{- end }}
{{- range .Values.args.extraArgs }}
- {{ . }}
{{- end }}
{{- end }}
ports:
{{- range $key, $value := .Values.containerPorts }}
- name: {{ $key }}
containerPort: {{ $value }}
protocol: TCP
{{- end }}
{{- with .Values.rawContainerPorts }}
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.livenessProbe }}
livenessProbe:
{{- toYaml . | trim | nindent 12 }}
{{- end }}
{{- with .Values.readinessProbe }}
readinessProbe:
{{- toYaml . | trim | nindent 12 }}
{{- end }}
{{- with .Values.startupProbe }}
startupProbe:
{{- toYaml . | trim | nindent 12 }}
{{- end }}
{{- with .Values.extraEnvs }}
env:
{{- toYaml . | trim | nindent 12 }}
{{- end }}
{{- with .Values.extraEnvFrom }}
envFrom:
{{- toYaml . | trim | nindent 12 }}
{{- end }}
resources:
{{- toYaml .Values.resources | nindent 12 }}
{{- if .Values.lifecycle }}
lifecycle:
{{- if eq "string" (printf "%T" .Values.lifecycle) }}
{{ tpl .Values.lifecycle . | indent 12 }}
{{- else }}
{{ toYaml .Values.lifecycle | indent 12 }}
{{- end }}
{{- end }}
volumeMounts:
- name: haproxy-config
mountPath: {{ .Values.configMount.mountPath }}
{{- if .Values.configMount.subPath }}
subPath: {{ .Values.configMount.subPath }}
{{- end }}
{{- if .Values.includes }}
- name: includes
mountPath: {{ .Values.includesMountPath }}
{{- end }}
{{- with.Values.extraVolumeMounts }}
{{- toYaml . | nindent 12 }}
{{- end }}
{{- range $mountedSecret := .Values.mountedSecrets }}
- name: {{ $mountedSecret.volumeName }}
mountPath: {{ $mountedSecret.mountPath }}
{{- end }}
{{- with.Values.initContainers }}
initContainers:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,63 @@
{{/*
Copyright 2020 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if and (eq .Values.kind "Deployment") .Values.autoscaling.enabled }}
{{- if not .Values.keda.enabled }}
{{- if .Capabilities.APIVersions.Has "autoscaling/v2" }}
apiVersion: autoscaling/v2
{{- else if .Capabilities.APIVersions.Has "autoscaling/v2beta2" }}
apiVersion: autoscaling/v2beta2
{{- else }}
{{- fail "ERROR: You must have autoscaling/v2 or autoscaling/v2beta2 to use HorizontalPodAutoscaler" }}
{{- end }}
kind: HorizontalPodAutoscaler
metadata:
name: {{ include "haproxy.fullname" . }}
namespace: {{ include "haproxy.namespace" . }}
labels:
{{- include "haproxy.labels" . | nindent 4 }}
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: {{ include "haproxy.fullname" . }}
minReplicas: {{ .Values.autoscaling.minReplicas }}
maxReplicas: {{ .Values.autoscaling.maxReplicas }}
{{- if .Values.autoscaling.behavior }}
behavior: {{- toYaml .Values.autoscaling.behavior | nindent 4 }}
{{- end }}
metrics:
{{- if .Values.autoscaling.targetMemoryUtilizationPercentage }}
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }}
{{- end }}
{{- if .Values.autoscaling.targetCPUUtilizationPercentage }}
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
{{- end }}
{{- with .Values.autoscaling.additionalMetrics }}
{{- toYaml . | trim | nindent 4 }}
{{- end }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,40 @@
{{- if .Values.httpRoute.enabled -}}
{{- $fullName := include "haproxy.fullname" . -}}
{{- $svcPort := .Values.httpRoute.servicePort -}}
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: {{ $fullName }}
labels:
{{- include "haproxy.labels" . | nindent 4 }}
{{- with .Values.httpRoute.labels }}
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.httpRoute.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
parentRefs:
{{- with .Values.httpRoute.parentRefs }}
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.httpRoute.hostnames }}
hostnames:
{{- toYaml . | nindent 4 }}
{{- end }}
rules:
{{- range .Values.httpRoute.rules }}
{{- with .matches }}
- matches:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .filters }}
filters:
{{- toYaml . | nindent 8 }}
{{- end }}
backendRefs:
- name: {{ $fullName }}
port: {{ $svcPort }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,59 @@
{{- if .Values.ingress.enabled -}}
{{- $fullName := include "haproxy.fullname" . -}}
{{- $svcPort := .Values.ingress.servicePort -}}
{{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }}
{{- if not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class") }}
{{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}}
{{- end }}
{{- end }}
{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}}
apiVersion: networking.k8s.io/v1
{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
apiVersion: networking.k8s.io/v1beta1
{{- else -}}
apiVersion: extensions/v1beta1
{{- end }}
kind: Ingress
metadata:
name: {{ $fullName }}
namespace: {{ include "haproxy.namespace" . }}
labels:
{{- include "haproxy.labels" . | nindent 4 }}
{{- with .Values.ingress.labels }}
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.ingress.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }}
ingressClassName: {{ .Values.ingress.className }}
{{- end }}
rules:
{{- range .Values.ingress.hosts }}
- host: {{ .host | quote }}
http:
paths:
{{- range .paths }}
- path: {{ .path }}
{{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }}
pathType: {{ .pathType }}
{{- end }}
backend:
{{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }}
service:
name: {{ $fullName }}
port:
number: {{ $svcPort }}
{{- else }}
serviceName: {{ $fullName }}
servicePort: {{ $svcPort }}
{{- end }}
{{- end }}
{{- end }}
{{- if .Values.ingress.tls }}
tls:
{{- toYaml .Values.ingress.tls | nindent 4 }}
{{- end -}}
{{- end }}

View File

@@ -0,0 +1,54 @@
{{/*
Copyright 2021 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if and (eq .Values.kind "Deployment") .Values.keda.enabled }}
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: {{ include "haproxy.fullname" . }}
namespace: {{ include "haproxy.namespace" . }}
labels:
{{- include "haproxy.labels" . | nindent 4 }}
{{- if .Values.keda.scaledObject.annotations }}
annotations: {{ toYaml .Values.keda.scaledObject.annotations | nindent 4 }}
{{- end }}
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: {{ include "haproxy.fullname" . }}
pollingInterval: {{ .Values.keda.pollingInterval }}
cooldownPeriod: {{ .Values.keda.cooldownPeriod }}
minReplicaCount: {{ .Values.keda.minReplicas }}
maxReplicaCount: {{ .Values.keda.maxReplicas }}
triggers:
{{- with .Values.keda.triggers }}
{{ toYaml . | indent 2 }}
{{ end }}
{{- with .Values.keda.fallback }}
fallback:
{{ toYaml . | indent 4 }}
{{- end }}
advanced:
restoreToOriginalReplicaCount: {{ .Values.keda.restoreToOriginalReplicaCount }}
{{- if .Values.keda.behavior }}
horizontalPodAutoscalerConfig:
behavior:
{{ with .Values.keda.behavior -}}
{{ toYaml . | indent 8 }}
{{ end }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,41 @@
{{/*
Copyright 2019 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if .Values.PodDisruptionBudget.enable }}
{{- if .Capabilities.APIVersions.Has "policy/v1" }}
apiVersion: policy/v1
{{- else if .Capabilities.APIVersions.Has "policy/v1beta1" }}
apiVersion: policy/v1beta1
{{- else }}
{{- fail "ERROR: You must have policy/v1 or policy/v1 to use PodDisruptionBudget" }}
{{- end }}
kind: PodDisruptionBudget
metadata:
name: {{ include "haproxy.fullname" . }}
namespace: {{ include "haproxy.namespace" . }}
labels:
{{- include "haproxy.labels" . | nindent 4 }}
spec:
{{- if .Values.PodDisruptionBudget.maxUnavailable }}
maxUnavailable: {{ .Values.PodDisruptionBudget.maxUnavailable }}
{{- end }}
{{- if .Values.PodDisruptionBudget.minAvailable }}
minAvailable: {{ .Values.PodDisruptionBudget.minAvailable }}
{{- end }}
selector:
matchLabels:
{{- include "haproxy.selectorLabels" . | nindent 6 }}
{{- end }}

View File

@@ -0,0 +1,85 @@
{{/*
Copyright 2020 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if (semverCompare "<1.25.0-0" .Capabilities.KubeVersion.Version) }}
{{- if and .Values.rbac.create .Values.podSecurityPolicy.enabled -}}
{{- $useHostNetwork := .Values.daemonset.useHostNetwork -}}
{{- $useHostPort := .Values.daemonset.useHostPort -}}
{{- $hostPorts := .Values.daemonset.hostPorts -}}
{{- if .Capabilities.APIVersions.Has "policy/v1/PodSecurityPolicy" }}
apiVersion: policy/v1
{{- else }}
apiVersion: policy/v1beta1
{{- end }}
kind: PodSecurityPolicy
metadata:
name: {{ include "haproxy.fullname" . }}
namespace: {{ include "haproxy.namespace" . }}
labels:
{{- include "haproxy.labels" . | nindent 4 }}
{{- if .Values.podSecurityPolicy.annotations }}
annotations:
{{ toYaml .Values.podSecurityPolicy.annotations | indent 4 }}
{{- else }}
annotations:
seccomp.security.alpha.kubernetes.io/allowedProfileNames: 'docker/default,runtime/default'
apparmor.security.beta.kubernetes.io/allowedProfileNames: 'runtime/default'
seccomp.security.alpha.kubernetes.io/defaultProfileName: 'runtime/default'
apparmor.security.beta.kubernetes.io/defaultProfileName: 'runtime/default'
{{- end }}
spec:
allowPrivilegeEscalation: true
allowedCapabilities:
- NET_BIND_SERVICE
defaultAllowPrivilegeEscalation: false
fsGroup:
rule: MustRunAs
ranges:
- max: 65535
min: 1
{{- if $useHostNetwork }}
hostNetwork: true
{{- end }}
{{- if or $useHostPort $useHostNetwork }}
hostPorts:
{{- range $key, $value := .Values.containerPorts }}
- min: {{ $value }}
max: {{ $value }}
{{- end }}
{{- end }}
hostIPC: false
hostPID: false
privileged: false
runAsUser:
rule: RunAsAny
seLinux:
rule: RunAsAny
supplementalGroups:
rule: MustRunAs
ranges:
- max: 65535
min: 1
volumes:
- configMap
- emptyDir
- projected
- secret
{{- with .Values.podSecurityPolicy.allowedUnsafeSysctls }}
allowedUnsafeSysctls:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,28 @@
{{/*
Copyright 2020 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if .Values.imageCredentials.registry }}
apiVersion: v1
kind: Secret
metadata:
name: {{ include "haproxy.fullname" . }}
namespace: {{ include "haproxy.namespace" . }}
labels:
{{- include "haproxy.labels" . | nindent 4 }}
type: kubernetes.io/dockerconfigjson
data:
.dockerconfigjson: {{ include "haproxy.imagePullSecret" . }}
{{- end }}

View File

@@ -0,0 +1,34 @@
{{/*
Copyright 2019 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if and .Values.rbac.create .Values.podSecurityPolicy.enabled -}}
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: {{ include "haproxy.fullname" . }}
namespace: {{ include "haproxy.namespace" . }}
labels:
{{- include "haproxy.labels" . | nindent 4 }}
rules:
- apiGroups:
- "policy"
resources:
- podsecuritypolicies
verbs:
- use
resourceNames:
- {{ include "haproxy.fullname" . }}
{{- end -}}

View File

@@ -0,0 +1,33 @@
{{/*
Copyright 2019 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if and .Values.rbac.create .Values.podSecurityPolicy.enabled -}}
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: {{ include "haproxy.fullname" . }}
namespace: {{ include "haproxy.namespace" . }}
labels:
{{- include "haproxy.labels" . | nindent 4 }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: {{ include "haproxy.fullname" . }}
subjects:
- kind: ServiceAccount
name: {{ include "haproxy.serviceAccountName" . }}
namespace: {{ .Release.Namespace }}
{{- end -}}

View File

@@ -0,0 +1,91 @@
{{/*
Copyright 2020 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
apiVersion: v1
kind: Service
metadata:
name: {{ include "haproxy.fullname" . }}
namespace: {{ include "haproxy.namespace" . }}
labels:
{{- include "haproxy.labels" . | nindent 4 }}
{{- range $key, $value := .Values.service.labels }}
{{ $key }}: {{ $value | quote }}
{{- end }}
annotations:
{{- range $key, $value := .Values.service.annotations }}
{{ $key }}: {{ $value | quote }}
{{- end }}
spec:
type: {{ .Values.service.type }}
selector:
{{- include "haproxy.selectorLabels" . | nindent 4 }}
{{- if .Values.service.externalTrafficPolicy }}
externalTrafficPolicy: {{ .Values.service.externalTrafficPolicy }}
{{- end }}
{{- if .Values.service.internalTrafficPolicy }}
internalTrafficPolicy: {{ .Values.service.internalTrafficPolicy }}
{{- end }}
{{- with .Values.service.clusterIP }}
clusterIP: {{ . | quote}}
{{- end }}
{{- with .Values.service.loadBalancerIP }}
loadBalancerIP: {{ . | quote }}
{{- end }}
{{- with .Values.service.loadBalancerSourceRanges }}
loadBalancerSourceRanges:
{{- toYaml . | nindent 2 }}
{{- end }}
{{- if .Values.service.ipFamilies }}
ipFamilies:
{{- toYaml .Values.service.ipFamilies | nindent 2 }}
{{- end }}
{{- if .Values.service.ipFamilyPolicy }}
ipFamilyPolicy: {{ .Values.service.ipFamilyPolicy | quote }}
{{- end }}
{{- with .Values.service.externalIPs }}
externalIPs:
{{- toYaml . | nindent 2 }}
{{- end }}
{{- if or .Values.containerPorts .Values.service.additionalPorts .Values.service.rawAdditionalPorts }}
{{- $nodePorts := .Values.service.nodePorts }}
{{- $servicePortType := .Values.service.type }}
ports:
{{- with .Values.containerPorts }}
{{- range $key, $port := . }}
- name: {{ $key }}
protocol: TCP
port: {{ $port }}
targetPort: {{ $key }}
{{- if and (hasKey $nodePorts $key) (eq $servicePortType "NodePort") }}
nodePort: {{ get $nodePorts $key }}
{{- end }}
{{- end }}
{{- end }}
{{- with .Values.service.additionalPorts }}
{{- range $key, $port := . }}
- name: {{ $key }}
protocol: TCP
port: {{ $port }}
targetPort: {{ $key }}
{{- if and (hasKey $nodePorts $key) (eq $servicePortType "NodePort") }}
nodePort: {{ get $nodePorts $key }}
{{- end }}
{{- end }}
{{- end }}
{{- with .Values.service.rawAdditionalPorts }}
{{- toYaml . | nindent 2 }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,32 @@
{{/*
Copyright 2020 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if .Values.serviceAccount.create -}}
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ include "haproxy.serviceAccountName" . }}
namespace: {{ include "haproxy.namespace" . }}
labels:
{{- include "haproxy.labels" . | nindent 4 }}
{{- with .Values.serviceAccount.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- if hasKey .Values.serviceAccount "automountServiceAccountToken" }}
automountServiceAccountToken: {{ .Values.serviceAccount.automountServiceAccountToken }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,37 @@
{{/*
Copyright 2022 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if and (.Capabilities.APIVersions.Has "monitoring.coreos.com/v1") .Values.serviceMonitor.enabled }}
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: {{ include "haproxy.fullname" . }}
namespace: {{ include "haproxy.namespace" . }}
labels:
{{- include "haproxy.labels" . | nindent 4 }}
{{- if .Values.serviceMonitor.extraLabels }}
{{ toYaml .Values.serviceMonitor.extraLabels | nindent 4 }}
{{- end }}
spec:
endpoints:
{{ .Values.serviceMonitor.endpoints | toYaml | nindent 4 }}
namespaceSelector:
matchNames:
- {{ .Release.Namespace }}
selector:
matchLabels:
{{- include "haproxy.selectorLabels" . | nindent 6 }}
{{- end }}

Some files were not shown because too many files have changed in this diff Show More