Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Sandor Szombat 2020-02-13 10:46:27 +01:00
commit 4ed3d29a89
46 changed files with 228 additions and 143 deletions

View file

@ -232,11 +232,15 @@ dep-ensure: check-go-version ## Update and vendo go dependencies.
.PHONY: dev-env .PHONY: dev-env
dev-env: check-go-version ## Starts a local Kubernetes cluster using minikube, building and deploying the ingress controller. dev-env: check-go-version ## Starts a local Kubernetes cluster using minikube, building and deploying the ingress controller.
@DIND_TASKS=0 USE_DOCKER=false build/dev-env.sh @build/dev-env.sh
.PHONY: live-docs .PHONY: live-docs
live-docs: ## Build and launch a local copy of the documentation website in http://localhost:3000 live-docs: ## Build and launch a local copy of the documentation website in http://localhost:3000
@docker build --pull -t ingress-nginx/mkdocs images/mkdocs @docker buildx build \
--pull \
--load \
--progress plain \
-t ingress-nginx/mkdocs images/mkdocs
@docker run --rm -it -p 3000:3000 -v ${PWD}:/docs ingress-nginx/mkdocs @docker run --rm -it -p 3000:3000 -v ${PWD}:/docs ingress-nginx/mkdocs
.PHONY: build-docs .PHONY: build-docs

View file

@ -22,10 +22,7 @@ set -o errexit
set -o nounset set -o nounset
set -o pipefail set -o pipefail
NAMESPACE="${NAMESPACE:-ingress-nginx}" DIR=$(cd $(dirname "${BASH_SOURCE}") && pwd -P)
echo "NAMESPACE is set to ${NAMESPACE}"
kubectl config use-context minikube
export TAG=dev export TAG=dev
export ARCH=amd64 export ARCH=amd64
@ -33,46 +30,77 @@ export REGISTRY=${REGISTRY:-ingress-controller}
DEV_IMAGE=${REGISTRY}/nginx-ingress-controller:${TAG} DEV_IMAGE=${REGISTRY}/nginx-ingress-controller:${TAG}
{ [ "$(minikube status | grep -c Running)" -ge 2 ] && minikube status | grep -qE ': Configured$|Correctly Configured'; } \ if ! command -v kind &> /dev/null; then
|| minikube start \ echo "kind is not installed"
--extra-config=kubelet.sync-frequency=1s \ echo "Use a package manager or visit the official site https://kind.sigs.k8s.io"
--extra-config=apiserver.authorization-mode=RBAC exit 1
fi
# shellcheck disable=SC2046 if ! command -v kubectl &> /dev/null; then
eval $(minikube docker-env --shell bash) echo "Please install kubectl 1.15 or higher"
exit 1
fi
KUBE_CLIENT_VERSION=$(kubectl version --client --short | awk '{print $3}' | cut -d. -f2) || true
if [[ ${KUBE_CLIENT_VERSION} -lt 14 ]]; then
echo "Please update kubectl to 1.15 or higher"
exit 1
fi
echo "[dev-env] building container" echo "[dev-env] building container"
make build container make build container
docker tag "${REGISTRY}/nginx-ingress-controller-${ARCH}:${TAG}" "${DEV_IMAGE}" docker tag "${REGISTRY}/nginx-ingress-controller-${ARCH}:${TAG}" "${DEV_IMAGE}"
# kubectl >= 1.14 includes Kustomize via "apply -k". Makes it easier to use on Linux as well, assuming kubectl installed export K8S_VERSION=${K8S_VERSION:-v1.17.2@sha256:59df31fc61d1da5f46e8a61ef612fa53d3f9140f82419d1ef1a6b9656c6b737c}
KUBE_CLIENT_VERSION=$(kubectl version --client --short | awk '{print $3}' | cut -d. -f2) || true
if [[ ${KUBE_CLIENT_VERSION} -lt 14 ]]; then
for tool in kubectl kustomize; do
echo "[dev-env] installing $tool"
$tool version || brew install $tool
done
fi
if ! kubectl get namespace "${NAMESPACE}"; then export DOCKER_CLI_EXPERIMENTAL=enabled
kubectl create namespace "${NAMESPACE}"
fi
kubectl get deploy nginx-ingress-controller -n "${NAMESPACE}" && kubectl delete deploy nginx-ingress-controller -n "${NAMESPACE}" KIND_CLUSTER_NAME="ingress-nginx-dev"
ROOT=./deploy/minikube if ! kind get clusters -q | grep -q ${KIND_CLUSTER_NAME}; then
echo "[dev-env] creating Kubernetes cluster with kind"
if [[ ${KUBE_CLIENT_VERSION} -lt 14 ]]; then cat <<EOF | kind create cluster --name ${KIND_CLUSTER_NAME} --config=-
pushd $ROOT kind: Cluster
kustomize edit set namespace "${NAMESPACE}" apiVersion: kind.x-k8s.io/v1alpha4
kustomize edit set image "quay.io/kubernetes-ingress-controller/nginx-ingress-controller=${DEV_IMAGE}" nodes:
popd - role: control-plane
kubeadmConfigPatches:
echo "[dev-env] deploying NGINX Ingress controller in namespace $NAMESPACE" - |
kustomize build $ROOT | kubectl apply -f - kind: InitConfiguration
nodeRegistration:
kubeletExtraArgs:
node-labels: "ingress-ready=true"
authorization-mode: "AlwaysAllow"
extraPortMappings:
- containerPort: 80
hostPort: 80
protocol: TCP
- containerPort: 443
hostPort: 443
protocol: TCP
EOF
else else
sed -i -e "s|^namespace: .*|namespace: ${NAMESPACE}|g" "${ROOT}/kustomization.yaml" echo "[dev-env] using existing Kubernetes kind cluster"
echo "[dev-env] deploying NGINX Ingress controller in namespace $NAMESPACE"
kubectl apply -k "${ROOT}"
fi fi
echo "[dev-env] copying docker images to cluster..."
kind load docker-image --name="${KIND_CLUSTER_NAME}" "${DEV_IMAGE}"
echo "[dev-env] deploying NGINX Ingress controller..."
kubectl create namespace ingress-nginx || true
kubectl apply -k ${DIR}/../deploy/kind
echo "[dev-env] deleting old ingress-nginx pods..."
MINUTE_AGO=$(python -c "from datetime import datetime,timedelta; print((datetime.utcnow()-timedelta(seconds=60)).strftime('%Y-%m-%dT%H:%M:%SZ'))")
kubectl get pods --namespace ingress-nginx -o go-template \
--template '{{range .items}}{{.metadata.name}} {{.metadata.creationTimestamp}}{{"\n"}}{{end}}' | \
awk -v MINUTE_AGO=$MINUTE_AGO '$2 <= MINUTE_AGO { print $1 }' | \
xargs kubectl delete pod --namespace ingress-nginx
cat <<EOF
Kubernetes cluster ready and ingress-nginx listening in localhost using ports 80 and 443
To delete the dev cluster execute: 'kind delete cluster --name ingress-nginx-dev'
EOF

View file

@ -45,13 +45,6 @@ FLAGS=$@
PKG=k8s.io/ingress-nginx PKG=k8s.io/ingress-nginx
ARCH=$(go env GOARCH) ARCH=$(go env GOARCH)
MINIKUBE_PATH=${HOME}/.minikube
MINIKUBE_VOLUME="-v ${MINIKUBE_PATH}:${MINIKUBE_PATH}"
if [ ! -d "${MINIKUBE_PATH}" ]; then
echo "Minikube directory not found! Volume will be excluded from docker build."
MINIKUBE_VOLUME=""
fi
# create output directory as current user to avoid problem with docker. # create output directory as current user to avoid problem with docker.
mkdir -p "${KUBE_ROOT}/bin" "${KUBE_ROOT}/bin/${ARCH}" mkdir -p "${KUBE_ROOT}/bin" "${KUBE_ROOT}/bin/${ARCH}"
@ -67,7 +60,6 @@ docker run \
-v "${KUBE_ROOT}/bin/${ARCH}:/go/bin/linux_${ARCH}" \ -v "${KUBE_ROOT}/bin/${ARCH}:/go/bin/linux_${ARCH}" \
-v "/var/run/docker.sock:/var/run/docker.sock" \ -v "/var/run/docker.sock:/var/run/docker.sock" \
-v "${INGRESS_VOLUME}:/etc/ingress-controller/" \ -v "${INGRESS_VOLUME}:/etc/ingress-controller/" \
${MINIKUBE_VOLUME} \
-w "/go/src/${PKG}" \ -w "/go/src/${PKG}" \
-u $(id -u ${USER}):$(id -g ${USER}) \ -u $(id -u ${USER}):$(id -g ${USER}) \
${E2E_IMAGE} /bin/bash -c "${FLAGS}" ${E2E_IMAGE} /bin/bash -c "${FLAGS}"

View file

@ -94,11 +94,6 @@ until curl --output /dev/null -fsSL http://localhost:8001/; do
sleep 5 sleep 5
done done
MINIKUBE_VOLUME=
if [[ -d "${HOME}/.minikube" ]]; then
MINIKUBE_VOLUME=" -v ${HOME}/.minikube:${HOME}/.minikube "
fi
# if we run as user we cannot bind to port 80 and 443 # if we run as user we cannot bind to port 80 and 443
docker run \ docker run \
--rm \ --rm \
@ -109,7 +104,6 @@ docker run \
-e POD_NAME="${POD_NAME}" \ -e POD_NAME="${POD_NAME}" \
-v "${SSL_VOLUME}:/etc/ingress-controller/ssl/" \ -v "${SSL_VOLUME}:/etc/ingress-controller/ssl/" \
-v "${HOME}/.kube:${HOME}/.kube:ro" \ -v "${HOME}/.kube:${HOME}/.kube:ro" \
${MINIKUBE_VOLUME} \
"${IMAGE}-${ARCH}:${TAG}" /nginx-ingress-controller \ "${IMAGE}-${ARCH}:${TAG}" /nginx-ingress-controller \
--update-status=false \ --update-status=false \
--v=2 \ --v=2 \

View file

@ -31,6 +31,7 @@ import (
"k8s.io/ingress-nginx/internal/ingress/annotations/parser" "k8s.io/ingress-nginx/internal/ingress/annotations/parser"
"k8s.io/ingress-nginx/internal/ingress/controller" "k8s.io/ingress-nginx/internal/ingress/controller"
ngx_config "k8s.io/ingress-nginx/internal/ingress/controller/config" ngx_config "k8s.io/ingress-nginx/internal/ingress/controller/config"
"k8s.io/ingress-nginx/internal/ingress/status"
ing_net "k8s.io/ingress-nginx/internal/net" ing_net "k8s.io/ingress-nginx/internal/net"
"k8s.io/ingress-nginx/internal/nginx" "k8s.io/ingress-nginx/internal/nginx"
) )
@ -175,6 +176,8 @@ Takes the form "<host>:port". If not provided, no admission controller is starte
streamPort = flags.Int("stream-port", 10247, "Port to use for the lua TCP/UDP endpoint configuration.") streamPort = flags.Int("stream-port", 10247, "Port to use for the lua TCP/UDP endpoint configuration.")
profilerPort = flags.Int("profiler-port", 10245, "Port to use for expose the ingress controller Go profiler when it is enabled.") profilerPort = flags.Int("profiler-port", 10245, "Port to use for expose the ingress controller Go profiler when it is enabled.")
statusUpdateInterval = flags.Int("status-update-interval", status.UpdateInterval, "Time interval in seconds in which the status should check if an update is required. Default is 60 seconds")
) )
flags.MarkDeprecated("force-namespace-isolation", `This flag doesn't do anything.`) flags.MarkDeprecated("force-namespace-isolation", `This flag doesn't do anything.`)
@ -201,6 +204,13 @@ https://blog.maxmind.com/2019/12/18/significant-changes-to-accessing-and-using-g
return true, nil, nil return true, nil, nil
} }
if *statusUpdateInterval < 5 {
klog.Warningf("The defined time to update the Ingress status too low (%v seconds). Adjusting to 5 seconds", *statusUpdateInterval)
status.UpdateInterval = 5
} else {
status.UpdateInterval = *statusUpdateInterval
}
if *ingressClass != "" { if *ingressClass != "" {
klog.Infof("Watching for Ingress class: %s", *ingressClass) klog.Infof("Watching for Ingress class: %s", *ingressClass)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 606 KiB

After

Width:  |  Height:  |  Size: 329 KiB

View file

@ -7,3 +7,5 @@ bases:
images: images:
- name: quay.io/kubernetes-ingress-controller/nginx-ingress-controller - name: quay.io/kubernetes-ingress-controller/nginx-ingress-controller
newTag: dev newTag: dev
patchesStrategicMerge:
- service-hostport.yaml

View file

@ -0,0 +1,25 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-ingress-controller
spec:
replicas: 1
template:
metadata:
annotations:
prometheus.io/port: "10254"
prometheus.io/scrape: "true"
spec:
containers:
- name: nginx-ingress-controller
ports:
- containerPort: 80
hostPort: 80
- containerPort: 443
hostPort: 443
nodeSelector:
ingress-ready: "true"
tolerations:
- key: node-role.kubernetes.io/master
operator: Equal
effect: NoSchedule

View file

@ -78,7 +78,6 @@ minikube addons disable ingress
```console ```console
$ kubectl get pods -n ingress-nginx $ kubectl get pods -n ingress-nginx
NAME READY STATUS RESTARTS AGE NAME READY STATUS RESTARTS AGE
default-http-backend-66b447d9cf-rrlf9 1/1 Running 0 12s
nginx-ingress-controller-fdcdcd6dd-vvpgs 1/1 Running 0 11s nginx-ingress-controller-fdcdcd6dd-vvpgs 1/1 Running 0 11s
``` ```

View file

@ -19,11 +19,6 @@ cd ingress-nginx
### Initial developer environment build ### Initial developer environment build
>**Prequisites**: Minikube must be installed.
See [releases](https://github.com/kubernetes/minikube/releases) for installation instructions.
If you are using **MacOS** and deploying to **minikube**, the following command will build the local nginx controller container image and deploy the ingress controller onto a minikube cluster with RBAC enabled in the namespace `ingress-nginx`:
``` ```
$ make dev-env $ make dev-env
``` ```

View file

@ -40,7 +40,7 @@ If you do not already have an instance of the NGINX Ingress controller running,
ingress-nginx ClusterIP 10.0.0.13 <none> 80/TCP,443/TCP 10m ingress-nginx ClusterIP 10.0.0.13 <none> 80/TCP,443/TCP 10m
``` ```
!!! Note !!! note
The `ingress-nginx` Service is of type `ClusterIP` in this example. This may vary depending on your environment. The `ingress-nginx` Service is of type `ClusterIP` in this example. This may vary depending on your environment.
Make sure you can use the Service to reach NGINX before proceeding with the rest of this example. Make sure you can use the Service to reach NGINX before proceeding with the rest of this example.

View file

@ -26,9 +26,9 @@ wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/docs/exam
``` ```
!!! Important !!! Important
Running a docker registry without TLS requires we configure our local docker daemon with the insecure registry flag. Running a docker registry without TLS requires we configure our local docker daemon with the insecure registry flag.
Please check [deploy a plain http registry](https://docs.docker.com/registry/insecure/#deploy-a-plain-http-registry) Please check [deploy a plain http registry](https://docs.docker.com/registry/insecure/#deploy-a-plain-http-registry)
### With TLS ### With TLS

View file

@ -7,6 +7,9 @@ metadata:
namespace: default namespace: default
spec: spec:
replicas: 1 replicas: 1
selector:
matchLabels:
k8s-app: fortune-teller-app
template: template:
metadata: metadata:
labels: labels:

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 84 KiB

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 141 KiB

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 112 KiB

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB

After

Width:  |  Height:  |  Size: 60 KiB

View file

@ -44,6 +44,7 @@ They are set in the container spec of the `nginx-ingress-controller` Deployment
| `--udp-services-configmap string` | Name of the ConfigMap containing the definition of the UDP services to expose. The key in the map indicates the external port to be used. The value is a reference to a Service in the form "namespace/name:port", where "port" can either be a port name or number. | | `--udp-services-configmap string` | Name of the ConfigMap containing the definition of the UDP services to expose. The key in the map indicates the external port to be used. The value is a reference to a Service in the form "namespace/name:port", where "port" can either be a port name or number. |
| `--update-status` | Update the load-balancer status of Ingress objects this controller satisfies. Requires setting the publish-service parameter to a valid Service reference. (default true) | | `--update-status` | Update the load-balancer status of Ingress objects this controller satisfies. Requires setting the publish-service parameter to a valid Service reference. (default true) |
| `--update-status-on-shutdown` | Update the load-balancer status of Ingress objects when the controller shuts down. Requires the update-status parameter. (default true) | | `--update-status-on-shutdown` | Update the load-balancer status of Ingress objects when the controller shuts down. Requires the update-status parameter. (default true) |
| `--status-update-interval` | Time interval in seconds in which the status should check if an update is required. (default 60 seconds) |
| `-v`, `--v Level` | log level for V logs | | `-v`, `--v Level` | log level for V logs |
| `--version` | Show release information about the NGINX Ingress controller and exit. | | `--version` | Show release information about the NGINX Ingress controller and exit. |
| `--vmodule moduleSpec` | comma-separated list of pattern=N settings for file-filtered logging | | `--vmodule moduleSpec` | comma-separated list of pattern=N settings for file-filtered logging |

View file

@ -79,15 +79,13 @@ spec:
servicePort: fastcgi servicePort: fastcgi
``` ```
## The FastCGI Ingress Annotations ## FastCGI Ingress Annotations
### The `nginx.ingress.kubernetes.io/backend-protocol` Annotation To enable FastCGI, the `nginx.ingress.kubernetes.io/backend-protocol` annotation needs to be set to `FCGI`, which overrides the default `HTTP` value.
To enable FastCGI, the `backend-protocol` annotation needs to be set to `FCGI`, which overrides the default `HTTP` value.
> `nginx.ingress.kubernetes.io/backend-protocol: "FCGI"` > `nginx.ingress.kubernetes.io/backend-protocol: "FCGI"`
This enables the _FastCGI_ mode for the whole _Ingress_ object. **This enables the _FastCGI_ mode for all paths defined in the _Ingress_ object**
### The `nginx.ingress.kubernetes.io/fastcgi-index` Annotation ### The `nginx.ingress.kubernetes.io/fastcgi-index` Annotation

View file

@ -9,8 +9,8 @@ The ingress controller supports **case insensitive** regular expressions in the
This can be enabled by setting the `nginx.ingress.kubernetes.io/use-regex` annotation to `true` (the default is false). This can be enabled by setting the `nginx.ingress.kubernetes.io/use-regex` annotation to `true` (the default is false).
!!! hint !!! hint
Kubernetes only accept expressions that comply with the RE2 engine syntax. It is possible that valid expressions accepted by NGINX cannot be used with ingress-nginx, because the PCRE library (used in NGINX) supports a wider syntax than RE2. Kubernetes only accept expressions that comply with the RE2 engine syntax. It is possible that valid expressions accepted by NGINX cannot be used with ingress-nginx, because the PCRE library (used in NGINX) supports a wider syntax than RE2.
See the [RE2 Syntax](https://github.com/google/re2/wiki/Syntax) documentation for differences. See the [RE2 Syntax](https://github.com/google/re2/wiki/Syntax) documentation for differences.
See the [description](./nginx-configuration/annotations.md#use-regex) of the `use-regex` annotation for more details. See the [description](./nginx-configuration/annotations.md#use-regex) of the `use-regex` annotation for more details.

View file

@ -171,7 +171,7 @@ If you use the ``cookie`` affinity type you can also specify the name of the coo
The NGINX annotation `nginx.ingress.kubernetes.io/session-cookie-path` defines the path that will be set on the cookie. This is optional unless the annotation `nginx.ingress.kubernetes.io/use-regex` is set to true; Session cookie paths do not support regex. The NGINX annotation `nginx.ingress.kubernetes.io/session-cookie-path` defines the path that will be set on the cookie. This is optional unless the annotation `nginx.ingress.kubernetes.io/use-regex` is set to true; Session cookie paths do not support regex.
Use `nginx.ingress.kubernetes.io/session-cookie-samesite` to apply a `SameSite` attribute to the sticky cookie. Browser accepted values are `None`, `Lax`, and `Strict`. Some older browsers reject cookies with the more-recently-defined `SameSite=None`. To omit `SameSite=None` from these older browsers, add the annotation `nginx.ingress.kubernetes.io/session-cookie-conditional-samesite-none: "true"`. Use `nginx.ingress.kubernetes.io/session-cookie-samesite` to apply a `SameSite` attribute to the sticky cookie. Browser accepted values are `None`, `Lax`, and `Strict`. Some browsers reject cookies with `SameSite=None`, including those created before the `SameSite=None` specification (e.g. Chrome 5X). Other browsers mistakenly treat `SameSite=None` cookies as `SameSite=Strict` (e.g. Safari running on OSX 14). To omit `SameSite=None` from browsers with these incompatibilities, add the annotation `nginx.ingress.kubernetes.io/session-cookie-conditional-samesite-none: "true"`.
### Authentication ### Authentication
@ -352,7 +352,7 @@ Enables automatic conversion of preload links specified in the “Link” respon
Allows the definition of one or more aliases in the server definition of the NGINX configuration using the annotation `nginx.ingress.kubernetes.io/server-alias: "<alias 1>,<alias 2>"`. Allows the definition of one or more aliases in the server definition of the NGINX configuration using the annotation `nginx.ingress.kubernetes.io/server-alias: "<alias 1>,<alias 2>"`.
This will create a server with the same configuration, but adding new values to the `server_name` directive. This will create a server with the same configuration, but adding new values to the `server_name` directive.
!!! Note !!! note
A server-alias name cannot conflict with the hostname of an existing server. If it does, the server-alias annotation will be ignored. A server-alias name cannot conflict with the hostname of an existing server. If it does, the server-alias annotation will be ignored.
If a server-alias is created and later a new server with the same hostname is created, the new server configuration will take If a server-alias is created and later a new server with the same hostname is created, the new server configuration will take
place over the alias configuration. place over the alias configuration.
@ -446,7 +446,8 @@ By default the controller redirects all requests to an existing service that pro
`nginx.ingress.kubernetes.io/enable-global-auth`: `nginx.ingress.kubernetes.io/enable-global-auth`:
indicates if GlobalExternalAuth configuration should be applied or not to this Ingress rule. Default values is set to `"true"`. indicates if GlobalExternalAuth configuration should be applied or not to this Ingress rule. Default values is set to `"true"`.
!!! note For more information please see [global-auth-url](./configmap.md#global-auth-url). !!! note
For more information please see [global-auth-url](./configmap.md#global-auth-url).
### Rate limiting ### Rate limiting
@ -837,7 +838,7 @@ nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
### Use Regex ### Use Regex
!!! attention !!! attention
When using this annotation with the NGINX annotation `nginx.ingress.kubernetes.io/affinity` of type `cookie`, `nginx.ingress.kubernetes.io/session-cookie-path` must be also set; Session cookie paths do not support regex. When using this annotation with the NGINX annotation `nginx.ingress.kubernetes.io/affinity` of type `cookie`, `nginx.ingress.kubernetes.io/session-cookie-path` must be also set; Session cookie paths do not support regex.
Using the `nginx.ingress.kubernetes.io/use-regex` annotation will indicate whether or not the paths defined on an Ingress use regular expressions. The default value is `false`. Using the `nginx.ingress.kubernetes.io/use-regex` annotation will indicate whether or not the paths defined on an Ingress use regular expressions. The default value is `false`.
@ -885,4 +886,4 @@ nginx.ingress.kubernetes.io/mirror-request-body: "off"
The request sent to the mirror is linked to the orignial request. If you have a slow mirror backend, then the orignial request will throttle. The request sent to the mirror is linked to the orignial request. If you have a slow mirror backend, then the orignial request will throttle.
For more information on the mirror module see https://nginx.org/en/docs/http/ngx_http_mirror_module.html For more information on the mirror module see [ngx_http_mirror_module](https://nginx.org/en/docs/http/ngx_http_mirror_module.html)

View file

@ -14,7 +14,7 @@ data:
ssl-protocols: SSLv2 ssl-protocols: SSLv2
``` ```
!!! Important !!! important
The key and values in a ConfigMap can only be strings. The key and values in a ConfigMap can only be strings.
This means that we want a value with boolean values we need to quote the values, like "true" or "false". This means that we want a value with boolean values we need to quote the values, like "true" or "false".
Same for numbers, like "100". Same for numbers, like "100".
@ -567,7 +567,7 @@ Since `0.27.0` and due to a [change in the MaxMind databases](https://blog.maxmi
For this reason, it is required to define a new flag `--maxmind-license-key` in the ingress controller deployment to download the databases needed during the initialization of the ingress controller. For this reason, it is required to define a new flag `--maxmind-license-key` in the ingress controller deployment to download the databases needed during the initialization of the ingress controller.
Alternatively, it is possible to use a volume to mount the files `/etc/nginx/geoip/GeoLite2-City.mmdb` and `/etc/nginx/geoip/GeoLite2-ASN.mmdb`, avoiding the overhead of the download. Alternatively, it is possible to use a volume to mount the files `/etc/nginx/geoip/GeoLite2-City.mmdb` and `/etc/nginx/geoip/GeoLite2-ASN.mmdb`, avoiding the overhead of the download.
!!! Important !!! important
If the feature is enabled but the files are missing, GeoIP2 will not be enabled. If the feature is enabled but the files are missing, GeoIP2 will not be enabled.
_**default:**_ false _**default:**_ false

View file

@ -100,8 +100,7 @@ All these options (including host) allow environment variables, such as `$HOSTNA
## Examples ## Examples
The following examples show how to deploy and test different distributed tracing systems. These example can be performed The following examples show how to deploy and test different distributed tracing systems. These example can be performed using Minikube.
using Minikube.
### Zipkin ### Zipkin

View file

@ -78,7 +78,6 @@ or per-Ingress with the `nginx.ingress.kubernetes.io/ssl-redirect: "false"`
annotation in the particular resource. annotation in the particular resource.
!!! tip !!! tip
When using SSL offloading outside of cluster (e.g. AWS ELB) it may be useful to enforce a 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 no TLS certificate available. redirect to HTTPS even when there is no TLS certificate available.
This can be achieved by using the `nginx.ingress.kubernetes.io/force-ssl-redirect: "true"` This can be achieved by using the `nginx.ingress.kubernetes.io/force-ssl-redirect: "true"`

View file

@ -218,8 +218,8 @@ func (a authReq) Parse(ing *networking.Ingress) (interface{}, error) {
return nil, ing_errors.NewLocationDenied(fmt.Sprintf("unable to find configMap %q", proxySetHeaderMap)) return nil, ing_errors.NewLocationDenied(fmt.Sprintf("unable to find configMap %q", proxySetHeaderMap))
} }
for header, value := range proxySetHeadersMapContents.Data { for header := range proxySetHeadersMapContents.Data {
if !ValidHeader(header) || !ValidHeader(value) { if !ValidHeader(header) {
return nil, ing_errors.NewLocationDenied("invalid proxy-set-headers in configmap") return nil, ing_errors.NewLocationDenied("invalid proxy-set-headers in configmap")
} }
} }

View file

@ -276,8 +276,8 @@ func TestProxySetHeaders(t *testing.T) {
}{ }{
{"single header", "http://goog.url", map[string]string{"header": "h1"}, false}, {"single header", "http://goog.url", map[string]string{"header": "h1"}, false},
{"no header map", "http://goog.url", nil, true}, {"no header map", "http://goog.url", nil, true},
{"header with spaces", "http://goog.url", map[string]string{"header": "bad value"}, true}, {"header with spaces", "http://goog.url", map[string]string{"header": "bad value"}, false},
{"header with other bad symbols", "http://goog.url", map[string]string{"header": "bad+value"}, true}, {"header with other bad symbols", "http://goog.url", map[string]string{"header": "bad+value"}, false},
} }
for _, test := range tests { for _, test := range tests {

View file

@ -82,6 +82,7 @@ func (a mirror) Parse(ing *networking.Ingress) (interface{}, error) {
config.Target, err = parser.GetStringAnnotation("mirror-target", ing) config.Target, err = parser.GetStringAnnotation("mirror-target", ing)
if err != nil { if err != nil {
config.Target = "" config.Target = ""
config.Source = ""
} }
return config, nil return config, nil

View file

@ -47,7 +47,7 @@ func TestParse(t *testing.T) {
Target: "https://test.env.com/$request_uri", Target: "https://test.env.com/$request_uri",
}}, }},
{map[string]string{requestBody: "off"}, &Config{ {map[string]string{requestBody: "off"}, &Config{
Source: ngxURI, Source: "",
RequestBody: "off", RequestBody: "off",
Target: "", Target: "",
}}, }},

View file

@ -535,18 +535,39 @@ func New(
AddFunc: func(obj interface{}) { AddFunc: func(obj interface{}) {
cm := obj.(*corev1.ConfigMap) cm := obj.(*corev1.ConfigMap)
key := k8s.MetaNamespaceKey(cm) key := k8s.MetaNamespaceKey(cm)
triggerUpdate := false
// updates to configuration configmaps can trigger an update // updates to configuration configmaps can trigger an update
if changeTriggerUpdate(key) { if changeTriggerUpdate(key) {
recorder.Eventf(cm, corev1.EventTypeNormal, "CREATE", fmt.Sprintf("ConfigMap %v", key)) recorder.Eventf(cm, corev1.EventTypeNormal, "CREATE", fmt.Sprintf("ConfigMap %v", key))
triggerUpdate = true
if key == configmap { if key == configmap {
store.setConfig(cm) store.setConfig(cm)
} }
} }
updateCh.In() <- Event{ ings := store.listers.IngressWithAnnotation.List()
Type: ConfigurationEvent, for _, ingKey := range ings {
Obj: obj, key := k8s.MetaNamespaceKey(ingKey)
ing, err := store.getIngress(key)
if err != nil {
klog.Errorf("could not find Ingress %v in local store: %v", key, err)
continue
}
if parser.AnnotationsReferencesConfigmap(ing) {
recorder.Eventf(cm, corev1.EventTypeNormal, "CREATE", fmt.Sprintf("ConfigMap %v", key))
store.syncIngress(ing)
triggerUpdate = true
}
}
if triggerUpdate {
updateCh.In() <- Event{
Type: ConfigurationEvent,
Obj: obj,
}
} }
}, },
UpdateFunc: func(old, cur interface{}) { UpdateFunc: func(old, cur interface{}) {

View file

@ -275,6 +275,7 @@ func configForLua(input interface{}) string {
return fmt.Sprintf(`{ return fmt.Sprintf(`{
use_forwarded_headers = %t, use_forwarded_headers = %t,
use_proxy_protocol = %t,
is_ssl_passthrough_enabled = %t, is_ssl_passthrough_enabled = %t,
http_redirect_code = %v, http_redirect_code = %v,
listen_ports = { ssl_proxy = "%v", https = "%v" }, listen_ports = { ssl_proxy = "%v", https = "%v" },
@ -285,6 +286,7 @@ func configForLua(input interface{}) string {
hsts_preload = %t, hsts_preload = %t,
}`, }`,
all.Cfg.UseForwardedHeaders, all.Cfg.UseForwardedHeaders,
all.Cfg.UseProxyProtocol,
all.IsSSLPassthroughEnabled, all.IsSSLPassthroughEnabled,
all.Cfg.HTTPRedirectCode, all.Cfg.HTTPRedirectCode,
all.ListenPorts.SSLProxy, all.ListenPorts.SSLProxy,

View file

@ -40,9 +40,9 @@ import (
"k8s.io/ingress-nginx/internal/task" "k8s.io/ingress-nginx/internal/task"
) )
const ( // UpdateInterval defines the time interval, in seconds, in
updateInterval = 60 * time.Second // which the status should check if an update is required.
) var UpdateInterval = 60
// Syncer ... // Syncer ...
type Syncer interface { type Syncer interface {
@ -98,7 +98,7 @@ func (s statusSync) Run(stopCh chan struct{}) {
// when this instance is the leader we need to enqueue // when this instance is the leader we need to enqueue
// an item to trigger the update of the Ingress status. // an item to trigger the update of the Ingress status.
wait.PollUntil(updateInterval, func() (bool, error) { wait.PollUntil(time.Duration(UpdateInterval)*time.Second, func() (bool, error) {
s.syncQueue.EnqueueTask(task.GetDummyObject("sync status")) s.syncQueue.EnqueueTask(task.GetDummyObject("sync status"))
return false, nil return false, nil
}, stopCh) }, stopCh)

View file

@ -1,34 +0,0 @@
repo: kubernetes/ingress
labels:
- name: area/api
color: ededed
- name: area/docs
color: 1d76db
- name: area/infra
color: bfdadc
- name: backend/gce
color: "5319e7"
- name: backend/generic
color: c2e0c6
- name: backend/nginx
color: c5def5
- name: bug
color: ee0701
- name: 'cncf-cla: no'
color: ededed
- name: 'cncf-cla: yes'
color: ededed
- name: duplicate
color: cccccc
- name: enhancement
color: 84b6eb
- name: help wanted
color: 128A0C
- name: invalid
color: e6e6e6
- name: lgtm
color: 15dd18
- name: question
color: cc317c
- name: wontfix
color: ffffff

View file

@ -1,4 +1,4 @@
mkdocs-material~=4.4.0 mkdocs-material~=4.6.2
mkdocs~=1.0.4 mkdocs~=1.0.4
pymdown-extensions~=6.0 pymdown-extensions~=6.3
pygments~=2.3.1 pygments~=2.5.2

View file

@ -54,15 +54,12 @@ function _M.set_cookie(self, value)
end end
end end
if cookie_samesite then
cookie_path = cookie_path .. "; SameSite=" .. cookie_samesite
end
local cookie_data = { local cookie_data = {
key = self:cookie_name(), key = self:cookie_name(),
value = value, value = value,
path = cookie_path, path = cookie_path,
httponly = true, httponly = true,
samesite = cookie_samesite,
secure = ngx.var.https == "on", secure = ngx.var.https == "on",
} }

View file

@ -123,6 +123,12 @@ function _M.rewrite(location_config)
end end
end end
if config.use_proxy_protocol then
if ngx.var.proxy_protocol_server_port == "443" then
ngx.var.pass_access_scheme = "https"
end
end
ngx.var.pass_port = ngx.var.pass_server_port ngx.var.pass_port = ngx.var.pass_server_port
if config.is_ssl_passthrough_enabled then if config.is_ssl_passthrough_enabled then
if ngx.var.pass_server_port == config.listen_ports.ssl_proxy then if ngx.var.pass_server_port == config.listen_ports.ssl_proxy then

View file

@ -114,6 +114,7 @@ describe("Sticky", function()
set = function(self, payload) set = function(self, payload)
assert.equal(payload.key, test_backend.sessionAffinityConfig.cookieSessionAffinity.name) assert.equal(payload.key, test_backend.sessionAffinityConfig.cookieSessionAffinity.name)
assert.equal(payload.path, ngx.var.location_path) assert.equal(payload.path, ngx.var.location_path)
assert.equal(payload.samesite, nil)
assert.equal(payload.domain, nil) assert.equal(payload.domain, nil)
assert.equal(payload.httponly, true) assert.equal(payload.httponly, true)
assert.equal(payload.secure, false) assert.equal(payload.secure, false)
@ -143,6 +144,7 @@ describe("Sticky", function()
set = function(self, payload) set = function(self, payload)
assert.equal(payload.key, test_backend.sessionAffinityConfig.cookieSessionAffinity.name) assert.equal(payload.key, test_backend.sessionAffinityConfig.cookieSessionAffinity.name)
assert.equal(payload.path, ngx.var.location_path) assert.equal(payload.path, ngx.var.location_path)
assert.equal(payload.samesite, nil)
assert.equal(payload.domain, nil) assert.equal(payload.domain, nil)
assert.equal(payload.httponly, true) assert.equal(payload.httponly, true)
assert.equal(payload.secure, true) assert.equal(payload.secure, true)
@ -185,6 +187,7 @@ describe("Sticky", function()
set = function(self, payload) set = function(self, payload)
assert.equal(payload.key, test_backend.sessionAffinityConfig.cookieSessionAffinity.name) assert.equal(payload.key, test_backend.sessionAffinityConfig.cookieSessionAffinity.name)
assert.equal(payload.path, ngx.var.location_path) assert.equal(payload.path, ngx.var.location_path)
assert.equal(payload.samesite, nil)
assert.equal(payload.domain, nil) assert.equal(payload.domain, nil)
assert.equal(payload.httponly, true) assert.equal(payload.httponly, true)
assert.equal(payload.secure, false) assert.equal(payload.secure, false)
@ -228,6 +231,7 @@ describe("Sticky", function()
assert.equal(payload.path, ngx.var.location_path) assert.equal(payload.path, ngx.var.location_path)
assert.equal(payload.domain, ngx.var.host) assert.equal(payload.domain, ngx.var.host)
assert.equal(payload.httponly, true) assert.equal(payload.httponly, true)
assert.equal(payload.samesite, nil)
return true, nil return true, nil
end, end,
get = function(k) return false end, get = function(k) return false end,
@ -368,6 +372,7 @@ describe("Sticky", function()
set = function(self, payload) set = function(self, payload)
assert.equal(payload.key, test_backend.sessionAffinityConfig.cookieSessionAffinity.name) assert.equal(payload.key, test_backend.sessionAffinityConfig.cookieSessionAffinity.name)
assert.equal(payload.path, ngx.var.location_path) assert.equal(payload.path, ngx.var.location_path)
assert.equal(payload.samesite, nil)
assert.equal(payload.domain, nil) assert.equal(payload.domain, nil)
assert.equal(payload.httponly, true) assert.equal(payload.httponly, true)
assert.equal(payload.secure, false) assert.equal(payload.secure, false)
@ -405,13 +410,14 @@ describe("Sticky", function()
cookie.new = mocked_cookie_new cookie.new = mocked_cookie_new
end) end)
local function test_set_cookie(sticky, samesite, conditional_samesite_none, expected_path) local function test_set_cookie(sticky, samesite, conditional_samesite_none, expected_path, expected_samesite)
local s = {} local s = {}
cookie.new = function(self) cookie.new = function(self)
local cookie_instance = { local cookie_instance = {
set = function(self, payload) set = function(self, payload)
assert.equal(payload.key, test_backend.sessionAffinityConfig.cookieSessionAffinity.name) assert.equal(payload.key, test_backend.sessionAffinityConfig.cookieSessionAffinity.name)
assert.equal(payload.path, expected_path) assert.equal(payload.path, expected_path)
assert.equal(payload.samesite, expected_samesite)
assert.equal(payload.domain, nil) assert.equal(payload.domain, nil)
assert.equal(payload.httponly, true) assert.equal(payload.httponly, true)
assert.equal(payload.secure, false) assert.equal(payload.secure, false)
@ -433,27 +439,27 @@ describe("Sticky", function()
end end
it("returns a cookie with SameSite=Strict when user specifies samesite strict", function() it("returns a cookie with SameSite=Strict when user specifies samesite strict", function()
test_set_cookie(sticky_balanced, "Strict", false, "/; SameSite=Strict") test_set_cookie(sticky_balanced, "Strict", false, "/", "Strict")
end) end)
it("returns a cookie with SameSite=Strict when user specifies samesite strict and conditional samesite none", function() it("returns a cookie with SameSite=Strict when user specifies samesite strict and conditional samesite none", function()
test_set_cookie(sticky_balanced, "Strict", true, "/; SameSite=Strict") test_set_cookie(sticky_balanced, "Strict", true, "/", "Strict")
end) end)
it("returns a cookie with SameSite=Lax when user specifies samesite lax", function() it("returns a cookie with SameSite=Lax when user specifies samesite lax", function()
test_set_cookie(sticky_balanced, "Lax", false, "/; SameSite=Lax") test_set_cookie(sticky_balanced, "Lax", false, "/", "Lax")
end) end)
it("returns a cookie with SameSite=Lax when user specifies samesite lax and conditional samesite none", function() it("returns a cookie with SameSite=Lax when user specifies samesite lax and conditional samesite none", function()
test_set_cookie(sticky_balanced, "Lax", true, "/; SameSite=Lax") test_set_cookie(sticky_balanced, "Lax", true, "/", "Lax")
end) end)
it("returns a cookie with SameSite=None when user specifies samesite None", function() it("returns a cookie with SameSite=None when user specifies samesite None", function()
test_set_cookie(sticky_balanced, "None", false, "/; SameSite=None") test_set_cookie(sticky_balanced, "None", false, "/", "None")
end) end)
it("returns a cookie with SameSite=None when user specifies samesite None and conditional samesite none with supported user agent", function() it("returns a cookie with SameSite=None when user specifies samesite None and conditional samesite none with supported user agent", function()
mock_ngx({ var = { location_path = "/", host = "test.com" , http_user_agent = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.2704.103 Safari/537.36"} }) mock_ngx({ var = { location_path = "/", host = "test.com" , http_user_agent = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.2704.103 Safari/537.36"} })
test_set_cookie(sticky_balanced, "None", true, "/; SameSite=None") test_set_cookie(sticky_balanced, "None", true, "/", "None")
end) end)
it("returns a cookie without SameSite=None when user specifies samesite None and conditional samesite none with unsupported user agent", function() it("returns a cookie without SameSite=None when user specifies samesite None and conditional samesite none with unsupported user agent", function()
mock_ngx({ var = { location_path = "/", host = "test.com" , http_user_agent = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36"} }) mock_ngx({ var = { location_path = "/", host = "test.com" , http_user_agent = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36"} })
test_set_cookie(sticky_balanced, "None", true, "/") test_set_cookie(sticky_balanced, "None", true, "/", nil)
end) end)
end) end)
end) end)

View file

@ -69,7 +69,7 @@ var _ = framework.IngressNginxDescribe("Annotations - Mirror", func() {
It("should disable mirror-request-body", func() { It("should disable mirror-request-body", func() {
annotations := map[string]string{ annotations := map[string]string{
"nginx.ingress.kubernetes.io/mirror-uri": "http://localhost/mirror", "nginx.ingress.kubernetes.io/mirror-target": "http://localhost/mirror",
"nginx.ingress.kubernetes.io/mirror-request-body": "off", "nginx.ingress.kubernetes.io/mirror-request-body": "off",
} }

View file

@ -47,6 +47,11 @@ if ! command -v parallel &> /dev/null; then
exit 1 exit 1
fi fi
if ! command -v kind --version &> /dev/null; then
echo "kind is not installed. Use the package manager or visit the official site https://kind.sigs.k8s.io/"
exit 1
fi
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
export TAG=dev export TAG=dev
@ -59,8 +64,6 @@ export DOCKER_CLI_EXPERIMENTAL=enabled
KIND_CLUSTER_NAME="ingress-nginx-dev" KIND_CLUSTER_NAME="ingress-nginx-dev"
kind --version || $(echo "Please install kind before running e2e tests";exit 1)
echo "[dev-env] creating Kubernetes cluster with kind" echo "[dev-env] creating Kubernetes cluster with kind"
export KUBECONFIG="${HOME}/.kube/kind-config-${KIND_CLUSTER_NAME}" export KUBECONFIG="${HOME}/.kube/kind-config-${KIND_CLUSTER_NAME}"

View file

@ -69,6 +69,39 @@ var _ = framework.IngressNginxDescribe("Proxy Protocol", func() {
body := string(data) body := string(data)
Expect(body).Should(ContainSubstring(fmt.Sprintf("host=%v", "proxy-protocol"))) Expect(body).Should(ContainSubstring(fmt.Sprintf("host=%v", "proxy-protocol")))
Expect(body).Should(ContainSubstring(fmt.Sprintf("x-forwarded-port=1234"))) Expect(body).Should(ContainSubstring(fmt.Sprintf("x-forwarded-port=1234")))
Expect(body).Should(ContainSubstring(fmt.Sprintf("x-forwarded-proto=http")))
Expect(body).Should(ContainSubstring(fmt.Sprintf("x-forwarded-for=192.168.0.1")))
})
It("should respect proto passed by the PROXY Protocol server port", func() {
host := "proxy-protocol"
f.UpdateNginxConfigMapData(setting, "true")
f.EnsureIngress(framework.NewSingleIngress(host, "/", host, f.Namespace, framework.EchoService, 80, nil))
f.WaitForNginxServer(host,
func(server string) bool {
return strings.Contains(server, "server_name proxy-protocol") &&
strings.Contains(server, "listen 80 proxy_protocol")
})
ip := f.GetNginxIP()
conn, err := net.Dial("tcp", net.JoinHostPort(ip, "80"))
Expect(err).NotTo(HaveOccurred(), "unexpected error creating connection to %s:80", ip)
defer conn.Close()
header := "PROXY TCP4 192.168.0.1 192.168.0.11 56324 443\r\n"
conn.Write([]byte(header))
conn.Write([]byte("GET / HTTP/1.1\r\nHost: proxy-protocol\r\n\r\n"))
data, err := ioutil.ReadAll(conn)
Expect(err).NotTo(HaveOccurred(), "unexpected error reading connection data")
body := string(data)
Expect(body).Should(ContainSubstring(fmt.Sprintf("host=%v", "proxy-protocol")))
Expect(body).Should(ContainSubstring(fmt.Sprintf("x-forwarded-port=443")))
Expect(body).Should(ContainSubstring(fmt.Sprintf("x-forwarded-proto=https")))
Expect(body).Should(ContainSubstring(fmt.Sprintf("x-forwarded-for=192.168.0.1"))) Expect(body).Should(ContainSubstring(fmt.Sprintf("x-forwarded-for=192.168.0.1")))
}) })
}) })