From a207c20b9c7a65c9e2020418eb512c26241565c6 Mon Sep 17 00:00:00 2001 From: lgtm <1gtm@users.noreply.github.com> Date: Mon, 18 Mar 2024 06:30:39 -0700 Subject: [PATCH] Prepare for release v2024.3.18 (#62) ProductLine: Voyager Release: v2024.3.18 Release-tracker: https://github.com/voyagermesh/CHANGELOG/pull/29 Signed-off-by: 1gtm <1gtm@appscode.com> --- config.dev.yaml | 2 +- config.yaml | 2 +- .../CHANGELOG-v2021.04.20-beta.2.md | 170 ++ .../v2024.3.18/CHANGELOG-v2021.04.24-rc.0.md | 184 ++ .../docs/v2024.3.18/CHANGELOG-v2021.09.15.md | 1320 ++++++++++ .../docs/v2024.3.18/CHANGELOG-v2021.10.16.md | 64 + .../docs/v2024.3.18/CHANGELOG-v2021.10.17.md | 51 + .../docs/v2024.3.18/CHANGELOG-v2021.10.18.md | 63 + .../docs/v2024.3.18/CHANGELOG-v2022.01.01.md | 70 + .../docs/v2024.3.18/CHANGELOG-v2022.01.07.md | 43 + .../docs/v2024.3.18/CHANGELOG-v2022.01.10.md | 60 + .../docs/v2024.3.18/CHANGELOG-v2022.02.22.md | 63 + .../docs/v2024.3.18/CHANGELOG-v2022.03.17.md | 60 + .../docs/v2024.3.18/CHANGELOG-v2022.04.13.md | 58 + .../docs/v2024.3.18/CHANGELOG-v2022.06.20.md | 67 + .../docs/v2024.3.18/CHANGELOG-v2022.08.17.md | 62 + .../docs/v2024.3.18/CHANGELOG-v2022.12.11.md | 75 + .../docs/v2024.3.18/CHANGELOG-v2023.02.22.md | 62 + .../docs/v2024.3.18/CHANGELOG-v2023.05.16.md | 78 + .../docs/v2024.3.18/CHANGELOG-v2023.9.18.md | 68 + .../docs/v2024.3.18/CHANGELOG-v2024.3.18.md | 71 + content/docs/v2024.3.18/CHANGELOG.md | 2193 +++++++++++++++++ content/docs/v2024.3.18/CONTRIBUTING.md | 66 + content/docs/v2024.3.18/README.md | 43 + content/docs/v2024.3.18/_index.md | 15 + content/docs/v2024.3.18/acknowledgement.md | 30 + content/docs/v2024.3.18/concepts/README.md | 31 + content/docs/v2024.3.18/concepts/_index.md | 15 + content/docs/v2024.3.18/concepts/haproxy.md | 0 .../concepts/ingress-types/_index.md | 17 + .../concepts/ingress-types/hostport.md | 182 ++ .../concepts/ingress-types/internal.md | 146 ++ .../concepts/ingress-types/loadbalancer.md | 211 ++ .../concepts/ingress-types/nodeport.md | 233 ++ content/docs/v2024.3.18/concepts/overview.md | 86 + .../cert-manager/azure/certificate.yaml | 11 + .../examples/cert-manager/azure/ingress.yaml | 25 + .../examples/cert-manager/azure/issuer.yaml | 28 + .../examples/cert-manager/certificate.yaml | 15 + .../google_cloud/certificate.yaml | 11 + .../cert-manager/google_cloud/ingress.yaml | 25 + .../cert-manager/google_cloud/issuer.yaml | 21 + .../cert-manager/http/clusterissuer.yaml | 19 + .../examples/cert-manager/http/ingress.yaml | 24 + .../examples/cert-manager/issuer.yaml | 19 + .../examples/cert-manager/multiple.yaml | 47 + .../cert-manager/route53/certificate.yaml | 0 .../cert-manager/route53/ingress.yaml | 0 .../examples/cert-manager/route53/issuer.yaml | 0 .../ingress/pod-placement/deploy-servers.sh | 25 + .../ingress-w-node-selector.yaml | 27 + .../ingress-w-pod-anti-affinity.yaml | 39 + .../pod-placement/ingress-w-toleration.yaml | 30 + .../ingress/types/hostport/deploy-servers.sh | 21 + .../ingress/types/hostport/haproxy.cfg | 47 + .../examples/ingress/types/hostport/ing.yaml | 27 + .../ingress/types/internal/deploy-servers.sh | 21 + .../ingress/types/internal/haproxy.cfg | 47 + .../examples/ingress/types/internal/ing.yaml | 27 + .../types/loadbalancer/deploy-servers.sh | 21 + .../ingress/types/loadbalancer/haproxy.cfg | 47 + .../ingress/types/loadbalancer/ing.yaml | 27 + .../ingress/types/nodeport/deploy-servers.sh | 21 + .../ingress/types/nodeport/haproxy.cfg | 47 + .../examples/ingress/types/nodeport/ing.yaml | 28 + .../monitoring/builtin-prometheus/demo-1.yaml | 43 + .../monitoring/builtin-prometheus/demo-2.yaml | 90 + .../monitoring/builtin-prometheus/ing.yaml | 20 + .../monitoring/coreos-operator/demo-0.yaml | 100 + .../monitoring/coreos-operator/demo-1.yaml | 68 + .../monitoring/coreos-operator/ing.yaml | 22 + .../monitoring/metrics-collector.yaml | 20 + .../examples/monitoring/profiler.yaml | 20 + .../examples/monitoring/stats-ing.yaml | 19 + content/docs/v2024.3.18/guides/_index.md | 15 + .../v2024.3.18/guides/cert-manager/README.md | 41 + .../v2024.3.18/guides/cert-manager/_index.md | 15 + .../cert-manager/dns01_challenge/_index.md | 16 + .../dns01_challenge/aws-route53.md | 216 ++ .../cert-manager/dns01_challenge/azure-dns.md | 182 ++ .../dns01_challenge/google-cloud-dns.md | 155 ++ .../multiple-challenge-solver.md | 85 + .../guides/cert-manager/get-started.md | 143 ++ .../cert-manager/http01_challenge/_index.md | 16 + .../cert-manager/http01_challenge/overview.md | 131 + .../docs/v2024.3.18/guides/ingress/README.md | 64 + .../docs/v2024.3.18/guides/ingress/_index.md | 15 + .../guides/ingress/configuration/_index.md | 15 + .../ingress/configuration/accept-proxy.md | 118 + .../ingress/configuration/agent-check.md | 116 + .../ingress/configuration/annotations.md | 89 + .../ingress/configuration/backend-rule.md | 48 + .../ingress/configuration/bind-address.md | 19 + .../guides/ingress/configuration/body-size.md | 186 ++ .../ingress/configuration/config-volumes.md | 196 ++ .../ingress/configuration/custom-templates.md | 70 + .../ingress/configuration/default-options.md | 104 + .../ingress/configuration/default-timeouts.md | 119 + .../ingress/configuration/error-files.md | 45 + .../ingress/configuration/frontend-rule.md | 174 ++ .../ingress/configuration/hard-stop-after.md | 106 + .../ingress/configuration/health-check.md | 123 + .../guides/ingress/configuration/http-2.md | 387 +++ .../ingress/configuration/keep-source-ip.md | 63 + .../ingress/configuration/loadbalancer-ip.md | 47 + .../configuration/loadbalancing-algorithm.md | 118 + .../ingress/configuration/max-connections.md | 166 ++ .../guides/ingress/configuration/node-port.md | 208 ++ .../ingress/configuration/pod-annotations.md | 62 + .../ingress/configuration/rate-limit.md | 109 + .../ingress/configuration/rewrite-target.md | 155 ++ .../configuration/service-annotations.md | 64 + .../ingress/configuration/ssl-passthrough.md | 107 + .../ingress/configuration/ssl-redirect.md | 175 ++ .../guides/ingress/configuration/whitelist.md | 101 + .../v2024.3.18/guides/ingress/debugging.md | 2 + .../v2024.3.18/guides/ingress/dns/_index.md | 15 + .../guides/ingress/dns/external-dns.md | 88 + .../guides/ingress/graceful-reload.md | 184 ++ .../docs/v2024.3.18/guides/ingress/grpc.md | 2 + .../v2024.3.18/guides/ingress/http/_index.md | 15 + .../ingress/http/blue-green-deployment.md | 138 ++ .../v2024.3.18/guides/ingress/http/cors.md | 134 + .../guides/ingress/http/custom-http-port.md | 76 + .../guides/ingress/http/external-svc.md | 165 ++ .../v2024.3.18/guides/ingress/http/hsts.md | 229 ++ .../v2024.3.18/guides/ingress/http/http2.md | 62 + .../guides/ingress/http/rewrite-rules.md | 52 + .../guides/ingress/http/single-service.md | 85 + .../guides/ingress/http/source-range.md | 75 + .../guides/ingress/http/statefulset-pod.md | 129 + .../guides/ingress/http/sticky-session.md | 141 ++ .../guides/ingress/http/virtual-hosting.md | 121 + .../guides/ingress/monitoring/_index.md | 15 + .../ingress/monitoring/haproxy-stats.md | 161 ++ .../ingress/monitoring/operator-profiling.md | 95 + .../ingress/monitoring/operator-stats.md | 80 + .../monitoring/using-builtin-prometheus.md | 299 +++ .../using-coreos-prometheus-operator.md | 217 ++ .../guides/ingress/pod-placement.md | 292 +++ .../docs/v2024.3.18/guides/ingress/scaling.md | 94 + .../guides/ingress/security/_index.md | 15 + .../guides/ingress/security/basic-auth.md | 295 +++ .../ingress/security/oauth-dashboard.md | 190 ++ .../guides/ingress/security/oauth-github.md | 287 +++ .../guides/ingress/security/oauth-google.md | 289 +++ .../guides/ingress/security/oauth.md | 146 ++ .../ingress/security/restrict-namespace.md | 2 + .../guides/ingress/security/tls-auth.md | 232 ++ content/docs/v2024.3.18/guides/ingress/ssh.md | 2 + .../v2024.3.18/guides/ingress/tcp/_index.md | 15 + .../v2024.3.18/guides/ingress/tcp/overview.md | 70 + .../v2024.3.18/guides/ingress/tcp/tcp-sni.md | 194 ++ .../v2024.3.18/guides/ingress/tls/_index.md | 15 + .../guides/ingress/tls/aws-cert-manager.md | 82 + .../guides/ingress/tls/backend-tls.md | 88 + .../guides/ingress/tls/multiple-tls.md | 284 +++ .../v2024.3.18/guides/ingress/tls/overview.md | 216 ++ .../v2024.3.18/guides/ingress/websocket.md | 2 + .../images/cert-manager/azure/a-record.png | Bin 0 -> 177418 bytes .../cert-manager/azure/client-secret.png | Bin 0 -> 142965 bytes .../cert-manager/azure/client-tenant.png | Bin 0 -> 191258 bytes .../azure/dns-zone-contributor.png | Bin 0 -> 263103 bytes .../cert-manager/azure/new-registration.png | Bin 0 -> 143098 bytes .../cert-manager/azure/new-registration2.png | Bin 0 -> 141312 bytes .../cert-manager/azure/subscriptions.png | Bin 0 -> 88479 bytes .../images/cert-manager/azure/user-access.png | Bin 0 -> 258455 bytes .../images/cert-manager/google_dns/svcac1.png | Bin 0 -> 65322 bytes .../images/cert-manager/google_dns/svcac2.png | Bin 0 -> 79504 bytes .../images/cert-manager/google_dns/svcac3.png | Bin 0 -> 118252 bytes .../images/cert-manager/route53/a-record.png | Bin 0 -> 140255 bytes .../cert-manager/route53/access-type.png | Bin 0 -> 76067 bytes .../images/cert-manager/route53/add-user.png | Bin 0 -> 71009 bytes .../cert-manager/route53/attach-policy.png | Bin 0 -> 59856 bytes .../cert-manager/route53/create-policy.png | Bin 0 -> 133508 bytes .../cert-manager/route53/hosted-zone-id.png | Bin 0 -> 77313 bytes .../images/cert-manager/route53/iam.png | Bin 0 -> 243019 bytes .../cert-manager/route53/policy-json.png | Bin 0 -> 109900 bytes .../cert-manager/route53/review-policy.png | Bin 0 -> 60606 bytes .../cert-manager/route53/review-user.png | Bin 0 -> 59946 bytes .../images/cert-manager/route53/route53.png | Bin 0 -> 219830 bytes .../cert-manager/route53/success-user.png | Bin 0 -> 66488 bytes .../custom-template/installer.png | Bin 0 -> 71933 bytes .../multiple-tls/aa.appscode.ninja.png | Bin 0 -> 71352 bytes .../multiple-tls/bb.appscode.ninja.png | Bin 0 -> 71777 bytes .../ingress/multiple-tls/cert-details.png | Bin 0 -> 121661 bytes .../multiple-tls/connection-secure.png | Bin 0 -> 81550 bytes .../ingress/multiple-tls/google-dns.png | Bin 0 -> 51058 bytes .../multiple-tls/https.aa.appscode.ninja.png | Bin 0 -> 75407 bytes .../multiple-tls/https.bb.appscode.ninja.png | Bin 0 -> 72486 bytes .../images/ingress/voyager-ingress.png | Bin 0 -> 25551 bytes .../images/monitoring/builtin-prometheus.png | Bin 0 -> 54465 bytes .../images/monitoring/coreos-operator.png | Bin 0 -> 43472 bytes .../images/monitoring/operator-metrics.png | Bin 0 -> 114176 bytes .../images/monitoring/operator-profiler.png | Bin 0 -> 19647 bytes .../images/monitoring/stats-view.png | Bin 0 -> 108833 bytes .../images/setup/community_license_form.png | Bin 0 -> 54568 bytes .../images/setup/enterprise_license_form.png | Bin 0 -> 54595 bytes content/docs/v2024.3.18/reference/_index.md | 16 + .../docs/v2024.3.18/reference/cli/_index.md | 16 + .../docs/v2024.3.18/reference/cli/voyager.md | 36 + .../v2024.3.18/reference/cli/voyager_check.md | 35 + .../reference/cli/voyager_completion.md | 67 + .../reference/cli/voyager_convert.md | 34 + .../reference/cli/voyager_version.md | 35 + .../v2024.3.18/reference/operator/_index.md | 16 + .../v2024.3.18/reference/operator/voyager.md | 41 + .../reference/operator/voyager_coordinator.md | 52 + .../reference/operator/voyager_init.md | 52 + .../reference/operator/voyager_operator.md | 59 + .../reference/operator/voyager_run.md | 112 + .../reference/operator/voyager_version.md | 44 + content/docs/v2024.3.18/setup/README.md | 38 + content/docs/v2024.3.18/setup/_index.md | 14 + .../docs/v2024.3.18/setup/install/_index.md | 16 + .../setup/install/troubleshooting.md | 72 + .../docs/v2024.3.18/setup/install/voyager.md | 157 ++ .../docs/v2024.3.18/setup/uninstall/_index.md | 16 + .../v2024.3.18/setup/uninstall/voyager.md | 55 + .../docs/v2024.3.18/setup/upgrade/index.md | 101 + content/docs/v2024.3.18/support.md | 28 + data/authors/md-ishtiaq-islam.json | 9 + data/authors/obaydullah.json | 9 + data/authors/saurov-chandra-biswas.json | 9 + data/authors/tamal-saha.json | 2 +- data/customers.json | 98 +- data/products/appscode.json | 22 +- data/products/configsyncer.json | 18 +- data/products/gateway.json | 6 +- data/products/guard.json | 6 +- data/products/kubeci.json | 6 +- data/products/kubedb.json | 144 +- data/products/kubedb/databases/redis.json | 1 + .../cost-effectiveness.json | 4 +- data/products/kubeform.json | 6 +- data/products/kubeshield.json | 6 +- data/products/kubestash.json | 6 +- data/products/kubevault.json | 46 +- data/products/pharmer.json | 6 +- data/products/searchlight.json | 6 +- data/products/service-broker.json | 6 +- data/products/stash-cli.json | 172 +- data/products/stash-elasticsearch.json | 182 +- data/products/stash-etcd.json | 12 +- data/products/stash-kubedump.json | 12 +- data/products/stash-mariadb.json | 12 +- data/products/stash-mongodb.json | 216 +- data/products/stash-mysql.json | 72 +- data/products/stash-nats.json | 22 +- data/products/stash-percona-xtradb.json | 36 +- data/products/stash-postgres.json | 110 +- data/products/stash.json | 196 +- data/products/swift.json | 6 +- data/products/voyager.json | 43 +- firebase.bk.json | 6 +- firebase.json | 6 +- .../images/authors/md-ishtiaq-islam.jpg | Bin 0 -> 8973 bytes static/assets/images/authors/obaydullah.jpg | Bin 0 -> 8512 bytes .../profile-photos-28x28/md-ishtiaq-islam.jpg | Bin 0 -> 10245 bytes .../profile-photos-28x28/obaydullah.jpg | Bin 0 -> 8512 bytes .../profile-photos-84x84/md-ishtiaq-islam.jpg | Bin 0 -> 9222 bytes .../profile-photos-84x84/obaydullah.jpg | Bin 0 -> 8512 bytes .../saurov-chandra-biswas.jpg | Bin 0 -> 11756 bytes .../images/customers/2024/100-furtune.png | Bin 0 -> 3347 bytes static/assets/images/customers/2024/carro.png | Bin 0 -> 30373 bytes .../assets/images/customers/2024/clewmed.png | Bin 0 -> 19507 bytes .../assets/images/customers/2024/dataloop.png | Bin 0 -> 5486 bytes .../assets/images/customers/2024/decisio.png | Bin 0 -> 3455 bytes .../assets/images/customers/2024/emerson.png | Bin 0 -> 2532 bytes .../images/customers/2024/fastspeed.png | Bin 0 -> 2569 bytes .../images/customers/2024/ge-healthcare.png | Bin 0 -> 4931 bytes .../images/customers/2024/greenhouse.png | Bin 0 -> 3636 bytes static/assets/images/customers/2024/huma.png | Bin 0 -> 2288 bytes .../assets/images/customers/2024/irembo.png | Bin 0 -> 2202 bytes static/assets/images/customers/2024/nokia.png | Bin 0 -> 1345 bytes .../images/customers/2024/oak-ridge.png | Bin 0 -> 5489 bytes .../assets/images/customers/2024/orange.png | Bin 0 -> 3049 bytes static/assets/images/customers/2024/vaimo.png | Bin 0 -> 2547 bytes .../assets/images/customers/2024/wiliot.png | Bin 0 -> 4498 bytes .../images/employees/md-ishtiaq-islam.jpg | Bin 0 -> 8973 bytes static/assets/images/press/1.png | Bin 745573 -> 24460 bytes static/assets/images/press/2.png | Bin 59938 -> 18477 bytes static/assets/images/press/3.png | Bin 163947 -> 41601 bytes static/assets/images/press/4.png | Bin 38188 -> 9251 bytes .../products/appscode/appscode-hero.png | Bin 69358 -> 18925 bytes .../appscode/features/backup-recovery.jpg | Bin 0 -> 47906 bytes .../products/appscode/features/insight.jpg | Bin 0 -> 48637 bytes .../products/appscode/features/monitoring.jpg | Bin 0 -> 61398 bytes .../appscode/features/ui-features.png | Bin 0 -> 51665 bytes .../appscode/icons/global/check-box.png | Bin 0 -> 1022 bytes .../appscode/icons/global/check-box.svg | 18 + .../appscode/icons/global/play-icon.png | Bin 0 -> 2415 bytes .../products/kubedb/kubedb-illustration-1.png | Bin 0 -> 34236 bytes 293 files changed, 19295 insertions(+), 238 deletions(-) create mode 100644 content/docs/v2024.3.18/CHANGELOG-v2021.04.20-beta.2.md create mode 100644 content/docs/v2024.3.18/CHANGELOG-v2021.04.24-rc.0.md create mode 100644 content/docs/v2024.3.18/CHANGELOG-v2021.09.15.md create mode 100644 content/docs/v2024.3.18/CHANGELOG-v2021.10.16.md create mode 100644 content/docs/v2024.3.18/CHANGELOG-v2021.10.17.md create mode 100644 content/docs/v2024.3.18/CHANGELOG-v2021.10.18.md create mode 100644 content/docs/v2024.3.18/CHANGELOG-v2022.01.01.md create mode 100644 content/docs/v2024.3.18/CHANGELOG-v2022.01.07.md create mode 100644 content/docs/v2024.3.18/CHANGELOG-v2022.01.10.md create mode 100644 content/docs/v2024.3.18/CHANGELOG-v2022.02.22.md create mode 100644 content/docs/v2024.3.18/CHANGELOG-v2022.03.17.md create mode 100644 content/docs/v2024.3.18/CHANGELOG-v2022.04.13.md create mode 100644 content/docs/v2024.3.18/CHANGELOG-v2022.06.20.md create mode 100644 content/docs/v2024.3.18/CHANGELOG-v2022.08.17.md create mode 100644 content/docs/v2024.3.18/CHANGELOG-v2022.12.11.md create mode 100644 content/docs/v2024.3.18/CHANGELOG-v2023.02.22.md create mode 100644 content/docs/v2024.3.18/CHANGELOG-v2023.05.16.md create mode 100644 content/docs/v2024.3.18/CHANGELOG-v2023.9.18.md create mode 100644 content/docs/v2024.3.18/CHANGELOG-v2024.3.18.md create mode 100644 content/docs/v2024.3.18/CHANGELOG.md create mode 100644 content/docs/v2024.3.18/CONTRIBUTING.md create mode 100644 content/docs/v2024.3.18/README.md create mode 100644 content/docs/v2024.3.18/_index.md create mode 100644 content/docs/v2024.3.18/acknowledgement.md create mode 100644 content/docs/v2024.3.18/concepts/README.md create mode 100644 content/docs/v2024.3.18/concepts/_index.md create mode 100644 content/docs/v2024.3.18/concepts/haproxy.md create mode 100644 content/docs/v2024.3.18/concepts/ingress-types/_index.md create mode 100644 content/docs/v2024.3.18/concepts/ingress-types/hostport.md create mode 100644 content/docs/v2024.3.18/concepts/ingress-types/internal.md create mode 100644 content/docs/v2024.3.18/concepts/ingress-types/loadbalancer.md create mode 100644 content/docs/v2024.3.18/concepts/ingress-types/nodeport.md create mode 100644 content/docs/v2024.3.18/concepts/overview.md create mode 100644 content/docs/v2024.3.18/examples/cert-manager/azure/certificate.yaml create mode 100644 content/docs/v2024.3.18/examples/cert-manager/azure/ingress.yaml create mode 100644 content/docs/v2024.3.18/examples/cert-manager/azure/issuer.yaml create mode 100644 content/docs/v2024.3.18/examples/cert-manager/certificate.yaml create mode 100644 content/docs/v2024.3.18/examples/cert-manager/google_cloud/certificate.yaml create mode 100644 content/docs/v2024.3.18/examples/cert-manager/google_cloud/ingress.yaml create mode 100644 content/docs/v2024.3.18/examples/cert-manager/google_cloud/issuer.yaml create mode 100644 content/docs/v2024.3.18/examples/cert-manager/http/clusterissuer.yaml create mode 100644 content/docs/v2024.3.18/examples/cert-manager/http/ingress.yaml create mode 100644 content/docs/v2024.3.18/examples/cert-manager/issuer.yaml create mode 100644 content/docs/v2024.3.18/examples/cert-manager/multiple.yaml create mode 100644 content/docs/v2024.3.18/examples/cert-manager/route53/certificate.yaml create mode 100644 content/docs/v2024.3.18/examples/cert-manager/route53/ingress.yaml create mode 100644 content/docs/v2024.3.18/examples/cert-manager/route53/issuer.yaml create mode 100755 content/docs/v2024.3.18/examples/ingress/pod-placement/deploy-servers.sh create mode 100644 content/docs/v2024.3.18/examples/ingress/pod-placement/ingress-w-node-selector.yaml create mode 100644 content/docs/v2024.3.18/examples/ingress/pod-placement/ingress-w-pod-anti-affinity.yaml create mode 100644 content/docs/v2024.3.18/examples/ingress/pod-placement/ingress-w-toleration.yaml create mode 100755 content/docs/v2024.3.18/examples/ingress/types/hostport/deploy-servers.sh create mode 100644 content/docs/v2024.3.18/examples/ingress/types/hostport/haproxy.cfg create mode 100644 content/docs/v2024.3.18/examples/ingress/types/hostport/ing.yaml create mode 100755 content/docs/v2024.3.18/examples/ingress/types/internal/deploy-servers.sh create mode 100644 content/docs/v2024.3.18/examples/ingress/types/internal/haproxy.cfg create mode 100644 content/docs/v2024.3.18/examples/ingress/types/internal/ing.yaml create mode 100755 content/docs/v2024.3.18/examples/ingress/types/loadbalancer/deploy-servers.sh create mode 100644 content/docs/v2024.3.18/examples/ingress/types/loadbalancer/haproxy.cfg create mode 100644 content/docs/v2024.3.18/examples/ingress/types/loadbalancer/ing.yaml create mode 100755 content/docs/v2024.3.18/examples/ingress/types/nodeport/deploy-servers.sh create mode 100644 content/docs/v2024.3.18/examples/ingress/types/nodeport/haproxy.cfg create mode 100644 content/docs/v2024.3.18/examples/ingress/types/nodeport/ing.yaml create mode 100644 content/docs/v2024.3.18/examples/monitoring/builtin-prometheus/demo-1.yaml create mode 100644 content/docs/v2024.3.18/examples/monitoring/builtin-prometheus/demo-2.yaml create mode 100644 content/docs/v2024.3.18/examples/monitoring/builtin-prometheus/ing.yaml create mode 100644 content/docs/v2024.3.18/examples/monitoring/coreos-operator/demo-0.yaml create mode 100644 content/docs/v2024.3.18/examples/monitoring/coreos-operator/demo-1.yaml create mode 100644 content/docs/v2024.3.18/examples/monitoring/coreos-operator/ing.yaml create mode 100644 content/docs/v2024.3.18/examples/monitoring/metrics-collector.yaml create mode 100644 content/docs/v2024.3.18/examples/monitoring/profiler.yaml create mode 100644 content/docs/v2024.3.18/examples/monitoring/stats-ing.yaml create mode 100644 content/docs/v2024.3.18/guides/_index.md create mode 100644 content/docs/v2024.3.18/guides/cert-manager/README.md create mode 100644 content/docs/v2024.3.18/guides/cert-manager/_index.md create mode 100644 content/docs/v2024.3.18/guides/cert-manager/dns01_challenge/_index.md create mode 100644 content/docs/v2024.3.18/guides/cert-manager/dns01_challenge/aws-route53.md create mode 100644 content/docs/v2024.3.18/guides/cert-manager/dns01_challenge/azure-dns.md create mode 100644 content/docs/v2024.3.18/guides/cert-manager/dns01_challenge/google-cloud-dns.md create mode 100644 content/docs/v2024.3.18/guides/cert-manager/dns01_challenge/multiple-challenge-solver.md create mode 100644 content/docs/v2024.3.18/guides/cert-manager/get-started.md create mode 100644 content/docs/v2024.3.18/guides/cert-manager/http01_challenge/_index.md create mode 100644 content/docs/v2024.3.18/guides/cert-manager/http01_challenge/overview.md create mode 100644 content/docs/v2024.3.18/guides/ingress/README.md create mode 100644 content/docs/v2024.3.18/guides/ingress/_index.md create mode 100644 content/docs/v2024.3.18/guides/ingress/configuration/_index.md create mode 100644 content/docs/v2024.3.18/guides/ingress/configuration/accept-proxy.md create mode 100644 content/docs/v2024.3.18/guides/ingress/configuration/agent-check.md create mode 100644 content/docs/v2024.3.18/guides/ingress/configuration/annotations.md create mode 100644 content/docs/v2024.3.18/guides/ingress/configuration/backend-rule.md create mode 100644 content/docs/v2024.3.18/guides/ingress/configuration/bind-address.md create mode 100644 content/docs/v2024.3.18/guides/ingress/configuration/body-size.md create mode 100644 content/docs/v2024.3.18/guides/ingress/configuration/config-volumes.md create mode 100644 content/docs/v2024.3.18/guides/ingress/configuration/custom-templates.md create mode 100644 content/docs/v2024.3.18/guides/ingress/configuration/default-options.md create mode 100644 content/docs/v2024.3.18/guides/ingress/configuration/default-timeouts.md create mode 100644 content/docs/v2024.3.18/guides/ingress/configuration/error-files.md create mode 100644 content/docs/v2024.3.18/guides/ingress/configuration/frontend-rule.md create mode 100644 content/docs/v2024.3.18/guides/ingress/configuration/hard-stop-after.md create mode 100644 content/docs/v2024.3.18/guides/ingress/configuration/health-check.md create mode 100644 content/docs/v2024.3.18/guides/ingress/configuration/http-2.md create mode 100644 content/docs/v2024.3.18/guides/ingress/configuration/keep-source-ip.md create mode 100644 content/docs/v2024.3.18/guides/ingress/configuration/loadbalancer-ip.md create mode 100644 content/docs/v2024.3.18/guides/ingress/configuration/loadbalancing-algorithm.md create mode 100644 content/docs/v2024.3.18/guides/ingress/configuration/max-connections.md create mode 100644 content/docs/v2024.3.18/guides/ingress/configuration/node-port.md create mode 100644 content/docs/v2024.3.18/guides/ingress/configuration/pod-annotations.md create mode 100644 content/docs/v2024.3.18/guides/ingress/configuration/rate-limit.md create mode 100644 content/docs/v2024.3.18/guides/ingress/configuration/rewrite-target.md create mode 100644 content/docs/v2024.3.18/guides/ingress/configuration/service-annotations.md create mode 100644 content/docs/v2024.3.18/guides/ingress/configuration/ssl-passthrough.md create mode 100644 content/docs/v2024.3.18/guides/ingress/configuration/ssl-redirect.md create mode 100644 content/docs/v2024.3.18/guides/ingress/configuration/whitelist.md create mode 100644 content/docs/v2024.3.18/guides/ingress/debugging.md create mode 100755 content/docs/v2024.3.18/guides/ingress/dns/_index.md create mode 100644 content/docs/v2024.3.18/guides/ingress/dns/external-dns.md create mode 100644 content/docs/v2024.3.18/guides/ingress/graceful-reload.md create mode 100644 content/docs/v2024.3.18/guides/ingress/grpc.md create mode 100644 content/docs/v2024.3.18/guides/ingress/http/_index.md create mode 100644 content/docs/v2024.3.18/guides/ingress/http/blue-green-deployment.md create mode 100644 content/docs/v2024.3.18/guides/ingress/http/cors.md create mode 100644 content/docs/v2024.3.18/guides/ingress/http/custom-http-port.md create mode 100644 content/docs/v2024.3.18/guides/ingress/http/external-svc.md create mode 100644 content/docs/v2024.3.18/guides/ingress/http/hsts.md create mode 100644 content/docs/v2024.3.18/guides/ingress/http/http2.md create mode 100644 content/docs/v2024.3.18/guides/ingress/http/rewrite-rules.md create mode 100644 content/docs/v2024.3.18/guides/ingress/http/single-service.md create mode 100644 content/docs/v2024.3.18/guides/ingress/http/source-range.md create mode 100644 content/docs/v2024.3.18/guides/ingress/http/statefulset-pod.md create mode 100644 content/docs/v2024.3.18/guides/ingress/http/sticky-session.md create mode 100644 content/docs/v2024.3.18/guides/ingress/http/virtual-hosting.md create mode 100644 content/docs/v2024.3.18/guides/ingress/monitoring/_index.md create mode 100644 content/docs/v2024.3.18/guides/ingress/monitoring/haproxy-stats.md create mode 100644 content/docs/v2024.3.18/guides/ingress/monitoring/operator-profiling.md create mode 100644 content/docs/v2024.3.18/guides/ingress/monitoring/operator-stats.md create mode 100644 content/docs/v2024.3.18/guides/ingress/monitoring/using-builtin-prometheus.md create mode 100644 content/docs/v2024.3.18/guides/ingress/monitoring/using-coreos-prometheus-operator.md create mode 100644 content/docs/v2024.3.18/guides/ingress/pod-placement.md create mode 100644 content/docs/v2024.3.18/guides/ingress/scaling.md create mode 100644 content/docs/v2024.3.18/guides/ingress/security/_index.md create mode 100644 content/docs/v2024.3.18/guides/ingress/security/basic-auth.md create mode 100644 content/docs/v2024.3.18/guides/ingress/security/oauth-dashboard.md create mode 100644 content/docs/v2024.3.18/guides/ingress/security/oauth-github.md create mode 100644 content/docs/v2024.3.18/guides/ingress/security/oauth-google.md create mode 100644 content/docs/v2024.3.18/guides/ingress/security/oauth.md create mode 100644 content/docs/v2024.3.18/guides/ingress/security/restrict-namespace.md create mode 100644 content/docs/v2024.3.18/guides/ingress/security/tls-auth.md create mode 100644 content/docs/v2024.3.18/guides/ingress/ssh.md create mode 100644 content/docs/v2024.3.18/guides/ingress/tcp/_index.md create mode 100644 content/docs/v2024.3.18/guides/ingress/tcp/overview.md create mode 100644 content/docs/v2024.3.18/guides/ingress/tcp/tcp-sni.md create mode 100644 content/docs/v2024.3.18/guides/ingress/tls/_index.md create mode 100644 content/docs/v2024.3.18/guides/ingress/tls/aws-cert-manager.md create mode 100644 content/docs/v2024.3.18/guides/ingress/tls/backend-tls.md create mode 100644 content/docs/v2024.3.18/guides/ingress/tls/multiple-tls.md create mode 100644 content/docs/v2024.3.18/guides/ingress/tls/overview.md create mode 100644 content/docs/v2024.3.18/guides/ingress/websocket.md create mode 100644 content/docs/v2024.3.18/images/cert-manager/azure/a-record.png create mode 100644 content/docs/v2024.3.18/images/cert-manager/azure/client-secret.png create mode 100644 content/docs/v2024.3.18/images/cert-manager/azure/client-tenant.png create mode 100644 content/docs/v2024.3.18/images/cert-manager/azure/dns-zone-contributor.png create mode 100644 content/docs/v2024.3.18/images/cert-manager/azure/new-registration.png create mode 100644 content/docs/v2024.3.18/images/cert-manager/azure/new-registration2.png create mode 100644 content/docs/v2024.3.18/images/cert-manager/azure/subscriptions.png create mode 100644 content/docs/v2024.3.18/images/cert-manager/azure/user-access.png create mode 100644 content/docs/v2024.3.18/images/cert-manager/google_dns/svcac1.png create mode 100644 content/docs/v2024.3.18/images/cert-manager/google_dns/svcac2.png create mode 100644 content/docs/v2024.3.18/images/cert-manager/google_dns/svcac3.png create mode 100644 content/docs/v2024.3.18/images/cert-manager/route53/a-record.png create mode 100644 content/docs/v2024.3.18/images/cert-manager/route53/access-type.png create mode 100644 content/docs/v2024.3.18/images/cert-manager/route53/add-user.png create mode 100644 content/docs/v2024.3.18/images/cert-manager/route53/attach-policy.png create mode 100644 content/docs/v2024.3.18/images/cert-manager/route53/create-policy.png create mode 100644 content/docs/v2024.3.18/images/cert-manager/route53/hosted-zone-id.png create mode 100644 content/docs/v2024.3.18/images/cert-manager/route53/iam.png create mode 100644 content/docs/v2024.3.18/images/cert-manager/route53/policy-json.png create mode 100644 content/docs/v2024.3.18/images/cert-manager/route53/review-policy.png create mode 100644 content/docs/v2024.3.18/images/cert-manager/route53/review-user.png create mode 100644 content/docs/v2024.3.18/images/cert-manager/route53/route53.png create mode 100644 content/docs/v2024.3.18/images/cert-manager/route53/success-user.png create mode 100644 content/docs/v2024.3.18/images/ingress/configuration/custom-template/installer.png create mode 100644 content/docs/v2024.3.18/images/ingress/multiple-tls/aa.appscode.ninja.png create mode 100644 content/docs/v2024.3.18/images/ingress/multiple-tls/bb.appscode.ninja.png create mode 100644 content/docs/v2024.3.18/images/ingress/multiple-tls/cert-details.png create mode 100644 content/docs/v2024.3.18/images/ingress/multiple-tls/connection-secure.png create mode 100644 content/docs/v2024.3.18/images/ingress/multiple-tls/google-dns.png create mode 100644 content/docs/v2024.3.18/images/ingress/multiple-tls/https.aa.appscode.ninja.png create mode 100644 content/docs/v2024.3.18/images/ingress/multiple-tls/https.bb.appscode.ninja.png create mode 100644 content/docs/v2024.3.18/images/ingress/voyager-ingress.png create mode 100644 content/docs/v2024.3.18/images/monitoring/builtin-prometheus.png create mode 100644 content/docs/v2024.3.18/images/monitoring/coreos-operator.png create mode 100644 content/docs/v2024.3.18/images/monitoring/operator-metrics.png create mode 100644 content/docs/v2024.3.18/images/monitoring/operator-profiler.png create mode 100644 content/docs/v2024.3.18/images/monitoring/stats-view.png create mode 100644 content/docs/v2024.3.18/images/setup/community_license_form.png create mode 100644 content/docs/v2024.3.18/images/setup/enterprise_license_form.png create mode 100644 content/docs/v2024.3.18/reference/_index.md create mode 100644 content/docs/v2024.3.18/reference/cli/_index.md create mode 100644 content/docs/v2024.3.18/reference/cli/voyager.md create mode 100644 content/docs/v2024.3.18/reference/cli/voyager_check.md create mode 100644 content/docs/v2024.3.18/reference/cli/voyager_completion.md create mode 100644 content/docs/v2024.3.18/reference/cli/voyager_convert.md create mode 100644 content/docs/v2024.3.18/reference/cli/voyager_version.md create mode 100644 content/docs/v2024.3.18/reference/operator/_index.md create mode 100644 content/docs/v2024.3.18/reference/operator/voyager.md create mode 100644 content/docs/v2024.3.18/reference/operator/voyager_coordinator.md create mode 100644 content/docs/v2024.3.18/reference/operator/voyager_init.md create mode 100644 content/docs/v2024.3.18/reference/operator/voyager_operator.md create mode 100644 content/docs/v2024.3.18/reference/operator/voyager_run.md create mode 100644 content/docs/v2024.3.18/reference/operator/voyager_version.md create mode 100644 content/docs/v2024.3.18/setup/README.md create mode 100644 content/docs/v2024.3.18/setup/_index.md create mode 100644 content/docs/v2024.3.18/setup/install/_index.md create mode 100644 content/docs/v2024.3.18/setup/install/troubleshooting.md create mode 100644 content/docs/v2024.3.18/setup/install/voyager.md create mode 100644 content/docs/v2024.3.18/setup/uninstall/_index.md create mode 100644 content/docs/v2024.3.18/setup/uninstall/voyager.md create mode 100644 content/docs/v2024.3.18/setup/upgrade/index.md create mode 100644 content/docs/v2024.3.18/support.md create mode 100644 data/authors/md-ishtiaq-islam.json create mode 100644 data/authors/obaydullah.json create mode 100644 data/authors/saurov-chandra-biswas.json create mode 100644 static/assets/images/authors/md-ishtiaq-islam.jpg create mode 100644 static/assets/images/authors/obaydullah.jpg create mode 100644 static/assets/images/authors/profile-photos-28x28/md-ishtiaq-islam.jpg create mode 100644 static/assets/images/authors/profile-photos-28x28/obaydullah.jpg create mode 100644 static/assets/images/authors/profile-photos-84x84/md-ishtiaq-islam.jpg create mode 100644 static/assets/images/authors/profile-photos-84x84/obaydullah.jpg create mode 100644 static/assets/images/authors/profile-photos-84x84/saurov-chandra-biswas.jpg create mode 100644 static/assets/images/customers/2024/100-furtune.png create mode 100644 static/assets/images/customers/2024/carro.png create mode 100644 static/assets/images/customers/2024/clewmed.png create mode 100644 static/assets/images/customers/2024/dataloop.png create mode 100644 static/assets/images/customers/2024/decisio.png create mode 100644 static/assets/images/customers/2024/emerson.png create mode 100644 static/assets/images/customers/2024/fastspeed.png create mode 100644 static/assets/images/customers/2024/ge-healthcare.png create mode 100644 static/assets/images/customers/2024/greenhouse.png create mode 100644 static/assets/images/customers/2024/huma.png create mode 100644 static/assets/images/customers/2024/irembo.png create mode 100644 static/assets/images/customers/2024/nokia.png create mode 100644 static/assets/images/customers/2024/oak-ridge.png create mode 100644 static/assets/images/customers/2024/orange.png create mode 100644 static/assets/images/customers/2024/vaimo.png create mode 100644 static/assets/images/customers/2024/wiliot.png create mode 100644 static/assets/images/employees/md-ishtiaq-islam.jpg create mode 100644 static/assets/images/products/appscode/features/backup-recovery.jpg create mode 100644 static/assets/images/products/appscode/features/insight.jpg create mode 100644 static/assets/images/products/appscode/features/monitoring.jpg create mode 100644 static/assets/images/products/appscode/features/ui-features.png create mode 100644 static/assets/images/products/appscode/icons/global/check-box.png create mode 100644 static/assets/images/products/appscode/icons/global/check-box.svg create mode 100644 static/assets/images/products/appscode/icons/global/play-icon.png create mode 100644 static/assets/images/products/kubedb/kubedb-illustration-1.png diff --git a/config.dev.yaml b/config.dev.yaml index d07420967..a439d4492 100644 --- a/config.dev.yaml +++ b/config.dev.yaml @@ -28,7 +28,7 @@ params: blog_url: https://appscode.com/blog slack_url: https://slack.appscode.com github_url: https://github.com/appscode - twitter_url: https://twitter.com/AppsCodeHQ + twitter_url: https://x.com/AppsCodeHQ facebook_url: https://www.facebook.com/appscode youtube_url: https://www.youtube.com/c/AppsCodeInc contact_email: support@appscode.com diff --git a/config.yaml b/config.yaml index d4b9720d7..8e3b523a0 100644 --- a/config.yaml +++ b/config.yaml @@ -28,7 +28,7 @@ params: blog_url: https://appscode.com/blog slack_url: https://slack.appscode.com github_url: https://github.com/appscode - twitter_url: https://twitter.com/AppsCodeHQ + twitter_url: https://x.com/AppsCodeHQ facebook_url: https://www.facebook.com/appscode youtube_url: https://www.youtube.com/c/AppsCodeInc contact_email: support@appscode.com diff --git a/content/docs/v2024.3.18/CHANGELOG-v2021.04.20-beta.2.md b/content/docs/v2024.3.18/CHANGELOG-v2021.04.20-beta.2.md new file mode 100644 index 000000000..15f3c4666 --- /dev/null +++ b/content/docs/v2024.3.18/CHANGELOG-v2021.04.20-beta.2.md @@ -0,0 +1,170 @@ +--- +title: Changelog | Voyager +description: Changelog +menu: + docs_v2024.3.18: + identifier: changelog-voyager-v2021.04.20-beta.2 + name: Changelog-v2021.04.20-beta.2 + parent: welcome + weight: 20210420 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: welcome +url: /docs/v2024.3.18/welcome/changelog-v2021.04.20-beta.2/ +aliases: +- /docs/v2024.3.18/CHANGELOG-v2021.04.20-beta.2/ +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +# Voyager v2021.04.20-beta.2 (2021-04-25) + + +## [voyagermesh/installer](https://github.com/voyagermesh/installer) + +### [v2021.04.20-beta.2](https://github.com/voyagermesh/installer/releases/tag/v2021.04.20-beta.2) + +- [37b8597](https://github.com/voyagermesh/installer/commit/37b8597) Prepare for release v2021.04.20-beta.2 (#71) +- [3a33e2e](https://github.com/voyagermesh/installer/commit/3a33e2e) Update Makefile +- [9c19ed2](https://github.com/voyagermesh/installer/commit/9c19ed2) Add voyager-crds chart (#66) +- [252f14a](https://github.com/voyagermesh/installer/commit/252f14a) Add cleaner skip option for YAML installation process (#65) +- [d737d14](https://github.com/voyagermesh/installer/commit/d737d14) Remove protobuf code generator (#64) +- [6fdc1ca](https://github.com/voyagermesh/installer/commit/6fdc1ca) Update repository config (#63) +- [81c5627](https://github.com/voyagermesh/installer/commit/81c5627) Update Kubernetes v1.18.9 dependencies (#62) +- [acf9453](https://github.com/voyagermesh/installer/commit/acf9453) Update repository config (#61) +- [9de2b98](https://github.com/voyagermesh/installer/commit/9de2b98) Update Kubernetes v1.18.9 dependencies (#60) +- [d2f88f6](https://github.com/voyagermesh/installer/commit/d2f88f6) Update repository config (#59) +- [2f97c0d](https://github.com/voyagermesh/installer/commit/2f97c0d) Update repository config (#58) +- [a17dcd6](https://github.com/voyagermesh/installer/commit/a17dcd6) Update Kubernetes v1.18.9 dependencies (#57) +- [1b34287](https://github.com/voyagermesh/installer/commit/1b34287) Update Kubernetes v1.18.9 dependencies (#56) +- [ce2fa80](https://github.com/voyagermesh/installer/commit/ce2fa80) Update Kubernetes v1.18.9 dependencies (#55) +- [3b9833f](https://github.com/voyagermesh/installer/commit/3b9833f) Update Kubernetes v1.18.9 dependencies (#54) +- [05c1ae4](https://github.com/voyagermesh/installer/commit/05c1ae4) Update repository config (#53) +- [9d5c567](https://github.com/voyagermesh/installer/commit/9d5c567) Update repository config (#52) +- [68974d1](https://github.com/voyagermesh/installer/commit/68974d1) Update Kubernetes v1.18.9 dependencies (#51) +- [1834e92](https://github.com/voyagermesh/installer/commit/1834e92) Update repository config (#50) +- [88837e9](https://github.com/voyagermesh/installer/commit/88837e9) Update Kubernetes v1.18.9 dependencies (#49) +- [fd8dd22](https://github.com/voyagermesh/installer/commit/fd8dd22) Update Kubernetes v1.18.9 dependencies (#48) +- [e5acaa0](https://github.com/voyagermesh/installer/commit/e5acaa0) Update Kubernetes v1.18.9 dependencies (#47) +- [b8f929a](https://github.com/voyagermesh/installer/commit/b8f929a) Update Kubernetes v1.18.9 dependencies (#46) +- [0d18bec](https://github.com/voyagermesh/installer/commit/0d18bec) Update Kubernetes v1.18.9 dependencies (#44) +- [eba9d11](https://github.com/voyagermesh/installer/commit/eba9d11) Update Kubernetes v1.18.9 dependencies (#43) +- [3e27095](https://github.com/voyagermesh/installer/commit/3e27095) Update repository config (#42) +- [877c601](https://github.com/voyagermesh/installer/commit/877c601) Update Kubernetes v1.18.9 dependencies (#41) +- [5cd3131](https://github.com/voyagermesh/installer/commit/5cd3131) Update repository config (#40) +- [14e8b27](https://github.com/voyagermesh/installer/commit/14e8b27) Update Kubernetes v1.18.9 dependencies (#39) +- [f219188](https://github.com/voyagermesh/installer/commit/f219188) Update Kubernetes v1.18.9 dependencies (#38) +- [58f432a](https://github.com/voyagermesh/installer/commit/58f432a) Update repository config (#37) +- [41dc0fd](https://github.com/voyagermesh/installer/commit/41dc0fd) Update repository config (#36) +- [a54c114](https://github.com/voyagermesh/installer/commit/a54c114) Update Kubernetes v1.18.9 dependencies (#35) +- [d95070d](https://github.com/voyagermesh/installer/commit/d95070d) Update Kubernetes v1.18.3 dependencies (#34) +- [c5ca00c](https://github.com/voyagermesh/installer/commit/c5ca00c) Update Kubernetes v1.18.3 dependencies (#33) +- [30dfe30](https://github.com/voyagermesh/installer/commit/30dfe30) Update Kubernetes v1.18.3 dependencies (#32) +- [e89a026](https://github.com/voyagermesh/installer/commit/e89a026) Update Kubernetes v1.18.3 dependencies (#31) +- [b91a6e9](https://github.com/voyagermesh/installer/commit/b91a6e9) Update Kubernetes v1.18.3 dependencies (#30) +- [236a3b1](https://github.com/voyagermesh/installer/commit/236a3b1) Update Kubernetes v1.18.3 dependencies (#29) +- [a2d4bff](https://github.com/voyagermesh/installer/commit/a2d4bff) Update Kubernetes v1.18.3 dependencies (#28) +- [bc8cac9](https://github.com/voyagermesh/installer/commit/bc8cac9) Update Kubernetes v1.18.3 dependencies (#27) +- [8c93371](https://github.com/voyagermesh/installer/commit/8c93371) Update Kubernetes v1.18.3 dependencies (#26) +- [51a239d](https://github.com/voyagermesh/installer/commit/51a239d) Update Kubernetes v1.18.3 dependencies (#25) +- [475bd11](https://github.com/voyagermesh/installer/commit/475bd11) Update Kubernetes v1.18.3 dependencies (#24) +- [4c472a4](https://github.com/voyagermesh/installer/commit/4c472a4) Update Kubernetes v1.18.3 dependencies (#23) +- [40c34b1](https://github.com/voyagermesh/installer/commit/40c34b1) Update to Kubernetes v1.18.3 (#22) +- [2b52571](https://github.com/voyagermesh/installer/commit/2b52571) Update to Kubernetes v1.18.3 (#21) +- [2d5ff81](https://github.com/voyagermesh/installer/commit/2d5ff81) Update to Kubernetes v1.18.3 (#20) +- [1c8cd5e](https://github.com/voyagermesh/installer/commit/1c8cd5e) Make chart registry configurable (#19) +- [c75e2fd](https://github.com/voyagermesh/installer/commit/c75e2fd) Publish to testing dir for alpha/beta releases +- [0fbed72](https://github.com/voyagermesh/installer/commit/0fbed72) Update to Kubernetes v1.18.3 (#18) +- [04abb9d](https://github.com/voyagermesh/installer/commit/04abb9d) Update ci.yml +- [52f62df](https://github.com/voyagermesh/installer/commit/52f62df) Tag chart and app version as string for yq +- [3aed33c](https://github.com/voyagermesh/installer/commit/3aed33c) Update update-release-tracker.sh +- [fe16afc](https://github.com/voyagermesh/installer/commit/fe16afc) Update update-release-tracker.sh +- [9740a56](https://github.com/voyagermesh/installer/commit/9740a56) Update release.yml +- [290be5b](https://github.com/voyagermesh/installer/commit/290be5b) Add script to update release tracker on pr merge (#17) +- [0256621](https://github.com/voyagermesh/installer/commit/0256621) Update kubernetes versions in CI workflow +- [5b4e797](https://github.com/voyagermesh/installer/commit/5b4e797) Add commands to update chart (#16) +- [59872d2](https://github.com/voyagermesh/installer/commit/59872d2) Fix chart release process (#15) +- [cf8f550](https://github.com/voyagermesh/installer/commit/cf8f550) Fix release workflow script +- [70ff5a6](https://github.com/voyagermesh/installer/commit/70ff5a6) Update .kodiak.toml +- [4c429a3](https://github.com/voyagermesh/installer/commit/4c429a3) Update to Kubernetes v1.18.3 (#10) +- [25d6aac](https://github.com/voyagermesh/installer/commit/25d6aac) Update to Kubernetes v1.18.3 +- [aeebca4](https://github.com/voyagermesh/installer/commit/aeebca4) Create .kodiak.toml + + + +## [voyagermesh/voyager](https://github.com/voyagermesh/voyager) + +### [v13.0.0-beta.2](https://github.com/voyagermesh/voyager/releases/tag/v13.0.0-beta.2) + +- [31e87b8e](https://github.com/voyagermesh/voyager/commit/31e87b8e) Disable building arm64 images +- [404a6bcd](https://github.com/voyagermesh/voyager/commit/404a6bcd) Update Dockerfile +- [4ae3aa3f](https://github.com/voyagermesh/voyager/commit/4ae3aa3f) Fix build +- [ae95cdb8](https://github.com/voyagermesh/voyager/commit/ae95cdb8) Build voyager binary before building haproxy image +- [8531ae0e](https://github.com/voyagermesh/voyager/commit/8531ae0e) Fix socklog download url +- [c2f9a803](https://github.com/voyagermesh/voyager/commit/c2f9a803) Publish images to GH registry +- [c2b1a5ce](https://github.com/voyagermesh/voyager/commit/c2b1a5ce) Add license verifier (#1583) +- [94562494](https://github.com/voyagermesh/voyager/commit/94562494) Update repository config (#1584) +- [ea232e45](https://github.com/voyagermesh/voyager/commit/ea232e45) Update license header (#1582) +- [0bdded99](https://github.com/voyagermesh/voyager/commit/0bdded99) Avoid issuing cert two times at creation (#1535) +- [b356066d](https://github.com/voyagermesh/voyager/commit/b356066d) fix CheckCertificates goroutine to run an infinite loop again (#1531) +- [7bd08749](https://github.com/voyagermesh/voyager/commit/7bd08749) Avoid concurrent haproxy starts or reloads (#1547) +- [5b423374](https://github.com/voyagermesh/voyager/commit/5b423374) Update kind in CI +- [6e9cced0](https://github.com/voyagermesh/voyager/commit/6e9cced0) Update README.md +- [c7f806e6](https://github.com/voyagermesh/voyager/commit/c7f806e6) Update repository config (#1579) +- [e13dc9e7](https://github.com/voyagermesh/voyager/commit/e13dc9e7) Update repository config (#1577) +- [a4705e66](https://github.com/voyagermesh/voyager/commit/a4705e66) Update Kubernetes v1.18.9 dependencies (#1576) +- [e937812b](https://github.com/voyagermesh/voyager/commit/e937812b) Update repository config (#1574) +- [8a9f92cc](https://github.com/voyagermesh/voyager/commit/8a9f92cc) Update repository config (#1573) +- [08872d74](https://github.com/voyagermesh/voyager/commit/08872d74) Update Kubernetes v1.18.9 dependencies (#1572) +- [01ad6049](https://github.com/voyagermesh/voyager/commit/01ad6049) Update Kubernetes v1.18.9 dependencies (#1571) +- [89e39d57](https://github.com/voyagermesh/voyager/commit/89e39d57) Update repository config (#1570) +- [777e2c53](https://github.com/voyagermesh/voyager/commit/777e2c53) Update repository config (#1569) +- [6fcc2041](https://github.com/voyagermesh/voyager/commit/6fcc2041) Update Kubernetes v1.18.9 dependencies (#1568) +- [120682e7](https://github.com/voyagermesh/voyager/commit/120682e7) Update Kubernetes v1.18.9 dependencies (#1567) +- [23193a8e](https://github.com/voyagermesh/voyager/commit/23193a8e) Update Kubernetes v1.18.9 dependencies (#1566) +- [23553514](https://github.com/voyagermesh/voyager/commit/23553514) Update Kubernetes v1.18.9 dependencies (#1565) +- [924fced5](https://github.com/voyagermesh/voyager/commit/924fced5) Update Kubernetes v1.18.9 dependencies (#1564) +- [8e0dc012](https://github.com/voyagermesh/voyager/commit/8e0dc012) Update Kubernetes v1.18.9 dependencies (#1563) +- [e54d2622](https://github.com/voyagermesh/voyager/commit/e54d2622) Update repository config (#1561) +- [ba9e4aa7](https://github.com/voyagermesh/voyager/commit/ba9e4aa7) Update Kubernetes v1.18.9 dependencies (#1559) +- [285dac84](https://github.com/voyagermesh/voyager/commit/285dac84) Update Kubernetes v1.18.9 dependencies (#1558) +- [f5e66408](https://github.com/voyagermesh/voyager/commit/f5e66408) Update Kubernetes v1.18.9 dependencies (#1557) +- [a51e4aa4](https://github.com/voyagermesh/voyager/commit/a51e4aa4) Update Kubernetes v1.18.9 dependencies (#1555) +- [1afdf274](https://github.com/voyagermesh/voyager/commit/1afdf274) Update Kubernetes v1.18.9 dependencies (#1554) +- [93e691ea](https://github.com/voyagermesh/voyager/commit/93e691ea) Update Kubernetes v1.18.9 dependencies (#1552) +- [3d1c72d4](https://github.com/voyagermesh/voyager/commit/3d1c72d4) Update Kubernetes v1.18.9 dependencies (#1549) +- [d48b88ed](https://github.com/voyagermesh/voyager/commit/d48b88ed) Update repository config (#1551) +- [603868db](https://github.com/voyagermesh/voyager/commit/603868db) Update repository config (#1550) +- [869936e4](https://github.com/voyagermesh/voyager/commit/869936e4) Update repository config (#1548) +- [ac8399a7](https://github.com/voyagermesh/voyager/commit/ac8399a7) Update Kubernetes v1.18.9 dependencies (#1546) +- [3889306c](https://github.com/voyagermesh/voyager/commit/3889306c) Update Kubernetes v1.18.9 dependencies (#1544) +- [2256661e](https://github.com/voyagermesh/voyager/commit/2256661e) Update repository config (#1543) +- [ed48d8f0](https://github.com/voyagermesh/voyager/commit/ed48d8f0) Update repository config (#1542) +- [c1d898d3](https://github.com/voyagermesh/voyager/commit/c1d898d3) Update Kubernetes v1.18.9 dependencies (#1541) +- [7764aac4](https://github.com/voyagermesh/voyager/commit/7764aac4) Update Kubernetes v1.18.3 dependencies (#1540) +- [f9f1732e](https://github.com/voyagermesh/voyager/commit/f9f1732e) Update Kubernetes v1.18.3 dependencies (#1539) +- [b3f18ffd](https://github.com/voyagermesh/voyager/commit/b3f18ffd) Update Kubernetes v1.18.3 dependencies (#1536) +- [c92a0f15](https://github.com/voyagermesh/voyager/commit/c92a0f15) Update Kubernetes v1.18.3 dependencies (#1534) +- [aa701496](https://github.com/voyagermesh/voyager/commit/aa701496) Update Kubernetes v1.18.3 dependencies (#1532) +- [cacef44c](https://github.com/voyagermesh/voyager/commit/cacef44c) Update Kubernetes v1.18.3 dependencies (#1529) +- [f9248332](https://github.com/voyagermesh/voyager/commit/f9248332) Update Kubernetes v1.18.3 dependencies (#1528) +- [fd3aa94c](https://github.com/voyagermesh/voyager/commit/fd3aa94c) Update Kubernetes v1.18.3 dependencies (#1527) +- [85915ab8](https://github.com/voyagermesh/voyager/commit/85915ab8) Update Kubernetes v1.18.3 dependencies (#1524) +- [dd3cc508](https://github.com/voyagermesh/voyager/commit/dd3cc508) Update to Kubernetes v1.18.3 (#1521) +- [cbd7d3e2](https://github.com/voyagermesh/voyager/commit/cbd7d3e2) Update to Kubernetes v1.18.3 (#1520) +- [d00a4c72](https://github.com/voyagermesh/voyager/commit/d00a4c72) Update to Kubernetes v1.18.3 (#1519) +- [c6bbe8cc](https://github.com/voyagermesh/voyager/commit/c6bbe8cc) Update to Kubernetes v1.18.3 (#1518) +- [dcc94c7e](https://github.com/voyagermesh/voyager/commit/dcc94c7e) Update ci.yml +- [d9c38862](https://github.com/voyagermesh/voyager/commit/d9c38862) Update update-release-tracker.sh +- [5c74ad2b](https://github.com/voyagermesh/voyager/commit/5c74ad2b) Update update-release-tracker.sh +- [21b03bbb](https://github.com/voyagermesh/voyager/commit/21b03bbb) Add script to update release tracker on pr merge (#1516) +- [57503de5](https://github.com/voyagermesh/voyager/commit/57503de5) Update .kodiak.toml +- [dbdb1e5c](https://github.com/voyagermesh/voyager/commit/dbdb1e5c) Update to Kubernetes v1.18.3 (#1514) +- [1abc059e](https://github.com/voyagermesh/voyager/commit/1abc059e) Update to Kubernetes v1.18.3 +- [7a61045e](https://github.com/voyagermesh/voyager/commit/7a61045e) Create .kodiak.toml + + + + diff --git a/content/docs/v2024.3.18/CHANGELOG-v2021.04.24-rc.0.md b/content/docs/v2024.3.18/CHANGELOG-v2021.04.24-rc.0.md new file mode 100644 index 000000000..32a79b55e --- /dev/null +++ b/content/docs/v2024.3.18/CHANGELOG-v2021.04.24-rc.0.md @@ -0,0 +1,184 @@ +--- +title: Changelog | Voyager +description: Changelog +menu: + docs_v2024.3.18: + identifier: changelog-voyager-v2021.04.24-rc.0 + name: Changelog-v2021.04.24-rc.0 + parent: welcome + weight: 20210424 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: welcome +url: /docs/v2024.3.18/welcome/changelog-v2021.04.24-rc.0/ +aliases: +- /docs/v2024.3.18/CHANGELOG-v2021.04.24-rc.0/ +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +# Voyager v2021.04.24-rc.0 (2021-04-25) + + +## [voyagermesh/installer](https://github.com/voyagermesh/installer) + +### [v2021.04.24-rc.0](https://github.com/voyagermesh/installer/releases/tag/v2021.04.24-rc.0) + +- [7996020](https://github.com/voyagermesh/installer/commit/7996020) Prepare for release v2021.04.24-rc.0 (#72) +- [37b8597](https://github.com/voyagermesh/installer/commit/37b8597) Prepare for release v2021.04.20-beta.2 (#71) +- [3a33e2e](https://github.com/voyagermesh/installer/commit/3a33e2e) Update Makefile +- [9c19ed2](https://github.com/voyagermesh/installer/commit/9c19ed2) Add voyager-crds chart (#66) +- [252f14a](https://github.com/voyagermesh/installer/commit/252f14a) Add cleaner skip option for YAML installation process (#65) +- [d737d14](https://github.com/voyagermesh/installer/commit/d737d14) Remove protobuf code generator (#64) +- [6fdc1ca](https://github.com/voyagermesh/installer/commit/6fdc1ca) Update repository config (#63) +- [81c5627](https://github.com/voyagermesh/installer/commit/81c5627) Update Kubernetes v1.18.9 dependencies (#62) +- [acf9453](https://github.com/voyagermesh/installer/commit/acf9453) Update repository config (#61) +- [9de2b98](https://github.com/voyagermesh/installer/commit/9de2b98) Update Kubernetes v1.18.9 dependencies (#60) +- [d2f88f6](https://github.com/voyagermesh/installer/commit/d2f88f6) Update repository config (#59) +- [2f97c0d](https://github.com/voyagermesh/installer/commit/2f97c0d) Update repository config (#58) +- [a17dcd6](https://github.com/voyagermesh/installer/commit/a17dcd6) Update Kubernetes v1.18.9 dependencies (#57) +- [1b34287](https://github.com/voyagermesh/installer/commit/1b34287) Update Kubernetes v1.18.9 dependencies (#56) +- [ce2fa80](https://github.com/voyagermesh/installer/commit/ce2fa80) Update Kubernetes v1.18.9 dependencies (#55) +- [3b9833f](https://github.com/voyagermesh/installer/commit/3b9833f) Update Kubernetes v1.18.9 dependencies (#54) +- [05c1ae4](https://github.com/voyagermesh/installer/commit/05c1ae4) Update repository config (#53) +- [9d5c567](https://github.com/voyagermesh/installer/commit/9d5c567) Update repository config (#52) +- [68974d1](https://github.com/voyagermesh/installer/commit/68974d1) Update Kubernetes v1.18.9 dependencies (#51) +- [1834e92](https://github.com/voyagermesh/installer/commit/1834e92) Update repository config (#50) +- [88837e9](https://github.com/voyagermesh/installer/commit/88837e9) Update Kubernetes v1.18.9 dependencies (#49) +- [fd8dd22](https://github.com/voyagermesh/installer/commit/fd8dd22) Update Kubernetes v1.18.9 dependencies (#48) +- [e5acaa0](https://github.com/voyagermesh/installer/commit/e5acaa0) Update Kubernetes v1.18.9 dependencies (#47) +- [b8f929a](https://github.com/voyagermesh/installer/commit/b8f929a) Update Kubernetes v1.18.9 dependencies (#46) +- [0d18bec](https://github.com/voyagermesh/installer/commit/0d18bec) Update Kubernetes v1.18.9 dependencies (#44) +- [eba9d11](https://github.com/voyagermesh/installer/commit/eba9d11) Update Kubernetes v1.18.9 dependencies (#43) +- [3e27095](https://github.com/voyagermesh/installer/commit/3e27095) Update repository config (#42) +- [877c601](https://github.com/voyagermesh/installer/commit/877c601) Update Kubernetes v1.18.9 dependencies (#41) +- [5cd3131](https://github.com/voyagermesh/installer/commit/5cd3131) Update repository config (#40) +- [14e8b27](https://github.com/voyagermesh/installer/commit/14e8b27) Update Kubernetes v1.18.9 dependencies (#39) +- [f219188](https://github.com/voyagermesh/installer/commit/f219188) Update Kubernetes v1.18.9 dependencies (#38) +- [58f432a](https://github.com/voyagermesh/installer/commit/58f432a) Update repository config (#37) +- [41dc0fd](https://github.com/voyagermesh/installer/commit/41dc0fd) Update repository config (#36) +- [a54c114](https://github.com/voyagermesh/installer/commit/a54c114) Update Kubernetes v1.18.9 dependencies (#35) +- [d95070d](https://github.com/voyagermesh/installer/commit/d95070d) Update Kubernetes v1.18.3 dependencies (#34) +- [c5ca00c](https://github.com/voyagermesh/installer/commit/c5ca00c) Update Kubernetes v1.18.3 dependencies (#33) +- [30dfe30](https://github.com/voyagermesh/installer/commit/30dfe30) Update Kubernetes v1.18.3 dependencies (#32) +- [e89a026](https://github.com/voyagermesh/installer/commit/e89a026) Update Kubernetes v1.18.3 dependencies (#31) +- [b91a6e9](https://github.com/voyagermesh/installer/commit/b91a6e9) Update Kubernetes v1.18.3 dependencies (#30) +- [236a3b1](https://github.com/voyagermesh/installer/commit/236a3b1) Update Kubernetes v1.18.3 dependencies (#29) +- [a2d4bff](https://github.com/voyagermesh/installer/commit/a2d4bff) Update Kubernetes v1.18.3 dependencies (#28) +- [bc8cac9](https://github.com/voyagermesh/installer/commit/bc8cac9) Update Kubernetes v1.18.3 dependencies (#27) +- [8c93371](https://github.com/voyagermesh/installer/commit/8c93371) Update Kubernetes v1.18.3 dependencies (#26) +- [51a239d](https://github.com/voyagermesh/installer/commit/51a239d) Update Kubernetes v1.18.3 dependencies (#25) +- [475bd11](https://github.com/voyagermesh/installer/commit/475bd11) Update Kubernetes v1.18.3 dependencies (#24) +- [4c472a4](https://github.com/voyagermesh/installer/commit/4c472a4) Update Kubernetes v1.18.3 dependencies (#23) +- [40c34b1](https://github.com/voyagermesh/installer/commit/40c34b1) Update to Kubernetes v1.18.3 (#22) +- [2b52571](https://github.com/voyagermesh/installer/commit/2b52571) Update to Kubernetes v1.18.3 (#21) +- [2d5ff81](https://github.com/voyagermesh/installer/commit/2d5ff81) Update to Kubernetes v1.18.3 (#20) +- [1c8cd5e](https://github.com/voyagermesh/installer/commit/1c8cd5e) Make chart registry configurable (#19) +- [c75e2fd](https://github.com/voyagermesh/installer/commit/c75e2fd) Publish to testing dir for alpha/beta releases +- [0fbed72](https://github.com/voyagermesh/installer/commit/0fbed72) Update to Kubernetes v1.18.3 (#18) +- [04abb9d](https://github.com/voyagermesh/installer/commit/04abb9d) Update ci.yml +- [52f62df](https://github.com/voyagermesh/installer/commit/52f62df) Tag chart and app version as string for yq +- [3aed33c](https://github.com/voyagermesh/installer/commit/3aed33c) Update update-release-tracker.sh +- [fe16afc](https://github.com/voyagermesh/installer/commit/fe16afc) Update update-release-tracker.sh +- [9740a56](https://github.com/voyagermesh/installer/commit/9740a56) Update release.yml +- [290be5b](https://github.com/voyagermesh/installer/commit/290be5b) Add script to update release tracker on pr merge (#17) +- [0256621](https://github.com/voyagermesh/installer/commit/0256621) Update kubernetes versions in CI workflow +- [5b4e797](https://github.com/voyagermesh/installer/commit/5b4e797) Add commands to update chart (#16) +- [59872d2](https://github.com/voyagermesh/installer/commit/59872d2) Fix chart release process (#15) +- [cf8f550](https://github.com/voyagermesh/installer/commit/cf8f550) Fix release workflow script +- [70ff5a6](https://github.com/voyagermesh/installer/commit/70ff5a6) Update .kodiak.toml +- [4c429a3](https://github.com/voyagermesh/installer/commit/4c429a3) Update to Kubernetes v1.18.3 (#10) +- [25d6aac](https://github.com/voyagermesh/installer/commit/25d6aac) Update to Kubernetes v1.18.3 +- [aeebca4](https://github.com/voyagermesh/installer/commit/aeebca4) Create .kodiak.toml +- [7aa3256](https://github.com/voyagermesh/installer/commit/7aa3256) Prepare release v13.0.0-beta.1 (#9) +- [c46cf95](https://github.com/voyagermesh/installer/commit/c46cf95) Add permissions for networking.k8s.io (#8) +- [40e7bef](https://github.com/voyagermesh/installer/commit/40e7bef) Generate both v1beta1 and v1 CRD YAML (#7) +- [080d925](https://github.com/voyagermesh/installer/commit/080d925) Prepare release v13.0.0-beta.0 +- [3e5eb03](https://github.com/voyagermesh/installer/commit/3e5eb03) Update to Kubernetes v1.18.3 (#6) + + + +## [voyagermesh/voyager](https://github.com/voyagermesh/voyager) + +### [v13.0.0-rc.0](https://github.com/voyagermesh/voyager/releases/tag/v13.0.0-rc.0) + +- [e43f1b78](https://github.com/voyagermesh/voyager/commit/e43f1b78) Update readme +- [31e87b8e](https://github.com/voyagermesh/voyager/commit/31e87b8e) Disable building arm64 images +- [404a6bcd](https://github.com/voyagermesh/voyager/commit/404a6bcd) Update Dockerfile +- [4ae3aa3f](https://github.com/voyagermesh/voyager/commit/4ae3aa3f) Fix build +- [ae95cdb8](https://github.com/voyagermesh/voyager/commit/ae95cdb8) Build voyager binary before building haproxy image +- [8531ae0e](https://github.com/voyagermesh/voyager/commit/8531ae0e) Fix socklog download url +- [c2f9a803](https://github.com/voyagermesh/voyager/commit/c2f9a803) Publish images to GH registry +- [c2b1a5ce](https://github.com/voyagermesh/voyager/commit/c2b1a5ce) Add license verifier (#1583) +- [94562494](https://github.com/voyagermesh/voyager/commit/94562494) Update repository config (#1584) +- [ea232e45](https://github.com/voyagermesh/voyager/commit/ea232e45) Update license header (#1582) +- [0bdded99](https://github.com/voyagermesh/voyager/commit/0bdded99) Avoid issuing cert two times at creation (#1535) +- [b356066d](https://github.com/voyagermesh/voyager/commit/b356066d) fix CheckCertificates goroutine to run an infinite loop again (#1531) +- [7bd08749](https://github.com/voyagermesh/voyager/commit/7bd08749) Avoid concurrent haproxy starts or reloads (#1547) +- [5b423374](https://github.com/voyagermesh/voyager/commit/5b423374) Update kind in CI +- [6e9cced0](https://github.com/voyagermesh/voyager/commit/6e9cced0) Update README.md +- [c7f806e6](https://github.com/voyagermesh/voyager/commit/c7f806e6) Update repository config (#1579) +- [e13dc9e7](https://github.com/voyagermesh/voyager/commit/e13dc9e7) Update repository config (#1577) +- [a4705e66](https://github.com/voyagermesh/voyager/commit/a4705e66) Update Kubernetes v1.18.9 dependencies (#1576) +- [e937812b](https://github.com/voyagermesh/voyager/commit/e937812b) Update repository config (#1574) +- [8a9f92cc](https://github.com/voyagermesh/voyager/commit/8a9f92cc) Update repository config (#1573) +- [08872d74](https://github.com/voyagermesh/voyager/commit/08872d74) Update Kubernetes v1.18.9 dependencies (#1572) +- [01ad6049](https://github.com/voyagermesh/voyager/commit/01ad6049) Update Kubernetes v1.18.9 dependencies (#1571) +- [89e39d57](https://github.com/voyagermesh/voyager/commit/89e39d57) Update repository config (#1570) +- [777e2c53](https://github.com/voyagermesh/voyager/commit/777e2c53) Update repository config (#1569) +- [6fcc2041](https://github.com/voyagermesh/voyager/commit/6fcc2041) Update Kubernetes v1.18.9 dependencies (#1568) +- [120682e7](https://github.com/voyagermesh/voyager/commit/120682e7) Update Kubernetes v1.18.9 dependencies (#1567) +- [23193a8e](https://github.com/voyagermesh/voyager/commit/23193a8e) Update Kubernetes v1.18.9 dependencies (#1566) +- [23553514](https://github.com/voyagermesh/voyager/commit/23553514) Update Kubernetes v1.18.9 dependencies (#1565) +- [924fced5](https://github.com/voyagermesh/voyager/commit/924fced5) Update Kubernetes v1.18.9 dependencies (#1564) +- [8e0dc012](https://github.com/voyagermesh/voyager/commit/8e0dc012) Update Kubernetes v1.18.9 dependencies (#1563) +- [e54d2622](https://github.com/voyagermesh/voyager/commit/e54d2622) Update repository config (#1561) +- [ba9e4aa7](https://github.com/voyagermesh/voyager/commit/ba9e4aa7) Update Kubernetes v1.18.9 dependencies (#1559) +- [285dac84](https://github.com/voyagermesh/voyager/commit/285dac84) Update Kubernetes v1.18.9 dependencies (#1558) +- [f5e66408](https://github.com/voyagermesh/voyager/commit/f5e66408) Update Kubernetes v1.18.9 dependencies (#1557) +- [a51e4aa4](https://github.com/voyagermesh/voyager/commit/a51e4aa4) Update Kubernetes v1.18.9 dependencies (#1555) +- [1afdf274](https://github.com/voyagermesh/voyager/commit/1afdf274) Update Kubernetes v1.18.9 dependencies (#1554) +- [93e691ea](https://github.com/voyagermesh/voyager/commit/93e691ea) Update Kubernetes v1.18.9 dependencies (#1552) +- [3d1c72d4](https://github.com/voyagermesh/voyager/commit/3d1c72d4) Update Kubernetes v1.18.9 dependencies (#1549) +- [d48b88ed](https://github.com/voyagermesh/voyager/commit/d48b88ed) Update repository config (#1551) +- [603868db](https://github.com/voyagermesh/voyager/commit/603868db) Update repository config (#1550) +- [869936e4](https://github.com/voyagermesh/voyager/commit/869936e4) Update repository config (#1548) +- [ac8399a7](https://github.com/voyagermesh/voyager/commit/ac8399a7) Update Kubernetes v1.18.9 dependencies (#1546) +- [3889306c](https://github.com/voyagermesh/voyager/commit/3889306c) Update Kubernetes v1.18.9 dependencies (#1544) +- [2256661e](https://github.com/voyagermesh/voyager/commit/2256661e) Update repository config (#1543) +- [ed48d8f0](https://github.com/voyagermesh/voyager/commit/ed48d8f0) Update repository config (#1542) +- [c1d898d3](https://github.com/voyagermesh/voyager/commit/c1d898d3) Update Kubernetes v1.18.9 dependencies (#1541) +- [7764aac4](https://github.com/voyagermesh/voyager/commit/7764aac4) Update Kubernetes v1.18.3 dependencies (#1540) +- [f9f1732e](https://github.com/voyagermesh/voyager/commit/f9f1732e) Update Kubernetes v1.18.3 dependencies (#1539) +- [b3f18ffd](https://github.com/voyagermesh/voyager/commit/b3f18ffd) Update Kubernetes v1.18.3 dependencies (#1536) +- [c92a0f15](https://github.com/voyagermesh/voyager/commit/c92a0f15) Update Kubernetes v1.18.3 dependencies (#1534) +- [aa701496](https://github.com/voyagermesh/voyager/commit/aa701496) Update Kubernetes v1.18.3 dependencies (#1532) +- [cacef44c](https://github.com/voyagermesh/voyager/commit/cacef44c) Update Kubernetes v1.18.3 dependencies (#1529) +- [f9248332](https://github.com/voyagermesh/voyager/commit/f9248332) Update Kubernetes v1.18.3 dependencies (#1528) +- [fd3aa94c](https://github.com/voyagermesh/voyager/commit/fd3aa94c) Update Kubernetes v1.18.3 dependencies (#1527) +- [85915ab8](https://github.com/voyagermesh/voyager/commit/85915ab8) Update Kubernetes v1.18.3 dependencies (#1524) +- [dd3cc508](https://github.com/voyagermesh/voyager/commit/dd3cc508) Update to Kubernetes v1.18.3 (#1521) +- [cbd7d3e2](https://github.com/voyagermesh/voyager/commit/cbd7d3e2) Update to Kubernetes v1.18.3 (#1520) +- [d00a4c72](https://github.com/voyagermesh/voyager/commit/d00a4c72) Update to Kubernetes v1.18.3 (#1519) +- [c6bbe8cc](https://github.com/voyagermesh/voyager/commit/c6bbe8cc) Update to Kubernetes v1.18.3 (#1518) +- [dcc94c7e](https://github.com/voyagermesh/voyager/commit/dcc94c7e) Update ci.yml +- [d9c38862](https://github.com/voyagermesh/voyager/commit/d9c38862) Update update-release-tracker.sh +- [5c74ad2b](https://github.com/voyagermesh/voyager/commit/5c74ad2b) Update update-release-tracker.sh +- [21b03bbb](https://github.com/voyagermesh/voyager/commit/21b03bbb) Add script to update release tracker on pr merge (#1516) +- [57503de5](https://github.com/voyagermesh/voyager/commit/57503de5) Update .kodiak.toml +- [dbdb1e5c](https://github.com/voyagermesh/voyager/commit/dbdb1e5c) Update to Kubernetes v1.18.3 (#1514) +- [1abc059e](https://github.com/voyagermesh/voyager/commit/1abc059e) Update to Kubernetes v1.18.3 +- [7a61045e](https://github.com/voyagermesh/voyager/commit/7a61045e) Create .kodiak.toml +- [4081635b](https://github.com/voyagermesh/voyager/commit/4081635b) Prepare release v13.0.0-beta.1 (#1512) +- [9b527d39](https://github.com/voyagermesh/voyager/commit/9b527d39) Generate both v1beta1 and v1 CRD YAML (#1511) +- [bb85c779](https://github.com/voyagermesh/voyager/commit/bb85c779) Prepare release v13.0.0-beta.0 (#1510) +- [c19455cf](https://github.com/voyagermesh/voyager/commit/c19455cf) Update to Kubernetes v1.18.3 (#1509) +- [9e750a13](https://github.com/voyagermesh/voyager/commit/9e750a13) Update README.md +- [f89dc723](https://github.com/voyagermesh/voyager/commit/f89dc723) Merge pull request #1507 from smarkets/fix-readme-docs-links +- [6ed3c7eb](https://github.com/voyagermesh/voyager/commit/6ed3c7eb) Fix README.md documentation links + + + + diff --git a/content/docs/v2024.3.18/CHANGELOG-v2021.09.15.md b/content/docs/v2024.3.18/CHANGELOG-v2021.09.15.md new file mode 100644 index 000000000..465045362 --- /dev/null +++ b/content/docs/v2024.3.18/CHANGELOG-v2021.09.15.md @@ -0,0 +1,1320 @@ +--- +title: Changelog | Voyager +description: Changelog +menu: + docs_v2024.3.18: + identifier: changelog-voyager-v2021.09.15 + name: Changelog-v2021.09.15 + parent: welcome + weight: 20210915 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: welcome +url: /docs/v2024.3.18/welcome/changelog-v2021.09.15/ +aliases: +- /docs/v2024.3.18/CHANGELOG-v2021.09.15/ +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +# Voyager v2021.09.15 (2021-09-16) + + +## [voyagermesh/apimachinery](https://github.com/voyagermesh/apimachinery) + +### [v0.1.0](https://github.com/voyagermesh/apimachinery/releases/tag/v0.1.0) + +- [c844b999](https://github.com/voyagermesh/apimachinery/commit/c844b999) Rework coordinator spec +- [dcf06153](https://github.com/voyagermesh/apimachinery/commit/dcf06153) Add CoordinatorResources field +- [f7b25e1f](https://github.com/voyagermesh/apimachinery/commit/f7b25e1f) Update api version annotations +- [3997eecd](https://github.com/voyagermesh/apimachinery/commit/3997eecd) Fix conversion v1 <-> v1beta1 +- [113fdd00](https://github.com/voyagermesh/apimachinery/commit/113fdd00) fix test +- [3c1f975e](https://github.com/voyagermesh/apimachinery/commit/3c1f975e) Update repository config (#8) +- [1f77bba1](https://github.com/voyagermesh/apimachinery/commit/1f77bba1) Update repository config (#7) +- [778bf7c9](https://github.com/voyagermesh/apimachinery/commit/778bf7c9) Update repository config (#6) +- [9a90d80f](https://github.com/voyagermesh/apimachinery/commit/9a90d80f) Update repository config (#5) +- [64ecf754](https://github.com/voyagermesh/apimachinery/commit/64ecf754) Only support secrets for TLS (#4) +- [5d540cbc](https://github.com/voyagermesh/apimachinery/commit/5d540cbc) Update dependencies (#3) +- [33b32bcd](https://github.com/voyagermesh/apimachinery/commit/33b32bcd) Test crds (#2) +- [06d18c2e](https://github.com/voyagermesh/apimachinery/commit/06d18c2e) Bring back v1beta1 api (#1) +- [0ad79ce9](https://github.com/voyagermesh/apimachinery/commit/0ad79ce9) Introduce v1 api version +- [73cfae18](https://github.com/voyagermesh/apimachinery/commit/73cfae18) Use voyager namespace +- [a95ec426](https://github.com/voyagermesh/apimachinery/commit/a95ec426) Update audit lib +- [1eebfc34](https://github.com/voyagermesh/apimachinery/commit/1eebfc34) Send audit events if analytics enabled (#1588) +- [6ea37116](https://github.com/voyagermesh/apimachinery/commit/6ea37116) Publish audit events +- [a300c51e](https://github.com/voyagermesh/apimachinery/commit/a300c51e) Use klog/v2 +- [19049190](https://github.com/voyagermesh/apimachinery/commit/19049190) Bring back grpc test +- [021a811f](https://github.com/voyagermesh/apimachinery/commit/021a811f) Update Kubernetes toolchain to v1.21.0 (#1585) +- [6677d82a](https://github.com/voyagermesh/apimachinery/commit/6677d82a) Update readme +- [7be79b98](https://github.com/voyagermesh/apimachinery/commit/7be79b98) Disable building arm64 images +- [e874bff6](https://github.com/voyagermesh/apimachinery/commit/e874bff6) Fix build +- [1a0f2c56](https://github.com/voyagermesh/apimachinery/commit/1a0f2c56) Build voyager binary before building haproxy image +- [ec811d3b](https://github.com/voyagermesh/apimachinery/commit/ec811d3b) Publish images to GH registry +- [cd3d0ea5](https://github.com/voyagermesh/apimachinery/commit/cd3d0ea5) Add license verifier (#1583) +- [6f3b9e74](https://github.com/voyagermesh/apimachinery/commit/6f3b9e74) Update repository config (#1584) +- [215976bb](https://github.com/voyagermesh/apimachinery/commit/215976bb) Update license header (#1582) +- [ebb61059](https://github.com/voyagermesh/apimachinery/commit/ebb61059) Update kind in CI +- [2ffaed1a](https://github.com/voyagermesh/apimachinery/commit/2ffaed1a) Update README.md +- [b2ec514b](https://github.com/voyagermesh/apimachinery/commit/b2ec514b) Update repository config (#1579) +- [387c5239](https://github.com/voyagermesh/apimachinery/commit/387c5239) Update repository config (#1577) +- [854c7d96](https://github.com/voyagermesh/apimachinery/commit/854c7d96) Update Kubernetes v1.18.9 dependencies (#1576) +- [1d92dc76](https://github.com/voyagermesh/apimachinery/commit/1d92dc76) Update repository config (#1574) +- [ccbe91a3](https://github.com/voyagermesh/apimachinery/commit/ccbe91a3) Update Kubernetes v1.18.9 dependencies (#1572) +- [255b0bcd](https://github.com/voyagermesh/apimachinery/commit/255b0bcd) Update Kubernetes v1.18.9 dependencies (#1571) +- [8f8e1dda](https://github.com/voyagermesh/apimachinery/commit/8f8e1dda) Update repository config (#1570) +- [2ae78311](https://github.com/voyagermesh/apimachinery/commit/2ae78311) Update repository config (#1569) +- [19e0a2e0](https://github.com/voyagermesh/apimachinery/commit/19e0a2e0) Update Kubernetes v1.18.9 dependencies (#1568) +- [5391e76a](https://github.com/voyagermesh/apimachinery/commit/5391e76a) Update Kubernetes v1.18.9 dependencies (#1567) +- [fd3ad20a](https://github.com/voyagermesh/apimachinery/commit/fd3ad20a) Update Kubernetes v1.18.9 dependencies (#1566) +- [44f58333](https://github.com/voyagermesh/apimachinery/commit/44f58333) Update Kubernetes v1.18.9 dependencies (#1565) +- [cca8be02](https://github.com/voyagermesh/apimachinery/commit/cca8be02) Update Kubernetes v1.18.9 dependencies (#1564) +- [b22ca14b](https://github.com/voyagermesh/apimachinery/commit/b22ca14b) Update Kubernetes v1.18.9 dependencies (#1563) +- [e1088ef3](https://github.com/voyagermesh/apimachinery/commit/e1088ef3) Update repository config (#1561) +- [f5f59ab3](https://github.com/voyagermesh/apimachinery/commit/f5f59ab3) Update Kubernetes v1.18.9 dependencies (#1559) +- [c42207db](https://github.com/voyagermesh/apimachinery/commit/c42207db) Update Kubernetes v1.18.9 dependencies (#1558) +- [306ce6d6](https://github.com/voyagermesh/apimachinery/commit/306ce6d6) Update Kubernetes v1.18.9 dependencies (#1557) +- [5bc96bb6](https://github.com/voyagermesh/apimachinery/commit/5bc96bb6) Update Kubernetes v1.18.9 dependencies (#1555) +- [9090362c](https://github.com/voyagermesh/apimachinery/commit/9090362c) Update Kubernetes v1.18.9 dependencies (#1554) +- [3ea1cbf8](https://github.com/voyagermesh/apimachinery/commit/3ea1cbf8) Update Kubernetes v1.18.9 dependencies (#1552) +- [79094a86](https://github.com/voyagermesh/apimachinery/commit/79094a86) Update Kubernetes v1.18.9 dependencies (#1549) +- [6e9f0a46](https://github.com/voyagermesh/apimachinery/commit/6e9f0a46) Update repository config (#1550) +- [11c3976b](https://github.com/voyagermesh/apimachinery/commit/11c3976b) Update Kubernetes v1.18.9 dependencies (#1546) +- [16c838e4](https://github.com/voyagermesh/apimachinery/commit/16c838e4) Update Kubernetes v1.18.9 dependencies (#1544) +- [a96efae7](https://github.com/voyagermesh/apimachinery/commit/a96efae7) Update repository config (#1543) +- [0fdc3aec](https://github.com/voyagermesh/apimachinery/commit/0fdc3aec) Update repository config (#1542) +- [adad38e7](https://github.com/voyagermesh/apimachinery/commit/adad38e7) Update Kubernetes v1.18.9 dependencies (#1541) +- [5a40bbe3](https://github.com/voyagermesh/apimachinery/commit/5a40bbe3) Update Kubernetes v1.18.3 dependencies (#1540) +- [4c06823e](https://github.com/voyagermesh/apimachinery/commit/4c06823e) Update Kubernetes v1.18.3 dependencies (#1539) +- [03966151](https://github.com/voyagermesh/apimachinery/commit/03966151) Update Kubernetes v1.18.3 dependencies (#1536) +- [34263c96](https://github.com/voyagermesh/apimachinery/commit/34263c96) Update Kubernetes v1.18.3 dependencies (#1534) +- [978fa2e4](https://github.com/voyagermesh/apimachinery/commit/978fa2e4) Update Kubernetes v1.18.3 dependencies (#1532) +- [6a43e6c2](https://github.com/voyagermesh/apimachinery/commit/6a43e6c2) Update Kubernetes v1.18.3 dependencies (#1529) +- [3e85fce7](https://github.com/voyagermesh/apimachinery/commit/3e85fce7) Update Kubernetes v1.18.3 dependencies (#1528) +- [18d16b90](https://github.com/voyagermesh/apimachinery/commit/18d16b90) Update Kubernetes v1.18.3 dependencies (#1527) +- [bc0a8afe](https://github.com/voyagermesh/apimachinery/commit/bc0a8afe) Update Kubernetes v1.18.3 dependencies (#1524) +- [10e4f502](https://github.com/voyagermesh/apimachinery/commit/10e4f502) Update to Kubernetes v1.18.3 (#1521) +- [4d2704ac](https://github.com/voyagermesh/apimachinery/commit/4d2704ac) Update to Kubernetes v1.18.3 (#1520) +- [cb16eb57](https://github.com/voyagermesh/apimachinery/commit/cb16eb57) Update to Kubernetes v1.18.3 (#1519) +- [24cae34e](https://github.com/voyagermesh/apimachinery/commit/24cae34e) Update to Kubernetes v1.18.3 (#1518) +- [2adc321a](https://github.com/voyagermesh/apimachinery/commit/2adc321a) Update ci.yml +- [0f568527](https://github.com/voyagermesh/apimachinery/commit/0f568527) Update update-release-tracker.sh +- [e989d1c8](https://github.com/voyagermesh/apimachinery/commit/e989d1c8) Update update-release-tracker.sh +- [a4189823](https://github.com/voyagermesh/apimachinery/commit/a4189823) Add script to update release tracker on pr merge (#1516) +- [b82735cd](https://github.com/voyagermesh/apimachinery/commit/b82735cd) Update .kodiak.toml +- [2acc748e](https://github.com/voyagermesh/apimachinery/commit/2acc748e) Update to Kubernetes v1.18.3 (#1514) +- [758e165f](https://github.com/voyagermesh/apimachinery/commit/758e165f) Update to Kubernetes v1.18.3 +- [43d5f6ca](https://github.com/voyagermesh/apimachinery/commit/43d5f6ca) Create .kodiak.toml +- [edea0341](https://github.com/voyagermesh/apimachinery/commit/edea0341) Prepare release v13.0.0-beta.1 (#1512) +- [a5a1d134](https://github.com/voyagermesh/apimachinery/commit/a5a1d134) Generate both v1beta1 and v1 CRD YAML (#1511) +- [c8539097](https://github.com/voyagermesh/apimachinery/commit/c8539097) Prepare release v13.0.0-beta.0 (#1510) +- [97f29eb4](https://github.com/voyagermesh/apimachinery/commit/97f29eb4) Update to Kubernetes v1.18.3 (#1509) +- [85934b04](https://github.com/voyagermesh/apimachinery/commit/85934b04) Update README.md +- [d62cf07d](https://github.com/voyagermesh/apimachinery/commit/d62cf07d) Merge pull request #1507 from smarkets/fix-readme-docs-links +- [00fe910e](https://github.com/voyagermesh/apimachinery/commit/00fe910e) Fix README.md documentation links +- [c8072132](https://github.com/voyagermesh/apimachinery/commit/c8072132) Prepare release v12.0.0 +- [e86772f1](https://github.com/voyagermesh/apimachinery/commit/e86772f1) Merge pull request #1503 from smarkets/master +- [d7554dd2](https://github.com/voyagermesh/apimachinery/commit/d7554dd2) Fix Update***Status helpers (#1505) +- [1de2c1fa](https://github.com/voyagermesh/apimachinery/commit/1de2c1fa) Update crazy-max/ghaction-docker-buildx flag +- [b23e3ecb](https://github.com/voyagermesh/apimachinery/commit/b23e3ecb) Use recommended kubernetes app labels (#1504) +- [6420effc](https://github.com/voyagermesh/apimachinery/commit/6420effc) Trigger the workflow on push or pull request +- [2ad37b9a](https://github.com/voyagermesh/apimachinery/commit/2ad37b9a) Change go module to voyagermesh.dev/voyager (#1500) +- [37480b2b](https://github.com/voyagermesh/apimachinery/commit/37480b2b) Update repository location (#1499) +- [dc8138c6](https://github.com/voyagermesh/apimachinery/commit/dc8138c6) Pass image pull secrets to helm chart +- [6c80753e](https://github.com/voyagermesh/apimachinery/commit/6c80753e) Show v12.0.0-rc.2 on README.md +- [d951acf5](https://github.com/voyagermesh/apimachinery/commit/d951acf5) Fix Helm chart publishing step in release workflow +- [a4547741](https://github.com/voyagermesh/apimachinery/commit/a4547741) Checkout repo in Helm job of release workflow +- [94371ee7](https://github.com/voyagermesh/apimachinery/commit/94371ee7) Fix HAProxy alpine image tag +- [2677e606](https://github.com/voyagermesh/apimachinery/commit/2677e606) Fix socklog arch in HAProxy 1.9.15 +- [a76b3d50](https://github.com/voyagermesh/apimachinery/commit/a76b3d50) Build HAProxy images from Makefile (#1498) +- [083615cd](https://github.com/voyagermesh/apimachinery/commit/083615cd) Build chart in release workflow +- [5cfb4cd3](https://github.com/voyagermesh/apimachinery/commit/5cfb4cd3) Install builddeps in release workflow +- [406c119e](https://github.com/voyagermesh/apimachinery/commit/406c119e) Use BASH_SOURCE to calculate $REPO_ROOT (#1497) +- [07afbc63](https://github.com/voyagermesh/apimachinery/commit/07afbc63) Rerun make gen fmt +- [5ad0a377](https://github.com/voyagermesh/apimachinery/commit/5ad0a377) Update CHANGELOG.md (#1496) +- [6dd778c5](https://github.com/voyagermesh/apimachinery/commit/6dd778c5) Security: Upgrade to HAProxy 1.19.15 (#1495) +- [ee1096dd](https://github.com/voyagermesh/apimachinery/commit/ee1096dd) Add rbac permissions for statefulset (#1494) +- [f350bbd1](https://github.com/voyagermesh/apimachinery/commit/f350bbd1) workload-kind support StatefulSet (#1482) +- [6576893f](https://github.com/voyagermesh/apimachinery/commit/6576893f) Apply various fixes to chart (#1493) +- [13426bbc](https://github.com/voyagermesh/apimachinery/commit/13426bbc) Merge pull request #1486 from jayjun/renewal +- [502109ab](https://github.com/voyagermesh/apimachinery/commit/502109ab) Merge pull request #1491 from smarkets/haproxy-exporter-image-repository +- [f11db3b3](https://github.com/voyagermesh/apimachinery/commit/f11db3b3) Add restrict-to-operator-namespace flag (#1481) +- [5de9075e](https://github.com/voyagermesh/apimachinery/commit/5de9075e) Add missing ingresses/status resource to operator ClusterRole (#1488) +- [880abc78](https://github.com/voyagermesh/apimachinery/commit/880abc78) Bump cloud.google.com/go to get timeout fix (#1487) +- [849febd5](https://github.com/voyagermesh/apimachinery/commit/849febd5) charts: Pass through haproxy and export image repository options +- [306ec67b](https://github.com/voyagermesh/apimachinery/commit/306ec67b) docs: Add documentation for haproxy and exporter repository arguments +- [9c80ca03](https://github.com/voyagermesh/apimachinery/commit/9c80ca03) Allow specifying rather than generating certs (#1479) +- [1184c68b](https://github.com/voyagermesh/apimachinery/commit/1184c68b) Refactor CI pipeline to build once. (#1476) +- [b6f5c93f](https://github.com/voyagermesh/apimachinery/commit/b6f5c93f) Bring back support for k8s 1.11 (#1475) +- [18a8b37f](https://github.com/voyagermesh/apimachinery/commit/18a8b37f) Use node[0]'s internal ip as minikube ip (#1474) +- [130ac325](https://github.com/voyagermesh/apimachinery/commit/130ac325) Prepare v12.0.0-rc.1 (#1473) +- [70b92854](https://github.com/voyagermesh/apimachinery/commit/70b92854) Pass --version flag to helm search repo command +- [517c6dcb](https://github.com/voyagermesh/apimachinery/commit/517c6dcb) Fix css class for helm 3 tab (#1470) +- [2f31439e](https://github.com/voyagermesh/apimachinery/commit/2f31439e) Prepare release v12.0.0-rc.0 (#1469) +- [580a3aad](https://github.com/voyagermesh/apimachinery/commit/580a3aad) Update installation instructions (#1467) +- [fc45a16a](https://github.com/voyagermesh/apimachinery/commit/fc45a16a) Run e2e tests in minikube (#1466) +- [8dfa49ca](https://github.com/voyagermesh/apimachinery/commit/8dfa49ca) Various fixes to chart (#1465) +- [12189523](https://github.com/voyagermesh/apimachinery/commit/12189523) Delete script based installer (#1464) +- [70bdbc9a](https://github.com/voyagermesh/apimachinery/commit/70bdbc9a) Revendor (#1463) +- [0b9469f3](https://github.com/voyagermesh/apimachinery/commit/0b9469f3) Fix typo for APISchemaIngress (#1461) +- [b7a16f8c](https://github.com/voyagermesh/apimachinery/commit/b7a16f8c) Use OwnerReference helpers from kmodules (#1460) +- [d3b76aa8](https://github.com/voyagermesh/apimachinery/commit/d3b76aa8) Fix helm v3.0.0 chart error on install (#1459) +- [479b9608](https://github.com/voyagermesh/apimachinery/commit/479b9608) Run fuzz tests for and set `preserveUnknownFields: false (#1458) +- [5272a522](https://github.com/voyagermesh/apimachinery/commit/5272a522) Properly handle empty image pull secret name in installer (#1457) +- [fd002b8f](https://github.com/voyagermesh/apimachinery/commit/fd002b8f) Fix broken links and chart validation (#1456) +- [00f33c66](https://github.com/voyagermesh/apimachinery/commit/00f33c66) Update client-go to kubernetes-1.16.3 (#1455) +- [97370527](https://github.com/voyagermesh/apimachinery/commit/97370527) Fix Linter Issues (#1448) +- [8e4a5907](https://github.com/voyagermesh/apimachinery/commit/8e4a5907) Use controller-tools@v0.2.2 to generate structural schema (#1450) +- [01e70986](https://github.com/voyagermesh/apimachinery/commit/01e70986) Various Makefile improvements (#1447) +- [2d6f6dfb](https://github.com/voyagermesh/apimachinery/commit/2d6f6dfb) Typo fix (#1445) +- [8b8212ed](https://github.com/voyagermesh/apimachinery/commit/8b8212ed) Use kubebuilder to generate crd manifests (#1442) +- [a6c4fe9c](https://github.com/voyagermesh/apimachinery/commit/a6c4fe9c) Fix helm chart install v11.0.1 (#1441) +- [a38f4212](https://github.com/voyagermesh/apimachinery/commit/a38f4212) Push docker image to GitHub registry +- [f5bb9864](https://github.com/voyagermesh/apimachinery/commit/f5bb9864) Update readme to show v11.0.1 +- [6e39a5df](https://github.com/voyagermesh/apimachinery/commit/6e39a5df) Fix frontmatter +- [8074e2d8](https://github.com/voyagermesh/apimachinery/commit/8074e2d8) Update changelog +- [88e81815](https://github.com/voyagermesh/apimachinery/commit/88e81815) Prepare v11.0.1 release +- [9ac046a0](https://github.com/voyagermesh/apimachinery/commit/9ac046a0) Fix broken helm chart: unexpected end definition in cluster-rol… (#1436) +- [f3ed6bc5](https://github.com/voyagermesh/apimachinery/commit/f3ed6bc5) Download onessl version v0.13.1 for Kubernetes 1.16 fix (#1437) +- [0f125f3b](https://github.com/voyagermesh/apimachinery/commit/0f125f3b) Enable GitHub actions +- [db9c905f](https://github.com/voyagermesh/apimachinery/commit/db9c905f) Templatize front matter (#1434) +- [1053495d](https://github.com/voyagermesh/apimachinery/commit/1053495d) Update changelog +- [02fee171](https://github.com/voyagermesh/apimachinery/commit/02fee171) Fix Dockerfile path +- [aa90d758](https://github.com/voyagermesh/apimachinery/commit/aa90d758) Fix frontmatter menu +- [ea7d3300](https://github.com/voyagermesh/apimachinery/commit/ea7d3300) Fix front matter +- [e04eff0e](https://github.com/voyagermesh/apimachinery/commit/e04eff0e) Run as fsGroup: 65535 +- [70d30963](https://github.com/voyagermesh/apimachinery/commit/70d30963) How to change scopes on a running kubernetes cluster. (#1428) +- [d888d6c5](https://github.com/voyagermesh/apimachinery/commit/d888d6c5) Add --ingress-class to hack/deploy/voyager.sh (#1430) +- [c6091400](https://github.com/voyagermesh/apimachinery/commit/c6091400) Use docker buildx +- [a24f7add](https://github.com/voyagermesh/apimachinery/commit/a24f7add) Prepare docs for v11.0.0 release (#1432) +- [f8c6b23f](https://github.com/voyagermesh/apimachinery/commit/f8c6b23f) Downgrade prometheus-operator dependency +- [5025c7ba](https://github.com/voyagermesh/apimachinery/commit/5025c7ba) Update dependencies (#1431) +- [d2653fec](https://github.com/voyagermesh/apimachinery/commit/d2653fec) Remove survey link +- [a3890408](https://github.com/voyagermesh/apimachinery/commit/a3890408) Use github.com/golang/protobuf@v1.2.0 +- [f62ad126](https://github.com/voyagermesh/apimachinery/commit/f62ad126) Add cert-manager docs (#1417) +- [33411980](https://github.com/voyagermesh/apimachinery/commit/33411980) Avoid 503 Error Doc (#1407) +- [9459ff10](https://github.com/voyagermesh/apimachinery/commit/9459ff10) Use github.com/akamai/AkamaiOPEN-edgegrid-golang@v0.8.0 (#1421) +- [5258eb78](https://github.com/voyagermesh/apimachinery/commit/5258eb78) Update .travis.yml +- [9fde8f29](https://github.com/voyagermesh/apimachinery/commit/9fde8f29) Add license header for Makefile (#1420) +- [36be6f50](https://github.com/voyagermesh/apimachinery/commit/36be6f50) Update azure-sdk-for-go to v31.1.0 (#1419) +- [6ef79b2f](https://github.com/voyagermesh/apimachinery/commit/6ef79b2f) Add hard-stop-after (#1405) +- [d1777218](https://github.com/voyagermesh/apimachinery/commit/d1777218) Change timeout connect to 5s (#1406) +- [1b9a9f04](https://github.com/voyagermesh/apimachinery/commit/1b9a9f04) Remove --rbac flag (#1397) +- [e61316ef](https://github.com/voyagermesh/apimachinery/commit/e61316ef) Allow Backend Weight to be 0 (#1396) +- [b6167d6d](https://github.com/voyagermesh/apimachinery/commit/b6167d6d) Add HAProxy Agent Check (#1395) +- [4739aa5a](https://github.com/voyagermesh/apimachinery/commit/4739aa5a) Update .yaml apps/v1 and Update Vendor to Fix DaemonSet Issue (#1410) +- [48a96ee4](https://github.com/voyagermesh/apimachinery/commit/48a96ee4) Allow replica change when no hpa (#1409) +- [633e7cbb](https://github.com/voyagermesh/apimachinery/commit/633e7cbb) Fix Docs and Example Files (#1408) +- [41be94ca](https://github.com/voyagermesh/apimachinery/commit/41be94ca) Docs: notice about tls secret special characters (#1416) +- [18263847](https://github.com/voyagermesh/apimachinery/commit/18263847) Add missing +- [f56b5563](https://github.com/voyagermesh/apimachinery/commit/f56b5563) Update to k8s client libraries to 1.14.0 (#1392) +- [21931c0c](https://github.com/voyagermesh/apimachinery/commit/21931c0c) Add Makefile (#1398) +- [03f2cc78](https://github.com/voyagermesh/apimachinery/commit/03f2cc78) Add GO cache directories +- [ad7c3b9a](https://github.com/voyagermesh/apimachinery/commit/ad7c3b9a) Use absolute path as aliases for reference docs (#1394) +- [bea3b4e3](https://github.com/voyagermesh/apimachinery/commit/bea3b4e3) Use GO Modules (#1391) +- [945e6209](https://github.com/voyagermesh/apimachinery/commit/945e6209) Revendor dependencies in preparation for go module support (#1390) +- [e172fd1c](https://github.com/voyagermesh/apimachinery/commit/e172fd1c) remove single quotes from servicePort (#1365) +- [6aeab0e7](https://github.com/voyagermesh/apimachinery/commit/6aeab0e7) Fix Typo (#1384) +- [9c0285b3](https://github.com/voyagermesh/apimachinery/commit/9c0285b3) Update README.md +- [153fc2da](https://github.com/voyagermesh/apimachinery/commit/153fc2da) Prepare docs for 10.0.0 release (#1383) +- [f8680f8a](https://github.com/voyagermesh/apimachinery/commit/f8680f8a) Update Kubernetes client libraries to 1.13.5 (#1379) +- [faec4e9f](https://github.com/voyagermesh/apimachinery/commit/faec4e9f) Update README.md +- [8806c979](https://github.com/voyagermesh/apimachinery/commit/8806c979) Get id-token from Authorization header (#1376) +- [c3b7789c](https://github.com/voyagermesh/apimachinery/commit/c3b7789c) Update haproxy version to 1.9.6 (#1374) +- [937cdf8a](https://github.com/voyagermesh/apimachinery/commit/937cdf8a) Update haproxy version to 1.9.4 (#1368) +- [1a1ba749](https://github.com/voyagermesh/apimachinery/commit/1a1ba749) Clarify how HAProxy presents certificates to clients (#1358) +- [0248eca2](https://github.com/voyagermesh/apimachinery/commit/0248eca2) Update Kubernetes client libraries to 1.13.0 (#1359) +- [4761686a](https://github.com/voyagermesh/apimachinery/commit/4761686a) Update README.md +- [430dd7e6](https://github.com/voyagermesh/apimachinery/commit/430dd7e6) Update LE certificate renewal buffer info (#1355) +- [db6a42e4](https://github.com/voyagermesh/apimachinery/commit/db6a42e4) Release 9.0.0 (#1354) +- [7e972312](https://github.com/voyagermesh/apimachinery/commit/7e972312) Fix hugo frontmatter for HTTP/2 doc (#1353) +- [9890a298](https://github.com/voyagermesh/apimachinery/commit/9890a298) Fix e2e test for empty backend (#1352) +- [e87174e1](https://github.com/voyagermesh/apimachinery/commit/e87174e1) Update changelog for 9.0.0 (#1350) +- [4e9c274e](https://github.com/voyagermesh/apimachinery/commit/4e9c274e) Prepare docs for 9.0.0 release (#1349) +- [8037e7dd](https://github.com/voyagermesh/apimachinery/commit/8037e7dd) Add guides for configuring multiple TLS (#1342) +- [4d86d3cc](https://github.com/voyagermesh/apimachinery/commit/4d86d3cc) Add option for configuring load balancing algorithm in backends (#1340) +- [ca02efc7](https://github.com/voyagermesh/apimachinery/commit/ca02efc7) Pass Annotations to Operator PodTemplate (#1347) +- [40a9d146](https://github.com/voyagermesh/apimachinery/commit/40a9d146) Don't use priority class when operator namespace is not kube-system (#1346) +- [4570c43e](https://github.com/voyagermesh/apimachinery/commit/4570c43e) Use onessl 0.10.0 (#1345) +- [8e49f415](https://github.com/voyagermesh/apimachinery/commit/8e49f415) Fix the case for deploying using MINGW64 for windows (#1344) +- [5ab8f3c7](https://github.com/voyagermesh/apimachinery/commit/5ab8f3c7) Update sticky-session.md (#1341) +- [6bdd46ff](https://github.com/voyagermesh/apimachinery/commit/6bdd46ff) Add test for gRPC stream (#1339) +- [0bb76144](https://github.com/voyagermesh/apimachinery/commit/0bb76144) Add support for Gandi V5 acme dns provider (#1338) +- [9e41b5f7](https://github.com/voyagermesh/apimachinery/commit/9e41b5f7) Add support for gRPC (#1328) +- [2fc167f3](https://github.com/voyagermesh/apimachinery/commit/2fc167f3) readme: single-service update (#1323) +- [e75f6622](https://github.com/voyagermesh/apimachinery/commit/e75f6622) single-service: should be 'test-service' instead of 'test-server' (#1322) +- [ca3fe1af](https://github.com/voyagermesh/apimachinery/commit/ca3fe1af) readme: overview: certificates.voyager.appscode.com (#1324) +- [c3c58101](https://github.com/voyagermesh/apimachinery/commit/c3c58101) Support mounting any configmap/secret into HAProxy pod (#1330) +- [a92f6a1e](https://github.com/voyagermesh/apimachinery/commit/a92f6a1e) readme: minor typo fix (#1321) +- [6f457d57](https://github.com/voyagermesh/apimachinery/commit/6f457d57) Update haproxy version to 1.9.2 (#1312) +- [86707118](https://github.com/voyagermesh/apimachinery/commit/86707118) Update TCP docs (#1336) +- [307bed12](https://github.com/voyagermesh/apimachinery/commit/307bed12) Add option for configuring certificate renewal (#1316) +- [ecb3730e](https://github.com/voyagermesh/apimachinery/commit/ecb3730e) Add support for named service port (#1310) +- [09cc6765](https://github.com/voyagermesh/apimachinery/commit/09cc6765) Fix ClusterProvider name for concourse tests (#1313) +- [bed9023f](https://github.com/voyagermesh/apimachinery/commit/bed9023f) Add certificate health checker (#1309) +- [c71cf697](https://github.com/voyagermesh/apimachinery/commit/c71cf697) Update xenwolf/lego to 2018-12 (#1305) +- [f9882e85](https://github.com/voyagermesh/apimachinery/commit/f9882e85) Update webhook error message format for Kubernetes 1.13+ (#1306) +- [6e368076](https://github.com/voyagermesh/apimachinery/commit/6e368076) Update appscode/oauth2_proxy image version (#1301) +- [5842ee64](https://github.com/voyagermesh/apimachinery/commit/5842ee64) Set periodic analytics (#1298) +- [8105630b](https://github.com/voyagermesh/apimachinery/commit/8105630b) Fixed typo (#1295) +- [ec6d6b06](https://github.com/voyagermesh/apimachinery/commit/ec6d6b06) Update Kubernetes client libraries to 1.12.0 (#1292) +- [aae1145d](https://github.com/voyagermesh/apimachinery/commit/aae1145d) Update xray to handle any webhook denied request (#1282) +- [1c025f5b](https://github.com/voyagermesh/apimachinery/commit/1c025f5b) Expose flags to chart (#1281) +- [19952dc3](https://github.com/voyagermesh/apimachinery/commit/19952dc3) Pass image pull secrets for cleaner job in chart (#1280) +- [3b12338e](https://github.com/voyagermesh/apimachinery/commit/3b12338e) Update kubernetes client libraries to 1.12.0 (#1279) +- [236a684f](https://github.com/voyagermesh/apimachinery/commit/236a684f) Show provider list for helm installer +- [27c164af](https://github.com/voyagermesh/apimachinery/commit/27c164af) Update changelog +- [66514c84](https://github.com/voyagermesh/apimachinery/commit/66514c84) Fix xray attempt counter +- [e42017da](https://github.com/voyagermesh/apimachinery/commit/e42017da) Expose flags to installer script (#1278) +- [49ec9038](https://github.com/voyagermesh/apimachinery/commit/49ec9038) Fix webhook xray checker (#1277) +- [16fbfc6a](https://github.com/voyagermesh/apimachinery/commit/16fbfc6a) Handle ErrCallingWebhook in xray (#1276) +- [457d8930](https://github.com/voyagermesh/apimachinery/commit/457d8930) Prepare docs for 8.0.1 release (#1275) +- [2a5ff790](https://github.com/voyagermesh/apimachinery/commit/2a5ff790) Update error message for webhook xray in installer script +- [57ecdce5](https://github.com/voyagermesh/apimachinery/commit/57ecdce5) Fix upgrade flow for installer script (#1273) +- [5a5f9925](https://github.com/voyagermesh/apimachinery/commit/5a5f9925) Update README.md +- [60359076](https://github.com/voyagermesh/apimachinery/commit/60359076) Fix Ingress column header (#1272) +- [7d3be9e6](https://github.com/voyagermesh/apimachinery/commit/7d3be9e6) Fix chart (#1271) +- [aec30bad](https://github.com/voyagermesh/apimachinery/commit/aec30bad) Prepare docs for 8.0.0 release (#1269) +- [ab4145d8](https://github.com/voyagermesh/apimachinery/commit/ab4145d8) Set SideEffects to None for webhooks (#1270) +- [b17d76ea](https://github.com/voyagermesh/apimachinery/commit/b17d76ea) Detect failure quickly. (#1268) +- [1074eb18](https://github.com/voyagermesh/apimachinery/commit/1074eb18) Check webhooks are activated in installer script (#1266) +- [07d9b36b](https://github.com/voyagermesh/apimachinery/commit/07d9b36b) Support readinessProbe and livenessProbe (#1263) +- [781756c5](https://github.com/voyagermesh/apimachinery/commit/781756c5) Write webhook xray event to operator workload (#1265) +- [45c3f24f](https://github.com/voyagermesh/apimachinery/commit/45c3f24f) Add validation webhook xray (#1261) +- [5cfb0f94](https://github.com/voyagermesh/apimachinery/commit/5cfb0f94) Update error-files.md (#1260) +- [036c791f](https://github.com/voyagermesh/apimachinery/commit/036c791f) Update FixAKS helper (#1259) +- [d149e6c0](https://github.com/voyagermesh/apimachinery/commit/d149e6c0) Use FQDN for kube-apiserver in AKS (#1258) +- [ffce360d](https://github.com/voyagermesh/apimachinery/commit/ffce360d) Rename webhook apiserver ca CN (#1257) +- [81e85c1d](https://github.com/voyagermesh/apimachinery/commit/81e85c1d) Check if Kubernetes version is supported before running operator (#1256) +- [95cc4098](https://github.com/voyagermesh/apimachinery/commit/95cc4098) Format user roles (#1255) +- [c8d8431c](https://github.com/voyagermesh/apimachinery/commit/c8d8431c) Enable webhooks by default in chart (#1254) +- [7aaad11f](https://github.com/voyagermesh/apimachinery/commit/7aaad11f) Update README.md +- [92cc3169](https://github.com/voyagermesh/apimachinery/commit/92cc3169) Update values.yaml +- [fbffb9cf](https://github.com/voyagermesh/apimachinery/commit/fbffb9cf) Support configuring cleaner image via values in chart (#1253) +- [d1b00ca6](https://github.com/voyagermesh/apimachinery/commit/d1b00ca6) add support for custom templates from config map to chart (#1246) +- [a94d5a8f](https://github.com/voyagermesh/apimachinery/commit/a94d5a8f) Remove support for Go 1.9 compiler +- [ab5da7d9](https://github.com/voyagermesh/apimachinery/commit/ab5da7d9) Merge commit 'ad6658c7954fdb859b71234edee0ac7d182ae042' +- [90c535cf](https://github.com/voyagermesh/apimachinery/commit/90c535cf) Use forked k8s.io/client-go v1.11.3 (#1243) +- [0992575c](https://github.com/voyagermesh/apimachinery/commit/0992575c) Update k8s.io/apiserver (#1241) +- [0ac0d665](https://github.com/voyagermesh/apimachinery/commit/0ac0d665) Merge commit 'c6b7add0b726df04be1b2e6f672b48f69bca42d8' +- [62b1ecbb](https://github.com/voyagermesh/apimachinery/commit/62b1ecbb) Merge commit '3c2ed9a2025e7d1eb26082f64c3c49683df01846' +- [d2b42cc1](https://github.com/voyagermesh/apimachinery/commit/d2b42cc1) Use kubernetes-1.11.3 (#1240) +- [a4a80e0c](https://github.com/voyagermesh/apimachinery/commit/a4a80e0c) Update CertStore (#1239) +- [2b997095](https://github.com/voyagermesh/apimachinery/commit/2b997095) Support pod annotations in chart (#1236) +- [39e66108](https://github.com/voyagermesh/apimachinery/commit/39e66108) Set serviceAccount for cleaner job (#1235) +- [5ce5adf4](https://github.com/voyagermesh/apimachinery/commit/5ce5adf4) Cleanup webhooks when chart is deleted (#1233) +- [0de886e1](https://github.com/voyagermesh/apimachinery/commit/0de886e1) Use IntHash as status.observedGeneration (#1231) +- [bf939eb8](https://github.com/voyagermesh/apimachinery/commit/bf939eb8) Update pipeline (#1230) +- [328d8888](https://github.com/voyagermesh/apimachinery/commit/328d8888) Merge commit 'e120f1f0a84476916440cd6d3618e5e0b125dcfd' +- [5aadbdb3](https://github.com/voyagermesh/apimachinery/commit/5aadbdb3) Add observedGenerationHash field (#1228) +- [34e4528c](https://github.com/voyagermesh/apimachinery/commit/34e4528c) Merge commit '9a5765f9a432ce84af0aca911316c0bd1699976e' +- [042c2fd8](https://github.com/voyagermesh/apimachinery/commit/042c2fd8) Fix uninstall for concourse (#1227) +- [2a013a70](https://github.com/voyagermesh/apimachinery/commit/2a013a70) Use priorityClass `system-cluster-critical` for operator pods. (#1223) +- [a60f4636](https://github.com/voyagermesh/apimachinery/commit/a60f4636) Revendor prometheus-operator (#1222) +- [59753762](https://github.com/voyagermesh/apimachinery/commit/59753762) Use apps/v1 apiGroup (#1221) +- [a121f350](https://github.com/voyagermesh/apimachinery/commit/a121f350) Merge commit 'b47d10c19f5225f9bc0f6c59afa7e1431bee1dcb' +- [c35e0380](https://github.com/voyagermesh/apimachinery/commit/c35e0380) Use concourse scripts from libbuild (#1219) +- [d9d03142](https://github.com/voyagermesh/apimachinery/commit/d9d03142) Merge commit '063baab00c216f575d04b47425198206f7feb2f0' +- [ffcddbca](https://github.com/voyagermesh/apimachinery/commit/ffcddbca) Merge commit 'a6dde7470230ff685bdce6ab3a99a7b18eb1a92f' +- [c57e7a6b](https://github.com/voyagermesh/apimachinery/commit/c57e7a6b) Add AlreadyObserved helpers (#1218) +- [b6576c53](https://github.com/voyagermesh/apimachinery/commit/b6576c53) Add categories (#1217) +- [acea9da9](https://github.com/voyagermesh/apimachinery/commit/acea9da9) Fix UpdateStatus helpers (#1216) +- [a20798b6](https://github.com/voyagermesh/apimachinery/commit/a20798b6) Merge commit '7b3ebe903887fb97f6c6f9ef67303eae072db583' +- [0ea61cfc](https://github.com/voyagermesh/apimachinery/commit/0ea61cfc) Upgrade xenwolf/lego library (#1214) +- [9d254eac](https://github.com/voyagermesh/apimachinery/commit/9d254eac) Support pod priority (#1213) +- [e0af0a2d](https://github.com/voyagermesh/apimachinery/commit/e0af0a2d) Enable status sub resource for crd yamls (#1212) +- [07767c73](https://github.com/voyagermesh/apimachinery/commit/07767c73) Move crds to api folder (#1209) +- [38f381a8](https://github.com/voyagermesh/apimachinery/commit/38f381a8) Retry UpdateStatus calls (#1208) +- [f73adbc1](https://github.com/voyagermesh/apimachinery/commit/f73adbc1) Revendor monitoring-agent-api (#1207) +- [83be45f3](https://github.com/voyagermesh/apimachinery/commit/83be45f3) Use kmodules.xyz/monitoring-agent-api (#1206) +- [a9c916d3](https://github.com/voyagermesh/apimachinery/commit/a9c916d3) Document limited NLB support (#1205) +- [93bacb0a](https://github.com/voyagermesh/apimachinery/commit/93bacb0a) Merge commit 'b73ca4d8b1038c8753aecd6469dc3128f2986446' +- [57ac071e](https://github.com/voyagermesh/apimachinery/commit/57ac071e) Update GKE cluster role (#1204) +- [3ac9e3ec](https://github.com/voyagermesh/apimachinery/commit/3ac9e3ec) Add throughput graph (#1201) +- [5cd98d15](https://github.com/voyagermesh/apimachinery/commit/5cd98d15) Correctly handle ignored openapi prefixes (#1198) +- [d12bc114](https://github.com/voyagermesh/apimachinery/commit/d12bc114) Repare docs for 7.4.0 release (#1192) +- [86c2c840](https://github.com/voyagermesh/apimachinery/commit/86c2c840) Use version and additional columns for crds (#1183) +- [8355cf60](https://github.com/voyagermesh/apimachinery/commit/8355cf60) Chart support for custom tolerations and affinity (#1182) +- [1118f1fb](https://github.com/voyagermesh/apimachinery/commit/1118f1fb) Update client-go to v8.0.0 (#1177) +- [cff3fc25](https://github.com/voyagermesh/apimachinery/commit/cff3fc25) Update chart installation instruction for Kubernetes 1.11 (#1180) +- [8234eb72](https://github.com/voyagermesh/apimachinery/commit/8234eb72) Prepare docs for 7.3.0 (#1179) +- [17312469](https://github.com/voyagermesh/apimachinery/commit/17312469) Format shell scripts (#1178) +- [7577c591](https://github.com/voyagermesh/apimachinery/commit/7577c591) Merge commit 'cd04c141128a36cbac75b3c61d9638f50a54f9ed' +- [7748674f](https://github.com/voyagermesh/apimachinery/commit/7748674f) Remove status from crd.yaml (#1176) +- [d68e484d](https://github.com/voyagermesh/apimachinery/commit/d68e484d) Use HAProxy 1.8.12 (#1175) +- [0446dfaf](https://github.com/voyagermesh/apimachinery/commit/0446dfaf) Add description to crd structs (#1174) +- [54acce19](https://github.com/voyagermesh/apimachinery/commit/54acce19) Document enableStatusSubresource in chart (#1171) +- [04fce77a](https://github.com/voyagermesh/apimachinery/commit/04fce77a) Enable status subresource for voyager crds (#1169) +- [625cf2c7](https://github.com/voyagermesh/apimachinery/commit/625cf2c7) Remove deprecated fields from Certificate crd (#1170) +- [01111af4](https://github.com/voyagermesh/apimachinery/commit/01111af4) Remove description on root schema (#1168) +- [1df7a323](https://github.com/voyagermesh/apimachinery/commit/1df7a323) Add nodeSelector for the operator (#1166) +- [ea0bd992](https://github.com/voyagermesh/apimachinery/commit/ea0bd992) Update changelog for 7.2.0 +- [51c6c630](https://github.com/voyagermesh/apimachinery/commit/51c6c630) Preparep docs for 7.2.0 release (#1160) +- [010d439a](https://github.com/voyagermesh/apimachinery/commit/010d439a) Use secrets for TLS connections (#1159) +- [251c4c88](https://github.com/voyagermesh/apimachinery/commit/251c4c88) Update faq.md +- [300a250d](https://github.com/voyagermesh/apimachinery/commit/300a250d) Update operator-profiling.md +- [6ee973c7](https://github.com/voyagermesh/apimachinery/commit/6ee973c7) Added docs for backend health check (#1156) +- [9b3fd711](https://github.com/voyagermesh/apimachinery/commit/9b3fd711) Document operator profiler (#1158) +- [9dfa67ef](https://github.com/voyagermesh/apimachinery/commit/9dfa67ef) Update operator-stats.md +- [2d9cfb09](https://github.com/voyagermesh/apimachinery/commit/2d9cfb09) Update operator-stats.md +- [682cc172](https://github.com/voyagermesh/apimachinery/commit/682cc172) Document how to view operator metrics (#1157) +- [90d626d1](https://github.com/voyagermesh/apimachinery/commit/90d626d1) Allow user to set healthCheckNodePort (#1153) +- [ac2f4c9c](https://github.com/voyagermesh/apimachinery/commit/ac2f4c9c) Fix fmt string in validator (#1154) +- [5b9cc7a7](https://github.com/voyagermesh/apimachinery/commit/5b9cc7a7) Always use RBAC-enabled instructions for monitoring tutorials (#1152) +- [efa4f7f3](https://github.com/voyagermesh/apimachinery/commit/efa4f7f3) Expose webhook server to expose operator metrics (#1151) +- [cc57f6e8](https://github.com/voyagermesh/apimachinery/commit/cc57f6e8) Pause certificate checks (#1149) +- [9093c7fb](https://github.com/voyagermesh/apimachinery/commit/9093c7fb) Revendor dependencies (#1150) +- [112365cc](https://github.com/voyagermesh/apimachinery/commit/112365cc) Forward X-Auth-Request-Id-Token header in oauth (#1126) +- [77075e9f](https://github.com/voyagermesh/apimachinery/commit/77075e9f) Revendor xenolf/lego (#1147) +- [3d28bb2b](https://github.com/voyagermesh/apimachinery/commit/3d28bb2b) Add api clients to readme +- [a2dd04be](https://github.com/voyagermesh/apimachinery/commit/a2dd04be) Update install.md +- [f92ae807](https://github.com/voyagermesh/apimachinery/commit/f92ae807) Move openapi-spec to api folder (#1143) +- [64031878](https://github.com/voyagermesh/apimachinery/commit/64031878) fix link +- [e78017b4](https://github.com/voyagermesh/apimachinery/commit/e78017b4) Install in kube-system namespace via Helm +- [931af0fb](https://github.com/voyagermesh/apimachinery/commit/931af0fb) Node port services are supported by external-dns (#1138) +- [c6325c00](https://github.com/voyagermesh/apimachinery/commit/c6325c00) Update changelog +- [70b44e00](https://github.com/voyagermesh/apimachinery/commit/70b44e00) Allocate cpu for operator pod. (#1136) +- [1108e045](https://github.com/voyagermesh/apimachinery/commit/1108e045) Prepare docs for 7.1.1 release (#1135) +- [0439388d](https://github.com/voyagermesh/apimachinery/commit/0439388d) Do not create namespace from yaml, it gets created with kubectl manually (#1132) +- [b7e490ae](https://github.com/voyagermesh/apimachinery/commit/b7e490ae) Get new LE account if user hits rate limits (#1134) +- [7d8f322b](https://github.com/voyagermesh/apimachinery/commit/7d8f322b) Fix rbac permissions for service monitors (#1133) +- [4d0f915f](https://github.com/voyagermesh/apimachinery/commit/4d0f915f) Fix haproxy-stats page link (#1131) +- [3e46f219](https://github.com/voyagermesh/apimachinery/commit/3e46f219) Update changelog (#1129) +- [aab258a5](https://github.com/voyagermesh/apimachinery/commit/aab258a5) haproxy-stats.md typo fix (#1127) +- [b0008a0c](https://github.com/voyagermesh/apimachinery/commit/b0008a0c) Add togglable tabs for Installation: Script & Helm (#1125) +- [3a386d99](https://github.com/voyagermesh/apimachinery/commit/3a386d99) Prepare docs for 7.1.0 release (#1111) +- [b526f4fd](https://github.com/voyagermesh/apimachinery/commit/b526f4fd) Concourse tests (#1081) +- [328f7a9b](https://github.com/voyagermesh/apimachinery/commit/328f7a9b) Forward X-Auth-Request headers in oauth (#1114) +- [15d40978](https://github.com/voyagermesh/apimachinery/commit/15d40978) Upgrade to HAProxy 1.8.9 (#1124) +- [4be48403](https://github.com/voyagermesh/apimachinery/commit/4be48403) Revendor dependencies (#1123) +- [b6423ff6](https://github.com/voyagermesh/apimachinery/commit/b6423ff6) Fix documentation about external-dns service (#1120) +- [2a1a19fe](https://github.com/voyagermesh/apimachinery/commit/2a1a19fe) Add support for aks (#1119) +- [f61fd386](https://github.com/voyagermesh/apimachinery/commit/f61fd386) Added digitalocean & Linode provider to installer script (#1113) +- [7727207f](https://github.com/voyagermesh/apimachinery/commit/7727207f) Additional metallb support (#1117) +- [9a27980d](https://github.com/voyagermesh/apimachinery/commit/9a27980d) Apply validation rules to ingress names (#1110) +- [adf91b31](https://github.com/voyagermesh/apimachinery/commit/adf91b31) Document how to setup kube dashboard with Voyager (#1101) +- [108c90ef](https://github.com/voyagermesh/apimachinery/commit/108c90ef) Document using Google oauth with Voyager (#1100) +- [56b424c9](https://github.com/voyagermesh/apimachinery/commit/56b424c9) Add LoadBalancer type ingress support for DO and Linode (#1109) +- [bb3ef893](https://github.com/voyagermesh/apimachinery/commit/bb3ef893) Detect haproxy-image-tag in dev mode (#1082) +- [a0c60ec8](https://github.com/voyagermesh/apimachinery/commit/a0c60ec8) Update timeout key list (#1104) +- [c95a2c18](https://github.com/voyagermesh/apimachinery/commit/c95a2c18) Update version for 1.7 (#1094) +- [f1a6ebff](https://github.com/voyagermesh/apimachinery/commit/f1a6ebff) Fix installer script for --restrict-to-namespace mode (#1091) +- [8fc277e8](https://github.com/voyagermesh/apimachinery/commit/8fc277e8) Use yaml file to create service account in installer script (#1088) +- [bfd1e9db](https://github.com/voyagermesh/apimachinery/commit/bfd1e9db) Avoid waiting for api services when not installed (#1087) +- [317747f2](https://github.com/voyagermesh/apimachinery/commit/317747f2) Fix formatting errors in validator (#1085) +- [addb868e](https://github.com/voyagermesh/apimachinery/commit/addb868e) Update changelog (#1077) +- [2ab7fe8d](https://github.com/voyagermesh/apimachinery/commit/2ab7fe8d) Prepare 7.0.0 release (#1076) +- [a1f63505](https://github.com/voyagermesh/apimachinery/commit/a1f63505) Prepare docs for 7.0.0-rc.3 (#1072) +- [08158a03](https://github.com/voyagermesh/apimachinery/commit/08158a03) Checked nil pointer before validating oauth (#1071) +- [73787be8](https://github.com/voyagermesh/apimachinery/commit/73787be8) Update changelog (#1069) +- [b6104242](https://github.com/voyagermesh/apimachinery/commit/b6104242) Delete user roles on purge (#1067) +- [2e732c0e](https://github.com/voyagermesh/apimachinery/commit/2e732c0e) Use hooks for user roles in chart (#1066) +- [14cc1387](https://github.com/voyagermesh/apimachinery/commit/14cc1387) Use onessl 0.3.0 +- [9e98a03c](https://github.com/voyagermesh/apimachinery/commit/9e98a03c) Update changelog (#1065) +- [1669ce52](https://github.com/voyagermesh/apimachinery/commit/1669ce52) Clarify messaging (#1064) +- [c7c7d0b3](https://github.com/voyagermesh/apimachinery/commit/c7c7d0b3) Install correct version of voyager chart (#1063) +- [dab2837c](https://github.com/voyagermesh/apimachinery/commit/dab2837c) Avoid creating apiservice when webhooks are not used. (#1062) +- [3cd1060b](https://github.com/voyagermesh/apimachinery/commit/3cd1060b) Add --haproxy-image-tag flag to installer (#1061) +- [6b0f793e](https://github.com/voyagermesh/apimachinery/commit/6b0f793e) Prepare docs for 7.0.0-rc.2 (#1060) +- [0a5cc05f](https://github.com/voyagermesh/apimachinery/commit/0a5cc05f) Support NodeSelector and Tolerations via annotation for std ingress (#1059) +- [13c82dd8](https://github.com/voyagermesh/apimachinery/commit/13c82dd8) Update README.md +- [41c3cad0](https://github.com/voyagermesh/apimachinery/commit/41c3cad0) No auth-check for auth-backend-path itself (#1056) +- [f166a61d](https://github.com/voyagermesh/apimachinery/commit/f166a61d) Added http2 example (#1052) +- [a32e2fa8](https://github.com/voyagermesh/apimachinery/commit/a32e2fa8) Update changelog (#1051) +- [9781b2df](https://github.com/voyagermesh/apimachinery/commit/9781b2df) Prepare docs for 7.0.0-rc.1 (#1050) +- [12231b0f](https://github.com/voyagermesh/apimachinery/commit/12231b0f) Support ALPN options in HTTP mode (#1042) +- [325b82e5](https://github.com/voyagermesh/apimachinery/commit/325b82e5) Find TLS secret only if NoTLS=false (#1041) +- [e9c81388](https://github.com/voyagermesh/apimachinery/commit/e9c81388) Include a test pem to fool haproxy in operator pod. (#1038) +- [e1390c7e](https://github.com/voyagermesh/apimachinery/commit/e1390c7e) Fix ambiguous comment (#1039) +- [5032fa7d](https://github.com/voyagermesh/apimachinery/commit/5032fa7d) Use double quotes with `*` (#1037) +- [b9ad1108](https://github.com/voyagermesh/apimachinery/commit/b9ad1108) Fix tcp-sni doc (#1036) +- [734aeafc](https://github.com/voyagermesh/apimachinery/commit/734aeafc) Fix installers (#1035) +- [c772b124](https://github.com/voyagermesh/apimachinery/commit/c772b124) Fix release script for alpine image (#1034) +- [55ea6780](https://github.com/voyagermesh/apimachinery/commit/55ea6780) Prepare docs for 7.0.0-rc.0 (#1027) +- [5d0ddf61](https://github.com/voyagermesh/apimachinery/commit/5d0ddf61) Update tcp-sni doc (#1033) +- [bd79baee](https://github.com/voyagermesh/apimachinery/commit/bd79baee) Updated doc for ssl-passthrough (#1031) +- [c06db022](https://github.com/voyagermesh/apimachinery/commit/c06db022) Separated config-check from render-config (#1030) +- [4bcaddba](https://github.com/voyagermesh/apimachinery/commit/4bcaddba) Fix typo (#1032) +- [e333fbe5](https://github.com/voyagermesh/apimachinery/commit/e333fbe5) Remove AssignTypeKind and GetGroupVersionKind util methods (#1029) +- [a5481eed](https://github.com/voyagermesh/apimachinery/commit/a5481eed) Support SNI in TCP mode (#805) +- [e95998a3](https://github.com/voyagermesh/apimachinery/commit/e95998a3) Handle empty renewed certificate (#1025) +- [1e17bf54](https://github.com/voyagermesh/apimachinery/commit/1e17bf54) Add haproxy stretch image (#1014) +- [6771df32](https://github.com/voyagermesh/apimachinery/commit/6771df32) Don't panic if admission options is nil (#1019) +- [dc342443](https://github.com/voyagermesh/apimachinery/commit/dc342443) Add Update***Status helpers (#1017) +- [10590411](https://github.com/voyagermesh/apimachinery/commit/10590411) Update client-go v7.0.0 (#1016) +- [7d8aa391](https://github.com/voyagermesh/apimachinery/commit/7d8aa391) Rename flag --analytics to --enable-analytics (#1013) +- [6416c01d](https://github.com/voyagermesh/apimachinery/commit/6416c01d) Revert "Remove voyager crds before uninstalling operator (#1010)" +- [eb2340b7](https://github.com/voyagermesh/apimachinery/commit/eb2340b7) Update workload api (#1011) +- [68a5742c](https://github.com/voyagermesh/apimachinery/commit/68a5742c) Issue wildcard certs using LE ACME v2 (#996) +- [a3264471](https://github.com/voyagermesh/apimachinery/commit/a3264471) Remove voyager crds before uninstalling operator (#1010) +- [eb378dcc](https://github.com/voyagermesh/apimachinery/commit/eb378dcc) Update private registry support in chart (#1009) +- [86a61029](https://github.com/voyagermesh/apimachinery/commit/86a61029) Support both Deployment and DaemonSet to run HAProxy pods (#999) +- [030d00eb](https://github.com/voyagermesh/apimachinery/commit/030d00eb) Rename --analytics -> --enable-analytics (#1008) +- [f2c282da](https://github.com/voyagermesh/apimachinery/commit/f2c282da) Print namespace where voyager is installed (#1007) +- [5832d549](https://github.com/voyagermesh/apimachinery/commit/5832d549) Change default HAProxy tag to 1.8.8-6.1.0 (#1006) +- [0f3d251c](https://github.com/voyagermesh/apimachinery/commit/0f3d251c) Improve installer (#1005) +- [cd4340d5](https://github.com/voyagermesh/apimachinery/commit/cd4340d5) Updated validator for merging empty-host with wildcard-host (#998) +- [5dd24267](https://github.com/voyagermesh/apimachinery/commit/5dd24267) Used appscode/oauth2_proxy (#995) +- [84d4a809](https://github.com/voyagermesh/apimachinery/commit/84d4a809) Add support for external-auth/oauth (#954) +- [02bb735a](https://github.com/voyagermesh/apimachinery/commit/02bb735a) Fix .gitignore file (#993) +- [5aee21c5](https://github.com/voyagermesh/apimachinery/commit/5aee21c5) Use HAProxy 1.8.8 (#992) +- [c67bf447](https://github.com/voyagermesh/apimachinery/commit/c67bf447) Use separate offshootLabels and offshootSelector (#991) +- [2f433c72](https://github.com/voyagermesh/apimachinery/commit/2f433c72) Use HAProxy 1.8.7 (#806) +- [eb123955](https://github.com/voyagermesh/apimachinery/commit/eb123955) Revendor DNSimple api (#988) +- [684fef50](https://github.com/voyagermesh/apimachinery/commit/684fef50) concourse configs (#946) +- [1ede9d2f](https://github.com/voyagermesh/apimachinery/commit/1ede9d2f) Add namespace to relevant kubernetes resources (#985) +- [775b05db](https://github.com/voyagermesh/apimachinery/commit/775b05db) Set version in swagger.json (#983) +- [b91417ab](https://github.com/voyagermesh/apimachinery/commit/b91417ab) Update chart readme (#982) +- [d8a9be41](https://github.com/voyagermesh/apimachinery/commit/d8a9be41) Update chart repository location (#981) +- [cb392a16](https://github.com/voyagermesh/apimachinery/commit/cb392a16) Support installing from local installer scripts (#979) +- [ef1c49ea](https://github.com/voyagermesh/apimachinery/commit/ef1c49ea) Generate correct schema for int-or-string type (#978) +- [7e888493](https://github.com/voyagermesh/apimachinery/commit/7e888493) Move swagger.json to apis pkg (#976) +- [f2d4fc06](https://github.com/voyagermesh/apimachinery/commit/f2d4fc06) Generate swagger.json (#975) +- [95dd4c79](https://github.com/voyagermesh/apimachinery/commit/95dd4c79) Add install package for voyager crds (#974) +- [5472b9dd](https://github.com/voyagermesh/apimachinery/commit/5472b9dd) Fix openapi spec for voyager crds (#973) +- [497c964a](https://github.com/voyagermesh/apimachinery/commit/497c964a) Adding support to Akamai FastDNS as challenge provider (#965) +- [c93f8945](https://github.com/voyagermesh/apimachinery/commit/c93f8945) Add metallb as a cloud provider option (#972) +- [ae3394c1](https://github.com/voyagermesh/apimachinery/commit/ae3394c1) Fix errors while updating existing CRD (#971) +- [d8dafe6f](https://github.com/voyagermesh/apimachinery/commit/d8dafe6f) Skip setting ListKind (#963) +- [f0ac9e30](https://github.com/voyagermesh/apimachinery/commit/f0ac9e30) Add CRD Validation (#962) +- [f585cf50](https://github.com/voyagermesh/apimachinery/commit/f585cf50) Hard to copy line (#960) +- [f1fd111a](https://github.com/voyagermesh/apimachinery/commit/f1fd111a) Add missing RBAC for service monitors in chart (#958) +- [02fac19a](https://github.com/voyagermesh/apimachinery/commit/02fac19a) Revendor dependencies (#957) +- [49600ee8](https://github.com/voyagermesh/apimachinery/commit/49600ee8) Fix install instruction for minikube 0.24.x (Kube 1.8.0) (#956) +- [37668930](https://github.com/voyagermesh/apimachinery/commit/37668930) Skip downloading onessl if already exists (#953) +- [eeec2d38](https://github.com/voyagermesh/apimachinery/commit/eeec2d38) Revendor jsonpatch library (#952) +- [9b1932a5](https://github.com/voyagermesh/apimachinery/commit/9b1932a5) Add front matter for changelog (#951) +- [67d27c90](https://github.com/voyagermesh/apimachinery/commit/67d27c90) Use appscode/kubernetes-webhook-util (#950) +- [defc2759](https://github.com/voyagermesh/apimachinery/commit/defc2759) Reorg objects deleted in uninstall command (#949) +- [bd3fe0e7](https://github.com/voyagermesh/apimachinery/commit/bd3fe0e7) Update basic-auth.md +- [e059b56b](https://github.com/voyagermesh/apimachinery/commit/e059b56b) Revendor admission api +- [5107b04f](https://github.com/voyagermesh/apimachinery/commit/5107b04f) Revendor webhook api (#944) +- [0839e8bd](https://github.com/voyagermesh/apimachinery/commit/0839e8bd) Mention how to handle wildcard domains in documentation (#938) +- [7f71a9af](https://github.com/voyagermesh/apimachinery/commit/7f71a9af) Add links for badges (#937) +- [9153adcb](https://github.com/voyagermesh/apimachinery/commit/9153adcb) Add Slack badge +- [d3e1c3a6](https://github.com/voyagermesh/apimachinery/commit/d3e1c3a6) Add coverage badge +- [90fa8590](https://github.com/voyagermesh/apimachinery/commit/90fa8590) Vendor test dependencies (#936) +- [d793a314](https://github.com/voyagermesh/apimachinery/commit/d793a314) Add badge for travis +- [5b737ea0](https://github.com/voyagermesh/apimachinery/commit/5b737ea0) Add travis.yaml (#935) +- [98dab0ea](https://github.com/voyagermesh/apimachinery/commit/98dab0ea) Update README.md +- [cc08bb38](https://github.com/voyagermesh/apimachinery/commit/cc08bb38) Add badge for docker pull stats (#934) +- [364c57fa](https://github.com/voyagermesh/apimachinery/commit/364c57fa) Update docs for 6.0.0-rc.3 (#932) +- [10d4740d](https://github.com/voyagermesh/apimachinery/commit/10d4740d) Document how to create internal LB in openstack (#931) +- [4f0ba8b0](https://github.com/voyagermesh/apimachinery/commit/4f0ba8b0) Various fixes and improved logging (#928) +- [0bb346be](https://github.com/voyagermesh/apimachinery/commit/0bb346be) Fix typo in README (#927) +- [0c69f201](https://github.com/voyagermesh/apimachinery/commit/0c69f201) Update install.md +- [f7f9d110](https://github.com/voyagermesh/apimachinery/commit/f7f9d110) Update overview.md (#926) +- [971839c0](https://github.com/voyagermesh/apimachinery/commit/971839c0) Update install.md +- [8fe9a8cc](https://github.com/voyagermesh/apimachinery/commit/8fe9a8cc) Delete Jenkinsfile +- [3b513a27](https://github.com/voyagermesh/apimachinery/commit/3b513a27) Simplify purge section +- [61a049ac](https://github.com/voyagermesh/apimachinery/commit/61a049ac) Show output after installation +- [5e14ae09](https://github.com/voyagermesh/apimachinery/commit/5e14ae09) Add "New to Voyager" header (#922) +- [96a19c9e](https://github.com/voyagermesh/apimachinery/commit/96a19c9e) Add --purge flag (#921) +- [15a9da3c](https://github.com/voyagermesh/apimachinery/commit/15a9da3c) Make headerRule, rewriteRule plural (#919) +- [d498da31](https://github.com/voyagermesh/apimachinery/commit/d498da31) Detect change when deletion timestamp is set for Ingress (#916) +- [d029ef64](https://github.com/voyagermesh/apimachinery/commit/d029ef64) Make it clear that installer is a single command (#915) +- [c6ced112](https://github.com/voyagermesh/apimachinery/commit/c6ced112) Update docs that --rbac is default on (#914) +- [2b690c1e](https://github.com/voyagermesh/apimachinery/commit/2b690c1e) Enable RBAC by default in installer (#913) +- [0a7f6ec5](https://github.com/voyagermesh/apimachinery/commit/0a7f6ec5) Update hostport.md +- [bac6e429](https://github.com/voyagermesh/apimachinery/commit/bac6e429) Fix installer (#912) +- [05e89cc1](https://github.com/voyagermesh/apimachinery/commit/05e89cc1) Prepare docs for 6.0.0-rc.2 (#911) +- [f97c9796](https://github.com/voyagermesh/apimachinery/commit/f97c9796) Update chart to match RBAC best practices for charts (#909) +- [ae7ad819](https://github.com/voyagermesh/apimachinery/commit/ae7ad819) Add checks to installer script (#908) +- [1419524d](https://github.com/voyagermesh/apimachinery/commit/1419524d) Cleanup admission webhook (#907) +- [31803453](https://github.com/voyagermesh/apimachinery/commit/31803453) Update changelog for 6.0.0-rc.1 (#905) +- [962f15a0](https://github.com/voyagermesh/apimachinery/commit/962f15a0) Fix front matter for changelog +- [87aeb761](https://github.com/voyagermesh/apimachinery/commit/87aeb761) Prepare docs for 6.0.0-rc.1 (#904) +- [94f711a3](https://github.com/voyagermesh/apimachinery/commit/94f711a3) Update links to latest release (#901) +- [686eec33](https://github.com/voyagermesh/apimachinery/commit/686eec33) Support --enable-admission-webhook=false (#900) +- [88a4747d](https://github.com/voyagermesh/apimachinery/commit/88a4747d) Sync chart to stable charts repo (#898) +- [edf15c3a](https://github.com/voyagermesh/apimachinery/commit/edf15c3a) Document Prometheus integration (#896) +- [19749243](https://github.com/voyagermesh/apimachinery/commit/19749243) Improve docs (#895) +- [4eb48e8a](https://github.com/voyagermesh/apimachinery/commit/4eb48e8a) Revendor haproxy exporter +- [dcbeb89a](https://github.com/voyagermesh/apimachinery/commit/dcbeb89a) Update haproxy exporter (#894) +- [0cae24fd](https://github.com/voyagermesh/apimachinery/commit/0cae24fd) Document user facing RBAC roles (#892) +- [9688320d](https://github.com/voyagermesh/apimachinery/commit/9688320d) Delete annotations-old.md +- [d0c81173](https://github.com/voyagermesh/apimachinery/commit/d0c81173) Update docs for supported annotations (#871) +- [d82251f8](https://github.com/voyagermesh/apimachinery/commit/d82251f8) Skip generating UpdateStatus method (#887) +- [44a9317b](https://github.com/voyagermesh/apimachinery/commit/44a9317b) Delete internal types (#886) +- [a832b2c9](https://github.com/voyagermesh/apimachinery/commit/a832b2c9) List CRD resources in user roles +- [063d58a1](https://github.com/voyagermesh/apimachinery/commit/063d58a1) Use official code generator scripts (#885) +- [9a4b652d](https://github.com/voyagermesh/apimachinery/commit/9a4b652d) Use HAProxy 1.7.10 (#884) +- [500b02e4](https://github.com/voyagermesh/apimachinery/commit/500b02e4) Move node selector to Ingress spec (#883) +- [c8f14f23](https://github.com/voyagermesh/apimachinery/commit/c8f14f23) Only check NodePort if provided (#880) +- [c92285a1](https://github.com/voyagermesh/apimachinery/commit/c92285a1) Create user facing aggregate roles (#879) +- [11b59013](https://github.com/voyagermesh/apimachinery/commit/11b59013) Use rbac/v1 api (#878) +- [4b2472a0](https://github.com/voyagermesh/apimachinery/commit/4b2472a0) Use github.com/pkg/errors +- [38874bea](https://github.com/voyagermesh/apimachinery/commit/38874bea) Use github.com/pkg/errors (#877) +- [131cf3ec](https://github.com/voyagermesh/apimachinery/commit/131cf3ec) Fix annotation +- [7e48299f](https://github.com/voyagermesh/apimachinery/commit/7e48299f) Update changelog +- [b1a4580d](https://github.com/voyagermesh/apimachinery/commit/b1a4580d) Update changelog +- [9799536d](https://github.com/voyagermesh/apimachinery/commit/9799536d) Prepare docs for 6.0.0-rc.0 +- [f9b537ee](https://github.com/voyagermesh/apimachinery/commit/f9b537ee) Use service port by default for LB type nodeport (#870) +- [e39d0ece](https://github.com/voyagermesh/apimachinery/commit/e39d0ece) Removed deprecated sticky annotation (#868) +- [5d591c4e](https://github.com/voyagermesh/apimachinery/commit/5d591c4e) Fix formatting +- [0cde2be4](https://github.com/voyagermesh/apimachinery/commit/0cde2be4) Drop support for Kube 1.7 from chart +- [9722bcd2](https://github.com/voyagermesh/apimachinery/commit/9722bcd2) Update chart readme +- [2239faaf](https://github.com/voyagermesh/apimachinery/commit/2239faaf) Fix remaining chart issues +- [0f8e5f73](https://github.com/voyagermesh/apimachinery/commit/0f8e5f73) Update charts to support api registration (#862) +- [7801f1fa](https://github.com/voyagermesh/apimachinery/commit/7801f1fa) Label all installer resources. +- [32e1746c](https://github.com/voyagermesh/apimachinery/commit/32e1746c) Document IAM permission required for AWS +- [7d36da02](https://github.com/voyagermesh/apimachinery/commit/7d36da02) Ignore error for missing backend services (#860) +- [3d8f3c6b](https://github.com/voyagermesh/apimachinery/commit/3d8f3c6b) Fixed e2e tests (#863) +- [c18f41ec](https://github.com/voyagermesh/apimachinery/commit/c18f41ec) Modify remaining ${} forms +- [1997f7c7](https://github.com/voyagermesh/apimachinery/commit/1997f7c7) Delete all voyager resources while uninstalling +- [b5009dea](https://github.com/voyagermesh/apimachinery/commit/b5009dea) Use binary operator for checking status of semver command +- [262e5f4d](https://github.com/voyagermesh/apimachinery/commit/262e5f4d) Modify remaining ${} forms +- [1a1455dd](https://github.com/voyagermesh/apimachinery/commit/1a1455dd) Use ${} form for onessl envsubst (#861) +- [43703b0b](https://github.com/voyagermesh/apimachinery/commit/43703b0b) Make operator run locally (#859) +- [e648caf1](https://github.com/voyagermesh/apimachinery/commit/e648caf1) Update comment regarding RBAC (#858) +- [c8ac28bc](https://github.com/voyagermesh/apimachinery/commit/c8ac28bc) Merge admission webhook and operator into one binary (#856) +- [7e11029b](https://github.com/voyagermesh/apimachinery/commit/7e11029b) Use envsubst from onessl +- [c79aeaa0](https://github.com/voyagermesh/apimachinery/commit/c79aeaa0) Update overview.md +- [cc44550f](https://github.com/voyagermesh/apimachinery/commit/cc44550f) Delete ingress-merging.md +- [c185e158](https://github.com/voyagermesh/apimachinery/commit/c185e158) Delete ingress-class.md +- [973b999b](https://github.com/voyagermesh/apimachinery/commit/973b999b) Update overview.md +- [f514660b](https://github.com/voyagermesh/apimachinery/commit/f514660b) Delete external-ip.md +- [5de5538a](https://github.com/voyagermesh/apimachinery/commit/5de5538a) Update loadbalancer.md +- [1f8f2cfd](https://github.com/voyagermesh/apimachinery/commit/1f8f2cfd) Install admission webhook for Kubernetes >=1.9.0 (#855) +- [3cfedd73](https://github.com/voyagermesh/apimachinery/commit/3cfedd73) Merge uninstall script into the voyager.sh script (#854) +- [eec0e222](https://github.com/voyagermesh/apimachinery/commit/eec0e222) Fixed panic during annotation parsing (#853) +- [ddff88ec](https://github.com/voyagermesh/apimachinery/commit/ddff88ec) Checked timeout and dns-resolver maps (#852) +- [feba0328](https://github.com/voyagermesh/apimachinery/commit/feba0328) Add missing RBAC for ServiceMonitor (#851) +- [c2f2303c](https://github.com/voyagermesh/apimachinery/commit/c2f2303c) Type check for annotations in validator (#844) +- [b81ecc6c](https://github.com/voyagermesh/apimachinery/commit/b81ecc6c) Delete gke.md +- [f292c8a7](https://github.com/voyagermesh/apimachinery/commit/f292c8a7) Document GKE permission options (#850) +- [a57d1654](https://github.com/voyagermesh/apimachinery/commit/a57d1654) Ignore --run-on-master flags for GKE (#849) +- [fcc16288](https://github.com/voyagermesh/apimachinery/commit/fcc16288) Change BackendRule to BackendRules (#845) +- [61aa607b](https://github.com/voyagermesh/apimachinery/commit/61aa607b) Checked for invalid backend service name (#839) +- [d7050f0a](https://github.com/voyagermesh/apimachinery/commit/d7050f0a) Copy generic-admission-server code into pkg (#835) +- [7fe38828](https://github.com/voyagermesh/apimachinery/commit/7fe38828) Update changelog +- [0389b2cd](https://github.com/voyagermesh/apimachinery/commit/0389b2cd) Merge commit '955bbbbaea3dee5158f9a32dcc7c058ff1f6804d' +- [82321c3e](https://github.com/voyagermesh/apimachinery/commit/82321c3e) Implement work-queue in operator (#803) +- [b1a92a97](https://github.com/voyagermesh/apimachinery/commit/b1a92a97) Update install.md +- [4b482046](https://github.com/voyagermesh/apimachinery/commit/4b482046) Update changelog +- [bb2fb1f8](https://github.com/voyagermesh/apimachinery/commit/bb2fb1f8) Use deterministic-suffix instead of random-suffix in backend name (#815) +- [a05d7ad0](https://github.com/voyagermesh/apimachinery/commit/a05d7ad0) Prepare docs for 6.0.0-alpha.0 (#830) +- [8fc5bcb9](https://github.com/voyagermesh/apimachinery/commit/8fc5bcb9) Updating kube-mon so service-monitor-endpoint-port is optional (#822) +- [59c8242f](https://github.com/voyagermesh/apimachinery/commit/59c8242f) Set --provider flag for installation instructions +- [61a9beb9](https://github.com/voyagermesh/apimachinery/commit/61a9beb9) Pass cloud provider to operator +- [8087acc0](https://github.com/voyagermesh/apimachinery/commit/8087acc0) Add ValidatingAdmissionWebhook for Voyager CRDs (#828) +- [16b44b6c](https://github.com/voyagermesh/apimachinery/commit/16b44b6c) Support private docker registry in installer (#829) +- [2f5da050](https://github.com/voyagermesh/apimachinery/commit/2f5da050) Use kubectl auth reconcile in installer script (#827) +- [e79034b9](https://github.com/voyagermesh/apimachinery/commit/e79034b9) Update changelog (#826) +- [bafb1c32](https://github.com/voyagermesh/apimachinery/commit/bafb1c32) Update client-go to 6.0.0 (#825) +- [0699da86](https://github.com/voyagermesh/apimachinery/commit/0699da86) Update copyright year to 2018 (#824) +- [a51e4de2](https://github.com/voyagermesh/apimachinery/commit/a51e4de2) Merge tls-mounter & kloader into haproxy-controller (#823) +- [efbd1984](https://github.com/voyagermesh/apimachinery/commit/efbd1984) Fix links in custom-templates.md +- [08bf7290](https://github.com/voyagermesh/apimachinery/commit/08bf7290) Update service.yaml +- [6aa8f96f](https://github.com/voyagermesh/apimachinery/commit/6aa8f96f) Improve concepts docs (#809) +- [032beb18](https://github.com/voyagermesh/apimachinery/commit/032beb18) Ignored not-found error for DNS resolver annotations (#812) +- [18ed58c4](https://github.com/voyagermesh/apimachinery/commit/18ed58c4) Add changelog (#801) +- [2fdfcec9](https://github.com/voyagermesh/apimachinery/commit/2fdfcec9) Add prometheus flags to command that uses it (#810) +- [8519448c](https://github.com/voyagermesh/apimachinery/commit/8519448c) Revendor coreos prometheus operator 0.16.0 (#808) +- [088e19f5](https://github.com/voyagermesh/apimachinery/commit/088e19f5) Revendor log wrapper (#804) +- [6b4a2c14](https://github.com/voyagermesh/apimachinery/commit/6b4a2c14) Fix links in chart (#802) +- [d3ae0b41](https://github.com/voyagermesh/apimachinery/commit/d3ae0b41) Fix doc links +- [44845bdc](https://github.com/voyagermesh/apimachinery/commit/44845bdc) Prepare docs for 5.0.0-rc.11 (#799) +- [0afab18d](https://github.com/voyagermesh/apimachinery/commit/0afab18d) Reorganize docs for hosting on product site (#798) +- [a2628612](https://github.com/voyagermesh/apimachinery/commit/a2628612) Update dead links (#794) +- [22020faf](https://github.com/voyagermesh/apimachinery/commit/22020faf) Detect client id from ENV (#795) +- [66257638](https://github.com/voyagermesh/apimachinery/commit/66257638) Support additional CORS headers (#793) +- [0530688c](https://github.com/voyagermesh/apimachinery/commit/0530688c) Support ingress.appscode.com key for all annotations (#792) +- [254c3e23](https://github.com/voyagermesh/apimachinery/commit/254c3e23) Fix panic in cert store +- [02a9148d](https://github.com/voyagermesh/apimachinery/commit/02a9148d) Use CertStore from kutil (#789) +- [5f479723](https://github.com/voyagermesh/apimachinery/commit/5f479723) Fix error message for ingress validator +- [40a6f431](https://github.com/voyagermesh/apimachinery/commit/40a6f431) Allow adding new domain to cert crd (#788) +- [141415a0](https://github.com/voyagermesh/apimachinery/commit/141415a0) Prepare docs for 5.0.0-rc.10 +- [7ef47374](https://github.com/voyagermesh/apimachinery/commit/7ef47374) Add front matter for docs 5.0.0-rc.9 (#784) +- [51911e13](https://github.com/voyagermesh/apimachinery/commit/51911e13) Generate host acl correctly for `*` host (#786) +- [c068180c](https://github.com/voyagermesh/apimachinery/commit/c068180c) Prepare docs for 5.0.0-rc.9 (#782) +- [95b9959d](https://github.com/voyagermesh/apimachinery/commit/95b9959d) Keep dependencies fixes to Kube 1.8.3 +- [c2be1108](https://github.com/voyagermesh/apimachinery/commit/c2be1108) Move Acme paths to top of path list (#781) +- [f043e440](https://github.com/voyagermesh/apimachinery/commit/f043e440) Use cmp methods from kutil (#777) +- [b2ba018b](https://github.com/voyagermesh/apimachinery/commit/b2ba018b) Remove TryPatch methods +- [3bf68313](https://github.com/voyagermesh/apimachinery/commit/3bf68313) Fix master node-selector +- [7c46fd1a](https://github.com/voyagermesh/apimachinery/commit/7c46fd1a) Show how to run haproxy pods on master (#776) +- [7760e959](https://github.com/voyagermesh/apimachinery/commit/7760e959) Use verb type to indicate mutation (#775) +- [7c4afe94](https://github.com/voyagermesh/apimachinery/commit/7c4afe94) Use kube-mon repo (#774) +- [2dfb17e2](https://github.com/voyagermesh/apimachinery/commit/2dfb17e2) Update docs for 5.0.0-rc.8 (#772) +- [0c5f4e5f](https://github.com/voyagermesh/apimachinery/commit/0c5f4e5f) Fix installation instructions in guides (#770) +- [60c7c312](https://github.com/voyagermesh/apimachinery/commit/60c7c312) Document how to use external-ip (#769) +- [7c273fa9](https://github.com/voyagermesh/apimachinery/commit/7c273fa9) Support wildcard in TLS searching (#768) +- [57c1f7cf](https://github.com/voyagermesh/apimachinery/commit/57c1f7cf) Merge monitor service ports correctly (#767) +- [baab567a](https://github.com/voyagermesh/apimachinery/commit/baab567a) Set ClientID for analytics (#765) +- [0c6c49d8](https://github.com/voyagermesh/apimachinery/commit/0c6c49d8) Rename tasks to guides (#764) +- [f20f81d8](https://github.com/voyagermesh/apimachinery/commit/f20f81d8) Remove cert features from readme +- [9081869a](https://github.com/voyagermesh/apimachinery/commit/9081869a) Revise ingress docs (#755) +- [f96fe708](https://github.com/voyagermesh/apimachinery/commit/f96fe708) Update stats-and-prometheus.md +- [ed66416c](https://github.com/voyagermesh/apimachinery/commit/ed66416c) Update stats-and-prometheus.md +- [c17574cd](https://github.com/voyagermesh/apimachinery/commit/c17574cd) Support --restrict-to-namespace flag +- [ddf6ebb4](https://github.com/voyagermesh/apimachinery/commit/ddf6ebb4) Prepare for 5.0.0-rc.7 release (#757) +- [e20ca104](https://github.com/voyagermesh/apimachinery/commit/e20ca104) Installer for custom template (#756) +- [a33e760e](https://github.com/voyagermesh/apimachinery/commit/a33e760e) Fix img & pod placement +- [8d1d11b8](https://github.com/voyagermesh/apimachinery/commit/8d1d11b8) Update pod-placement.md +- [9f0baa17](https://github.com/voyagermesh/apimachinery/commit/9f0baa17) Document updated cert manager (#581) +- [3680c2a5](https://github.com/voyagermesh/apimachinery/commit/3680c2a5) Document pod placement options (#753) +- [45110d7d](https://github.com/voyagermesh/apimachinery/commit/45110d7d) Change left_menu -> menu_name (#748) +- [e81e564e](https://github.com/voyagermesh/apimachinery/commit/e81e564e) Use RegisterCRDs from kutil (#743) +- [4862a52f](https://github.com/voyagermesh/apimachinery/commit/4862a52f) Use forked golang/x/oauth2 library (#741) +- [a1042f56](https://github.com/voyagermesh/apimachinery/commit/a1042f56) Merge commit '4dfd4b50ce4941fc64a6f283a5fc2fb31d007fdc' +- [91b64829](https://github.com/voyagermesh/apimachinery/commit/91b64829) Prepare docs for 5.0.0-rc.6 release (#739) +- [7e9910b2](https://github.com/voyagermesh/apimachinery/commit/7e9910b2) Revendor dependencies (#736) +- [a85be9bc](https://github.com/voyagermesh/apimachinery/commit/a85be9bc) Prepare docs for 5.0.0-rc.5 release (#735) +- [a0d208e1](https://github.com/voyagermesh/apimachinery/commit/a0d208e1) Add aliases for README file (#731) +- [19337935](https://github.com/voyagermesh/apimachinery/commit/19337935) Update front matter for docs (#730) +- [d3e655f7](https://github.com/voyagermesh/apimachinery/commit/d3e655f7) Add Docs Front Matter (#728) +- [df4f9f01](https://github.com/voyagermesh/apimachinery/commit/df4f9f01) Update run-on-master.yaml +- [b26a081e](https://github.com/voyagermesh/apimachinery/commit/b26a081e) Prepare docs for 5.0.0-rc.4 (#723) +- [3e37a9a6](https://github.com/voyagermesh/apimachinery/commit/3e37a9a6) Make voyager YAMLs installable from internet (#722) +- [069ac433](https://github.com/voyagermesh/apimachinery/commit/069ac433) Add front matter for voyager cli ref (#721) +- [b9ba3855](https://github.com/voyagermesh/apimachinery/commit/b9ba3855) Support rewrite-target annotation (#720) +- [7543eda0](https://github.com/voyagermesh/apimachinery/commit/7543eda0) Correctly handle updated ingress.class annotation (#715) +- [ac65b839](https://github.com/voyagermesh/apimachinery/commit/ac65b839) Update README.md +- [8e5c9abd](https://github.com/voyagermesh/apimachinery/commit/8e5c9abd) Perform ssl-redirect after matching host (#702) +- [67de7715](https://github.com/voyagermesh/apimachinery/commit/67de7715) Support aws or route53 as providers which read dns credential from ENV (#712) +- [2dd5a34f](https://github.com/voyagermesh/apimachinery/commit/2dd5a34f) Document azure support for load-balancer-ip (#708) +- [c5c67ff4](https://github.com/voyagermesh/apimachinery/commit/c5c67ff4) Revise StatsAccessor interface (#704) +- [aac42427](https://github.com/voyagermesh/apimachinery/commit/aac42427) Support direct scrapping via Prometheus (#703) +- [d58e9585](https://github.com/voyagermesh/apimachinery/commit/d58e9585) Merge pull request #649 from deuill/feature/frontend-bind-specific-address +- [249ca60a](https://github.com/voyagermesh/apimachinery/commit/249ca60a) Allow for binding HTTP or TCP ingress rules to specific addresses +- [883e4a79](https://github.com/voyagermesh/apimachinery/commit/883e4a79) Merge pull request #693 from drf/send-proxy +- [6db70341](https://github.com/voyagermesh/apimachinery/commit/6db70341) Apply annotation to service and add e2e tests +- [ebc2ddc5](https://github.com/voyagermesh/apimachinery/commit/ebc2ddc5) Add to backends the options for send-proxy variants for server. +- [82b18b8f](https://github.com/voyagermesh/apimachinery/commit/82b18b8f) Fix build (#700) +- [a050189d](https://github.com/voyagermesh/apimachinery/commit/a050189d) Support ExternalIPs (#690) +- [a876af52](https://github.com/voyagermesh/apimachinery/commit/a876af52) Enable server health check using service annotations and backend rules (#695) +- [d1c53533](https://github.com/voyagermesh/apimachinery/commit/d1c53533) Send copied object for transformation +- [173e961b](https://github.com/voyagermesh/apimachinery/commit/173e961b) Change pkg alias +- [116bf6e2](https://github.com/voyagermesh/apimachinery/commit/116bf6e2) Revendor kutil +- [0df6c52b](https://github.com/voyagermesh/apimachinery/commit/0df6c52b) Support PROXY protocol in test server (#699) +- [a05c434f](https://github.com/voyagermesh/apimachinery/commit/a05c434f) Update install.md +- [17b06c0d](https://github.com/voyagermesh/apimachinery/commit/17b06c0d) Update install.md +- [a9944c7f](https://github.com/voyagermesh/apimachinery/commit/a9944c7f) Update install.md +- [513ec609](https://github.com/voyagermesh/apimachinery/commit/513ec609) Update chart +- [a2527b0a](https://github.com/voyagermesh/apimachinery/commit/a2527b0a) Use DeepCopy with PATCH calls. (#685) +- [415626ad](https://github.com/voyagermesh/apimachinery/commit/415626ad) Update _helpers.tpl +- [299c6da8](https://github.com/voyagermesh/apimachinery/commit/299c6da8) Add nodeSelector to chart values +- [6ad95e56](https://github.com/voyagermesh/apimachinery/commit/6ad95e56) Move chart inside stable folder (#681) +- [d5373d15](https://github.com/voyagermesh/apimachinery/commit/d5373d15) Make chart namespaced (#680) +- [82ea7fe2](https://github.com/voyagermesh/apimachinery/commit/82ea7fe2) Add image/tag variables in chart (#677) +- [2db53f83](https://github.com/voyagermesh/apimachinery/commit/2db53f83) Prepare docs for 5.0.0-rc.3 (#675) +- [c77bd752](https://github.com/voyagermesh/apimachinery/commit/c77bd752) Add ImagePullSecrets in Ingress (#674) +- [df3f09eb](https://github.com/voyagermesh/apimachinery/commit/df3f09eb) Support openstack provider (#671) +- [a150b887](https://github.com/voyagermesh/apimachinery/commit/a150b887) Prepare docs for 5.0.0-rc.2 +- [30c2dafe](https://github.com/voyagermesh/apimachinery/commit/30c2dafe) Support GoDaddy DNS provier (#672) +- [55b6392a](https://github.com/voyagermesh/apimachinery/commit/55b6392a) Add `deletecollection` permission to voyager operator (#666) +- [f99a204c](https://github.com/voyagermesh/apimachinery/commit/f99a204c) Prepare docs for 5.0.0-rc.1 +- [037cabe7](https://github.com/voyagermesh/apimachinery/commit/037cabe7) Enable TCP mode in port 80 (#664) +- [15f7372e](https://github.com/voyagermesh/apimachinery/commit/15f7372e) Remove unused fields from LocalTypedReference (#662) +- [8a7dbd9c](https://github.com/voyagermesh/apimachinery/commit/8a7dbd9c) Update codegen.sh +- [b6899fb1](https://github.com/voyagermesh/apimachinery/commit/b6899fb1) Update codegen.sh +- [16b9a874](https://github.com/voyagermesh/apimachinery/commit/16b9a874) Use prometheus-operator v1 api/client (#658) +- [d2eecdcd](https://github.com/voyagermesh/apimachinery/commit/d2eecdcd) Generate openapi spec (#596) +- [38d50cdb](https://github.com/voyagermesh/apimachinery/commit/38d50cdb) Fix project name in header for auto generated files (#655) +- [1f095744](https://github.com/voyagermesh/apimachinery/commit/1f095744) Document the important of order of paths (#654) +- [84bb5abe](https://github.com/voyagermesh/apimachinery/commit/84bb5abe) Prepare docs for 5.0.0-rc.0 (#653) +- [97aa681d](https://github.com/voyagermesh/apimachinery/commit/97aa681d) Update prometheus-operator to implement DeepCopy() (#652) +- [4054b482](https://github.com/voyagermesh/apimachinery/commit/4054b482) Change `k8s.io/api/core/v1` pkg alias to core (#650) +- [4000f76b](https://github.com/voyagermesh/apimachinery/commit/4000f76b) Use client-go 5.x (#629) +- [9fdec22e](https://github.com/voyagermesh/apimachinery/commit/9fdec22e) Update developer-guide (#642) +- [17318855](https://github.com/voyagermesh/apimachinery/commit/17318855) Prepare docs for 4.0.0-rc.18 +- [9903618d](https://github.com/voyagermesh/apimachinery/commit/9903618d) Prepare docs for 4.0.0-rc.17 +- [6142a40f](https://github.com/voyagermesh/apimachinery/commit/6142a40f) Raise kubernetes/client-go QPS and Burst config (#641) +- [16886c7c](https://github.com/voyagermesh/apimachinery/commit/16886c7c) Prepare docs for 4.0.0-rc.16 +- [5312b3a0](https://github.com/voyagermesh/apimachinery/commit/5312b3a0) Implement `ingress.appscode.com/type: internal` (#636) +- [d6bc5027](https://github.com/voyagermesh/apimachinery/commit/d6bc5027) Prepare docs for 4.0.0-rc.15 +- [d3fd1200](https://github.com/voyagermesh/apimachinery/commit/d3fd1200) Update chart helper truncate length (#633) +- [0a669eed](https://github.com/voyagermesh/apimachinery/commit/0a669eed) Prepare docs for 4.0.0-rc.14 +- [0344575b](https://github.com/voyagermesh/apimachinery/commit/0344575b) Prepare docs for 4.0.0-rc.13 release +- [9490df01](https://github.com/voyagermesh/apimachinery/commit/9490df01) Replace reflect.Equal with github.com/google/go-cmp (#626) +- [538ba6d3](https://github.com/voyagermesh/apimachinery/commit/538ba6d3) Prepare docs for 4.0.0-rc.12 (#622) +- [e57c4131](https://github.com/voyagermesh/apimachinery/commit/e57c4131) Support TLS auth annotations (#621) +- [71b855fd](https://github.com/voyagermesh/apimachinery/commit/71b855fd) Support Basic auth in FrontendRules (#617) +- [041f20e5](https://github.com/voyagermesh/apimachinery/commit/041f20e5) Update hsts.md +- [39896579](https://github.com/voyagermesh/apimachinery/commit/39896579) Prepare docs for 4.0.0-rc.11 +- [3f30f051](https://github.com/voyagermesh/apimachinery/commit/3f30f051) Allow restricting voyager in a single namespace (#619) +- [cdc41868](https://github.com/voyagermesh/apimachinery/commit/cdc41868) Support ingress.kubernetes.io/ssl-redirect (#616) +- [93ddb8d7](https://github.com/voyagermesh/apimachinery/commit/93ddb8d7) Remove support for ingress.appscode.com/egress-points annotations (#615) +- [b947db1f](https://github.com/voyagermesh/apimachinery/commit/b947db1f) TLS auth (#606) +- [8a183e91](https://github.com/voyagermesh/apimachinery/commit/8a183e91) Move CRD definition to api folder. (#613) +- [7f1d2f1c](https://github.com/voyagermesh/apimachinery/commit/7f1d2f1c) Merge commit '3b48dbcfa7b6118fbf0a38ec4da9e284ac656137' +- [b9a7b0cd](https://github.com/voyagermesh/apimachinery/commit/b9a7b0cd) Clarify prometheus operator version (#612) +- [b1b621a1](https://github.com/voyagermesh/apimachinery/commit/b1b621a1) Prepare docs for 4.0.0-rc.10 release (#611) +- [33c5e01f](https://github.com/voyagermesh/apimachinery/commit/33c5e01f) Update prometheus-operator dependency to 0.13.0 (#609) +- [3b5be1a5](https://github.com/voyagermesh/apimachinery/commit/3b5be1a5) Update install.md +- [7bbc560b](https://github.com/voyagermesh/apimachinery/commit/7bbc560b) Document how to detect operator version (#607) +- [08daf7f9](https://github.com/voyagermesh/apimachinery/commit/08daf7f9) Secret Update reflection (#605) +- [d720b853](https://github.com/voyagermesh/apimachinery/commit/d720b853) Fix port in installer yaml +- [e6d67af5](https://github.com/voyagermesh/apimachinery/commit/e6d67af5) Merge commit '02768a825c3f5b0aa736804598dcf0ac729d6bf7' +- [c35585c7](https://github.com/voyagermesh/apimachinery/commit/c35585c7) Prepare 4.0.0-rc.9 docs +- [50a188b8](https://github.com/voyagermesh/apimachinery/commit/50a188b8) Fix validator so can specify either HTTP or TCP (#597) +- [2e64ccba](https://github.com/voyagermesh/apimachinery/commit/2e64ccba) Delete *.generated.go files for ugorji +- [92d1ba1f](https://github.com/voyagermesh/apimachinery/commit/92d1ba1f) Limit Connections (#571) +- [45f44a95](https://github.com/voyagermesh/apimachinery/commit/45f44a95) Prepare 4.0.0-rc.8 docs +- [ad639313](https://github.com/voyagermesh/apimachinery/commit/ad639313) Assume cert store as Secret, if Vault missing. (#592) +- [6e776552](https://github.com/voyagermesh/apimachinery/commit/6e776552) Fix Ingress validator secret ref checks. +- [a6299175](https://github.com/voyagermesh/apimachinery/commit/a6299175) Prepare docs for 4.0.0-rc.7 +- [e856629c](https://github.com/voyagermesh/apimachinery/commit/e856629c) Migrate Ingress before projection (#591) +- [faf415e9](https://github.com/voyagermesh/apimachinery/commit/faf415e9) Prepare docs for 4.0.0-rc.6 +- [85b6edfd](https://github.com/voyagermesh/apimachinery/commit/85b6edfd) Fix HTTP challenger (#589) +- [9cdf4cb9](https://github.com/voyagermesh/apimachinery/commit/9cdf4cb9) Prepare docs for 4.0.0-rc.5 (#585) +- [d8755a34](https://github.com/voyagermesh/apimachinery/commit/d8755a34) Add errofiles annotation (#574) +- [4cf0fb45](https://github.com/voyagermesh/apimachinery/commit/4cf0fb45) Add force-ssl-redirect (#563) +- [f84351ec](https://github.com/voyagermesh/apimachinery/commit/f84351ec) Update kutil dependency +- [16d00fe5](https://github.com/voyagermesh/apimachinery/commit/16d00fe5) Rename SecretRef to TLSRef (#580) +- [9b49aaf0](https://github.com/voyagermesh/apimachinery/commit/9b49aaf0) Add LocalTypedReference type (#579) +- [273fbd41](https://github.com/voyagermesh/apimachinery/commit/273fbd41) Update docs for 4.0.0-rc.4 (#576) +- [22413228](https://github.com/voyagermesh/apimachinery/commit/22413228) Fix NodePort mode in GKE. (#575) +- [80519a15](https://github.com/voyagermesh/apimachinery/commit/80519a15) Prepare docs for 4.0.0-rc.3 (#569) +- [5afabb13](https://github.com/voyagermesh/apimachinery/commit/5afabb13) Add PATCH permission and fix deployment RBAC spec (#568) +- [490c2c8c](https://github.com/voyagermesh/apimachinery/commit/490c2c8c) Revendor kutil +- [e09ddf15](https://github.com/voyagermesh/apimachinery/commit/e09ddf15) Set TypeMeta when creating object (#567) +- [faab334c](https://github.com/voyagermesh/apimachinery/commit/faab334c) Fix logging (#566) +- [ec811e80](https://github.com/voyagermesh/apimachinery/commit/ec811e80) Fix RBAC permissions for apps/v1beta1 Deployments (#565) +- [06119a65](https://github.com/voyagermesh/apimachinery/commit/06119a65) Prepare docs for 4.0.0-rc.2 (#561) +- [965e1d08](https://github.com/voyagermesh/apimachinery/commit/965e1d08) Docs for 4.0 - part 1 (#556) +- [bad7aabd](https://github.com/voyagermesh/apimachinery/commit/bad7aabd) Fix #522 (#557) +- [b7dd64ba](https://github.com/voyagermesh/apimachinery/commit/b7dd64ba) Use default empty string for ingressClass in chart +- [ae169c5d](https://github.com/voyagermesh/apimachinery/commit/ae169c5d) Add ingress class support for helm chart (#559) +- [4eb83f7b](https://github.com/voyagermesh/apimachinery/commit/4eb83f7b) Generate ugorji stuff (#553) +- [94f9c5f1](https://github.com/voyagermesh/apimachinery/commit/94f9c5f1) Add max-connections annotation (#546) +- [1e1e31ff](https://github.com/voyagermesh/apimachinery/commit/1e1e31ff) Add init-only mode for tls mounter (#548) +- [80ceb505](https://github.com/voyagermesh/apimachinery/commit/80ceb505) Fix deployment yaml +- [9b34f38f](https://github.com/voyagermesh/apimachinery/commit/9b34f38f) Update minimum required Kubernetes version for chart +- [5f37382b](https://github.com/voyagermesh/apimachinery/commit/5f37382b) Update roles to allow full access to TPR apigroup +- [72005677](https://github.com/voyagermesh/apimachinery/commit/72005677) Revendor lego to fix Azure dns provider +- [f32dc66c](https://github.com/voyagermesh/apimachinery/commit/f32dc66c) Update docs to CRD from TPR (#544) +- [c4e4daaa](https://github.com/voyagermesh/apimachinery/commit/c4e4daaa) Update weighted.md +- [7cac111b](https://github.com/voyagermesh/apimachinery/commit/7cac111b) Add whitelist-source-range annotation (#539) +- [2df6a312](https://github.com/voyagermesh/apimachinery/commit/2df6a312) Make SecretRef pointer again (#540) +- [96abed3e](https://github.com/voyagermesh/apimachinery/commit/96abed3e) Add links to user guide (#537) +- [63841b70](https://github.com/voyagermesh/apimachinery/commit/63841b70) Install voyager operator as critical addon (#536) +- [afcbc9ba](https://github.com/voyagermesh/apimachinery/commit/afcbc9ba) Update readme to point out CRD migration +- [8c1fd198](https://github.com/voyagermesh/apimachinery/commit/8c1fd198) Update docs for 4.0.0-rc.1 release +- [cfcf4687](https://github.com/voyagermesh/apimachinery/commit/cfcf4687) Use CreateOrPatch apis with RBAC. Also sets ownerReference. (#533) +- [2d493f31](https://github.com/voyagermesh/apimachinery/commit/2d493f31) Rewrap quote +- [e49e6e24](https://github.com/voyagermesh/apimachinery/commit/e49e6e24) Explain why tcp connections can't be whitelisted for AWS LoadBlancers (#514) +- [72389f40](https://github.com/voyagermesh/apimachinery/commit/72389f40) Update readme +- [a3a6b7ed](https://github.com/voyagermesh/apimachinery/commit/a3a6b7ed) Prepare docs for 4.0.0-rc.0 +- [e6dcf824](https://github.com/voyagermesh/apimachinery/commit/e6dcf824) Reimplement certificate controller (#506) +- [9443137d](https://github.com/voyagermesh/apimachinery/commit/9443137d) Fix install guide link. (#523) +- [0c3dc1f1](https://github.com/voyagermesh/apimachinery/commit/0c3dc1f1) Add HAProxy 1.7.9 (#522) +- [a481163d](https://github.com/voyagermesh/apimachinery/commit/a481163d) Add hsts-preload and hsts-include-subdomains annotations (#519) +- [40fe6cd2](https://github.com/voyagermesh/apimachinery/commit/40fe6cd2) Add hsts-max-age annotation (#515) +- [29994cf6](https://github.com/voyagermesh/apimachinery/commit/29994cf6) Revendor haproxy-exporter (#513) +- [91ca7007](https://github.com/voyagermesh/apimachinery/commit/91ca7007) Prepare docs for 3.2.1 patch release. +- [b411ca8b](https://github.com/voyagermesh/apimachinery/commit/b411ca8b) Update RBAC to allow watching nodes. (#510) +- [b4e6443e](https://github.com/voyagermesh/apimachinery/commit/b4e6443e) Clarify google cloud DNS credential type. +- [e1942267](https://github.com/voyagermesh/apimachinery/commit/e1942267) Fix DNS provider key for Google cloud DNS. (#509) +- [1b92e443](https://github.com/voyagermesh/apimachinery/commit/1b92e443) Update provider.md +- [2504c63a](https://github.com/voyagermesh/apimachinery/commit/2504c63a) Update default values for chart +- [9d04186f](https://github.com/voyagermesh/apimachinery/commit/9d04186f) Update README.md +- [5e51bede](https://github.com/voyagermesh/apimachinery/commit/5e51bede) Update provider.md +- [eb2e6e5b](https://github.com/voyagermesh/apimachinery/commit/eb2e6e5b) Update provider.md +- [5e0269c4](https://github.com/voyagermesh/apimachinery/commit/5e0269c4) Update create.md +- [569e1866](https://github.com/voyagermesh/apimachinery/commit/569e1866) Fix HTTP Provider Certificate (#502) +- [94354706](https://github.com/voyagermesh/apimachinery/commit/94354706) Add ssl passthrough support for annotations (#501) +- [abe2e4fc](https://github.com/voyagermesh/apimachinery/commit/abe2e4fc) Update chart readme. +- [15e3fd8f](https://github.com/voyagermesh/apimachinery/commit/15e3fd8f) Add Max Body size and CORS annotations (#500) +- [1e46272c](https://github.com/voyagermesh/apimachinery/commit/1e46272c) Change HAProxy image tag to 1.7.6-4.0.0-alpha.1 (#499) +- [0bebdca6](https://github.com/voyagermesh/apimachinery/commit/0bebdca6) Add support for `ingress.kubernetes.io/session-cookie-hash`. (#497) +- [fdc7271d](https://github.com/voyagermesh/apimachinery/commit/fdc7271d) Change return type to *apiv1.ObjectReference +- [1f72dc62](https://github.com/voyagermesh/apimachinery/commit/1f72dc62) Correct a small typo in the weighted doco (#495) +- [20fca9e7](https://github.com/voyagermesh/apimachinery/commit/20fca9e7) Add ObjectReference methods. (#494) +- [88871c5d](https://github.com/voyagermesh/apimachinery/commit/88871c5d) Add support for `ingress.kubernetes.io/affinity` and `ingress.kubernetes.io/session-cookie-name` (#493) +- [2af9b328](https://github.com/voyagermesh/apimachinery/commit/2af9b328) Update weighted.md +- [4409bcba](https://github.com/voyagermesh/apimachinery/commit/4409bcba) Update statefulset-pod.md +- [8bcb5ad1](https://github.com/voyagermesh/apimachinery/commit/8bcb5ad1) Remove operator service flag in chart +- [6201c997](https://github.com/voyagermesh/apimachinery/commit/6201c997) Update Chart RBAC format as recommended. (#490) +- [abce2dcd](https://github.com/voyagermesh/apimachinery/commit/abce2dcd) Use svc.Spec.ExternalTrafficPolicy (#489) +- [37974996](https://github.com/voyagermesh/apimachinery/commit/37974996) Use log & errors to appscode/go pkg (#487) +- [86e75811](https://github.com/voyagermesh/apimachinery/commit/86e75811) Use Deployment for HostPort mode (#486) +- [c646802f](https://github.com/voyagermesh/apimachinery/commit/c646802f) Replace TPR with CRD (#419) +- [4f4317eb](https://github.com/voyagermesh/apimachinery/commit/4f4317eb) Document noTLS feature (#485) +- [45801a03](https://github.com/voyagermesh/apimachinery/commit/45801a03) Update custom-http-port.md +- [0d5b8f8c](https://github.com/voyagermesh/apimachinery/commit/0d5b8f8c) Update custom-http-port.md +- [0ac62a18](https://github.com/voyagermesh/apimachinery/commit/0ac62a18) Update basic-auth.md +- [a8dc0aa4](https://github.com/voyagermesh/apimachinery/commit/a8dc0aa4) Prepare docs for 3.2.0 (#476) +- [3c53a624](https://github.com/voyagermesh/apimachinery/commit/3c53a624) Fix links in docs (#478) +- [ce4b53a1](https://github.com/voyagermesh/apimachinery/commit/ce4b53a1) Fix typo in doc (#479) +- [f21012eb](https://github.com/voyagermesh/apimachinery/commit/f21012eb) Enable accept-proxy (#475) +- [069653c6](https://github.com/voyagermesh/apimachinery/commit/069653c6) Fix NodePort mode for GCE (#472) +- [e0956d21](https://github.com/voyagermesh/apimachinery/commit/e0956d21) Correctly detect APISchema() (#471) +- [ed4b30fb](https://github.com/voyagermesh/apimachinery/commit/ed4b30fb) Implement Basic Auth for HTTP Ingresses (#470) +- [79b86894](https://github.com/voyagermesh/apimachinery/commit/79b86894) Fix typo. +- [d365c3ad](https://github.com/voyagermesh/apimachinery/commit/d365c3ad) Document how to use custom templates for HAProxy (#462) +- [cf870620](https://github.com/voyagermesh/apimachinery/commit/cf870620) Prepare docs for 3.2.0-rc.3 +- [804ce40b](https://github.com/voyagermesh/apimachinery/commit/804ce40b) Remove from log message. +- [0741c4c9](https://github.com/voyagermesh/apimachinery/commit/0741c4c9) Frontend rules (#467) +- [e262fd0e](https://github.com/voyagermesh/apimachinery/commit/e262fd0e) Fix NPE (#469) +- [0eec3609](https://github.com/voyagermesh/apimachinery/commit/0eec3609) Update NodePort docs (#466) +- [4b911ce6](https://github.com/voyagermesh/apimachinery/commit/4b911ce6) Modify certificate docs. (#463) +- [e93b44f6](https://github.com/voyagermesh/apimachinery/commit/e93b44f6) Apply Session affinity to Backend service (#460) +- [2b51d89e](https://github.com/voyagermesh/apimachinery/commit/2b51d89e) Prepare docs for 3.2.0-rc.2 +- [eecb812e](https://github.com/voyagermesh/apimachinery/commit/eecb812e) Support custom user templates (#454) +- [39625816](https://github.com/voyagermesh/apimachinery/commit/39625816) Add ingress.appscode.com/accept-proxy annotation (#452) +- [81f95919](https://github.com/voyagermesh/apimachinery/commit/81f95919) Increase informer resync period to 5 mins +- [d6687a35](https://github.com/voyagermesh/apimachinery/commit/d6687a35) Move analytics collector to root command (#450) +- [851fcc6f](https://github.com/voyagermesh/apimachinery/commit/851fcc6f) Add doc for node scaler +- [14d5de2e](https://github.com/voyagermesh/apimachinery/commit/14d5de2e) Fix doc link +- [d0570436](https://github.com/voyagermesh/apimachinery/commit/d0570436) Prepare docs for 3.2.0-rc.1 release +- [ae2dffd7](https://github.com/voyagermesh/apimachinery/commit/ae2dffd7) Add kubectl commands. +- [f541ff5a](https://github.com/voyagermesh/apimachinery/commit/f541ff5a) Show how to use kubectl. (#442) +- [d2917093](https://github.com/voyagermesh/apimachinery/commit/d2917093) Add Docs (#438) +- [6d86d5ce](https://github.com/voyagermesh/apimachinery/commit/6d86d5ce) Update annotations.go +- [008ac3f4](https://github.com/voyagermesh/apimachinery/commit/008ac3f4) Fix secret name (#433) +- [2467bc41](https://github.com/voyagermesh/apimachinery/commit/2467bc41) Fix secret name (#434) +- [7968825b](https://github.com/voyagermesh/apimachinery/commit/7968825b) Fix load-balancer-ip annotation (#431) +- [7882f349](https://github.com/voyagermesh/apimachinery/commit/7882f349) Minor fix (#432) +- [6946dbaa](https://github.com/voyagermesh/apimachinery/commit/6946dbaa) Prepare docs for 3.2.0-rc.0 (#426) +- [9dba00d0](https://github.com/voyagermesh/apimachinery/commit/9dba00d0) Restart HAProxy in case of renew certificates (#427) +- [5b5828be](https://github.com/voyagermesh/apimachinery/commit/5b5828be) Fix Host:Port Matching issue. (#425) +- [efc944c4](https://github.com/voyagermesh/apimachinery/commit/efc944c4) Fix cert (#410) +- [dd766ffa](https://github.com/voyagermesh/apimachinery/commit/dd766ffa) Fix Ingress validation error (#421) +- [63a645f4](https://github.com/voyagermesh/apimachinery/commit/63a645f4) Add Patch API Supports (#412) +- [a006a31e](https://github.com/voyagermesh/apimachinery/commit/a006a31e) Support TLS Backend (#408) +- [9b0c48e3](https://github.com/voyagermesh/apimachinery/commit/9b0c48e3) Update client-go to 3.0.0 from 3.0.0-beta (#406) +- [ac9af6bb](https://github.com/voyagermesh/apimachinery/commit/ac9af6bb) Improve test suite (#394) +- [33b5eb58](https://github.com/voyagermesh/apimachinery/commit/33b5eb58) Allow custom options (#403) +- [89bcc0ea](https://github.com/voyagermesh/apimachinery/commit/89bcc0ea) Update Azure SDK to 10.2.1-beta (#402) +- [47315e9a](https://github.com/voyagermesh/apimachinery/commit/47315e9a) Remove links to forum (#395) +- [35a533e2](https://github.com/voyagermesh/apimachinery/commit/35a533e2) Revise ingress controller update operations (#385) +- [4ee3e069](https://github.com/voyagermesh/apimachinery/commit/4ee3e069) Split ingress controller into micro controllers (#383) +- [744a9072](https://github.com/voyagermesh/apimachinery/commit/744a9072) Update aws sdk to v1.6.10 (#381) +- [d2a9773d](https://github.com/voyagermesh/apimachinery/commit/d2a9773d) Fix GO reportcard issues. (#379) +- [d13952d9](https://github.com/voyagermesh/apimachinery/commit/d13952d9) Update Ingress spec (#317) +- [c3f31ac8](https://github.com/voyagermesh/apimachinery/commit/c3f31ac8) Prepare docs for 3.1.4 release +- [b1e9721d](https://github.com/voyagermesh/apimachinery/commit/b1e9721d) Detect port changes correctly. (#376) +- [d19fc429](https://github.com/voyagermesh/apimachinery/commit/d19fc429) Revendor lego to detect DNS zone correctly. (#375) +- [d7236bc1](https://github.com/voyagermesh/apimachinery/commit/d7236bc1) Revendor lego (#373) +- [590ff358](https://github.com/voyagermesh/apimachinery/commit/590ff358) Merge commit '818765fcb70c5413ba8cf0f6797d54b84746b8e3' +- [d9f9c07e](https://github.com/voyagermesh/apimachinery/commit/d9f9c07e) Define timeouts in sec explicitly (#361) +- [34a26553](https://github.com/voyagermesh/apimachinery/commit/34a26553) DisableAutoGenTag for cobra commands. +- [264f954f](https://github.com/voyagermesh/apimachinery/commit/264f954f) Prepare docs for 3.1.3 release. +- [86d35db2](https://github.com/voyagermesh/apimachinery/commit/86d35db2) Fix test docs for ginkgo tests (#352) +- [dbc2dc97](https://github.com/voyagermesh/apimachinery/commit/dbc2dc97) Converting E2E tests to use Ginkgo (#334) +- [5432253c](https://github.com/voyagermesh/apimachinery/commit/5432253c) Add DCO (#351) +- [7966ae20](https://github.com/voyagermesh/apimachinery/commit/7966ae20) Allow secret create/update for Voyager cert controller. (#338) +- [5fa441ee](https://github.com/voyagermesh/apimachinery/commit/5fa441ee) Prepare docs for 3.1.2 release. (#336) +- [249503e1](https://github.com/voyagermesh/apimachinery/commit/249503e1) Use Lets Encrypt Prod URL as default (#335) +- [e9095ada](https://github.com/voyagermesh/apimachinery/commit/e9095ada) Document --rbac flag +- [ba596c69](https://github.com/voyagermesh/apimachinery/commit/ba596c69) Add install scripts (#332) +- [fea391b0](https://github.com/voyagermesh/apimachinery/commit/fea391b0) Prepare docs for 3.1.1 release. (#328) +- [1132d72c](https://github.com/voyagermesh/apimachinery/commit/1132d72c) Add cloud provider specific install scripts. (#327) +- [1f1219f5](https://github.com/voyagermesh/apimachinery/commit/1f1219f5) Disable critical addon feature (#326) +- [4a948c06](https://github.com/voyagermesh/apimachinery/commit/4a948c06) Fix typos (#325) +- [f93c66d2](https://github.com/voyagermesh/apimachinery/commit/f93c66d2) Delete deployments.yaml +- [b8813e2f](https://github.com/voyagermesh/apimachinery/commit/b8813e2f) Fix various chart issues (#324) +- [c6cac099](https://github.com/voyagermesh/apimachinery/commit/c6cac099) Correctly detect changed ports (#322) +- [3888103c](https://github.com/voyagermesh/apimachinery/commit/3888103c) Update voyager-without-rbac.yaml +- [92dad49a](https://github.com/voyagermesh/apimachinery/commit/92dad49a) Add Custom timeout docs (#323) +- [de8af4b8](https://github.com/voyagermesh/apimachinery/commit/de8af4b8) Revendor dependencies. (#312) +- [671bf699](https://github.com/voyagermesh/apimachinery/commit/671bf699) Use ```console instead of ```sh syntax highlighting (#309) +- [d754aae8](https://github.com/voyagermesh/apimachinery/commit/d754aae8) Fix Adding SSL to an existing ingress does not mount certs #260 (#306) +- [c0bfc3b9](https://github.com/voyagermesh/apimachinery/commit/c0bfc3b9) Fix External Service redirect Issue (#304) +- [1fc5ba46](https://github.com/voyagermesh/apimachinery/commit/1fc5ba46) Install Voyager as critical addon (#301) +- [949f6e39](https://github.com/voyagermesh/apimachinery/commit/949f6e39) Add ingress label to exported metrics (#300) +- [33899f8b](https://github.com/voyagermesh/apimachinery/commit/33899f8b) Build voyager binary using alpine docker image +- [f87b680b](https://github.com/voyagermesh/apimachinery/commit/f87b680b) Merge commit 'c085ca2be9aa3c81c386ecee3ec40d10be095496' +- [af75b4e4](https://github.com/voyagermesh/apimachinery/commit/af75b4e4) Prepare docs for 3.1.0 release +- [7971b073](https://github.com/voyagermesh/apimachinery/commit/7971b073) Fix RBAC configs (#295) +- [9e07bf47](https://github.com/voyagermesh/apimachinery/commit/9e07bf47) Record events against TPR (#290) +- [9a64773e](https://github.com/voyagermesh/apimachinery/commit/9a64773e) Rename deployment.yaml to deployments.yaml +- [17283e4e](https://github.com/voyagermesh/apimachinery/commit/17283e4e) Bring back deployment.yaml for old version of docs. +- [67c97d85](https://github.com/voyagermesh/apimachinery/commit/67c97d85) Make node selectors options for HostPort (#293) +- [b8259b16](https://github.com/voyagermesh/apimachinery/commit/b8259b16) Delete kube lister classes. (#291) +- [85d371f1](https://github.com/voyagermesh/apimachinery/commit/85d371f1) Create RBAC roles for Voyager during installation (#256) +- [05dd1bdb](https://github.com/voyagermesh/apimachinery/commit/05dd1bdb) Add configure option for Haproxy default timeout. (#286) +- [fa53e0d1](https://github.com/voyagermesh/apimachinery/commit/fa53e0d1) Support setting resource for pods (#289) +- [adc3baeb](https://github.com/voyagermesh/apimachinery/commit/adc3baeb) Add tpr constants (#288) +- [b44b3083](https://github.com/voyagermesh/apimachinery/commit/b44b3083) Remove event framework (#282) +- [6d2665db](https://github.com/voyagermesh/apimachinery/commit/6d2665db) Apply app:voyager label to operator and TPRs. +- [4b113880](https://github.com/voyagermesh/apimachinery/commit/4b113880) Revendor dependencies +- [4e6e158c](https://github.com/voyagermesh/apimachinery/commit/4e6e158c) Merge commit 'cbe1cc465f506dcfbfe359f78e60a2d607121e25' +- [d9beae11](https://github.com/voyagermesh/apimachinery/commit/d9beae11) fix the contribution guild link (#274) (#275) +- [c205cec9](https://github.com/voyagermesh/apimachinery/commit/c205cec9) Clarify that the SSL listener should only be on 443. (#269) +- [f966a084](https://github.com/voyagermesh/apimachinery/commit/f966a084) Remove reference to kubed +- [b227b727](https://github.com/voyagermesh/apimachinery/commit/b227b727) Add command reference docs (#265) +- [42433f45](https://github.com/voyagermesh/apimachinery/commit/42433f45) Remove broken links +- [a67f5ff0](https://github.com/voyagermesh/apimachinery/commit/a67f5ff0) Update dev docs. (#264) +- [91318842](https://github.com/voyagermesh/apimachinery/commit/91318842) Update major chart version per review. +- [e44b36f2](https://github.com/voyagermesh/apimachinery/commit/e44b36f2) Add appVersion to Chart +- [55607b6b](https://github.com/voyagermesh/apimachinery/commit/55607b6b) Support non-default service account with offshoot pods (#255) +- [94fbc85b](https://github.com/voyagermesh/apimachinery/commit/94fbc85b) Point to HPA example on readme pages. (#254) +- [f178a880](https://github.com/voyagermesh/apimachinery/commit/f178a880) Add example with hpa (#253) +- [fef2d214](https://github.com/voyagermesh/apimachinery/commit/fef2d214) Fix default stats service name +- [682b1465](https://github.com/voyagermesh/apimachinery/commit/682b1465) Update docs. +- [672c57df](https://github.com/voyagermesh/apimachinery/commit/672c57df) Update docs +- [f3235900](https://github.com/voyagermesh/apimachinery/commit/f3235900) Small typo fix (CLOUDE_CONFIG => CLOUD_CONFIG) (#251) +- [5cde5131](https://github.com/voyagermesh/apimachinery/commit/5cde5131) Compute scrape URL correctly +- [9380262c](https://github.com/voyagermesh/apimachinery/commit/9380262c) Fix exporter. +- [5620d1f8](https://github.com/voyagermesh/apimachinery/commit/5620d1f8) Update stats-and-prometheus.md +- [3d8b34dc](https://github.com/voyagermesh/apimachinery/commit/3d8b34dc) Apply labels to stats service for service monitor (#248) +- [53135c9a](https://github.com/voyagermesh/apimachinery/commit/53135c9a) Use stats service port name in ServiceMonitor (#246) +- [ddb36644](https://github.com/voyagermesh/apimachinery/commit/ddb36644) Initialize kube clients in exporter +- [36601cc8](https://github.com/voyagermesh/apimachinery/commit/36601cc8) Note test-ns policy (#243) +- [8ccb4af4](https://github.com/voyagermesh/apimachinery/commit/8ccb4af4) Update README.md +- [7a3e7ddc](https://github.com/voyagermesh/apimachinery/commit/7a3e7ddc) Update README.md +- [3b7d72b8](https://github.com/voyagermesh/apimachinery/commit/3b7d72b8) Update README.md +- [30b3ceb8](https://github.com/voyagermesh/apimachinery/commit/30b3ceb8) Fix testframework for aws and update docs. (#237) +- [461177fc](https://github.com/voyagermesh/apimachinery/commit/461177fc) Add acs provider (#236) +- [f12684f3](https://github.com/voyagermesh/apimachinery/commit/f12684f3) Revert "Change api group to networking.appscode.com (#232)" +- [523baa35](https://github.com/voyagermesh/apimachinery/commit/523baa35) Document http->https redirect with AWS cert manager (#235) +- [60293992](https://github.com/voyagermesh/apimachinery/commit/60293992) Update chart readme for cloud config (#234) +- [517d7920](https://github.com/voyagermesh/apimachinery/commit/517d7920) Make cloud config configurable. (#233) +- [2457effc](https://github.com/voyagermesh/apimachinery/commit/2457effc) Change api group to networking.appscode.com (#232) +- [b5efcfb2](https://github.com/voyagermesh/apimachinery/commit/b5efcfb2) Fix labels import +- [417025f6](https://github.com/voyagermesh/apimachinery/commit/417025f6) Update ***Getter interfaces match form (#231) +- [fb2aff62](https://github.com/voyagermesh/apimachinery/commit/fb2aff62) Delete pods & services matching old labels before starting operator (#230) +- [e51d86c6](https://github.com/voyagermesh/apimachinery/commit/e51d86c6) Add dns-resolver-check-health annotation to for ExternalName service (#226) +- [763a98f7](https://github.com/voyagermesh/apimachinery/commit/763a98f7) Use PreRun & PostRun to send analytics. (#224) +- [6325a235](https://github.com/voyagermesh/apimachinery/commit/6325a235) Update metric endpoints documentation (#223) +- [447bc444](https://github.com/voyagermesh/apimachinery/commit/447bc444) Fix port used for exposing metrics from operator. (#222) +- [d79658dd](https://github.com/voyagermesh/apimachinery/commit/d79658dd) Minor cleanup of monitoring annotations. +- [3d63fbb3](https://github.com/voyagermesh/apimachinery/commit/3d63fbb3) Mount cloud config in chart (#220) +- [2c000e80](https://github.com/voyagermesh/apimachinery/commit/2c000e80) Add cloud config file (#218) +- [ef1f7469](https://github.com/voyagermesh/apimachinery/commit/ef1f7469) Fix bugs (#217) +- [6fa35a33](https://github.com/voyagermesh/apimachinery/commit/6fa35a33) Rename exporter port to targetPort (#216) +- [42d157c7](https://github.com/voyagermesh/apimachinery/commit/42d157c7) Use Voyager group name correctly. (#215) +- [6b2f2f9d](https://github.com/voyagermesh/apimachinery/commit/6b2f2f9d) Merge commit '5a7c63280d7aa7b8c68d8b867dd0efabf73d92c6' +- [4eb5196c](https://github.com/voyagermesh/apimachinery/commit/4eb5196c) Update TPR api groups. +- [f059bfa4](https://github.com/voyagermesh/apimachinery/commit/f059bfa4) Update default ports (#214) +- [dc4afe28](https://github.com/voyagermesh/apimachinery/commit/dc4afe28) Update docs for service monitor integration (#213) +- [dfb86722](https://github.com/voyagermesh/apimachinery/commit/dfb86722) Change api group to voyager.appscode.com (#209) +- [05890bac](https://github.com/voyagermesh/apimachinery/commit/05890bac) Update docs to point to 3.0.0 (#208) +- [dadab06f](https://github.com/voyagermesh/apimachinery/commit/dadab06f) Stop creating stats service. (#207) +- [3c81a2fe](https://github.com/voyagermesh/apimachinery/commit/3c81a2fe) Automatically create ServiceMonitor for built-in exporter (#203) +- [c7c9dea7](https://github.com/voyagermesh/apimachinery/commit/c7c9dea7) Update labels applied to HAProxy pods & services. (#206) +- [66d3ea84](https://github.com/voyagermesh/apimachinery/commit/66d3ea84) Update NOTES.txt +- [1381ec53](https://github.com/voyagermesh/apimachinery/commit/1381ec53) Remove deprecated Daemon type. (#205) +- [9311d860](https://github.com/voyagermesh/apimachinery/commit/9311d860) Fix client-go fake import (#204) +- [b0d19bf1](https://github.com/voyagermesh/apimachinery/commit/b0d19bf1) Update README.md +- [d5821a5c](https://github.com/voyagermesh/apimachinery/commit/d5821a5c) Update release.md +- [84910d55](https://github.com/voyagermesh/apimachinery/commit/84910d55) Change default HAProxy image to 1.7.6-3.0.0 (#202) +- [f8b2b145](https://github.com/voyagermesh/apimachinery/commit/f8b2b145) Merge commit 'b074920b5d2073bac14cb7f41e8671a897072c13' +- [d435d068](https://github.com/voyagermesh/apimachinery/commit/d435d068) Merge commit '59330c227bd4165b3ced36dcbbb93f206f0760ad' +- [3f0587a3](https://github.com/voyagermesh/apimachinery/commit/3f0587a3) Track operator version (#200) +- [399cbef4](https://github.com/voyagermesh/apimachinery/commit/399cbef4) Update README.md +- [573416b9](https://github.com/voyagermesh/apimachinery/commit/573416b9) Add voyager export command (#199) +- [5f9f6656](https://github.com/voyagermesh/apimachinery/commit/5f9f6656) Update docs. (#198) +- [b87121eb](https://github.com/voyagermesh/apimachinery/commit/b87121eb) Use client-go (#196) +- [8c554673](https://github.com/voyagermesh/apimachinery/commit/8c554673) Update pod selectors +- [b52ba35c](https://github.com/voyagermesh/apimachinery/commit/b52ba35c) Update selector for operator deployment. +- [fc03bb58](https://github.com/voyagermesh/apimachinery/commit/fc03bb58) Update selector for svc +- [93b156fe](https://github.com/voyagermesh/apimachinery/commit/93b156fe) Delete keep-source-ip.md +- [d43ecd84](https://github.com/voyagermesh/apimachinery/commit/d43ecd84) Fix chart path (#191) +- [3fbfafd0](https://github.com/voyagermesh/apimachinery/commit/3fbfafd0) Document flag options (#190) +- [ae10f2b7](https://github.com/voyagermesh/apimachinery/commit/ae10f2b7) Docs for 1.5.6 (#183) +- [fe69629e](https://github.com/voyagermesh/apimachinery/commit/fe69629e) Create deployments.yaml +- [23abc80b](https://github.com/voyagermesh/apimachinery/commit/23abc80b) Add various comments in chart review +- [dd54134b](https://github.com/voyagermesh/apimachinery/commit/dd54134b) Merge commit 'dc0c1dee9a4f2c9faf611eac3456de866e4402f0' +- [b89e4161](https://github.com/voyagermesh/apimachinery/commit/b89e4161) ./hack/make.py test_deploy to generate deployments yaml (#184) +- [b7cf38da](https://github.com/voyagermesh/apimachinery/commit/b7cf38da) Install voyager operator in kube-system namespace +- [bc6a37ca](https://github.com/voyagermesh/apimachinery/commit/bc6a37ca) Merge commit '1dfe6c897bf277f03152548a968b2681c1d7413f' +- [abcbdf65](https://github.com/voyagermesh/apimachinery/commit/abcbdf65) Set metrics port to :8080 by default (#180) +- [14f65bc4](https://github.com/voyagermesh/apimachinery/commit/14f65bc4) Stop redefining -h flag for run command. (#179) +- [48d797fb](https://github.com/voyagermesh/apimachinery/commit/48d797fb) Prepare docs for 1.5.6 (#178) +- [97852bd6](https://github.com/voyagermesh/apimachinery/commit/97852bd6) Remove cluster name flag (#177) +- [ae7126b0](https://github.com/voyagermesh/apimachinery/commit/ae7126b0) Bring back NewIngressFromEngress +- [f9c824d2](https://github.com/voyagermesh/apimachinery/commit/f9c824d2) Remove --cluster-name flag (#176) +- [ae0ad436](https://github.com/voyagermesh/apimachinery/commit/ae0ad436) Remove persist annotation (#174) +- [6c61b9cb](https://github.com/voyagermesh/apimachinery/commit/6c61b9cb) Add support for ServiceTypeExternalName (#167) +- [a198b2a7](https://github.com/voyagermesh/apimachinery/commit/a198b2a7) Add nil check before reading options from Ingress annotations. (#170) +- [be337629](https://github.com/voyagermesh/apimachinery/commit/be337629) Update default HAProxy image to 1.7.5-1.5.6 +- [5bb6e829](https://github.com/voyagermesh/apimachinery/commit/5bb6e829) Various cleanup of annotations (#169) +- [e94cb9b9](https://github.com/voyagermesh/apimachinery/commit/e94cb9b9) Fix chart readme +- [515182e6](https://github.com/voyagermesh/apimachinery/commit/515182e6) Combine annotation keys ip & persist into persist (#162) +- [a025889f](https://github.com/voyagermesh/apimachinery/commit/a025889f) Make nodeSelector annotation applicable for any more. (#160) +- [ffb68e6a](https://github.com/voyagermesh/apimachinery/commit/ffb68e6a) Explain versioning policy. (#158) +- [8cd3d89e](https://github.com/voyagermesh/apimachinery/commit/8cd3d89e) Apply various comments from official charts team (#157) +- [677a713c](https://github.com/voyagermesh/apimachinery/commit/677a713c) Expose monitoring port in chart and deploy yamls (#156) +- [a065ffbf](https://github.com/voyagermesh/apimachinery/commit/a065ffbf) Move component docs directly under user-guide (#155) +- [b96418ab](https://github.com/voyagermesh/apimachinery/commit/b96418ab) Expose Operator & HAProxy metrics (#153) +- [16e7e01a](https://github.com/voyagermesh/apimachinery/commit/16e7e01a) Reorganize code to add run sub command (#152) +- [0ed1cbdc](https://github.com/voyagermesh/apimachinery/commit/0ed1cbdc) Correctly import forked cloudprovider package. +- [948fcba5](https://github.com/voyagermesh/apimachinery/commit/948fcba5) Add forked cloudprovider in third_party package (#151) +- [1094e855](https://github.com/voyagermesh/apimachinery/commit/1094e855) Ensure loadbalancer resource (#145) +- [a090de04](https://github.com/voyagermesh/apimachinery/commit/a090de04) Add LoadBalancerSourceRange to ingress Spec (#148) +- [0a15147f](https://github.com/voyagermesh/apimachinery/commit/0a15147f) Use ci-space cluster for testing (#131) +- [1f5006d4](https://github.com/voyagermesh/apimachinery/commit/1f5006d4) Remove dependency on k8s-addons (#141) +- [00618724](https://github.com/voyagermesh/apimachinery/commit/00618724) Revendor analytics library. +- [c3e05ae1](https://github.com/voyagermesh/apimachinery/commit/c3e05ae1) Fix stats behavior (#130) +- [b6b8d43d](https://github.com/voyagermesh/apimachinery/commit/b6b8d43d) Add Jenkinsfile (#118) +- [91fa3b10](https://github.com/voyagermesh/apimachinery/commit/91fa3b10) tcp.md: fix typo/port mismatch (#119) +- [bb6062b6](https://github.com/voyagermesh/apimachinery/commit/bb6062b6) Update README.md +- [9acaac3b](https://github.com/voyagermesh/apimachinery/commit/9acaac3b) Update README.md +- [5a22acdc](https://github.com/voyagermesh/apimachinery/commit/5a22acdc) Prepare docs for 1.5.5 release +- [37897a03](https://github.com/voyagermesh/apimachinery/commit/37897a03) Update top readme file (#112) +- [b506bbea](https://github.com/voyagermesh/apimachinery/commit/b506bbea) Update docs (#111) +- [0e4058f3](https://github.com/voyagermesh/apimachinery/commit/0e4058f3) NodePort Tests, Annotations Documentation (#110) +- [ddd44d7f](https://github.com/voyagermesh/apimachinery/commit/ddd44d7f) Add `go` and `glide` commands (#101) +- [599d61cd](https://github.com/voyagermesh/apimachinery/commit/599d61cd) Update docs to build HAProxy 1.7.5 (#92) +- [5b487b89](https://github.com/voyagermesh/apimachinery/commit/5b487b89) Update svc instead of Deleting svc (#87) +- [9931f0bc](https://github.com/voyagermesh/apimachinery/commit/9931f0bc) Rename Daemon type to HostPort (#84) +- [1f7957b9](https://github.com/voyagermesh/apimachinery/commit/1f7957b9) Update 1.5.5 Documentation (#82) +- [ce1d854b](https://github.com/voyagermesh/apimachinery/commit/ce1d854b) Feature: backend rules (#80) +- [85411591](https://github.com/voyagermesh/apimachinery/commit/85411591) Use appscode/errors v2 (#81) +- [3dc3133d](https://github.com/voyagermesh/apimachinery/commit/3dc3133d) Use https git url for our lego fork +- [f29012c8](https://github.com/voyagermesh/apimachinery/commit/f29012c8) Prepare docs for 1.5.4 release +- [7904d56f](https://github.com/voyagermesh/apimachinery/commit/7904d56f) Rename operator deployment to voyager-operator (#71) +- [f634810b](https://github.com/voyagermesh/apimachinery/commit/f634810b) Revendor dependencies. +- [5c727011](https://github.com/voyagermesh/apimachinery/commit/5c727011) Update statefulset-pod.md +- [e7611829](https://github.com/voyagermesh/apimachinery/commit/e7611829) Prepare docs for 1.5.3 release (#67) +- [a91fb2ae](https://github.com/voyagermesh/apimachinery/commit/a91fb2ae) Ingress Hostname based traffic forwarding (#66) +- [9eeb2e4f](https://github.com/voyagermesh/apimachinery/commit/9eeb2e4f) Update README.md +- [d88c87c9](https://github.com/voyagermesh/apimachinery/commit/d88c87c9) Spelling correction for SNI +- [eec1acf8](https://github.com/voyagermesh/apimachinery/commit/eec1acf8) Update docs to new chart location (#60) +- [402df8ef](https://github.com/voyagermesh/apimachinery/commit/402df8ef) Move chart to root directory (#59) +- [d4572d13](https://github.com/voyagermesh/apimachinery/commit/d4572d13) Add service to deployment.yaml (#58) +- [77206b2b](https://github.com/voyagermesh/apimachinery/commit/77206b2b) Prepare docs for version 1.5.2 (#57) +- [615510a1](https://github.com/voyagermesh/apimachinery/commit/615510a1) Add service in voyager (#56) +- [63b1ef7e](https://github.com/voyagermesh/apimachinery/commit/63b1ef7e) Various fixes to voyager chart (#55) +- [c4d8dc47](https://github.com/voyagermesh/apimachinery/commit/c4d8dc47) Merge commit '462dda880bd3d562e8f6af28b22a636cdb153fa2' +- [e96c537a](https://github.com/voyagermesh/apimachinery/commit/e96c537a) Use unversioned time. (#54) +- [c357345b](https://github.com/voyagermesh/apimachinery/commit/c357345b) Document http provider for LE (#53) +- [413f43f2](https://github.com/voyagermesh/apimachinery/commit/413f43f2) Update docs on DNS provider (#51) +- [c50600c2](https://github.com/voyagermesh/apimachinery/commit/c50600c2) Merge remote-tracking branch 'origin/master' +- [4b359cfe](https://github.com/voyagermesh/apimachinery/commit/4b359cfe) Initial voyager chart (#43) +- [2958606f](https://github.com/voyagermesh/apimachinery/commit/2958606f) Update README.md +- [fca91a3b](https://github.com/voyagermesh/apimachinery/commit/fca91a3b) Prepare docs for version 1.5.1 +- [348c7a6d](https://github.com/voyagermesh/apimachinery/commit/348c7a6d) Enable GKE (#45) +- [bb9a9e33](https://github.com/voyagermesh/apimachinery/commit/bb9a9e33) Add link to HAProxy +- [0d483c7d](https://github.com/voyagermesh/apimachinery/commit/0d483c7d) Fix Typos (#42) +- [0e1fef21](https://github.com/voyagermesh/apimachinery/commit/0e1fef21) update README (#41) +- [6dec948a](https://github.com/voyagermesh/apimachinery/commit/6dec948a) Explain how to update kloader version +- [3f34f16b](https://github.com/voyagermesh/apimachinery/commit/3f34f16b) Move release.md to developer guide. +- [0b40b621](https://github.com/voyagermesh/apimachinery/commit/0b40b621) Add doc explaining release process. (#37) +- [cf5ac0e1](https://github.com/voyagermesh/apimachinery/commit/cf5ac0e1) Add ALPN options to TCP Backends (#35) +- [9149e8f5](https://github.com/voyagermesh/apimachinery/commit/9149e8f5) Update docs with voyager options and test modes (#34) +- [6aebb45a](https://github.com/voyagermesh/apimachinery/commit/6aebb45a) Adding Tests - Unit and E2E (#12) +- [879cb88c](https://github.com/voyagermesh/apimachinery/commit/879cb88c) Update doc fix for #19 (#26) +- [33931ac5](https://github.com/voyagermesh/apimachinery/commit/33931ac5) Revendor dependencies. (#23) +- [7064a6f2](https://github.com/voyagermesh/apimachinery/commit/7064a6f2) Update README.md +- [997c0dcf](https://github.com/voyagermesh/apimachinery/commit/997c0dcf) Add example on front page. (#16) +- [c2f95947](https://github.com/voyagermesh/apimachinery/commit/c2f95947) README typos (#15) +- [5577a442](https://github.com/voyagermesh/apimachinery/commit/5577a442) Add links to HAProxy Docker image +- [1f707212](https://github.com/voyagermesh/apimachinery/commit/1f707212) Add links of subsections (#11) +- [34ae9069](https://github.com/voyagermesh/apimachinery/commit/34ae9069) Refactor docs (#10) +- [9fde741f](https://github.com/voyagermesh/apimachinery/commit/9fde741f) Rename voyager to Voyager (#8) +- [ed6549ac](https://github.com/voyagermesh/apimachinery/commit/ed6549ac) Use appscode/lego +- [8429c4a4](https://github.com/voyagermesh/apimachinery/commit/8429c4a4) Add acknowledgements (#7) +- [3a9bef41](https://github.com/voyagermesh/apimachinery/commit/3a9bef41) Documentation for voyager (#6) +- [3e44b51b](https://github.com/voyagermesh/apimachinery/commit/3e44b51b) Revendor to remove DeleteOptions +- [29be74c8](https://github.com/voyagermesh/apimachinery/commit/29be74c8) Revendor k8s-addons +- [91e70955](https://github.com/voyagermesh/apimachinery/commit/91e70955) Set default HAproxy to 1.7.2-k8s +- [909ea91f](https://github.com/voyagermesh/apimachinery/commit/909ea91f) Revendor. +- [94def797](https://github.com/voyagermesh/apimachinery/commit/94def797) Update README.md +- [42f5a55e](https://github.com/voyagermesh/apimachinery/commit/42f5a55e) Update README.md +- [5c7818df](https://github.com/voyagermesh/apimachinery/commit/5c7818df) Use our forked appscode/lego lib. +- [fade0840](https://github.com/voyagermesh/apimachinery/commit/fade0840) Use release-1.5 for k8s-addons. +- [9783125f](https://github.com/voyagermesh/apimachinery/commit/9783125f) Revendor to update Vultr/Lego lib. +- [edf2d572](https://github.com/voyagermesh/apimachinery/commit/edf2d572) Properly version k8s cloud providers. +- [b3dd4288](https://github.com/voyagermesh/apimachinery/commit/b3dd4288) Use appscode/go repo. +- [02b202b7](https://github.com/voyagermesh/apimachinery/commit/02b202b7) Merge commit '0e3394e0d8ebec7afdcc06940203811032d62344' as 'hack/libbuild' +- [f26d15dd](https://github.com/voyagermesh/apimachinery/commit/f26d15dd) Initial public release + + + +## [voyagermesh/haproxy-ingress](https://github.com/voyagermesh/haproxy-ingress) + +### [v13.0.0](https://github.com/voyagermesh/haproxy-ingress/releases/tag/v13.0.0) + +- [591bae2f](https://github.com/voyagermesh/haproxy-ingress/commit/591bae2f) Prepare for release v13.0.0 (#6) +- [e53fdb56](https://github.com/voyagermesh/haproxy-ingress/commit/e53fdb56) Fix linter error +- [bbc79553](https://github.com/voyagermesh/haproxy-ingress/commit/bbc79553) Fix CI +- [564e11cb](https://github.com/voyagermesh/haproxy-ingress/commit/564e11cb) Disable grpc test as breaks build +- [cea1bf26](https://github.com/voyagermesh/haproxy-ingress/commit/cea1bf26) Remove --enable-validating-webhook flag +- [9d8e9803](https://github.com/voyagermesh/haproxy-ingress/commit/9d8e9803) Add v1beta1 <-> v1 crd converter (#5) +- [5601bd36](https://github.com/voyagermesh/haproxy-ingress/commit/5601bd36) Fix lua script loading (#4) +- [dee97c55](https://github.com/voyagermesh/haproxy-ingress/commit/dee97c55) Log everything to stdout and notice to stderr +- [c8a1394d](https://github.com/voyagermesh/haproxy-ingress/commit/c8a1394d) Enable built-in prometheus exporter +- [c331002a](https://github.com/voyagermesh/haproxy-ingress/commit/c331002a) Implement voyager.appscode.com/v1 api operator (#3) +- [222e6506](https://github.com/voyagermesh/haproxy-ingress/commit/222e6506) Update repository config (#2) +- [110e198e](https://github.com/voyagermesh/haproxy-ingress/commit/110e198e) Stop using api versions removed in k8s 1.22 (#1) +- [56e15b13](https://github.com/voyagermesh/haproxy-ingress/commit/56e15b13) Use voyager namespace +- [87d89fab](https://github.com/voyagermesh/haproxy-ingress/commit/87d89fab) Update audit lib +- [a9dd2d72](https://github.com/voyagermesh/haproxy-ingress/commit/a9dd2d72) Send audit events if analytics enabled (#1588) +- [af1ec7b8](https://github.com/voyagermesh/haproxy-ingress/commit/af1ec7b8) Publish audit events +- [a527eb62](https://github.com/voyagermesh/haproxy-ingress/commit/a527eb62) Use klog/v2 +- [d3756322](https://github.com/voyagermesh/haproxy-ingress/commit/d3756322) Bring back grpc test +- [44fe45ea](https://github.com/voyagermesh/haproxy-ingress/commit/44fe45ea) Update Kubernetes toolchain to v1.21.0 (#1585) +- [e43f1b78](https://github.com/voyagermesh/haproxy-ingress/commit/e43f1b78) Update readme +- [31e87b8e](https://github.com/voyagermesh/haproxy-ingress/commit/31e87b8e) Disable building arm64 images +- [404a6bcd](https://github.com/voyagermesh/haproxy-ingress/commit/404a6bcd) Update Dockerfile +- [4ae3aa3f](https://github.com/voyagermesh/haproxy-ingress/commit/4ae3aa3f) Fix build +- [ae95cdb8](https://github.com/voyagermesh/haproxy-ingress/commit/ae95cdb8) Build voyager binary before building haproxy image +- [8531ae0e](https://github.com/voyagermesh/haproxy-ingress/commit/8531ae0e) Fix socklog download url +- [c2f9a803](https://github.com/voyagermesh/haproxy-ingress/commit/c2f9a803) Publish images to GH registry +- [c2b1a5ce](https://github.com/voyagermesh/haproxy-ingress/commit/c2b1a5ce) Add license verifier (#1583) +- [94562494](https://github.com/voyagermesh/haproxy-ingress/commit/94562494) Update repository config (#1584) +- [ea232e45](https://github.com/voyagermesh/haproxy-ingress/commit/ea232e45) Update license header (#1582) +- [0bdded99](https://github.com/voyagermesh/haproxy-ingress/commit/0bdded99) Avoid issuing cert two times at creation (#1535) +- [b356066d](https://github.com/voyagermesh/haproxy-ingress/commit/b356066d) fix CheckCertificates goroutine to run an infinite loop again (#1531) +- [7bd08749](https://github.com/voyagermesh/haproxy-ingress/commit/7bd08749) Avoid concurrent haproxy starts or reloads (#1547) +- [5b423374](https://github.com/voyagermesh/haproxy-ingress/commit/5b423374) Update kind in CI +- [6e9cced0](https://github.com/voyagermesh/haproxy-ingress/commit/6e9cced0) Update README.md +- [c7f806e6](https://github.com/voyagermesh/haproxy-ingress/commit/c7f806e6) Update repository config (#1579) +- [e13dc9e7](https://github.com/voyagermesh/haproxy-ingress/commit/e13dc9e7) Update repository config (#1577) +- [a4705e66](https://github.com/voyagermesh/haproxy-ingress/commit/a4705e66) Update Kubernetes v1.18.9 dependencies (#1576) +- [e937812b](https://github.com/voyagermesh/haproxy-ingress/commit/e937812b) Update repository config (#1574) +- [8a9f92cc](https://github.com/voyagermesh/haproxy-ingress/commit/8a9f92cc) Update repository config (#1573) +- [08872d74](https://github.com/voyagermesh/haproxy-ingress/commit/08872d74) Update Kubernetes v1.18.9 dependencies (#1572) +- [01ad6049](https://github.com/voyagermesh/haproxy-ingress/commit/01ad6049) Update Kubernetes v1.18.9 dependencies (#1571) +- [89e39d57](https://github.com/voyagermesh/haproxy-ingress/commit/89e39d57) Update repository config (#1570) +- [777e2c53](https://github.com/voyagermesh/haproxy-ingress/commit/777e2c53) Update repository config (#1569) +- [6fcc2041](https://github.com/voyagermesh/haproxy-ingress/commit/6fcc2041) Update Kubernetes v1.18.9 dependencies (#1568) +- [120682e7](https://github.com/voyagermesh/haproxy-ingress/commit/120682e7) Update Kubernetes v1.18.9 dependencies (#1567) +- [23193a8e](https://github.com/voyagermesh/haproxy-ingress/commit/23193a8e) Update Kubernetes v1.18.9 dependencies (#1566) +- [23553514](https://github.com/voyagermesh/haproxy-ingress/commit/23553514) Update Kubernetes v1.18.9 dependencies (#1565) +- [924fced5](https://github.com/voyagermesh/haproxy-ingress/commit/924fced5) Update Kubernetes v1.18.9 dependencies (#1564) +- [8e0dc012](https://github.com/voyagermesh/haproxy-ingress/commit/8e0dc012) Update Kubernetes v1.18.9 dependencies (#1563) +- [e54d2622](https://github.com/voyagermesh/haproxy-ingress/commit/e54d2622) Update repository config (#1561) +- [ba9e4aa7](https://github.com/voyagermesh/haproxy-ingress/commit/ba9e4aa7) Update Kubernetes v1.18.9 dependencies (#1559) +- [285dac84](https://github.com/voyagermesh/haproxy-ingress/commit/285dac84) Update Kubernetes v1.18.9 dependencies (#1558) +- [f5e66408](https://github.com/voyagermesh/haproxy-ingress/commit/f5e66408) Update Kubernetes v1.18.9 dependencies (#1557) +- [a51e4aa4](https://github.com/voyagermesh/haproxy-ingress/commit/a51e4aa4) Update Kubernetes v1.18.9 dependencies (#1555) +- [1afdf274](https://github.com/voyagermesh/haproxy-ingress/commit/1afdf274) Update Kubernetes v1.18.9 dependencies (#1554) +- [93e691ea](https://github.com/voyagermesh/haproxy-ingress/commit/93e691ea) Update Kubernetes v1.18.9 dependencies (#1552) +- [3d1c72d4](https://github.com/voyagermesh/haproxy-ingress/commit/3d1c72d4) Update Kubernetes v1.18.9 dependencies (#1549) +- [d48b88ed](https://github.com/voyagermesh/haproxy-ingress/commit/d48b88ed) Update repository config (#1551) +- [603868db](https://github.com/voyagermesh/haproxy-ingress/commit/603868db) Update repository config (#1550) +- [869936e4](https://github.com/voyagermesh/haproxy-ingress/commit/869936e4) Update repository config (#1548) +- [ac8399a7](https://github.com/voyagermesh/haproxy-ingress/commit/ac8399a7) Update Kubernetes v1.18.9 dependencies (#1546) +- [3889306c](https://github.com/voyagermesh/haproxy-ingress/commit/3889306c) Update Kubernetes v1.18.9 dependencies (#1544) +- [2256661e](https://github.com/voyagermesh/haproxy-ingress/commit/2256661e) Update repository config (#1543) +- [ed48d8f0](https://github.com/voyagermesh/haproxy-ingress/commit/ed48d8f0) Update repository config (#1542) +- [c1d898d3](https://github.com/voyagermesh/haproxy-ingress/commit/c1d898d3) Update Kubernetes v1.18.9 dependencies (#1541) +- [7764aac4](https://github.com/voyagermesh/haproxy-ingress/commit/7764aac4) Update Kubernetes v1.18.3 dependencies (#1540) +- [f9f1732e](https://github.com/voyagermesh/haproxy-ingress/commit/f9f1732e) Update Kubernetes v1.18.3 dependencies (#1539) +- [b3f18ffd](https://github.com/voyagermesh/haproxy-ingress/commit/b3f18ffd) Update Kubernetes v1.18.3 dependencies (#1536) +- [c92a0f15](https://github.com/voyagermesh/haproxy-ingress/commit/c92a0f15) Update Kubernetes v1.18.3 dependencies (#1534) +- [aa701496](https://github.com/voyagermesh/haproxy-ingress/commit/aa701496) Update Kubernetes v1.18.3 dependencies (#1532) +- [cacef44c](https://github.com/voyagermesh/haproxy-ingress/commit/cacef44c) Update Kubernetes v1.18.3 dependencies (#1529) +- [f9248332](https://github.com/voyagermesh/haproxy-ingress/commit/f9248332) Update Kubernetes v1.18.3 dependencies (#1528) +- [fd3aa94c](https://github.com/voyagermesh/haproxy-ingress/commit/fd3aa94c) Update Kubernetes v1.18.3 dependencies (#1527) +- [85915ab8](https://github.com/voyagermesh/haproxy-ingress/commit/85915ab8) Update Kubernetes v1.18.3 dependencies (#1524) +- [dd3cc508](https://github.com/voyagermesh/haproxy-ingress/commit/dd3cc508) Update to Kubernetes v1.18.3 (#1521) +- [cbd7d3e2](https://github.com/voyagermesh/haproxy-ingress/commit/cbd7d3e2) Update to Kubernetes v1.18.3 (#1520) +- [d00a4c72](https://github.com/voyagermesh/haproxy-ingress/commit/d00a4c72) Update to Kubernetes v1.18.3 (#1519) +- [c6bbe8cc](https://github.com/voyagermesh/haproxy-ingress/commit/c6bbe8cc) Update to Kubernetes v1.18.3 (#1518) +- [dcc94c7e](https://github.com/voyagermesh/haproxy-ingress/commit/dcc94c7e) Update ci.yml +- [d9c38862](https://github.com/voyagermesh/haproxy-ingress/commit/d9c38862) Update update-release-tracker.sh +- [5c74ad2b](https://github.com/voyagermesh/haproxy-ingress/commit/5c74ad2b) Update update-release-tracker.sh +- [21b03bbb](https://github.com/voyagermesh/haproxy-ingress/commit/21b03bbb) Add script to update release tracker on pr merge (#1516) +- [57503de5](https://github.com/voyagermesh/haproxy-ingress/commit/57503de5) Update .kodiak.toml +- [dbdb1e5c](https://github.com/voyagermesh/haproxy-ingress/commit/dbdb1e5c) Update to Kubernetes v1.18.3 (#1514) +- [1abc059e](https://github.com/voyagermesh/haproxy-ingress/commit/1abc059e) Update to Kubernetes v1.18.3 +- [7a61045e](https://github.com/voyagermesh/haproxy-ingress/commit/7a61045e) Create .kodiak.toml +- [4081635b](https://github.com/voyagermesh/haproxy-ingress/commit/4081635b) Prepare release v13.0.0-beta.1 (#1512) +- [9b527d39](https://github.com/voyagermesh/haproxy-ingress/commit/9b527d39) Generate both v1beta1 and v1 CRD YAML (#1511) +- [bb85c779](https://github.com/voyagermesh/haproxy-ingress/commit/bb85c779) Prepare release v13.0.0-beta.0 (#1510) +- [c19455cf](https://github.com/voyagermesh/haproxy-ingress/commit/c19455cf) Update to Kubernetes v1.18.3 (#1509) +- [9e750a13](https://github.com/voyagermesh/haproxy-ingress/commit/9e750a13) Update README.md +- [f89dc723](https://github.com/voyagermesh/haproxy-ingress/commit/f89dc723) Merge pull request #1507 from smarkets/fix-readme-docs-links +- [6ed3c7eb](https://github.com/voyagermesh/haproxy-ingress/commit/6ed3c7eb) Fix README.md documentation links + + + +## [voyagermesh/installer](https://github.com/voyagermesh/installer) + +### [v2021.09.15](https://github.com/voyagermesh/installer/releases/tag/v2021.09.15) + +- [12faf00](https://github.com/voyagermesh/installer/commit/12faf00) Prepare for release v2021.09.15 (#86) +- [d5e9b00](https://github.com/voyagermesh/installer/commit/d5e9b00) Fix import-crds script +- [62ba7dc](https://github.com/voyagermesh/installer/commit/62ba7dc) Make validating webhooks required +- [65f05df](https://github.com/voyagermesh/installer/commit/65f05df) Mark /convert path as always allow (#85) +- [0f5d596](https://github.com/voyagermesh/installer/commit/0f5d596) Use HAProxy 2.4.4 (#84) +- [d53eea0](https://github.com/voyagermesh/installer/commit/d53eea0) Update repository config (#83) +- [8fb004a](https://github.com/voyagermesh/installer/commit/8fb004a) Delete voyager.appscode.com_certificates.yaml +- [d966bb5](https://github.com/voyagermesh/installer/commit/d966bb5) Update repository config (#82) +- [323b08d](https://github.com/voyagermesh/installer/commit/323b08d) Update repository config (#81) +- [876aef6](https://github.com/voyagermesh/installer/commit/876aef6) Update chart description +- [a423445](https://github.com/voyagermesh/installer/commit/a423445) Update dependencies (#80) +- [05ede0e](https://github.com/voyagermesh/installer/commit/05ede0e) Minimum required k8s version to 1.19 +- [d06bf03](https://github.com/voyagermesh/installer/commit/d06bf03) Switch to AppsCode Community License +- [8ea7f8a](https://github.com/voyagermesh/installer/commit/8ea7f8a) Update README.md +- [e44a1c6](https://github.com/voyagermesh/installer/commit/e44a1c6) Stop using api versions removed in k8s 1.22 (#79) +- [a9822dd](https://github.com/voyagermesh/installer/commit/a9822dd) Add registryFQDN support (#78) +- [7db2985](https://github.com/voyagermesh/installer/commit/7db2985) Use Kubernetes v1.21.0 toolchain (#77) +- [2920e4c](https://github.com/voyagermesh/installer/commit/2920e4c) Use Kubernetes v1.21.0 toolchain (#76) +- [8d822e2](https://github.com/voyagermesh/installer/commit/8d822e2) Use Kubernetes v1.21.0 toolchain (#75) +- [88bbfdc](https://github.com/voyagermesh/installer/commit/88bbfdc) Use Kubernetes v1.21.0 toolchain (#74) +- [bf96a48](https://github.com/voyagermesh/installer/commit/bf96a48) Update Kubernetes toolchain to v1.21.0 (#73) +- [589ed14](https://github.com/voyagermesh/installer/commit/589ed14) Use apiregistration.k8s.io/v1 +- [7996020](https://github.com/voyagermesh/installer/commit/7996020) Prepare for release v2021.04.24-rc.0 (#72) +- [37b8597](https://github.com/voyagermesh/installer/commit/37b8597) Prepare for release v2021.04.20-beta.2 (#71) +- [3a33e2e](https://github.com/voyagermesh/installer/commit/3a33e2e) Update Makefile +- [9c19ed2](https://github.com/voyagermesh/installer/commit/9c19ed2) Add voyager-crds chart (#66) +- [252f14a](https://github.com/voyagermesh/installer/commit/252f14a) Add cleaner skip option for YAML installation process (#65) +- [d737d14](https://github.com/voyagermesh/installer/commit/d737d14) Remove protobuf code generator (#64) +- [6fdc1ca](https://github.com/voyagermesh/installer/commit/6fdc1ca) Update repository config (#63) +- [81c5627](https://github.com/voyagermesh/installer/commit/81c5627) Update Kubernetes v1.18.9 dependencies (#62) +- [acf9453](https://github.com/voyagermesh/installer/commit/acf9453) Update repository config (#61) +- [9de2b98](https://github.com/voyagermesh/installer/commit/9de2b98) Update Kubernetes v1.18.9 dependencies (#60) +- [d2f88f6](https://github.com/voyagermesh/installer/commit/d2f88f6) Update repository config (#59) +- [2f97c0d](https://github.com/voyagermesh/installer/commit/2f97c0d) Update repository config (#58) +- [a17dcd6](https://github.com/voyagermesh/installer/commit/a17dcd6) Update Kubernetes v1.18.9 dependencies (#57) +- [1b34287](https://github.com/voyagermesh/installer/commit/1b34287) Update Kubernetes v1.18.9 dependencies (#56) +- [ce2fa80](https://github.com/voyagermesh/installer/commit/ce2fa80) Update Kubernetes v1.18.9 dependencies (#55) +- [3b9833f](https://github.com/voyagermesh/installer/commit/3b9833f) Update Kubernetes v1.18.9 dependencies (#54) +- [05c1ae4](https://github.com/voyagermesh/installer/commit/05c1ae4) Update repository config (#53) +- [9d5c567](https://github.com/voyagermesh/installer/commit/9d5c567) Update repository config (#52) +- [68974d1](https://github.com/voyagermesh/installer/commit/68974d1) Update Kubernetes v1.18.9 dependencies (#51) +- [1834e92](https://github.com/voyagermesh/installer/commit/1834e92) Update repository config (#50) +- [88837e9](https://github.com/voyagermesh/installer/commit/88837e9) Update Kubernetes v1.18.9 dependencies (#49) +- [fd8dd22](https://github.com/voyagermesh/installer/commit/fd8dd22) Update Kubernetes v1.18.9 dependencies (#48) +- [e5acaa0](https://github.com/voyagermesh/installer/commit/e5acaa0) Update Kubernetes v1.18.9 dependencies (#47) +- [b8f929a](https://github.com/voyagermesh/installer/commit/b8f929a) Update Kubernetes v1.18.9 dependencies (#46) +- [0d18bec](https://github.com/voyagermesh/installer/commit/0d18bec) Update Kubernetes v1.18.9 dependencies (#44) +- [eba9d11](https://github.com/voyagermesh/installer/commit/eba9d11) Update Kubernetes v1.18.9 dependencies (#43) +- [3e27095](https://github.com/voyagermesh/installer/commit/3e27095) Update repository config (#42) +- [877c601](https://github.com/voyagermesh/installer/commit/877c601) Update Kubernetes v1.18.9 dependencies (#41) +- [5cd3131](https://github.com/voyagermesh/installer/commit/5cd3131) Update repository config (#40) +- [14e8b27](https://github.com/voyagermesh/installer/commit/14e8b27) Update Kubernetes v1.18.9 dependencies (#39) +- [f219188](https://github.com/voyagermesh/installer/commit/f219188) Update Kubernetes v1.18.9 dependencies (#38) +- [58f432a](https://github.com/voyagermesh/installer/commit/58f432a) Update repository config (#37) +- [41dc0fd](https://github.com/voyagermesh/installer/commit/41dc0fd) Update repository config (#36) +- [a54c114](https://github.com/voyagermesh/installer/commit/a54c114) Update Kubernetes v1.18.9 dependencies (#35) +- [d95070d](https://github.com/voyagermesh/installer/commit/d95070d) Update Kubernetes v1.18.3 dependencies (#34) +- [c5ca00c](https://github.com/voyagermesh/installer/commit/c5ca00c) Update Kubernetes v1.18.3 dependencies (#33) +- [30dfe30](https://github.com/voyagermesh/installer/commit/30dfe30) Update Kubernetes v1.18.3 dependencies (#32) +- [e89a026](https://github.com/voyagermesh/installer/commit/e89a026) Update Kubernetes v1.18.3 dependencies (#31) +- [b91a6e9](https://github.com/voyagermesh/installer/commit/b91a6e9) Update Kubernetes v1.18.3 dependencies (#30) +- [236a3b1](https://github.com/voyagermesh/installer/commit/236a3b1) Update Kubernetes v1.18.3 dependencies (#29) +- [a2d4bff](https://github.com/voyagermesh/installer/commit/a2d4bff) Update Kubernetes v1.18.3 dependencies (#28) +- [bc8cac9](https://github.com/voyagermesh/installer/commit/bc8cac9) Update Kubernetes v1.18.3 dependencies (#27) +- [8c93371](https://github.com/voyagermesh/installer/commit/8c93371) Update Kubernetes v1.18.3 dependencies (#26) +- [51a239d](https://github.com/voyagermesh/installer/commit/51a239d) Update Kubernetes v1.18.3 dependencies (#25) +- [475bd11](https://github.com/voyagermesh/installer/commit/475bd11) Update Kubernetes v1.18.3 dependencies (#24) +- [4c472a4](https://github.com/voyagermesh/installer/commit/4c472a4) Update Kubernetes v1.18.3 dependencies (#23) +- [40c34b1](https://github.com/voyagermesh/installer/commit/40c34b1) Update to Kubernetes v1.18.3 (#22) +- [2b52571](https://github.com/voyagermesh/installer/commit/2b52571) Update to Kubernetes v1.18.3 (#21) +- [2d5ff81](https://github.com/voyagermesh/installer/commit/2d5ff81) Update to Kubernetes v1.18.3 (#20) +- [1c8cd5e](https://github.com/voyagermesh/installer/commit/1c8cd5e) Make chart registry configurable (#19) +- [c75e2fd](https://github.com/voyagermesh/installer/commit/c75e2fd) Publish to testing dir for alpha/beta releases +- [0fbed72](https://github.com/voyagermesh/installer/commit/0fbed72) Update to Kubernetes v1.18.3 (#18) +- [04abb9d](https://github.com/voyagermesh/installer/commit/04abb9d) Update ci.yml +- [52f62df](https://github.com/voyagermesh/installer/commit/52f62df) Tag chart and app version as string for yq +- [3aed33c](https://github.com/voyagermesh/installer/commit/3aed33c) Update update-release-tracker.sh +- [fe16afc](https://github.com/voyagermesh/installer/commit/fe16afc) Update update-release-tracker.sh +- [9740a56](https://github.com/voyagermesh/installer/commit/9740a56) Update release.yml +- [290be5b](https://github.com/voyagermesh/installer/commit/290be5b) Add script to update release tracker on pr merge (#17) +- [0256621](https://github.com/voyagermesh/installer/commit/0256621) Update kubernetes versions in CI workflow +- [5b4e797](https://github.com/voyagermesh/installer/commit/5b4e797) Add commands to update chart (#16) +- [59872d2](https://github.com/voyagermesh/installer/commit/59872d2) Fix chart release process (#15) +- [cf8f550](https://github.com/voyagermesh/installer/commit/cf8f550) Fix release workflow script +- [70ff5a6](https://github.com/voyagermesh/installer/commit/70ff5a6) Update .kodiak.toml +- [4c429a3](https://github.com/voyagermesh/installer/commit/4c429a3) Update to Kubernetes v1.18.3 (#10) +- [25d6aac](https://github.com/voyagermesh/installer/commit/25d6aac) Update to Kubernetes v1.18.3 +- [aeebca4](https://github.com/voyagermesh/installer/commit/aeebca4) Create .kodiak.toml +- [7aa3256](https://github.com/voyagermesh/installer/commit/7aa3256) Prepare release v13.0.0-beta.1 (#9) +- [c46cf95](https://github.com/voyagermesh/installer/commit/c46cf95) Add permissions for networking.k8s.io (#8) +- [40e7bef](https://github.com/voyagermesh/installer/commit/40e7bef) Generate both v1beta1 and v1 CRD YAML (#7) +- [080d925](https://github.com/voyagermesh/installer/commit/080d925) Prepare release v13.0.0-beta.0 +- [3e5eb03](https://github.com/voyagermesh/installer/commit/3e5eb03) Update to Kubernetes v1.18.3 (#6) + + + + diff --git a/content/docs/v2024.3.18/CHANGELOG-v2021.10.16.md b/content/docs/v2024.3.18/CHANGELOG-v2021.10.16.md new file mode 100644 index 000000000..95f48be05 --- /dev/null +++ b/content/docs/v2024.3.18/CHANGELOG-v2021.10.16.md @@ -0,0 +1,64 @@ +--- +title: Changelog | Voyager +description: Changelog +menu: + docs_v2024.3.18: + identifier: changelog-voyager-v2021.10.16 + name: Changelog-v2021.10.16 + parent: welcome + weight: 20211016 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: welcome +url: /docs/v2024.3.18/welcome/changelog-v2021.10.16/ +aliases: +- /docs/v2024.3.18/CHANGELOG-v2021.10.16/ +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +# Voyager v2021.10.16 (2021-10-16) + + +## [voyagermesh/apimachinery](https://github.com/voyagermesh/apimachinery) + +### [v0.1.1](https://github.com/voyagermesh/apimachinery/releases/tag/v0.1.1) + +- [a7704e79](https://github.com/voyagermesh/apimachinery/commit/a7704e79) Set TypeMeta for converter methods (#15) +- [2ccd9780](https://github.com/voyagermesh/apimachinery/commit/2ccd9780) Fix jwt-go security vulnerability (#14) +- [7c884131](https://github.com/voyagermesh/apimachinery/commit/7c884131) Fix jwt-go security vulnerability (#13) +- [660e4478](https://github.com/voyagermesh/apimachinery/commit/660e4478) Update dependencies to publish SiteInfo (#12) +- [c175c94c](https://github.com/voyagermesh/apimachinery/commit/c175c94c) Update repository config (#11) +- [aabe0c90](https://github.com/voyagermesh/apimachinery/commit/aabe0c90) Rename minikube to kind (#10) +- [4216e746](https://github.com/voyagermesh/apimachinery/commit/4216e746) Remove deprecated fields (#9) + + + +## [voyagermesh/haproxy-ingress](https://github.com/voyagermesh/haproxy-ingress) + +### [v13.0.1](https://github.com/voyagermesh/haproxy-ingress/releases/tag/v13.0.1) + +- [1f65f08c](https://github.com/voyagermesh/haproxy-ingress/commit/1f65f08c) Prepare for release v13.0.1 (#24) +- [89dcd122](https://github.com/voyagermesh/haproxy-ingress/commit/89dcd122) Run separate operator and webhook server pods (#23) +- [f5621d0d](https://github.com/voyagermesh/haproxy-ingress/commit/f5621d0d) Fix jwt-go security vulnerability (#21) +- [b968bc02](https://github.com/voyagermesh/haproxy-ingress/commit/b968bc02) Use nats.go v1.13.0 (#20) +- [e3c0c421](https://github.com/voyagermesh/haproxy-ingress/commit/e3c0c421) Setup SiteInfo publisher (#19) +- [5a3f21d3](https://github.com/voyagermesh/haproxy-ingress/commit/5a3f21d3) Update dependencies to publish SiteInfo (#18) + + + +## [voyagermesh/installer](https://github.com/voyagermesh/installer) + +### [v2021.10.16](https://github.com/voyagermesh/installer/releases/tag/v2021.10.16) + +- [c609411](https://github.com/voyagermesh/installer/commit/c609411) Prepare for release v2021.10.16 (#91) +- [66bc3ad](https://github.com/voyagermesh/installer/commit/66bc3ad) Use separate deployments for operator and webhook server (#90) +- [b2d8453](https://github.com/voyagermesh/installer/commit/b2d8453) Fix jwt-go security vulnerability (#89) +- [de86de2](https://github.com/voyagermesh/installer/commit/de86de2) Update dependencies to publish SiteInfo (#88) +- [0e722e0](https://github.com/voyagermesh/installer/commit/0e722e0) Update repository config (#87) + + + + diff --git a/content/docs/v2024.3.18/CHANGELOG-v2021.10.17.md b/content/docs/v2024.3.18/CHANGELOG-v2021.10.17.md new file mode 100644 index 000000000..5a7ddddfd --- /dev/null +++ b/content/docs/v2024.3.18/CHANGELOG-v2021.10.17.md @@ -0,0 +1,51 @@ +--- +title: Changelog | Voyager +description: Changelog +menu: + docs_v2024.3.18: + identifier: changelog-voyager-v2021.10.17 + name: Changelog-v2021.10.17 + parent: welcome + weight: 20211017 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: welcome +url: /docs/v2024.3.18/welcome/changelog-v2021.10.17/ +aliases: +- /docs/v2024.3.18/CHANGELOG-v2021.10.17/ +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +# Voyager v2021.10.17 (2021-10-16) + + +## [voyagermesh/apimachinery](https://github.com/voyagermesh/apimachinery) + +### [v0.1.2](https://github.com/voyagermesh/apimachinery/releases/tag/v0.1.2) + +- [1e37c726](https://github.com/voyagermesh/apimachinery/commit/1e37c726) Recover from conversion panic (#16) + + + +## [voyagermesh/haproxy-ingress](https://github.com/voyagermesh/haproxy-ingress) + +### [v13.0.2](https://github.com/voyagermesh/haproxy-ingress/releases/tag/v13.0.2) + +- [dab93b5e](https://github.com/voyagermesh/haproxy-ingress/commit/dab93b5e) Prepare for release v13.0.2 (#26) +- [42ef435b](https://github.com/voyagermesh/haproxy-ingress/commit/42ef435b) Log ensure crd error without failing operator (#25) +- [29e080ba](https://github.com/voyagermesh/haproxy-ingress/commit/29e080ba) Fix flag conflict + + + +## [voyagermesh/installer](https://github.com/voyagermesh/installer) + +### [v2021.10.17](https://github.com/voyagermesh/installer/releases/tag/v2021.10.17) + +- [a92784d](https://github.com/voyagermesh/installer/commit/a92784d) Prepare for release v2021.10.17 (#92) + + + + diff --git a/content/docs/v2024.3.18/CHANGELOG-v2021.10.18.md b/content/docs/v2024.3.18/CHANGELOG-v2021.10.18.md new file mode 100644 index 000000000..725a3b0e8 --- /dev/null +++ b/content/docs/v2024.3.18/CHANGELOG-v2021.10.18.md @@ -0,0 +1,63 @@ +--- +title: Changelog | Voyager +description: Changelog +menu: + docs_v2024.3.18: + identifier: changelog-voyager-v2021.10.18 + name: Changelog-v2021.10.18 + parent: welcome + weight: 20211018 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: welcome +url: /docs/v2024.3.18/welcome/changelog-v2021.10.18/ +aliases: +- /docs/v2024.3.18/CHANGELOG-v2021.10.18/ +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +# Voyager v2021.10.18 (2021-10-18) + + +## [voyagermesh/apimachinery](https://github.com/voyagermesh/apimachinery) + +### [v0.1.3](https://github.com/voyagermesh/apimachinery/releases/tag/v0.1.3) + +- [21c78451](https://github.com/voyagermesh/apimachinery/commit/21c78451) Fix v1beta1 to v1 type conversion (#17) +- [1fcd5596](https://github.com/voyagermesh/apimachinery/commit/1fcd5596) Remove kubectl.kubernetes.io/last-applied-configuration annotation + + + +## [voyagermesh/cli](https://github.com/voyagermesh/cli) + +### [v0.0.3](https://github.com/voyagermesh/cli/releases/tag/v0.0.3) + +- [115ccc1](https://github.com/voyagermesh/cli/commit/115ccc1) Prepare for release v0.0.3 (#2) + + + +## [voyagermesh/haproxy-ingress](https://github.com/voyagermesh/haproxy-ingress) + +### [v13.0.3](https://github.com/voyagermesh/haproxy-ingress/releases/tag/v13.0.3) + +- [bf746ef6](https://github.com/voyagermesh/haproxy-ingress/commit/bf746ef6) Prepare for release v13.0.3 (#30) +- [73778780](https://github.com/voyagermesh/haproxy-ingress/commit/73778780) Remove check and convert commands +- [5755c97e](https://github.com/voyagermesh/haproxy-ingress/commit/5755c97e) Move reference docs to a sub menu (#29) +- [8e5ab525](https://github.com/voyagermesh/haproxy-ingress/commit/8e5ab525) Load HAProxy templates using git submodule (#28) +- [69192031](https://github.com/voyagermesh/haproxy-ingress/commit/69192031) Add haproxy-templates git submodule +- [0f4310a6](https://github.com/voyagermesh/haproxy-ingress/commit/0f4310a6) Fix conversion panic (#27) + + + +## [voyagermesh/installer](https://github.com/voyagermesh/installer) + +### [v2021.10.18](https://github.com/voyagermesh/installer/releases/tag/v2021.10.18) + +- [7a4972c](https://github.com/voyagermesh/installer/commit/7a4972c) Prepare for release v2021.10.18 (#93) + + + + diff --git a/content/docs/v2024.3.18/CHANGELOG-v2022.01.01.md b/content/docs/v2024.3.18/CHANGELOG-v2022.01.01.md new file mode 100644 index 000000000..92fe721c1 --- /dev/null +++ b/content/docs/v2024.3.18/CHANGELOG-v2022.01.01.md @@ -0,0 +1,70 @@ +--- +title: Changelog | Voyager +description: Changelog +menu: + docs_v2024.3.18: + identifier: changelog-voyager-v2022.01.01 + name: Changelog-v2022.01.01 + parent: welcome + weight: 20220101 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: welcome +url: /docs/v2024.3.18/welcome/changelog-v2022.01.01/ +aliases: +- /docs/v2024.3.18/CHANGELOG-v2022.01.01/ +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +# Voyager v2022.01.01 (2022-01-02) + + +## [voyagermesh/apimachinery](https://github.com/voyagermesh/apimachinery) + +### [v0.2.0](https://github.com/voyagermesh/apimachinery/releases/tag/v0.2.0) + +- [b9ccd598](https://github.com/voyagermesh/apimachinery/commit/b9ccd598) Support proxy security context (#21) +- [1991e135](https://github.com/voyagermesh/apimachinery/commit/1991e135) Update repository config (#20) +- [0393f8de](https://github.com/voyagermesh/apimachinery/commit/0393f8de) Update repository config (#19) +- [f792df1d](https://github.com/voyagermesh/apimachinery/commit/f792df1d) Fix satori/go.uuid security vulnerability (#18) + + + +## [voyagermesh/cli](https://github.com/voyagermesh/cli) + +### [v0.0.4](https://github.com/voyagermesh/cli/releases/tag/v0.0.4) + +- [7ee2d31](https://github.com/voyagermesh/cli/commit/7ee2d31) Prepare for release v0.0.4 (#3) +- [979d215](https://github.com/voyagermesh/cli/commit/979d215) Correctly initialize klog flags + + + +## [voyagermesh/haproxy-ingress](https://github.com/voyagermesh/haproxy-ingress) + +### [v14.0.0](https://github.com/voyagermesh/haproxy-ingress/releases/tag/v14.0.0) + +- [cdb54de8](https://github.com/voyagermesh/haproxy-ingress/commit/cdb54de8) Prepare for release v14.0.0 (#34) +- [e591ca27](https://github.com/voyagermesh/haproxy-ingress/commit/e591ca27) Log changed files when haproxy is reloaded (#33) +- [83a3b1f0](https://github.com/voyagermesh/haproxy-ingress/commit/83a3b1f0) Various cleanup (#32) +- [1be18011](https://github.com/voyagermesh/haproxy-ingress/commit/1be18011) Update configreader +- [77b702a2](https://github.com/voyagermesh/haproxy-ingress/commit/77b702a2) Fix satori/go.uuid security vulnerability (#31) +- [b371aae6](https://github.com/voyagermesh/haproxy-ingress/commit/b371aae6) update templates + + + +## [voyagermesh/installer](https://github.com/voyagermesh/installer) + +### [v2022.01.01](https://github.com/voyagermesh/installer/releases/tag/v2022.01.01) + +- [0d683d5](https://github.com/voyagermesh/installer/commit/0d683d5) Prepare for release v2022.01.01 (#97) +- [3583265](https://github.com/voyagermesh/installer/commit/3583265) Remove enableAnalytics flag +- [21e6643](https://github.com/voyagermesh/installer/commit/21e6643) Update default HAProxy version to 2.5.0 (#96) +- [c3f75c3](https://github.com/voyagermesh/installer/commit/c3f75c3) Update repository config (#95) +- [2a22b46](https://github.com/voyagermesh/installer/commit/2a22b46) Fix satori/go.uuid security vulnerability (#94) + + + + diff --git a/content/docs/v2024.3.18/CHANGELOG-v2022.01.07.md b/content/docs/v2024.3.18/CHANGELOG-v2022.01.07.md new file mode 100644 index 000000000..4c09ea9e1 --- /dev/null +++ b/content/docs/v2024.3.18/CHANGELOG-v2022.01.07.md @@ -0,0 +1,43 @@ +--- +title: Changelog | Voyager +description: Changelog +menu: + docs_v2024.3.18: + identifier: changelog-voyager-v2022.01.07 + name: Changelog-v2022.01.07 + parent: welcome + weight: 20220107 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: welcome +url: /docs/v2024.3.18/welcome/changelog-v2022.01.07/ +aliases: +- /docs/v2024.3.18/CHANGELOG-v2022.01.07/ +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +# Voyager v2022.01.07 (2022-01-07) + + +## [voyagermesh/haproxy-ingress](https://github.com/voyagermesh/haproxy-ingress) + +### [v14.0.1](https://github.com/voyagermesh/haproxy-ingress/releases/tag/v14.0.1) + +- [f9861aed](https://github.com/voyagermesh/haproxy-ingress/commit/f9861aed) Log diffs for changed config files (#36) +- [ddcf94de](https://github.com/voyagermesh/haproxy-ingress/commit/ddcf94de) Run trivy scanner (#35) + + + +## [voyagermesh/installer](https://github.com/voyagermesh/installer) + +### [v2022.01.07](https://github.com/voyagermesh/installer/releases/tag/v2022.01.07) + +- [912f293](https://github.com/voyagermesh/installer/commit/912f293) Prepare for release v2022.01.07 (#98) +- [63c4565](https://github.com/voyagermesh/installer/commit/63c4565) Enable arm64 nodes by default + + + + diff --git a/content/docs/v2024.3.18/CHANGELOG-v2022.01.10.md b/content/docs/v2024.3.18/CHANGELOG-v2022.01.10.md new file mode 100644 index 000000000..3c9bab150 --- /dev/null +++ b/content/docs/v2024.3.18/CHANGELOG-v2022.01.10.md @@ -0,0 +1,60 @@ +--- +title: Changelog | Voyager +description: Changelog +menu: + docs_v2024.3.18: + identifier: changelog-voyager-v2022.01.10 + name: Changelog-v2022.01.10 + parent: welcome + weight: 20220110 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: welcome +url: /docs/v2024.3.18/welcome/changelog-v2022.01.10/ +aliases: +- /docs/v2024.3.18/CHANGELOG-v2022.01.10/ +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +# Voyager v2022.01.10 (2022-01-10) + + +## [voyagermesh/apimachinery](https://github.com/voyagermesh/apimachinery) + +### [v0.3.0](https://github.com/voyagermesh/apimachinery/releases/tag/v0.3.0) + +- [7d6c4d04](https://github.com/voyagermesh/apimachinery/commit/7d6c4d04) Convert ProxySecurityContext from v1beta1 to v1 api (#22) + + + +## [voyagermesh/cli](https://github.com/voyagermesh/cli) + +### [v0.0.5](https://github.com/voyagermesh/cli/releases/tag/v0.0.5) + +- [1824d2f](https://github.com/voyagermesh/cli/commit/1824d2f) Prepare for release v0.0.5 (#4) + + + +## [voyagermesh/haproxy-ingress](https://github.com/voyagermesh/haproxy-ingress) + +### [v14.1.0](https://github.com/voyagermesh/haproxy-ingress/releases/tag/v14.1.0) + +- [96ea81cb](https://github.com/voyagermesh/haproxy-ingress/commit/96ea81cb) Prepare for release v14.1.0 (#38) +- [9df118f9](https://github.com/voyagermesh/haproxy-ingress/commit/9df118f9) Mount emptyDir to /var/run (#37) +- [b48d48f9](https://github.com/voyagermesh/haproxy-ingress/commit/b48d48f9) Use HAProxy 2.5 (no patch) version + + + +## [voyagermesh/installer](https://github.com/voyagermesh/installer) + +### [v2022.01.10](https://github.com/voyagermesh/installer/releases/tag/v2022.01.10) + +- [dac9c9b](https://github.com/voyagermesh/installer/commit/dac9c9b) Prepare for release v2022.01.10 (#100) +- [40a8b9a](https://github.com/voyagermesh/installer/commit/40a8b9a) Use HAProxy 2.5-alpine version (#99) + + + + diff --git a/content/docs/v2024.3.18/CHANGELOG-v2022.02.22.md b/content/docs/v2024.3.18/CHANGELOG-v2022.02.22.md new file mode 100644 index 000000000..29a81546f --- /dev/null +++ b/content/docs/v2024.3.18/CHANGELOG-v2022.02.22.md @@ -0,0 +1,63 @@ +--- +title: Changelog | Voyager +description: Changelog +menu: + docs_v2024.3.18: + identifier: changelog-voyager-v2022.02.22 + name: Changelog-v2022.02.22 + parent: welcome + weight: 20220222 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: welcome +url: /docs/v2024.3.18/welcome/changelog-v2022.02.22/ +aliases: +- /docs/v2024.3.18/CHANGELOG-v2022.02.22/ +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +# Voyager v2022.02.22 (2022-02-18) + + +## [voyagermesh/apimachinery](https://github.com/voyagermesh/apimachinery) + +### [v0.4.0](https://github.com/voyagermesh/apimachinery/releases/tag/v0.4.0) + +- [1f3d5fa1](https://github.com/voyagermesh/apimachinery/commit/1f3d5fa1) Update SiteInfo (#24) +- [54c9652d](https://github.com/voyagermesh/apimachinery/commit/54c9652d) Update repository config (#23) + + + +## [voyagermesh/cli](https://github.com/voyagermesh/cli) + +### [v0.0.6](https://github.com/voyagermesh/cli/releases/tag/v0.0.6) + +- [0adaf81](https://github.com/voyagermesh/cli/commit/0adaf81) Prepare for release v0.0.6 (#5) + + + +## [voyagermesh/haproxy-ingress](https://github.com/voyagermesh/haproxy-ingress) + +### [v14.2.0](https://github.com/voyagermesh/haproxy-ingress/releases/tag/v14.2.0) + +- [1e0fe986](https://github.com/voyagermesh/haproxy-ingress/commit/1e0fe986) Prepare for release v14.2.0 (#41) +- [42297611](https://github.com/voyagermesh/haproxy-ingress/commit/42297611) Publish GenericResource event (#40) +- [90e4b8c3](https://github.com/voyagermesh/haproxy-ingress/commit/90e4b8c3) Update SiteInfo (#39) + + + +## [voyagermesh/installer](https://github.com/voyagermesh/installer) + +### [v2022.02.22](https://github.com/voyagermesh/installer/releases/tag/v2022.02.22) + +- [ee7b622](https://github.com/voyagermesh/installer/commit/ee7b622) Prepare for release v2022.02.22 (#105) +- [bfb6acb](https://github.com/voyagermesh/installer/commit/bfb6acb) Update repository config (#104) +- [c171823](https://github.com/voyagermesh/installer/commit/c171823) Use well-known os label (#103) +- [d1d214e](https://github.com/voyagermesh/installer/commit/d1d214e) Update SiteInfo (#102) + + + + diff --git a/content/docs/v2024.3.18/CHANGELOG-v2022.03.17.md b/content/docs/v2024.3.18/CHANGELOG-v2022.03.17.md new file mode 100644 index 000000000..81003a285 --- /dev/null +++ b/content/docs/v2024.3.18/CHANGELOG-v2022.03.17.md @@ -0,0 +1,60 @@ +--- +title: Changelog | Voyager +description: Changelog +menu: + docs_v2024.3.18: + identifier: changelog-voyager-v2022.03.17 + name: Changelog-v2022.03.17 + parent: welcome + weight: 20220317 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: welcome +url: /docs/v2024.3.18/welcome/changelog-v2022.03.17/ +aliases: +- /docs/v2024.3.18/CHANGELOG-v2022.03.17/ +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +# Voyager v2022.03.17 (2022-03-17) + + +## [voyagermesh/cli](https://github.com/voyagermesh/cli) + +### [v0.0.7](https://github.com/voyagermesh/cli/releases/tag/v0.0.7) + +- [16d852a](https://github.com/voyagermesh/cli/commit/16d852a) Prepare for release v0.0.7 (#8) +- [8b0b309](https://github.com/voyagermesh/cli/commit/8b0b309) Build darwin/arm64 images +- [b68c523](https://github.com/voyagermesh/cli/commit/b68c523) Use Go 1.18 (#7) +- [0bc96a7](https://github.com/voyagermesh/cli/commit/0bc96a7) make fmt (#6) + + + +## [voyagermesh/haproxy-ingress](https://github.com/voyagermesh/haproxy-ingress) + +### [v14.2.1](https://github.com/voyagermesh/haproxy-ingress/releases/tag/v14.2.1) + +- [73961286](https://github.com/voyagermesh/haproxy-ingress/commit/73961286) Prepare for release v14.2.1 (#46) +- [c9319f58](https://github.com/voyagermesh/haproxy-ingress/commit/c9319f58) Use Go 1.18 (#43) +- [56e996e9](https://github.com/voyagermesh/haproxy-ingress/commit/56e996e9) Fix CVEs reported in trivy scanner (#45) +- [6609a2e3](https://github.com/voyagermesh/haproxy-ingress/commit/6609a2e3) git submodule updated +- [cc3ccde8](https://github.com/voyagermesh/haproxy-ingress/commit/cc3ccde8) make fmt (#42) + + + +## [voyagermesh/installer](https://github.com/voyagermesh/installer) + +### [v2022.03.17](https://github.com/voyagermesh/installer/releases/tag/v2022.03.17) + +- [f9d677a](https://github.com/voyagermesh/installer/commit/f9d677a) Prepare for release v2022.03.17 (#109) +- [a1e348f](https://github.com/voyagermesh/installer/commit/a1e348f) Use k8s 1.23.3 in ci +- [e1f4155](https://github.com/voyagermesh/installer/commit/e1f4155) Use Go 1.18 (#107) +- [68be613](https://github.com/voyagermesh/installer/commit/68be613) Fix chart schema (#108) +- [4bcfebc](https://github.com/voyagermesh/installer/commit/4bcfebc) make fmt (#106) + + + + diff --git a/content/docs/v2024.3.18/CHANGELOG-v2022.04.13.md b/content/docs/v2024.3.18/CHANGELOG-v2022.04.13.md new file mode 100644 index 000000000..d929db0d5 --- /dev/null +++ b/content/docs/v2024.3.18/CHANGELOG-v2022.04.13.md @@ -0,0 +1,58 @@ +--- +title: Changelog | Voyager +description: Changelog +menu: + docs_v2024.3.18: + identifier: changelog-voyager-v2022.04.13 + name: Changelog-v2022.04.13 + parent: welcome + weight: 20220413 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: welcome +url: /docs/v2024.3.18/welcome/changelog-v2022.04.13/ +aliases: +- /docs/v2024.3.18/CHANGELOG-v2022.04.13/ +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +# Voyager v2022.04.13 (2022-04-14) + + +## [voyagermesh/apimachinery](https://github.com/voyagermesh/apimachinery) + +### [v0.4.2](https://github.com/voyagermesh/apimachinery/releases/tag/v0.4.2) + +- [0eb8cb31](https://github.com/voyagermesh/apimachinery/commit/0eb8cb31) Use Go 1.18 (#27) + + + +## [voyagermesh/cli](https://github.com/voyagermesh/cli) + +### [v0.0.8](https://github.com/voyagermesh/cli/releases/tag/v0.0.8) + +- [70b38ac](https://github.com/voyagermesh/cli/commit/70b38ac) Prepare for release v0.0.8 (#9) + + + +## [voyagermesh/haproxy-ingress](https://github.com/voyagermesh/haproxy-ingress) + +### [v14.2.2](https://github.com/voyagermesh/haproxy-ingress/releases/tag/v14.2.2) + +- [8182f293](https://github.com/voyagermesh/haproxy-ingress/commit/8182f293) Prepare for release v14.2.2 (#47) +- [91478824](https://github.com/voyagermesh/haproxy-ingress/commit/91478824) Add scanner + + + +## [voyagermesh/installer](https://github.com/voyagermesh/installer) + +### [v2022.04.13](https://github.com/voyagermesh/installer/releases/tag/v2022.04.13) + +- [2172ee0](https://github.com/voyagermesh/installer/commit/2172ee0) Prepare for release v2022.04.13 (#110) + + + + diff --git a/content/docs/v2024.3.18/CHANGELOG-v2022.06.20.md b/content/docs/v2024.3.18/CHANGELOG-v2022.06.20.md new file mode 100644 index 000000000..64148d1b3 --- /dev/null +++ b/content/docs/v2024.3.18/CHANGELOG-v2022.06.20.md @@ -0,0 +1,67 @@ +--- +title: Changelog | Voyager +description: Changelog +menu: + docs_v2024.3.18: + identifier: changelog-voyager-v2022.06.20 + name: Changelog-v2022.06.20 + parent: welcome + weight: 20220620 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: welcome +url: /docs/v2024.3.18/welcome/changelog-v2022.06.20/ +aliases: +- /docs/v2024.3.18/CHANGELOG-v2022.06.20/ +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +# Voyager v2022.06.20 (2022-06-17) + + +## [voyagermesh/apimachinery](https://github.com/voyagermesh/apimachinery) + +### [v0.5.0](https://github.com/voyagermesh/apimachinery/releases/tag/v0.5.0) + +- [9a6e26b7](https://github.com/voyagermesh/apimachinery/commit/9a6e26b7) Update to k8s 1.24 toolchain (#29) +- [6bfee384](https://github.com/voyagermesh/apimachinery/commit/6bfee384) Test against Kubernetes 1.24.0 (#28) + + + +## [voyagermesh/cli](https://github.com/voyagermesh/cli) + +### [v0.0.9](https://github.com/voyagermesh/cli/releases/tag/v0.0.9) + +- [696408d](https://github.com/voyagermesh/cli/commit/696408d) Prepare for release v0.0.9 (#11) +- [7b82992](https://github.com/voyagermesh/cli/commit/7b82992) Update to k8s 1.24 toolchain (#10) + + + +## [voyagermesh/haproxy-ingress](https://github.com/voyagermesh/haproxy-ingress) + +### [v15.0.0](https://github.com/voyagermesh/haproxy-ingress/releases/tag/v15.0.0) + +- [b9b68401](https://github.com/voyagermesh/haproxy-ingress/commit/b9b684018) Prepare for release v15.0.0 (#51) +- [804b350d](https://github.com/voyagermesh/haproxy-ingress/commit/804b350d9) Fix port detection for external name type service (#50) +- [126137a9](https://github.com/voyagermesh/haproxy-ingress/commit/126137a90) Fix CVE-2022-1586 CVE-2022-1587 +- [0a61fc9c](https://github.com/voyagermesh/haproxy-ingress/commit/0a61fc9c4) Update to k8s 1.24 toolchain (#49) +- [46b78cfe](https://github.com/voyagermesh/haproxy-ingress/commit/46b78cfed) Test against Kubernetes 1.24.0 (#48) + + + +## [voyagermesh/installer](https://github.com/voyagermesh/installer) + +### [v2022.06.20](https://github.com/voyagermesh/installer/releases/tag/v2022.06.20) + +- [61e1f75](https://github.com/voyagermesh/installer/commit/61e1f75) Prepare for release v2022.06.20 (#113) +- [d207168](https://github.com/voyagermesh/installer/commit/d207168) Get operator from chart appVersion +- [9bc4b6c](https://github.com/voyagermesh/installer/commit/9bc4b6c) Update to k8s 1.24 toolchain (#112) +- [84ab347](https://github.com/voyagermesh/installer/commit/84ab347) Test against Kubernetes 1.24.0 (#111) +- [02028da](https://github.com/voyagermesh/installer/commit/02028da) Change MY_POD_ env prefix to POD_ + + + + diff --git a/content/docs/v2024.3.18/CHANGELOG-v2022.08.17.md b/content/docs/v2024.3.18/CHANGELOG-v2022.08.17.md new file mode 100644 index 000000000..917de4d0e --- /dev/null +++ b/content/docs/v2024.3.18/CHANGELOG-v2022.08.17.md @@ -0,0 +1,62 @@ +--- +title: Changelog | Voyager +description: Changelog +menu: + docs_v2024.3.18: + identifier: changelog-voyager-v2022.08.17 + name: Changelog-v2022.08.17 + parent: welcome + weight: 20220817 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: welcome +url: /docs/v2024.3.18/welcome/changelog-v2022.08.17/ +aliases: +- /docs/v2024.3.18/CHANGELOG-v2022.08.17/ +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +# Voyager v2022.08.17 (2022-08-17) + + +## [voyagermesh/apimachinery](https://github.com/voyagermesh/apimachinery) + +### [v0.6.0](https://github.com/voyagermesh/apimachinery/releases/tag/v0.6.0) + +- [b0448934](https://github.com/voyagermesh/apimachinery/commit/b0448934) Use k8s 1.25 libs (#30) + + + +## [voyagermesh/cli](https://github.com/voyagermesh/cli) + +### [v0.0.10](https://github.com/voyagermesh/cli/releases/tag/v0.0.10) + +- [e5c1876](https://github.com/voyagermesh/cli/commit/e5c1876) Prepare for release v0.0.10 (#13) +- [865f31f](https://github.com/voyagermesh/cli/commit/865f31f) Use k8s 1.25 libs (#12) + + + +## [voyagermesh/haproxy-ingress](https://github.com/voyagermesh/haproxy-ingress) + +### [v16.0.0](https://github.com/voyagermesh/haproxy-ingress/releases/tag/v16.0.0) + +- [c4dcbf00](https://github.com/voyagermesh/haproxy-ingress/commit/c4dcbf001) Prepare for release v16.0.0 (#53) +- [65d5fa3f](https://github.com/voyagermesh/haproxy-ingress/commit/65d5fa3fb) Use HAProxy 2.6 +- [fae4ad3a](https://github.com/voyagermesh/haproxy-ingress/commit/fae4ad3a5) Use k8s 1.25 libs (#52) + + + +## [voyagermesh/installer](https://github.com/voyagermesh/installer) + +### [v2022.08.17](https://github.com/voyagermesh/installer/releases/tag/v2022.08.17) + +- [9725acc](https://github.com/voyagermesh/installer/commit/9725acc) Prepare for release v2022.08.17 (#116) +- [eaf13e0](https://github.com/voyagermesh/installer/commit/eaf13e0) Use k8s 1.25 libs (#115) +- [29170d3](https://github.com/voyagermesh/installer/commit/29170d3) Add permission for license-proxyserver (#114) + + + + diff --git a/content/docs/v2024.3.18/CHANGELOG-v2022.12.11.md b/content/docs/v2024.3.18/CHANGELOG-v2022.12.11.md new file mode 100644 index 000000000..319c78adc --- /dev/null +++ b/content/docs/v2024.3.18/CHANGELOG-v2022.12.11.md @@ -0,0 +1,75 @@ +--- +title: Changelog | Voyager +description: Changelog +menu: + docs_v2024.3.18: + identifier: changelog-voyager-v2022.12.11 + name: Changelog-v2022.12.11 + parent: welcome + weight: 20221211 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: welcome +url: /docs/v2024.3.18/welcome/changelog-v2022.12.11/ +aliases: +- /docs/v2024.3.18/CHANGELOG-v2022.12.11/ +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +# Voyager v2022.12.11 (2022-12-10) + + +## [voyagermesh/apimachinery](https://github.com/voyagermesh/apimachinery) + +### [v0.7.0](https://github.com/voyagermesh/apimachinery/releases/tag/v0.7.0) + +- [03ca8808](https://github.com/voyagermesh/apimachinery/commit/03ca8808) Update deps +- [6e495f8a](https://github.com/voyagermesh/apimachinery/commit/6e495f8a) Run GH actions on ubuntu-20.04 (#34) +- [e54c78b8](https://github.com/voyagermesh/apimachinery/commit/e54c78b8) Test against Kubernetes 1.25.0 (#33) +- [aaa19a94](https://github.com/voyagermesh/apimachinery/commit/aaa19a94) Use Go 1.19 (#32) +- [11bcee3c](https://github.com/voyagermesh/apimachinery/commit/11bcee3c) Use k8s 1.25.1 libs (#31) + + + +## [voyagermesh/cli](https://github.com/voyagermesh/cli) + +### [v0.0.11](https://github.com/voyagermesh/cli/releases/tag/v0.0.11) + +- [ee6eb0d](https://github.com/voyagermesh/cli/commit/ee6eb0d) Prepare for release v0.0.11 (#17) +- [7bf2e36](https://github.com/voyagermesh/cli/commit/7bf2e36) Run GH actions on ubuntu-20.04 (#16) +- [d597ca1](https://github.com/voyagermesh/cli/commit/d597ca1) Stop using ioutil (#15) +- [38e08ab](https://github.com/voyagermesh/cli/commit/38e08ab) Use k8s 1.25.1 libs (#14) + + + +## [voyagermesh/haproxy-ingress](https://github.com/voyagermesh/haproxy-ingress) + +### [v17.0.0](https://github.com/voyagermesh/haproxy-ingress/releases/tag/v17.0.0) + +- [b9e3daaa](https://github.com/voyagermesh/haproxy-ingress/commit/b9e3daaa4) Prepare for release v17.0.0 (#59) +- [cf06e700](https://github.com/voyagermesh/haproxy-ingress/commit/cf06e700c) Remove vulnerable deps +- [3370de4f](https://github.com/voyagermesh/haproxy-ingress/commit/3370de4f0) Run GH actions on ubuntu-20.04 (#58) +- [ccaa9278](https://github.com/voyagermesh/haproxy-ingress/commit/ccaa9278e) Acquire license from proxyserver (#57) +- [3b86fefe](https://github.com/voyagermesh/haproxy-ingress/commit/3b86fefef) Update KIND (#56) +- [a407ff28](https://github.com/voyagermesh/haproxy-ingress/commit/a407ff284) Use Go 1.19 (#55) +- [d53c24dc](https://github.com/voyagermesh/haproxy-ingress/commit/d53c24dce) Use k8s 1.25.1 libs (#54) +- [c9db24b2](https://github.com/voyagermesh/haproxy-ingress/commit/c9db24b25) Fix CVE-2022-27664 + + + +## [voyagermesh/installer](https://github.com/voyagermesh/installer) + +### [v2022.12.11](https://github.com/voyagermesh/installer/releases/tag/v2022.12.11) + +- [d8dd39f](https://github.com/voyagermesh/installer/commit/d8dd39f) Prepare for release v2022.12.11 (#120) +- [0f1c6c1](https://github.com/voyagermesh/installer/commit/0f1c6c1) Update kubectl version +- [8decf70](https://github.com/voyagermesh/installer/commit/8decf70) Run GH actions on ubuntu-20.04 (#119) +- [cd18ec8](https://github.com/voyagermesh/installer/commit/cd18ec8) Test against Kubernetes 1.25.0 (#118) +- [18fefdf](https://github.com/voyagermesh/installer/commit/18fefdf) Use Go 1.19 (#117) + + + + diff --git a/content/docs/v2024.3.18/CHANGELOG-v2023.02.22.md b/content/docs/v2024.3.18/CHANGELOG-v2023.02.22.md new file mode 100644 index 000000000..579ae582a --- /dev/null +++ b/content/docs/v2024.3.18/CHANGELOG-v2023.02.22.md @@ -0,0 +1,62 @@ +--- +title: Changelog | Voyager +description: Changelog +menu: + docs_v2024.3.18: + identifier: changelog-voyager-v2023.02.22 + name: Changelog-v2023.02.22 + parent: welcome + weight: 20230222 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: welcome +url: /docs/v2024.3.18/welcome/changelog-v2023.02.22/ +aliases: +- /docs/v2024.3.18/CHANGELOG-v2023.02.22/ +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +# Voyager v2023.02.22 (2023-02-23) + + +## [voyagermesh/apimachinery](https://github.com/voyagermesh/apimachinery) + +### [v0.7.1](https://github.com/voyagermesh/apimachinery/releases/tag/v0.7.1) + +- [8aa11417](https://github.com/voyagermesh/apimachinery/commit/8aa11417) Update dependencies (#35) + + + +## [voyagermesh/cli](https://github.com/voyagermesh/cli) + +### [v0.0.12](https://github.com/voyagermesh/cli/releases/tag/v0.0.12) + +- [4e9c89e](https://github.com/voyagermesh/cli/commit/4e9c89e) Prepare for release v0.0.12 (#18) + + + +## [voyagermesh/haproxy-ingress](https://github.com/voyagermesh/haproxy-ingress) + +### [v17.0.1](https://github.com/voyagermesh/haproxy-ingress/releases/tag/v17.0.1) + +- [663cfff4](https://github.com/voyagermesh/haproxy-ingress/commit/663cfff4b) Prepare for release v17.0.1 (#61) +- [7aa174bc](https://github.com/voyagermesh/haproxy-ingress/commit/7aa174bc7) Update dependencies +- [ece0471a](https://github.com/voyagermesh/haproxy-ingress/commit/ece0471ae) Update submodules +- [ea8416d3](https://github.com/voyagermesh/haproxy-ingress/commit/ea8416d32) Fix NPE using licenseproxy-server (#60) +- [e65b1682](https://github.com/voyagermesh/haproxy-ingress/commit/e65b16829) Fix NPE using licenseproxy-server (#60) + + + +## [voyagermesh/installer](https://github.com/voyagermesh/installer) + +### [v2023.02.22](https://github.com/voyagermesh/installer/releases/tag/v2023.02.22) + +- [e1d3789](https://github.com/voyagermesh/installer/commit/e1d3789) Prepare for release v2023.02.22 (#121) +- [7451bba](https://github.com/voyagermesh/installer/commit/7451bba) Publish helm charts as OCI artifacts + + + + diff --git a/content/docs/v2024.3.18/CHANGELOG-v2023.05.16.md b/content/docs/v2024.3.18/CHANGELOG-v2023.05.16.md new file mode 100644 index 000000000..483dba9e7 --- /dev/null +++ b/content/docs/v2024.3.18/CHANGELOG-v2023.05.16.md @@ -0,0 +1,78 @@ +--- +title: Changelog | Voyager +description: Changelog +menu: + docs_v2024.3.18: + identifier: changelog-voyager-v2023.05.16 + name: Changelog-v2023.05.16 + parent: welcome + weight: 20230516 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: welcome +url: /docs/v2024.3.18/welcome/changelog-v2023.05.16/ +aliases: +- /docs/v2024.3.18/CHANGELOG-v2023.05.16/ +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +# Voyager v2023.05.16 (2023-05-16) + + +## [voyagermesh/apimachinery](https://github.com/voyagermesh/apimachinery) + +### [v0.7.2](https://github.com/voyagermesh/apimachinery/releases/tag/v0.7.2) + +- [d3eab942](https://github.com/voyagermesh/apimachinery/commit/d3eab942) Update deps +- [d741654b](https://github.com/voyagermesh/apimachinery/commit/d741654b) Test against K8s 1.27.1 (#40) +- [f17a74a0](https://github.com/voyagermesh/apimachinery/commit/f17a74a0) Use uid 65534 and test against K8s 1.27.0 (#39) +- [5313fa2b](https://github.com/voyagermesh/apimachinery/commit/5313fa2b) Use ghcr.io/appscode/gengo (#38) +- [3cf19792](https://github.com/voyagermesh/apimachinery/commit/3cf19792) Use ghcr.io for appscode/golang-dev (#37) +- [882d1506](https://github.com/voyagermesh/apimachinery/commit/882d1506) Update wrokflows (Go 1.20, k8s 1.26) (#36) + + + +## [voyagermesh/cli](https://github.com/voyagermesh/cli) + +### [v0.0.13](https://github.com/voyagermesh/cli/releases/tag/v0.0.13) + +- [8941c49](https://github.com/voyagermesh/cli/commit/8941c49) Prepare for release v0.0.13 (#21) +- [2704ce0](https://github.com/voyagermesh/cli/commit/2704ce0) Use ghcr.io for appscode/golang-dev (#20) +- [c059723](https://github.com/voyagermesh/cli/commit/c059723) Update wrokflows (Go 1.20, k8s 1.26) (#19) + + + +## [voyagermesh/haproxy-ingress](https://github.com/voyagermesh/haproxy-ingress) + +### [v17.0.2](https://github.com/voyagermesh/haproxy-ingress/releases/tag/v17.0.2) + +- [e1ec6dc2](https://github.com/voyagermesh/haproxy-ingress/commit/e1ec6dc2b) Prepare for release v17.0.2 (#66) +- [50755363](https://github.com/voyagermesh/haproxy-ingress/commit/50755363b) Use HAProxy 2.6.12 (#65) +- [ad1af389](https://github.com/voyagermesh/haproxy-ingress/commit/ad1af389d) Publish to ghcr.io (#64) +- [b52228b5](https://github.com/voyagermesh/haproxy-ingress/commit/b52228b56) Add docker image label +- [dcde7f21](https://github.com/voyagermesh/haproxy-ingress/commit/dcde7f21f) Use ghcr.io for appscode/golang-dev (#63) +- [f46f506d](https://github.com/voyagermesh/haproxy-ingress/commit/f46f506da) Update wrokflows (Go 1.20, k8s 1.26) (#62) + + + +## [voyagermesh/installer](https://github.com/voyagermesh/installer) + +### [v2023.05.16](https://github.com/voyagermesh/installer/releases/tag/v2023.05.16) + +- [fabe300](https://github.com/voyagermesh/installer/commit/fabe300) Prepare for release v2023.05.16 (#131) +- [1f818ff](https://github.com/voyagermesh/installer/commit/1f818ff) Use kubectl 1.24 +- [f1f56c3](https://github.com/voyagermesh/installer/commit/f1f56c3) Test against K8s 1.27.1 (#130) +- [fa3a42c](https://github.com/voyagermesh/installer/commit/fa3a42c) Use uid 65534 and test against K8s 1.27.0 (#129) +- [59d0d9a](https://github.com/voyagermesh/installer/commit/59d0d9a) Use ghcr.io/appscode/gengo (#128) +- [f2ffd5a](https://github.com/voyagermesh/installer/commit/f2ffd5a) Stop publishing oci images to docker hub +- [9ef2b81](https://github.com/voyagermesh/installer/commit/9ef2b81) Use ghcr.io (#127) +- [c44f262](https://github.com/voyagermesh/installer/commit/c44f262) Use ghcr.io for appscode/golang-dev (#126) +- [d40e2fb](https://github.com/voyagermesh/installer/commit/d40e2fb) Update workflows (Go 1.20, k8s 1.26) (#125) +- [371fe3f](https://github.com/voyagermesh/installer/commit/371fe3f) Update wrokflows (Go 1.20, k8s 1.26) (#124) + + + + diff --git a/content/docs/v2024.3.18/CHANGELOG-v2023.9.18.md b/content/docs/v2024.3.18/CHANGELOG-v2023.9.18.md new file mode 100644 index 000000000..9b7822d28 --- /dev/null +++ b/content/docs/v2024.3.18/CHANGELOG-v2023.9.18.md @@ -0,0 +1,68 @@ +--- +title: Changelog | Voyager +description: Changelog +menu: + docs_v2024.3.18: + identifier: changelog-voyager-v2023.9.18 + name: Changelog-v2023.9.18 + parent: welcome + weight: 20230918 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: welcome +url: /docs/v2024.3.18/welcome/changelog-v2023.9.18/ +aliases: +- /docs/v2024.3.18/CHANGELOG-v2023.9.18/ +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +# Voyager v2023.9.18 (2023-09-17) + + +## [voyagermesh/apimachinery](https://github.com/voyagermesh/apimachinery) + +### [v0.7.3](https://github.com/voyagermesh/apimachinery/releases/tag/v0.7.3) + +- [7a511cc9](https://github.com/voyagermesh/apimachinery/commit/7a511cc9) Support custom ssl chipher annotation +- [757c19c1](https://github.com/voyagermesh/apimachinery/commit/757c19c1) Update license verifier (#41) + + + +## [voyagermesh/cli](https://github.com/voyagermesh/cli) + +### [v0.0.14](https://github.com/voyagermesh/cli/releases/tag/v0.0.14) + +- [d137c94](https://github.com/voyagermesh/cli/commit/d137c94) Prepare for release v0.0.14 (#22) + + + +## [voyagermesh/haproxy-ingress](https://github.com/voyagermesh/haproxy-ingress) + +### [v17.0.3](https://github.com/voyagermesh/haproxy-ingress/releases/tag/v17.0.3) + +- [8ac3587f](https://github.com/voyagermesh/haproxy-ingress/commit/8ac3587fb) Prepare for release v17.0.3 (#70) +- [0c7e59b3](https://github.com/voyagermesh/haproxy-ingress/commit/0c7e59b35) update haproxy template +- [f97e23e0](https://github.com/voyagermesh/haproxy-ingress/commit/f97e23e0d) Support custom ssl chipher (#69) +- [e461f0bc](https://github.com/voyagermesh/haproxy-ingress/commit/e461f0bc2) Update license verifier (#67) +- [5f4fb903](https://github.com/voyagermesh/haproxy-ingress/commit/5f4fb9032) Delete docker image is commit is not tagged + + + +## [voyagermesh/installer](https://github.com/voyagermesh/installer) + +### [v2023.9.18](https://github.com/voyagermesh/installer/releases/tag/v2023.9.18) + +- [7189d8a](https://github.com/voyagermesh/installer/commit/7189d8a) Prepare for release v2023.9.18 (#135) +- [2216fd3](https://github.com/voyagermesh/installer/commit/2216fd3) Handle charts without doc.yaml +- [576f837](https://github.com/voyagermesh/installer/commit/576f837) Update gateway 0.5.0 crds +- [8044712](https://github.com/voyagermesh/installer/commit/8044712) Use gateway v0.0.2 +- [2bc3aa6](https://github.com/voyagermesh/installer/commit/2bc3aa6) Upgrade to release/v0.5 (#134) +- [7fafdeb](https://github.com/voyagermesh/installer/commit/7fafdeb) Remove non crd objects from crds folder +- [677b93d](https://github.com/voyagermesh/installer/commit/677b93d) Use helm repo version + + + + diff --git a/content/docs/v2024.3.18/CHANGELOG-v2024.3.18.md b/content/docs/v2024.3.18/CHANGELOG-v2024.3.18.md new file mode 100644 index 000000000..76129eb8d --- /dev/null +++ b/content/docs/v2024.3.18/CHANGELOG-v2024.3.18.md @@ -0,0 +1,71 @@ +--- +title: Changelog | Voyager +description: Changelog +menu: + docs_v2024.3.18: + identifier: changelog-voyager-v2024.3.18 + name: Changelog-v2024.3.18 + parent: welcome + weight: 20240318 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: welcome +url: /docs/v2024.3.18/welcome/changelog-v2024.3.18/ +aliases: +- /docs/v2024.3.18/CHANGELOG-v2024.3.18/ +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +# Voyager v2024.3.18 (2024-03-18) + + +## [voyagermesh/apimachinery](https://github.com/voyagermesh/apimachinery) + +### [v0.8.0](https://github.com/voyagermesh/apimachinery/releases/tag/v0.8.0) + +- [5baa586c](https://github.com/voyagermesh/apimachinery/commit/5baa586c) Update deps +- [dbb90e92](https://github.com/voyagermesh/apimachinery/commit/dbb90e92) Use Go 1.22 (#45) +- [d50e1045](https://github.com/voyagermesh/apimachinery/commit/d50e1045) Update deps (#44) +- [b98cecb9](https://github.com/voyagermesh/apimachinery/commit/b98cecb9) Use k8s 1.29 client libs (#43) +- [06618b9e](https://github.com/voyagermesh/apimachinery/commit/06618b9e) Update deps + + + +## [voyagermesh/cli](https://github.com/voyagermesh/cli) + +### [v0.0.15](https://github.com/voyagermesh/cli/releases/tag/v0.0.15) + +- [99baac8](https://github.com/voyagermesh/cli/commit/99baac8) Prepare for release v0.0.15 (#24) +- [586acaf](https://github.com/voyagermesh/cli/commit/586acaf) Use Go 1.22 (#23) + + + +## [voyagermesh/haproxy-ingress](https://github.com/voyagermesh/haproxy-ingress) + +### [v17.1.0](https://github.com/voyagermesh/haproxy-ingress/releases/tag/v17.1.0) + +- [04b22e90](https://github.com/voyagermesh/haproxy-ingress/commit/04b22e905) Prepare for release v17.1.0 (#83) +- [d12ccf31](https://github.com/voyagermesh/haproxy-ingress/commit/d12ccf311) Use haproxy 2.6.16 +- [90e5842a](https://github.com/voyagermesh/haproxy-ingress/commit/90e5842af) Update deps +- [8ce183c7](https://github.com/voyagermesh/haproxy-ingress/commit/8ce183c7d) Use Go 1.22 (#82) +- [4ed0abc5](https://github.com/voyagermesh/haproxy-ingress/commit/4ed0abc5f) Update deps (#79) +- [c43d785c](https://github.com/voyagermesh/haproxy-ingress/commit/c43d785cd) Use k8s 1.29 client libs (#76) +- [a832564a](https://github.com/voyagermesh/haproxy-ingress/commit/a832564ad) Send hourly audit events (#75) +- [d2b57c9d](https://github.com/voyagermesh/haproxy-ingress/commit/d2b57c9da) Update deps +- [664aa057](https://github.com/voyagermesh/haproxy-ingress/commit/664aa0578) Disable cleanup of image + + + +## [voyagermesh/installer](https://github.com/voyagermesh/installer) + +### [v2024.3.18](https://github.com/voyagermesh/installer/releases/tag/v2024.3.18) + +- [32154e1](https://github.com/voyagermesh/installer/commit/32154e1) Prepare for release v2024.3.18 (#139) +- [18d19e2](https://github.com/voyagermesh/installer/commit/18d19e2) Use Go 1.22 (#138) + + + + diff --git a/content/docs/v2024.3.18/CHANGELOG.md b/content/docs/v2024.3.18/CHANGELOG.md new file mode 100644 index 000000000..a6899d410 --- /dev/null +++ b/content/docs/v2024.3.18/CHANGELOG.md @@ -0,0 +1,2193 @@ +--- +title: Changelog | Voyager +description: Changelog +menu: + docs_v2024.3.18: + identifier: changelog-voyager + name: Changelog + parent: welcome + weight: 10 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: welcome +url: /docs/v2024.3.18/welcome/changelog/ +aliases: +- /docs/v2024.3.18/CHANGELOG/ +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +# Change Log + +## [v13.0.0-beta.1](https://github.com/voyagermesh/voyager/tree/v13.0.0-beta.1) (2020-05-26) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/v13.0.0-beta.0...v13.0.0-beta.1) + +**Merged pull requests:** + +- Prepare release v13.0.0-beta.1 [\#1512](https://github.com/voyagermesh/voyager/pull/1512) ([tamalsaha](https://github.com/tamalsaha)) +- Generate both v1beta1 and v1 CRD YAML [\#1511](https://github.com/voyagermesh/voyager/pull/1511) ([tamalsaha](https://github.com/tamalsaha)) + +## [v13.0.0-beta.0](https://github.com/voyagermesh/voyager/tree/v13.0.0-beta.0) (2020-05-22) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/v12.0.0...v13.0.0-beta.0) + +**Closed issues:** + +- README.md documentation links are broken [\#1506](https://github.com/voyagermesh/voyager/issues/1506) +- v12 release? [\#1492](https://github.com/voyagermesh/voyager/issues/1492) + +**Merged pull requests:** + +- Prepare release v13.0.0-beta.0 [\#1510](https://github.com/voyagermesh/voyager/pull/1510) ([tamalsaha](https://github.com/tamalsaha)) +- Update to Kubernetes v1.18.3 [\#1509](https://github.com/voyagermesh/voyager/pull/1509) ([tamalsaha](https://github.com/tamalsaha)) +- Fix README.md documentation links [\#1507](https://github.com/voyagermesh/voyager/pull/1507) ([RobertKirk](https://github.com/RobertKirk)) + +## [v12.0.0](https://github.com/voyagermesh/voyager/tree/v12.0.0) (2020-05-18) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/v12.0.0-rc.2...v12.0.0) + +**Closed issues:** + +- voyager helm install failed for version v12.0.0-rc.2 [\#1501](https://github.com/voyagermesh/voyager/issues/1501) +- Automatic certificate renewal didn't occur [\#1443](https://github.com/voyagermesh/voyager/issues/1443) + +**Merged pull requests:** + +- Fix Update\*\*\*Status helpers [\#1505](https://github.com/voyagermesh/voyager/pull/1505) ([tamalsaha](https://github.com/tamalsaha)) +- Use recommended kubernetes app labels [\#1504](https://github.com/voyagermesh/voyager/pull/1504) ([tamalsaha](https://github.com/tamalsaha)) +- Correctly load \(HAProxy|Exporter\)ImageRepository options [\#1503](https://github.com/voyagermesh/voyager/pull/1503) ([RobertKirk](https://github.com/RobertKirk)) +- Change go module to voyagermesh.dev/voyager [\#1500](https://github.com/voyagermesh/voyager/pull/1500) ([tamalsaha](https://github.com/tamalsaha)) +- Update repository location [\#1499](https://github.com/voyagermesh/voyager/pull/1499) ([tamalsaha](https://github.com/tamalsaha)) + +## [v12.0.0-rc.2](https://github.com/voyagermesh/voyager/tree/v12.0.0-rc.2) (2020-04-25) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/v12.0.0-rc.1...v12.0.0-rc.2) + +**Closed issues:** + +- Voyager operator continue crash forbidden permission [\#1483](https://github.com/voyagermesh/voyager/issues/1483) +- Allow option to set Docker repository for HAProxy and Exporter images [\#1449](https://github.com/voyagermesh/voyager/issues/1449) + +**Merged pull requests:** + +- Build HAProxy images from Makefile [\#1498](https://github.com/voyagermesh/voyager/pull/1498) ([tamalsaha](https://github.com/tamalsaha)) +- Use BASH\_SOURCE to calculate $REPO\_ROOT [\#1497](https://github.com/voyagermesh/voyager/pull/1497) ([tamalsaha](https://github.com/tamalsaha)) +- Update CHANGELOG.md [\#1496](https://github.com/voyagermesh/voyager/pull/1496) ([tamalsaha](https://github.com/tamalsaha)) +- Security: Upgrade to HAProxy 1.19.15 [\#1495](https://github.com/voyagermesh/voyager/pull/1495) ([tamalsaha](https://github.com/tamalsaha)) +- Add rbac permissions for statefulset [\#1494](https://github.com/voyagermesh/voyager/pull/1494) ([tamalsaha](https://github.com/tamalsaha)) +- Apply various fixes to chart [\#1493](https://github.com/voyagermesh/voyager/pull/1493) ([tamalsaha](https://github.com/tamalsaha)) +- Haproxy exporter image repository [\#1491](https://github.com/voyagermesh/voyager/pull/1491) ([RobertKirk](https://github.com/RobertKirk)) +- Add missing ingresses/status resource to operator ClusterRole [\#1488](https://github.com/voyagermesh/voyager/pull/1488) ([aletundo](https://github.com/aletundo)) +- Bump cloud.google.com/go to get timeout fix [\#1487](https://github.com/voyagermesh/voyager/pull/1487) ([joshk0](https://github.com/joshk0)) +- Never exit certificates renewal infinite loop [\#1486](https://github.com/voyagermesh/voyager/pull/1486) ([jayjun](https://github.com/jayjun)) +- workload-kind support StatefulSet [\#1482](https://github.com/voyagermesh/voyager/pull/1482) ([kuring](https://github.com/kuring)) +- Add restrict-to-operator-namespace flag [\#1481](https://github.com/voyagermesh/voyager/pull/1481) ([mazzy89](https://github.com/mazzy89)) +- Allow specifying rather than generating certs [\#1479](https://github.com/voyagermesh/voyager/pull/1479) ([tamalsaha](https://github.com/tamalsaha)) +- Refactor CI pipeline to build once. [\#1476](https://github.com/voyagermesh/voyager/pull/1476) ([tamalsaha](https://github.com/tamalsaha)) +- Bring back support for k8s 1.11 [\#1475](https://github.com/voyagermesh/voyager/pull/1475) ([tamalsaha](https://github.com/tamalsaha)) +- Use node\[0\]'s internal ip as minikube ip [\#1474](https://github.com/voyagermesh/voyager/pull/1474) ([tamalsaha](https://github.com/tamalsaha)) + +## [v12.0.0-rc.1](https://github.com/voyagermesh/voyager/tree/v12.0.0-rc.1) (2020-01-03) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/v12.0.0-rc.0...v12.0.0-rc.1) + +**Closed issues:** + +- Voyager stops with Fatal [\#1471](https://github.com/voyagermesh/voyager/issues/1471) +- Helm Chart v11.0.1 errors on install [\#1438](https://github.com/voyagermesh/voyager/issues/1438) +- Voyager 10 fails to deploy with Helm installer [\#1400](https://github.com/voyagermesh/voyager/issues/1400) +- RBAC issue with helm install [\#1333](https://github.com/voyagermesh/voyager/issues/1333) + +**Merged pull requests:** + +- Prepare v12.0.0-rc.1 [\#1473](https://github.com/voyagermesh/voyager/pull/1473) ([tamalsaha](https://github.com/tamalsaha)) +- Exit only if UpdateStatus returns error. [\#1472](https://github.com/voyagermesh/voyager/pull/1472) ([tamalsaha](https://github.com/tamalsaha)) + +## [v12.0.0-rc.0](https://github.com/voyagermesh/voyager/tree/v12.0.0-rc.0) (2020-01-03) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/v11.0.1...v12.0.0-rc.0) + +**Closed issues:** + +- Voyager with GKE HTTP\(S\) -L7 Load balancer [\#1453](https://github.com/voyagermesh/voyager/issues/1453) +- Voyager Installation Issue [\#1452](https://github.com/voyagermesh/voyager/issues/1452) +- ServiceMonitor endpoint path created with the wrong APISchemaIngress \(typo?\) [\#1451](https://github.com/voyagermesh/voyager/issues/1451) +- Problem with lets encrypt certificates [\#1444](https://github.com/voyagermesh/voyager/issues/1444) +- Helm Chart v11.0.0 errors on install [\#1433](https://github.com/voyagermesh/voyager/issues/1433) + +**Merged pull requests:** + +- Fix css class for helm 3 tab [\#1470](https://github.com/voyagermesh/voyager/pull/1470) ([tamalsaha](https://github.com/tamalsaha)) +- Prepare release v12.0.0-rc.0 [\#1469](https://github.com/voyagermesh/voyager/pull/1469) ([tamalsaha](https://github.com/tamalsaha)) +- Fix failed e2e tests [\#1468](https://github.com/voyagermesh/voyager/pull/1468) ([tamalsaha](https://github.com/tamalsaha)) +- Update installation instructions [\#1467](https://github.com/voyagermesh/voyager/pull/1467) ([tamalsaha](https://github.com/tamalsaha)) +- Run e2e tests in minikube [\#1466](https://github.com/voyagermesh/voyager/pull/1466) ([tamalsaha](https://github.com/tamalsaha)) +- Various fixes to chart [\#1465](https://github.com/voyagermesh/voyager/pull/1465) ([tamalsaha](https://github.com/tamalsaha)) +- Delete script based installer [\#1464](https://github.com/voyagermesh/voyager/pull/1464) ([tamalsaha](https://github.com/tamalsaha)) +- Revendor [\#1463](https://github.com/voyagermesh/voyager/pull/1463) ([tamalsaha](https://github.com/tamalsaha)) +- Fix typo for APISchemaIngress [\#1461](https://github.com/voyagermesh/voyager/pull/1461) ([ttauveron](https://github.com/ttauveron)) +- Use OwnerReference helpers from kmodules [\#1460](https://github.com/voyagermesh/voyager/pull/1460) ([tamalsaha](https://github.com/tamalsaha)) +- Fix helm v3.0.0 chart error on install [\#1459](https://github.com/voyagermesh/voyager/pull/1459) ([bg-master](https://github.com/bg-master)) +- Run fuzz tests for and set `preserveUnknownFields: false [\#1458](https://github.com/voyagermesh/voyager/pull/1458) ([tamalsaha](https://github.com/tamalsaha)) +- Properly handle empty image pull secret name in installer [\#1457](https://github.com/voyagermesh/voyager/pull/1457) ([tamalsaha](https://github.com/tamalsaha)) +- Fix broken links and chart validation [\#1456](https://github.com/voyagermesh/voyager/pull/1456) ([tamalsaha](https://github.com/tamalsaha)) +- Update client-go to kubernetes-1.16.3 [\#1455](https://github.com/voyagermesh/voyager/pull/1455) ([tamalsaha](https://github.com/tamalsaha)) +- Use controller-tools@v0.2.2 to generate structural schema [\#1450](https://github.com/voyagermesh/voyager/pull/1450) ([tamalsaha](https://github.com/tamalsaha)) +- Fix Linter Issues [\#1448](https://github.com/voyagermesh/voyager/pull/1448) ([faem](https://github.com/faem)) +- Various Makefile improvements [\#1447](https://github.com/voyagermesh/voyager/pull/1447) ([tamalsaha](https://github.com/tamalsaha)) +- Typo fix [\#1445](https://github.com/voyagermesh/voyager/pull/1445) ([jwenz723](https://github.com/jwenz723)) +- Use kubebuilder to generate crd manifests [\#1442](https://github.com/voyagermesh/voyager/pull/1442) ([tamalsaha](https://github.com/tamalsaha)) +- Fix helm chart install v11.0.1 [\#1441](https://github.com/voyagermesh/voyager/pull/1441) ([soosap](https://github.com/soosap)) + +## [v11.0.1](https://github.com/voyagermesh/voyager/tree/v11.0.1) (2019-09-20) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/v11.0.0...v11.0.1) + +**Merged pull requests:** + +- Download onessl version v0.13.1 for Kubernetes 1.16 fix [\#1437](https://github.com/voyagermesh/voyager/pull/1437) ([tamalsaha](https://github.com/tamalsaha)) +- Fix broken helm chart: unexpected end definition in cluster-role.yaml [\#1436](https://github.com/voyagermesh/voyager/pull/1436) ([kirrmann](https://github.com/kirrmann)) +- Templatize front matter [\#1434](https://github.com/voyagermesh/voyager/pull/1434) ([tamalsaha](https://github.com/tamalsaha)) + +## [v11.0.0](https://github.com/voyagermesh/voyager/tree/v11.0.0) (2019-09-10) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/10.0.0...v11.0.0) + +**Closed issues:** + +- Integration issue with Jenkins [\#1403](https://github.com/voyagermesh/voyager/issues/1403) +- TLS on backend communication [\#1401](https://github.com/voyagermesh/voyager/issues/1401) +- Remove --rbac flag [\#1388](https://github.com/voyagermesh/voyager/issues/1388) +- Allow Backend Weight to be 0 [\#1387](https://github.com/voyagermesh/voyager/issues/1387) +- Voyager Let's Encrypt fails when using HTTP-01 challenge with multiple domains [\#1385](https://github.com/voyagermesh/voyager/issues/1385) +- Drain a backend in terminating status? [\#1196](https://github.com/voyagermesh/voyager/issues/1196) + +**Merged pull requests:** + +- Prepare docs for v11.0.0 release [\#1432](https://github.com/voyagermesh/voyager/pull/1432) ([tamalsaha](https://github.com/tamalsaha)) +- Update dependencies [\#1431](https://github.com/voyagermesh/voyager/pull/1431) ([tamalsaha](https://github.com/tamalsaha)) +- Add --ingress-class to hack/deploy/voyager.sh [\#1430](https://github.com/voyagermesh/voyager/pull/1430) ([mildred](https://github.com/mildred)) +- How to change scopes on a running kubernetes cluster. [\#1428](https://github.com/voyagermesh/voyager/pull/1428) ([sniip-code](https://github.com/sniip-code)) +- Use github.com/akamai/AkamaiOPEN-edgegrid-golang@v0.8.0 [\#1421](https://github.com/voyagermesh/voyager/pull/1421) ([tamalsaha](https://github.com/tamalsaha)) +- Add license header for Makefile [\#1420](https://github.com/voyagermesh/voyager/pull/1420) ([tamalsaha](https://github.com/tamalsaha)) +- Update azure-sdk-for-go to v31.1.0 [\#1419](https://github.com/voyagermesh/voyager/pull/1419) ([tamalsaha](https://github.com/tamalsaha)) +- Add cert-manager docs [\#1417](https://github.com/voyagermesh/voyager/pull/1417) ([kfoozminus](https://github.com/kfoozminus)) +- Docs: notice about tls secret special characters [\#1416](https://github.com/voyagermesh/voyager/pull/1416) ([mkozjak](https://github.com/mkozjak)) +- Update .yaml apps/v1 and Update Vendor to Fix DaemonSet Issue [\#1410](https://github.com/voyagermesh/voyager/pull/1410) ([kfoozminus](https://github.com/kfoozminus)) +- Allow replica change when no hpa [\#1409](https://github.com/voyagermesh/voyager/pull/1409) ([kfoozminus](https://github.com/kfoozminus)) +- Fix Docs and Example Files [\#1408](https://github.com/voyagermesh/voyager/pull/1408) ([kfoozminus](https://github.com/kfoozminus)) +- Avoid 503 Error Doc [\#1407](https://github.com/voyagermesh/voyager/pull/1407) ([kfoozminus](https://github.com/kfoozminus)) +- Change timeout connect to 5s [\#1406](https://github.com/voyagermesh/voyager/pull/1406) ([kfoozminus](https://github.com/kfoozminus)) +- Add hard-stop-after [\#1405](https://github.com/voyagermesh/voyager/pull/1405) ([kfoozminus](https://github.com/kfoozminus)) +- Add Makefile [\#1398](https://github.com/voyagermesh/voyager/pull/1398) ([tamalsaha](https://github.com/tamalsaha)) +- Remove --rbac flag [\#1397](https://github.com/voyagermesh/voyager/pull/1397) ([kfoozminus](https://github.com/kfoozminus)) +- Allow Backend Weight to be 0 [\#1396](https://github.com/voyagermesh/voyager/pull/1396) ([kfoozminus](https://github.com/kfoozminus)) +- Add HAProxy Agent Check [\#1395](https://github.com/voyagermesh/voyager/pull/1395) ([kfoozminus](https://github.com/kfoozminus)) +- Use absolute path as aliases for reference docs [\#1394](https://github.com/voyagermesh/voyager/pull/1394) ([tamalsaha](https://github.com/tamalsaha)) +- Update to k8s client libraries to 1.14.0 [\#1392](https://github.com/voyagermesh/voyager/pull/1392) ([tamalsaha](https://github.com/tamalsaha)) +- Use GO Modules [\#1391](https://github.com/voyagermesh/voyager/pull/1391) ([tamalsaha](https://github.com/tamalsaha)) +- Revendor dependencies in preparation for go module support [\#1390](https://github.com/voyagermesh/voyager/pull/1390) ([tamalsaha](https://github.com/tamalsaha)) +- Fix Typo [\#1384](https://github.com/voyagermesh/voyager/pull/1384) ([kfoozminus](https://github.com/kfoozminus)) +- remove single quotes from servicePort [\#1365](https://github.com/voyagermesh/voyager/pull/1365) ([fatelgit](https://github.com/fatelgit)) + +## [10.0.0](https://github.com/voyagermesh/voyager/tree/10.0.0) (2019-04-29) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/9.0.0...10.0.0) + +**Closed issues:** + +- Custom LUA scripts support [\#1370](https://github.com/voyagermesh/voyager/issues/1370) +- 9.0.0 fails to install on new GKE cluster [\#1360](https://github.com/voyagermesh/voyager/issues/1360) +- Cannot use voyager/client with client-go collision with vendored packages [\#1356](https://github.com/voyagermesh/voyager/issues/1356) +- Oauth2\_Proxy is dead, long live Oauth2\_Proxy [\#1302](https://github.com/voyagermesh/voyager/issues/1302) +- Upgrade to HAProxy 1.9.5 [\#1362](https://github.com/voyagermesh/voyager/issues/1362) + +**Merged pull requests:** + +- Prepare docs for 10.0.0 release [\#1383](https://github.com/voyagermesh/voyager/pull/1383) ([tamalsaha](https://github.com/tamalsaha)) +- Update Kubernetes client libraries to 1.13.5 [\#1379](https://github.com/voyagermesh/voyager/pull/1379) ([tamalsaha](https://github.com/tamalsaha)) +- Get id-token from Authorization header [\#1376](https://github.com/voyagermesh/voyager/pull/1376) ([diptadas](https://github.com/diptadas)) +- Update haproxy version to 1.9.6 [\#1374](https://github.com/voyagermesh/voyager/pull/1374) ([diptadas](https://github.com/diptadas)) +- Update haproxy version to 1.9.4 [\#1368](https://github.com/voyagermesh/voyager/pull/1368) ([diptadas](https://github.com/diptadas)) +- Update Kubernetes client libraries to 1.13.0 [\#1359](https://github.com/voyagermesh/voyager/pull/1359) ([tamalsaha](https://github.com/tamalsaha)) +- Clarify how HAProxy presents certificates to clients [\#1358](https://github.com/voyagermesh/voyager/pull/1358) ([diptadas](https://github.com/diptadas)) + +## [9.0.0](https://github.com/voyagermesh/voyager/tree/9.0.0) (2019-02-20) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/8.0.1...9.0.0) + +**Implemented enhancements:** + +- Mount custom configmap [\#1304](https://github.com/voyagermesh/voyager/issues/1304) + +**Fixed bugs:** + +- appscode/oauth2\_proxy:2.3.0 is broken [\#1300](https://github.com/voyagermesh/voyager/issues/1300) +- Unavailable services get removed from HAProxy configuration [\#1285](https://github.com/voyagermesh/voyager/issues/1285) + +**Closed issues:** + +- Add support for Gandi V5 acme dns provider [\#1337](https://github.com/voyagermesh/voyager/issues/1337) +- Memory and CPU requests for Daemonset? [\#1335](https://github.com/voyagermesh/voyager/issues/1335) +- HAProxy OAuth2 [\#1329](https://github.com/voyagermesh/voyager/issues/1329) +- Do not sort ALPN options [\#1327](https://github.com/voyagermesh/voyager/issues/1327) +- Support Haproxy 1.9.2 and gRPC [\#1326](https://github.com/voyagermesh/voyager/issues/1326) +- 503 Service Unavailable [\#1319](https://github.com/voyagermesh/voyager/issues/1319) +- Certificate renew should be configurable [\#1314](https://github.com/voyagermesh/voyager/issues/1314) +- Ingress Configuration with URL Redirection [\#1307](https://github.com/voyagermesh/voyager/issues/1307) +- unsupported LBType LoadBalancer [\#1297](https://github.com/voyagermesh/voyager/issues/1297) +- ingress uses unsupported LBType LoadBalancer [\#1293](https://github.com/voyagermesh/voyager/issues/1293) +- Dependabot couldn't find a Gopkg.toml for this project [\#1289](https://github.com/voyagermesh/voyager/issues/1289) +- Voyager can't communicate with other pods other than stats port [\#1287](https://github.com/voyagermesh/voyager/issues/1287) +- Cannot set cookie name or path [\#1286](https://github.com/voyagermesh/voyager/issues/1286) +- Voyager pods are destroyed and recreated without any clear reason. [\#1284](https://github.com/voyagermesh/voyager/issues/1284) +- Potential Issue With VOYAGER\_\* Environment Variables [\#1224](https://github.com/voyagermesh/voyager/issues/1224) +- support of named servicePort [\#1193](https://github.com/voyagermesh/voyager/issues/1193) +- Disable onessl analytics when voyager analytics is disabled [\#1332](https://github.com/voyagermesh/voyager/issues/1332) +- TLS with HTTP and TCP - Certificate Mismatch [\#1325](https://github.com/voyagermesh/voyager/issues/1325) +- installation error [\#1318](https://github.com/voyagermesh/voyager/issues/1318) +- Readiness probe failed: HTTP probe failed with statuscode: 403 [\#1296](https://github.com/voyagermesh/voyager/issues/1296) +- 503 Service Unavailable when nodePort is set to 443 [\#1290](https://github.com/voyagermesh/voyager/issues/1290) +- Stuck at deletion - finalizers: voyager.appscode.com [\#1249](https://github.com/voyagermesh/voyager/issues/1249) +- TCP SNI doesn't seem to work [\#1247](https://github.com/voyagermesh/voyager/issues/1247) +- Support multiple certificates for tls struct [\#1167](https://github.com/voyagermesh/voyager/issues/1167) +- Document how to use LB alg `leastconn` [\#945](https://github.com/voyagermesh/voyager/issues/945) + +**Merged pull requests:** + +- Update LE certificate renewal buffer info [\#1355](https://github.com/voyagermesh/voyager/pull/1355) ([tamalsaha](https://github.com/tamalsaha)) +- Release 9.0.0 [\#1354](https://github.com/voyagermesh/voyager/pull/1354) ([tamalsaha](https://github.com/tamalsaha)) +- Fix hugo frontmatter for HTTP/2 doc [\#1353](https://github.com/voyagermesh/voyager/pull/1353) ([tamalsaha](https://github.com/tamalsaha)) +- Fix e2e test for empty backend [\#1352](https://github.com/voyagermesh/voyager/pull/1352) ([tamalsaha](https://github.com/tamalsaha)) +- Update changelog for 9.0.0 [\#1350](https://github.com/voyagermesh/voyager/pull/1350) ([tamalsaha](https://github.com/tamalsaha)) +- Prepare docs for 9.0.0 release [\#1349](https://github.com/voyagermesh/voyager/pull/1349) ([tamalsaha](https://github.com/tamalsaha)) +- Don't remove backends with empty endpoints [\#1348](https://github.com/voyagermesh/voyager/pull/1348) ([tamalsaha](https://github.com/tamalsaha)) +- Pass Annotations to Operator PodTemplate [\#1347](https://github.com/voyagermesh/voyager/pull/1347) ([tamalsaha](https://github.com/tamalsaha)) +- Don't use priority class when operator namespace is not kube-system [\#1346](https://github.com/voyagermesh/voyager/pull/1346) ([tamalsaha](https://github.com/tamalsaha)) +- Use onessl 0.10.0 [\#1345](https://github.com/voyagermesh/voyager/pull/1345) ([tamalsaha](https://github.com/tamalsaha)) +- Fix the case for deploying using MINGW64 for windows [\#1344](https://github.com/voyagermesh/voyager/pull/1344) ([tamalsaha](https://github.com/tamalsaha)) +- Add guides for configuring multiple TLS [\#1342](https://github.com/voyagermesh/voyager/pull/1342) ([diptadas](https://github.com/diptadas)) +- Update sticky-session.md [\#1341](https://github.com/voyagermesh/voyager/pull/1341) ([mkozjak](https://github.com/mkozjak)) +- Add option for configuring load balancing algorithm in backends [\#1340](https://github.com/voyagermesh/voyager/pull/1340) ([diptadas](https://github.com/diptadas)) +- Add test for gRPC stream [\#1339](https://github.com/voyagermesh/voyager/pull/1339) ([diptadas](https://github.com/diptadas)) +- Add support for Gandi V5 acme dns provider [\#1338](https://github.com/voyagermesh/voyager/pull/1338) ([ThomasKliszowski](https://github.com/ThomasKliszowski)) +- Update TCP docs [\#1336](https://github.com/voyagermesh/voyager/pull/1336) ([diptadas](https://github.com/diptadas)) +- Fix test-server certs [\#1331](https://github.com/voyagermesh/voyager/pull/1331) ([diptadas](https://github.com/diptadas)) +- Support mounting any configmap/secret into HAProxy pod [\#1330](https://github.com/voyagermesh/voyager/pull/1330) ([diptadas](https://github.com/diptadas)) +- Add support for gRPC [\#1328](https://github.com/voyagermesh/voyager/pull/1328) ([diptadas](https://github.com/diptadas)) +- readme: overview: certificates.voyager.appscode.com [\#1324](https://github.com/voyagermesh/voyager/pull/1324) ([mkozjak](https://github.com/mkozjak)) +- readme: single-service update [\#1323](https://github.com/voyagermesh/voyager/pull/1323) ([mkozjak](https://github.com/mkozjak)) +- single-service: should be 'test-service' instead of 'test-server' [\#1322](https://github.com/voyagermesh/voyager/pull/1322) ([mkozjak](https://github.com/mkozjak)) +- readme: minor typo fix [\#1321](https://github.com/voyagermesh/voyager/pull/1321) ([mkozjak](https://github.com/mkozjak)) +- Add option for configuring certificate renewal [\#1316](https://github.com/voyagermesh/voyager/pull/1316) ([diptadas](https://github.com/diptadas)) +- Add finalizer only when firewall supported [\#1315](https://github.com/voyagermesh/voyager/pull/1315) ([diptadas](https://github.com/diptadas)) +- Fix ClusterProvider name for concourse tests [\#1313](https://github.com/voyagermesh/voyager/pull/1313) ([tahsinrahman](https://github.com/tahsinrahman)) +- Update haproxy version to 1.9.2 [\#1312](https://github.com/voyagermesh/voyager/pull/1312) ([diptadas](https://github.com/diptadas)) +- Fix cookie name and hash type in service annotation [\#1311](https://github.com/voyagermesh/voyager/pull/1311) ([diptadas](https://github.com/diptadas)) +- Add support for named service port [\#1310](https://github.com/voyagermesh/voyager/pull/1310) ([diptadas](https://github.com/diptadas)) +- Add certificate health checker [\#1309](https://github.com/voyagermesh/voyager/pull/1309) ([tamalsaha](https://github.com/tamalsaha)) +- Update webhook error message format for Kubernetes 1.13+ [\#1306](https://github.com/voyagermesh/voyager/pull/1306) ([tamalsaha](https://github.com/tamalsaha)) +- Update xenwolf/lego to 2018-12 [\#1305](https://github.com/voyagermesh/voyager/pull/1305) ([tamalsaha](https://github.com/tamalsaha)) +- Update appscode/oauth2\_proxy image version [\#1301](https://github.com/voyagermesh/voyager/pull/1301) ([diptadas](https://github.com/diptadas)) +- Set periodic analytics [\#1298](https://github.com/voyagermesh/voyager/pull/1298) ([tamalsaha](https://github.com/tamalsaha)) +- Fixed typo [\#1295](https://github.com/voyagermesh/voyager/pull/1295) ([endrec](https://github.com/endrec)) +- Update Kubernetes client libraries to 1.12.0 [\#1292](https://github.com/voyagermesh/voyager/pull/1292) ([tamalsaha](https://github.com/tamalsaha)) +- Update xray to handle any webhook denied request [\#1282](https://github.com/voyagermesh/voyager/pull/1282) ([tamalsaha](https://github.com/tamalsaha)) +- Expose flags to chart [\#1281](https://github.com/voyagermesh/voyager/pull/1281) ([tamalsaha](https://github.com/tamalsaha)) +- Pass image pull secrets for cleaner job in chart [\#1280](https://github.com/voyagermesh/voyager/pull/1280) ([tamalsaha](https://github.com/tamalsaha)) +- Update kubernetes client libraries to 1.12.0 [\#1279](https://github.com/voyagermesh/voyager/pull/1279) ([tamalsaha](https://github.com/tamalsaha)) + +## [8.0.1](https://github.com/voyagermesh/voyager/tree/8.0.1) (2018-10-11) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/8.0.0...8.0.1) + +**Fixed bugs:** + +- Support EKS [\#1130](https://github.com/voyagermesh/voyager/issues/1130) +- Test against AKS [\#1112](https://github.com/voyagermesh/voyager/issues/1112) +- Only use apps/v1 apigroup from controller. [\#1274](https://github.com/voyagermesh/voyager/pull/1274) ([tamalsaha](https://github.com/tamalsaha)) + +**Merged pull requests:** + +- Expose flags to installer script [\#1278](https://github.com/voyagermesh/voyager/pull/1278) ([tamalsaha](https://github.com/tamalsaha)) +- Fix webhook xray checker [\#1277](https://github.com/voyagermesh/voyager/pull/1277) ([tamalsaha](https://github.com/tamalsaha)) +- Handle ErrCallingWebhook in xray [\#1276](https://github.com/voyagermesh/voyager/pull/1276) ([tamalsaha](https://github.com/tamalsaha)) +- Prepare docs for 8.0.1 release [\#1275](https://github.com/voyagermesh/voyager/pull/1275) ([tamalsaha](https://github.com/tamalsaha)) +- Fix upgrade flow for installer script [\#1273](https://github.com/voyagermesh/voyager/pull/1273) ([tamalsaha](https://github.com/tamalsaha)) + +## [8.0.0](https://github.com/voyagermesh/voyager/tree/8.0.0) (2018-10-09) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/7.4.0...8.0.0) + +**Fixed bugs:** + +- Support custom errorfiles with .http ext [\#1238](https://github.com/voyagermesh/voyager/issues/1238) +- Correctly handle ignored openapi prefixes [\#1198](https://github.com/voyagermesh/voyager/pull/1198) ([tamalsaha](https://github.com/tamalsaha)) + +**Closed issues:** + +- Understanding/Documenting CPU Usage, behaviour and limits. [\#1267](https://github.com/voyagermesh/voyager/issues/1267) +- "enableValidatingWebhook: false" doesn't work anymore [\#1264](https://github.com/voyagermesh/voyager/issues/1264) +- Support readiness and liveness probes in generated deployments [\#1262](https://github.com/voyagermesh/voyager/issues/1262) +- Haproxy pods are constantly recreated when using multiple annotations [\#1251](https://github.com/voyagermesh/voyager/issues/1251) +- Support TLSv1.3 [\#1245](https://github.com/voyagermesh/voyager/issues/1245) +- Support Internal Load Balancer Type [\#1197](https://github.com/voyagermesh/voyager/issues/1197) +- Fix error message [\#1194](https://github.com/voyagermesh/voyager/issues/1194) +- official page: docs link dead [\#1190](https://github.com/voyagermesh/voyager/issues/1190) +- Use apps/v1 api [\#583](https://github.com/voyagermesh/voyager/issues/583) + +**Merged pull requests:** + +- Fix Ingress column header [\#1272](https://github.com/voyagermesh/voyager/pull/1272) ([tamalsaha](https://github.com/tamalsaha)) +- Fix chart [\#1271](https://github.com/voyagermesh/voyager/pull/1271) ([tamalsaha](https://github.com/tamalsaha)) +- Set SideEffects to None for webhooks [\#1270](https://github.com/voyagermesh/voyager/pull/1270) ([tamalsaha](https://github.com/tamalsaha)) +- Prepare docs for 8.0.0 release [\#1269](https://github.com/voyagermesh/voyager/pull/1269) ([tamalsaha](https://github.com/tamalsaha)) +- Detect failure quickly. [\#1268](https://github.com/voyagermesh/voyager/pull/1268) ([tamalsaha](https://github.com/tamalsaha)) +- Check webhooks are activated in installer script [\#1266](https://github.com/voyagermesh/voyager/pull/1266) ([tamalsaha](https://github.com/tamalsaha)) +- Write webhook xray event to operator workload [\#1265](https://github.com/voyagermesh/voyager/pull/1265) ([tamalsaha](https://github.com/tamalsaha)) +- Support readinessProbe and livenessProbe [\#1263](https://github.com/voyagermesh/voyager/pull/1263) ([bpineau](https://github.com/bpineau)) +- Update error-files.md [\#1260](https://github.com/voyagermesh/voyager/pull/1260) ([simnyc](https://github.com/simnyc)) +- Update FixAKS helper [\#1259](https://github.com/voyagermesh/voyager/pull/1259) ([tamalsaha](https://github.com/tamalsaha)) +- Use FQDN for kube-apiserver in AKS [\#1258](https://github.com/voyagermesh/voyager/pull/1258) ([tamalsaha](https://github.com/tamalsaha)) +- Rename webhook apiserver ca CN [\#1257](https://github.com/voyagermesh/voyager/pull/1257) ([tamalsaha](https://github.com/tamalsaha)) +- Check if Kubernetes version is supported before running operator [\#1256](https://github.com/voyagermesh/voyager/pull/1256) ([tamalsaha](https://github.com/tamalsaha)) +- Format user roles [\#1255](https://github.com/voyagermesh/voyager/pull/1255) ([tamalsaha](https://github.com/tamalsaha)) +- Enable webhooks by default in chart [\#1254](https://github.com/voyagermesh/voyager/pull/1254) ([tamalsaha](https://github.com/tamalsaha)) +- Support configuring cleaner image via values in chart [\#1253](https://github.com/voyagermesh/voyager/pull/1253) ([tamalsaha](https://github.com/tamalsaha)) +- Sort pod annotations to avoid template changes [\#1252](https://github.com/voyagermesh/voyager/pull/1252) ([lbernail](https://github.com/lbernail)) +- Use --pull flag with docker build [\#1248](https://github.com/voyagermesh/voyager/pull/1248) ([tamalsaha](https://github.com/tamalsaha)) +- add support for custom templates from config map to chart [\#1246](https://github.com/voyagermesh/voyager/pull/1246) ([bodewig](https://github.com/bodewig)) +- Use forked k8s.io/client-go v1.11.3 [\#1243](https://github.com/voyagermesh/voyager/pull/1243) ([tamalsaha](https://github.com/tamalsaha)) +- Update k8s.io/apiserver [\#1241](https://github.com/voyagermesh/voyager/pull/1241) ([tamalsaha](https://github.com/tamalsaha)) +- Use kubernetes-1.11.3 [\#1240](https://github.com/voyagermesh/voyager/pull/1240) ([tamalsaha](https://github.com/tamalsaha)) +- Update CertStore [\#1239](https://github.com/voyagermesh/voyager/pull/1239) ([tamalsaha](https://github.com/tamalsaha)) +- Touch custom errorfiles provided in configmap [\#1237](https://github.com/voyagermesh/voyager/pull/1237) ([tamalsaha](https://github.com/tamalsaha)) +- Support pod annotations in chart [\#1236](https://github.com/voyagermesh/voyager/pull/1236) ([tamalsaha](https://github.com/tamalsaha)) +- Set serviceAccount for cleaner job [\#1235](https://github.com/voyagermesh/voyager/pull/1235) ([tamalsaha](https://github.com/tamalsaha)) +- Cleanup webhooks when chart is deleted [\#1233](https://github.com/voyagermesh/voyager/pull/1233) ([tamalsaha](https://github.com/tamalsaha)) +- Fix log formatting [\#1232](https://github.com/voyagermesh/voyager/pull/1232) ([tamalsaha](https://github.com/tamalsaha)) +- Use IntHash as status.observedGeneration [\#1231](https://github.com/voyagermesh/voyager/pull/1231) ([tamalsaha](https://github.com/tamalsaha)) +- Update pipeline [\#1230](https://github.com/voyagermesh/voyager/pull/1230) ([tahsinrahman](https://github.com/tahsinrahman)) +- Add observedGenerationHash field [\#1228](https://github.com/voyagermesh/voyager/pull/1228) ([tamalsaha](https://github.com/tamalsaha)) +- Fix uninstall for concourse [\#1227](https://github.com/voyagermesh/voyager/pull/1227) ([tahsinrahman](https://github.com/tahsinrahman)) +- Use priorityClass `system-cluster-critical` for operator pods. [\#1223](https://github.com/voyagermesh/voyager/pull/1223) ([tamalsaha](https://github.com/tamalsaha)) +- Revendor prometheus-operator [\#1222](https://github.com/voyagermesh/voyager/pull/1222) ([tamalsaha](https://github.com/tamalsaha)) +- Use apps/v1 apiGroup [\#1221](https://github.com/voyagermesh/voyager/pull/1221) ([tamalsaha](https://github.com/tamalsaha)) +- Use concourse scripts from libbuild [\#1219](https://github.com/voyagermesh/voyager/pull/1219) ([tahsinrahman](https://github.com/tahsinrahman)) +- Add AlreadyObserved helpers [\#1218](https://github.com/voyagermesh/voyager/pull/1218) ([tamalsaha](https://github.com/tamalsaha)) +- Add categories [\#1217](https://github.com/voyagermesh/voyager/pull/1217) ([tamalsaha](https://github.com/tamalsaha)) +- Fix UpdateStatus helpers [\#1216](https://github.com/voyagermesh/voyager/pull/1216) ([tamalsaha](https://github.com/tamalsaha)) +- Upgrade xenwolf/lego library [\#1214](https://github.com/voyagermesh/voyager/pull/1214) ([tamalsaha](https://github.com/tamalsaha)) +- Support pod priority [\#1213](https://github.com/voyagermesh/voyager/pull/1213) ([tamalsaha](https://github.com/tamalsaha)) +- Enable status sub resource for crd yamls [\#1212](https://github.com/voyagermesh/voyager/pull/1212) ([tamalsaha](https://github.com/tamalsaha)) +- Move crds to api folder [\#1209](https://github.com/voyagermesh/voyager/pull/1209) ([tamalsaha](https://github.com/tamalsaha)) +- Retry UpdateStatus calls [\#1208](https://github.com/voyagermesh/voyager/pull/1208) ([tamalsaha](https://github.com/tamalsaha)) +- Revendor monitoring-agent-api [\#1207](https://github.com/voyagermesh/voyager/pull/1207) ([tamalsaha](https://github.com/tamalsaha)) +- Use kmodules.xyz/monitoring-agent-api [\#1206](https://github.com/voyagermesh/voyager/pull/1206) ([tamalsaha](https://github.com/tamalsaha)) +- Document limited NLB support [\#1205](https://github.com/voyagermesh/voyager/pull/1205) ([tamalsaha](https://github.com/tamalsaha)) +- Update GKE cluster role [\#1204](https://github.com/voyagermesh/voyager/pull/1204) ([tamalsaha](https://github.com/tamalsaha)) +- Add throughput graph [\#1201](https://github.com/voyagermesh/voyager/pull/1201) ([tamalsaha](https://github.com/tamalsaha)) +- Don't error out if old monitoring agent is missing [\#1195](https://github.com/voyagermesh/voyager/pull/1195) ([tamalsaha](https://github.com/tamalsaha)) +- Prepare docs for 7.4.0 release [\#1192](https://github.com/voyagermesh/voyager/pull/1192) ([tamalsaha](https://github.com/tamalsaha)) +- Add validation webhook xray [\#1261](https://github.com/voyagermesh/voyager/pull/1261) ([tamalsaha](https://github.com/tamalsaha)) + +## [7.4.0](https://github.com/voyagermesh/voyager/tree/7.4.0) (2018-07-12) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/7.3.0...7.4.0) + +**Closed issues:** + +- Supporting multiple hostnames per backend service [\#1187](https://github.com/voyagermesh/voyager/issues/1187) +- Custom Tolerations and affinity [\#1181](https://github.com/voyagermesh/voyager/issues/1181) + +**Merged pull requests:** + +- Prepare docs for 7.4.0 release [\#1189](https://github.com/voyagermesh/voyager/pull/1189) ([tamalsaha](https://github.com/tamalsaha)) +- Use version and additional columns for crds [\#1183](https://github.com/voyagermesh/voyager/pull/1183) ([tamalsaha](https://github.com/tamalsaha)) +- Chart support for custom tolerations and affinity [\#1182](https://github.com/voyagermesh/voyager/pull/1182) ([octplane](https://github.com/octplane)) +- Update client-go to v8.0.0 [\#1177](https://github.com/voyagermesh/voyager/pull/1177) ([tamalsaha](https://github.com/tamalsaha)) + +## [7.3.0](https://github.com/voyagermesh/voyager/tree/7.3.0) (2018-07-08) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/7.2.0...7.3.0) + +**Fixed bugs:** + +- Upgrade HAProxy [\#1173](https://github.com/voyagermesh/voyager/issues/1173) +- Throw validation error when LBType changes. [\#1172](https://github.com/voyagermesh/voyager/pull/1172) ([tamalsaha](https://github.com/tamalsaha)) + +**Closed issues:** + +- Backend name conflicts for multiple bind addresses [\#1164](https://github.com/voyagermesh/voyager/issues/1164) +- RBAC broken in 7.2 if using ClusterRole [\#1163](https://github.com/voyagermesh/voyager/issues/1163) +- Crash when operator container starts [\#1161](https://github.com/voyagermesh/voyager/issues/1161) + +**Merged pull requests:** + +- Update chart installation instruction for Kubernetes 1.11 [\#1180](https://github.com/voyagermesh/voyager/pull/1180) ([tamalsaha](https://github.com/tamalsaha)) +- Prepare docs for 7.3.0 [\#1179](https://github.com/voyagermesh/voyager/pull/1179) ([tamalsaha](https://github.com/tamalsaha)) +- Format shell scripts [\#1178](https://github.com/voyagermesh/voyager/pull/1178) ([tamalsaha](https://github.com/tamalsaha)) +- Remove status from crd.yaml [\#1176](https://github.com/voyagermesh/voyager/pull/1176) ([tamalsaha](https://github.com/tamalsaha)) +- Add description to crd structs [\#1174](https://github.com/voyagermesh/voyager/pull/1174) ([tamalsaha](https://github.com/tamalsaha)) +- Use HAProxy 1.8.12 [\#1175](https://github.com/voyagermesh/voyager/pull/1175) ([tamalsaha](https://github.com/tamalsaha)) +- Document enableStatusSubresource in chart [\#1171](https://github.com/voyagermesh/voyager/pull/1171) ([tamalsaha](https://github.com/tamalsaha)) +- Remove deprecated fields from Certificate crd [\#1170](https://github.com/voyagermesh/voyager/pull/1170) ([tamalsaha](https://github.com/tamalsaha)) +- Enable status subresource for voyager crds [\#1169](https://github.com/voyagermesh/voyager/pull/1169) ([tamalsaha](https://github.com/tamalsaha)) +- Remove description on root schema [\#1168](https://github.com/voyagermesh/voyager/pull/1168) ([conorbranagan](https://github.com/conorbranagan)) +- Add nodeSelector for the operator [\#1166](https://github.com/voyagermesh/voyager/pull/1166) ([ocdi](https://github.com/ocdi)) +- Fixed auto-generated backend names [\#1165](https://github.com/voyagermesh/voyager/pull/1165) ([diptadas](https://github.com/diptadas)) + +## [7.2.0](https://github.com/voyagermesh/voyager/tree/7.2.0) (2018-06-25) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/7.1.1...7.2.0) + +**Implemented enhancements:** + +- Allow user to set healthCheckNodePort for LoadBalancer [\#1128](https://github.com/voyagermesh/voyager/issues/1128) + +**Fixed bugs:** + +- Certificate renew fails [\#1023](https://github.com/voyagermesh/voyager/issues/1023) +- Operator's memory usage over time [\#1004](https://github.com/voyagermesh/voyager/issues/1004) + +**Closed issues:** + +- 4xx and 5xx stats are not reported via prometheus exporter [\#1146](https://github.com/voyagermesh/voyager/issues/1146) +- Release java client for Voyager [\#1142](https://github.com/voyagermesh/voyager/issues/1142) +- Document ingress.appscode.com/check [\#1140](https://github.com/voyagermesh/voyager/issues/1140) +- tls-backend annotation ignored for external service [\#1139](https://github.com/voyagermesh/voyager/issues/1139) +- Revendor lego [\#1137](https://github.com/voyagermesh/voyager/issues/1137) +- support forwarding authorization header for oauth2\_proxy [\#1073](https://github.com/voyagermesh/voyager/issues/1073) +- Pause Certificate [\#1022](https://github.com/voyagermesh/voyager/issues/1022) + +**Merged pull requests:** + +- Preparep docs for 7.2.0 release [\#1160](https://github.com/voyagermesh/voyager/pull/1160) ([tamalsaha](https://github.com/tamalsaha)) +- Document operator profiler [\#1158](https://github.com/voyagermesh/voyager/pull/1158) ([tamalsaha](https://github.com/tamalsaha)) +- Added docs for backend health check [\#1156](https://github.com/voyagermesh/voyager/pull/1156) ([diptadas](https://github.com/diptadas)) +- Fix fmt string in validator [\#1154](https://github.com/voyagermesh/voyager/pull/1154) ([tamalsaha](https://github.com/tamalsaha)) +- Allow user to set healthCheckNodePort [\#1153](https://github.com/voyagermesh/voyager/pull/1153) ([diptadas](https://github.com/diptadas)) +- Pause certificate checks [\#1149](https://github.com/voyagermesh/voyager/pull/1149) ([tamalsaha](https://github.com/tamalsaha)) +- Parse tls-backend annotation for external service [\#1148](https://github.com/voyagermesh/voyager/pull/1148) ([enver](https://github.com/enver)) +- Revendor xenolf/lego [\#1147](https://github.com/voyagermesh/voyager/pull/1147) ([tamalsaha](https://github.com/tamalsaha)) +- Move openapi-spec to api folder [\#1143](https://github.com/voyagermesh/voyager/pull/1143) ([tamalsaha](https://github.com/tamalsaha)) +- Node port services are supported by external-dns [\#1138](https://github.com/voyagermesh/voyager/pull/1138) ([tamalsaha](https://github.com/tamalsaha)) +- Forward X-Auth-Request-Id-Token header in oauth [\#1126](https://github.com/voyagermesh/voyager/pull/1126) ([diptadas](https://github.com/diptadas)) +- Use secrets for TLS connections [\#1159](https://github.com/voyagermesh/voyager/pull/1159) ([tamalsaha](https://github.com/tamalsaha)) +- Document how to view operator metrics [\#1157](https://github.com/voyagermesh/voyager/pull/1157) ([tamalsaha](https://github.com/tamalsaha)) +- Fix fmt string in validator [\#1155](https://github.com/voyagermesh/voyager/pull/1155) ([tamalsaha](https://github.com/tamalsaha)) +- Always use RBAC-enabled instructions for monitoring tutorials [\#1152](https://github.com/voyagermesh/voyager/pull/1152) ([tamalsaha](https://github.com/tamalsaha)) +- Expose webhook server to expose operator metrics [\#1151](https://github.com/voyagermesh/voyager/pull/1151) ([tamalsaha](https://github.com/tamalsaha)) +- Revendor dependencies [\#1150](https://github.com/voyagermesh/voyager/pull/1150) ([tamalsaha](https://github.com/tamalsaha)) +- Use one global event recorder [\#1141](https://github.com/voyagermesh/voyager/pull/1141) ([tamalsaha](https://github.com/tamalsaha)) + +## [7.1.1](https://github.com/voyagermesh/voyager/tree/7.1.1) (2018-06-13) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/7.1.0...7.1.1) + +**Fixed bugs:** + +- Fix rbac permissions for service monitors [\#1133](https://github.com/voyagermesh/voyager/pull/1133) ([tamalsaha](https://github.com/tamalsaha)) + +**Closed issues:** + +- Get new LE account if user hits rate limits [\#1122](https://github.com/voyagermesh/voyager/issues/1122) + +**Merged pull requests:** + +- Prepare docs for 7.1.1 release [\#1135](https://github.com/voyagermesh/voyager/pull/1135) ([tamalsaha](https://github.com/tamalsaha)) +- Get new LE account if user hits rate limits [\#1134](https://github.com/voyagermesh/voyager/pull/1134) ([tamalsaha](https://github.com/tamalsaha)) +- Do not create namespace from yaml, it gets created with kubectl manually [\#1132](https://github.com/voyagermesh/voyager/pull/1132) ([gavvvr](https://github.com/gavvvr)) +- Allocate cpu for operator pod. [\#1136](https://github.com/voyagermesh/voyager/pull/1136) ([tamalsaha](https://github.com/tamalsaha)) + +## [7.1.0](https://github.com/voyagermesh/voyager/tree/7.1.0) (2018-06-13) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/5.0.0...7.1.0) + +**Fixed bugs:** + +- Deleting voyager gets stuck [\#1098](https://github.com/voyagermesh/voyager/issues/1098) +- Port 443 is opened with aws cert manager even only TCP is used [\#707](https://github.com/voyagermesh/voyager/issues/707) +- acme-challenge .well-known path is getting redirected [\#1097](https://github.com/voyagermesh/voyager/issues/1097) +- CRD registration fails with --restrict-to-namespace [\#1083](https://github.com/voyagermesh/voyager/issues/1083) +- Fix formatting errors in validator [\#1085](https://github.com/voyagermesh/voyager/pull/1085) ([tamalsaha](https://github.com/tamalsaha)) + +**Closed issues:** + +- Add metallb support for ExternalTrafficPolicy [\#1116](https://github.com/voyagermesh/voyager/issues/1116) +- Add support for metallb in install script [\#1115](https://github.com/voyagermesh/voyager/issues/1115) +- Add load-balancer-ip annotation support for metallb. [\#1105](https://github.com/voyagermesh/voyager/issues/1105) +- Update timeout keys [\#1103](https://github.com/voyagermesh/voyager/issues/1103) +- ReplicaSet pod always in Terminating status in GKE [\#1095](https://github.com/voyagermesh/voyager/issues/1095) +- Problem with TCP Ingress on GKE [\#1084](https://github.com/voyagermesh/voyager/issues/1084) +- Fix HAProxy config checks [\#1028](https://github.com/voyagermesh/voyager/issues/1028) +- Inject side-car to configure sysctl [\#758](https://github.com/voyagermesh/voyager/issues/758) +- oauth2 to accept self-signed certificates in backend [\#1107](https://github.com/voyagermesh/voyager/issues/1107) +- get username from oauth2\_proxy and forward this to protected backend [\#1102](https://github.com/voyagermesh/voyager/issues/1102) +- Document how to setup kube dashboard with Voyager [\#1075](https://github.com/voyagermesh/voyager/issues/1075) +- Document using Google oauth with Voyager [\#1074](https://github.com/voyagermesh/voyager/issues/1074) + +**Merged pull requests:** + +- Fix haproxy-stats page link [\#1131](https://github.com/voyagermesh/voyager/pull/1131) ([tamalsaha](https://github.com/tamalsaha)) +- Update changelog [\#1129](https://github.com/voyagermesh/voyager/pull/1129) ([tamalsaha](https://github.com/tamalsaha)) +- haproxy-stats.md typo fix [\#1127](https://github.com/voyagermesh/voyager/pull/1127) ([gavvvr](https://github.com/gavvvr)) +- Upgrade to HAProxy 1.8.9 [\#1124](https://github.com/voyagermesh/voyager/pull/1124) ([tamalsaha](https://github.com/tamalsaha)) +- Revendor dependencies [\#1123](https://github.com/voyagermesh/voyager/pull/1123) ([tamalsaha](https://github.com/tamalsaha)) +- Stop processing http request for LE well-known acme challenge path [\#1121](https://github.com/voyagermesh/voyager/pull/1121) ([tamalsaha](https://github.com/tamalsaha)) +- Fix documentation about external-dns service [\#1120](https://github.com/voyagermesh/voyager/pull/1120) ([giovannicandido](https://github.com/giovannicandido)) +- Add support for aks [\#1119](https://github.com/voyagermesh/voyager/pull/1119) ([tamalsaha](https://github.com/tamalsaha)) +- Additional metallb support [\#1117](https://github.com/voyagermesh/voyager/pull/1117) ([zsandrus](https://github.com/zsandrus)) +- Forward X-Auth-Request headers in oauth [\#1114](https://github.com/voyagermesh/voyager/pull/1114) ([diptadas](https://github.com/diptadas)) +- Added digitalocean & Linode provider to installer script [\#1113](https://github.com/voyagermesh/voyager/pull/1113) ([diptadas](https://github.com/diptadas)) +- Prepare docs for 7.1.0 release [\#1111](https://github.com/voyagermesh/voyager/pull/1111) ([tamalsaha](https://github.com/tamalsaha)) +- Add LoadBalancer type ingress support for DO and Linode [\#1109](https://github.com/voyagermesh/voyager/pull/1109) ([tamalsaha](https://github.com/tamalsaha)) +- Add metallb to providers that can have LoadBalancerIP set. [\#1106](https://github.com/voyagermesh/voyager/pull/1106) ([zsandrus](https://github.com/zsandrus)) +- Update timeout key list [\#1104](https://github.com/voyagermesh/voyager/pull/1104) ([tamalsaha](https://github.com/tamalsaha)) +- Document how to setup kube dashboard with Voyager [\#1101](https://github.com/voyagermesh/voyager/pull/1101) ([diptadas](https://github.com/diptadas)) +- Document using Google oauth with Voyager [\#1100](https://github.com/voyagermesh/voyager/pull/1100) ([diptadas](https://github.com/diptadas)) +- Update version for 1.7 [\#1094](https://github.com/voyagermesh/voyager/pull/1094) ([tamalsaha](https://github.com/tamalsaha)) +- Wait for loadbalancer ip assignment in e2e tests [\#1090](https://github.com/voyagermesh/voyager/pull/1090) ([diptadas](https://github.com/diptadas)) +- Added test for service auth annotation updates [\#1089](https://github.com/voyagermesh/voyager/pull/1089) ([diptadas](https://github.com/diptadas)) +- Detect haproxy-image-tag in dev mode [\#1082](https://github.com/voyagermesh/voyager/pull/1082) ([diptadas](https://github.com/diptadas)) +- Add togglable tabs for Installation: Script & Helm [\#1125](https://github.com/voyagermesh/voyager/pull/1125) ([sajibcse68](https://github.com/sajibcse68)) +- Apply validation rules to ingress names [\#1110](https://github.com/voyagermesh/voyager/pull/1110) ([tamalsaha](https://github.com/tamalsaha)) +- Concourse tests [\#1081](https://github.com/voyagermesh/voyager/pull/1081) ([tahsinrahman](https://github.com/tahsinrahman)) + +## [5.0.0](https://github.com/voyagermesh/voyager/tree/5.0.0) (2018-06-01) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/7.0.0...5.0.0) + +**Implemented enhancements:** + +- Allow configuration of error files [\#525](https://github.com/voyagermesh/voyager/issues/525) +- Don't require spec.providerCredentialSecretName for own provider [\#366](https://github.com/voyagermesh/voyager/issues/366) +- Limit Connections [\#571](https://github.com/voyagermesh/voyager/pull/571) ([sadlil](https://github.com/sadlil)) +- Reimplement certificate controller [\#506](https://github.com/voyagermesh/voyager/pull/506) ([sadlil](https://github.com/sadlil)) +- Fix HTTP Provider Certificate [\#502](https://github.com/voyagermesh/voyager/pull/502) ([sadlil](https://github.com/sadlil)) +- Add ssl passthrough support for annotations [\#501](https://github.com/voyagermesh/voyager/pull/501) ([sadlil](https://github.com/sadlil)) +- Add Max Body size and CORS annotations [\#500](https://github.com/voyagermesh/voyager/pull/500) ([sadlil](https://github.com/sadlil)) +- Add support for affinity annotations for ingress [\#493](https://github.com/voyagermesh/voyager/pull/493) ([sadlil](https://github.com/sadlil)) + +**Fixed bugs:** + +- failed calling admission webhook "admission.voyager.appscode.com" [\#1080](https://github.com/voyagermesh/voyager/issues/1080) +- Upgrade Prometheus Operator [\#608](https://github.com/voyagermesh/voyager/issues/608) +- Test wildcard domains work with TLS [\#598](https://github.com/voyagermesh/voyager/issues/598) +- Watch secrets and update the config when Basic auth changes [\#560](https://github.com/voyagermesh/voyager/issues/560) +- Using HTTP challenge provider results in pod stuck at ContainerCreating stage [\#455](https://github.com/voyagermesh/voyager/issues/455) +- Avoid concurrency for NewACMEClient [\#382](https://github.com/voyagermesh/voyager/issues/382) +- ProviderCredential has to be created before Certificate object [\#370](https://github.com/voyagermesh/voyager/issues/370) +- Make AWS\_ACCESS\_KEY\_ID optional [\#644](https://github.com/voyagermesh/voyager/pull/644) ([tamalsaha](https://github.com/tamalsaha)) +- All Tests and Bug fixes for release-4 [\#628](https://github.com/voyagermesh/voyager/pull/628) ([sadlil](https://github.com/sadlil)) +- Don't reload HAProxy using tls mounter setup phase [\#610](https://github.com/voyagermesh/voyager/pull/610) ([tamalsaha](https://github.com/tamalsaha)) +- Inject well-known/acme-challenge path at the top of rules [\#588](https://github.com/voyagermesh/voyager/pull/588) ([tamalsaha](https://github.com/tamalsaha)) +- Fix NodePort mode in GKE [\#575](https://github.com/voyagermesh/voyager/pull/575) ([tamalsaha](https://github.com/tamalsaha)) +- Add PATCH permission and fix deployment RBAC spec [\#568](https://github.com/voyagermesh/voyager/pull/568) ([tamalsaha](https://github.com/tamalsaha)) +- Fix RBAC permissions for apps/v1beta1 Deployments [\#565](https://github.com/voyagermesh/voyager/pull/565) ([tamalsaha](https://github.com/tamalsaha)) +- Fix cert controller bugs [\#541](https://github.com/voyagermesh/voyager/pull/541) ([sadlil](https://github.com/sadlil)) + +**Closed issues:** + +- 7.0.0 chart fails on already existing clusterrole [\#1092](https://github.com/voyagermesh/voyager/issues/1092) +- Basic auth doesn't work 5.0.0-rc.11 [\#1079](https://github.com/voyagermesh/voyager/issues/1079) +- loadBalancerIP is ignored in azure mode [\#572](https://github.com/voyagermesh/voyager/issues/572) +- NodePort mode adds port to host header rule, but shouldn't [\#552](https://github.com/voyagermesh/voyager/issues/552) +- Test 3.2.0 to 5.0.0 migration is smooth [\#527](https://github.com/voyagermesh/voyager/issues/527) +- Bug: not creating RBAC roles in NodePort mode [\#524](https://github.com/voyagermesh/voyager/issues/524) +- Allow configuring options for each server entry [\#516](https://github.com/voyagermesh/voyager/issues/516) +- Redesign Certificate CRD [\#505](https://github.com/voyagermesh/voyager/issues/505) +- Upgrade haproxy\_exporter to 0.8.0 [\#504](https://github.com/voyagermesh/voyager/issues/504) +- \[Feature request\] Support for tolerations in ingress pod spec [\#503](https://github.com/voyagermesh/voyager/issues/503) +- DNS resolver test is timing out [\#484](https://github.com/voyagermesh/voyager/issues/484) +- Use Deployment for HostPort mode [\#446](https://github.com/voyagermesh/voyager/issues/446) +- Allow users to provide custom templates [\#444](https://github.com/voyagermesh/voyager/issues/444) +- Add Voyager to official ingress project docs. [\#437](https://github.com/voyagermesh/voyager/issues/437) +- Basic Auth annotations implementation [\#424](https://github.com/voyagermesh/voyager/issues/424) +- Set DNSpolicy to ClusterFirstWithHostNet in HostPort mode [\#417](https://github.com/voyagermesh/voyager/issues/417) +- se fields service.spec.externalTrafficPolicy and service.spec.healthCheckNodePort instead [\#415](https://github.com/voyagermesh/voyager/issues/415) +- Validate certificates [\#393](https://github.com/voyagermesh/voyager/issues/393) +- Document AWS IAM permissions for LE DNS validation. [\#337](https://github.com/voyagermesh/voyager/issues/337) +- Use kubernetes/code-generator to generate clients [\#329](https://github.com/voyagermesh/voyager/issues/329) +- Install Voyager as critical addon [\#292](https://github.com/voyagermesh/voyager/issues/292) +- Use OwnerReference [\#285](https://github.com/voyagermesh/voyager/issues/285) +- Bring annotation parity with Nginx Ingress [\#278](https://github.com/voyagermesh/voyager/issues/278) +- Update GCP annotation for preserving source IP [\#276](https://github.com/voyagermesh/voyager/issues/276) +- Switch to CustomResourceDefinitions [\#239](https://github.com/voyagermesh/voyager/issues/239) +- Use Deployments from apps/v1beta1 [\#238](https://github.com/voyagermesh/voyager/issues/238) + +**Merged pull requests:** + +- Prepare docs for 5.0.0 release [\#1093](https://github.com/voyagermesh/voyager/pull/1093) ([tamalsaha](https://github.com/tamalsaha)) +- Fix installer script for --restrict-to-namespace mode [\#1091](https://github.com/voyagermesh/voyager/pull/1091) ([tamalsaha](https://github.com/tamalsaha)) +- Use yaml file to create service account in installer script [\#1088](https://github.com/voyagermesh/voyager/pull/1088) ([tamalsaha](https://github.com/tamalsaha)) +- Avoid waiting for api services when not installed [\#1087](https://github.com/voyagermesh/voyager/pull/1087) ([tamalsaha](https://github.com/tamalsaha)) +- Trigger update when service auth-annotations changed [\#1086](https://github.com/voyagermesh/voyager/pull/1086) ([diptadas](https://github.com/diptadas)) +- Update developer-guide [\#642](https://github.com/voyagermesh/voyager/pull/642) ([sadlil](https://github.com/sadlil)) +- Support TLS auth annotations [\#621](https://github.com/voyagermesh/voyager/pull/621) ([tamalsaha](https://github.com/tamalsaha)) +- Support Basic auth in FrontendRules [\#617](https://github.com/voyagermesh/voyager/pull/617) ([tamalsaha](https://github.com/tamalsaha)) +- Support ingress.kubernetes.io/ssl-redirect [\#616](https://github.com/voyagermesh/voyager/pull/616) ([tamalsaha](https://github.com/tamalsaha)) +- Secret Update reflection [\#605](https://github.com/voyagermesh/voyager/pull/605) ([sadlil](https://github.com/sadlil)) +- Add LocalTypedReference type [\#579](https://github.com/voyagermesh/voyager/pull/579) ([tamalsaha](https://github.com/tamalsaha)) +- Add ingress class support for helm chart [\#559](https://github.com/voyagermesh/voyager/pull/559) ([xcompass](https://github.com/xcompass)) +- Docs for 4.0 - part 1 [\#556](https://github.com/voyagermesh/voyager/pull/556) ([sadlil](https://github.com/sadlil)) +- Don't log error if to-be-deleted object is missing. [\#554](https://github.com/voyagermesh/voyager/pull/554) ([tamalsaha](https://github.com/tamalsaha)) +- Generate ugorji stuff [\#553](https://github.com/voyagermesh/voyager/pull/553) ([tamalsaha](https://github.com/tamalsaha)) +- Add owner reference for Ingress [\#530](https://github.com/voyagermesh/voyager/pull/530) ([tamalsaha](https://github.com/tamalsaha)) +- Add HAProxy 1.7.9 [\#522](https://github.com/voyagermesh/voyager/pull/522) ([tamalsaha](https://github.com/tamalsaha)) +- Add support for `ingress.kubernetes.io/session-cookie-hash`. [\#497](https://github.com/voyagermesh/voyager/pull/497) ([sadlil](https://github.com/sadlil)) + +## [7.0.0](https://github.com/voyagermesh/voyager/tree/7.0.0) (2018-05-28) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/7.0.0-rc.3...7.0.0) + +**Merged pull requests:** + +- Update changelog [\#1077](https://github.com/voyagermesh/voyager/pull/1077) ([tamalsaha](https://github.com/tamalsaha)) +- Prepare 7.0.0 release [\#1076](https://github.com/voyagermesh/voyager/pull/1076) ([tamalsaha](https://github.com/tamalsaha)) + +## [7.0.0-rc.3](https://github.com/voyagermesh/voyager/tree/7.0.0-rc.3) (2018-05-23) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/7.0.0-rc.2...7.0.0-rc.3) + +**Fixed bugs:** + +- rc2 operator crashes [\#1070](https://github.com/voyagermesh/voyager/issues/1070) + +**Merged pull requests:** + +- Prepare docs for 7.0.0-rc.3 [\#1072](https://github.com/voyagermesh/voyager/pull/1072) ([tamalsaha](https://github.com/tamalsaha)) +- Checked nil pointer before validating oauth [\#1071](https://github.com/voyagermesh/voyager/pull/1071) ([diptadas](https://github.com/diptadas)) +- Update changelog [\#1069](https://github.com/voyagermesh/voyager/pull/1069) ([tamalsaha](https://github.com/tamalsaha)) + +## [7.0.0-rc.2](https://github.com/voyagermesh/voyager/tree/7.0.0-rc.2) (2018-05-23) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/7.0.0-rc.1...7.0.0-rc.2) + +**Fixed bugs:** + +- Fix OAuth implementation [\#1053](https://github.com/voyagermesh/voyager/issues/1053) +- Use hooks for user roles in chart [\#1066](https://github.com/voyagermesh/voyager/pull/1066) ([tamalsaha](https://github.com/tamalsaha)) + +**Closed issues:** + +- Can't run tests on Solus linux, path for minikube is hardcoded [\#1047](https://github.com/voyagermesh/voyager/issues/1047) + +**Merged pull requests:** + +- Don't exit if migration fails. [\#1068](https://github.com/voyagermesh/voyager/pull/1068) ([tamalsaha](https://github.com/tamalsaha)) +- Delete user roles on purge [\#1067](https://github.com/voyagermesh/voyager/pull/1067) ([tamalsaha](https://github.com/tamalsaha)) +- Update changelog [\#1065](https://github.com/voyagermesh/voyager/pull/1065) ([tamalsaha](https://github.com/tamalsaha)) +- Clarify messaging [\#1064](https://github.com/voyagermesh/voyager/pull/1064) ([tamalsaha](https://github.com/tamalsaha)) +- Install correct version of voyager chart [\#1063](https://github.com/voyagermesh/voyager/pull/1063) ([tamalsaha](https://github.com/tamalsaha)) +- Avoid creating apiservice when webhooks are not used. [\#1062](https://github.com/voyagermesh/voyager/pull/1062) ([tamalsaha](https://github.com/tamalsaha)) +- Add --haproxy-image-tag flag to installer [\#1061](https://github.com/voyagermesh/voyager/pull/1061) ([tamalsaha](https://github.com/tamalsaha)) +- Prepare docs for 7.0.0-rc.2 [\#1060](https://github.com/voyagermesh/voyager/pull/1060) ([tamalsaha](https://github.com/tamalsaha)) +- Support NodeSelector and Tolerations via annotation for std ingress [\#1059](https://github.com/voyagermesh/voyager/pull/1059) ([tamalsaha](https://github.com/tamalsaha)) +- Remove redundant assignment [\#1058](https://github.com/voyagermesh/voyager/pull/1058) ([gavvvr](https://github.com/gavvvr)) +- Move oauth2-proxy image to Voyager repo [\#1057](https://github.com/voyagermesh/voyager/pull/1057) ([tamalsaha](https://github.com/tamalsaha)) +- No auth-check for auth-backend-path itself [\#1056](https://github.com/voyagermesh/voyager/pull/1056) ([diptadas](https://github.com/diptadas)) +- Added http2 example [\#1052](https://github.com/voyagermesh/voyager/pull/1052) ([ssro](https://github.com/ssro)) + +## [7.0.0-rc.1](https://github.com/voyagermesh/voyager/tree/7.0.0-rc.1) (2018-05-14) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/7.0.0-rc.0...7.0.0-rc.1) + +**Fixed bugs:** + +- Fix panic [\#1045](https://github.com/voyagermesh/voyager/issues/1045) +- Include a test pem to fool haproxy in operator pod. [\#1038](https://github.com/voyagermesh/voyager/pull/1038) ([tamalsaha](https://github.com/tamalsaha)) + +**Closed issues:** + +- Delete Ingress \(service and co.\) [\#1043](https://github.com/voyagermesh/voyager/issues/1043) +- Allow h2 ALPN option for http mode [\#1040](https://github.com/voyagermesh/voyager/issues/1040) +- Letsencrypt wildcard certs? [\#1024](https://github.com/voyagermesh/voyager/issues/1024) +- CrashLoopBackOff on GKE [\#990](https://github.com/voyagermesh/voyager/issues/990) +- CrashLoopBackOff [\#987](https://github.com/voyagermesh/voyager/issues/987) + +**Merged pull requests:** + +- Update changelog [\#1051](https://github.com/voyagermesh/voyager/pull/1051) ([tamalsaha](https://github.com/tamalsaha)) +- Prepare docs for 7.0.0-rc.1 [\#1050](https://github.com/voyagermesh/voyager/pull/1050) ([tamalsaha](https://github.com/tamalsaha)) +- Correctly set port to binder [\#1049](https://github.com/voyagermesh/voyager/pull/1049) ([tamalsaha](https://github.com/tamalsaha)) +- Do not use absolute path for minikube, fixes \#1047 for 6.0 branch [\#1048](https://github.com/voyagermesh/voyager/pull/1048) ([gavvvr](https://github.com/gavvvr)) +- Fix TestALPNOptions [\#1046](https://github.com/voyagermesh/voyager/pull/1046) ([tamalsaha](https://github.com/tamalsaha)) +- Support ALPN options in HTTP mode [\#1042](https://github.com/voyagermesh/voyager/pull/1042) ([diptadas](https://github.com/diptadas)) +- Find TLS secret only if NoTLS=false [\#1041](https://github.com/voyagermesh/voyager/pull/1041) ([diptadas](https://github.com/diptadas)) +- Fix ambiguous comment [\#1039](https://github.com/voyagermesh/voyager/pull/1039) ([jaymeyerowitz](https://github.com/jaymeyerowitz)) +- Use double quotes with `\*` [\#1037](https://github.com/voyagermesh/voyager/pull/1037) ([tamalsaha](https://github.com/tamalsaha)) +- Fix tcp-sni doc [\#1036](https://github.com/voyagermesh/voyager/pull/1036) ([tamalsaha](https://github.com/tamalsaha)) + +## [7.0.0-rc.0](https://github.com/voyagermesh/voyager/tree/7.0.0-rc.0) (2018-05-10) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/6.0.0...7.0.0-rc.0) + +**Fixed bugs:** + +- question re: ssl-passthrough [\#1012](https://github.com/voyagermesh/voyager/issues/1012) +- SSL redirect not working for LB type NodePort [\#967](https://github.com/voyagermesh/voyager/issues/967) +- Fix installers [\#1035](https://github.com/voyagermesh/voyager/pull/1035) ([tamalsaha](https://github.com/tamalsaha)) +- Generate correct schema for int-or-string type [\#978](https://github.com/voyagermesh/voyager/pull/978) ([tamalsaha](https://github.com/tamalsaha)) +- Fix openapi spec for voyager crds [\#973](https://github.com/voyagermesh/voyager/pull/973) ([tamalsaha](https://github.com/tamalsaha)) +- Fix errors while updating existing CRD [\#971](https://github.com/voyagermesh/voyager/pull/971) ([diptadas](https://github.com/diptadas)) +- Add RBAC for events [\#961](https://github.com/voyagermesh/voyager/pull/961) ([tamalsaha](https://github.com/tamalsaha)) + +**Closed issues:** + +- Test failing for LB type NodePort in Minikube v26 [\#1000](https://github.com/voyagermesh/voyager/issues/1000) +- Support Stretch / Alpine based HAproxy image [\#997](https://github.com/voyagermesh/voyager/issues/997) +- Consider implementing LetsEncrypt wildcard certificates [\#994](https://github.com/voyagermesh/voyager/issues/994) +- Test HAproxy config before setting to configmap [\#989](https://github.com/voyagermesh/voyager/issues/989) +- labels are not inherited to resources created via voyager Ingress [\#986](https://github.com/voyagermesh/voyager/issues/986) +- Add Explicit {{ .Release.Namespace }} reference in Helm Chart [\#984](https://github.com/voyagermesh/voyager/issues/984) +- Support for MetalLB [\#970](https://github.com/voyagermesh/voyager/issues/970) +- Failed to update existing CRDs [\#969](https://github.com/voyagermesh/voyager/issues/969) +- Voyager ingress pod re-created in case of tls setup [\#966](https://github.com/voyagermesh/voyager/issues/966) +- Support for parsing manifest yaml spec into client-go data structures [\#964](https://github.com/voyagermesh/voyager/issues/964) +- Getting error while trying to install release-6.0: Error: unknown shorthand flag: 'o' in -o=json [\#959](https://github.com/voyagermesh/voyager/issues/959) +- voyager pod replica is changed [\#940](https://github.com/voyagermesh/voyager/issues/940) +- Bring back DaemonSet support to place pods [\#897](https://github.com/voyagermesh/voyager/issues/897) +- Support SNI mode in TCP [\#751](https://github.com/voyagermesh/voyager/issues/751) +- Support external-auth /oauth2 [\#638](https://github.com/voyagermesh/voyager/issues/638) +- Generate non-GO clients for Voyager CRDs [\#456](https://github.com/voyagermesh/voyager/issues/456) +- Issue wildcard certs using ACME v2 [\#185](https://github.com/voyagermesh/voyager/issues/185) + +**Merged pull requests:** + +- Fix release script for alpine image [\#1034](https://github.com/voyagermesh/voyager/pull/1034) ([tamalsaha](https://github.com/tamalsaha)) +- Updated tcp-sni doc [\#1033](https://github.com/voyagermesh/voyager/pull/1033) ([diptadas](https://github.com/diptadas)) +- Fix typo [\#1032](https://github.com/voyagermesh/voyager/pull/1032) ([jaymeyerowitz](https://github.com/jaymeyerowitz)) +- Updated doc for ssl-passthrough [\#1031](https://github.com/voyagermesh/voyager/pull/1031) ([diptadas](https://github.com/diptadas)) +- Separated config-check from render-config [\#1030](https://github.com/voyagermesh/voyager/pull/1030) ([diptadas](https://github.com/diptadas)) +- Remove AssignTypeKind and GetGroupVersionKind util methods [\#1029](https://github.com/voyagermesh/voyager/pull/1029) ([tamalsaha](https://github.com/tamalsaha)) +- Prepare docs for 7.0.0-rc.0 [\#1027](https://github.com/voyagermesh/voyager/pull/1027) ([tamalsaha](https://github.com/tamalsaha)) +- Check HAProxy config before writing into configmap [\#1026](https://github.com/voyagermesh/voyager/pull/1026) ([diptadas](https://github.com/diptadas)) +- Handle empty renewed certificate [\#1025](https://github.com/voyagermesh/voyager/pull/1025) ([tamalsaha](https://github.com/tamalsaha)) +- Update chart path for release-5.0 [\#1021](https://github.com/voyagermesh/voyager/pull/1021) ([tamalsaha](https://github.com/tamalsaha)) +- Fix imagePullSecrets location for 5.0.0 chart [\#1020](https://github.com/voyagermesh/voyager/pull/1020) ([gavvvr](https://github.com/gavvvr)) +- Don't panic if admission options is nil [\#1019](https://github.com/voyagermesh/voyager/pull/1019) ([tamalsaha](https://github.com/tamalsaha)) +- Disable admission controllers for webhook server [\#1018](https://github.com/voyagermesh/voyager/pull/1018) ([tamalsaha](https://github.com/tamalsaha)) +- Add Update\*\*\*Status helpers [\#1017](https://github.com/voyagermesh/voyager/pull/1017) ([tamalsaha](https://github.com/tamalsaha)) +- Update client-go v7.0.0 [\#1016](https://github.com/voyagermesh/voyager/pull/1016) ([tamalsaha](https://github.com/tamalsaha)) +- Add haproxy stretch image [\#1014](https://github.com/voyagermesh/voyager/pull/1014) ([diptadas](https://github.com/diptadas)) +- Rename flag --analytics to --enable-analytics [\#1013](https://github.com/voyagermesh/voyager/pull/1013) ([diptadas](https://github.com/diptadas)) +- Update workload api [\#1011](https://github.com/voyagermesh/voyager/pull/1011) ([tamalsaha](https://github.com/tamalsaha)) +- Remove voyager crds before uninstalling operator [\#1010](https://github.com/voyagermesh/voyager/pull/1010) ([tamalsaha](https://github.com/tamalsaha)) +- Update private registry support in chart [\#1009](https://github.com/voyagermesh/voyager/pull/1009) ([tamalsaha](https://github.com/tamalsaha)) +- Rename --analytics -\> --enable-analytics [\#1008](https://github.com/voyagermesh/voyager/pull/1008) ([tamalsaha](https://github.com/tamalsaha)) +- Print namespace where voyager is installed [\#1007](https://github.com/voyagermesh/voyager/pull/1007) ([tamalsaha](https://github.com/tamalsaha)) +- Change default HAProxy tag to 1.8.8-6.1.0 [\#1006](https://github.com/voyagermesh/voyager/pull/1006) ([tamalsaha](https://github.com/tamalsaha)) +- Improve installer [\#1005](https://github.com/voyagermesh/voyager/pull/1005) ([tamalsaha](https://github.com/tamalsaha)) +- Fixed minikube urls for LB type hostport [\#1003](https://github.com/voyagermesh/voyager/pull/1003) ([diptadas](https://github.com/diptadas)) +- Regex replace host header only if port matched in SSL redirect [\#1002](https://github.com/voyagermesh/voyager/pull/1002) ([diptadas](https://github.com/diptadas)) +- Fixed nodeport service url for minikube [\#1001](https://github.com/voyagermesh/voyager/pull/1001) ([diptadas](https://github.com/diptadas)) +- Support both Deployment and DaemonSet to run HAProxy pods [\#999](https://github.com/voyagermesh/voyager/pull/999) ([tamalsaha](https://github.com/tamalsaha)) +- Updated validator for merging empty-host with wildcard-host [\#998](https://github.com/voyagermesh/voyager/pull/998) ([diptadas](https://github.com/diptadas)) +- Issue wildcard certs using LE ACME v2 [\#996](https://github.com/voyagermesh/voyager/pull/996) ([tamalsaha](https://github.com/tamalsaha)) +- Use appscode/oauth2\_proxy docker image [\#995](https://github.com/voyagermesh/voyager/pull/995) ([diptadas](https://github.com/diptadas)) +- Fix .gitignore file [\#993](https://github.com/voyagermesh/voyager/pull/993) ([tamalsaha](https://github.com/tamalsaha)) +- Use HAProxy 1.8.8 [\#992](https://github.com/voyagermesh/voyager/pull/992) ([tamalsaha](https://github.com/tamalsaha)) +- Use separate offshootLabels and offshootSelector [\#991](https://github.com/voyagermesh/voyager/pull/991) ([tamalsaha](https://github.com/tamalsaha)) +- Revendor DNSimple api [\#988](https://github.com/voyagermesh/voyager/pull/988) ([tamalsaha](https://github.com/tamalsaha)) +- Add namespace to relevant kubernetes resources [\#985](https://github.com/voyagermesh/voyager/pull/985) ([Rigdon](https://github.com/Rigdon)) +- Set version in swagger.json [\#983](https://github.com/voyagermesh/voyager/pull/983) ([tamalsaha](https://github.com/tamalsaha)) +- Update chart readme [\#982](https://github.com/voyagermesh/voyager/pull/982) ([tamalsaha](https://github.com/tamalsaha)) +- Update chart repository location [\#981](https://github.com/voyagermesh/voyager/pull/981) ([tamalsaha](https://github.com/tamalsaha)) +- Support installing from local installer scripts [\#979](https://github.com/voyagermesh/voyager/pull/979) ([tamalsaha](https://github.com/tamalsaha)) +- Move swagger.json to apis pkg [\#976](https://github.com/voyagermesh/voyager/pull/976) ([tamalsaha](https://github.com/tamalsaha)) +- Generate swagger.json [\#975](https://github.com/voyagermesh/voyager/pull/975) ([tamalsaha](https://github.com/tamalsaha)) +- Add install package for voyager crds [\#974](https://github.com/voyagermesh/voyager/pull/974) ([tamalsaha](https://github.com/tamalsaha)) +- \#970 Added metallb as a cloud provider option [\#972](https://github.com/voyagermesh/voyager/pull/972) ([schubter](https://github.com/schubter)) +- Fix SSL redirect for LB type NodePort [\#968](https://github.com/voyagermesh/voyager/pull/968) ([diptadas](https://github.com/diptadas)) +- Adding support to Akamai FastDNS provider for certificates [\#965](https://github.com/voyagermesh/voyager/pull/965) ([jeffersongirao](https://github.com/jeffersongirao)) +- Skip setting ListKind [\#963](https://github.com/voyagermesh/voyager/pull/963) ([tamalsaha](https://github.com/tamalsaha)) +- Add CRD Validation [\#962](https://github.com/voyagermesh/voyager/pull/962) ([tamalsaha](https://github.com/tamalsaha)) +- hard to copy line [\#960](https://github.com/voyagermesh/voyager/pull/960) ([joshuacox](https://github.com/joshuacox)) +- Add support for external-auth/oauth [\#954](https://github.com/voyagermesh/voyager/pull/954) ([diptadas](https://github.com/diptadas)) +- concourse configs [\#946](https://github.com/voyagermesh/voyager/pull/946) ([tahsinrahman](https://github.com/tahsinrahman)) +- Use HAProxy 1.8.7 [\#806](https://github.com/voyagermesh/voyager/pull/806) ([tamalsaha](https://github.com/tamalsaha)) +- Support SNI in TCP mode [\#805](https://github.com/voyagermesh/voyager/pull/805) ([tamalsaha](https://github.com/tamalsaha)) + +## [6.0.0](https://github.com/voyagermesh/voyager/tree/6.0.0) (2018-03-30) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/6.0.0-rc.2...6.0.0) + +**Fixed bugs:** + +- Controller is not doing Sync/Add/Update for Service [\#941](https://github.com/voyagermesh/voyager/issues/941) +- TCP Ingress: invalid memory address or nil pointer dereference [\#906](https://github.com/voyagermesh/voyager/issues/906) +- Preemptible instances issues \(6.0.0.rc.0\) [\#902](https://github.com/voyagermesh/voyager/issues/902) +- Voyager 6.0.0 on GKE 1.8.5: Failed to list \*v1beta1.Ingress: unstructured cannot convert field labels [\#889](https://github.com/voyagermesh/voyager/issues/889) +- Add missing RBAC for service monitors in chart [\#958](https://github.com/voyagermesh/voyager/pull/958) ([tamalsaha](https://github.com/tamalsaha)) +- Run service monitor informer in its own go routine. [\#929](https://github.com/voyagermesh/voyager/pull/929) ([tamalsaha](https://github.com/tamalsaha)) +- Various fixes and improved logging [\#928](https://github.com/voyagermesh/voyager/pull/928) ([tamalsaha](https://github.com/tamalsaha)) +- Use user provided cookie name for default backend [\#920](https://github.com/voyagermesh/voyager/pull/920) ([tamalsaha](https://github.com/tamalsaha)) +- Fixed ingress finalizer [\#917](https://github.com/voyagermesh/voyager/pull/917) ([diptadas](https://github.com/diptadas)) +- Detect change when deletion timestamp is set for Ingress [\#916](https://github.com/voyagermesh/voyager/pull/916) ([tamalsaha](https://github.com/tamalsaha)) + +**Closed issues:** + +- voyager.sh install file now fails for k8s version below 1.9.0 [\#955](https://github.com/voyagermesh/voyager/issues/955) +- Support LB type in Openstack [\#930](https://github.com/voyagermesh/voyager/issues/930) +- Deployment model of voyager a bit overcomplex? [\#924](https://github.com/voyagermesh/voyager/issues/924) +- HTTP to HTTPS redirect [\#923](https://github.com/voyagermesh/voyager/issues/923) +- OpenStack support [\#669](https://github.com/voyagermesh/voyager/issues/669) +- Expose HAProxy config template var w/ Voyager deployment.spec.replicas [\#517](https://github.com/voyagermesh/voyager/issues/517) +- Improve AWS support [\#163](https://github.com/voyagermesh/voyager/issues/163) +- Use alpine as the base image for haproxy [\#108](https://github.com/voyagermesh/voyager/issues/108) +- Truly Seamless Reloads with HAProxy [\#89](https://github.com/voyagermesh/voyager/issues/89) + +**Merged pull requests:** + +- Revendor dependencies [\#957](https://github.com/voyagermesh/voyager/pull/957) ([tamalsaha](https://github.com/tamalsaha)) +- Fix install instruction for minikube 0.24.x \(Kube 1.8.0\) [\#956](https://github.com/voyagermesh/voyager/pull/956) ([tamalsaha](https://github.com/tamalsaha)) +- Skip downloading onessl if already exists [\#953](https://github.com/voyagermesh/voyager/pull/953) ([tamalsaha](https://github.com/tamalsaha)) +- Revendor jsonpatch library [\#952](https://github.com/voyagermesh/voyager/pull/952) ([tamalsaha](https://github.com/tamalsaha)) +- Add front matter for changelog [\#951](https://github.com/voyagermesh/voyager/pull/951) ([tamalsaha](https://github.com/tamalsaha)) +- Use appscode/kubernetes-webhook-util [\#950](https://github.com/voyagermesh/voyager/pull/950) ([tamalsaha](https://github.com/tamalsaha)) +- Reorg objects deleted in uninstall command [\#949](https://github.com/voyagermesh/voyager/pull/949) ([tamalsaha](https://github.com/tamalsaha)) +- Fixed nodeport-errorfile test [\#948](https://github.com/voyagermesh/voyager/pull/948) ([diptadas](https://github.com/diptadas)) +- Fixed haproxy duplicate logging [\#947](https://github.com/voyagermesh/voyager/pull/947) ([diptadas](https://github.com/diptadas)) +- Revendor webhook api [\#944](https://github.com/voyagermesh/voyager/pull/944) ([tamalsaha](https://github.com/tamalsaha)) +- Use correct queue for ingress [\#942](https://github.com/voyagermesh/voyager/pull/942) ([tamalsaha](https://github.com/tamalsaha)) +- Mention how to handle wildcard domains in documentation [\#938](https://github.com/voyagermesh/voyager/pull/938) ([hofmeister](https://github.com/hofmeister)) +- Add links for badges [\#937](https://github.com/voyagermesh/voyager/pull/937) ([tamalsaha](https://github.com/tamalsaha)) +- Install deps using glide in travis [\#936](https://github.com/voyagermesh/voyager/pull/936) ([tamalsaha](https://github.com/tamalsaha)) +- Add travis.yaml [\#935](https://github.com/voyagermesh/voyager/pull/935) ([tamalsaha](https://github.com/tamalsaha)) +- Add badge for docker pull stats [\#934](https://github.com/voyagermesh/voyager/pull/934) ([tamalsaha](https://github.com/tamalsaha)) +- Update docs for 6.0.0 [\#932](https://github.com/voyagermesh/voyager/pull/932) ([tamalsaha](https://github.com/tamalsaha)) +- Document how to create internal LB in openstack [\#931](https://github.com/voyagermesh/voyager/pull/931) ([tamalsaha](https://github.com/tamalsaha)) +- Fix typo in README [\#927](https://github.com/voyagermesh/voyager/pull/927) ([shaneog](https://github.com/shaneog)) +- Update overview.md [\#926](https://github.com/voyagermesh/voyager/pull/926) ([bewiwi](https://github.com/bewiwi)) +- Add "New to Voyager" header [\#922](https://github.com/voyagermesh/voyager/pull/922) ([tamalsaha](https://github.com/tamalsaha)) +- Add --purge flag [\#921](https://github.com/voyagermesh/voyager/pull/921) ([tamalsaha](https://github.com/tamalsaha)) +- Make headerRule, rewriteRule plural [\#919](https://github.com/voyagermesh/voyager/pull/919) ([tamalsaha](https://github.com/tamalsaha)) +- Make it clear that installer is a single command [\#915](https://github.com/voyagermesh/voyager/pull/915) ([tamalsaha](https://github.com/tamalsaha)) + +## [6.0.0-rc.2](https://github.com/voyagermesh/voyager/tree/6.0.0-rc.2) (2018-03-05) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/6.0.0-rc.1...6.0.0-rc.2) + +**Merged pull requests:** + +- Update docs that --rbac is default on [\#914](https://github.com/voyagermesh/voyager/pull/914) ([tamalsaha](https://github.com/tamalsaha)) +- Enable RBAC by default in installer [\#913](https://github.com/voyagermesh/voyager/pull/913) ([tamalsaha](https://github.com/tamalsaha)) +- Fix installer [\#912](https://github.com/voyagermesh/voyager/pull/912) ([tamalsaha](https://github.com/tamalsaha)) +- Prepare docs for 6.0.0-rc.2 [\#911](https://github.com/voyagermesh/voyager/pull/911) ([tamalsaha](https://github.com/tamalsaha)) +- Stop using field selector in haproxy controller [\#910](https://github.com/voyagermesh/voyager/pull/910) ([tamalsaha](https://github.com/tamalsaha)) +- Update chart to match RBAC best practices for charts [\#909](https://github.com/voyagermesh/voyager/pull/909) ([tamalsaha](https://github.com/tamalsaha)) +- Add checks to installer script [\#908](https://github.com/voyagermesh/voyager/pull/908) ([tamalsaha](https://github.com/tamalsaha)) +- Cleanup admission webhook [\#907](https://github.com/voyagermesh/voyager/pull/907) ([tamalsaha](https://github.com/tamalsaha)) +- Update changelog for 6.0.0-rc.1 [\#905](https://github.com/voyagermesh/voyager/pull/905) ([tamalsaha](https://github.com/tamalsaha)) + +## [6.0.0-rc.1](https://github.com/voyagermesh/voyager/tree/6.0.0-rc.1) (2018-02-28) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/6.0.0-rc.0...6.0.0-rc.1) + +**Implemented enhancements:** + +- Source IP affinity [\#759](https://github.com/voyagermesh/voyager/issues/759) + +**Fixed bugs:** + +- basic auth remove on upgrade to 5.0.0-rc11 [\#873](https://github.com/voyagermesh/voyager/issues/873) +- whitelist did not work [\#866](https://github.com/voyagermesh/voyager/issues/866) +- Update voyager docs [\#50](https://github.com/voyagermesh/voyager/issues/50) + +**Closed issues:** + +- Update Prometheus integration [\#893](https://github.com/voyagermesh/voyager/issues/893) +- Disabling HSTS - doesn't work [\#881](https://github.com/voyagermesh/voyager/issues/881) +- Upgrade from 5.0.0-rc.11 to 6.0.0-rc.0 [\#876](https://github.com/voyagermesh/voyager/issues/876) +- AWS ELB Proxy IP forwarded for occurs errors [\#749](https://github.com/voyagermesh/voyager/issues/749) +- How to use voyager instead of kubernetes nginx ingress controller [\#742](https://github.com/voyagermesh/voyager/issues/742) +- RBAC for voyager [\#732](https://github.com/voyagermesh/voyager/issues/732) +- Document default mode does not work for minikube [\#545](https://github.com/voyagermesh/voyager/issues/545) +- Document how to use Host IP as external IP in minikube for LoadBalancer type Service [\#511](https://github.com/voyagermesh/voyager/issues/511) +- Document RBAC setup on installer page. [\#508](https://github.com/voyagermesh/voyager/issues/508) +- Document external-dns configuration [\#355](https://github.com/voyagermesh/voyager/issues/355) +- Document why each ingress creates a new HAProxy in voyager [\#331](https://github.com/voyagermesh/voyager/issues/331) + +**Merged pull requests:** + +- Prepare docs for 6.0.0-rc.1 [\#904](https://github.com/voyagermesh/voyager/pull/904) ([tamalsaha](https://github.com/tamalsaha)) +- Fix service name in chart [\#903](https://github.com/voyagermesh/voyager/pull/903) ([tamalsaha](https://github.com/tamalsaha)) +- Update links to latest release [\#901](https://github.com/voyagermesh/voyager/pull/901) ([tamalsaha](https://github.com/tamalsaha)) +- Support --enable-admission-webhook=false [\#900](https://github.com/voyagermesh/voyager/pull/900) ([tamalsaha](https://github.com/tamalsaha)) +- Support multiple webhooks of same apiversion [\#899](https://github.com/voyagermesh/voyager/pull/899) ([tamalsaha](https://github.com/tamalsaha)) +- Sync chart to stable charts repo [\#898](https://github.com/voyagermesh/voyager/pull/898) ([tamalsaha](https://github.com/tamalsaha)) +- Document Prometheus integration [\#896](https://github.com/voyagermesh/voyager/pull/896) ([tamalsaha](https://github.com/tamalsaha)) +- Improve docs [\#895](https://github.com/voyagermesh/voyager/pull/895) ([tamalsaha](https://github.com/tamalsaha)) +- Update haproxy exporter [\#894](https://github.com/voyagermesh/voyager/pull/894) ([tamalsaha](https://github.com/tamalsaha)) +- Document user facing RBAC roles [\#892](https://github.com/voyagermesh/voyager/pull/892) ([tamalsaha](https://github.com/tamalsaha)) +- Skip generating UpdateStatus method [\#887](https://github.com/voyagermesh/voyager/pull/887) ([tamalsaha](https://github.com/tamalsaha)) +- Delete internal types [\#886](https://github.com/voyagermesh/voyager/pull/886) ([tamalsaha](https://github.com/tamalsaha)) +- Use official code generator scripts [\#885](https://github.com/voyagermesh/voyager/pull/885) ([tamalsaha](https://github.com/tamalsaha)) +- Use HAProxy 1.7.10 [\#884](https://github.com/voyagermesh/voyager/pull/884) ([tamalsaha](https://github.com/tamalsaha)) +- Move node selector to Ingress spec [\#883](https://github.com/voyagermesh/voyager/pull/883) ([tamalsaha](https://github.com/tamalsaha)) +- Only check NodePort if provided [\#880](https://github.com/voyagermesh/voyager/pull/880) ([tamalsaha](https://github.com/tamalsaha)) +- Create user facing aggregate roles [\#879](https://github.com/voyagermesh/voyager/pull/879) ([tamalsaha](https://github.com/tamalsaha)) +- Use rbac/v1 api [\#878](https://github.com/voyagermesh/voyager/pull/878) ([tamalsaha](https://github.com/tamalsaha)) +- Use github.com/pkg/errors [\#877](https://github.com/voyagermesh/voyager/pull/877) ([tamalsaha](https://github.com/tamalsaha)) +- Update docs for supported annotations [\#871](https://github.com/voyagermesh/voyager/pull/871) ([diptadas](https://github.com/diptadas)) + +## [6.0.0-rc.0](https://github.com/voyagermesh/voyager/tree/6.0.0-rc.0) (2018-02-14) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/5.0.0-rc.11...6.0.0-rc.0) + +**Fixed bugs:** + +- Document GKE cluster RBAC setup [\#564](https://github.com/voyagermesh/voyager/issues/564) + +**Closed issues:** + +- LoadBalancer vs NodePort with manually setup LB \(haproxy.cfg difference\) [\#867](https://github.com/voyagermesh/voyager/issues/867) +- Ignore Rule if backend service is missing [\#848](https://github.com/voyagermesh/voyager/issues/848) +- Failed to list ServiceMonitor [\#847](https://github.com/voyagermesh/voyager/issues/847) +- Uninstall deletes object only from kube-system namespace [\#846](https://github.com/voyagermesh/voyager/issues/846) +- Multi backends for one domain [\#833](https://github.com/voyagermesh/voyager/issues/833) +- TCP Ingress Health Check Annotations not Working [\#832](https://github.com/voyagermesh/voyager/issues/832) +- DNS-01 Challenge provider missing key in credential [\#821](https://github.com/voyagermesh/voyager/issues/821) +- Allow users to specify backend names [\#819](https://github.com/voyagermesh/voyager/issues/819) +- Should we make acl names part of the "api"? [\#818](https://github.com/voyagermesh/voyager/issues/818) +- ACL generation: Support cookie matching [\#817](https://github.com/voyagermesh/voyager/issues/817) +- Default http-\>https redirect turns DELETE \(and possibly other HTTP verbs\) into GET [\#816](https://github.com/voyagermesh/voyager/issues/816) +- Panic in runtime.go when using TLS [\#814](https://github.com/voyagermesh/voyager/issues/814) +- ACL generation: Support multiple path matching per rule [\#813](https://github.com/voyagermesh/voyager/issues/813) +- ACL in haproxy not created correctly when an ingress has a single host rule [\#807](https://github.com/voyagermesh/voyager/issues/807) +- Constant "Back-off restarting failed container" for a nonexistent bad ingress. [\#797](https://github.com/voyagermesh/voyager/issues/797) +- When a pod linked to a service is deleted, Voyager Operator crashes and does not update ConfigMap [\#790](https://github.com/voyagermesh/voyager/issues/790) +- Pod reboot loop with "One or more Ingress objects are invalid" [\#779](https://github.com/voyagermesh/voyager/issues/779) +- Using Voyager and Let's Encrypt in multiple Kubernetes clusters in different regions [\#687](https://github.com/voyagermesh/voyager/issues/687) +- Self-referential Ingress and Certificate must be done in order [\#661](https://github.com/voyagermesh/voyager/issues/661) +- GRPC example [\#604](https://github.com/voyagermesh/voyager/issues/604) +- Websocket example [\#603](https://github.com/voyagermesh/voyager/issues/603) +- Support direct scrapping via Prometheus [\#593](https://github.com/voyagermesh/voyager/issues/593) +- Use field selectors in TLS mounters [\#558](https://github.com/voyagermesh/voyager/issues/558) +- Update Voyager to use workqueue [\#535](https://github.com/voyagermesh/voyager/issues/535) +- Change BackendRule to BackendRules [\#468](https://github.com/voyagermesh/voyager/issues/468) +- Use Kutil based PATCH to apply changes [\#457](https://github.com/voyagermesh/voyager/issues/457) +- Use Secret to store HAProxy.conf [\#447](https://github.com/voyagermesh/voyager/issues/447) +- voyager check should check annotations and dump the parsed annotations [\#367](https://github.com/voyagermesh/voyager/issues/367) +- Document IAM permission needed for HostPort mode [\#358](https://github.com/voyagermesh/voyager/issues/358) +- Canonicalize TemplateData [\#348](https://github.com/voyagermesh/voyager/issues/348) + +**Merged pull requests:** + +- Remove bad acl from haproxy template [\#875](https://github.com/voyagermesh/voyager/pull/875) ([tamalsaha](https://github.com/tamalsaha)) +- annotations.md typo fix [\#874](https://github.com/voyagermesh/voyager/pull/874) ([mu5h3r](https://github.com/mu5h3r)) +- Use service port by default for LB type nodeport [\#870](https://github.com/voyagermesh/voyager/pull/870) ([diptadas](https://github.com/diptadas)) +- Fixed configmap cleanup when ingress deleted [\#869](https://github.com/voyagermesh/voyager/pull/869) ([diptadas](https://github.com/diptadas)) +- Removed deprecated sticky annotation [\#868](https://github.com/voyagermesh/voyager/pull/868) ([diptadas](https://github.com/diptadas)) +- Pass client config to webhook [\#865](https://github.com/voyagermesh/voyager/pull/865) ([tamalsaha](https://github.com/tamalsaha)) +- Fixed e2e tests [\#863](https://github.com/voyagermesh/voyager/pull/863) ([diptadas](https://github.com/diptadas)) +- Update charts to support api registration [\#862](https://github.com/voyagermesh/voyager/pull/862) ([tamalsaha](https://github.com/tamalsaha)) +- Use ${} form for onessl envsubst [\#861](https://github.com/voyagermesh/voyager/pull/861) ([tamalsaha](https://github.com/tamalsaha)) +- Ignore error for missing backend services [\#860](https://github.com/voyagermesh/voyager/pull/860) ([diptadas](https://github.com/diptadas)) +- Make operator run locally [\#859](https://github.com/voyagermesh/voyager/pull/859) ([tamalsaha](https://github.com/tamalsaha)) +- Update comment regarding RBAC [\#858](https://github.com/voyagermesh/voyager/pull/858) ([bcyrill](https://github.com/bcyrill)) +- Don't append duplicate group versions [\#857](https://github.com/voyagermesh/voyager/pull/857) ([tamalsaha](https://github.com/tamalsaha)) +- Merge admission webhook and operator into one binary [\#856](https://github.com/voyagermesh/voyager/pull/856) ([tamalsaha](https://github.com/tamalsaha)) +- Install admission webhook for Kubernetes \>=1.9.0 [\#855](https://github.com/voyagermesh/voyager/pull/855) ([tamalsaha](https://github.com/tamalsaha)) +- Merge uninstall script into the voyager.sh script [\#854](https://github.com/voyagermesh/voyager/pull/854) ([tamalsaha](https://github.com/tamalsaha)) +- Fixed panic during annotation parsing [\#853](https://github.com/voyagermesh/voyager/pull/853) ([diptadas](https://github.com/diptadas)) +- Checked timeout and dns-resolver maps [\#852](https://github.com/voyagermesh/voyager/pull/852) ([diptadas](https://github.com/diptadas)) +- Add missing RBAC for ServiceMonitor [\#851](https://github.com/voyagermesh/voyager/pull/851) ([tamalsaha](https://github.com/tamalsaha)) +- Document GKE permission options [\#850](https://github.com/voyagermesh/voyager/pull/850) ([tamalsaha](https://github.com/tamalsaha)) +- Ignore --run-on-master flags for GKE [\#849](https://github.com/voyagermesh/voyager/pull/849) ([tamalsaha](https://github.com/tamalsaha)) +- Change BackendRule to BackendRules [\#845](https://github.com/voyagermesh/voyager/pull/845) ([tamalsaha](https://github.com/tamalsaha)) +- Type check for annotations in validator [\#844](https://github.com/voyagermesh/voyager/pull/844) ([diptadas](https://github.com/diptadas)) +- Revise host and path acl names to make them part of "api" [\#843](https://github.com/voyagermesh/voyager/pull/843) ([tamalsaha](https://github.com/tamalsaha)) +- Preserve original HTTP verb on redirect [\#842](https://github.com/voyagermesh/voyager/pull/842) ([tamalsaha](https://github.com/tamalsaha)) +- Only assign deployment replicas initially [\#841](https://github.com/voyagermesh/voyager/pull/841) ([diptadas](https://github.com/diptadas)) +- Fix DNS-01 Challenge provider missing key in credential [\#840](https://github.com/voyagermesh/voyager/pull/840) ([tamalsaha](https://github.com/tamalsaha)) +- Checked for invalid backend service name in validator [\#839](https://github.com/voyagermesh/voyager/pull/839) ([diptadas](https://github.com/diptadas)) +- Removed panic in operator for bad-ingress [\#837](https://github.com/voyagermesh/voyager/pull/837) ([diptadas](https://github.com/diptadas)) +- Checked nil backend before assigning [\#836](https://github.com/voyagermesh/voyager/pull/836) ([diptadas](https://github.com/diptadas)) +- Copy generic-admission-server code into pkg [\#835](https://github.com/voyagermesh/voyager/pull/835) ([tamalsaha](https://github.com/tamalsaha)) +- Log TemplateData in debug mode [\#834](https://github.com/voyagermesh/voyager/pull/834) ([tamalsaha](https://github.com/tamalsaha)) +- Removed maps from template data [\#831](https://github.com/voyagermesh/voyager/pull/831) ([diptadas](https://github.com/diptadas)) +- Prepare docs for 6.0.0-alpha.0 [\#830](https://github.com/voyagermesh/voyager/pull/830) ([tamalsaha](https://github.com/tamalsaha)) +- Support private docker registry in installer [\#829](https://github.com/voyagermesh/voyager/pull/829) ([tamalsaha](https://github.com/tamalsaha)) +- Add ValidatingAdmissionWebhook for Voyager CRDs [\#828](https://github.com/voyagermesh/voyager/pull/828) ([tamalsaha](https://github.com/tamalsaha)) +- Use kubectl auth reconcile in installer script [\#827](https://github.com/voyagermesh/voyager/pull/827) ([tamalsaha](https://github.com/tamalsaha)) +- Update changelog [\#826](https://github.com/voyagermesh/voyager/pull/826) ([tamalsaha](https://github.com/tamalsaha)) +- Update client-go to 6.0.0 [\#825](https://github.com/voyagermesh/voyager/pull/825) ([tamalsaha](https://github.com/tamalsaha)) +- Update copyright year to 2018 [\#824](https://github.com/voyagermesh/voyager/pull/824) ([tamalsaha](https://github.com/tamalsaha)) +- Merge tls-mounter & kloader into haproxy-controller [\#823](https://github.com/voyagermesh/voyager/pull/823) ([tamalsaha](https://github.com/tamalsaha)) +- Updating kube-mon so service-monitor-endpoint-port is optional [\#822](https://github.com/voyagermesh/voyager/pull/822) ([jeffersongirao](https://github.com/jeffersongirao)) +- Fix unit tests [\#820](https://github.com/voyagermesh/voyager/pull/820) ([jeffersongirao](https://github.com/jeffersongirao)) +- Use deterministic-suffix instead of random-suffix in backend name [\#815](https://github.com/voyagermesh/voyager/pull/815) ([diptadas](https://github.com/diptadas)) +- Ignored not-found error for DNS resolver annotations [\#812](https://github.com/voyagermesh/voyager/pull/812) ([diptadas](https://github.com/diptadas)) +- Add prometheus flags to command that uses it [\#810](https://github.com/voyagermesh/voyager/pull/810) ([tamalsaha](https://github.com/tamalsaha)) +- Improve concepts docs [\#809](https://github.com/voyagermesh/voyager/pull/809) ([tamalsaha](https://github.com/tamalsaha)) +- Revendor coreos prometheus operator 0.16.0 [\#808](https://github.com/voyagermesh/voyager/pull/808) ([tamalsaha](https://github.com/tamalsaha)) +- Revendor log wrapper [\#804](https://github.com/voyagermesh/voyager/pull/804) ([tamalsaha](https://github.com/tamalsaha)) +- Implement work-queue in operator [\#803](https://github.com/voyagermesh/voyager/pull/803) ([diptadas](https://github.com/diptadas)) +- Fix links in chart [\#802](https://github.com/voyagermesh/voyager/pull/802) ([tamalsaha](https://github.com/tamalsaha)) +- Add changelog [\#801](https://github.com/voyagermesh/voyager/pull/801) ([tamalsaha](https://github.com/tamalsaha)) + +## [5.0.0-rc.11](https://github.com/voyagermesh/voyager/tree/5.0.0-rc.11) (2018-01-04) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/5.0.0-rc.10...5.0.0-rc.11) + +**Fixed bugs:** + +- Avoid unnecessary config reloads in HAProxy [\#512](https://github.com/voyagermesh/voyager/issues/512) +- Allow adding new domain to cert crd [\#788](https://github.com/voyagermesh/voyager/pull/788) ([tamalsaha](https://github.com/tamalsaha)) + +**Closed issues:** + +- Support all annotations under ingress.appscode.com key [\#791](https://github.com/voyagermesh/voyager/issues/791) +- expose port on host [\#778](https://github.com/voyagermesh/voyager/issues/778) +- Missing Ingress Annotation in Documentation [\#668](https://github.com/voyagermesh/voyager/issues/668) +- Support additional CORS headers [\#656](https://github.com/voyagermesh/voyager/issues/656) + +**Merged pull requests:** + +- Prepare docs for 5.0.0-rc.11 [\#799](https://github.com/voyagermesh/voyager/pull/799) ([tamalsaha](https://github.com/tamalsaha)) +- Reorganize docs for hosting on product site [\#798](https://github.com/voyagermesh/voyager/pull/798) ([tamalsaha](https://github.com/tamalsaha)) +- Detect client id from ENV [\#795](https://github.com/voyagermesh/voyager/pull/795) ([tamalsaha](https://github.com/tamalsaha)) +- Update dead links [\#794](https://github.com/voyagermesh/voyager/pull/794) ([ghost](https://github.com/ghost)) +- Support additional CORS headers [\#793](https://github.com/voyagermesh/voyager/pull/793) ([diptadas](https://github.com/diptadas)) +- Support ingress.appscode.com key for all annotations [\#792](https://github.com/voyagermesh/voyager/pull/792) ([diptadas](https://github.com/diptadas)) +- Use CertStore from kutil [\#789](https://github.com/voyagermesh/voyager/pull/789) ([tamalsaha](https://github.com/tamalsaha)) + +## [5.0.0-rc.10](https://github.com/voyagermesh/voyager/tree/5.0.0-rc.10) (2017-12-29) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/5.0.0-rc.9...5.0.0-rc.10) + +**Fixed bugs:** + +- Set selector for headless service of a HostPort ingress [\#785](https://github.com/voyagermesh/voyager/pull/785) ([tamalsaha](https://github.com/tamalsaha)) + +**Closed issues:** + +- Issues with ACME well-known paths [\#787](https://github.com/voyagermesh/voyager/issues/787) + +**Merged pull requests:** + +- Generate host acl correctly for `\*` host [\#786](https://github.com/voyagermesh/voyager/pull/786) ([tamalsaha](https://github.com/tamalsaha)) +- Add front matter for docs 5.0.0-rc.9 [\#784](https://github.com/voyagermesh/voyager/pull/784) ([sajibcse68](https://github.com/sajibcse68)) + +## [5.0.0-rc.9](https://github.com/voyagermesh/voyager/tree/5.0.0-rc.9) (2017-12-28) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/5.0.0-rc.8...5.0.0-rc.9) + +**Fixed bugs:** + +- Move Acme paths to top of path list [\#781](https://github.com/voyagermesh/voyager/pull/781) ([tamalsaha](https://github.com/tamalsaha)) + +**Closed issues:** + +- Baremetal setup not working at all [\#780](https://github.com/voyagermesh/voyager/issues/780) +- Patching voyager ingress fails [\#773](https://github.com/voyagermesh/voyager/issues/773) + +**Merged pull requests:** + +- Prepare docs for 5.0.0-rc.9 [\#782](https://github.com/voyagermesh/voyager/pull/782) ([tamalsaha](https://github.com/tamalsaha)) +- Use cmp methods from kutil [\#777](https://github.com/voyagermesh/voyager/pull/777) ([tamalsaha](https://github.com/tamalsaha)) +- Show how to run haproxy pods on master [\#776](https://github.com/voyagermesh/voyager/pull/776) ([tamalsaha](https://github.com/tamalsaha)) +- Use verb type to indicate mutation [\#775](https://github.com/voyagermesh/voyager/pull/775) ([tamalsaha](https://github.com/tamalsaha)) +- Use kube-mon repo [\#774](https://github.com/voyagermesh/voyager/pull/774) ([tamalsaha](https://github.com/tamalsaha)) + +## [5.0.0-rc.8](https://github.com/voyagermesh/voyager/tree/5.0.0-rc.8) (2017-12-20) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/5.0.0-rc.7...5.0.0-rc.8) + +**Fixed bugs:** + +- Fix backend name checking for haproxy template [\#771](https://github.com/voyagermesh/voyager/pull/771) ([tamalsaha](https://github.com/tamalsaha)) +- Fix installation instructions in guides [\#770](https://github.com/voyagermesh/voyager/pull/770) ([tamalsaha](https://github.com/tamalsaha)) +- Support wildcard in TLS searching [\#768](https://github.com/voyagermesh/voyager/pull/768) ([tamalsaha](https://github.com/tamalsaha)) +- Merge monitor service ports correctly [\#767](https://github.com/voyagermesh/voyager/pull/767) ([tamalsaha](https://github.com/tamalsaha)) + +**Merged pull requests:** + +- Update docs for 5.0.0-rc.8 [\#772](https://github.com/voyagermesh/voyager/pull/772) ([tamalsaha](https://github.com/tamalsaha)) +- Document how to use external-ip [\#769](https://github.com/voyagermesh/voyager/pull/769) ([tamalsaha](https://github.com/tamalsaha)) +- Update RBAC for analytics [\#766](https://github.com/voyagermesh/voyager/pull/766) ([tamalsaha](https://github.com/tamalsaha)) +- Set ClientID for analytics [\#765](https://github.com/voyagermesh/voyager/pull/765) ([tamalsaha](https://github.com/tamalsaha)) +- Rename tasks to guides [\#764](https://github.com/voyagermesh/voyager/pull/764) ([tamalsaha](https://github.com/tamalsaha)) +- Revise ingress docs [\#755](https://github.com/voyagermesh/voyager/pull/755) ([tamalsaha](https://github.com/tamalsaha)) + +## [5.0.0-rc.7](https://github.com/voyagermesh/voyager/tree/5.0.0-rc.7) (2017-12-13) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/5.0.0-rc.6...5.0.0-rc.7) + +**Closed issues:** + +- List of created ingresses? [\#745](https://github.com/voyagermesh/voyager/issues/745) +- create san cert with panic [\#744](https://github.com/voyagermesh/voyager/issues/744) + +**Merged pull requests:** + +- Prepare for 5.0.0-rc.7 release [\#757](https://github.com/voyagermesh/voyager/pull/757) ([tamalsaha](https://github.com/tamalsaha)) +- Installer for custom template [\#756](https://github.com/voyagermesh/voyager/pull/756) ([tamalsaha](https://github.com/tamalsaha)) +- Change left\_menu -\> menu\_name [\#748](https://github.com/voyagermesh/voyager/pull/748) ([tamalsaha](https://github.com/tamalsaha)) +- Fix panic when crt.status.LastIssuedCertificate is missing on renew [\#746](https://github.com/voyagermesh/voyager/pull/746) ([tamalsaha](https://github.com/tamalsaha)) +- Use RegisterCRDs from kutil [\#743](https://github.com/voyagermesh/voyager/pull/743) ([tamalsaha](https://github.com/tamalsaha)) +- Document updated cert manager [\#581](https://github.com/voyagermesh/voyager/pull/581) ([tamalsaha](https://github.com/tamalsaha)) + +## [5.0.0-rc.6](https://github.com/voyagermesh/voyager/tree/5.0.0-rc.6) (2017-12-05) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/5.0.0-rc.5...5.0.0-rc.6) + +**Merged pull requests:** + +- Use forked golang/x/oauth2 library [\#741](https://github.com/voyagermesh/voyager/pull/741) ([tamalsaha](https://github.com/tamalsaha)) +- Prepare docs for 5.0.0-rc.6 release [\#739](https://github.com/voyagermesh/voyager/pull/739) ([tamalsaha](https://github.com/tamalsaha)) +- Avoid duplicate ACLs for host [\#738](https://github.com/voyagermesh/voyager/pull/738) ([tamalsaha](https://github.com/tamalsaha)) +- Trim space from ACME user email [\#737](https://github.com/voyagermesh/voyager/pull/737) ([tamalsaha](https://github.com/tamalsaha)) +- Revendor dependencies [\#736](https://github.com/voyagermesh/voyager/pull/736) ([tamalsaha](https://github.com/tamalsaha)) + +## [5.0.0-rc.5](https://github.com/voyagermesh/voyager/tree/5.0.0-rc.5) (2017-12-01) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/5.0.0-rc.4...5.0.0-rc.5) + +**Fixed bugs:** + +- No certificates were found while parsing the bundle. [\#725](https://github.com/voyagermesh/voyager/issues/725) + +**Merged pull requests:** + +- Prepare docs for 5.0.0-rc.5 release [\#735](https://github.com/voyagermesh/voyager/pull/735) ([tamalsaha](https://github.com/tamalsaha)) +- Correctly encode cert for renewal. [\#734](https://github.com/voyagermesh/voyager/pull/734) ([tamalsaha](https://github.com/tamalsaha)) +- Add aliases for README file [\#731](https://github.com/voyagermesh/voyager/pull/731) ([sajibcse68](https://github.com/sajibcse68)) +- Update version in front matter for docs [\#730](https://github.com/voyagermesh/voyager/pull/730) ([tamalsaha](https://github.com/tamalsaha)) +- Add Docs Front Matter [\#728](https://github.com/voyagermesh/voyager/pull/728) ([sajibcse68](https://github.com/sajibcse68)) + +## [5.0.0-rc.4](https://github.com/voyagermesh/voyager/tree/5.0.0-rc.4) (2017-11-28) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/5.0.0-rc.3...5.0.0-rc.4) + +**Implemented enhancements:** + +- Print namespace of missing service name [\#710](https://github.com/voyagermesh/voyager/issues/710) +- Support Health Check for backend [\#683](https://github.com/voyagermesh/voyager/issues/683) +- Allow send-ing proxy header to backend [\#164](https://github.com/voyagermesh/voyager/issues/164) + +**Fixed bugs:** + +- Check voyager respects --ingress-class flag [\#711](https://github.com/voyagermesh/voyager/issues/711) +- Adding annotation `ingress.kubernetes.io/hsts` makes voyager generate invalid haproxy config [\#701](https://github.com/voyagermesh/voyager/issues/701) +- Perform ssl-redirect after matching host [\#691](https://github.com/voyagermesh/voyager/issues/691) +- haproxy.cfg:42 rsprep error [\#678](https://github.com/voyagermesh/voyager/issues/678) +- Fix ssl-passthrough [\#665](https://github.com/voyagermesh/voyager/issues/665) +- HTTP -\> HTTPS redirection does not work in 1.8 cluster with AWS cert manager [\#639](https://github.com/voyagermesh/voyager/issues/639) +- Don't use backend name to generate acl name [\#726](https://github.com/voyagermesh/voyager/pull/726) ([tamalsaha](https://github.com/tamalsaha)) +- Unconditionally set headers defined in Ingress [\#717](https://github.com/voyagermesh/voyager/pull/717) ([tamalsaha](https://github.com/tamalsaha)) +- Correctly handle updated ingress.class annotation [\#715](https://github.com/voyagermesh/voyager/pull/715) ([tamalsaha](https://github.com/tamalsaha)) +- Support aws or route53 as providers which read dns credential from ENV [\#712](https://github.com/voyagermesh/voyager/pull/712) ([tamalsaha](https://github.com/tamalsaha)) + +**Closed issues:** + +- Stop cross namespace support when restricted to one namespace [\#698](https://github.com/voyagermesh/voyager/issues/698) +- One or more Ingress objects are invalid [\#697](https://github.com/voyagermesh/voyager/issues/697) +- Cannot create TCP ingress in k8s 1.8.2 and voyager 5.0.0-rc3 [\#696](https://github.com/voyagermesh/voyager/issues/696) +- monitor openstack [\#694](https://github.com/voyagermesh/voyager/issues/694) +- Configure HAProxy to terminate SSL and send PROXYv2 [\#692](https://github.com/voyagermesh/voyager/issues/692) +- voyager 5-rc3 non kube-system ingress , error [\#689](https://github.com/voyagermesh/voyager/issues/689) +- error creating a very simple object on version 5-rc3 [\#688](https://github.com/voyagermesh/voyager/issues/688) +- Support ExternalIPs [\#686](https://github.com/voyagermesh/voyager/issues/686) +- Support rewrite-target annotation [\#657](https://github.com/voyagermesh/voyager/issues/657) +- Document importance to order of paths [\#422](https://github.com/voyagermesh/voyager/issues/422) + +**Merged pull requests:** + +- Cleanup wildcard in ACL name [\#727](https://github.com/voyagermesh/voyager/pull/727) ([tamalsaha](https://github.com/tamalsaha)) +- Load AWS\_HOSTED\_ZONE\_ID if provided by user [\#724](https://github.com/voyagermesh/voyager/pull/724) ([tamalsaha](https://github.com/tamalsaha)) +- Prepare docs for 5.0.0-rc.4 [\#723](https://github.com/voyagermesh/voyager/pull/723) ([tamalsaha](https://github.com/tamalsaha)) +- Make voyager YAMLs installable from internet [\#722](https://github.com/voyagermesh/voyager/pull/722) ([tamalsaha](https://github.com/tamalsaha)) +- Add front matter for voyager cli ref [\#721](https://github.com/voyagermesh/voyager/pull/721) ([tamalsaha](https://github.com/tamalsaha)) +- Support rewrite-target annotation [\#720](https://github.com/voyagermesh/voyager/pull/720) ([tamalsaha](https://github.com/tamalsaha)) +- Print namespace of missing service name [\#716](https://github.com/voyagermesh/voyager/pull/716) ([tamalsaha](https://github.com/tamalsaha)) +- Use http-response set-header instead of rspadd [\#714](https://github.com/voyagermesh/voyager/pull/714) ([tamalsaha](https://github.com/tamalsaha)) +- Use const for test domain [\#713](https://github.com/voyagermesh/voyager/pull/713) ([tamalsaha](https://github.com/tamalsaha)) +- Don't allow cross ns backend when voyager is restricted to own ns [\#709](https://github.com/voyagermesh/voyager/pull/709) ([tamalsaha](https://github.com/tamalsaha)) +- Document azure support for load-balancer-ip [\#708](https://github.com/voyagermesh/voyager/pull/708) ([tamalsaha](https://github.com/tamalsaha)) +- Convert rules for SSL Passthrough [\#706](https://github.com/voyagermesh/voyager/pull/706) ([diptadas](https://github.com/diptadas)) +- Keep all newlines in haproxy.cfg [\#705](https://github.com/voyagermesh/voyager/pull/705) ([tamalsaha](https://github.com/tamalsaha)) +- Revise StatsAccessor interface [\#704](https://github.com/voyagermesh/voyager/pull/704) ([tamalsaha](https://github.com/tamalsaha)) +- Support direct scrapping via Prometheus [\#703](https://github.com/voyagermesh/voyager/pull/703) ([tamalsaha](https://github.com/tamalsaha)) +- Perform ssl-redirect after matching host [\#702](https://github.com/voyagermesh/voyager/pull/702) ([tamalsaha](https://github.com/tamalsaha)) +- Fix build [\#700](https://github.com/voyagermesh/voyager/pull/700) ([tamalsaha](https://github.com/tamalsaha)) +- Support PROXY protocol in test server [\#699](https://github.com/voyagermesh/voyager/pull/699) ([diptadas](https://github.com/diptadas)) +- Enable server health check using service annotations and backend rules [\#695](https://github.com/voyagermesh/voyager/pull/695) ([diptadas](https://github.com/diptadas)) +- Add to backends the options for send-proxy variants for server. [\#693](https://github.com/voyagermesh/voyager/pull/693) ([drf](https://github.com/drf)) +- Support ExternalIPs [\#690](https://github.com/voyagermesh/voyager/pull/690) ([tamalsaha](https://github.com/tamalsaha)) +- Use DeepCopy with PATCH calls. [\#685](https://github.com/voyagermesh/voyager/pull/685) ([tamalsaha](https://github.com/tamalsaha)) +- Fix template rendering [\#682](https://github.com/voyagermesh/voyager/pull/682) ([tamalsaha](https://github.com/tamalsaha)) +- Move chart inside stable folder [\#681](https://github.com/voyagermesh/voyager/pull/681) ([tamalsaha](https://github.com/tamalsaha)) +- Make chart namespaced [\#680](https://github.com/voyagermesh/voyager/pull/680) ([tamalsaha](https://github.com/tamalsaha)) +- Allow for binding HTTP or TCP ingress rules to specific addresses [\#649](https://github.com/voyagermesh/voyager/pull/649) ([deuill](https://github.com/deuill)) + +## [5.0.0-rc.3](https://github.com/voyagermesh/voyager/tree/5.0.0-rc.3) (2017-11-02) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/5.0.0-rc.2...5.0.0-rc.3) + +**Closed issues:** + +- Support imagePullSecrets for HAProxy pods [\#673](https://github.com/voyagermesh/voyager/issues/673) +- Document how to configure DNS in Hostport / NodePort mode [\#354](https://github.com/voyagermesh/voyager/issues/354) + +**Merged pull requests:** + +- Add image/tag variables in chart [\#677](https://github.com/voyagermesh/voyager/pull/677) ([tamalsaha](https://github.com/tamalsaha)) +- Detect change in imagePullSecrets [\#676](https://github.com/voyagermesh/voyager/pull/676) ([tamalsaha](https://github.com/tamalsaha)) +- Prepare docs for 5.0.0-rc.3 [\#675](https://github.com/voyagermesh/voyager/pull/675) ([tamalsaha](https://github.com/tamalsaha)) +- Add ImagePullSecrets in Ingress [\#674](https://github.com/voyagermesh/voyager/pull/674) ([tamalsaha](https://github.com/tamalsaha)) + +## [5.0.0-rc.2](https://github.com/voyagermesh/voyager/tree/5.0.0-rc.2) (2017-11-02) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/5.0.0-rc.1...5.0.0-rc.2) + +**Fixed bugs:** + +- Add `deletecollection` permission to voyager operator [\#666](https://github.com/voyagermesh/voyager/pull/666) ([tamalsaha](https://github.com/tamalsaha)) + +**Merged pull requests:** + +- Support GoDaddy DNS provider [\#672](https://github.com/voyagermesh/voyager/pull/672) ([tamalsaha](https://github.com/tamalsaha)) +- Support openstack provider [\#671](https://github.com/voyagermesh/voyager/pull/671) ([tamalsaha](https://github.com/tamalsaha)) +- Support `ingress.appscode.com/keep-source-ip` annotation for NodePort mode [\#667](https://github.com/voyagermesh/voyager/pull/667) ([tamalsaha](https://github.com/tamalsaha)) + +## [5.0.0-rc.1](https://github.com/voyagermesh/voyager/tree/5.0.0-rc.1) (2017-10-26) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/5.0.0-alpha.1...5.0.0-rc.1) + +**Fixed bugs:** + +- TCP mode does not work in port 80 [\#663](https://github.com/voyagermesh/voyager/issues/663) + +**Merged pull requests:** + +- Enable TCP mode in port 80 [\#664](https://github.com/voyagermesh/voyager/pull/664) ([tamalsaha](https://github.com/tamalsaha)) +- Remove unused fields from LocalTypedReference [\#662](https://github.com/voyagermesh/voyager/pull/662) ([tamalsaha](https://github.com/tamalsaha)) + +## [5.0.0-alpha.1](https://github.com/voyagermesh/voyager/tree/5.0.0-alpha.1) (2017-10-24) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/5.0.0-rc.0...5.0.0-alpha.1) + +**Fixed bugs:** + +- Avoid redirecting ACME requests to https scheme [\#660](https://github.com/voyagermesh/voyager/pull/660) ([tamalsaha](https://github.com/tamalsaha)) + +## [5.0.0-rc.0](https://github.com/voyagermesh/voyager/tree/5.0.0-rc.0) (2017-10-23) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/4.0.0-rc.18...5.0.0-rc.0) + +**Implemented enhancements:** + +- Allow for binding frontends to specific addresses [\#602](https://github.com/voyagermesh/voyager/issues/602) + +**Fixed bugs:** + +- Fix Certificate Test Name [\#648](https://github.com/voyagermesh/voyager/pull/648) ([sadlil](https://github.com/sadlil)) + +**Merged pull requests:** + +- Use typed versioned client for CRD [\#659](https://github.com/voyagermesh/voyager/pull/659) ([tamalsaha](https://github.com/tamalsaha)) +- Use prometheus-operator v1 api/client [\#658](https://github.com/voyagermesh/voyager/pull/658) ([tamalsaha](https://github.com/tamalsaha)) +- Fix project name in header for auto generated files [\#655](https://github.com/voyagermesh/voyager/pull/655) ([tamalsaha](https://github.com/tamalsaha)) +- Document the important of order of paths [\#654](https://github.com/voyagermesh/voyager/pull/654) ([tamalsaha](https://github.com/tamalsaha)) +- Prepare docs for 5.0.0-rc.0 [\#653](https://github.com/voyagermesh/voyager/pull/653) ([tamalsaha](https://github.com/tamalsaha)) +- Update prometheus-operator to implement DeepCopy\(\) [\#652](https://github.com/voyagermesh/voyager/pull/652) ([tamalsaha](https://github.com/tamalsaha)) +- Fix NPE in time.Equal method [\#651](https://github.com/voyagermesh/voyager/pull/651) ([tamalsaha](https://github.com/tamalsaha)) +- Change `k8s.io/api/core/v1` pkg alias to core [\#650](https://github.com/voyagermesh/voyager/pull/650) ([tamalsaha](https://github.com/tamalsaha)) +- Use client-go 5.x [\#629](https://github.com/voyagermesh/voyager/pull/629) ([tamalsaha](https://github.com/tamalsaha)) +- Generate openapi spec [\#596](https://github.com/voyagermesh/voyager/pull/596) ([tamalsaha](https://github.com/tamalsaha)) + +## [4.0.0-rc.18](https://github.com/voyagermesh/voyager/tree/4.0.0-rc.18) (2017-10-18) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/4.0.0-rc.17...4.0.0-rc.18) + +**Closed issues:** + +- Operator doesn't create CRD groups [\#643](https://github.com/voyagermesh/voyager/issues/643) + +## [4.0.0-rc.17](https://github.com/voyagermesh/voyager/tree/4.0.0-rc.17) (2017-10-18) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/4.0.0-rc.16...4.0.0-rc.17) + +**Closed issues:** + +- Up kubernetes/client-go QPS and Burst config [\#640](https://github.com/voyagermesh/voyager/issues/640) + +**Merged pull requests:** + +- Raise kubernetes/client-go QPS and Burst config [\#641](https://github.com/voyagermesh/voyager/pull/641) ([tamalsaha](https://github.com/tamalsaha)) + +## [4.0.0-rc.16](https://github.com/voyagermesh/voyager/tree/4.0.0-rc.16) (2017-10-16) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/4.0.0-rc.15...4.0.0-rc.16) + +**Fixed bugs:** + +- haproxy points to wrong file on tcp+tls config [\#630](https://github.com/voyagermesh/voyager/issues/630) + +**Closed issues:** + +- Support `ingress.appscode.com/type: internal` [\#627](https://github.com/voyagermesh/voyager/issues/627) + +**Merged pull requests:** + +- Implement `ingress.appscode.com/type: internal` [\#636](https://github.com/voyagermesh/voyager/pull/636) ([tamalsaha](https://github.com/tamalsaha)) + +## [4.0.0-rc.15](https://github.com/voyagermesh/voyager/tree/4.0.0-rc.15) (2017-10-16) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/4.0.0-rc.14...4.0.0-rc.15) + +**Fixed bugs:** + +- Fix tcp frontend template [\#634](https://github.com/voyagermesh/voyager/pull/634) ([tamalsaha](https://github.com/tamalsaha)) + +**Merged pull requests:** + +- Update chart helper truncate length [\#633](https://github.com/voyagermesh/voyager/pull/633) ([tamalsaha](https://github.com/tamalsaha)) + +## [4.0.0-rc.14](https://github.com/voyagermesh/voyager/tree/4.0.0-rc.14) (2017-10-16) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/4.0.0-rc.13...4.0.0-rc.14) + +**Merged pull requests:** + +- Rename SecretName to CertFile [\#632](https://github.com/voyagermesh/voyager/pull/632) ([tamalsaha](https://github.com/tamalsaha)) + +## [4.0.0-rc.13](https://github.com/voyagermesh/voyager/tree/4.0.0-rc.13) (2017-10-16) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/4.0.0-rc.12...4.0.0-rc.13) + +**Fixed bugs:** + +- Replace reflect.Equal with github.com/google/go-cmp [\#626](https://github.com/voyagermesh/voyager/pull/626) ([tamalsaha](https://github.com/tamalsaha)) + +**Merged pull requests:** + +- Update unit tests [\#623](https://github.com/voyagermesh/voyager/pull/623) ([julianvmodesto](https://github.com/julianvmodesto)) + +## [4.0.0-rc.12](https://github.com/voyagermesh/voyager/tree/4.0.0-rc.12) (2017-10-13) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/4.0.0-rc.11...4.0.0-rc.12) + +**Merged pull requests:** + +- Prepare docs for 4.0.0-rc.12 [\#622](https://github.com/voyagermesh/voyager/pull/622) ([tamalsaha](https://github.com/tamalsaha)) + +## [4.0.0-rc.11](https://github.com/voyagermesh/voyager/tree/4.0.0-rc.11) (2017-10-12) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/4.0.0-rc.10...4.0.0-rc.11) + +**Implemented enhancements:** + +- TLS auth [\#606](https://github.com/voyagermesh/voyager/pull/606) ([sadlil](https://github.com/sadlil)) + +**Fixed bugs:** + +- TLS auth [\#606](https://github.com/voyagermesh/voyager/pull/606) ([sadlil](https://github.com/sadlil)) + +**Closed issues:** + +- Allow restricting voyager in a single namespace [\#582](https://github.com/voyagermesh/voyager/issues/582) +- zone-specific static IP on gke rather than global static [\#414](https://github.com/voyagermesh/voyager/issues/414) +- Add flag to handling standard ingress [\#369](https://github.com/voyagermesh/voyager/issues/369) + +**Merged pull requests:** + +- Allow restricting voyager in a single namespace [\#619](https://github.com/voyagermesh/voyager/pull/619) ([tamalsaha](https://github.com/tamalsaha)) +- Add support for CRL when using TLS Auth [\#618](https://github.com/voyagermesh/voyager/pull/618) ([tamalsaha](https://github.com/tamalsaha)) +- Remove support for ingress.appscode.com/egress-points annotations [\#615](https://github.com/voyagermesh/voyager/pull/615) ([tamalsaha](https://github.com/tamalsaha)) +- Add Wildcard domain Test [\#614](https://github.com/voyagermesh/voyager/pull/614) ([sadlil](https://github.com/sadlil)) +- Move CRD definition to api folder. [\#613](https://github.com/voyagermesh/voyager/pull/613) ([tamalsaha](https://github.com/tamalsaha)) + +## [4.0.0-rc.10](https://github.com/voyagermesh/voyager/tree/4.0.0-rc.10) (2017-10-10) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/4.0.0-rc.9...4.0.0-rc.10) + +**Closed issues:** + +- Change test domain appscode.dev -\> appscode.test [\#590](https://github.com/voyagermesh/voyager/issues/590) + +**Merged pull requests:** + +- Clarify Prometheus operator version [\#612](https://github.com/voyagermesh/voyager/pull/612) ([tamalsaha](https://github.com/tamalsaha)) +- Prepare docs for 4.0.0-rc.10 release [\#611](https://github.com/voyagermesh/voyager/pull/611) ([tamalsaha](https://github.com/tamalsaha)) +- Update Prometheus operator dependency to 0.13.0 [\#609](https://github.com/voyagermesh/voyager/pull/609) ([tamalsaha](https://github.com/tamalsaha)) +- Add doc showing how to detect operator version [\#607](https://github.com/voyagermesh/voyager/pull/607) ([tamalsaha](https://github.com/tamalsaha)) +- Use .test TLD [\#601](https://github.com/voyagermesh/voyager/pull/601) ([tamalsaha](https://github.com/tamalsaha)) + +## [4.0.0-rc.9](https://github.com/voyagermesh/voyager/tree/4.0.0-rc.9) (2017-10-08) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/4.0.0-rc.8...4.0.0-rc.9) + +**Fixed bugs:** + +- Fix validator so can specify either HTTP or TCP [\#597](https://github.com/voyagermesh/voyager/pull/597) ([tamalsaha](https://github.com/tamalsaha)) + +**Merged pull requests:** + +- Enable stats for e2e test [\#595](https://github.com/voyagermesh/voyager/pull/595) ([tamalsaha](https://github.com/tamalsaha)) +- Fix stats auth indentation when auth is omitted [\#594](https://github.com/voyagermesh/voyager/pull/594) ([tamalsaha](https://github.com/tamalsaha)) + +## [4.0.0-rc.8](https://github.com/voyagermesh/voyager/tree/4.0.0-rc.8) (2017-10-06) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/4.0.0-rc.7...4.0.0-rc.8) + +**Fixed bugs:** + +- Assume cert store as Secret, if Vault missing. [\#592](https://github.com/voyagermesh/voyager/pull/592) ([tamalsaha](https://github.com/tamalsaha)) + +## [4.0.0-rc.7](https://github.com/voyagermesh/voyager/tree/4.0.0-rc.7) (2017-10-06) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/4.0.0-rc.6...4.0.0-rc.7) + +**Fixed bugs:** + +- Migrate Ingress before projection [\#591](https://github.com/voyagermesh/voyager/pull/591) ([tamalsaha](https://github.com/tamalsaha)) + +## [4.0.0-rc.6](https://github.com/voyagermesh/voyager/tree/4.0.0-rc.6) (2017-10-06) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/4.0.0-rc.5...4.0.0-rc.6) + +**Fixed bugs:** + +- LE: Too many invalid authorizations recently [\#587](https://github.com/voyagermesh/voyager/issues/587) +- Fix HTTP challenger [\#589](https://github.com/voyagermesh/voyager/pull/589) ([tamalsaha](https://github.com/tamalsaha)) + +## [4.0.0-rc.5](https://github.com/voyagermesh/voyager/tree/4.0.0-rc.5) (2017-10-06) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/4.0.0-rc.4...4.0.0-rc.5) + +**Fixed bugs:** + +- Support static ip for Azure/ACS cluster. [\#584](https://github.com/voyagermesh/voyager/pull/584) ([tamalsaha](https://github.com/tamalsaha)) + +**Merged pull requests:** + +- Prepare docs for 4.0.0-rc.5 [\#585](https://github.com/voyagermesh/voyager/pull/585) ([tamalsaha](https://github.com/tamalsaha)) +- Rename SecretRef to TLSRef [\#580](https://github.com/voyagermesh/voyager/pull/580) ([tamalsaha](https://github.com/tamalsaha)) +- Add errofiles annotation [\#574](https://github.com/voyagermesh/voyager/pull/574) ([diptadas](https://github.com/diptadas)) +- Add force-ssl-redirect annotation [\#563](https://github.com/voyagermesh/voyager/pull/563) ([diptadas](https://github.com/diptadas)) + +## [4.0.0-rc.4](https://github.com/voyagermesh/voyager/tree/4.0.0-rc.4) (2017-10-05) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/3.2.2...4.0.0-rc.4) + +**Closed issues:** + +- Log GO's current thread id [\#573](https://github.com/voyagermesh/voyager/issues/573) + +**Merged pull requests:** + +- Update docs for 4.0.0-rc.4 [\#576](https://github.com/voyagermesh/voyager/pull/576) ([tamalsaha](https://github.com/tamalsaha)) + +## [3.2.2](https://github.com/voyagermesh/voyager/tree/3.2.2) (2017-10-05) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/4.0.0-rc.3...3.2.2) + +**Merged pull requests:** + +- Disable OCSP must staple [\#570](https://github.com/voyagermesh/voyager/pull/570) ([tamalsaha](https://github.com/tamalsaha)) + +## [4.0.0-rc.3](https://github.com/voyagermesh/voyager/tree/4.0.0-rc.3) (2017-10-04) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/4.0.0-rc.2...4.0.0-rc.3) + +**Merged pull requests:** + +- Prepare docs for 4.0.0-rc.3 [\#569](https://github.com/voyagermesh/voyager/pull/569) ([tamalsaha](https://github.com/tamalsaha)) +- Set TypeMeta when creating object [\#567](https://github.com/voyagermesh/voyager/pull/567) ([tamalsaha](https://github.com/tamalsaha)) +- Fix logging [\#566](https://github.com/voyagermesh/voyager/pull/566) ([tamalsaha](https://github.com/tamalsaha)) + +## [4.0.0-rc.2](https://github.com/voyagermesh/voyager/tree/4.0.0-rc.2) (2017-10-04) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/4.0.0-rc.1...4.0.0-rc.2) + +**Closed issues:** + +- Name server by pod name instead of endpoint ip [\#550](https://github.com/voyagermesh/voyager/issues/550) +- ocsp stapling [\#531](https://github.com/voyagermesh/voyager/issues/531) + +**Merged pull requests:** + +- Prepare docs for 4.0.0-rc.2 [\#561](https://github.com/voyagermesh/voyager/pull/561) ([tamalsaha](https://github.com/tamalsaha)) +- Fix \#552 [\#557](https://github.com/voyagermesh/voyager/pull/557) ([sadlil](https://github.com/sadlil)) +- Add service auth annotation [\#555](https://github.com/voyagermesh/voyager/pull/555) ([diptadas](https://github.com/diptadas)) +- Name server by pod name instead of endpoint ip [\#551](https://github.com/voyagermesh/voyager/pull/551) ([sadlil](https://github.com/sadlil)) +- Add max-connections annotation [\#546](https://github.com/voyagermesh/voyager/pull/546) ([diptadas](https://github.com/diptadas)) + +## [4.0.0-rc.1](https://github.com/voyagermesh/voyager/tree/4.0.0-rc.1) (2017-09-27) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/4.0.0-rc.0...4.0.0-rc.1) + +**Merged pull requests:** + +- Fix test [\#549](https://github.com/voyagermesh/voyager/pull/549) ([diptadas](https://github.com/diptadas)) +- Add init-only mode for tls mounter [\#548](https://github.com/voyagermesh/voyager/pull/548) ([tamalsaha](https://github.com/tamalsaha)) +- Fix tls mounter [\#547](https://github.com/voyagermesh/voyager/pull/547) ([sadlil](https://github.com/sadlil)) +- Update docs to CRD from TPR [\#544](https://github.com/voyagermesh/voyager/pull/544) ([tamalsaha](https://github.com/tamalsaha)) +- Fix tls mounter [\#543](https://github.com/voyagermesh/voyager/pull/543) ([tamalsaha](https://github.com/tamalsaha)) +- Ensure RBAC if Ingress is updated [\#542](https://github.com/voyagermesh/voyager/pull/542) ([tamalsaha](https://github.com/tamalsaha)) +- Make SecretRef pointer again [\#540](https://github.com/voyagermesh/voyager/pull/540) ([tamalsaha](https://github.com/tamalsaha)) +- Add whitelist-source-range annotation [\#539](https://github.com/voyagermesh/voyager/pull/539) ([diptadas](https://github.com/diptadas)) +- Add links to user guide [\#537](https://github.com/voyagermesh/voyager/pull/537) ([tamalsaha](https://github.com/tamalsaha)) +- Install voyager operator as critical addon [\#536](https://github.com/voyagermesh/voyager/pull/536) ([tamalsaha](https://github.com/tamalsaha)) +- Remove UpdateRBAC mode. [\#534](https://github.com/voyagermesh/voyager/pull/534) ([tamalsaha](https://github.com/tamalsaha)) +- Use CreateOrPatch apis with RBAC. Also sets ownerReference. [\#533](https://github.com/voyagermesh/voyager/pull/533) ([tamalsaha](https://github.com/tamalsaha)) +- Disable OCSP must staple [\#532](https://github.com/voyagermesh/voyager/pull/532) ([tamalsaha](https://github.com/tamalsaha)) +- Explain why tcp connections can't be whitelisted for AWS LoadBlancers [\#514](https://github.com/voyagermesh/voyager/pull/514) ([tamalsaha](https://github.com/tamalsaha)) + +## [4.0.0-rc.0](https://github.com/voyagermesh/voyager/tree/4.0.0-rc.0) (2017-09-24) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/3.2.1...4.0.0-rc.0) + +**Fixed bugs:** + +- AWS secrets don't seem to be used for ACME validation [\#526](https://github.com/voyagermesh/voyager/issues/526) +- Watcher should exit if it can't connect to master [\#136](https://github.com/voyagermesh/voyager/issues/136) + +**Closed issues:** + +- Support providing secrets as a PV [\#496](https://github.com/voyagermesh/voyager/issues/496) +- Use SharedInformer [\#443](https://github.com/voyagermesh/voyager/issues/443) +- GCE: Services \(LoadBalancer\) with static ip causes panic in 1.7 [\#416](https://github.com/voyagermesh/voyager/issues/416) +- Don't retry if rate-limited by LE [\#356](https://github.com/voyagermesh/voyager/issues/356) + +**Merged pull requests:** + +- Fix install guide link. [\#523](https://github.com/voyagermesh/voyager/pull/523) ([tamalsaha](https://github.com/tamalsaha)) +- Add e2e test for HSTS annotations [\#521](https://github.com/voyagermesh/voyager/pull/521) ([diptadas](https://github.com/diptadas)) +- Fix HSTS header template [\#520](https://github.com/voyagermesh/voyager/pull/520) ([diptadas](https://github.com/diptadas)) +- Add hsts-preload and hsts-include-subdomains annotations [\#519](https://github.com/voyagermesh/voyager/pull/519) ([diptadas](https://github.com/diptadas)) +- Update kloader to 4.0.1 [\#518](https://github.com/voyagermesh/voyager/pull/518) ([tamalsaha](https://github.com/tamalsaha)) +- Add hsts-max-age annotation [\#515](https://github.com/voyagermesh/voyager/pull/515) ([diptadas](https://github.com/diptadas)) +- Revendor haproxy-exporter [\#513](https://github.com/voyagermesh/voyager/pull/513) ([tamalsaha](https://github.com/tamalsaha)) + +## [3.2.1](https://github.com/voyagermesh/voyager/tree/3.2.1) (2017-09-19) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/4.0.0-alpha.1...3.2.1) + +**Merged pull requests:** + +- Update RBAC to allow watching nodes. [\#510](https://github.com/voyagermesh/voyager/pull/510) ([tamalsaha](https://github.com/tamalsaha)) +- Fix DNS provider key for Google cloud DNS. [\#509](https://github.com/voyagermesh/voyager/pull/509) ([tamalsaha](https://github.com/tamalsaha)) +- Change HAProxy image tag to 1.7.6-4.0.0-alpha.1 [\#499](https://github.com/voyagermesh/voyager/pull/499) ([tamalsaha](https://github.com/tamalsaha)) + +## [4.0.0-alpha.1](https://github.com/voyagermesh/voyager/tree/4.0.0-alpha.1) (2017-09-15) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/4.0.0-alpha.0...4.0.0-alpha.1) + +**Implemented enhancements:** + +- Fix tests for 4.0 [\#492](https://github.com/voyagermesh/voyager/pull/492) ([sadlil](https://github.com/sadlil)) + +**Closed issues:** + +- Allow configuring templates per Ingress [\#482](https://github.com/voyagermesh/voyager/issues/482) + +**Merged pull requests:** + +- Use kloader 4.0.0 [\#498](https://github.com/voyagermesh/voyager/pull/498) ([tamalsaha](https://github.com/tamalsaha)) +- Correct a small typo in the weighted doco [\#495](https://github.com/voyagermesh/voyager/pull/495) ([leprechaun](https://github.com/leprechaun)) +- Add ObjectReference methods. [\#494](https://github.com/voyagermesh/voyager/pull/494) ([tamalsaha](https://github.com/tamalsaha)) +- Update Chart RBAC format as recommended. [\#490](https://github.com/voyagermesh/voyager/pull/490) ([tamalsaha](https://github.com/tamalsaha)) + +## [4.0.0-alpha.0](https://github.com/voyagermesh/voyager/tree/4.0.0-alpha.0) (2017-09-11) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/3.2.0...4.0.0-alpha.0) + +**Implemented enhancements:** + +- Replace TPR with CRD [\#419](https://github.com/voyagermesh/voyager/pull/419) ([sadlil](https://github.com/sadlil)) + +**Merged pull requests:** + +- Use svc.Spec.ExternalTrafficPolicy [\#489](https://github.com/voyagermesh/voyager/pull/489) ([tamalsaha](https://github.com/tamalsaha)) +- Use DNSPolicy ClusterFirstWithHostNet for HostPort mode. [\#488](https://github.com/voyagermesh/voyager/pull/488) ([tamalsaha](https://github.com/tamalsaha)) +- Use log & errors to appscode/go pkg [\#487](https://github.com/voyagermesh/voyager/pull/487) ([tamalsaha](https://github.com/tamalsaha)) +- Use Deployment for HostPort mode [\#486](https://github.com/voyagermesh/voyager/pull/486) ([tamalsaha](https://github.com/tamalsaha)) + +## [3.2.0](https://github.com/voyagermesh/voyager/tree/3.2.0) (2017-09-11) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/3.2.0-rc.3...3.2.0) + +**Implemented enhancements:** + +- haproxy stats, named services [\#310](https://github.com/voyagermesh/voyager/issues/310) +- Serve both HTTP and HTTPS under same host [\#262](https://github.com/voyagermesh/voyager/issues/262) +- Open firewall for know providers in NodePort mode. [\#227](https://github.com/voyagermesh/voyager/issues/227) +- Allow users to specify NodePort for service ports in NodePort mode. [\#128](https://github.com/voyagermesh/voyager/issues/128) +- Run L7 ingress on non-standard ports [\#73](https://github.com/voyagermesh/voyager/issues/73) +- Validate Ingress [\#46](https://github.com/voyagermesh/voyager/issues/46) +- Update 3.2.0 Docs [\#477](https://github.com/voyagermesh/voyager/pull/477) ([sadlil](https://github.com/sadlil)) +- Implement Basic Auth for HTTP Ingresses [\#470](https://github.com/voyagermesh/voyager/pull/470) ([sadlil](https://github.com/sadlil)) +- Frontend rules [\#467](https://github.com/voyagermesh/voyager/pull/467) ([sadlil](https://github.com/sadlil)) +- Apply Session affinity to Backend service [\#460](https://github.com/voyagermesh/voyager/pull/460) ([sadlil](https://github.com/sadlil)) +- Restart HAProxy in case of renew certificates [\#413](https://github.com/voyagermesh/voyager/pull/413) ([sadlil](https://github.com/sadlil)) +- Converting E2E tests to use Ginkgo [\#334](https://github.com/voyagermesh/voyager/pull/334) ([sadlil](https://github.com/sadlil)) + +**Fixed bugs:** + +- Ingress validation error [\#420](https://github.com/voyagermesh/voyager/issues/420) +- Fix ACL for host:port in non-standard ports. [\#418](https://github.com/voyagermesh/voyager/issues/418) +- Update operations delete HAProxy pods gets reverted [\#386](https://github.com/voyagermesh/voyager/issues/386) +- Deleting and re-creating a Voyager Ingress in AWS fails due to leaked security groups [\#372](https://github.com/voyagermesh/voyager/issues/372) +- LE cert failed to issue with route53 [\#371](https://github.com/voyagermesh/voyager/issues/371) +- Restart HAProxy when new cert is issued. [\#340](https://github.com/voyagermesh/voyager/issues/340) +- Cert controller issues [\#124](https://github.com/voyagermesh/voyager/issues/124) +- Automatically update firewall when nodeSelector is changed. [\#20](https://github.com/voyagermesh/voyager/issues/20) +- Fix SG group name for GCE [\#472](https://github.com/voyagermesh/voyager/pull/472) ([tamalsaha](https://github.com/tamalsaha)) +- Correctly detect APISchema\(\) [\#471](https://github.com/voyagermesh/voyager/pull/471) ([tamalsaha](https://github.com/tamalsaha)) + +**Closed issues:** + +- Bug: stats.cfg generates an extra \t when no auth given [\#480](https://github.com/voyagermesh/voyager/issues/480) +- 3.2.0 docs [\#474](https://github.com/voyagermesh/voyager/issues/474) +- Allow Sticky session per service basis [\#453](https://github.com/voyagermesh/voyager/issues/453) +- Document how to whitelist IPs [\#441](https://github.com/voyagermesh/voyager/issues/441) +- Allow configuring logging [\#439](https://github.com/voyagermesh/voyager/issues/439) +- Add PATCH api support [\#411](https://github.com/voyagermesh/voyager/issues/411) +- Handle SSL frontend and backends [\#396](https://github.com/voyagermesh/voyager/issues/396) +- Set unit for timeouts in template [\#360](https://github.com/voyagermesh/voyager/issues/360) +- Add tests [\#357](https://github.com/voyagermesh/voyager/issues/357) +- Handle errors for serviceEndpoints\(\) and getEndpoints\(\) [\#350](https://github.com/voyagermesh/voyager/issues/350) +- Split ingress controller into micro controllers [\#347](https://github.com/voyagermesh/voyager/issues/347) +- setting a static port for type nodeport [\#344](https://github.com/voyagermesh/voyager/issues/344) +- Allow option http-keep-alive and TLS backends [\#343](https://github.com/voyagermesh/voyager/issues/343) +- Open port 443 in HTTP mode [\#333](https://github.com/voyagermesh/voyager/issues/333) +- Revise TCP secret name [\#319](https://github.com/voyagermesh/voyager/issues/319) +- Show validation error if multiple TCP rules are sharing the same port [\#318](https://github.com/voyagermesh/voyager/issues/318) +- Clean up cert controller. [\#287](https://github.com/voyagermesh/voyager/issues/287) +- Improve Prometheus labels from HAProxy Exporter [\#271](https://github.com/voyagermesh/voyager/issues/271) +- Convert tests to use Ginkgo [\#257](https://github.com/voyagermesh/voyager/issues/257) +- Add tests for TLS [\#175](https://github.com/voyagermesh/voyager/issues/175) +- Correctly compute content hash for HAproxy config [\#138](https://github.com/voyagermesh/voyager/issues/138) +- Improve test suite [\#31](https://github.com/voyagermesh/voyager/issues/31) + +**Merged pull requests:** + +- Document noTLS feature [\#485](https://github.com/voyagermesh/voyager/pull/485) ([tamalsaha](https://github.com/tamalsaha)) +- Keep whitespace from end to templates in haproxy.cfg [\#483](https://github.com/voyagermesh/voyager/pull/483) ([tamalsaha](https://github.com/tamalsaha)) +- Fix stats auth indentation when auth is omitted [\#481](https://github.com/voyagermesh/voyager/pull/481) ([julianvmodesto](https://github.com/julianvmodesto)) +- Fix typo in doc [\#479](https://github.com/voyagermesh/voyager/pull/479) ([pierreozoux](https://github.com/pierreozoux)) +- Fix links in docs [\#478](https://github.com/voyagermesh/voyager/pull/478) ([pierreozoux](https://github.com/pierreozoux)) +- Prepare docs for 3.2.0 [\#476](https://github.com/voyagermesh/voyager/pull/476) ([tamalsaha](https://github.com/tamalsaha)) +- Enable accept-proxy [\#475](https://github.com/voyagermesh/voyager/pull/475) ([tamalsaha](https://github.com/tamalsaha)) +- Document how to use custom templates for HAProxy [\#462](https://github.com/voyagermesh/voyager/pull/462) ([tamalsaha](https://github.com/tamalsaha)) +- Fix NPE [\#469](https://github.com/voyagermesh/voyager/pull/469) ([tamalsaha](https://github.com/tamalsaha)) +- Use .cfg extension for templates. [\#465](https://github.com/voyagermesh/voyager/pull/465) ([tamalsaha](https://github.com/tamalsaha)) +- Modify certificate docs. [\#463](https://github.com/voyagermesh/voyager/pull/463) ([sadlil](https://github.com/sadlil)) +- Support custom user templates [\#454](https://github.com/voyagermesh/voyager/pull/454) ([tamalsaha](https://github.com/tamalsaha)) +- Add ingress.appscode.com/accept-proxy annotation [\#452](https://github.com/voyagermesh/voyager/pull/452) ([tamalsaha](https://github.com/tamalsaha)) +- Update client-go to 3.0.0 from 3.0.0-beta [\#406](https://github.com/voyagermesh/voyager/pull/406) ([tamalsaha](https://github.com/tamalsaha)) +- Update Azure SDK to 10.2.1-beta [\#402](https://github.com/voyagermesh/voyager/pull/402) ([tamalsaha](https://github.com/tamalsaha)) +- Assign VoyagerCluster tag for Voyager Ingress [\#401](https://github.com/voyagermesh/voyager/pull/401) ([tamalsaha](https://github.com/tamalsaha)) +- Check for unset env var passed as flag values. [\#399](https://github.com/voyagermesh/voyager/pull/399) ([tamalsaha](https://github.com/tamalsaha)) +- Merge service and pod annotations [\#390](https://github.com/voyagermesh/voyager/pull/390) ([tamalsaha](https://github.com/tamalsaha)) +- Maintain support for Kubernetes 1.5 for HostPort daemonsets [\#388](https://github.com/voyagermesh/voyager/pull/388) ([tamalsaha](https://github.com/tamalsaha)) +- Split ingress controller into micro controllers [\#383](https://github.com/voyagermesh/voyager/pull/383) ([tamalsaha](https://github.com/tamalsaha)) +- Fix GO reportcard issues. [\#379](https://github.com/voyagermesh/voyager/pull/379) ([tamalsaha](https://github.com/tamalsaha)) +- Add voyager check command. [\#364](https://github.com/voyagermesh/voyager/pull/364) ([tamalsaha](https://github.com/tamalsaha)) +- Update Ingress spec [\#317](https://github.com/voyagermesh/voyager/pull/317) ([tamalsaha](https://github.com/tamalsaha)) + +## [3.2.0-rc.3](https://github.com/voyagermesh/voyager/tree/3.2.0-rc.3) (2017-09-07) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/3.2.0-rc.2...3.2.0-rc.3) + +**Closed issues:** + +- Fix NodePort docs [\#461](https://github.com/voyagermesh/voyager/issues/461) + +**Merged pull requests:** + +- Update NodePort docs [\#466](https://github.com/voyagermesh/voyager/pull/466) ([tamalsaha](https://github.com/tamalsaha)) + +## [3.2.0-rc.2](https://github.com/voyagermesh/voyager/tree/3.2.0-rc.2) (2017-09-06) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/3.2.0-rc.1...3.2.0-rc.2) + +**Fixed bugs:** + +- OVH DNS provider is not working [\#449](https://github.com/voyagermesh/voyager/issues/449) +- bug: ServiceAccount does not exist after upgrading [\#448](https://github.com/voyagermesh/voyager/issues/448) + +**Closed issues:** + +- `keep-source-ip` should enable PROXY protocol is bare metal cluster [\#451](https://github.com/voyagermesh/voyager/issues/451) + +**Merged pull requests:** + +- Create RBAC objects if missing [\#458](https://github.com/voyagermesh/voyager/pull/458) ([tamalsaha](https://github.com/tamalsaha)) +- Move analytics collector to root command [\#450](https://github.com/voyagermesh/voyager/pull/450) ([tamalsaha](https://github.com/tamalsaha)) + +## [3.2.0-rc.1](https://github.com/voyagermesh/voyager/tree/3.2.0-rc.1) (2017-09-01) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/3.2.0-rc.0...3.2.0-rc.1) + +**Fixed bugs:** + +- Don't sort HTTP paths since the order matters to HAProxy [\#445](https://github.com/voyagermesh/voyager/pull/445) ([tamalsaha](https://github.com/tamalsaha)) + +**Closed issues:** + +- Handle both TCP and HTTP requests on same frontend [\#430](https://github.com/voyagermesh/voyager/issues/430) + +**Merged pull requests:** + +- Show how to use kubectl. [\#442](https://github.com/voyagermesh/voyager/pull/442) ([tamalsaha](https://github.com/tamalsaha)) +- Add Docs [\#438](https://github.com/voyagermesh/voyager/pull/438) ([sadlil](https://github.com/sadlil)) +- Fix secret name [\#434](https://github.com/voyagermesh/voyager/pull/434) ([rstuven](https://github.com/rstuven)) +- Fix secret name [\#433](https://github.com/voyagermesh/voyager/pull/433) ([rstuven](https://github.com/rstuven)) +- Minor fix [\#432](https://github.com/voyagermesh/voyager/pull/432) ([rstuven](https://github.com/rstuven)) +- Fix load-balancer-ip annotation references [\#431](https://github.com/voyagermesh/voyager/pull/431) ([rstuven](https://github.com/rstuven)) + +## [3.2.0-rc.0](https://github.com/voyagermesh/voyager/tree/3.2.0-rc.0) (2017-08-28) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/3.2.0-beta.4...3.2.0-rc.0) + +**Fixed bugs:** + +- Fix Host:Port Matching issue. [\#425](https://github.com/voyagermesh/voyager/pull/425) ([sadlil](https://github.com/sadlil)) + +**Merged pull requests:** + +- Restart HAProxy in case of renew certificates [\#427](https://github.com/voyagermesh/voyager/pull/427) ([tamalsaha](https://github.com/tamalsaha)) +- Prepare docs for 3.2.0-rc.0 [\#426](https://github.com/voyagermesh/voyager/pull/426) ([tamalsaha](https://github.com/tamalsaha)) + +## [3.2.0-beta.4](https://github.com/voyagermesh/voyager/tree/3.2.0-beta.4) (2017-08-27) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/3.2.0-beta.3...3.2.0-beta.4) + +**Implemented enhancements:** + +- Add Patch API Supports [\#412](https://github.com/voyagermesh/voyager/pull/412) ([sadlil](https://github.com/sadlil)) + +**Merged pull requests:** + +- Fix Ingress validation error [\#421](https://github.com/voyagermesh/voyager/pull/421) ([tamalsaha](https://github.com/tamalsaha)) +- Fix cert [\#410](https://github.com/voyagermesh/voyager/pull/410) ([sadlil](https://github.com/sadlil)) +- Print back ingress in YAML format [\#409](https://github.com/voyagermesh/voyager/pull/409) ([tamalsaha](https://github.com/tamalsaha)) +- TLS Backend [\#408](https://github.com/voyagermesh/voyager/pull/408) ([sadlil](https://github.com/sadlil)) + +## [3.2.0-beta.3](https://github.com/voyagermesh/voyager/tree/3.2.0-beta.3) (2017-08-19) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/3.2.0-beta.2...3.2.0-beta.3) + +**Implemented enhancements:** + +- Allow custom options [\#403](https://github.com/voyagermesh/voyager/pull/403) ([sadlil](https://github.com/sadlil)) + +**Closed issues:** + +- single static port for the ingress resource and not a particular service [\#404](https://github.com/voyagermesh/voyager/issues/404) + +**Merged pull requests:** + +- Improve test suite [\#394](https://github.com/voyagermesh/voyager/pull/394) ([sadlil](https://github.com/sadlil)) + +## [3.2.0-beta.2](https://github.com/voyagermesh/voyager/tree/3.2.0-beta.2) (2017-08-16) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/3.2.0-beta.1...3.2.0-beta.2) + +## [3.2.0-beta.1](https://github.com/voyagermesh/voyager/tree/3.2.0-beta.1) (2017-08-16) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/3.2.0-beta.0...3.2.0-beta.1) + +**Merged pull requests:** + +- Change ingress sg tag to VoyagerCluster from KubernetesCluster [\#397](https://github.com/voyagermesh/voyager/pull/397) ([tamalsaha](https://github.com/tamalsaha)) +- Remove links to forum [\#395](https://github.com/voyagermesh/voyager/pull/395) ([tamalsaha](https://github.com/tamalsaha)) +- Open firewall for know providers in NodePort mode [\#392](https://github.com/voyagermesh/voyager/pull/392) ([tamalsaha](https://github.com/tamalsaha)) + +## [3.2.0-beta.0](https://github.com/voyagermesh/voyager/tree/3.2.0-beta.0) (2017-08-14) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/3.1.4...3.2.0-beta.0) + +**Closed issues:** + +- Validate existing Ingress before starting operator [\#346](https://github.com/voyagermesh/voyager/issues/346) + +**Merged pull requests:** + +- Make AWS HostPort SG name unique across clusters [\#391](https://github.com/voyagermesh/voyager/pull/391) ([tamalsaha](https://github.com/tamalsaha)) +- Fix AWS SecurityGroup leakage in HostPort mode [\#389](https://github.com/voyagermesh/voyager/pull/389) ([tamalsaha](https://github.com/tamalsaha)) +- Revise ingress controller update operations [\#385](https://github.com/voyagermesh/voyager/pull/385) ([tamalsaha](https://github.com/tamalsaha)) +- Split IsExists tests [\#384](https://github.com/voyagermesh/voyager/pull/384) ([tamalsaha](https://github.com/tamalsaha)) +- Update aws sdk to v1.6.10 [\#381](https://github.com/voyagermesh/voyager/pull/381) ([tamalsaha](https://github.com/tamalsaha)) +- Avoid getting provider secret [\#378](https://github.com/voyagermesh/voyager/pull/378) ([sadlil](https://github.com/sadlil)) +- Fix BUGS and Tests [\#363](https://github.com/voyagermesh/voyager/pull/363) ([sadlil](https://github.com/sadlil)) + +## [3.1.4](https://github.com/voyagermesh/voyager/tree/3.1.4) (2017-08-11) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/3.1.3...3.1.4) + +**Closed issues:** + +- Test aws cert manager 80-\>443 redirect [\#353](https://github.com/voyagermesh/voyager/issues/353) + +**Merged pull requests:** + +- Revendor lego [\#377](https://github.com/voyagermesh/voyager/pull/377) ([tamalsaha](https://github.com/tamalsaha)) +- Detect port changes correctly. [\#376](https://github.com/voyagermesh/voyager/pull/376) ([tamalsaha](https://github.com/tamalsaha)) +- Revendor lego to detect DNS zone correctly. [\#375](https://github.com/voyagermesh/voyager/pull/375) ([tamalsaha](https://github.com/tamalsaha)) +- Revendor lego [\#373](https://github.com/voyagermesh/voyager/pull/373) ([tamalsaha](https://github.com/tamalsaha)) +- Fix Implicit timeouts [\#361](https://github.com/voyagermesh/voyager/pull/361) ([sadlil](https://github.com/sadlil)) + +## [3.1.3](https://github.com/voyagermesh/voyager/tree/3.1.3) (2017-08-08) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/3.1.2...3.1.3) + +**Fixed bugs:** + +- Fix Event Recorder type [\#341](https://github.com/voyagermesh/voyager/pull/341) ([sadlil](https://github.com/sadlil)) +- Fix Domain Comparison [\#339](https://github.com/voyagermesh/voyager/pull/339) ([sadlil](https://github.com/sadlil)) +- Allow secret create/update for Voyager cert controller. [\#338](https://github.com/voyagermesh/voyager/pull/338) ([tamalsaha](https://github.com/tamalsaha)) + +**Merged pull requests:** + +- Fix test docs for ginkgo tests [\#352](https://github.com/voyagermesh/voyager/pull/352) ([sadlil](https://github.com/sadlil)) +- Add DCO [\#351](https://github.com/voyagermesh/voyager/pull/351) ([tamalsaha](https://github.com/tamalsaha)) +- Rename Ingress controller receiver to c from lbc [\#345](https://github.com/voyagermesh/voyager/pull/345) ([tamalsaha](https://github.com/tamalsaha)) + +## [3.1.2](https://github.com/voyagermesh/voyager/tree/3.1.2) (2017-08-02) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/3.1.1...3.1.2) + +**Implemented enhancements:** + +- Use Lets Encrypt Prod URL as default [\#335](https://github.com/voyagermesh/voyager/pull/335) ([sadlil](https://github.com/sadlil)) + +**Fixed bugs:** + +- Use Lets Encrypt Prod URL as default [\#335](https://github.com/voyagermesh/voyager/pull/335) ([sadlil](https://github.com/sadlil)) + +**Merged pull requests:** + +- Prepare docs for 3.1.2 release. [\#336](https://github.com/voyagermesh/voyager/pull/336) ([tamalsaha](https://github.com/tamalsaha)) +- Add install scripts [\#332](https://github.com/voyagermesh/voyager/pull/332) ([tamalsaha](https://github.com/tamalsaha)) + +## [3.1.1](https://github.com/voyagermesh/voyager/tree/3.1.1) (2017-07-22) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/3.1.0...3.1.1) + +**Merged pull requests:** + +- typos [\#325](https://github.com/voyagermesh/voyager/pull/325) ([nstott](https://github.com/nstott)) +- Prepare docs for 3.1.1 release. [\#328](https://github.com/voyagermesh/voyager/pull/328) ([tamalsaha](https://github.com/tamalsaha)) +- Add cloud provider specific install scripts. [\#327](https://github.com/voyagermesh/voyager/pull/327) ([tamalsaha](https://github.com/tamalsaha)) +- Disable critical addon feature [\#326](https://github.com/voyagermesh/voyager/pull/326) ([tamalsaha](https://github.com/tamalsaha)) + +## [3.1.0](https://github.com/voyagermesh/voyager/tree/3.1.0) (2017-07-21) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/3.0.0...3.1.0) + +**Implemented enhancements:** + +- Record events against TPR [\#79](https://github.com/voyagermesh/voyager/issues/79) +- Remove event framework from certificate [\#284](https://github.com/voyagermesh/voyager/pull/284) ([sadlil](https://github.com/sadlil)) +- Fix RBAC configs [\#295](https://github.com/voyagermesh/voyager/pull/295) ([sadlil](https://github.com/sadlil)) +- Add configure option for Haproxy default timeout. [\#286](https://github.com/voyagermesh/voyager/pull/286) ([sadlil](https://github.com/sadlil)) + +**Fixed bugs:** + +- podAffinityTerm.topologyKey: Required value: can not be empty [\#320](https://github.com/voyagermesh/voyager/issues/320) +- Restore objects if deleted by mistake. [\#283](https://github.com/voyagermesh/voyager/issues/283) +- HostPort mode does not work for AWS [\#281](https://github.com/voyagermesh/voyager/issues/281) +- Externalservice redirection gets reset [\#279](https://github.com/voyagermesh/voyager/issues/279) +- Voyager doesn't work with cloud = minikube and type = HostPort [\#272](https://github.com/voyagermesh/voyager/issues/272) +- Adding cert manager to existing ingress does not open port 443 [\#267](https://github.com/voyagermesh/voyager/issues/267) +- Bug: annotations are not applied [\#266](https://github.com/voyagermesh/voyager/issues/266) +- Add newline in pem file [\#261](https://github.com/voyagermesh/voyager/issues/261) +- Adding SSL to an existing ingress does not mount certs [\#260](https://github.com/voyagermesh/voyager/issues/260) +- Set topology key for pod anti-affinity [\#321](https://github.com/voyagermesh/voyager/pull/321) ([tamalsaha](https://github.com/tamalsaha)) +- Correctly detect changed ports [\#322](https://github.com/voyagermesh/voyager/pull/322) ([tamalsaha](https://github.com/tamalsaha)) +- Fix Adding SSL to an existing ingress does not mount certs \#260 [\#306](https://github.com/voyagermesh/voyager/pull/306) ([sadlil](https://github.com/sadlil)) +- Fix External Service redirect Issue [\#304](https://github.com/voyagermesh/voyager/pull/304) ([sadlil](https://github.com/sadlil)) +- Fix RBAC configs [\#295](https://github.com/voyagermesh/voyager/pull/295) ([sadlil](https://github.com/sadlil)) +- Fix Operator panic on service restore [\#273](https://github.com/voyagermesh/voyager/pull/273) ([sadlil](https://github.com/sadlil)) + +**Closed issues:** + +- Difficulties to setup, scarce docs [\#303](https://github.com/voyagermesh/voyager/issues/303) +- Setup Issues [\#298](https://github.com/voyagermesh/voyager/issues/298) +- Setup Issues [\#297](https://github.com/voyagermesh/voyager/issues/297) +- configurable HAProxy defaults [\#280](https://github.com/voyagermesh/voyager/issues/280) +- Support setting resource for pods [\#277](https://github.com/voyagermesh/voyager/issues/277) +- The link to contribution guide in README.md is broken. [\#274](https://github.com/voyagermesh/voyager/issues/274) +- Voyager exporter sidecar isn't exporting any metrics [\#270](https://github.com/voyagermesh/voyager/issues/270) +- Adding an AWS Cert and opening 80 and 443 doesn't work for plain http:// [\#268](https://github.com/voyagermesh/voyager/issues/268) +- Support HorizontalPodAutoscaling for HAProxy pods [\#242](https://github.com/voyagermesh/voyager/issues/242) +- Test updated chart with RBAC [\#302](https://github.com/voyagermesh/voyager/issues/302) +- Delete TPR when NS is deleted [\#258](https://github.com/voyagermesh/voyager/issues/258) +- voyager-operator should ensure that ServiceAccount/Role/RoleBinding exists for created voyager deploys. [\#252](https://github.com/voyagermesh/voyager/issues/252) +- RBAC objects for Voyager operator. [\#241](https://github.com/voyagermesh/voyager/issues/241) +- Should all hosts be passed to EnsureLoadBalancer [\#88](https://github.com/voyagermesh/voyager/issues/88) + +**Merged pull requests:** + +- Fix various chart issues [\#324](https://github.com/voyagermesh/voyager/pull/324) ([tamalsaha](https://github.com/tamalsaha)) +- Add Custom timeout docs [\#323](https://github.com/voyagermesh/voyager/pull/323) ([sadlil](https://github.com/sadlil)) +- Revendor dependencies. [\#312](https://github.com/voyagermesh/voyager/pull/312) ([tamalsaha](https://github.com/tamalsaha)) +- move RecognizeWellKnownRegions\(\) to the beginning of newAWSCloud\(\) [\#311](https://github.com/voyagermesh/voyager/pull/311) ([jipperinbham](https://github.com/jipperinbham)) +- Add ingress label to exported metrics [\#300](https://github.com/voyagermesh/voyager/pull/300) ([tamalsaha](https://github.com/tamalsaha)) +- Support setting resource for pods [\#289](https://github.com/voyagermesh/voyager/pull/289) ([tamalsaha](https://github.com/tamalsaha)) +- fix the contribution guild link \(\#274\) [\#275](https://github.com/voyagermesh/voyager/pull/275) ([aimof](https://github.com/aimof)) +- Update aws-cert-manager.md [\#269](https://github.com/voyagermesh/voyager/pull/269) ([julianvmodesto](https://github.com/julianvmodesto)) +- Add command reference docs [\#265](https://github.com/voyagermesh/voyager/pull/265) ([tamalsaha](https://github.com/tamalsaha)) +- Point to HPA example on readme pages. [\#254](https://github.com/voyagermesh/voyager/pull/254) ([tamalsaha](https://github.com/tamalsaha)) +- Add example with hpa [\#253](https://github.com/voyagermesh/voyager/pull/253) ([julianvmodesto](https://github.com/julianvmodesto)) +- Use ```bash instead of ```sh syntax highlighting [\#309](https://github.com/voyagermesh/voyager/pull/309) ([tamalsaha](https://github.com/tamalsaha)) +- Install Voyager as critical addon [\#301](https://github.com/voyagermesh/voyager/pull/301) ([tamalsaha](https://github.com/tamalsaha)) +- Add Stats Service events [\#299](https://github.com/voyagermesh/voyager/pull/299) ([sadlil](https://github.com/sadlil)) +- Recover ServiceMonitor [\#294](https://github.com/voyagermesh/voyager/pull/294) ([tamalsaha](https://github.com/tamalsaha)) +- Make node selectors optional for HostPort [\#293](https://github.com/voyagermesh/voyager/pull/293) ([tamalsaha](https://github.com/tamalsaha)) +- Delete kube lister classes. [\#291](https://github.com/voyagermesh/voyager/pull/291) ([tamalsaha](https://github.com/tamalsaha)) +- Record events against TPR [\#290](https://github.com/voyagermesh/voyager/pull/290) ([tamalsaha](https://github.com/tamalsaha)) +- Add tpr constants [\#288](https://github.com/voyagermesh/voyager/pull/288) ([tamalsaha](https://github.com/tamalsaha)) +- Remove event framework [\#282](https://github.com/voyagermesh/voyager/pull/282) ([tamalsaha](https://github.com/tamalsaha)) +- Update dev docs. [\#264](https://github.com/voyagermesh/voyager/pull/264) ([tamalsaha](https://github.com/tamalsaha)) +- Add a newline between crt & key. [\#263](https://github.com/voyagermesh/voyager/pull/263) ([tamalsaha](https://github.com/tamalsaha)) +- Create RBAC roles for Voyager during installation [\#256](https://github.com/voyagermesh/voyager/pull/256) ([tamalsaha](https://github.com/tamalsaha)) +- Support non-default service account with offshoot pods [\#255](https://github.com/voyagermesh/voyager/pull/255) ([tamalsaha](https://github.com/tamalsaha)) + +## [3.0.0](https://github.com/voyagermesh/voyager/tree/3.0.0) (2017-06-23) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/1.5.6...3.0.0) + +**Implemented enhancements:** + +- Automatically create ServiceMonitor for built-in exporter [\#154](https://github.com/voyagermesh/voyager/issues/154) +- Fix testframework for aws and update docs. [\#237](https://github.com/voyagermesh/voyager/pull/237) ([sadlil](https://github.com/sadlil)) + +**Fixed bugs:** + +- Delete pods & services matching old labels before starting operator [\#229](https://github.com/voyagermesh/voyager/issues/229) +- Check for updates properly [\#250](https://github.com/voyagermesh/voyager/pull/250) ([tamalsaha](https://github.com/tamalsaha)) +- Don't restore stats service if stats is disabled. [\#249](https://github.com/voyagermesh/voyager/pull/249) ([tamalsaha](https://github.com/tamalsaha)) +- Apply labels to stats service for service monitor [\#248](https://github.com/voyagermesh/voyager/pull/248) ([tamalsaha](https://github.com/tamalsaha)) +- Fix Bugs [\#247](https://github.com/voyagermesh/voyager/pull/247) ([sadlil](https://github.com/sadlil)) +- Correctly parse target port [\#245](https://github.com/voyagermesh/voyager/pull/245) ([tamalsaha](https://github.com/tamalsaha)) +- Fix testframework for aws and update docs. [\#237](https://github.com/voyagermesh/voyager/pull/237) ([sadlil](https://github.com/sadlil)) +- Add dns-resolver-check-health annotation to for ExternalName service [\#226](https://github.com/voyagermesh/voyager/pull/226) ([tamalsaha](https://github.com/tamalsaha)) +- Add cloud config file [\#218](https://github.com/voyagermesh/voyager/pull/218) ([sadlil](https://github.com/sadlil)) +- Fix bugs [\#217](https://github.com/voyagermesh/voyager/pull/217) ([sadlil](https://github.com/sadlil)) + +**Closed issues:** + +- Add chart value for --cloud-config mount [\#228](https://github.com/voyagermesh/voyager/issues/228) +- Document http-\>https redirect with AWS cert manager [\#225](https://github.com/voyagermesh/voyager/issues/225) +- Update version policy [\#194](https://github.com/voyagermesh/voyager/issues/194) +- Change api group to voyager.appscode.com [\#193](https://github.com/voyagermesh/voyager/issues/193) +- Use client-go [\#192](https://github.com/voyagermesh/voyager/issues/192) +- Use pod anti-affinity for deployments [\#161](https://github.com/voyagermesh/voyager/issues/161) +- Change api group to voyager.appscode.com [\#142](https://github.com/voyagermesh/voyager/issues/142) + +**Merged pull requests:** + +- Small typo fix \(CLOUDE\_CONFIG =\> CLOUD\_CONFIG\) [\#251](https://github.com/voyagermesh/voyager/pull/251) ([thecodeassassin](https://github.com/thecodeassassin)) +- Document http-\>https redirect with AWS cert manager [\#235](https://github.com/voyagermesh/voyager/pull/235) ([tamalsaha](https://github.com/tamalsaha)) +- Remove deprecated Daemon type. [\#205](https://github.com/voyagermesh/voyager/pull/205) ([tamalsaha](https://github.com/tamalsaha)) +- Automatically create ServiceMonitor for built-in exporter [\#203](https://github.com/voyagermesh/voyager/pull/203) ([tamalsaha](https://github.com/tamalsaha)) +- Track operator version [\#200](https://github.com/voyagermesh/voyager/pull/200) ([tamalsaha](https://github.com/tamalsaha)) +- Update version policy to point to client-go [\#198](https://github.com/voyagermesh/voyager/pull/198) ([tamalsaha](https://github.com/tamalsaha)) +- Use client-go [\#196](https://github.com/voyagermesh/voyager/pull/196) ([tamalsaha](https://github.com/tamalsaha)) +- Use stats service port name in ServiceMonitor [\#246](https://github.com/voyagermesh/voyager/pull/246) ([tamalsaha](https://github.com/tamalsaha)) +- Use correct api schema when checking ingress class. [\#244](https://github.com/voyagermesh/voyager/pull/244) ([tamalsaha](https://github.com/tamalsaha)) +- Note test-ns policy [\#243](https://github.com/voyagermesh/voyager/pull/243) ([tamalsaha](https://github.com/tamalsaha)) +- Add acs provider [\#236](https://github.com/voyagermesh/voyager/pull/236) ([tamalsaha](https://github.com/tamalsaha)) +- Update chart readme for cloud config [\#234](https://github.com/voyagermesh/voyager/pull/234) ([tamalsaha](https://github.com/tamalsaha)) +- Make cloud config configurable. [\#233](https://github.com/voyagermesh/voyager/pull/233) ([tamalsaha](https://github.com/tamalsaha)) +- Change api group to networking.appscode.com [\#232](https://github.com/voyagermesh/voyager/pull/232) ([tamalsaha](https://github.com/tamalsaha)) +- Update \*\*\*Getter interfaces match form [\#231](https://github.com/voyagermesh/voyager/pull/231) ([tamalsaha](https://github.com/tamalsaha)) +- Delete pods & services matching old labels before starting operator [\#230](https://github.com/voyagermesh/voyager/pull/230) ([tamalsaha](https://github.com/tamalsaha)) +- Use PreRun & PostRun to send analytics. [\#224](https://github.com/voyagermesh/voyager/pull/224) ([tamalsaha](https://github.com/tamalsaha)) +- Update metric endpoints documentation. [\#223](https://github.com/voyagermesh/voyager/pull/223) ([tamalsaha](https://github.com/tamalsaha)) +- Fix port used for exposing metrics from operator. [\#222](https://github.com/voyagermesh/voyager/pull/222) ([tamalsaha](https://github.com/tamalsaha)) +- Open both port 443 & 80 when AWS cert manager is in use. [\#221](https://github.com/voyagermesh/voyager/pull/221) ([tamalsaha](https://github.com/tamalsaha)) +- Mount cloud config in chart [\#220](https://github.com/voyagermesh/voyager/pull/220) ([tamalsaha](https://github.com/tamalsaha)) +- Use root user inside docker [\#219](https://github.com/voyagermesh/voyager/pull/219) ([tamalsaha](https://github.com/tamalsaha)) +- Rename exporter port to targetPort [\#216](https://github.com/voyagermesh/voyager/pull/216) ([tamalsaha](https://github.com/tamalsaha)) +- Use Voyager group name correctly. [\#215](https://github.com/voyagermesh/voyager/pull/215) ([tamalsaha](https://github.com/tamalsaha)) +- Update default ports [\#214](https://github.com/voyagermesh/voyager/pull/214) ([tamalsaha](https://github.com/tamalsaha)) +- Update docs for service monitor integration [\#213](https://github.com/voyagermesh/voyager/pull/213) ([tamalsaha](https://github.com/tamalsaha)) +- Fix unit test build issues [\#210](https://github.com/voyagermesh/voyager/pull/210) ([tamalsaha](https://github.com/tamalsaha)) +- Change api group to voyager.appscode.com [\#209](https://github.com/voyagermesh/voyager/pull/209) ([tamalsaha](https://github.com/tamalsaha)) +- Update docs to point to 3.0.0 [\#208](https://github.com/voyagermesh/voyager/pull/208) ([tamalsaha](https://github.com/tamalsaha)) +- Stop creating stats service. [\#207](https://github.com/voyagermesh/voyager/pull/207) ([tamalsaha](https://github.com/tamalsaha)) +- Update labels applied to HAProxy pods & services. [\#206](https://github.com/voyagermesh/voyager/pull/206) ([tamalsaha](https://github.com/tamalsaha)) +- Fix client-go fake import [\#204](https://github.com/voyagermesh/voyager/pull/204) ([tamalsaha](https://github.com/tamalsaha)) +- Change default HAProxy image to 1.7.6-3.0.0 [\#202](https://github.com/voyagermesh/voyager/pull/202) ([tamalsaha](https://github.com/tamalsaha)) +- Add HAProxy 1.7.6 dockerfiles. [\#201](https://github.com/voyagermesh/voyager/pull/201) ([tamalsaha](https://github.com/tamalsaha)) +- Add voyager export command [\#199](https://github.com/voyagermesh/voyager/pull/199) ([tamalsaha](https://github.com/tamalsaha)) +- Only keep Firewall\(\) interface in cloud provider [\#195](https://github.com/voyagermesh/voyager/pull/195) ([tamalsaha](https://github.com/tamalsaha)) + +## [1.5.6](https://github.com/voyagermesh/voyager/tree/1.5.6) (2017-06-16) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/1.5.5...1.5.6) + +**Implemented enhancements:** + +- Delete docker image from docker hub after integration test [\#125](https://github.com/voyagermesh/voyager/issues/125) +- Change how stats work [\#106](https://github.com/voyagermesh/voyager/issues/106) +- Use AWS ELB Proxy Protocol [\#100](https://github.com/voyagermesh/voyager/issues/100) +- Track Kube's refactoring cloud provider API [\#36](https://github.com/voyagermesh/voyager/issues/36) +- Expose HAProxy stats to prometheus [\#13](https://github.com/voyagermesh/voyager/issues/13) +- Support AWS cert manager [\#189](https://github.com/voyagermesh/voyager/pull/189) ([tamalsaha](https://github.com/tamalsaha)) +- Merge existing pods and service during create ingress resource [\#181](https://github.com/voyagermesh/voyager/pull/181) ([sadlil](https://github.com/sadlil)) +- Add support for ServiceTypeExternalName [\#167](https://github.com/voyagermesh/voyager/pull/167) ([sadlil](https://github.com/sadlil)) +- Collect analytics for voyager usages [\#133](https://github.com/voyagermesh/voyager/pull/133) ([sadlil](https://github.com/sadlil)) +- Fix stats behavior [\#130](https://github.com/voyagermesh/voyager/pull/130) ([sadlil](https://github.com/sadlil)) +- Improve test framework [\#121](https://github.com/voyagermesh/voyager/pull/121) ([sadlil](https://github.com/sadlil)) + +**Fixed bugs:** + +- Error out if Daemon type does not provide a node selector. [\#159](https://github.com/voyagermesh/voyager/issues/159) +- Disable analytics when running tests [\#147](https://github.com/voyagermesh/voyager/issues/147) +- Missing services should be an warning not error stack error [\#137](https://github.com/voyagermesh/voyager/issues/137) +- Bad ingress object results in unstable HAProxy [\#135](https://github.com/voyagermesh/voyager/issues/135) +- Add ingress hostname to Ingress [\#132](https://github.com/voyagermesh/voyager/issues/132) +- Deleting LB deployment does not get recreated [\#123](https://github.com/voyagermesh/voyager/issues/123) +- Ensure HAproxy running when endpoints changes. [\#120](https://github.com/voyagermesh/voyager/issues/120) +- Updating Ingress annotations are not picked up by controller [\#115](https://github.com/voyagermesh/voyager/issues/115) +- Fix Ingress Status Update Properly. [\#134](https://github.com/voyagermesh/voyager/pull/134) ([sadlil](https://github.com/sadlil)) +- Expose monitoring port in chart and deploy yamls [\#156](https://github.com/voyagermesh/voyager/pull/156) ([tamalsaha](https://github.com/tamalsaha)) +- Add LoadBalancerSourceRange to ingress Spec [\#148](https://github.com/voyagermesh/voyager/pull/148) ([sadlil](https://github.com/sadlil)) +- Ensure loadbalancer resource [\#145](https://github.com/voyagermesh/voyager/pull/145) ([sadlil](https://github.com/sadlil)) +- Add annotation to add accept-proxy in bind statements [\#144](https://github.com/voyagermesh/voyager/pull/144) ([sadlil](https://github.com/sadlil)) +- Remove unwanted stacktrace from log [\#139](https://github.com/voyagermesh/voyager/pull/139) ([sadlil](https://github.com/sadlil)) +- Fix stats behavior [\#130](https://github.com/voyagermesh/voyager/pull/130) ([sadlil](https://github.com/sadlil)) + +**Closed issues:** + +- Allow exposing port 443 on the LoadBalancer Service [\#188](https://github.com/voyagermesh/voyager/issues/188) +- Source IP detection [\#146](https://github.com/voyagermesh/voyager/issues/146) +- helm chart [\#113](https://github.com/voyagermesh/voyager/issues/113) +- Merge pods & services even on create [\#172](https://github.com/voyagermesh/voyager/issues/172) +- Document 1.5.6 changes [\#150](https://github.com/voyagermesh/voyager/issues/150) +- Support Services of type ExternalName [\#127](https://github.com/voyagermesh/voyager/issues/127) +- Collect usage analytics [\#126](https://github.com/voyagermesh/voyager/issues/126) +- Support use of field spec.loadBalancerSourceRanges on Services of type LoadBalancer [\#122](https://github.com/voyagermesh/voyager/issues/122) + +**Merged pull requests:** + +- Fix chart path [\#191](https://github.com/voyagermesh/voyager/pull/191) ([tamalsaha](https://github.com/tamalsaha)) +- ./hack/make.py test\_deploy to generate deployments yaml [\#184](https://github.com/voyagermesh/voyager/pull/184) ([ashiquzzaman33](https://github.com/ashiquzzaman33)) +- Disable analytics for test runs [\#182](https://github.com/voyagermesh/voyager/pull/182) ([tamalsaha](https://github.com/tamalsaha)) +- Prepare docs for 1.5.6 [\#178](https://github.com/voyagermesh/voyager/pull/178) ([tamalsaha](https://github.com/tamalsaha)) +- Remove cluster name flag [\#177](https://github.com/voyagermesh/voyager/pull/177) ([tamalsaha](https://github.com/tamalsaha)) +- Remove persist annotation [\#174](https://github.com/voyagermesh/voyager/pull/174) ([tamalsaha](https://github.com/tamalsaha)) +- Add TLS certs for testing [\#173](https://github.com/voyagermesh/voyager/pull/173) ([tamalsaha](https://github.com/tamalsaha)) +- Run kloader check without exec [\#171](https://github.com/voyagermesh/voyager/pull/171) ([tamalsaha](https://github.com/tamalsaha)) +- Error out if Daemon type does not provide a node selector. [\#168](https://github.com/voyagermesh/voyager/pull/168) ([tamalsaha](https://github.com/tamalsaha)) +- Remove dependency on k8s-addons [\#141](https://github.com/voyagermesh/voyager/pull/141) ([tamalsaha](https://github.com/tamalsaha)) +- Use kloader 1.5.1 and check config before starting runit. [\#140](https://github.com/voyagermesh/voyager/pull/140) ([tamalsaha](https://github.com/tamalsaha)) +- Use ci-space cluster for testing [\#131](https://github.com/voyagermesh/voyager/pull/131) ([ashiquzzaman33](https://github.com/ashiquzzaman33)) +- tcp.md: fix typo/port mismatch [\#119](https://github.com/voyagermesh/voyager/pull/119) ([alekssaul](https://github.com/alekssaul)) +- Add Jenkinsfile [\#118](https://github.com/voyagermesh/voyager/pull/118) ([ashiquzzaman33](https://github.com/ashiquzzaman33)) +- Jenkins test patch1 [\#117](https://github.com/voyagermesh/voyager/pull/117) ([ashiquzzaman33](https://github.com/ashiquzzaman33)) +- Document flag options [\#190](https://github.com/voyagermesh/voyager/pull/190) ([tamalsaha](https://github.com/tamalsaha)) +- Docs for 1.5.6 [\#183](https://github.com/voyagermesh/voyager/pull/183) ([sadlil](https://github.com/sadlil)) +- Set metrics port to :8080 by default [\#180](https://github.com/voyagermesh/voyager/pull/180) ([tamalsaha](https://github.com/tamalsaha)) +- Stop redefining -h flag for run command. [\#179](https://github.com/voyagermesh/voyager/pull/179) ([tamalsaha](https://github.com/tamalsaha)) +- Remove --cluster-name flag [\#176](https://github.com/voyagermesh/voyager/pull/176) ([tamalsaha](https://github.com/tamalsaha)) +- Add nil check before reading options from Ingress annotations. [\#170](https://github.com/voyagermesh/voyager/pull/170) ([tamalsaha](https://github.com/tamalsaha)) +- Various cleanup of annotations [\#169](https://github.com/voyagermesh/voyager/pull/169) ([tamalsaha](https://github.com/tamalsaha)) +- Use hyphen separated words as annotation key. [\#166](https://github.com/voyagermesh/voyager/pull/166) ([tamalsaha](https://github.com/tamalsaha)) +- Use ingress.appscode.com/keep-source-ip: true to preserve source IP [\#165](https://github.com/voyagermesh/voyager/pull/165) ([tamalsaha](https://github.com/tamalsaha)) +- Combine annotation keys ip & persist into persist [\#162](https://github.com/voyagermesh/voyager/pull/162) ([tamalsaha](https://github.com/tamalsaha)) +- Make nodeSelector annotation applicable for any mode. [\#160](https://github.com/voyagermesh/voyager/pull/160) ([tamalsaha](https://github.com/tamalsaha)) +- Explain versioning policy. [\#158](https://github.com/voyagermesh/voyager/pull/158) ([tamalsaha](https://github.com/tamalsaha)) +- Apply various comments from official charts team [\#157](https://github.com/voyagermesh/voyager/pull/157) ([tamalsaha](https://github.com/tamalsaha)) +- Move component docs directly under user-guide [\#155](https://github.com/voyagermesh/voyager/pull/155) ([tamalsaha](https://github.com/tamalsaha)) +- Expose Operator & HAProxy metrics [\#153](https://github.com/voyagermesh/voyager/pull/153) ([tamalsaha](https://github.com/tamalsaha)) +- Reorganize code to add run sub command [\#152](https://github.com/voyagermesh/voyager/pull/152) ([tamalsaha](https://github.com/tamalsaha)) +- Add forked cloudprovider in third\_party package [\#151](https://github.com/voyagermesh/voyager/pull/151) ([tamalsaha](https://github.com/tamalsaha)) + +## [1.5.5](https://github.com/voyagermesh/voyager/tree/1.5.5) (2017-05-22) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/1.5.4...1.5.5) + +**Implemented enhancements:** + +- Support user provided annotations [\#103](https://github.com/voyagermesh/voyager/issues/103) +- Rename Daemon type to HostPort [\#72](https://github.com/voyagermesh/voyager/issues/72) +- expose NodePort like functionality to Ingress [\#68](https://github.com/voyagermesh/voyager/issues/68) +- Cross Namespace Service Support [\#40](https://github.com/voyagermesh/voyager/issues/40) +- Support health checks [\#38](https://github.com/voyagermesh/voyager/issues/38) +- Support full spectrum of HAProxy rules [\#21](https://github.com/voyagermesh/voyager/issues/21) +- Add user provided annotations in LoadBalancer in Service/Pods [\#105](https://github.com/voyagermesh/voyager/pull/105) ([sadlil](https://github.com/sadlil)) +- Feature weighted backend [\#77](https://github.com/voyagermesh/voyager/pull/77) ([sadlil](https://github.com/sadlil)) +- Update svc instead of Deleting svc [\#87](https://github.com/voyagermesh/voyager/pull/87) ([sadlil](https://github.com/sadlil)) +- Feature: backend rules [\#80](https://github.com/voyagermesh/voyager/pull/80) ([sadlil](https://github.com/sadlil)) + +**Fixed bugs:** + +- Update service in NodePort & LoadBalancer mode [\#86](https://github.com/voyagermesh/voyager/issues/86) +- Fix ALPN negotiation [\#32](https://github.com/voyagermesh/voyager/issues/32) +- Use annotations for backend weight [\#83](https://github.com/voyagermesh/voyager/pull/83) ([sadlil](https://github.com/sadlil)) +- Fix Loadbalancer Port Open Issues [\#99](https://github.com/voyagermesh/voyager/pull/99) ([sadlil](https://github.com/sadlil)) +- Ensure pod delete [\#97](https://github.com/voyagermesh/voyager/pull/97) ([sadlil](https://github.com/sadlil)) +- Update svc instead of Deleting svc [\#87](https://github.com/voyagermesh/voyager/pull/87) ([sadlil](https://github.com/sadlil)) + +**Closed issues:** + +- Allow free form HTTP rewriting [\#76](https://github.com/voyagermesh/voyager/issues/76) +- Test NodePort mode [\#98](https://github.com/voyagermesh/voyager/issues/98) +- Ensure pods are deleted before deleting RC / Deployment [\#96](https://github.com/voyagermesh/voyager/issues/96) +- Test that previously open NodePort is not reassigned [\#95](https://github.com/voyagermesh/voyager/issues/95) +- Use HAProxy 1.7.5 [\#90](https://github.com/voyagermesh/voyager/issues/90) +- Document 1.5.5 milestone features [\#78](https://github.com/voyagermesh/voyager/issues/78) +- Specify different services in a backend with weights [\#75](https://github.com/voyagermesh/voyager/issues/75) + +**Merged pull requests:** + +- Update top readme file [\#112](https://github.com/voyagermesh/voyager/pull/112) ([tamalsaha](https://github.com/tamalsaha)) +- Update docs [\#111](https://github.com/voyagermesh/voyager/pull/111) ([tamalsaha](https://github.com/tamalsaha)) +- NodePort Tests, Annotations Documentation [\#110](https://github.com/voyagermesh/voyager/pull/110) ([sadlil](https://github.com/sadlil)) +- Change HAProxy image to 1.7.5-1.5.5 [\#93](https://github.com/voyagermesh/voyager/pull/93) ([tamalsaha](https://github.com/tamalsaha)) +- Rename Daemon type to HostPort [\#84](https://github.com/voyagermesh/voyager/pull/84) ([tamalsaha](https://github.com/tamalsaha)) +- Use appscode/errors v2 [\#81](https://github.com/voyagermesh/voyager/pull/81) ([tamalsaha](https://github.com/tamalsaha)) +- Avoid upgrade in operator docker image [\#109](https://github.com/voyagermesh/voyager/pull/109) ([tamalsaha](https://github.com/tamalsaha)) +- Use alpine as the base image for operator [\#107](https://github.com/voyagermesh/voyager/pull/107) ([tamalsaha](https://github.com/tamalsaha)) +- Add `go` and `glide` commands to developer docs [\#101](https://github.com/voyagermesh/voyager/pull/101) ([julianvmodesto](https://github.com/julianvmodesto)) +- Ensure forward secrecy [\#94](https://github.com/voyagermesh/voyager/pull/94) ([tamalsaha](https://github.com/tamalsaha)) +- Update docs to build HAProxy 1.7.5 [\#92](https://github.com/voyagermesh/voyager/pull/92) ([tamalsaha](https://github.com/tamalsaha)) +- Use HAProxy 1.7.5 [\#91](https://github.com/voyagermesh/voyager/pull/91) ([tamalsaha](https://github.com/tamalsaha)) +- Introduce NodePort mode [\#85](https://github.com/voyagermesh/voyager/pull/85) ([tamalsaha](https://github.com/tamalsaha)) +- Update 1.5.5 Documentation [\#82](https://github.com/voyagermesh/voyager/pull/82) ([sadlil](https://github.com/sadlil)) + +## [1.5.4](https://github.com/voyagermesh/voyager/tree/1.5.4) (2017-05-08) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/1.5.3...1.5.4) + +**Fixed bugs:** + +- Voyager pod is restarting itself when attached backend pod restarts [\#69](https://github.com/voyagermesh/voyager/issues/69) +- Do not restart lb pod when backend pod restarts [\#70](https://github.com/voyagermesh/voyager/pull/70) ([sadlil](https://github.com/sadlil)) + +**Merged pull requests:** + +- Rename operator deployment to voyager-operator [\#71](https://github.com/voyagermesh/voyager/pull/71) ([tamalsaha](https://github.com/tamalsaha)) + +## [1.5.3](https://github.com/voyagermesh/voyager/tree/1.5.3) (2017-05-03) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/1.5.2...1.5.3) + +**Implemented enhancements:** + +- Support StatefulSet pod names in Voyager [\#14](https://github.com/voyagermesh/voyager/issues/14) +- Ingress Hostname based traffic forwarding [\#66](https://github.com/voyagermesh/voyager/pull/66) ([sadlil](https://github.com/sadlil)) + +**Fixed bugs:** + +- cloud-provider & cloud-name can't be always required [\#64](https://github.com/voyagermesh/voyager/issues/64) + +**Merged pull requests:** + +- Prepare docs for 1.5.3 release [\#67](https://github.com/voyagermesh/voyager/pull/67) ([tamalsaha](https://github.com/tamalsaha)) +- cloud-provider & cloud-name is not required for unknown providers. [\#65](https://github.com/voyagermesh/voyager/pull/65) ([tamalsaha](https://github.com/tamalsaha)) +- Test/fix ingress name [\#63](https://github.com/voyagermesh/voyager/pull/63) ([ashiquzzaman33](https://github.com/ashiquzzaman33)) +- Update docs to new chart location [\#60](https://github.com/voyagermesh/voyager/pull/60) ([tamalsaha](https://github.com/tamalsaha)) +- Move chart to root directory [\#59](https://github.com/voyagermesh/voyager/pull/59) ([tamalsaha](https://github.com/tamalsaha)) + +## [1.5.2](https://github.com/voyagermesh/voyager/tree/1.5.2) (2017-04-21) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/1.5.1...1.5.2) + +**Implemented enhancements:** + +- Add Retry on DaemonMode Loadbalancer http test call [\#52](https://github.com/voyagermesh/voyager/pull/52) ([sadlil](https://github.com/sadlil)) +- Fix Documentation [\#51](https://github.com/voyagermesh/voyager/pull/51) ([sadlil](https://github.com/sadlil)) + +**Fixed bugs:** + +- Slack channel token\_revoked [\#48](https://github.com/voyagermesh/voyager/issues/48) +- Service ports should be int [\#47](https://github.com/voyagermesh/voyager/issues/47) + +**Merged pull requests:** + +- Add service to deployments.yaml [\#58](https://github.com/voyagermesh/voyager/pull/58) ([tamalsaha](https://github.com/tamalsaha)) +- Prepare docs for version 1.5.2 [\#57](https://github.com/voyagermesh/voyager/pull/57) ([tamalsaha](https://github.com/tamalsaha)) +- Add service in voyager [\#56](https://github.com/voyagermesh/voyager/pull/56) ([saumanbiswas](https://github.com/saumanbiswas)) +- Fix stable chart [\#55](https://github.com/voyagermesh/voyager/pull/55) ([saumanbiswas](https://github.com/saumanbiswas)) +- Use unversioned time. [\#54](https://github.com/voyagermesh/voyager/pull/54) ([tamalsaha](https://github.com/tamalsaha)) +- Doc/fix update [\#53](https://github.com/voyagermesh/voyager/pull/53) ([sadlil](https://github.com/sadlil)) +- Initial voyager chart [\#43](https://github.com/voyagermesh/voyager/pull/43) ([saumanbiswas](https://github.com/saumanbiswas)) + +## [1.5.1](https://github.com/voyagermesh/voyager/tree/1.5.1) (2017-04-05) +[Full Changelog](https://github.com/voyagermesh/voyager/compare/1.5.0...1.5.1) + +**Implemented enhancements:** + +- Enable GKE [\#44](https://github.com/voyagermesh/voyager/issues/44) + +**Merged pull requests:** + +- Enable GKE [\#45](https://github.com/voyagermesh/voyager/pull/45) ([tamalsaha](https://github.com/tamalsaha)) +- Fix Typos [\#42](https://github.com/voyagermesh/voyager/pull/42) ([sunkuet02](https://github.com/sunkuet02)) +- update README [\#41](https://github.com/voyagermesh/voyager/pull/41) ([utf18](https://github.com/utf18)) + +## [1.5.0](https://github.com/voyagermesh/voyager/tree/1.5.0) (2017-03-01) +**Implemented enhancements:** + +- Various clean ups [\#18](https://github.com/voyagermesh/voyager/issues/18) +- Add ALPN options to TCP Backends [\#35](https://github.com/voyagermesh/voyager/pull/35) ([sadlil](https://github.com/sadlil)) +- Update docs with voyager options and test modes [\#34](https://github.com/voyagermesh/voyager/pull/34) ([sadlil](https://github.com/sadlil)) +- Add alpn option while TLS is used [\#25](https://github.com/voyagermesh/voyager/pull/25) ([sadlil](https://github.com/sadlil)) +- Adding Tests - Unit and E2E [\#12](https://github.com/voyagermesh/voyager/pull/12) ([sadlil](https://github.com/sadlil)) +- Ensure TPR at runtime [\#9](https://github.com/voyagermesh/voyager/pull/9) ([sadlil](https://github.com/sadlil)) +- add ingress-class [\#4](https://github.com/voyagermesh/voyager/pull/4) ([sadlil](https://github.com/sadlil)) +- Renamed ingress annotations to "ingress.appscode.com" [\#3](https://github.com/voyagermesh/voyager/pull/3) ([sadlil](https://github.com/sadlil)) +- use updated reloader. [\#2](https://github.com/voyagermesh/voyager/pull/2) ([sadlil](https://github.com/sadlil)) + +**Fixed bugs:** + +- Failing to deploy [\#29](https://github.com/voyagermesh/voyager/issues/29) +- Remove ALPN h2 for https [\#33](https://github.com/voyagermesh/voyager/pull/33) ([sadlil](https://github.com/sadlil)) +- Update doc fix for \#19 [\#26](https://github.com/voyagermesh/voyager/pull/26) ([sadlil](https://github.com/sadlil)) + +**Closed issues:** + +- Update documentation for nodeSelector cleanup [\#24](https://github.com/voyagermesh/voyager/issues/24) + +**Merged pull requests:** + +- Add doc explaining release process. [\#37](https://github.com/voyagermesh/voyager/pull/37) ([tamalsaha](https://github.com/tamalsaha)) +- Pass KLOADER\_ARGS as env variable [\#30](https://github.com/voyagermesh/voyager/pull/30) ([tamalsaha](https://github.com/tamalsaha)) +- Init cloud provider for Azure. [\#28](https://github.com/voyagermesh/voyager/pull/28) ([tamalsaha](https://github.com/tamalsaha)) +- Revendor dependencies. [\#23](https://github.com/voyagermesh/voyager/pull/23) ([tamalsaha](https://github.com/tamalsaha)) +- Use Ubuntu:16.04 as the base image to enable ALPN. [\#22](https://github.com/voyagermesh/voyager/pull/22) ([tamalsaha](https://github.com/tamalsaha)) +- Resolve \#18 [\#19](https://github.com/voyagermesh/voyager/pull/19) ([sadlil](https://github.com/sadlil)) +- Add example on front page. [\#16](https://github.com/voyagermesh/voyager/pull/16) ([tamalsaha](https://github.com/tamalsaha)) +- README typos [\#15](https://github.com/voyagermesh/voyager/pull/15) ([JakeAustwick](https://github.com/JakeAustwick)) +- Add links of subsections [\#11](https://github.com/voyagermesh/voyager/pull/11) ([sadlil](https://github.com/sadlil)) +- Update docs [\#10](https://github.com/voyagermesh/voyager/pull/10) ([sadlil](https://github.com/sadlil)) +- Rename voyager to Voyager [\#8](https://github.com/voyagermesh/voyager/pull/8) ([sadlil](https://github.com/sadlil)) +- Add acknowledgements [\#7](https://github.com/voyagermesh/voyager/pull/7) ([sadlil](https://github.com/sadlil)) +- Documentation for voyager [\#6](https://github.com/voyagermesh/voyager/pull/6) ([sadlil](https://github.com/sadlil)) +- Use kloader. [\#5](https://github.com/voyagermesh/voyager/pull/5) ([tamalsaha](https://github.com/tamalsaha)) +- Custom pongo2 filters for loading haproxy data. [\#1](https://github.com/voyagermesh/voyager/pull/1) ([sadlil](https://github.com/sadlil)) + + + +\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/GitHub-Changelog-Generator)* \ No newline at end of file diff --git a/content/docs/v2024.3.18/CONTRIBUTING.md b/content/docs/v2024.3.18/CONTRIBUTING.md new file mode 100644 index 000000000..3586d717d --- /dev/null +++ b/content/docs/v2024.3.18/CONTRIBUTING.md @@ -0,0 +1,66 @@ +--- +title: Contributing | Voyager +description: Contributing +menu: + docs_v2024.3.18: + identifier: contributing-voyager + name: Contributing + parent: welcome + weight: 10 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: welcome +url: /docs/v2024.3.18/welcome/contributing/ +aliases: +- /docs/v2024.3.18/CONTRIBUTING/ +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +# Contribution Guidelines +Want to hack on Voyager? + +AppsCode projects are [Apache 2.0 licensed](https://github.com/voyagermesh/voyager/blob/master/LICENSE) and accept contributions via +GitHub pull requests. This document outlines some of the conventions on +development workflow, commit message formatting, contact points and other +resources to make it easier to get your contribution accepted. + +## Certificate of Origin + +By contributing to this project you agree to the Developer Certificate of +Origin (DCO). This document was created by the Linux Kernel community and is a +simple statement that you, as a contributor, have the legal right to make the +contribution. See the [DCO](https://github.com/voyagermesh/voyager/blob/master/DCO) file for details. + +## Developer Guide + +We have a [Developer Guide](/docs/v2024.3.18/setup/developer-guide/overview) that outlines everything you need to know from setting up your +dev environment to how to build and test Voyager. If you find something undocumented or incorrect along the way, +please feel free to send a Pull Request. + +## Getting Help + +If you have a question about Voyager or having problem using it, you can contact us on the [AppsCode Slack team](https://appscode.slack.com/messages/C0XQFLGRM/details/) channel `#general`. Follow [this link](https://slack.appscode.com) to get invitation to our Slack channel. + +## Bugs/Feature request + +If you have found a bug with Voyager or want to request for new features, please [file an issue](https://github.com/voyagermesh/voyager/issues/new). + +## Submit PR + +If you fix a bug or developed a new feature, feel free to submit a PR. In either case, please file a [GitHub issue](https://github.com/voyagermesh/voyager/issues/new) first, so that we can have a discussion on it. This is a rough outline of what a contributor's workflow looks like: + + +- Create a topic branch from where you want to base your work (usually master). +- Make commits of logical units. +- Push your changes to a topic branch in your fork of the repository. +- Make sure the tests pass, and add any new tests as appropriate. +- Submit a pull request to the original repository. + +Thanks for your contributions! + +## Spread the word + +If you have written blog post or tutorial on Voyager, please share it with us on [Twitter](https://twitter.com/AppsCodeHQ) or [Slack](https://slack.appscode.com). diff --git a/content/docs/v2024.3.18/README.md b/content/docs/v2024.3.18/README.md new file mode 100644 index 000000000..ef09f815b --- /dev/null +++ b/content/docs/v2024.3.18/README.md @@ -0,0 +1,43 @@ +--- +title: Welcome | Voyager +description: Welcome to Voyager +menu: + docs_v2024.3.18: + identifier: readme-voyager + name: Readme + parent: welcome + weight: -1 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: welcome +url: /docs/v2024.3.18/welcome/ +aliases: +- /docs/v2024.3.18/ +- /docs/v2024.3.18/README/ +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +# Voyager + +Voyager is a [HAProxy](http://www.haproxy.org/) backed secure L7 and L4 ingress controller for Kubernetes developed by [AppsCode](https://appscode.com). This can be used with any Kubernetes cloud providers including aws, gce, gke, azure, acs. This can also be used with bare metal Kubernetes clusters. + +From here you can learn all about Voyager's architecture and how to deploy and use Voyager. + +- [Concepts](/docs/v2024.3.18/concepts/). Concepts explain some significant aspect of Voyager. This +is where you can learn about what Voyager does and how it does it. + +- [Setup](/docs/v2024.3.18/setup/). Setup contains instructions for installing + the Voyager in various cloud providers. + +- Guides. Guides show you how to perform tasks with Voyager. These are organized under [Ingress](/docs/v2024.3.18/guides/ingress) and [Certificate](/docs/v2024.3.18/guides/certificate). + +- [Reference](/docs/v2024.3.18/reference/). Detailed exhaustive lists of +command-line options, configuration options, API definitions, and procedures. + +We're always looking for help improving our documentation, so please don't hesitate to +[file an issue](https://github.com/voyagermesh/voyager/issues/new) if you see some problem. +Or better yet, submit your own [contributions](/docs/v2024.3.18/CONTRIBUTING) to help +make our docs better. diff --git a/content/docs/v2024.3.18/_index.md b/content/docs/v2024.3.18/_index.md new file mode 100644 index 000000000..627800bf6 --- /dev/null +++ b/content/docs/v2024.3.18/_index.md @@ -0,0 +1,15 @@ +--- +title: Docs | Voyager +description: Voyager Docs +menu: + docs_v2024.3.18: + identifier: welcome + name: Welcome + weight: 10 +menu_name: docs_v2024.3.18 +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + diff --git a/content/docs/v2024.3.18/acknowledgement.md b/content/docs/v2024.3.18/acknowledgement.md new file mode 100644 index 000000000..dfdb1f0b8 --- /dev/null +++ b/content/docs/v2024.3.18/acknowledgement.md @@ -0,0 +1,30 @@ +--- +title: Acknowledgement | Voyager +description: Acknowledgement +menu: + docs_v2024.3.18: + identifier: acknowledgement-voyager + name: Acknowledgement + parent: welcome + weight: 20 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: welcome +url: /docs/v2024.3.18/welcome/acknowledgement/ +aliases: +- /docs/v2024.3.18/acknowledgement/ +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +# Acknowledgement + + - docker-library/haproxy https://github.com/docker-library/haproxy + - kubernetes/contrib https://github.com/kubernetes/contrib/tree/master/service-loadbalancer + - kubernetes/ingress https://github.com/kubernetes/ingress + - xenolf/lego https://github.com/appscode/lego + - kelseyhightower/kube-cert-manager https://github.com/kelseyhightower/kube-cert-manager + - PalmStoneGames/kube-cert-manager https://github.com/PalmStoneGames/kube-cert-manager + - [Kubernetes cloudprovider implementation](https://github.com/kubernetes/kubernetes/tree/master/pkg/cloudprovider) diff --git a/content/docs/v2024.3.18/concepts/README.md b/content/docs/v2024.3.18/concepts/README.md new file mode 100644 index 000000000..a7598ba48 --- /dev/null +++ b/content/docs/v2024.3.18/concepts/README.md @@ -0,0 +1,31 @@ +--- +title: Concepts | Voyager +menu: + docs_v2024.3.18: + identifier: concepts-readme + name: Readme + parent: concepts + weight: -1 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: concepts +url: /docs/v2024.3.18/concepts/ +aliases: +- /docs/v2024.3.18/concepts/README/ +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +# Concepts + +Concepts help you learn about the different parts of the Voyager and the abstractions it uses. + +- [Overview](/docs/v2024.3.18/concepts/overview). Provides a conceptual introduction to Voyager, including the problems it solves and its high-level architecture. + +- Types of Ingress + - [LoadBalancer](/docs/v2024.3.18/concepts/ingress-types/loadbalancer). Explains how LoadBalancer type Ingress works. + - [NodePort](/docs/v2024.3.18/concepts/ingress-types/nodeport). Explains how NodePort type Ingress works. + - [HostPort](/docs/v2024.3.18/concepts/ingress-types/hostport). Explains how HostPort type Ingress works. + - [Internal](/docs/v2024.3.18/concepts/ingress-types/internal). Explains how Internal type Ingress works. diff --git a/content/docs/v2024.3.18/concepts/_index.md b/content/docs/v2024.3.18/concepts/_index.md new file mode 100644 index 000000000..648797786 --- /dev/null +++ b/content/docs/v2024.3.18/concepts/_index.md @@ -0,0 +1,15 @@ +--- +title: Guides +description: Voyager Guides +menu: + docs_v2024.3.18: + identifier: concepts + name: Concepts + weight: 20 +menu_name: docs_v2024.3.18 +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + diff --git a/content/docs/v2024.3.18/concepts/haproxy.md b/content/docs/v2024.3.18/concepts/haproxy.md new file mode 100644 index 000000000..e69de29bb diff --git a/content/docs/v2024.3.18/concepts/ingress-types/_index.md b/content/docs/v2024.3.18/concepts/ingress-types/_index.md new file mode 100644 index 000000000..5d292ba41 --- /dev/null +++ b/content/docs/v2024.3.18/concepts/ingress-types/_index.md @@ -0,0 +1,17 @@ +--- +title: Types of Ingress | Voyager +menu: + docs_v2024.3.18: + identifier: ingress-types-concepts + name: Types of Ingress + parent: concepts + weight: 15 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: concepts +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + diff --git a/content/docs/v2024.3.18/concepts/ingress-types/hostport.md b/content/docs/v2024.3.18/concepts/ingress-types/hostport.md new file mode 100644 index 000000000..223bdb9f7 --- /dev/null +++ b/content/docs/v2024.3.18/concepts/ingress-types/hostport.md @@ -0,0 +1,182 @@ +--- +title: HostPort Ingress | Voyager +menu: + docs_v2024.3.18: + identifier: hostport-ingress + name: HostPort + parent: ingress-types-concepts + weight: 20 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: concepts +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +# HostPort + +In `HostPort` type Ingress, HAProxy pods are run via a Kubernetes deployment named `voyager-${ingress-name}` with `hostNetwork: true`. A headless Service is also created for the HAProxy pods. To enable this, apply the `ingress.appscode.com/type: HostPort` annotation on a Ingress object. + +## How It Works + +- First, install Voyager operator in your cluster following the steps [here](/docs/v2024.3.18/setup/install). + +- Now, deploy test servers using [this script](/docs/v2024.3.18/examples/ingress/types/hostport/deploy-servers.sh) script. + +```bash +curl -fsSL https://raw.githubusercontent.com/voyagermesh/voyager/{{< param "info.version" >}}/docs/examples/ingress/types/hostport/deploy-servers.sh | bash + +deployment "nginx" created +service "web" exposed +deployment "echoserver" created +service "rest" exposed +``` + +- Now, create an Ingress object running + +```bash +kubectl apply -f https://raw.githubusercontent.com/voyagermesh/voyager/{{< param "info.version" >}}/docs/examples/ingress/types/hostport/ing.yaml +``` + +Please note the annotation on ingress: + +```yaml + annotations: + ingress.appscode.com/type: HostPort +``` + +```bash +$ kubectl get pods,svc +NAME READY STATUS RESTARTS AGE +po/echoserver-566fcc4fdb-7fth7 1/1 Running 0 6m +po/nginx-d5dc44cf7-m4xcg 1/1 Running 0 6m +po/voyager-test-ingress-668594cc46-5zswh 1/1 Running 0 4m + +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +svc/kubernetes ClusterIP 10.96.0.1 443/TCP 1h +svc/rest ClusterIP 10.103.13.42 80/TCP 6m +svc/voyager-test-ingress ClusterIP None 80/TCP 4m +svc/web ClusterIP 10.99.232.60 80/TCP 6m +``` + +- Now, ssh into the minikube vm and run the following commands from host: + +```bash +$ minikube ssh + +$ curl -vv 127.0.0.1 -H "Host: web.example.com" +> GET / HTTP/1.1 +> Host: web.example.com +> User-Agent: curl/7.53.0 +> Accept: */* +> +< HTTP/1.1 200 OK +< Server: nginx/1.13.8 +< Date: Thu, 28 Dec 2017 04:27:20 GMT +< Content-Type: text/html +< Content-Length: 612 +< Last-Modified: Tue, 26 Dec 2017 11:11:22 GMT +< ETag: "5a422e5a-264" +< Accept-Ranges: bytes +< + + + +Welcome to nginx! + + + +

Welcome to nginx!

+

If you see this page, the nginx web server is successfully installed and +working. Further configuration is required.

+ +

For online documentation and support please refer to +nginx.org.
+Commercial support is available at +nginx.com.

+ +

Thank you for using nginx.

+ + +``` + +```bash +$ curl -vv 127.0.0.1 -H "Host: app.example.com" +> GET / HTTP/1.1 +> Host: app.example.com +> User-Agent: curl/7.53.0 +> Accept: */* +> +< HTTP/1.1 200 OK +< Server: nginx/1.10.0 +< Date: Thu, 28 Dec 2017 04:27:39 GMT +< Content-Type: text/plain +< Transfer-Encoding: chunked +< +CLIENT VALUES: +client_address=172.17.0.1 +command=GET +real path=/ +query=nil +request_version=1.1 +request_uri=http://app.example.com:8080/ + +SERVER VALUES: +server_version=nginx: 1.10.0 - lua: 10001 + +HEADERS RECEIVED: +accept=*/* +connection=close +host=app.example.com +user-agent=curl/7.53.0 +x-forwarded-for=127.0.0.1 +BODY: +``` + +Now, if you run `netstat`, you should port 80 is listened on by haproxy. + +```bash +$ netstat -tuln | grep 80 +tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN +tcp 0 0 127.0.0.1:2380 0.0.0.0:* LISTEN +``` + +## FAQ + +## Does Voyager configure firewalls for HostPort Ingress? + +Voyager operator will configure firewall rules for HostPort Ingress for the following cloud providers: AWS, GCE/GKE . + +## What IAM permissions are required for Voyager operator to configure firewalls for HostPort Ingress in AWS? + + - Master: For aws clusters provisioned via [Kops](https://github.com/kubernetes/kops/blob/master/docs/iam_roles.md), no additional permission should be needed. Master instances already has `ec2:*` iam permissions. + +- Nodes: `Describe*` permissions are applied by default. Additional `write` permissions need to be applied are: +``` +{ + "Effect": "Allow", + "Action": [ + "ec2:AuthorizeSecurityGroupIngress", + "ec2:CreateRoute", + "ec2:CreateSecurityGroup", + "ec2:CreateTags", + "ec2:DeleteRoute", + "ec2:DeleteSecurityGroup", + "ec2:ModifyInstanceAttribute", + "ec2:RevokeSecurityGroupIngress", + "ec2:DescribeInstances", + "ec2:DescribeRouteTables", + "ec2:DescribeSecurityGroups", + "ec2:DescribeSubnets" + ], + "Resource": "*" +} +``` diff --git a/content/docs/v2024.3.18/concepts/ingress-types/internal.md b/content/docs/v2024.3.18/concepts/ingress-types/internal.md new file mode 100644 index 000000000..34c911dc2 --- /dev/null +++ b/content/docs/v2024.3.18/concepts/ingress-types/internal.md @@ -0,0 +1,146 @@ +--- +title: Internal Ingress | Voyager +menu: + docs_v2024.3.18: + identifier: internal-ingress + name: Internal + parent: ingress-types-concepts + weight: 25 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: concepts +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +# Internal + +In `Internal` type Ingress, HAProxy pods are exposed via a ClusterIP type Kubernetes service named `voyager-${ingress-name}`. To enable this, apply the `ingress.appscode.com/type: Internal` annotation on a Ingress object. Unlike Kubernetes Service which operates at L4 level, this creates a cluster internal L7 proxy. An example use-case is proxy for ElasticSearch cluster to handle persistent connections, alleviating the ElasticSearch servers from having to deal w/ tons of connection creations. + +## How It Works + +- First, install Voyager operator in your cluster following the steps [here](/docs/v2024.3.18/setup/install). + +- Now, deploy test servers using [this script](/docs/v2024.3.18/examples/ingress/types/internal/deploy-servers.sh) script. + +```bash +curl -fsSL https://raw.githubusercontent.com/voyagermesh/voyager/{{< param "info.version" >}}/docs/examples/ingress/types/internal/deploy-servers.sh | bash + +deployment "nginx" created +service "web" exposed +deployment "echoserver" created +service "rest" exposed +``` + +- Now, create an Ingress object running + +```bash +kubectl apply -f https://raw.githubusercontent.com/voyagermesh/voyager/{{< param "info.version" >}}/docs/examples/ingress/types/internal/ing.yaml +``` + +Please note the annotation on ingress: + +```yaml + annotations: + ingress.appscode.com/type: Internal +``` + +```bash +$ kubectl get pods,svc +NAME READY STATUS RESTARTS AGE +po/echoserver-566fcc4fdb-bw4xm 1/1 Running 0 1m +po/nginx-d5dc44cf7-brgd4 1/1 Running 0 1m +po/voyager-test-ingress-6859dc5ddd-9mmz2 1/1 Running 0 34s + +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +svc/kubernetes ClusterIP 10.96.0.1 443/TCP 7m +svc/rest ClusterIP 10.105.80.152 80/TCP 1m +svc/voyager-test-ingress ClusterIP 10.97.153.185 80/TCP 34s +svc/web ClusterIP 10.96.37.26 80/TCP 1m + +$ minikube ip +192.168.99.100 +``` + +- Now, ssh into the minikube vm and run the following commands from host: + +```bash +$ minikube ssh + +$ curl -vv 10.97.153.185 -H "Host: web.example.com" +> GET / HTTP/1.1 +> Host: web.example.com +> User-Agent: curl/7.53.0 +> Accept: */* +> +< HTTP/1.1 200 OK +< Server: nginx/1.13.8 +< Date: Thu, 18 Jan 2018 06:58:29 GMT +< Content-Type: text/html +< Content-Length: 612 +< Last-Modified: Tue, 26 Dec 2017 11:11:22 GMT +< ETag: "5a422e5a-264" +< Accept-Ranges: bytes +< + + + +Welcome to nginx! + + + +

Welcome to nginx!

+

If you see this page, the nginx web server is successfully installed and +working. Further configuration is required.

+ +

For online documentation and support please refer to +nginx.org.
+Commercial support is available at +nginx.com.

+ +

Thank you for using nginx.

+ + +``` + +```bash +$ curl -vv 10.97.153.185 -H "Host: app.example.com" +> GET / HTTP/1.1 +> Host: app.example.com +> User-Agent: curl/7.53.0 +> Accept: */* +> +< HTTP/1.1 200 OK +< Server: nginx/1.10.0 +< Date: Thu, 18 Jan 2018 06:59:05 GMT +< Content-Type: text/plain +< Transfer-Encoding: chunked +< +CLIENT VALUES: +client_address=172.17.0.7 +command=GET +real path=/ +query=nil +request_version=1.1 +request_uri=http://app.example.com:8080/ + +SERVER VALUES: +server_version=nginx: 1.10.0 - lua: 10001 + +HEADERS RECEIVED: +accept=*/* +connection=close +host=app.example.com +user-agent=curl/7.53.0 +x-forwarded-for=10.0.2.15 +BODY: +-no body in request- +``` diff --git a/content/docs/v2024.3.18/concepts/ingress-types/loadbalancer.md b/content/docs/v2024.3.18/concepts/ingress-types/loadbalancer.md new file mode 100644 index 000000000..77e37f19a --- /dev/null +++ b/content/docs/v2024.3.18/concepts/ingress-types/loadbalancer.md @@ -0,0 +1,211 @@ +--- +title: LoadBalancer Ingress | Voyager +menu: + docs_v2024.3.18: + identifier: loadbalancer-ingress + name: LoadBalancer + parent: ingress-types-concepts + weight: 10 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: concepts +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +# LoadBalancer + +In `LoadBalancer` type Ingress, HAProxy pods are exposed via a LoadBalancer type Kubernetes service named `voyager-${ingress-name}`. You can apply the `ingress.appscode.com/type: LoadBalancer` annotation on a Ingress object to enable this type of Ingress. This is also the default type for Ingress objects. So, this annotation is not required to enable this type. + +## How It Works + +- First, install Voyager operator in your cluster following the steps [here](/docs/v2024.3.18/setup/install). + +- Now, deploy test servers using [this script](/docs/v2024.3.18/examples/ingress/types/loadbalancer/deploy-servers.sh) script. + +```bash +curl -fsSL https://raw.githubusercontent.com/voyagermesh/voyager/{{< param "info.version" >}}/docs/examples/ingress/types/loadbalancer/deploy-servers.sh | bash + +deployment "nginx" created +service "web" exposed +deployment "echoserver" created +service "rest" exposed +``` + +- Now, create an Ingress object running + +```bash +kubectl apply -f https://raw.githubusercontent.com/voyagermesh/voyager/{{< param "info.version" >}}/docs/examples/ingress/types/loadbalancer/ing.yaml +``` + +Please note the annotation on ingress: + +```yaml + annotations: + ingress.appscode.com/type: LoadBalancer +``` + +```bash +$ kubectl get pods,svc +NAME READY STATUS RESTARTS AGE +po/echoserver-848b75d85-wxdrz 1/1 Running 0 2m +po/nginx-7c87f569d-5q5mf 1/1 Running 0 3m +po/voyager-test-ingress-687d6b7c65-qjqzt 1/1 Running 0 1m + +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +svc/kubernetes ClusterIP 10.11.240.1 443/TCP 4m +svc/rest ClusterIP 10.11.252.242 80/TCP 2m +svc/voyager-test-ingress LoadBalancer 10.11.248.185 35.226.114.148 80:30854/TCP 1m +svc/web ClusterIP 10.11.253.33 80/TCP 2m +``` + +```bash +$ curl -vv 35.226.114.148 -H "Host: web.example.com" +* Rebuilt URL to: 35.226.114.148/ +* Trying 35.226.114.148... +* Connected to 35.226.114.148 (35.226.114.148) port 80 (#0) +> GET / HTTP/1.1 +> Host: web.example.com +> User-Agent: curl/7.47.0 +> Accept: */* +> +< HTTP/1.1 200 OK +< Server: nginx/1.13.8 +< Date: Thu, 18 Jan 2018 06:40:49 GMT +< Content-Type: text/html +< Content-Length: 612 +< Last-Modified: Tue, 26 Dec 2017 11:11:22 GMT +< ETag: "5a422e5a-264" +< Accept-Ranges: bytes +< + + + +Welcome to nginx! + + + +

Welcome to nginx!

+

If you see this page, the nginx web server is successfully installed and +working. Further configuration is required.

+ +

For online documentation and support please refer to +nginx.org.
+Commercial support is available at +nginx.com.

+ +

Thank you for using nginx.

+ + +* Connection #0 to host 35.226.114.148 left intact +``` + +```bash +$ curl -vv 35.226.114.148 -H "Host: app.example.com" +* Rebuilt URL to: 35.226.114.148/ +* Trying 35.226.114.148... +* Connected to 35.226.114.148 (35.226.114.148) port 80 (#0) +> GET / HTTP/1.1 +> Host: app.example.com +> User-Agent: curl/7.47.0 +> Accept: */* +> +< HTTP/1.1 200 OK +< Server: nginx/1.10.0 +< Date: Thu, 18 Jan 2018 06:41:36 GMT +< Content-Type: text/plain +< Transfer-Encoding: chunked +< +CLIENT VALUES: +client_address=10.8.0.14 +command=GET +real path=/ +query=nil +request_version=1.1 +request_uri=http://app.example.com:8080/ + +SERVER VALUES: +server_version=nginx: 1.10.0 - lua: 10001 + +HEADERS RECEIVED: +accept=*/* +connection=close +host=app.example.com +user-agent=curl/7.47.0 +x-forwarded-for=10.8.0.1 +BODY: +* Connection #0 to host 35.226.114.148 left intact +``` + +## FAQ + +**How do I ensure that IP assigned my Ingress does not change?** + +You can allocate a static IP to a LoadBalancer Ingress managed by Voyager. Say for example, you are using GKE. When you create an Ingress object, Voyager will create a Kubernetes Service of type LoadBalancer. This service will automatically get a regional IP. If you want to keep that IP, you can mark that IP as static in Google cloud console +and the apply the annotation to your Ingress. + +```yaml + annotations: + ingress.appscode.com/type: LoadBalancer + ` ingress.appscode.com/load-balancer-ip: 'a.b.c.d'` +``` + + +**How do I use a Global Static IP (anycast IP) with an Ingress in GKE?** + +You can't use Global Static IP with a LoabBalancer Ingress managed by GKE. Voyager creates a `LoadBalancer` Service to expose HAProxy pods. Under the hood, Kubernetes creates a `Network LoadBalancer` to expose that Kubernetes service. Network LoadBalancers can only use regional static IPs. + +If you want to use Global static IP with Google Cloud, these pods need to be exposed via a HTTP LoadBalancer. Voyager does not support this today. This is not a priority for us but if you want to contribute, we can talk more. To use HTTP LoadBalancers today, you can use the `gce` ingress controller: https://github.com/kubernetes/ingress-gce . You may already know that HTTP LoadBalancer can only open port 80, 8080 and 443 and serve HTTP traffic. Please consult the official docs for more details: https://cloud.google.com/compute/docs/load-balancing/ + + +**How to use LoadBalancer type ingress in Openstack?** + +If you need to create an internal LB in Openstack, you can do so using `ingress.appscode.com/annotations-service` annotation on the Ingress object. + +```yaml + annotations: + ingress.appscode.com/type: LoadBalancer + ingress.appscode.com/annotations-service: | + { + "service.beta.kubernetes.io/openstack-internal-load-balancer": "true" + } +``` + + +**How to use LoadBalancer type ingress in Minikube cluster?** + +Minikube clusters do not support service type `LoadBalancer`. So, you can try the following workarounds: + +- You can set the `Host` header is your http request to match the expected domain and port. This will ensure HAProxy matches the rules properly. + +```bash +$ curl -vv : -H "Host: app.example.com" +``` + +- This work around is available thanks to [@david92rl](https://github.com/david92rl). You can use a service type ClusterIP with an ip fixed (like 10.0.0.150), then create a route to it from host machine. + +**_Minikube on Mac with virtualbox/vmware providers_** + +```bash +sudo route -n delete ${K8S_NETWORK} > /dev/null 2>&1 +sudo route -n add ${K8S_NETWORK} $(minikube ip) +interface=$(ifconfig 'bridge0' | grep member | awk '{print $2}' | xargs | awk '{print $1}') +sudo ifconfig bridge0 -hostfilter ${interface} +``` + +**_Minikube on Linux_** + +```bash +sudo ip route del ${K8S_NETWORK} +sudo ip route add ${K8S_NETWORK} via $(minikube ip) +``` + +*K8S_NETWORK* usually is `10.0.0.0/24` but it's worth to double check always. diff --git a/content/docs/v2024.3.18/concepts/ingress-types/nodeport.md b/content/docs/v2024.3.18/concepts/ingress-types/nodeport.md new file mode 100644 index 000000000..862d26798 --- /dev/null +++ b/content/docs/v2024.3.18/concepts/ingress-types/nodeport.md @@ -0,0 +1,233 @@ +--- +title: NodePort Ingress | Voyager +menu: + docs_v2024.3.18: + identifier: nodeport-ingress + name: NodePort + parent: ingress-types-concepts + weight: 15 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: concepts +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +# NodePort + +In `NodePort` type Ingress, HAProxy pods are exposed via a NodePort type Kubernetes service named `voyager-${ingress-name}`. To enable this, apply the `ingress.appscode.com/type: NodePort` annotation on a Ingress object. + +## How It Works + +- First, install Voyager operator in your cluster following the steps [here](/docs/v2024.3.18/setup/install). + +- Then, deploy and expose a test server. + +```bash +$ kubectl run test-server --image=gcr.io/google_containers/echoserver:1.8 +deployment "test-server" created + +$ kubectl expose deployment test-server --type=LoadBalancer --port=80 --target-port=8080 +service "test-server" exposed +``` + +- Now, create an Ingress with `ingress.appscode.com/type: NodePort` annotation. + +```yaml +$ kubectl apply -f test-ingress.yaml + +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: default + annotations: + ingress.appscode.com/type: NodePort +spec: + rules: + - host: voyager.appscode.test + http: + paths: + - path: /foo + backend: + service: + name: test-server + port: + number: 80 +``` + +```bash +$ kubectl get pods,svc +NAME READY STATUS RESTARTS AGE +po/test-server-68ddc845cd-x7dtv 1/1 Running 0 4h +po/voyager-test-ingress-5b758664f6-4vptr 1/1 Running 0 1m + +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +svc/kubernetes ClusterIP 10.96.0.1 443/TCP 2d +svc/test-server LoadBalancer 10.105.13.31 80:30390/TCP 21h +svc/voyager-test-ingress NodePort 10.107.182.219 80:30800/TCP 39m +``` + +```bash +$ minikube service --url voyager-test-ingress +http://192.168.99.100:30800 +``` + +```bash +$ curl -v -H 'Host: voyager.appscode.test' 192.168.99.100:30800/foo +* Trying 192.168.99.100... +* Connected to 192.168.99.100 (192.168.99.100) port 30800 (#0) +> GET /foo HTTP/1.1 +> Host: voyager.appscode.test +> User-Agent: curl/7.47.0 +> Accept: */* +> +< HTTP/1.1 200 OK +< Date: Wed, 14 Feb 2018 09:34:30 GMT +< Content-Type: text/plain +< Transfer-Encoding: chunked +< Server: echoserver +< + + +Hostname: test-server-68ddc845cd-x7dtv + +Pod Information: + -no pod information available- + +Server values: + server_version=nginx: 1.13.3 - lua: 10008 + +Request Information: + client_address=172.17.0.6 + method=GET + real path=/foo + query= + request_version=1.1 + request_uri=http://voyager.appscode.test:8080/foo + +Request Headers: + accept=*/* + connection=close + host=voyager.appscode.test + user-agent=curl/7.47.0 + x-forwarded-for=172.17.0.1 + +Request Body: + -no body in request- + +* Connection #0 to host 192.168.99.100 left intact +``` + +## External IP +If you are using NodePort type Ingress, you can specify [`externalIPs`](https://kubernetes.io/docs/concepts/services-networking/service/#external-ips) for the NodePort service used to export HAProxy pods. + +If you are running Voyager as Ingress controller in your `baremetal` cluster and want to assing a VIP to the HAProxy service for a highly available Ingress setup, you should use this option. + +Below is an example Ingress yaml that shows how to specify externalIPs: + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: default + annotations: + ingress.appscode.com/type: NodePort +spec: + externalIPs: + - a.b.c.d + rules: + - host: voyager.appscode.test + http: + paths: + - path: /foo + backend: + service: + name: test-server + port: + number: 80 +``` + +## Understanding `ingress.appscode.com/use-node-port` annotation + +When you are using `NodePort` type Ingress, your external clients (example, web browser) can connect to your backend services in 2 ways: + + - You may expose the NodePort service using an external hardware loadbalancer (like F5) or software loadbalancer like ALB in AWS. In these scenarios, the front loadbalancer will receive connections on service port from external clients (like web browser) and connect to the HAProxy NodePorts. So, HAProxy will see that incoming traffic is using Host like `domain:ing-port`. To ensure that HAProxy matches against the NodePort, use the annotation `ingress.appscode.com/use-node-port: "false"`. This is also considered the default value for this annotation. So, if you do not provide this annotation, it will be considered set to `false`. + + - Using the `NodePort` assigned to the HAProxy service. In this scenarios, external traffic directly hits the HAProxy NodePort service. So, HAProxy will see that incoming traffic is using Host like `domain:node-port`. To ensure that HAProxy matches against the NodePort, use the annotation `ingress.appscode.com/use-node-port: "true"` . +To ensure that HAProxy service ports stay fixed, define them in the Ingress YAML following: https://github.com/voyagermesh/voyager/blob/master/docs/guides/ingress/configuration/node-port.md + +Below is an example Ingress with `ingress.appscode.com/use-node-port` annotation: + +```yaml +$ kubectl apply -f test-ingress.yaml + +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: default + annotations: + ingress.appscode.com/type: NodePort + ingress.appscode.com/use-node-port: "true" +spec: + rules: + - host: voyager.appscode.test + http: + paths: + - path: /foo + backend: + service: + name: test-server + port: + number: 80 +``` + +```bash +$ curl -v -H 'Host: voyager.appscode.test:30800' 192.168.99.100:30800/foo +* Trying 192.168.99.100... +* Connected to 192.168.99.100 (192.168.99.100) port 30800 (#0) +> GET /foo HTTP/1.1 +> Host: voyager.appscode.test:30800 +> User-Agent: curl/7.47.0 +> Accept: */* +> +< HTTP/1.1 200 OK +< Date: Wed, 14 Feb 2018 09:47:43 GMT +< Content-Type: text/plain +< Transfer-Encoding: chunked +< Server: echoserver +< + + +Hostname: test-server-68ddc845cd-x7dtv + +Pod Information: + -no pod information available- + +Server values: + server_version=nginx: 1.13.3 - lua: 10008 + +Request Information: + client_address=172.17.0.6 + method=GET + real path=/foo + query= + request_version=1.1 + request_uri=http://voyager.appscode.test:8080/foo + +Request Headers: + accept=*/* + connection=close + host=voyager.appscode.test:30800 + user-agent=curl/7.47.0 + x-forwarded-for=172.17.0.1 + +Request Body: + -no body in request- + +* Connection #0 to host 192.168.99.100 left intact +``` \ No newline at end of file diff --git a/content/docs/v2024.3.18/concepts/overview.md b/content/docs/v2024.3.18/concepts/overview.md new file mode 100644 index 000000000..58bee7f94 --- /dev/null +++ b/content/docs/v2024.3.18/concepts/overview.md @@ -0,0 +1,86 @@ +--- +title: Overview | Voyager +menu: + docs_v2024.3.18: + identifier: overview-concepts + name: Overview + parent: concepts + weight: 10 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: concepts +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +# Voyager +Voyager is a [HAProxy](http://www.haproxy.org/) backed [secure](#certificate) L7 and L4 [ingress](#ingress) controller for Kubernetes developed by +[AppsCode](https://appscode.com). This can be used with any Kubernetes cloud providers including aws, gce, gke, azure, acs. This can also be used with bare metal Kubernetes clusters. + + +## Ingress +Voyager provides L7 and L4 loadbalancing using Kubernetes standard [Ingress](https://kubernetes.io/docs/concepts/services-networking/ingress/) resource. This is built on top of the [HAProxy](http://www.haproxy.org/) to support high availability, sticky sessions, name and path-based virtual hosting among other features. The following diagram shows how voyager operator works. Voyager also provides a custom [Ingress](/docs/v2024.3.18/guides/ingress) resource under `voyager.appscode.com` api group that extends the functionality of standard Ingress in a Kubernetes native way. + +![voyager-ingress](/docs/v2024.3.18/images/ingress/voyager-ingress.png) + +The above diagram shows how the Voyager operator works. When Voyager is [installed](/docs/v2024.3.18/setup/install) in a Kubernetes cluster, a pod named `voyager-operator-***` starts running in `voyager` namespace by default. This operator pod watches for Kubernetes Ingress resources and Voyager's own Ingress CRD. When an Ingress object is created, Voyager operator creates 3 Kubernetes resources in the same namespace of the Ingress: + +- a Configmap named `voyager-${ingress-name}`: This contains the auto generated HAProxy configuration under `haproxy.cfg` key. + +- a Deployment named `voyager-${ingress-name}`: This runs HAProxy pods that mounts the above configmap. Each pod has one container for HAProxy. This container also includes some additional binary to reload HAProxy when the respective configmap updates. This also includes logic for mounting and updating SSL secrets referenced in the corresponding Ingress resource. HAProxy pods can also contain a side-car container for exporting Prometheus ready metrics, if [enabled](/docs/v2024.3.18/guides/ingress/monitoring/haproxy-stats). + +- a Service named `voyager-${ingress-name}`: This Kubernetes Service exposes the above HAProxy pods to the internet. The type of Service can be configured by user via `ingress.appscode.com/type` annotation on the Ingress. + +- a Service named `voyager-${ingress-name}-stats`: This Kubernetes Service is used to expose Prometheus ready metrics for HAProxy pods. This service is always of type `ClusterIP` and only created if stats are [enabled](/docs/v2024.3.18/guides/ingress/monitoring/haproxy-stats). + +## Certificate + +Voyager can automagically provision and refresh SSL certificates issued from Let's Encrypt using a custom Kubernetes [Certificate](/docs/v2024.3.18/guides/certificate) resource. + +- Provision free TLS certificates from Let's Encrypt, +- Manage issued certificates using a Kubernetes Third Party Resource, +- Domain validation using ACME dns-01 challenges, +- Support for multiple DNS providers, +- Auto Renew Certificates, +- Use issued Certificates with Ingress to Secure Communications. + + +## FAQ + +**How do I run Voyager with other Ingress controllers in the same cluster?** + +Yes, Voyager can be used to manager Ingress objects alongside with other ingress controller. Voyager comes with its own CRD called `Ingress` under api version `voyager.appscode.com/v1` . This CRD is not recognized by other ingress controllers that works with the Kubernetes official Ingress object under `networking.k8s.io/v1` api version. + +By default, Voyager will also manage Kubernetes Ingress objects under `networking.k8s.io/v1` api version. Voyager can be configured to only handle default Kubernetes Ingress objects with ingress.class `voyager` . To do that, pass the flag `--ingress-class=voyager` in operator pod. After that + +```yaml + annotations: + kubernetes.io/ingress.class=voyager +``` + +**Why does Voyager creates separate HAProxy pods for each Ingress?** + +Various Ingress controller behave differently regarding whether separate Ingress object will result in separate LoadBalancer. + +- nginx: Nginx controller seem to combine Ingress objects into one and expose via same Nginx instance. +- gce: A separate GCE L7 is created for each Ingress object. +- Voyager: A separate HAProxy deployment is created for each Ingress. + +There is not a clear indication what is the intended behavior from https://kubernetes.io/docs/concepts/services-networking/ingress/ . Reasons why we think one LB (GCE L7 / nginx / haproxy) per Ingress is a better choice: + +1. This gives users choice/control whether they want to serve all service using the same IP or use separate IP. In voyager, to serve using same LB, users need to put them in the same Ingress. + +2. I think ux is clearer with this mode. If user don't have access to other namespaces, they may not know what else is going on. + +3. Voyager supports TCP. If 2 separate backend wants to use the same port, they need separate LB IP. Also, since all TCP services served via same LB is in the same YAML, it makes it easy to see what other ports are in use. + +4. In Voyager, the order of paths for same host is important. We maintain this order in generated HAProxy config. If the Ingresses are auto merged, user loses this control. This might be ok, since paths are matched as the url prefix. But will not work, if other options are used. + +5. Users can spread services across LB pods. If used with HPA, users can only scale up HAProxy deployments that they want. + +6. We do soft reload HAProxy. This gives better isolation. + + + diff --git a/content/docs/v2024.3.18/examples/cert-manager/azure/certificate.yaml b/content/docs/v2024.3.18/examples/cert-manager/azure/certificate.yaml new file mode 100644 index 000000000..27a507afa --- /dev/null +++ b/content/docs/v2024.3.18/examples/cert-manager/azure/certificate.yaml @@ -0,0 +1,11 @@ +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: kiteci-azure-dns + namespace: default +spec: + secretName: kiteci-azure-dns-tls + issuerRef: + name: letsencrypt-staging-dns + dnsNames: + - kiteci-azure-dns.appscode.info \ No newline at end of file diff --git a/content/docs/v2024.3.18/examples/cert-manager/azure/ingress.yaml b/content/docs/v2024.3.18/examples/cert-manager/azure/ingress.yaml new file mode 100644 index 000000000..857e6c127 --- /dev/null +++ b/content/docs/v2024.3.18/examples/cert-manager/azure/ingress.yaml @@ -0,0 +1,25 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: test-ingress-deploy-k8s-azure-dns + namespace: default + annotations: + kubernetes.io/ingress.class: voyager + certmanager.k8s.io/issuer: "letsencrypt-staging-dns" + certmanager.k8s.io/acme-challenge-type: dns01 +spec: + tls: + - hosts: + - kiteci-azure-dns.appscode.info + secretName: kiteci-azure-dns-tls + rules: + - host: kiteci-azure-dns.appscode.info + http: + paths: + - backend: + service: + name: web + port: + number: 80 + path: / + pathType: Prefix diff --git a/content/docs/v2024.3.18/examples/cert-manager/azure/issuer.yaml b/content/docs/v2024.3.18/examples/cert-manager/azure/issuer.yaml new file mode 100644 index 000000000..196c0ce9e --- /dev/null +++ b/content/docs/v2024.3.18/examples/cert-manager/azure/issuer.yaml @@ -0,0 +1,28 @@ +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: letsencrypt-staging-dns + namespace: default +spec: + acme: + server: https://acme-staging-v02.api.letsencrypt.org/directory + email: example@kite.com + # Name of a secret used to store the ACME account private key + privateKeySecretRef: + name: example-issuer-account-key + solvers: + - dns01: + azureDNS: + # Service principal clientId (also called appId) + clientID: riu478u-486ij8-uiu487j-468rjg8 + # A secretKeyRef to a service principal ClientSecret (password) + clientSecretSecretRef: + name: azuredns-secret + key: client-secret + # Azure subscription Id + subscriptionID: 45ji8t4-rgi4859-g845jg-9jjf9945r + # Azure AD tenant Id + tenantID: 348585ej-4358fdg8-f4588fg-45889fg + # ResourceGroup name where dns zone is provisioned + resourceGroupName: dev + hostedZoneName: appscode.info \ No newline at end of file diff --git a/content/docs/v2024.3.18/examples/cert-manager/certificate.yaml b/content/docs/v2024.3.18/examples/cert-manager/certificate.yaml new file mode 100644 index 000000000..9078cfd83 --- /dev/null +++ b/content/docs/v2024.3.18/examples/cert-manager/certificate.yaml @@ -0,0 +1,15 @@ +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: example + namespace: default +spec: + secretName: example-tls + duration: 24h + renewBefore: 12h + dnsNames: + - foo.example.com + - bar.example.com + issuerRef: + name: my-internal-ca + kind: Issuer \ No newline at end of file diff --git a/content/docs/v2024.3.18/examples/cert-manager/google_cloud/certificate.yaml b/content/docs/v2024.3.18/examples/cert-manager/google_cloud/certificate.yaml new file mode 100644 index 000000000..ba66f8ece --- /dev/null +++ b/content/docs/v2024.3.18/examples/cert-manager/google_cloud/certificate.yaml @@ -0,0 +1,11 @@ +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: kiteci-dns + namespace: default +spec: + secretName: kiteci-dns-tls + issuerRef: + name: letsencrypt-staging-dns + dnsNames: + - kiteci-dns.appscode.ninja \ No newline at end of file diff --git a/content/docs/v2024.3.18/examples/cert-manager/google_cloud/ingress.yaml b/content/docs/v2024.3.18/examples/cert-manager/google_cloud/ingress.yaml new file mode 100644 index 000000000..1a1f5656f --- /dev/null +++ b/content/docs/v2024.3.18/examples/cert-manager/google_cloud/ingress.yaml @@ -0,0 +1,25 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: test-ingress-deploy-k8s-dns + namespace: default + annotations: + kubernetes.io/ingress.class: voyager + certmanager.k8s.io/issuer: "letsencrypt-staging-dns" + certmanager.k8s.io/acme-challenge-type: dns01 +spec: + tls: + - hosts: + - kiteci-dns.appscode.ninja + secretName: kiteci-dns-tls + rules: + - host: kiteci-dns.appscode.ninja + http: + paths: + - backend: + service: + name: web + port: + number: 80 + path: / + pathType: Prefix diff --git a/content/docs/v2024.3.18/examples/cert-manager/google_cloud/issuer.yaml b/content/docs/v2024.3.18/examples/cert-manager/google_cloud/issuer.yaml new file mode 100644 index 000000000..062a05913 --- /dev/null +++ b/content/docs/v2024.3.18/examples/cert-manager/google_cloud/issuer.yaml @@ -0,0 +1,21 @@ +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: letsencrypt-staging-dns + namespace: default +spec: + acme: + server: https://acme-staging-v02.api.letsencrypt.org/directory + email: example@kite.com + # Name of a secret used to store the ACME account private key + privateKeySecretRef: + name: example-issuer-account-key + solvers: + - dns01: + cloudDNS: + # A secretKeyRef to a google cloud json service account + serviceAccountSecretRef: + name: clouddns-service-account + key: service-account.json + # The project in which to update the DNS zone + project: test-cert \ No newline at end of file diff --git a/content/docs/v2024.3.18/examples/cert-manager/http/clusterissuer.yaml b/content/docs/v2024.3.18/examples/cert-manager/http/clusterissuer.yaml new file mode 100644 index 000000000..fa1d8a857 --- /dev/null +++ b/content/docs/v2024.3.18/examples/cert-manager/http/clusterissuer.yaml @@ -0,0 +1,19 @@ +apiVersion: cert-manager.io/v1 +kind: ClusterIssuer +metadata: + name: letsencrypt-staging +spec: + acme: + # You must replace this email address with your own. + # Let's Encrypt will use this to contact you about expiring + # certificates, and issues related to your account. + email: user@example.com + server: https://acme-staging-v02.api.letsencrypt.org/directory + privateKeySecretRef: + # Secret resource used to store the account's private key. + name: example-issuer-account-key + # Add a single challenge solver, HTTP01 using nginx + solvers: + - http01: + ingress: + name: test-ingress \ No newline at end of file diff --git a/content/docs/v2024.3.18/examples/cert-manager/http/ingress.yaml b/content/docs/v2024.3.18/examples/cert-manager/http/ingress.yaml new file mode 100644 index 000000000..34fbfe94d --- /dev/null +++ b/content/docs/v2024.3.18/examples/cert-manager/http/ingress.yaml @@ -0,0 +1,24 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: default + annotations: + kubernetes.io/ingress.class: voyager + certmanager.k8s.io/cluster-issuer: "letsencrypt-staging" + certmanager.k8s.io/acme-challenge-type: http01 +spec: + tls: + - hosts: + - kiteci.appscode.ninja + secretName: quickstart-kiteci-tls + rules: + - http: + paths: + - backend: + service: + name: web + port: + number: 80 + path: / + pathType: Prefix diff --git a/content/docs/v2024.3.18/examples/cert-manager/issuer.yaml b/content/docs/v2024.3.18/examples/cert-manager/issuer.yaml new file mode 100644 index 000000000..ecbbc0421 --- /dev/null +++ b/content/docs/v2024.3.18/examples/cert-manager/issuer.yaml @@ -0,0 +1,19 @@ +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: letsencrypt-prod + namespace: edge-services +spec: + acme: + # The ACME server URL + server: https://acme-v02.api.letsencrypt.org/directory + # Email address used for ACME registration + email: user@example.com + # Name of a secret used to store the ACME account private key + privateKeySecretRef: + name: letsencrypt-prod + # Enable HTTP01 validations + solvers: + - http01: + ingress: + class: voyager diff --git a/content/docs/v2024.3.18/examples/cert-manager/multiple.yaml b/content/docs/v2024.3.18/examples/cert-manager/multiple.yaml new file mode 100644 index 000000000..3dcbccf28 --- /dev/null +++ b/content/docs/v2024.3.18/examples/cert-manager/multiple.yaml @@ -0,0 +1,47 @@ +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: letsencrypt-staging-dns + namespace: default +spec: + acme: + server: https://acme-staging-v02.api.letsencrypt.org/directory + email: example@kite.com + # Name of a secret used to store the ACME account private key + privateKeySecretRef: + name: example-issuer-account-key + solvers: + - http01: + ingress: + name: test-ingress-deploy-k8s + - dns01: + route53: + accessKeyID: KIR2WO5YWT + region: us-east-1 + secretAccessKeySecretRef: + name: route53-secret + key: secret-access-key + hostedZoneID: J13B3AB + - dns01: + azureDNS: + # Service principal clientId (also called appId) + clientID: riu478u-486ij8-uiu487j-468rjg8 + # A secretKeyRef to a service principal ClientSecret (password) + clientSecretSecretRef: + name: azuredns-secret + key: client-secret + # Azure subscription Id + subscriptionID: 45ji8t4-rgi4859-g845jg-9jjf9945r + # Azure AD tenant Id + tenantID: 348585ej-4358fdg8-f4588fg-45889fg + # ResourceGroup name where dns zone is provisioned + resourceGroupName: dev + hostedZoneName: appscode.info + - dns01: + cloudDNS: + # A secretKeyRef to a google cloud json service account + serviceAccountSecretRef: + name: clouddns-service-account + key: service-account.json + # The project in which to update the DNS zone + project: test-cert \ No newline at end of file diff --git a/content/docs/v2024.3.18/examples/cert-manager/route53/certificate.yaml b/content/docs/v2024.3.18/examples/cert-manager/route53/certificate.yaml new file mode 100644 index 000000000..e69de29bb diff --git a/content/docs/v2024.3.18/examples/cert-manager/route53/ingress.yaml b/content/docs/v2024.3.18/examples/cert-manager/route53/ingress.yaml new file mode 100644 index 000000000..e69de29bb diff --git a/content/docs/v2024.3.18/examples/cert-manager/route53/issuer.yaml b/content/docs/v2024.3.18/examples/cert-manager/route53/issuer.yaml new file mode 100644 index 000000000..e69de29bb diff --git a/content/docs/v2024.3.18/examples/ingress/pod-placement/deploy-servers.sh b/content/docs/v2024.3.18/examples/ingress/pod-placement/deploy-servers.sh new file mode 100755 index 000000000..bbc8b259a --- /dev/null +++ b/content/docs/v2024.3.18/examples/ingress/pod-placement/deploy-servers.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +# Copyright The Voyager Authors. +# +# 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. + +set -x + +kubectl create namespace demo + +kubectl run nginx --image=nginx --namespace=demo +kubectl expose deployment nginx --name=web --namespace=demo --port=80 --target-port=80 + +kubectl run echoserver --image=gcr.io/google_containers/echoserver:1.4 --namespace=demo +kubectl expose deployment echoserver --name=rest --namespace=demo --port=80 --target-port=8080 diff --git a/content/docs/v2024.3.18/examples/ingress/pod-placement/ingress-w-node-selector.yaml b/content/docs/v2024.3.18/examples/ingress/pod-placement/ingress-w-node-selector.yaml new file mode 100644 index 000000000..469a3af1f --- /dev/null +++ b/content/docs/v2024.3.18/examples/ingress/pod-placement/ingress-w-node-selector.yaml @@ -0,0 +1,27 @@ +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: ingress-w-node-selector + namespace: demo + annotations: + ingress.appscode.com/type: NodePort + ingress.appscode.com/use-node-port: 'true' + ingress.appscode.com/replicas: '2' +spec: + nodeSelector: + kubernetes.io/hostname: minikube + rules: + - http: + paths: + - path: / + backend: + service; + name: rest + port: + number: 80 + - path: /web + backend: + service: + name: web + port: + number: 80 diff --git a/content/docs/v2024.3.18/examples/ingress/pod-placement/ingress-w-pod-anti-affinity.yaml b/content/docs/v2024.3.18/examples/ingress/pod-placement/ingress-w-pod-anti-affinity.yaml new file mode 100644 index 000000000..a5a84515d --- /dev/null +++ b/content/docs/v2024.3.18/examples/ingress/pod-placement/ingress-w-pod-anti-affinity.yaml @@ -0,0 +1,39 @@ +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: ingress-w-pod-anti-affinity + namespace: demo + annotations: + ingress.appscode.com/type: NodePort + ingress.appscode.com/use-node-port: 'true' + ingress.appscode.com/replicas: '2' +spec: + rules: + - http: + paths: + - path: / + backend: + service: + name: rest + port: + number: 80 + - path: /web + backend: + service: + name: web + port: + number: 80 + affinity: + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchExpressions: + - key: origin + operator: In + values: + - voyager + - key: origin-name + operator: In + values: + - voyager-ingress-w-pod-anti-affinity + topologyKey: 'kubernetes.io/hostname' diff --git a/content/docs/v2024.3.18/examples/ingress/pod-placement/ingress-w-toleration.yaml b/content/docs/v2024.3.18/examples/ingress/pod-placement/ingress-w-toleration.yaml new file mode 100644 index 000000000..37097c853 --- /dev/null +++ b/content/docs/v2024.3.18/examples/ingress/pod-placement/ingress-w-toleration.yaml @@ -0,0 +1,30 @@ +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: ingress-w-toleration + namespace: demo + annotations: + ingress.appscode.com/type: NodePort + ingress.appscode.com/use-node-port: 'true' + ingress.appscode.com/replicas: '2' +spec: + rules: + - http: + paths: + - path: / + backend: + service: + name: rest + port: + number: 80 + - path: /web + backend: + service: + name: web + port: + number: 80 + tolerations: + - key: IngressOnly + operator: Equal + value: 'true' + effect: NoSchedule diff --git a/content/docs/v2024.3.18/examples/ingress/types/hostport/deploy-servers.sh b/content/docs/v2024.3.18/examples/ingress/types/hostport/deploy-servers.sh new file mode 100755 index 000000000..e074a0b6d --- /dev/null +++ b/content/docs/v2024.3.18/examples/ingress/types/hostport/deploy-servers.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +# Copyright The Voyager Authors. +# +# 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. + +kubectl run nginx --image=nginx +kubectl expose deployment nginx --name=web --port=80 --target-port=80 + +kubectl run echoserver --image=gcr.io/google_containers/echoserver:1.4 +kubectl expose deployment echoserver --name=rest --port=80 --target-port=8080 diff --git a/content/docs/v2024.3.18/examples/ingress/types/hostport/haproxy.cfg b/content/docs/v2024.3.18/examples/ingress/types/hostport/haproxy.cfg new file mode 100644 index 000000000..2520a2546 --- /dev/null +++ b/content/docs/v2024.3.18/examples/ingress/types/hostport/haproxy.cfg @@ -0,0 +1,47 @@ +# HAProxy configuration generated by https://github.com/appscode/voyager +# DO NOT EDIT! +global + daemon + stats socket /tmp/haproxy + server-state-file global + server-state-base /var/state/haproxy/ + # log using a syslog socket + log /dev/log local0 info + log /dev/log local0 notice + tune.ssl.default-dh-param 2048 + ssl-default-bind-ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK + hard-stop-after 30s +defaults + log global + # https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#4.2-option%20abortonclose + # https://github.com/voyagermesh/voyager/pull/403 + option dontlognull + option http-server-close + # Timeout values + timeout client 50s + timeout client-fin 50s + timeout connect 5s + timeout server 50s + timeout tunnel 50s + # Configure error files + # default traffic mode is http + # mode is overwritten in case of tcp services + mode http +frontend http-0_0_0_0-80 + bind *:80 + mode http + option httplog + option forwardfor + acl is_proxy_https hdr(X-Forwarded-Proto) https + acl host_acl_web.example.com hdr(host) -i web.example.com + acl host_acl_web.example.com hdr(host) -i web.example.com:80 + acl url_acl_web.example.com__ path_beg / + use_backend web.default:80-xmavcn if host_acl_web.example.com url_acl_web.example.com__ + acl host_acl_..example.com hdr_end(host) -i .example.com + acl host_acl_..example.com hdr_end(host) -i .example.com:80 + acl url_acl_..example.com__ path_beg / + use_backend rest.default:80-juma3e if host_acl_..example.com url_acl_..example.com__ +backend web.default:80-xmavcn + server pod-nginx-d5dc44cf7-dq7p7 172.17.0.4:80 +backend rest.default:80-juma3e + server pod-echoserver-566fcc4fdb-v8xj5 172.17.0.5:8080 diff --git a/content/docs/v2024.3.18/examples/ingress/types/hostport/ing.yaml b/content/docs/v2024.3.18/examples/ingress/types/hostport/ing.yaml new file mode 100644 index 000000000..6ccb24e85 --- /dev/null +++ b/content/docs/v2024.3.18/examples/ingress/types/hostport/ing.yaml @@ -0,0 +1,27 @@ +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: default + annotations: + ingress.appscode.com/type: HostPort +spec: + rules: + - host: 'web.example.com' + http: + paths: + - backend: + service: + name: web + port: + number: 80 + path: / + - host: '*.example.com' + http: + paths: + - backend: + service: + name: rest + port: + number: 80 + path: / diff --git a/content/docs/v2024.3.18/examples/ingress/types/internal/deploy-servers.sh b/content/docs/v2024.3.18/examples/ingress/types/internal/deploy-servers.sh new file mode 100755 index 000000000..e074a0b6d --- /dev/null +++ b/content/docs/v2024.3.18/examples/ingress/types/internal/deploy-servers.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +# Copyright The Voyager Authors. +# +# 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. + +kubectl run nginx --image=nginx +kubectl expose deployment nginx --name=web --port=80 --target-port=80 + +kubectl run echoserver --image=gcr.io/google_containers/echoserver:1.4 +kubectl expose deployment echoserver --name=rest --port=80 --target-port=8080 diff --git a/content/docs/v2024.3.18/examples/ingress/types/internal/haproxy.cfg b/content/docs/v2024.3.18/examples/ingress/types/internal/haproxy.cfg new file mode 100644 index 000000000..2520a2546 --- /dev/null +++ b/content/docs/v2024.3.18/examples/ingress/types/internal/haproxy.cfg @@ -0,0 +1,47 @@ +# HAProxy configuration generated by https://github.com/appscode/voyager +# DO NOT EDIT! +global + daemon + stats socket /tmp/haproxy + server-state-file global + server-state-base /var/state/haproxy/ + # log using a syslog socket + log /dev/log local0 info + log /dev/log local0 notice + tune.ssl.default-dh-param 2048 + ssl-default-bind-ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK + hard-stop-after 30s +defaults + log global + # https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#4.2-option%20abortonclose + # https://github.com/voyagermesh/voyager/pull/403 + option dontlognull + option http-server-close + # Timeout values + timeout client 50s + timeout client-fin 50s + timeout connect 5s + timeout server 50s + timeout tunnel 50s + # Configure error files + # default traffic mode is http + # mode is overwritten in case of tcp services + mode http +frontend http-0_0_0_0-80 + bind *:80 + mode http + option httplog + option forwardfor + acl is_proxy_https hdr(X-Forwarded-Proto) https + acl host_acl_web.example.com hdr(host) -i web.example.com + acl host_acl_web.example.com hdr(host) -i web.example.com:80 + acl url_acl_web.example.com__ path_beg / + use_backend web.default:80-xmavcn if host_acl_web.example.com url_acl_web.example.com__ + acl host_acl_..example.com hdr_end(host) -i .example.com + acl host_acl_..example.com hdr_end(host) -i .example.com:80 + acl url_acl_..example.com__ path_beg / + use_backend rest.default:80-juma3e if host_acl_..example.com url_acl_..example.com__ +backend web.default:80-xmavcn + server pod-nginx-d5dc44cf7-dq7p7 172.17.0.4:80 +backend rest.default:80-juma3e + server pod-echoserver-566fcc4fdb-v8xj5 172.17.0.5:8080 diff --git a/content/docs/v2024.3.18/examples/ingress/types/internal/ing.yaml b/content/docs/v2024.3.18/examples/ingress/types/internal/ing.yaml new file mode 100644 index 000000000..33775d8c8 --- /dev/null +++ b/content/docs/v2024.3.18/examples/ingress/types/internal/ing.yaml @@ -0,0 +1,27 @@ +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: default + annotations: + ingress.appscode.com/type: Internal +spec: + rules: + - host: 'web.example.com' + http: + paths: + - backend: + service: + name: web + port: + number: 80 + path: / + - host: '*.example.com' + http: + paths: + - backend: + service: + name: rest + port: + number: 80 + path: / diff --git a/content/docs/v2024.3.18/examples/ingress/types/loadbalancer/deploy-servers.sh b/content/docs/v2024.3.18/examples/ingress/types/loadbalancer/deploy-servers.sh new file mode 100755 index 000000000..e074a0b6d --- /dev/null +++ b/content/docs/v2024.3.18/examples/ingress/types/loadbalancer/deploy-servers.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +# Copyright The Voyager Authors. +# +# 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. + +kubectl run nginx --image=nginx +kubectl expose deployment nginx --name=web --port=80 --target-port=80 + +kubectl run echoserver --image=gcr.io/google_containers/echoserver:1.4 +kubectl expose deployment echoserver --name=rest --port=80 --target-port=8080 diff --git a/content/docs/v2024.3.18/examples/ingress/types/loadbalancer/haproxy.cfg b/content/docs/v2024.3.18/examples/ingress/types/loadbalancer/haproxy.cfg new file mode 100644 index 000000000..2520a2546 --- /dev/null +++ b/content/docs/v2024.3.18/examples/ingress/types/loadbalancer/haproxy.cfg @@ -0,0 +1,47 @@ +# HAProxy configuration generated by https://github.com/appscode/voyager +# DO NOT EDIT! +global + daemon + stats socket /tmp/haproxy + server-state-file global + server-state-base /var/state/haproxy/ + # log using a syslog socket + log /dev/log local0 info + log /dev/log local0 notice + tune.ssl.default-dh-param 2048 + ssl-default-bind-ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK + hard-stop-after 30s +defaults + log global + # https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#4.2-option%20abortonclose + # https://github.com/voyagermesh/voyager/pull/403 + option dontlognull + option http-server-close + # Timeout values + timeout client 50s + timeout client-fin 50s + timeout connect 5s + timeout server 50s + timeout tunnel 50s + # Configure error files + # default traffic mode is http + # mode is overwritten in case of tcp services + mode http +frontend http-0_0_0_0-80 + bind *:80 + mode http + option httplog + option forwardfor + acl is_proxy_https hdr(X-Forwarded-Proto) https + acl host_acl_web.example.com hdr(host) -i web.example.com + acl host_acl_web.example.com hdr(host) -i web.example.com:80 + acl url_acl_web.example.com__ path_beg / + use_backend web.default:80-xmavcn if host_acl_web.example.com url_acl_web.example.com__ + acl host_acl_..example.com hdr_end(host) -i .example.com + acl host_acl_..example.com hdr_end(host) -i .example.com:80 + acl url_acl_..example.com__ path_beg / + use_backend rest.default:80-juma3e if host_acl_..example.com url_acl_..example.com__ +backend web.default:80-xmavcn + server pod-nginx-d5dc44cf7-dq7p7 172.17.0.4:80 +backend rest.default:80-juma3e + server pod-echoserver-566fcc4fdb-v8xj5 172.17.0.5:8080 diff --git a/content/docs/v2024.3.18/examples/ingress/types/loadbalancer/ing.yaml b/content/docs/v2024.3.18/examples/ingress/types/loadbalancer/ing.yaml new file mode 100644 index 000000000..9d140319c --- /dev/null +++ b/content/docs/v2024.3.18/examples/ingress/types/loadbalancer/ing.yaml @@ -0,0 +1,27 @@ +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: default + annotations: + ingress.appscode.com/type: LoadBalancer +spec: + rules: + - host: 'web.example.com' + http: + paths: + - backend: + service: + name: web + port: + number: 80 + path: / + - host: '*.example.com' + http: + paths: + - backend: + service: + name: rest + port: + number: 80 + path: / diff --git a/content/docs/v2024.3.18/examples/ingress/types/nodeport/deploy-servers.sh b/content/docs/v2024.3.18/examples/ingress/types/nodeport/deploy-servers.sh new file mode 100755 index 000000000..e074a0b6d --- /dev/null +++ b/content/docs/v2024.3.18/examples/ingress/types/nodeport/deploy-servers.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +# Copyright The Voyager Authors. +# +# 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. + +kubectl run nginx --image=nginx +kubectl expose deployment nginx --name=web --port=80 --target-port=80 + +kubectl run echoserver --image=gcr.io/google_containers/echoserver:1.4 +kubectl expose deployment echoserver --name=rest --port=80 --target-port=8080 diff --git a/content/docs/v2024.3.18/examples/ingress/types/nodeport/haproxy.cfg b/content/docs/v2024.3.18/examples/ingress/types/nodeport/haproxy.cfg new file mode 100644 index 000000000..2520a2546 --- /dev/null +++ b/content/docs/v2024.3.18/examples/ingress/types/nodeport/haproxy.cfg @@ -0,0 +1,47 @@ +# HAProxy configuration generated by https://github.com/appscode/voyager +# DO NOT EDIT! +global + daemon + stats socket /tmp/haproxy + server-state-file global + server-state-base /var/state/haproxy/ + # log using a syslog socket + log /dev/log local0 info + log /dev/log local0 notice + tune.ssl.default-dh-param 2048 + ssl-default-bind-ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK + hard-stop-after 30s +defaults + log global + # https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#4.2-option%20abortonclose + # https://github.com/voyagermesh/voyager/pull/403 + option dontlognull + option http-server-close + # Timeout values + timeout client 50s + timeout client-fin 50s + timeout connect 5s + timeout server 50s + timeout tunnel 50s + # Configure error files + # default traffic mode is http + # mode is overwritten in case of tcp services + mode http +frontend http-0_0_0_0-80 + bind *:80 + mode http + option httplog + option forwardfor + acl is_proxy_https hdr(X-Forwarded-Proto) https + acl host_acl_web.example.com hdr(host) -i web.example.com + acl host_acl_web.example.com hdr(host) -i web.example.com:80 + acl url_acl_web.example.com__ path_beg / + use_backend web.default:80-xmavcn if host_acl_web.example.com url_acl_web.example.com__ + acl host_acl_..example.com hdr_end(host) -i .example.com + acl host_acl_..example.com hdr_end(host) -i .example.com:80 + acl url_acl_..example.com__ path_beg / + use_backend rest.default:80-juma3e if host_acl_..example.com url_acl_..example.com__ +backend web.default:80-xmavcn + server pod-nginx-d5dc44cf7-dq7p7 172.17.0.4:80 +backend rest.default:80-juma3e + server pod-echoserver-566fcc4fdb-v8xj5 172.17.0.5:8080 diff --git a/content/docs/v2024.3.18/examples/ingress/types/nodeport/ing.yaml b/content/docs/v2024.3.18/examples/ingress/types/nodeport/ing.yaml new file mode 100644 index 000000000..4fe57fecc --- /dev/null +++ b/content/docs/v2024.3.18/examples/ingress/types/nodeport/ing.yaml @@ -0,0 +1,28 @@ +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: default + annotations: + ingress.appscode.com/type: NodePort + ingress.appscode.com/use-node-port: 'false' +spec: + rules: + - host: 'web.example.com' + http: + paths: + - backend: + service: + name: web + port: + number: 80 + path: / + - host: '*.example.com' + http: + paths: + - backend: + service: + name: rest + port: + number: 80 + path: / diff --git a/content/docs/v2024.3.18/examples/monitoring/builtin-prometheus/demo-1.yaml b/content/docs/v2024.3.18/examples/monitoring/builtin-prometheus/demo-1.yaml new file mode 100644 index 000000000..8803354f8 --- /dev/null +++ b/content/docs/v2024.3.18/examples/monitoring/builtin-prometheus/demo-1.yaml @@ -0,0 +1,43 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: prometheus-server-conf + labels: + name: prometheus-server-conf + namespace: demo +data: + prometheus.yml: |- + global: + scrape_interval: 5s + evaluation_interval: 5s + scrape_configs: + - job_name: 'kubernetes-service-endpoints' + + kubernetes_sd_configs: + - role: endpoints + + relabel_configs: + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape] + action: keep + regex: true + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme] + action: replace + target_label: __scheme__ + regex: (https?) + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path] + action: replace + target_label: __metrics_path__ + regex: (.+) + - source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port] + action: replace + target_label: __address__ + regex: ([^:]+)(?::\d+)?;(\d+) + replacement: $1:$2 + - action: labelmap + regex: __meta_kubernetes_service_label_(.+) + - source_labels: [__meta_kubernetes_namespace] + action: replace + target_label: kubernetes_namespace + - source_labels: [__meta_kubernetes_service_name] + action: replace + target_label: kubernetes_name diff --git a/content/docs/v2024.3.18/examples/monitoring/builtin-prometheus/demo-2.yaml b/content/docs/v2024.3.18/examples/monitoring/builtin-prometheus/demo-2.yaml new file mode 100644 index 000000000..6e184d5f6 --- /dev/null +++ b/content/docs/v2024.3.18/examples/monitoring/builtin-prometheus/demo-2.yaml @@ -0,0 +1,90 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: prometheus-server +rules: +- apiGroups: [""] + resources: + - nodes + - nodes/proxy + - services + - endpoints + - pods + verbs: ["get", "list", "watch"] +- apiGroups: + - extensions + resources: + - ingresses + verbs: ["get", "list", "watch"] +- nonResourceURLs: ["/metrics"] + verbs: ["get"] +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: prometheus-server + namespace: demo +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: prometheus-server +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: prometheus-server +subjects: +- kind: ServiceAccount + name: prometheus-server + namespace: demo +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: prometheus-server + namespace: demo +spec: + replicas: 1 + selector: + matchLabels: + app: prometheus-server + template: + metadata: + labels: + app: prometheus-server + spec: + serviceAccountName: prometheus-server + containers: + - name: prometheus + image: prom/prometheus:v2.1.0 + args: + - "--config.file=/etc/prometheus/prometheus.yml" + - "--storage.tsdb.path=/prometheus/" + ports: + - containerPort: 9090 + volumeMounts: + - name: prometheus-config-volume + mountPath: /etc/prometheus/ + - name: prometheus-storage-volume + mountPath: /prometheus/ + volumes: + - name: prometheus-config-volume + configMap: + defaultMode: 420 + name: prometheus-server-conf + - name: prometheus-storage-volume + emptyDir: {} +--- +apiVersion: v1 +kind: Service +metadata: + name: prometheus-service + namespace: demo +spec: + selector: + app: prometheus-server + type: NodePort + ports: + - port: 9090 + targetPort: 9090 + nodePort: 30901 diff --git a/content/docs/v2024.3.18/examples/monitoring/builtin-prometheus/ing.yaml b/content/docs/v2024.3.18/examples/monitoring/builtin-prometheus/ing.yaml new file mode 100644 index 000000000..d83742a24 --- /dev/null +++ b/content/docs/v2024.3.18/examples/monitoring/builtin-prometheus/ing.yaml @@ -0,0 +1,20 @@ +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: stats-ing + namespace: demo + annotations: + ingress.appscode.com/type: 'NodePort' + ingress.appscode.com/stats: 'true' + ingress.appscode.com/monitoring-agent: 'prometheus.io/builtin' +spec: + rules: + - host: voyager.appscode.test + http: + paths: + - path: / + backend: + service: + name: web + port: + number: 80 diff --git a/content/docs/v2024.3.18/examples/monitoring/coreos-operator/demo-0.yaml b/content/docs/v2024.3.18/examples/monitoring/coreos-operator/demo-0.yaml new file mode 100644 index 000000000..30bd06025 --- /dev/null +++ b/content/docs/v2024.3.18/examples/monitoring/coreos-operator/demo-0.yaml @@ -0,0 +1,100 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: prometheus-operator +rules: +- apiGroups: + - extensions + resources: + - thirdpartyresources + verbs: + - "*" +- apiGroups: + - apiextensions.k8s.io + resources: + - customresourcedefinitions + verbs: + - "*" +- apiGroups: + - monitoring.coreos.com + resources: + - alertmanagers + - prometheuses + - servicemonitors + verbs: + - "*" +- apiGroups: + - apps + resources: + - statefulsets + verbs: ["*"] +- apiGroups: [""] + resources: + - configmaps + - secrets + verbs: ["*"] +- apiGroups: [""] + resources: + - pods + verbs: ["list", "delete"] +- apiGroups: [""] + resources: + - services + - endpoints + verbs: ["get", "create", "update"] +- apiGroups: [""] + resources: + - nodes + verbs: ["list", "watch"] +- apiGroups: [""] + resources: + - namespaces + verbs: ["list"] +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: prometheus-operator + namespace: demo +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: prometheus-operator +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: prometheus-operator +subjects: +- kind: ServiceAccount + name: prometheus-operator + namespace: demo +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: prometheus-operator + namespace: demo + labels: + operator: prometheus +spec: + replicas: 1 + selector: + matchLabels: + operator: prometheus + template: + metadata: + labels: + operator: prometheus + spec: + serviceAccountName: prometheus-operator + containers: + - name: prometheus-operator + image: quay.io/coreos/prometheus-operator:v0.16.0 + resources: + requests: + cpu: 100m + memory: 50Mi + limits: + cpu: 200m + memory: 100Mi diff --git a/content/docs/v2024.3.18/examples/monitoring/coreos-operator/demo-1.yaml b/content/docs/v2024.3.18/examples/monitoring/coreos-operator/demo-1.yaml new file mode 100644 index 000000000..7f4b1d600 --- /dev/null +++ b/content/docs/v2024.3.18/examples/monitoring/coreos-operator/demo-1.yaml @@ -0,0 +1,68 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: prometheus +rules: +- apiGroups: [""] + resources: + - nodes + - services + - endpoints + - pods + verbs: ["get", "list", "watch"] +- apiGroups: [""] + resources: + - configmaps + verbs: ["get"] +- nonResourceURLs: ["/metrics"] + verbs: ["get"] +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: prometheus + namespace: demo +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: prometheus +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: prometheus +subjects: +- kind: ServiceAccount + name: prometheus + namespace: demo +--- +apiVersion: monitoring.coreos.com/v1 +kind: Prometheus +metadata: + name: prometheus + namespace: demo +spec: + serviceAccountName: prometheus + serviceMonitorSelector: + matchLabels: + app: voyager + version: v1.7.0 + resources: + requests: + memory: 400Mi +--- +apiVersion: v1 +kind: Service +metadata: + name: prometheus + namespace: demo +spec: + type: LoadBalancer + ports: + - name: web + nodePort: 30900 + port: 9090 + protocol: TCP + targetPort: web + selector: + prometheus: prometheus diff --git a/content/docs/v2024.3.18/examples/monitoring/coreos-operator/ing.yaml b/content/docs/v2024.3.18/examples/monitoring/coreos-operator/ing.yaml new file mode 100644 index 000000000..54fecfc83 --- /dev/null +++ b/content/docs/v2024.3.18/examples/monitoring/coreos-operator/ing.yaml @@ -0,0 +1,22 @@ +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: stats-ing + namespace: demo + annotations: + ingress.appscode.com/type: 'NodePort' + ingress.appscode.com/stats: 'true' + ingress.appscode.com/monitoring-agent: 'prometheus.io/coreos-operator' + ingress.appscode.com/service-monitor-labels: '{"app": "voyager"}' + ingress.appscode.com/service-monitor-namespace: 'demo' +spec: + rules: + - host: voyager.appscode.test + http: + paths: + - path: / + backend: + service: + name: web + port: + number: 80 diff --git a/content/docs/v2024.3.18/examples/monitoring/metrics-collector.yaml b/content/docs/v2024.3.18/examples/monitoring/metrics-collector.yaml new file mode 100644 index 000000000..e4377de77 --- /dev/null +++ b/content/docs/v2024.3.18/examples/monitoring/metrics-collector.yaml @@ -0,0 +1,20 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: appscode:system:metrics-collector +rules: +- nonResourceURLs: ["/metrics"] + verbs: ["get"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: appscode:system:metrics-collector +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: appscode:system:metrics-collector +subjects: +- apiGroup: rbac.authorization.k8s.io + kind: User + name: system:anonymous diff --git a/content/docs/v2024.3.18/examples/monitoring/profiler.yaml b/content/docs/v2024.3.18/examples/monitoring/profiler.yaml new file mode 100644 index 000000000..1e1a35030 --- /dev/null +++ b/content/docs/v2024.3.18/examples/monitoring/profiler.yaml @@ -0,0 +1,20 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: appscode:system:profiler +rules: +- nonResourceURLs: ["/debug/pprof/", "/debug/pprof/*"] + verbs: ["get", "post"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: appscode:system:profiler +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: appscode:system:profiler +subjects: +- apiGroup: rbac.authorization.k8s.io + kind: User + name: system:anonymous diff --git a/content/docs/v2024.3.18/examples/monitoring/stats-ing.yaml b/content/docs/v2024.3.18/examples/monitoring/stats-ing.yaml new file mode 100644 index 000000000..aad8546dd --- /dev/null +++ b/content/docs/v2024.3.18/examples/monitoring/stats-ing.yaml @@ -0,0 +1,19 @@ +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: stats-ing + namespace: demo + annotations: + ingress.appscode.com/type: 'NodePort' + ingress.appscode.com/stats: 'true' +spec: + rules: + - host: voyager.appscode.test + http: + paths: + - path: / + backend: + service: + name: web + port: + number: 80 diff --git a/content/docs/v2024.3.18/guides/_index.md b/content/docs/v2024.3.18/guides/_index.md new file mode 100644 index 000000000..2dba01d4e --- /dev/null +++ b/content/docs/v2024.3.18/guides/_index.md @@ -0,0 +1,15 @@ +--- +title: Guides | Voyager +menu: + docs_v2024.3.18: + identifier: guides + name: Guides + weight: 40 + pre: dropdown +menu_name: docs_v2024.3.18 +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + diff --git a/content/docs/v2024.3.18/guides/cert-manager/README.md b/content/docs/v2024.3.18/guides/cert-manager/README.md new file mode 100644 index 000000000..87f350607 --- /dev/null +++ b/content/docs/v2024.3.18/guides/cert-manager/README.md @@ -0,0 +1,41 @@ +--- +title: cert-manager | Voyager +menu: + docs_v2024.3.18: + identifier: readme-cert-manager + name: Readme + parent: cert-manager-guides + weight: -1 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +url: /docs/v2024.3.18/guides/cert-manager/ +aliases: +- /docs/v2024.3.18/guides/cert-manager/README/ +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +# Guides + +Guides show you how to use [jetstack/cert-manager](https://github.com/jetstack/cert-manager) with Voyager to issue free TLS/SSL certificates from Let's Encrypt. + +## Features + +- Provision free TLS certificates (including wildcard certificates) from Let's Encrypt. +- Manage certificates declaratively using a Kubernetes Custom Resource Definition (CRD). +- Domain validation using ACME http-01 and dns-01 challenges. +- Support for many popular DNS providers. +- Auto Renew certificates. +- Use issued certificates with Ingress to secure communications. + +## Next Steps + +- [Issue Let's Encrypt certificate using HTTP-01 challenge](/docs/v2024.3.18/guides/cert-manager/http01_challenge/overview) +- DNS-01 challenge providers + - [Issue Let's Encrypt certificate using AWS Route53](/docs/v2024.3.18/guides/cert-manager/dns01_challenge/aws-route53) + - [Issue Let's Encrypt certificate using Azure DNS](/docs/v2024.3.18/guides/cert-manager/dns01_challenge/azure-dns) + - [Issue Let's Encrypt certificate using Google Cloud DNS](/docs/v2024.3.18/guides/cert-manager/dns01_challenge/google-cloud-dns) + - [Multiple Providers](/docs/v2024.3.18/guides/cert-manager/dns01_challenge/multiple-challenge-solver) diff --git a/content/docs/v2024.3.18/guides/cert-manager/_index.md b/content/docs/v2024.3.18/guides/cert-manager/_index.md new file mode 100644 index 000000000..81c5e4a7e --- /dev/null +++ b/content/docs/v2024.3.18/guides/cert-manager/_index.md @@ -0,0 +1,15 @@ +--- +title: cert-manager +menu: + docs_v2024.3.18: + identifier: cert-manager-guides + name: Cert Manager + parent: guides + weight: 200 +menu_name: docs_v2024.3.18 +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + diff --git a/content/docs/v2024.3.18/guides/cert-manager/dns01_challenge/_index.md b/content/docs/v2024.3.18/guides/cert-manager/dns01_challenge/_index.md new file mode 100644 index 000000000..59dc53749 --- /dev/null +++ b/content/docs/v2024.3.18/guides/cert-manager/dns01_challenge/_index.md @@ -0,0 +1,16 @@ +--- +title: DNS01 Challenge +description: DNS01 Challenge +menu: + docs_v2024.3.18: + identifier: dns01-cert-manager + parent: cert-manager-guides + name: DNS01 Challenge + weight: 30 +menu_name: docs_v2024.3.18 +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + diff --git a/content/docs/v2024.3.18/guides/cert-manager/dns01_challenge/aws-route53.md b/content/docs/v2024.3.18/guides/cert-manager/dns01_challenge/aws-route53.md new file mode 100644 index 000000000..6986feabd --- /dev/null +++ b/content/docs/v2024.3.18/guides/cert-manager/dns01_challenge/aws-route53.md @@ -0,0 +1,216 @@ +--- +title: Issue Let's Encrypt certificate using Amazon Route53 +description: Issue Let's Encrypt certificate using Amazon Route53 in Kubernetes +menu: + docs_v2024.3.18: + identifier: amazon-route53-cert-manager + name: Amazon Route53 + parent: dns01-cert-manager + weight: 15 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# Issue Let's Encrypt certificate using Amazon Route53 + +This tutorial shows how to issue free SSL certificate from Let's Encrypt via DNS challenge for domains using Amazon Route53. + +This article has been tested with a GKE cluster. + +```bash +$ kubectl version --short +Client Version: v1.8.8 +Server Version: v1.8.8-gke.0 +``` + +## 1. Setup Issuer + +Go to IAM page and create a user + +![iam](/docs/v2024.3.18/images/cert-manager/route53/iam.png) + +![add-user](/docs/v2024.3.18/images/cert-manager/route53/add-user.png) + +![access-type](/docs/v2024.3.18/images/cert-manager/route53/access-type.png) + +Click on next and select `Attach existing policies directly` and click on `Create Policy`. This will take you to a new page. + +![create-policy](/docs/v2024.3.18/images/cert-manager/route53/create-policy.png) + +Now click on `json` and paste this and click `Review Policy` + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": "route53:GetChange", + "Resource": "arn:aws:route53:::change/*" + }, + { + "Effect": "Allow", + "Action": "route53:ChangeResourceRecordSets", + "Resource": "arn:aws:route53:::hostedzone/*" + }, + { + "Effect": "Allow", + "Action": "route53:ListHostedZonesByName", + "Resource": "*" + } + ] +} +``` + +Name the policy and click `Create policy`. + +![review-policy](/docs/v2024.3.18/images/cert-manager/route53/review-policy.png) + +Now go back to previous add user page, hit the refresh button and attach this policy to this user: + +![attach-policy](/docs/v2024.3.18/images/cert-manager/route53/attach-policy.png) + +Click on next (tags are optional - you can ignore this) and finish the process. Download the `.csv` file. + +![success-user](/docs/v2024.3.18/images/cert-manager/route53/success-user.png) + +Create a secret with the `Secret Access Key` + +```bash +kubectl create secret generic route53-secret --from-literal=secret-access-key="skjdflk4598sf/dkfj490jdfg/dlfjk59lkj" +``` + +Copy `Access key ID` from this same page and `hostedZoneID` from the following page: + +![hosted-zone-id](/docs/v2024.3.18/images/cert-manager/route53/hosted-zone-id.png) + +And put them in [issuer.yaml](/docs/v2024.3.18/examples/cert-manager/route53/issuer.yaml) + +```yaml +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: letsencrypt-staging-dns + namespace: default +spec: + acme: + server: https://acme-staging-v02.api.letsencrypt.org/directory + email: example@kite.com + # Name of a secret used to store the ACME account private key + privateKeySecretRef: + name: example-issuer-account-key + solvers: + - dns01: + route53: + accessKeyID: KIR2WO5YWT + region: us-east-1 + secretAccessKeySecretRef: + name: route53-secret + key: secret-access-key + hostedZoneID: J13B3AB +``` + +Then create this issuer by `kubectl apply -f issuer.yaml` + +## 2. Create Ingress + +We are going to use a nginx server as the backend. To deploy nginx server, run the following commands: + +```bash +kubectl run nginx --image=nginx +kubectl expose deployment nginx --name=web --port=80 --target-port=80 +``` + +Now create [ingress.yaml](/docs/v2024.3.18/examples/cert-manager/route53/ingress.yaml): + +```yaml +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: test-ingress-deploy-k8s-route53-dns + namespace: default + annotations: + kubernetes.io/ingress.class: voyager + certmanager.k8s.io/issuer: "letsencrypt-staging-dns" + certmanager.k8s.io/acme-challenge-type: dns01 +spec: + tls: + - hosts: + - kiteci-route53-dns.appscode.me + secretName: kiteci-route53-dns-tls + rules: + - host: kiteci-route53-dns.appscode.me + http: + paths: + - backend: + service: + name: web + port: + number: 80 + path: / + pathType: Prefix +``` + +Then take the `EXTERNAL-IP` from the corresponding service and add a A-record in AWS Route53: + +```bash +kubectl get svc +``` + +```bash +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +voyager-test-ingress-deploy-k8s-route53-dns LoadBalancer 10.7.248.189 35.225.111.106 443:30713/TCP,80:31137/TCP 21m +``` + +![a-record](/docs/v2024.3.18/images/cert-manager/route53/a-record.png) + +## 3. Create Certificate + +Then create this [certificate.yaml](/docs/v2024.3.18/examples/cert-manager/route53/certificate.yaml) + +```yaml +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: kiteci-route53-dns + namespace: default +spec: + secretName: kiteci-route53-dns-tls + issuerRef: + name: letsencrypt-staging-dns + dnsNames: + - kiteci-route53-dns.appscode.me +``` + +List the certificates and describe that certificate and wait until you see `Certificate issued successfully` when you describe the certificate. + +```bash +kubectl get certificates.certmanager.k8s.io --all-namespaces + +default kiteci-route53-dns True kiteci-route53-dns-tls 1m +``` + +```bash +kubectl describe certificates.certmanager.k8s.io kiteci-route53-dns +``` + +```bash +... +Events: + Type Reason Age From Message + ---- ------ ---- ---- ------- + Normal Generated 6s cert-manager Generated new private key + Normal GenerateSelfSigned 6s cert-manager Generated temporary self signed certificate + Normal OrderCreated 6s cert-manager Created Order resource "kiteci-route53-dns-290497833" + Normal OrderComplete 5s cert-manager Order "kiteci-route53-dns-290497833" completed successfully + Normal CertIssued 5s cert-manager Certificate issued successfully +``` + +Then visit `kiteci-route53-dns.appscode.me` from browser and check the certificate that it was issued from let's encrypt. (For let's encrypt staging environment, you will see that the certificate was issued by `Fake LE Intermediate X1`.) diff --git a/content/docs/v2024.3.18/guides/cert-manager/dns01_challenge/azure-dns.md b/content/docs/v2024.3.18/guides/cert-manager/dns01_challenge/azure-dns.md new file mode 100644 index 000000000..e90638b1d --- /dev/null +++ b/content/docs/v2024.3.18/guides/cert-manager/dns01_challenge/azure-dns.md @@ -0,0 +1,182 @@ +--- +title: Issue Let's Encrypt certificate using Azure DNS +description: Issue Let's Encrypt certificate using Azure DNS in Kubernetes +menu: + docs_v2024.3.18: + identifier: azure-dns-cert-manager + name: Azure DNS + parent: dns01-cert-manager + weight: 15 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# Issue Let's Encrypt certificate using Azure DNS + +This tutorial shows how to issue free SSL certificate from Let's Encrypt via DNS challenge for domains using Azure DNS service. + +This article has been tested with a GKE cluster. + +```bash +$ kubectl version --short +Client Version: v1.8.8 +Server Version: v1.8.8-gke.0 +``` + +## 1. Setup Issuer + +Go to your DNS Zone page: + +![a-record](/docs/v2024.3.18/images/cert-manager/azure/a-record.png) + +You'll need this `Subscription id` and `Resource group` later while creating issuer. + +Go to Azure Active Directory -> App registrations and click on `New Registration` + +![new-registration](/docs/v2024.3.18/images/cert-manager/azure/new-registration.png) +![new-registration2](/docs/v2024.3.18/images/cert-manager/azure/new-registration2.png) + +You'll need the `Application (client) ID` and `Directory (tenant) ID` later for creating issuer. + +![client-tenant](/docs/v2024.3.18/images/cert-manager/azure/client-tenant.png) + +Now, create a new client-secret. + +![client-secret](/docs/v2024.3.18/images/cert-manager/azure/client-secret.png) + +Copy the password for this client-secret and create a kubernetes secret: + +```bash +kubectl create secret generic azuredns-secret --from-literal=client-secret="sdfsdfTEser@k3casdfbsdfsdf_m[4" +``` + +Now go to Subscriptions page and click on the corresponding subscription for your dns zone: + +![subscriptions](/docs/v2024.3.18/images/cert-manager/azure/subscriptions.png) + +Click on `Access control (IAM)` and `Add` -> `Add role assignment`. +If you see this as `Add role assignment (disabled)` then have your portal administrator perform this step, otherwise ignore this. + +Your administrator needs to go to the same page and add you as `Owner` or `User Access Administrator` + +![user-access](/docs/v2024.3.18/images/cert-manager/azure/user-access.png) + +Now that you have access to this, go to Subscriptions -> Access control (IAM) -> Add and you should be able to `Add role assignment`. Add `DNS Zone Contributor` to `dns-challenge` (the app registration you created before) + +![dns-zone-contributor](/docs/v2024.3.18/images/cert-manager/azure/dns-zone-contributor.png) + +Now create this issuer by applying [issuer.yaml](/docs/v2024.3.18/examples/cert-manager/azure/issuer.yaml) + +```yaml +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: letsencrypt-staging-dns + namespace: default +spec: + acme: + server: https://acme-staging-v02.api.letsencrypt.org/directory + email: example@kite.com + # Name of a secret used to store the ACME account private key + privateKeySecretRef: + name: example-issuer-account-key + solvers: + - dns01: + azureDNS: + # Service principal clientId (also called appId) + clientID: riu478u-486ij8-uiu487j-468rjg8 + # A secretKeyRef to a service principal ClientSecret (password) + clientSecretSecretRef: + name: azuredns-secret + key: client-secret + # Azure subscription Id + subscriptionID: 45ji8t4-rgi4859-g845jg-9jjf9945r + # Azure AD tenant Id + tenantID: 348585ej-4358fdg8-f4588fg-45889fg + # ResourceGroup name where dns zone is provisioned + resourceGroupName: dev + hostedZoneName: appscode.info +``` + +## 2. Create Ingress + +We are going to use a nginx server as the backend. To deploy nginx server, run the following commands: + +```bash +kubectl run nginx --image=nginx +kubectl expose deployment nginx --name=web --port=80 --target-port=80 +``` + +Now, Create [ingress.yaml](/docs/v2024.3.18/examples/cert-manager/azure/ingress.yaml) + +```yaml +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: test-ingress-deploy-k8s-azure-dns + namespace: default + annotations: + kubernetes.io/ingress.class: voyager + certmanager.k8s.io/issuer: "letsencrypt-staging-dns" + certmanager.k8s.io/acme-challenge-type: dns01 +spec: + tls: + - hosts: + - kiteci-azure-dns.appscode.info + secretName: kiteci-azure-dns-tls + rules: + - host: kiteci-azure-dns.appscode.info + http: + paths: + - backend: + service: + name: web + port: + number: 80 + path: / + pathType: Prefix +``` + +Then take the `EXTERNAL-IP` from the corresponding service and add a A-record in Azure DNS: + +```bash +kubectl get svc +``` + +```bash +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +voyager-test-ingress-deploy-k8s-azure-dns LoadBalancer 10.7.254.246 35.192.150.216 443:31233/TCP,80:32271/TCP 26h +``` + +## 3. Create Certificate + +Then create this [certificate.yaml](/docs/v2024.3.18/examples/cert-manager/azure/certificate.yaml) + +```yaml +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: kiteci-azure-dns + namespace: default +spec: + secretName: kiteci-azure-dns-tls + issuerRef: + name: letsencrypt-staging-dns + dnsNames: + - kiteci-azure-dns.appscode.info +``` + +Now, List the certificates and describe that certificate and wait until you see `Certificate issued successfully` when you describe the certificate. + +```bash +kubectl get certificates.certmanager.k8s.io --all-namespaces +``` + +Then visit `kiteci-azure-dns.appscode.info` from browser and check the certificate that it was issued from let's encrypt. (For let's encrypt staging environment, you will see that the certificate was issued by `Fake LE Intermediate X1`.) diff --git a/content/docs/v2024.3.18/guides/cert-manager/dns01_challenge/google-cloud-dns.md b/content/docs/v2024.3.18/guides/cert-manager/dns01_challenge/google-cloud-dns.md new file mode 100644 index 000000000..a9f1ae085 --- /dev/null +++ b/content/docs/v2024.3.18/guides/cert-manager/dns01_challenge/google-cloud-dns.md @@ -0,0 +1,155 @@ +--- +title: Issue Let's Encrypt certificate using Google Cloud DNS +description: Issue Let's Encrypt certificate using Google Cloud DNS in Kubernetes +menu: + docs_v2024.3.18: + identifier: google-cloud-dns-cert-manager + name: Google Cloud DNS + parent: dns01-cert-manager + weight: 15 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# Issue Let's Encrypt certificate using Google Cloud DNS + +This tutorial shows how to issue free SSL certificate from Let's Encrypt via DNS challenge for domains using Google Cloud DNS service. + +This article has been tested with a GKE cluster. + +```bash +$ kubectl version --short +Client Version: v1.8.8 +Server Version: v1.8.8-gke.0 +``` + +## 1. Setup Issuer/ClusterIssuer + +Now create a service account from your Google Cloud Console + +![svcac1](/docs/v2024.3.18/images/cert-manager/google_dns/svcac1.png) +![svcac2](/docs/v2024.3.18/images/cert-manager/google_dns/svcac2.png) +![svcac3](/docs/v2024.3.18/images/cert-manager/google_dns/svcac3.png) + +Then create a Kubernetes Secret with this Service Account: + +```bash +kubectl create secret generic clouddns-service-account --from-file=service-account.json= +``` + +Now create this issuer by applying [issuer.yaml](/docs/v2024.3.18/examples/cert-manager/google_cloud/issuer.yaml) + +```yaml +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: letsencrypt-staging-dns + namespace: default +spec: + acme: + server: https://acme-staging-v02.api.letsencrypt.org/directory + email: example@kite.com + # Name of a secret used to store the ACME account private key + privateKeySecretRef: + name: example-issuer-account-key + solvers: + - dns01: + cloudDNS: + # A secretKeyRef to a google cloud json service account + serviceAccountSecretRef: + name: clouddns-service-account + key: service-account.json + # The project in which to update the DNS zone + project: test-cert +``` + +## 2. Create Ingress + +We are going to use a nginx server as the backend. To deploy nginx server, run the following commands: + +```bash +kubectl run nginx --image=nginx +kubectl expose deployment nginx --name=web --port=80 --target-port=80 +``` + +Now, Create [ingress.yaml](/docs/v2024.3.18/examples/cert-manager/google_cloud/ingress.yaml) + +```yaml +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: test-ingress-deploy-k8s-dns + namespace: default + annotations: + kubernetes.io/ingress.class: voyager + certmanager.k8s.io/issuer: "letsencrypt-staging-dns" + certmanager.k8s.io/acme-challenge-type: dns01 +spec: + tls: + - hosts: + - kiteci-dns.appscode.ninja + secretName: kiteci-dns-tls + rules: + - host: kiteci-dns.appscode.ninja + http: + paths: + - backend: + service: + name: web + port: + number: 80 + path: / + pathType: Prefix +``` + +Then take the `EXTERNAL-IP` from the corresponding service: + +```bash +kubectl get svc +``` + +```bash +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +voyager-test-ingress-deploy-k8s-route53-dns LoadBalancer 10.7.248.189 35.225.111.106 443:30713/TCP,80:31137/TCP 21m +``` + +Create an A-record for `kiteci-dns.appscode.ninja` mapped to `35.225.111.106` with Google DNS. + +Wait until you can see it resolved: + +```bash +dig +short kiteci-dns.appscode.ninja +``` + +## 3. Create Certificate + +Then create this [certificate.yaml](/docs/v2024.3.18/examples/cert-manager/google_cloud/certificate.yaml) + +```yaml +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: kiteci-dns + namespace: default +spec: + secretName: kiteci-dns-tls + issuerRef: + name: letsencrypt-staging-dns + dnsNames: + - kiteci-dns.appscode.ninja +``` + +Now, List the certificates and describe that certificate and wait until you see `Certificate issued successfully` when you describe the certificate. + +```bash +kubectl get certificates.certmanager.k8s.io --all-namespaces +``` + +Then visit `kiteci-dns.appscode.ninja` from browser and check the certificate that it was issued from let's encrypt. (For let's encrypt staging environment, you will see that the certificate was issued by `Fake LE Intermediate X1`.) diff --git a/content/docs/v2024.3.18/guides/cert-manager/dns01_challenge/multiple-challenge-solver.md b/content/docs/v2024.3.18/guides/cert-manager/dns01_challenge/multiple-challenge-solver.md new file mode 100644 index 000000000..3160a5bb4 --- /dev/null +++ b/content/docs/v2024.3.18/guides/cert-manager/dns01_challenge/multiple-challenge-solver.md @@ -0,0 +1,85 @@ +--- +title: Multiple Solver Type +description: Multiple Solver Type +menu: + docs_v2024.3.18: + identifier: multiple-solver-type + name: Multiple Solver Type + parent: dns01-cert-manager + weight: 15 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# Multiple Solver Type + +A number of different DNS providers are supported for the ACME issuer. Below is a listing of available providers, their .yaml configurations, along with additional Kubernetes and provider specific notes regarding their usage. + +- [ACME-DNS](https://docs.cert-manager.io/en/latest/tasks/issuers/setup-acme/dns01/acme-dns.html) +- [Akamai FastDNS](https://docs.cert-manager.io/en/latest/tasks/issuers/setup-acme/dns01/akamai.html) +- [AzureDNS](/docs/v2024.3.18/guides/cert-manager/dns01_challenge/azure-dns) +- [Cloudflare](https://docs.cert-manager.io/en/latest/tasks/issuers/setup-acme/dns01/cloudflare.html) +- [Google CloudDNS](/docs/v2024.3.18/guides/cert-manager/dns01_challenge/google-cloud-dns) +- [Amazon Route53](/docs/v2024.3.18/guides/cert-manager/dns01_challenge/aws-route53) +- [DigitalOcean](https://docs.cert-manager.io/en/latest/tasks/issuers/setup-acme/dns01/digitalocean.html) +- [RFC-2136](https://docs.cert-manager.io/en/latest/tasks/issuers/setup-acme/dns01/rfc2136.html) + +Additionally, you can create only one Issuer/ClusterIssuer for each of http01 or dns01 challenge or even for +multiple dns providers, like [this](/docs/v2024.3.18/examples/cert-manager/multiple.yaml): + +```yaml +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: letsencrypt-staging-dns + namespace: default +spec: + acme: + server: https://acme-staging-v02.api.letsencrypt.org/directory + email: example@kite.com + # Name of a secret used to store the ACME account private key + privateKeySecretRef: + name: example-issuer-account-key + solvers: + - http01: + ingress: + name: test-ingress-deploy-k8s + - dns01: + route53: + accessKeyID: KIR2WO5YWT + region: us-east-1 + secretAccessKeySecretRef: + name: route53-secret + key: secret-access-key + hostedZoneID: J13B3AB + - dns01: + azureDNS: + # Service principal clientId (also called appId) + clientID: riu478u-486ij8-uiu487j-468rjg8 + # A secretKeyRef to a service principal ClientSecret (password) + clientSecretSecretRef: + name: azuredns-secret + key: client-secret + # Azure subscription Id + subscriptionID: 45ji8t4-rgi4859-g845jg-9jjf9945r + # Azure AD tenant Id + tenantID: 348585ej-4358fdg8-f4588fg-45889fg + # ResourceGroup name where dns zone is provisioned + resourceGroupName: dev + hostedZoneName: appscode.info + - dns01: + cloudDNS: + # A secretKeyRef to a google cloud json service account + serviceAccountSecretRef: + name: clouddns-service-account + key: service-account.json + # The project in which to update the DNS zone + project: test-cert +``` diff --git a/content/docs/v2024.3.18/guides/cert-manager/get-started.md b/content/docs/v2024.3.18/guides/cert-manager/get-started.md new file mode 100644 index 000000000..ce47f4ad7 --- /dev/null +++ b/content/docs/v2024.3.18/guides/cert-manager/get-started.md @@ -0,0 +1,143 @@ +--- +title: Get Started with cert-manager | Voyager +menu: + docs_v2024.3.18: + identifier: get-started-cert-manager + name: Get Started + parent: cert-manager-guides + weight: 10 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +## 1. Install Cert-Manager + +https://docs.cert-manager.io/en/latest/getting-started/install/kubernetes.html + +```bash +kubectl create namespace cert-manager +kubectl label namespace cert-manager certmanager.k8s.io/disable-validation=true +kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.4.1/cert-manager.yaml +``` + +## 2. Setup Issuer/ClusterIssuer + +### [Supported Issuer](https://docs.cert-manager.io/en/latest/tasks/issuers/index.html) + +These are the supported Certificate Issuers: + +1. [acme](https://docs.cert-manager.io/en/latest/tasks/issuers/setup-acme/index.html) +2. [ca](https://docs.cert-manager.io/en/latest/tasks/issuers/setup-ca.html) +3. [self signed](https://docs.cert-manager.io/en/latest/tasks/issuers/setup-selfsigned.html) +4. [vault](https://docs.cert-manager.io/en/latest/tasks/issuers/setup-vault.html) +5. [venafi](https://docs.cert-manager.io/en/latest/tasks/issuers/setup-venafi.html) + +Here we will show issuing certificates from Let's Encrypt using ACME protocol. For others, click on the link for the respective issuers. + +#### [acme](https://docs.cert-manager.io/en/latest/tasks/issuers/setup-acme/index.html) + +The ACME Issuer type represents a single Account registered with the ACME server. When you create a new ACME Issuer, cert-manager will generate a private key which is used to identify you with the ACME server. To set up a basic ACME issuer, you should create a new Issuer or ClusterIssuer resource. + +### [Issuer](https://docs.cert-manager.io/en/latest/reference/issuers.html) + +Issuers (and ClusterIssuers) represent a certificate authority from which signed x509 certificates can be obtained, such as Let’s Encrypt. You will need at least one Issuer or ClusterIssuer in order to begin issuing certificates within your cluster. + +Like this [issuer.yaml](/docs/v2024.3.18/examples/cert-manager/issuer.yaml) + +```yaml +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: letsencrypt-prod + namespace: edge-services +spec: + acme: + # The ACME server URL + server: https://acme-v02.api.letsencrypt.org/directory + # Email address used for ACME registration + email: user@example.com + # Name of a secret used to store the ACME account private key + privateKeySecretRef: + name: letsencrypt-prod + # Enable HTTP01 validations + solvers: + - http01: + ingress: + class: voyager +``` + +The `spec.email` will be used to register for your let's encrypt account and `privateKeySecretRef` will contain the private key of this account. + +#### [ClusterIssuer](https://docs.cert-manager.io/en/latest/reference/clusterissuers.html) + +An Issuer is a namespaced resource, and it is not possible to issue certificates from an Issuer in a different namespace. If you want to create a single issuer than can be consumed in multiple namespaces, you should consider creating a ClusterIssuer resource. + +```yaml +apiVersion: cert-manager.io/v1 +kind: ClusterIssuer +metadata: + name: letsencrypt-prod +spec: + acme: + # The ACME server URL + server: https://acme-v02.api.letsencrypt.org/directory + # Email address used for ACME registration + email: user@example.com + # Name of a secret used to store the ACME account private key + privateKeySecretRef: + name: letsencrypt-prod + # Enable HTTP01 validations + solvers: + - http01: + ingress: + class: voyager +``` + +When referencing a Secret resource in ClusterIssuer resources (eg `spec.acme.solvers.dns01.cloudflare.apiKeySecretRef`) the Secret needs to be in the same namespace as the cert-manager controller pod. You can optionally override this by using the `--cluster-resource-namespace` argument to the controller. + +### Let's Encrypt Production vs Staging Environment + +For production use, use the Let's Encrypt Production API like above. For testing things out, you can use the Staging API as there is a rate limit for issuing certificates. Just replace the `spec.acme.server` like this + +```yaml +spec: + acme: + server: https://acme-staging-v02.api.letsencrypt.org/directory +``` + +In this doc, we used the staging api and as a result, you will see that the certificate was issued by `Fake LE Intermediate X1`. + +For more to know, visit [here](https://letsencrypt.org/docs/rate-limits/) + +### [Certificate Duration and Renewal Window](https://docs.cert-manager.io/en/latest/reference/certificates.html) + +The default duration for all certificates is 90 days and the default renewal windows is 30 days. This means that certificates are considered valid for 3 months and renewal will be attempted within 1 month of expiration. + +You can change that value using `duration` and `renewBefore` field in [certificate.yaml](/docs/v2024.3.18/examples/cert-manager/certificate.yaml), + +```yaml +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: example + namespace: edge-services +spec: + secretName: example-tls + duration: 24h + renewBefore: 12h + dnsNames: + - foo.example.com + - bar.example.com + issuerRef: + name: my-internal-ca + kind: Issuer +``` + +That means, this certificate's validity period is 24 hours and it will begin trying to renew 12 hours before the certificate expiration. diff --git a/content/docs/v2024.3.18/guides/cert-manager/http01_challenge/_index.md b/content/docs/v2024.3.18/guides/cert-manager/http01_challenge/_index.md new file mode 100644 index 000000000..a09a6da17 --- /dev/null +++ b/content/docs/v2024.3.18/guides/cert-manager/http01_challenge/_index.md @@ -0,0 +1,16 @@ +--- +title: HTTP01 Challenge +description: HTTP01 Challenge +menu: + docs_v2024.3.18: + identifier: http01-cert-manager + parent: cert-manager-guides + name: HTTP01 Challenge + weight: 20 +menu_name: docs_v2024.3.18 +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + diff --git a/content/docs/v2024.3.18/guides/cert-manager/http01_challenge/overview.md b/content/docs/v2024.3.18/guides/cert-manager/http01_challenge/overview.md new file mode 100644 index 000000000..ec3d1127b --- /dev/null +++ b/content/docs/v2024.3.18/guides/cert-manager/http01_challenge/overview.md @@ -0,0 +1,131 @@ +--- +title: Issue Let's Encrypt certificate using HTTP-01 challenge with cert-manager +description: Issue Let's Encrypt certificate using HTTP-01 challenge with cert-manager in Kubernetes +menu: + docs_v2024.3.18: + identifier: overview-http-cert-manager + name: Overview + parent: http01-cert-manager + weight: 10 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# Issue Let's Encrypt certificate using HTTP-01 challenge with cert-manager + +## 1. Setup Issuer/ClusterIssuer + +Setup a [ClusterIssuer (Or Issuer)](/docs/v2024.3.18/guides/cert-manager/get-started) for your Ingress by applying +this [clusterissuer.yaml](/docs/v2024.3.18/examples/cert-manager/http/clusterissuer.yaml) + + + +```yaml +apiVersion: cert-manager.io/v1 +kind: ClusterIssuer +metadata: + name: letsencrypt-staging +spec: + acme: + # You must replace this email address with your own. + # Let's Encrypt will use this to contact you about expiring + # certificates, and issues related to your account. + email: user@example.com + server: https://acme-staging-v02.api.letsencrypt.org/directory + privateKeySecretRef: + # Secret resource used to store the account's private key. + name: example-issuer-account-key + # Add a single challenge solver, HTTP01 using nginx + solvers: + - http01: + ingress: + name: test-ingress +``` + +Here `test-ingress` is the name of ingress you're going to create. + +**IngressClass or IngressName?** + +If the ingressClass field is specified, cert-manager will create new Ingress resources in order to route traffic to the ‘acmesolver’ pods, which are responsible for responding to ACME challenge validation requests. If the `ingress.name` field is specified, cert-manager will edit the named ingress resource in order to solve HTTP01 challenges. Since Voyager allocates a separate external IP for each Ingress resource, use `ingress.name` mechanism for Voyager. + +## 2. Create Ingress + +We are going to use a nginx server as the backend. To deploy nginx server, run the following commands: + +```bash +kubectl run nginx --image=nginx +kubectl expose deployment nginx --name=web --port=80 --target-port=80 +``` + +Now create your ingress by applying [ingress.yaml](/docs/v2024.3.18/examples/cert-manager/http/ingress.yaml) + +```yaml +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: default + annotations: + kubernetes.io/ingress.class: voyager + certmanager.k8s.io/cluster-issuer: "letsencrypt-staging" + certmanager.k8s.io/acme-challenge-type: http01 +spec: + tls: + - hosts: + - kiteci.appscode.ninja + secretName: quickstart-kiteci-tls + rules: + - http: + paths: + - backend: + service: + name: web + port: + number: 80 + path: / + pathType: Prefix +``` + +Then you'll see that a Certificate crd is created automatically for this ingress + +```bash +kubectl get certificates.certmanager.k8s.io --all-namespaces +``` + +But the certificate is still invalid. + +Now take the `EXTERNAL-IP` from the corresponding service: + +```bash +kubectl get svc +``` + +```bash +NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +default voyager-test-ingress LoadBalancer 10.7.249.7 35.239.22.162 80:31919/TCP,443:32751/TCP 44s +``` + +Create an A-record for `kiteci-dns.appscode.ninja` mapped to `35.239.22.162`. + +Wait till this is resolved: + +```bash +dig +short kiteci-dns.appscode.ninja +``` + +Describe that certificate and wait until you see `Certificate issued successfully` when you describe the certificate. + +```bash +kubectl describe certificates.certmanager.k8s.io quickstart-kiteci-tls +``` + +Let’s Encrypt does not support issuing wildcard certificates with HTTP-01 challenges. To issue wildcard certificates, you must use the DNS-01 challenge. + +The dnsNames field specifies a list of Subject Alternative Names to be associated with the certificate. If the commonName field is omitted, the first element in the list will be the common name. diff --git a/content/docs/v2024.3.18/guides/ingress/README.md b/content/docs/v2024.3.18/guides/ingress/README.md new file mode 100644 index 000000000..628f2c1ec --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/README.md @@ -0,0 +1,64 @@ +--- +title: Ingress | Voyager +menu: + docs_v2024.3.18: + identifier: readme-ingress + name: Readme + parent: ingress-guides + weight: -1 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +url: /docs/v2024.3.18/guides/ingress/ +aliases: +- /docs/v2024.3.18/guides/ingress/README/ +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +# Guides + +Guides show you how to use Voyager as a Kubernetes Ingress controller. + +- HTTP + - [Exposing Service via Ingress](/docs/v2024.3.18/guides/ingress/http/single-service) + - [Virtual Hosting](/docs/v2024.3.18/guides/ingress/http/virtual-hosting) + - [Supports Loadbalancer Source Range](/docs/v2024.3.18/guides/ingress/http/source-range) + - [URL and Request Header Re-writing](/docs/v2024.3.18/guides/ingress/http/rewrite-rules) + - [Enable CORS](/docs/v2024.3.18/guides/ingress/http/cors) + - [Custom HTTP Port](/docs/v2024.3.18/guides/ingress/http/custom-http-port) + - [Using External Service as Ingress Backend](/docs/v2024.3.18/guides/ingress/http/external-svc) + - [HSTS](/docs/v2024.3.18/guides/ingress/http/hsts) + - [Forward Traffic to StatefulSet Pods](/docs/v2024.3.18/guides/ingress/http/statefulset-pod) + - [Configure Sticky session to Backends](/docs/v2024.3.18/guides/ingress/http/sticky-session) + - [Blue Green Deployments using weighted Loadbalancing](/docs/v2024.3.18/guides/ingress/http/blue-green-deployment) +- TLS/SSL + - [TLS Termination](/docs/v2024.3.18/guides/ingress/tls/overview) + - [Multiple TLS Entries](/docs/v2024.3.18/guides/ingress/tls/multiple-tls) + - [Backend TLS](/docs/v2024.3.18/guides/ingress/tls/backend-tls) + - [Supports AWS certificate manager](/docs/v2024.3.18/guides/ingress/tls/aws-cert-manager) +- TCP + - [TCP LoadBalancing](/docs/v2024.3.18/guides/ingress/tcp/overview) + - [TCP SNI](/docs/v2024.3.18/guides/ingress/tcp/tcp-sni) +- Configuration + - [Customize generated HAProxy config via BackendRule](/docs/v2024.3.18/guides/ingress/configuration/backend-rule) (can be used for [http rewriting](https://www.haproxy.com/doc/aloha/7.0/haproxy/http_rewriting.html), add [health checks](https://www.haproxy.com/doc/aloha/7.0/haproxy/healthchecks.html), etc.) + - [Apply Frontend Rules](/docs/v2024.3.18/guides/ingress/configuration/frontend-rule) + - [Supported Annotations](/docs/v2024.3.18/guides/ingress/configuration/annotations) + - [Specify NodePort](/docs/v2024.3.18/guides/ingress/configuration/node-port) + - [Configure global options](/docs/v2024.3.18/guides/ingress/configuration/default-options) + - [Configure Custom Timeouts for HAProxy](/docs/v2024.3.18/guides/ingress/configuration/default-timeouts) + - [Configure Load balancing algorithm](/docs/v2024.3.18/guides/ingress/configuration/loadbalancing-algorithm) + - [Using Custom HAProxy Templates](/docs/v2024.3.18/guides/ingress/configuration/custom-templates) + - [Using Additional Configuration Files](/docs/v2024.3.18/guides/ingress/configuration/config-volumes) + - [Using HTTP/2 and gRPC](/docs/v2024.3.18/guides/ingress/configuration/http-2) +- Security + - [Configure Basic Auth for HTTP Backends](/docs/v2024.3.18/guides/ingress/security/basic-auth) + - [Configure External Auth for HTTP Backends](/docs/v2024.3.18/guides/ingress/security/oauth) + - [TLS Authentication](/docs/v2024.3.18/guides/ingress/security/tls-auth) +- Monitoring + - [Exposing HAProxy Stats](/docs/v2024.3.18/guides/ingress/monitoring/haproxy-stats) +- [Scaling Ingress](/docs/v2024.3.18/guides/ingress/scaling) +- [Placement of Ingress Pods](/docs/v2024.3.18/guides/ingress/pod-placement) +- [Avoid 503 with Graceful Server Shutdown](/docs/v2024.3.18/guides/ingress/graceful-reload) \ No newline at end of file diff --git a/content/docs/v2024.3.18/guides/ingress/_index.md b/content/docs/v2024.3.18/guides/ingress/_index.md new file mode 100644 index 000000000..4a2dc467f --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/_index.md @@ -0,0 +1,15 @@ +--- +title: Ingress +menu: + docs_v2024.3.18: + identifier: ingress-guides + name: Ingress + parent: guides + weight: 100 +menu_name: docs_v2024.3.18 +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + diff --git a/content/docs/v2024.3.18/guides/ingress/configuration/_index.md b/content/docs/v2024.3.18/guides/ingress/configuration/_index.md new file mode 100644 index 000000000..e782f73cd --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/configuration/_index.md @@ -0,0 +1,15 @@ +--- +title: Configuration +menu: + docs_v2024.3.18: + identifier: config-ingress + name: Configuration + parent: ingress-guides + weight: 25 +menu_name: docs_v2024.3.18 +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + diff --git a/content/docs/v2024.3.18/guides/ingress/configuration/accept-proxy.md b/content/docs/v2024.3.18/guides/ingress/configuration/accept-proxy.md new file mode 100644 index 000000000..36668eb13 --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/configuration/accept-proxy.md @@ -0,0 +1,118 @@ +--- +title: Configure Ingress Accept Proxy +menu: + docs_v2024.3.18: + identifier: accept-proxy-configuration + name: Accept Proxy + parent: config-ingress + weight: 10 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# Accept Proxy + +If set to `true`, enforces the use of the PROXY protocol over any connection accepted by HAProxy. +It will add the `accept-proxy` keyword on the `bind` line of the generated `haproxy.cfg`. + +## Ingress Example + +First create a test-server and expose it via service: + +```bash +$ kubectl run test-server --image=gcr.io/google_containers/echoserver:1.8 +deployment "test-server" created + +$ kubectl expose deployment test-server --type=LoadBalancer --port=80 --target-port=8080 +service "test-server" exposed +``` + +Then create the ingress: + +```yaml +$ kubectl apply -f test-ingress.yaml + +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: default + annotations: + ingress.appscode.com/accept-proxy: "true" +spec: + rules: + - host: voyager.appscode.test + http: + paths: + - path: /foo + backend: + service: + name: test-server + port: + number: 80 +``` + +```bash +$ kubectl get pods,svc +NAME READY STATUS RESTARTS AGE +po/test-server-68ddc845cd-x7dtv 1/1 Running 0 23h +po/voyager-test-ingress-5b758664f6-mb4hs 1/1 Running 0 2m + +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +svc/kubernetes ClusterIP 10.96.0.1 443/TCP 2d +svc/test-server LoadBalancer 10.105.13.31 80:30390/TCP 1d +svc/voyager-test-ingress LoadBalancer 10.106.53.141 80:30966/TCP 2m +``` + +Generated haproxy.cfg: + +```ini +# HAProxy configuration generated by https://github.com/appscode/voyager +# DO NOT EDIT! +global + daemon + stats socket /tmp/haproxy + server-state-file global + server-state-base /var/state/haproxy/ + # log using a syslog socket + log /dev/log local0 info + log /dev/log local0 notice + tune.ssl.default-dh-param 2048 + ssl-default-bind-ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK + hard-stop-after 30s +defaults + log global + # https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#4.2-option%20abortonclose + # https://github.com/voyagermesh/voyager/pull/403 + option dontlognull + option http-server-close + # Timeout values + timeout client 50s + timeout client-fin 50s + timeout connect 5s + timeout server 50s + timeout tunnel 50s + # Configure error files + # default traffic mode is http + # mode is overwritten in case of tcp services + mode http +frontend http-0_0_0_0-80 + bind *:80 accept-proxy + mode http + option httplog + option forwardfor + acl is_proxy_https hdr(X-Forwarded-Proto) https + acl acl_voyager.appscode.test hdr(host) -i voyager.appscode.test + acl acl_voyager.appscode.test hdr(host) -i voyager.appscode.test:80 + acl acl_voyager.appscode.test:foo path_beg /foo + use_backend test-server.default:80 if acl_voyager.appscode.test acl_voyager.appscode.test:foo +backend test-server.default:80 + server pod-test-server-68ddc845cd-x7dtv 172.17.0.4:8080 +``` \ No newline at end of file diff --git a/content/docs/v2024.3.18/guides/ingress/configuration/agent-check.md b/content/docs/v2024.3.18/guides/ingress/configuration/agent-check.md new file mode 100644 index 000000000..656f8ab68 --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/configuration/agent-check.md @@ -0,0 +1,116 @@ +--- +title: Agent Check | Kubernetes Ingress +menu: + docs_v2024.3.18: + identifier: agent-check + name: Agent Check + parent: config-ingress + weight: 20 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# Agent Check + +[haproxy-agent-check](http://cbonte.github.io/haproxy-dconv/1.8/configuration.html#5.2-agent-check) can be enabled for a specific backend server by assigning the agent server port in `ingress.appscode.com/agent-port` annotations to the corresponding service. You can also add [agent-inter](http://cbonte.github.io/haproxy-dconv/1.8/configuration.html#agent-inter) in `ingress.appscode.com/agent-interval` annotations to the same service, which defaults to 2000ms if not mentioned. + +## Example + +First deploy and expose a test server: + +```yaml +$ kubectl apply -f test-server.yaml + +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + run: test-server + name: test-server + namespace: default +spec: + selector: + matchLabels: + run: test-server + template: + metadata: + labels: + run: test-server + spec: + containers: + - image: appscode/test-server:2.4 + name: test-server +--- +apiVersion: v1 +kind: Service +metadata: + labels: + run: test-server + name: test-server + namespace: default +spec: + ports: + - port: 8080 + targetPort: 8080 + name: web + - port: 5555 + targetPort: 5555 + name: agent + selector: + run: test-server +``` + +Here, port 8080 will serve client's request and port 5555 will be used for agent-check. + +Then deploy the ingress: + +```yaml +$ kubectl apply test-ingress.yaml + +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: default +spec: + rules: + - http: + paths: + - path: /app + backend: + service: + name: test-server + port: + number: 8080 +``` + +Now we need to annotate the backend service to enable agent-check for that backend. + +```bash +$ kubectl annotate svc test-server ingress.appscode.com/agent-port="5555" +``` + +To change the default agent-interval value, annotate the same service with: +```bash +$ kubectl annotate svc test-server ingress.appscode.com/agent-interval="3s" +``` + +## Time Format + +These timeout values are generally expressed in milliseconds (unless explicitly stated +otherwise) but may be expressed in any other unit by suffixing the unit to the +numeric value. Supported units are : + +- us : microseconds. 1 microsecond = 1/1000000 second +- ms : milliseconds. 1 millisecond = 1/1000 second. This is the default. +- s : seconds. 1s = 1000ms +- m : minutes. 1m = 60s = 60000ms +- h : hours. 1h = 60m = 3600s = 3600000ms +- d : days. 1d = 24h = 1440m = 86400s = 86400000ms diff --git a/content/docs/v2024.3.18/guides/ingress/configuration/annotations.md b/content/docs/v2024.3.18/guides/ingress/configuration/annotations.md new file mode 100644 index 000000000..539556afe --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/configuration/annotations.md @@ -0,0 +1,89 @@ +--- +title: Configure Ingress Annotations +menu: + docs_v2024.3.18: + identifier: annotations-configuration + name: Annotations + parent: config-ingress + weight: 1 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# Configure ingress with annotations + +Below is the full list of supported annotations: + +| Keys | Value | Default | +|--------|-----------|----------| +| [ingress.appscode.com/type](/docs/v2024.3.18/concepts/README) | LoadBalancer, HostPort, NodePort, Internal | `LoadBalancer` | +| [ingress.appscode.com/api-schema](/docs/v2024.3.18/concepts/overview) | {APIGroup}/{APIVersion} | `voyager.appscode.com/v1` | +| [ingress.appscode.com/accept-proxy](/docs/v2024.3.18/guides/ingress/configuration/accept-proxy) | bool | `false` | +| [ingress.appscode.com/affinity](/docs/v2024.3.18/guides/ingress/http/sticky-session) | `cookie` | | +| [ingress.appscode.com/session-cookie-hash](/docs/v2024.3.18/guides/ingress/http/sticky-session) | string | | +| [ingress.appscode.com/session-cookie-name](/docs/v2024.3.18/guides/ingress/http/sticky-session) | string | `SERVERID` | +| [ingress.appscode.com/hsts](/docs/v2024.3.18/guides/ingress/http/hsts) | bool | `true` | +| [ingress.appscode.com/hsts-include-subdomains](/docs/v2024.3.18/guides/ingress/http/hsts) | bool | `false` | +| [ingress.appscode.com/hsts-max-age](/docs/v2024.3.18/guides/ingress/http/hsts) | string | `15768000` | +| [ingress.appscode.com/hsts-preload](/docs/v2024.3.18/guides/ingress/http/hsts) | bool | `false` | +| [ingress.appscode.com/use-node-port](/docs/v2024.3.18/concepts/ingress-types/nodeport) | bool | `false` | +| [ingress.appscode.com/enable-cors](/docs/v2024.3.18/guides/ingress/http/cors) | bool | `false` | +| [ingress.appscode.com/cors-allow-headers](/docs/v2024.3.18/guides/ingress/http/cors) | string | `DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization` | +| [ingress.appscode.com/cors-allow-methods](/docs/v2024.3.18/guides/ingress/http/cors) | string | `GET,PUT,POST,DELETE,PATCH,OPTIONS` | +| [ingress.appscode.com/cors-allow-origin](/docs/v2024.3.18/guides/ingress/http/cors) | string | `*` | +| [ingress.appscode.com/default-option](/docs/v2024.3.18/guides/ingress/configuration/default-options) | map | `{"http-server-close": "true", "dontlognull": "true"}` | +| [ingress.appscode.com/default-timeout](/docs/v2024.3.18/guides/ingress/configuration/default-timeouts) | map | `{"connect": "5s", "server": "50s", "client": "50s", "client-fin": "50s", "tunnel": "50s"}` | +| [ingress.appscode.com/hard-stop-after](/docs/v2024.3.18/guides/ingress/configuration/hard-stop-after) | string | `30s` | +| [ingress.appscode.com/auth-type](/docs/v2024.3.18/guides/ingress/security/basic-auth) | `basic` | | +| [ingress.appscode.com/auth-realm](/docs/v2024.3.18/guides/ingress/security/basic-auth) | string | | +| [ingress.appscode.com/auth-secret](/docs/v2024.3.18/guides/ingress/security/basic-auth) | string | | +| [ingress.appscode.com/auth-tls-error-page](/docs/v2024.3.18/guides/ingress/security/tls-auth) | string | | +| [ingress.appscode.com/auth-tls-secret](/docs/v2024.3.18/guides/ingress/security/tls-auth) | string | | +| [ingress.appscode.com/auth-tls-verify-client](/docs/v2024.3.18/guides/ingress/security/tls-auth) | `required` or, `optional` | `required` | +| [ingress.appscode.com/backend-tls](/docs/v2024.3.18/guides/ingress/tls/backend-tls) | string | | +| [ingress.appscode.com/replicas](/docs/v2024.3.18/guides/ingress/scaling) | int | `1` | +| [ingress.appscode.com/backend-weight](/docs/v2024.3.18/guides/ingress/http/blue-green-deployment) | int | 1 | +| [ingress.appscode.com/whitelist-source-range](/docs/v2024.3.18/guides/ingress/configuration/whitelist) | string | | +| [ingress.appscode.com/max-connections](/docs/v2024.3.18/guides/ingress/configuration/max-connections) | int | | +| [ingress.appscode.com/ssl-redirect](/docs/v2024.3.18/guides/ingress/configuration/ssl-redirect) | bool | `true` | +| [ingress.appscode.com/force-ssl-redirect](/docs/v2024.3.18/guides/ingress/configuration/ssl-redirect) | bool | `false` | +| [ingress.appscode.com/limit-connection](/docs/v2024.3.18/guides/ingress/configuration/rate-limit) | int | | +| [ingress.appscode.com/limit-rpm](/docs/v2024.3.18/guides/ingress/configuration/rate-limit) | int | | +| [ingress.appscode.com/limit-rps](/docs/v2024.3.18/guides/ingress/configuration/rate-limit) | int | | +| [ingress.appscode.com/errorfiles](/docs/v2024.3.18/guides/ingress/configuration/error-files) | string | | +| [ingress.appscode.com/proxy-body-size](/docs/v2024.3.18/guides/ingress/configuration/body-size) | int | | +| [ingress.appscode.com/ssl-passthrough](/docs/v2024.3.18/guides/ingress/configuration/ssl-passthrough) | bool | `false` | +| [ingress.appscode.com/rewrite-target](/docs/v2024.3.18/guides/ingress/configuration/rewrite-target) | string | | +| [ingress.appscode.com/keep-source-ip](/docs/v2024.3.18/guides/ingress/configuration/keep-source-ip) | bool | `false` | +| [ingress.appscode.com/health-check-nodeport](/docs/v2024.3.18/guides/ingress/configuration/keep-source-ip) | int | | +| [ingress.appscode.com/load-balancer-ip](/docs/v2024.3.18/guides/ingress/configuration/loadbalancer-ip) | string | | +| [ingress.appscode.com/annotations-pod](/docs/v2024.3.18/guides/ingress/configuration/pod-annotations) | map | | +| [ingress.appscode.com/annotations-service](/docs/v2024.3.18/guides/ingress/configuration/service-annotations) | map | | +| [ingress.appscode.com/stats](/docs/v2024.3.18/guides/ingress/monitoring/haproxy-stats) | bool | `false` | +| [ingress.appscode.com/stats-port](/docs/v2024.3.18/guides/ingress/monitoring/haproxy-stats) | int | `56789` | +| [ingress.appscode.com/stats-secret-name](/docs/v2024.3.18/guides/ingress/monitoring/haproxy-stats) | string | | +| [ingress.appscode.com/monitoring-agent](/docs/v2024.3.18/guides/ingress/monitoring/using-coreos-prometheus-operator) | string | | +| [ingress.appscode.com/service-monitor-labels](/docs/v2024.3.18/guides/ingress/monitoring/using-coreos-prometheus-operator) | map | | +| [ingress.appscode.com/service-monitor-namespace](/docs/v2024.3.18/guides/ingress/monitoring/using-coreos-prometheus-operator) | string | | +| [ingress.appscode.com/service-monitor-endpoint-port](/docs/v2024.3.18/guides/ingress/monitoring/using-coreos-prometheus-operator) | integer | 56790 | +| [ingress.appscode.com/service-monitor-endpoint-scrape-interval](/docs/v2024.3.18/guides/ingress/monitoring/using-coreos-prometheus-operator) | string | | +| [ingress.appscode.com/use-dns-resolver](/docs/v2024.3.18/guides/ingress/http/external-svc#using-external-domain) | bool | `false` | +| [ingress.appscode.com/dns-resolver-nameservers](/docs/v2024.3.18/guides/ingress/http/external-svc#using-external-domain) | string | | +| [ingress.appscode.com/dns-resolver-check-health](/docs/v2024.3.18/guides/ingress/http/external-svc#using-external-domain) | bool | `true` | +| [ingress.appscode.com/dns-resolver-retries](/docs/v2024.3.18/guides/ingress/http/external-svc#using-external-domain) | int | `0` | +| [ingress.appscode.com/dns-resolver-timeout](/docs/v2024.3.18/guides/ingress/http/external-svc#using-external-domain) | map | | +| [ingress.appscode.com/dns-resolver-hold](/docs/v2024.3.18/guides/ingress/http/external-svc#using-external-domain) | map | | +| [ingress.appscode.com/workload-kind](/docs/v2024.3.18/guides/ingress/pod-placement#choosing-workload-kind) | string | `Deployment` | +| [ingress.appscode.com/node-selector](/docs/v2024.3.18/guides/ingress/pod-placement#using-node-selector) | map | | +| [ingress.appscode.com/tolerations](/docs/v2024.3.18/guides/ingress/pod-placement#using-taints-and-toleration) | array | | +| [ingress.appscode.com/check](/docs/v2024.3.18/guides/ingress/configuration/health-check) | bool | `false` | +| [ingress.appscode.com/check-port](/docs/v2024.3.18/guides/ingress/configuration/health-check) | int | | +| [ingress.appscode.com/agent-port](/docs/v2024.3.18/guides/ingress/configuration/agent-check) | int | | +| [ingress.appscode.com/agent-interval](/docs/v2024.3.18/guides/ingress/configuration/agent-check) | string | "2000ms" | diff --git a/content/docs/v2024.3.18/guides/ingress/configuration/backend-rule.md b/content/docs/v2024.3.18/guides/ingress/configuration/backend-rule.md new file mode 100644 index 000000000..741d8b796 --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/configuration/backend-rule.md @@ -0,0 +1,48 @@ +--- +title: Backend Rules | Kubernetes Ingress +menu: + docs_v2024.3.18: + identifier: backend-config + name: Backend Rule + parent: config-ingress + weight: 100 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# Backend Rules + +Voyager supports full spectrum of HAProxy backend rules via `backendRule`. Read [more](https://cbonte.github.io/haproxy-dconv/1.7/configuration.html) +about HAProxy backend rules. + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: default +spec: + rules: + - host: appscode.example.com + http: + paths: + - path: '/test' + backend: + service: + name: test-service + port: + number: 80 + backendRules: + - 'acl add_url capture.req.uri -m beg /test-second' + - 'http-response set-header X-Added-From-Proxy added-from-proxy if add_url' +``` + +This example will apply an acl to the server backend, and a extra header from Loadbalancer if request uri +starts with `/test-second`. \ No newline at end of file diff --git a/content/docs/v2024.3.18/guides/ingress/configuration/bind-address.md b/content/docs/v2024.3.18/guides/ingress/configuration/bind-address.md new file mode 100644 index 000000000..134debaa3 --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/configuration/bind-address.md @@ -0,0 +1,19 @@ +--- +title: Configure Ingress Bind Address +menu: + docs_v2024.3.18: + identifier: bind-address-configuration + name: Bind Address + parent: config-ingress + weight: 10 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + diff --git a/content/docs/v2024.3.18/guides/ingress/configuration/body-size.md b/content/docs/v2024.3.18/guides/ingress/configuration/body-size.md new file mode 100644 index 000000000..51aae7951 --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/configuration/body-size.md @@ -0,0 +1,186 @@ +--- +title: Configure Ingress Body Size +menu: + docs_v2024.3.18: + identifier: body-size-configuration + name: Body Size + parent: config-ingress + weight: 10 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# Maximum Body Size + +You can configure maximum allowed request body size in bytes using `ingress.appscode.com/proxy-body-size` annotation. It will applied globally for all frontends. If request body size exceeds the specified size then it will through error with code `400`. + +## Ingress Example + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: default + annotations: + ingress.appscode.com/proxy-body-size: "8" +spec: + rules: + - host: voyager.appscode.test + http: + paths: + - path: /foo + backend: + service: + name: test-server + port: + number: 80 +``` + +It will add following to all frontends in generated haproxy.cfg: + +```ini +http-request deny deny_status 400 if { req.body_size gt 8 } +``` + +Generated haproxy.cfg: + +```ini +# HAProxy configuration generated by https://github.com/appscode/voyager +# DO NOT EDIT! +global + daemon + stats socket /tmp/haproxy + server-state-file global + server-state-base /var/state/haproxy/ + # log using a syslog socket + log /dev/log local0 info + log /dev/log local0 notice + tune.ssl.default-dh-param 2048 + ssl-default-bind-ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK + hard-stop-after 30s +defaults + log global + # https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#4.2-option%20abortonclose + # https://github.com/voyagermesh/voyager/pull/403 + option dontlognull + option http-server-close + # Timeout values + timeout client 50s + timeout client-fin 50s + timeout connect 5s + timeout server 50s + timeout tunnel 50s + # Configure error files + # default traffic mode is http + # mode is overwritten in case of tcp services + mode http +frontend http-0_0_0_0-80 + bind *:80 + mode http + option httplog + option forwardfor + http-request deny deny_status 400 if { req.body_size gt 8 } + acl is_proxy_https hdr(X-Forwarded-Proto) https + acl acl_voyager.appscode.test hdr(host) -i voyager.appscode.test + acl acl_voyager.appscode.test hdr(host) -i voyager.appscode.test:80 + acl acl_voyager.appscode.test:foo path_beg /foo + use_backend test-server.default:80 if acl_voyager.appscode.test acl_voyager.appscode.test:foo +backend test-server.default:80 + server pod-test-server-68ddc845cd-x5c78 172.17.0.4:8080 +``` + +Get url for ingress service: + +```bash +$ minikube service --url voyager-test-ingress +http://192.168.99.100:31996 +``` + +Send request with content-length smaller than allowed size: + +```bash +$ curl -X POST -v -H 'Host: voyager.appscode.test' --data "hello" 192.168.99.100:31996/foo +Note: Unnecessary use of -X or --request, POST is already inferred. +* Trying 192.168.99.100... +* Connected to 192.168.99.100 (192.168.99.100) port 31996 (#0) +> POST /foo HTTP/1.1 +> Host: voyager.appscode.test +> User-Agent: curl/7.47.0 +> Accept: */* +> Content-Length: 5 +> Content-Type: application/x-www-form-urlencoded +> +* upload completely sent off: 5 out of 5 bytes +< HTTP/1.1 200 OK +< Date: Fri, 16 Feb 2018 12:15:45 GMT +< Content-Type: text/plain +< Transfer-Encoding: chunked +< Server: echoserver +< + + +Hostname: test-server-68ddc845cd-x5c78 + +Pod Information: + -no pod information available- + +Server values: + server_version=nginx: 1.13.3 - lua: 10008 + +Request Information: + client_address=172.17.0.5 + method=POST + real path=/foo + query= + request_version=1.1 + request_uri=http://voyager.appscode.test:8080/foo + +Request Headers: + accept=*/* + connection=close + content-length=5 + content-type=application/x-www-form-urlencoded + host=voyager.appscode.test + user-agent=curl/7.47.0 + x-forwarded-for=172.17.0.1 + +Request Body: +hello + +* Connection #0 to host 192.168.99.100 left intact +``` + +Send another request with content-length larger than allowed size: + +```bash +$ curl -X POST -v -H 'Host: voyager.appscode.test' --data "this is raw data" 192.168.99.100:31996/foo +Note: Unnecessary use of -X or --request, POST is already inferred. +* Trying 192.168.99.100... +* Connected to 192.168.99.100 (192.168.99.100) port 31996 (#0) +> POST /foo HTTP/1.1 +> Host: voyager.appscode.test +> User-Agent: curl/7.47.0 +> Accept: */* +> Content-Length: 16 +> Content-Type: application/x-www-form-urlencoded +> +* upload completely sent off: 16 out of 16 bytes +* HTTP 1.0, assume close after body +< HTTP/1.0 400 Bad request +< Cache-Control: no-cache +< Connection: close +< Content-Type: text/html +< +

400 Bad request

+Your browser sent an invalid request. + +* Closing connection 0 +``` \ No newline at end of file diff --git a/content/docs/v2024.3.18/guides/ingress/configuration/config-volumes.md b/content/docs/v2024.3.18/guides/ingress/configuration/config-volumes.md new file mode 100644 index 000000000..2550d06ae --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/configuration/config-volumes.md @@ -0,0 +1,196 @@ +--- +title: Configuration Volumes +menu: + docs_v2024.3.18: + identifier: config-volumes + name: Configuration Volumes + parent: config-ingress + weight: 10 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# Configuration Volumes + +You might want to provide additional files to the haproxy container and use them in the haproxy configuration. For example, specifying a CA file for verifying backend server. Using voyager, you can mount additional files from secrets/configmaps by configuring `spec.configVolumes`. + +Note that, when `spec.configVolumes` is used, operator will skip the validation for generated haproxy configuration. + +## Example: Backend Server Verification + +First create demo namespace for this example. + +``` +$ kubectl create namespace demo +namespace/demo created +``` + +### Deploy Test Server + +Deploy a TLS enabled test server. + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + run: test-server + name: test-server + namespace: demo +spec: + selector: + matchLabels: + run: test-server + template: + metadata: + labels: + run: test-server + spec: + containers: + - image: appscode/test-server:2.3 + name: test-server + args: + - --ca + imagePullPolicy: Always +--- +apiVersion: v1 +kind: Service +metadata: + labels: + run: test-server + name: test-server + namespace: demo + annotations: + ingress.appscode.com/backend-tls: ssl ca-file /tmp/ca/ca.pem +spec: + ports: + - port: 6443 + targetPort: 6443 + name: https + selector: + run: test-server +``` + +Here, using `ingress.appscode.com/backend-tls` annotation we have specified the path of CA file. HAProxy will use this CA file to verify the backend server. So, we need to provide the CA file inside the haproxy-container in path `/tmp/ca/ca.pem`. + +### Create Secret + +If you use your own backend server, you might already have the CA file. Run following commands to get the CA file of the test-server used in this example. + +``` +$ kubectl get pods -n demo -l run=test-server +NAME READY STATUS RESTARTS AGE +test-server-64855d98cc-7bfpr 1/1 Running 0 74s +$ kubectl exec -it -n demo test-server-64855d98cc-7bfpr cat cert.pem > ca.pem +``` + +Now, create a secret using the CA file. + +``` +$ kubectl create secret generic ca-secret -n demo --from-file=ca.pem +secret/ca-secret created +``` + +### Create Ingress + +Create the ingress and specify the secret in `spec.configVolumes`. + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: demo +spec: + configVolumes: + - name: ca-vol + secret: + secretName: ca-secret + mountPath: /tmp/ca + rules: + - host: "ssl.appscode.test" + http: + paths: + - path: /apis + backend: + service: + name: test-server + port: + number: 6443 +``` + +### Generated haproxy.cfg + +```ini +# HAProxy configuration generated by https://github.com/appscode/voyager +# DO NOT EDIT! +global + daemon + stats socket /var/run/haproxy.sock level admin expose-fd listeners + server-state-file global + server-state-base /var/state/haproxy/ + # log using a syslog socket + log /dev/log local0 info + tune.ssl.default-dh-param 2048 + ssl-default-bind-ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK + lua-load /etc/auth-request.lua + hard-stop-after 30s +defaults + log global + # https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#4.2-option%20abortonclose + # https://github.com/voyagermesh/voyager/pull/403 + option dontlognull + option http-server-close + # Timeout values + timeout client 50s + timeout client-fin 50s + timeout connect 5s + timeout server 50s + timeout tunnel 50s + # Configure error files + # default traffic mode is http + # mode is overwritten in case of tcp services + mode http +frontend http-0_0_0_0-80 + bind *:80 + mode http + option httplog + option forwardfor + acl is_proxy_https hdr(X-Forwarded-Proto) https + acl is_proxy_https ssl_fc + http-request set-var(req.scheme) str(https) if is_proxy_https + http-request set-var(req.scheme) str(http) if ! is_proxy_https + acl acl_ssl.appscode.test hdr(host) -i ssl.appscode.test + acl acl_ssl.appscode.test hdr(host) -i ssl.appscode.test:80 + acl acl_ssl.appscode.test:apis path_beg /apis + use_backend test-server.demo:6443 if acl_ssl.appscode.test acl_ssl.appscode.test:apis +backend test-server.demo:6443 + server pod-test-server-64855d98cc-7bfpr 172.17.0.5:6443 ssl ca-file /tmp/ca/ca.pem +``` + +### Check Response + +```bash +$ minikube service --url voyager-test-ingress -n demo +http://192.168.99.100:32598 + +$ curl -H "Host: ssl.appscode.test" 'http://192.168.99.100:32598/apis' +{"type":"http","host":"ssl.appscode.test","serverPort":":6443","path":"/apis","method":"GET","headers":{"Accept":["*/*"],"Connection":["close"],"User-Agent":["curl/7.58.0"],"X-Forwarded-For":["172.17.0.1"]}} +``` + +Note that, in this example, `curl` connects with HAProxy in no-tls mode, but HAProxy connects with backend server in tls mode. + +### Cleanup + +``` +$ kubectl delete ns demo +namespace "demo" deleted +``` + diff --git a/content/docs/v2024.3.18/guides/ingress/configuration/custom-templates.md b/content/docs/v2024.3.18/guides/ingress/configuration/custom-templates.md new file mode 100644 index 000000000..511d8000a --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/configuration/custom-templates.md @@ -0,0 +1,70 @@ +--- +title: Using Custom HAProxy Templates | Kubernetes Ingress +menu: + docs_v2024.3.18: + identifier: custom-tpl-config + name: Custom Templates + parent: config-ingress + weight: 10 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# Using Custom HAProxy Templates + +Since 3.2.0, Voyager can use custom templates provided by users to render HAProxy configuration. Voyager comes with a set of GO [text/templates](https://golang.org/pkg/text/template/) found [here](https://github.com/voyagermesh/voyager/tree/{{< param "info.version" >}}/hack/docker/voyager/templates). These templates are mounted at `/srv/voyager/templates`. You can mount a ConfigMap with matching template names when installing Voyager operator to a different location and pass that to Voyager operator using `--custom-templates` flag. Voyager will [load](https://github.com/voyagermesh/voyager/blob/3ae30cd023ff8fa6301d2656bf9fbc5765529691/pkg/haproxy/template.go#L40) the built-in templates first and then load any custom templates if provided. As long as the custom templates have [same name](https://golang.org/pkg/text/template/#Template.ParseGlob) as the built-in templates, custom templates will be used render HAProxy config. You can overwrite any number of templates as you wish. Also note that templates are loaded when Voyager operator starts. So, if you want to reload custom templates, you need to restart the running Voyager operator pod (not HAProxy pods). + +In this example, we are going to overwrite the [defaults.cfg](https://raw.githubusercontent.com/voyagermesh/voyager/{{< param "info.version" >}}/hack/docker/voyager/templates/defaults.cfg) template which is used to render the [`defaults`](https://github.com/voyagermesh/voyager/blob/3ae30cd023ff8fa6301d2656bf9fbc5765529691/hack/docker/voyager/templates/haproxy.cfg#L6) section of HAProxy config. + +```bash +$ cat /tmp/defaults.cfg + +defaults + log global + + # my custom template + # https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#4.2-option%20abortonclose + option dontlog-normal + log /dev/log local0 notice alert + option dontlognull + option http-server-close + + # Timeout values + timeout client 5s + timeout client-fin 5s + timeout connect 5s + timeout server 5s + timeout tunnel 5s + + # default traffic mode is http + # mode is overwritten in case of tcp services + mode http +``` + +Now create a ConfigMap using the defaults.cfg as key and the file content as the value. + +```bash +$ kubectl create configmap -n voyager voyager-templates --from-file=/tmp/defaults.cfg +``` + +Now, the ConfigMap `voyager-templates` has to be mounted in the voyager operator pod and `--custom-templates` flag has to be set. To do this, set `templates.cfgmap` value to Voyager operator chart. + +```bash +$ helm install voyager oci://ghcr.io/appscode-charts/voyager \ + --version {{< param "info.version" >}} \ + --namespace voyager --create-namespace \ + --set cloudProvider=minikube \ + --set templates.cfgmap=voyager-templates \ + --wait --burst-limit=10000 --debug +``` + +![installer](/docs/v2024.3.18/images/ingress/configuration/custom-template/installer.png) + +This will restart the Voyager operator pods. After start, Voyager pod will update any existing HAProxy configuration to the new templates. diff --git a/content/docs/v2024.3.18/guides/ingress/configuration/default-options.md b/content/docs/v2024.3.18/guides/ingress/configuration/default-options.md new file mode 100644 index 000000000..7f80d7555 --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/configuration/default-options.md @@ -0,0 +1,104 @@ +--- +title: Default HAProxy Options | Kubernetes Ingress +menu: + docs_v2024.3.18: + identifier: options-config + name: HAProxy Options + parent: config-ingress + weight: 10 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# Default HAProxy Options + +Voyager Supports all valid options for [defaults section of HAProxy config](https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#4.2-option%20abortonclose). You can provide these options using a json encoded map in Ingress annotations like below: + +`ingress.appscode.com/default-option: '{"http-keep-alive": "true", "dontlognull": "true", "clitcpka": "false"}'` + +This will be appended in the defaults section of HAProxy as: + +```ini +option http-keep-alive +option dontlognull +no option clitcpka +``` + +If you don't set the annotation `{"http-server-close": "true", "dontlognull": "true"}` will be considered as default value + +Ingress Example: + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: default + annotations: + ingress.appscode.com/default-option: '{"http-keep-alive": "true", "dontlognull": "true", "clitcpka": "false"}' +spec: + rules: + - host: voyager.appscode.test + http: + paths: + - path: /foo + backend: + service: + name: test-server + port: + number: 80 +``` + +Generated haproxy.cfg: + +```ini +# HAProxy configuration generated by https://github.com/appscode/voyager +# DO NOT EDIT! +global + daemon + stats socket /tmp/haproxy + server-state-file global + server-state-base /var/state/haproxy/ + # log using a syslog socket + log /dev/log local0 info + log /dev/log local0 notice + tune.ssl.default-dh-param 2048 + ssl-default-bind-ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK + hard-stop-after 30s +defaults + log global + # https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#4.2-option%20abortonclose + # https://github.com/voyagermesh/voyager/pull/403 + no option clitcpka + option dontlognull + option http-keep-alive + # Timeout values + timeout client 50s + timeout client-fin 50s + timeout connect 5s + timeout server 50s + timeout tunnel 50s + # Configure error files + # default traffic mode is http + # mode is overwritten in case of tcp services + mode http +frontend http-0_0_0_0-80 + bind *:80 + mode http + option httplog + option forwardfor + acl is_proxy_https hdr(X-Forwarded-Proto) https + acl acl_voyager.appscode.test hdr(host) -i voyager.appscode.test + acl acl_voyager.appscode.test hdr(host) -i voyager.appscode.test:80 + acl acl_voyager.appscode.test:foo path_beg /foo + use_backend test-server.default:80 if acl_voyager.appscode.test acl_voyager.appscode.test:foo +backend test-server.default:80 + server pod-test-server-68ddc845cd-x7dtv 172.17.0.4:8080 +``` diff --git a/content/docs/v2024.3.18/guides/ingress/configuration/default-timeouts.md b/content/docs/v2024.3.18/guides/ingress/configuration/default-timeouts.md new file mode 100644 index 000000000..921d7688f --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/configuration/default-timeouts.md @@ -0,0 +1,119 @@ +--- +title: Customize Ingress Timeouts | Kubernetes Ingress +menu: + docs_v2024.3.18: + identifier: custom-timeouts-config + name: Configure Timeouts + parent: config-ingress + weight: 10 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# Customize Timeouts + +Custom timeouts can be configured for HAProxy via annotations. Supports all valid timeout option +for defaults section of HAProxy. [Read More](https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#4.2-timeout%20check) + +`ingress.appscode.com/default-timeout` expects a JSON encoded map of timeouts values. +Valid map keys are `connect`, `server`, `client`, `client-fin` and `tunnel`. + +Ingress Example: + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: default + annotations: + ingress.appscode.com/default-timeout: '{"connect": "15s", "server": "20s"}' +spec: + rules: + - host: voyager.appscode.test + http: + paths: + - path: /foo + backend: + service: + name: test-server + port: + number: 80 +``` + +Generated haproxy.cfg: + +```bash +# HAProxy configuration generated by https://github.com/appscode/voyager +# DO NOT EDIT! +global + daemon + stats socket /tmp/haproxy + server-state-file global + server-state-base /var/state/haproxy/ + # log using a syslog socket + log /dev/log local0 info + log /dev/log local0 notice + tune.ssl.default-dh-param 2048 + ssl-default-bind-ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK + hard-stop-after 30s +defaults + log global + # https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#4.2-option%20abortonclose + # https://github.com/voyagermesh/voyager/pull/403 + option dontlognull + option http-server-close + # Timeout values + timeout client 50s + timeout client-fin 50s + timeout connect 15s + timeout server 20s + timeout tunnel 50s + # Configure error files + # default traffic mode is http + # mode is overwritten in case of tcp services + mode http +frontend http-0_0_0_0-80 + bind *:80 + mode http + option httplog + option forwardfor + acl is_proxy_https hdr(X-Forwarded-Proto) https + acl acl_voyager.appscode.test hdr(host) -i voyager.appscode.test + acl acl_voyager.appscode.test hdr(host) -i voyager.appscode.test:80 + acl acl_voyager.appscode.test:foo path_beg /foo + use_backend test-server.default:80 if acl_voyager.appscode.test acl_voyager.appscode.test:foo +backend test-server.default:80 + server pod-test-server-68ddc845cd-x7dtv 172.17.0.4:8080 +``` + +If any required timeouts is not provided timeouts will be populated with the following values. + +```ini + timeout connect 5s + timeout client 50s + timeout client-fin 50s + timeout server 50s + timeout tunnel 50s +``` + +## Time Format + +These timeout values are generally expressed in milliseconds (unless explicitly stated +otherwise) but may be expressed in any other unit by suffixing the unit to the +numeric value. It is important to consider this because it will not be repeated +for every keyword. Supported units are : + +- us : microseconds. 1 microsecond = 1/1000000 second +- ms : milliseconds. 1 millisecond = 1/1000 second. This is the default. +- s : seconds. 1s = 1000ms +- m : minutes. 1m = 60s = 60000ms +- h : hours. 1h = 60m = 3600s = 3600000ms +- d : days. 1d = 24h = 1440m = 86400s = 86400000ms diff --git a/content/docs/v2024.3.18/guides/ingress/configuration/error-files.md b/content/docs/v2024.3.18/guides/ingress/configuration/error-files.md new file mode 100644 index 000000000..7db57f33f --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/configuration/error-files.md @@ -0,0 +1,45 @@ +--- +title: Configure Ingress Error Files +menu: + docs_v2024.3.18: + identifier: error-files-configuration + name: Error Files + parent: config-ingress + weight: 10 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# Error Files + +Using voyager you can configure haproxy to return a file-content or, execute a command instead of returning generated errors. To achieve this you need to create a `configmap` specifying the file-content or, command for different status codes. Then you have to specify the `configmap` name using `ingress.appscode.com/errorfiles` annotation. Then contents of the configmap will be mounted in the haproxy pod in path `/srv/voyager/errorfiles`. + +Supported commands are: `errorfile, errorloc, errorloc302, errorloc303`. +And supported status codes are: `200, 400, 403, 405, 408, 429, 500, 502, 503, 504`. + +For example, lets consider a `configmap` with following key-value pairs: + +```ini +503.http : +408 : []byte("errorfile /dev/null") +500 : []byte("errorloc https://example.com/500.hlml") +``` + +It will generate following block in `defaults` section of haproxy.cfg: + +```ini +errorfile 503 /srv/voyager/errorfiles/503.http +errorfile 408 /dev/null +errorloc 500 https://example.com/500.hlml +``` + +Note that, when status code with `.http` suffix is used as key, the command will be `errorfile` and you just need to specify the file contents as value. + +To learn more about these command see [here](https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#4.2-errorfile). diff --git a/content/docs/v2024.3.18/guides/ingress/configuration/frontend-rule.md b/content/docs/v2024.3.18/guides/ingress/configuration/frontend-rule.md new file mode 100644 index 000000000..f7e1fe4d8 --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/configuration/frontend-rule.md @@ -0,0 +1,174 @@ +--- +title: Frontend Ingress Rules| Voyager +menu: + docs_v2024.3.18: + identifier: frontend-rule-config + name: Frontend Rule + parent: config-ingress + weight: 105 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# Frontend Rules + +Frontend rules specify a set of rules that are applied to HAProxy frontend configuration. +The set of keywords are from here https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#4.1. +Only frontend sections can be applied here. **It is up to user to provide valid sets of rules**. +This allows acls or other options in frontend sections in HAProxy config. Frontend rules will be mapped to `spec.rules` according to HAProxy port. + + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: default +spec: + frontendRules: + - port: 80 # Applies all the rule in frontend section for port 80 + rules: + - timeout client 5s # Set the maximum inactivity time on the client side. + - port: 9898 # Applies all the rule in frontend section for port 9898 + rules: + - timeout client 500s # Set the maximum inactivity time on the client side. + rules: + - host: foo.bar.com + http: + paths: + - backend: + service: + name: s1 + port: + number: 80 + - host: bar.foo.com + http: + paths: + - backend: + service: + name: s2 + port: + number: 80 + - host: tcp.bar.com + tcp: + port: 9898 + backend: + service: + name: tcp-service + port: + number: 50077 +``` + +This example ingress shows how to configure frontend rules in ingress resource. All the frontend rules for port 80 +will be applied to all the backends which listens to port 80. + + +## Example: Whitelist IP Addresses using Frontend Rules +This example demonstrates How to whitelist some IP addresses for a backend using frontend rule. + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: default + annotations: + ingress.appscode.com/keep-source-ip: "true" +spec: + frontendRules: + - port: 80 + rules: + # you can use IP addresses but also networks in the src acl. Both 192.168.20.0/24 and 192.168.10.3 work. + - acl network_allowed src 128.196.0.5 128.196.0.5 + - block if !network_allowed + - port: 9898 + rules: + - acl network_allowed src 20.30.40.50 8.9.9.0/27 + - tcp-request connection reject if !network_allowed + rules: + - host: foo.bar.com + http: + paths: + - backend: + service: + name: s1 + port: + number: 80 + - host: tcp.bar.com + tcp: + port: 9898 + backend: + service: + name: tcp-service + port: + number: 50077 +``` + +## Example: ACL from file + +This example demonstrates how to use additional files with frontend rules. First create a configmap containing whitelisted IPs: + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: whitelist-config + namespace: default +data: + whitelist.lst: 192.168.1.1/32 192.168.2.1/32 192.168.0.1/24 +``` + +Then mount this configmap using `spec.configVolumes` and specify the file path using frontend rules. + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: default + annotations: + ingress.appscode.com/keep-source-ip: "true" +spec: + configVolumes: + - name: whitelist-vol + configMap: + name: whitelist-config + mountPath: /etc/haproxy + frontendRules: + - port: 80 + rules: + - acl network_allowed src -f /etc/haproxy/whitelist.lst + - block if !network_allowed + rules: + - host: foo.bar.com + http: + paths: + - backend: + service: + name: s1 + port: + number: 80 +``` + +See [here](/docs/v2024.3.18/guides/ingress/configuration/config-volumes) for complete example of `configVolumes`. + +## FAQ + +### Why does not IP whitelisting work in LoadBalancer type Ingress in AWS? + +From [HAProxy official documentation](https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#5.1-accept-proxy): + + ``` +The PROXY protocol dictates the layer 3/4 addresses of the incoming connection +to be used everywhere an address is used, with the only exception of +"tcp-request connection" rules which will only see the real connection address. +``` + +The issue is that `keep-source-ip: true` annotation will enable `accept-proxy` option in HAProxy. But HAProxy does not use the IP received via PROXY protocol with `tcp-request connection reject`. Instead HAProxy uses the real IP it detected (which is the IP address of ELB in this case). This is actually an important security feature. Otherwise, any one can open a TCP connection and spoof their IP using the PROXY protocol header and by pass the whitelist. This works with HTTP on the backend rules, because in HTTP mode, HAProxy checks the header and by using `accept-proxy`, we have told HAProxy to trust the header in PROXY protocol. So, for TCP connections that are behind ELB, you need to reject connection at ELB layer using `spec.loadBalancerSourceRanges` in Ingress. If you were running a bare-metal cluster, where traffic directly hits HAProxy, `tcp-request connection reject` will behave as expected. diff --git a/content/docs/v2024.3.18/guides/ingress/configuration/hard-stop-after.md b/content/docs/v2024.3.18/guides/ingress/configuration/hard-stop-after.md new file mode 100644 index 000000000..db8870851 --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/configuration/hard-stop-after.md @@ -0,0 +1,106 @@ +--- +title: Hard Stop After | Kubernetes Ingress +menu: + docs_v2024.3.18: + identifier: hard-stop-after + name: Hard Stop After + parent: config-ingress + weight: 10 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# Hard Stop After + +[ingress.appscode.com/hard-stop-after] annotation defines the maximum duration an old haproxy configuration process may exist after configuration reload (e.g. any change in your ingress or backend service or deployment that invokes haproxy configuration change). Note that, this old configuration won't accept any new requests. It only holds importance if there are existing connections that haven't finished serving. If not mentioned, it will have 30s as default value. [Read More](https://cbonte.github.io/haproxy-dconv/1.9/configuration.html#hard-stop-after) + +Note that, if you change your backend pod's `terminationGracePeriodSeconds` (default value 30s) to allow graceful shutdown and finish serving current requests for more than 30s, then you will have to change this value accordingly (to allow remaining connections to route via haproxy process). + +Ingress Example: + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: default + annotations: + ingress.appscode.com/hard-stop-after: 60s +spec: + rules: + - host: voyager.appscode.test + http: + paths: + - path: /foo + backend: + service: + name: test-server + port: + number: 80 +``` + +Generated haproxy.cfg: + +```bash +# HAProxy configuration generated by https://github.com/appscode/voyager +# DO NOT EDIT! +global + daemon + stats socket /tmp/haproxy + server-state-file global + server-state-base /var/state/haproxy/ + # log using a syslog socket + log /dev/log local0 info + log /dev/log local0 notice + tune.ssl.default-dh-param 2048 + ssl-default-bind-ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK + hard-stop-after 60s +defaults + log global + # https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#4.2-option%20abortonclose + # https://github.com/voyagermesh/voyager/pull/403 + option dontlognull + option http-server-close + # Timeout values + timeout client 50s + timeout client-fin 50s + timeout connect 5s + timeout server 50s + timeout tunnel 50s + # Configure error files + # default traffic mode is http + # mode is overwritten in case of tcp services + mode http +frontend http-0_0_0_0-80 + bind *:80 + mode http + option httplog + option forwardfor + acl is_proxy_https hdr(X-Forwarded-Proto) https + acl acl_voyager.appscode.test hdr(host) -i voyager.appscode.test + acl acl_voyager.appscode.test hdr(host) -i voyager.appscode.test:80 + acl acl_voyager.appscode.test:foo path_beg /foo + use_backend test-server.default:80 if acl_voyager.appscode.test acl_voyager.appscode.test:foo +backend test-server.default:80 + server pod-test-server-68ddc845cd-x7dtv 172.17.0.4:8080 +``` + +## Time Format + +These timeout values are generally expressed in milliseconds (unless explicitly stated +otherwise) but may be expressed in any other unit by suffixing the unit to the +numeric value. Supported units are : + +- us : microseconds. 1 microsecond = 1/1000000 second +- ms : milliseconds. 1 millisecond = 1/1000 second. This is the default. +- s : seconds. 1s = 1000ms +- m : minutes. 1m = 60s = 60000ms +- h : hours. 1h = 60m = 3600s = 3600000ms +- d : days. 1d = 24h = 1440m = 86400s = 86400000ms diff --git a/content/docs/v2024.3.18/guides/ingress/configuration/health-check.md b/content/docs/v2024.3.18/guides/ingress/configuration/health-check.md new file mode 100644 index 000000000..846a0d60f --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/configuration/health-check.md @@ -0,0 +1,123 @@ +--- +title: Backend Health Check | Kubernetes Ingress +menu: + docs_v2024.3.18: + identifier: health-check + name: Backend Health Check + parent: config-ingress + weight: 100 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# Server Health Check + +You can enable [haproxy-health-checks](https://www.haproxy.com/documentation/aloha/7-0/traffic-management/lb-layer7/health-checks/) for a specific backend server by applying `ingress.appscode.com/check` and `ingress.appscode.com/check-port` annotations to the corresponding service. You can also configure health-check behavior using backend rules. + +## Example + +First deploy and expose a test server: + +```yaml +$ kubectl apply -f test-server.yaml + +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + run: test-server + name: test-server + namespace: default +spec: + selector: + matchLabels: + run: test-server + template: + metadata: + labels: + run: test-server + spec: + containers: + - image: appscode/test-server:2.2 + name: test-server +--- +apiVersion: v1 +kind: Service +metadata: + labels: + run: test-server + name: test-server + namespace: default +spec: + ports: + - port: 8080 + targetPort: 8080 + name: web + - port: 9090 + targetPort: 9090 + name: health + selector: + run: test-server +``` + +Here, port 8080 will serve client's request and port 9090 will be used for health checks. + +Then deploy the ingress: + +```yaml +$ kubectl apply test-ingress.yaml + +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: default +spec: + rules: + - http: + paths: + - path: /app + backend: + service: + name: test-server + port: + number: 8080 +``` + +Now we need to annotate the backend service to enable health check for that backend. + +```bash +$ kubectl annotate svc test-server ingress.appscode.com/check="true" +$ kubectl annotate svc test-server ingress.appscode.com/check-port="9090" +``` + +You can also specify the health-check behaviour using backend rules. For example: + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: default +spec: + rules: + - http: + paths: + - path: /app + backend: + service: + name: test-server + port: + number: 8080 + backendRules: + - 'option httpchk GET /testpath/ok' + - 'http-check expect rstring (testpath/ok)' +``` + diff --git a/content/docs/v2024.3.18/guides/ingress/configuration/http-2.md b/content/docs/v2024.3.18/guides/ingress/configuration/http-2.md new file mode 100644 index 000000000..90b64763f --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/configuration/http-2.md @@ -0,0 +1,387 @@ +--- +title: Configure HTTP/2 and GRPC | Kubernetes Ingress +menu: + docs_v2024.3.18: + identifier: enable-http-2 + name: Configure HTTP/2 and GRPC + parent: config-ingress + weight: 10 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# Configure HTTP/2 and GRPC + +You can configure HTTP/2 by configuring `proto` or, `alpn` under `rules.http` section (for frontend) or, `backend` section (for specific backend). If you want to use only `HTTP/2.0`, then you can specify it using `proto: h2`. However, if you like to use both `HTTP/2.0` and `HTTP/1.1` in a preferred order, then you need to specify the order using `ALPN`. + +Please note the followings: +- TLS needed to be configured for using `ALPN`. +- A single rule/backend can't use both `ALPN` and `proto`. +- Multiple rules pointing the same frontend can't use different `ALPN` or, `proto` configurations. + +## Example: gRPC Without TLS + +First create demo namespace for this example. + +``` +$ kubectl create namespace demo +namespace/demo created +``` + +### Deploy gRPC Test Server + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + run: grpc-server + name: grpc-server + namespace: demo +spec: + selector: + matchLabels: + run: grpc-server + template: + metadata: + labels: + run: grpc-server + spec: + containers: + - image: appscode/hello-grpc:0.1.0 + args: + - run + - --v=3 + name: grpc-server + imagePullPolicy: Always + ports: + - containerPort: 8080 +--- +apiVersion: v1 +kind: Service +metadata: + labels: + run: grpc-server + name: grpc-server + namespace: demo +spec: + ports: + - port: 3000 + targetPort: 8080 + name: h2c + selector: + run: grpc-server +``` + +### Create Ingress + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: demo +spec: + rules: + - host: "*" + http: + port: 3001 + proto: h2 + paths: + - path: / + backend: + service: + name: grpc-server + port: + number: 3000 + proto: h2 +``` + +### Generated haproxy.cfg + +```ini +# HAProxy configuration generated by https://github.com/appscode/voyager +# DO NOT EDIT! +global + daemon + stats socket /var/run/haproxy.sock level admin expose-fd listeners + server-state-file global + server-state-base /var/state/haproxy/ + # log using a syslog socket + log /dev/log local0 info + tune.ssl.default-dh-param 2048 + ssl-default-bind-ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK + lua-load /etc/auth-request.lua + hard-stop-after 30s +defaults + log global + # https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#4.2-option%20abortonclose + # https://github.com/voyagermesh/voyager/pull/403 + option dontlognull + option http-server-close + option http-use-htx + option logasap + # Timeout values + timeout client 50s + timeout client-fin 50s + timeout connect 5s + timeout server 50s + timeout tunnel 50s + # Configure error files + # default traffic mode is http + # mode is overwritten in case of tcp services + mode http +frontend http-0_0_0_0-3001 + bind *:3001 proto h2 + mode http + option httplog + option forwardfor + acl is_proxy_https hdr(X-Forwarded-Proto) https + acl is_proxy_https ssl_fc + http-request set-var(req.scheme) str(https) if is_proxy_https + http-request set-var(req.scheme) str(http) if ! is_proxy_https + acl acl_: path_beg / + use_backend grpc-server.demo:3000 if acl_: +backend grpc-server.demo:3000 + server pod-grpc-server-6c7f686bbb-jhngb 172.17.0.6:8080 proto h2 +``` + +### Check Response + +```bash +$ minikube service --url voyager-test-ingress -n demo +http://192.168.99.100:30652 +``` + +Run gRPC client using docker. + +``` +$ docker run -it appscode/hello-grpc:0.1.0 client --address=192.168.99.100:30652 --name=Voyager +2019/02/05 08:01:18 192.168.99.100:30652 +2019/02/05 08:01:18 intro:"hello, Voyager!" +``` + +### Cleanup + +``` +$ kubectl delete ns demo +namespace "demo" deleted +``` + +## Example: gRPC With TLS + +First create demo namespace for this example. + +``` +$ kubectl create namespace demo +namespace/demo created +``` + +### Create Secrets + +Generate certs and create secret for backend server. Here we are using [onessl](https://github.com/kubepack/onessl). You can use openssl or any other tools to generate the certificates. + +``` +$ mkdir server-certs; cd server-certs +$ onessl create ca-cert +$ onessl create server-cert --domains ssl.appscode.test --ips 192.168.99.100,127.0.0.1 +$ cat {server.crt,ca.crt} > bundle.crt +$ kubectl create secret tls server-secret -n demo --cert=bundle.crt --key=server.key +``` + +Generate certs and create secret for haproxy: + +``` +$ mkdir haproxy-certs; cd haproxy-certs +$ onessl create ca-cert +$ onessl create server-cert --domains ssl.appscode.test --ips 192.168.99.100,127.0.0.1 +$ cat {server.crt,ca.crt} > bundle.crt +$ kubectl create secret tls haproxy-secret -n demo --cert=bundle.crt --key=server.key +``` + +### Deploy gRPC Test Server + +Deploy the gRPC server and mount the `server-secret`. + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + run: grpc-server + name: grpc-server + namespace: demo +spec: + selector: + matchLabels: + run: grpc-server + template: + metadata: + labels: + run: grpc-server + spec: + volumes: + - name: secret-vol + secret: + secretName: server-secret + containers: + - image: appscode/hello-grpc:0.1.0 + args: + - run + - --tls-cert-file=/etc/certs/tls.crt + - --tls-private-key-file=/etc/certs/tls.key + - --v=3 + name: grpc-server + imagePullPolicy: Always + ports: + - containerPort: 8443 + volumeMounts: + - name: secret-vol + mountPath: "/etc/certs" + readOnly: true +--- +apiVersion: v1 +kind: Service +metadata: + labels: + run: grpc-server + name: grpc-server + namespace: demo + annotations: + ingress.appscode.com/backend-tls: ssl ca-file /tmp/certs/tls.crt +spec: + ports: + - port: 3000 + targetPort: 8443 + name: h2 + selector: + run: grpc-server +``` + +Here, `ingress.appscode.com/backend-tls` will be used by voyager to configure backend TLS. + +### Create Ingress + +Create ingress and specify the `spec.tls` and `spec.configVolumes`. + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: demo +spec: + tls: + - secretName: haproxy-secret + hosts: + - "*" + configVolumes: + - name: server-certs-vol + secret: + secretName: server-secret + mountPath: /tmp/certs + rules: + - host: "*" + http: + port: 3001 + alpn: + - h2 + - http/1.1 + paths: + - path: / + backend: + service: + name: grpc-server + port: + number: 3000 + alpn: + - h2 + - http/1.1 +``` + +### Generated haproxy.cfg + +```ini +# HAProxy configuration generated by https://github.com/appscode/voyager +# DO NOT EDIT! +global + daemon + stats socket /var/run/haproxy.sock level admin expose-fd listeners + server-state-file global + server-state-base /var/state/haproxy/ + # log using a syslog socket + log /dev/log local0 info + tune.ssl.default-dh-param 2048 + ssl-default-bind-ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK + lua-load /etc/auth-request.lua + hard-stop-after 30s +defaults + log global + # https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#4.2-option%20abortonclose + # https://github.com/voyagermesh/voyager/pull/403 + option dontlognull + option http-server-close + option http-use-htx + option logasap + # Timeout values + timeout client 50s + timeout client-fin 50s + timeout connect 5s + timeout server 50s + timeout tunnel 50s + # Configure error files + # default traffic mode is http + # mode is overwritten in case of tcp services + mode http +frontend http-0_0_0_0-3001 + bind *:3001 ssl no-sslv3 no-tlsv10 no-tls-tickets crt /etc/ssl/private/haproxy/tls/ alpn h2,http/1.1 + # Mark all cookies as secure + rsprep ^Set-Cookie:\ (.*) Set-Cookie:\ \1;\ Secure + # Add the HSTS header with a 6 month default max-age + http-response set-header Strict-Transport-Security max-age=15768000 + mode http + option httplog + option forwardfor + acl is_proxy_https hdr(X-Forwarded-Proto) https + acl is_proxy_https ssl_fc + http-request set-var(req.scheme) str(https) if is_proxy_https + http-request set-var(req.scheme) str(http) if ! is_proxy_https + acl acl_: path_beg / + use_backend grpc-server.demo:3000 if acl_: +backend grpc-server.demo:3000 + server pod-grpc-server-7578bf9696-rbq49 172.17.0.7:8443 ssl ca-file /tmp/certs/server.crt alpn h2,http/1.1 +``` + +### Check Response + +```bash +$ minikube service --url voyager-test-ingress -n demo +http://192.168.99.100:30446 +``` + +Run gRPC client using docker and specify the haproxy certs. + +``` +$ docker run -v $(pwd)/haproxy-certs:/tmp/certs -it appscode/hello-grpc:0.1.0 client --address=192.168.99.100:30446 --crt=/tmp/certs/bundle.crt --name=Voyager +2019/02/05 12:11:13 192.168.99.100:30446 +2019/02/05 12:11:13 intro:"hello, Voyager!" +``` + +### Cleanup + +``` +$ kubectl delete ns demo +namespace "demo" deleted +``` + +## Reference + +- https://www.haproxy.com/blog/haproxy-1-9-2-adds-grpc-support + diff --git a/content/docs/v2024.3.18/guides/ingress/configuration/keep-source-ip.md b/content/docs/v2024.3.18/guides/ingress/configuration/keep-source-ip.md new file mode 100644 index 000000000..aac648d5c --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/configuration/keep-source-ip.md @@ -0,0 +1,63 @@ +--- +title: Configure Ingress Keep Source IP +menu: + docs_v2024.3.18: + identifier: keep-source-ip-configuration + name: Keep Source IP + parent: config-ingress + weight: 10 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# Keep Source IP + +You can preserve client source IP by setting annotation `ingress.appscode.com/keep-source-ip` to `true`. + +For `LoadBalancer` type ingresses, the actual configuration generated depends on the underlying cloud provider. + +- `GCE, GKE, Azure, ACS`: Sets `ExternalTrafficPolicy` to `Local` for services used to expose HAProxy. See [here](https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/#preserving-the-client-source-ip). +- `AWS`: Enables [accept-proxy](accept-proxy.md) that enforces the use of the PROXY protocol over any connection accepted by any of the sockets declared on the same line. + +For `NodePort` type ingresses, it sets `ExternalTrafficPolicy` to `Local` regardless the cloud provider. + +## Ingress Example + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: default + annotations: + ingress.appscode.com/keep-source-ip: "true" + ingress.appscode.com/health-check-nodeport: "32312" +spec: + rules: + - host: voyager.appscode.test + http: + paths: + - path: /foo + backend: + service: + name: test-server + port: + number: 80 +``` + +Here `health-check-nodeport` annotation specifies `HealthCheckNodePort` field for services used to expose HAProxy. If not specified, it will be auto-assigned by kubernetes. Note that, it is only effective when `keep-source-ip` is `true` and ingress type is `LoadBalancer`. + +--- + +**NB:** Please note that, Kubernetes support for AWS NLB is limited as of 1.11.x release. Check [kubernetes/features#423](https://github.com/kubernetes/features/issues/423#issuecomment-407512634) for NLB support status. + +`service.beta.kubernetes.io/aws-load-balancer-proxy-protocol: "*"` annotation is not supported for AWS NLB as of 1.11.x release. At this time proxy protocol attribute needs to be set on the NLB target group either manually from the aws console or from [aws cli](https://docs.aws.amazon.com/cli/latest/reference/elbv2/modify-target-group-attributes.html). + +--- \ No newline at end of file diff --git a/content/docs/v2024.3.18/guides/ingress/configuration/loadbalancer-ip.md b/content/docs/v2024.3.18/guides/ingress/configuration/loadbalancer-ip.md new file mode 100644 index 000000000..a64d952ef --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/configuration/loadbalancer-ip.md @@ -0,0 +1,47 @@ +--- +title: Configure Ingress Loadbalancer IP +menu: + docs_v2024.3.18: + identifier: loadbalancer-ip-configuration + name: Loadbalancer IP + parent: config-ingress + weight: 10 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# LoadBalancer IP + +For `LoadBalancer` type ingresses, you can specify `LoadBalancerIP` of HAProxy services using `ingress.appscode.com/load-balancer-ip` annotation. + +Note that, this feature is supported for cloud providers GCE, GKE, Azure, ACS and Openstack. + +## Ingress Example + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: default + annotations: + ingress.appscode.com/load-balancer-ip: "78.11.24.19" +spec: + rules: + - host: voyager.appscode.test + http: + paths: + - path: /foo + backend: + service: + name: test-server + port: + number: 80 +``` \ No newline at end of file diff --git a/content/docs/v2024.3.18/guides/ingress/configuration/loadbalancing-algorithm.md b/content/docs/v2024.3.18/guides/ingress/configuration/loadbalancing-algorithm.md new file mode 100644 index 000000000..54630f665 --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/configuration/loadbalancing-algorithm.md @@ -0,0 +1,118 @@ +--- +title: Load Balancing Algorithm | Kubernetes Ingress +menu: + docs_v2024.3.18: + identifier: load-balancing-algorithm + name: Load Balancing Algorithm + parent: config-ingress + weight: 10 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# Configure Load Balancing Algorithm + +You can configure a backend to use a specific [load balancing algorithm](https://cbonte.github.io/haproxy-dconv/1.9/configuration.html#balance) using `backend.loadBalanceOn`. You can specify any HAProxy supported options along with arguments. + +Ingress Example: + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: demo +spec: + defaultBackend: + service: + name: test-server + port: + number: 80 + loadBalanceOn: roundrobin # configure for default backend + rules: + - http: + port: 8989 + paths: + - backend: + service: + name: test-server + port: + number: 8989 + loadBalanceOn: static-rr # configure for http backend + - tcp: + port: 4545 + backend: + service: + name: test-server + port: + number: 4545 + loadBalanceOn: leastconn # configure for tcp backend +``` + +Generated haproxy.cfg: + +```ini +# HAProxy configuration generated by https://github.com/appscode/voyager +# DO NOT EDIT! +global + daemon + stats socket /var/run/haproxy.sock level admin expose-fd listeners + server-state-file global + server-state-base /var/state/haproxy/ + # log using a syslog socket + log /dev/log local0 info + tune.ssl.default-dh-param 2048 + ssl-default-bind-ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK + lua-load /etc/auth-request.lua + hard-stop-after 30s +defaults + log global + # https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#4.2-option%20abortonclose + # https://github.com/voyagermesh/voyager/pull/403 + option dontlognull + option http-server-close + # Timeout values + timeout client 50s + timeout client-fin 50s + timeout connect 5s + timeout server 50s + timeout tunnel 50s + # Configure error files + # default traffic mode is http + # mode is overwritten in case of tcp services + mode http +frontend http-0_0_0_0-8989 + bind *:8989 + mode http + option httplog + option forwardfor + acl is_proxy_https hdr(X-Forwarded-Proto) https + acl is_proxy_https ssl_fc + http-request set-var(req.scheme) str(https) if is_proxy_https + http-request set-var(req.scheme) str(http) if ! is_proxy_https + use_backend test-server.demo:8989 + default_backend default-backend +backend test-server.demo:8989 + balance static-rr + server pod-test-server-47lck 172.17.0.5:8989 +frontend tcp-0_0_0_0-4545 + bind *:4545 + mode tcp + default_backend test-server.demo:4545 +backend test-server.demo:4545 + mode tcp + balance leastconn + server pod-test-server-47lck 172.17.0.5:4545 +backend default-backend + balance roundrobin + server pod-test-server-47lck 172.17.0.5:8080 +``` + +Instead of configuring backends you can also specify load balancing algorithm in `defaults` sections. For that, you need to add `balance ` in `defaults.cfg` using custom template. See [here](/docs/v2024.3.18/guides/ingress/configuration/custom-templates) for detailed example on custom template. diff --git a/content/docs/v2024.3.18/guides/ingress/configuration/max-connections.md b/content/docs/v2024.3.18/guides/ingress/configuration/max-connections.md new file mode 100644 index 000000000..8a05b2e25 --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/configuration/max-connections.md @@ -0,0 +1,166 @@ +--- +title: Configure Ingress Max Connections +menu: + docs_v2024.3.18: + identifier: max-connections-configuration + name: Max Connections + parent: config-ingress + weight: 10 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# Maximum Connections + +You can specify the maximum number of concurrent connections through the `ingress.appscode.com/max-connections` annotation. When applied to ingress, this rule will be applied globally for all backends. To apply for a specific backend, you need to apply the annotation to associated pod. + +## Ingress Example + +First create a test-server and expose it via service: + +```bash +$ kubectl run test-server --image=gcr.io/google_containers/echoserver:1.8 +deployment "test-server" created + +$ kubectl expose deployment test-server --type=LoadBalancer --port=80 --target-port=8080 +service "test-server" exposed +``` + +Then create the ingress: + +```yaml +$ kubectl apply -f test-ingress.yaml + +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: default + annotations: + ingress.appscode.com/max-connections: "1" +spec: + rules: + - host: voyager.appscode.test + http: + paths: + - path: /foo + backend: + service: + name: test-server + port: + number: 80 +``` + +This will add `maxconn 1` in global section of generated haproxy.cfg. + +Generated haproxy.cfg: + +```ini +# HAProxy configuration generated by https://github.com/appscode/voyager +# DO NOT EDIT! +global + daemon + stats socket /tmp/haproxy + server-state-file global + server-state-base /var/state/haproxy/ + maxconn 1 + # log using a syslog socket + log /dev/log local0 info + log /dev/log local0 notice + tune.ssl.default-dh-param 2048 + ssl-default-bind-ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK + hard-stop-after 30s +defaults + log global + # https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#4.2-option%20abortonclose + # https://github.com/voyagermesh/voyager/pull/403 + option dontlognull + option http-server-close + # Timeout values + timeout client 50s + timeout client-fin 50s + timeout connect 5s + timeout server 50s + timeout tunnel 50s + # Configure error files + # default traffic mode is http + # mode is overwritten in case of tcp services + mode http +frontend http-0_0_0_0-80 + bind *:80 + mode http + option httplog + option forwardfor + acl is_proxy_https hdr(X-Forwarded-Proto) https + acl acl_voyager.appscode.test hdr(host) -i voyager.appscode.test + acl acl_voyager.appscode.test hdr(host) -i voyager.appscode.test:80 + acl acl_voyager.appscode.test:foo path_beg /foo + use_backend test-server.default:80 if acl_voyager.appscode.test acl_voyager.appscode.test:foo +backend test-server.default:80 + server pod-test-server-68ddc845cd-x7dtv 172.17.0.4:80 +``` + +## Pod Annotation + +To apply it for specific backend let's patch the deployment and add the annotation to pod template: + +```bash +$ kubectl patch deployment test-server -p '{"spec":{"template":{"metadata":{"annotations":{"ingress.appscode.com/max-connections": "3"}}}}}' +deployment "test-server" patched +``` + +This will add `maxconn 3` in server section of generated haproxy.cfg. + +Generated haproxy.cfg: + +```ini +# HAProxy configuration generated by https://github.com/appscode/voyager +# DO NOT EDIT! +global + daemon + stats socket /tmp/haproxy + server-state-file global + server-state-base /var/state/haproxy/ + maxconn 1 + # log using a syslog socket + log /dev/log local0 info + log /dev/log local0 notice + tune.ssl.default-dh-param 2048 + ssl-default-bind-ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK + hard-stop-after 30s +defaults + log global + # https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#4.2-option%20abortonclose + # https://github.com/voyagermesh/voyager/pull/403 + option dontlognull + option http-server-close + # Timeout values + timeout client 50s + timeout client-fin 50s + timeout connect 5s + timeout server 50s + timeout tunnel 50s + # Configure error files + # default traffic mode is http + # mode is overwritten in case of tcp services + mode http +frontend http-0_0_0_0-80 + bind *:80 + mode http + option httplog + option forwardfor + acl is_proxy_https hdr(X-Forwarded-Proto) https + acl acl_voyager.appscode.test hdr(host) -i voyager.appscode.test + acl acl_voyager.appscode.test hdr(host) -i voyager.appscode.test:80 + acl acl_voyager.appscode.test:foo path_beg /foo + use_backend test-server.default:80 if acl_voyager.appscode.test acl_voyager.appscode.test:foo +backend test-server.default:80 + server pod-test-server-77b558b98-8kc2d 172.17.0.4:80 maxconn 3 +``` \ No newline at end of file diff --git a/content/docs/v2024.3.18/guides/ingress/configuration/node-port.md b/content/docs/v2024.3.18/guides/ingress/configuration/node-port.md new file mode 100644 index 000000000..0b0145c95 --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/configuration/node-port.md @@ -0,0 +1,208 @@ +--- +title: Specify Ingress NodePort | Kubernetes Ingress +menu: + docs_v2024.3.18: + identifier: nodeport-config + name: Specify NodePort + parent: config-ingress + weight: 10 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# Specify NodePort + +If you are using a `NodePort` or `LoadBalancer` type Ingress, a `NodePort` or `LoadBalancer` type Service is used to expose HAProxy pods respectively. If no node port is specified for each HAProxy Service port, Kubernetes will randomly assign one for you. + +Since 3.2.0, you have the option to specify a NodePort for each HAProxy Service port. This allows you to guarantee that the port will not get changed, as you make changes to an Ingress object. If you specify nothing, Kubernetes will auto assign as before. + +### Ingress Example + +First create a test-server and expose it via service: + +```bash +$ kubectl run test-server --image=gcr.io/google_containers/echoserver:1.8 +deployment "test-server" created + +$ kubectl expose deployment test-server --type=LoadBalancer --port=80 --target-port=8080 +service "test-server" exposed +``` + +Then create the ingress: + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: default + annotations: + ingress.appscode.com/type: NodePort +spec: + rules: + - host: one.example.com + http: + port: 8989 + nodePort: 32666 + paths: + - path: /t1 + backend: + service: + name: test-server + port: + number: 80 + - path: /t2 + backend: + service: + name: test-server + port: + number: 80 + - host: other.example.com + http: + port: 8989 + nodePort: 32666 + paths: + - backend: + service: + name: test-server + port: + number: 80 + - host: appscode.example.com + tcp: + port: 4343 + nodePort: 32667 + backend: + service: + name: test-server + port: + number: 80 +``` + +Since `ingress.appscode.com/type: NodePort` annotation is used, this Ingress is going to expose HAProxy pods via a `NodePort` Service. This service will listen to `8989` and `4343` port for incoming HTTP connections and these port will map to specified node ports, and will pass any request coming to it to the desired backend. + +```bash +$ kubectl get pods,svc +NAME READY STATUS RESTARTS AGE +po/test-server-68ddc845cd-x7dtv 1/1 Running 0 23h +po/voyager-test-ingress-77cc5d54d-sgzkv 1/1 Running 0 18s + +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +svc/kubernetes ClusterIP 10.96.0.1 443/TCP 2d +svc/test-server LoadBalancer 10.105.13.31 80:30390/TCP 1d +svc/voyager-test-ingress NodePort 10.106.53.141 8989:32666/TCP,4343:32667/TCP 26m +``` + +```yaml +$ kubectl get svc voyager-test-ingress -o yaml + +apiVersion: v1 +kind: Service +metadata: + annotations: + ingress.appscode.com/last-applied-annotation-keys: "" + ingress.appscode.com/origin-api-schema: voyager.appscode.com/v1 + ingress.appscode.com/origin-name: test-ingress + creationTimestamp: 2018-02-15T03:51:06Z + name: voyager-test-ingress + namespace: default + ownerReferences: + - apiVersion: voyager.appscode.com/v1 + blockOwnerDeletion: true + kind: Ingress + name: test-ingress + uid: 73203752-1203-11e8-b2d5-080027eaa7b2 + resourceVersion: "65769" + selfLink: /api/v1/namespaces/default/services/voyager-test-ingress + uid: 732a5322-1203-11e8-b2d5-080027eaa7b2 +spec: + clusterIP: 10.106.53.141 + externalTrafficPolicy: Cluster + ports: + - name: tcp-8989 + nodePort: 32666 + port: 8989 + protocol: TCP + targetPort: 8989 + - name: tcp-4343 + nodePort: 32667 + port: 4343 + protocol: TCP + targetPort: 4343 + selector: + origin: voyager + origin-api-group: voyager.appscode.com + origin-name: test-ingress + sessionAffinity: None + type: NodePort +status: + loadBalancer: {} +``` + +Now, if you check the HAProxy configuration generated by Voyager, you should see something like below: + +```ini +# HAProxy configuration generated by https://github.com/appscode/voyager +# DO NOT EDIT! +global + daemon + stats socket /tmp/haproxy + server-state-file global + server-state-base /var/state/haproxy/ + # log using a syslog socket + log /dev/log local0 info + log /dev/log local0 notice + tune.ssl.default-dh-param 2048 + ssl-default-bind-ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK + hard-stop-after 30s +defaults + log global + # https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#4.2-option%20abortonclose + # https://github.com/voyagermesh/voyager/pull/403 + option dontlognull + option http-server-close + # Timeout values + timeout client 50s + timeout client-fin 50s + timeout connect 5s + timeout server 50s + timeout tunnel 50s + # Configure error files + # default traffic mode is http + # mode is overwritten in case of tcp services + mode http +frontend http-0_0_0_0-8989 + bind *:8989 + mode http + option httplog + option forwardfor + acl is_proxy_https hdr(X-Forwarded-Proto) https + acl acl_other.example.com hdr(host) -i other.example.com:8989 + use_backend test-server.default:80-2bdf8f33305898e39d66486c50d39fc1 if acl_other.example.com + acl acl_one.example.com hdr(host) -i one.example.com:8989 + acl acl_one.example.com:t2 path_beg /t2 + use_backend test-server.default:80-64e63a31b2e805238363fc7982c38f12 if acl_one.example.com acl_one.example.com:t2 + acl acl_one.example.com:t1 path_beg /t1 + use_backend test-server.default:80-6c5cadcbfcb85a324f0cf5c4654dd952 if acl_one.example.com acl_one.example.com:t1 +backend test-server.default:80-2bdf8f33305898e39d66486c50d39fc1 + server pod-test-server-68ddc845cd-x7dtv 172.17.0.4:8080 +backend test-server.default:80-64e63a31b2e805238363fc7982c38f12 + server pod-test-server-68ddc845cd-x7dtv 172.17.0.4:8080 +backend test-server.default:80-6c5cadcbfcb85a324f0cf5c4654dd952 + server pod-test-server-68ddc845cd-x7dtv 172.17.0.4:8080 +frontend tcp-0_0_0_0-4343 + bind *:4343 + mode tcp + default_backend test-server.default:80-b700282ee9f2823f5b4ad3452658a791 +backend test-server.default:80-b700282ee9f2823f5b4ad3452658a791 + mode tcp + server pod-test-server-68ddc845cd-x7dtv 172.17.0.4:8080 +``` + +Port 8989 has 2 separate hosts `one.example.com` and `other.example.com`. `one.example.com` has 2 paths `/t1` and `/t2`. Since they all are exposed via the same HTTP port, they must use the same NodePort. diff --git a/content/docs/v2024.3.18/guides/ingress/configuration/pod-annotations.md b/content/docs/v2024.3.18/guides/ingress/configuration/pod-annotations.md new file mode 100644 index 000000000..b64e133e6 --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/configuration/pod-annotations.md @@ -0,0 +1,62 @@ +--- +title: Configure Ingress Pod Annotations +menu: + docs_v2024.3.18: + identifier: pod-annotations-configuration + name: Pod Annotations + parent: config-ingress + weight: 10 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# Pod Annotations + +You can specify annotations applied to HAProxy pods through ingress annotation `ingress.appscode.com/annotations-pod`. You have to provide it as a json formatted string to string map. + +## Ingress Example + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: default + annotations: + ingress.appscode.com/annotations-pod: '{"foo": "bar", "bar":"foo"}' +spec: + rules: + - host: voyager.appscode.test + http: + paths: + - path: /foo + backend: + service: + name: test-server + port: + number: 80 +``` + +It will add following annotations to HAProxy pods: + +```yaml +annotations: + bar: foo + foo: bar + ingress.appscode.com/last-applied-annotation-keys: bar,foo +``` + +```bash +$ kubectl get pods voyager-test-ingress-6dbdbdf4f7-9f6w7 -o=jsonpath='{.metadata.annotations}' | tr " " "\n" + +map[foo:bar +bar:foo +ingress.appscode.com/last-applied-annotation-keys:foo,bar] +``` \ No newline at end of file diff --git a/content/docs/v2024.3.18/guides/ingress/configuration/rate-limit.md b/content/docs/v2024.3.18/guides/ingress/configuration/rate-limit.md new file mode 100644 index 000000000..5c57a58f8 --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/configuration/rate-limit.md @@ -0,0 +1,109 @@ +--- +title: Configure Ingress Rate Limit +menu: + docs_v2024.3.18: + identifier: rate-limit-configuration + name: Rate Limit + parent: config-ingress + weight: 10 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# Rate limiting + +You can define a limit on the connections that can be opened by a single client IP address through annotations. This can be used to mitigate DDoS Attacks. + +- `ingress.appscode.com/limit-connection`: number of concurrent connections allowed from a single IP address. + +- `ingress.appscode.com/limit-rps`: number of connections that may be accepted from a given IP each second. + +- `ingress.appscode.com/limit-rpm`: number of connections that may be accepted from a given IP each minute. + +These rules will be applied globally to all frontends. Note that, `limit-rpm` will takes precedence if you specify both `limit-rpm` and `limit-rps`. + +## Ingress Example + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: default + annotations: + ingress.appscode.com/limit-connection: "3" + ingress.appscode.com/limit-rpm: "15" +spec: + rules: + - host: voyager.appscode.test + http: + paths: + - path: /foo + backend: + service: + name: test-server + port: + number: 80 +``` + +Generated haproxy.cfg: + +```ini +# HAProxy configuration generated by https://github.com/appscode/voyager +# DO NOT EDIT! +global + daemon + stats socket /tmp/haproxy + server-state-file global + server-state-base /var/state/haproxy/ + # log using a syslog socket + log /dev/log local0 info + log /dev/log local0 notice + tune.ssl.default-dh-param 2048 + ssl-default-bind-ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK + hard-stop-after 30s +defaults + log global + # https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#4.2-option%20abortonclose + # https://github.com/voyagermesh/voyager/pull/403 + option dontlognull + option http-server-close + # Timeout values + timeout client 50s + timeout client-fin 50s + timeout connect 5s + timeout server 50s + timeout tunnel 50s + # Configure error files + # default traffic mode is http + # mode is overwritten in case of tcp services + mode http +frontend http-0_0_0_0-80 + bind *:80 + mode http + stick-table type ip size 100k expire 2m store conn_cur + acl __mark_as_overload_conn__ sc1_conn_cur gt 3 + tcp-request content track-sc1 src + http-request deny if __mark_as_overload_conn__ + tcp-request inspect-delay 5s + stick-table type ip size 1m expire 5m store conn_rate(60s) + acl __mark_as_overload__ sc1_conn_rate gt 15 + tcp-request content track-sc1 src + http-request deny if __mark_as_overload__ + option httplog + option forwardfor + acl is_proxy_https hdr(X-Forwarded-Proto) https + acl acl_voyager.appscode.test hdr(host) -i voyager.appscode.test + acl acl_voyager.appscode.test hdr(host) -i voyager.appscode.test:80 + acl acl_voyager.appscode.test:foo path_beg /foo + use_backend test-server.default:80 if acl_voyager.appscode.test acl_voyager.appscode.test:foo +backend test-server.default:80 + server pod-test-server-68ddc845cd-6rnwn 172.17.0.4:80 +``` \ No newline at end of file diff --git a/content/docs/v2024.3.18/guides/ingress/configuration/rewrite-target.md b/content/docs/v2024.3.18/guides/ingress/configuration/rewrite-target.md new file mode 100644 index 000000000..8a01f8483 --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/configuration/rewrite-target.md @@ -0,0 +1,155 @@ +--- +title: Configure Ingress Rewrite Target +menu: + docs_v2024.3.18: + identifier: rewrite-target-configuration + name: Rewrite Target + parent: config-ingress + weight: 10 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# Rewrite Target + +In some scenarios the exposed URL in the backend service differs from the specified path in the Ingress rule. This will cause any request to return 404. In such scenarios you can set the path expected by the service using `ingress.appscode.com/rewrite-target` annotation. This will be applied globally for all paths. + +## Ingress Example + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: default + annotations: + ingress.appscode.com/rewrite-target: "/bar" +spec: + rules: + - host: voyager.appscode.test + http: + paths: + - path: /foo + backend: + service: + name: test-server + port: + number: 80 +``` + +It will add following rule to replace request path in generated haproxy.cfg: + +```ini +reqrep ^([^\ :]*)\ /foo(.*$) \1\ /bar\2 +``` + +Generated haproxy.cfg: + +```ini +# HAProxy configuration generated by https://github.com/appscode/voyager +# DO NOT EDIT! +global + daemon + stats socket /tmp/haproxy + server-state-file global + server-state-base /var/state/haproxy/ + # log using a syslog socket + log /dev/log local0 info + log /dev/log local0 notice + tune.ssl.default-dh-param 2048 + ssl-default-bind-ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK + hard-stop-after 30s +defaults + log global + # https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#4.2-option%20abortonclose + # https://github.com/voyagermesh/voyager/pull/403 + option dontlognull + option http-server-close + # Timeout values + timeout client 50s + timeout client-fin 50s + timeout connect 5s + timeout server 50s + timeout tunnel 50s + # Configure error files + # default traffic mode is http + # mode is overwritten in case of tcp services + mode http +frontend http-0_0_0_0-80 + bind *:80 + mode http + option httplog + option forwardfor + acl is_proxy_https hdr(X-Forwarded-Proto) https + acl acl_voyager.appscode.test hdr(host) -i voyager.appscode.test + acl acl_voyager.appscode.test hdr(host) -i voyager.appscode.test:80 + acl acl_voyager.appscode.test:foo path_beg /foo + use_backend test-server.default:80 if acl_voyager.appscode.test acl_voyager.appscode.test:foo +backend test-server.default:80 + reqrep ^([^\ :]*)\ /foo(.*$) \1\ /bar\2 + server pod-test-server-68ddc845cd-x5c78 172.17.0.2:8080 +``` + +Get url for ingress service: + +```bash +$ minikube service --url voyager-test-ingress +http://192.168.99.100:31228 +``` + +Send request with path `/foo`: + +```bash +$ curl -v -H 'Host: voyager.appscode.test' 192.168.99.100:31228/foo +* Trying 192.168.99.100... +* Connected to 192.168.99.100 (192.168.99.100) port 31228 (#0) +> GET /foo HTTP/1.1 +> Host: voyager.appscode.test +> User-Agent: curl/7.47.0 +> Accept: */* +> +< HTTP/1.1 200 OK +< Date: Mon, 19 Feb 2018 05:53:14 GMT +< Content-Type: text/plain +< Transfer-Encoding: chunked +< Server: echoserver +< + + +Hostname: test-server-68ddc845cd-x5c78 + +Pod Information: + -no pod information available- + +Server values: + server_version=nginx: 1.13.3 - lua: 10008 + +Request Information: + client_address=172.17.0.5 + method=GET + real path=/bar + query= + request_version=1.1 + request_uri=http://voyager.appscode.test:8080/bar + +Request Headers: + accept=*/* + connection=close + host=voyager.appscode.test + user-agent=curl/7.47.0 + x-forwarded-for=172.17.0.1 + +Request Body: + -no body in request- + +* Connection #0 to host 192.168.99.100 left intact +``` + +Here although original request is sent to path `/foo`, it is redirected to path `/bar`. \ No newline at end of file diff --git a/content/docs/v2024.3.18/guides/ingress/configuration/service-annotations.md b/content/docs/v2024.3.18/guides/ingress/configuration/service-annotations.md new file mode 100644 index 000000000..2608118c7 --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/configuration/service-annotations.md @@ -0,0 +1,64 @@ +--- +title: Configure Ingress Service Annotations +menu: + docs_v2024.3.18: + identifier: service-annotations-configuration + name: Service Annotations + parent: config-ingress + weight: 10 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# Service Annotations + +You can specify annotations applied to HAProxy services through ingress annotation `ingress.appscode.com/annotations-service`. You have to provide it as a json formatted string to string map. + +## Ingress Example + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: default + annotations: + ingress.appscode.com/annotations-service: '{"foo": "bar", "bar":"foo"}' +spec: + rules: + - host: voyager.appscode.test + http: + paths: + - path: /foo + backend: + service: + name: test-server + port: + number: 80 +``` + +It will add following annotations to HAProxy pods: + +```yaml +annotations: + bar: foo + foo: bar + ingress.appscode.com/last-applied-annotation-keys: bar,foo +``` + +```bash +$ kubectl get svc voyager-test-ingress -o=jsonpath='{.metadata.annotations}' | tr " " "\n" + +map[foo:bar +bar:foo +ingress.appscode.com/last-applied-annotation-keys:foo,bar +ingress.appscode.com/origin-api-schema:voyager.appscode.com/v1 +ingress.appscode.com/origin-name:test-ingress] +``` \ No newline at end of file diff --git a/content/docs/v2024.3.18/guides/ingress/configuration/ssl-passthrough.md b/content/docs/v2024.3.18/guides/ingress/configuration/ssl-passthrough.md new file mode 100644 index 000000000..efee58d79 --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/configuration/ssl-passthrough.md @@ -0,0 +1,107 @@ +--- +title: Configure Ingress Ssl Passthrough +menu: + docs_v2024.3.18: + identifier: ssl-passthrough-configuration + name: Ssl Passthrough + parent: config-ingress + weight: 10 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# SSL Passthrough + +The annotation `ingress.appscode.com/ssl-passthrough` allows to configure TLS termination in the backend and not in haproxy. When set to `true`, passes TLS connections directly to backend. + +If `ssl-passthrough` is used, HAProxy will use `tcp`. For more details see [here](https://www.haproxy.com/documentation/haproxy/deployment-guides/tls-infrastructure/). When `ssl-passthrough` is enabled, Voyager automatically converts your HTTP ingress rules to TCP rules. + +Please note that following features are not supported when using `ssl-passthrough`: + +- Multiple paths for HTTP rules. +- `headerRules` and `rewriteRules` for backends. +- Specifying TLS for TCP rules. So even if you define `spec.tls` for your HTTP hosts, it will be ignored. + +Voyager will not modify your existing TCP rules. Instead it will cause a validation error if TLS defined for existing TCP rules on same port. In that case, you have to either ensure TCP hosts do not match with `spec.tls` or, just set `noTLS=true` for those TCP rules. + +## Ingress Example + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: default + annotations: + ingress.appscode.com/ssl-passthrough: "true" +spec: + rules: + - host: voyager.appscode.test + http: + port: 8443 + paths: + - path: /foo + backend: + service: + name: test-server + port: + number: 443 +``` + +Generated haproxy.cfg: + +```ini +# HAProxy configuration generated by https://github.com/appscode/voyager +# DO NOT EDIT! +global + daemon + stats socket /var/run/haproxy.sock level admin expose-fd listeners + server-state-file global + server-state-base /var/state/haproxy/ + # log using a syslog socket + log /dev/log local0 info + tune.ssl.default-dh-param 2048 + ssl-default-bind-ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK + lua-load /etc/auth-request.lua + hard-stop-after 30s +defaults + log global + # https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#4.2-option%20abortonclose + # https://github.com/voyagermesh/voyager/pull/403 + option dontlognull + option http-server-close + # Timeout values + timeout client 50s + timeout client-fin 50s + timeout connect 5s + timeout server 50s + timeout tunnel 50s + # Configure error files + # default traffic mode is http + # mode is overwritten in case of tcp services + mode http +frontend tcp-0_0_0_0-8443 + bind *:8443 + mode tcp + default_backend test-server.default:443 +backend test-server.default:443 + mode tcp + server pod-test-server-777ccbbc49-g7q6t 172.17.0.4:6443 +``` + +Now check the response: + +```bash +$ minikube service --url voyager-test-ingress +http://192.168.99.100:31692 + +$ curl -k https://192.168.99.100:31692 +{"type":"http","host":"192.168.99.100:31692","serverPort":":6443","path":"/","method":"GET","headers":{"Accept":["*/*"],"User-Agent":["curl/7.47.0"]}} +``` diff --git a/content/docs/v2024.3.18/guides/ingress/configuration/ssl-redirect.md b/content/docs/v2024.3.18/guides/ingress/configuration/ssl-redirect.md new file mode 100644 index 000000000..46c085644 --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/configuration/ssl-redirect.md @@ -0,0 +1,175 @@ +--- +title: Configure Ingress Ssl Redirect +menu: + docs_v2024.3.18: + identifier: ssl-redirect-configuration + name: Ssl Redirect + parent: config-ingress + weight: 10 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# SSL Redirect + +By default voyager redirects (301) to HTTPS if TLS is enabled for that ingress. If you want to disable that behavior globally, you can use `ingress.appscode.com/ssl-redirect: "false"` annotation. + +When using SSL offloading outside of cluster (e.g. AWS ELB) it may be useful to enforce a redirect to HTTPS even when there is not TLS cert available. This can be achieved by using the `ingress.appscode.com/force-ssl-redirect: "true"` annotation. It will redirect for all port 80 HTTP paths to HTTPS. + +## Ingress Example + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: default + annotations: + ingress.appscode.com/ssl-redirect: "false" +spec: + tls: + - secretName: tls-secret + hosts: + - voyager.appscode.test + rules: + - host: voyager.appscode.test + http: + paths: + - path: /foo + backend: + service: + name: test-server + port: + number: 80 +``` + +Since TLS enabled for `voyager.appscode.test`, by default it will add `redirect scheme https` for that host in generated haproxy.cfg. But as we disabled ssl-redirect through annotation, no redirect rule generated. + +Generated haproxy.cfg: + +```ini +# HAProxy configuration generated by https://github.com/appscode/voyager +# DO NOT EDIT! +global + daemon + stats socket /tmp/haproxy + server-state-file global + server-state-base /var/state/haproxy/ + # log using a syslog socket + log /dev/log local0 info + log /dev/log local0 notice + tune.ssl.default-dh-param 2048 + ssl-default-bind-ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK + hard-stop-after 30s +defaults + log global + # https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#4.2-option%20abortonclose + # https://github.com/voyagermesh/voyager/pull/403 + option dontlognull + option http-server-close + # Timeout values + timeout client 50s + timeout client-fin 50s + timeout connect 5s + timeout server 50s + timeout tunnel 50s + # Configure error files + # default traffic mode is http + # mode is overwritten in case of tcp services + mode http +frontend http-0_0_0_0-443 + bind *:443 ssl no-sslv3 no-tlsv10 no-tls-tickets crt /etc/ssl/private/haproxy/tls/ alpn http/1.1 + # Mark all cookies as secure + rsprep ^Set-Cookie:\ (.*) Set-Cookie:\ \1;\ Secure + # Add the HSTS header with a 6 month default max-age + http-response set-header Strict-Transport-Security max-age=15768000 + mode http + option httplog + option forwardfor + acl is_proxy_https hdr(X-Forwarded-Proto) https + acl acl_voyager.appscode.test hdr(host) -i voyager.appscode.test + acl acl_voyager.appscode.test hdr(host) -i voyager.appscode.test:443 + acl acl_voyager.appscode.test:foo path_beg /foo + use_backend test-server.default:80 if acl_voyager.appscode.test acl_voyager.appscode.test:foo +backend test-server.default:80 + server pod-test-server-68ddc845cd-6rnwn 172.17.0.4:80 +``` + +### With force redirect + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: default + annotations: + ingress.appscode.com/force-ssl-redirect: "true" +spec: + rules: + - host: voyager.appscode.test + http: + paths: + - path: /foo + backend: + service: + name: test-server + port: + number: 80 +``` + +Although no TLS specified, `redirect scheme https` added for all port 80 HTTP paths as we enabled force-redirect. + +Generated haproxy.cfg: + +```ini +# HAProxy configuration generated by https://github.com/appscode/voyager +# DO NOT EDIT! +global + daemon + stats socket /tmp/haproxy + server-state-file global + server-state-base /var/state/haproxy/ + # log using a syslog socket + log /dev/log local0 info + log /dev/log local0 notice + tune.ssl.default-dh-param 2048 + ssl-default-bind-ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK + hard-stop-after 30s +defaults + log global + # https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#4.2-option%20abortonclose + # https://github.com/voyagermesh/voyager/pull/403 + option dontlognull + option http-server-close + # Timeout values + timeout client 50s + timeout client-fin 50s + timeout connect 5s + timeout server 50s + timeout tunnel 50s + # Configure error files + # default traffic mode is http + # mode is overwritten in case of tcp services + mode http +frontend http-0_0_0_0-80 + bind *:80 + mode http + option httplog + option forwardfor + acl is_proxy_https hdr(X-Forwarded-Proto) https + acl acl_voyager.appscode.test hdr(host) -i voyager.appscode.test + acl acl_voyager.appscode.test hdr(host) -i voyager.appscode.test:80 + acl acl_voyager.appscode.test:foo path_beg /foo + redirect scheme https code 308 if ! is_proxy_https acl_voyager.appscode.test acl_voyager.appscode.test:foo + use_backend test-server.default:80 if acl_voyager.appscode.test acl_voyager.appscode.test:foo +backend test-server.default:80 + server pod-test-server-68ddc845cd-6rnwn 172.17.0.4:80 +``` \ No newline at end of file diff --git a/content/docs/v2024.3.18/guides/ingress/configuration/whitelist.md b/content/docs/v2024.3.18/guides/ingress/configuration/whitelist.md new file mode 100644 index 000000000..36337a3e8 --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/configuration/whitelist.md @@ -0,0 +1,101 @@ +--- +title: Configure Ingress Whitelist +menu: + docs_v2024.3.18: + identifier: whitelist-configuration + name: Whitelist + parent: config-ingress + weight: 10 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# Whitelist Source Range + +You can specify the allowed client IP source ranges through the `ingress.appscode.com/whitelist-source-range` annotation. The value is a space separated list of CIDRs, e.g. `192.168.20.0/24 192.168.10.3`. This rule will be applied globally for all frontends. To apply for a specific frontend, you need to manually add `src acl` using [frontend-rules](frontend-rule.md). + +## Ingress Example + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: default + annotations: + ingress.appscode.com/whitelist-source-range: "192.168.20.0/24 192.168.10.3" +spec: + rules: + - host: voyager.appscode.test + http: + paths: + - path: /foo + backend: + service: + name: test-server + port: + number: 80 +``` + +It will add following `src acl` to all frontends in generated haproxy.cfg: + +```ini +acl network_allowed src 192.168.20.0/24 192.168.10.3 +block if restricted_page !network_allowed +``` + +Generated haproxy.cfg: + +```ini +# HAProxy configuration generated by https://github.com/appscode/voyager +# DO NOT EDIT! +global + daemon + stats socket /tmp/haproxy + server-state-file global + server-state-base /var/state/haproxy/ + # log using a syslog socket + log /dev/log local0 info + log /dev/log local0 notice + tune.ssl.default-dh-param 2048 + ssl-default-bind-ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK + hard-stop-after 30s +defaults + log global + # https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#4.2-option%20abortonclose + # https://github.com/voyagermesh/voyager/pull/403 + option dontlognull + option http-server-close + # Timeout values + timeout client 50s + timeout client-fin 50s + timeout connect 5s + timeout server 50s + timeout tunnel 50s + # Configure error files + # default traffic mode is http + # mode is overwritten in case of tcp services + mode http +frontend http-0_0_0_0-80 + bind *:80 + mode http + # Add whitelisted ips + acl network_allowed src 192.168.20.0/24 192.168.10.3 + block if restricted_page !network_allowed + option httplog + option forwardfor + acl is_proxy_https hdr(X-Forwarded-Proto) https + acl acl_voyager.appscode.test hdr(host) -i voyager.appscode.test + acl acl_voyager.appscode.test hdr(host) -i voyager.appscode.test:80 + acl acl_voyager.appscode.test:foo path_beg /foo + use_backend test-server.default:80 if acl_voyager.appscode.test acl_voyager.appscode.test:foo +backend test-server.default:80 + server pod-test-server-68ddc845cd-x7dtv 172.17.0.4:80 +``` \ No newline at end of file diff --git a/content/docs/v2024.3.18/guides/ingress/debugging.md b/content/docs/v2024.3.18/guides/ingress/debugging.md new file mode 100644 index 000000000..9a7f9145a --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/debugging.md @@ -0,0 +1,2 @@ +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + diff --git a/content/docs/v2024.3.18/guides/ingress/dns/_index.md b/content/docs/v2024.3.18/guides/ingress/dns/_index.md new file mode 100755 index 000000000..ea7b6c9b7 --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/dns/_index.md @@ -0,0 +1,15 @@ +--- +title: Configuring External DNS +menu: + docs_v2024.3.18: + identifier: dns-ingress + name: DNS + parent: ingress-guides + weight: 30 +menu_name: docs_v2024.3.18 +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + diff --git a/content/docs/v2024.3.18/guides/ingress/dns/external-dns.md b/content/docs/v2024.3.18/guides/ingress/dns/external-dns.md new file mode 100644 index 000000000..6cd29bee3 --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/dns/external-dns.md @@ -0,0 +1,88 @@ +--- +title: Configure External DNS for Kubernetes Ingress +menu: + docs_v2024.3.18: + identifier: external-dns-dns + name: External DNS + parent: dns-ingress + weight: 10 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# Configuring external DNS servers + +[external-dns](https://github.com/kubernetes-incubator/external-dns) project can be used to configure external DNS servers for Voyager managed ingresses. + +## LoadBalancer Ingress + +For a [LoadBalancer](/docs/v2024.3.18/concepts/ingress-types/loadbalancer) type Ingress, apply `"external-dns.alpha.kubernetes.io/hostname"` annotation on the **service** that exposes HAProxy pods. This service should have a name like `voyager-{ingress-name}` in the same namespace of the Ingress object. Since, Voyager uses its own CRD for Ingress, `external-dns` project must use the service to discover loadbalancer ip. + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress-voyager + namespace: vdimov-dev + annotations: + ingress.appscode.com/annotations-service: | + { + "external-dns.alpha.kubernetes.io/hostname" : "voyager.example.com,voyager-1.example.com,voyager-2.example.com" + } + ingress.appscode.com/replicas: '2' +spec: + rules: + - host: voyager.example.com + http: + paths: + - backend: + service: + name: web + port: + number: 80 +``` + +## NodePort Ingress + +Since [v0.5.3](https://github.com/kubernetes-incubator/external-dns/releases/tag/v0.5.3), `external-dns` supports [NodePort](/docs/v2024.3.18/concepts/ingress-types/nodeport) ingress. + + +## HostPort Ingress + +[HostPort](/docs/v2024.3.18/concepts/ingress-types/hostport) type Ingress is [supported by external-dns](https://github.com/kubernetes-incubator/external-dns/blob/v0.5.2/docs/tutorials/hostport). Here, apply `"external-dns.alpha.kubernetes.io/hostname"` annotation on the HAProxy **services**. + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress-voyager + namespace: vdimov-dev + annotations: + ingress.appscode.com/type: HostPort + ingress.appscode.com/annotations-service: | + { + "external-dns.alpha.kubernetes.io/hostname" : "voyager.example.com,voyager-1.example.com,voyager-2.example.com" + } + ingress.appscode.com/replicas: '2' +spec: + rules: + - host: voyager.example.com + http: + paths: + - backend: + service: + name: web + port: + number: 80 +``` + +## Internal Ingress + +[Internal](/docs/v2024.3.18/concepts/ingress-types/internal) ingress is not accessible from outside a cluster. Hence, there is nothing to configure in external DNS servers. diff --git a/content/docs/v2024.3.18/guides/ingress/graceful-reload.md b/content/docs/v2024.3.18/guides/ingress/graceful-reload.md new file mode 100644 index 000000000..3b6d6d54b --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/graceful-reload.md @@ -0,0 +1,184 @@ +--- +title: Avoid 503 with Graceful Server Shutdown | Voyager +menu: + docs_v2024.3.18: + identifier: avoid-503-with-server-graceful-shutdown + name: Avoid 503 with Graceful Server Shutdown + parent: ingress-guides + weight: 50 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# Avoid 503 with Graceful Server Shutdown + +Multiple Voyager users have been facing an issue regarding getting 503 response randomly after updating ingress. So, we looked into what was going wrong and here's the solution and the reason behind this problem. + +HAProxy supports both graceful and hard stop. For Voyager, we are using graceful stop. The graceful stop is triggered when the SIGUSR1 signal is sent to the haproxy process. It consists in only unbinding from listening ports, but continue to process existing connections until they close. Once the last connection is closed, the process leaves. + +So suppose you scaled down or deleted some of your backend application pods. These events will happen simultaneously: + +1. The pod will go into terminating status and drop all the existing connections and you will get 503 response. +2. It will be removed from service endpoint. +3. HAProxy configuration will be reloaded - the dead pods will be removed from the config (and new pods will be inserted if that's the case). + +If you do have a graceful shutdown for your backend pods, as soon as your backend pod dies, it will be removed from your service endpoint and HAProxy configuration - but the pod will (hopefully) finish serving the existing requests. + +Here are 2 ways for the pod to finish serving existing requests. + +### 1. Catch SIGTERM and Ignore + +So how are we going to implement the graceful shutdown of the backend server? + +From kubernetes doc: + +> When a user requests deletion of a Pod, the system records the intended grace period before the Pod is allowed to be forcefully killed, and a TERM signal is sent to the main process in each container. Once the grace period has expired, the KILL signal is sent to those processes, and the Pod is then deleted from the API server. + +One difference between SIGTERM and SIGKILL is - the process can register a handler for SIGTERM and choose to ignore it. But SIGKILL cannot be ignored. + +So when the containers in your pod receives SIGTERM, in default state when you don't catch it, the container is killed immediately. But as you want to finish serving existing connections, you need to catch this signal to wait for grace period to be finished (mentioned by `terminationGracePeriodSeconds` in pod's spec). After this period ends, SIGKILL is sent to the container and there's nothing else you can do to stop it from being dead! + +One thing worth mentioning here, as soon as a pod receive SIGTERM it goes into `terminating` state no matter whether you handle this signal or not (and new pods are created if your deployment needs). Also, simultaneously with this, this pod is removed from endpoints list for corresponding service. + +Now, what are you going to do after catching SIGTERM? Here are two samples: + +#### i. Add Sleep + +A simple example is shown here written Golang. Let's say you have one server running like this: + +```go +http.ListenAndServe(":8080", nil) +``` + +Put that in a goroutine and add these lines to your main process + +```go +go http.ListenAndServe(":8080", nil) + +ch := make(chan os.Signal, 1) +signal.Notify(ch, syscall.SIGTERM) + +<-ch +time.Sleep(30 * time.Second) +``` + +This `30` came from the default value of `terminationGracePeriodSeconds`. These lines are going to catch the SIGTERM signal and make sure that your server in the other process runs until the grace period ends. + +Full code: + +```go +package main + +import ( + "fmt" + "log" + "net/http" + "os" + "os/signal" + "syscall" + "time" +) + +func handler(w http.ResponseWriter, r *http.Request) { + log.Print("Hello world received a request.") + fmt.Fprintf(w, "Hello %s!\n", "world") +} + +func main() { + + log.Print("Hello world sample started.") + http.HandleFunc("/", handler) + go http.ListenAndServe(":8080", nil) + + ch := make(chan os.Signal, 1) + signal.Notify(ch, os.Interrupt, syscall.SIGTERM) + + <-ch + time.Sleep(30 * time.Second) + +} +``` + +#### ii. Add Server Shutdown + +You can also gracefully shutdown each server individually after catching SIGTERM. + +```go +package main + +import ( + "context" + "fmt" + "log" + "net/http" + "os" + "os/signal" + "syscall" + "time" +) + +type httpHandler struct { +} + +func (h httpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + time.Sleep(5 * time.Second) + log.Print("Hello world received a request.") + fmt.Fprintf(w, "Hello %s!\n", "world") +} + +func main() { + + log.Print("Hello world sample started.") + server := &http.Server{Addr: ":8080", Handler: httpHandler{}} + go server.ListenAndServe() + + ch := make(chan os.Signal, 1) + signal.Notify(ch, os.Interrupt, syscall.SIGTERM) + + <-ch + + time.Sleep(5 * time.Second) // in case pod receives new request + + ctx, _ := context.WithTimeout(context.Background(), 20*time.Second) + if err := server.Shutdown(ctx); err != nil { + } + +} +``` + +When `server.Shutdown(ctx)` is called, it stops taking new requests and tries to finish serving all current requests, but doesn't wait more than 20 seconds. + +### 2. Add a preStop hook + +You can also add a prestop hook to container to make sure the container isn't killed until grace period ends. + +```go +spec: + containers: + - image: kfoozminus/graceful:v1 + imagePullPolicy: Always + lifecycle: + preStop: + exec: + command: + - sleep + - "30" + name: nginx + resources: {} + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + dnsPolicy: ClusterFirst + restartPolicy: Always + schedulerName: default-scheduler + securityContext: {} + terminationGracePeriodSeconds: 30 +``` + +preStop is executed before SIGTERM is sent. So in this case, SIGTERM is sent 30s after shutdown is initiated. The preStop hook cannot block more than the grace period though. If "sleep 60" was executed as preStop hook, the pod will terminate after 30s, that is, the grace period. diff --git a/content/docs/v2024.3.18/guides/ingress/grpc.md b/content/docs/v2024.3.18/guides/ingress/grpc.md new file mode 100644 index 000000000..9a7f9145a --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/grpc.md @@ -0,0 +1,2 @@ +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + diff --git a/content/docs/v2024.3.18/guides/ingress/http/_index.md b/content/docs/v2024.3.18/guides/ingress/http/_index.md new file mode 100644 index 000000000..edfe8e388 --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/http/_index.md @@ -0,0 +1,15 @@ +--- +title: HTTP +menu: + docs_v2024.3.18: + identifier: http-ingress + name: HTTP + parent: ingress-guides + weight: 10 +menu_name: docs_v2024.3.18 +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + diff --git a/content/docs/v2024.3.18/guides/ingress/http/blue-green-deployment.md b/content/docs/v2024.3.18/guides/ingress/http/blue-green-deployment.md new file mode 100644 index 000000000..0bf145bcf --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/http/blue-green-deployment.md @@ -0,0 +1,138 @@ +--- +title: Blue Green Deployments | Kubernetes Ingress +menu: + docs_v2024.3.18: + identifier: blue-green-http + name: Blue Green Deployment + parent: http-ingress + weight: 60 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# Blue Green Deployments + +Voyager supports Blue Green deployments using weighted loadbalancing for backend pods. Following example illustrates a weighted loadbalancer scenario. + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: deployment + app-version: v1 +  name: deployment-1 + namespace: default +spec: + replicas: 1 + selector: + matchLabels: + app: deployment + app-version: v1 + template: + metadata: + labels: + app: deployment + app-version: v1 + annotations: + ingress.appscode.com/backend-weight: "90" + spec: + containers: + - env: + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + image: appscode/test-server:1.1 + imagePullPolicy: IfNotPresent + name: server + ports: + - containerPort: 8080 + name: http-1 + protocol: TCP +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: deployment + app-version: v2 + name: deployment-2 + namespace: default +spec: + replicas: 1 + selector: + matchLabels: + app: deployment + app-version: v2 + template: + metadata: + labels: + app: deployment + app-version: v2 + annotations: + ingress.appscode.com/backend-weight: "10" + spec: + containers: + - env: + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + image: appscode/test-server:1.1 + imagePullPolicy: IfNotPresent + name: server + ports: + - containerPort: 8080 + name: http-1 + protocol: TCP +``` + +Two different workload with the annotation `ingress.appscode.com/backend-weight` and one single service pointing to them + +```yaml +apiVersion: v1 +kind: Service +metadata: + name: deployment-svc + namespace: default +spec: + ports: + - name: http-1 + port: 80 + protocol: TCP + targetPort: 8080 + selector: + app: deployment +``` + +The following ingress will forward 90% traffic to `deployment-1` and 10% to `deployment-2` + +```yml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ing + namespace: default +spec: + rules: + - http: + paths: + - backend: + service: + name: deployment-svc + port: + number: 80 + path: /testpath +``` + +The default [weight](http://cbonte.github.io/haproxy-dconv/1.8/configuration.html#weight) is 1, and the maximal value is 256. A value of 0 means the server will not participate in load-balancing but will still accept persistent connections. \ No newline at end of file diff --git a/content/docs/v2024.3.18/guides/ingress/http/cors.md b/content/docs/v2024.3.18/guides/ingress/http/cors.md new file mode 100644 index 000000000..dfe1d41f8 --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/http/cors.md @@ -0,0 +1,134 @@ +--- +title: CORS | Kubernetes Ingress +menu: + docs_v2024.3.18: + identifier: cors-http + name: CORS + parent: http-ingress + weight: 30 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# CORS + +Voyager can enable and configure CORS for all HTTP frontends via following ingress annotations: + +- `ingress.appscode.com/enable-cors`: If set to `true` enables CORS for all HTTP Frontend. By default CORS is disabled. +- `ingress.appscode.com/cors-allow-headers`: Specifies allowed headers when CORS enabled. Default value is `DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization`. +- `ingress.appscode.com/cors-allow-methods`: Specifies allowed methods when CORS enabled. Default value is `GET,PUT,POST,DELETE,PATCH,OPTIONS`. +- `ingress.appscode.com/cors-allow-origin`: Specifies allowed origins when CORS enabled. Default value is `*`. + +## Ingress Example + +First create a test-server and expose it via service: + +```bash +$ kubectl run test-server --image=gcr.io/google_containers/echoserver:1.8 +deployment "test-server" created + +$ kubectl expose deployment test-server --type=LoadBalancer --port=80 --target-port=8080 +service "test-server" exposed +``` + +Then create the ingress: + +```yaml +$ kubectl apply -f test-ingress.yaml + +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: default + annotations: + ingress.appscode.com/enable-cors: "true" + ingress.appscode.com/cors-allow-headers: "Keep-Alive,User-Agent" + ingress.appscode.com/cors-allow-methods: "GET,PUT" + ingress.appscode.com/cors-allow-origin: "http://foo.example" +spec: + rules: + - host: voyager.appscode.test + http: + paths: + - path: /foo + backend: + service: + name: test-server + port: + number: 80 +``` + +```bash +$ kubectl get pods,svc +NAME READY STATUS RESTARTS AGE +po/test-server-68ddc845cd-x7dtv 1/1 Running 0 1d +po/voyager-test-ingress-5b758664f6-hjwjb 1/1 Running 0 20m + +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +svc/kubernetes ClusterIP 10.96.0.1 443/TCP 3d +svc/test-server LoadBalancer 10.105.13.31 80:30390/TCP 1d +svc/voyager-test-ingress LoadBalancer 10.106.53.141 80:32218/TCP 1h + +$ minikube service --url voyager-test-ingress +http://192.168.99.100:32218 +``` + +Applying the annotation in ingress will have the following effects, will add the CORS Header in the response. + +```bash +$ curl -v -H 'Host: voyager.appscode.test' 192.168.99.100:32218/foo +* Trying 192.168.99.100... +* Connected to 192.168.99.100 (192.168.99.100) port 32218 (#0) +> GET /foo HTTP/1.1 +> Host: voyager.appscode.test +> User-Agent: curl/7.47.0 +> Accept: */* +> +< HTTP/1.1 200 OK +< Date: Thu, 15 Feb 2018 05:06:49 GMT +< Content-Type: text/plain +< Transfer-Encoding: chunked +< Server: echoserver +< Access-Control-Allow-Origin: http://foo.example +< Access-Control-Allow-Methods: GET,PUT +< Access-Control-Allow-Credentials: true +< Access-Control-Allow-Headers: Keep-Alive,User-Agent +< + + +Hostname: test-server-68ddc845cd-x7dtv + +Pod Information: + -no pod information available- + +Server values: + server_version=nginx: 1.13.3 - lua: 10008 + +Request Information: + client_address=172.17.0.5 + method=GET + real path=/foo + query= + request_version=1.1 + request_uri=http://voyager.appscode.test:8080/foo + +Request Headers: + accept=*/* + connection=close + host=voyager.appscode.test + user-agent=curl/7.47.0 + x-forwarded-for=172.17.0.1 + +Request Body: + -no body in request- + +* Connection #0 to host 192.168.99.100 left intact +``` \ No newline at end of file diff --git a/content/docs/v2024.3.18/guides/ingress/http/custom-http-port.md b/content/docs/v2024.3.18/guides/ingress/http/custom-http-port.md new file mode 100644 index 000000000..4e6de3e84 --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/http/custom-http-port.md @@ -0,0 +1,76 @@ +--- +title: Custom HTTP Port | Kubernetes Ingress +menu: + docs_v2024.3.18: + identifier: custom-port-http + name: Custom HTTP Port + parent: http-ingress + weight: 35 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# Custom HTTP Port + +Voyager 3.2+ supports using any non-standard port (beyond 80 and 443) for L7 traffic. If no port is specified, port 80 or 443 will be used depending on whether TLS is used or not. + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: default +spec: + rules: + - host: one.example.com + http: + port: '8989' + paths: + - path: /admin + backend: + service: + name: admin-service + port: + number: 80 + - path: / + backend: + service: + name: test-service + port: + number: 80 + - host: other.example.com + http: + port: '8989' + paths: + - backend: + service: + name: other-service + port: + number: 80 + - host: one.example.com + http: + port: '4343' + paths: + - backend: + service: + name: test-service + port: + number: 80 + +``` + +For this configuration, the loadbalancer will listen to `8989` and `4343` port for incoming HTTP connections, and will +pass any request coming to it to the desired backend. + +### Restrictions: +- For one Ingress resource you cannot have multiple `tcp` rules listening to same port, even if they do not have +same `host`. + +- Different hosts can use the same port for `http` rules diff --git a/content/docs/v2024.3.18/guides/ingress/http/external-svc.md b/content/docs/v2024.3.18/guides/ingress/http/external-svc.md new file mode 100644 index 000000000..bb506a902 --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/http/external-svc.md @@ -0,0 +1,165 @@ +--- +title: Using External Service as Ingress Backend | Kubernetes Ingress +menu: + docs_v2024.3.18: + identifier: external-svc-backend-http + name: External SVC + parent: http-ingress + weight: 40 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# Using External Service as Ingress Backend + +You can use an external service as a Backend for Kubernetes Ingress. There are 2 options depending on whether the external service has an external IP or DNS record. + +## Using External IP + +You can introduce any [external IP address as a Kubernetes service](https://github.com/kubernetes/kubernetes/issues/8631#issuecomment-104404768) by creating a matching Service and Endpoint object. Then you can use this service as a backend for your Ingress rules. + +```yaml +apiVersion: v1 +kind: Service +metadata: + name: external-ip + namespace: default +spec: + ports: + - name: app + port: 80 + protocol: TCP + targetPort: 9855 + clusterIP: None + type: ClusterIP +--- +apiVersion: v1 +kind: Endpoints +metadata: + name: external-ip + namespace: default +subsets: +- addresses: + # list all external ips for this service + - ip: 172.17.0.5 + ports: + - name: app + port: 9855 + protocol: TCP +``` + +Now, you can use this `external-ip` Service as a backend in your Ingress definition. For example: + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ings-rhvulnlb + namespace: default +spec: + defaultBackend: + service: + name: external-ip + port: + number: 80 +``` + + +## Using External Domain + +You can introduce an external service into a Kubernetes cluster by creating a [`ExternalName`](https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services---service-types) type service. Voyager can forward traffic in both HTTP and TCP mode to the named domain in the `ExternalName` service by resolving dns. For static resolution of DNS record when HAProxy config is parsed, only use the `ingress.appscode.com/use-dns-resolver: "true"` annotation on the respective service. To periodically resolve dns, [DNS resolvers](https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#5.3) must be configured using annotations on the service name. + +| Keys | Value | Default | Description | +|--------|-----------|----------|-------------| +| ingress.appscode.com/use-dns-resolver | bool | false for L7, always true for L4 | If set, DNS resolution will be used | +| ingress.appscode.com/dns-resolver-nameservers | array | | `Optional`. If set to an array of DNS nameservers, these will be used HAProxy to periodically resolve DNS. If not set, HAProxy parses the server line definition and matches a host name at start up. | +| ingress.appscode.com/dns-resolver-check-health | bool | | `Optional`. If nameservers are set, this defaults to `true`. Set to `false`, to disable periodic dns resolution. | +| ingress.appscode.com/dns-resolver-retries | integer | | `Optional`. If set, this defines the number of queries to send to resolve a server name before giving up. If not set, default value pre-configured by HAProxy is used. | +| ingress.appscode.com/dns-resolver-timeout | map | | `Optional`. If set, defines timeouts related to name resolution. Define value as '{ "event": "time" }'. For a list of valid events, please consult [HAProxy documentation](https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#5.3.2-timeout). | +| ingress.appscode.com/dns-resolver-hold | map | | `Optional`. If set, Defines period during which the last name resolution should be kept based on last resolution status. Define value as '{ "status": "period" }'. For a list of valid status, please consult [HAProxy documentation](https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#5.3.2-hold). | + +Following example illustrates the scenario. + +``` +apiVersion: v1 +kind: Service +metadata: + name: external-ns + namespace: default + annotations: + ingress.appscode.com/use-dns-resolver: "true" + ingress.appscode.com/dns-resolver-nameservers: '["8.8.8.8:53", "8.8.4.4:53"]' +spec: + externalName: google.com + type: ExternalName +``` + +If this service is used in ingress, the traffic will forward to google.com's address. + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ings-rhvulnlb + namespace: default +spec: + defaultBackend: + service: + name: external-ns + port: + number: 80 +``` + +### HTTP Redirect +If `ingress.appscode.com/use-dns-resolver` annotation is set to false or missing on a `ExternalName` type service, +Voyager resolves L7 ingress in the following ways. + +``` +apiVersion: v1 +kind: Service +metadata: + name: external-ns + namespace: default +spec: + externalName: google.com + type: ExternalName +``` + +#### Default redirect +If No BackendRules are configured for the endpoint, Voyager will configure HAProxy to redirect traffic to provided domain and port. +The redirect code will be 301 (permanent redirect). Scheme (http or https) used by endpoint is preserved on redirect. + +``` +backend: + service: + name: external-svc-non-dns + port: + number: 80 +``` + +The generated redirect line in HAProxy config: + +``` +http-request redirect location http[s]://{{e.ExternalName}}:{{ e.Port }} code 301 +``` + +#### Backend Rule + +If Backendrules are configured, Voyager will not auto generate any redirect rule. This allows users to use full spectrum of HTTP redirection options available in HAProxy. To learn about these option, consult [HAProxy documentation](https://www.haproxy.com/doc/aloha/7.0/haproxy/http_redirection.html#redirection-examples). + +``` +backend: + backendRules: + - http-request redirect location https://google.com code 302 + service: + name: external-svc-non-dns + port: + number: 80 +``` diff --git a/content/docs/v2024.3.18/guides/ingress/http/hsts.md b/content/docs/v2024.3.18/guides/ingress/http/hsts.md new file mode 100644 index 000000000..14f5cda56 --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/http/hsts.md @@ -0,0 +1,229 @@ +--- +title: HSTS | Kubernetes Ingress +menu: + docs_v2024.3.18: + identifier: hsts-http + name: HSTS + parent: http-ingress + weight: 45 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# HSTS + +HTTP Strict Transport Security (HSTS) is a web security policy mechanism which helps to protect websites against protocol downgrade attacks and cookie hijacking. It allows web servers to declare that web browsers (or other complying user agents) should only interact with it using secure +HTTPS connections, and never via the insecure HTTP protocol. HSTS is an IETF standards track protocol and is specified in RFC 6797. + +The HSTS Policy is communicated by the server to the user agent via an HTTPS response header field named "Strict-Transport-Security". +HSTS Policy specifies a period of time during which the user agent should only access the server in a secure fashion. + +Voyager can insert HSTS headers in http response if configured via following ingress annotations: + +- `ingress.appscode.com/hsts`: If `false` disables HSTS. By default HSTS is enabled. +- `ingress.appscode.com/hsts-preload`: If `true` enables HSTS preload. +- `ingress.appscode.com/hsts-include-subdomains`: If `true` HSTS rule applies to all of the site's sub domains. +- `ingress.appscode.com/hsts-max-age`: Specifies the time (in seconds) the browser should connect to the server using the HTTPS connection. You can also specify time with units such as "300ms", "-1.5h" or "2h45m". Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". Default value is `15768000` (6 months). + +## Ingress example + +First create a test-server and expose it via service: + +```bash +$ kubectl run test-server --image=gcr.io/google_containers/echoserver:1.8 +deployment "test-server" created + +$ kubectl expose deployment test-server --type=LoadBalancer --port=80 --target-port=8080 +service "test-server" exposed +``` + +Then create required tls-certificates: + +```bash +$ ./onessl-linux-amd64 create ca-cert +Wrote ca certificates in /home/appscode + +$ ./onessl-linux-amd64 create server-cert tls +Wrote server certificates in /home/appscode + +$ kubectl create secret tls tls-secret --key tls.key --cert tls.crt +secret "tls-secret" created +``` + +Now create the ingress with HSTS annotations: + +```yaml +$ kubectl apply -f test-ingress.yaml + +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: default + annotations: + ingress.appscode.com/hsts: "true" + ingress.appscode.com/hsts-preload: "true" + ingress.appscode.com/hsts-include-subdomains: "true" + ingress.appscode.com/hsts-max-age: "100" +spec: + tls: + - secretName: tls-secret + hosts: + - voyager.appscode.test + rules: + - host: voyager.appscode.test + http: + paths: + - path: /foo + backend: + service: + name: test-server + port: + number: 80 +``` + +Generated haproxy.cfg: + +```ini +# HAProxy configuration generated by https://github.com/appscode/voyager +# DO NOT EDIT! +global + daemon + stats socket /tmp/haproxy + server-state-file global + server-state-base /var/state/haproxy/ + # log using a syslog socket + log /dev/log local0 info + log /dev/log local0 notice + tune.ssl.default-dh-param 2048 + ssl-default-bind-ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK + hard-stop-after 30s +defaults + log global + # https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#4.2-option%20abortonclose + # https://github.com/voyagermesh/voyager/pull/403 + option dontlognull + option http-server-close + # Timeout values + timeout client 50s + timeout client-fin 50s + timeout connect 5s + timeout server 50s + timeout tunnel 50s + # Configure error files + # default traffic mode is http + # mode is overwritten in case of tcp services + mode http +frontend http-0_0_0_0-80 + bind *:80 + mode http + option httplog + option forwardfor + acl is_proxy_https hdr(X-Forwarded-Proto) https + acl acl_voyager.appscode.test hdr(host) -i voyager.appscode.test + acl acl_voyager.appscode.test hdr(host) -i voyager.appscode.test:80 + acl acl_voyager.appscode.test:foo path_beg /foo + redirect scheme https code 308 if ! is_proxy_https acl_voyager.appscode.test acl_voyager.appscode.test:foo +frontend http-0_0_0_0-443 + bind *:443 ssl no-sslv3 no-tlsv10 no-tls-tickets crt /etc/ssl/private/haproxy/tls/ alpn http/1.1 + # Mark all cookies as secure + rsprep ^Set-Cookie:\ (.*) Set-Cookie:\ \1;\ Secure + # Add the HSTS header with a 6 month default max-age + http-response set-header Strict-Transport-Security max-age=100;\ preload;\ includeSubDomains + mode http + option httplog + option forwardfor + acl is_proxy_https hdr(X-Forwarded-Proto) https + acl acl_voyager.appscode.test hdr(host) -i voyager.appscode.test + acl acl_voyager.appscode.test hdr(host) -i voyager.appscode.test:443 + acl acl_voyager.appscode.test:foo path_beg /foo + use_backend test-server.default:80 if acl_voyager.appscode.test acl_voyager.appscode.test:foo +backend test-server.default:80 + server pod-test-server-68ddc845cd-tpq7d 172.17.0.4:8080 +``` + +Get url for offshoot voyager service: + +```bash +$ kubectl get service voyager-test-ingress +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +voyager-test-ingress LoadBalancer 10.106.67.91 443:32273/TCP,80:31129/TCP 21m + +$ minikube service --url voyager-test-ingress +http://192.168.99.100:32273 +http://192.168.99.100:31129 +``` + +Applying the annotation in ingress will have the following effects, will add the HSTS Header in the response. + +```bash +$ curl -v -k -H 'Host: voyager.appscode.test' https://192.168.99.100:32273/foo + +* Trying 192.168.99.100... +* Connected to 192.168.99.100 (192.168.99.100) port 32273 (#0) +* found 148 certificates in /etc/ssl/certs/ca-certificates.crt +* found 597 certificates in /etc/ssl/certs +* ALPN, offering http/1.1 +* SSL connection using TLS1.2 / ECDHE_RSA_AES_128_GCM_SHA256 +* server certificate verification SKIPPED +* server certificate status verification SKIPPED +* common name: tls (does not match '192.168.99.100') +* server certificate expiration date OK +* server certificate activation date OK +* certificate public key: RSA +* certificate version: #3 +* subject: CN=tls +* start date: Tue, 13 Feb 2018 09:14:08 GMT +* expire date: Wed, 13 Feb 2019 09:14:15 GMT +* issuer: CN=ca +* compression: NULL +* ALPN, server accepted to use http/1.1 +> GET /foo HTTP/1.1 +> Host: voyager.appscode.test +> User-Agent: curl/7.47.0 +> Accept: */* +> +< HTTP/1.1 200 OK +< Date: Tue, 13 Feb 2018 11:42:02 GMT +< Content-Type: text/plain +< Transfer-Encoding: chunked +< Server: echoserver +< Strict-Transport-Security: max-age=100; preload; includeSubDomains +< + + +Hostname: test-server-68ddc845cd-tpq7d + +Pod Information: + -no pod information available- + +Server values: + server_version=nginx: 1.13.3 - lua: 10008 + +Request Information: + client_address=172.17.0.5 + method=GET + real path=/foo + query= + request_version=1.1 + request_uri=http://voyager.appscode.test:8080/foo + +Request Headers: + accept=*/* + connection=close + host=voyager.appscode.test + user-agent=curl/7.47.0 + x-forwarded-for=172.17.0.1 + +Request Body: + -no body in request- + +* Connection #0 to host 192.168.99.100 left intact +``` \ No newline at end of file diff --git a/content/docs/v2024.3.18/guides/ingress/http/http2.md b/content/docs/v2024.3.18/guides/ingress/http/http2.md new file mode 100644 index 000000000..83492c2dd --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/http/http2.md @@ -0,0 +1,62 @@ +--- +title: HTTP2 | Kubernetes Ingress +menu: + docs_v2024.3.18: + identifier: h2-http + name: HTTP2 + parent: http-ingress + weight: 26 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# Enable HTTP/2 on ingress resource + +Voyager can enable HTTP/2 from version >=8.0.1 + +To enable http2, you must first setup a [certificate](/docs/v2024.3.18/guides/certificate) (Let's Encrypt), or use an existing one. Then create an ingress object like below: + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: haproxy-ingress # name of the ingress + namespace: default # namespace (optional) + annotations: + ingress.appscode.com/replicas: '2' + # ... other annotations +spec: + tls: + - hosts: + - host.example.com + secretName: tls-host + rules: + - host: host.example.com + http: + paths: + - path: "/" + backend: + service: + name: host-service + port: + number: 8000 + alpn: + - h2 + - http/1.1 + - http/1.0 +``` + +The important bit here is `alpn`. In this example the ingress can negotiate from `HTTP/2` all the way down to `HTTP/1.0`. If `alpn` isn't specified at all, the negotiated protocol will be `HTTP/1.1` (default). + +The above settings are reflected in the generated haproxy `ConfigMap`: + +```frontend http-0_0_0_0-443 + bind *:443 ssl no-sslv3 no-tlsv10 no-tls-tickets crt /etc/ssl/private/haproxy/tls/ alpn h2,http/1.1,http/1.0 +``` diff --git a/content/docs/v2024.3.18/guides/ingress/http/rewrite-rules.md b/content/docs/v2024.3.18/guides/ingress/http/rewrite-rules.md new file mode 100644 index 000000000..c58d6edf2 --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/http/rewrite-rules.md @@ -0,0 +1,52 @@ +--- +title: Header and URL Rewriting | Voyager +menu: + docs_v2024.3.18: + identifier: rewrite-http + name: Rewrite Support + parent: http-ingress + weight: 25 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# Header and URL Rewriting + +AppsCode Ingress support header and URL modification at the loadbalancer level. To ensure simplicity, +the backend rules follow the HAProxy syntax as it is. To add some rewrite rules for a HTTP path, follow the example below: + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: default +spec: + rules: + - host: appscode.example.com + http: + paths: + - backend: + service: + name: test-service + port: + number: 80 + backendRules: + - http-request replace-uri ^/(.*)$ /testings/\\1 + - http-request set-header X-Forwarded-Host %[base] +``` + +The first rule specified in `backendRules` is used to modify the request url including the host. Current example +will add an `/testings` prefix in every request URI before forwarding it to backend. + +The second rule specified in `backendRules` will be applicable before going to the backend. +These rule will add header in the request if the header is already not present in the request header. +In the example `X-Forwarded-Host` header is added to the request if it is not already there, `%[base]` indicates +the base URL the load balancer received the requests. diff --git a/content/docs/v2024.3.18/guides/ingress/http/single-service.md b/content/docs/v2024.3.18/guides/ingress/http/single-service.md new file mode 100644 index 000000000..bee53e2e2 --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/http/single-service.md @@ -0,0 +1,85 @@ +--- +title: Exposing Service | Kubernetes Ingress +menu: + docs_v2024.3.18: + identifier: single-svc-http + name: Single Service + parent: http-ingress + weight: 10 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# Exposing Service via Ingress + +There are existing Kubernetes concepts which allows you to expose a single service. However, you can do so +through an AppsCode Ingress as well, simply by specifying a default backend with no rules. + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: default +spec: + defaultBackend: + service: + name: test-service + port: + number: 80 +``` + +This will create a load balancer forwarding all traffic to `test-service` service, unconditionally. The +loadbalancer ip can be found inside `Status` Field of the loadbalancer described response. **If there are other +rules defined in Ingress then the loadbalancer will forward traffic to the `test-service` when no other `rule` is +matched.** + +**As Example:** + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: default +spec: + defaultBackend: + service: + name: default-service + port: + number: 80 + rules: + - host: appscode.example.com + http: + paths: + - backend: + service: + name: test-service + port: + number: 80 + - host: default.example.com + http: + paths: + - backend: + service: + name: default-service + port: + number: 80 +``` +**Default Backend**: An Ingress with no rules, like the one shown in the previous section, sends all +traffic to a single default backend. You can use the same technique to tell a loadbalancer +where to find your website’s 404 page, by specifying a set of rules and a default backend. +Traffic is routed to your default backend if none of the Hosts in your Ingress matches the Host in +request header, and/or none of the paths match url of request. + +This Ingress will forward traffic to `test-service` if request comes from the host `appscode.example.com` only. +Other requests will be forwarded to default backend, `default-service`. + +Default Backend also supports `headerRules` and `rewriteRules`. diff --git a/content/docs/v2024.3.18/guides/ingress/http/source-range.md b/content/docs/v2024.3.18/guides/ingress/http/source-range.md new file mode 100644 index 000000000..e883e8271 --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/http/source-range.md @@ -0,0 +1,75 @@ +--- +title: Loadbalancer Source Range | Kubernetes Ingress +menu: + docs_v2024.3.18: + name: Source Range + parent: http-ingress + weight: 20 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# Loadbalancer Source Range + +When using an Ingress with `ingress.appscode.com/type: LoadBalancer` annotation, you can specify the IP ranges +that are allowed to access the load balancer by using `spec.loadBalancerSourceRanges`. +This field takes a list of IP CIDR ranges, which will be forwarded to Kubernetes, that will use to +configure firewall exceptions. This feature is currently supported on Google Compute Engine, +Google Container Engine and AWS. This field will be ignored if the cloud provider does not support the feature. + +Assuming 10.0.0.0/8 is the internal subnet. In the following example, a load balancer will be created +that is only accessible to cluster internal ips. This will not allow clients from outside of your +Kubernetes cluster to access the load balancer. + +``` +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: default +spec: + rules: + - host: appscode.example.com + http: + paths: + - backend: + service: + name: test-service + port: + number: 80 + loadBalancerSourceRanges: + - 10.0.0.0/8 +``` + +In the following example, a load balancer will be created that is only accessible to clients with +IP addresses from 130.211.204.1 and 130.211.204.2. + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: default +spec: + rules: + - host: appscode.example.com + http: + paths: + - backend: + service: + name: test-service + port: + number: 80 + loadBalancerSourceRanges: + - 130.211.204.1/32 + - 130.211.204.2/32 +``` + +NB: Currently there is a [bug in Kubernetes](https://github.com/kubernetes/kubernetes/issues/34218) due to which changing `loadBalancerSourceRanges` does not change SecurityGroup in AWS. diff --git a/content/docs/v2024.3.18/guides/ingress/http/statefulset-pod.md b/content/docs/v2024.3.18/guides/ingress/http/statefulset-pod.md new file mode 100644 index 000000000..dc9d43f52 --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/http/statefulset-pod.md @@ -0,0 +1,129 @@ +--- +title: Forward Traffic to StatefulSet Pods | Kubernetes Ingress +menu: + docs_v2024.3.18: + identifier: statefulset-http + name: Statefulset Pod + parent: http-ingress + weight: 50 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# Forward Traffic to StatefulSet + +## Forward Traffic to all Pods of a StatefulSet + +There is the usual way of forwarding traffic to a Service matching a StatefulSet. Create a Service with the pods label selector as +selector, and use the service name as Backend ServiceName. + +```yaml +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: http + namespace: default +spec: + serviceName: "nginx-set" + replicas: 2 + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: gcr.io/google_containers/nginx-slim:0.8 + ports: + - containerPort: 80 + name: http +---- +apiVersion: v1 +kind: Service +metadata: + name: nginx-set + namespace: default + labels: + app: nginx +spec: + ports: + - port: 80 + name: http + clusterIP: None + selector: + app: nginx +``` + +Create another service for StatefulSets pods with selector. + +```yaml +apiVersion: v1 +kind: Service +metadata: + name: nginx-service + namespace: default + labels: + app: nginx +spec: + ports: + - port: 80 + name: http + selector: + app: nginx + +``` + +And Use the service in the ingress Backend service name, as: + +```yaml +backend: + service: + name: nginx-service + port: + number: 80 +``` + +That will forward traffic to your StatefulSets Pods. + + +## Forward Traffic to specific Pods of a StatefulSet +There is a way to send traffic to all or specific pod of a StatefulSet using voyager. You can set `hostNames` field in `Backend`, traffic will only forwarded to those pods. + +For Example the above StatefulSet will create two pod. +``` +web-0 +web-1 +``` +Those are the host names. + +Now Create a ingress that will only forward traffic to web-0 +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: default +spec: + rules: + - host: appscode.example.com + http: + paths: + - path: '/testPath' + backend: + hostNames: + - web-0 + service: + name: nginx-set #! There is no extra service. This + port: + number: 80 # is the Statefulset's Headless Service +``` + +Viola. Now all `/testPath` traffic will be sent to pod web-0 only. There is no extra service also. +The StatefulSet's Headless Service is enough. By using all the hostNames You can forward traffic to all pods. diff --git a/content/docs/v2024.3.18/guides/ingress/http/sticky-session.md b/content/docs/v2024.3.18/guides/ingress/http/sticky-session.md new file mode 100644 index 000000000..3b377b1b6 --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/http/sticky-session.md @@ -0,0 +1,141 @@ +--- +title: Sticky Session | Kubernetes Ingress +menu: + docs_v2024.3.18: + identifier: sticky-http + name: Sticky Session + parent: http-ingress + weight: 55 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# Sticky Session + +Voyager 3.2.0+ can configure [sticky connections](https://www.haproxy.com/blog/load-balancing-affinity-persistence-sticky-sessions-what-you-need-to-know/) in 2 modes. By applying annotation to an Ingress resource, you can configure all backends in that ingress to use sticky session. Or you can apply annotation to a service and configure +backends using that service to use sticky session. + +`ingress.appscode.com/sticky-session` annotations is deprecated in voyager 4.0.0+ and removed in 8.0.1+. Use `ingress.appscode.com/affinity` instead. + +## Sticky Ingress + +Applying annotation `ingress.appscode.com/affinity` to Ingress will configure all backends to support sticky session. + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: default + annotations: + ingress.appscode.com/affinity: 'cookie' +spec: + rules: + - host: foo.bar.com + http: + paths: + - backend: + service: + name: s1 + port: + number: 80 + - host: bar.foo.com + http: + paths: + - backend: + service: + name: s2 + port: + number: 80 + - host: tcp.bar.com + tcp: + port: 9898 + backend: + service: + name: tcp-service + port: + number: 50077 +``` + +For the above ingress, all three backend connections will be sticky. + +## Sticky Service + +Applying annotation `ingress.appscode.com/affinity` to a service configures any backend +that uses that service to use sticky connection. As an example, the following Ingress will only +configure sticky connections for backends that use `s1` Service. + +```yaml +kind: Service +apiVersion: v1 +metadata: + name: s1 + namespace: default + annotations: + ingress.appscode.com/affinity: 'cookie' +spec: + selector: + app: app + ports: + - name: http + protocol: TCP + port: 80 + targetPort: 9376 + - name: ops + protocol: TCP + port: 5050 + targetPort: 5089 +``` + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: default +spec: + rules: + - host: foo.bar.com + http: + paths: + - path: /admin + backend: + service: + name: s1 # Sticky, since service s1 is annotated + port: + number: 5050 + - path: / + backend: + service: + name: s1 # Sticky, since service s1 is annotated + port: + number: 80 + - host: bar.foo.com + http: + paths: + - backend: + service: + name: s2 # Not sticky + port: + number: 80 + - host: tcp.bar.com + tcp: + port: 9898 + backend: + service: + name: tcp-service # Not sticky + port: + number: 50077 +``` + +## Other Annotations + +- `ingress.appscode.com/session-cookie-name`: When affinity is set to `cookie`, the name of the cookie to use. +- `ingress.appscode.com/session-cookie-hash`: When affinity is set to `cookie`, the hash algorithm used: md5, sha, index. diff --git a/content/docs/v2024.3.18/guides/ingress/http/virtual-hosting.md b/content/docs/v2024.3.18/guides/ingress/http/virtual-hosting.md new file mode 100644 index 000000000..a030c394d --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/http/virtual-hosting.md @@ -0,0 +1,121 @@ +--- +title: Virtual Hosting | Kubernetes Ingress +menu: + docs_v2024.3.18: + identifier: virtual-hosting-http + name: Virtual Hosting + parent: http-ingress + weight: 15 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# Virtual Hosting + +## Hostname based Routing + +Name-based virtual hosts use multiple host names for the same IP address. + +``` +foo.bar.com --| |-> foo.bar.com s1:80 + | load balancer | +bar.foo.com --| |-> bar.foo.com s2:80 +``` +The following Ingress tells the backing loadbalancer to route requests based on the [Host header](https://tools.ietf.org/html/rfc7230#section-5.4). + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: default +spec: + rules: + - host: foo.bar.com + http: + paths: + - backend: + service: + name: s1 + port: + number: 80 + - host: bar.foo.com + http: + paths: + - backend: + service: + name: s2 + port: + number: 80 +``` + +> AppsCode Ingress also support **wildcard** Name based virtual hosting. +If the `host` field is set to `*.bar.com`, Ingress will forward traffic for any subdomain of `bar.com`. +so `foo.bar.com` or `test.bar.com` will forward traffic to the desired backends. + +## Cross Namespace traffic routing +If your ingress in namespace `foo` and your application is in namespace `bar` you can still forward traffic. + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: foo +spec: + rules: + - host: foo.bar.com + http: + paths: + - backend: + service: + name: s1.bar # serviceName.Namespace + port: + number: 80 +``` + +## Path based Routing + +A setup can be like: + +``` +foo.bar.com -> load balancer -> / foo s1:80 + / bar s2:80 +``` + +would require an Ingress such as: + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: default +spec: + rules: + - host: appscode.example.com + http: + paths: + - path: "/foo" + backend: + service: + name: s1 + port: + number: 80 + - path: "/bar" + backend: + service: + name: s2 + port: + number: 80 +``` + +The Ingress controller will provision an implementation specific loadbalancer that satisfies the Ingress, +as long as the services (s1, s2) exist. diff --git a/content/docs/v2024.3.18/guides/ingress/monitoring/_index.md b/content/docs/v2024.3.18/guides/ingress/monitoring/_index.md new file mode 100644 index 000000000..187f0d905 --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/monitoring/_index.md @@ -0,0 +1,15 @@ +--- +title: Monitoring +menu: + docs_v2024.3.18: + identifier: monitoring-ingress + name: Monitoring + parent: ingress-guides + weight: 40 +menu_name: docs_v2024.3.18 +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + diff --git a/content/docs/v2024.3.18/guides/ingress/monitoring/haproxy-stats.md b/content/docs/v2024.3.18/guides/ingress/monitoring/haproxy-stats.md new file mode 100644 index 000000000..7a14e70a7 --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/monitoring/haproxy-stats.md @@ -0,0 +1,161 @@ +--- +title: Exposing HAProxy Stats +menu: + docs_v2024.3.18: + identifier: haproxy-stats-monitoring + name: Exposing HAProxy Stats + parent: monitoring-ingress + weight: 10 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# Exposing HAProxy Stats + +To expose HAProxy stats, please use the following annotations: + +| Keys | Value | Default | Description | +|-----------------------------------------|---------|-----------|---------------------------------------------------| +| ingress.appscode.com/stats | bool | `"false"` | `Required`. If set, HAProxy stats will be exposed | +| ingress.appscode.com/stats-port | integer | `"56789"` | `Optional`. Port used to expose HAProxy stats | +| ingress.appscode.com/stats-secret-name | string | x | `Optional`. Secret used to provide username & password to secure HAProxy stats endpoint. Secret must contain keys `username` and `password` | + +If `ingress.appscode.com/stats: "true"` annotation is set, a ClusterIP service `voyager--stats` will be +created by Voyager operator. ClusterIP type service used to expose HAproxy stats. This ensures stats endpoint +is not exposed to the internet. + +## Accessing HAProxy Stats + +To access the HAPRoxy stats webpage, you can use port forwarding feature in kubectl. This article shows you the relevant steps using a minikube cluster. + + +### Before You Begin + +At first, you need to have a Kubernetes cluster, and the kubectl command-line tool must be configured to communicate with your cluster. If you do not already have a cluster, you can create one by using [Minikube](https://github.com/kubernetes/minikube). + +Now, deploy Voyager operator following instructions [here](/docs/v2024.3.18/setup/install). + +Note that the yaml files that are used in this tutorial, stored in [docs/examples](https://github.com/voyagermesh/voyager/tree/master/docs/examples/monitoring) folder in GitHub repository [voyagermesh/voyager](https://github.com/voyagermesh/voyager). + +To keep things isolated, this tutorial uses a separate namespace called `demo` throughout this tutorial. Run the following command to prepare your cluster for this tutorial: + +```bash +$ kubectl create namespace demo +namespace "demo" created + +$ kubectl get ns +NAME STATUS AGE +default Active 45m +demo Active 10s +kube-public Active 45m +voyager Active 45m +``` + +### Create Ingress + +We are going to use a nginx server as the backend. To deploy nginx server, run the following commands: + +```bash +kubectl run nginx --image=nginx -n demo +kubectl expose deployment nginx --name=web --port=80 --target-port=80 -n demo +``` + +Now create Ingress `ing.yaml` + +```bash +$ kubectl apply -f https://raw.githubusercontent.com/voyagermesh/voyager/{{< param "info.version" >}}/docs/examples/monitoring/stats-ing.yaml +ingress "stats-ing" created +``` + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: stats-ing + namespace: demo + annotations: + ingress.appscode.com/type: 'NodePort' + ingress.appscode.com/stats: 'true' +spec: + rules: + - host: voyager.appscode.test + http: + paths: + - path: / + backend: + service: + name: web + port: + number: 80 +``` + +```bash +$ kubectl get pods,svc -n demo +NAME READY STATUS RESTARTS AGE +po/nginx-8586cf59-6hbx8 1/1 Running 0 4m +po/voyager-stats-ing-6cb494cc6d-q2rnn 1/1 Running 0 39s + +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +svc/voyager-stats-ing NodePort 10.110.126.89 80:31019/TCP 39s +svc/voyager-stats-ing-stats ClusterIP 10.107.28.13 56789/TCP 39s +svc/web ClusterIP 10.106.250.209 80/TCP 4m + +$ minikube ip +192.168.99.100 + +$ curl http://192.168.99.100:31019 -H "Host:voyager.appscode.test" + + + +Welcome to nginx! + + + +

Welcome to nginx!

+

If you see this page, the nginx web server is successfully installed and +working. Further configuration is required.

+ +

For online documentation and support please refer to +nginx.org.
+Commercial support is available at +nginx.com.

+ +

Thank you for using nginx.

+ + + +$ kubectl port-forward voyager-stats-ing-6cb494cc6d-q2rnn -n demo 56789:56789 +Forwarding from 127.0.0.1:56789 -> 56789 +Handling connection for 56789 +``` + +![stats-page](/docs/v2024.3.18/images/monitoring/stats-view.png) + + +### Cleaning up + +To cleanup the Kubernetes resources created by this tutorial, run: + +```bash +$ kubectl delete ns demo +namespace "demo" deleted +``` + +## Next Steps + +- To monitor your HAProxy pods using builtin [Prometheus](https://prometheus.io/) scraper, visit [here](/docs/v2024.3.18/guides/ingress/monitoring/using-builtin-prometheus). +- To monitor your HAProxy pods using [CoreOS Prometheus Operator](/docs/v2024.3.18/guides/ingress/monitoring/using-coreos-prometheus-operator), visit [here](/docs/v2024.3.18/guides/ingress/monitoring/using-coreos-prometheus-operator). +- To monitor Voyager operator using Prometheus, visit [here](/docs/v2024.3.18/guides/ingress/monitoring/operator-stats). diff --git a/content/docs/v2024.3.18/guides/ingress/monitoring/operator-profiling.md b/content/docs/v2024.3.18/guides/ingress/monitoring/operator-profiling.md new file mode 100644 index 000000000..918754922 --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/monitoring/operator-profiling.md @@ -0,0 +1,95 @@ +--- +title: Profiling Voyager operator +menu: + docs_v2024.3.18: + identifier: operator-stats-profiling + name: Profiling Voyager operator + parent: monitoring-ingress + weight: 30 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# Profiling Voyager operator + +Voyager operator serves [runtime profiling data](https://golang.org/pkg/net/http/pprof/) in the format expected by the pprof visualization tool on port `:8443`. The handled paths all begin with /debug/pprof/. + +Follow the steps below to expose profiling data: + +1. Give `system:anonymous` user access to `/debug/pprof/` paths. **This is not safe to do on a production cluster.** + +```yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: appscode:system:profiler +rules: +- nonResourceURLs: ["/debug/pprof/", "/debug/pprof/*"] + verbs: ["get", "post"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: appscode:system:profiler +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: appscode:system:profiler +subjects: +- apiGroup: rbac.authorization.k8s.io + kind: User + name: system:anonymous +``` + +```bash +$ kubectl auth reconcile -f docs/examples/monitoring/profiler.yaml +clusterrole.rbac.authorization.k8s.io "appscode:system:profiler" reconciled +clusterrolebinding.rbac.authorization.k8s.io "appscode:system:profiler" reconciled +``` + +2. Now, forward the port `:8443` to your workstation. + +``` +$ kubectl get pods -n voyager | grep voyager +voyager-operator-f89dcccdb-plvmt 1/1 Running 0 27m + +$ kubectl port-forward -n voyager voyager-operator-f89dcccdb-plvmt 8443 +Forwarding from 127.0.0.1:8443 -> 8443 +Forwarding from [::1]:8443 -> 8443 +``` + +3. Now, visit the url: https://127.0.0.1:8443/debug/pprof/ + +![operator-profiler](/docs/v2024.3.18/images/monitoring/operator-profiler.png) + +To look at a 30-second CPU profile: + +```bash +$ go tool pprof https+insecure://localhost:8443/debug/pprof/profile +Entering interactive mode (type "help" for commands, "o" for options) +(pprof) top10 +(pprof) pdf +``` + +To look at the heap profile: + +```bash +$ go tool pprof https+insecure://localhost:8443/debug/pprof/heap +(pprof) top10 +(pprof) pdf +``` + +4. Once you are done, remove access to `system:anonymous` user. + +```bash +$ kubectl delete -f docs/examples/monitoring/profiler.yaml +clusterrole.rbac.authorization.k8s.io "appscode:system:profiler" deleted +clusterrolebinding.rbac.authorization.k8s.io "appscode:system:profiler" deleted +``` diff --git a/content/docs/v2024.3.18/guides/ingress/monitoring/operator-stats.md b/content/docs/v2024.3.18/guides/ingress/monitoring/operator-stats.md new file mode 100644 index 000000000..a33f84dd5 --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/monitoring/operator-stats.md @@ -0,0 +1,80 @@ +--- +title: Monitoring Voyager operator +menu: + docs_v2024.3.18: + identifier: operator-stats-monitoring + name: Monitoring Voyager operator + parent: monitoring-ingress + weight: 25 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# Monitoring Voyager operator + +Voyager operator exposes Prometheus ready metrics via the following endpoints on port `:8443`: + +- `/metrics`: Scrape this to monitor operator. + +Follow the steps below to view the metrics: + +1. Give `system:anonymous` user access to `/metrics` url. **This is not safe to do on a production cluster.** + +```yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: appscode:system:metrics-collector +rules: +- nonResourceURLs: ["/metrics"] + verbs: ["get"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: appscode:system:metrics-collector +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: appscode:system:metrics-collector +subjects: +- apiGroup: rbac.authorization.k8s.io + kind: User + name: system:anonymous +``` + +```bash +$ kubectl auth reconcile -f docs/examples/monitoring/metrics-collector.yaml +clusterrole.rbac.authorization.k8s.io "appscode:system:metrics-collector" reconciled +clusterrolebinding.rbac.authorization.k8s.io "appscode:system:metrics-collector" reconciled +``` + +2. Now, forward the port `:8443` to your workstation. + +``` +$ kubectl get pods -n voyager | grep voyager +voyager-operator-f89dcccdb-plvmt 1/1 Running 0 27m + +$ kubectl port-forward -n voyager voyager-operator-f89dcccdb-plvmt 8443 +Forwarding from 127.0.0.1:8443 -> 8443 +Forwarding from [::1]:8443 -> 8443 +``` + +3. Now, visit the url: https://127.0.0.1:8443/metrics + +![operator-metrics](/docs/v2024.3.18/images/monitoring/operator-metrics.png) + +4. Once you are done, remove access to `system:anonymous` user. + +```bash +$ kubectl delete -f docs/examples/monitoring/metrics-collector.yaml +clusterrole.rbac.authorization.k8s.io "appscode:system:metrics-collector" deleted +clusterrolebinding.rbac.authorization.k8s.io "appscode:system:metrics-collector" deleted +``` diff --git a/content/docs/v2024.3.18/guides/ingress/monitoring/using-builtin-prometheus.md b/content/docs/v2024.3.18/guides/ingress/monitoring/using-builtin-prometheus.md new file mode 100644 index 000000000..bdb2a4c07 --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/monitoring/using-builtin-prometheus.md @@ -0,0 +1,299 @@ +--- +title: Monitor HAProxy using Prometheus +menu: + docs_v2024.3.18: + identifier: builtin-prom-monitoring + name: Monitor HAProxy using Prometheus + parent: monitoring-ingress + weight: 15 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# Monitor HAProxy using Prometheus + +This tutorial will show you how to monitor Voyager managed HAProxy pods using builtin [Prometheus](https://prometheus.io/) scraper. + +## Before You Begin + +At first, you need to have a Kubernetes cluster, and the kubectl command-line tool must be configured to communicate with your cluster. If you do not already have a cluster, you can create one by using [Minikube](https://github.com/kubernetes/minikube). + +Now, deploy Voyager operator following instructions [here](/docs/v2024.3.18/setup/install). + +To keep things isolated, this tutorial uses a separate namespace called `demo` throughout this tutorial. Run the following command to prepare your cluster for this tutorial: + +```bash +$ kubectl create namespace demo +namespace "demo" created + +$ kubectl get ns +NAME STATUS AGE +default Active 45m +demo Active 10s +kube-public Active 45m +voyager Active 45m +``` + +Note that the yaml files that are used in this tutorial, stored in [docs/examples](https://github.com/voyagermesh/voyager/tree/master/docs/examples/monitoring) folder in GitHub repository [voyagermesh/voyager](https://github.com/voyagermesh/voyager). + +## Create Ingress + +We are going to use a nginx server as the backend. To deploy nginx server, run the following commands: + +```bash +kubectl run nginx --image=nginx -n demo +kubectl expose deployment nginx --name=web --port=80 --target-port=80 -n demo +``` + +Now create Ingress `ing.yaml` + +```bash +$ kubectl apply -f https://raw.githubusercontent.com/voyagermesh/voyager/{{< param "info.version" >}}/docs/examples/monitoring/builtin-prometheus/ing.yaml +ingress "stats-ing" created +``` + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: stats-ing + namespace: demo + annotations: + ingress.appscode.com/type: 'NodePort' + ingress.appscode.com/stats: 'true' + ingress.appscode.com/monitoring-agent: 'prometheus.io/builtin' +spec: + rules: + - host: voyager.appscode.test + http: + paths: + - path: / + backend: + service: + name: web + port: + number: 80 +``` + +Voyager operator watches for `Ingress` objects using Kubernetes api. When a `Ingress` object is created, Voyager operator will create a new HAProxy deployment and a NodePort Service with name `voyager-{ingress-name}`. Since `ingress.appscode.com/stats` annotation was configured, a stats service object is configured accordingly. Here, + +| Keys | Value | Default | Description | +|-----------------------------------------|---------|-----------|---------------------------------------------------| +| ingress.appscode.com/stats | bool | `"false"` | `Required`. If set, HAProxy stats will be exposed | +| ingress.appscode.com/monitoring-agent | string | | `Required`. Indicates the monitoring agent used. Here built-in scraper in [Prometheus](https://github.com/prometheus/prometheus) is used to monitor the HAProxy pods. Voyager operator will configure the stats service in a way that the Prometheus server will automatically find out the service endpoint and scrape metrics from exporter. | + +You can verify it running the following commands: + +```bash +$ kubectl get pods,svc -n demo +NAME READY STATUS RESTARTS AGE +po/nginx-8586cf59-r2m59 1/1 Running 0 1m +po/voyager-stats-ing-5bf6b54949-5zs4x 2/2 Running 0 1m + +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +svc/voyager-stats-ing NodePort 10.111.51.103 80:31094/TCP 1m +svc/voyager-stats-ing-stats ClusterIP 10.97.119.249 56789/TCP,56790/TCP 1m +svc/web ClusterIP 10.98.249.140 80/TCP 1m +``` + +```yaml +$ kubectl get svc -n demo voyager-stats-ing-stats -o yaml + +apiVersion: v1 +kind: Service +metadata: + annotations: + ingress.appscode.com/origin-api-schema: voyager.appscode.com/v1 + ingress.appscode.com/origin-name: stats-ing + monitoring.appscode.com/agent: prometheus.io/builtin + prometheus.io/path: /voyager.appscode.com/v1/namespaces/demo/ingresses/stats-ing/metrics + prometheus.io/port: "56790" + prometheus.io/scrape: "true" + creationTimestamp: 2018-02-25T21:48:24Z + labels: + feature: stats + origin: voyager + origin-api-group: voyager.appscode.com + origin-name: stats-ing + name: voyager-stats-ing-stats + namespace: demo + resourceVersion: "317" + selfLink: /api/v1/namespaces/demo/services/voyager-stats-ing-stats + uid: 9ac02c7c-1a75-11e8-a133-080027640ad5 +spec: + clusterIP: 10.97.119.249 + ports: + - name: stats + port: 56789 + protocol: TCP + targetPort: stats + - name: http + port: 56790 + protocol: TCP + targetPort: http + selector: + origin: voyager + origin-api-group: voyager.appscode.com + origin-name: stats-ing + sessionAffinity: None + type: ClusterIP +status: + loadBalancer: {} +``` + +We can see that the service contains these specific annotations. The Prometheus server will discover the exporter using these specifications. + +```yaml +prometheus.io/path: ... +prometheus.io/port: ... +prometheus.io/scrape: ... +``` + +## Deploy and configure Prometheus Server + +The Prometheus server is needed to configure so that it can discover endpoints of services. If a Prometheus server is already running in cluster and if it is configured in a way that it can discover service endpoints, no extra configuration will be needed. If there is no existing Prometheus server running, rest of this tutorial will create a Prometheus server with appropriate configuration. + +The configuration file to `Prometheus-Server` will be provided by `ConfigMap`. The below config map will be created: + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: prometheus-server-conf + labels: + name: prometheus-server-conf + namespace: demo +data: + prometheus.yml: |- + global: + scrape_interval: 5s + evaluation_interval: 5s + scrape_configs: + - job_name: 'kubernetes-service-endpoints' + + kubernetes_sd_configs: + - role: endpoints + + relabel_configs: + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape] + action: keep + regex: true + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme] + action: replace + target_label: __scheme__ + regex: (https?) + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path] + action: replace + target_label: __metrics_path__ + regex: (.+) + - source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port] + action: replace + target_label: __address__ + regex: ([^:]+)(?::\d+)?;(\d+) + replacement: $1:$2 + - action: labelmap + regex: __meta_kubernetes_service_label_(.+) + - source_labels: [__meta_kubernetes_namespace] + action: replace + target_label: kubernetes_namespace + - source_labels: [__meta_kubernetes_service_name] + action: replace + target_label: kubernetes_name +``` + +```bash +$ kubectl create -f https://raw.githubusercontent.com/voyagermesh/voyager/{{< param "info.version" >}}/docs/examples/monitoring/builtin-prometheus/demo-1.yaml +configmap "prometheus-server-conf" created +``` + +Now, the below yaml is used to deploy Prometheus in kubernetes : + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: prometheus-server + namespace: demo +spec: + replicas: 1 + selector: + matchLabels: + app: prometheus-server + template: + metadata: + labels: + app: prometheus-server + spec: + containers: + - name: prometheus + image: prom/prometheus:v2.1.0 + args: + - "--config.file=/etc/prometheus/prometheus.yml" + - "--storage.tsdb.path=/prometheus/" + ports: + - containerPort: 9090 + volumeMounts: + - name: prometheus-config-volume + mountPath: /etc/prometheus/ + - name: prometheus-storage-volume + mountPath: /prometheus/ + volumes: + - name: prometheus-config-volume + configMap: + defaultMode: 420 + name: prometheus-server-conf + - name: prometheus-storage-volume + emptyDir: {} +``` + +Now, run the following command to deploy prometheus in kubernetes: + +```bash +$ kubectl create -f https://raw.githubusercontent.com/voyagermesh/voyager/{{< param "info.version" >}}/docs/examples/monitoring/builtin-prometheus/demo-2.yaml +clusterrole "prometheus-server" created +serviceaccount "prometheus-server" created +clusterrolebinding "prometheus-server" created +deployment "prometheus-server" created +service "prometheus-service" created +``` + +### Prometheus Dashboard + +Now to open prometheus dashboard on Browser: + +```bash +$ kubectl get svc -n demo +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +voyager ClusterIP None 59m +mgo-mon-prometheus ClusterIP 10.104.88.103 27017/TCP,56790/TCP 59m +prometheus-service LoadBalancer 10.103.201.246 9090:30901/TCP 8s + + +$ minikube ip +192.168.99.100 + +$ minikube service prometheus-service -n demo --url +http://192.168.99.100:30901 +``` + +Now, open your browser and go to the following URL: _http://{minikube-ip}:{prometheus-svc-nodeport}_ to visit Prometheus Dashboard. According to the above example, this URL will be [http://192.168.99.100:30901](http://192.168.99.100:30901). + +Now, if you go the Prometheus Dashboard, you should see that the HAProxy pod as one of the targets. + +![prometheus-builtin](/docs/v2024.3.18/images/monitoring/builtin-prometheus.png) + +## Cleaning up + +To cleanup the Kubernetes resources created by this tutorial, run: + +```bash +$ kubectl delete ns demo +namespace "demo" deleted +``` diff --git a/content/docs/v2024.3.18/guides/ingress/monitoring/using-coreos-prometheus-operator.md b/content/docs/v2024.3.18/guides/ingress/monitoring/using-coreos-prometheus-operator.md new file mode 100644 index 000000000..3831a1b20 --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/monitoring/using-coreos-prometheus-operator.md @@ -0,0 +1,217 @@ +--- +title: Monitor HAProxy using CoreOS Prometheus operator +menu: + docs_v2024.3.18: + identifier: coreos-operator-monitoring + name: Monitor with CoreOS Prometheus operator + parent: monitoring-ingress + weight: 20 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# Monitor HAProxy using CoreOS Prometheus operator + +This tutorial will show you how to monitor Voyager managed HAProxy pods using Prometheus via [CoreOS Prometheus Operator](https://github.com/coreos/prometheus-operator). + +## Before You Begin + +At first, you need to have a Kubernetes cluster, and the kubectl command-line tool must be configured to communicate with your cluster. If you do not already have a cluster, you can create one by using [Minikube](https://github.com/kubernetes/minikube). + +Now, deploy Voyager operator following instructions [here](/docs/v2024.3.18/setup/install). + +To keep things isolated, this tutorial uses a separate namespace called `demo` throughout this tutorial. Run the following command to prepare your cluster for this tutorial: + +```bash +$ kubectl create namespace demo +namespace "demo" created + +$ kubectl get ns +NAME STATUS AGE +default Active 45m +demo Active 10s +kube-public Active 45m +voyager Active 45m +``` + +Note that the yaml files that are used in this tutorial, stored in [docs/examples](https://github.com/voyagermesh/voyager/tree/master/docs/examples/monitoring) folder in GitHub repository [voyagermesh/voyager](https://github.com/voyagermesh/voyager). + +## Deploy CoreOS-Prometheus Operator + +Now, run the following command to prepare your cluster for this tutorial: + +```bash +$ kubectl create -f https://raw.githubusercontent.com/voyagermesh/voyager/{{< param "info.version" >}}/docs/examples/monitoring/coreos-operator/demo-0.yaml +clusterrole "prometheus-operator" created +serviceaccount "prometheus-operator" created +clusterrolebinding "prometheus-operator" created +deployment "prometheus-operator" created + +$ kubectl get pods -n demo --watch +NAME READY STATUS RESTARTS AGE +prometheus-operator-79cb9dcd4b-2njgq 1/1 Running 0 2m + + +$ kubectl get crd +NAME AGE +alertmanagers.monitoring.coreos.com 11m +prometheuses.monitoring.coreos.com 11m +servicemonitors.monitoring.coreos.com 11m +``` + +Once the Prometheus operator CRDs are registered, run the following command to create a Prometheus. + +```bash +$ kubectl create -f https://raw.githubusercontent.com/voyagermesh/voyager/{{< param "info.version" >}}/docs/examples/monitoring/coreos-operator/demo-1.yaml +clusterrole "prometheus" created +serviceaccount "prometheus" created +clusterrolebinding "prometheus" created +prometheus "prometheus" created +service "prometheus" created +``` + +### Prometheus Dashboard + +Now to open prometheus dashboard on Browser: + +```bash +$ kubectl get svc -n demo +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +prometheus LoadBalancer 10.99.201.154 9090:30900/TCP 5m +prometheus-operated ClusterIP None 9090/TCP 5m + +$ minikube ip +192.168.99.100 + +$ minikube service prometheus -n demo --url +http://192.168.99.100:30900 +``` + +Now, open your browser and go to the following URL: _http://{minikube-ip}:{prometheus-svc-nodeport}_ to visit Prometheus Dashboard. According to the above example, this URL will be [http://192.168.99.100:30900](http://192.168.99.100:30900). + +## Create Ingress + +We are going to use a nginx server as the backend. To deploy nginx server, run the following commands: + +```bash +kubectl run nginx --image=nginx -n demo +kubectl expose deployment nginx --name=web --port=80 --target-port=80 -n demo +``` + +Now create Ingress `ing.yaml` + +```bash +$ kubectl apply -f https://raw.githubusercontent.com/voyagermesh/voyager/{{< param "info.version" >}}/docs/examples/monitoring/coreos-operator/ing.yaml +ingress "stats-ing" created +``` + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: stats-ing + namespace: demo + annotations: + ingress.appscode.com/type: 'NodePort' + ingress.appscode.com/stats: 'true' + ingress.appscode.com/monitoring-agent: 'prometheus.io/coreos-operator' + ingress.appscode.com/service-monitor-labels: '{"app": "voyager"}' + ingress.appscode.com/service-monitor-namespace: 'demo' +spec: + rules: + - host: voyager.appscode.test + http: + paths: + - path: / + backend: + service: + name: web + port: + number: 80 +``` + +Voyager operator watches for `Ingress` objects using Kubernetes api. When a `Ingress` object is created, Voyager operator will create a new HAProxy deployment and a NodePort Service with name `voyager-{ingress-name}`. Since `ingress.appscode.com/stats` annotation was configured, a stats service object is configured accordingly. Here, + +| Keys | Value | Default | Description | +|---------------------------------------------------------------|---------|---------|---------------------------------------------| +| ingress.appscode.com/stats | bool | `false` | `Required`. If set, HAProxy stats will be exposed | +| ingress.appscode.com/monitoring-agent | string | | `Required`. Indicates the monitoring agent used. Here, we are using [CoreOS Prometheus Operator](https://coreos.com/operators/prometheus/docs/latest/). This agent was previously identified as `coreos-prometheus-operator` | +| ingress.appscode.com/service-monitor-labels | map | | `Required`. Indicates labels applied to service monitor. | +| ingress.appscode.com/service-monitor-namespace | string | | `Required`. Indicates namespace where service monitors are created. This must be the same namespace of the Prometheus instance. | +| ingress.appscode.com/service-monitor-endpoint-port | integer | 56790 | `Optional`. Indicates the port used by exporter side-car to expose Prometheus metrics endpoint. If the default port 56790 is used to expose traffic, change it to an unused port. | +| ingress.appscode.com/service-monitor-endpoint-scrape-interval | string | | `Optional`. Indicates the scrape interval for HAProxy exporter endpoint + +You can verify it running the following commands: + +```bash +$ kubectl get pods,svc -n demo +NAME READY STATUS RESTARTS AGE +po/nginx-8586cf59-rbc7x 1/1 Running 0 5m +po/prometheus-operator-6c5f58dc5b-67wgb 1/1 Running 0 7m +po/prometheus-prometheus-0 2/2 Running 0 7m +po/voyager-stats-ing-5bf6b54949-kmc9w 2/2 Running 0 3m + +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +svc/prometheus LoadBalancer 10.111.248.128 9090:30900/TCP 7m +svc/prometheus-operated ClusterIP None 9090/TCP 7m +svc/voyager-stats-ing NodePort 10.105.130.139 80:31916/TCP 3m +svc/voyager-stats-ing-stats ClusterIP 10.111.55.62 56789/TCP,56790/TCP 3m +svc/web ClusterIP 10.107.186.226 80/TCP 5m +``` + +```yaml +$ kubectl get servicemonitor -n demo +NAME AGE +voyager-demo-stats-ing 4m + +$ kubectl get servicemonitor -n demo voyager-demo-stats-ing -o yaml +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + clusterName: "" + creationTimestamp: 2018-02-25T22:20:48Z + labels: + app: voyager + monitoring.appscode.com/service: voyager-stats-ing-stats.demo + name: voyager-demo-stats-ing + namespace: demo + resourceVersion: "1820" + selfLink: /apis/monitoring.coreos.com/v1/namespaces/demo/servicemonitors/voyager-demo-stats-ing + uid: 217225cb-1a7a-11e8-a133-080027640ad5 +spec: + endpoints: + - path: /voyager.appscode.com/v1/namespaces/demo/ingresses/stats-ing/metrics + port: http + targetPort: 0 + namespaceSelector: + matchNames: + - demo + selector: + matchLabels: + feature: stats + origin: voyager + origin-api-group: voyager.appscode.com + origin-name: stats-ing +``` + +Now, if you go the Prometheus Dashboard, you should see that this database endpoint as one of the targets. + +![coreos-operator](/docs/v2024.3.18/images/monitoring/coreos-operator.png) + +__Known Limitations:__ If the database password is updated, exporter must be restarted to use the new credentials. This issue is tracked [here](https://github.com/kubedb/project/issues/53). + +## Cleaning up + +To cleanup the Kubernetes resources created by this tutorial, run: + +```bash +$ kubectl delete ns demo +namespace "demo" deleted +``` diff --git a/content/docs/v2024.3.18/guides/ingress/pod-placement.md b/content/docs/v2024.3.18/guides/ingress/pod-placement.md new file mode 100644 index 000000000..890b3426a --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/pod-placement.md @@ -0,0 +1,292 @@ +--- +title: Placement of Ingress Pods | Voyager +menu: + docs_v2024.3.18: + identifier: pod-placement-ingress + name: Pod Placement + parent: ingress-guides + weight: 50 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# Placement of Ingress Pods + +Voyager has rich support for how HAProxy pods are placed on cluster nodes. Please check [here](https://kubernetes.io/docs/concepts/configuration/assign-pod-node/) to understand Kubernetes' support for pod placement. + +## Before You Begin + +At first, you need to have a Kubernetes cluster, and the kubectl command-line tool must be configured to communicate with your cluster. If you do not already have a cluster, you can create one by using [Minikube](https://github.com/kubernetes/minikube). + +Now, install Voyager operator in your cluster following the steps [here](/docs/v2024.3.18/setup/install). + +To keep things isolated, this tutorial uses a separate namespace called `demo` throughout this tutorial. Run the following command to prepare your cluster for this tutorial: + +```bash +$ curl -fSsL https://raw.githubusercontent.com/voyagermesh/voyager/{{< param "info.version" >}}/docs/examples/ingress/pod-placement/deploy-servers.sh | bash ++ kubectl create namespace demo +namespace "demo" created ++ kubectl run nginx --image=nginx --namespace=demo +deployment "nginx" created ++ kubectl expose deployment nginx --name=web --namespace=demo --port=80 --target-port=80 +service "web" exposed ++ kubectl run echoserver --image=gcr.io/google_containers/echoserver:1.4 --namespace=demo +deployment "echoserver" created ++ kubectl expose deployment echoserver --name=rest --namespace=demo --port=80 --target-port=8080 +service "rest" exposed +``` + +### Choosing Workload Kind + +By default Voyager will run HAProxy pods using `Deployment`. Since 8.0.1 release, Voyager can run HAProxy pods using either Deployment or DaemonSet. Set the annotation `ingress.appscode.com/workload-kind` on an ingress object to either `Deployment` or `DaemonSet` to enable this feature. If this annotation is missing, HAProxy pods will be run using a `Deployment` as before. + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: ingress-w-node-selector + namespace: demo + annotations: + ingress.appscode.com/workload-kind: DaemonSet +``` + +### Using Node Selector + +[Node selectors](https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector) can be used assign HAProxy ingress pods to specific nodes. Below is an example where ingress pods are run on node with name`minikube`. + +```bash +kubectl apply -f https://raw.githubusercontent.com/voyagermesh/voyager/{{< param "info.version" >}}/docs/examples/ingress/pod-placement/ingress-w-node-selector.yaml +``` + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: ingress-w-node-selector + namespace: demo + annotations: + ingress.appscode.com/type: NodePort + ingress.appscode.com/use-node-port: 'true' + ingress.appscode.com/replicas: '2' +spec: + nodeSelector: + kubernetes.io/hostname: minikube + rules: + - http: + paths: + - path: / + backend: + service: + name: rest + port: + number: 80 + - path: /web + backend: + service: + name: web + port: + number: 80 +``` + +If you are using official `networking.k8s.io/v1` ingress api group, use `ingress.appscode.com/node-selector` annotation to provide the selectors. For example: + +``` +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: ingress-w-node-selector + namespace: demo + annotations: + ingress.appscode.com/type: NodePort + ingress.appscode.com/use-node-port: 'true' + ingress.appscode.com/replicas: '2' + ingress.appscode.com/node-selector: '{"kubernetes.io/hostname": "minikube"}' +spec: + rules: + - http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: rest + port: + number: 80 + - path: /web + pathType: Prefix + backend: + service: + name: web + port: + number: 80 +``` + +### Using Pod Anti-affinity + +[Affinity rules](https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity) can be used assign HAProxy ingress pods to specific nodes or ensure that 2 separate HAProxy ingress pods are not placed on same node. Affinity rules are set via `spec.affinity` field in Voyager Ingress CRD. Below is an example where ingress pods are spread over run on node with name`minikube`. + +```bash +kubectl apply -f https://raw.githubusercontent.com/voyagermesh/voyager/{{< param "info.version" >}}/docs/examples/ingress/pod-placement/ingress-w-pod-anti-affinity.yaml +``` + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: ingress-w-pod-anti-affinity + namespace: demo + annotations: + ingress.appscode.com/type: NodePort + ingress.appscode.com/use-node-port: 'true' + ingress.appscode.com/replicas: '2' +spec: + rules: + - http: + paths: + - path: / + backend: + service: + name: rest + port: + number: 80 + - path: /web + backend: + service: + name: web + port: + number: 80 + affinity: + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchExpressions: + - key: origin + operator: In + values: + - voyager + - key: origin-name + operator: In + values: + - voyager-ingress-w-pod-anti-affinity + topologyKey: 'kubernetes.io/hostname' +``` + +### Using Taints and Toleration + +Using [taints and toleration](https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/), you can run voyager pods on dedicated nodes. + +```bash +# taint nodes where only HAProxy ingress pods will run +kubectl taint nodes minikube IngressOnly=true:NoSchedule + +kubectl apply -f https://raw.githubusercontent.com/voyagermesh/voyager/{{< param "info.version" >}}/docs/examples/ingress/pod-placement/ingress-w-toleration.yaml +``` + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: ingress-w-toleration + namespace: demo + annotations: + ingress.appscode.com/type: NodePort + ingress.appscode.com/use-node-port: 'true' + ingress.appscode.com/replicas: '2' +spec: + rules: + - http: + paths: + - path: / + backend: + service: + name: rest + port: + number: 80 + - path: /web + backend: + service: + name: web + port: + number: 80 + tolerations: + - key: IngressOnly + operator: Equal + value: 'true' + effect: NoSchedule +``` + +If you are using official `networking.k8s.io/v1` ingress api group, use `ingress.appscode.com/tolerations` annotation to provide the toleration information. For example: + +``` +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: ingress-w-toleration + namespace: demo + annotations: + ingress.appscode.com/type: NodePort + ingress.appscode.com/use-node-port: 'true' + ingress.appscode.com/replicas: '2' + ingress.appscode.com/tolerations: '[{"key": "IngressOnly", "operator": "Equal", "value": "true", "effect": "NoSchedule"}]' +spec: + rules: + - http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: rest + port: + number: 80 + - path: /web + pathType: Prefix + backend: + service: + name: web + port: + number: 80 +``` + +You can use these various option in combination with each other to achieve desired result. Say, you want to run your HAProxy pods on master instances. This can be done using an Ingress like below: + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: ingress-w-node-selector + namespace: demo + annotations: + ingress.appscode.com/type: NodePort + ingress.appscode.com/use-node-port: 'true' + ingress.appscode.com/replicas: '2' +spec: + nodeSelector: + node-role.kubernetes.io/master: "" + rules: + - http: + paths: + - path: / + backend: + service: + name: rest + port: + number: 80 + - path: /web + backend: + service: + name: web + port: + number: 80 + tolerations: + - effect: NoSchedule + key: node-role.kubernetes.io/master + operator: Exists +``` diff --git a/content/docs/v2024.3.18/guides/ingress/scaling.md b/content/docs/v2024.3.18/guides/ingress/scaling.md new file mode 100644 index 000000000..424f1b2d0 --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/scaling.md @@ -0,0 +1,94 @@ +--- +title: Scaling Ingress | Voyager +menu: + docs_v2024.3.18: + identifier: scaling-ingress + name: Scaling Ingress + parent: ingress-guides + weight: 45 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# Scaling Ingress + +## Replicas + +For each Ingress resource, Voyager deploys HAProxy in a Deployment prefixed by +`voyager-` and the name of the Ingress. + +This Deployment has `.spec.replicas = 1` by default. To start the ingress with the desired +number of replicas, use the `ingress.appscode.com/replicas` annotation. + +Note that, Voyager won't sync with this annotation if there is a HPA controlling the ingress deployment. +This regulation is followed so that HPA on ingress deployment does not experience any conflicts. + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: my-app + namespace: default + annotations: + ingress.appscode.com/replicas: '2' +spec: + defaultBackend: + service: + name: my-app + port: + number: 80 +``` + +```bash +$ kubectl get deploy voyager-my-app +NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE +voyager-my-app 2 2 2 2 1d +``` + +## Horizontal Pod Autoscaling + +[Kubernetes has the HorizontalPodAutoscaler object for autoscaling pods](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/). + +> With Horizontal Pod Autoscaling, Kubernetes automatically scales the number +> of pods in a replication controller, deployment or replica set based on +> observed CPU utilization (or, with alpha support, on some other, application-provided metrics). + +To set up a HorizontalPodAutoscaler for a Voyager HAPRoxy deployment, you can +use the `kubectl autoscale` command or defining a HorizontalPodAutoscaler +resource. + +```bash +kubectl autoscale deployment voyager-my-app --cpu-percent=20 --min=2 --max=10 +``` + +```yaml +apiVersion: autoscaling/v1 +kind: HorizontalPodAutoscaler +metadata: + name: voyager-my-app + namespace: default +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: voyager-my-app + minReplicas: 2 + maxReplicas: 10 + targetCPUUtilizationPercentage: 20 +``` + +``` +$ kubectl get hpa +NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE +voyager-my-app Deployment/voyager-my-app 0% / 20% 2 10 2 1d +``` + +## Node Autoscaling +If you are using [autoscaler](https://github.com/kubernetes/autoscaler/tree/master/cluster-autoscaler) to dynamically add and remove nodes, you might be interested in using `ingress.appscode.com/node-selector` to control which hosts are selected to run HAProxy pods. This is a recommended annotation for HostPort type ingress. diff --git a/content/docs/v2024.3.18/guides/ingress/security/_index.md b/content/docs/v2024.3.18/guides/ingress/security/_index.md new file mode 100644 index 000000000..8e11de848 --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/security/_index.md @@ -0,0 +1,15 @@ +--- +title: Security +menu: + docs_v2024.3.18: + identifier: security-ingress + name: Security + parent: ingress-guides + weight: 35 +menu_name: docs_v2024.3.18 +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + diff --git a/content/docs/v2024.3.18/guides/ingress/security/basic-auth.md b/content/docs/v2024.3.18/guides/ingress/security/basic-auth.md new file mode 100644 index 000000000..a5dba5729 --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/security/basic-auth.md @@ -0,0 +1,295 @@ +--- +title: Basic Authentication | Kubernetes Ingress +menu: + docs_v2024.3.18: + identifier: basic-auth-security + name: Basic Auth + parent: security-ingress + weight: 10 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +aliases: +- /docs/v2024.3.18/guides/ingress/security/ +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# Basic Authentication + +This example demonstrates how to configure +[Basic Authentication](https://tools.ietf.org/html/rfc2617) on +Voyager Ingress controller. + + +## Using Basic Authentication + +Voyager Ingress read user and password from files stored on secrets, one user +and password per line. Secret name, realm and type are configured with annotations +in the ingress resource: + +* `ingress.appscode.com/auth-type`: the only supported type is `basic` +* `ingress.appscode.com/auth-realm`: an optional string with authentication realm +* `ingress.appscode.com/auth-secret`: name of the secret + +Each line of the `auth` file should have: + +* user and insecure password separated with a pair of colons: `::`; or +* user and an encrypted password separated with colons: `:` + +If passwords are provided in plain text, Voyager operator will encrypt them before rendering HAProxy configuration. +HAProxy evaluates encrypted passwords with [crypt](http://man7.org/linux/man-pages/man3/crypt.3.html) function. Use `mkpasswd` or +`makepasswd` to create it. `mkpasswd` can be found on Alpine Linux container. + +### Configure + +Create a secret to our users: + +* `john` and password `admin` using insecure plain text password +* `jane` and password `guest` using encrypted password + +```bash +$ mkpasswd -m des ## a short, des encryption, syntax from Busybox on Alpine Linux +Password: (type 'guest' and press Enter) +E5BrlrQ5IXYK2 + +$ cat >auth <

401 Unauthorized

+You need a valid user and password to access this content. + +``` + +Send a valid user: + +```bash +$ curl -i -u 'john:admin' ip:port +HTTP/1.1 200 OK +Date: Fri, 08 Sep 2017 09:31:43 GMT +Content-Length: 0 +Content-Type: text/plain; charset=utf-8 + +``` + +Using `jane:guest` user/passwd should have the same output. + +## Using Basic Auth for backend service + +Voyager Ingress can be configured to use Basic Auth per Backend service by applying the annotations to +kubernetes service. + +```yaml +apiVersion: v1 +kind: Service +metadata: + name: test-svc + namespace: default + annotations: + ingress.appscode.com/auth-type: basic + ingress.appscode.com/auth-realm: My Server + ingress.appscode.com/auth-secret: mypasswd +spec: + ports: + - name: http-1 + port: 80 + protocol: TCP + targetPort: 8080 + selector: + app: deployment +``` + +Create an Ingress with Basic Auth only on path `/auth` + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: hello-basic-auth + namespace: default +spec: + rules: + - http: + paths: + - path: /no-auth + backend: + service: + name: test-server + port: + number: 80 + - http: + paths: + - path: /auth + backend: + service: + name: test-svc + port: + number: 80 +``` + +Test without user and password: + +```bash +$ curl -i ip:port/auth +HTTP/1.0 401 Unauthorized +Cache-Control: no-cache +Connection: close +Content-Type: text/html +Authentication problem. Ignoring this. +WWW-Authenticate: Basic realm="My Server" + +

401 Unauthorized

+You need a valid user and password to access this content. + +``` + +Send a valid user: + +```bash +$ curl -i -u 'john:admin' ip:port/auth +HTTP/1.1 200 OK +Date: Fri, 08 Sep 2017 09:31:43 GMT +Content-Length: 0 +Content-Type: text/plain; charset=utf-8 + +``` + +No auth enabled Backend + +```bash +$ curl -i ip:port/no-auth +HTTP/1.1 200 OK +Date: Fri, 08 Sep 2017 09:31:43 GMT +Content-Length: 0 +Content-Type: text/plain; charset=utf-8 + +``` + +## Using Basic Auth In Frontend + +Basic Auth can also be configured per frontend in voyager ingress via FrontendRules. + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: hello-basic-auth + namespace: default +spec: + frontendRules: + - port: 8080 + auth: + basic: + secretName: mypasswd + realm: My Server + rules: + - http: + port: 80 + paths: + - path: /no-auth + backend: + service: + name: test-server + port: + number: 80 + - http: + port: 8080 + paths: + - path: /auth + backend: + service: + name: test-svc + port: + number: 80 +``` + +Test without user and password: + +```bash +$ curl -i ip:8080/auth +HTTP/1.0 401 Unauthorized +Cache-Control: no-cache +Connection: close +Content-Type: text/html +Authentication problem. Ignoring this. +WWW-Authenticate: Basic realm="My Server" + +

401 Unauthorized

+You need a valid user and password to access this content. + +``` + +Send a valid user: + +```bash +$ curl -i -u 'john:admin' ip:8080/auth +HTTP/1.1 200 OK +Date: Fri, 08 Sep 2017 09:31:43 GMT +Content-Length: 0 +Content-Type: text/plain; charset=utf-8 + +``` + +No auth enabled Backend +```bash +$ curl -i ip:9090/no-auth +HTTP/1.1 200 OK +Date: Fri, 08 Sep 2017 09:31:43 GMT +Content-Length: 0 +Content-Type: text/plain; charset=utf-8 + +``` + +## Acknowledgement + - This document has been adapted from [kubernetes/ingress](https://github.com/kubernetes/ingress/tree/master/examples/auth/basic/haproxy) project. diff --git a/content/docs/v2024.3.18/guides/ingress/security/oauth-dashboard.md b/content/docs/v2024.3.18/guides/ingress/security/oauth-dashboard.md new file mode 100644 index 000000000..e5d6d13a4 --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/security/oauth-dashboard.md @@ -0,0 +1,190 @@ +--- +title: Securing Kubernetes Dashboard | Kubernetes Ingress +menu: + docs_v2024.3.18: + identifier: oauth2-dashboard + name: Kubernetes Dashboard + parent: oauth2-security + weight: 20 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# Securing Kubernetes Dashboard Using GitHub Oauth + +In this example we will deploy kubernetes dashboard and access it through ingress. Also secure the access with voyager external auth using github as auth provider. + +## Deploy Dashboard + +``` +$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v1.8.3/src/deploy/recommended/kubernetes-dashboard.yaml +``` + +By default the dashboard configures HTTPS with a self signed certificate. We need to apply `ingress.appscode.com/backend-tls: ssl verify none` annotation to `kubernetes-dashboard` service so that haproxy pod can establish HTTPS connection with dashboard pod. + +``` +$ kubectl annotate service kubernetes-dashboard -n voyager ingress.appscode.com/backend-tls='ssl verify none' +``` + +## Configure GitHub Oauth App + +Configure github auth provider by following instructions provided [here](https://github.com/bitly/oauth2_proxy#github-auth-provider) and generate client-id and client-secret. + +Set `Authorization callback URL` to `https:///oauth2/callback`. In this example it is set to `https://voyager.appscode.ninja`. + +## Configure and Deploy Oauth Proxy + +```yaml +$ kubectl apply -f oauth2-proxy.yaml + +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + k8s-app: oauth2-proxy + name: oauth2-proxy + namespace: voyager +spec: + replicas: 1 + selector: + matchLabels: + k8s-app: oauth2-proxy + template: + metadata: + labels: + k8s-app: oauth2-proxy + spec: + containers: + - args: + - --provider=github + - --email-domain=* + - --upstream=file:///dev/null + - --http-address=0.0.0.0:4180 + - --cookie-secure=true + env: + - name: OAUTH2_PROXY_CLIENT_ID + value: ... + - name: OAUTH2_PROXY_CLIENT_SECRET + value: ... + - name: OAUTH2_PROXY_COOKIE_SECRET + value: ... + image: quay.io/pusher/oauth2_proxy:v3.1.0 + imagePullPolicy: Always + name: oauth2-proxy + ports: + - containerPort: 4180 + protocol: TCP +--- +apiVersion: v1 +kind: Service +metadata: + labels: + k8s-app: oauth2-proxy + name: oauth2-proxy + namespace: voyager +spec: + ports: + - name: http + port: 4180 + protocol: TCP + targetPort: 4180 + selector: + k8s-app: oauth2-proxy +``` + +## Create TLS Secret + +```bash +$ openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /tmp/tls.key -out /tmp/tls.crt -subj "/CN=voyager.appscode.ninja" +$ kubectl create secret tls tls-secret --key /tmp/tls.key --cert /tmp/tls.crt -n voyager +``` + +## Deploy Ingress + +```yaml +$ kubectl apply -f auth-ingress.yaml + +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: auth-ingress + namespace: voyager +spec: + tls: + - secretName: tls-secret + hosts: + - voyager.appscode.ninja + frontendRules: + - port: 443 + auth: + oauth: + - host: voyager.appscode.ninja + authBackend: auth-be + authPath: /oauth2/auth + signinPath: /oauth2/start + paths: + - / + rules: + - host: voyager.appscode.ninja + http: + paths: + - path: / + backend: + service: + name: kubernetes-dashboard + port: + number: 443 + - path: /oauth2 + backend: + name: auth-be + service: + name: oauth2-proxy + port: + number: 4180 +``` + +## Access DashBoard + +Now browse https://voyager.appscode.ninja, it will redirect you to GitHub login page. After successful login, it will redirect you to dashboard login page. + +We will use token of an existing service-account `replicaset-controller` to login dashboard. It should have permissions to see Replica Sets in the cluster. You can also create your own service-account with different roles. + +``` +$ kubectl describe serviceaccount -n voyager replicaset-controller + +Name: replicaset-controller +Namespace: voyager +Labels: +Annotations: +Image pull secrets: +Mountable secrets: replicaset-controller-token-b5mgw +Tokens: replicaset-controller-token-b5mgw +Events: +``` + +``` +$ kubectl describe secret replicaset-controller-token-b5mgw -n voyager + +Name: replicaset-controller-token-b5mgw +Namespace: voyager +Labels: +Annotations: kubernetes.io/service-account.name=replicaset-controller + kubernetes.io/service-account.uid=b53b12b6-693c-11e8-9cb8-8ee164da275a + +Type: kubernetes.io/service-account-token + +Data +==== +ca.crt: 1006 bytes +namespace: 11 bytes +token: ... +``` + +Now use the token to login dashboard. diff --git a/content/docs/v2024.3.18/guides/ingress/security/oauth-github.md b/content/docs/v2024.3.18/guides/ingress/security/oauth-github.md new file mode 100644 index 000000000..e96495f5a --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/security/oauth-github.md @@ -0,0 +1,287 @@ +--- +title: OAuth2 Authentication Using GitHub | Kubernetes Ingress +menu: + docs_v2024.3.18: + identifier: oauth2-github + name: OAuth2 GitHub + parent: oauth2-security + weight: 20 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# OAuth2 Authentication Using GitHub + +This example will demonstrate how to configure external authentication in both TLS and non-TLS mode using GitHub as auth provider. + +## Example using GitHub (no TLS) + +First configure github auth provider by following instructions provided [here](https://github.com/bitly/oauth2_proxy#github-auth-provider) and generate client-id and client-secret. + +Set `Authorization callback URL` to `http:///oauth2/callback`. +In this example it is set to `http://voyager.appscode.ninja`. + +Now deploy and expose a test server: + +```bash +$ kubectl run test-server --image=gcr.io/google_containers/echoserver:1.8 +$ kubectl expose deployment test-server --port=80 --target-port=8080 +``` + +Configure, deploy and expose oauth2-proxy: + +```yaml +$ kubectl apply -f oauth2-proxy.yaml + +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + k8s-app: oauth2-proxy + name: oauth2-proxy + namespace: default +spec: + replicas: 1 + selector: + matchLabels: + k8s-app: oauth2-proxy + template: + metadata: + labels: + k8s-app: oauth2-proxy + spec: + containers: + - args: + - --provider=github + - --email-domain=* + - --upstream=file:///dev/null + - --http-address=0.0.0.0:4180 + - --cookie-secure=false + - --set-xauthrequest=true + env: + - name: OAUTH2_PROXY_CLIENT_ID + value: ... + - name: OAUTH2_PROXY_CLIENT_SECRET + value: ... + - name: OAUTH2_PROXY_COOKIE_SECRET + value: ... + image: quay.io/pusher/oauth2_proxy:v3.1.0 + imagePullPolicy: Always + name: oauth2-proxy + ports: + - containerPort: 4180 + protocol: TCP +--- +apiVersion: v1 +kind: Service +metadata: + labels: + k8s-app: oauth2-proxy + name: oauth2-proxy + namespace: default +spec: + ports: + - name: http + port: 4180 + protocol: TCP + targetPort: 4180 + selector: + k8s-app: oauth2-proxy +``` + +Here, `--set-xauthrequest` flag sets `X-Auth-Request-User` and `X-Auth-Request-Email` headers, which will be forwarded to backend. + +Finally create the ingress: + +```yaml +$ kubectl apply -f auth-ingress.yaml + +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: auth-ingress + namespace: default +spec: + frontendRules: + - port: 80 + auth: + oauth: + - host: voyager.appscode.ninja + authBackend: auth-be + authPath: /oauth2/auth + signinPath: /oauth2/start + paths: + - /app + rules: + - host: voyager.appscode.ninja + http: + paths: + - path: /health + backend: + service: + name: test-server + port: + number: 80 + - path: /app + backend: + service: + name: test-server + port: + number: 80 + - path: /oauth2 + backend: + name: auth-be + service: + name: oauth2-proxy + port: + number: 4180 +``` + +Now browse the followings: + +- http://voyager.appscode.ninja/app (external-auth required) +- http://voyager.appscode.ninja/health (external-auth not required) + +## Example using GitHub (with TLS) + +First configure github auth provider by following instructions provided [here](https://github.com/bitly/oauth2_proxy#github-auth-provider) and generate client-id and client-secret. + +Set `Authorization callback URL` to `https:///oauth2/callback`. +In this example it is set to `https://voyager.appscode.ninja`. + +Now deploy and expose a test server: + +```bash +$ kubectl run test-server --image=gcr.io/google_containers/echoserver:1.8 +$ kubectl expose deployment test-server --port=80 --target-port=8080 +``` + +Create TLS secret: + +```bash +$ openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /tmp/tls.key -out /tmp/tls.crt -subj "/CN=voyager.appscode.ninja" +$ kubectl create secret tls tls-secret --key /tmp/tls.key --cert /tmp/tls.crt +``` + +Configure, deploy and expose oauth2-proxy: + +```yaml +$ kubectl apply -f oauth2-proxy.yaml + +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + k8s-app: oauth2-proxy + name: oauth2-proxy + namespace: default +spec: + replicas: 1 + selector: + matchLabels: + k8s-app: oauth2-proxy + template: + metadata: + labels: + k8s-app: oauth2-proxy + spec: + containers: + - args: + - --provider=github + - --email-domain=* + - --upstream=file:///dev/null + - --http-address=0.0.0.0:4180 + - --cookie-secure=true + - --set-xauthrequest=true + env: + - name: OAUTH2_PROXY_CLIENT_ID + value: ... + - name: OAUTH2_PROXY_CLIENT_SECRET + value: ... + - name: OAUTH2_PROXY_COOKIE_SECRET + value: ... + image: quay.io/pusher/oauth2_proxy:v3.1.0 + imagePullPolicy: Always + name: oauth2-proxy + ports: + - containerPort: 4180 + protocol: TCP +--- +apiVersion: v1 +kind: Service +metadata: + labels: + k8s-app: oauth2-proxy + name: oauth2-proxy + namespace: default +spec: + ports: + - name: http + port: 4180 + protocol: TCP + targetPort: 4180 + selector: + k8s-app: oauth2-proxy +``` + +Finally create the ingress: + +```yaml +$ kubectl apply -f auth-ingress.yaml + +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: auth-ingress + namespace: default +spec: + tls: + - secretName: tls-secret + hosts: + - voyager.appscode.ninja + frontendRules: + - port: 443 + auth: + oauth: + - host: voyager.appscode.ninja + authBackend: auth-be + authPath: /oauth2/auth + signinPath: /oauth2/start + paths: + - /app + rules: + - host: voyager.appscode.ninja + http: + paths: + - path: /health + backend: + service: + name: test-server + port: + number: 80 + - path: /app + backend: + service: + name: test-server + port: + number: 80 + - path: /oauth2 + backend: + name: auth-be + service: + name: oauth2-proxy + port: + number: 4180 +``` + +Now browse the followings: + +- https://voyager.appscode.ninja/app (external-auth required) +- https://voyager.appscode.ninja/health (external-auth not required) diff --git a/content/docs/v2024.3.18/guides/ingress/security/oauth-google.md b/content/docs/v2024.3.18/guides/ingress/security/oauth-google.md new file mode 100644 index 000000000..db7aad8a3 --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/security/oauth-google.md @@ -0,0 +1,289 @@ +--- +title: OAuth2 Authentication | Kubernetes Ingress +menu: + docs_v2024.3.18: + identifier: oauth2-google + name: OAuth2 Google + parent: oauth2-security + weight: 20 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# OAuth2 Authentication Using Google + +This example will demonstrate how to configure external authentication in both TLS and non-TLS mode using Google as auth provider. + +## Example using Google (no TLS) + +First configure google auth provider by following instructions provided [here](https://github.com/bitly/oauth2_proxy#google-auth-provider) and generate client-id and client-secret. + +In this example `Authorized JavaScript origins` is set to `http://voyager.appscode.ninja` +and `Authorized redirect URIs` is set to `http://voyager.appscode.ninja/oauth2/callback`. + +Now deploy and expose a test server: + +```bash +$ kubectl run test-server --image=gcr.io/google_containers/echoserver:1.8 +$ kubectl expose deployment test-server --port=80 --target-port=8080 +``` + +Configure, deploy and expose oauth2-proxy: + +```yaml +$ kubectl apply -f oauth2-proxy.yaml + +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + k8s-app: oauth2-proxy + name: oauth2-proxy + namespace: default +spec: + replicas: 1 + selector: + matchLabels: + k8s-app: oauth2-proxy + template: + metadata: + labels: + k8s-app: oauth2-proxy + spec: + containers: + - args: + - --provider=google + - --email-domain=* + - --upstream=file:///dev/null + - --http-address=0.0.0.0:4180 + - --cookie-secure=false + - --pass-authorization-header=true + - --set-authorization-header=true + - --set-xauthrequest=true + env: + - name: OAUTH2_PROXY_CLIENT_ID + value: ... + - name: OAUTH2_PROXY_CLIENT_SECRET + value: ... + - name: OAUTH2_PROXY_COOKIE_SECRET + value: ... + image: quay.io/pusher/oauth2_proxy:v3.1.0 + imagePullPolicy: Always + name: oauth2-proxy + ports: + - containerPort: 4180 + protocol: TCP +--- +apiVersion: v1 +kind: Service +metadata: + labels: + k8s-app: oauth2-proxy + name: oauth2-proxy + namespace: default +spec: + ports: + - name: http + port: 4180 + protocol: TCP + targetPort: 4180 + selector: + k8s-app: oauth2-proxy +``` + +Here, `--set-xauthrequest` flag sets `X-Auth-Request-User` and `X-Auth-Request-Email` headers, which will be forwarded to backend. `--pass-authorization-header` and `--set-authorization-header` set OIDC IDToken via `Authorization` Bearer header and `X-Auth-Request-Id-Token` header. + +Finally create the ingress: + +```yaml +$ kubectl apply -f auth-ingress.yaml + +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: auth-ingress + namespace: default +spec: + frontendRules: + - port: 80 + auth: + oauth: + - host: voyager.appscode.ninja + authBackend: auth-be + authPath: /oauth2/auth + signinPath: /oauth2/start + paths: + - /app + rules: + - host: voyager.appscode.ninja + http: + paths: + - path: /health + backend: + service: + name: test-server + port: + number: 80 + - path: /app + backend: + service: + name: test-server + port: + number: 80 + - path: /oauth2 + backend: + name: auth-be + service: + name: oauth2-proxy + port: + number: 4180 +``` + +Now browse the followings: + +- http://voyager.appscode.ninja/app (external-auth required) +- http://voyager.appscode.ninja/health (external-auth not required) + +## Example using Google (with TLS) + +First configure google auth provider by following instructions provided [here](https://github.com/bitly/oauth2_proxy#google-auth-provider) and generate client-id and client-secret. + +In this example `Authorized JavaScript origins` is set to `https://voyager.appscode.ninja` +and `Authorized redirect URIs` is set to `https://voyager.appscode.ninja/oauth2/callback`. + +Now deploy and expose a test server: + +```bash +$ kubectl run test-server --image=gcr.io/google_containers/echoserver:1.8 +$ kubectl expose deployment test-server --port=80 --target-port=8080 +``` + +Create TLS secret: + +```bash +$ openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /tmp/tls.key -out /tmp/tls.crt -subj "/CN=voyager.appscode.ninja" +$ kubectl create secret tls tls-secret --key /tmp/tls.key --cert /tmp/tls.crt +``` + +Configure, deploy and expose oauth2-proxy: + +```yaml +$ kubectl apply -f oauth2-proxy.yaml + +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + k8s-app: oauth2-proxy + name: oauth2-proxy + namespace: default +spec: + replicas: 1 + selector: + matchLabels: + k8s-app: oauth2-proxy + template: + metadata: + labels: + k8s-app: oauth2-proxy + spec: + containers: + - args: + - --provider=google + - --email-domain=* + - --upstream=file:///dev/null + - --http-address=0.0.0.0:4180 + - --cookie-secure=true + - --set-xauthrequest=true + env: + - name: OAUTH2_PROXY_CLIENT_ID + value: ... + - name: OAUTH2_PROXY_CLIENT_SECRET + value: ... + - name: OAUTH2_PROXY_COOKIE_SECRET + value: ... + image: quay.io/pusher/oauth2_proxy:v3.1.0 + imagePullPolicy: Always + name: oauth2-proxy + ports: + - containerPort: 4180 + protocol: TCP +--- +apiVersion: v1 +kind: Service +metadata: + labels: + k8s-app: oauth2-proxy + name: oauth2-proxy + namespace: default +spec: + ports: + - name: http + port: 4180 + protocol: TCP + targetPort: 4180 + selector: + k8s-app: oauth2-proxy +``` + +Finally create the ingress: + +```yaml +$ kubectl apply -f auth-ingress.yaml + +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: auth-ingress + namespace: default +spec: + tls: + - secretName: tls-secret + hosts: + - voyager.appscode.ninja + frontendRules: + - port: 443 + auth: + oauth: + - host: voyager.appscode.ninja + authBackend: auth-be + authPath: /oauth2/auth + signinPath: /oauth2/start + paths: + - /app + rules: + - host: voyager.appscode.ninja + http: + paths: + - path: /health + backend: + service: + name: test-server + port: + number: 80 + - path: /app + backend: + service: + name: test-server + port: + number: 80 + - path: /oauth2 + backend: + name: auth-be + service: + name: oauth2-proxy + port: + number: 4180 +``` + +Now browse the followings: + +- https://voyager.appscode.ninja/app (external-auth required) +- https://voyager.appscode.ninja/health (external-auth not required) \ No newline at end of file diff --git a/content/docs/v2024.3.18/guides/ingress/security/oauth.md b/content/docs/v2024.3.18/guides/ingress/security/oauth.md new file mode 100644 index 000000000..2bb5129ab --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/security/oauth.md @@ -0,0 +1,146 @@ +--- +title: OAuth2 Authentication | Kubernetes Ingress +menu: + docs_v2024.3.18: + identifier: oauth2-security + name: OAuth2 + parent: security-ingress + weight: 20 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# OAuth2 Authentication + +You can configure [external authentication / oauth](https://oauth.net/2/) on Voyager Ingress controller via `frontendrules`. For this you have to configure and expose [oauth2-proxy](https://github.com/bitly/oauth2_proxy) and specify it as a backend under same host. For example: + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: auth-ingress + namespace: default +spec: + frontendRules: + - port: 80 + auth: + oauth: + - host: voyager.appscode.ninja + authBackend: auth-be + authPath: /oauth2/auth + signinPath: /oauth2/start + paths: + - /app + rules: + - host: voyager.appscode.ninja + http: + paths: + - path: /health + backend: + service: + name: test-server + port: + number: 80 + - path: /app + backend: + service: + name: test-server + port: + number: 80 + - path: /oauth2 + backend: + name: auth-be + service: + name: oauth2-proxy + port: + number: 4180 +``` + +Please note the followings: + +- Oauth will be enabled only for the specified paths. It is not necessary that this paths should match with the paths specified in the http-rules. + +- Auth backend and app backend should be under same host. + +- For secure/tls connections, you have to set `cookie-secure=true` (default) and for insecure/non-tls connections, you have to set `cookie-secure=false` while configuring `oauth2-proxy`. + +- You can use any random string as `OAUTH2_PROXY_COOKIE_SECRET` while configuring `oauth2-proxy`. You can generate one using following command: + +```bash +$ python -c 'import os,base64; print base64.b64encode(os.urandom(16))' +``` + +- If you use standard ports, you have to write frontend rules under port `80` for non-tls and under port `443` for tls. + +- You can not use different auth backends for different paths under same host and port. However, it is possible to configure different auth backends for different hosts under same port. For example: + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: auth-ingress + namespace: default +spec: + frontendRules: + - port: 80 + auth: + oauth: + - host: team01.example.com + authBackend: google-auth + authPath: /google/auth + signinPath: /google/start + paths: + - /foo + - host: team02.example.com + authBackend: github-auth + authPath: /github/auth + signinPath: /github/start + paths: + - /bar + rules: + - host: team01.example.com + http: + paths: + - path: /foo + backend: + service: + name: test-server + port: + number: 80 + - path: /google + backend: + name: google-auth + service: + name: oauth2-proxy-google + port: + number: 4180 + - host: team02.example.com + http: + paths: + - path: /bar + backend: + service: + name: test-server + port: + number: 80 + - path: /github + backend: + name: github-auth + service: + name: oauth2-proxy-github + port: + number: 4180 +``` + +## Next Steps + +- Learn how to configure GitHub as auth provider [here](oauth-github.md). +- Learn how to configure Google as auth provider [here](oauth-google.md). +- Learn how to secure Kubernetes Dashboard using voyager external auth [here](oauth-dashboard.md). diff --git a/content/docs/v2024.3.18/guides/ingress/security/restrict-namespace.md b/content/docs/v2024.3.18/guides/ingress/security/restrict-namespace.md new file mode 100644 index 000000000..9a7f9145a --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/security/restrict-namespace.md @@ -0,0 +1,2 @@ +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + diff --git a/content/docs/v2024.3.18/guides/ingress/security/tls-auth.md b/content/docs/v2024.3.18/guides/ingress/security/tls-auth.md new file mode 100644 index 000000000..8a4f186f6 --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/security/tls-auth.md @@ -0,0 +1,232 @@ +--- +title: TLS Authentication | Kubernetes Ingress +menu: + docs_v2024.3.18: + identifier: tls-auth-security + name: TLS Auth + parent: security-ingress + weight: 15 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# TLS Authentication + +This example demonstrates how to configure [TLS Authentication](https://tools.ietf.org/html/rfc2617) on Voyager Ingress controller. + +- [Using tls auth in Ingress](#using-tls-authentication) +- [Using tls auth in Frontend](#using-tls-auth-in-frontend) + +Before diving into the deep learn about TLS Auth with HAProxy. + +- [SSL Client certificate management at application level](https://www.haproxy.com/blog/ssl-client-certificate-management-at-application-level/) +- [Client side ssl certificates](https://raymii.org/s/tutorials/haproxy_client_side_ssl_certificates.html) + +## Using TLS Authentication + +Voyager Ingress read ca certificates from files stored on secrets with `ca.crt` key. + +- `ingress.appscode.com/auth-tls-secret`: Name of secret for TLS client certification validation. +- `ingress.appscode.com/auth-tls-error-page`: The page that user should be redirected in case of Auth error +- `ingress.appscode.com/auth-tls-verify-client`: Enables verification option of client certificates. + +### Configure + +Create tls secret for enable ssl termination: + +```bash +$ kubectl create secret tls server --cert=/path/to/cert/file --key=/path/to/key/file +``` + +Create ca cert secret: + +```bash +$ kubectl create secret generic ca --from-file=/path/to/ca.crt +``` + +Create an Ingress with TLS Auth annotations: + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + annotations: + ingress.appscode.com/auth-tls-secret: ca + ingress.appscode.com/auth-tls-verify-client: required + ingress.appscode.com/auth-tls-error-page: "https://auth.example.com/errors.html" + name: hello-tls-auth + namespace: default +spec: + tls: + - secretName: server + hosts: + - auth.example.com + rules: + - host: auth.example.com + http: + paths: + - path: /testpath + backend: + service: + name: test-server + port: + number: 80 +``` + +Test without certificates: + +```bash +$ curl -i -vvv 'https://auth.example.com' +* Hostname was NOT found in DNS cache +* Trying 192.168.99.100... +* Connected to http.appscode.test (192.168.99.100) port 443 (#0) +* successfully set certificate verify locations: +* CAfile: none + CApath: /etc/ssl/certs +* SSLv3, TLS handshake, Client hello (1): +* SSLv3, TLS handshake, Server hello (2): +* SSLv3, TLS handshake, CERT (11): +* SSLv3, TLS handshake, Server key exchange (12): +* SSLv3, TLS handshake, Request CERT (13): +* SSLv3, TLS handshake, Server finished (14): +* SSLv3, TLS handshake, CERT (11): +* SSLv3, TLS handshake, Client key exchange (16): +* SSLv3, TLS change cipher, Client hello (1): +* SSLv3, TLS handshake, Finished (20): +* SSLv3, TLS alert, Server hello (2): +* error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure +* Closing connection 0 +curl: (35) error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure +``` + +Send a valid client certificate: + +```bash +$ curl -v -s --key client.key --cert client.crt https://auth.example.com +HTTP/1.1 200 OK +Date: Fri, 08 Sep 2017 09:31:43 GMT +Content-Length: 0 +Content-Type: text/plain; charset=utf-8 + +``` + +Send a invalid client certificate, that will redirect to error page if provided: + +```bash +$ curl -v -s --key invalidclient.key --cert invalidclient.crt https://auth.example.com +HTTP/1.1 302 +Location: https://auth.example.com/errors.html +``` + +## Using TLS Auth In Frontend + +Basic Auth can also be configured per frontend in voyager ingress via FrontendRules. + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: hello-basic-auth + namespace: default +spec: + frontendRules: + - port: 8080 + auth: + tls: + secretName: server + verifyClient: required + errorPage: "https://auth.example.com/error.html" + headers: + X-SSL-Client-CN: "%{+Q}[ssl_c_s_dn(cn)]" # Add headers to Request based on SSL verification + X-SSL: "%[ssl_fc]", + tls: + - ref: + kind: Secret + name: server + hosts: + - auth.example.com + rules: + - host: auth.example.com + http: + paths: + - path: /no-auth + backend: + service: + name: test-server + port: + number: 80 + - host: auth.example.com + http: + port: 8080 + paths: + - path: /auth + backend: + service: + name: test-svc + port: + number: 80 +``` + +Request in non-tls port: + +```bash +$ curl -v -s https://auth.example.com +HTTP/1.1 200 OK +Date: Fri, 08 Sep 2017 09:31:43 GMT +Content-Length: 0 +Content-Type: text/plain; charset=utf-8 + +``` + +Test without certificates: + +```bash +$ curl -i -vvv 'https://auth.example.com:8080' +* Hostname was NOT found in DNS cache +* Trying 192.168.99.100... +* Connected to http.appscode.test (192.168.99.100) port 443 (#0) +* successfully set certificate verify locations: +* CAfile: none + CApath: /etc/ssl/certs +* SSLv3, TLS handshake, Client hello (1): +* SSLv3, TLS handshake, Server hello (2): +* SSLv3, TLS handshake, CERT (11): +* SSLv3, TLS handshake, Server key exchange (12): +* SSLv3, TLS handshake, Request CERT (13): +* SSLv3, TLS handshake, Server finished (14): +* SSLv3, TLS handshake, CERT (11): +* SSLv3, TLS handshake, Client key exchange (16): +* SSLv3, TLS change cipher, Client hello (1): +* SSLv3, TLS handshake, Finished (20): +* SSLv3, TLS alert, Server hello (2): +* error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure +* Closing connection 0 +curl: (35) error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure +``` + +Send a valid client certificate: + +```bash +$ curl -v -s --key client.key --cert client.crt https://auth.example.com:8080 +HTTP/1.1 200 OK +Date: Fri, 08 Sep 2017 09:31:43 GMT +Content-Length: 0 +Content-Type: text/plain; charset=utf-8 +``` + +Backend server will receive Headers `X-SSL` and `X-SSL-Client-CN`. + +Send a invalid client certificate, that will redirect to error page if provided: + +```bash +$ curl -v -s --key invalidclient.key --cert invalidclient.crt https://auth.example.com:8080 +HTTP/1.1 302 +Location: https://auth.example.com/errors.html +``` diff --git a/content/docs/v2024.3.18/guides/ingress/ssh.md b/content/docs/v2024.3.18/guides/ingress/ssh.md new file mode 100644 index 000000000..9a7f9145a --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/ssh.md @@ -0,0 +1,2 @@ +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + diff --git a/content/docs/v2024.3.18/guides/ingress/tcp/_index.md b/content/docs/v2024.3.18/guides/ingress/tcp/_index.md new file mode 100644 index 000000000..ea560bb8a --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/tcp/_index.md @@ -0,0 +1,15 @@ +--- +title: TCP +menu: + docs_v2024.3.18: + identifier: tcp-ingress + name: TCP + parent: ingress-guides + weight: 20 +menu_name: docs_v2024.3.18 +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + diff --git a/content/docs/v2024.3.18/guides/ingress/tcp/overview.md b/content/docs/v2024.3.18/guides/ingress/tcp/overview.md new file mode 100644 index 000000000..545188380 --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/tcp/overview.md @@ -0,0 +1,70 @@ +--- +title: TCP LoadBalancing | Kubernetes Ingress +menu: + docs_v2024.3.18: + identifier: overview-tcp + name: Overview + parent: tcp-ingress + weight: 10 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# TCP LoadBalancing + +TCP load balancing is one of the core features of Voyager Ingress. Voyager can handle TCP Load balancing with or without TLS. One Voyager Ingress can also be used to load balance both HTTP and TCP. + +One Simple TCP Rule Would be: + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: default +spec: + tls: + - secretName: mycert + hosts: + - other.example.com + rules: + - host: one.example.com + tcp: + port: 9898 + backend: + service: + name: tcp-service + port: + number: 50077 + - host: other.example.com + tcp: + port: 7878 + backend: + service: + name: tcp-service + port: + number: 50077 + - host: other.example.com + tcp: + port: 7800 + noTLS: true + backend: + service: + name: tcp-service + port: + number: 50077 +``` + +For this Ingress, HAProxy will open up 3 separate ports: +- port 9898: Passes traffic to pods behind tcp-service:50077. Uses no TLS, since `spec.TLS` does not have a matching host. + +- port 7878: Passes traffic to pods behind tcp-service:50077. Uses TLS, since `spec.TLS` has a matching host. + +- port 7880: Passes traffic to pods behind tcp-service:50077. __Uses no TLS__, even though `spec.TLS` has a matching host. This is because `tcp.noTLS` is set to true for this rule. diff --git a/content/docs/v2024.3.18/guides/ingress/tcp/tcp-sni.md b/content/docs/v2024.3.18/guides/ingress/tcp/tcp-sni.md new file mode 100644 index 000000000..66cdb5d16 --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/tcp/tcp-sni.md @@ -0,0 +1,194 @@ +--- +title: TCP SNI | Kubernetes Ingress +menu: + docs_v2024.3.18: + identifier: tcp-sni + name: TCP SNI + parent: tcp-ingress + weight: 20 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# Using TCP SNI + +In TCP mode, HAProxy can choose backends using Server Name Indication (SNI). This allows clients to include the hostname during `SSL Hello`. SNI hostname is send in plain text. So, HAProxy can choose backend based on SNI hostname even in TCP mode. + +This example demonstrates how to configure Voyager to choose backends based on SNI in TCP mode. + +## Minikube walk-through + +### Deploy test server + +```bash +$ kubectl apply -f https://raw.githubusercontent.com/appscode/voyager/master/test/test-server/deploy/test-server.yaml +``` + +### Create ingress + +```yaml +$ kubectl apply -f tcp-sni.yaml + +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: default + annotations: + ingress.appscode.com/type: NodePort + ingress.appscode.com/use-node-port: "true" +spec: + rules: + - host: voyager.appscode.test + tcp: + nodePort: 32666 + port: 8443 + backend: + service: + name: test-server + port: + number: 6443 + - host: voyager.appscode.com + tcp: + nodePort: 32666 + port: 8443 + backend: + service: + name: test-server + port: + number: 3443 +``` + +### Generated haproxy.cfg + +``` +# HAProxy configuration generated by https://github.com/appscode/voyager +# DO NOT EDIT! +global + daemon + stats socket /var/run/haproxy.sock level admin expose-fd listeners + server-state-file global + server-state-base /var/state/haproxy/ + # log using a syslog socket + log /dev/log local0 info + tune.ssl.default-dh-param 2048 + ssl-default-bind-ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK + lua-load /etc/auth-request.lua + hard-stop-after 30s +defaults + log global + # https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#4.2-option%20abortonclose + # https://github.com/voyagermesh/voyager/pull/403 + option dontlognull + option http-server-close + # Timeout values + timeout client 50s + timeout client-fin 50s + timeout connect 5s + timeout server 50s + timeout tunnel 50s + # Configure error files + # default traffic mode is http + # mode is overwritten in case of tcp services + mode http +frontend tcp-0_0_0_0-8443 + bind *:8443 + mode tcp + tcp-request inspect-delay 5s + tcp-request content accept if { req_ssl_hello_type 1 } + use_backend test-server.default:6443 if { req_ssl_sni -i voyager.appscode.test } + use_backend test-server.default:3443 if { req_ssl_sni -i voyager.appscode.com } +backend test-server.default:6443 + mode tcp + server pod-test-server-tct6l 172.17.0.4:6443 +backend test-server.default:3443 + mode tcp + server pod-test-server-tct6l 172.17.0.4:3443 +``` + +### Get service url + +```bash +$ minikube service --url voyager-test-ingress + +http://192.168.99.100:32666 +``` + +### Update /etc/hosts + +```bash +$ nano /etc/hosts + +192.168.99.100 voyager.appscode.test +192.168.99.100 voyager.appscode.com +192.168.99.100 voyager.appscode.org +``` + +### Send requests + +```bash +$ curl -k http://voyager.appscode.test:32666 +curl: (52) Empty reply from server + +$ curl -k https://voyager.appscode.test:32666 +{"type":"http","host":"voyager.appscode.test:8090","serverPort":":6443","path":"/","method":"GET","headers":{"Accept":["*/*"],"User-Agent":["curl/7.47.0"]}} + +$ curl -k https://voyager.appscode.com:32666 +{"type":"http","host":"voyager.appscode.com:8090","serverPort":":3443","path":"/","method":"GET","headers":{"Accept":["*/*"],"User-Agent":["curl/7.47.0"]}} + +$ curl -k https://voyager.appscode.org:32666 +curl: (35) gnutls_handshake() failed: The TLS connection was non-properly terminated. +``` + +- In 1st request is in `http`, so HAProxy could not resolve request SNI. +- In 2nd request, request is forwarded to `test-server:6443` based on host. +- In 3rd request, request is forwarded to `test-server:3443` based on host. +- In 4th request, host not matched with any rules, so no backend to serve the request. + +## Notes + +- For single host, traffic will be routed to backend without consulting SNI information. + +- You can specify TLS for multiple hosts, in that case HAProxy will terminate TLS and then choose backend based on SNI. + +- Conflicting TLS among different hosts under same port will cause validation error. That means you can't use TLS for one host, while other host under same port don't use TLS. Note that, if you specify `NoTLS=true` for any rule (both TCP and HTTP), voyager will ignore `Spec.TLS` for that rule. + +- All TCP rules under same port must have same set of ALPN options. Voyager will cause validation error if you specify ALPN for one rule but not for another rule or, different ALPN for different rules. + +- You can use wildcard hosts like `*.example.com`. + +- If host is not specified or, only `*` is used as host for any TCP rule, no other rule can be defined for that port. + +For example following will cause validation error: + +```yaml +spec: + rules: + - host: * + tcp: + port: 8443 + backend: + service: + name: test-server + port: + number: 6443 + - host: voyager.appscode.com + tcp: + port: 8443 + backend: + service: + name: test-server + port: + number: 3443 +``` + +## References + +- https://www.haproxy.com/blog/enhanced-ssl-load-balancing-with-server-name-indication-sni-tls-extension/ diff --git a/content/docs/v2024.3.18/guides/ingress/tls/_index.md b/content/docs/v2024.3.18/guides/ingress/tls/_index.md new file mode 100644 index 000000000..0c97ba44e --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/tls/_index.md @@ -0,0 +1,15 @@ +--- +title: TLS +menu: + docs_v2024.3.18: + identifier: tls-ingress + name: TLS + parent: ingress-guides + weight: 15 +menu_name: docs_v2024.3.18 +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + diff --git a/content/docs/v2024.3.18/guides/ingress/tls/aws-cert-manager.md b/content/docs/v2024.3.18/guides/ingress/tls/aws-cert-manager.md new file mode 100644 index 000000000..aebe99e49 --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/tls/aws-cert-manager.md @@ -0,0 +1,82 @@ +--- +title: Using AWS Certificate Manager | Kubernetes Ingress +menu: + docs_v2024.3.18: + identifier: aws-cm-tls + name: AWS Cert Manager + parent: tls-ingress + weight: 15 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# Using AWS Certificate Manager + +Voyager can use AWS certificate manager to terminate SSL connections for `LoadBalancer` type ingress in `aws` provider. To use this feature, +add the following annotations to Ingress; + +```yaml + ingress.appscode.com/annotations-service: | + { + "service.beta.kubernetes.io/aws-load-balancer-ssl-cert": "arn:aws:acm:...", + "service.beta.kubernetes.io/aws-load-balancer-backend-protocol": "http", + "service.beta.kubernetes.io/aws-load-balancer-ssl-ports": "443" + } +``` + +Voyager operator will apply these annotation on `LoadBalancer` service used to expose HAProxy to internet. +This service will (logically) listen on port 443, terminate SSL and forward to port 80 on HAProxy pods. Also, +ELB will listen on port 80 and forward cleartext traffic to port 80. + +```yaml +apiVersion: v1 +kind: Service +metadata: + name: + annotations: + service.beta.kubernetes.io/aws-load-balancer-ssl-cert: 'arn:aws:acm:...' + service.beta.kubernetes.io/aws-load-balancer-backend-protocol: http +spec: + type: LoadBalancer + ports: + - port: 443 + targetPort: 80 + - port: 80 + targetPort: 80 + ... +``` +[Elastic Load Balancing](http://docs.aws.amazon.com/elasticloadbalancing/latest/classic/x-forwarded-headers.html#x-forwarded-proto) +stores the protocol used between the client and the load balancer in the `X-Forwarded-Proto` request +header and passes the header along to HAProxy. The `X-Forwarded-Proto` request header helps HAProxy +identify the protocol (HTTP or HTTPS) that a client used to connect to load balancer. If you would +like to redirect cleartext client traffic on port 80 to port 443, please add redirect backend rules +when `X-Forwarded-Proto` header value is `HTTPS`. Please see the following ingress example and +[example rules](https://www.exratione.com/2014/10/managing-haproxy-configuration-when-your-server-may-or-may-not-be-behind-an-ssl-terminating-proxy/). + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-aws-ingress + namespace: default +spec: + rules: + - host: appscode.example.com + http: + paths: + - backend: + service: + name: test-service + port: + number: 80 + backendRules: + - 'acl is_proxy_https hdr(X-Forwarded-Proto) https' + - 'redirect scheme https code 301 if ! is_proxy_https' +``` diff --git a/content/docs/v2024.3.18/guides/ingress/tls/backend-tls.md b/content/docs/v2024.3.18/guides/ingress/tls/backend-tls.md new file mode 100644 index 000000000..1e899b458 --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/tls/backend-tls.md @@ -0,0 +1,88 @@ +--- +title: Backend TLS Support | Kubernetes Ingress +menu: + docs_v2024.3.18: + identifier: backend-tls + name: Backend TLS + parent: tls-ingress + weight: 20 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# Backend TLS Support + +Voyager can connect to a tls enabled backend server with or without ssl verification. + +Available options: + +- `ssl`: Creates a TLS/SSL socket when connecting to this server in order to cipher/decipher the traffic. If verify not set the following error may occurred: + +> Verify is enabled by default but no CA file specified. If you're running on a LAN where you're certain to trust the server's certificate, please set an explicit 'verify none' statement on the 'server' line, or use 'ssl-server-verify none' in the global section to disable server-side verifications by default. + +- `verify [none|required]`: Sets HAProxy‘s behavior regarding the certificated presented by the server: + - `none`: Doesn’t verify the certificate of the server + - `required (default value)`: TLS handshake is aborted if the validation of the certificate presented by the server returns an error. + +- `verifyhost `: Sets a to look for in the Subject and SubjectAlternateNames fields provided in the certificate sent by the server. If can’t be found, then the TLS handshake is aborted. This only applies when verify required is configured. + +- `ca-file `: Specify a CA file to verify the backend server. See [here](/docs/v2024.3.18/guides/ingress/configuration/config-volumes) for complete example. + +Example: `ingress.appscode.com/backend-tls: "ssl verify none"` + +If this annotation is not set HAProxy will connect to backend as http. This value should not be set if the backend do not support https resolution. + +Example: + +```yaml +kind: Service +apiVersion: v1 +metadata: + name: my-service + namespace: default + annotations: + ingress.appscode.com/backend-tls: ssl verify none +spec: + selector: + app: MyApp + ports: + - protocol: TCP + port: 80 + targetPort: 9376 +``` + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: default +spec: + defaultBackend: + service: + name: test-service + port: + number: 80 + rules: + - host: appscode.example.com + http: + paths: + - backend: + service: + name: my-service + port: + number: 80 +``` + +Reference: + +- https://cbonte.github.io/haproxy-dconv/1.8/configuration.html#5.2-ssl +- https://cbonte.github.io/haproxy-dconv/1.8/configuration.html#5.2-verify +- https://cbonte.github.io/haproxy-dconv/1.8/configuration.html#5.2-verifyhost diff --git a/content/docs/v2024.3.18/guides/ingress/tls/multiple-tls.md b/content/docs/v2024.3.18/guides/ingress/tls/multiple-tls.md new file mode 100644 index 000000000..5e616e614 --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/tls/multiple-tls.md @@ -0,0 +1,284 @@ +--- +title: Multiple TLS Certificates | Kubernetes Ingress +menu: + docs_v2024.3.18: + identifier: multiple-tls-certs + name: Multiple TLS Certificates + parent: tls-ingress + weight: 10 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# Multiple TLS Certificates + +You can secure an Ingress by specifying TLS secrets or `certificates.voyager.appscode.com` resources inside `spec.tls` section of the Ingress. Voyager writes the TLS secrets in `/etc/ssl/private/haproxy/tls/{secret-name}.pem` files inside the HAProxy pod. So if you specify multiple TLS secrets, all of them will be mounted in `/etc/ssl/private/haproxy/tls` folder. HAProxy presents the certificate to clients which matches with the TLS Server Name Indication (SNI) field of the request. If no SNI is provided by the client or if the SNI does not match with any certificate, then the first loaded certificate will be presented. So you need send request with correct SNI. Note that, `Host` header does not indicates the SNI. + +This tutorial will show you how to configure multiple TLS secrets/certificates for different hosts within a single ingress. + +## Before You Begin + +At first, you need to have a Kubernetes cluster, and the kubectl command-line tool must be configured to communicate with your cluster. Then install Voyager operator in your cluster by following the steps [here](/docs/v2024.3.18/setup/install). + +To keep things isolated, we will use a separate namespace called `demo` throughout this tutorial. Run the following command to prepare your cluster for this tutorial: + +```bash +$ kubectl create namespace demo +namespace "demo" created +``` + +## Deploy Test Servers + +Deploy a test server that serves two different ports. + +```yaml +$ kubectl apply -f test-server.yaml + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: test-server + namespace: demo +spec: + selector: + matchLabels: + app: test-server + template: + metadata: + labels: + app: test-server + spec: + containers: + - name: server + image: appscode/test-server:2.3 + imagePullPolicy: Always + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + ports: + - name: http-1 + containerPort: 8080 + - name: http-2 + containerPort: 8989 +--- +apiVersion: v1 +kind: Service +metadata: + name: test-server + namespace: demo + labels: + app: test-server +spec: + selector: + app: test-server + ports: + - port: 8080 + name: http-1 + protocol: TCP + targetPort: 8080 + - port: 8989 + name: http-2 + protocol: TCP + targetPort: 8989 +``` + +## Create Ingress Without TLS + +Create a ingress that points to the different port of the test server for different hosts. + +```yaml +$ kubectl apply -f ingress.yaml + +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: demo +spec: + rules: + - host: aa.appscode.ninja + http: + paths: + - backend: + service: + name: test-server + port: + number: 8080 + - host: bb.appscode.ninja + http: + paths: + - backend: + service: + name: test-server + port: + number: 8989 +``` + +## Configure DNS + +Get external IP for the ingress: + +```bash +$ kubectl get service -n demo + +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +test-server ClusterIP 10.55.242.68 8080/TCP,8989/TCP 6m +voyager-test-ingress LoadBalancer 10.55.249.12 104.154.239.169 80:31584/TCP 1m +``` + +Set the external IP of the ingress service to the DNS record for `aa.appscode.ninja` and `bb.appscode.ninja`. + +![google-dns](/docs/v2024.3.18/images/ingress/multiple-tls/google-dns.png) + +Now wait a little to confirm that these new domains are resolving: + +```bash +$ dig +short aa.appscode.ninja +104.154.239.169 + +$ dig +short bb.appscode.ninja +104.154.239.169 +``` + +## Check HTTP Response + +Visit `http://aa.appscode.ninja` and `http://bb.appscode.ninja` in your browser: + +![aa.appscode.ninja](/docs/v2024.3.18/images/ingress/multiple-tls/aa.appscode.ninja.png) +![bb.appscode.ninja](/docs/v2024.3.18/images/ingress/multiple-tls/bb.appscode.ninja.png) + +## Create Certificate + +In this tutorial we will issue free SSL certificates from Let’s Encrypt via DNS challenge for domains using Google Cloud DNS service. If you like to use HTTP challenge or other DNS service provider, please follow the docs [here](/docs/v2024.3.18/guides/certificate/). + +Create a secret with Google service account JSON key. Note that, this service account must have DNS Administrator permission. + +```bash +$ kubectl create secret generic voyager-gce -n demo \ + --from-literal=GCE_PROJECT= \ + --from-file=GOOGLE_SERVICE_ACCOUNT_JSON_KEY= +``` + +Create another secret to provide ACME user email. Change the email to a valid email address and run the following command: + +```bash +$ kubectl create secret generic acme-account --from-literal=ACME_EMAIL=me@example.com + -n demo +``` + +Create two Certificate CRDs to issue TLS certificates from Let’s Encrypt using DNS challenge: + +```yaml +$ kubectl apply -f certificate.yaml + +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: aa-ninja + namespace: demo +spec: + dnsNames: + - aa.appscode.ninja + issuerRef: + name: letsencrypt-staging-dns + secretName: aa-ninja +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: bb-ninja + namespace: demo +spec: + dnsNames: + - bb.appscode.ninja + issuerRef: + name: letsencrypt-staging-dns + secretName: bb-ninja +``` + +After several minutes, you should see two new secrets named `tls-aa-ninja` and `tls-bb-ninja`. These secrets contains the `tls.crt` and `tls.key`. + +```bash +$ kubectl get secrets -n demo + +NAME TYPE DATA AGE +acme-account Opaque 3 2m +default-token-ml4xb kubernetes.io/service-account-token 3 1h +tls-aa-ninja kubernetes.io/tls 2 47s +tls-bb-ninja kubernetes.io/tls 2 17s +voyager-gce Opaque 2 2m +voyager-test-ingress-token-8jbgh kubernetes.io/service-account-token 3 54m +``` + +## Ingress With TLS + +Update the previously created ingress and specify the certificates in the TLS section. + + ```yaml +$ kubectl apply -f ingress-tls.yaml + +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: demo +spec: + tls: + - hosts: + - aa.appscode.ninja + secretName: aa-ninja + - hosts: + - bb.appscode.ninja + secretName: bb-ninja + rules: + - host: aa.appscode.ninja + http: + paths: + - backend: + service: + name: test-server + port: + number: 8080 + - host: bb.appscode.ninja + http: + paths: + - backend: + service: + name: test-server + port: + number: 8989 +``` + +## Check HTTPS Response + +Visit `https://aa.appscode.ninja` and `https://bb.appscode.ninja` in your browser: + +![https.aa.appscode.ninja](/docs/v2024.3.18/images/ingress/multiple-tls/https.aa.appscode.ninja.png) +![https.bb.appscode.ninja](/docs/v2024.3.18/images/ingress/multiple-tls/https.bb.appscode.ninja.png) + +## Check Certificate Details + +You can see the certificate details from your browser: + +![connection-secure](/docs/v2024.3.18/images/ingress/multiple-tls/connection-secure.png) +![cert-details](/docs/v2024.3.18/images/ingress/multiple-tls/cert-details.png) + +## Cleaning up + +To cleanup the Kubernetes resources created by this tutorial, run: + +```bash +$ kubectl delete namespace demo +namespace "demo" deleted +``` + +If you would like to uninstall Voyager operator, please follow the steps [here](/docs/v2024.3.18/setup/uninstall). diff --git a/content/docs/v2024.3.18/guides/ingress/tls/overview.md b/content/docs/v2024.3.18/guides/ingress/tls/overview.md new file mode 100644 index 000000000..a1ab06c78 --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/tls/overview.md @@ -0,0 +1,216 @@ +--- +title: TLS | Kubernetes Ingress +menu: + docs_v2024.3.18: + identifier: overview-tls + name: Overview + parent: tls-ingress + weight: 10 +product_name: voyager +menu_name: docs_v2024.3.18 +section_menu_id: guides +info: + cli: v0.0.15 + installer: v2024.3.18 + version: v2024.3.18 +--- + +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + +# TLS +You can secure an Ingress by specifying a secret containing TLS pem or by referring a `certificates.voyager.appscode.com` resource. +`certificates.voyager.appscode.com` can manage an certificate resource and use that certificate to encrypt communication. + +This tutorial will show you how to secure an Ingress using TLS/SSL certificates. + +## Before You Begin + +At first, you need to have a Kubernetes cluster, and the kubectl command-line tool must be configured to communicate with your cluster. If you do not already have a cluster, you can create one by using [Minikube](https://github.com/kubernetes/minikube). + +Now, install Voyager operator in your `minikube` cluster following the steps [here](/docs/v2024.3.18/setup/install). + +```bash +minikube start +./hack/deploy/minikube.sh +``` + +To keep things isolated, this tutorial uses a separate namespace called `demo` throughout this tutorial. Run the following command to prepare your cluster for this tutorial: + +```bash +$ kubectl create namespace demo +namespace "demo" created +``` + +## Sourcing TLS Certificate + +You can use an existing TLS certificate/key pair or use Voyager to issue free SSL certificates from Let's Encrypt. + +### Import Existing Certificate + +To import an existing TLS certificate/key pair into a Kubernetes cluster, run the following command. + +```bash +$ kubectl create secret tls tls-secret --namespace=demo --cert=path/to/tls.cert --key=path/to/tls.key +secret "tls-secret" created +``` + +This will create a Secret with the PEM formatted certificate under `tls.crt` key and the PEM formatted private key under `tls.key` key. + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: tls-secret + namespace: demo +data: + tls.crt: YmFzZTY0IGVuY29kZWQgY2VydA== + tls.key: YmFzZTY0IGVuY29kZWQga2V5 +``` + +### Issue Certificates from Let's Encrypt + +To issue a free TLS/SSL certificate from Let's Encrypt, create a `Certificate` object with the list of domains. To learn more, please visit the following links: + +- [Using HTTP-01 challenge](/docs/v2024.3.18/guides/certificate/http/overview) +- [Using DNS-01 challenge](/docs/v2024.3.18/guides/certificate/dns/providers) + +## Secure HTTP Service + +To terminate a HTTP service, + +Caveats: +- You can't terminate default backend + +For HTTP, If the `spec.TLS` section in an Ingress specifies different hosts, they will be multiplexed +on the same port according to hostname specified through SNI TLS extension (Voyager supports SNI). + +For handling wildcard domains use **"\*"** as hostname ( [Example](https://github.com/tamalsaha/voyager-wildcard/blob/master/mrasero/ing-https.yaml) ) + +Referencing this secret in an Ingress will tell the Voyager to secure the channel from client to the loadbalancer using TLS: + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: demo +spec: + tls: + - secretName: tls-secret + hosts: + - one.example.com + rules: + - host: one.example.com + http: + paths: + - backend: + service: + name: test-service + port: + number: 80 +``` +This Ingress will open an `https` listener to secure the channel from the client to the loadbalancer, +terminate TLS at load balancer with the secret retried via SNI and forward unencrypted traffic to the +`test-service`. + +## Secure TCP Service + +Adding a TCP TLS termination at Voyager Ingress is slightly different than HTTP, as TCP mode does not have +SNI support. A TCP endpoint with TLS termination, will look like this in Voyager Ingress: + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: demo +spec: + tls: + - secretName: testsecret + hosts: + - appscode.example.com + rules: + - host: appscode.example.com + tcp: + port: 9898 + backend: + service: + name: tcp-service + port: + number: 50077 +``` +You need to set the secretName field with the TCP rule to use a certificate. + +## FAQ + +**Q: How to serve both TLS and non-TLS under same host?** + +Voyager Ingress can support for TLS and non-TLS traffic for same host in both HTTP and TCP mode. To do that you need to specify `noTLS: true` for the corresponding rule. Here is an example: + +```yaml +apiVersion: voyager.appscode.com/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: demo +spec: + tls: + - secretName: onecert + hosts: + - one.example.com + rules: + - host: one.example.com + http: + paths: + - backend: + service: + name: test-service + port: + number: 80 + - host: one.example.com + http: + noTLS: true + paths: + - backend: + service: + name: test-service + port: + number: 80 + - host: one.example.com + tcp: + port: 7878 + backend: + service: + name: tcp-service + port: + number: 50077 + - host: one.example.com + tcp: + port: 7800 + noTLS: true + backend: + service: + name: tcp-service + port: + number: 50077 +``` + +For this Ingress, HAProxy will open up 3 separate ports: + +- port 443: This is used by `spec.rules[0]`. Passes traffic to pods behind test-server:80. Uses TLS, since `spec.TLS` has a matching host. + +- port 80: This is used by `spec.rules[1]`. Passes traffic to pods behind test-server:80. __Uses no TLS__, even though `spec.TLS` has a matching host. This is because `http.noTLS` is set to true for this rule. + +- port 7878: This is used by `spec.rules[2]`. Passes traffic to pods behind tcp-service:50077. Uses TLS, since `spec.TLS` has a matching host. + +- port 7880: This is used by `spec.rules[3]`. Passes traffic to pods behind tcp-service:50077. __Uses no TLS__, even though `spec.TLS` has a matching host. This is because `tcp.noTLS` is set to true for this rule. + +## Cleaning up + +To cleanup the Kubernetes resources created by this tutorial, run: + +```bash +kubectl delete ns demo +``` + +If you would like to uninstall Voyager operator, please follow the steps [here](/docs/v2024.3.18/setup/uninstall). diff --git a/content/docs/v2024.3.18/guides/ingress/websocket.md b/content/docs/v2024.3.18/guides/ingress/websocket.md new file mode 100644 index 000000000..9a7f9145a --- /dev/null +++ b/content/docs/v2024.3.18/guides/ingress/websocket.md @@ -0,0 +1,2 @@ +> New to Voyager? Please start [here](/docs/v2024.3.18/concepts/overview). + diff --git a/content/docs/v2024.3.18/images/cert-manager/azure/a-record.png b/content/docs/v2024.3.18/images/cert-manager/azure/a-record.png new file mode 100644 index 0000000000000000000000000000000000000000..ebb645942ec1a4a4ec85d0ddf2ee44553e8825cb GIT binary patch literal 177418 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ⓈCYuMf}iCbTm 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Ɋ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 H^V5F-pohz_ literal 0 HcmV?d00001 diff --git a/content/docs/v2024.3.18/images/cert-manager/azure/client-secret.png b/content/docs/v2024.3.18/images/cert-manager/azure/client-secret.png new file mode 100644 index 0000000000000000000000000000000000000000..d59d765941a5c463f29d997d8a08928fe2991c4b GIT binary patch literal 142965 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

qiSaJezCe#9Osr)JeT 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 KGVZwc?f(S}YBX&C literal 0 HcmV?d00001 diff --git a/content/docs/v2024.3.18/images/cert-manager/azure/client-tenant.png b/content/docs/v2024.3.18/images/cert-manager/azure/client-tenant.png new file mode 100644 index 0000000000000000000000000000000000000000..e6e05e436137159e3481b07ff761816a3565841a GIT binary patch literal 191258 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⋙NQWi!hUv3t?)RB7tcV^TbZ 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