From a03213218fa4ee31c044523ff7fbdf0b3100fe99 Mon Sep 17 00:00:00 2001 From: Travis Bot Date: Tue, 4 Sep 2018 23:47:40 +0000 Subject: [PATCH] Deploy GitHub Pages --- 404.html | 12 + deploy/baremetal/index.html | 1470 +++++++++++++++++ deploy/index.html | 47 +- deploy/rbac/index.html | 16 +- deploy/upgrade/index.html | 14 +- development/index.html | 47 +- examples/PREREQUISITES/index.html | 29 +- examples/affinity/cookie/README/index.html | 19 +- examples/auth/basic/README/index.html | 17 +- examples/auth/client-certs/README/index.html | 12 + examples/auth/external-auth/README/index.html | 24 +- .../oauth-external-auth/README/index.html | 15 +- .../configuration-snippets/README/index.html | 13 +- .../custom-configuration/README/index.html | 14 +- .../custom-errors/README/index.html | 21 +- .../custom-headers/README/index.html | 13 +- .../custom-upstream-check/README/index.html | 20 +- .../external-auth-headers/README/index.html | 16 +- .../ssl-dh-param/README/index.html | 17 +- .../customization/sysctl/README/index.html | 12 + examples/docker-registry/README/index.html | 16 +- examples/grpc/README/index.html | 17 +- examples/index.html | 12 + examples/multi-tls/README/index.html | 22 +- examples/rewrite/README/index.html | 20 +- examples/static-ip/README/index.html | 23 +- examples/tls-termination/README/index.html | 13 +- how-it-works/index.html | 12 + images/baremetal/baremetal_overview.gliffy | 1 + images/baremetal/baremetal_overview.jpg | Bin 0 -> 38234 bytes images/baremetal/cloud_overview.gliffy | 1 + images/baremetal/cloud_overview.jpg | Bin 0 -> 48236 bytes images/baremetal/hostnetwork.gliffy | 1 + images/baremetal/hostnetwork.jpg | Bin 0 -> 41504 bytes images/baremetal/nodeport.gliffy | 1 + images/baremetal/nodeport.jpg | Bin 0 -> 48359 bytes images/baremetal/user_edge.gliffy | 1 + images/baremetal/user_edge.jpg | Bin 0 -> 63036 bytes index.html | 12 + search/search_index.json | 144 +- sitemap.xml | 93 +- troubleshooting/index.html | 27 +- user-guide/cli-arguments/index.html | 12 + user-guide/custom-errors/index.html | 12 + user-guide/default-backend/index.html | 12 + .../exposing-tcp-udp-services/index.html | 13 +- user-guide/external-articles/index.html | 12 + user-guide/miscellaneous/index.html | 12 + user-guide/monitoring/index.html | 19 +- user-guide/multiple-ingress/index.html | 15 +- .../annotations/index.html | 82 +- .../nginx-configuration/configmap/index.html | 36 +- .../custom-template/index.html | 13 +- user-guide/nginx-configuration/index.html | 12 + .../nginx-configuration/log-format/index.html | 13 +- .../third-party-addons/modsecurity/index.html | 12 + .../third-party-addons/opentracing/index.html | 130 +- user-guide/tls/index.html | 15 +- 58 files changed, 2308 insertions(+), 376 deletions(-) create mode 100644 deploy/baremetal/index.html create mode 100644 images/baremetal/baremetal_overview.gliffy create mode 100644 images/baremetal/baremetal_overview.jpg create mode 100644 images/baremetal/cloud_overview.gliffy create mode 100644 images/baremetal/cloud_overview.jpg create mode 100644 images/baremetal/hostnetwork.gliffy create mode 100644 images/baremetal/hostnetwork.jpg create mode 100644 images/baremetal/nodeport.gliffy create mode 100644 images/baremetal/nodeport.jpg create mode 100644 images/baremetal/user_edge.gliffy create mode 100644 images/baremetal/user_edge.jpg diff --git a/404.html b/404.html index af4d32d3c..fb30c2755 100644 --- a/404.html +++ b/404.html @@ -352,6 +352,18 @@ +
  • + + Bare-metal considerations + +
  • + + + + + + +
  • Role Based Access Control (RBAC) diff --git a/deploy/baremetal/index.html b/deploy/baremetal/index.html new file mode 100644 index 000000000..924a8964e --- /dev/null +++ b/deploy/baremetal/index.html @@ -0,0 +1,1470 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Bare-metal considerations - NGINX Ingress Controller + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content + + + +
    + +
    + +
    + + + + + + + + + + +
    +
    + + +
    +
    +
    + +
    +
    +
    + + +
    +
    +
    + + +
    +
    +
    + + +
    +
    + + + + + +

    Bare-metal considerations

    +

    In traditional cloud environments, where network load balancers are available on-demand, a single Kubernetes manifest +suffices to provide a single point of contact to the NGINX Ingress controller to external clients and, indirectly, to +any application running inside the cluster. Bare-metal environments lack this commodity, requiring a slightly +different setup to offer the same kind of access to external consumers.

    +

    Cloud environment +Bare-metal environment

    +

    The rest of this document describes a few recommended approaches to deploying the NGINX Ingress controller inside a +Kubernetes cluster running on bare-metal.

    +

    Over a NodePort Service

    +

    Due to its simplicity, this is the setup a user will deploy by default when following the steps described in the +installation guide.

    +
    +

    Info

    +

    A Service of type NodePort exposes, via the kube-proxy component, the same unprivileged port (default: +30000-32767) on every Kubernetes node, masters included. For more information, see Services.

    +
    +

    In this configuration, the NGINX container remains isolated from the host network. As a result, it can safely bind to +any port, including the standard HTTP ports 80 and 443. However, due to the container namespace isolation, a client +located outside the cluster network (e.g. on the public internet) is not able to access Ingress hosts directly on ports +80 and 443. Instead, the external client must append the NodePort allocated to the ingress-nginx Service to HTTP +requests.

    +

    NodePort request flow

    +
    +

    Example

    +

    Given the NodePort 30100 allocated to the ingress-nginx Service

    +
    $ kubectl -n ingress-nginx get svc
    +NAME                   TYPE        CLUSTER-IP     PORT(S)
    +default-http-backend   ClusterIP   10.0.64.249    80/TCP
    +ingress-nginx          NodePort    10.0.220.217   80:30100/TCP,443:30101/TCP
    +
    + +

    and a Kubernetes node with the public IP address 203.0.113.2 (the external IP is added as an example, in most +bare-metal environments this value is <None>)

    +
    $ kubectl describe node 
    +NAME     STATUS   ROLES    EXTERNAL-IP
    +host-1   Ready    master   203.0.113.1
    +host-2   Ready    node     203.0.113.2
    +host-3   Ready    node     203.0.113.3
    +
    + +

    a client would reach an Ingress with host: myapp.example.com at http://myapp.example.com:30100, where the +myapp.example.com subdomain resolves to the 203.0.113.2 IP address.

    +
    +
    +

    Impact on the host system

    +

    While it may sound tempting to reconfigure the NodePort range using the --service-node-port-range API server flag +to include unprivileged ports and be able to expose ports 80 and 443, doing so may result in unexpected issues +including (but not limited to) the use of ports otherwise reserved to system daemons and the necessity to grant +kube-proxy privileges it may otherwise not require.

    +

    This practice is therefore discouraged. See the other approaches proposed in this page for alternatives.

    +
    +

    This approach has a few other limitations one ought to be aware of:

    +
      +
    • Source IP address
    • +
    +

    Services of type NodePort perform source address translation by default. This means the source IP of a +HTTP request is always the IP address of the Kubernetes node that received the request from the perspective of +NGINX.

    +

    The recommended way to preserve the source IP in a NodePort setup is to set the value of the externalTrafficPolicy +field of the ingress-nginx Service spec to Local (example).

    +
    +

    Warning

    +

    This setting effectively drops packets sent to Kubernetes nodes which are not running any instance of the NGINX +Ingress controller. Consider assigning NGINX Pods to specific nodes in order to control on what nodes +the NGINX Ingress controller should be scheduled or not scheduled.

    +
    +
    +

    Example

    +

    In a Kubernetes cluster composed of 3 nodes (the external IP is added as an example, in most bare-metal environments +this value is <None>)

    +
    $ kubectl describe node 
    +NAME     STATUS   ROLES    EXTERNAL-IP
    +host-1   Ready    master   203.0.113.1
    +host-2   Ready    node     203.0.113.2
    +host-3   Ready    node     203.0.113.3
    +
    + +

    with a nginx-ingress-controller Deployment composed of 2 replicas

    +
    $ kubectl -n ingress-nginx get pod -o wide
    +NAME                                       READY   STATUS    IP           NODE
    +default-http-backend-7c5bc89cc9-p86md      1/1     Running   172.17.1.1   host-2
    +nginx-ingress-controller-cf9ff8c96-8vvf8   1/1     Running   172.17.0.3   host-3
    +nginx-ingress-controller-cf9ff8c96-pxsds   1/1     Running   172.17.1.4   host-2
    +
    + +

    Requests sent to host-2 and host-3 would be forwarded to NGINX and original client's IP would be preserved, +while requests to host-1 would get dropped because there is no NGINX replica running on that node.

    +
    +
      +
    • Ingress status
    • +
    +

    Because NodePort Services do not get a LoadBalancerIP assigned by definition, the NGINX Ingress controller does not +update the status of Ingress objects it manages.

    +
    $ kubectl get ingress
    +NAME           HOSTS               ADDRESS   PORTS
    +test-ingress   myapp.example.com             80
    +
    + +

    Despite the fact there is no load balancer providing a public IP address to the NGINX Ingress controller, it is possible +to force the status update of all managed Ingress objects by setting the externalIPs field of the ingress-nginx +Service.

    +
    +

    Example

    +

    Given the following 3-node Kubernetes cluster (the external IP is added as an example, in most bare-metal +environments this value is <None>)

    +
    $ kubectl describe node 
    +NAME     STATUS   ROLES    EXTERNAL-IP
    +host-1   Ready    master   203.0.113.1
    +host-2   Ready    node     203.0.113.2
    +host-3   Ready    node     203.0.113.3
    +
    + +

    one could edit the ingress-nginx Service and add the following field to the object spec

    +
    spec:
    +  externalIPs:
    +  - 203.0.113.1
    +  - 203.0.113.2
    +  - 203.0.113.3
    +
    + +

    which would in turn be reflected on Ingress objects as follows:

    +
    $ kubectl get ingress -o wide
    +NAME           HOSTS               ADDRESS                               PORTS
    +test-ingress   myapp.example.com   203.0.113.1,203.0.113.2,203.0.113.3   80
    +
    + +
    +
      +
    • Redirects
    • +
    +

    As NGINX is not aware of the port translation operated by the NodePort Service, backend applications are responsible +for generating redirect URLs that take into account the URL used by external clients, including the NodePort.

    +
    +

    Example

    +

    Redirects generated by NGINX, for instance HTTP to HTTPS or domain to www.domain, are generated without +NodePort:

    +
    $ curl http://myapp.example.com:30100`
    +HTTP/1.1 308 Permanent Redirect
    +Server: nginx/1.15.2
    +Location: https://myapp.example.com/  #-> missing NodePort in HTTPS redirect
    +
    + +
    +

    Via the host network

    +

    In a setup where there is no external load balancer available but using NodePorts is not an option, one can configure +ingress-nginx Pods to use the network of the host they run on instead of a dedicated network namespace. The benefit of +this approach is that the NGINX Ingress controller can bind ports 80 and 443 directly to Kubernetes nodes' network +interfaces, without the extra network translation imposed by NodePort Services.

    +
    +

    Note

    +

    This approach does not leverage any Service object to expose the NGINX Ingress controller. If the ingress-nginx +Service exists in the target cluster, it is recommended to delete it.

    +
    +

    This can be achieved by enabling the hostNetwork option in the Pods' spec.

    +
    template:
    +  spec:
    +    hostNetwork: true
    +
    + +
    +

    Security considerations

    +

    Enabling this option exposes every system daemon to the NGINX Ingress controller on any network interface, +including the host's loopback. Please evaluate the impact this may have on the security of your system carefully.

    +
    +
    +

    Example

    +

    Consider this nginx-ingress-controller Deployment composed of 2 replicas, NGINX Pods inherit from the IP address +of their host instead of an internal Pod IP.

    +
    $ kubectl -n ingress-nginx get pod -o wide
    +NAME                                       READY   STATUS    IP            NODE
    +default-http-backend-7c5bc89cc9-p86md      1/1     Running   172.17.1.1    host-2
    +nginx-ingress-controller-5b4cf5fc6-7lg6c   1/1     Running   203.0.113.3   host-3
    +nginx-ingress-controller-5b4cf5fc6-lzrls   1/1     Running   203.0.113.2   host-2
    +
    + +
    +

    One major limitation of this deployment approach is that only a single NGINX Ingress controller Pod may be scheduled +on each cluster node, because binding the same port multiple times on the same network interface is technically +impossible. Pods that are unschedulable due to such situation fail with the following event:

    +
    $ kubectl -n ingress-nginx describe pod <unschedulable-nginx-ingress-controller-pod>
    +...
    +Events:
    +  Type     Reason            From               Message
    +  ----     ------            ----               -------
    +  Warning  FailedScheduling  default-scheduler  0/3 nodes are available: 3 node(s) didn't have free ports for the requested pod ports.
    +
    + +

    One way to ensure only schedulable Pods are created is to deploy the NGINX Ingress controller as a DaemonSet instead +of a traditional Deployment.

    +
    +

    Info

    +

    A DaemonSet schedules exactly one type of Pod per cluster node, masters included, unless a node is configured to +repel those Pods. For more information, see DaemonSet.

    +
    +

    Because most properties of DaemonSet objects are identical to Deployment objects, this documentation page leaves the +configuration of the corresponding manifest at the user's discretion.

    +

    DaemonSet with hostNetwork flow

    +

    Like with NodePorts, this approach has a few quirks it is important to be aware of.

    +
      +
    • DNS resolution
    • +
    +

    Pods configured with hostNetwork: true do not use the internal DNS resolver (i.e. kube-dns or CoreDNS), unless +their dnsPolicy spec field is set to ClusterFirstWithHostNet. Consider using this setting if NGINX is +expected to resolve internal names for any reason.

    +
      +
    • Ingress status
    • +
    +

    Because there is no Service exposing the NGINX Ingress controller in a configuration using the host network, the default +--publish-service flag used in standard cloud setups does not apply and the status of all Ingress objects remains +blank.

    +
    $ kubectl get ingress
    +NAME           HOSTS               ADDRESS   PORTS
    +test-ingress   myapp.example.com             80
    +
    + +

    Instead, and because bare-metal nodes usually don't have an ExternalIP, one has to enable the +--report-node-internal-ip-address flag, which sets the status of all Ingress objects to the internal IP +address of all nodes running the NGINX Ingress controller.

    +
    +

    Example

    +

    Given a nginx-ingress-controller DaemonSet composed of 2 replicas

    +
    $ kubectl -n ingress-nginx get pod -o wide
    +NAME                                       READY   STATUS    IP            NODE
    +default-http-backend-7c5bc89cc9-p86md      1/1     Running   172.17.1.1    host-2
    +nginx-ingress-controller-5b4cf5fc6-7lg6c   1/1     Running   203.0.113.3   host-3
    +nginx-ingress-controller-5b4cf5fc6-lzrls   1/1     Running   203.0.113.2   host-2
    +
    + +

    the controller sets the status of all Ingress objects it manages to the following value:

    +
    $ kubectl get ingress -o wide
    +NAME           HOSTS               ADDRESS                   PORTS
    +test-ingress   myapp.example.com   203.0.113.2,203.0.113.3   80
    +
    + +
    +
    +

    Note

    +

    Alternatively, it is possible to override the address written to Ingress objects using the +--publish-status-address flag. See Command line arguments.

    +
    +

    Using a self-provisioned edge

    +

    Similarly to cloud environments, this deployment approach requires an edge network component providing a public +entrypoint to the Kubernetes cluster. This edge component can be either hardware (e.g. vendor appliance) or software +(e.g. HAproxy) and is usually managed outside of the Kubernetes landscape by operations teams.

    +

    Such deployment builds upon the NodePort Service described above in Over a NodePort Service, +with one significant difference: external clients do not access cluster nodes directly, only the edge component does. +This is particularly suitable for private Kubernetes clusters where none of the nodes has a public IP address.

    +

    On the edge side, the only prerequisite is to dedicate a public IP address that forwards all HTTP traffic to Kubernetes +nodes and/or masters. Incoming traffic on TCP ports 80 and 443 is forwarded to the corresponding HTTP and HTTPS NodePort +on the target nodes as shown in the diagram below:

    +

    User edge

    + + + + + + + + + + +
    +
    +
    +
    + + + + +
    + + + + + + + + + + + + + \ No newline at end of file diff --git a/deploy/index.html b/deploy/index.html index bbf12e618..7df44d3dc 100644 --- a/deploy/index.html +++ b/deploy/index.html @@ -461,8 +461,8 @@
  • - - Baremetal + + Bare-metal
  • @@ -514,6 +514,18 @@ +
  • + + Bare-metal considerations + +
  • + + + + + + +
  • Role Based Access Control (RBAC) @@ -1268,8 +1280,8 @@
  • - - Baremetal + + Bare-metal
  • @@ -1335,7 +1347,7 @@
  • AWS
  • GCE - GKE
  • Azure
  • -
  • Baremetal
  • +
  • Bare-metal
  • Verify installation
  • @@ -1348,7 +1360,6 @@
    kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/mandatory.yaml
     
    -

    Provider Specific Steps

    There are cloud provider specific yaml files.

    Docker for Mac

    @@ -1357,13 +1368,11 @@
    kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/cloud-generic.yaml
     
    -

    minikube

    For standard usage:

    minikube addons enable ingress
     
    -

    For development:

    1. Disable the ingress addon:
    2. @@ -1371,7 +1380,6 @@
      $ minikube addons disable ingress
       
      -
      1. Execute make dev-env
      2. Confirm the nginx-ingress-controller deployment exists:
      3. @@ -1382,7 +1390,6 @@ nginx-ingress-controller-fdcdcd6dd-vvpgs 1/1 Running 0 11s -

        AWS

        In AWS we use an Elastic Load Balancer (ELB) to expose the NGINX Ingress controller behind a Service of Type=LoadBalancer. Since Kubernetes v1.9.0 it is possible to use a classic load balancer (ELB) or network load balancer (NLB) @@ -1398,7 +1405,6 @@ Please check the kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/aws/patch-configmap-l4.yaml -

        For L7:

        Change line of the file provider/aws/service-l7.yaml replacing the dummy id with a valid one "arn:aws:acm:us-west-2:XXXXXXXX:certificate/XXXXXX-XXXXXXX-XXXXXXX-XXXXXXXX" Then execute:

        @@ -1406,7 +1412,6 @@ Then execute:

        kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/aws/patch-configmap-l7.yaml -

        This example creates an ELB with just two listeners, one in port 80 and another in port 443

        Listeners

        Network Load Balancer (NLB)
        @@ -1414,30 +1419,29 @@ Then execute:

        kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/aws/service-nlb.yaml
         
        -

        GCE - GKE

        kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/cloud-generic.yaml
         
        -

        Important Note: proxy protocol is not supported in GCE/GKE

        Azure

        kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/cloud-generic.yaml
         
        - -

        Baremetal

        +

        Bare-metal

        Using NodePort:

        kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/baremetal/service-nodeport.yaml
         
        - +
        +

        Tip

        +

        For extended notes regarding deployments on bare-metal, see Bare-metal considerations.

        +

        Verify installation

        To check if the ingress controller pods have started, run the following command:

        kubectl get pods --all-namespaces -l app=ingress-nginx --watch
         
        -

        Once the operator pods are running, you can cancel the above command by typing Ctrl+C. Now, you are ready to create your first ingress.

        Detect installed version

        @@ -1447,19 +1451,16 @@ Now, you are ready to create your first ingress.

        kubectl exec -it $POD_NAME -n $POD_NAMESPACE -- /nginx-ingress-controller --version -

        Using Helm

        NGINX Ingress controller can be installed via Helm using the chart stable/nginx-ingress from the official charts repository. To install the chart with the release name my-nginx:

        helm install stable/nginx-ingress --name my-nginx
         
        -

        If the kubernetes cluster has RBAC enabled, then run:

        helm install stable/nginx-ingress --name my-nginx --set rbac.create=true
         
        -

        Detect installed version:

        POD_NAME=$(kubectl get pods -l app=nginx-ingress -o jsonpath='{.items[0].metadata.name}')
         kubectl exec -it $POD_NAME -- /nginx-ingress-controller --version
        @@ -1499,13 +1500,13 @@ To install the chart with the release name my-nginx
                 
                 
        -          
        -

        simply change the 0.9.0 tag to the version you wish to upgrade to. The easiest way to do this is e.g. (do note you may need to change the name parameter according to your installation):

        kubectl set image deployment/nginx-ingress-controller \
           nginx-ingress-controller=nginx:quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.18.0
         
        -

        For interactive editing, use kubectl edit deployment nginx-ingress-controller.

        With Helm

        If you installed ingress-nginx using the Helm command in the deployment docs so its name is ngx-ingress, diff --git a/development/index.html b/development/index.html index a7bd6bd7b..c7a65d924 100644 --- a/development/index.html +++ b/development/index.html @@ -356,6 +356,18 @@ +

      4. + + Bare-metal considerations + +
      5. + + + + + + +
      6. Role Based Access Control (RBAC) @@ -1251,7 +1263,6 @@ git clone https://github.com/$YOUR_GITHUB_USERNAME/ingress-nginx.git cd ingress-nginx -

        Initial developer environment build

        Prequisites: Minikube must be installed. @@ -1261,19 +1272,14 @@ See releases for i

        $ make dev-env
         
        -

        Updating the deployment

        -

        The nginx controller container image can be rebuilt using:

        +

        The nginx controller container image can be rebuilt using:

        $ ARCH=amd64 TAG=dev REGISTRY=$USER/ingress-controller make build container
        -
        - - -

        The image will only be used by pods created after the rebuild. To delete old pods which will cause new ones to spin up:

        +

        +

        The image will only be used by pods created after the rebuild. To delete old pods which will cause new ones to spin up:

        $ kubectl get pods -n ingress-nginx
         $ kubectl delete pod -n ingress-nginx nginx-ingress-controller-<unique-pod-id>
        -
        - - +

        Dependencies

        The build uses dependencies in the vendor directory, which must be installed before building a binary/image. Occasionally, you @@ -1290,12 +1296,10 @@ might need to update the dependencies.

        platform : linux/amd64 -

        If you have an older version of dep, you can update it as follows:

        $ go get -u github.com/golang/dep
         
        -

        This will automatically save the dependencies to the vendor/ directory.

        $ cd $GOPATH/src/k8s.io/ingress-nginx
         $ dep ensure
        @@ -1303,7 +1307,6 @@ might need to update the dependencies.

        $ dep prune
        -

        Building

        All ingress controllers are built through a Makefile. Depending on your requirements you can build a raw server binary, a local container image, @@ -1316,25 +1319,20 @@ or push an image to a remote repository.

        $ export REGISTRY=<your-docker-registry> -

        To find the registry simply run: docker system info | grep Registry

        Nginx Controller

        -

        Build a raw server binary

        +

        Build a raw server binary

        $ make build
        -
        - - +

        TODO: add more specific instructions needed for raw server binary.

        Build a local container image

        $ TAG=<tag> REGISTRY=$USER/ingress-controller make docker-build
         
        -

        Push the container image to a remote repository

        $ TAG=<tag> REGISTRY=$USER/ingress-controller make docker-push
         
        -

        Deploying

        There are several ways to deploy the ingress controller onto a cluster. Please check the deployment guide

        @@ -1344,31 +1342,26 @@ Please check the deployment guide

        $ make test -

        If you have access to a Kubernetes cluster, you can also run e2e tests using ginkgo.

        $ cd $GOPATH/src/k8s.io/ingress-nginx
         $ make e2e-test
         
        -

        To run unit-tests for lua code locally, run:

        $ cd $GOPATH/src/k8s.io/ingress-nginx
         $ ./rootfs/etc/nginx/lua/test/up.sh
         $ make lua-test
         
        -

        Lua tests are located in $GOPATH/src/k8s.io/ingress-nginx/rootfs/etc/nginx/lua/test. When creating a new test file it must follow the naming convention <mytest>_test.lua or it will be ignored.

        Releasing

        All Makefiles will produce a release binary, as shown above. To publish this to a wider Kubernetes user base, push the image to a container registry, like gcr.io. All release images are hosted under gcr.io/google_containers and tagged according to a semver scheme.

        -

        An example release might look like:

        +

        An example release might look like:

        $ make release
        -
        - - +

        Please follow these guidelines to cut a release:

      @@ -1177,7 +1190,6 @@ Connection: keep-alive <span>The page you're looking for could not be found.</span>
      -

      A request with a custom Accept header returns the corresponding document type (JSON):

      $ curl -D- -H 'Accept: application/json' http://10.0.0.13/
       HTTP/1.1 404 Not Found
      @@ -1191,7 +1203,6 @@ Vary: Accept-Encoding
       { "message": "The page you're looking for could not be found" }
       
      -

      To go further with this example, feel free to deploy your own applications and Ingress objects, and validate that the responses are still in the correct format when a backend returns 503 (eg. if you scale a Deployment down to 0 replica).

      diff --git a/examples/customization/custom-headers/README/index.html b/examples/customization/custom-headers/README/index.html index 0cf2ae395..932e6896b 100644 --- a/examples/customization/custom-headers/README/index.html +++ b/examples/customization/custom-headers/README/index.html @@ -358,6 +358,18 @@ +
    3. + + Bare-metal considerations + +
    4. + + + + + + +
    5. Role Based Access Control (RBAC) @@ -1105,7 +1117,6 @@ server

      | kubectl apply -f - -

      Test

      Check the contents of the configmap is present in the nginx.conf file using: kubectl exec nginx-ingress-controller-873061567-4n3k2 -n kube-system cat /etc/nginx/nginx.conf

      diff --git a/examples/customization/custom-upstream-check/README/index.html b/examples/customization/custom-upstream-check/README/index.html index c87dec7b6..87f3d685a 100644 --- a/examples/customization/custom-upstream-check/README/index.html +++ b/examples/customization/custom-upstream-check/README/index.html @@ -358,6 +358,18 @@ +
    6. + + Bare-metal considerations + +
    7. + + + + + + +
    8. Role Based Access Control (RBAC) @@ -1070,17 +1082,13 @@ spec: " | kubectl create -f - - -

      Check the annotation is present in the Ingress rule:

      +

      Check the annotation is present in the Ingress rule:

      kubectl get ingress http-svc -o yaml
      -
      - - +

      Check the NGINX configuration is updated using kubectl or the status page:

      $ kubectl exec nginx-ingress-controller-v1ppm cat /etc/nginx/nginx.conf
       
      -
      -

      Test 1: public service with no auth header

      $ curl -H 'Host: public-demo-echo-service.kube.local' -v 192.168.99.100
       * Rebuilt URL to: 192.168.99.100/
      @@ -1107,7 +1118,6 @@ follows:

      UserID: , UserRole:
      -

      Test 2: secure service with no auth header

      $ curl -H 'Host: secure-demo-echo-service.kube.local' -v 192.168.99.100
       * Rebuilt URL to: 192.168.99.100/
      @@ -1135,7 +1145,6 @@ follows:

      * Connection #0 to host 192.168.99.100 left intact
      -

      Test 3: public service with valid auth header

      $ curl -H 'Host: public-demo-echo-service.kube.local' -H 'User:internal' -v 192.168.99.100
       * Rebuilt URL to: 192.168.99.100/
      @@ -1158,7 +1167,6 @@ follows:

      UserID: 1443635317331776148, UserRole: admin
      -

      Test 4: public service with valid auth header

      -
      $ kubectl create -f configmap.yaml
       
      -

      Custom DH parameters secret

      $> openssl dhparam 1024 2> /dev/null | base64
       LS0tLS1CRUdJTiBESCBQQVJBTUVURVJ...
       
      -
      $ cat ssl-dh-param.yaml
       apiVersion: v1
       data:
      @@ -1162,11 +1171,9 @@ use a ConfigMap to configure custom Diffie-Hellman parameters file to help with
           app: ingress-nginx
       
      -
      $ kubectl create -f ssl-dh-param.yaml
       
      -

      Test

      Check the contents of the configmap is present in the nginx.conf file using: kubectl exec nginx-ingress-controller-873061567-4n3k2 -n kube-system cat /etc/nginx/nginx.conf

      diff --git a/examples/customization/sysctl/README/index.html b/examples/customization/sysctl/README/index.html index fa9ecfb6f..f4c1dde60 100644 --- a/examples/customization/sysctl/README/index.html +++ b/examples/customization/sysctl/README/index.html @@ -358,6 +358,18 @@ +
    9. + + Bare-metal considerations + +
    10. + + + + + + +
    11. Role Based Access Control (RBAC) diff --git a/examples/docker-registry/README/index.html b/examples/docker-registry/README/index.html index b4783c925..08c7c5443 100644 --- a/examples/docker-registry/README/index.html +++ b/examples/docker-registry/README/index.html @@ -358,6 +358,18 @@ +
    12. + + Bare-metal considerations + +
    13. + + + + + + +
    14. Role Based Access Control (RBAC) @@ -1153,7 +1165,6 @@
      kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/docs/examples/docker-registry/deployment.yaml
       
      -

      Important

      DO NOT RUN THIS IN PRODUCTION

      @@ -1165,7 +1176,6 @@
      wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/docs/examples/docker-registry/ingress-without-tls.yaml
       
      -

      Important

      @@ -1176,7 +1186,6 @@
      wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/docs/examples/docker-registry/ingress-with-tls.yaml
       
      -

      Deploy kube lego use Let's Encrypt certificates or edit the ingress rule to use a secret with an existing SSL certificate.

      Testing

      To test the registry is working correctly we download a known image from docker hub, create a tag pointing to the new registry and upload the image:

      @@ -1185,7 +1194,6 @@ docker push `registry.<your domain>/ubuntu:16.04`
      -

      Please replace registry.<your domain> with your domain.

      diff --git a/examples/grpc/README/index.html b/examples/grpc/README/index.html index 88535d488..1c13c2d4a 100644 --- a/examples/grpc/README/index.html +++ b/examples/grpc/README/index.html @@ -358,6 +358,18 @@ +
    15. + + Bare-metal considerations + +
    16. + + + + + + +
    17. Role Based Access Control (RBAC) @@ -1198,7 +1210,6 @@ nginx controller.

      $ kubectl create -f app.yaml
       
      -

      This is a standard kubernetes deployment object. It is running a grpc service listening on port 50051.

      The sample application @@ -1212,7 +1223,6 @@ is a grpc server implemented in go. Here's the stripped-down implementation:

      } -

      The takeaway is that we are not doing any TLS configuration on the server (as we are terminating TLS at the ingress level, grpc traffic will travel unencrypted inside the cluster and arrive "insecure").

      @@ -1223,14 +1233,12 @@ itself, add the ingress annotation nginx.ingress.kubern
      $ kubectl create -f svc.yaml
       
      -

      Here we have a typical service. Nothing special, just routing traffic to the backend application on port 50051.

      Step 3: the kubernetes Ingress

      $ kubectl create -f ingress.yaml
       
      -

      A few things to note:

      1. We've tagged the ingress with the annotation @@ -1252,7 +1260,6 @@ can actually talk to the backend. To do this, we'll use the } -

        Debugging Hints

        1. Obviously, watch the logs on your app.
        2. diff --git a/examples/index.html b/examples/index.html index 39038039b..5dc980b93 100644 --- a/examples/index.html +++ b/examples/index.html @@ -358,6 +358,18 @@ +
        3. + + Bare-metal considerations + +
        4. + + + + + + +
        5. Role Based Access Control (RBAC) diff --git a/examples/multi-tls/README/index.html b/examples/multi-tls/README/index.html index dfd083d9d..2a510c6c0 100644 --- a/examples/multi-tls/README/index.html +++ b/examples/multi-tls/README/index.html @@ -358,6 +358,18 @@ +
        6. + + Bare-metal considerations + +
        7. + + + + + + +
        8. Role Based Access Control (RBAC) @@ -1054,7 +1066,7 @@
        9. Create tls secrets for foo.bar.com and bar.baz.com as indicated in the yaml
        10. Create multi-tls.yaml
        -

        This should generate a segment like:

        +

        This should generate a segment like:

        $ kubectl exec -it nginx-ingress-controller-6vwd1 -- cat /etc/nginx/nginx.conf | grep "foo.bar.com" -B 7 -A 35
             server {
                 listen 80;
        @@ -1097,10 +1109,8 @@
         
                     proxy_pass http://default-http-svc-80;
                 }
        -
        - - -

        And you should be able to reach your nginx service or http-svc service using a hostname switch:

        +

        +

        And you should be able to reach your nginx service or http-svc service using a hostname switch:

        $  kubectl get ing
         NAME      RULE          BACKEND   ADDRESS                         AGE
         foo-tls   -                       104.154.30.67                   13m
        @@ -1138,7 +1148,7 @@
         
         $ curl 104.154.30.67
         default backend - 404
        -
        +

        diff --git a/examples/rewrite/README/index.html b/examples/rewrite/README/index.html index f8e7f0822..18cdb3dfe 100644 --- a/examples/rewrite/README/index.html +++ b/examples/rewrite/README/index.html @@ -358,6 +358,18 @@ +
      2. + + Bare-metal considerations + +
      3. + + + + + + +
      4. Role Based Access Control (RBAC) @@ -1232,7 +1244,6 @@ and that you have an ingress controller running in " | kubectl create -f - -

        Check the rewrite is working

        $ curl -v http://172.17.4.99/something -H 'Host: rewrite.bar.com'
         *   Trying 172.17.4.99...
        @@ -1275,9 +1286,8 @@ BODY:
         -no body in request-
         
        -

        App Root

        -

        Create an Ingress rule with a app-root annotation:

        +

        Create an Ingress rule with a app-root annotation:

        $ echo "
         apiVersion: extensions/v1beta1
         kind: Ingress
        @@ -1296,9 +1306,7 @@ BODY:
                   servicePort: 80
                 path: /
         " | kubectl create -f -
        -
        - - +

        Check the rewrite is working

        $ curl -I -k http://approot.bar.com/
         HTTP/1.1 302 Moved Temporarily
        diff --git a/examples/static-ip/README/index.html b/examples/static-ip/README/index.html
        index 40c742fe0..0ca658a92 100644
        --- a/examples/static-ip/README/index.html
        +++ b/examples/static-ip/README/index.html
        @@ -358,6 +358,18 @@
                   
         
         
        +  
      5. + + Bare-metal considerations + +
      6. + + + + + + +
      7. Role Based Access Control (RBAC) @@ -1171,7 +1183,6 @@ behind a Service of Type=LoadBalancer.

        nginx-ingress-lb 10.0.138.113 104.154.109.191 80:31457/TCP,443:32240/TCP 15m
      8. -

        then, update the ingress controller so it adopts the static IP of the Service by passing the --publish-service flag (the example yaml used in the next step already has it set to "nginx-ingress-lb").

        @@ -1179,7 +1190,6 @@ already has it set to "nginx-ingress-lb").

        deployment "nginx-ingress-controller" created -

        Assigning the IP to an Ingress

        From here on every Ingress created with the ingress.class annotation set to nginx will get the IP allocated in the previous step

        @@ -1201,7 +1211,6 @@ already has it set to "nginx-ingress-lb").

        ... -

        Retaining the IP

        You can test retention by deleting the Ingress

        $ kubectl delete ing nginx-ingress
        @@ -1215,7 +1224,6 @@ already has it set to "nginx-ingress-lb").

        nginx-ingress * 104.154.109.191 80, 443 13m
        -

        Note that unlike the GCE Ingress, the same loadbalancer IP is shared amongst all Ingresses, because all requests are proxied through the same set of nginx @@ -1227,10 +1235,9 @@ controllers.

        "nginx-ingress-lb" patched -

        and promote the IP to static (promotion works differently for cloudproviders, provided example is for GKE/GCE) -`

        +`
        $ gcloud compute addresses create nginx-ingress-lb --addresses 104.154.109.191 --region us-central1
         Created [https://www.googleapis.com/compute/v1/projects/kubernetesdev/regions/us-central1/addresses/nginx-ingress-lb].
         ---
        @@ -1245,9 +1252,7 @@ provided example is for GKE/GCE)
         status: IN_USE
         users:
         - us-central1/forwardingRules/a09f6913ae80e11e6a8c542010af0000
        -
        - - +

        Now even if the Service is deleted, the IP will persist, so you can recreate the Service with spec.loadBalancerIP set to 104.154.109.191.

        diff --git a/examples/tls-termination/README/index.html b/examples/tls-termination/README/index.html index 3beb0eff0..a13b31658 100644 --- a/examples/tls-termination/README/index.html +++ b/examples/tls-termination/README/index.html @@ -358,6 +358,18 @@ +
      9. + + Bare-metal considerations + +
      10. + + + + + + +
      11. Role Based Access Control (RBAC) @@ -1130,7 +1142,6 @@ TLS cert, and forward un-encrypted HTTP traffic to the test HTTP service.

        kubectl apply -f ingress.yaml
         
        -

        Validation

        You can confirm that the Ingress works.

        $ kubectl describe ing nginx-test
        diff --git a/how-it-works/index.html b/how-it-works/index.html
        index 0e5ed9062..c1ca5dad8 100644
        --- a/how-it-works/index.html
        +++ b/how-it-works/index.html
        @@ -356,6 +356,18 @@
                   
         
         
        +  
      12. + + Bare-metal considerations + +
      13. + + + + + + +
      14. Role Based Access Control (RBAC) diff --git a/images/baremetal/baremetal_overview.gliffy b/images/baremetal/baremetal_overview.gliffy new file mode 100644 index 000000000..40ccaa4c9 --- /dev/null +++ b/images/baremetal/baremetal_overview.gliffy @@ -0,0 +1 @@ +{"contentType":"application/gliffy+json","version":"1.3","stage":{"background":"#FFFFFF","width":737,"height":464,"nodeIndex":367,"autoFit":true,"exportBorder":false,"gridOn":true,"snapToGrid":false,"drawingGuidesOn":true,"pageBreaksOn":false,"printGridOn":false,"printPaper":null,"printShrinkToFit":false,"printPortrait":false,"maxWidth":5000,"maxHeight":5000,"themeData":null,"imageCache":{},"viewportType":"default","fitBB":{"min":{"x":36.86442430045474,"y":20},"max":{"x":736.8644243004547,"y":464}},"printModel":{"pageSize":"Letter","portrait":true,"fitToOnePage":false,"displayPageBreaks":false},"objects":[{"x":50.0,"y":52.0,"rotation":0.0,"id":356,"width":146.0,"height":1.0,"uid":"com.gliffy.shape.basic.basic_v1.default.line","order":64,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Line","Line":{"strokeWidth":2.0,"strokeColor":"#999999","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":0,"startArrowRotation":"auto","endArrowRotation":"auto","interpolationType":"linear","cornerRadius":null,"controlPath":[[0.0,0.0],[189.00264548413074,0.0]],"lockSegments":{},"ortho":false}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":46.86442430045474,"y":29.0,"rotation":0.0,"id":354,"width":245.0,"height":22.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":63,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":5,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

        Bare-metal environment

        ","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":326.86442430045474,"y":20.0,"rotation":0.0,"id":325,"width":120.0,"height":90.0,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":57,"lockAspectRatio":false,"lockShape":false,"children":[{"x":7.225609756097583,"y":20.0,"rotation":0.0,"id":317,"width":62.5,"height":50.0,"uid":"com.gliffy.shape.android.android_v1.icons.monitor","order":56,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.android.android_v1.icons.monitor","strokeWidth":1.0,"strokeColor":"#000000","fillColor":"#676767","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":74.72560975609758,"y":30.0,"rotation":0.0,"id":314,"width":38.048780487804876,"height":40.0,"uid":"com.gliffy.shape.android.android_v1.icons.person","order":54,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.android.android_v1.icons.person","strokeWidth":1.0,"strokeColor":"#000000","fillColor":"#676767","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":0.0,"y":0.0,"rotation":0.0,"id":315,"width":120.0,"height":90.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":3,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":2.0,"strokeColor":"#cccccc","fillColor":"#FFFFFF","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":547.0,"y":626.5,"rotation":0.0,"id":351,"width":46.0,"height":91.0,"uid":"com.gliffy.shape.basic.basic_v1.default.line","order":62,"lockAspectRatio":false,"lockShape":false,"constraints":{"constraints":[],"startConstraint":{"type":"StartPositionConstraint","StartPositionConstraint":{"nodeId":315,"py":1.0,"px":0.5}},"endConstraint":{"type":"EndPositionConstraint","EndPositionConstraint":{"nodeId":353,"py":0.0,"px":0.5}}},"graphic":{"type":"Line","Line":{"strokeWidth":2.0,"strokeColor":"#666666","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":17,"startArrowRotation":"auto","endArrowRotation":"auto","interpolationType":"linear","cornerRadius":null,"controlPath":[[-160.13557569954526,-516.5],[-160.13557569954526,-501.83321142036345],[-160.13557569954526,-487.1664228407269],[-160.13557569954526,-472.49963426109036]],"lockSegments":{},"ortho":true}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":367.04382652400767,"y":154.0,"rotation":0.0,"id":353,"width":40.0,"height":16.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":0,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#ffffff","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":314.0310909671214,"y":265.5,"rotation":0.0,"id":337,"width":40.0,"height":16.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":1,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#ff0000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":36.86442430045474,"y":204.0,"rotation":0.0,"id":221,"width":700.0,"height":260.0,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":48,"lockAspectRatio":false,"lockShape":false,"children":[{"x":10.0,"y":8.5,"rotation":0.0,"id":153,"width":42.0,"height":41.0,"uid":"com.gliffy.shape.basic.basic_v1.default.image","order":17,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Image","Image":{"url":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACoAAAApCAYAAABDV7v1AAAAAXNSR0IArs4c6QAAAAlwSFlzAAA9hAAAPYQB1ayvdAAAActpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDUuNC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIgogICAgICAgICAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyI+CiAgICAgICAgIDx4bXA6Q3JlYXRvclRvb2w+d3d3Lmlua3NjYXBlLm9yZzwveG1wOkNyZWF0b3JUb29sPgogICAgICAgICA8dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk9yaWVudGF0aW9uPgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4KGMtVWAAAD9hJREFUWAmdWAl0ltWZfr7l37JvSBIIq1AETTBhCUeBgAtKW9qisdYz6tixyAxLUceOMvYYempPrYwWgbFF0PbUnqqo48zRnsG2mlhFAiSAQDuCYRMSAglZ/iz/8n3fnee93/+ziY6de873/99y73uf+77Pu9xr4P/TlDJqVtVb9XU1LmAoEVGxpG2SZXn/ZCjzFgVlAGqz65nP7llfst+fgmPqOOYxjjH8MX/L1BT4tzRlVC1qsps2TEmmR1Utaa1UlrEUSn3bCuVleM6A/mTaGXDj3QME9bKpvLU71w7bdXbMop2Bpg1VTnqR6fdf9P/lgFKDVfddCPDqFe0z4LlLqZvbrFCu7SX7oTzHoUAtk2pWhmnbZiCTgHsc6vgVuN66XeuHf5gGVCWAf0nAX0LDXwy0Tpk1qDfr6+Zw9X6rXHpyLgxvGZ++YYXzDDfeS0hKNGwaUFbA9PslPb6GQWrAI5CAFcwRDcvHN6DMtc3rit/xewI1dcqul351Bkddul0aKAFWtTZZ55t48vK2+aZSy2GY86xgNtxElEi8BMXavAhSZgJ29fhzXZ1j6pfyxG/yR82ZwfPGbvE895nd68t+z2+6aQ2XVrmXAvwZoDV179pnNUiTVy5v+xbNuMy0gjWmFSLAPhFKDSqL/1p/IkSuvwwq/Pb2TH3/nZf6MTHii9fexu9sBKy1TA1nkTlxXol6w8AzzWtK3khT4AIM/jifT6l7gJqU1YgpejvabufAJaYdqqYiCLBX5hNTCriUgcW8QJBPnQmFLELf+mQxmQDMfrgdHXGFkrCBmMSGC1UiGualbKEEuQ064Tayen1O0ccvaUWlsLCfbmcnTIOsWt42p7ezrdkMRH5jBTOrvWRMEWRSI0qZOT1Y/hVReQRWGDTQQyZ39zroifJKKhSFDLj8xnB1/hC5l3ltAqPsaNJzYh4pUS1z9nZOaJ6yoq1Gm1/Appq+qa2lGanJqu+3jvCUetUOF1zFwY6b6E8K+eggAer+Ap3I1Bbf5BCgOFAXNXr4gIsBmn8gpnCQ990EG6SWcwKG7vsZuJRJa3C4MmQumdMO51/lut5rgkUw1da+IhQ7Z0J5UC5uskO5BU6sk0ZT4sWBOH22nU9iXkEq2pOWSRcapEnfa/WwtdPDyCwDDy0Io6jARlG+hYe+HkZZhoH3Ozy8d9JDgoaWMdJEhsgSmSe4qJjEBc4lczqxM3E7lFdAQ90kfQ/lj9HK1EM3T1qlsFleo0r/GmwKpsPeNuGOIc/e6VKozjZABerVCYDxBLf+GxHMKCeokiDycizYoma2nywp0jQ42pbEB7sH8eSf49hDml9bYKboAGyLKtxYaOBMnN7pkbAGTK7B0iRXagrFbBjTVeU18YYLYSgmLDF/S3HbNnrjFCfen8wOqMB7Jzz12r1ZxvxZ2XjutW4sf3UAVcMtNJ1myKsJ4c752RhTFhJcZ5s4krSLnAcHj8Tw/JtR/HRrAlVFJpqOufjFHRm455t5eKshioUbo5g5zEKfA8cKZEoC2dlcWDLd52qdadfeBpPKdFuGHB9Nfo8nT4TjlrglQjBOdroIh0wsu6MAoSBw36uDeOnuTNx6Yy6slPZa2xPYsW+QiQf41vU5MhL/8Yde2FTR1CsjKB4SwLhRYfxocQhXlHXj7pcHsOmuTHx3Yb7ue/w0vZBWk0XSkuJh8n5cVeep0dRmSw1mm/ah/CbhgMtZyxkrczwnLq5mDDgK02mmJVsG0XyoHSvvzMOiWwtw8zUJDBsagElKdNHN32zow6aGQTQ0Onj422EsvME3feP/JPDE5hjmTuvHousiuOnaLORm27jja3mYOz0Tw4uDWsuPv9iDX3/ioDrfxIAEP9pXeUkYVjCXgCv4piXamm2Y2aVV2lgkwFTDphkZUTTT2V/S4Iw8E5sOOhi7sgNHjsc1FwVktN/Fyl+cwV1PRhESvyTny4ZoB+UDUFbEe74TCtz+4yhWbTyDfnqfcFhAHjoWx/h/7cSvWxxcQ5BxASmRTBDAcEw7LBoWnkJ4yixk6DxuCHmVNrj0l84SIrWHTslmAJER57WMiInFC7IQYwj6FSeTVBAWT0u1kNzz9Z9Oefje14L4e/I5Qgqd38rz6ZxctMTaVEsL0KGXi9TOvXmz4eqR5YtPXsalX6FcyYx6RTJODxJt7WR4uf/GCEYNDyFJYMdPJmBxgoorMvD08kJs+GoE+NhDkPEy3YISTw572LggA6uXFaH8KxFNl+NtCSRJqzEjQrj/+gh2ciG2cE0PTSOml7CM4KuJGhtFaaBBOzmRShzmkRsSA2QyGSKBvJsxtDDPwLQrw/IaR07EMfGHHfhwV79+zsuxce8t+di6sQDXVhJwqs2qykDjswX4B37LkdzK9n5THyoe68BRypBWXR5BDkNeHxef8kv9nj8mfYVYjOEsxifISw3UNa1KKRJoele8TsMkUgH6EevgW8dYGEZeSduxP4Zom4d5/96DP25lBcXGqIsZkzMxati5UCXan1aeqb/Lz9sfMPys78UZWqfpLzH9vqw4gNsoezfnEK2mjMh/8WflSB1gmKiUL/5nT02VN2zMEQJUQmvKHEyN44fZyAibcGiyfYeTGFtmYjq1fMPjPXh1Sw+HMd+nUlbbqQTaTvsbAKZjkYnf/b4b837Sg7kFBsYOM7UMl8TMzLAwoZQcYXZiJNPhSWSlANNhGLKgpokMu2pRawbNXS4hwe/gC5ePurF7Ua5eBHO4h70nXLQc89BSbGIEAZ/qcsk5ap8zHTgcw91rurQDvnh/vo6dwsfuqIcrR5s6u4HW2JPvMgJ4mhJFjCq6+CPQixp3MMJTo0Iw2iriXg7PGqvICeI3xe/FJ6SYCAtxRE4qGIjWLh9iYs0dEUyZGMboYUEMLUolcI5rPeVg2w6iZrxu+zuHQJkPOf6+2nwsvM4hvxPY+dc4jrSzrEtZQCud08hcrq2YSg1Jp2JRzVOKHSsYbaWsCiuQFfKSfS4HmcIVqS1belKaPer55TtHZGVa+PHiQm0yPn6mTa/IwCs/dMVcmHpVhv4uMVfa0KKAvqZXZLLCOhchxBI44uFt6cQpx5BSUjI6JKHJstoIZIbc5MBk2/SMqaYVAC3vEqQVpakm0NSPXB9CKQN4yRAbV47zvVm0I7yS1seA39vv4VRnElkZJi4fGUaEPK69KVd/lx8JxAePxNE34GFooY1sen92pgmJwSn64vabc1E+LoSTHQ5OMJW+vj2OA91K5bCwpOaUadq0tDfNVoY3RfjpMRbksNDaQQ49Mi+Cuxb4ebizy0HLp3GMLA3qnH+I95v+qxcdveTpGQ9/2uvioZuDeGK57/ESAdJNwDzHvqvfjGN2uY2xTMmFTB7fW5Ct+TtIzgsdhD5XMc5Ks8wu3PXiAGrKLCXFN0t/vjUrSTBzJPctNK8ypb68jOR+f38CuVk9+Piog4074jj4iYf6x/Mwe2oWCnJZPR1zsOWQizkjqV2aat60iA5RMtG+A4NaWzKxmH1+NQP+tqSmz/N7HcwZbuJfcn1e79w3gFmPdqNwhIkHpwcxviyA+r0JlOQbxiAtK6FSYjvRjhS9fsq8Wuq6CYfFrTUqYqr/POIaz+3iJo5KmkotoNTA6w0DmF6ewZrTxhP35GLLz7pxfEDhm2MtVEzwtRHtc7FsQ7fwC2+tCjCY2ygfz0JlbB/2U/sibzXHFubbiHOyN/7MAFrMkMVN4MoGJoFYHMVMqyPCpkqw/KRxGOLDluslP+UO2HtUb30NUzKxm2SHUSy5ZnLl17BuFF+oKTTxzM4kGnb42ahiQgb+cG82Dn7oYsGUECt6X0PvNPahnrXq+7ze3e73FVBfZ5+PP3Dx1nezUTnJd7IPmvvx1PYkZlERMsc1nEPmHMG5BYNgMVhCCTYy9VFNqMplrSu4uXraSUQZHHRjP7+JQwQoSZxMBL72YAG+MtpPpw3b+3TJd/nIEE4w/9/y0070s584sk11vP5Ioa62pGg+xkr/uhnZWmgLK6fbVrOaYt88erhUTiL7XNMHEYrZ0vLi0RVN60rXaEDNa0t/7ib7XuBeRZ79gstPEZp7Sca8AgpklYcHftkNcShps6dl0dt9J9qxfxCNJzzQN/AJM+TONhfb9w7qfhIR0iCPtSbw8HNdaCZthnCXGmeGOgeSzqPnVa4VzrV4CvOCgJSXhmxBpIyqWsTNVaj1PZ4jVfOsiNMZktxlpF6rxOesANDIfU8l90pr7snRsTIdJ6U+7ex2EO3j5oeDchiGCvLsswWJBPjdfx3EP7/Qg3e5/5qZSyvRT86BPDtXwgrlBIlhW05h6UwpQwWjBqGPUnhCN3lF2yju6BrNQPgyVi8UowjtLFadGnMJfxfBynHE6Z8N4a4zoB0jJFvKS7QE00yQ1Y0sYtwPTqGbPjWLILupivMqptQkRpIHHgHXibUTWvXun5ccSWPT0butaYMnGt21PvtM6fQHP1LKvZM2l92gnGWeRSAZRwrdg8xaj04LYv7MLNTTgVb/rgcD3JXJ4UMXAbV3MvYeS2D7R4N49o0oItyBXTEmjEGWdw2HXYzMNLh9Zuw5F3NFYZzLZKbkrsj0FjavKW1Og5T1X0BhOcoRVV+95PgDdjj333znki6K21hxEn+CDmpj62NFuIzZZtYP2rGDhYreR1Nb8KtBne91bUa7TGYIkqMe0ercH3VAwksG1SncT4EVZsEOZptuPPpA87rSpy8+fzqrLfZDPVbJVOAZ5lM8DHs+EOZmxlCSGnQQlwOEPacUVs4JYwQz1f6DMexghX4Da8qaEoaXUhPVDDdyyf1svruRVdPu0ywPmQhkr/T9WWHs61QsQkQqQ7rf3EA4z5Q5BSRnM+rRoLGkvus1p+95SFbHIxR9SgcjXrzYiXc3WoFs0VFCVh6XspqOdLDVoVn78fI7jJUM1n3UsBzp0Pq68pHqR+7FJeUCT0xeYt/GPf04cIIftOkNRnSxqEqwQA44sZ5t8cIz/yhgamuJi1jkPt0uMH36ZZob5UuPjLaNYCMz1xBxLpo/EOBhxdGYZ7R3M7zQKcYQRIKWP0e3tBT/X/K97BSOsjhup7f7mUeCuvDOdx6eJZz2LGPa+c5zoZSLOHr+x0m1+4P7N09KVC5tnUcU/y1IuOOSMwZLwIYsZYjmJFh/Hsi0PAErm0QJDDFaJZ15mH/08Q3r4HlNa0vfFodu2mBIcv9Mu4Cj538VkEIDcmYLCfqA7KmkRiBc7kiUIablAdr/CVJkykKkL08jIWP5KCWHxzqYbFQPCkhx5M8DKTI+F6h83DxJB1EIwemNzwcyhwaoBEnsOtVekjcy8BJN+qb6eyJDZHnJ3k27nil9SrqnHfkSQ/WrLwSKOjmfPOdcyf72dcp1ZDcnJxLisXJ9+eaP4V7I7RZZiJWknEfOZy90nouF/i9FYjxzfww9WAAAAABJRU5ErkJggg==","urlHash":null,"fileName":null,"imageId":null,"strokeWidth":2.0,"strokeColor":"#000000","dropShadow":false,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":0.0,"y":0.0,"rotation":0.0,"id":3,"width":700.0,"height":260.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":5,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#f5f5f5","gradient":true,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":582.8644243004547,"y":273.5,"rotation":0.0,"id":229,"width":88.0,"height":100.0,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":49,"lockAspectRatio":false,"lockShape":false,"children":[{"x":61.5,"y":56.0,"rotation":0.0,"id":199,"width":3.0,"height":3.0,"uid":"com.gliffy.shape.basic.basic_v1.default.circle","order":47,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.ellipse.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#000000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":19.0,"y":52.5,"rotation":0.0,"id":200,"width":50.0,"height":10.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":45,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":61.5,"y":43.0,"rotation":0.0,"id":202,"width":3.0,"height":3.0,"uid":"com.gliffy.shape.basic.basic_v1.default.circle","order":43,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.ellipse.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#000000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":19.0,"y":39.5,"rotation":0.0,"id":203,"width":50.0,"height":10.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":41,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":-6.0,"y":6.0,"rotation":90.0,"id":204,"width":100.0,"height":88.0,"uid":"com.gliffy.shape.basic.basic_v1.default.hexagon","order":39,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.hexagon.basic_v1","strokeWidth":0.0,"strokeColor":"#000000","fillColor":"#3a5de9","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":436.197757633788,"y":273.5,"rotation":0.0,"id":231,"width":88.0,"height":100.0,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":50,"lockAspectRatio":false,"lockShape":false,"children":[{"x":61.5,"y":56.0,"rotation":0.0,"id":190,"width":3.0,"height":3.0,"uid":"com.gliffy.shape.basic.basic_v1.default.circle","order":37,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.ellipse.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#000000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":19.0,"y":52.5,"rotation":0.0,"id":191,"width":50.0,"height":10.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":35,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":61.5,"y":43.0,"rotation":0.0,"id":193,"width":3.0,"height":3.0,"uid":"com.gliffy.shape.basic.basic_v1.default.circle","order":33,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.ellipse.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#000000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":19.0,"y":39.5,"rotation":0.0,"id":194,"width":50.0,"height":10.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":31,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":-6.0,"y":6.0,"rotation":90.0,"id":195,"width":100.0,"height":88.0,"uid":"com.gliffy.shape.basic.basic_v1.default.hexagon","order":29,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.hexagon.basic_v1","strokeWidth":0.0,"strokeColor":"#000000","fillColor":"#3a5de9","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":289.5310909671214,"y":273.5,"rotation":0.0,"id":233,"width":88.0,"height":100.0,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":51,"lockAspectRatio":false,"lockShape":false,"children":[{"x":61.5,"y":56.0,"rotation":0.0,"id":161,"width":3.0,"height":3.0,"uid":"com.gliffy.shape.basic.basic_v1.default.circle","order":27,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.ellipse.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#000000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":19.0,"y":52.5,"rotation":0.0,"id":162,"width":50.0,"height":10.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":25,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":61.5,"y":43.0,"rotation":0.0,"id":164,"width":3.0,"height":3.0,"uid":"com.gliffy.shape.basic.basic_v1.default.circle","order":23,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.ellipse.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#000000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":19.0,"y":39.5,"rotation":0.0,"id":165,"width":50.0,"height":10.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":21,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":-6.0,"y":6.0,"rotation":90.0,"id":166,"width":100.0,"height":88.0,"uid":"com.gliffy.shape.basic.basic_v1.default.hexagon","order":19,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.hexagon.basic_v1","strokeWidth":0.0,"strokeColor":"#000000","fillColor":"#3a5de9","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":142.86442430045474,"y":273.5,"rotation":0.0,"id":235,"width":88.0,"height":100.0,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":52,"lockAspectRatio":false,"lockShape":false,"children":[{"x":61.5,"y":56.0,"rotation":0.0,"id":181,"width":3.0,"height":3.0,"uid":"com.gliffy.shape.basic.basic_v1.default.circle","order":15,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.ellipse.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#000000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":19.0,"y":52.5,"rotation":0.0,"id":182,"width":50.0,"height":10.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":13,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":61.5,"y":43.0,"rotation":0.0,"id":184,"width":3.0,"height":3.0,"uid":"com.gliffy.shape.basic.basic_v1.default.circle","order":11,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.ellipse.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#000000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":19.0,"y":39.5,"rotation":0.0,"id":185,"width":50.0,"height":10.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":9,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":-6.0,"y":6.0,"rotation":90.0,"id":186,"width":100.0,"height":88.0,"uid":"com.gliffy.shape.basic.basic_v1.default.hexagon","order":7,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.hexagon.basic_v1","strokeWidth":0.0,"strokeColor":"#000000","fillColor":"#3a5de9","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":144.36442430045474,"y":383.5,"rotation":0.0,"id":346,"width":85.0,"height":19.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":58,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

        master

        ","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":291.5310909671214,"y":383.5,"rotation":0.0,"id":348,"width":85.0,"height":19.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":59,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

        node

        ","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":439.197757633788,"y":383.5,"rotation":0.0,"id":349,"width":85.0,"height":19.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":60,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

        node

        ","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":584.8644243004547,"y":383.5,"rotation":0.0,"id":350,"width":85.0,"height":19.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":61,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

        node

        ","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":336.86442430045474,"y":162.0,"rotation":0.0,"id":244,"width":100.0,"height":88.0,"uid":"com.gliffy.shape.basic.basic_v1.default.hexagon","order":65,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.hexagon.basic_v1","strokeWidth":0.0,"strokeColor":"#000000","fillColor":"#ff1745","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[{"x":2.0,"y":0.0,"rotation":0.0,"id":362,"width":96.0,"height":78.0,"uid":null,"order":67,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":8,"paddingRight":8,"paddingBottom":8,"paddingLeft":8,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":5,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

        ?

        ","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"layers":[{"guid":"mcqBzoFMGdMI","order":0,"name":"Layer 0","active":true,"locked":false,"visible":true,"nodeIndex":68}],"shapeStyles":{},"lineStyles":{"global":{"stroke":"#ff1745","strokeWidth":2,"endArrow":17,"orthoMode":0}},"textStyles":{"global":{"bold":true,"face":"Bangers","size":"72px","color":"#ffffff"}}},"metadata":{"title":"untitled","revision":0,"exportBorder":false,"loadPosition":"default","autosaveDisabled":false,"lastSerialized":1536076015434,"libraries":["com.gliffy.libraries.android.android_v1.icons","com.gliffy.libraries.basic.basic_v1.default","com.gliffy.libraries.flowchart.flowchart_v1.default","com.gliffy.libraries.swimlanes.swimlanes_v1.default","com.gliffy.libraries.uml.uml_v2.class","com.gliffy.libraries.uml.uml_v2.sequence","com.gliffy.libraries.uml.uml_v2.activity","com.gliffy.libraries.erd.erd_v1.default","com.gliffy.libraries.ui.ui_v3.containers_content","com.gliffy.libraries.ui.ui_v3.forms_controls","com.gliffy.libraries.images"]},"embeddedResources":{"index":0,"resources":[]}} \ No newline at end of file diff --git a/images/baremetal/baremetal_overview.jpg b/images/baremetal/baremetal_overview.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ecf19d55125774247ed2ff59813460bfa1c91aa3 GIT binary patch literal 38234 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≤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 environment

        ","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":439.6388145443572,"y":190.0,"rotation":0.0,"id":341,"width":85.0,"height":40.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":121,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

        Cloud Load Balancer

        ","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":382.0,"y":258.0,"rotation":0.0,"id":332,"width":46.0,"height":91.0,"uid":"com.gliffy.shape.basic.basic_v1.default.line","order":118,"lockAspectRatio":false,"lockShape":false,"constraints":{"constraints":[],"startConstraint":{"type":"StartPositionConstraint","StartPositionConstraint":{"nodeId":352,"py":1.0,"px":0.5}},"endConstraint":{"type":"EndPositionConstraint","EndPositionConstraint":{"nodeId":334,"py":0.0,"px":0.5}}},"graphic":{"type":"Line","Line":{"strokeWidth":2.0,"strokeColor":"#ff9100","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":17,"startArrowRotation":"auto","endArrowRotation":"auto","interpolationType":"linear","cornerRadius":null,"controlPath":[[4.685022076901703,9.0],[4.685022076901703,49.75],[98.197757633788,49.75],[98.197757633788,90.5]],"lockSegments":{},"ortho":true}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":582.8644243004547,"y":356.5,"rotation":0.0,"id":229,"width":88.0,"height":100.0,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":54,"lockAspectRatio":false,"lockShape":false,"children":[{"x":61.5,"y":56.0,"rotation":0.0,"id":199,"width":3.0,"height":3.0,"uid":"com.gliffy.shape.basic.basic_v1.default.circle","order":52,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.ellipse.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#000000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":19.0,"y":52.5,"rotation":0.0,"id":200,"width":50.0,"height":10.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":50,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":61.5,"y":43.0,"rotation":0.0,"id":202,"width":3.0,"height":3.0,"uid":"com.gliffy.shape.basic.basic_v1.default.circle","order":48,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.ellipse.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#000000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":19.0,"y":39.5,"rotation":0.0,"id":203,"width":50.0,"height":10.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":46,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":-6.0,"y":6.0,"rotation":90.0,"id":204,"width":100.0,"height":88.0,"uid":"com.gliffy.shape.basic.basic_v1.default.hexagon","order":44,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.hexagon.basic_v1","strokeWidth":0.0,"strokeColor":"#000000","fillColor":"#3a5de9","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":436.197757633788,"y":356.5,"rotation":0.0,"id":231,"width":88.0,"height":100.0,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":55,"lockAspectRatio":false,"lockShape":false,"children":[{"x":61.5,"y":56.0,"rotation":0.0,"id":190,"width":3.0,"height":3.0,"uid":"com.gliffy.shape.basic.basic_v1.default.circle","order":42,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.ellipse.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#000000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":19.0,"y":52.5,"rotation":0.0,"id":191,"width":50.0,"height":10.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":40,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":61.5,"y":43.0,"rotation":0.0,"id":193,"width":3.0,"height":3.0,"uid":"com.gliffy.shape.basic.basic_v1.default.circle","order":38,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.ellipse.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#000000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":19.0,"y":39.5,"rotation":0.0,"id":194,"width":50.0,"height":10.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":36,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":-6.0,"y":6.0,"rotation":90.0,"id":195,"width":100.0,"height":88.0,"uid":"com.gliffy.shape.basic.basic_v1.default.hexagon","order":34,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.hexagon.basic_v1","strokeWidth":0.0,"strokeColor":"#000000","fillColor":"#3a5de9","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":36.86442430045474,"y":287.0,"rotation":0.0,"id":221,"width":700.0,"height":260.0,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":53,"lockAspectRatio":false,"lockShape":false,"children":[{"x":10.0,"y":8.5,"rotation":0.0,"id":153,"width":42.0,"height":41.0,"uid":"com.gliffy.shape.basic.basic_v1.default.image","order":22,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Image","Image":{"url":"data:image/png;base64,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","urlHash":null,"fileName":null,"imageId":null,"strokeWidth":2.0,"strokeColor":"#000000","dropShadow":false,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":0.0,"y":0.0,"rotation":0.0,"id":3,"width":700.0,"height":260.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":10,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#f5f5f5","gradient":true,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":342.86442430045474,"y":160.0,"rotation":0.0,"id":309,"width":88.0,"height":100.0,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":112,"lockAspectRatio":false,"lockShape":false,"children":[{"x":41.45900267858218,"y":42.043467278595216,"rotation":315.0,"id":303,"width":34.19748871496461,"height":34.46423803734757,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":112,"lockAspectRatio":false,"lockShape":false,"children":[{"x":-3.460796792227029,"y":-61.40762145606963,"rotation":320.0,"id":304,"width":212.0,"height":12.0,"uid":"com.gliffy.shape.basic.basic_v1.default.line","order":100,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Line","Line":{"strokeWidth":5.0,"strokeColor":"#ffffff","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":0,"startArrowRotation":"auto","endArrowRotation":"auto","interpolationType":"linear","cornerRadius":null,"controlPath":[[-0.5000000000002558,-1.7053025658242404E-13],[-11.786227735623157,13.450402450764898]],"lockSegments":{},"ortho":false}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":8.709929813125086,"y":19.35027714058682,"rotation":0.0,"id":305,"width":16.77762908871432,"height":11.763683756173897,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":111,"lockAspectRatio":false,"lockShape":false,"children":[{"x":-0.6111854556428398,"y":3.881841878086945,"rotation":50.0,"id":306,"width":12.0,"height":4.0,"uid":"com.gliffy.shape.basic.basic_v1.default.ellipse","order":108,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.ellipse.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":5.38881454435716,"y":3.881841878086945,"rotation":310.0,"id":307,"width":12.0,"height":4.0,"uid":"com.gliffy.shape.basic.basic_v1.default.ellipse","order":104,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.ellipse.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":12.343508606453213,"y":42.04346727859516,"rotation":45.0,"id":298,"width":34.19748871496461,"height":34.46423803734757,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":96,"lockAspectRatio":false,"lockShape":false,"children":[{"x":-3.460796792227029,"y":-61.40762145606963,"rotation":320.0,"id":299,"width":212.0,"height":12.0,"uid":"com.gliffy.shape.basic.basic_v1.default.line","order":84,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Line","Line":{"strokeWidth":5.0,"strokeColor":"#ffffff","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":0,"startArrowRotation":"auto","endArrowRotation":"auto","interpolationType":"linear","cornerRadius":null,"controlPath":[[-0.5000000000002558,-1.7053025658242404E-13],[-11.786227735623157,13.450402450764898]],"lockSegments":{},"ortho":false}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":8.709929813125086,"y":19.35027714058682,"rotation":0.0,"id":300,"width":16.77762908871432,"height":11.763683756173897,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":95,"lockAspectRatio":false,"lockShape":false,"children":[{"x":-0.6111854556428398,"y":3.881841878086945,"rotation":50.0,"id":301,"width":12.0,"height":4.0,"uid":"com.gliffy.shape.basic.basic_v1.default.ellipse","order":92,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.ellipse.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":5.38881454435716,"y":3.881841878086945,"rotation":310.0,"id":302,"width":12.0,"height":4.0,"uid":"com.gliffy.shape.basic.basic_v1.default.ellipse","order":88,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.ellipse.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":26.901255642517697,"y":48.0000000000001,"rotation":0.0,"id":297,"width":34.19748871496461,"height":34.46423803734757,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":79,"lockAspectRatio":false,"lockShape":false,"children":[{"x":-3.460796792227029,"y":-61.40762145606963,"rotation":320.0,"id":286,"width":212.0,"height":12.0,"uid":"com.gliffy.shape.basic.basic_v1.default.line","order":64,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Line","Line":{"strokeWidth":5.0,"strokeColor":"#ffffff","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":0,"startArrowRotation":"auto","endArrowRotation":"auto","interpolationType":"linear","cornerRadius":null,"controlPath":[[-0.5000000000002558,-1.7053025658242404E-13],[-11.786227735623157,13.450402450764898]],"lockSegments":{},"ortho":false}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":8.709929813125086,"y":19.35027714058682,"rotation":0.0,"id":296,"width":16.77762908871432,"height":11.763683756173897,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":77,"lockAspectRatio":false,"lockShape":false,"children":[{"x":-0.6111854556428398,"y":3.881841878086945,"rotation":50.0,"id":284,"width":12.0,"height":4.0,"uid":"com.gliffy.shape.basic.basic_v1.default.ellipse","order":72,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.ellipse.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":5.38881454435716,"y":3.881841878086945,"rotation":310.0,"id":285,"width":12.0,"height":4.0,"uid":"com.gliffy.shape.basic.basic_v1.default.ellipse","order":68,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.ellipse.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":36.0,"y":42.0,"rotation":0.0,"id":250,"width":16.0,"height":16.0,"uid":"com.gliffy.shape.basic.basic_v1.default.circle","order":74,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.ellipse.basic_v1","strokeWidth":5.0,"strokeColor":"#ffffff","fillColor":"#ff9100","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":45.5,"y":20.000000000000004,"rotation":0.0,"id":256,"width":1.0,"height":34.0,"uid":"com.gliffy.shape.basic.basic_v1.default.line","order":61,"lockAspectRatio":false,"lockShape":false,"constraints":{"constraints":[],"startConstraint":{"type":"StartPositionConstraint","StartPositionConstraint":{"nodeId":253,"py":0.5,"px":0.5}},"endConstraint":{"type":"EndPositionConstraint","EndPositionConstraint":{"nodeId":250,"py":0.5,"px":0.5}}},"graphic":{"type":"Line","Line":{"strokeWidth":5.0,"strokeColor":"#ffffff","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":0,"startArrowRotation":"auto","endArrowRotation":"auto","interpolationType":"linear","cornerRadius":null,"controlPath":[[-1.5,7.0],[-1.5,18.5],[-1.5,18.5],[-1.5,30.0]],"lockSegments":{},"ortho":true}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":36.0,"y":19.000000000000004,"rotation":0.0,"id":253,"width":16.0,"height":16.0,"uid":"com.gliffy.shape.basic.basic_v1.default.circle","order":59,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.ellipse.basic_v1","strokeWidth":0.0,"strokeColor":"#ffffff","fillColor":"#ffffff","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":-6.0,"y":6.0000000000000036,"rotation":90.0,"id":244,"width":100.0,"height":88.0,"uid":"com.gliffy.shape.basic.basic_v1.default.hexagon","order":8,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.hexagon.basic_v1","strokeWidth":0.0,"strokeColor":"#000000","fillColor":"#ff9100","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":326.86442430045474,"y":20.0,"rotation":0.0,"id":325,"width":120.0,"height":90.0,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":117,"lockAspectRatio":false,"lockShape":false,"children":[{"x":7.225609756097583,"y":20.0,"rotation":0.0,"id":317,"width":62.5,"height":50.0,"uid":"com.gliffy.shape.android.android_v1.icons.monitor","order":116,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.android.android_v1.icons.monitor","strokeWidth":1.0,"strokeColor":"#000000","fillColor":"#676767","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":74.72560975609758,"y":30.0,"rotation":0.0,"id":314,"width":38.048780487804876,"height":40.0,"uid":"com.gliffy.shape.android.android_v1.icons.person","order":114,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.android.android_v1.icons.person","strokeWidth":1.0,"strokeColor":"#000000","fillColor":"#676767","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":0.0,"y":0.0,"rotation":0.0,"id":315,"width":120.0,"height":90.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":6,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":2.0,"strokeColor":"#cccccc","fillColor":"#FFFFFF","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":289.5310909671214,"y":356.5,"rotation":0.0,"id":233,"width":88.0,"height":100.0,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":56,"lockAspectRatio":false,"lockShape":false,"children":[{"x":61.5,"y":56.0,"rotation":0.0,"id":161,"width":3.0,"height":3.0,"uid":"com.gliffy.shape.basic.basic_v1.default.circle","order":32,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.ellipse.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#000000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":19.0,"y":52.5,"rotation":0.0,"id":162,"width":50.0,"height":10.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":30,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":61.5,"y":43.0,"rotation":0.0,"id":164,"width":3.0,"height":3.0,"uid":"com.gliffy.shape.basic.basic_v1.default.circle","order":28,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.ellipse.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#000000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":19.0,"y":39.5,"rotation":0.0,"id":165,"width":50.0,"height":10.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":26,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":-6.0,"y":6.0,"rotation":90.0,"id":166,"width":100.0,"height":88.0,"uid":"com.gliffy.shape.basic.basic_v1.default.hexagon","order":24,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.hexagon.basic_v1","strokeWidth":0.0,"strokeColor":"#000000","fillColor":"#3a5de9","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":314.0310909671214,"y":348.5,"rotation":0.0,"id":337,"width":40.0,"height":16.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":2,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#ff0000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":607.3644243004547,"y":348.5,"rotation":0.0,"id":338,"width":40.0,"height":16.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":3,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#ff0000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":460.197757633788,"y":348.5,"rotation":0.0,"id":334,"width":40.0,"height":16.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":4,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#ff0000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":392.0,"y":268.0,"rotation":0.0,"id":339,"width":46.0,"height":91.0,"uid":"com.gliffy.shape.basic.basic_v1.default.line","order":119,"lockAspectRatio":false,"lockShape":false,"constraints":{"constraints":[],"startConstraint":{"type":"StartPositionConstraint","StartPositionConstraint":{"nodeId":352,"py":1.0,"px":0.5}},"endConstraint":{"type":"EndPositionConstraint","EndPositionConstraint":{"nodeId":338,"py":0.0,"px":0.5}}},"graphic":{"type":"Line","Line":{"strokeWidth":2.0,"strokeColor":"#ff9100","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":17,"startArrowRotation":"auto","endArrowRotation":"auto","interpolationType":"linear","cornerRadius":null,"controlPath":[[-5.314977923098297,-1.0],[-5.314977923098297,39.75],[235.36442430045474,39.75],[235.36442430045474,80.5]],"lockSegments":{},"ortho":true}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":537.0,"y":616.5,"rotation":0.0,"id":340,"width":46.0,"height":91.0,"uid":"com.gliffy.shape.basic.basic_v1.default.line","order":120,"lockAspectRatio":false,"lockShape":false,"constraints":{"constraints":[],"startConstraint":{"type":"StartPositionConstraint","StartPositionConstraint":{"nodeId":352,"py":1.0,"px":0.5}},"endConstraint":{"type":"EndPositionConstraint","EndPositionConstraint":{"nodeId":337,"py":0.0,"px":0.5}}},"graphic":{"type":"Line","Line":{"strokeWidth":2.0,"strokeColor":"#ff9100","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":17,"startArrowRotation":"auto","endArrowRotation":"auto","interpolationType":"linear","cornerRadius":null,"controlPath":[[-150.3149779230983,-349.5],[-150.3149779230983,-308.75],[-202.96890903287863,-308.75],[-202.96890903287863,-268.0]],"lockSegments":{},"ortho":true}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":142.86442430045474,"y":356.5,"rotation":0.0,"id":235,"width":88.0,"height":100.0,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":57,"lockAspectRatio":false,"lockShape":false,"children":[{"x":61.5,"y":56.0,"rotation":0.0,"id":181,"width":3.0,"height":3.0,"uid":"com.gliffy.shape.basic.basic_v1.default.circle","order":20,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.ellipse.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#000000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":19.0,"y":52.5,"rotation":0.0,"id":182,"width":50.0,"height":10.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":18,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":61.5,"y":43.0,"rotation":0.0,"id":184,"width":3.0,"height":3.0,"uid":"com.gliffy.shape.basic.basic_v1.default.circle","order":16,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.ellipse.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#000000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":19.0,"y":39.5,"rotation":0.0,"id":185,"width":50.0,"height":10.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":14,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":-6.0,"y":6.0,"rotation":90.0,"id":186,"width":100.0,"height":88.0,"uid":"com.gliffy.shape.basic.basic_v1.default.hexagon","order":12,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.hexagon.basic_v1","strokeWidth":0.0,"strokeColor":"#000000","fillColor":"#3a5de9","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":144.36442430045474,"y":466.5,"rotation":0.0,"id":346,"width":85.0,"height":19.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":122,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

        master

        ","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":291.5310909671214,"y":466.5,"rotation":0.0,"id":348,"width":85.0,"height":19.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":123,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

        node

        ","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":439.197757633788,"y":466.5,"rotation":0.0,"id":349,"width":85.0,"height":19.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":124,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

        node

        ","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":584.8644243004547,"y":466.5,"rotation":0.0,"id":350,"width":85.0,"height":19.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":125,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

        node

        ","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":547.0,"y":626.5,"rotation":0.0,"id":351,"width":46.0,"height":91.0,"uid":"com.gliffy.shape.basic.basic_v1.default.line","order":126,"lockAspectRatio":false,"lockShape":false,"constraints":{"constraints":[],"startConstraint":{"type":"StartPositionConstraint","StartPositionConstraint":{"nodeId":315,"py":1.0,"px":0.5}},"endConstraint":{"type":"EndPositionConstraint","EndPositionConstraint":{"nodeId":353,"py":0.0,"px":0.5}}},"graphic":{"type":"Line","Line":{"strokeWidth":2.0,"strokeColor":"#666666","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":17,"startArrowRotation":"auto","endArrowRotation":"auto","interpolationType":"linear","cornerRadius":null,"controlPath":[[-160.13557569954526,-516.5],[-160.13557569954526,-501.83321142036345],[-160.13557569954526,-487.1664228407269],[-160.13557569954526,-472.49963426109036]],"lockSegments":{},"ortho":true}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":366.6850220769017,"y":251.0,"rotation":0.0,"id":352,"width":40.0,"height":16.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":1,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#ffffff","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":367.04382652400767,"y":154.0,"rotation":0.0,"id":353,"width":40.0,"height":16.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":0,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#ffffff","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"layers":[{"guid":"mcqBzoFMGdMI","order":0,"name":"Layer 0","active":true,"locked":false,"visible":true,"nodeIndex":131}],"shapeStyles":{},"lineStyles":{"global":{"stroke":"#999999","strokeWidth":2,"endArrow":0,"orthoMode":0}},"textStyles":{"global":{"bold":true,"face":"Roboto Slab","size":"16px","color":"#999999"}}},"metadata":{"title":"untitled","revision":0,"exportBorder":false,"loadPosition":"default","autosaveDisabled":false,"lastSerialized":1536074379631,"libraries":["com.gliffy.libraries.android.android_v1.icons","com.gliffy.libraries.basic.basic_v1.default","com.gliffy.libraries.flowchart.flowchart_v1.default","com.gliffy.libraries.swimlanes.swimlanes_v1.default","com.gliffy.libraries.uml.uml_v2.class","com.gliffy.libraries.uml.uml_v2.sequence","com.gliffy.libraries.uml.uml_v2.activity","com.gliffy.libraries.erd.erd_v1.default","com.gliffy.libraries.ui.ui_v3.containers_content","com.gliffy.libraries.ui.ui_v3.forms_controls","com.gliffy.libraries.images"]},"embeddedResources":{"index":0,"resources":[]}} \ No newline at end of file diff --git a/images/baremetal/cloud_overview.jpg b/images/baremetal/cloud_overview.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ec8830e883cc2e13c7b24b798bc135693305c5fa GIT binary patch literal 48236 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 I_FK>Y0ha_p;Q#;t literal 0 HcmV?d00001 diff --git a/images/baremetal/hostnetwork.gliffy b/images/baremetal/hostnetwork.gliffy new file mode 100644 index 000000000..952ea7816 --- /dev/null +++ b/images/baremetal/hostnetwork.gliffy @@ -0,0 +1 @@ +{"contentType":"application/gliffy+json","version":"1.3","stage":{"background":"#FFFFFF","width":737,"height":442,"nodeIndex":465,"autoFit":true,"exportBorder":false,"gridOn":true,"snapToGrid":false,"drawingGuidesOn":true,"pageBreaksOn":false,"printGridOn":false,"printPaper":null,"printShrinkToFit":false,"printPortrait":false,"maxWidth":5000,"maxHeight":5000,"themeData":null,"imageCache":{},"viewportType":"default","fitBB":{"min":{"x":36.86442430045474,"y":20},"max":{"x":736.8644243004547,"y":442}},"printModel":{"pageSize":"Letter","portrait":true,"fitToOnePage":false,"displayPageBreaks":false},"objects":[{"x":438.6388145443572,"y":293.0,"rotation":90.0,"id":388,"width":40.0,"height":16.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":4,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#ff0000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":356.5310909671214,"y":293.0,"rotation":90.0,"id":389,"width":40.0,"height":16.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":5,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#ff0000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":36.86442430045474,"y":182.0,"rotation":0.0,"id":221,"width":700.0,"height":260.0,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":44,"lockAspectRatio":false,"lockShape":false,"children":[{"x":10.0,"y":8.5,"rotation":0.0,"id":153,"width":42.0,"height":41.0,"uid":"com.gliffy.shape.basic.basic_v1.default.image","order":13,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Image","Image":{"url":"data:image/png;base64,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","urlHash":null,"fileName":null,"imageId":null,"strokeWidth":2.0,"strokeColor":"#000000","dropShadow":false,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":0.0,"y":0.0,"rotation":0.0,"id":3,"width":700.0,"height":260.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":9,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#f5f5f5","gradient":true,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":582.8644243004547,"y":251.5,"rotation":0.0,"id":229,"width":88.0,"height":100.0,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":47,"lockAspectRatio":false,"lockShape":false,"children":[{"x":61.5,"y":56.0,"rotation":0.0,"id":199,"width":3.0,"height":3.0,"uid":"com.gliffy.shape.basic.basic_v1.default.circle","order":55,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.ellipse.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#000000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":19.0,"y":52.5,"rotation":0.0,"id":200,"width":50.0,"height":10.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":53,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":61.5,"y":43.0,"rotation":0.0,"id":202,"width":3.0,"height":3.0,"uid":"com.gliffy.shape.basic.basic_v1.default.circle","order":49,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.ellipse.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#000000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":19.0,"y":39.5,"rotation":0.0,"id":203,"width":50.0,"height":10.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":46,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":-6.0,"y":6.0,"rotation":90.0,"id":204,"width":100.0,"height":88.0,"uid":"com.gliffy.shape.basic.basic_v1.default.hexagon","order":43,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.hexagon.basic_v1","strokeWidth":0.0,"strokeColor":"#000000","fillColor":"#3a5de9","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":436.197757633788,"y":251.5,"rotation":0.0,"id":231,"width":88.0,"height":100.0,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":50,"lockAspectRatio":false,"lockShape":false,"children":[{"x":61.5,"y":56.0,"rotation":0.0,"id":190,"width":3.0,"height":3.0,"uid":"com.gliffy.shape.basic.basic_v1.default.circle","order":41,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.ellipse.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#000000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":19.0,"y":52.5,"rotation":0.0,"id":191,"width":50.0,"height":10.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":39,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":61.5,"y":43.0,"rotation":0.0,"id":193,"width":3.0,"height":3.0,"uid":"com.gliffy.shape.basic.basic_v1.default.circle","order":37,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.ellipse.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#000000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":19.0,"y":39.5,"rotation":0.0,"id":194,"width":50.0,"height":10.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":35,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":-6.0,"y":6.0,"rotation":90.0,"id":195,"width":100.0,"height":88.0,"uid":"com.gliffy.shape.basic.basic_v1.default.hexagon","order":31,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.hexagon.basic_v1","strokeWidth":0.0,"strokeColor":"#000000","fillColor":"#3a5de9","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":289.5310909671214,"y":251.5,"rotation":0.0,"id":233,"width":88.0,"height":100.0,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":51,"lockAspectRatio":false,"lockShape":false,"children":[{"x":61.5,"y":56.0,"rotation":0.0,"id":161,"width":3.0,"height":3.0,"uid":"com.gliffy.shape.basic.basic_v1.default.circle","order":29,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.ellipse.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#000000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":19.0,"y":52.5,"rotation":0.0,"id":162,"width":50.0,"height":10.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":25,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":61.5,"y":43.0,"rotation":0.0,"id":164,"width":3.0,"height":3.0,"uid":"com.gliffy.shape.basic.basic_v1.default.circle","order":23,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.ellipse.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#000000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":19.0,"y":39.5,"rotation":0.0,"id":165,"width":50.0,"height":10.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":19,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":-6.0,"y":6.0,"rotation":90.0,"id":166,"width":100.0,"height":88.0,"uid":"com.gliffy.shape.basic.basic_v1.default.hexagon","order":17,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.hexagon.basic_v1","strokeWidth":0.0,"strokeColor":"#000000","fillColor":"#3a5de9","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":537.0,"y":616.5,"rotation":0.0,"id":340,"width":46.0,"height":91.0,"uid":"com.gliffy.shape.basic.basic_v1.default.line","order":57,"lockAspectRatio":false,"lockShape":false,"constraints":{"constraints":[],"startConstraint":{"type":"StartPositionConstraint","StartPositionConstraint":{"nodeId":315,"py":1.0,"px":0.5}},"endConstraint":{"type":"EndPositionConstraint","EndPositionConstraint":{"nodeId":334,"py":0.0,"px":0.5}}},"graphic":{"type":"Line","Line":{"strokeWidth":2.0,"strokeColor":"#00bfa6","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":17,"startArrowRotation":"auto","endArrowRotation":"auto","interpolationType":"linear","cornerRadius":null,"controlPath":[[-150.13557569954526,-506.5],[-150.13557569954526,-459.25],[-56.802242366212,-459.25],[-56.802242366212,-382.0]],"lockSegments":{"1":true},"ortho":true}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":144.36442430045474,"y":361.5,"rotation":0.0,"id":346,"width":85.0,"height":19.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":58,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

        master

        ","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":291.5310909671214,"y":361.5,"rotation":0.0,"id":348,"width":85.0,"height":19.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":59,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

        node

        ","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":439.197757633788,"y":361.5,"rotation":0.0,"id":349,"width":85.0,"height":19.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":62,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

        node

        ","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":584.8644243004547,"y":361.5,"rotation":0.0,"id":350,"width":85.0,"height":19.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":63,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

        node

        ","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":46.86442430045474,"y":29.0,"rotation":0.0,"id":354,"width":245.0,"height":22.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":66,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

        Via the host network

        ","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":50.0,"y":52.0,"rotation":0.0,"id":356,"width":146.0,"height":1.0,"uid":"com.gliffy.shape.basic.basic_v1.default.line","order":67,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Line","Line":{"strokeWidth":2.0,"strokeColor":"#999999","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":0,"startArrowRotation":"auto","endArrowRotation":"auto","interpolationType":"linear","cornerRadius":null,"controlPath":[[0.0,0.0],[158.00316452527144,0.0]],"lockSegments":{},"ortho":false}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":142.86442430045474,"y":251.5,"rotation":0.0,"id":235,"width":88.0,"height":100.0,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":68,"lockAspectRatio":false,"lockShape":false,"children":[{"x":-6.0,"y":6.0,"rotation":90.0,"id":186,"width":100.0,"height":88.0,"uid":"com.gliffy.shape.basic.basic_v1.default.hexagon","order":11,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.hexagon.basic_v1","strokeWidth":0.0,"strokeColor":"#000000","fillColor":"#3a5de9","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":19.0,"y":39.5,"rotation":0.0,"id":185,"width":50.0,"height":10.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":15,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":61.5,"y":43.0,"rotation":0.0,"id":184,"width":3.0,"height":3.0,"uid":"com.gliffy.shape.basic.basic_v1.default.circle","order":21,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.ellipse.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#000000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":19.0,"y":52.5,"rotation":0.0,"id":182,"width":50.0,"height":10.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":27,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":61.5,"y":56.0,"rotation":0.0,"id":181,"width":3.0,"height":3.0,"uid":"com.gliffy.shape.basic.basic_v1.default.circle","order":33,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.ellipse.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#000000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":452.197757633788,"y":271.0,"rotation":0.0,"id":383,"width":53.00000000000006,"height":60.0,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":69,"lockAspectRatio":false,"lockShape":false,"children":[{"x":0.0,"y":5.5,"rotation":0.0,"id":380,"width":53.0,"height":49.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":76,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

        N

        ","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":-3.599999999999966,"y":3.6000000000000227,"rotation":90.0,"id":377,"width":60.0,"height":52.8,"uid":"com.gliffy.shape.basic.basic_v1.default.hexagon","order":74,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.hexagon.basic_v1","strokeWidth":0.0,"strokeColor":"#000000","fillColor":"#00963a","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":326.86442430045474,"y":20.0,"rotation":0.0,"id":325,"width":120.0,"height":90.0,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":56,"lockAspectRatio":false,"lockShape":false,"children":[{"x":7.225609756097583,"y":20.0,"rotation":0.0,"id":317,"width":62.5,"height":50.0,"uid":"com.gliffy.shape.android.android_v1.icons.monitor","order":65,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.android.android_v1.icons.monitor","strokeWidth":1.0,"strokeColor":"#000000","fillColor":"#676767","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":74.72560975609758,"y":30.0,"rotation":0.0,"id":314,"width":38.048780487804876,"height":40.0,"uid":"com.gliffy.shape.android.android_v1.icons.person","order":61,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.android.android_v1.icons.person","strokeWidth":1.0,"strokeColor":"#000000","fillColor":"#676767","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":0.0,"y":0.0,"rotation":0.0,"id":315,"width":120.0,"height":90.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":7,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":2.0,"strokeColor":"#cccccc","fillColor":"#FFFFFF","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":160.36442430045471,"y":271.5,"rotation":0.0,"id":434,"width":53.00000000000006,"height":60.0,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":72,"lockAspectRatio":false,"lockShape":false,"children":[{"x":0.0,"y":5.5,"rotation":0.0,"id":435,"width":53.0,"height":49.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":82,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

        N

        ","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":-3.599999999999966,"y":3.6000000000000227,"rotation":90.0,"id":436,"width":60.0,"height":52.8,"uid":"com.gliffy.shape.basic.basic_v1.default.hexagon","order":79,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.hexagon.basic_v1","strokeWidth":0.0,"strokeColor":"#000000","fillColor":"#00963a","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":307.0310909671214,"y":274.0,"rotation":0.0,"id":437,"width":53.00000000000006,"height":60.0,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":77,"lockAspectRatio":false,"lockShape":false,"children":[{"x":0.0,"y":5.5,"rotation":0.0,"id":438,"width":53.0,"height":49.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":86,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

        N

        ","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":-3.599999999999966,"y":3.6000000000000227,"rotation":90.0,"id":439,"width":60.0,"height":52.8,"uid":"com.gliffy.shape.basic.basic_v1.default.hexagon","order":84,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.hexagon.basic_v1","strokeWidth":0.0,"strokeColor":"#000000","fillColor":"#00963a","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":600.8644243004546,"y":271.5,"rotation":0.0,"id":440,"width":53.00000000000006,"height":60.0,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":80,"lockAspectRatio":false,"lockShape":false,"children":[{"x":0.0,"y":5.5,"rotation":0.0,"id":441,"width":53.0,"height":49.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":90,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

        N

        ","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":-3.599999999999966,"y":3.6000000000000227,"rotation":90.0,"id":442,"width":60.0,"height":52.8,"uid":"com.gliffy.shape.basic.basic_v1.default.hexagon","order":88,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.hexagon.basic_v1","strokeWidth":0.0,"strokeColor":"#000000","fillColor":"#00963a","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":607.3644243004547,"y":234.5,"rotation":0.0,"id":338,"width":40.0,"height":16.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":3,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#ff0000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":613.728060664091,"y":217.04551732809568,"rotation":0.0,"id":454,"width":84.49629087449557,"height":52.954482671904316,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":93,"lockAspectRatio":false,"lockShape":false,"children":[{"x":0.0,"y":21.954482671904316,"rotation":0.0,"id":448,"width":27.272727272727273,"height":15.0,"uid":"com.gliffy.shape.android.android_v1.icons.expand","order":92,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.android.android_v1.icons.expand","strokeWidth":1.0,"strokeColor":"#000000","fillColor":"#676767","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":11.636363636363626,"y":16.977241335952158,"rotation":29.999999999999996,"id":390,"width":73.0,"height":19.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":71,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

        80/tcp

        ","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":460.197757633788,"y":234.5,"rotation":0.0,"id":334,"width":40.0,"height":16.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":0,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#ff0000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":314.0310909671214,"y":234.5,"rotation":0.0,"id":337,"width":40.0,"height":16.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":1,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#ff0000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":169.36442430045474,"y":234.5,"rotation":0.0,"id":365,"width":40.0,"height":16.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":2,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#ff0000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":466.6388145443572,"y":218.54551732809568,"rotation":0.0,"id":456,"width":84.49629087449557,"height":52.954482671904316,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":94,"lockAspectRatio":false,"lockShape":false,"children":[{"x":0.0,"y":21.954482671904316,"rotation":0.0,"id":457,"width":27.272727272727273,"height":15.0,"uid":"com.gliffy.shape.android.android_v1.icons.expand","order":98,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.android.android_v1.icons.expand","strokeWidth":1.0,"strokeColor":"#000000","fillColor":"#676767","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":11.636363636363626,"y":16.977241335952158,"rotation":29.999999999999996,"id":458,"width":73.0,"height":19.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":96,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

        80/tcp

        ","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":320.7829455298736,"y":217.04551732809568,"rotation":0.0,"id":459,"width":84.49629087449557,"height":52.954482671904316,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":99,"lockAspectRatio":false,"lockShape":false,"children":[{"x":0.0,"y":21.954482671904316,"rotation":0.0,"id":460,"width":27.272727272727273,"height":15.0,"uid":"com.gliffy.shape.android.android_v1.icons.expand","order":103,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.android.android_v1.icons.expand","strokeWidth":1.0,"strokeColor":"#000000","fillColor":"#676767","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":11.636363636363626,"y":16.977241335952158,"rotation":29.999999999999996,"id":461,"width":73.0,"height":19.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":101,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

        80/tcp

        ","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":173.11627886320696,"y":217.04551732809568,"rotation":0.0,"id":462,"width":84.49629087449557,"height":52.954482671904316,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":104,"lockAspectRatio":false,"lockShape":false,"children":[{"x":0.0,"y":21.954482671904316,"rotation":0.0,"id":463,"width":27.272727272727273,"height":15.0,"uid":"com.gliffy.shape.android.android_v1.icons.expand","order":108,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.android.android_v1.icons.expand","strokeWidth":1.0,"strokeColor":"#000000","fillColor":"#676767","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":11.636363636363626,"y":16.977241335952158,"rotation":29.999999999999996,"id":464,"width":73.0,"height":19.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":106,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

        80/tcp

        ","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"layers":[{"guid":"mcqBzoFMGdMI","order":0,"name":"Layer 0","active":true,"locked":false,"visible":true,"nodeIndex":109}],"shapeStyles":{},"lineStyles":{"global":{"stroke":"#00bfa6","strokeWidth":3,"endArrow":1,"orthoMode":0}},"textStyles":{"global":{"face":"Roboto Slab","size":"36px","color":"#676767"}}},"metadata":{"title":"untitled","revision":0,"exportBorder":false,"loadPosition":"default","autosaveDisabled":false,"lastSerialized":1536084812394,"libraries":["com.gliffy.libraries.android.android_v1.icons","com.gliffy.libraries.basic.basic_v1.default","com.gliffy.libraries.flowchart.flowchart_v1.default","com.gliffy.libraries.swimlanes.swimlanes_v1.default","com.gliffy.libraries.uml.uml_v2.class","com.gliffy.libraries.uml.uml_v2.sequence","com.gliffy.libraries.uml.uml_v2.activity","com.gliffy.libraries.erd.erd_v1.default","com.gliffy.libraries.ui.ui_v3.containers_content","com.gliffy.libraries.ui.ui_v3.forms_controls","com.gliffy.libraries.images"]},"embeddedResources":{"index":0,"resources":[]}} \ No newline at end of file diff --git a/images/baremetal/hostnetwork.jpg b/images/baremetal/hostnetwork.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f86dc4a6214a596ced591be9d8b1ab2b2925f5ba GIT binary patch literal 41504 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 Y3BkWE(0@ZL`!|N8|9793?qKBq0Y^DPhyVZp literal 0 HcmV?d00001 diff --git a/images/baremetal/nodeport.gliffy b/images/baremetal/nodeport.gliffy new file mode 100644 index 000000000..6823d8856 --- /dev/null +++ b/images/baremetal/nodeport.gliffy @@ -0,0 +1 @@ +{"contentType":"application/gliffy+json","version":"1.3","stage":{"background":"#FFFFFF","width":737,"height":442,"nodeIndex":434,"autoFit":true,"exportBorder":false,"gridOn":true,"snapToGrid":false,"drawingGuidesOn":true,"pageBreaksOn":false,"printGridOn":false,"printPaper":null,"printShrinkToFit":false,"printPortrait":false,"maxWidth":5000,"maxHeight":5000,"themeData":null,"imageCache":{},"viewportType":"default","fitBB":{"min":{"x":36.86442430045474,"y":20},"max":{"x":736.8644243004547,"y":442}},"printModel":{"pageSize":"Letter","portrait":true,"fitToOnePage":false,"displayPageBreaks":false},"objects":[{"x":438.6388145443572,"y":293.0,"rotation":90.0,"id":388,"width":40.0,"height":16.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":0,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#ff0000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":356.5310909671214,"y":293.0,"rotation":90.0,"id":389,"width":40.0,"height":16.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":1,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#ff0000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":169.36442430045474,"y":211.5,"rotation":0.0,"id":365,"width":40.0,"height":16.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":2,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#ff0000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":314.0310909671214,"y":204.5,"rotation":0.0,"id":337,"width":40.0,"height":16.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":3,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#ff0000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":607.3644243004547,"y":211.5,"rotation":0.0,"id":338,"width":40.0,"height":16.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":4,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#ff0000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":460.197757633788,"y":211.5,"rotation":0.0,"id":334,"width":40.0,"height":16.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":5,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#ff0000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":36.86442430045474,"y":182.0,"rotation":0.0,"id":221,"width":700.0,"height":260.0,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":52,"lockAspectRatio":false,"lockShape":false,"children":[{"x":10.0,"y":8.5,"rotation":0.0,"id":153,"width":42.0,"height":41.0,"uid":"com.gliffy.shape.basic.basic_v1.default.image","order":13,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Image","Image":{"url":"data:image/png;base64,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","urlHash":null,"fileName":null,"imageId":null,"strokeWidth":2.0,"strokeColor":"#000000","dropShadow":false,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":0.0,"y":0.0,"rotation":0.0,"id":3,"width":700.0,"height":260.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":9,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#f5f5f5","gradient":true,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":582.8644243004547,"y":251.5,"rotation":0.0,"id":229,"width":88.0,"height":100.0,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":53,"lockAspectRatio":false,"lockShape":false,"children":[{"x":61.5,"y":56.0,"rotation":0.0,"id":199,"width":3.0,"height":3.0,"uid":"com.gliffy.shape.basic.basic_v1.default.circle","order":51,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.ellipse.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#000000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":19.0,"y":52.5,"rotation":0.0,"id":200,"width":50.0,"height":10.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":49,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":61.5,"y":43.0,"rotation":0.0,"id":202,"width":3.0,"height":3.0,"uid":"com.gliffy.shape.basic.basic_v1.default.circle","order":47,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.ellipse.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#000000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":19.0,"y":39.5,"rotation":0.0,"id":203,"width":50.0,"height":10.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":45,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":-6.0,"y":6.0,"rotation":90.0,"id":204,"width":100.0,"height":88.0,"uid":"com.gliffy.shape.basic.basic_v1.default.hexagon","order":43,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.hexagon.basic_v1","strokeWidth":0.0,"strokeColor":"#000000","fillColor":"#3a5de9","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":436.197757633788,"y":251.5,"rotation":0.0,"id":231,"width":88.0,"height":100.0,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":54,"lockAspectRatio":false,"lockShape":false,"children":[{"x":61.5,"y":56.0,"rotation":0.0,"id":190,"width":3.0,"height":3.0,"uid":"com.gliffy.shape.basic.basic_v1.default.circle","order":41,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.ellipse.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#000000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":19.0,"y":52.5,"rotation":0.0,"id":191,"width":50.0,"height":10.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":39,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":61.5,"y":43.0,"rotation":0.0,"id":193,"width":3.0,"height":3.0,"uid":"com.gliffy.shape.basic.basic_v1.default.circle","order":37,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.ellipse.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#000000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":19.0,"y":39.5,"rotation":0.0,"id":194,"width":50.0,"height":10.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":35,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":-6.0,"y":6.0,"rotation":90.0,"id":195,"width":100.0,"height":88.0,"uid":"com.gliffy.shape.basic.basic_v1.default.hexagon","order":31,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.hexagon.basic_v1","strokeWidth":0.0,"strokeColor":"#000000","fillColor":"#3a5de9","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":289.5310909671214,"y":251.5,"rotation":0.0,"id":233,"width":88.0,"height":100.0,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":55,"lockAspectRatio":false,"lockShape":false,"children":[{"x":61.5,"y":56.0,"rotation":0.0,"id":161,"width":3.0,"height":3.0,"uid":"com.gliffy.shape.basic.basic_v1.default.circle","order":29,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.ellipse.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#000000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":19.0,"y":52.5,"rotation":0.0,"id":162,"width":50.0,"height":10.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":25,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":61.5,"y":43.0,"rotation":0.0,"id":164,"width":3.0,"height":3.0,"uid":"com.gliffy.shape.basic.basic_v1.default.circle","order":23,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.ellipse.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#000000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":19.0,"y":39.5,"rotation":0.0,"id":165,"width":50.0,"height":10.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":19,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":-6.0,"y":6.0,"rotation":90.0,"id":166,"width":100.0,"height":88.0,"uid":"com.gliffy.shape.basic.basic_v1.default.hexagon","order":17,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.hexagon.basic_v1","strokeWidth":0.0,"strokeColor":"#000000","fillColor":"#3a5de9","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":537.0,"y":616.5,"rotation":0.0,"id":340,"width":46.0,"height":91.0,"uid":"com.gliffy.shape.basic.basic_v1.default.line","order":61,"lockAspectRatio":false,"lockShape":false,"constraints":{"constraints":[],"startConstraint":{"type":"StartPositionConstraint","StartPositionConstraint":{"nodeId":315,"py":1.0,"px":0.5}},"endConstraint":{"type":"EndPositionConstraint","EndPositionConstraint":{"nodeId":337,"py":0.0,"px":0.5}}},"graphic":{"type":"Line","Line":{"strokeWidth":2.0,"strokeColor":"#661fff","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":17,"startArrowRotation":"auto","endArrowRotation":"auto","interpolationType":"linear","cornerRadius":null,"controlPath":[[-150.13557569954526,-506.5],[-150.13557569954526,-470.75],[-202.96890903287863,-470.75],[-202.96890903287863,-412.0]],"lockSegments":{"1":true},"ortho":true}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":144.36442430045474,"y":361.5,"rotation":0.0,"id":346,"width":85.0,"height":19.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":62,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

        master

        ","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":291.5310909671214,"y":361.5,"rotation":0.0,"id":348,"width":85.0,"height":19.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":63,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

        node

        ","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":439.197757633788,"y":361.5,"rotation":0.0,"id":349,"width":85.0,"height":19.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":64,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

        node

        ","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":584.8644243004547,"y":361.5,"rotation":0.0,"id":350,"width":85.0,"height":19.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":65,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

        node

        ","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":46.86442430045474,"y":29.0,"rotation":0.0,"id":354,"width":245.0,"height":22.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":66,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

        Over a NodePort Service

        ","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":50.0,"y":52.0,"rotation":0.0,"id":356,"width":146.0,"height":1.0,"uid":"com.gliffy.shape.basic.basic_v1.default.line","order":67,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Line","Line":{"strokeWidth":2.0,"strokeColor":"#999999","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":0,"startArrowRotation":"auto","endArrowRotation":"auto","interpolationType":"linear","cornerRadius":null,"controlPath":[[0.0,0.0],[182.0109886792553,0.0]],"lockSegments":{},"ortho":false}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":120.84003405655233,"y":220.0,"rotation":0.0,"id":360,"width":584.0,"height":21.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":68,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#efe8ff","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":142.86442430045474,"y":251.5,"rotation":0.0,"id":235,"width":88.0,"height":100.0,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":69,"lockAspectRatio":false,"lockShape":false,"children":[{"x":-6.0,"y":6.0,"rotation":90.0,"id":186,"width":100.0,"height":88.0,"uid":"com.gliffy.shape.basic.basic_v1.default.hexagon","order":11,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.hexagon.basic_v1","strokeWidth":0.0,"strokeColor":"#000000","fillColor":"#3a5de9","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":19.0,"y":39.5,"rotation":0.0,"id":185,"width":50.0,"height":10.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":15,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":61.5,"y":43.0,"rotation":0.0,"id":184,"width":3.0,"height":3.0,"uid":"com.gliffy.shape.basic.basic_v1.default.circle","order":21,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.ellipse.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#000000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":19.0,"y":52.5,"rotation":0.0,"id":182,"width":50.0,"height":10.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":27,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":61.5,"y":56.0,"rotation":0.0,"id":181,"width":3.0,"height":3.0,"uid":"com.gliffy.shape.basic.basic_v1.default.circle","order":33,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.ellipse.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#000000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":452.197757633788,"y":271.0,"rotation":0.0,"id":383,"width":53.00000000000006,"height":60.0,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":72,"lockAspectRatio":false,"lockShape":false,"children":[{"x":0.0,"y":5.5,"rotation":0.0,"id":380,"width":53.0,"height":49.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":74,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

        N

        ","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":-3.599999999999966,"y":3.6000000000000227,"rotation":90.0,"id":377,"width":60.0,"height":52.8,"uid":"com.gliffy.shape.basic.basic_v1.default.hexagon","order":71,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.hexagon.basic_v1","strokeWidth":0.0,"strokeColor":"#000000","fillColor":"#00963a","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":543.0,"y":1028.5,"rotation":0.0,"id":385,"width":46.0,"height":91.0,"uid":"com.gliffy.shape.basic.basic_v1.default.line","order":75,"lockAspectRatio":false,"lockShape":false,"constraints":{"constraints":[],"startConstraint":{"type":"StartPositionConstraint","StartPositionConstraint":{"nodeId":389,"py":0.0,"px":0.5}},"endConstraint":{"type":"EndPositionConstraint","EndPositionConstraint":{"nodeId":388,"py":1.0,"px":0.5}}},"graphic":{"type":"Line","Line":{"strokeWidth":2.0,"strokeColor":"#00963a","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":17,"startArrowRotation":"auto","endArrowRotation":"auto","interpolationType":"linear","cornerRadius":null,"controlPath":[[-158.46890903287863,-727.5],[-136.4330011738,-727.5],[-114.39709331472142,-727.5],[-92.36118545564278,-727.5]],"lockSegments":{},"ortho":true}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":425.6025671054047,"y":321.25,"rotation":29.999999999999996,"id":390,"width":73.0,"height":19.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":76,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

        80/tcp

        ","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":602.0093065339395,"y":201.27275866404784,"rotation":0.0,"id":407,"width":85.71023553303064,"height":60.454482671904316,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":81,"lockAspectRatio":false,"lockShape":false,"children":[{"x":-1.1448822334847364,"y":20.727241335952158,"rotation":29.999999999999996,"id":402,"width":88.0,"height":19.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":78,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

        30100/tcp

        ","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":11.243144374054054,"y":37.22724133595216,"rotation":0.0,"id":403,"width":27.272727272727277,"height":15.0,"uid":"com.gliffy.shape.android.android_v1.icons.expand","order":80,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.android.android_v1.icons.expand","strokeWidth":1.0,"strokeColor":"#000000","fillColor":"#676767","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":456.3426398672726,"y":201.27275866404784,"rotation":0.0,"id":408,"width":85.71023553303064,"height":60.454482671904316,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":86,"lockAspectRatio":false,"lockShape":false,"children":[{"x":-1.1448822334847364,"y":20.727241335952158,"rotation":29.999999999999996,"id":409,"width":88.0,"height":19.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":83,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

        30100/tcp

        ","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":11.243144374054054,"y":37.22724133595216,"rotation":0.0,"id":410,"width":27.272727272727277,"height":15.0,"uid":"com.gliffy.shape.android.android_v1.icons.expand","order":85,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.android.android_v1.icons.expand","strokeWidth":1.0,"strokeColor":"#000000","fillColor":"#676767","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":309.6759732006058,"y":201.27275866404784,"rotation":0.0,"id":411,"width":85.71023553303064,"height":60.454482671904316,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":91,"lockAspectRatio":false,"lockShape":false,"children":[{"x":-1.1448822334847364,"y":20.727241335952158,"rotation":29.999999999999996,"id":412,"width":88.0,"height":19.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":88,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

        30100/tcp

        ","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":11.243144374054054,"y":37.22724133595216,"rotation":0.0,"id":413,"width":27.272727272727277,"height":15.0,"uid":"com.gliffy.shape.android.android_v1.icons.expand","order":90,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.android.android_v1.icons.expand","strokeWidth":1.0,"strokeColor":"#000000","fillColor":"#676767","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":162.00930653393908,"y":201.27275866404784,"rotation":0.0,"id":414,"width":85.71023553303064,"height":60.454482671904316,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":96,"lockAspectRatio":false,"lockShape":false,"children":[{"x":-1.1448822334847364,"y":20.727241335952158,"rotation":29.999999999999996,"id":415,"width":88.0,"height":19.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":93,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

        30100/tcp

        ","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":11.243144374054054,"y":37.22724133595216,"rotation":0.0,"id":416,"width":27.272727272727277,"height":15.0,"uid":"com.gliffy.shape.android.android_v1.icons.expand","order":95,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.android.android_v1.icons.expand","strokeWidth":1.0,"strokeColor":"#000000","fillColor":"#676767","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":62.86442430045474,"y":253.5,"rotation":0.0,"id":341,"width":80.0,"height":38.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":100,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

        NodePort

        \n

        Service

        ","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":100.84003405655234,"y":218.01650429449558,"rotation":315.0,"id":426,"width":40.0,"height":35.0,"uid":"com.gliffy.shape.android.android_v1.icons.forward","order":103,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.android.android_v1.icons.forward","strokeWidth":1.0,"strokeColor":"#000000","fillColor":"#676767","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":326.86442430045474,"y":20.0,"rotation":0.0,"id":325,"width":120.0,"height":90.0,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":60,"lockAspectRatio":false,"lockShape":false,"children":[{"x":7.225609756097583,"y":20.0,"rotation":0.0,"id":317,"width":62.5,"height":50.0,"uid":"com.gliffy.shape.android.android_v1.icons.monitor","order":59,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.android.android_v1.icons.monitor","strokeWidth":1.0,"strokeColor":"#000000","fillColor":"#676767","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":74.72560975609758,"y":30.0,"rotation":0.0,"id":314,"width":38.048780487804876,"height":40.0,"uid":"com.gliffy.shape.android.android_v1.icons.person","order":57,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.android.android_v1.icons.person","strokeWidth":1.0,"strokeColor":"#000000","fillColor":"#676767","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":0.0,"y":0.0,"rotation":0.0,"id":315,"width":120.0,"height":90.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":7,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":2.0,"strokeColor":"#cccccc","fillColor":"#FFFFFF","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"layers":[{"guid":"mcqBzoFMGdMI","order":0,"name":"Layer 0","active":true,"locked":false,"visible":true,"nodeIndex":109}],"shapeStyles":{},"lineStyles":{"global":{"stroke":"#00963a","strokeWidth":3,"endArrow":1,"orthoMode":0}},"textStyles":{"global":{"face":"Roboto Slab","size":"36px","color":"#676767"}}},"metadata":{"title":"untitled","revision":0,"exportBorder":false,"loadPosition":"default","autosaveDisabled":false,"lastSerialized":1536083644406,"libraries":["com.gliffy.libraries.android.android_v1.icons","com.gliffy.libraries.basic.basic_v1.default","com.gliffy.libraries.flowchart.flowchart_v1.default","com.gliffy.libraries.swimlanes.swimlanes_v1.default","com.gliffy.libraries.uml.uml_v2.class","com.gliffy.libraries.uml.uml_v2.sequence","com.gliffy.libraries.uml.uml_v2.activity","com.gliffy.libraries.erd.erd_v1.default","com.gliffy.libraries.ui.ui_v3.containers_content","com.gliffy.libraries.ui.ui_v3.forms_controls","com.gliffy.libraries.images"]},"embeddedResources":{"index":0,"resources":[]}} \ No newline at end of file diff --git a/images/baremetal/nodeport.jpg b/images/baremetal/nodeport.jpg new file mode 100644 index 0000000000000000000000000000000000000000..012f5338328751caa134e55eb660888e442a724d GIT binary patch literal 48359 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 )QQ6a3c?R&P1?)+B_W8^bwp0>lHfFdAn< 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 literal 0 HcmV?d00001 diff --git a/images/baremetal/user_edge.gliffy b/images/baremetal/user_edge.gliffy new file mode 100644 index 000000000..387dffaa5 --- /dev/null +++ b/images/baremetal/user_edge.gliffy @@ -0,0 +1 @@ +{"contentType":"application/gliffy+json","version":"1.3","stage":{"background":"#FFFFFF","width":737,"height":577,"nodeIndex":443,"autoFit":true,"exportBorder":false,"gridOn":true,"snapToGrid":false,"drawingGuidesOn":true,"pageBreaksOn":false,"printGridOn":false,"printPaper":null,"printShrinkToFit":false,"printPortrait":false,"maxWidth":5000,"maxHeight":5000,"themeData":null,"imageCache":{},"viewportType":"default","fitBB":{"min":{"x":36.86442430045474,"y":20},"max":{"x":736.8644243004547,"y":577}},"printModel":{"pageSize":"Letter","portrait":true,"fitToOnePage":false,"displayPageBreaks":false},"objects":[{"x":50.0,"y":52.0,"rotation":0.0,"id":356,"width":146.0,"height":1.0,"uid":"com.gliffy.shape.basic.basic_v1.default.line","order":78,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Line","Line":{"strokeWidth":2.0,"strokeColor":"#999999","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":0,"startArrowRotation":"auto","endArrowRotation":"auto","interpolationType":"linear","cornerRadius":null,"controlPath":[[0.0,0.0],[224.00892839349058,0.0]],"lockSegments":{},"ortho":false}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":46.86442430045474,"y":29.0,"rotation":0.0,"id":354,"width":245.0,"height":22.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":77,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

        Using a self-provisioned edge

        ","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":326.86442430045474,"y":20.0,"rotation":0.0,"id":325,"width":120.0,"height":90.0,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":69,"lockAspectRatio":false,"lockShape":false,"children":[{"x":7.225609756097583,"y":20.0,"rotation":0.0,"id":317,"width":62.5,"height":50.0,"uid":"com.gliffy.shape.android.android_v1.icons.monitor","order":68,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.android.android_v1.icons.monitor","strokeWidth":1.0,"strokeColor":"#000000","fillColor":"#676767","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":74.72560975609758,"y":30.0,"rotation":0.0,"id":314,"width":38.048780487804876,"height":40.0,"uid":"com.gliffy.shape.android.android_v1.icons.person","order":66,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.android.android_v1.icons.person","strokeWidth":1.0,"strokeColor":"#000000","fillColor":"#676767","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":0.0,"y":0.0,"rotation":0.0,"id":315,"width":120.0,"height":90.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":15,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":2.0,"strokeColor":"#cccccc","fillColor":"#FFFFFF","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":392.0,"y":268.0,"rotation":0.0,"id":339,"width":46.0,"height":91.0,"uid":"com.gliffy.shape.basic.basic_v1.default.line","order":70,"lockAspectRatio":false,"lockShape":false,"constraints":{"constraints":[],"startConstraint":{"type":"StartPositionConstraint","StartPositionConstraint":{"nodeId":395,"py":1.0,"px":0.5}},"endConstraint":{"type":"EndPositionConstraint","EndPositionConstraint":{"nodeId":383,"py":0.0,"px":0.5}}},"graphic":{"type":"Line","Line":{"strokeWidth":2.0,"strokeColor":"#009687","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":17,"startArrowRotation":"auto","endArrowRotation":"auto","interpolationType":"linear","cornerRadius":null,"controlPath":[[-4.45617347599233,-1.0],[-4.45617347599233,31.75],[236.36442430045474,31.75],[236.36442430045474,74.5]],"lockSegments":{"1":true},"ortho":true}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":547.0,"y":626.5,"rotation":0.0,"id":351,"width":46.0,"height":91.0,"uid":"com.gliffy.shape.basic.basic_v1.default.line","order":76,"lockAspectRatio":false,"lockShape":false,"constraints":{"constraints":[],"startConstraint":{"type":"StartPositionConstraint","StartPositionConstraint":{"nodeId":315,"py":1.0,"px":0.5}},"endConstraint":{"type":"EndPositionConstraint","EndPositionConstraint":{"nodeId":353,"py":0.0,"px":0.5}}},"graphic":{"type":"Line","Line":{"strokeWidth":2.0,"strokeColor":"#666666","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":17,"startArrowRotation":"auto","endArrowRotation":"auto","interpolationType":"linear","cornerRadius":null,"controlPath":[[-160.13557569954526,-516.5],[-160.13557569954526,-501.83321142036345],[-160.13557569954526,-487.1664228407269],[-160.13557569954526,-472.49963426109036]],"lockSegments":{},"ortho":true}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":36.86442430045474,"y":317.0,"rotation":0.0,"id":221,"width":700.0,"height":260.0,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":60,"lockAspectRatio":false,"lockShape":false,"children":[{"x":10.0,"y":8.5,"rotation":0.0,"id":153,"width":42.0,"height":41.0,"uid":"com.gliffy.shape.basic.basic_v1.default.image","order":29,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Image","Image":{"url":"data:image/png;base64,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","urlHash":null,"fileName":null,"imageId":null,"strokeWidth":2.0,"strokeColor":"#000000","dropShadow":false,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":0.0,"y":0.0,"rotation":0.0,"id":3,"width":700.0,"height":260.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":17,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#f5f5f5","gradient":true,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":142.86442430045474,"y":386.5,"rotation":0.0,"id":235,"width":88.0,"height":100.0,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":64,"lockAspectRatio":false,"lockShape":false,"children":[{"x":61.5,"y":56.0,"rotation":0.0,"id":181,"width":3.0,"height":3.0,"uid":"com.gliffy.shape.basic.basic_v1.default.circle","order":27,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.ellipse.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#000000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":19.0,"y":52.5,"rotation":0.0,"id":182,"width":50.0,"height":10.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":25,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":61.5,"y":43.0,"rotation":0.0,"id":184,"width":3.0,"height":3.0,"uid":"com.gliffy.shape.basic.basic_v1.default.circle","order":23,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.ellipse.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#000000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":19.0,"y":39.5,"rotation":0.0,"id":185,"width":50.0,"height":10.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":21,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":-6.0,"y":6.0,"rotation":90.0,"id":186,"width":100.0,"height":88.0,"uid":"com.gliffy.shape.basic.basic_v1.default.hexagon","order":19,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.hexagon.basic_v1","strokeWidth":0.0,"strokeColor":"#000000","fillColor":"#3a5de9","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":144.36442430045474,"y":496.5,"rotation":0.0,"id":346,"width":85.0,"height":19.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":72,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

        master

        ","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":584.8644243004547,"y":496.5,"rotation":0.0,"id":350,"width":85.0,"height":19.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":75,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

        node

        ","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":63.86442430045474,"y":388.5,"rotation":0.0,"id":368,"width":80.0,"height":38.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":101,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

        NodePort

        \n

        Service

        ","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":367.04382652400767,"y":154.0,"rotation":0.0,"id":353,"width":40.0,"height":16.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":13,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#ffffff","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":431.04382652400767,"y":199.5,"rotation":0.0,"id":341,"width":116.0,"height":38.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":71,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

        User-managed

        public edge

        ","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":101.84003405655233,"y":353.0165042944956,"rotation":315.0,"id":367,"width":40.0,"height":35.0,"uid":"com.gliffy.shape.android.android_v1.icons.forward","order":102,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.android.android_v1.icons.forward","strokeWidth":1.0,"strokeColor":"#000000","fillColor":"#676767","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":391.78489778522317,"y":149.5,"rotation":29.999999999999996,"id":389,"width":68.0,"height":19.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":103,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

        80/tcp

        ","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":367.54382652400767,"y":251.0,"rotation":0.0,"id":395,"width":40.0,"height":16.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":12,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#ffffff","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":402.0,"y":278.0,"rotation":0.0,"id":396,"width":46.0,"height":91.0,"uid":"com.gliffy.shape.basic.basic_v1.default.line","order":104,"lockAspectRatio":false,"lockShape":false,"constraints":{"constraints":[],"startConstraint":{"type":"StartPositionConstraint","StartPositionConstraint":{"nodeId":395,"py":1.0,"px":0.5}},"endConstraint":{"type":"EndPositionConstraint","EndPositionConstraint":{"nodeId":382,"py":0.0,"px":0.5}}},"graphic":{"type":"Line","Line":{"strokeWidth":2.0,"strokeColor":"#009687","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":17,"startArrowRotation":"auto","endArrowRotation":"auto","interpolationType":"linear","cornerRadius":null,"controlPath":[[-14.45617347599233,-11.0],[-14.45617347599233,21.75],[79.197757633788,21.75],[79.197757633788,64.5]],"lockSegments":{"1":true},"ortho":true}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":1043.0,"y":375.5,"rotation":0.0,"id":397,"width":46.0,"height":91.0,"uid":"com.gliffy.shape.basic.basic_v1.default.line","order":105,"lockAspectRatio":false,"lockShape":false,"constraints":{"constraints":[],"startConstraint":{"type":"StartPositionConstraint","StartPositionConstraint":{"nodeId":395,"py":1.0,"px":0.5}},"endConstraint":{"type":"EndPositionConstraint","EndPositionConstraint":{"nodeId":384,"py":0.0,"px":0.5}}},"graphic":{"type":"Line","Line":{"strokeWidth":2.0,"strokeColor":"#009687","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":17,"startArrowRotation":"auto","endArrowRotation":"auto","interpolationType":"linear","cornerRadius":null,"controlPath":[[-655.4561734759923,-108.5],[-655.4561734759923,-75.75],[-707.9689090328786,-75.75],[-707.9689090328786,-33.0]],"lockSegments":{"1":true},"ortho":true}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":1088.0,"y":394.5,"rotation":0.0,"id":398,"width":46.0,"height":91.0,"uid":"com.gliffy.shape.basic.basic_v1.default.line","order":106,"lockAspectRatio":false,"lockShape":false,"constraints":{"constraints":[],"startConstraint":{"type":"StartPositionConstraint","StartPositionConstraint":{"nodeId":395,"py":1.0,"px":0.5}},"endConstraint":{"type":"EndPositionConstraint","EndPositionConstraint":{"nodeId":385,"py":0.0,"px":0.5}}},"graphic":{"type":"Line","Line":{"strokeWidth":2.0,"strokeColor":"#009687","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":17,"startArrowRotation":"auto","endArrowRotation":"auto","interpolationType":"linear","cornerRadius":null,"controlPath":[[-700.4561734759923,-127.5],[-700.4561734759923,-94.75],[-897.6355756995453,-94.75],[-897.6355756995453,-52.0]],"lockSegments":{"1":true},"ortho":true}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":337.04382652400767,"y":167.0,"rotation":90.0,"id":363,"width":100.0,"height":88.0,"uid":"com.gliffy.shape.basic.basic_v1.default.hexagon","order":79,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.hexagon.basic_v1","strokeWidth":0.0,"strokeColor":"#000000","fillColor":"#009687","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":360.68668366686484,"y":187.50000000000003,"rotation":90.0,"id":402,"width":53.7142857142857,"height":47.0,"uid":"com.gliffy.shape.android.android_v1.icons.forward","order":107,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.android.android_v1.icons.forward","strokeWidth":1.0,"strokeColor":"#000000","fillColor":"#ffffff","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":439.197757633788,"y":496.5,"rotation":0.0,"id":349,"width":85.0,"height":19.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":74,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

        node

        ","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":582.8644243004547,"y":386.5,"rotation":0.0,"id":229,"width":88.0,"height":100.0,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":61,"lockAspectRatio":false,"lockShape":false,"children":[{"x":61.5,"y":56.0,"rotation":0.0,"id":199,"width":3.0,"height":3.0,"uid":"com.gliffy.shape.basic.basic_v1.default.circle","order":59,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.ellipse.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#000000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":19.0,"y":52.5,"rotation":0.0,"id":200,"width":50.0,"height":10.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":57,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":61.5,"y":43.0,"rotation":0.0,"id":202,"width":3.0,"height":3.0,"uid":"com.gliffy.shape.basic.basic_v1.default.circle","order":55,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.ellipse.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#000000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":19.0,"y":39.5,"rotation":0.0,"id":203,"width":50.0,"height":10.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":53,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":-6.0,"y":6.0,"rotation":90.0,"id":204,"width":100.0,"height":88.0,"uid":"com.gliffy.shape.basic.basic_v1.default.hexagon","order":51,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.hexagon.basic_v1","strokeWidth":0.0,"strokeColor":"#000000","fillColor":"#3a5de9","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":436.197757633788,"y":386.5,"rotation":0.0,"id":231,"width":88.0,"height":100.0,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":62,"lockAspectRatio":false,"lockShape":false,"children":[{"x":61.5,"y":56.0,"rotation":0.0,"id":190,"width":3.0,"height":3.0,"uid":"com.gliffy.shape.basic.basic_v1.default.circle","order":49,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.ellipse.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#000000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":19.0,"y":52.5,"rotation":0.0,"id":191,"width":50.0,"height":10.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":47,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":61.5,"y":43.0,"rotation":0.0,"id":193,"width":3.0,"height":3.0,"uid":"com.gliffy.shape.basic.basic_v1.default.circle","order":45,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.ellipse.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#000000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":19.0,"y":39.5,"rotation":0.0,"id":194,"width":50.0,"height":10.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":43,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":-6.0,"y":6.0,"rotation":90.0,"id":195,"width":100.0,"height":88.0,"uid":"com.gliffy.shape.basic.basic_v1.default.hexagon","order":41,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.hexagon.basic_v1","strokeWidth":0.0,"strokeColor":"#000000","fillColor":"#3a5de9","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":571.8644243004546,"y":455.97724133595216,"rotation":29.999999999999996,"id":406,"width":73.0,"height":19.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":114,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

        80/tcp

        ","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":170.36442430045474,"y":342.5,"rotation":0.0,"id":385,"width":40.0,"height":16.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":8,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#ff0000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":315.0310909671214,"y":342.5,"rotation":0.0,"id":384,"width":40.0,"height":16.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":9,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#ff0000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":608.3644243004547,"y":342.5,"rotation":0.0,"id":383,"width":40.0,"height":16.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":10,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#ff0000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":461.197757633788,"y":342.5,"rotation":0.0,"id":382,"width":40.0,"height":16.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":11,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#ff0000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":121.84003405655233,"y":355.0,"rotation":0.0,"id":381,"width":584.0,"height":21.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":80,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#e5f8fb","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":603.0093065339395,"y":336.27275866404784,"rotation":0.0,"id":378,"width":85.71023553303064,"height":60.454482671904316,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":85,"lockAspectRatio":false,"lockShape":false,"children":[{"x":-1.1448822334847364,"y":20.727241335952158,"rotation":29.999999999999996,"id":379,"width":88.0,"height":19.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":82,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

        30100/tcp

        ","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":11.243144374054054,"y":37.22724133595216,"rotation":0.0,"id":380,"width":27.272727272727277,"height":15.0,"uid":"com.gliffy.shape.android.android_v1.icons.expand","order":84,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.android.android_v1.icons.expand","strokeWidth":1.0,"strokeColor":"#000000","fillColor":"#676767","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":457.3426398672726,"y":336.27275866404784,"rotation":0.0,"id":375,"width":85.71023553303064,"height":60.454482671904316,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":90,"lockAspectRatio":false,"lockShape":false,"children":[{"x":-1.1448822334847364,"y":20.727241335952158,"rotation":29.999999999999996,"id":376,"width":88.0,"height":19.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":87,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

        30100/tcp

        ","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":11.243144374054054,"y":37.22724133595216,"rotation":0.0,"id":377,"width":27.272727272727277,"height":15.0,"uid":"com.gliffy.shape.android.android_v1.icons.expand","order":89,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.android.android_v1.icons.expand","strokeWidth":1.0,"strokeColor":"#000000","fillColor":"#676767","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":310.6759732006058,"y":336.27275866404784,"rotation":0.0,"id":372,"width":85.71023553303064,"height":60.454482671904316,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":95,"lockAspectRatio":false,"lockShape":false,"children":[{"x":-1.1448822334847364,"y":20.727241335952158,"rotation":29.999999999999996,"id":373,"width":88.0,"height":19.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":92,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

        30100/tcp

        ","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":11.243144374054054,"y":37.22724133595216,"rotation":0.0,"id":374,"width":27.272727272727277,"height":15.0,"uid":"com.gliffy.shape.android.android_v1.icons.expand","order":94,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.android.android_v1.icons.expand","strokeWidth":1.0,"strokeColor":"#000000","fillColor":"#676767","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":163.00930653393908,"y":336.27275866404784,"rotation":0.0,"id":369,"width":85.71023553303064,"height":60.454482671904316,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":100,"lockAspectRatio":false,"lockShape":false,"children":[{"x":-1.1448822334847364,"y":20.727241335952158,"rotation":29.999999999999996,"id":370,"width":88.0,"height":19.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":97,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

        30100/tcp

        ","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":11.243144374054054,"y":37.22724133595216,"rotation":0.0,"id":371,"width":27.272727272727277,"height":15.0,"uid":"com.gliffy.shape.android.android_v1.icons.expand","order":99,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.android.android_v1.icons.expand","strokeWidth":1.0,"strokeColor":"#000000","fillColor":"#676767","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":545.3333333333333,"y":1163.3863793320238,"rotation":0.0,"id":407,"width":46.0,"height":91.0,"uid":"com.gliffy.shape.basic.basic_v1.default.line","order":113,"lockAspectRatio":false,"lockShape":false,"constraints":{"constraints":[],"startConstraint":{"type":"StartPositionConstraint","StartPositionConstraint":{"nodeId":435,"py":0.0,"px":0.5}},"endConstraint":{"type":"EndPositionConstraint","EndPositionConstraint":{"nodeId":413,"py":1.0,"px":0.5}}},"graphic":{"type":"Line","Line":{"strokeWidth":2.0,"strokeColor":"#00b8d4","fillColor":"none","dashStyle":null,"startArrow":17,"endArrow":17,"startArrowRotation":"auto","endArrowRotation":"auto","interpolationType":"linear","cornerRadius":null,"controlPath":[[-310.9724875712815,-727.4999999999999],[-293.4353868660686,-727.4999999999999],[-275.89828616085566,-727.4999999999999],[-258.3611854556427,-727.4999999999999]],"lockSegments":{},"ortho":true}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":289.5310909671214,"y":386.5,"rotation":0.0,"id":233,"width":88.0,"height":100.0,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":63,"lockAspectRatio":false,"lockShape":false,"children":[{"x":61.5,"y":56.0,"rotation":0.0,"id":161,"width":3.0,"height":3.0,"uid":"com.gliffy.shape.basic.basic_v1.default.circle","order":39,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.ellipse.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#000000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":19.0,"y":52.5,"rotation":0.0,"id":162,"width":50.0,"height":10.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":37,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":61.5,"y":43.0,"rotation":0.0,"id":164,"width":3.0,"height":3.0,"uid":"com.gliffy.shape.basic.basic_v1.default.circle","order":35,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.ellipse.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#000000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":19.0,"y":39.5,"rotation":0.0,"id":165,"width":50.0,"height":10.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":33,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":-6.0,"y":6.0,"rotation":90.0,"id":166,"width":100.0,"height":88.0,"uid":"com.gliffy.shape.basic.basic_v1.default.hexagon","order":31,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.hexagon.basic_v1","strokeWidth":0.0,"strokeColor":"#000000","fillColor":"#3a5de9","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":274.97214787769053,"y":427.8863793320239,"rotation":90.0,"id":413,"width":40.0,"height":16.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":7,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#ff0000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":292.5310909671214,"y":496.5,"rotation":0.0,"id":348,"width":85.0,"height":19.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":73,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

        node

        ","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":307.5310909671215,"y":405.8863793320239,"rotation":0.0,"id":408,"width":53.00000000000006,"height":60.0,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":110,"lockAspectRatio":false,"lockShape":false,"children":[{"x":0.0,"y":5.5,"rotation":0.0,"id":409,"width":53.0,"height":49.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":112,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

        N

        ","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":-3.599999999999966,"y":3.6000000000000227,"rotation":90.0,"id":410,"width":60.0,"height":52.8,"uid":"com.gliffy.shape.basic.basic_v1.default.hexagon","order":109,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.hexagon.basic_v1","strokeWidth":0.0,"strokeColor":"#000000","fillColor":"#00963a","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":353.5310909671214,"y":428.5,"rotation":90.0,"id":431,"width":40.0,"height":16.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":6,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#ff0000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":419.197757633788,"y":428.5,"rotation":90.0,"id":432,"width":40.0,"height":16.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":5,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#ff0000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":206.36442430045474,"y":428.5,"rotation":90.0,"id":435,"width":40.0,"height":16.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":4,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#ff0000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":555.3333333333333,"y":1173.3863793320238,"rotation":0.0,"id":436,"width":46.0,"height":91.0,"uid":"com.gliffy.shape.basic.basic_v1.default.line","order":115,"lockAspectRatio":false,"lockShape":false,"constraints":{"constraints":[],"startConstraint":{"type":"StartPositionConstraint","StartPositionConstraint":{"nodeId":431,"py":0.0,"px":0.5}},"endConstraint":{"type":"EndPositionConstraint","EndPositionConstraint":{"nodeId":432,"py":1.0,"px":0.5}}},"graphic":{"type":"Line","Line":{"strokeWidth":2.0,"strokeColor":"#00b8d4","fillColor":"none","dashStyle":null,"startArrow":17,"endArrow":17,"startArrowRotation":"auto","endArrowRotation":"auto","interpolationType":"linear","cornerRadius":null,"controlPath":[[-173.80224236621189,-736.8863793320238],[-157.24668681065634,-736.8863793320238],[-140.6911312551008,-736.8863793320238],[-124.13557569954526,-736.8863793320238]],"lockSegments":{},"ortho":true}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":278.5310909671214,"y":455.97724133595216,"rotation":29.999999999999996,"id":437,"width":73.0,"height":19.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":116,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

        80/tcp

        ","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":598.8644243004547,"y":405.47724133595216,"rotation":0.0,"id":438,"width":53.00000000000006,"height":60.0,"uid":"com.gliffy.shape.basic.basic_v1.default.group","order":117,"lockAspectRatio":false,"lockShape":false,"children":[{"x":0.0,"y":5.5,"rotation":0.0,"id":439,"width":53.0,"height":49.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":121,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

        N

        ","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":-3.599999999999966,"y":3.6000000000000227,"rotation":90.0,"id":440,"width":60.0,"height":52.8,"uid":"com.gliffy.shape.basic.basic_v1.default.hexagon","order":119,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.hexagon.basic_v1","strokeWidth":0.0,"strokeColor":"#000000","fillColor":"#00963a","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":565.3333333333333,"y":1183.3863793320238,"rotation":0.0,"id":441,"width":46.0,"height":91.0,"uid":"com.gliffy.shape.basic.basic_v1.default.line","order":122,"lockAspectRatio":false,"lockShape":false,"constraints":{"constraints":[],"startConstraint":{"type":"StartPositionConstraint","StartPositionConstraint":{"nodeId":433,"py":0.0,"px":0.5}},"endConstraint":{"type":"EndPositionConstraint","EndPositionConstraint":{"nodeId":434,"py":1.0,"px":0.5}}},"graphic":{"type":"Line","Line":{"strokeWidth":2.0,"strokeColor":"#00b8d4","fillColor":"none","dashStyle":null,"startArrow":17,"endArrow":17,"startArrowRotation":"auto","endArrowRotation":"auto","interpolationType":"linear","cornerRadius":null,"controlPath":[[-37.13557569954526,-746.8863793320238],[-20.246686810656342,-746.8863793320238],[-3.3577979217674283,-746.8863793320238],[13.531090967121486,-746.8863793320238]],"lockSegments":{},"ortho":true}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":500.197757633788,"y":428.5,"rotation":90.0,"id":433,"width":40.0,"height":16.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":1,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#ff0000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"},{"x":566.8644243004547,"y":428.5,"rotation":90.0,"id":434,"width":40.0,"height":16.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":3,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":0.0,"strokeColor":"#333333","fillColor":"#ff0000","gradient":false,"dashStyle":null,"dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[],"hidden":false,"layerId":"mcqBzoFMGdMI"}],"layers":[{"guid":"mcqBzoFMGdMI","order":0,"name":"Layer 0","active":true,"locked":false,"visible":true,"nodeIndex":123}],"shapeStyles":{},"lineStyles":{"global":{"stroke":"#00b8d4","strokeWidth":2,"orthoMode":0,"startArrow":17}},"textStyles":{"global":{"bold":true,"face":"Roboto Slab","size":"16px","color":"#00b8d4"}}},"metadata":{"title":"untitled","revision":0,"exportBorder":false,"loadPosition":"default","autosaveDisabled":false,"lastSerialized":1536087239311,"libraries":["com.gliffy.libraries.android.android_v1.icons","com.gliffy.libraries.basic.basic_v1.default","com.gliffy.libraries.flowchart.flowchart_v1.default","com.gliffy.libraries.swimlanes.swimlanes_v1.default","com.gliffy.libraries.uml.uml_v2.class","com.gliffy.libraries.uml.uml_v2.sequence","com.gliffy.libraries.uml.uml_v2.activity","com.gliffy.libraries.erd.erd_v1.default","com.gliffy.libraries.ui.ui_v3.containers_content","com.gliffy.libraries.ui.ui_v3.forms_controls","com.gliffy.libraries.images"]},"embeddedResources":{"index":0,"resources":[]}} \ No newline at end of file diff --git a/images/baremetal/user_edge.jpg b/images/baremetal/user_edge.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f1165f5cc8176657b1fb34dbdd54e373eb6fd4f0 GIT binary patch literal 63036 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 literal 0 HcmV?d00001 diff --git a/index.html b/index.html index dfe9a3db9..8d950c662 100644 --- a/index.html +++ b/index.html @@ -394,6 +394,18 @@ +

      15. + + Bare-metal considerations + +
      16. + + + + + + +
      17. Role Based Access Control (RBAC) diff --git a/search/search_index.json b/search/search_index.json index 2a2d821ef..e9c48ffe2 100644 --- a/search/search_index.json +++ b/search/search_index.json @@ -17,7 +17,7 @@ }, { "location": "/deploy/", - "text": "Installation Guide\n\u00b6\n\n\nContents\n\u00b6\n\n\n\n\nGeneric Deployment\n\n\nMandatory command\n\n\nProvider Specific Steps\n\n\nDocker for Mac\n\n\nminikube\n\n\nAWS\n\n\nGCE - GKE\n\n\nAzure\n\n\nBaremetal\n\n\n\n\n\n\nVerify installation\n\n\nDetect installed version\n\n\nUsing Helm\n\n\n\n\nGeneric Deployment\n\u00b6\n\n\nThe following resources are required for a generic deployment.\n\n\nMandatory command\n\u00b6\n\n\nkubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/mandatory.yaml\n\n\n\n\n\n\nProvider Specific Steps\n\u00b6\n\n\nThere are cloud provider specific yaml files.\n\n\nDocker for Mac\n\u00b6\n\n\nKubernetes is available in Docker for Mac (from \nversion 18.06.0-ce\n)\n\n\nCreate a service\n\n\nkubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/cloud-generic.yaml\n\n\n\n\n\n\nminikube\n\u00b6\n\n\nFor standard usage:\n\n\nminikube addons enable ingress\n\n\n\n\n\n\nFor development:\n\n\n\n\nDisable the ingress addon:\n\n\n\n\n$\n minikube addons disable ingress\n\n\n\n\n\n\n\nExecute \nmake dev-env\n\n\nConfirm the \nnginx-ingress-controller\n deployment exists:\n\n\n\n\n$\n kubectl get pods -n ingress-nginx \n\nNAME READY STATUS RESTARTS AGE\n\n\ndefault-http-backend-66b447d9cf-rrlf9 1/1 Running 0 12s\n\n\nnginx-ingress-controller-fdcdcd6dd-vvpgs 1/1 Running 0 11s\n\n\n\n\n\n\nAWS\n\u00b6\n\n\nIn AWS we use an Elastic Load Balancer (ELB) to expose the NGINX Ingress controller behind a Service of \nType=LoadBalancer\n.\nSince Kubernetes v1.9.0 it is possible to use a classic load balancer (ELB) or network load balancer (NLB)\nPlease check the \nelastic load balancing AWS details page\n\n\nElastic Load Balancer - ELB\n\u00b6\n\n\nThis setup requires to choose in which layer (L4 or L7) we want to configure the ELB:\n\n\n\n\nLayer 4\n: use TCP as the listener protocol for ports 80 and 443.\n\n\nLayer 7\n: use HTTP as the listener protocol for port 80 and terminate TLS in the ELB\n\n\n\n\nFor L4:\n\n\nkubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/aws/service-l4.yaml\n\n\nkubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/aws/patch-configmap-l4.yaml\n\n\n\n\n\n\nFor L7:\n\n\nChange line of the file \nprovider/aws/service-l7.yaml\n replacing the dummy id with a valid one \n\"arn:aws:acm:us-west-2:XXXXXXXX:certificate/XXXXXX-XXXXXXX-XXXXXXX-XXXXXXXX\"\n\nThen execute:\n\n\nkubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/aws/service-l7.yaml\n\n\nkubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/aws/patch-configmap-l7.yaml\n\n\n\n\n\n\nThis example creates an ELB with just two listeners, one in port 80 and another in port 443\n\n\n\n\nNetwork Load Balancer (NLB)\n\u00b6\n\n\nThis type of load balancer is supported since v1.10.0 as an ALPHA feature.\n\n\nkubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/aws/service-nlb.yaml\n\n\n\n\n\n\nGCE - GKE\n\u00b6\n\n\nkubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/cloud-generic.yaml\n\n\n\n\n\n\nImportant Note:\n proxy protocol is not supported in GCE/GKE\n\n\nAzure\n\u00b6\n\n\nkubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/cloud-generic.yaml\n\n\n\n\n\n\nBaremetal\n\u00b6\n\n\nUsing \nNodePort\n:\n\n\nkubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/baremetal/service-nodeport.yaml\n\n\n\n\n\n\nVerify installation\n\u00b6\n\n\nTo check if the ingress controller pods have started, run the following command:\n\n\nkubectl get pods --all-namespaces -l app=ingress-nginx --watch\n\n\n\n\n\n\nOnce the operator pods are running, you can cancel the above command by typing \nCtrl+C\n.\nNow, you are ready to create your first ingress.\n\n\nDetect installed version\n\u00b6\n\n\nTo detect which version of the ingress controller is running, exec into the pod and run \nnginx-ingress-controller version\n command.\n\n\nPOD_NAMESPACE=ingress-nginx\n\n\nPOD_NAME=$(kubectl get pods -n $POD_NAMESPACE -l app=ingress-nginx -o jsonpath='{.items[0].metadata.name}')\n\n\nkubectl exec -it $POD_NAME -n $POD_NAMESPACE -- /nginx-ingress-controller --version\n\n\n\n\n\n\nUsing Helm\n\u00b6\n\n\nNGINX Ingress controller can be installed via \nHelm\n using the chart \nstable/nginx-ingress\n from the official charts repository. \nTo install the chart with the release name \nmy-nginx\n:\n\n\nhelm install stable/nginx-ingress --name my-nginx\n\n\n\n\n\n\nIf the kubernetes cluster has RBAC enabled, then run:\n\n\nhelm install stable/nginx-ingress --name my-nginx --set rbac.create=true\n\n\n\n\n\n\nDetect installed version:\n\n\nPOD_NAME=$(kubectl get pods -l app=nginx-ingress -o jsonpath='{.items[0].metadata.name}')\n\n\nkubectl exec -it $POD_NAME -- /nginx-ingress-controller --version", + "text": "Installation Guide\n\u00b6\n\n\nContents\n\u00b6\n\n\n\n\nGeneric Deployment\n\n\nMandatory command\n\n\nProvider Specific Steps\n\n\nDocker for Mac\n\n\nminikube\n\n\nAWS\n\n\nGCE - GKE\n\n\nAzure\n\n\nBare-metal\n\n\n\n\n\n\nVerify installation\n\n\nDetect installed version\n\n\nUsing Helm\n\n\n\n\nGeneric Deployment\n\u00b6\n\n\nThe following resources are required for a generic deployment.\n\n\nMandatory command\n\u00b6\n\n\nkubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/mandatory.yaml\n\n\n\n\n\nProvider Specific Steps\n\u00b6\n\n\nThere are cloud provider specific yaml files.\n\n\nDocker for Mac\n\u00b6\n\n\nKubernetes is available in Docker for Mac (from \nversion 18.06.0-ce\n)\n\n\nCreate a service\n\n\nkubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/cloud-generic.yaml\n\n\n\n\n\nminikube\n\u00b6\n\n\nFor standard usage:\n\n\nminikube addons enable ingress\n\n\n\n\n\nFor development:\n\n\n\n\nDisable the ingress addon:\n\n\n\n\n$\n minikube addons disable ingress\n\n\n\n\n\n\nExecute \nmake dev-env\n\n\nConfirm the \nnginx-ingress-controller\n deployment exists:\n\n\n\n\n$\n kubectl get pods -n ingress-nginx \n\nNAME READY STATUS RESTARTS AGE\n\n\ndefault-http-backend-66b447d9cf-rrlf9 1/1 Running 0 12s\n\n\nnginx-ingress-controller-fdcdcd6dd-vvpgs 1/1 Running 0 11s\n\n\n\n\n\nAWS\n\u00b6\n\n\nIn AWS we use an Elastic Load Balancer (ELB) to expose the NGINX Ingress controller behind a Service of \nType=LoadBalancer\n.\nSince Kubernetes v1.9.0 it is possible to use a classic load balancer (ELB) or network load balancer (NLB)\nPlease check the \nelastic load balancing AWS details page\n\n\nElastic Load Balancer - ELB\n\u00b6\n\n\nThis setup requires to choose in which layer (L4 or L7) we want to configure the ELB:\n\n\n\n\nLayer 4\n: use TCP as the listener protocol for ports 80 and 443.\n\n\nLayer 7\n: use HTTP as the listener protocol for port 80 and terminate TLS in the ELB\n\n\n\n\nFor L4:\n\n\nkubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/aws/service-l4.yaml\n\n\nkubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/aws/patch-configmap-l4.yaml\n\n\n\n\n\nFor L7:\n\n\nChange line of the file \nprovider/aws/service-l7.yaml\n replacing the dummy id with a valid one \n\"arn:aws:acm:us-west-2:XXXXXXXX:certificate/XXXXXX-XXXXXXX-XXXXXXX-XXXXXXXX\"\n\nThen execute:\n\n\nkubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/aws/service-l7.yaml\n\n\nkubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/aws/patch-configmap-l7.yaml\n\n\n\n\n\nThis example creates an ELB with just two listeners, one in port 80 and another in port 443\n\n\n\n\nNetwork Load Balancer (NLB)\n\u00b6\n\n\nThis type of load balancer is supported since v1.10.0 as an ALPHA feature.\n\n\nkubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/aws/service-nlb.yaml\n\n\n\n\n\nGCE - GKE\n\u00b6\n\n\nkubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/cloud-generic.yaml\n\n\n\n\n\nImportant Note:\n proxy protocol is not supported in GCE/GKE\n\n\nAzure\n\u00b6\n\n\nkubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/cloud-generic.yaml\n\n\n\n\n\nBare-metal\n\u00b6\n\n\nUsing \nNodePort\n:\n\n\nkubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/baremetal/service-nodeport.yaml\n\n\n\n\n\n\n\nTip\n\n\nFor extended notes regarding deployments on bare-metal, see \nBare-metal considerations\n.\n\n\n\n\nVerify installation\n\u00b6\n\n\nTo check if the ingress controller pods have started, run the following command:\n\n\nkubectl get pods --all-namespaces -l app=ingress-nginx --watch\n\n\n\n\n\nOnce the operator pods are running, you can cancel the above command by typing \nCtrl+C\n.\nNow, you are ready to create your first ingress.\n\n\nDetect installed version\n\u00b6\n\n\nTo detect which version of the ingress controller is running, exec into the pod and run \nnginx-ingress-controller version\n command.\n\n\nPOD_NAMESPACE=ingress-nginx\n\n\nPOD_NAME=$(kubectl get pods -n $POD_NAMESPACE -l app=ingress-nginx -o jsonpath='{.items[0].metadata.name}')\n\n\nkubectl exec -it $POD_NAME -n $POD_NAMESPACE -- /nginx-ingress-controller --version\n\n\n\n\n\nUsing Helm\n\u00b6\n\n\nNGINX Ingress controller can be installed via \nHelm\n using the chart \nstable/nginx-ingress\n from the official charts repository. \nTo install the chart with the release name \nmy-nginx\n:\n\n\nhelm install stable/nginx-ingress --name my-nginx\n\n\n\n\n\nIf the kubernetes cluster has RBAC enabled, then run:\n\n\nhelm install stable/nginx-ingress --name my-nginx --set rbac.create=true\n\n\n\n\n\nDetect installed version:\n\n\nPOD_NAME=$(kubectl get pods -l app=nginx-ingress -o jsonpath='{.items[0].metadata.name}')\n\n\nkubectl exec -it $POD_NAME -- /nginx-ingress-controller --version", "title": "Installation Guide" }, { @@ -27,7 +27,7 @@ }, { "location": "/deploy/#contents", - "text": "Generic Deployment Mandatory command Provider Specific Steps Docker for Mac minikube AWS GCE - GKE Azure Baremetal Verify installation Detect installed version Using Helm", + "text": "Generic Deployment Mandatory command Provider Specific Steps Docker for Mac minikube AWS GCE - GKE Azure Bare-metal Verify installation Detect installed version Using Helm", "title": "Contents" }, { @@ -81,9 +81,9 @@ "title": "Azure" }, { - "location": "/deploy/#baremetal", - "text": "Using NodePort : kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/baremetal/service-nodeport.yaml", - "title": "Baremetal" + "location": "/deploy/#bare-metal", + "text": "Using NodePort : kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/baremetal/service-nodeport.yaml Tip For extended notes regarding deployments on bare-metal, see Bare-metal considerations .", + "title": "Bare-metal" }, { "location": "/deploy/#verify-installation", @@ -100,6 +100,31 @@ "text": "NGINX Ingress controller can be installed via Helm using the chart stable/nginx-ingress from the official charts repository. \nTo install the chart with the release name my-nginx : helm install stable/nginx-ingress --name my-nginx If the kubernetes cluster has RBAC enabled, then run: helm install stable/nginx-ingress --name my-nginx --set rbac.create=true Detect installed version: POD_NAME=$(kubectl get pods -l app=nginx-ingress -o jsonpath='{.items[0].metadata.name}') kubectl exec -it $POD_NAME -- /nginx-ingress-controller --version", "title": "Using Helm" }, + { + "location": "/deploy/baremetal/", + "text": "Bare-metal considerations\n\u00b6\n\n\nIn traditional \ncloud\n environments, where network load balancers are available on-demand, a single Kubernetes manifest\nsuffices to provide a single point of contact to the NGINX Ingress controller to external clients and, indirectly, to\nany application running inside the cluster. \nBare-metal\n environments lack this commodity, requiring a slightly\ndifferent setup to offer the same kind of access to external consumers.\n\n\n\n\n\n\nThe rest of this document describes a few recommended approaches to deploying the NGINX Ingress controller inside a\nKubernetes cluster running on bare-metal.\n\n\nOver a NodePort Service\n\u00b6\n\n\nDue to its simplicity, this is the setup a user will deploy by default when following the steps described in the\n\ninstallation guide\n.\n\n\n\n\nInfo\n\n\nA Service of type \nNodePort\n exposes, via the \nkube-proxy\n component, the \nsame unprivileged\n port (default:\n30000-32767) on every Kubernetes node, masters included. For more information, see \nServices\n.\n\n\n\n\nIn this configuration, the NGINX container remains isolated from the host network. As a result, it can safely bind to\nany port, including the standard HTTP ports 80 and 443. However, due to the container namespace isolation, a client\nlocated outside the cluster network (e.g. on the public internet) is not able to access Ingress hosts directly on ports\n80 and 443. Instead, the external client must append the NodePort allocated to the \ningress-nginx\n Service to HTTP\nrequests.\n\n\n\n\n\n\nExample\n\n\nGiven the NodePort \n30100\n allocated to the \ningress-nginx\n Service\n\n\n$\n kubectl -n ingress-nginx get svc\n\nNAME TYPE CLUSTER-IP PORT(S)\n\n\ndefault-http-backend ClusterIP 10.0.64.249 80/TCP\n\n\ningress-nginx NodePort 10.0.220.217 80:30100/TCP,443:30101/TCP\n\n\n\n\n\nand a Kubernetes node with the public IP address \n203.0.113.2\n (the external IP is added as an example, in most\nbare-metal environments this value is )\n\n\n$\n kubectl describe node \n\nNAME STATUS ROLES EXTERNAL-IP\n\n\nhost-1 Ready master 203.0.113.1\n\n\nhost-2 Ready node 203.0.113.2\n\n\nhost-3 Ready node 203.0.113.3\n\n\n\n\n\na client would reach an Ingress with \nhost\n:\n \nmyapp\n.\nexample\n.\ncom\n at \nhttp://myapp.example.com:30100\n, where the\nmyapp.example.com subdomain resolves to the 203.0.113.2 IP address.\n\n\n\n\n\n\nImpact on the host system\n\n\nWhile it may sound tempting to reconfigure the NodePort range using the \n--service-node-port-range\n API server flag\nto include unprivileged ports and be able to expose ports 80 and 443, doing so may result in unexpected issues\nincluding (but not limited to) the use of ports otherwise reserved to system daemons and the necessity to grant\n\nkube-proxy\n privileges it may otherwise not require.\n\n\nThis practice is therefore \ndiscouraged\n. See the other approaches proposed in this page for alternatives.\n\n\n\n\nThis approach has a few other limitations one ought to be aware of:\n\n\n\n\nSource IP address\n\n\n\n\nServices of type NodePort perform \nsource address translation\n by default. This means the source IP of a\nHTTP request is always \nthe IP address of the Kubernetes node that received the request\n from the perspective of\nNGINX.\n\n\nThe recommended way to preserve the source IP in a NodePort setup is to set the value of the \nexternalTrafficPolicy\n\nfield of the \ningress-nginx\n Service spec to \nLocal\n (\nexample\n).\n\n\n\n\nWarning\n\n\nThis setting effectively \ndrops packets\n sent to Kubernetes nodes which are not running any instance of the NGINX\nIngress controller. Consider \nassigning NGINX Pods to specific nodes\n in order to control on what nodes\nthe NGINX Ingress controller should be scheduled or not scheduled.\n\n\n\n\n\n\nExample\n\n\nIn a Kubernetes cluster composed of 3 nodes (the external IP is added as an example, in most bare-metal environments\nthis value is )\n\n\n$\n kubectl describe node \n\nNAME STATUS ROLES EXTERNAL-IP\n\n\nhost-1 Ready master 203.0.113.1\n\n\nhost-2 Ready node 203.0.113.2\n\n\nhost-3 Ready node 203.0.113.3\n\n\n\n\n\nwith a \nnginx-ingress-controller\n Deployment composed of 2 replicas\n\n\n$\n kubectl -n ingress-nginx get pod -o wide\n\nNAME READY STATUS IP NODE\n\n\ndefault-http-backend-7c5bc89cc9-p86md 1/1 Running 172.17.1.1 host-2\n\n\nnginx-ingress-controller-cf9ff8c96-8vvf8 1/1 Running 172.17.0.3 host-3\n\n\nnginx-ingress-controller-cf9ff8c96-pxsds 1/1 Running 172.17.1.4 host-2\n\n\n\n\n\nRequests sent to \nhost-2\n and \nhost-3\n would be forwarded to NGINX and original client's IP would be preserved,\nwhile requests to \nhost-1\n would get dropped because there is no NGINX replica running on that node.\n\n\n\n\n\n\nIngress status\n\n\n\n\nBecause NodePort Services do not get a LoadBalancerIP assigned by definition, the NGINX Ingress controller \ndoes not\nupdate the status of Ingress objects it manages\n.\n\n\n$\n kubectl get ingress\n\nNAME HOSTS ADDRESS PORTS\n\n\ntest-ingress myapp.example.com 80\n\n\n\n\n\nDespite the fact there is no load balancer providing a public IP address to the NGINX Ingress controller, it is possible\nto force the status update of all managed Ingress objects by setting the \nexternalIPs\n field of the \ningress-nginx\n\nService.\n\n\n\n\nExample\n\n\nGiven the following 3-node Kubernetes cluster (the external IP is added as an example, in most bare-metal\nenvironments this value is )\n\n\n$\n kubectl describe node \n\nNAME STATUS ROLES EXTERNAL-IP\n\n\nhost-1 Ready master 203.0.113.1\n\n\nhost-2 Ready node 203.0.113.2\n\n\nhost-3 Ready node 203.0.113.3\n\n\n\n\n\none could edit the \ningress-nginx\n Service and add the following field to the object spec\n\n\nspec\n:\n\n \nexternalIPs\n:\n\n \n-\n \n203.0.113.1\n\n \n-\n \n203.0.113.2\n\n \n-\n \n203.0.113.3\n\n\n\n\n\nwhich would in turn be reflected on Ingress objects as follows:\n\n\n$\n kubectl get ingress -o wide\n\nNAME HOSTS ADDRESS PORTS\n\n\ntest-ingress myapp.example.com 203.0.113.1,203.0.113.2,203.0.113.3 80\n\n\n\n\n\n\n\n\n\nRedirects\n\n\n\n\nAs NGINX is \nnot aware of the port translation operated by the NodePort Service\n, backend applications are responsible\nfor generating redirect URLs that take into account the URL used by external clients, including the NodePort.\n\n\n\n\nExample\n\n\nRedirects generated by NGINX, for instance HTTP to HTTPS or \ndomain\n to \nwww.domain\n, are generated without\nNodePort:\n\n\n$\n curl http://myapp.example.com:30100\n`\n\n\nHTTP/1.1 308 Permanent Redirect\n\n\nServer: nginx/1.15.2\n\n\nLocation: https://myapp.example.com/ #-> missing NodePort in HTTPS redirect\n\n\n\n\n\n\n\nVia the host network\n\u00b6\n\n\nIn a setup where there is no external load balancer available but using NodePorts is not an option, one can configure\n\ningress-nginx\n Pods to use the network of the host they run on instead of a dedicated network namespace. The benefit of\nthis approach is that the NGINX Ingress controller can bind ports 80 and 443 directly to Kubernetes nodes' network\ninterfaces, without the extra network translation imposed by NodePort Services.\n\n\n\n\nNote\n\n\nThis approach does not leverage any Service object to expose the NGINX Ingress controller. If the \ningress-nginx\n\nService exists in the target cluster, it is \nrecommended to delete it\n.\n\n\n\n\nThis can be achieved by enabling the \nhostNetwork\n option in the Pods' spec.\n\n\ntemplate\n:\n\n \nspec\n:\n\n \nhostNetwork\n:\n \ntrue\n\n\n\n\n\n\n\nSecurity considerations\n\n\nEnabling this option \nexposes every system daemon to the NGINX Ingress controller\n on any network interface,\nincluding the host's loopback. Please evaluate the impact this may have on the security of your system carefully.\n\n\n\n\n\n\nExample\n\n\nConsider this \nnginx-ingress-controller\n Deployment composed of 2 replicas, NGINX Pods inherit from the IP address\nof their host instead of an internal Pod IP.\n\n\n$\n kubectl -n ingress-nginx get pod -o wide\n\nNAME READY STATUS IP NODE\n\n\ndefault-http-backend-7c5bc89cc9-p86md 1/1 Running 172.17.1.1 host-2\n\n\nnginx-ingress-controller-5b4cf5fc6-7lg6c 1/1 Running 203.0.113.3 host-3\n\n\nnginx-ingress-controller-5b4cf5fc6-lzrls 1/1 Running 203.0.113.2 host-2\n\n\n\n\n\n\n\nOne major limitation of this deployment approach is that only \na single NGINX Ingress controller Pod\n may be scheduled\non each cluster node, because binding the same port multiple times on the same network interface is technically\nimpossible. Pods that are unschedulable due to such situation fail with the following event:\n\n\n$\n kubectl -n ingress-nginx describe pod \n\n...\n\n\nEvents:\n\n\n Type Reason From Message\n\n\n ---- ------ ---- -------\n\n\n Warning FailedScheduling default-scheduler 0/3 nodes are available: 3 node(s) didn't have free ports for the requested pod ports.\n\n\n\n\n\nOne way to ensure only schedulable Pods are created is to deploy the NGINX Ingress controller as a \nDaemonSet\n instead\nof a traditional Deployment.\n\n\n\n\nInfo\n\n\nA DaemonSet schedules exactly one type of Pod per cluster node, masters included, unless a node is configured to\n\nrepel those Pods\n. For more information, see \nDaemonSet\n.\n\n\n\n\nBecause most properties of DaemonSet objects are identical to Deployment objects, this documentation page leaves the\nconfiguration of the corresponding manifest at the user's discretion.\n\n\n\n\nLike with NodePorts, this approach has a few quirks it is important to be aware of.\n\n\n\n\nDNS resolution\n\n\n\n\nPods configured with \nhostNetwork\n:\n \ntrue\n do not use the internal DNS resolver (i.e. \nkube-dns\n or \nCoreDNS\n), unless\ntheir \ndnsPolicy\n spec field is set to \nClusterFirstWithHostNet\n. Consider using this setting if NGINX is\nexpected to resolve internal names for any reason.\n\n\n\n\nIngress status\n\n\n\n\nBecause there is no Service exposing the NGINX Ingress controller in a configuration using the host network, the default\n\n--publish-service\n flag used in standard cloud setups \ndoes not apply\n and the status of all Ingress objects remains\nblank.\n\n\n$\n kubectl get ingress\n\nNAME HOSTS ADDRESS PORTS\n\n\ntest-ingress myapp.example.com 80\n\n\n\n\n\nInstead, and because bare-metal nodes usually don't have an ExternalIP, one has to enable the\n\n--report-node-internal-ip-address\n flag, which sets the status of all Ingress objects to the internal IP\naddress of all nodes running the NGINX Ingress controller.\n\n\n\n\nExample\n\n\nGiven a \nnginx-ingress-controller\n DaemonSet composed of 2 replicas\n\n\n$\n kubectl -n ingress-nginx get pod -o wide\n\nNAME READY STATUS IP NODE\n\n\ndefault-http-backend-7c5bc89cc9-p86md 1/1 Running 172.17.1.1 host-2\n\n\nnginx-ingress-controller-5b4cf5fc6-7lg6c 1/1 Running 203.0.113.3 host-3\n\n\nnginx-ingress-controller-5b4cf5fc6-lzrls 1/1 Running 203.0.113.2 host-2\n\n\n\n\n\nthe controller sets the status of all Ingress objects it manages to the following value:\n\n\n$\n kubectl get ingress -o wide\n\nNAME HOSTS ADDRESS PORTS\n\n\ntest-ingress myapp.example.com 203.0.113.2,203.0.113.3 80\n\n\n\n\n\n\n\n\n\nNote\n\n\nAlternatively, it is possible to override the address written to Ingress objects using the\n\n--publish-status-address\n flag. See \nCommand line arguments\n.\n\n\n\n\nUsing a self-provisioned edge\n\u00b6\n\n\nSimilarly to cloud environments, this deployment approach requires an edge network component providing a public\nentrypoint to the Kubernetes cluster. This edge component can be either hardware (e.g. vendor appliance) or software\n(e.g. \nHAproxy\n) and is usually managed outside of the Kubernetes landscape by operations teams.\n\n\nSuch deployment builds upon the NodePort Service described above in \nOver a NodePort Service\n,\nwith one significant difference: external clients do not access cluster nodes directly, only the edge component does.\nThis is particularly suitable for private Kubernetes clusters where none of the nodes has a public IP address.\n\n\nOn the edge side, the only prerequisite is to dedicate a public IP address that forwards all HTTP traffic to Kubernetes\nnodes and/or masters. Incoming traffic on TCP ports 80 and 443 is forwarded to the corresponding HTTP and HTTPS NodePort\non the target nodes as shown in the diagram below:", + "title": "Bare-metal considerations" + }, + { + "location": "/deploy/baremetal/#bare-metal-considerations", + "text": "In traditional cloud environments, where network load balancers are available on-demand, a single Kubernetes manifest\nsuffices to provide a single point of contact to the NGINX Ingress controller to external clients and, indirectly, to\nany application running inside the cluster. Bare-metal environments lack this commodity, requiring a slightly\ndifferent setup to offer the same kind of access to external consumers. The rest of this document describes a few recommended approaches to deploying the NGINX Ingress controller inside a\nKubernetes cluster running on bare-metal.", + "title": "Bare-metal considerations" + }, + { + "location": "/deploy/baremetal/#over-a-nodeport-service", + "text": "Due to its simplicity, this is the setup a user will deploy by default when following the steps described in the installation guide . Info A Service of type NodePort exposes, via the kube-proxy component, the same unprivileged port (default:\n30000-32767) on every Kubernetes node, masters included. For more information, see Services . In this configuration, the NGINX container remains isolated from the host network. As a result, it can safely bind to\nany port, including the standard HTTP ports 80 and 443. However, due to the container namespace isolation, a client\nlocated outside the cluster network (e.g. on the public internet) is not able to access Ingress hosts directly on ports\n80 and 443. Instead, the external client must append the NodePort allocated to the ingress-nginx Service to HTTP\nrequests. Example Given the NodePort 30100 allocated to the ingress-nginx Service $ kubectl -n ingress-nginx get svc NAME TYPE CLUSTER-IP PORT(S) default-http-backend ClusterIP 10.0.64.249 80/TCP ingress-nginx NodePort 10.0.220.217 80:30100/TCP,443:30101/TCP and a Kubernetes node with the public IP address 203.0.113.2 (the external IP is added as an example, in most\nbare-metal environments this value is ) $ kubectl describe node NAME STATUS ROLES EXTERNAL-IP host-1 Ready master 203.0.113.1 host-2 Ready node 203.0.113.2 host-3 Ready node 203.0.113.3 a client would reach an Ingress with host : myapp . example . com at http://myapp.example.com:30100 , where the\nmyapp.example.com subdomain resolves to the 203.0.113.2 IP address. Impact on the host system While it may sound tempting to reconfigure the NodePort range using the --service-node-port-range API server flag\nto include unprivileged ports and be able to expose ports 80 and 443, doing so may result in unexpected issues\nincluding (but not limited to) the use of ports otherwise reserved to system daemons and the necessity to grant kube-proxy privileges it may otherwise not require. This practice is therefore discouraged . See the other approaches proposed in this page for alternatives. This approach has a few other limitations one ought to be aware of: Source IP address Services of type NodePort perform source address translation by default. This means the source IP of a\nHTTP request is always the IP address of the Kubernetes node that received the request from the perspective of\nNGINX. The recommended way to preserve the source IP in a NodePort setup is to set the value of the externalTrafficPolicy \nfield of the ingress-nginx Service spec to Local ( example ). Warning This setting effectively drops packets sent to Kubernetes nodes which are not running any instance of the NGINX\nIngress controller. Consider assigning NGINX Pods to specific nodes in order to control on what nodes\nthe NGINX Ingress controller should be scheduled or not scheduled. Example In a Kubernetes cluster composed of 3 nodes (the external IP is added as an example, in most bare-metal environments\nthis value is ) $ kubectl describe node NAME STATUS ROLES EXTERNAL-IP host-1 Ready master 203.0.113.1 host-2 Ready node 203.0.113.2 host-3 Ready node 203.0.113.3 with a nginx-ingress-controller Deployment composed of 2 replicas $ kubectl -n ingress-nginx get pod -o wide NAME READY STATUS IP NODE default-http-backend-7c5bc89cc9-p86md 1/1 Running 172.17.1.1 host-2 nginx-ingress-controller-cf9ff8c96-8vvf8 1/1 Running 172.17.0.3 host-3 nginx-ingress-controller-cf9ff8c96-pxsds 1/1 Running 172.17.1.4 host-2 Requests sent to host-2 and host-3 would be forwarded to NGINX and original client's IP would be preserved,\nwhile requests to host-1 would get dropped because there is no NGINX replica running on that node. Ingress status Because NodePort Services do not get a LoadBalancerIP assigned by definition, the NGINX Ingress controller does not\nupdate the status of Ingress objects it manages . $ kubectl get ingress NAME HOSTS ADDRESS PORTS test-ingress myapp.example.com 80 Despite the fact there is no load balancer providing a public IP address to the NGINX Ingress controller, it is possible\nto force the status update of all managed Ingress objects by setting the externalIPs field of the ingress-nginx \nService. Example Given the following 3-node Kubernetes cluster (the external IP is added as an example, in most bare-metal\nenvironments this value is ) $ kubectl describe node NAME STATUS ROLES EXTERNAL-IP host-1 Ready master 203.0.113.1 host-2 Ready node 203.0.113.2 host-3 Ready node 203.0.113.3 one could edit the ingress-nginx Service and add the following field to the object spec spec : \n externalIPs : \n - 203.0.113.1 \n - 203.0.113.2 \n - 203.0.113.3 which would in turn be reflected on Ingress objects as follows: $ kubectl get ingress -o wide NAME HOSTS ADDRESS PORTS test-ingress myapp.example.com 203.0.113.1,203.0.113.2,203.0.113.3 80 Redirects As NGINX is not aware of the port translation operated by the NodePort Service , backend applications are responsible\nfor generating redirect URLs that take into account the URL used by external clients, including the NodePort. Example Redirects generated by NGINX, for instance HTTP to HTTPS or domain to www.domain , are generated without\nNodePort: $ curl http://myapp.example.com:30100 ` HTTP/1.1 308 Permanent Redirect Server: nginx/1.15.2 Location: https://myapp.example.com/ #-> missing NodePort in HTTPS redirect", + "title": "Over a NodePort Service" + }, + { + "location": "/deploy/baremetal/#via-the-host-network", + "text": "In a setup where there is no external load balancer available but using NodePorts is not an option, one can configure ingress-nginx Pods to use the network of the host they run on instead of a dedicated network namespace. The benefit of\nthis approach is that the NGINX Ingress controller can bind ports 80 and 443 directly to Kubernetes nodes' network\ninterfaces, without the extra network translation imposed by NodePort Services. Note This approach does not leverage any Service object to expose the NGINX Ingress controller. If the ingress-nginx \nService exists in the target cluster, it is recommended to delete it . This can be achieved by enabling the hostNetwork option in the Pods' spec. template : \n spec : \n hostNetwork : true Security considerations Enabling this option exposes every system daemon to the NGINX Ingress controller on any network interface,\nincluding the host's loopback. Please evaluate the impact this may have on the security of your system carefully. Example Consider this nginx-ingress-controller Deployment composed of 2 replicas, NGINX Pods inherit from the IP address\nof their host instead of an internal Pod IP. $ kubectl -n ingress-nginx get pod -o wide NAME READY STATUS IP NODE default-http-backend-7c5bc89cc9-p86md 1/1 Running 172.17.1.1 host-2 nginx-ingress-controller-5b4cf5fc6-7lg6c 1/1 Running 203.0.113.3 host-3 nginx-ingress-controller-5b4cf5fc6-lzrls 1/1 Running 203.0.113.2 host-2 One major limitation of this deployment approach is that only a single NGINX Ingress controller Pod may be scheduled\non each cluster node, because binding the same port multiple times on the same network interface is technically\nimpossible. Pods that are unschedulable due to such situation fail with the following event: $ kubectl -n ingress-nginx describe pod ... Events: Type Reason From Message ---- ------ ---- ------- Warning FailedScheduling default-scheduler 0/3 nodes are available: 3 node(s) didn't have free ports for the requested pod ports. One way to ensure only schedulable Pods are created is to deploy the NGINX Ingress controller as a DaemonSet instead\nof a traditional Deployment. Info A DaemonSet schedules exactly one type of Pod per cluster node, masters included, unless a node is configured to repel those Pods . For more information, see DaemonSet . Because most properties of DaemonSet objects are identical to Deployment objects, this documentation page leaves the\nconfiguration of the corresponding manifest at the user's discretion. Like with NodePorts, this approach has a few quirks it is important to be aware of. DNS resolution Pods configured with hostNetwork : true do not use the internal DNS resolver (i.e. kube-dns or CoreDNS ), unless\ntheir dnsPolicy spec field is set to ClusterFirstWithHostNet . Consider using this setting if NGINX is\nexpected to resolve internal names for any reason. Ingress status Because there is no Service exposing the NGINX Ingress controller in a configuration using the host network, the default --publish-service flag used in standard cloud setups does not apply and the status of all Ingress objects remains\nblank. $ kubectl get ingress NAME HOSTS ADDRESS PORTS test-ingress myapp.example.com 80 Instead, and because bare-metal nodes usually don't have an ExternalIP, one has to enable the --report-node-internal-ip-address flag, which sets the status of all Ingress objects to the internal IP\naddress of all nodes running the NGINX Ingress controller. Example Given a nginx-ingress-controller DaemonSet composed of 2 replicas $ kubectl -n ingress-nginx get pod -o wide NAME READY STATUS IP NODE default-http-backend-7c5bc89cc9-p86md 1/1 Running 172.17.1.1 host-2 nginx-ingress-controller-5b4cf5fc6-7lg6c 1/1 Running 203.0.113.3 host-3 nginx-ingress-controller-5b4cf5fc6-lzrls 1/1 Running 203.0.113.2 host-2 the controller sets the status of all Ingress objects it manages to the following value: $ kubectl get ingress -o wide NAME HOSTS ADDRESS PORTS test-ingress myapp.example.com 203.0.113.2,203.0.113.3 80 Note Alternatively, it is possible to override the address written to Ingress objects using the --publish-status-address flag. See Command line arguments .", + "title": "Via the host network" + }, + { + "location": "/deploy/baremetal/#using-a-self-provisioned-edge", + "text": "Similarly to cloud environments, this deployment approach requires an edge network component providing a public\nentrypoint to the Kubernetes cluster. This edge component can be either hardware (e.g. vendor appliance) or software\n(e.g. HAproxy ) and is usually managed outside of the Kubernetes landscape by operations teams. Such deployment builds upon the NodePort Service described above in Over a NodePort Service ,\nwith one significant difference: external clients do not access cluster nodes directly, only the edge component does.\nThis is particularly suitable for private Kubernetes clusters where none of the nodes has a public IP address. On the edge side, the only prerequisite is to dedicate a public IP address that forwards all HTTP traffic to Kubernetes\nnodes and/or masters. Incoming traffic on TCP ports 80 and 443 is forwarded to the corresponding HTTP and HTTPS NodePort\non the target nodes as shown in the diagram below:", + "title": "Using a self-provisioned edge" + }, { "location": "/deploy/rbac/", "text": "Role Based Access Control (RBAC)\n\u00b6\n\n\nOverview\n\u00b6\n\n\nThis example applies to nginx-ingress-controllers being deployed in an environment with RBAC enabled.\n\n\nRole Based Access Control is comprised of four layers:\n\n\n\n\nClusterRole\n - permissions assigned to a role that apply to an entire cluster\n\n\nClusterRoleBinding\n - binding a ClusterRole to a specific account\n\n\nRole\n - permissions assigned to a role that apply to a specific namespace\n\n\nRoleBinding\n - binding a Role to a specific account\n\n\n\n\nIn order for RBAC to be applied to an nginx-ingress-controller, that controller\nshould be assigned to a \nServiceAccount\n. That \nServiceAccount\n should be\nbound to the \nRole\ns and \nClusterRole\ns defined for the nginx-ingress-controller.\n\n\nService Accounts created in this example\n\u00b6\n\n\nOne ServiceAccount is created in this example, \nnginx-ingress-serviceaccount\n.\n\n\nPermissions Granted in this example\n\u00b6\n\n\nThere are two sets of permissions defined in this example. Cluster-wide\npermissions defined by the \nClusterRole\n named \nnginx-ingress-clusterrole\n, and\nnamespace specific permissions defined by the \nRole\n named \nnginx-ingress-role\n.\n\n\nCluster Permissions\n\u00b6\n\n\nThese permissions are granted in order for the nginx-ingress-controller to be\nable to function as an ingress across the cluster. These permissions are\ngranted to the ClusterRole named \nnginx-ingress-clusterrole\n\n\n\n\nconfigmaps\n, \nendpoints\n, \nnodes\n, \npods\n, \nsecrets\n: list, watch\n\n\nnodes\n: get\n\n\nservices\n, \ningresses\n: get, list, watch\n\n\nevents\n: create, patch\n\n\ningresses/status\n: update\n\n\n\n\nNamespace Permissions\n\u00b6\n\n\nThese permissions are granted specific to the nginx-ingress namespace. These\npermissions are granted to the Role named \nnginx-ingress-role\n\n\n\n\nconfigmaps\n, \npods\n, \nsecrets\n: get\n\n\nendpoints\n: get\n\n\n\n\nFurthermore to support leader-election, the nginx-ingress-controller needs to\nhave access to a \nconfigmap\n using the resourceName \ningress-controller-leader-nginx\n\n\n\n\nNote that resourceNames can NOT be used to limit requests using the \u201ccreate\u201d\nverb because authorizers only have access to information that can be obtained\nfrom the request URL, method, and headers (resource names in a \u201ccreate\u201d request\nare part of the request body).\n\n\n\n\n\n\nconfigmaps\n: get, update (for resourceName \ningress-controller-leader-nginx\n)\n\n\nconfigmaps\n: create\n\n\n\n\nThis resourceName is the concatenation of the \nelection-id\n and the\n\ningress-class\n as defined by the ingress-controller, which defaults to:\n\n\n\n\nelection-id\n: \ningress-controller-leader\n\n\ningress-class\n: \nnginx\n\n\nresourceName\n : \n-\n\n\n\n\nPlease adapt accordingly if you overwrite either parameter when launching the\nnginx-ingress-controller.\n\n\nBindings\n\u00b6\n\n\nThe ServiceAccount \nnginx-ingress-serviceaccount\n is bound to the Role\n\nnginx-ingress-role\n and the ClusterRole \nnginx-ingress-clusterrole\n.\n\n\nThe serviceAccountName associated with the containers in the deployment must\nmatch the serviceAccount. The namespace references in the Deployment metadata, \ncontainer arguments, and POD_NAMESPACE should be in the nginx-ingress namespace.", @@ -142,7 +167,7 @@ }, { "location": "/deploy/upgrade/", - "text": "Upgrading\n\u00b6\n\n\n\n\nImportant\n\n\nNo matter the method you use for upgrading, \nif you use template overrides,\nmake sure your templates are compatible with the new version of ingress-nginx\n.\n\n\n\n\nWithout Helm\n\u00b6\n\n\nTo upgrade your ingress-nginx installation, it should be enough to change the version of the image\nin the controller Deployment.\n\n\nI.e. if your deployment resource looks like (partial example):\n\n\nkind\n:\n \nDeployment\n\n\nmetadata\n:\n\n \nname\n:\n \nnginx-ingress-controller\n\n \nnamespace\n:\n \ningress-nginx\n\n\nspec\n:\n\n \nreplicas\n:\n \n1\n\n \nselector\n:\n \n...\n\n \ntemplate\n:\n\n \nmetadata\n:\n \n...\n\n \nspec\n:\n\n \ncontainers\n:\n\n \n-\n \nname\n:\n \nnginx-ingress-controller\n\n \nimage\n:\n \nquay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.9.0\n\n \nargs\n:\n \n...\n\n\n\n\n\n\nsimply change the \n0.9.0\n tag to the version you wish to upgrade to.\nThe easiest way to do this is e.g. (do note you may need to change the name parameter according to your installation):\n\n\nkubectl set image deployment/nginx-ingress-controller \\\n nginx-ingress-controller=nginx:quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.18.0\n\n\n\n\n\nFor interactive editing, use \nkubectl edit deployment nginx-ingress-controller\n.\n\n\nWith Helm\n\u00b6\n\n\nIf you installed ingress-nginx using the Helm command in the deployment docs so its name is \nngx-ingress\n,\nyou should be able to upgrade using\n\n\nhelm upgrade --reuse-values ngx-ingress stable/nginx-ingress", + "text": "Upgrading\n\u00b6\n\n\n\n\nImportant\n\n\nNo matter the method you use for upgrading, \nif you use template overrides,\nmake sure your templates are compatible with the new version of ingress-nginx\n.\n\n\n\n\nWithout Helm\n\u00b6\n\n\nTo upgrade your ingress-nginx installation, it should be enough to change the version of the image\nin the controller Deployment.\n\n\nI.e. if your deployment resource looks like (partial example):\n\n\nkind\n:\n \nDeployment\n\n\nmetadata\n:\n\n \nname\n:\n \nnginx-ingress-controller\n\n \nnamespace\n:\n \ningress-nginx\n\n\nspec\n:\n\n \nreplicas\n:\n \n1\n\n \nselector\n:\n \n...\n\n \ntemplate\n:\n\n \nmetadata\n:\n \n...\n\n \nspec\n:\n\n \ncontainers\n:\n\n \n-\n \nname\n:\n \nnginx-ingress-controller\n\n \nimage\n:\n \nquay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.9.0\n\n \nargs\n:\n \n...\n\n\n\n\n\nsimply change the \n0.9.0\n tag to the version you wish to upgrade to.\nThe easiest way to do this is e.g. (do note you may need to change the name parameter according to your installation):\n\n\nkubectl set image deployment/nginx-ingress-controller \\\n nginx-ingress-controller=nginx:quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.18.0\n\n\n\n\nFor interactive editing, use \nkubectl edit deployment nginx-ingress-controller\n.\n\n\nWith Helm\n\u00b6\n\n\nIf you installed ingress-nginx using the Helm command in the deployment docs so its name is \nngx-ingress\n,\nyou should be able to upgrade using\n\n\nhelm upgrade --reuse-values ngx-ingress stable/nginx-ingress", "title": "Upgrading" }, { @@ -172,7 +197,7 @@ }, { "location": "/user-guide/nginx-configuration/annotations/", - "text": "Annotations\n\u00b6\n\n\nYou can add these Kubernetes annotations to specific Ingress objects to customize their behavior.\n\n\n\n\nTip\n\n\nAnnotation keys and values can only be strings.\nOther types, such as boolean or numeric values must be quoted,\ni.e. \n\"true\"\n, \n\"false\"\n, \n\"100\"\n.\n\n\n\n\n\n\nNote\n\n\nThe annotation prefix can be changed using the\n\n--annotations-prefix\n command line argument\n,\nbut the default is \nnginx.ingress.kubernetes.io\n, as described in the\ntable below.\n\n\n\n\n\n\n\n\n\n\nName\n\n\ntype\n\n\n\n\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/add-base-url\n\n\n\"true\" or \"false\"\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/app-root\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/affinity\n\n\ncookie\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/auth-realm\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/auth-secret\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/auth-type\n\n\nbasic or digest\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/auth-tls-secret\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/auth-tls-verify-depth\n\n\nnumber\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/auth-tls-verify-client\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/auth-tls-error-page\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/auth-tls-pass-certificate-to-upstream\n\n\n\"true\" or \"false\"\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/auth-url\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/backend-protocol\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/base-url-scheme\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/client-body-buffer-size\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/configuration-snippet\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/default-backend\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/enable-cors\n\n\n\"true\" or \"false\"\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/cors-allow-origin\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/cors-allow-methods\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/cors-allow-headers\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/cors-allow-credentials\n\n\n\"true\" or \"false\"\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/cors-max-age\n\n\nnumber\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/force-ssl-redirect\n\n\n\"true\" or \"false\"\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/from-to-www-redirect\n\n\n\"true\" or \"false\"\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/grpc-backend\n\n\n\"true\" or \"false\"\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/limit-connections\n\n\nnumber\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/limit-rps\n\n\nnumber\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/permanent-redirect\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/permanent-redirect-code\n\n\nnumber\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/proxy-body-size\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/proxy-cookie-domain\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/proxy-connect-timeout\n\n\nnumber\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/proxy-send-timeout\n\n\nnumber\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/proxy-read-timeout\n\n\nnumber\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/proxy-next-upstream\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/proxy-next-upstream-tries\n\n\nnumber\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/proxy-request-buffering\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/proxy-redirect-from\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/proxy-redirect-to\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/rewrite-log\n\n\nURI\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/rewrite-target\n\n\nURI\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/secure-backends\n\n\n\"true\" or \"false\"\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/secure-verify-ca-secret\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/server-alias\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/server-snippet\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/service-upstream\n\n\n\"true\" or \"false\"\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/session-cookie-name\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/session-cookie-hash\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/ssl-redirect\n\n\n\"true\" or \"false\"\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/ssl-passthrough\n\n\n\"true\" or \"false\"\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/upstream-max-fails\n\n\nnumber\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/upstream-fail-timeout\n\n\nnumber\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/upstream-hash-by\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/load-balance\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/upstream-vhost\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/whitelist-source-range\n\n\nCIDR\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/proxy-buffering\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/proxy-buffer-size\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/ssl-ciphers\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/connection-proxy-header\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/enable-access-log\n\n\n\"true\" or \"false\"\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/lua-resty-waf\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/lua-resty-waf-debug\n\n\n\"true\" or \"false\"\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/lua-resty-waf-ignore-rulesets\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/lua-resty-waf-extra-rules\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/enable-influxdb\n\n\n\"true\" or \"false\"\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/influxdb-measurement\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/influxdb-port\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/influxdb-host\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/influxdb-server-name\n\n\nstring\n\n\n\n\n\n\n\n\nRewrite\n\u00b6\n\n\nIn some scenarios the exposed URL in the backend service differs from the specified path in the Ingress rule. Without a rewrite any request will return 404.\nSet the annotation \nnginx.ingress.kubernetes.io/rewrite-target\n to the path expected by the service.\n\n\nIf the application contains relative links it is possible to add an additional annotation \nnginx.ingress.kubernetes.io/add-base-url\n that will prepend a \nbase\n tag\n in the header of the returned HTML from the backend.\n\n\nIf the scheme of \nbase\n tag\n need to be specific, set the annotation \nnginx.ingress.kubernetes.io/base-url-scheme\n to the scheme such as \nhttp\n and \nhttps\n.\n\n\nIf the Application Root is exposed in a different path and needs to be redirected, set the annotation \nnginx.ingress.kubernetes.io/app-root\n to redirect requests for \n/\n.\n\n\n\n\nExample\n\n\nPlease check the \nrewrite\n example.\n\n\n\n\nSession Affinity\n\u00b6\n\n\nThe annotation \nnginx.ingress.kubernetes.io/affinity\n enables and sets the affinity type in all Upstreams of an Ingress. This way, a request will always be directed to the same upstream server.\nThe only affinity type available for NGINX is \ncookie\n.\n\n\n\n\nExample\n\n\nPlease check the \naffinity\n example.\n\n\n\n\nCookie affinity\n\u00b6\n\n\nIf you use the \ncookie\n affinity type you can also specify the name of the cookie that will be used to route the requests with the annotation \nnginx.ingress.kubernetes.io/session-cookie-name\n. The default is to create a cookie named 'INGRESSCOOKIE'.\n\n\nIn case of NGINX the annotation \nnginx.ingress.kubernetes.io/session-cookie-hash\n defines which algorithm will be used to hash the used upstream. Default value is \nmd5\n and possible values are \nmd5\n, \nsha1\n and \nindex\n.\n\n\n\n\nAttention\n\n\nThe \nindex\n option is not an actual hash; an in-memory index is used instead, which has less overhead.\nHowever, with \nindex\n, matching against a changing upstream server list is inconsistent.\nSo, at reload, if upstream servers have changed, index values are not guaranteed to correspond to the same server as before!\n\nUse \nindex\n with caution\n and only if you need to!\n\n\n\n\nIn NGINX this feature is implemented by the third party module \nnginx-sticky-module-ng\n. The workflow used to define which upstream server will be used is explained \nhere\n\n\nAuthentication\n\u00b6\n\n\nIs possible to add authentication adding additional annotations in the Ingress rule. The source of the authentication is a secret that contains usernames and passwords inside the key \nauth\n.\n\n\nThe annotations are:\n\n\nnginx.ingress.kubernetes.io/auth-type: [basic|digest]\n\n\n\n\n\nIndicates the \nHTTP Authentication Type: Basic or Digest Access Authentication\n.\n\n\nnginx.ingress.kubernetes.io/auth-secret: secretName\n\n\n\n\n\nThe name of the Secret that contains the usernames and passwords which are granted access to the \npath\ns defined in the Ingress rules.\nThis annotation also accepts the alternative form \"namespace/secretName\", in which case the Secret lookup is performed in the referenced namespace instead of the Ingress namespace.\n\n\nnginx.ingress.kubernetes.io/auth-realm: \"realm string\"\n\n\n\n\n\n\n\nExample\n\n\nPlease check the \nauth\n example.\n\n\n\n\nCustom NGINX upstream checks\n\u00b6\n\n\nNGINX exposes some flags in the \nupstream configuration\n that enable the configuration of each server in the upstream. The Ingress controller allows custom \nmax_fails\n and \nfail_timeout\n parameters in a global context using \nupstream-max-fails\n and \nupstream-fail-timeout\n in the NGINX ConfigMap or in a particular Ingress rule. \nupstream-max-fails\n defaults to 0. This means NGINX will respect the container's \nreadinessProbe\n if it is defined. If there is no probe and no values for \nupstream-max-fails\n NGINX will continue to send traffic to the container.\n\n\n\n\nTip\n\n\nWith the default configuration NGINX will not health check your backends. Whenever the endpoints controller notices a readiness probe failure, that pod's IP will be removed from the list of endpoints. This will trigger the NGINX controller to also remove it from the upstreams.**\n\n\n\n\nTo use custom values in an Ingress rule define these annotations:\n\n\nnginx.ingress.kubernetes.io/upstream-max-fails\n: number of unsuccessful attempts to communicate with the server that should occur in the duration set by the \nupstream-fail-timeout\n parameter to consider the server unavailable.\n\n\nnginx.ingress.kubernetes.io/upstream-fail-timeout\n: time in seconds during which the specified number of unsuccessful attempts to communicate with the server should occur to consider the server unavailable. This is also the period of time the server will be considered unavailable.\n\n\nIn NGINX, backend server pools are called \"\nupstreams\n\". Each upstream contains the endpoints for a service. An upstream is created for each service that has Ingress rules defined.\n\n\n\n\nAttention\n\n\nAll Ingress rules using the same service will use the same upstream.\n\nOnly one of the Ingress rules should define annotations to configure the upstream servers.\n\n\n\n\n\n\nExample\n\n\nPlease check the \ncustom upstream check\n example.\n\n\n\n\nCustom NGINX upstream hashing\n\u00b6\n\n\nNGINX supports load balancing by client-server mapping based on \nconsistent hashing\n for a given key. The key can contain text, variables or any combination thereof. This feature allows for request stickiness other than client IP or cookies. The \nketama\n consistent hashing method will be used which ensures only a few keys would be remapped to different servers on upstream group changes.\n\n\nTo enable consistent hashing for a backend:\n\n\nnginx.ingress.kubernetes.io/upstream-hash-by\n: the nginx variable, text value or any combination thereof to use for consistent hashing. For example \nnginx.ingress.kubernetes.io/upstream-hash-by: \"$request_uri\"\n to consistently hash upstream requests by the current request URI.\n\n\nCustom NGINX load balancing\n\u00b6\n\n\nThis is similar to (https://github.com/kubernetes/ingress-nginx/blob/master/docs/user-guide/nginx-configuration/configmap.md#load-balance) but configures load balancing algorithm per ingress.\n\n\n\n\nNote that \nnginx.ingress.kubernetes.io/upstream-hash-by\n takes preference over this. If this and \nnginx.ingress.kubernetes.io/upstream-hash-by\n are not set then we fallback to using globally configured load balancing algorithm.\n\n\n\n\nCustom NGINX upstream vhost\n\u00b6\n\n\nThis configuration setting allows you to control the value for host in the following statement: \nproxy_set_header Host $host\n, which forms part of the location block. This is useful if you need to call the upstream server by something other than \n$host\n.\n\n\nClient Certificate Authentication\n\u00b6\n\n\nIt is possible to enable Client Certificate Authentication using additional annotations in Ingress Rule.\n\n\nThe annotations are:\n\n\n\n\nnginx.ingress.kubernetes.io/auth-tls-secret: secretName\n:\n The name of the Secret that contains the full Certificate Authority chain \nca.crt\n that is enabled to authenticate against this Ingress.\n This annotation also accepts the alternative form \"namespace/secretName\", in which case the Secret lookup is performed in the referenced namespace instead of the Ingress namespace.\n\n\nnginx.ingress.kubernetes.io/auth-tls-verify-depth\n:\n The validation depth between the provided client certificate and the Certification Authority chain.\n\n\nnginx.ingress.kubernetes.io/auth-tls-verify-client\n:\n Enables verification of client certificates.\n\n\nnginx.ingress.kubernetes.io/auth-tls-error-page\n:\n The URL/Page that user should be redirected in case of a Certificate Authentication Error\n\n\nnginx.ingress.kubernetes.io/auth-tls-pass-certificate-to-upstream\n:\n Indicates if the received certificates should be passed or not to the upstream server. By default this is disabled.\n\n\n\n\n\n\nExample\n\n\nPlease check the \nclient-certs\n example.\n\n\n\n\n\n\nAttention\n\n\nTLS with Client Authentication is \nnot\n possible in Cloudflare and might result in unexpected behavior.\n\n\nCloudflare only allows Authenticated Origin Pulls and is required to use their own certificate: \nhttps://blog.cloudflare.com/protecting-the-origin-with-tls-authenticated-origin-pulls/\n\n\nOnly Authenticated Origin Pulls are allowed and can be configured by following their tutorial: \nhttps://support.cloudflare.com/hc/en-us/articles/204494148-Setting-up-NGINX-to-use-TLS-Authenticated-Origin-Pulls\n\n\n\n\nConfiguration snippet\n\u00b6\n\n\nUsing this annotation you can add additional configuration to the NGINX location. For example:\n\n\nnginx.ingress.kubernetes.io/configuration-snippet\n:\n \n|\n\n \nmore_set_headers \"Request-Id: $req_id\";\n\n\n\n\n\n\nDefault Backend\n\u00b6\n\n\nThe ingress controller requires a \ndefault backend\n.\nThis service handles the response when the service in the Ingress rule does not have endpoints.\nThis is a global configuration for the ingress controller. In some cases could be required to return a custom content or format. In this scenario we can use the annotation \nnginx.ingress.kubernetes.io/default-backend: \n to specify a custom default backend.\n\n\nEnable CORS\n\u00b6\n\n\nTo enable Cross-Origin Resource Sharing (CORS) in an Ingress rule,\nadd the annotation \nnginx.ingress.kubernetes.io/enable-cors: \"true\"\n.\nThis will add a section in the server location enabling this functionality.\n\n\nCORS can be controlled with the following annotations:\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/cors-allow-methods\n\n controls which methods are accepted.\n This is a multi-valued field, separated by ',' and accepts only letters (upper and lower case).\n Example: \nnginx.ingress.kubernetes.io/cors-allow-methods: \"PUT, GET, POST, OPTIONS\"\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/cors-allow-headers\n\n controls which headers are accepted.\n This is a multi-valued field, separated by ',' and accepts letters, numbers, _ and -.\n Example: \nnginx.ingress.kubernetes.io/cors-allow-headers: \"X-Forwarded-For, X-app123-XPTO\"\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/cors-allow-origin\n\n controls what's the accepted Origin for CORS and defaults to '*'.\n This is a single field value, with the following format: \nhttp(s)://origin-site.com\n or \nhttp(s)://origin-site.com:port\n\n Example: \nnginx.ingress.kubernetes.io/cors-allow-origin: \"https://origin-site.com:4443\"\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/cors-allow-credentials\n\n controls if credentials can be passed during CORS operations.\n Example: \nnginx.ingress.kubernetes.io/cors-allow-credentials: \"true\"\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/cors-max-age\n\n controls how long preflight requests can be cached.\n Example: \nnginx.ingress.kubernetes.io/cors-max-age: 600\n\n\n\n\n\n\n\n\nNote\n\n\nFor more information please see \nhttps://enable-cors.org\n\n\n\n\nServer Alias\n\u00b6\n\n\nTo add Server Aliases to an Ingress rule add the annotation \nnginx.ingress.kubernetes.io/server-alias: \"\"\n.\nThis will create a server with the same configuration, but a different \nserver_name\n as the provided host.\n\n\n\n\nNote\n\n\nA server-alias name cannot conflict with the hostname of an existing server. If it does the server-alias annotation will be ignored.\nIf a server-alias is created and later a new server with the same hostname is created,\nthe new server configuration will take place over the alias configuration.\n\n\n\n\nFor more information please see \nthe \nserver_name\n documentation\n.\n\n\nServer snippet\n\u00b6\n\n\nUsing the annotation \nnginx.ingress.kubernetes.io/server-snippet\n it is possible to add custom configuration in the server configuration block.\n\n\napiVersion\n:\n \nextensions/v1beta1\n\n\nkind\n:\n \nIngress\n\n\nmetadata\n:\n\n \nannotations\n:\n\n \nnginx.ingress.kubernetes.io/server-snippet\n:\n \n|\n\n\nset $agentflag 0;\n\n\n\nif ($http_user_agent ~* \"(Mobile)\" ){\n\n \nset $agentflag 1;\n\n\n}\n\n\n\nif ( $agentflag = 1 ) {\n\n \nreturn 301 https://m.example.com;\n\n\n}\n\n\n\n\n\n\n\n\nAttention\n\n\nThis annotation can be used only once per host.\n\n\n\n\nClient Body Buffer Size\n\u00b6\n\n\nSets buffer size for reading client request body per location. In case the request body is larger than the buffer,\nthe whole body or only its part is written to a temporary file. By default, buffer size is equal to two memory pages.\nThis is 8K on x86, other 32-bit platforms, and x86-64. It is usually 16K on other 64-bit platforms. This annotation is\napplied to each location provided in the ingress rule.\n\n\n\n\nNote\n\n\nThe annotation value must be given in a format understood by Nginx.\n\n\n\n\n\n\nExample\n\n\n\n\nnginx.ingress.kubernetes.io/client-body-buffer-size: \"1000\"\n # 1000 bytes\n\n\nnginx.ingress.kubernetes.io/client-body-buffer-size: 1k\n # 1 kilobyte\n\n\nnginx.ingress.kubernetes.io/client-body-buffer-size: 1K\n # 1 kilobyte\n\n\nnginx.ingress.kubernetes.io/client-body-buffer-size: 1m\n # 1 megabyte\n\n\nnginx.ingress.kubernetes.io/client-body-buffer-size: 1M\n # 1 megabyte\n\n\n\n\n\n\nFor more information please see \nhttp://nginx.org\n\n\nExternal Authentication\n\u00b6\n\n\nTo use an existing service that provides authentication the Ingress rule can be annotated with \nnginx.ingress.kubernetes.io/auth-url\n to indicate the URL where the HTTP request should be sent.\n\n\nnginx.ingress.kubernetes.io/auth-url\n:\n \n\"URL\n \nto\n \nthe\n \nauthentication\n \nservice\"\n\n\n\n\n\n\nAdditionally it is possible to set:\n\n\n\n\nnginx.ingress.kubernetes.io/auth-method\n:\n \n\n to specify the HTTP method to use.\n\n\nnginx.ingress.kubernetes.io/auth-signin\n:\n \n\n to specify the location of the error page.\n\n\nnginx.ingress.kubernetes.io/auth-response-headers\n:\n \n\n to specify headers to pass to backend once authentication request completes.\n\n\nnginx.ingress.kubernetes.io/auth-request-redirect\n:\n \n\n to specify the X-Auth-Request-Redirect header value.\n\n\n\n\n\n\nExample\n\n\nPlease check the \nexternal-auth\n example.\n\n\n\n\nRate limiting\n\u00b6\n\n\nThese annotations define a limit on the connections that can be opened by a single client IP address.\nThis can be used to mitigate \nDDoS Attacks\n.\n\n\n\n\nnginx.ingress.kubernetes.io/limit-connections\n: number of concurrent connections allowed from a single IP address.\n\n\nnginx.ingress.kubernetes.io/limit-rps\n: number of connections that may be accepted from a given IP each second.\n\n\nnginx.ingress.kubernetes.io/limit-rpm\n: number of connections that may be accepted from a given IP each minute.\n\n\nnginx.ingress.kubernetes.io/limit-rate-after\n: sets the initial amount after which the further transmission of a response to a client will be rate limited.\n\n\nnginx.ingress.kubernetes.io/limit-rate\n: rate of request that accepted from a client each second.\n\n\n\n\nYou can specify the client IP source ranges to be excluded from rate-limiting through the \nnginx.ingress.kubernetes.io/limit-whitelist\n annotation. The value is a comma separated list of CIDRs.\n\n\nIf you specify multiple annotations in a single Ingress rule, \nlimit-rpm\n, and then \nlimit-rps\n takes precedence.\n\n\nThe annotation \nnginx.ingress.kubernetes.io/limit-rate\n, \nnginx.ingress.kubernetes.io/limit-rate-after\n define a limit the rate of response transmission to a client. The rate is specified in bytes per second. The zero value disables rate limiting. The limit is set per a request, and so if a client simultaneously opens two connections, the overall rate will be twice as much as the specified limit.\n\n\nTo configure this setting globally for all Ingress rules, the \nlimit-rate-after\n and \nlimit-rate\n value may be set in the \nNGINX ConfigMap\n. if you set the value in ingress annotation will cover global setting.\n\n\nPermanent Redirect\n\u00b6\n\n\nThis annotation allows to return a permanent redirect instead of sending data to the upstream. For example \nnginx.ingress.kubernetes.io/permanent-redirect: https://www.google.com\n would redirect everything to Google.\n\n\nPermanent Redirect Code\n\u00b6\n\n\nThis annotation allows you to modify the status code used for permanent redirects. For example \nnginx.ingress.kubernetes.io/permanent-redirect-code: '308'\n would return your permanent-redirect with a 308.\n\n\nSSL Passthrough\n\u00b6\n\n\nThe annotation \nnginx.ingress.kubernetes.io/ssl-passthrough\n allows to configure TLS termination in the pod and not in NGINX.\n\n\n\n\nAttention\n\n\nUsing the annotation \nnginx.ingress.kubernetes.io/ssl-passthrough\n invalidates all the other available annotations.\nThis is because SSL Passthrough works on level 4 of the OSI stack (TCP), not on the HTTP/HTTPS level.\n\n\n\n\n\n\nAttention\n\n\nThe use of this annotation requires the flag \n--enable-ssl-passthrough\n (By default it is disabled).\n\n\n\n\nSecure backends DEPRECATED (since 0.18.0)\n\u00b6\n\n\nPlease use \nnginx.ingress.kubernetes.io/backend-protocol: \"HTTPS\"\n\n\nBy default NGINX uses plain HTTP to reach the services.\nAdding the annotation \nnginx.ingress.kubernetes.io/secure-backends: \"true\"\n in the Ingress rule changes the protocol to HTTPS.\nIf you want to validate the upstream against a specific certificate, you can create a secret with it and reference the secret with the annotation \nnginx.ingress.kubernetes.io/secure-verify-ca-secret\n.\n\n\n\n\nAttention\n\n\nNote that if an invalid or non-existent secret is given,\nthe ingress controller will ignore the \nsecure-backends\n annotation.\n\n\n\n\nService Upstream\n\u00b6\n\n\nBy default the NGINX ingress controller uses a list of all endpoints (Pod IP/port) in the NGINX upstream configuration.\n\n\nThe \nnginx.ingress.kubernetes.io/service-upstream\n annotation disables that behavior and instead uses a single upstream in NGINX, the service's Cluster IP and port.\n\n\nThis can be desirable for things like zero-downtime deployments as it reduces the need to reload NGINX configuration when Pods come up and down. See issue \n#257\n.\n\n\nKnown Issues\n\u00b6\n\n\nIf the \nservice-upstream\n annotation is specified the following things should be taken into consideration:\n\n\n\n\nSticky Sessions will not work as only round-robin load balancing is supported.\n\n\nThe \nproxy_next_upstream\n directive will not have any effect meaning on error the request will not be dispatched to another upstream.\n\n\n\n\nServer-side HTTPS enforcement through redirect\n\u00b6\n\n\nBy default the controller redirects (308) to HTTPS if TLS is enabled for that ingress.\nIf you want to disable this behavior globally, you can use \nssl-redirect: \"false\"\n in the NGINX \nconfig map\n.\n\n\nTo configure this feature for specific ingress resources, you can use the \nnginx.ingress.kubernetes.io/ssl-redirect: \"false\"\n\nannotation in the particular resource.\n\n\nWhen using SSL offloading outside of cluster (e.g. AWS ELB) it may be useful to enforce a redirect to HTTPS\neven when there is no TLS certificate available.\nThis can be achieved by using the \nnginx.ingress.kubernetes.io/force-ssl-redirect: \"true\"\n annotation in the particular resource.\n\n\nRedirect from/to www.\n\u00b6\n\n\nIn some scenarios is required to redirect from \nwww.domain.com\n to \ndomain.com\n or vice versa.\nTo enable this feature use the annotation \nnginx.ingress.kubernetes.io/from-to-www-redirect: \"true\"\n\n\n\n\nAttention\n\n\nIf at some point a new Ingress is created with a host equal to one of the options (like \ndomain.com\n) the annotation will be omitted.\n\n\n\n\nWhitelist source range\n\u00b6\n\n\nYou can specify allowed client IP source ranges through the \nnginx.ingress.kubernetes.io/whitelist-source-range\n annotation.\nThe value is a comma separated list of \nCIDRs\n, e.g. \n10.0.0.0/24,172.10.0.1\n.\n\n\nTo configure this setting globally for all Ingress rules, the \nwhitelist-source-range\n value may be set in the \nNGINX ConfigMap\n.\n\n\n\n\nNote\n\n\nAdding an annotation to an Ingress rule overrides any global restriction.\n\n\n\n\nCustom timeouts\n\u00b6\n\n\nUsing the configuration configmap it is possible to set the default global timeout for connections to the upstream servers.\nIn some scenarios is required to have different values. To allow this we provide annotations that allows this customization:\n\n\n\n\nnginx.ingress.kubernetes.io/proxy-connect-timeout\n\n\nnginx.ingress.kubernetes.io/proxy-send-timeout\n\n\nnginx.ingress.kubernetes.io/proxy-read-timeout\n\n\nnginx.ingress.kubernetes.io/proxy-next-upstream\n\n\nnginx.ingress.kubernetes.io/proxy-next-upstream-tries\n\n\nnginx.ingress.kubernetes.io/proxy-request-buffering\n\n\n\n\nProxy redirect\n\u00b6\n\n\nWith the annotations \nnginx.ingress.kubernetes.io/proxy-redirect-from\n and \nnginx.ingress.kubernetes.io/proxy-redirect-to\n it is possible to\nset the text that should be changed in the \nLocation\n and \nRefresh\n header fields of a proxied server response (http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_redirect)\n\n\nSetting \"off\" or \"default\" in the annotation \nnginx.ingress.kubernetes.io/proxy-redirect-from\n disables \nnginx.ingress.kubernetes.io/proxy-redirect-to\n,\notherwise, both annotations must be used in unison. Note that each annotation must be a string without spaces.\n\n\nBy default the value of each annotation is \"off\".\n\n\nCustom max body size\n\u00b6\n\n\nFor NGINX, an 413 error will be returned to the client when the size in a request exceeds the maximum allowed size of the client request body. This size can be configured by the parameter \nclient_max_body_size\n.\n\n\nTo configure this setting globally for all Ingress rules, the \nproxy-body-size\n value may be set in the \nNGINX ConfigMap\n.\nTo use custom values in an Ingress rule define these annotation:\n\n\nnginx.ingress.kubernetes.io/proxy-body-size\n:\n \n8m\n\n\n\n\n\n\nProxy cookie domain\n\u00b6\n\n\nSets a text that \nshould be changed in the domain attribute\n of the \"Set-Cookie\" header fields of a proxied server response.\n\n\nTo configure this setting globally for all Ingress rules, the \nproxy-cookie-domain\n value may be set in the \nNGINX ConfigMap\n.\n\n\nProxy buffering\n\u00b6\n\n\nEnable or disable proxy buffering \nproxy_buffering\n.\nBy default proxy buffering is disabled in the NGINX config.\n\n\nTo configure this setting globally for all Ingress rules, the \nproxy-buffering\n value may be set in the \nNGINX ConfigMap\n.\nTo use custom values in an Ingress rule define these annotation:\n\n\nnginx.ingress.kubernetes.io/proxy-buffering\n:\n \n\"on\"\n\n\n\n\n\n\nProxy buffer size\n\u00b6\n\n\nSets the size of the buffer \nproxy_buffer_size\n used for reading the first part of the response received from the proxied server.\nBy default proxy buffer size is set as \"4k\"\n\n\nTo configure this setting globally, set \nproxy-buffer-size\n in \nNGINX ConfigMap\n. To use custom values in an Ingress rule, define this annotation:\n\n\nnginx.ingress.kubernetes.io/proxy-buffer-size\n:\n \n\"8k\"\n\n\n\n\n\n\nSSL ciphers\n\u00b6\n\n\nSpecifies the \nenabled ciphers\n.\n\n\nUsing this annotation will set the \nssl_ciphers\n directive at the server level. This configuration is active for all the paths in the host.\n\n\nnginx.ingress.kubernetes.io/ssl-ciphers\n:\n \n\"ALL:!aNULL:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP\"\n\n\n\n\n\n\nConnection proxy header\n\u00b6\n\n\nUsing this annotation will override the default connection header set by NGINX.\nTo use custom values in an Ingress rule, define the annotation:\n\n\nnginx.ingress.kubernetes.io/connection-proxy-header\n:\n \n\"keep-alive\"\n\n\n\n\n\n\nEnable Access Log\n\u00b6\n\n\nAccess logs are enabled by default, but in some scenarios access logs might be required to be disabled for a given\ningress. To do this, use the annotation:\n\n\nnginx.ingress.kubernetes.io/enable-access-log\n:\n \n\"false\"\n\n\n\n\n\n\nEnable Rewrite Log\n\u00b6\n\n\nRewrite logs are not enabled by default. In some scenarios it could be required to enable NGINX rewrite logs.\nNote that rewrite logs are sent to the error_log file at the notice level. To enable this feature use the annotation:\n\n\nnginx.ingress.kubernetes.io/enable-rewrite-log\n:\n \n\"true\"\n\n\n\n\n\n\nLua Resty WAF\n\u00b6\n\n\nUsing \nlua-resty-waf-*\n annotations we can enable and control the \nlua-resty-waf\n\nWeb Application Firewall per location.\n\n\nFollowing configuration will enable the WAF for the paths defined in the corresponding ingress:\n\n\nnginx.ingress.kubernetes.io/lua-resty-waf\n:\n \n\"active\"\n\n\n\n\n\n\nIn order to run it in debugging mode you can set \nnginx.ingress.kubernetes.io/lua-resty-waf-debug\n to \n\"true\"\n in addition to the above configuration.\nThe other possible values for \nnginx.ingress.kubernetes.io/lua-resty-waf\n are \ninactive\n and \nsimulate\n.\nIn \ninactive\n mode WAF won't do anything, whereas in \nsimulate\n mode it will log a warning message if there's a matching WAF rule for given request. This is useful to debug a rule and eliminate possible false positives before fully deploying it.\n\n\nlua-resty-waf\n comes with predefined set of rules \nhttps://github.com/p0pr0ck5/lua-resty-waf/tree/84b4f40362500dd0cb98b9e71b5875cb1a40f1ad/rules\n that covers ModSecurity CRS.\nYou can use \nnginx.ingress.kubernetes.io/lua-resty-waf-ignore-rulesets\n to ignore a subset of those rulesets. For an example:\n\n\nnginx.ingress.kubernetes.io/lua-resty-waf-ignore-rulesets\n:\n \n\"41000_sqli,\n \n42000_xss\"\n\n\n\n\n\n\nwill ignore the two mentioned rulesets.\n\n\nIt is also possible to configure custom WAF rules per ingress using the \nnginx.ingress.kubernetes.io/lua-resty-waf-extra-rules\n annotation. For an example the following snippet will configure a WAF rule to deny requests with query string value that contains word \nfoo\n:\n\n\nnginx.ingress.kubernetes.io/lua-resty-waf-extra-rules\n:\n \n'[=[\n \n{\n \n\"access\":\n \n[\n \n{\n \n\"actions\":\n \n{\n \n\"disrupt\"\n \n:\n \n\"DENY\"\n \n},\n \n\"id\":\n \n10001,\n \n\"msg\":\n \n\"my\n \ncustom\n \nrule\",\n \n\"operator\":\n \n\"STR_CONTAINS\",\n \n\"pattern\":\n \n\"foo\",\n \n\"vars\":\n \n[\n \n{\n \n\"parse\":\n \n[\n \n\"values\",\n \n1\n \n],\n \n\"type\":\n \n\"REQUEST_ARGS\"\n \n}\n \n]\n \n}\n \n],\n \n\"body_filter\":\n \n[],\n \n\"header_filter\":[]\n \n}\n \n]=]'\n\n\n\n\n\n\nFor details on how to write WAF rules, please refer to \nhttps://github.com/p0pr0ck5/lua-resty-waf\n.\n\n\ngRPC backend DEPRECATED (since 0.18.0)\n\u00b6\n\n\nPlease use \nnginx.ingress.kubernetes.io/backend-protocol: \"GRPC\"\n or \nnginx.ingress.kubernetes.io/backend-protocol: \"GRPCS\"\n\n\nSince NGINX 1.13.10 it is possible to expose \ngRPC services natively\n\n\nYou only need to add the annotation \nnginx.ingress.kubernetes.io/grpc-backend: \"true\"\n to enable this feature.\nAdditionally, if the gRPC service requires TLS, add \nnginx.ingress.kubernetes.io/secure-backends: \"true\"\n.\n\n\n\n\nAttention\n\n\nThis feature requires HTTP2 to work which means we need to expose this service using HTTPS.\nExposing a gRPC service using HTTP is not supported.\n\n\n\n\nInfluxDB\n\u00b6\n\n\nUsing \ninfluxdb-*\n annotations we can monitor requests passing through a Location by sending them to an InfluxDB backend exposing the UDP socket\nusing the \nnginx-influxdb-module\n.\n\n\nnginx.ingress.kubernetes.io/enable-influxdb\n:\n \n\"true\"\n\n\nnginx.ingress.kubernetes.io/influxdb-measurement\n:\n \n\"nginx-reqs\"\n\n\nnginx.ingress.kubernetes.io/influxdb-port\n:\n \n\"8089\"\n\n\nnginx.ingress.kubernetes.io/influxdb-host\n:\n \n\"127.0.0.1\"\n\n\nnginx.ingress.kubernetes.io/influxdb-server-name\n:\n \n\"nginx-ingress\"\n\n\n\n\n\n\nFor the \ninfluxdb-host\n parameter you have two options:\n\n\n\n\nUse an InfluxDB server configured with the \nUDP protocol\n enabled. \n\n\nDeploy Telegraf as a sidecar proxy to the Ingress controller configured to listen UDP with the \nsocket listener input\n and to write using\nanyone of the \noutputs plugins\n like InfluxDB, Apache Kafka,\nPrometheus, etc.. (recommended)\n\n\n\n\nIt's important to remember that there's no DNS resolver at this stage so you will have to configure\nan ip address to \nnginx.ingress.kubernetes.io/influxdb-host\n. If you deploy Influx or Telegraf as sidecar (another container in the same pod) this becomes straightforward since you can directly use \n127.0.0.1\n.\n\n\nBackend Protocol\n\u00b6\n\n\nUsing \nbackend-protocol\n annotations is possible to indicate how NGINX should communicate with the backend service.\nValid Values: HTTP, HTTPS, GRPC, GRPCS and AJP\n\n\nBy default NGINX uses \nHTTP\n.\n\n\nExample:\n\n\nnginx.ingress.kubernetes.io/backend-protocol\n:\n \n\"HTTPS\"", + "text": "Annotations\n\u00b6\n\n\nYou can add these Kubernetes annotations to specific Ingress objects to customize their behavior.\n\n\n\n\nTip\n\n\nAnnotation keys and values can only be strings.\nOther types, such as boolean or numeric values must be quoted,\ni.e. \n\"true\"\n, \n\"false\"\n, \n\"100\"\n.\n\n\n\n\n\n\nNote\n\n\nThe annotation prefix can be changed using the\n\n--annotations-prefix\n command line argument\n,\nbut the default is \nnginx.ingress.kubernetes.io\n, as described in the\ntable below.\n\n\n\n\n\n\n\n\n\n\nName\n\n\ntype\n\n\n\n\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/add-base-url\n\n\n\"true\" or \"false\"\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/app-root\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/affinity\n\n\ncookie\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/auth-realm\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/auth-secret\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/auth-type\n\n\nbasic or digest\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/auth-tls-secret\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/auth-tls-verify-depth\n\n\nnumber\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/auth-tls-verify-client\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/auth-tls-error-page\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/auth-tls-pass-certificate-to-upstream\n\n\n\"true\" or \"false\"\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/auth-url\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/backend-protocol\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/base-url-scheme\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/client-body-buffer-size\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/configuration-snippet\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/default-backend\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/enable-cors\n\n\n\"true\" or \"false\"\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/cors-allow-origin\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/cors-allow-methods\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/cors-allow-headers\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/cors-allow-credentials\n\n\n\"true\" or \"false\"\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/cors-max-age\n\n\nnumber\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/force-ssl-redirect\n\n\n\"true\" or \"false\"\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/from-to-www-redirect\n\n\n\"true\" or \"false\"\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/grpc-backend\n\n\n\"true\" or \"false\"\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/limit-connections\n\n\nnumber\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/limit-rps\n\n\nnumber\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/permanent-redirect\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/permanent-redirect-code\n\n\nnumber\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/proxy-body-size\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/proxy-cookie-domain\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/proxy-connect-timeout\n\n\nnumber\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/proxy-send-timeout\n\n\nnumber\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/proxy-read-timeout\n\n\nnumber\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/proxy-next-upstream\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/proxy-next-upstream-tries\n\n\nnumber\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/proxy-request-buffering\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/proxy-redirect-from\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/proxy-redirect-to\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/rewrite-log\n\n\nURI\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/rewrite-target\n\n\nURI\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/secure-backends\n\n\n\"true\" or \"false\"\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/secure-verify-ca-secret\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/server-alias\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/server-snippet\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/service-upstream\n\n\n\"true\" or \"false\"\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/session-cookie-name\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/session-cookie-hash\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/ssl-redirect\n\n\n\"true\" or \"false\"\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/ssl-passthrough\n\n\n\"true\" or \"false\"\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/upstream-max-fails\n\n\nnumber\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/upstream-fail-timeout\n\n\nnumber\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/upstream-hash-by\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/load-balance\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/upstream-vhost\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/whitelist-source-range\n\n\nCIDR\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/proxy-buffering\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/proxy-buffer-size\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/ssl-ciphers\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/connection-proxy-header\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/enable-access-log\n\n\n\"true\" or \"false\"\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/lua-resty-waf\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/lua-resty-waf-debug\n\n\n\"true\" or \"false\"\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/lua-resty-waf-ignore-rulesets\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/lua-resty-waf-extra-rules\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/enable-influxdb\n\n\n\"true\" or \"false\"\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/influxdb-measurement\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/influxdb-port\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/influxdb-host\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/influxdb-server-name\n\n\nstring\n\n\n\n\n\n\n\n\nRewrite\n\u00b6\n\n\nIn some scenarios the exposed URL in the backend service differs from the specified path in the Ingress rule. Without a rewrite any request will return 404.\nSet the annotation \nnginx.ingress.kubernetes.io/rewrite-target\n to the path expected by the service.\n\n\nIf the application contains relative links it is possible to add an additional annotation \nnginx.ingress.kubernetes.io/add-base-url\n that will prepend a \nbase\n tag\n in the header of the returned HTML from the backend.\n\n\nIf the scheme of \nbase\n tag\n need to be specific, set the annotation \nnginx.ingress.kubernetes.io/base-url-scheme\n to the scheme such as \nhttp\n and \nhttps\n.\n\n\nIf the Application Root is exposed in a different path and needs to be redirected, set the annotation \nnginx.ingress.kubernetes.io/app-root\n to redirect requests for \n/\n.\n\n\n\n\nExample\n\n\nPlease check the \nrewrite\n example.\n\n\n\n\nSession Affinity\n\u00b6\n\n\nThe annotation \nnginx.ingress.kubernetes.io/affinity\n enables and sets the affinity type in all Upstreams of an Ingress. This way, a request will always be directed to the same upstream server.\nThe only affinity type available for NGINX is \ncookie\n.\n\n\n\n\nExample\n\n\nPlease check the \naffinity\n example.\n\n\n\n\nCookie affinity\n\u00b6\n\n\nIf you use the \ncookie\n affinity type you can also specify the name of the cookie that will be used to route the requests with the annotation \nnginx.ingress.kubernetes.io/session-cookie-name\n. The default is to create a cookie named 'INGRESSCOOKIE'.\n\n\nIn case of NGINX the annotation \nnginx.ingress.kubernetes.io/session-cookie-hash\n defines which algorithm will be used to hash the used upstream. Default value is \nmd5\n and possible values are \nmd5\n, \nsha1\n and \nindex\n.\n\n\n\n\nAttention\n\n\nThe \nindex\n option is not an actual hash; an in-memory index is used instead, which has less overhead.\nHowever, with \nindex\n, matching against a changing upstream server list is inconsistent.\nSo, at reload, if upstream servers have changed, index values are not guaranteed to correspond to the same server as before!\n\nUse \nindex\n with caution\n and only if you need to!\n\n\n\n\nIn NGINX this feature is implemented by the third party module \nnginx-sticky-module-ng\n. The workflow used to define which upstream server will be used is explained \nhere\n\n\nAuthentication\n\u00b6\n\n\nIs possible to add authentication adding additional annotations in the Ingress rule. The source of the authentication is a secret that contains usernames and passwords inside the key \nauth\n.\n\n\nThe annotations are:\n\nnginx.ingress.kubernetes.io/auth-type: [basic|digest]\n\n\n\nIndicates the \nHTTP Authentication Type: Basic or Digest Access Authentication\n.\n\n\nnginx.ingress.kubernetes.io/auth-secret: secretName\n\n\n\n\nThe name of the Secret that contains the usernames and passwords which are granted access to the \npath\ns defined in the Ingress rules.\nThis annotation also accepts the alternative form \"namespace/secretName\", in which case the Secret lookup is performed in the referenced namespace instead of the Ingress namespace.\n\n\nnginx.ingress.kubernetes.io/auth-realm: \"realm string\"\n\n\n\n\n\n\nExample\n\n\nPlease check the \nauth\n example.\n\n\n\n\nCustom NGINX upstream checks\n\u00b6\n\n\nNGINX exposes some flags in the \nupstream configuration\n that enable the configuration of each server in the upstream. The Ingress controller allows custom \nmax_fails\n and \nfail_timeout\n parameters in a global context using \nupstream-max-fails\n and \nupstream-fail-timeout\n in the NGINX ConfigMap or in a particular Ingress rule. \nupstream-max-fails\n defaults to 0. This means NGINX will respect the container's \nreadinessProbe\n if it is defined. If there is no probe and no values for \nupstream-max-fails\n NGINX will continue to send traffic to the container.\n\n\n\n\nTip\n\n\nWith the default configuration NGINX will not health check your backends. Whenever the endpoints controller notices a readiness probe failure, that pod's IP will be removed from the list of endpoints. This will trigger the NGINX controller to also remove it from the upstreams.**\n\n\n\n\nTo use custom values in an Ingress rule define these annotations:\n\n\nnginx.ingress.kubernetes.io/upstream-max-fails\n: number of unsuccessful attempts to communicate with the server that should occur in the duration set by the \nupstream-fail-timeout\n parameter to consider the server unavailable.\n\n\nnginx.ingress.kubernetes.io/upstream-fail-timeout\n: time in seconds during which the specified number of unsuccessful attempts to communicate with the server should occur to consider the server unavailable. This is also the period of time the server will be considered unavailable.\n\n\nIn NGINX, backend server pools are called \"\nupstreams\n\". Each upstream contains the endpoints for a service. An upstream is created for each service that has Ingress rules defined.\n\n\n\n\nAttention\n\n\nAll Ingress rules using the same service will use the same upstream.\n\nOnly one of the Ingress rules should define annotations to configure the upstream servers.\n\n\n\n\n\n\nExample\n\n\nPlease check the \ncustom upstream check\n example.\n\n\n\n\nCustom NGINX upstream hashing\n\u00b6\n\n\nNGINX supports load balancing by client-server mapping based on \nconsistent hashing\n for a given key. The key can contain text, variables or any combination thereof. This feature allows for request stickiness other than client IP or cookies. The \nketama\n consistent hashing method will be used which ensures only a few keys would be remapped to different servers on upstream group changes.\n\n\nTo enable consistent hashing for a backend:\n\n\nnginx.ingress.kubernetes.io/upstream-hash-by\n: the nginx variable, text value or any combination thereof to use for consistent hashing. For example \nnginx.ingress.kubernetes.io/upstream-hash-by: \"$request_uri\"\n to consistently hash upstream requests by the current request URI.\n\n\nCustom NGINX load balancing\n\u00b6\n\n\nThis is similar to (https://github.com/kubernetes/ingress-nginx/blob/master/docs/user-guide/nginx-configuration/configmap.md#load-balance) but configures load balancing algorithm per ingress.\n\n\n\n\nNote that \nnginx.ingress.kubernetes.io/upstream-hash-by\n takes preference over this. If this and \nnginx.ingress.kubernetes.io/upstream-hash-by\n are not set then we fallback to using globally configured load balancing algorithm.\n\n\n\n\nCustom NGINX upstream vhost\n\u00b6\n\n\nThis configuration setting allows you to control the value for host in the following statement: \nproxy_set_header Host $host\n, which forms part of the location block. This is useful if you need to call the upstream server by something other than \n$host\n.\n\n\nClient Certificate Authentication\n\u00b6\n\n\nIt is possible to enable Client Certificate Authentication using additional annotations in Ingress Rule.\n\n\nThe annotations are:\n\n\n\n\nnginx.ingress.kubernetes.io/auth-tls-secret: secretName\n:\n The name of the Secret that contains the full Certificate Authority chain \nca.crt\n that is enabled to authenticate against this Ingress.\n This annotation also accepts the alternative form \"namespace/secretName\", in which case the Secret lookup is performed in the referenced namespace instead of the Ingress namespace.\n\n\nnginx.ingress.kubernetes.io/auth-tls-verify-depth\n:\n The validation depth between the provided client certificate and the Certification Authority chain.\n\n\nnginx.ingress.kubernetes.io/auth-tls-verify-client\n:\n Enables verification of client certificates.\n\n\nnginx.ingress.kubernetes.io/auth-tls-error-page\n:\n The URL/Page that user should be redirected in case of a Certificate Authentication Error\n\n\nnginx.ingress.kubernetes.io/auth-tls-pass-certificate-to-upstream\n:\n Indicates if the received certificates should be passed or not to the upstream server. By default this is disabled.\n\n\n\n\n\n\nExample\n\n\nPlease check the \nclient-certs\n example.\n\n\n\n\n\n\nAttention\n\n\nTLS with Client Authentication is \nnot\n possible in Cloudflare and might result in unexpected behavior.\n\n\nCloudflare only allows Authenticated Origin Pulls and is required to use their own certificate: \nhttps://blog.cloudflare.com/protecting-the-origin-with-tls-authenticated-origin-pulls/\n\n\nOnly Authenticated Origin Pulls are allowed and can be configured by following their tutorial: \nhttps://support.cloudflare.com/hc/en-us/articles/204494148-Setting-up-NGINX-to-use-TLS-Authenticated-Origin-Pulls\n\n\n\n\nConfiguration snippet\n\u00b6\n\n\nUsing this annotation you can add additional configuration to the NGINX location. For example:\n\n\nnginx.ingress.kubernetes.io/configuration-snippet\n:\n \n|\n\n \nmore_set_headers \"Request-Id: $req_id\";\n\n\n\n\n\nDefault Backend\n\u00b6\n\n\nThe ingress controller requires a \ndefault backend\n.\nThis service handles the response when the service in the Ingress rule does not have endpoints.\nThis is a global configuration for the ingress controller. In some cases could be required to return a custom content or format. In this scenario we can use the annotation \nnginx.ingress.kubernetes.io/default-backend: \n to specify a custom default backend.\n\n\nEnable CORS\n\u00b6\n\n\nTo enable Cross-Origin Resource Sharing (CORS) in an Ingress rule, add the annotation\n\nnginx.ingress.kubernetes.io/enable-cors: \"true\"\n. This will add a section in the server\nlocation enabling this functionality.\n\n\nCORS can be controlled with the following annotations:\n\n\n\n\nnginx.ingress.kubernetes.io/cors-allow-methods\n\n controls which methods are accepted. This is a multi-valued field, separated by ',' and\n accepts only letters (upper and lower case).\n\n\nDefault: \nGET, PUT, POST, DELETE, PATCH, OPTIONS\n\n\n\n\nExample: \nnginx.ingress.kubernetes.io/cors-allow-methods: \"PUT, GET, POST, OPTIONS\"\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/cors-allow-headers\n\n controls which headers are accepted. This is a multi-valued field, separated by ',' and accepts letters,\n numbers, _ and -.\n\n\n\n\nDefault: \nDNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization\n\n\n\n\nExample: \nnginx.ingress.kubernetes.io/cors-allow-headers: \"X-Forwarded-For, X-app123-XPTO\"\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/cors-allow-origin\n\n controls what's the accepted Origin for CORS.\n This is a single field value, with the following format: \nhttp(s)://origin-site.com\n or \nhttp(s)://origin-site.com:port\n\n\n\n\nDefault: \n*\n\n\n\n\nExample: \nnginx.ingress.kubernetes.io/cors-allow-origin: \"https://origin-site.com:4443\"\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/cors-allow-credentials\n\n controls if credentials can be passed during CORS operations.\n\n\n\n\nDefault: \ntrue\n\n\n\n\nExample: \nnginx.ingress.kubernetes.io/cors-allow-credentials: \"false\"\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/cors-max-age\n\n controls how long preflight requests can be cached.\n Default: \n1728000\n\n Example: \nnginx.ingress.kubernetes.io/cors-max-age: 600\n\n\n\n\n\n\n\n\nNote\n\n\nFor more information please see \nhttps://enable-cors.org\n \n\n\n\n\nServer Alias\n\u00b6\n\n\nTo add Server Aliases to an Ingress rule add the annotation \nnginx.ingress.kubernetes.io/server-alias: \"\"\n.\nThis will create a server with the same configuration, but a different \nserver_name\n as the provided host.\n\n\n\n\nNote\n\n\nA server-alias name cannot conflict with the hostname of an existing server. If it does the server-alias annotation will be ignored.\nIf a server-alias is created and later a new server with the same hostname is created,\nthe new server configuration will take place over the alias configuration.\n\n\n\n\nFor more information please see \nthe \nserver_name\n documentation\n.\n\n\nServer snippet\n\u00b6\n\n\nUsing the annotation \nnginx.ingress.kubernetes.io/server-snippet\n it is possible to add custom configuration in the server configuration block.\n\n\napiVersion\n:\n \nextensions/v1beta1\n\n\nkind\n:\n \nIngress\n\n\nmetadata\n:\n\n \nannotations\n:\n\n \nnginx.ingress.kubernetes.io/server-snippet\n:\n \n|\n\n\nset $agentflag 0;\n\n\n\nif ($http_user_agent ~* \"(Mobile)\" ){\n\n \nset $agentflag 1;\n\n\n}\n\n\n\nif ( $agentflag = 1 ) {\n\n \nreturn 301 https://m.example.com;\n\n\n}\n\n\n\n\n\n\n\nAttention\n\n\nThis annotation can be used only once per host.\n\n\n\n\nClient Body Buffer Size\n\u00b6\n\n\nSets buffer size for reading client request body per location. In case the request body is larger than the buffer,\nthe whole body or only its part is written to a temporary file. By default, buffer size is equal to two memory pages.\nThis is 8K on x86, other 32-bit platforms, and x86-64. It is usually 16K on other 64-bit platforms. This annotation is\napplied to each location provided in the ingress rule.\n\n\n\n\nNote\n\n\nThe annotation value must be given in a format understood by Nginx.\n\n\n\n\n\n\nExample\n\n\n\n\nnginx.ingress.kubernetes.io/client-body-buffer-size: \"1000\"\n # 1000 bytes\n\n\nnginx.ingress.kubernetes.io/client-body-buffer-size: 1k\n # 1 kilobyte\n\n\nnginx.ingress.kubernetes.io/client-body-buffer-size: 1K\n # 1 kilobyte\n\n\nnginx.ingress.kubernetes.io/client-body-buffer-size: 1m\n # 1 megabyte\n\n\nnginx.ingress.kubernetes.io/client-body-buffer-size: 1M\n # 1 megabyte\n\n\n\n\n\n\nFor more information please see \nhttp://nginx.org\n\n\nExternal Authentication\n\u00b6\n\n\nTo use an existing service that provides authentication the Ingress rule can be annotated with \nnginx.ingress.kubernetes.io/auth-url\n to indicate the URL where the HTTP request should be sent.\n\n\nnginx.ingress.kubernetes.io/auth-url\n:\n \n\"URL\n \nto\n \nthe\n \nauthentication\n \nservice\"\n\n\n\n\n\nAdditionally it is possible to set:\n\n\n\n\nnginx.ingress.kubernetes.io/auth-method\n:\n \n\n to specify the HTTP method to use.\n\n\nnginx.ingress.kubernetes.io/auth-signin\n:\n \n\n to specify the location of the error page.\n\n\nnginx.ingress.kubernetes.io/auth-response-headers\n:\n \n\n to specify headers to pass to backend once authentication request completes.\n\n\nnginx.ingress.kubernetes.io/auth-request-redirect\n:\n \n\n to specify the X-Auth-Request-Redirect header value.\n\n\n\n\n\n\nExample\n\n\nPlease check the \nexternal-auth\n example.\n\n\n\n\nRate limiting\n\u00b6\n\n\nThese annotations define a limit on the connections that can be opened by a single client IP address.\nThis can be used to mitigate \nDDoS Attacks\n.\n\n\n\n\nnginx.ingress.kubernetes.io/limit-connections\n: number of concurrent connections allowed from a single IP address.\n\n\nnginx.ingress.kubernetes.io/limit-rps\n: number of connections that may be accepted from a given IP each second.\n\n\nnginx.ingress.kubernetes.io/limit-rpm\n: number of connections that may be accepted from a given IP each minute.\n\n\nnginx.ingress.kubernetes.io/limit-rate-after\n: sets the initial amount after which the further transmission of a response to a client will be rate limited.\n\n\nnginx.ingress.kubernetes.io/limit-rate\n: rate of request that accepted from a client each second.\n\n\n\n\nYou can specify the client IP source ranges to be excluded from rate-limiting through the \nnginx.ingress.kubernetes.io/limit-whitelist\n annotation. The value is a comma separated list of CIDRs.\n\n\nIf you specify multiple annotations in a single Ingress rule, \nlimit-rpm\n, and then \nlimit-rps\n takes precedence.\n\n\nThe annotation \nnginx.ingress.kubernetes.io/limit-rate\n, \nnginx.ingress.kubernetes.io/limit-rate-after\n define a limit the rate of response transmission to a client. The rate is specified in bytes per second. The zero value disables rate limiting. The limit is set per a request, and so if a client simultaneously opens two connections, the overall rate will be twice as much as the specified limit.\n\n\nTo configure this setting globally for all Ingress rules, the \nlimit-rate-after\n and \nlimit-rate\n value may be set in the \nNGINX ConfigMap\n. if you set the value in ingress annotation will cover global setting.\n\n\nPermanent Redirect\n\u00b6\n\n\nThis annotation allows to return a permanent redirect instead of sending data to the upstream. For example \nnginx.ingress.kubernetes.io/permanent-redirect: https://www.google.com\n would redirect everything to Google.\n\n\nPermanent Redirect Code\n\u00b6\n\n\nThis annotation allows you to modify the status code used for permanent redirects. For example \nnginx.ingress.kubernetes.io/permanent-redirect-code: '308'\n would return your permanent-redirect with a 308.\n\n\nSSL Passthrough\n\u00b6\n\n\nThe annotation \nnginx.ingress.kubernetes.io/ssl-passthrough\n allows to configure TLS termination in the pod and not in NGINX.\n\n\n\n\nAttention\n\n\nUsing the annotation \nnginx.ingress.kubernetes.io/ssl-passthrough\n invalidates all the other available annotations.\nThis is because SSL Passthrough works on level 4 of the OSI stack (TCP), not on the HTTP/HTTPS level.\n\n\n\n\n\n\nAttention\n\n\nThe use of this annotation requires the flag \n--enable-ssl-passthrough\n (By default it is disabled).\n\n\n\n\nSecure backends DEPRECATED (since 0.18.0)\n\u00b6\n\n\nPlease use \nnginx.ingress.kubernetes.io/backend-protocol: \"HTTPS\"\n\n\nBy default NGINX uses plain HTTP to reach the services.\nAdding the annotation \nnginx.ingress.kubernetes.io/secure-backends: \"true\"\n in the Ingress rule changes the protocol to HTTPS.\nIf you want to validate the upstream against a specific certificate, you can create a secret with it and reference the secret with the annotation \nnginx.ingress.kubernetes.io/secure-verify-ca-secret\n.\n\n\n\n\nAttention\n\n\nNote that if an invalid or non-existent secret is given,\nthe ingress controller will ignore the \nsecure-backends\n annotation.\n\n\n\n\nService Upstream\n\u00b6\n\n\nBy default the NGINX ingress controller uses a list of all endpoints (Pod IP/port) in the NGINX upstream configuration.\n\n\nThe \nnginx.ingress.kubernetes.io/service-upstream\n annotation disables that behavior and instead uses a single upstream in NGINX, the service's Cluster IP and port.\n\n\nThis can be desirable for things like zero-downtime deployments as it reduces the need to reload NGINX configuration when Pods come up and down. See issue \n#257\n.\n\n\nKnown Issues\n\u00b6\n\n\nIf the \nservice-upstream\n annotation is specified the following things should be taken into consideration:\n\n\n\n\nSticky Sessions will not work as only round-robin load balancing is supported.\n\n\nThe \nproxy_next_upstream\n directive will not have any effect meaning on error the request will not be dispatched to another upstream.\n\n\n\n\nServer-side HTTPS enforcement through redirect\n\u00b6\n\n\nBy default the controller redirects (308) to HTTPS if TLS is enabled for that ingress.\nIf you want to disable this behavior globally, you can use \nssl-redirect: \"false\"\n in the NGINX \nconfig map\n.\n\n\nTo configure this feature for specific ingress resources, you can use the \nnginx.ingress.kubernetes.io/ssl-redirect: \"false\"\n\nannotation in the particular resource.\n\n\nWhen using SSL offloading outside of cluster (e.g. AWS ELB) it may be useful to enforce a redirect to HTTPS\neven when there is no TLS certificate available.\nThis can be achieved by using the \nnginx.ingress.kubernetes.io/force-ssl-redirect: \"true\"\n annotation in the particular resource.\n\n\nRedirect from/to www.\n\u00b6\n\n\nIn some scenarios is required to redirect from \nwww.domain.com\n to \ndomain.com\n or vice versa.\nTo enable this feature use the annotation \nnginx.ingress.kubernetes.io/from-to-www-redirect: \"true\"\n\n\n\n\nAttention\n\n\nIf at some point a new Ingress is created with a host equal to one of the options (like \ndomain.com\n) the annotation will be omitted.\n\n\n\n\nWhitelist source range\n\u00b6\n\n\nYou can specify allowed client IP source ranges through the \nnginx.ingress.kubernetes.io/whitelist-source-range\n annotation.\nThe value is a comma separated list of \nCIDRs\n, e.g. \n10.0.0.0/24,172.10.0.1\n.\n\n\nTo configure this setting globally for all Ingress rules, the \nwhitelist-source-range\n value may be set in the \nNGINX ConfigMap\n.\n\n\n\n\nNote\n\n\nAdding an annotation to an Ingress rule overrides any global restriction.\n\n\n\n\nCustom timeouts\n\u00b6\n\n\nUsing the configuration configmap it is possible to set the default global timeout for connections to the upstream servers.\nIn some scenarios is required to have different values. To allow this we provide annotations that allows this customization:\n\n\n\n\nnginx.ingress.kubernetes.io/proxy-connect-timeout\n\n\nnginx.ingress.kubernetes.io/proxy-send-timeout\n\n\nnginx.ingress.kubernetes.io/proxy-read-timeout\n\n\nnginx.ingress.kubernetes.io/proxy-next-upstream\n\n\nnginx.ingress.kubernetes.io/proxy-next-upstream-tries\n\n\nnginx.ingress.kubernetes.io/proxy-request-buffering\n\n\n\n\nProxy redirect\n\u00b6\n\n\nWith the annotations \nnginx.ingress.kubernetes.io/proxy-redirect-from\n and \nnginx.ingress.kubernetes.io/proxy-redirect-to\n it is possible to\nset the text that should be changed in the \nLocation\n and \nRefresh\n header fields of a proxied server response (http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_redirect)\n\n\nSetting \"off\" or \"default\" in the annotation \nnginx.ingress.kubernetes.io/proxy-redirect-from\n disables \nnginx.ingress.kubernetes.io/proxy-redirect-to\n,\notherwise, both annotations must be used in unison. Note that each annotation must be a string without spaces.\n\n\nBy default the value of each annotation is \"off\".\n\n\nCustom max body size\n\u00b6\n\n\nFor NGINX, an 413 error will be returned to the client when the size in a request exceeds the maximum allowed size of the client request body. This size can be configured by the parameter \nclient_max_body_size\n.\n\n\nTo configure this setting globally for all Ingress rules, the \nproxy-body-size\n value may be set in the \nNGINX ConfigMap\n.\nTo use custom values in an Ingress rule define these annotation:\n\n\nnginx.ingress.kubernetes.io/proxy-body-size\n:\n \n8m\n\n\n\n\n\nProxy cookie domain\n\u00b6\n\n\nSets a text that \nshould be changed in the domain attribute\n of the \"Set-Cookie\" header fields of a proxied server response.\n\n\nTo configure this setting globally for all Ingress rules, the \nproxy-cookie-domain\n value may be set in the \nNGINX ConfigMap\n.\n\n\nProxy buffering\n\u00b6\n\n\nEnable or disable proxy buffering \nproxy_buffering\n.\nBy default proxy buffering is disabled in the NGINX config.\n\n\nTo configure this setting globally for all Ingress rules, the \nproxy-buffering\n value may be set in the \nNGINX ConfigMap\n.\nTo use custom values in an Ingress rule define these annotation:\n\n\nnginx.ingress.kubernetes.io/proxy-buffering\n:\n \n\"on\"\n\n\n\n\n\nProxy buffer size\n\u00b6\n\n\nSets the size of the buffer \nproxy_buffer_size\n used for reading the first part of the response received from the proxied server.\nBy default proxy buffer size is set as \"4k\"\n\n\nTo configure this setting globally, set \nproxy-buffer-size\n in \nNGINX ConfigMap\n. To use custom values in an Ingress rule, define this annotation:\n\nnginx.ingress.kubernetes.io/proxy-buffer-size\n:\n \n\"8k\"\n\n\n\n\nSSL ciphers\n\u00b6\n\n\nSpecifies the \nenabled ciphers\n.\n\n\nUsing this annotation will set the \nssl_ciphers\n directive at the server level. This configuration is active for all the paths in the host.\n\n\nnginx.ingress.kubernetes.io/ssl-ciphers\n:\n \n\"ALL:!aNULL:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP\"\n\n\n\n\n\nConnection proxy header\n\u00b6\n\n\nUsing this annotation will override the default connection header set by NGINX.\nTo use custom values in an Ingress rule, define the annotation:\n\n\nnginx.ingress.kubernetes.io/connection-proxy-header\n:\n \n\"keep-alive\"\n\n\n\n\n\nEnable Access Log\n\u00b6\n\n\nAccess logs are enabled by default, but in some scenarios access logs might be required to be disabled for a given\ningress. To do this, use the annotation:\n\n\nnginx.ingress.kubernetes.io/enable-access-log\n:\n \n\"false\"\n\n\n\n\n\nEnable Rewrite Log\n\u00b6\n\n\nRewrite logs are not enabled by default. In some scenarios it could be required to enable NGINX rewrite logs.\nNote that rewrite logs are sent to the error_log file at the notice level. To enable this feature use the annotation:\n\n\nnginx.ingress.kubernetes.io/enable-rewrite-log\n:\n \n\"true\"\n\n\n\n\n\nLua Resty WAF\n\u00b6\n\n\nUsing \nlua-resty-waf-*\n annotations we can enable and control the \nlua-resty-waf\n\nWeb Application Firewall per location.\n\n\nFollowing configuration will enable the WAF for the paths defined in the corresponding ingress:\n\n\nnginx.ingress.kubernetes.io/lua-resty-waf\n:\n \n\"active\"\n\n\n\n\n\nIn order to run it in debugging mode you can set \nnginx.ingress.kubernetes.io/lua-resty-waf-debug\n to \n\"true\"\n in addition to the above configuration.\nThe other possible values for \nnginx.ingress.kubernetes.io/lua-resty-waf\n are \ninactive\n and \nsimulate\n.\nIn \ninactive\n mode WAF won't do anything, whereas in \nsimulate\n mode it will log a warning message if there's a matching WAF rule for given request. This is useful to debug a rule and eliminate possible false positives before fully deploying it.\n\n\nlua-resty-waf\n comes with predefined set of rules \nhttps://github.com/p0pr0ck5/lua-resty-waf/tree/84b4f40362500dd0cb98b9e71b5875cb1a40f1ad/rules\n that covers ModSecurity CRS.\nYou can use \nnginx.ingress.kubernetes.io/lua-resty-waf-ignore-rulesets\n to ignore a subset of those rulesets. For an example:\n\n\nnginx.ingress.kubernetes.io/lua-resty-waf-ignore-rulesets\n:\n \n\"41000_sqli,\n \n42000_xss\"\n\n\n\n\n\nwill ignore the two mentioned rulesets.\n\n\nIt is also possible to configure custom WAF rules per ingress using the \nnginx.ingress.kubernetes.io/lua-resty-waf-extra-rules\n annotation. For an example the following snippet will configure a WAF rule to deny requests with query string value that contains word \nfoo\n:\n\n\nnginx.ingress.kubernetes.io/lua-resty-waf-extra-rules\n:\n \n'[=[\n \n{\n \n\"access\":\n \n[\n \n{\n \n\"actions\":\n \n{\n \n\"disrupt\"\n \n:\n \n\"DENY\"\n \n},\n \n\"id\":\n \n10001,\n \n\"msg\":\n \n\"my\n \ncustom\n \nrule\",\n \n\"operator\":\n \n\"STR_CONTAINS\",\n \n\"pattern\":\n \n\"foo\",\n \n\"vars\":\n \n[\n \n{\n \n\"parse\":\n \n[\n \n\"values\",\n \n1\n \n],\n \n\"type\":\n \n\"REQUEST_ARGS\"\n \n}\n \n]\n \n}\n \n],\n \n\"body_filter\":\n \n[],\n \n\"header_filter\":[]\n \n}\n \n]=]'\n\n\n\n\n\nFor details on how to write WAF rules, please refer to \nhttps://github.com/p0pr0ck5/lua-resty-waf\n.\n\n\ngRPC backend DEPRECATED (since 0.18.0)\n\u00b6\n\n\nPlease use \nnginx.ingress.kubernetes.io/backend-protocol: \"GRPC\"\n or \nnginx.ingress.kubernetes.io/backend-protocol: \"GRPCS\"\n\n\nSince NGINX 1.13.10 it is possible to expose \ngRPC services natively\n\n\nYou only need to add the annotation \nnginx.ingress.kubernetes.io/grpc-backend: \"true\"\n to enable this feature.\nAdditionally, if the gRPC service requires TLS, add \nnginx.ingress.kubernetes.io/secure-backends: \"true\"\n.\n\n\n\n\nAttention\n\n\nThis feature requires HTTP2 to work which means we need to expose this service using HTTPS.\nExposing a gRPC service using HTTP is not supported.\n\n\n\n\nInfluxDB\n\u00b6\n\n\nUsing \ninfluxdb-*\n annotations we can monitor requests passing through a Location by sending them to an InfluxDB backend exposing the UDP socket\nusing the \nnginx-influxdb-module\n.\n\n\nnginx.ingress.kubernetes.io/enable-influxdb\n:\n \n\"true\"\n\n\nnginx.ingress.kubernetes.io/influxdb-measurement\n:\n \n\"nginx-reqs\"\n\n\nnginx.ingress.kubernetes.io/influxdb-port\n:\n \n\"8089\"\n\n\nnginx.ingress.kubernetes.io/influxdb-host\n:\n \n\"127.0.0.1\"\n\n\nnginx.ingress.kubernetes.io/influxdb-server-name\n:\n \n\"nginx-ingress\"\n\n\n\n\n\nFor the \ninfluxdb-host\n parameter you have two options:\n\n\n\n\nUse an InfluxDB server configured with the \nUDP protocol\n enabled. \n\n\nDeploy Telegraf as a sidecar proxy to the Ingress controller configured to listen UDP with the \nsocket listener input\n and to write using\nanyone of the \noutputs plugins\n like InfluxDB, Apache Kafka,\nPrometheus, etc.. (recommended)\n\n\n\n\nIt's important to remember that there's no DNS resolver at this stage so you will have to configure\nan ip address to \nnginx.ingress.kubernetes.io/influxdb-host\n. If you deploy Influx or Telegraf as sidecar (another container in the same pod) this becomes straightforward since you can directly use \n127.0.0.1\n.\n\n\nBackend Protocol\n\u00b6\n\n\nUsing \nbackend-protocol\n annotations is possible to indicate how NGINX should communicate with the backend service.\nValid Values: HTTP, HTTPS, GRPC, GRPCS and AJP\n\n\nBy default NGINX uses \nHTTP\n.\n\n\nExample:\n\n\nnginx.ingress.kubernetes.io/backend-protocol\n:\n \n\"HTTPS\"", "title": "Annotations" }, { @@ -197,7 +222,7 @@ }, { "location": "/user-guide/nginx-configuration/annotations/#authentication", - "text": "Is possible to add authentication adding additional annotations in the Ingress rule. The source of the authentication is a secret that contains usernames and passwords inside the key auth . The annotations are: nginx.ingress.kubernetes.io/auth-type: [basic|digest] Indicates the HTTP Authentication Type: Basic or Digest Access Authentication . nginx.ingress.kubernetes.io/auth-secret: secretName The name of the Secret that contains the usernames and passwords which are granted access to the path s defined in the Ingress rules.\nThis annotation also accepts the alternative form \"namespace/secretName\", in which case the Secret lookup is performed in the referenced namespace instead of the Ingress namespace. nginx.ingress.kubernetes.io/auth-realm: \"realm string\" Example Please check the auth example.", + "text": "Is possible to add authentication adding additional annotations in the Ingress rule. The source of the authentication is a secret that contains usernames and passwords inside the key auth . The annotations are: nginx.ingress.kubernetes.io/auth-type: [basic|digest] Indicates the HTTP Authentication Type: Basic or Digest Access Authentication . nginx.ingress.kubernetes.io/auth-secret: secretName The name of the Secret that contains the usernames and passwords which are granted access to the path s defined in the Ingress rules.\nThis annotation also accepts the alternative form \"namespace/secretName\", in which case the Secret lookup is performed in the referenced namespace instead of the Ingress namespace. nginx.ingress.kubernetes.io/auth-realm: \"realm string\" Example Please check the auth example.", "title": "Authentication" }, { @@ -237,7 +262,7 @@ }, { "location": "/user-guide/nginx-configuration/annotations/#enable-cors", - "text": "To enable Cross-Origin Resource Sharing (CORS) in an Ingress rule,\nadd the annotation nginx.ingress.kubernetes.io/enable-cors: \"true\" .\nThis will add a section in the server location enabling this functionality. CORS can be controlled with the following annotations: nginx.ingress.kubernetes.io/cors-allow-methods \n controls which methods are accepted.\n This is a multi-valued field, separated by ',' and accepts only letters (upper and lower case).\n Example: nginx.ingress.kubernetes.io/cors-allow-methods: \"PUT, GET, POST, OPTIONS\" nginx.ingress.kubernetes.io/cors-allow-headers \n controls which headers are accepted.\n This is a multi-valued field, separated by ',' and accepts letters, numbers, _ and -.\n Example: nginx.ingress.kubernetes.io/cors-allow-headers: \"X-Forwarded-For, X-app123-XPTO\" nginx.ingress.kubernetes.io/cors-allow-origin \n controls what's the accepted Origin for CORS and defaults to '*'.\n This is a single field value, with the following format: http(s)://origin-site.com or http(s)://origin-site.com:port \n Example: nginx.ingress.kubernetes.io/cors-allow-origin: \"https://origin-site.com:4443\" nginx.ingress.kubernetes.io/cors-allow-credentials \n controls if credentials can be passed during CORS operations.\n Example: nginx.ingress.kubernetes.io/cors-allow-credentials: \"true\" nginx.ingress.kubernetes.io/cors-max-age \n controls how long preflight requests can be cached.\n Example: nginx.ingress.kubernetes.io/cors-max-age: 600 Note For more information please see https://enable-cors.org", + "text": "To enable Cross-Origin Resource Sharing (CORS) in an Ingress rule, add the annotation nginx.ingress.kubernetes.io/enable-cors: \"true\" . This will add a section in the server\nlocation enabling this functionality. CORS can be controlled with the following annotations: nginx.ingress.kubernetes.io/cors-allow-methods \n controls which methods are accepted. This is a multi-valued field, separated by ',' and\n accepts only letters (upper and lower case). Default: GET, PUT, POST, DELETE, PATCH, OPTIONS Example: nginx.ingress.kubernetes.io/cors-allow-methods: \"PUT, GET, POST, OPTIONS\" nginx.ingress.kubernetes.io/cors-allow-headers \n controls which headers are accepted. This is a multi-valued field, separated by ',' and accepts letters,\n numbers, _ and -. Default: DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization Example: nginx.ingress.kubernetes.io/cors-allow-headers: \"X-Forwarded-For, X-app123-XPTO\" nginx.ingress.kubernetes.io/cors-allow-origin \n controls what's the accepted Origin for CORS.\n This is a single field value, with the following format: http(s)://origin-site.com or http(s)://origin-site.com:port Default: * Example: nginx.ingress.kubernetes.io/cors-allow-origin: \"https://origin-site.com:4443\" nginx.ingress.kubernetes.io/cors-allow-credentials \n controls if credentials can be passed during CORS operations. Default: true Example: nginx.ingress.kubernetes.io/cors-allow-credentials: \"false\" nginx.ingress.kubernetes.io/cors-max-age \n controls how long preflight requests can be cached.\n Default: 1728000 \n Example: nginx.ingress.kubernetes.io/cors-max-age: 600 Note For more information please see https://enable-cors.org", "title": "Enable CORS" }, { @@ -337,7 +362,7 @@ }, { "location": "/user-guide/nginx-configuration/annotations/#proxy-buffer-size", - "text": "Sets the size of the buffer proxy_buffer_size used for reading the first part of the response received from the proxied server.\nBy default proxy buffer size is set as \"4k\" To configure this setting globally, set proxy-buffer-size in NGINX ConfigMap . To use custom values in an Ingress rule, define this annotation: nginx.ingress.kubernetes.io/proxy-buffer-size : \"8k\"", + "text": "Sets the size of the buffer proxy_buffer_size used for reading the first part of the response received from the proxied server.\nBy default proxy buffer size is set as \"4k\" To configure this setting globally, set proxy-buffer-size in NGINX ConfigMap . To use custom values in an Ingress rule, define this annotation: nginx.ingress.kubernetes.io/proxy-buffer-size : \"8k\"", "title": "Proxy buffer size" }, { @@ -382,7 +407,7 @@ }, { "location": "/user-guide/nginx-configuration/configmap/", - "text": "ConfigMaps\n\u00b6\n\n\nConfigMaps allow you to decouple configuration artifacts from image content to keep containerized applications portable.\n\n\nThe ConfigMap API resource stores configuration data as key-value pairs. The data provides the configurations for system\ncomponents for the nginx-controller. Before you can begin using a config-map it must be \ndeployed\n.\n\n\nIn order to overwrite nginx-controller configuration values as seen in \nconfig.go\n,\nyou can add key-value pairs to the data section of the config-map. For Example:\n\n\ndata\n:\n\n \nmap-hash-bucket-size\n:\n \n\"128\"\n\n \nssl-protocols\n:\n \nSSLv2\n\n\n\n\n\n\n\n\nImportant\n\n\nThe key and values in a ConfigMap can only be strings.\nThis means that we want a value with boolean values we need to quote the values, like \"true\" or \"false\".\nSame for numbers, like \"100\".\n\n\n\"Slice\" types (defined below as \n[]string\n or \n[]int\n can be provided as a comma-delimited string.\n\n\n\n\nConfiguration options\n\u00b6\n\n\nThe following table shows a configuration option's name, type, and the default value:\n\n\n\n\n\n\n\n\nname\n\n\ntype\n\n\ndefault\n\n\n\n\n\n\n\n\n\n\nadd-headers\n\n\nstring\n\n\n\"\"\n\n\n\n\n\n\nallow-backend-server-header\n\n\nbool\n\n\n\"false\"\n\n\n\n\n\n\nhide-headers\n\n\nstring array\n\n\nempty\n\n\n\n\n\n\naccess-log-path\n\n\nstring\n\n\n\"/var/log/nginx/access.log\"\n\n\n\n\n\n\nerror-log-path\n\n\nstring\n\n\n\"/var/log/nginx/error.log\"\n\n\n\n\n\n\nenable-dynamic-tls-records\n\n\nbool\n\n\n\"true\"\n\n\n\n\n\n\nenable-modsecurity\n\n\nbool\n\n\n\"false\"\n\n\n\n\n\n\nenable-owasp-modsecurity-crs\n\n\nbool\n\n\n\"false\"\n\n\n\n\n\n\nclient-header-buffer-size\n\n\nstring\n\n\n\"1k\"\n\n\n\n\n\n\nclient-header-timeout\n\n\nint\n\n\n60\n\n\n\n\n\n\nclient-body-buffer-size\n\n\nstring\n\n\n\"8k\"\n\n\n\n\n\n\nclient-body-timeout\n\n\nint\n\n\n60\n\n\n\n\n\n\ndisable-access-log\n\n\nbool\n\n\nfalse\n\n\n\n\n\n\ndisable-ipv6\n\n\nbool\n\n\nfalse\n\n\n\n\n\n\ndisable-ipv6-dns\n\n\nbool\n\n\nfalse\n\n\n\n\n\n\nenable-underscores-in-headers\n\n\nbool\n\n\nfalse\n\n\n\n\n\n\nignore-invalid-headers\n\n\nbool\n\n\ntrue\n\n\n\n\n\n\nretry-non-idempotent\n\n\nbool\n\n\n\"false\"\n\n\n\n\n\n\nerror-log-level\n\n\nstring\n\n\n\"notice\"\n\n\n\n\n\n\nhttp2-max-field-size\n\n\nstring\n\n\n\"4k\"\n\n\n\n\n\n\nhttp2-max-header-size\n\n\nstring\n\n\n\"16k\"\n\n\n\n\n\n\nhsts\n\n\nbool\n\n\n\"true\"\n\n\n\n\n\n\nhsts-include-subdomains\n\n\nbool\n\n\n\"true\"\n\n\n\n\n\n\nhsts-max-age\n\n\nstring\n\n\n\"15724800\"\n\n\n\n\n\n\nhsts-preload\n\n\nbool\n\n\n\"false\"\n\n\n\n\n\n\nkeep-alive\n\n\nint\n\n\n75\n\n\n\n\n\n\nkeep-alive-requests\n\n\nint\n\n\n100\n\n\n\n\n\n\nlarge-client-header-buffers\n\n\nstring\n\n\n\"4 8k\"\n\n\n\n\n\n\nlog-format-escape-json\n\n\nbool\n\n\n\"false\"\n\n\n\n\n\n\nlog-format-upstream\n\n\nstring\n\n\n%v\n \n-\n \n[\n$the_real_ip\n]\n \n-\n \n$remote_user\n \n[\n$time_local\n]\n \n\"$request\"\n \n$status\n \n$body_bytes_sent\n \n\"$http_referer\"\n \n\"$http_user_agent\"\n \n$request_length\n \n$request_time\n \n[\n$proxy_upstream_name\n]\n \n$upstream_addr\n \n$upstream_response_length\n \n$upstream_response_time\n \n$upstream_status\n\n\n\n\n\n\nlog-format-stream\n\n\nstring\n\n\n[$time_local] $protocol $status $bytes_sent $bytes_received $session_time\n\n\n\n\n\n\nenable-multi-accept\n\n\nbool\n\n\n\"true\"\n\n\n\n\n\n\nmax-worker-connections\n\n\nint\n\n\n16384\n\n\n\n\n\n\nmap-hash-bucket-size\n\n\nint\n\n\n64\n\n\n\n\n\n\nnginx-status-ipv4-whitelist\n\n\n[]string\n\n\n\"127.0.0.1\"\n\n\n\n\n\n\nnginx-status-ipv6-whitelist\n\n\n[]string\n\n\n\"::1\"\n\n\n\n\n\n\nproxy-real-ip-cidr\n\n\n[]string\n\n\n\"0.0.0.0/0\"\n\n\n\n\n\n\nproxy-set-headers\n\n\nstring\n\n\n\"\"\n\n\n\n\n\n\nserver-name-hash-max-size\n\n\nint\n\n\n1024\n\n\n\n\n\n\nserver-name-hash-bucket-size\n\n\nint\n\n\n\n\n\n\n\n\n\nproxy-headers-hash-max-size\n\n\nint\n\n\n512\n\n\n\n\n\n\nproxy-headers-hash-bucket-size\n\n\nint\n\n\n64\n\n\n\n\n\n\nreuse-port\n\n\nbool\n\n\n\"true\"\n\n\n\n\n\n\nserver-tokens\n\n\nbool\n\n\n\"true\"\n\n\n\n\n\n\nssl-ciphers\n\n\nstring\n\n\n\"ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256\"\n\n\n\n\n\n\nssl-ecdh-curve\n\n\nstring\n\n\n\"auto\"\n\n\n\n\n\n\nssl-dh-param\n\n\nstring\n\n\n\"\"\n\n\n\n\n\n\nssl-protocols\n\n\nstring\n\n\n\"TLSv1.2\"\n\n\n\n\n\n\nssl-session-cache\n\n\nbool\n\n\n\"true\"\n\n\n\n\n\n\nssl-session-cache-size\n\n\nstring\n\n\n\"10m\"\n\n\n\n\n\n\nssl-session-tickets\n\n\nbool\n\n\n\"true\"\n\n\n\n\n\n\nssl-session-ticket-key\n\n\nstring\n\n\n\n\n\n\n\n\n\nssl-session-timeout\n\n\nstring\n\n\n\"10m\"\n\n\n\n\n\n\nssl-buffer-size\n\n\nstring\n\n\n\"4k\"\n\n\n\n\n\n\nuse-proxy-protocol\n\n\nbool\n\n\n\"false\"\n\n\n\n\n\n\nproxy-protocol-header-timeout\n\n\nstring\n\n\n\"5s\"\n\n\n\n\n\n\nuse-gzip\n\n\nbool\n\n\n\"true\"\n\n\n\n\n\n\nuse-geoip\n\n\nbool\n\n\n\"true\"\n\n\n\n\n\n\nenable-brotli\n\n\nbool\n\n\n\"false\"\n\n\n\n\n\n\nbrotli-level\n\n\nint\n\n\n4\n\n\n\n\n\n\nbrotli-types\n\n\nstring\n\n\n\"application/xml+rss application/atom+xml application/javascript application/x-javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/svg+xml image/x-icon text/css text/plain text/x-component\"\n\n\n\n\n\n\nuse-http2\n\n\nbool\n\n\n\"true\"\n\n\n\n\n\n\ngzip-level\n\n\nint\n\n\n5\n\n\n\n\n\n\ngzip-types\n\n\nstring\n\n\n\"application/atom+xml application/javascript application/x-javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/svg+xml image/x-icon text/css text/plain text/x-component\"\n\n\n\n\n\n\nworker-processes\n\n\nstring\n\n\n\n\n\n\n\n\n\nworker-cpu-affinity\n\n\nstring\n\n\n\"\"\n\n\n\n\n\n\nworker-shutdown-timeout\n\n\nstring\n\n\n\"10s\"\n\n\n\n\n\n\nload-balance\n\n\nstring\n\n\n\"round_robin\"\n\n\n\n\n\n\nvariables-hash-bucket-size\n\n\nint\n\n\n128\n\n\n\n\n\n\nvariables-hash-max-size\n\n\nint\n\n\n2048\n\n\n\n\n\n\nupstream-keepalive-connections\n\n\nint\n\n\n32\n\n\n\n\n\n\nlimit-conn-zone-variable\n\n\nstring\n\n\n\"$binary_remote_addr\"\n\n\n\n\n\n\nproxy-stream-timeout\n\n\nstring\n\n\n\"600s\"\n\n\n\n\n\n\nproxy-stream-responses\n\n\nint\n\n\n1\n\n\n\n\n\n\nbind-address\n\n\n[]string\n\n\n\"\"\n\n\n\n\n\n\nuse-forwarded-headers\n\n\nbool\n\n\n\"true\"\n\n\n\n\n\n\nforwarded-for-header\n\n\nstring\n\n\n\"X-Forwarded-For\"\n\n\n\n\n\n\ncompute-full-forwarded-for\n\n\nbool\n\n\n\"false\"\n\n\n\n\n\n\nproxy-add-original-uri-header\n\n\nbool\n\n\n\"true\"\n\n\n\n\n\n\ngenerate-request-id\n\n\nbool\n\n\n\"true\"\n\n\n\n\n\n\nenable-opentracing\n\n\nbool\n\n\n\"false\"\n\n\n\n\n\n\nzipkin-collector-host\n\n\nstring\n\n\n\"\"\n\n\n\n\n\n\nzipkin-collector-port\n\n\nint\n\n\n9411\n\n\n\n\n\n\nzipkin-service-name\n\n\nstring\n\n\n\"nginx\"\n\n\n\n\n\n\nzipkin-sample-rate\n\n\nfloat\n\n\n1.0\n\n\n\n\n\n\njaeger-collector-host\n\n\nstring\n\n\n\"\"\n\n\n\n\n\n\njaeger-collector-port\n\n\nint\n\n\n6831\n\n\n\n\n\n\njaeger-service-name\n\n\nstring\n\n\n\"nginx\"\n\n\n\n\n\n\njaeger-sampler-type\n\n\nstring\n\n\n\"const\"\n\n\n\n\n\n\njaeger-sampler-param\n\n\nstring\n\n\n\"1\"\n\n\n\n\n\n\nmain-snippet\n\n\nstring\n\n\n\"\"\n\n\n\n\n\n\nhttp-snippet\n\n\nstring\n\n\n\"\"\n\n\n\n\n\n\nserver-snippet\n\n\nstring\n\n\n\"\"\n\n\n\n\n\n\nlocation-snippet\n\n\nstring\n\n\n\"\"\n\n\n\n\n\n\ncustom-http-errors\n\n\n[]int\n\n\n[]int{}\n\n\n\n\n\n\nproxy-body-size\n\n\nstring\n\n\n\"1m\"\n\n\n\n\n\n\nproxy-connect-timeout\n\n\nint\n\n\n5\n\n\n\n\n\n\nproxy-read-timeout\n\n\nint\n\n\n60\n\n\n\n\n\n\nproxy-send-timeout\n\n\nint\n\n\n60\n\n\n\n\n\n\nproxy-buffer-size\n\n\nstring\n\n\n\"4k\"\n\n\n\n\n\n\nproxy-cookie-path\n\n\nstring\n\n\n\"off\"\n\n\n\n\n\n\nproxy-cookie-domain\n\n\nstring\n\n\n\"off\"\n\n\n\n\n\n\nproxy-next-upstream\n\n\nstring\n\n\n\"error timeout\"\n\n\n\n\n\n\nproxy-next-upstream-tries\n\n\nint\n\n\n3\n\n\n\n\n\n\nproxy-redirect-from\n\n\nstring\n\n\n\"off\"\n\n\n\n\n\n\nproxy-request-buffering\n\n\nstring\n\n\n\"on\"\n\n\n\n\n\n\nssl-redirect\n\n\nbool\n\n\n\"true\"\n\n\n\n\n\n\nwhitelist-source-range\n\n\n[]string\n\n\n[]string{}\n\n\n\n\n\n\nskip-access-log-urls\n\n\n[]string\n\n\n[]string{}\n\n\n\n\n\n\nlimit-rate\n\n\nint\n\n\n0\n\n\n\n\n\n\nlimit-rate-after\n\n\nint\n\n\n0\n\n\n\n\n\n\nhttp-redirect-code\n\n\nint\n\n\n308\n\n\n\n\n\n\nproxy-buffering\n\n\nstring\n\n\n\"off\"\n\n\n\n\n\n\nlimit-req-status-code\n\n\nint\n\n\n503\n\n\n\n\n\n\nno-tls-redirect-locations\n\n\nstring\n\n\n\"/.well-known/acme-challenge\"\n\n\n\n\n\n\nno-auth-locations\n\n\nstring\n\n\n\"/.well-known/acme-challenge\"\n\n\n\n\n\n\n\n\nadd-headers\n\u00b6\n\n\nSets custom headers from named configmap before sending traffic to the client. See \nproxy-set-headers\n. \nexample\n\n\nallow-backend-server-header\n\u00b6\n\n\nEnables the return of the header Server from the backend instead of the generic nginx string. \ndefault:\n is disabled\n\n\nhide-headers\n\u00b6\n\n\nSets additional header that will not be passed from the upstream server to the client response.\n\ndefault:\n empty\n\n\nReferences:\n\n\nhttp://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_hide_header\n\n\naccess-log-path\n\u00b6\n\n\nAccess log path. Goes to \n/var/log/nginx/access.log\n by default.\n\n\nNote:\n the file \n/var/log/nginx/access.log\n is a symlink to \n/dev/stdout\n\n\nerror-log-path\n\u00b6\n\n\nError log path. Goes to \n/var/log/nginx/error.log\n by default.\n\n\nNote:\n the file \n/var/log/nginx/error.log\n is a symlink to \n/dev/stderr\n\n\nReferences:\n\n\nhttp://nginx.org/en/docs/ngx_core_module.html#error_log\n\n\nenable-dynamic-tls-records\n\u00b6\n\n\nEnables dynamically sized TLS records to improve time-to-first-byte. \ndefault:\n is enabled\n\n\nReferences:\n\n\nhttps://blog.cloudflare.com/optimizing-tls-over-tcp-to-reduce-latency\n\n\nenable-modsecurity\n\u00b6\n\n\nEnables the modsecurity module for NGINX. \ndefault:\n is disabled\n\n\nenable-owasp-modsecurity-crs\n\u00b6\n\n\nEnables the OWASP ModSecurity Core Rule Set (CRS). \ndefault:\n is disabled\n\n\nclient-header-buffer-size\n\u00b6\n\n\nAllows to configure a custom buffer size for reading client request header.\n\n\nReferences:\n\n\nhttp://nginx.org/en/docs/http/ngx_http_core_module.html#client_header_buffer_size\n\n\nclient-header-timeout\n\u00b6\n\n\nDefines a timeout for reading client request header, in seconds.\n\n\nReferences:\n\n\nhttp://nginx.org/en/docs/http/ngx_http_core_module.html#client_header_timeout\n\n\nclient-body-buffer-size\n\u00b6\n\n\nSets buffer size for reading client request body.\n\n\nReferences:\n\n\nhttp://nginx.org/en/docs/http/ngx_http_core_module.html#client_body_buffer_size\n\n\nclient-body-timeout\n\u00b6\n\n\nDefines a timeout for reading client request body, in seconds.\n\n\nReferences:\n\n\nhttp://nginx.org/en/docs/http/ngx_http_core_module.html#client_body_timeout\n\n\ndisable-access-log\n\u00b6\n\n\nDisables the Access Log from the entire Ingress Controller. \ndefault:\n '\"false\"'\n\n\nReferences:\n\n\nhttp://nginx.org/en/docs/http/ngx_http_log_module.html#access_log\n\n\ndisable-ipv6\n\u00b6\n\n\nDisable listening on IPV6. \ndefault:\n is disabled\n\n\ndisable-ipv6-dns\n\u00b6\n\n\nDisable IPV6 for nginx DNS resolver. \ndefault:\n is disabled\n\n\nenable-underscores-in-headers\n\u00b6\n\n\nEnables underscores in header names. \ndefault:\n is disabled\n\n\nignore-invalid-headers\n\u00b6\n\n\nSet if header fields with invalid names should be ignored.\n\ndefault:\n is enabled\n\n\nretry-non-idempotent\n\u00b6\n\n\nSince 1.9.13 NGINX will not retry non-idempotent requests (POST, LOCK, PATCH) in case of an error in the upstream server. The previous behavior can be restored using the value \"true\".\n\n\nerror-log-level\n\u00b6\n\n\nConfigures the logging level of errors. Log levels above are listed in the order of increasing severity.\n\n\nReferences:\n\n\nhttp://nginx.org/en/docs/ngx_core_module.html#error_log\n\n\nhttp2-max-field-size\n\u00b6\n\n\nLimits the maximum size of an HPACK-compressed request header field.\n\n\nReferences:\n\n\nhttps://nginx.org/en/docs/http/ngx_http_v2_module.html#http2_max_field_size\n\n\nhttp2-max-header-size\n\u00b6\n\n\nLimits the maximum size of the entire request header list after HPACK decompression.\n\n\nReferences:\n\n\nhttps://nginx.org/en/docs/http/ngx_http_v2_module.html#http2_max_header_size\n\n\nhsts\n\u00b6\n\n\nEnables or disables the header HSTS in servers running SSL.\nHTTP Strict Transport Security (often abbreviated as HSTS) is a security feature (HTTP header) that tell browsers that it should only be communicated with using HTTPS, instead of using HTTP. It provides protection against protocol downgrade attacks and cookie theft.\n\n\nReferences:\n\n\n\n\nhttps://developer.mozilla.org/en-US/docs/Web/Security/HTTP_strict_transport_security\n\n\nhttps://blog.qualys.com/securitylabs/2016/03/28/the-importance-of-a-proper-http-strict-transport-security-implementation-on-your-web-server\n\n\n\n\nhsts-include-subdomains\n\u00b6\n\n\nEnables or disables the use of HSTS in all the subdomains of the server-name.\n\n\nhsts-max-age\n\u00b6\n\n\nSets the time, in seconds, that the browser should remember that this site is only to be accessed using HTTPS.\n\n\nhsts-preload\n\u00b6\n\n\nEnables or disables the preload attribute in the HSTS feature (when it is enabled) dd\n\n\nkeep-alive\n\u00b6\n\n\nSets the time during which a keep-alive client connection will stay open on the server side. The zero value disables keep-alive client connections.\n\n\nReferences:\n\n\nhttp://nginx.org/en/docs/http/ngx_http_core_module.html#keepalive_timeout\n\n\nkeep-alive-requests\n\u00b6\n\n\nSets the maximum number of requests that can be served through one keep-alive connection.\n\n\nReferences:\n\n\nhttp://nginx.org/en/docs/http/ngx_http_core_module.html#keepalive_requests\n\n\nlarge-client-header-buffers\n\u00b6\n\n\nSets the maximum number and size of buffers used for reading large client request header. \ndefault:\n 4 8k\n\n\nReferences:\n\n\nhttp://nginx.org/en/docs/http/ngx_http_core_module.html#large_client_header_buffers\n\n\nlog-format-escape-json\n\u00b6\n\n\nSets if the escape parameter allows JSON (\"true\") or default characters escaping in variables (\"false\") Sets the nginx \nlog format\n.\n\n\nlog-format-upstream\n\u00b6\n\n\nSets the nginx \nlog format\n.\nExample for json output:\n\n\nconsolelog-format-upstream: '{ \"time\": \"$time_iso8601\", \"remote_addr\": \"$proxy_protocol_addr\",\"x-forward-for\": \"$proxy_add_x_forwarded_for\", \"request_id\": \"$req_id\", \"remote_user\":\"$remote_user\", \"bytes_sent\": $bytes_sent, \"request_time\": $request_time, \"status\":$status, \"vhost\": \"$host\", \"request_proto\": \"$server_protocol\", \"path\": \"$uri\",\"request_query\": \"$args\", \"request_length\": $request_length, \"duration\": $request_time,\"method\": \"$request_method\", \"http_referrer\": \"$http_referer\", \"http_user_agent\":\"$http_user_agent\" }'\n\n\nPlease check the \nlog-format\n for definition of each field.\n\n\nlog-format-stream\n\u00b6\n\n\nSets the nginx \nstream format\n.\n\n\nenable-multi-accept\n\u00b6\n\n\nIf disabled, a worker process will accept one new connection at a time. Otherwise, a worker process will accept all new connections at a time.\n\ndefault:\n true\n\n\nReferences:\n\n\nhttp://nginx.org/en/docs/ngx_core_module.html#multi_accept\n\n\nmax-worker-connections\n\u00b6\n\n\nSets the maximum number of simultaneous connections that can be opened by each \nworker process\n\n\nmap-hash-bucket-size\n\u00b6\n\n\nSets the bucket size for the \nmap variables hash tables\n. The details of setting up hash tables are provided in a separate \ndocument\n.\n\n\nproxy-real-ip-cidr\n\u00b6\n\n\nIf use-proxy-protocol is enabled, proxy-real-ip-cidr defines the default the IP/network address of your external load balancer.\n\n\nproxy-set-headers\n\u00b6\n\n\nSets custom headers from named configmap before sending traffic to backends. The value format is namespace/name. See \nexample\n\n\nserver-name-hash-max-size\n\u00b6\n\n\nSets the maximum size of the \nserver names hash tables\n used in server names,map directive\u2019s values, MIME types, names of request header strings, etc.\n\n\nReferences:\n\n\nhttp://nginx.org/en/docs/hash.html\n\n\nserver-name-hash-bucket-size\n\u00b6\n\n\nSets the size of the bucket for the server names hash tables.\n\n\nReferences:\n\n\n\n\nhttp://nginx.org/en/docs/hash.html\n\n\nhttp://nginx.org/en/docs/http/ngx_http_core_module.html#server_names_hash_bucket_size\n\n\n\n\nproxy-headers-hash-max-size\n\u00b6\n\n\nSets the maximum size of the proxy headers hash tables.\n\n\nReferences:\n\n\n\n\nhttp://nginx.org/en/docs/hash.html\n\n\nhttps://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_headers_hash_max_size\n\n\n\n\nreuse-port\n\u00b6\n\n\nInstructs NGINX to create an individual listening socket for each worker process (using the SO_REUSEPORT socket option), allowing a kernel to distribute incoming connections between worker processes\n\ndefault:\n true\n\n\nproxy-headers-hash-bucket-size\n\u00b6\n\n\nSets the size of the bucket for the proxy headers hash tables.\n\n\nReferences:\n\n\n\n\nhttp://nginx.org/en/docs/hash.html\n\n\nhttps://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_headers_hash_bucket_size\n\n\n\n\nserver-tokens\n\u00b6\n\n\nSend NGINX Server header in responses and display NGINX version in error pages. \ndefault:\n is enabled\n\n\nssl-ciphers\n\u00b6\n\n\nSets the \nciphers\n list to enable. The ciphers are specified in the format understood by the OpenSSL library.\n\n\nThe default cipher list is:\n \nECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256\n.\n\n\nThe ordering of a ciphersuite is very important because it decides which algorithms are going to be selected in priority. The recommendation above prioritizes algorithms that provide perfect \nforward secrecy\n.\n\n\nPlease check the \nMozilla SSL Configuration Generator\n.\n\n\nssl-ecdh-curve\n\u00b6\n\n\nSpecifies a curve for ECDHE ciphers.\n\n\nReferences:\n\n\nhttp://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_ecdh_curve\n\n\nssl-dh-param\n\u00b6\n\n\nSets the name of the secret that contains Diffie-Hellman key to help with \"Perfect Forward Secrecy\".\n\n\nReferences:\n\n\n\n\nhttps://wiki.openssl.org/index.php/Diffie-Hellman_parameters\n\n\nhttps://wiki.mozilla.org/Security/Server_Side_TLS#DHE_handshake_and_dhparam\n\n\nhttp://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_dhparam\n\n\n\n\nssl-protocols\n\u00b6\n\n\nSets the \nSSL protocols\n to use. The default is: \nTLSv1.2\n.\n\n\nPlease check the result of the configuration using \nhttps://ssllabs.com/ssltest/analyze.html\n or \nhttps://testssl.sh\n.\n\n\nssl-session-cache\n\u00b6\n\n\nEnables or disables the use of shared \nSSL cache\n among worker processes.\n\n\nssl-session-cache-size\n\u00b6\n\n\nSets the size of the \nSSL shared session cache\n between all worker processes.\n\n\nssl-session-tickets\n\u00b6\n\n\nEnables or disables session resumption through \nTLS session tickets\n.\n\n\nssl-session-ticket-key\n\u00b6\n\n\nSets the secret key used to encrypt and decrypt TLS session tickets. The value must be a valid base64 string.\nTo create a ticket: \nopenssl rand 80 | openssl enc -A -base64\n\n\nTLS session ticket-key\n, by default, a randomly generated key is used. \n\n\nssl-session-timeout\n\u00b6\n\n\nSets the time during which a client may \nreuse the session\n parameters stored in a cache.\n\n\nssl-buffer-size\n\u00b6\n\n\nSets the size of the \nSSL buffer\n used for sending data. The default of 4k helps NGINX to improve TLS Time To First Byte (TTTFB).\n\n\nReferences:\n\n\nhttps://www.igvita.com/2013/12/16/optimizing-nginx-tls-time-to-first-byte/\n\n\nuse-proxy-protocol\n\u00b6\n\n\nEnables or disables the \nPROXY protocol\n to receive client connection (real IP address) information passed through proxy servers and load balancers such as HAProxy and Amazon Elastic Load Balancer (ELB).\n\n\nproxy-protocol-header-timeout\n\u00b6\n\n\nSets the timeout value for receiving the proxy-protocol headers. The default of 5 seconds prevents the TLS passthrough handler from waiting indefinitely on a dropped connection.\n\ndefault:\n 5s\n\n\nuse-gzip\n\u00b6\n\n\nEnables or disables compression of HTTP responses using the \n\"gzip\" module\n.\nThe default mime type list to compress is: \napplication/atom+xml application/javascript application/x-javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/svg+xml image/x-icon text/css text/plain text/x-component\n.\n\n\nuse-geoip\n\u00b6\n\n\nEnables or disables \n\"geoip\" module\n that creates variables with values depending on the client IP address, using the precompiled MaxMind databases.\n\ndefault:\n true\n\n\nenable-brotli\n\u00b6\n\n\nEnables or disables compression of HTTP responses using the \n\"brotli\" module\n.\nThe default mime type list to compress is: \napplication/xml+rss application/atom+xml application/javascript application/x-javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/svg+xml image/x-icon text/css text/plain text/x-component\n. \ndefault:\n is disabled\n\n\n\n\nNote:\n Brotli does not works in Safari < 11. For more information see \nhttps://caniuse.com/#feat=brotli\n\n\n\n\nbrotli-level\n\u00b6\n\n\nSets the Brotli Compression Level that will be used. \ndefault:\n 4\n\n\nbrotli-types\n\u00b6\n\n\nSets the MIME Types that will be compressed on-the-fly by brotli.\n\ndefault:\n \napplication/xml+rss application/atom+xml application/javascript application/x-javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/svg+xml image/x-icon text/css text/plain text/x-component\n\n\nuse-http2\n\u00b6\n\n\nEnables or disables \nHTTP/2\n support in secure connections.\n\n\ngzip-level\n\u00b6\n\n\nSets the gzip Compression Level that will be used. \ndefault:\n 5\n\n\ngzip-types\n\u00b6\n\n\nSets the MIME types in addition to \"text/html\" to compress. The special value \"*\" matches any MIME type. Responses with the \"text/html\" type are always compressed if \nuse-gzip\n is enabled.\n\n\nworker-processes\n\u00b6\n\n\nSets the number of \nworker processes\n.\nThe default of \"auto\" means number of available CPU cores.\n\n\nworker-cpu-affinity\n\u00b6\n\n\nBinds worker processes to the sets of CPUs. \nworker_cpu_affinity\n.\nBy default worker processes are not bound to any specific CPUs. The value can be:\n\n\n\n\n\"\": empty string indicate no affinity is applied.\n\n\ncpumask: e.g. \n0001 0010 0100 1000\n to bind processes to specific cpus.\n\n\nauto: binding worker processes automatically to available CPUs.\n\n\n\n\nworker-shutdown-timeout\n\u00b6\n\n\nSets a timeout for Nginx to \nwait for worker to gracefully shutdown\n. \ndefault:\n \"10s\"\n\n\nload-balance\n\u00b6\n\n\nSets the algorithm to use for load balancing.\nThe value can either be:\n\n\n\n\nround_robin: to use the default round robin loadbalancer\n\n\nleast_conn: to use the least connected method (\nnote\n that this is available only in non-dynamic mode: \n--enable-dynamic-configuration=false\n)\n\n\nip_hash: to use a hash of the server for routing (\nnote\n that this is available only in non-dynamic mode: \n--enable-dynamic-configuration=false\n, but alternatively you can consider using \nnginx.ingress.kubernetes.io/upstream-hash-by\n)\n\n\newma: to use the Peak EWMA method for routing (\nimplementation\n)\n\n\n\n\nThe default is \nround_robin\n.\n\n\nReferences:\n\n\nhttp://nginx.org/en/docs/http/load_balancing.html\n\n\nvariables-hash-bucket-size\n\u00b6\n\n\nSets the bucket size for the variables hash table.\n\n\nReferences:\n\n\nhttp://nginx.org/en/docs/http/ngx_http_map_module.html#variables_hash_bucket_size\n\n\nvariables-hash-max-size\n\u00b6\n\n\nSets the maximum size of the variables hash table.\n\n\nReferences:\n\n\nhttp://nginx.org/en/docs/http/ngx_http_map_module.html#variables_hash_max_size\n\n\nupstream-keepalive-connections\n\u00b6\n\n\nActivates the cache for connections to upstream servers. The connections parameter sets the maximum number of idle keepalive connections to upstream servers that are preserved in the cache of each worker process. When this\nnumber is exceeded, the least recently used connections are closed. \ndefault:\n 32\n\n\nReferences:\n\n\nhttp://nginx.org/en/docs/http/ngx_http_upstream_module.html#keepalive\n\n\nlimit-conn-zone-variable\n\u00b6\n\n\nSets parameters for a shared memory zone that will keep states for various keys of \nlimit_conn_zone\n. The default of \"$binary_remote_addr\" variable\u2019s size is always 4 bytes for IPv4 addresses or 16 bytes for IPv6 addresses.\n\n\nproxy-stream-timeout\n\u00b6\n\n\nSets the timeout between two successive read or write operations on client or proxied server connections. If no data is transmitted within this time, the connection is closed.\n\n\nReferences:\n\n\nhttp://nginx.org/en/docs/stream/ngx_stream_proxy_module.html#proxy_timeout\n\n\nproxy-stream-responses\n\u00b6\n\n\nSets the number of datagrams expected from the proxied server in response to the client request if the UDP protocol is used.\n\n\nReferences:\n\n\nhttp://nginx.org/en/docs/stream/ngx_stream_proxy_module.html#proxy_responses\n\n\nbind-address\n\u00b6\n\n\nSets the addresses on which the server will accept requests instead of *. It should be noted that these addresses must exist in the runtime environment or the controller will crash loop.\n\n\nuse-forwarded-headers\n\u00b6\n\n\nIf true, NGINX passes the incoming \nX-Forwarded-*\n headers to upstreams. Use this option when NGINX is behind another L7 proxy / load balancer that is setting these headers.\n\n\nIf false, NGINX ignores incoming \nX-Forwarded-*\n headers, filling them with the request information it sees. Use this option if NGINX is exposed directly to the internet, or it's behind a L3/packet-based load balancer that doesn't alter the source IP in the packets.\n\n\nforwarded-for-header\n\u00b6\n\n\nSets the header field for identifying the originating IP address of a client. \ndefault:\n X-Forwarded-For\n\n\ncompute-full-forwarded-for\n\u00b6\n\n\nAppend the remote address to the X-Forwarded-For header instead of replacing it. When this option is enabled, the upstream application is responsible for extracting the client IP based on its own list of trusted proxies.\n\n\nproxy-add-original-uri-header\n\u00b6\n\n\nAdds an X-Original-Uri header with the original request URI to the backend request\n\n\ngenerate-request-id\n\u00b6\n\n\nEnsures that X-Request-ID is defaulted to a random value, if no X-Request-ID is present in the request\n\n\nenable-opentracing\n\u00b6\n\n\nEnables the nginx Opentracing extension. \ndefault:\n is disabled\n\n\nReferences:\n\n\nhttps://github.com/opentracing-contrib/nginx-opentracing\n\n\nzipkin-collector-host\n\u00b6\n\n\nSpecifies the host to use when uploading traces. It must be a valid URL.\n\n\nzipkin-collector-port\n\u00b6\n\n\nSpecifies the port to use when uploading traces. \ndefault:\n 9411\n\n\nzipkin-service-name\n\u00b6\n\n\nSpecifies the service name to use for any traces created. \ndefault:\n nginx\n\n\nzipkin-sample-rate\n\u00b6\n\n\nSpecifies sample rate for any traces created. \ndefault:\n 1.0\n\n\njaeger-collector-host\n\u00b6\n\n\nSpecifies the host to use when uploading traces. It must be a valid URL.\n\n\njaeger-collector-port\n\u00b6\n\n\nSpecifies the port to use when uploading traces. \ndefault:\n 6831\n\n\njaeger-service-name\n\u00b6\n\n\nSpecifies the service name to use for any traces created. \ndefault:\n nginx\n\n\njaeger-sampler-type\n\u00b6\n\n\nSpecifies the sampler to be used when sampling traces. The available samplers are: const, probabilistic, ratelimiting, remote. \ndefault:\n const\n\n\njaeger-sampler-param\n\u00b6\n\n\nSpecifies the argument to be passed to the sampler constructor. Must be a number.\nFor const this should be 0 to never sample and 1 to always sample. \ndefault:\n 1\n\n\nmain-snippet\n\u00b6\n\n\nAdds custom configuration to the main section of the nginx configuration.\n\n\nhttp-snippet\n\u00b6\n\n\nAdds custom configuration to the http section of the nginx configuration.\n\n\nserver-snippet\n\u00b6\n\n\nAdds custom configuration to all the servers in the nginx configuration.\n\n\nlocation-snippet\n\u00b6\n\n\nAdds custom configuration to all the locations in the nginx configuration.\n\n\ncustom-http-errors\n\u00b6\n\n\nEnables which HTTP codes should be passed for processing with the \nerror_page directive\n\n\nSetting at least one code also enables \nproxy_intercept_errors\n which are required to process error_page.\n\n\nExample usage: \ncustom-http-errors: 404,415\n\n\nproxy-body-size\n\u00b6\n\n\nSets the maximum allowed size of the client request body.\nSee NGINX \nclient_max_body_size\n.\n\n\nproxy-connect-timeout\n\u00b6\n\n\nSets the timeout for \nestablishing a connection with a proxied server\n. It should be noted that this timeout cannot usually exceed 75 seconds.\n\n\nproxy-read-timeout\n\u00b6\n\n\nSets the timeout in seconds for \nreading a response from the proxied server\n. The timeout is set only between two successive read operations, not for the transmission of the whole response.\n\n\nproxy-send-timeout\n\u00b6\n\n\nSets the timeout in seconds for \ntransmitting a request to the proxied server\n. The timeout is set only between two successive write operations, not for the transmission of the whole request.\n\n\nproxy-buffer-size\n\u00b6\n\n\nSets the size of the buffer used for \nreading the first part of the response\n received from the proxied server. This part usually contains a small response header.\n\n\nproxy-cookie-path\n\u00b6\n\n\nSets a text that \nshould be changed in the path attribute\n of the \u201cSet-Cookie\u201d header fields of a proxied server response.\n\n\nproxy-cookie-domain\n\u00b6\n\n\nSets a text that \nshould be changed in the domain attribute\n of the \u201cSet-Cookie\u201d header fields of a proxied server response.\n\n\nproxy-next-upstream\n\u00b6\n\n\nSpecifies in \nwhich cases\n a request should be passed to the next server.\n\n\nproxy-next-upstream-tries\n\u00b6\n\n\nLimit the number of \npossible tries\n a request should be passed to the next server.\n\n\nproxy-redirect-from\n\u00b6\n\n\nSets the original text that should be changed in the \"Location\" and \"Refresh\" header fields of a proxied server response. \ndefault:\n off\n\n\nReferences:\n\n\nhttp://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_redirect\n\n\nproxy-request-buffering\n\u00b6\n\n\nEnables or disables \nbuffering of a client request body\n.\n\n\nssl-redirect\n\u00b6\n\n\nSets the global value of redirects (301) to HTTPS if the server has a TLS certificate (defined in an Ingress rule).\n\ndefault:\n \"true\"\n\n\nwhitelist-source-range\n\u00b6\n\n\nSets the default whitelisted IPs for each \nserver\n block. This can be overwritten by an annotation on an Ingress rule.\nSee \nngx_http_access_module\n.\n\n\nskip-access-log-urls\n\u00b6\n\n\nSets a list of URLs that should not appear in the NGINX access log. This is useful with urls like \n/health\n or \nhealth-check\n that make \"complex\" reading the logs. \ndefault:\n is empty\n\n\nlimit-rate\n\u00b6\n\n\nLimits the rate of response transmission to a client. The rate is specified in bytes per second. The zero value disables rate limiting. The limit is set per a request, and so if a client simultaneously opens two connections, the overall rate will be twice as much as the specified limit.\n\n\nReferences:\n\n\nhttp://nginx.org/en/docs/http/ngx_http_core_module.html#limit_rate\n\n\nlimit-rate-after\n\u00b6\n\n\nSets the initial amount after which the further transmission of a response to a client will be rate limited.\n\n\nReferences:\n\n\nhttp://nginx.org/en/docs/http/ngx_http_core_module.html#limit_rate_after\n\n\nhttp-redirect-code\n\u00b6\n\n\nSets the HTTP status code to be used in redirects.\nSupported codes are \n301\n,\n302\n,\n307\n and \n308\n\n\ndefault:\n 308\n\n\n\n\nWhy the default code is 308?\n\n\nRFC 7238\n was created to define the 308 (Permanent Redirect) status code that is similar to 301 (Moved Permanently) but it keeps the payload in the redirect. This is important if the we send a redirect in methods like POST.\n\n\n\n\nproxy-buffering\n\u00b6\n\n\nEnables or disables \nbuffering of responses from the proxied server\n.\n\n\nlimit-req-status-code\n\u00b6\n\n\nSets the \nstatus code to return in response to rejected requests\n. \ndefault:\n 503\n\n\nno-tls-redirect-locations\n\u00b6\n\n\nA comma-separated list of locations on which http requests will never get redirected to their https counterpart.\n\ndefault:\n \"/.well-known/acme-challenge\"\n\n\nno-auth-locations\n\u00b6\n\n\nA comma-separated list of locations that should not get authenticated.\n\ndefault:\n \"/.well-known/acme-challenge\"", + "text": "ConfigMaps\n\u00b6\n\n\nConfigMaps allow you to decouple configuration artifacts from image content to keep containerized applications portable.\n\n\nThe ConfigMap API resource stores configuration data as key-value pairs. The data provides the configurations for system\ncomponents for the nginx-controller. Before you can begin using a config-map it must be \ndeployed\n.\n\n\nIn order to overwrite nginx-controller configuration values as seen in \nconfig.go\n,\nyou can add key-value pairs to the data section of the config-map. For Example:\n\n\ndata\n:\n\n \nmap-hash-bucket-size\n:\n \n\"128\"\n\n \nssl-protocols\n:\n \nSSLv2\n\n\n\n\n\n\n\nImportant\n\n\nThe key and values in a ConfigMap can only be strings.\nThis means that we want a value with boolean values we need to quote the values, like \"true\" or \"false\".\nSame for numbers, like \"100\".\n\n\n\"Slice\" types (defined below as \n[]string\n or \n[]int\n can be provided as a comma-delimited string.\n\n\n\n\nConfiguration options\n\u00b6\n\n\nThe following table shows a configuration option's name, type, and the default value:\n\n\n\n\n\n\n\n\nname\n\n\ntype\n\n\ndefault\n\n\n\n\n\n\n\n\n\n\nadd-headers\n\n\nstring\n\n\n\"\"\n\n\n\n\n\n\nallow-backend-server-header\n\n\nbool\n\n\n\"false\"\n\n\n\n\n\n\nhide-headers\n\n\nstring array\n\n\nempty\n\n\n\n\n\n\naccess-log-path\n\n\nstring\n\n\n\"/var/log/nginx/access.log\"\n\n\n\n\n\n\nerror-log-path\n\n\nstring\n\n\n\"/var/log/nginx/error.log\"\n\n\n\n\n\n\nenable-dynamic-tls-records\n\n\nbool\n\n\n\"true\"\n\n\n\n\n\n\nenable-modsecurity\n\n\nbool\n\n\n\"false\"\n\n\n\n\n\n\nenable-owasp-modsecurity-crs\n\n\nbool\n\n\n\"false\"\n\n\n\n\n\n\nclient-header-buffer-size\n\n\nstring\n\n\n\"1k\"\n\n\n\n\n\n\nclient-header-timeout\n\n\nint\n\n\n60\n\n\n\n\n\n\nclient-body-buffer-size\n\n\nstring\n\n\n\"8k\"\n\n\n\n\n\n\nclient-body-timeout\n\n\nint\n\n\n60\n\n\n\n\n\n\ndisable-access-log\n\n\nbool\n\n\nfalse\n\n\n\n\n\n\ndisable-ipv6\n\n\nbool\n\n\nfalse\n\n\n\n\n\n\ndisable-ipv6-dns\n\n\nbool\n\n\nfalse\n\n\n\n\n\n\nenable-underscores-in-headers\n\n\nbool\n\n\nfalse\n\n\n\n\n\n\nignore-invalid-headers\n\n\nbool\n\n\ntrue\n\n\n\n\n\n\nretry-non-idempotent\n\n\nbool\n\n\n\"false\"\n\n\n\n\n\n\nerror-log-level\n\n\nstring\n\n\n\"notice\"\n\n\n\n\n\n\nhttp2-max-field-size\n\n\nstring\n\n\n\"4k\"\n\n\n\n\n\n\nhttp2-max-header-size\n\n\nstring\n\n\n\"16k\"\n\n\n\n\n\n\nhttp2-max-requests\n\n\nint\n\n\n1000\n\n\n\n\n\n\nhsts\n\n\nbool\n\n\n\"true\"\n\n\n\n\n\n\nhsts-include-subdomains\n\n\nbool\n\n\n\"true\"\n\n\n\n\n\n\nhsts-max-age\n\n\nstring\n\n\n\"15724800\"\n\n\n\n\n\n\nhsts-preload\n\n\nbool\n\n\n\"false\"\n\n\n\n\n\n\nkeep-alive\n\n\nint\n\n\n75\n\n\n\n\n\n\nkeep-alive-requests\n\n\nint\n\n\n100\n\n\n\n\n\n\nlarge-client-header-buffers\n\n\nstring\n\n\n\"4 8k\"\n\n\n\n\n\n\nlog-format-escape-json\n\n\nbool\n\n\n\"false\"\n\n\n\n\n\n\nlog-format-upstream\n\n\nstring\n\n\n%v\n \n-\n \n[\n$the_real_ip\n]\n \n-\n \n$remote_user\n \n[\n$time_local\n]\n \n\"$request\"\n \n$status\n \n$body_bytes_sent\n \n\"$http_referer\"\n \n\"$http_user_agent\"\n \n$request_length\n \n$request_time\n \n[\n$proxy_upstream_name\n]\n \n$upstream_addr\n \n$upstream_response_length\n \n$upstream_response_time\n \n$upstream_status\n\n\n\n\n\n\nlog-format-stream\n\n\nstring\n\n\n[$time_local] $protocol $status $bytes_sent $bytes_received $session_time\n\n\n\n\n\n\nenable-multi-accept\n\n\nbool\n\n\n\"true\"\n\n\n\n\n\n\nmax-worker-connections\n\n\nint\n\n\n16384\n\n\n\n\n\n\nmap-hash-bucket-size\n\n\nint\n\n\n64\n\n\n\n\n\n\nnginx-status-ipv4-whitelist\n\n\n[]string\n\n\n\"127.0.0.1\"\n\n\n\n\n\n\nnginx-status-ipv6-whitelist\n\n\n[]string\n\n\n\"::1\"\n\n\n\n\n\n\nproxy-real-ip-cidr\n\n\n[]string\n\n\n\"0.0.0.0/0\"\n\n\n\n\n\n\nproxy-set-headers\n\n\nstring\n\n\n\"\"\n\n\n\n\n\n\nserver-name-hash-max-size\n\n\nint\n\n\n1024\n\n\n\n\n\n\nserver-name-hash-bucket-size\n\n\nint\n\n\n\n\n\n\n\n\n\nproxy-headers-hash-max-size\n\n\nint\n\n\n512\n\n\n\n\n\n\nproxy-headers-hash-bucket-size\n\n\nint\n\n\n64\n\n\n\n\n\n\nreuse-port\n\n\nbool\n\n\n\"true\"\n\n\n\n\n\n\nserver-tokens\n\n\nbool\n\n\n\"true\"\n\n\n\n\n\n\nssl-ciphers\n\n\nstring\n\n\n\"ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256\"\n\n\n\n\n\n\nssl-ecdh-curve\n\n\nstring\n\n\n\"auto\"\n\n\n\n\n\n\nssl-dh-param\n\n\nstring\n\n\n\"\"\n\n\n\n\n\n\nssl-protocols\n\n\nstring\n\n\n\"TLSv1.2\"\n\n\n\n\n\n\nssl-session-cache\n\n\nbool\n\n\n\"true\"\n\n\n\n\n\n\nssl-session-cache-size\n\n\nstring\n\n\n\"10m\"\n\n\n\n\n\n\nssl-session-tickets\n\n\nbool\n\n\n\"true\"\n\n\n\n\n\n\nssl-session-ticket-key\n\n\nstring\n\n\n\n\n\n\n\n\n\nssl-session-timeout\n\n\nstring\n\n\n\"10m\"\n\n\n\n\n\n\nssl-buffer-size\n\n\nstring\n\n\n\"4k\"\n\n\n\n\n\n\nuse-proxy-protocol\n\n\nbool\n\n\n\"false\"\n\n\n\n\n\n\nproxy-protocol-header-timeout\n\n\nstring\n\n\n\"5s\"\n\n\n\n\n\n\nuse-gzip\n\n\nbool\n\n\n\"true\"\n\n\n\n\n\n\nuse-geoip\n\n\nbool\n\n\n\"true\"\n\n\n\n\n\n\nenable-brotli\n\n\nbool\n\n\n\"false\"\n\n\n\n\n\n\nbrotli-level\n\n\nint\n\n\n4\n\n\n\n\n\n\nbrotli-types\n\n\nstring\n\n\n\"application/xml+rss application/atom+xml application/javascript application/x-javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/svg+xml image/x-icon text/css text/plain text/x-component\"\n\n\n\n\n\n\nuse-http2\n\n\nbool\n\n\n\"true\"\n\n\n\n\n\n\ngzip-level\n\n\nint\n\n\n5\n\n\n\n\n\n\ngzip-types\n\n\nstring\n\n\n\"application/atom+xml application/javascript application/x-javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/svg+xml image/x-icon text/css text/plain text/x-component\"\n\n\n\n\n\n\nworker-processes\n\n\nstring\n\n\n\n\n\n\n\n\n\nworker-cpu-affinity\n\n\nstring\n\n\n\"\"\n\n\n\n\n\n\nworker-shutdown-timeout\n\n\nstring\n\n\n\"10s\"\n\n\n\n\n\n\nload-balance\n\n\nstring\n\n\n\"round_robin\"\n\n\n\n\n\n\nvariables-hash-bucket-size\n\n\nint\n\n\n128\n\n\n\n\n\n\nvariables-hash-max-size\n\n\nint\n\n\n2048\n\n\n\n\n\n\nupstream-keepalive-connections\n\n\nint\n\n\n32\n\n\n\n\n\n\nlimit-conn-zone-variable\n\n\nstring\n\n\n\"$binary_remote_addr\"\n\n\n\n\n\n\nproxy-stream-timeout\n\n\nstring\n\n\n\"600s\"\n\n\n\n\n\n\nproxy-stream-responses\n\n\nint\n\n\n1\n\n\n\n\n\n\nbind-address\n\n\n[]string\n\n\n\"\"\n\n\n\n\n\n\nuse-forwarded-headers\n\n\nbool\n\n\n\"true\"\n\n\n\n\n\n\nforwarded-for-header\n\n\nstring\n\n\n\"X-Forwarded-For\"\n\n\n\n\n\n\ncompute-full-forwarded-for\n\n\nbool\n\n\n\"false\"\n\n\n\n\n\n\nproxy-add-original-uri-header\n\n\nbool\n\n\n\"true\"\n\n\n\n\n\n\ngenerate-request-id\n\n\nbool\n\n\n\"true\"\n\n\n\n\n\n\nenable-opentracing\n\n\nbool\n\n\n\"false\"\n\n\n\n\n\n\nzipkin-collector-host\n\n\nstring\n\n\n\"\"\n\n\n\n\n\n\nzipkin-collector-port\n\n\nint\n\n\n9411\n\n\n\n\n\n\nzipkin-service-name\n\n\nstring\n\n\n\"nginx\"\n\n\n\n\n\n\nzipkin-sample-rate\n\n\nfloat\n\n\n1.0\n\n\n\n\n\n\njaeger-collector-host\n\n\nstring\n\n\n\"\"\n\n\n\n\n\n\njaeger-collector-port\n\n\nint\n\n\n6831\n\n\n\n\n\n\njaeger-service-name\n\n\nstring\n\n\n\"nginx\"\n\n\n\n\n\n\njaeger-sampler-type\n\n\nstring\n\n\n\"const\"\n\n\n\n\n\n\njaeger-sampler-param\n\n\nstring\n\n\n\"1\"\n\n\n\n\n\n\nmain-snippet\n\n\nstring\n\n\n\"\"\n\n\n\n\n\n\nhttp-snippet\n\n\nstring\n\n\n\"\"\n\n\n\n\n\n\nserver-snippet\n\n\nstring\n\n\n\"\"\n\n\n\n\n\n\nlocation-snippet\n\n\nstring\n\n\n\"\"\n\n\n\n\n\n\ncustom-http-errors\n\n\n[]int\n\n\n[]int{}\n\n\n\n\n\n\nproxy-body-size\n\n\nstring\n\n\n\"1m\"\n\n\n\n\n\n\nproxy-connect-timeout\n\n\nint\n\n\n5\n\n\n\n\n\n\nproxy-read-timeout\n\n\nint\n\n\n60\n\n\n\n\n\n\nproxy-send-timeout\n\n\nint\n\n\n60\n\n\n\n\n\n\nproxy-buffer-size\n\n\nstring\n\n\n\"4k\"\n\n\n\n\n\n\nproxy-cookie-path\n\n\nstring\n\n\n\"off\"\n\n\n\n\n\n\nproxy-cookie-domain\n\n\nstring\n\n\n\"off\"\n\n\n\n\n\n\nproxy-next-upstream\n\n\nstring\n\n\n\"error timeout\"\n\n\n\n\n\n\nproxy-next-upstream-tries\n\n\nint\n\n\n3\n\n\n\n\n\n\nproxy-redirect-from\n\n\nstring\n\n\n\"off\"\n\n\n\n\n\n\nproxy-request-buffering\n\n\nstring\n\n\n\"on\"\n\n\n\n\n\n\nssl-redirect\n\n\nbool\n\n\n\"true\"\n\n\n\n\n\n\nwhitelist-source-range\n\n\n[]string\n\n\n[]string{}\n\n\n\n\n\n\nskip-access-log-urls\n\n\n[]string\n\n\n[]string{}\n\n\n\n\n\n\nlimit-rate\n\n\nint\n\n\n0\n\n\n\n\n\n\nlimit-rate-after\n\n\nint\n\n\n0\n\n\n\n\n\n\nhttp-redirect-code\n\n\nint\n\n\n308\n\n\n\n\n\n\nproxy-buffering\n\n\nstring\n\n\n\"off\"\n\n\n\n\n\n\nlimit-req-status-code\n\n\nint\n\n\n503\n\n\n\n\n\n\nno-tls-redirect-locations\n\n\nstring\n\n\n\"/.well-known/acme-challenge\"\n\n\n\n\n\n\nno-auth-locations\n\n\nstring\n\n\n\"/.well-known/acme-challenge\"\n\n\n\n\n\n\n\n\nadd-headers\n\u00b6\n\n\nSets custom headers from named configmap before sending traffic to the client. See \nproxy-set-headers\n. \nexample\n\n\nallow-backend-server-header\n\u00b6\n\n\nEnables the return of the header Server from the backend instead of the generic nginx string. \ndefault:\n is disabled\n\n\nhide-headers\n\u00b6\n\n\nSets additional header that will not be passed from the upstream server to the client response.\n\ndefault:\n empty\n\n\nReferences:\n\n\nhttp://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_hide_header\n\n\naccess-log-path\n\u00b6\n\n\nAccess log path. Goes to \n/var/log/nginx/access.log\n by default.\n\n\nNote:\n the file \n/var/log/nginx/access.log\n is a symlink to \n/dev/stdout\n\n\nerror-log-path\n\u00b6\n\n\nError log path. Goes to \n/var/log/nginx/error.log\n by default.\n\n\nNote:\n the file \n/var/log/nginx/error.log\n is a symlink to \n/dev/stderr\n\n\nReferences:\n\n\nhttp://nginx.org/en/docs/ngx_core_module.html#error_log\n\n\nenable-dynamic-tls-records\n\u00b6\n\n\nEnables dynamically sized TLS records to improve time-to-first-byte. \ndefault:\n is enabled\n\n\nReferences:\n\n\nhttps://blog.cloudflare.com/optimizing-tls-over-tcp-to-reduce-latency\n\n\nenable-modsecurity\n\u00b6\n\n\nEnables the modsecurity module for NGINX. \ndefault:\n is disabled\n\n\nenable-owasp-modsecurity-crs\n\u00b6\n\n\nEnables the OWASP ModSecurity Core Rule Set (CRS). \ndefault:\n is disabled\n\n\nclient-header-buffer-size\n\u00b6\n\n\nAllows to configure a custom buffer size for reading client request header.\n\n\nReferences:\n\n\nhttp://nginx.org/en/docs/http/ngx_http_core_module.html#client_header_buffer_size\n\n\nclient-header-timeout\n\u00b6\n\n\nDefines a timeout for reading client request header, in seconds.\n\n\nReferences:\n\n\nhttp://nginx.org/en/docs/http/ngx_http_core_module.html#client_header_timeout\n\n\nclient-body-buffer-size\n\u00b6\n\n\nSets buffer size for reading client request body.\n\n\nReferences:\n\n\nhttp://nginx.org/en/docs/http/ngx_http_core_module.html#client_body_buffer_size\n\n\nclient-body-timeout\n\u00b6\n\n\nDefines a timeout for reading client request body, in seconds.\n\n\nReferences:\n\n\nhttp://nginx.org/en/docs/http/ngx_http_core_module.html#client_body_timeout\n\n\ndisable-access-log\n\u00b6\n\n\nDisables the Access Log from the entire Ingress Controller. \ndefault:\n '\"false\"'\n\n\nReferences:\n\n\nhttp://nginx.org/en/docs/http/ngx_http_log_module.html#access_log\n\n\ndisable-ipv6\n\u00b6\n\n\nDisable listening on IPV6. \ndefault:\n is disabled\n\n\ndisable-ipv6-dns\n\u00b6\n\n\nDisable IPV6 for nginx DNS resolver. \ndefault:\n is disabled\n\n\nenable-underscores-in-headers\n\u00b6\n\n\nEnables underscores in header names. \ndefault:\n is disabled\n\n\nignore-invalid-headers\n\u00b6\n\n\nSet if header fields with invalid names should be ignored.\n\ndefault:\n is enabled\n\n\nretry-non-idempotent\n\u00b6\n\n\nSince 1.9.13 NGINX will not retry non-idempotent requests (POST, LOCK, PATCH) in case of an error in the upstream server. The previous behavior can be restored using the value \"true\".\n\n\nerror-log-level\n\u00b6\n\n\nConfigures the logging level of errors. Log levels above are listed in the order of increasing severity.\n\n\nReferences:\n\n\nhttp://nginx.org/en/docs/ngx_core_module.html#error_log\n\n\nhttp2-max-field-size\n\u00b6\n\n\nLimits the maximum size of an HPACK-compressed request header field.\n\n\nReferences:\n\n\nhttps://nginx.org/en/docs/http/ngx_http_v2_module.html#http2_max_field_size\n\n\nhttp2-max-header-size\n\u00b6\n\n\nLimits the maximum size of the entire request header list after HPACK decompression.\n\n\nReferences:\n\n\nhttps://nginx.org/en/docs/http/ngx_http_v2_module.html#http2_max_header_size\n\n\nhttp2-max-requests\n\u00b6\n\n\nSets the maximum number of requests (including push requests) that can be served through one HTTP/2 connection, after which the next client request will lead to connection closing and the need of establishing a new connection.\n\n\nReferences:\n\n\nhttp://nginx.org/en/docs/http/ngx_http_v2_module.html#http2_max_requests\n\n\nhsts\n\u00b6\n\n\nEnables or disables the header HSTS in servers running SSL.\nHTTP Strict Transport Security (often abbreviated as HSTS) is a security feature (HTTP header) that tell browsers that it should only be communicated with using HTTPS, instead of using HTTP. It provides protection against protocol downgrade attacks and cookie theft.\n\n\nReferences:\n\n\n\n\nhttps://developer.mozilla.org/en-US/docs/Web/Security/HTTP_strict_transport_security\n\n\nhttps://blog.qualys.com/securitylabs/2016/03/28/the-importance-of-a-proper-http-strict-transport-security-implementation-on-your-web-server\n\n\n\n\nhsts-include-subdomains\n\u00b6\n\n\nEnables or disables the use of HSTS in all the subdomains of the server-name.\n\n\nhsts-max-age\n\u00b6\n\n\nSets the time, in seconds, that the browser should remember that this site is only to be accessed using HTTPS.\n\n\nhsts-preload\n\u00b6\n\n\nEnables or disables the preload attribute in the HSTS feature (when it is enabled) dd\n\n\nkeep-alive\n\u00b6\n\n\nSets the time during which a keep-alive client connection will stay open on the server side. The zero value disables keep-alive client connections.\n\n\nReferences:\n\n\nhttp://nginx.org/en/docs/http/ngx_http_core_module.html#keepalive_timeout\n\n\nkeep-alive-requests\n\u00b6\n\n\nSets the maximum number of requests that can be served through one keep-alive connection.\n\n\nReferences:\n\n\nhttp://nginx.org/en/docs/http/ngx_http_core_module.html#keepalive_requests\n\n\nlarge-client-header-buffers\n\u00b6\n\n\nSets the maximum number and size of buffers used for reading large client request header. \ndefault:\n 4 8k\n\n\nReferences:\n\n\nhttp://nginx.org/en/docs/http/ngx_http_core_module.html#large_client_header_buffers\n\n\nlog-format-escape-json\n\u00b6\n\n\nSets if the escape parameter allows JSON (\"true\") or default characters escaping in variables (\"false\") Sets the nginx \nlog format\n.\n\n\nlog-format-upstream\n\u00b6\n\n\nSets the nginx \nlog format\n.\nExample for json output:\n\n\nconsolelog-format-upstream: '{ \"time\": \"$time_iso8601\", \"remote_addr\": \"$proxy_protocol_addr\",\"x-forward-for\": \"$proxy_add_x_forwarded_for\", \"request_id\": \"$req_id\", \"remote_user\":\"$remote_user\", \"bytes_sent\": $bytes_sent, \"request_time\": $request_time, \"status\":$status, \"vhost\": \"$host\", \"request_proto\": \"$server_protocol\", \"path\": \"$uri\",\"request_query\": \"$args\", \"request_length\": $request_length, \"duration\": $request_time,\"method\": \"$request_method\", \"http_referrer\": \"$http_referer\", \"http_user_agent\":\"$http_user_agent\" }'\n\n\nPlease check the \nlog-format\n for definition of each field.\n\n\nlog-format-stream\n\u00b6\n\n\nSets the nginx \nstream format\n.\n\n\nenable-multi-accept\n\u00b6\n\n\nIf disabled, a worker process will accept one new connection at a time. Otherwise, a worker process will accept all new connections at a time.\n\ndefault:\n true\n\n\nReferences:\n\n\nhttp://nginx.org/en/docs/ngx_core_module.html#multi_accept\n\n\nmax-worker-connections\n\u00b6\n\n\nSets the maximum number of simultaneous connections that can be opened by each \nworker process\n\n\nmap-hash-bucket-size\n\u00b6\n\n\nSets the bucket size for the \nmap variables hash tables\n. The details of setting up hash tables are provided in a separate \ndocument\n.\n\n\nproxy-real-ip-cidr\n\u00b6\n\n\nIf use-proxy-protocol is enabled, proxy-real-ip-cidr defines the default the IP/network address of your external load balancer.\n\n\nproxy-set-headers\n\u00b6\n\n\nSets custom headers from named configmap before sending traffic to backends. The value format is namespace/name. See \nexample\n\n\nserver-name-hash-max-size\n\u00b6\n\n\nSets the maximum size of the \nserver names hash tables\n used in server names,map directive\u2019s values, MIME types, names of request header strings, etc.\n\n\nReferences:\n\n\nhttp://nginx.org/en/docs/hash.html\n\n\nserver-name-hash-bucket-size\n\u00b6\n\n\nSets the size of the bucket for the server names hash tables.\n\n\nReferences:\n\n\n\n\nhttp://nginx.org/en/docs/hash.html\n\n\nhttp://nginx.org/en/docs/http/ngx_http_core_module.html#server_names_hash_bucket_size\n\n\n\n\nproxy-headers-hash-max-size\n\u00b6\n\n\nSets the maximum size of the proxy headers hash tables.\n\n\nReferences:\n\n\n\n\nhttp://nginx.org/en/docs/hash.html\n\n\nhttps://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_headers_hash_max_size\n\n\n\n\nreuse-port\n\u00b6\n\n\nInstructs NGINX to create an individual listening socket for each worker process (using the SO_REUSEPORT socket option), allowing a kernel to distribute incoming connections between worker processes\n\ndefault:\n true\n\n\nproxy-headers-hash-bucket-size\n\u00b6\n\n\nSets the size of the bucket for the proxy headers hash tables.\n\n\nReferences:\n\n\n\n\nhttp://nginx.org/en/docs/hash.html\n\n\nhttps://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_headers_hash_bucket_size\n\n\n\n\nserver-tokens\n\u00b6\n\n\nSend NGINX Server header in responses and display NGINX version in error pages. \ndefault:\n is enabled\n\n\nssl-ciphers\n\u00b6\n\n\nSets the \nciphers\n list to enable. The ciphers are specified in the format understood by the OpenSSL library.\n\n\nThe default cipher list is:\n \nECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256\n.\n\n\nThe ordering of a ciphersuite is very important because it decides which algorithms are going to be selected in priority. The recommendation above prioritizes algorithms that provide perfect \nforward secrecy\n.\n\n\nPlease check the \nMozilla SSL Configuration Generator\n.\n\n\nssl-ecdh-curve\n\u00b6\n\n\nSpecifies a curve for ECDHE ciphers.\n\n\nReferences:\n\n\nhttp://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_ecdh_curve\n\n\nssl-dh-param\n\u00b6\n\n\nSets the name of the secret that contains Diffie-Hellman key to help with \"Perfect Forward Secrecy\".\n\n\nReferences:\n\n\n\n\nhttps://wiki.openssl.org/index.php/Diffie-Hellman_parameters\n\n\nhttps://wiki.mozilla.org/Security/Server_Side_TLS#DHE_handshake_and_dhparam\n\n\nhttp://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_dhparam\n\n\n\n\nssl-protocols\n\u00b6\n\n\nSets the \nSSL protocols\n to use. The default is: \nTLSv1.2\n.\n\n\nPlease check the result of the configuration using \nhttps://ssllabs.com/ssltest/analyze.html\n or \nhttps://testssl.sh\n.\n\n\nssl-session-cache\n\u00b6\n\n\nEnables or disables the use of shared \nSSL cache\n among worker processes.\n\n\nssl-session-cache-size\n\u00b6\n\n\nSets the size of the \nSSL shared session cache\n between all worker processes.\n\n\nssl-session-tickets\n\u00b6\n\n\nEnables or disables session resumption through \nTLS session tickets\n.\n\n\nssl-session-ticket-key\n\u00b6\n\n\nSets the secret key used to encrypt and decrypt TLS session tickets. The value must be a valid base64 string.\nTo create a ticket: \nopenssl rand 80 | openssl enc -A -base64\n\n\nTLS session ticket-key\n, by default, a randomly generated key is used. \n\n\nssl-session-timeout\n\u00b6\n\n\nSets the time during which a client may \nreuse the session\n parameters stored in a cache.\n\n\nssl-buffer-size\n\u00b6\n\n\nSets the size of the \nSSL buffer\n used for sending data. The default of 4k helps NGINX to improve TLS Time To First Byte (TTTFB).\n\n\nReferences:\n\n\nhttps://www.igvita.com/2013/12/16/optimizing-nginx-tls-time-to-first-byte/\n\n\nuse-proxy-protocol\n\u00b6\n\n\nEnables or disables the \nPROXY protocol\n to receive client connection (real IP address) information passed through proxy servers and load balancers such as HAProxy and Amazon Elastic Load Balancer (ELB).\n\n\nproxy-protocol-header-timeout\n\u00b6\n\n\nSets the timeout value for receiving the proxy-protocol headers. The default of 5 seconds prevents the TLS passthrough handler from waiting indefinitely on a dropped connection.\n\ndefault:\n 5s\n\n\nuse-gzip\n\u00b6\n\n\nEnables or disables compression of HTTP responses using the \n\"gzip\" module\n.\nThe default mime type list to compress is: \napplication/atom+xml application/javascript application/x-javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/svg+xml image/x-icon text/css text/plain text/x-component\n.\n\n\nuse-geoip\n\u00b6\n\n\nEnables or disables \n\"geoip\" module\n that creates variables with values depending on the client IP address, using the precompiled MaxMind databases.\n\ndefault:\n true\n\n\nenable-brotli\n\u00b6\n\n\nEnables or disables compression of HTTP responses using the \n\"brotli\" module\n.\nThe default mime type list to compress is: \napplication/xml+rss application/atom+xml application/javascript application/x-javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/svg+xml image/x-icon text/css text/plain text/x-component\n. \ndefault:\n is disabled\n\n\n\n\nNote:\n Brotli does not works in Safari < 11. For more information see \nhttps://caniuse.com/#feat=brotli\n\n\n\n\nbrotli-level\n\u00b6\n\n\nSets the Brotli Compression Level that will be used. \ndefault:\n 4\n\n\nbrotli-types\n\u00b6\n\n\nSets the MIME Types that will be compressed on-the-fly by brotli.\n\ndefault:\n \napplication/xml+rss application/atom+xml application/javascript application/x-javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/svg+xml image/x-icon text/css text/plain text/x-component\n\n\nuse-http2\n\u00b6\n\n\nEnables or disables \nHTTP/2\n support in secure connections.\n\n\ngzip-level\n\u00b6\n\n\nSets the gzip Compression Level that will be used. \ndefault:\n 5\n\n\ngzip-types\n\u00b6\n\n\nSets the MIME types in addition to \"text/html\" to compress. The special value \"*\" matches any MIME type. Responses with the \"text/html\" type are always compressed if \nuse-gzip\n is enabled.\n\n\nworker-processes\n\u00b6\n\n\nSets the number of \nworker processes\n.\nThe default of \"auto\" means number of available CPU cores.\n\n\nworker-cpu-affinity\n\u00b6\n\n\nBinds worker processes to the sets of CPUs. \nworker_cpu_affinity\n.\nBy default worker processes are not bound to any specific CPUs. The value can be:\n\n\n\n\n\"\": empty string indicate no affinity is applied.\n\n\ncpumask: e.g. \n0001 0010 0100 1000\n to bind processes to specific cpus.\n\n\nauto: binding worker processes automatically to available CPUs.\n\n\n\n\nworker-shutdown-timeout\n\u00b6\n\n\nSets a timeout for Nginx to \nwait for worker to gracefully shutdown\n. \ndefault:\n \"10s\"\n\n\nload-balance\n\u00b6\n\n\nSets the algorithm to use for load balancing.\nThe value can either be:\n\n\n\n\nround_robin: to use the default round robin loadbalancer\n\n\nleast_conn: to use the least connected method (\nnote\n that this is available only in non-dynamic mode: \n--enable-dynamic-configuration=false\n)\n\n\nip_hash: to use a hash of the server for routing (\nnote\n that this is available only in non-dynamic mode: \n--enable-dynamic-configuration=false\n, but alternatively you can consider using \nnginx.ingress.kubernetes.io/upstream-hash-by\n)\n\n\newma: to use the Peak EWMA method for routing (\nimplementation\n)\n\n\n\n\nThe default is \nround_robin\n.\n\n\nReferences:\n\n\nhttp://nginx.org/en/docs/http/load_balancing.html\n\n\nvariables-hash-bucket-size\n\u00b6\n\n\nSets the bucket size for the variables hash table.\n\n\nReferences:\n\n\nhttp://nginx.org/en/docs/http/ngx_http_map_module.html#variables_hash_bucket_size\n\n\nvariables-hash-max-size\n\u00b6\n\n\nSets the maximum size of the variables hash table.\n\n\nReferences:\n\n\nhttp://nginx.org/en/docs/http/ngx_http_map_module.html#variables_hash_max_size\n\n\nupstream-keepalive-connections\n\u00b6\n\n\nActivates the cache for connections to upstream servers. The connections parameter sets the maximum number of idle keepalive connections to upstream servers that are preserved in the cache of each worker process. When this\nnumber is exceeded, the least recently used connections are closed. \ndefault:\n 32\n\n\nReferences:\n\n\nhttp://nginx.org/en/docs/http/ngx_http_upstream_module.html#keepalive\n\n\nlimit-conn-zone-variable\n\u00b6\n\n\nSets parameters for a shared memory zone that will keep states for various keys of \nlimit_conn_zone\n. The default of \"$binary_remote_addr\" variable\u2019s size is always 4 bytes for IPv4 addresses or 16 bytes for IPv6 addresses.\n\n\nproxy-stream-timeout\n\u00b6\n\n\nSets the timeout between two successive read or write operations on client or proxied server connections. If no data is transmitted within this time, the connection is closed.\n\n\nReferences:\n\n\nhttp://nginx.org/en/docs/stream/ngx_stream_proxy_module.html#proxy_timeout\n\n\nproxy-stream-responses\n\u00b6\n\n\nSets the number of datagrams expected from the proxied server in response to the client request if the UDP protocol is used.\n\n\nReferences:\n\n\nhttp://nginx.org/en/docs/stream/ngx_stream_proxy_module.html#proxy_responses\n\n\nbind-address\n\u00b6\n\n\nSets the addresses on which the server will accept requests instead of *. It should be noted that these addresses must exist in the runtime environment or the controller will crash loop.\n\n\nuse-forwarded-headers\n\u00b6\n\n\nIf true, NGINX passes the incoming \nX-Forwarded-*\n headers to upstreams. Use this option when NGINX is behind another L7 proxy / load balancer that is setting these headers.\n\n\nIf false, NGINX ignores incoming \nX-Forwarded-*\n headers, filling them with the request information it sees. Use this option if NGINX is exposed directly to the internet, or it's behind a L3/packet-based load balancer that doesn't alter the source IP in the packets.\n\n\nforwarded-for-header\n\u00b6\n\n\nSets the header field for identifying the originating IP address of a client. \ndefault:\n X-Forwarded-For\n\n\ncompute-full-forwarded-for\n\u00b6\n\n\nAppend the remote address to the X-Forwarded-For header instead of replacing it. When this option is enabled, the upstream application is responsible for extracting the client IP based on its own list of trusted proxies.\n\n\nproxy-add-original-uri-header\n\u00b6\n\n\nAdds an X-Original-Uri header with the original request URI to the backend request\n\n\ngenerate-request-id\n\u00b6\n\n\nEnsures that X-Request-ID is defaulted to a random value, if no X-Request-ID is present in the request\n\n\nenable-opentracing\n\u00b6\n\n\nEnables the nginx Opentracing extension. \ndefault:\n is disabled\n\n\nReferences:\n\n\nhttps://github.com/opentracing-contrib/nginx-opentracing\n\n\nzipkin-collector-host\n\u00b6\n\n\nSpecifies the host to use when uploading traces. It must be a valid URL.\n\n\nzipkin-collector-port\n\u00b6\n\n\nSpecifies the port to use when uploading traces. \ndefault:\n 9411\n\n\nzipkin-service-name\n\u00b6\n\n\nSpecifies the service name to use for any traces created. \ndefault:\n nginx\n\n\nzipkin-sample-rate\n\u00b6\n\n\nSpecifies sample rate for any traces created. \ndefault:\n 1.0\n\n\njaeger-collector-host\n\u00b6\n\n\nSpecifies the host to use when uploading traces. It must be a valid URL.\n\n\njaeger-collector-port\n\u00b6\n\n\nSpecifies the port to use when uploading traces. \ndefault:\n 6831\n\n\njaeger-service-name\n\u00b6\n\n\nSpecifies the service name to use for any traces created. \ndefault:\n nginx\n\n\njaeger-sampler-type\n\u00b6\n\n\nSpecifies the sampler to be used when sampling traces. The available samplers are: const, probabilistic, ratelimiting, remote. \ndefault:\n const\n\n\njaeger-sampler-param\n\u00b6\n\n\nSpecifies the argument to be passed to the sampler constructor. Must be a number.\nFor const this should be 0 to never sample and 1 to always sample. \ndefault:\n 1\n\n\nmain-snippet\n\u00b6\n\n\nAdds custom configuration to the main section of the nginx configuration.\n\n\nhttp-snippet\n\u00b6\n\n\nAdds custom configuration to the http section of the nginx configuration.\n\n\nserver-snippet\n\u00b6\n\n\nAdds custom configuration to all the servers in the nginx configuration.\n\n\nlocation-snippet\n\u00b6\n\n\nAdds custom configuration to all the locations in the nginx configuration.\n\n\ncustom-http-errors\n\u00b6\n\n\nEnables which HTTP codes should be passed for processing with the \nerror_page directive\n\n\nSetting at least one code also enables \nproxy_intercept_errors\n which are required to process error_page.\n\n\nExample usage: \ncustom-http-errors: 404,415\n\n\nproxy-body-size\n\u00b6\n\n\nSets the maximum allowed size of the client request body.\nSee NGINX \nclient_max_body_size\n.\n\n\nproxy-connect-timeout\n\u00b6\n\n\nSets the timeout for \nestablishing a connection with a proxied server\n. It should be noted that this timeout cannot usually exceed 75 seconds.\n\n\nproxy-read-timeout\n\u00b6\n\n\nSets the timeout in seconds for \nreading a response from the proxied server\n. The timeout is set only between two successive read operations, not for the transmission of the whole response.\n\n\nproxy-send-timeout\n\u00b6\n\n\nSets the timeout in seconds for \ntransmitting a request to the proxied server\n. The timeout is set only between two successive write operations, not for the transmission of the whole request.\n\n\nproxy-buffer-size\n\u00b6\n\n\nSets the size of the buffer used for \nreading the first part of the response\n received from the proxied server. This part usually contains a small response header.\n\n\nproxy-cookie-path\n\u00b6\n\n\nSets a text that \nshould be changed in the path attribute\n of the \u201cSet-Cookie\u201d header fields of a proxied server response.\n\n\nproxy-cookie-domain\n\u00b6\n\n\nSets a text that \nshould be changed in the domain attribute\n of the \u201cSet-Cookie\u201d header fields of a proxied server response.\n\n\nproxy-next-upstream\n\u00b6\n\n\nSpecifies in \nwhich cases\n a request should be passed to the next server.\n\n\nproxy-next-upstream-tries\n\u00b6\n\n\nLimit the number of \npossible tries\n a request should be passed to the next server.\n\n\nproxy-redirect-from\n\u00b6\n\n\nSets the original text that should be changed in the \"Location\" and \"Refresh\" header fields of a proxied server response. \ndefault:\n off\n\n\nReferences:\n\n\nhttp://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_redirect\n\n\nproxy-request-buffering\n\u00b6\n\n\nEnables or disables \nbuffering of a client request body\n.\n\n\nssl-redirect\n\u00b6\n\n\nSets the global value of redirects (301) to HTTPS if the server has a TLS certificate (defined in an Ingress rule).\n\ndefault:\n \"true\"\n\n\nwhitelist-source-range\n\u00b6\n\n\nSets the default whitelisted IPs for each \nserver\n block. This can be overwritten by an annotation on an Ingress rule.\nSee \nngx_http_access_module\n.\n\n\nskip-access-log-urls\n\u00b6\n\n\nSets a list of URLs that should not appear in the NGINX access log. This is useful with urls like \n/health\n or \nhealth-check\n that make \"complex\" reading the logs. \ndefault:\n is empty\n\n\nlimit-rate\n\u00b6\n\n\nLimits the rate of response transmission to a client. The rate is specified in bytes per second. The zero value disables rate limiting. The limit is set per a request, and so if a client simultaneously opens two connections, the overall rate will be twice as much as the specified limit.\n\n\nReferences:\n\n\nhttp://nginx.org/en/docs/http/ngx_http_core_module.html#limit_rate\n\n\nlimit-rate-after\n\u00b6\n\n\nSets the initial amount after which the further transmission of a response to a client will be rate limited.\n\n\nReferences:\n\n\nhttp://nginx.org/en/docs/http/ngx_http_core_module.html#limit_rate_after\n\n\nhttp-redirect-code\n\u00b6\n\n\nSets the HTTP status code to be used in redirects.\nSupported codes are \n301\n,\n302\n,\n307\n and \n308\n\n\ndefault:\n 308\n\n\n\n\nWhy the default code is 308?\n\n\nRFC 7238\n was created to define the 308 (Permanent Redirect) status code that is similar to 301 (Moved Permanently) but it keeps the payload in the redirect. This is important if the we send a redirect in methods like POST.\n\n\n\n\nproxy-buffering\n\u00b6\n\n\nEnables or disables \nbuffering of responses from the proxied server\n.\n\n\nlimit-req-status-code\n\u00b6\n\n\nSets the \nstatus code to return in response to rejected requests\n. \ndefault:\n 503\n\n\nno-tls-redirect-locations\n\u00b6\n\n\nA comma-separated list of locations on which http requests will never get redirected to their https counterpart.\n\ndefault:\n \"/.well-known/acme-challenge\"\n\n\nno-auth-locations\n\u00b6\n\n\nA comma-separated list of locations that should not get authenticated.\n\ndefault:\n \"/.well-known/acme-challenge\"", "title": "ConfigMaps" }, { @@ -392,7 +417,7 @@ }, { "location": "/user-guide/nginx-configuration/configmap/#configuration-options", - "text": "The following table shows a configuration option's name, type, and the default value: name type default add-headers string \"\" allow-backend-server-header bool \"false\" hide-headers string array empty access-log-path string \"/var/log/nginx/access.log\" error-log-path string \"/var/log/nginx/error.log\" enable-dynamic-tls-records bool \"true\" enable-modsecurity bool \"false\" enable-owasp-modsecurity-crs bool \"false\" client-header-buffer-size string \"1k\" client-header-timeout int 60 client-body-buffer-size string \"8k\" client-body-timeout int 60 disable-access-log bool false disable-ipv6 bool false disable-ipv6-dns bool false enable-underscores-in-headers bool false ignore-invalid-headers bool true retry-non-idempotent bool \"false\" error-log-level string \"notice\" http2-max-field-size string \"4k\" http2-max-header-size string \"16k\" hsts bool \"true\" hsts-include-subdomains bool \"true\" hsts-max-age string \"15724800\" hsts-preload bool \"false\" keep-alive int 75 keep-alive-requests int 100 large-client-header-buffers string \"4 8k\" log-format-escape-json bool \"false\" log-format-upstream string %v - [ $the_real_ip ] - $remote_user [ $time_local ] \"$request\" $status $body_bytes_sent \"$http_referer\" \"$http_user_agent\" $request_length $request_time [ $proxy_upstream_name ] $upstream_addr $upstream_response_length $upstream_response_time $upstream_status log-format-stream string [$time_local] $protocol $status $bytes_sent $bytes_received $session_time enable-multi-accept bool \"true\" max-worker-connections int 16384 map-hash-bucket-size int 64 nginx-status-ipv4-whitelist []string \"127.0.0.1\" nginx-status-ipv6-whitelist []string \"::1\" proxy-real-ip-cidr []string \"0.0.0.0/0\" proxy-set-headers string \"\" server-name-hash-max-size int 1024 server-name-hash-bucket-size int proxy-headers-hash-max-size int 512 proxy-headers-hash-bucket-size int 64 reuse-port bool \"true\" server-tokens bool \"true\" ssl-ciphers string \"ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256\" ssl-ecdh-curve string \"auto\" ssl-dh-param string \"\" ssl-protocols string \"TLSv1.2\" ssl-session-cache bool \"true\" ssl-session-cache-size string \"10m\" ssl-session-tickets bool \"true\" ssl-session-ticket-key string ssl-session-timeout string \"10m\" ssl-buffer-size string \"4k\" use-proxy-protocol bool \"false\" proxy-protocol-header-timeout string \"5s\" use-gzip bool \"true\" use-geoip bool \"true\" enable-brotli bool \"false\" brotli-level int 4 brotli-types string \"application/xml+rss application/atom+xml application/javascript application/x-javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/svg+xml image/x-icon text/css text/plain text/x-component\" use-http2 bool \"true\" gzip-level int 5 gzip-types string \"application/atom+xml application/javascript application/x-javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/svg+xml image/x-icon text/css text/plain text/x-component\" worker-processes string worker-cpu-affinity string \"\" worker-shutdown-timeout string \"10s\" load-balance string \"round_robin\" variables-hash-bucket-size int 128 variables-hash-max-size int 2048 upstream-keepalive-connections int 32 limit-conn-zone-variable string \"$binary_remote_addr\" proxy-stream-timeout string \"600s\" proxy-stream-responses int 1 bind-address []string \"\" use-forwarded-headers bool \"true\" forwarded-for-header string \"X-Forwarded-For\" compute-full-forwarded-for bool \"false\" proxy-add-original-uri-header bool \"true\" generate-request-id bool \"true\" enable-opentracing bool \"false\" zipkin-collector-host string \"\" zipkin-collector-port int 9411 zipkin-service-name string \"nginx\" zipkin-sample-rate float 1.0 jaeger-collector-host string \"\" jaeger-collector-port int 6831 jaeger-service-name string \"nginx\" jaeger-sampler-type string \"const\" jaeger-sampler-param string \"1\" main-snippet string \"\" http-snippet string \"\" server-snippet string \"\" location-snippet string \"\" custom-http-errors []int []int{} proxy-body-size string \"1m\" proxy-connect-timeout int 5 proxy-read-timeout int 60 proxy-send-timeout int 60 proxy-buffer-size string \"4k\" proxy-cookie-path string \"off\" proxy-cookie-domain string \"off\" proxy-next-upstream string \"error timeout\" proxy-next-upstream-tries int 3 proxy-redirect-from string \"off\" proxy-request-buffering string \"on\" ssl-redirect bool \"true\" whitelist-source-range []string []string{} skip-access-log-urls []string []string{} limit-rate int 0 limit-rate-after int 0 http-redirect-code int 308 proxy-buffering string \"off\" limit-req-status-code int 503 no-tls-redirect-locations string \"/.well-known/acme-challenge\" no-auth-locations string \"/.well-known/acme-challenge\"", + "text": "The following table shows a configuration option's name, type, and the default value: name type default add-headers string \"\" allow-backend-server-header bool \"false\" hide-headers string array empty access-log-path string \"/var/log/nginx/access.log\" error-log-path string \"/var/log/nginx/error.log\" enable-dynamic-tls-records bool \"true\" enable-modsecurity bool \"false\" enable-owasp-modsecurity-crs bool \"false\" client-header-buffer-size string \"1k\" client-header-timeout int 60 client-body-buffer-size string \"8k\" client-body-timeout int 60 disable-access-log bool false disable-ipv6 bool false disable-ipv6-dns bool false enable-underscores-in-headers bool false ignore-invalid-headers bool true retry-non-idempotent bool \"false\" error-log-level string \"notice\" http2-max-field-size string \"4k\" http2-max-header-size string \"16k\" http2-max-requests int 1000 hsts bool \"true\" hsts-include-subdomains bool \"true\" hsts-max-age string \"15724800\" hsts-preload bool \"false\" keep-alive int 75 keep-alive-requests int 100 large-client-header-buffers string \"4 8k\" log-format-escape-json bool \"false\" log-format-upstream string %v - [ $the_real_ip ] - $remote_user [ $time_local ] \"$request\" $status $body_bytes_sent \"$http_referer\" \"$http_user_agent\" $request_length $request_time [ $proxy_upstream_name ] $upstream_addr $upstream_response_length $upstream_response_time $upstream_status log-format-stream string [$time_local] $protocol $status $bytes_sent $bytes_received $session_time enable-multi-accept bool \"true\" max-worker-connections int 16384 map-hash-bucket-size int 64 nginx-status-ipv4-whitelist []string \"127.0.0.1\" nginx-status-ipv6-whitelist []string \"::1\" proxy-real-ip-cidr []string \"0.0.0.0/0\" proxy-set-headers string \"\" server-name-hash-max-size int 1024 server-name-hash-bucket-size int proxy-headers-hash-max-size int 512 proxy-headers-hash-bucket-size int 64 reuse-port bool \"true\" server-tokens bool \"true\" ssl-ciphers string \"ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256\" ssl-ecdh-curve string \"auto\" ssl-dh-param string \"\" ssl-protocols string \"TLSv1.2\" ssl-session-cache bool \"true\" ssl-session-cache-size string \"10m\" ssl-session-tickets bool \"true\" ssl-session-ticket-key string ssl-session-timeout string \"10m\" ssl-buffer-size string \"4k\" use-proxy-protocol bool \"false\" proxy-protocol-header-timeout string \"5s\" use-gzip bool \"true\" use-geoip bool \"true\" enable-brotli bool \"false\" brotli-level int 4 brotli-types string \"application/xml+rss application/atom+xml application/javascript application/x-javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/svg+xml image/x-icon text/css text/plain text/x-component\" use-http2 bool \"true\" gzip-level int 5 gzip-types string \"application/atom+xml application/javascript application/x-javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/svg+xml image/x-icon text/css text/plain text/x-component\" worker-processes string worker-cpu-affinity string \"\" worker-shutdown-timeout string \"10s\" load-balance string \"round_robin\" variables-hash-bucket-size int 128 variables-hash-max-size int 2048 upstream-keepalive-connections int 32 limit-conn-zone-variable string \"$binary_remote_addr\" proxy-stream-timeout string \"600s\" proxy-stream-responses int 1 bind-address []string \"\" use-forwarded-headers bool \"true\" forwarded-for-header string \"X-Forwarded-For\" compute-full-forwarded-for bool \"false\" proxy-add-original-uri-header bool \"true\" generate-request-id bool \"true\" enable-opentracing bool \"false\" zipkin-collector-host string \"\" zipkin-collector-port int 9411 zipkin-service-name string \"nginx\" zipkin-sample-rate float 1.0 jaeger-collector-host string \"\" jaeger-collector-port int 6831 jaeger-service-name string \"nginx\" jaeger-sampler-type string \"const\" jaeger-sampler-param string \"1\" main-snippet string \"\" http-snippet string \"\" server-snippet string \"\" location-snippet string \"\" custom-http-errors []int []int{} proxy-body-size string \"1m\" proxy-connect-timeout int 5 proxy-read-timeout int 60 proxy-send-timeout int 60 proxy-buffer-size string \"4k\" proxy-cookie-path string \"off\" proxy-cookie-domain string \"off\" proxy-next-upstream string \"error timeout\" proxy-next-upstream-tries int 3 proxy-redirect-from string \"off\" proxy-request-buffering string \"on\" ssl-redirect bool \"true\" whitelist-source-range []string []string{} skip-access-log-urls []string []string{} limit-rate int 0 limit-rate-after int 0 http-redirect-code int 308 proxy-buffering string \"off\" limit-req-status-code int 503 no-tls-redirect-locations string \"/.well-known/acme-challenge\" no-auth-locations string \"/.well-known/acme-challenge\"", "title": "Configuration options" }, { @@ -500,6 +525,11 @@ "text": "Limits the maximum size of the entire request header list after HPACK decompression. References: https://nginx.org/en/docs/http/ngx_http_v2_module.html#http2_max_header_size", "title": "http2-max-header-size" }, + { + "location": "/user-guide/nginx-configuration/configmap/#http2-max-requests", + "text": "Sets the maximum number of requests (including push requests) that can be served through one HTTP/2 connection, after which the next client request will lead to connection closing and the need of establishing a new connection. References: http://nginx.org/en/docs/http/ngx_http_v2_module.html#http2_max_requests", + "title": "http2-max-requests" + }, { "location": "/user-guide/nginx-configuration/configmap/#hsts", "text": "Enables or disables the header HSTS in servers running SSL.\nHTTP Strict Transport Security (often abbreviated as HSTS) is a security feature (HTTP header) that tell browsers that it should only be communicated with using HTTPS, instead of using HTTP. It provides protection against protocol downgrade attacks and cookie theft. References: https://developer.mozilla.org/en-US/docs/Web/Security/HTTP_strict_transport_security https://blog.qualys.com/securitylabs/2016/03/28/the-importance-of-a-proper-http-strict-transport-security-implementation-on-your-web-server", @@ -967,7 +997,7 @@ }, { "location": "/user-guide/nginx-configuration/custom-template/", - "text": "Custom NGINX template\n\u00b6\n\n\nThe NGINX template is located in the file \n/etc/nginx/template/nginx.tmpl\n.\n\n\nUsing a \nVolume\n it is possible to use a custom template. \nThis includes using a \nConfigmap\n as source of the template\n\n\n \nvolumeMounts\n:\n\n \n-\n \nmountPath\n:\n \n/etc/nginx/template\n\n \nname\n:\n \nnginx-template-volume\n\n \nreadOnly\n:\n \ntrue\n\n \n \nvolumes\n:\n\n \n-\n \nname\n:\n \nnginx-template-volume\n\n \nconfigMap\n:\n\n \nname\n:\n \nnginx-template\n\n \nitems\n:\n\n \n-\n \nkey\n:\n \nnginx.tmpl\n\n \npath\n:\n \nnginx.tmpl\n\n\n\n\n\n\nPlease note the template is tied to the Go code. Do not change names in the variable \n$cfg\n.\n\n\nFor more information about the template syntax please check the \nGo template package\n.\nIn addition to the built-in functions provided by the Go package the following functions are also available:\n\n\n\n\nempty: returns true if the specified parameter (string) is empty\n\n\ncontains: \nstrings.Contains\n\n\nhasPrefix: \nstrings.HasPrefix\n\n\nhasSuffix: \nstrings.HasSuffix\n\n\ntoUpper: \nstrings.ToUpper\n\n\ntoLower: \nstrings.ToLower\n\n\nbuildLocation: helps to build the NGINX Location section in each server\n\n\nbuildProxyPass: builds the reverse proxy configuration\n\n\nbuildRateLimit: helps to build a limit zone inside a location if contains a rate limit annotation\n\n\n\n\nTODO:\n\n\n\n\nbuildAuthLocation:\n\n\nbuildAuthResponseHeaders:\n\n\nbuildResolvers:\n\n\nbuildLogFormatUpstream:\n\n\nbuildDenyVariable:\n\n\nbuildUpstreamName:\n\n\nbuildForwardedFor:\n\n\nbuildAuthSignURL:\n\n\nbuildNextUpstream:\n\n\nfilterRateLimits:\n\n\nformatIP:\n\n\ngetenv:\n\n\ngetIngressInformation:\n\n\nserverConfig:\n\n\nisLocationAllowed:\n\n\nisValidClientBodyBufferSize:", + "text": "Custom NGINX template\n\u00b6\n\n\nThe NGINX template is located in the file \n/etc/nginx/template/nginx.tmpl\n.\n\n\nUsing a \nVolume\n it is possible to use a custom template. \nThis includes using a \nConfigmap\n as source of the template\n\n\n \nvolumeMounts\n:\n\n \n-\n \nmountPath\n:\n \n/etc/nginx/template\n\n \nname\n:\n \nnginx-template-volume\n\n \nreadOnly\n:\n \ntrue\n\n \n \nvolumes\n:\n\n \n-\n \nname\n:\n \nnginx-template-volume\n\n \nconfigMap\n:\n\n \nname\n:\n \nnginx-template\n\n \nitems\n:\n\n \n-\n \nkey\n:\n \nnginx.tmpl\n\n \npath\n:\n \nnginx.tmpl\n\n\n\n\n\nPlease note the template is tied to the Go code. Do not change names in the variable \n$cfg\n.\n\n\nFor more information about the template syntax please check the \nGo template package\n.\nIn addition to the built-in functions provided by the Go package the following functions are also available:\n\n\n\n\nempty: returns true if the specified parameter (string) is empty\n\n\ncontains: \nstrings.Contains\n\n\nhasPrefix: \nstrings.HasPrefix\n\n\nhasSuffix: \nstrings.HasSuffix\n\n\ntoUpper: \nstrings.ToUpper\n\n\ntoLower: \nstrings.ToLower\n\n\nbuildLocation: helps to build the NGINX Location section in each server\n\n\nbuildProxyPass: builds the reverse proxy configuration\n\n\nbuildRateLimit: helps to build a limit zone inside a location if contains a rate limit annotation\n\n\n\n\nTODO:\n\n\n\n\nbuildAuthLocation:\n\n\nbuildAuthResponseHeaders:\n\n\nbuildResolvers:\n\n\nbuildLogFormatUpstream:\n\n\nbuildDenyVariable:\n\n\nbuildUpstreamName:\n\n\nbuildForwardedFor:\n\n\nbuildAuthSignURL:\n\n\nbuildNextUpstream:\n\n\nfilterRateLimits:\n\n\nformatIP:\n\n\ngetenv:\n\n\ngetIngressInformation:\n\n\nserverConfig:\n\n\nisLocationAllowed:\n\n\nisValidClientBodyBufferSize:", "title": "Custom NGINX template" }, { @@ -977,7 +1007,7 @@ }, { "location": "/user-guide/nginx-configuration/log-format/", - "text": "Log format\n\u00b6\n\n\nThe default configuration uses a custom logging format to add additional information about upstreams, response time and status.\n\n\nlog_format upstreaminfo\n\n\n '\n{{\n \nif\n \n$\ncfg.useProxyProtocol\n \n}}\n$proxy_protocol_addr\n{{\n \nelse\n \n}}\n$remote_addr\n{{\n \nend\n \n}}\n - '\n\n\n '[$the_real_ip] - $remote_user [$time_local] \"$request\" '\n\n\n '$status $body_bytes_sent \"$http_referer\" \"$http_user_agent\" '\n\n\n '$request_length $request_time [$proxy_upstream_name] $upstream_addr '\n\n\n '$upstream_response_length $upstream_response_time $upstream_status';\n\n\n\n\n\n\n\n\n\n\n\n\nPlaceholder\n\n\nDescription\n\n\n\n\n\n\n\n\n\n\n$proxy_protocol_addr\n\n\nremote address if proxy protocol is enabled\n\n\n\n\n\n\n$remote_addr\n\n\nremote address if proxy protocol is disabled (default)\n\n\n\n\n\n\n$the_real_ip\n\n\nthe source IP address of the client\n\n\n\n\n\n\n$remote_user\n\n\nuser name supplied with the Basic authentication\n\n\n\n\n\n\n$time_local\n\n\nlocal time in the Common Log Format\n\n\n\n\n\n\n$request\n\n\nfull original request line\n\n\n\n\n\n\n$status\n\n\nresponse status\n\n\n\n\n\n\n$body_bytes_sent\n\n\nnumber of bytes sent to a client, not counting the response header\n\n\n\n\n\n\n$http_referer\n\n\nvalue of the Referer header\n\n\n\n\n\n\n$http_user_agent\n\n\nvalue of User-Agent header\n\n\n\n\n\n\n$request_length\n\n\nrequest length (including request line, header, and request body)\n\n\n\n\n\n\n$request_time\n\n\ntime elapsed since the first bytes were read from the client\n\n\n\n\n\n\n$proxy_upstream_name\n\n\nname of the upstream. The format is \nupstream---\n\n\n\n\n\n\n$upstream_addr\n\n\nthe IP address and port (or the path to the domain socket) of the upstream server. If several servers were contacted during request processing, their addresses are separated by commas.\n\n\n\n\n\n\n$upstream_response_length\n\n\nthe length of the response obtained from the upstream server\n\n\n\n\n\n\n$upstream_response_time\n\n\ntime spent on receiving the response from the upstream server as seconds with millisecond resolution\n\n\n\n\n\n\n$upstream_status\n\n\nstatus code of the response obtained from the upstream server\n\n\n\n\n\n\n\n\nAdditional available variables:\n\n\n\n\n\n\n\n\nPlaceholder\n\n\nDescription\n\n\n\n\n\n\n\n\n\n\n$namespace\n\n\nnamespace of the ingress\n\n\n\n\n\n\n$ingress_name\n\n\nname of the ingress\n\n\n\n\n\n\n$service_name\n\n\nname of the service\n\n\n\n\n\n\n$service_port\n\n\nport of the service\n\n\n\n\n\n\n\n\nSources:\n\n\n\n\nUpstream variables\n\n\nEmbedded variables", + "text": "Log format\n\u00b6\n\n\nThe default configuration uses a custom logging format to add additional information about upstreams, response time and status.\n\n\nlog_format upstreaminfo\n\n\n '\n{{\n \nif\n \n$\ncfg.useProxyProtocol\n \n}}\n$proxy_protocol_addr\n{{\n \nelse\n \n}}\n$remote_addr\n{{\n \nend\n \n}}\n - '\n\n\n '[$the_real_ip] - $remote_user [$time_local] \"$request\" '\n\n\n '$status $body_bytes_sent \"$http_referer\" \"$http_user_agent\" '\n\n\n '$request_length $request_time [$proxy_upstream_name] $upstream_addr '\n\n\n '$upstream_response_length $upstream_response_time $upstream_status';\n\n\n\n\n\n\n\n\n\n\n\nPlaceholder\n\n\nDescription\n\n\n\n\n\n\n\n\n\n\n$proxy_protocol_addr\n\n\nremote address if proxy protocol is enabled\n\n\n\n\n\n\n$remote_addr\n\n\nremote address if proxy protocol is disabled (default)\n\n\n\n\n\n\n$the_real_ip\n\n\nthe source IP address of the client\n\n\n\n\n\n\n$remote_user\n\n\nuser name supplied with the Basic authentication\n\n\n\n\n\n\n$time_local\n\n\nlocal time in the Common Log Format\n\n\n\n\n\n\n$request\n\n\nfull original request line\n\n\n\n\n\n\n$status\n\n\nresponse status\n\n\n\n\n\n\n$body_bytes_sent\n\n\nnumber of bytes sent to a client, not counting the response header\n\n\n\n\n\n\n$http_referer\n\n\nvalue of the Referer header\n\n\n\n\n\n\n$http_user_agent\n\n\nvalue of User-Agent header\n\n\n\n\n\n\n$request_length\n\n\nrequest length (including request line, header, and request body)\n\n\n\n\n\n\n$request_time\n\n\ntime elapsed since the first bytes were read from the client\n\n\n\n\n\n\n$proxy_upstream_name\n\n\nname of the upstream. The format is \nupstream---\n\n\n\n\n\n\n$upstream_addr\n\n\nthe IP address and port (or the path to the domain socket) of the upstream server. If several servers were contacted during request processing, their addresses are separated by commas.\n\n\n\n\n\n\n$upstream_response_length\n\n\nthe length of the response obtained from the upstream server\n\n\n\n\n\n\n$upstream_response_time\n\n\ntime spent on receiving the response from the upstream server as seconds with millisecond resolution\n\n\n\n\n\n\n$upstream_status\n\n\nstatus code of the response obtained from the upstream server\n\n\n\n\n\n\n\n\nAdditional available variables:\n\n\n\n\n\n\n\n\nPlaceholder\n\n\nDescription\n\n\n\n\n\n\n\n\n\n\n$namespace\n\n\nnamespace of the ingress\n\n\n\n\n\n\n$ingress_name\n\n\nname of the ingress\n\n\n\n\n\n\n$service_name\n\n\nname of the service\n\n\n\n\n\n\n$service_port\n\n\nport of the service\n\n\n\n\n\n\n\n\nSources:\n\n\n\n\nUpstream variables\n\n\nEmbedded variables", "title": "Log format" }, { @@ -1017,7 +1047,7 @@ }, { "location": "/user-guide/exposing-tcp-udp-services/", - "text": "Exposing TCP and UDP services\n\u00b6\n\n\nIngress does not support TCP or UDP services. For this reason this Ingress controller uses the flags \n--tcp-services-configmap\n and \n--udp-services-configmap\n to point to an existing config map where the key is the external port to use and the value indicates the service to expose using the format:\n\n::[PROXY]:[PROXY]\n\n\nIt is also possible to use a number or the name of the port. The two last fields are optional.\nAdding \nPROXY\n in either or both of the two last fields we can use Proxy Protocol decoding (listen) and/or encoding (proxy_pass) in a TCP service (https://www.nginx.com/resources/admin-guide/proxy-protocol/).\n\n\nThe next example shows how to expose the service \nexample-go\n running in the namespace \ndefault\n in the port \n8080\n using the port \n9000\n\n\napiVersion\n:\n \nv1\n\n\nkind\n:\n \nConfigMap\n\n\nmetadata\n:\n\n \nname\n:\n \ntcp-services\n\n \nnamespace\n:\n \ningress-nginx\n\n\ndata\n:\n\n \n9000\n:\n \n\"default/example-go:8080\"\n\n\n\n\n\n\nSince 1.9.13 NGINX provides \nUDP Load Balancing\n.\nThe next example shows how to expose the service \nkube-dns\n running in the namespace \nkube-system\n in the port \n53\n using the port \n53\n\n\napiVersion\n:\n \nv1\n\n\nkind\n:\n \nConfigMap\n\n\nmetadata\n:\n\n \nname\n:\n \nudp-services\n\n \nnamespace\n:\n \ningress-nginx\n\n\ndata\n:\n\n\n \u00a0\n53\n:\n \n\"kube-system/kube-dns:53\"", + "text": "Exposing TCP and UDP services\n\u00b6\n\n\nIngress does not support TCP or UDP services. For this reason this Ingress controller uses the flags \n--tcp-services-configmap\n and \n--udp-services-configmap\n to point to an existing config map where the key is the external port to use and the value indicates the service to expose using the format:\n\n::[PROXY]:[PROXY]\n\n\nIt is also possible to use a number or the name of the port. The two last fields are optional.\nAdding \nPROXY\n in either or both of the two last fields we can use Proxy Protocol decoding (listen) and/or encoding (proxy_pass) in a TCP service (https://www.nginx.com/resources/admin-guide/proxy-protocol/).\n\n\nThe next example shows how to expose the service \nexample-go\n running in the namespace \ndefault\n in the port \n8080\n using the port \n9000\n\n\napiVersion\n:\n \nv1\n\n\nkind\n:\n \nConfigMap\n\n\nmetadata\n:\n\n \nname\n:\n \ntcp-services\n\n \nnamespace\n:\n \ningress-nginx\n\n\ndata\n:\n\n \n9000\n:\n \n\"default/example-go:8080\"\n\n\n\n\n\nSince 1.9.13 NGINX provides \nUDP Load Balancing\n.\nThe next example shows how to expose the service \nkube-dns\n running in the namespace \nkube-system\n in the port \n53\n using the port \n53\n\n\napiVersion\n:\n \nv1\n\n\nkind\n:\n \nConfigMap\n\n\nmetadata\n:\n\n \nname\n:\n \nudp-services\n\n \nnamespace\n:\n \ningress-nginx\n\n\ndata\n:\n\n\n \u00a0\n53\n:\n \n\"kube-system/kube-dns:53\"", "title": "Exposing TCP and UDP services" }, { @@ -1082,7 +1112,7 @@ }, { "location": "/user-guide/monitoring/", - "text": "Prometheus and Grafana installation\n\u00b6\n\n\nThis tutorial will show you how to install \nPrometheus\n and \nGrafana\n for scraping the metrics of the NGINX Ingress controller.\n\n\n\n\nImportant\n\n\nThis example uses \nemptyDir\n volumes for Prometheus and Grafana. This means once the pod gets terminated you will lose all the data.\n\n\n\n\nBefore You Begin\n\u00b6\n\n\nThe NGINX Ingress controller should already be deployed according to the deployment instructions \nhere\n.\n\n\nNote that the yaml files used in this tutorial are stored in the \ndeploy/monitoring\n folder of the GitHub repository \nkubernetes/ingress-nginx\n.\n\n\nDeploy and configure Prometheus Server\n\u00b6\n\n\nThe Prometheus server must be configured so that it can discover endpoints of services. If a Prometheus server is already running in the cluster and if it is configured in a way that it can find the ingress controller pods, no extra configuration is needed.\n\n\nIf there is no existing Prometheus server running, the rest of this tutorial will guide you through the steps needed to deploy a properly configured Prometheus server.\n\n\nRunning the following command deploys the prometheus configuration in Kubernetes:\n\n\nkubectl create -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/monitoring/configuration.yaml\n\n\nconfigmap \"prometheus-configuration\" created\n\n\n\n\n\n\nRunning the following command deploys prometheus in Kubernetes:\n\n\nkubectl create -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/monitoring/prometheus.yaml\n\n\nclusterrole \"prometheus-server\" created\n\n\nserviceaccount \"prometheus-server\" created\n\n\nclusterrolebinding \"prometheus-server\" created\n\n\ndeployment \"prometheus-server\" created\n\n\nservice \"prometheus-service\" created\n\n\n\n\n\n\nPrometheus Dashboard\n\u00b6\n\n\nOpen Prometheus dashboard in a web browser:\n\n\nkubectl get svc -n ingress-nginx\n\n\nNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE\n\n\ndefault-http-backend ClusterIP 10.103.59.201 80/TCP 3d\n\n\ningress-nginx NodePort 10.97.44.72 80:30100/TCP,443:30154/TCP,10254:32049/TCP 5h\n\n\nprometheus NodePort 10.98.233.86 9090:32630/TCP 1m\n\n\n\n\n\n\nObtain the IP address of the nodes in the running cluster:\n\n\nkubectl get nodes -o wide\n\n\n\n\n\n\nIn some cases where the node only have internal IP adresses we need to execute:\n\n\nkubectl get nodes --selector=kubernetes.io/role!=master -o jsonpath={.items[*].status.addresses[?\\(@.type==\\\"InternalIP\\\"\\)].address}\n\n\n10.192.0.2 10.192.0.3 10.192.0.4\n\n\n\n\n\n\nOpen your browser and visit the following URL: \nhttp://{node IP address}:{prometheus-svc-nodeport}\n to load the Prometheus Dashboard.\n\n\nAccording to the above example, this URL will be http://10.192.0.3:32630\n\n\n\n\nGrafana\n\u00b6\n\n\nkubectl create -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/monitoring/grafana.yaml\n\n\n\n\n\n\nkubectl get svc -n ingress-nginx\n\n\nNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE\n\n\ndefault-http-backend ClusterIP 10.103.59.201 80/TCP 3d\n\n\ningress-nginx NodePort 10.97.44.72 80:30100/TCP,443:30154/TCP,10254:32049/TCP 5h\n\n\nprometheus NodePort 10.98.233.86 9090:32630/TCP 10m\n\n\ngrafana NodePort 10.98.233.86 9090:31086/TCP 10m\n\n\n\n\n\n\nOpen your browser and visit the following URL: \nhttp://{node IP address}:{grafana-svc-nodeport}\n to load the Grafana Dashboard.\nAccording to the above example, this URL will be http://10.192.0.3:31086\n\n\nThe username and password is \nadmin\n\n\nAfter the login you can import the Grafana dashboard from \nhttps://github.com/kubernetes/ingress-nginx/tree/master/deploy/grafana/dashboards", + "text": "Prometheus and Grafana installation\n\u00b6\n\n\nThis tutorial will show you how to install \nPrometheus\n and \nGrafana\n for scraping the metrics of the NGINX Ingress controller.\n\n\n\n\nImportant\n\n\nThis example uses \nemptyDir\n volumes for Prometheus and Grafana. This means once the pod gets terminated you will lose all the data.\n\n\n\n\nBefore You Begin\n\u00b6\n\n\nThe NGINX Ingress controller should already be deployed according to the deployment instructions \nhere\n.\n\n\nNote that the yaml files used in this tutorial are stored in the \ndeploy/monitoring\n folder of the GitHub repository \nkubernetes/ingress-nginx\n.\n\n\nDeploy and configure Prometheus Server\n\u00b6\n\n\nThe Prometheus server must be configured so that it can discover endpoints of services. If a Prometheus server is already running in the cluster and if it is configured in a way that it can find the ingress controller pods, no extra configuration is needed.\n\n\nIf there is no existing Prometheus server running, the rest of this tutorial will guide you through the steps needed to deploy a properly configured Prometheus server.\n\n\nRunning the following command deploys the prometheus configuration in Kubernetes:\n\n\nkubectl create -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/monitoring/configuration.yaml\n\n\nconfigmap \"prometheus-configuration\" created\n\n\n\n\n\nRunning the following command deploys prometheus in Kubernetes:\n\n\nkubectl create -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/monitoring/prometheus.yaml\n\n\nclusterrole \"prometheus-server\" created\n\n\nserviceaccount \"prometheus-server\" created\n\n\nclusterrolebinding \"prometheus-server\" created\n\n\ndeployment \"prometheus-server\" created\n\n\nservice \"prometheus-service\" created\n\n\n\n\n\nPrometheus Dashboard\n\u00b6\n\n\nOpen Prometheus dashboard in a web browser:\n\n\nkubectl get svc -n ingress-nginx\n\n\nNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE\n\n\ndefault-http-backend ClusterIP 10.103.59.201 80/TCP 3d\n\n\ningress-nginx NodePort 10.97.44.72 80:30100/TCP,443:30154/TCP,10254:32049/TCP 5h\n\n\nprometheus NodePort 10.98.233.86 9090:32630/TCP 1m\n\n\n\n\n\nObtain the IP address of the nodes in the running cluster:\n\n\nkubectl get nodes -o wide\n\n\n\n\n\nIn some cases where the node only have internal IP adresses we need to execute:\n\n\nkubectl get nodes --selector=kubernetes.io/role!=master -o jsonpath={.items[*].status.addresses[?\\(@.type==\\\"InternalIP\\\"\\)].address}\n\n\n10.192.0.2 10.192.0.3 10.192.0.4\n\n\n\n\n\nOpen your browser and visit the following URL: \nhttp://{node IP address}:{prometheus-svc-nodeport}\n to load the Prometheus Dashboard.\n\n\nAccording to the above example, this URL will be http://10.192.0.3:32630\n\n\n\n\nGrafana\n\u00b6\n\n\nkubectl create -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/monitoring/grafana.yaml\n\n\n\n\n\nkubectl get svc -n ingress-nginx\n\n\nNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE\n\n\ndefault-http-backend ClusterIP 10.103.59.201 80/TCP 3d\n\n\ningress-nginx NodePort 10.97.44.72 80:30100/TCP,443:30154/TCP,10254:32049/TCP 5h\n\n\nprometheus NodePort 10.98.233.86 9090:32630/TCP 10m\n\n\ngrafana NodePort 10.98.233.86 9090:31086/TCP 10m\n\n\n\n\n\nOpen your browser and visit the following URL: \nhttp://{node IP address}:{grafana-svc-nodeport}\n to load the Grafana Dashboard.\nAccording to the above example, this URL will be http://10.192.0.3:31086\n\n\nThe username and password is \nadmin\n\n\nAfter the login you can import the Grafana dashboard from \nhttps://github.com/kubernetes/ingress-nginx/tree/master/deploy/grafana/dashboards", "title": "Prometheus and Grafana installation" }, { @@ -1112,7 +1142,7 @@ }, { "location": "/user-guide/multiple-ingress/", - "text": "Multiple Ingress controllers\n\u00b6\n\n\nIf you're running multiple ingress controllers, or running on a cloud provider that natively handles ingress such as GKE,\nyou need to specify the annotation \nkubernetes.io/ingress.class: \"nginx\"\n in all ingresses that you would like the ingress-nginx controller to claim.\n\n\nFor instance,\n\n\nmetadata\n:\n\n \nname\n:\n \nfoo\n\n \nannotations\n:\n\n \nkubernetes.io/ingress.class\n:\n \n\"gce\"\n\n\n\n\n\n\nwill target the GCE controller, forcing the nginx controller to ignore it, while an annotation like\n\n\nmetadata\n:\n\n \nname\n:\n \nfoo\n\n \nannotations\n:\n\n \nkubernetes.io/ingress.class\n:\n \n\"nginx\"\n\n\n\n\n\n\nwill target the nginx controller, forcing the GCE controller to ignore it.\n\n\nTo reiterate, setting the annotation to any value which does not match a valid ingress class will force the NGINX Ingress controller to ignore your Ingress.\nIf you are only running a single NGINX ingress controller, this can be achieved by setting the annotation to any value except \"nginx\" or an empty string.\n\n\nDo this if you wish to use one of the other Ingress controllers at the same time as the NGINX controller.\n\n\nMultiple ingress-nginx controllers\n\u00b6\n\n\nThis mechanism also provides users the ability to run \nmultiple\n NGINX ingress controllers (e.g. one which serves public traffic, one which serves \"internal\" traffic).\nTo do this, the option \n--ingress-class\n must be changed to a value unique for the cluster within the definition of the replication controller.\nHere is a partial example:\n\n\nspec\n:\n\n \ntemplate\n:\n\n \nspec\n:\n\n \ncontainers\n:\n\n \n-\n \nname\n:\n \nnginx-ingress-internal-controller\n\n \nargs\n:\n\n \n-\n \n/nginx-ingress-controller\n\n \n-\n \n'--default-backend-service=ingress/nginx-ingress-default-backend'\n\n \n-\n \n'--election-id=ingress-controller-leader-internal'\n\n \n-\n \n'--ingress-class=nginx-internal'\n\n \n-\n \n'--configmap=ingress/nginx-ingress-internal-controller'\n\n\n\n\n\n\n\n\nImportant\n\n\nDeploying multiple Ingress controllers, of different types (e.g., \ningress-nginx\n & \ngce\n), and not specifying a class annotation will\nresult in both or all controllers fighting to satisfy the Ingress, and all of them racing to update Ingress status field in confusing ways.\n\n\nWhen running multiple ingress-nginx controllers, it will only process an unset class annotation if one of the controllers uses the default\n\n--ingress-class\n value (see \nIsValid\n method in \ninternal/ingress/annotations/class/main.go\n), otherwise the class annotation become required.", + "text": "Multiple Ingress controllers\n\u00b6\n\n\nIf you're running multiple ingress controllers, or running on a cloud provider that natively handles ingress such as GKE,\nyou need to specify the annotation \nkubernetes.io/ingress.class: \"nginx\"\n in all ingresses that you would like the ingress-nginx controller to claim.\n\n\nFor instance,\n\n\nmetadata\n:\n\n \nname\n:\n \nfoo\n\n \nannotations\n:\n\n \nkubernetes.io/ingress.class\n:\n \n\"gce\"\n\n\n\n\n\nwill target the GCE controller, forcing the nginx controller to ignore it, while an annotation like\n\n\nmetadata\n:\n\n \nname\n:\n \nfoo\n\n \nannotations\n:\n\n \nkubernetes.io/ingress.class\n:\n \n\"nginx\"\n\n\n\n\n\nwill target the nginx controller, forcing the GCE controller to ignore it.\n\n\nTo reiterate, setting the annotation to any value which does not match a valid ingress class will force the NGINX Ingress controller to ignore your Ingress.\nIf you are only running a single NGINX ingress controller, this can be achieved by setting the annotation to any value except \"nginx\" or an empty string.\n\n\nDo this if you wish to use one of the other Ingress controllers at the same time as the NGINX controller.\n\n\nMultiple ingress-nginx controllers\n\u00b6\n\n\nThis mechanism also provides users the ability to run \nmultiple\n NGINX ingress controllers (e.g. one which serves public traffic, one which serves \"internal\" traffic).\nTo do this, the option \n--ingress-class\n must be changed to a value unique for the cluster within the definition of the replication controller.\nHere is a partial example:\n\n\nspec\n:\n\n \ntemplate\n:\n\n \nspec\n:\n\n \ncontainers\n:\n\n \n-\n \nname\n:\n \nnginx-ingress-internal-controller\n\n \nargs\n:\n\n \n-\n \n/nginx-ingress-controller\n\n \n-\n \n'--default-backend-service=ingress/nginx-ingress-default-backend'\n\n \n-\n \n'--election-id=ingress-controller-leader-internal'\n\n \n-\n \n'--ingress-class=nginx-internal'\n\n \n-\n \n'--configmap=ingress/nginx-ingress-internal-controller'\n\n\n\n\n\n\n\nImportant\n\n\nDeploying multiple Ingress controllers, of different types (e.g., \ningress-nginx\n & \ngce\n), and not specifying a class annotation will\nresult in both or all controllers fighting to satisfy the Ingress, and all of them racing to update Ingress status field in confusing ways.\n\n\nWhen running multiple ingress-nginx controllers, it will only process an unset class annotation if one of the controllers uses the default\n\n--ingress-class\n value (see \nIsValid\n method in \ninternal/ingress/annotations/class/main.go\n), otherwise the class annotation become required.", "title": "Multiple Ingress controllers" }, { @@ -1127,7 +1157,7 @@ }, { "location": "/user-guide/tls/", - "text": "TLS/HTTPS\n\u00b6\n\n\nTLS Secrets\n\u00b6\n\n\nAnytime we reference a TLS secret, we mean a PEM-encoded X.509, RSA (2048) secret.\n\n\nYou can generate a self-signed certificate and private key with with:\n\n\n$ openssl req -x509 -nodes -days \n365\n -newkey rsa:2048 -keyout \n${\nKEY_FILE\n}\n -out \n${\nCERT_FILE\n}\n -subj \n\"/CN=\n${\nHOST\n}\n/O=\n${\nHOST\n}\n\"\n`\n\n\n\n\n\n\nThen create the secret in the cluster via:\n\n\nkubectl create secret tls \n${\nCERT_NAME\n}\n --key \n${\nKEY_FILE\n}\n --cert \n${\nCERT_FILE\n}\n\n\n\n\n\n\nThe resulting secret will be of type \nkubernetes.io/tls\n.\n\n\nDefault SSL Certificate\n\u00b6\n\n\nNGINX provides the option to configure a server as a catch-all with\n\nserver_name\n\nfor requests that do not match any of the configured server names.\nThis configuration works without out-of-the-box for HTTP traffic.\nFor HTTPS, a certificate is naturally required.\n\n\nFor this reason the Ingress controller provides the flag \n--default-ssl-certificate\n.\nThe secret referred to by this flag contains the default certificate to be used when\naccessing the catch-all server.\nIf this flag is not provided NGINX will use a self-signed certificate.\n\n\nFor instance, if you have a TLS secret \nfoo-tls\n in the \ndefault\n namespace,\nadd \n--default-ssl-certificate=default/foo-tls\n in the \nnginx-controller\n deployment.\n\n\nSSL Passthrough\n\u00b6\n\n\nThe flag \n--enable-ssl-passthrough\n enables the SSL passthrough feature.\nBy default this feature is disabled.\n\n\nThis is required to enable passthrough backends in Ingress configurations.\n\n\nTODO: Improve this documentation.\n\n\nHTTP Strict Transport Security\n\u00b6\n\n\nHTTP Strict Transport Security (HSTS) is an opt-in security enhancement specified\nthrough the use of a special response header. Once a supported browser receives\nthis header that browser will prevent any communications from being sent over\nHTTP to the specified domain and will instead send all communications over HTTPS.\n\n\nHSTS is enabled by default.\n\n\nTo disable this behavior use \nhsts: \"false\"\n in the configuration \nConfigMap\n.\n\n\nServer-side HTTPS enforcement through redirect\n\u00b6\n\n\nBy default the controller redirects HTTP clients to the HTTPS port\n443 using a 308 Permanent Redirect response if TLS is enabled for that Ingress.\n\n\nThis can be disabled globally using \nssl-redirect: \"false\"\n in the NGINX \nconfig map\n,\nor per-Ingress with the \nnginx.ingress.kubernetes.io/ssl-redirect: \"false\"\n\nannotation in the particular resource.\n\n\n\n\nTip\n\n\nWhen using SSL offloading outside of cluster (e.g. AWS ELB) it may be useful to enforce a\nredirect to HTTPS even when there is no TLS certificate available.\nThis can be achieved by using the \nnginx.ingress.kubernetes.io/force-ssl-redirect: \"true\"\n\nannotation in the particular resource.\n\n\n\n\nAutomated Certificate Management with Kube-Lego\n\u00b6\n\n\n\n\nTip\n\n\nKube-Lego has reached end-of-life and is being\nreplaced by \ncert-manager\n.\n\n\n\n\nKube-Lego\n automatically requests missing or expired certificates from \nLet's Encrypt\n\nby monitoring ingress resources and their referenced secrets.\n\n\nTo enable this for an ingress resource you have to add an annotation:\n\n\nkubectl annotate ing ingress-demo kubernetes.io/tls-acme=\"true\"\n\n\n\n\n\n\nTo setup Kube-Lego you can take a look at this \nfull example\n.\nThe first version to fully support Kube-Lego is Nginx Ingress controller 0.8.\n\n\nDefault TLS Version and Ciphers\n\u00b6\n\n\nTo provide the most secure baseline configuration possible,\n\n\nnginx-ingress defaults to using TLS 1.2 only and a \nsecure set of TLS ciphers\n.\n\n\nLegacy TLS\n\u00b6\n\n\nThe default configuration, though secure, does not support some older browsers and operating systems.\n\n\nFor instance, TLS 1.1+ is only enabled by default from Android 5.0 on. At the time of writing,\nMay 2018, \napproximately 15% of Android devices\n\nare not compatible with nginx-ingress's default configuration.\n\n\nTo change this default behavior, use a \nConfigMap\n.\n\n\nA sample ConfigMap fragment to allow these older clients to connect could look something like the following:\n\n\nkind\n:\n \nConfigMap\n\n\napiVersion\n:\n \nv1\n\n\nmetadata\n:\n\n \nname\n:\n \nnginx\n-\nconfig\n\n\ndata\n:\n\n \nssl\n-\nciphers\n:\n \n\"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:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA\"\n\n \nssl\n-\nprotocols\n:\n \n\"TLSv1 TLSv1.1 TLSv1.2\"", + "text": "TLS/HTTPS\n\u00b6\n\n\nTLS Secrets\n\u00b6\n\n\nAnytime we reference a TLS secret, we mean a PEM-encoded X.509, RSA (2048) secret.\n\n\nYou can generate a self-signed certificate and private key with with:\n\n\n$ openssl req -x509 -nodes -days \n365\n -newkey rsa:2048 -keyout \n${\nKEY_FILE\n}\n -out \n${\nCERT_FILE\n}\n -subj \n\"/CN=\n${\nHOST\n}\n/O=\n${\nHOST\n}\n\"\n`\n\n\n\n\n\nThen create the secret in the cluster via:\n\n\nkubectl create secret tls \n${\nCERT_NAME\n}\n --key \n${\nKEY_FILE\n}\n --cert \n${\nCERT_FILE\n}\n\n\n\n\n\nThe resulting secret will be of type \nkubernetes.io/tls\n.\n\n\nDefault SSL Certificate\n\u00b6\n\n\nNGINX provides the option to configure a server as a catch-all with\n\nserver_name\n\nfor requests that do not match any of the configured server names.\nThis configuration works without out-of-the-box for HTTP traffic.\nFor HTTPS, a certificate is naturally required.\n\n\nFor this reason the Ingress controller provides the flag \n--default-ssl-certificate\n.\nThe secret referred to by this flag contains the default certificate to be used when\naccessing the catch-all server.\nIf this flag is not provided NGINX will use a self-signed certificate.\n\n\nFor instance, if you have a TLS secret \nfoo-tls\n in the \ndefault\n namespace,\nadd \n--default-ssl-certificate=default/foo-tls\n in the \nnginx-controller\n deployment.\n\n\nSSL Passthrough\n\u00b6\n\n\nThe flag \n--enable-ssl-passthrough\n enables the SSL passthrough feature.\nBy default this feature is disabled.\n\n\nThis is required to enable passthrough backends in Ingress configurations.\n\n\nTODO: Improve this documentation.\n\n\nHTTP Strict Transport Security\n\u00b6\n\n\nHTTP Strict Transport Security (HSTS) is an opt-in security enhancement specified\nthrough the use of a special response header. Once a supported browser receives\nthis header that browser will prevent any communications from being sent over\nHTTP to the specified domain and will instead send all communications over HTTPS.\n\n\nHSTS is enabled by default.\n\n\nTo disable this behavior use \nhsts: \"false\"\n in the configuration \nConfigMap\n.\n\n\nServer-side HTTPS enforcement through redirect\n\u00b6\n\n\nBy default the controller redirects HTTP clients to the HTTPS port\n443 using a 308 Permanent Redirect response if TLS is enabled for that Ingress.\n\n\nThis can be disabled globally using \nssl-redirect: \"false\"\n in the NGINX \nconfig map\n,\nor per-Ingress with the \nnginx.ingress.kubernetes.io/ssl-redirect: \"false\"\n\nannotation in the particular resource.\n\n\n\n\nTip\n\n\nWhen using SSL offloading outside of cluster (e.g. AWS ELB) it may be useful to enforce a\nredirect to HTTPS even when there is no TLS certificate available.\nThis can be achieved by using the \nnginx.ingress.kubernetes.io/force-ssl-redirect: \"true\"\n\nannotation in the particular resource.\n\n\n\n\nAutomated Certificate Management with Kube-Lego\n\u00b6\n\n\n\n\nTip\n\n\nKube-Lego has reached end-of-life and is being\nreplaced by \ncert-manager\n.\n\n\n\n\nKube-Lego\n automatically requests missing or expired certificates from \nLet's Encrypt\n\nby monitoring ingress resources and their referenced secrets.\n\n\nTo enable this for an ingress resource you have to add an annotation:\n\n\nkubectl annotate ing ingress-demo kubernetes.io/tls-acme=\"true\"\n\n\n\n\n\nTo setup Kube-Lego you can take a look at this \nfull example\n.\nThe first version to fully support Kube-Lego is Nginx Ingress controller 0.8.\n\n\nDefault TLS Version and Ciphers\n\u00b6\n\n\nTo provide the most secure baseline configuration possible,\n\n\nnginx-ingress defaults to using TLS 1.2 only and a \nsecure set of TLS ciphers\n.\n\n\nLegacy TLS\n\u00b6\n\n\nThe default configuration, though secure, does not support some older browsers and operating systems.\n\n\nFor instance, TLS 1.1+ is only enabled by default from Android 5.0 on. At the time of writing,\nMay 2018, \napproximately 15% of Android devices\n\nare not compatible with nginx-ingress's default configuration.\n\n\nTo change this default behavior, use a \nConfigMap\n.\n\n\nA sample ConfigMap fragment to allow these older clients to connect could look something like the following:\n\n\nkind\n:\n \nConfigMap\n\n\napiVersion\n:\n \nv1\n\n\nmetadata\n:\n\n \nname\n:\n \nnginx\n-\nconfig\n\n\ndata\n:\n\n \nssl\n-\nciphers\n:\n \n\"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:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA\"\n\n \nssl\n-\nprotocols\n:\n \n\"TLSv1 TLSv1.1 TLSv1.2\"", "title": "TLS/HTTPS" }, { @@ -1187,7 +1217,7 @@ }, { "location": "/user-guide/third-party-addons/opentracing/", - "text": "OpenTracing\n\u00b6\n\n\nEnables requests served by nginx for distributed tracing via The OpenTracing Project.\n\n\nUsing the third party module \nopentracing-contrib/nginx-opentracing\n the NGINX ingress controller can configure NGINX to enable \nOpenTracing\n instrumentation.\nBy default this feature is disabled.\n\n\nUsage\n\u00b6\n\n\nTo enable the instrumentation we must enable opentracing in the configuration configmap:\n\n\ndata\n:\n\n \nenable\n-\nopentracing\n:\n \n\"true\"\n\n\n\n\n\n\nWe must also set the host to use when uploading traces:\n\n\nzipkin-collector-host: zipkin.default.svc.cluster.local\njaeger-collector-host: jaeger-collector.default.svc.cluster.local\n\n\n\n\n\nNext you will need to deploy a distributed tracing system which uses OpenTracing. Both \nZipkin\n and\n\nJaeger\n have been tested.\n\n\nOther optional configuration options:\n\n\n# specifies the port to use when uploading traces\nzipkin-collector-port\n\n# specifies the service name to use for any traces created, Default: nginx\nzipkin-service-name\n\n# specifies sample rate for any traces created. Default: 1.0\nzipkin-sample-rate\n\n# specifies the port to use when uploading traces\njaeger-collector-port\n\n# specifies the service name to use for any traces created, Default: nginx\njaeger-service-name\n\n# specifies the sampler to be used when sampling traces.\n# The available samplers are: const, probabilistic, ratelimiting, remote, Default: const\njaeger-sampler-type\n\n# specifies the argument to be passed to the sampler constructor, Default: 1\njaeger-sampler-param\n\n\n\n\n\nExamples\n\u00b6\n\n\nThe following examples show how to deploy and test different distributed tracing systems. These example can be performed\nusing Minikube.\n\n\nZipkin\n\u00b6\n\n\nIn the \nrnburn/zipkin-date-server\n\ngithub repository is an example of a dockerized date service. To install the example and zipkin collector run:\n\n\nkubectl create -f https://raw.githubusercontent.com/rnburn/zipkin-date-server/master/kubernetes/zipkin.yaml\nkubectl create -f https://raw.githubusercontent.com/rnburn/zipkin-date-server/master/kubernetes/deployment.yaml\n\n\n\n\n\nAlso we need to configure the NGINX controller configmap with the required values:\n\n\n$ \necho\n \n'\n\n\napiVersion: v1\n\n\nkind: ConfigMap\n\n\ndata:\n\n\n enable-opentracing: \"true\"\n\n\n zipkin-collector-host: zipkin.default.svc.cluster.local\n\n\nmetadata:\n\n\n name: nginx-load-balancer-conf\n\n\n namespace: kube-system\n\n\n'\n \n|\n kubectl replace -f -\n\n\n\n\n\nIn the zipkin interface we can see the details:\n\n\n\nJaeger\n\u00b6\n\n\n\n\n\n\nEnable Ingress addon in minikube:\n \n$ minikube addons \nenable\n ingress\n\n\n\n\n\n\nAdd minikube IP to /etc/hosts:\n \n$ \necho\n \n\"\n$(\nminikube ip\n)\n example.com\"\n \n|\n sudo tee -a /etc/hosts\n\n\n\n\n\n\nApply a Basic Service and Ingress Resource:\n ```\n # Create Echoheaders Deployment\n $ kubectl run echoheaders --image=k8s.gcr.io/echoserver:1.4 --replicas=1 --port=8080\n\n\nExpose as a Cluster-IP\n\u00b6\n\n\n$ kubectl expose deployment echoheaders --port=80 --target-port=8080 --name=echoheaders-x\n\n\nApply the Ingress Resource\n\u00b6\n\n\n$ echo '\n apiVersion: extensions/v1beta1\n kind: Ingress\n metadata:\n name: echo-ingress\n spec:\n rules:\n - host: example.com\n http:\n paths:\n - backend:\n serviceName: echoheaders-x\n servicePort: 80\n path: /echo\n ' | kubectl apply -f -\n```\n\n\n\n\n\n\nEnable OpenTracing and set the zipkin-collector-host:\n \n$ \necho\n \n'\n apiVersion: v1\n kind: ConfigMap\n data:\n enable-opentracing: \"true\"\n zipkin-collector-host: zipkin.default.svc.cluster.local\n jaeger-collector-host: jaeger-collector.default.svc.cluster.local\n metadata:\n name: nginx-load-balancer-conf\n namespace: kube-system\n '\n \n|\n kubectl replace -f -\n\n\n\n\n\n\nApply the Jaeger All-In-One Template:\n \n$ kubectl apply -f https://raw.githubusercontent.com/jaegertracing/jaeger-kubernetes/master/all-in-one/jaeger-all-in-one-template.yml\n\n\n\n\n\n\nMake a few requests to the Service:\n ```\n $ curl example.com/echo -d \"meow\"\n\n\nCLIENT VALUES:\nclient_address=172.17.0.5\ncommand=POST\nreal path=/echo\nquery=nil\nrequest_version=1.1\nrequest_uri=http://example.com:8080/echo\n\n\nSERVER VALUES:\nserver_version=nginx: 1.10.0 - lua: 10001\n\n\nHEADERS RECEIVED:\naccept=\n/\n\nconnection=close\ncontent-length=4\ncontent-type=application/x-www-form-urlencoded\nhost=example.com\nuser-agent=curl/7.54.0\nx-forwarded-for=192.168.99.1\nx-forwarded-host=example.com\nx-forwarded-port=80\nx-forwarded-proto=http\nx-original-uri=/echo\nx-real-ip=192.168.99.1\nx-scheme=http\nBODY:\nmeow\n```\n\n\n\n\n\n\nView the Jaeger UI:\n ```\n $ minikube service jaeger-query --url\n\n\nhttp://192.168.99.100:30183\n```\n\n\nIn the jaeger interface we can see the details:", + "text": "OpenTracing\n\u00b6\n\n\nEnables requests served by nginx for distributed tracing via The OpenTracing Project.\n\n\nUsing the third party module \nopentracing-contrib/nginx-opentracing\n the NGINX ingress controller can configure NGINX to enable \nOpenTracing\n instrumentation.\nBy default this feature is disabled.\n\n\nUsage\n\u00b6\n\n\nTo enable the instrumentation we must enable opentracing in the configuration configmap:\n\ndata\n:\n\n \nenable\n-\nopentracing\n:\n \n\"true\"\n\n\n\n\nWe must also set the host to use when uploading traces:\n\n\nzipkin-collector-host: zipkin.default.svc.cluster.local\njaeger-collector-host: jaeger-collector.default.svc.cluster.local\n\n\n\n\nNext you will need to deploy a distributed tracing system which uses OpenTracing. Both \nZipkin\n and\n\nJaeger\n have been tested.\n\n\nOther optional configuration options:\n\n# specifies the port to use when uploading traces\nzipkin-collector-port\n\n# specifies the service name to use for any traces created, Default: nginx\nzipkin-service-name\n\n# specifies sample rate for any traces created. Default: 1.0\nzipkin-sample-rate\n\n# specifies the port to use when uploading traces\njaeger-collector-port\n\n# specifies the service name to use for any traces created, Default: nginx\njaeger-service-name\n\n# specifies the sampler to be used when sampling traces.\n# The available samplers are: const, probabilistic, ratelimiting, remote, Default: const\njaeger-sampler-type\n\n# specifies the argument to be passed to the sampler constructor, Default: 1\njaeger-sampler-param\n\n\n\nExamples\n\u00b6\n\n\nThe following examples show how to deploy and test different distributed tracing systems. These example can be performed\nusing Minikube.\n\n\nZipkin\n\u00b6\n\n\nIn the \nrnburn/zipkin-date-server\n\ngithub repository is an example of a dockerized date service. To install the example and zipkin collector run:\n\n\nkubectl create -f https://raw.githubusercontent.com/rnburn/zipkin-date-server/master/kubernetes/zipkin.yaml\nkubectl create -f https://raw.githubusercontent.com/rnburn/zipkin-date-server/master/kubernetes/deployment.yaml\n\n\n\n\nAlso we need to configure the NGINX controller configmap with the required values:\n\n\n$ \necho\n \n'\n\n\napiVersion: v1\n\n\nkind: ConfigMap\n\n\ndata:\n\n\n enable-opentracing: \"true\"\n\n\n zipkin-collector-host: zipkin.default.svc.cluster.local\n\n\nmetadata:\n\n\n name: nginx-load-balancer-conf\n\n\n namespace: kube-system\n\n\n'\n \n|\n kubectl replace -f -\n\n\n\n\nIn the zipkin interface we can see the details:\n\n\n\nJaeger\n\u00b6\n\n\n\n\n\n\nEnable Ingress addon in minikube:\n \n$ minikube addons \nenable\n ingress\n\n\n\n\n\n\n\nAdd minikube IP to /etc/hosts:\n \n$ \necho\n \n\"\n$(\nminikube ip\n)\n example.com\"\n \n|\n sudo tee -a /etc/hosts\n\n\n\n\n\n\n\nApply a Basic Service and Ingress Resource:\n \n# Create Echoheaders Deployment\n$ kubectl run echoheaders --image=k8s.gcr.io/echoserver:1.4 --replicas=1 --port=8080\n\n# Expose as a Cluster-IP\n$ kubectl expose deployment echoheaders --port=80 --target-port=8080 --name=echoheaders-x\n\n# Apply the Ingress Resource\n$ echo '\n apiVersion: extensions/v1beta1\n kind: Ingress\n metadata:\n name: echo-ingress\n spec:\n rules:\n - host: example.com\n http:\n paths:\n - backend:\n serviceName: echoheaders-x\n servicePort: 80\n path: /echo\n ' | kubectl apply -f -\n\n\n\n\n\n\n\nEnable OpenTracing and set the zipkin-collector-host:\n \n$ \necho\n \n'\n\n\n apiVersion: v1\n\n\n kind: ConfigMap\n\n\n data:\n\n\n enable-opentracing: \"true\"\n\n\n zipkin-collector-host: zipkin.default.svc.cluster.local\n\n\n jaeger-collector-host: jaeger-collector.default.svc.cluster.local\n\n\n metadata:\n\n\n name: nginx-load-balancer-conf\n\n\n namespace: kube-system\n\n\n '\n \n|\n kubectl replace -f -\n\n\n\n\n\n\n\nApply the Jaeger All-In-One Template:\n \n$ kubectl apply -f https://raw.githubusercontent.com/jaegertracing/jaeger-kubernetes/master/all-in-one/jaeger-all-in-one-template.yml\n\n\n\n\n\n\n\nMake a few requests to the Service:\n \n$ curl example.com/echo -d \n\"meow\"\n\n\nCLIENT VALUES:\n\nclient_address\n=\n172\n.17.0.5\n\ncommand\n=\nPOST\nreal \npath\n=\n/echo\n\nquery\n=\nnil\n\nrequest_version\n=\n1\n.1\n\nrequest_uri\n=\nhttp://example.com:8080/echo\n\nSERVER VALUES:\n\nserver_version\n=\nnginx: \n1\n.10.0 - lua: \n10001\n\n\nHEADERS RECEIVED:\n\naccept\n=\n*/*\n\nconnection\n=\nclose\ncontent-length\n=\n4\n\ncontent-type\n=\napplication/x-www-form-urlencoded\n\nhost\n=\nexample.com\nuser-agent\n=\ncurl/7.54.0\nx-forwarded-for\n=\n192\n.168.99.1\nx-forwarded-host\n=\nexample.com\nx-forwarded-port\n=\n80\n\nx-forwarded-proto\n=\nhttp\nx-original-uri\n=\n/echo\nx-real-ip\n=\n192\n.168.99.1\nx-scheme\n=\nhttp\nBODY:\nmeow\n\n\n\n\n\n\n\nView the Jaeger UI:\n \n$ minikube service jaeger-query --url\n\nhttp://192.168.99.100:30183\n\n\n\nIn the jaeger interface we can see the details:", "title": "OpenTracing" }, { @@ -1197,7 +1227,7 @@ }, { "location": "/user-guide/third-party-addons/opentracing/#usage", - "text": "To enable the instrumentation we must enable opentracing in the configuration configmap: data : \n enable - opentracing : \"true\" We must also set the host to use when uploading traces: zipkin-collector-host: zipkin.default.svc.cluster.local\njaeger-collector-host: jaeger-collector.default.svc.cluster.local Next you will need to deploy a distributed tracing system which uses OpenTracing. Both Zipkin and Jaeger have been tested. Other optional configuration options: # specifies the port to use when uploading traces\nzipkin-collector-port\n\n# specifies the service name to use for any traces created, Default: nginx\nzipkin-service-name\n\n# specifies sample rate for any traces created. Default: 1.0\nzipkin-sample-rate\n\n# specifies the port to use when uploading traces\njaeger-collector-port\n\n# specifies the service name to use for any traces created, Default: nginx\njaeger-service-name\n\n# specifies the sampler to be used when sampling traces.\n# The available samplers are: const, probabilistic, ratelimiting, remote, Default: const\njaeger-sampler-type\n\n# specifies the argument to be passed to the sampler constructor, Default: 1\njaeger-sampler-param", + "text": "To enable the instrumentation we must enable opentracing in the configuration configmap: data : \n enable - opentracing : \"true\" We must also set the host to use when uploading traces: zipkin-collector-host: zipkin.default.svc.cluster.local\njaeger-collector-host: jaeger-collector.default.svc.cluster.local Next you will need to deploy a distributed tracing system which uses OpenTracing. Both Zipkin and Jaeger have been tested. Other optional configuration options: # specifies the port to use when uploading traces\nzipkin-collector-port\n\n# specifies the service name to use for any traces created, Default: nginx\nzipkin-service-name\n\n# specifies sample rate for any traces created. Default: 1.0\nzipkin-sample-rate\n\n# specifies the port to use when uploading traces\njaeger-collector-port\n\n# specifies the service name to use for any traces created, Default: nginx\njaeger-service-name\n\n# specifies the sampler to be used when sampling traces.\n# The available samplers are: const, probabilistic, ratelimiting, remote, Default: const\njaeger-sampler-type\n\n# specifies the argument to be passed to the sampler constructor, Default: 1\njaeger-sampler-param", "title": "Usage" }, { @@ -1212,19 +1242,9 @@ }, { "location": "/user-guide/third-party-addons/opentracing/#jaeger", - "text": "Enable Ingress addon in minikube:\n $ minikube addons enable ingress Add minikube IP to /etc/hosts:\n $ echo \" $( minikube ip ) example.com\" | sudo tee -a /etc/hosts Apply a Basic Service and Ingress Resource:\n ```\n # Create Echoheaders Deployment\n $ kubectl run echoheaders --image=k8s.gcr.io/echoserver:1.4 --replicas=1 --port=8080", + "text": "Enable Ingress addon in minikube:\n $ minikube addons enable ingress Add minikube IP to /etc/hosts:\n $ echo \" $( minikube ip ) example.com\" | sudo tee -a /etc/hosts Apply a Basic Service and Ingress Resource:\n # Create Echoheaders Deployment\n$ kubectl run echoheaders --image=k8s.gcr.io/echoserver:1.4 --replicas=1 --port=8080\n\n# Expose as a Cluster-IP\n$ kubectl expose deployment echoheaders --port=80 --target-port=8080 --name=echoheaders-x\n\n# Apply the Ingress Resource\n$ echo '\n apiVersion: extensions/v1beta1\n kind: Ingress\n metadata:\n name: echo-ingress\n spec:\n rules:\n - host: example.com\n http:\n paths:\n - backend:\n serviceName: echoheaders-x\n servicePort: 80\n path: /echo\n ' | kubectl apply -f - Enable OpenTracing and set the zipkin-collector-host:\n $ echo ' apiVersion: v1 kind: ConfigMap data: enable-opentracing: \"true\" zipkin-collector-host: zipkin.default.svc.cluster.local jaeger-collector-host: jaeger-collector.default.svc.cluster.local metadata: name: nginx-load-balancer-conf namespace: kube-system ' | kubectl replace -f - Apply the Jaeger All-In-One Template:\n $ kubectl apply -f https://raw.githubusercontent.com/jaegertracing/jaeger-kubernetes/master/all-in-one/jaeger-all-in-one-template.yml Make a few requests to the Service:\n $ curl example.com/echo -d \"meow\" \n\nCLIENT VALUES: client_address = 172 .17.0.5 command = POST\nreal path = /echo query = nil request_version = 1 .1 request_uri = http://example.com:8080/echo\n\nSERVER VALUES: server_version = nginx: 1 .10.0 - lua: 10001 \n\nHEADERS RECEIVED: accept = */* connection = close\ncontent-length = 4 \ncontent-type = application/x-www-form-urlencoded host = example.com\nuser-agent = curl/7.54.0\nx-forwarded-for = 192 .168.99.1\nx-forwarded-host = example.com\nx-forwarded-port = 80 \nx-forwarded-proto = http\nx-original-uri = /echo\nx-real-ip = 192 .168.99.1\nx-scheme = http\nBODY:\nmeow View the Jaeger UI:\n $ minikube service jaeger-query --url\n\nhttp://192.168.99.100:30183 In the jaeger interface we can see the details:", "title": "Jaeger" }, - { - "location": "/user-guide/third-party-addons/opentracing/#expose-as-a-cluster-ip", - "text": "$ kubectl expose deployment echoheaders --port=80 --target-port=8080 --name=echoheaders-x", - "title": "Expose as a Cluster-IP" - }, - { - "location": "/user-guide/third-party-addons/opentracing/#apply-the-ingress-resource", - "text": "$ echo '\n apiVersion: extensions/v1beta1\n kind: Ingress\n metadata:\n name: echo-ingress\n spec:\n rules:\n - host: example.com\n http:\n paths:\n - backend:\n serviceName: echoheaders-x\n servicePort: 80\n path: /echo\n ' | kubectl apply -f -\n``` Enable OpenTracing and set the zipkin-collector-host:\n $ echo ' apiVersion: v1 kind: ConfigMap data: enable-opentracing: \"true\" zipkin-collector-host: zipkin.default.svc.cluster.local jaeger-collector-host: jaeger-collector.default.svc.cluster.local metadata: name: nginx-load-balancer-conf namespace: kube-system ' | kubectl replace -f - Apply the Jaeger All-In-One Template:\n $ kubectl apply -f https://raw.githubusercontent.com/jaegertracing/jaeger-kubernetes/master/all-in-one/jaeger-all-in-one-template.yml Make a few requests to the Service:\n ```\n $ curl example.com/echo -d \"meow\" CLIENT VALUES:\nclient_address=172.17.0.5\ncommand=POST\nreal path=/echo\nquery=nil\nrequest_version=1.1\nrequest_uri=http://example.com:8080/echo SERVER VALUES:\nserver_version=nginx: 1.10.0 - lua: 10001 HEADERS RECEIVED:\naccept= / \nconnection=close\ncontent-length=4\ncontent-type=application/x-www-form-urlencoded\nhost=example.com\nuser-agent=curl/7.54.0\nx-forwarded-for=192.168.99.1\nx-forwarded-host=example.com\nx-forwarded-port=80\nx-forwarded-proto=http\nx-original-uri=/echo\nx-real-ip=192.168.99.1\nx-scheme=http\nBODY:\nmeow\n``` View the Jaeger UI:\n ```\n $ minikube service jaeger-query --url http://192.168.99.100:30183\n``` In the jaeger interface we can see the details:", - "title": "Apply the Ingress Resource" - }, { "location": "/examples/", "text": "Ingress examples\n\u00b6\n\n\nThis directory contains a catalog of examples on how to run, configure and scale Ingress.\n\nPlease review the \nprerequisites\n before trying them.\n\n\n\n\n\n\n\n\nCategory\n\n\nName\n\n\nDescription\n\n\nComplexity Level\n\n\n\n\n\n\n\n\n\n\nApps\n\n\nDocker Registry\n\n\nTODO\n\n\nTODO\n\n\n\n\n\n\nAuth\n\n\nBasic authentication\n\n\npassword protect your website\n\n\nIntermediate\n\n\n\n\n\n\nAuth\n\n\nClient certificate authentication\n\n\nsecure your website with client certificate authentication\n\n\nIntermediate\n\n\n\n\n\n\nAuth\n\n\nExternal authentication plugin\n\n\ndefer to an external authentication service\n\n\nIntermediate\n\n\n\n\n\n\nAuth\n\n\nOAuth external auth\n\n\nTODO\n\n\nTODO\n\n\n\n\n\n\nCustomization\n\n\nConfiguration snippets\n\n\ncustomize nginx location configuration using annotations\n\n\nAdvanced\n\n\n\n\n\n\nCustomization\n\n\nCustom configuration\n\n\nTODO\n\n\nTODO\n\n\n\n\n\n\nCustomization\n\n\nCustom DH parameters for perfect forward secrecy\n\n\nTODO\n\n\nTODO\n\n\n\n\n\n\nCustomization\n\n\nCustom errors\n\n\nserve custom error pages from the default backend\n\n\nIntermediate\n\n\n\n\n\n\nCustomization\n\n\nCustom headers\n\n\nset custom headers before sending traffic to backends\n\n\nAdvanced\n\n\n\n\n\n\nCustomization\n\n\nCustom upstream check\n\n\nTODO\n\n\nTODO\n\n\n\n\n\n\nCustomization\n\n\nExternal authentication with response header propagation\n\n\nTODO\n\n\nTODO\n\n\n\n\n\n\nCustomization\n\n\nSysctl tuning\n\n\nTODO\n\n\nTODO\n\n\n\n\n\n\nFeatures\n\n\nRewrite\n\n\nTODO\n\n\nTODO\n\n\n\n\n\n\nFeatures\n\n\nSession stickiness\n\n\nroute requests consistently to the same endpoint\n\n\nAdvanced\n\n\n\n\n\n\nScaling\n\n\nStatic IP\n\n\na single ingress gets a single static IP\n\n\nIntermediate\n\n\n\n\n\n\nTLS\n\n\nMulti TLS certificate termination\n\n\nTODO\n\n\nTODO\n\n\n\n\n\n\nTLS\n\n\nTLS termination\n\n\nTODO\n\n\nTODO", @@ -1237,7 +1257,7 @@ }, { "location": "/examples/PREREQUISITES/", - "text": "Prerequisites\n\u00b6\n\n\nMany of the examples in this directory have common prerequisites.\n\n\nTLS certificates\n\u00b6\n\n\nUnless otherwise mentioned, the TLS secret used in examples is a 2048 bit RSA\nkey/cert pair with an arbitrarily chosen hostname, created as follows\n\n\n$\n openssl req -x509 -nodes -days \n365\n -newkey rsa:2048 -keyout tls.key -out tls.crt -subj \n\"/CN=nginxsvc/O=nginxsvc\"\n\n\nGenerating a 2048 bit RSA private key\n\n\n................+++\n\n\n................+++\n\n\nwriting new private key to 'tls.key'\n\n\n-----\n\n\n\n$\n kubectl create secret tls tls-secret --key tls.key --cert tls.crt\n\nsecret \"tls-secret\" created\n\n\n\n\n\n\nCA Authentication\n\u00b6\n\n\nYou can act as your very own CA, or use an existing one. As an exercise / learning, we're going to generate our\nown CA, and also generate a client certificate.\n\n\nThese instructions are based on CoreOS OpenSSL. \nSee live doc.\n\n\nGenerating a CA\n\u00b6\n\n\nFirst of all, you've to generate a CA. This is going to be the one who will sign your client certificates.\nIn real production world, you may face CAs with intermediate certificates, as the following:\n\n\n$\n openssl s_client -connect www.google.com:443\n\n[...]\n\n\n---\n\n\nCertificate chain\n\n\n 0 s:/C=US/ST=California/L=Mountain View/O=Google Inc/CN=www.google.com\n\n\n i:/C=US/O=Google Inc/CN=Google Internet Authority G2\n\n\n 1 s:/C=US/O=Google Inc/CN=Google Internet Authority G2\n\n\n i:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA\n\n\n 2 s:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA\n\n\n i:/C=US/O=Equifax/OU=Equifax Secure Certificate Authority\n\n\n\n\n\n\nTo generate our CA Certificate, we've to run the following commands:\n\n\n$\n openssl genrsa -out ca.key \n2048\n\n\n$\n openssl req -x509 -new -nodes -key ca.key -days \n10000\n -out ca.crt -subj \n\"/CN=example-ca\"\n\n\n\n\n\n\nThis will generate two files: A private key (ca.key) and a public key (ca.crt). This CA is valid for 10000 days.\nThe ca.crt can be used later in the step of creation of CA authentication secret.\n\n\nGenerating the client certificate\n\u00b6\n\n\nThe following steps generate a client certificate signed by the CA generated above. This client can be\nused to authenticate in a tls-auth configured ingress.\n\n\nFirst, we need to generate an 'openssl.cnf' file that will be used while signing the keys:\n\n\n[req]\n\n\nreq_extensions = v3_req\n\n\ndistinguished_name = req_distinguished_name\n\n\n[req_distinguished_name]\n\n\n[ v3_req ]\n\n\nbasicConstraints = CA:FALSE\n\n\nkeyUsage = nonRepudiation, digitalSignature, keyEncipherment\n\n\n\n\n\n\nThen, a user generates his very own private key (that he needs to keep secret)\nand a CSR (Certificate Signing Request) that will be sent to the CA to sign and generate a certificate.\n\n\n$\n openssl genrsa -out client1.key \n2048\n\n\n$\n openssl req -new -key client1.key -out client1.csr -subj \n\"/CN=client1\"\n -config openssl.cnf\n\n\n\n\n\nAs the CA receives the generated 'client1.csr' file, it signs it and generates a client.crt certificate:\n\n\n$\n openssl x509 -req -in client1.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client1.crt -days \n365\n -extensions v3_req -extfile openssl.cnf\n\n\n\n\n\nThen, you'll have 3 files: the client.key (user's private key), client.crt (user's public key) and client.csr (disposable CSR).\n\n\nCreating the CA Authentication secret\n\u00b6\n\n\nIf you're using the CA Authentication feature, you need to generate a secret containing \nall the authorized CAs. You must download them from your CA site in PEM format (like the following):\n\n\n-----BEGIN CERTIFICATE-----\n[....]\n-----END CERTIFICATE-----\n\n\n\n\n\nYou can have as many certificates as you want. If they're in the binary DER format, \nyou can convert them as the following:\n\n\n$\n openssl x509 -in certificate.der -inform der -out certificate.crt -outform pem\n\n\n\n\n\nThen, you've to concatenate them all in only one file, named 'ca.crt' as the following:\n\n\n$\n cat certificate1.crt certificate2.crt certificate3.crt >> ca.crt\n\n\n\n\n\nThe final step is to create a secret with the content of this file. This secret is going to be used in \nthe TLS Auth directive:\n\n\n$\n kubectl create secret generic caingress --namespace\n=\ndefault --from-file\n=\nca.crt\n=\n\n\n\n\n\n\nNote:\n You can also generate the CA Authentication Secret along with the TLS Secret by using:\n\n\n$\n kubectl create secret generic caingress --namespace\n=\ndefault --from-file\n=\nca.crt\n=\n --from-file\n=\ntls.crt\n=\n --from-file\n=\ntls.key\n=\n\n\n\n\n\n\nTest HTTP Service\n\u00b6\n\n\nAll examples that require a test HTTP Service use the standard http-svc pod,\nwhich you can deploy as follows\n\n\n$\n kubectl create -f http-svc.yaml\n\nservice \"http-svc\" created\n\n\nreplicationcontroller \"http-svc\" created\n\n\n\n$\n kubectl get po\n\nNAME READY STATUS RESTARTS AGE\n\n\nhttp-svc-p1t3t 1/1 Running 0 1d\n\n\n\n$\n kubectl get svc\n\nNAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE\n\n\nhttp-svc 10.0.122.116 80:30301/TCP 1d\n\n\n\n\n\n\nYou can test that the HTTP Service works by exposing it temporarily\n\n\n$\n kubectl patch svc http-svc -p \n'{\"spec\":{\"type\": \"LoadBalancer\"}}'\n\n\n\"http-svc\" patched\n\n\n\n$\n kubectl get svc http-svc\n\nNAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE\n\n\nhttp-svc 10.0.122.116 80:30301/TCP 1d\n\n\n\n$\n kubectl describe svc http-svc\n\nName: http-svc\n\n\nNamespace: default\n\n\nLabels: app=http-svc\n\n\nSelector: app=http-svc\n\n\nType: LoadBalancer\n\n\nIP: 10.0.122.116\n\n\nLoadBalancer Ingress: 108.59.87.136\n\n\nPort: http 80/TCP\n\n\nNodePort: http 30301/TCP\n\n\nEndpoints: 10.180.1.6:8080\n\n\nSession Affinity: None\n\n\nEvents:\n\n\n FirstSeen LastSeen Count From SubObjectPath Type Reason Message\n\n\n --------- -------- ----- ---- ------------- -------- ------ -------\n\n\n 1m 1m 1 {service-controller } Normal Type ClusterIP -> LoadBalancer\n\n\n 1m 1m 1 {service-controller } Normal CreatingLoadBalancer Creating load balancer\n\n\n 16s 16s 1 {service-controller } Normal CreatedLoadBalancer Created load balancer\n\n\n\n$\n curl \n108\n.59.87.126\n\nCLIENT VALUES:\n\n\nclient_address=10.240.0.3\n\n\ncommand=GET\n\n\nreal path=/\n\n\nquery=nil\n\n\nrequest_version=1.1\n\n\nrequest_uri=http://108.59.87.136:8080/\n\n\n\nSERVER VALUES:\n\n\nserver_version=nginx: 1.9.11 - lua: 10001\n\n\n\nHEADERS RECEIVED:\n\n\naccept=*/*\n\n\nhost=108.59.87.136\n\n\nuser-agent=curl/7.46.0\n\n\nBODY:\n\n\n-no body in request-\n\n\n\n$\n kubectl patch svc http-svc -p \n'{\"spec\":{\"type\": \"NodePort\"}}'\n\n\n\"http-svc\" patched", + "text": "Prerequisites\n\u00b6\n\n\nMany of the examples in this directory have common prerequisites.\n\n\nTLS certificates\n\u00b6\n\n\nUnless otherwise mentioned, the TLS secret used in examples is a 2048 bit RSA\nkey/cert pair with an arbitrarily chosen hostname, created as follows\n\n\n$\n openssl req -x509 -nodes -days \n365\n -newkey rsa:2048 -keyout tls.key -out tls.crt -subj \n\"/CN=nginxsvc/O=nginxsvc\"\n\n\nGenerating a 2048 bit RSA private key\n\n\n................+++\n\n\n................+++\n\n\nwriting new private key to 'tls.key'\n\n\n-----\n\n\n\n$\n kubectl create secret tls tls-secret --key tls.key --cert tls.crt\n\nsecret \"tls-secret\" created\n\n\n\n\n\nCA Authentication\n\u00b6\n\n\nYou can act as your very own CA, or use an existing one. As an exercise / learning, we're going to generate our\nown CA, and also generate a client certificate.\n\n\nThese instructions are based on CoreOS OpenSSL. \nSee live doc.\n\n\nGenerating a CA\n\u00b6\n\n\nFirst of all, you've to generate a CA. This is going to be the one who will sign your client certificates.\nIn real production world, you may face CAs with intermediate certificates, as the following:\n\n\n$\n openssl s_client -connect www.google.com:443\n\n[...]\n\n\n---\n\n\nCertificate chain\n\n\n 0 s:/C=US/ST=California/L=Mountain View/O=Google Inc/CN=www.google.com\n\n\n i:/C=US/O=Google Inc/CN=Google Internet Authority G2\n\n\n 1 s:/C=US/O=Google Inc/CN=Google Internet Authority G2\n\n\n i:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA\n\n\n 2 s:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA\n\n\n i:/C=US/O=Equifax/OU=Equifax Secure Certificate Authority\n\n\n\n\n\nTo generate our CA Certificate, we've to run the following commands:\n\n\n$\n openssl genrsa -out ca.key \n2048\n\n\n$\n openssl req -x509 -new -nodes -key ca.key -days \n10000\n -out ca.crt -subj \n\"/CN=example-ca\"\n\n\n\n\n\nThis will generate two files: A private key (ca.key) and a public key (ca.crt). This CA is valid for 10000 days.\nThe ca.crt can be used later in the step of creation of CA authentication secret.\n\n\nGenerating the client certificate\n\u00b6\n\n\nThe following steps generate a client certificate signed by the CA generated above. This client can be\nused to authenticate in a tls-auth configured ingress.\n\n\nFirst, we need to generate an 'openssl.cnf' file that will be used while signing the keys:\n\n\n[req]\n\n\nreq_extensions = v3_req\n\n\ndistinguished_name = req_distinguished_name\n\n\n[req_distinguished_name]\n\n\n[ v3_req ]\n\n\nbasicConstraints = CA:FALSE\n\n\nkeyUsage = nonRepudiation, digitalSignature, keyEncipherment\n\n\n\n\n\nThen, a user generates his very own private key (that he needs to keep secret)\nand a CSR (Certificate Signing Request) that will be sent to the CA to sign and generate a certificate.\n\n\n$\n openssl genrsa -out client1.key \n2048\n\n\n$\n openssl req -new -key client1.key -out client1.csr -subj \n\"/CN=client1\"\n -config openssl.cnf\n\n\n\n\nAs the CA receives the generated 'client1.csr' file, it signs it and generates a client.crt certificate:\n\n\n$\n openssl x509 -req -in client1.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client1.crt -days \n365\n -extensions v3_req -extfile openssl.cnf\n\n\n\n\nThen, you'll have 3 files: the client.key (user's private key), client.crt (user's public key) and client.csr (disposable CSR).\n\n\nCreating the CA Authentication secret\n\u00b6\n\n\nIf you're using the CA Authentication feature, you need to generate a secret containing \nall the authorized CAs. You must download them from your CA site in PEM format (like the following):\n\n\n-----BEGIN CERTIFICATE-----\n[....]\n-----END CERTIFICATE-----\n\n\n\n\nYou can have as many certificates as you want. If they're in the binary DER format, \nyou can convert them as the following:\n\n\n$\n openssl x509 -in certificate.der -inform der -out certificate.crt -outform pem\n\n\n\n\nThen, you've to concatenate them all in only one file, named 'ca.crt' as the following:\n\n\n$\n cat certificate1.crt certificate2.crt certificate3.crt >> ca.crt\n\n\n\n\nThe final step is to create a secret with the content of this file. This secret is going to be used in \nthe TLS Auth directive:\n\n\n$\n kubectl create secret generic caingress --namespace\n=\ndefault --from-file\n=\nca.crt\n=\n\n\n\n\n\nNote:\n You can also generate the CA Authentication Secret along with the TLS Secret by using:\n\n$\n kubectl create secret generic caingress --namespace\n=\ndefault --from-file\n=\nca.crt\n=\n --from-file\n=\ntls.crt\n=\n --from-file\n=\ntls.key\n=\n\n\n\n\nTest HTTP Service\n\u00b6\n\n\nAll examples that require a test HTTP Service use the standard http-svc pod,\nwhich you can deploy as follows\n\n\n$\n kubectl create -f http-svc.yaml\n\nservice \"http-svc\" created\n\n\nreplicationcontroller \"http-svc\" created\n\n\n\n$\n kubectl get po\n\nNAME READY STATUS RESTARTS AGE\n\n\nhttp-svc-p1t3t 1/1 Running 0 1d\n\n\n\n$\n kubectl get svc\n\nNAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE\n\n\nhttp-svc 10.0.122.116 80:30301/TCP 1d\n\n\n\n\n\nYou can test that the HTTP Service works by exposing it temporarily\n\n\n$\n kubectl patch svc http-svc -p \n'{\"spec\":{\"type\": \"LoadBalancer\"}}'\n\n\n\"http-svc\" patched\n\n\n\n$\n kubectl get svc http-svc\n\nNAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE\n\n\nhttp-svc 10.0.122.116 80:30301/TCP 1d\n\n\n\n$\n kubectl describe svc http-svc\n\nName: http-svc\n\n\nNamespace: default\n\n\nLabels: app=http-svc\n\n\nSelector: app=http-svc\n\n\nType: LoadBalancer\n\n\nIP: 10.0.122.116\n\n\nLoadBalancer Ingress: 108.59.87.136\n\n\nPort: http 80/TCP\n\n\nNodePort: http 30301/TCP\n\n\nEndpoints: 10.180.1.6:8080\n\n\nSession Affinity: None\n\n\nEvents:\n\n\n FirstSeen LastSeen Count From SubObjectPath Type Reason Message\n\n\n --------- -------- ----- ---- ------------- -------- ------ -------\n\n\n 1m 1m 1 {service-controller } Normal Type ClusterIP -> LoadBalancer\n\n\n 1m 1m 1 {service-controller } Normal CreatingLoadBalancer Creating load balancer\n\n\n 16s 16s 1 {service-controller } Normal CreatedLoadBalancer Created load balancer\n\n\n\n$\n curl \n108\n.59.87.126\n\nCLIENT VALUES:\n\n\nclient_address=10.240.0.3\n\n\ncommand=GET\n\n\nreal path=/\n\n\nquery=nil\n\n\nrequest_version=1.1\n\n\nrequest_uri=http://108.59.87.136:8080/\n\n\n\nSERVER VALUES:\n\n\nserver_version=nginx: 1.9.11 - lua: 10001\n\n\n\nHEADERS RECEIVED:\n\n\naccept=*/*\n\n\nhost=108.59.87.136\n\n\nuser-agent=curl/7.46.0\n\n\nBODY:\n\n\n-no body in request-\n\n\n\n$\n kubectl patch svc http-svc -p \n'{\"spec\":{\"type\": \"NodePort\"}}'\n\n\n\"http-svc\" patched", "title": "Prerequisites" }, { @@ -1267,7 +1287,7 @@ }, { "location": "/examples/PREREQUISITES/#creating-the-ca-authentication-secret", - "text": "If you're using the CA Authentication feature, you need to generate a secret containing \nall the authorized CAs. You must download them from your CA site in PEM format (like the following): -----BEGIN CERTIFICATE-----\n[....]\n-----END CERTIFICATE----- You can have as many certificates as you want. If they're in the binary DER format, \nyou can convert them as the following: $ openssl x509 -in certificate.der -inform der -out certificate.crt -outform pem Then, you've to concatenate them all in only one file, named 'ca.crt' as the following: $ cat certificate1.crt certificate2.crt certificate3.crt >> ca.crt The final step is to create a secret with the content of this file. This secret is going to be used in \nthe TLS Auth directive: $ kubectl create secret generic caingress --namespace = default --from-file = ca.crt = Note: You can also generate the CA Authentication Secret along with the TLS Secret by using: $ kubectl create secret generic caingress --namespace = default --from-file = ca.crt = --from-file = tls.crt = --from-file = tls.key = ", + "text": "If you're using the CA Authentication feature, you need to generate a secret containing \nall the authorized CAs. You must download them from your CA site in PEM format (like the following): -----BEGIN CERTIFICATE-----\n[....]\n-----END CERTIFICATE----- You can have as many certificates as you want. If they're in the binary DER format, \nyou can convert them as the following: $ openssl x509 -in certificate.der -inform der -out certificate.crt -outform pem Then, you've to concatenate them all in only one file, named 'ca.crt' as the following: $ cat certificate1.crt certificate2.crt certificate3.crt >> ca.crt The final step is to create a secret with the content of this file. This secret is going to be used in \nthe TLS Auth directive: $ kubectl create secret generic caingress --namespace = default --from-file = ca.crt = Note: You can also generate the CA Authentication Secret along with the TLS Secret by using: $ kubectl create secret generic caingress --namespace = default --from-file = ca.crt = --from-file = tls.crt = --from-file = tls.key = ", "title": "Creating the CA Authentication secret" }, { @@ -1277,7 +1297,7 @@ }, { "location": "/examples/affinity/cookie/README/", - "text": "Sticky Session\n\u00b6\n\n\nThis example demonstrates how to achieve session affinity using cookies\n\n\nDeployment\n\u00b6\n\n\nSession stickiness is achieved through 3 annotations on the Ingress, as shown in the \nexample\n.\n\n\n\n\n\n\n\n\nName\n\n\nDescription\n\n\nValues\n\n\n\n\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/affinity\n\n\nSets the affinity type\n\n\nstring (in NGINX only \ncookie\n is possible\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/session-cookie-name\n\n\nName of the cookie that will be used\n\n\nstring (default to INGRESSCOOKIE)\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/session-cookie-hash\n\n\nType of hash that will be used in cookie value\n\n\nsha1/md5/index\n\n\n\n\n\n\n\n\nYou can create the ingress to test this\n\n\nkubectl create -f ingress.yaml\n\n\n\n\n\n\nValidation\n\u00b6\n\n\nYou can confirm that the Ingress works.\n\n\n$\n kubectl describe ing nginx-test\n\nName: nginx-test\n\n\nNamespace: default\n\n\nAddress: \n\n\nDefault backend: default-http-backend:80 (10.180.0.4:8080,10.240.0.2:8080)\n\n\nRules:\n\n\n Host Path Backends\n\n\n ---- ---- --------\n\n\n stickyingress.example.com \n\n\n / nginx-service:80 ()\n\n\nAnnotations:\n\n\n affinity: cookie\n\n\n session-cookie-hash: sha1\n\n\n session-cookie-name: INGRESSCOOKIE\n\n\nEvents:\n\n\n FirstSeen LastSeen Count From SubObjectPath Type Reason Message\n\n\n --------- -------- ----- ---- ------------- -------- ------ -------\n\n\n 7s 7s 1 {nginx-ingress-controller } Normal CREATE default/nginx-test\n\n\n\n\n$\n curl -I http://stickyingress.example.com\n\nHTTP/1.1 200 OK\n\n\nServer: nginx/1.11.9\n\n\nDate: Fri, 10 Feb 2017 14:11:12 GMT\n\n\nContent-Type: text/html\n\n\nContent-Length: 612\n\n\nConnection: keep-alive\n\n\nSet-Cookie: INGRESSCOOKIE=a9907b79b248140b56bb13723f72b67697baac3d; Path=/; HttpOnly\n\n\nLast-Modified: Tue, 24 Jan 2017 14:02:19 GMT\n\n\nETag: \"58875e6b-264\"\n\n\nAccept-Ranges: bytes\n\n\n\n\n\n\nIn the example above, you can see a line containing the 'Set-Cookie: INGRESSCOOKIE' setting the right defined stickiness cookie.\nThis cookie is created by NGINX containing the hash of the used upstream in that request. \nIf the user changes this cookie, NGINX creates a new one and redirect the user to another upstream.\n\n\nIf the backend pool grows up NGINX will keep sending the requests through the same server of the first request, even if it's overloaded.\n\n\nWhen the backend server is removed, the requests are then re-routed to another upstream server and NGINX creates a new cookie, as the previous hash became invalid.\n\n\nWhen you have more than one Ingress Object pointing to the same Service, but one containing affinity configuration and other don't, the first created Ingress will be used. \nThis means that you can face the situation that you've configured Session Affinity in one Ingress and it doesn't reflects in NGINX configuration, because there is another Ingress Object pointing to the same service that doesn't configure this.", + "text": "Sticky Session\n\u00b6\n\n\nThis example demonstrates how to achieve session affinity using cookies\n\n\nDeployment\n\u00b6\n\n\nSession stickiness is achieved through 3 annotations on the Ingress, as shown in the \nexample\n.\n\n\n\n\n\n\n\n\nName\n\n\nDescription\n\n\nValues\n\n\n\n\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/affinity\n\n\nSets the affinity type\n\n\nstring (in NGINX only \ncookie\n is possible\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/session-cookie-name\n\n\nName of the cookie that will be used\n\n\nstring (default to INGRESSCOOKIE)\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/session-cookie-hash\n\n\nType of hash that will be used in cookie value\n\n\nsha1/md5/index\n\n\n\n\n\n\n\n\nYou can create the ingress to test this\n\n\nkubectl create -f ingress.yaml\n\n\n\n\n\nValidation\n\u00b6\n\n\nYou can confirm that the Ingress works.\n\n\n$\n kubectl describe ing nginx-test\n\nName: nginx-test\n\n\nNamespace: default\n\n\nAddress: \n\n\nDefault backend: default-http-backend:80 (10.180.0.4:8080,10.240.0.2:8080)\n\n\nRules:\n\n\n Host Path Backends\n\n\n ---- ---- --------\n\n\n stickyingress.example.com \n\n\n / nginx-service:80 ()\n\n\nAnnotations:\n\n\n affinity: cookie\n\n\n session-cookie-hash: sha1\n\n\n session-cookie-name: INGRESSCOOKIE\n\n\nEvents:\n\n\n FirstSeen LastSeen Count From SubObjectPath Type Reason Message\n\n\n --------- -------- ----- ---- ------------- -------- ------ -------\n\n\n 7s 7s 1 {nginx-ingress-controller } Normal CREATE default/nginx-test\n\n\n\n\n$\n curl -I http://stickyingress.example.com\n\nHTTP/1.1 200 OK\n\n\nServer: nginx/1.11.9\n\n\nDate: Fri, 10 Feb 2017 14:11:12 GMT\n\n\nContent-Type: text/html\n\n\nContent-Length: 612\n\n\nConnection: keep-alive\n\n\nSet-Cookie: INGRESSCOOKIE=a9907b79b248140b56bb13723f72b67697baac3d; Path=/; HttpOnly\n\n\nLast-Modified: Tue, 24 Jan 2017 14:02:19 GMT\n\n\nETag: \"58875e6b-264\"\n\n\nAccept-Ranges: bytes\n\n\n\nIn the example above, you can see a line containing the 'Set-Cookie: INGRESSCOOKIE' setting the right defined stickiness cookie.\nThis cookie is created by NGINX containing the hash of the used upstream in that request. \nIf the user changes this cookie, NGINX creates a new one and redirect the user to another upstream.\n\n\nIf the backend pool grows up NGINX will keep sending the requests through the same server of the first request, even if it's overloaded.\n\n\nWhen the backend server is removed, the requests are then re-routed to another upstream server and NGINX creates a new cookie, as the previous hash became invalid.\n\n\nWhen you have more than one Ingress Object pointing to the same Service, but one containing affinity configuration and other don't, the first created Ingress will be used. \nThis means that you can face the situation that you've configured Session Affinity in one Ingress and it doesn't reflects in NGINX configuration, because there is another Ingress Object pointing to the same service that doesn't configure this.", "title": "Sticky Session" }, { @@ -1292,12 +1312,12 @@ }, { "location": "/examples/affinity/cookie/README/#validation", - "text": "You can confirm that the Ingress works. $ kubectl describe ing nginx-test Name: nginx-test Namespace: default Address: Default backend: default-http-backend:80 (10.180.0.4:8080,10.240.0.2:8080) Rules: Host Path Backends ---- ---- -------- stickyingress.example.com / nginx-service:80 () Annotations: affinity: cookie session-cookie-hash: sha1 session-cookie-name: INGRESSCOOKIE Events: FirstSeen LastSeen Count From SubObjectPath Type Reason Message --------- -------- ----- ---- ------------- -------- ------ ------- 7s 7s 1 {nginx-ingress-controller } Normal CREATE default/nginx-test $ curl -I http://stickyingress.example.com HTTP/1.1 200 OK Server: nginx/1.11.9 Date: Fri, 10 Feb 2017 14:11:12 GMT Content-Type: text/html Content-Length: 612 Connection: keep-alive Set-Cookie: INGRESSCOOKIE=a9907b79b248140b56bb13723f72b67697baac3d; Path=/; HttpOnly Last-Modified: Tue, 24 Jan 2017 14:02:19 GMT ETag: \"58875e6b-264\" Accept-Ranges: bytes In the example above, you can see a line containing the 'Set-Cookie: INGRESSCOOKIE' setting the right defined stickiness cookie.\nThis cookie is created by NGINX containing the hash of the used upstream in that request. \nIf the user changes this cookie, NGINX creates a new one and redirect the user to another upstream. If the backend pool grows up NGINX will keep sending the requests through the same server of the first request, even if it's overloaded. When the backend server is removed, the requests are then re-routed to another upstream server and NGINX creates a new cookie, as the previous hash became invalid. When you have more than one Ingress Object pointing to the same Service, but one containing affinity configuration and other don't, the first created Ingress will be used. \nThis means that you can face the situation that you've configured Session Affinity in one Ingress and it doesn't reflects in NGINX configuration, because there is another Ingress Object pointing to the same service that doesn't configure this.", + "text": "You can confirm that the Ingress works. $ kubectl describe ing nginx-test Name: nginx-test Namespace: default Address: Default backend: default-http-backend:80 (10.180.0.4:8080,10.240.0.2:8080) Rules: Host Path Backends ---- ---- -------- stickyingress.example.com / nginx-service:80 () Annotations: affinity: cookie session-cookie-hash: sha1 session-cookie-name: INGRESSCOOKIE Events: FirstSeen LastSeen Count From SubObjectPath Type Reason Message --------- -------- ----- ---- ------------- -------- ------ ------- 7s 7s 1 {nginx-ingress-controller } Normal CREATE default/nginx-test $ curl -I http://stickyingress.example.com HTTP/1.1 200 OK Server: nginx/1.11.9 Date: Fri, 10 Feb 2017 14:11:12 GMT Content-Type: text/html Content-Length: 612 Connection: keep-alive Set-Cookie: INGRESSCOOKIE=a9907b79b248140b56bb13723f72b67697baac3d; Path=/; HttpOnly Last-Modified: Tue, 24 Jan 2017 14:02:19 GMT ETag: \"58875e6b-264\" Accept-Ranges: bytes \nIn the example above, you can see a line containing the 'Set-Cookie: INGRESSCOOKIE' setting the right defined stickiness cookie.\nThis cookie is created by NGINX containing the hash of the used upstream in that request. \nIf the user changes this cookie, NGINX creates a new one and redirect the user to another upstream. If the backend pool grows up NGINX will keep sending the requests through the same server of the first request, even if it's overloaded. When the backend server is removed, the requests are then re-routed to another upstream server and NGINX creates a new cookie, as the previous hash became invalid. When you have more than one Ingress Object pointing to the same Service, but one containing affinity configuration and other don't, the first created Ingress will be used. \nThis means that you can face the situation that you've configured Session Affinity in one Ingress and it doesn't reflects in NGINX configuration, because there is another Ingress Object pointing to the same service that doesn't configure this.", "title": "Validation" }, { "location": "/examples/auth/basic/README/", - "text": "Basic Authentication\n\u00b6\n\n\nThis example shows how to add authentication in a Ingress rule using a secret that contains a file generated with \nhtpasswd\n.\nIt's important the file generated is named \nauth\n (actually - that the secret has a key \ndata.auth\n), otherwise the ingress-controller returns a 503.\n\n\n$\n htpasswd -c auth foo\n\nNew password: \n\n\nNew password:\n\n\nRe-type new password:\n\n\nAdding password for user foo\n\n\n\n\n\n\n$\n kubectl create secret generic basic-auth --from-file\n=\nauth\n\nsecret \"basic-auth\" created\n\n\n\n\n\n\n$\n kubectl get secret basic-auth -o yaml\n\napiVersion: v1\n\n\ndata:\n\n\n auth: Zm9vOiRhcHIxJE9GRzNYeWJwJGNrTDBGSERBa29YWUlsSDkuY3lzVDAK\n\n\nkind: Secret\n\n\nmetadata:\n\n\n name: basic-auth\n\n\n namespace: default\n\n\ntype: Opaque\n\n\n\n\n\n\necho \"\n\n\napiVersion: extensions/v1beta1\n\n\nkind: Ingress\n\n\nmetadata:\n\n\n name: ingress-with-auth\n\n\n annotations:\n\n\n #\n \ntype\n of authentication\n\n nginx.ingress.kubernetes.io/auth-type: basic\n\n\n #\n name of the secret that contains the user/password definitions\n\n nginx.ingress.kubernetes.io/auth-secret: basic-auth\n\n\n #\n message to display with an appropriate context why the authentication is required\n\n nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required - foo'\n\n\nspec:\n\n\n rules:\n\n\n - host: foo.bar.com\n\n\n http:\n\n\n paths:\n\n\n - path: /\n\n\n backend:\n\n\n serviceName: http-svc\n\n\n servicePort: 80\n\n\n\" | kubectl create -f -\n\n\n\n\n\n\n$ curl -v http://10.2.29.4/ -H 'Host: foo.bar.com'\n* Trying 10.2.29.4...\n* Connected to 10.2.29.4 (10.2.29.4) port 80 (#0)\n> GET / HTTP/1.1\n> Host: foo.bar.com\n> User-Agent: curl/7.43.0\n> Accept: */*\n>\n\n< HTTP\n/1.1\n \n401\n \nUnauthorized\n\n\n<\n \nServer:\n \nnginx/1.10.0\n\n\n<\n \nDate:\n \nWed,\n \n11\n \nMay\n \n2016\n \n05:27:23\n \nGMT\n\n\n<\n \nContent-Type:\n \ntext/html\n\n\n<\n \nContent-Length:\n \n195\n\n\n<\n \nConnection:\n \nkeep-alive\n\n\n<\n \nWWW-Authenticate:\n \nBasic\n \nrealm=\n\"Authentication Required - foo\"\n\n\n<\n\n\n\n\n\n\n401 Authorization Required\n\n\n\n\n\n\n

        \n401 Authorization Required\n

        \n\n\n
        \nnginx/1.10.0\n
        \n\n\n\n\n\n\n\n* Connection #0 to host 10.2.29.4 left intact\n\n\n\n\n\n$ curl -v http://10.2.29.4/ -H \n'Host: foo.bar.com'\n -u \n'foo:bar'\n\n* Trying \n10\n.2.29.4...\n* Connected to \n10\n.2.29.4 \n(\n10\n.2.29.4\n)\n port \n80\n \n(\n#0)\n\n* Server auth using Basic with user \n'foo'\n\n> GET / HTTP/1.1\n> Host: foo.bar.com\n> Authorization: Basic \nZm9vOmJhcg\n==\n\n> User-Agent: curl/7.43.0\n> Accept: */*\n>\n< HTTP/1.1 \n200\n OK\n< Server: nginx/1.10.0\n< Date: Wed, \n11\n May \n2016\n \n06\n:05:26 GMT\n< Content-Type: text/plain\n< Transfer-Encoding: chunked\n< Connection: keep-alive\n< Vary: Accept-Encoding\n<\nCLIENT VALUES:\n\nclient_address\n=\n10\n.2.29.4\n\ncommand\n=\nGET\nreal \npath\n=\n/\n\nquery\n=\nnil\n\nrequest_version\n=\n1\n.1\n\nrequest_uri\n=\nhttp://foo.bar.com:8080/\n\nSERVER VALUES:\n\nserver_version\n=\nnginx: \n1\n.9.11 - lua: \n10001\n\n\nHEADERS RECEIVED:\n\naccept\n=\n*/*\n\nauthorization\n=\nBasic \nZm9vOmJhcg\n==\n\n\nconnection\n=\nclose\n\nhost\n=\nfoo.bar.com\nuser-agent\n=\ncurl/7.43.0\nx-forwarded-for\n=\n10\n.2.29.1\nx-forwarded-host\n=\nfoo.bar.com\nx-forwarded-port\n=\n80\n\nx-forwarded-proto\n=\nhttp\nx-real-ip\n=\n10\n.2.29.1\nBODY:\n* Connection \n#0 to host 10.2.29.4 left intact\n\n-no body in request-", + "text": "Basic Authentication\n\u00b6\n\n\nThis example shows how to add authentication in a Ingress rule using a secret that contains a file generated with \nhtpasswd\n.\nIt's important the file generated is named \nauth\n (actually - that the secret has a key \ndata.auth\n), otherwise the ingress-controller returns a 503.\n\n\n$\n htpasswd -c auth foo\n\nNew password: \n\n\nNew password:\n\n\nRe-type new password:\n\n\nAdding password for user foo\n\n\n\n\n\n$\n kubectl create secret generic basic-auth --from-file\n=\nauth\n\nsecret \"basic-auth\" created\n\n\n\n\n\n$\n kubectl get secret basic-auth -o yaml\n\napiVersion: v1\n\n\ndata:\n\n\n auth: Zm9vOiRhcHIxJE9GRzNYeWJwJGNrTDBGSERBa29YWUlsSDkuY3lzVDAK\n\n\nkind: Secret\n\n\nmetadata:\n\n\n name: basic-auth\n\n\n namespace: default\n\n\ntype: Opaque\n\n\n\n\n\necho \"\n\n\napiVersion: extensions/v1beta1\n\n\nkind: Ingress\n\n\nmetadata:\n\n\n name: ingress-with-auth\n\n\n annotations:\n\n\n #\n \ntype\n of authentication\n\n nginx.ingress.kubernetes.io/auth-type: basic\n\n\n #\n name of the secret that contains the user/password definitions\n\n nginx.ingress.kubernetes.io/auth-secret: basic-auth\n\n\n #\n message to display with an appropriate context why the authentication is required\n\n nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required - foo'\n\n\nspec:\n\n\n rules:\n\n\n - host: foo.bar.com\n\n\n http:\n\n\n paths:\n\n\n - path: /\n\n\n backend:\n\n\n serviceName: http-svc\n\n\n servicePort: 80\n\n\n\" | kubectl create -f -\n\n\n\n\n\n$ curl -v http://10.2.29.4/ -H 'Host: foo.bar.com'\n* Trying 10.2.29.4...\n* Connected to 10.2.29.4 (10.2.29.4) port 80 (#0)\n> GET / HTTP/1.1\n> Host: foo.bar.com\n> User-Agent: curl/7.43.0\n> Accept: */*\n>\n\n< HTTP\n/1.1\n \n401\n \nUnauthorized\n\n\n<\n \nServer:\n \nnginx/1.10.0\n\n\n<\n \nDate:\n \nWed,\n \n11\n \nMay\n \n2016\n \n05:27:23\n \nGMT\n\n\n<\n \nContent-Type:\n \ntext/html\n\n\n<\n \nContent-Length:\n \n195\n\n\n<\n \nConnection:\n \nkeep-alive\n\n\n<\n \nWWW-Authenticate:\n \nBasic\n \nrealm=\n\"Authentication Required - foo\"\n\n\n<\n\n\n\n\n\n\n401 Authorization Required\n\n\n\n\n\n\n

        \n401 Authorization Required\n

        \n\n\n
        \nnginx/1.10.0\n
        \n\n\n\n\n\n\n\n* Connection #0 to host 10.2.29.4 left intact\n\n\n\n\n$ curl -v http://10.2.29.4/ -H \n'Host: foo.bar.com'\n -u \n'foo:bar'\n\n* Trying \n10\n.2.29.4...\n* Connected to \n10\n.2.29.4 \n(\n10\n.2.29.4\n)\n port \n80\n \n(\n#0)\n\n* Server auth using Basic with user \n'foo'\n\n> GET / HTTP/1.1\n> Host: foo.bar.com\n> Authorization: Basic \nZm9vOmJhcg\n==\n\n> User-Agent: curl/7.43.0\n> Accept: */*\n>\n< HTTP/1.1 \n200\n OK\n< Server: nginx/1.10.0\n< Date: Wed, \n11\n May \n2016\n \n06\n:05:26 GMT\n< Content-Type: text/plain\n< Transfer-Encoding: chunked\n< Connection: keep-alive\n< Vary: Accept-Encoding\n<\nCLIENT VALUES:\n\nclient_address\n=\n10\n.2.29.4\n\ncommand\n=\nGET\nreal \npath\n=\n/\n\nquery\n=\nnil\n\nrequest_version\n=\n1\n.1\n\nrequest_uri\n=\nhttp://foo.bar.com:8080/\n\nSERVER VALUES:\n\nserver_version\n=\nnginx: \n1\n.9.11 - lua: \n10001\n\n\nHEADERS RECEIVED:\n\naccept\n=\n*/*\n\nauthorization\n=\nBasic \nZm9vOmJhcg\n==\n\n\nconnection\n=\nclose\n\nhost\n=\nfoo.bar.com\nuser-agent\n=\ncurl/7.43.0\nx-forwarded-for\n=\n10\n.2.29.1\nx-forwarded-host\n=\nfoo.bar.com\nx-forwarded-port\n=\n80\n\nx-forwarded-proto\n=\nhttp\nx-real-ip\n=\n10\n.2.29.1\nBODY:\n* Connection \n#0 to host 10.2.29.4 left intact\n\n-no body in request-", "title": "Basic Authentication" }, { @@ -1322,7 +1342,7 @@ }, { "location": "/examples/auth/external-auth/README/", - "text": "External Basic Authentication\n\u00b6\n\n\nExample 1:\n\u00b6\n\n\nUse an external service (Basic Auth) located in \nhttps://httpbin.org\n \n\n\n$ kubectl create -f ingress.yaml\ningress \n\"external-auth\"\n created\n\n$ kubectl get ing external-auth\nNAME HOSTS ADDRESS PORTS AGE\nexternal-auth external-auth-01.sample.com \n172\n.17.4.99 \n80\n 13s\n\n$ kubectl get ing external-auth -o yaml\napiVersion: extensions/v1beta1\nkind: Ingress\nmetadata:\n annotations:\n nginx.ingress.kubernetes.io/auth-url: https://httpbin.org/basic-auth/user/passwd\n creationTimestamp: \n2016\n-10-03T13:50:35Z\n generation: \n1\n\n name: external-auth\n namespace: default\n resourceVersion: \n\"2068378\"\n\n selfLink: /apis/extensions/v1beta1/namespaces/default/ingresses/external-auth\n uid: 5c388f1d-8970-11e6-9004-080027d2dc94\nspec:\n rules:\n - host: external-auth-01.sample.com\n http:\n paths:\n - backend:\n serviceName: http-svc\n servicePort: \n80\n\n path: /\nstatus:\n loadBalancer:\n ingress:\n - ip: \n172\n.17.4.99\n$\n\n\n\n\n\nTest 1: no username/password (expect code 401)\n\n\n$\n curl -k http://172.17.4.99 -v -H \n'Host: external-auth-01.sample.com'\n\n\n* Rebuilt URL to: http://172.17.4.99/\n\n\n* Trying 172.17.4.99...\n\n\n* Connected to 172.17.4.99 (172.17.4.99) port 80 (#0)\n\n\n>\n GET / HTTP/1.1\n\n>\n Host: external-auth-01.sample.com\n\n>\n User-Agent: curl/7.50.1\n\n>\n Accept: */*\n\n>\n\n\n< HTTP/1.1 401 Unauthorized\n\n\n< Server: nginx/1.11.3\n\n\n< Date: Mon, 03 Oct 2016 14:52:08 GMT\n\n\n< Content-Type: text/html\n\n\n< Content-Length: 195\n\n\n< Connection: keep-alive\n\n\n< WWW-Authenticate: Basic realm=\"Fake Realm\"\n\n\n<\n\n\n\n\n\n401 Authorization Required\n\n\n\n\n\n

        401 Authorization Required

        \n\n\n
        nginx/1.11.3
        \n\n\n\n\n\n\n\n\n* Connection #0 to host 172.17.4.99 left intact\n\n\n\n\n\n\nTest 2: valid username/password (expect code 200)\n\n\n$ curl -k http://172.17.4.99 -v -H \n'Host: external-auth-01.sample.com'\n -u \n'user:passwd'\n\n* Rebuilt URL to: http://172.17.4.99/\n* Trying \n172\n.17.4.99...\n* Connected to \n172\n.17.4.99 \n(\n172\n.17.4.99\n)\n port \n80\n \n(\n#0)\n\n* Server auth using Basic with user \n'user'\n\n> GET / HTTP/1.1\n> Host: external-auth-01.sample.com\n> Authorization: Basic \ndXNlcjpwYXNzd2Q\n=\n\n> User-Agent: curl/7.50.1\n> Accept: */*\n>\n< HTTP/1.1 \n200\n OK\n< Server: nginx/1.11.3\n< Date: Mon, \n03\n Oct \n2016\n \n14\n:52:50 GMT\n< Content-Type: text/plain\n< Transfer-Encoding: chunked\n< Connection: keep-alive\n<\nCLIENT VALUES:\n\nclient_address\n=\n10\n.2.60.2\n\ncommand\n=\nGET\nreal \npath\n=\n/\n\nquery\n=\nnil\n\nrequest_version\n=\n1\n.1\n\nrequest_uri\n=\nhttp://external-auth-01.sample.com:8080/\n\nSERVER VALUES:\n\nserver_version\n=\nnginx: \n1\n.9.11 - lua: \n10001\n\n\nHEADERS RECEIVED:\n\naccept\n=\n*/*\n\nauthorization\n=\nBasic \ndXNlcjpwYXNzd2Q\n=\n\n\nconnection\n=\nclose\n\nhost\n=\nexternal-auth-01.sample.com\nuser-agent\n=\ncurl/7.50.1\nx-forwarded-for\n=\n10\n.2.60.1\nx-forwarded-host\n=\nexternal-auth-01.sample.com\nx-forwarded-port\n=\n80\n\nx-forwarded-proto\n=\nhttp\nx-real-ip\n=\n10\n.2.60.1\nBODY:\n* Connection \n#0 to host 172.17.4.99 left intact\n\n-no body in request-\n\n\n\n\n\nTest 3: invalid username/password (expect code 401)\n\n\ncurl -k http://172.17.4.99 -v -H 'Host: external-auth-01.sample.com' -u 'user:user'\n* Rebuilt URL to: http://172.17.4.99/\n* Trying 172.17.4.99...\n* Connected to 172.17.4.99 (172.17.4.99) port 80 (#0)\n* Server auth using Basic with user 'user'\n> GET / HTTP/1.1\n> Host: external-auth-01.sample.com\n> Authorization: Basic dXNlcjp1c2Vy\n> User-Agent: curl/7.50.1\n> Accept: */*\n>\n\n< HTTP\n/1.1\n \n401\n \nUnauthorized\n\n\n<\n \nServer:\n \nnginx/1.11.3\n\n\n<\n \nDate:\n \nMon,\n \n03\n \nOct\n \n2016\n \n14:53:04\n \nGMT\n\n\n<\n \nContent-Type:\n \ntext/html\n\n\n<\n \nContent-Length:\n \n195\n\n\n<\n \nConnection:\n \nkeep-alive\n\n\n*\n \nAuthentication\n \nproblem.\n \nIgnoring\n \nthis.\n\n\n<\n \nWWW-Authenticate:\n \nBasic\n \nrealm=\n\"Fake Realm\"\n\n\n<\n\n\n\n\n\n\n401 Authorization Required\n\n\n\n\n\n\n

        \n401 Authorization Required\n

        \n\n\n
        \nnginx/1.11.3\n
        \n\n\n\n\n\n\n\n* Connection #0 to host 172.17.4.99 left intact", + "text": "External Basic Authentication\n\u00b6\n\n\nExample 1:\n\u00b6\n\n\nUse an external service (Basic Auth) located in \nhttps://httpbin.org\n \n\n\n$ kubectl create -f ingress.yaml\ningress \n\"external-auth\"\n created\n\n$ kubectl get ing external-auth\nNAME HOSTS ADDRESS PORTS AGE\nexternal-auth external-auth-01.sample.com \n172\n.17.4.99 \n80\n 13s\n\n$ kubectl get ing external-auth -o yaml\napiVersion: extensions/v1beta1\nkind: Ingress\nmetadata:\n annotations:\n nginx.ingress.kubernetes.io/auth-url: https://httpbin.org/basic-auth/user/passwd\n creationTimestamp: \n2016\n-10-03T13:50:35Z\n generation: \n1\n\n name: external-auth\n namespace: default\n resourceVersion: \n\"2068378\"\n\n selfLink: /apis/extensions/v1beta1/namespaces/default/ingresses/external-auth\n uid: 5c388f1d-8970-11e6-9004-080027d2dc94\nspec:\n rules:\n - host: external-auth-01.sample.com\n http:\n paths:\n - backend:\n serviceName: http-svc\n servicePort: \n80\n\n path: /\nstatus:\n loadBalancer:\n ingress:\n - ip: \n172\n.17.4.99\n$\n\n\n\n\nTest 1: no username/password (expect code 401)\n\n\n$\n curl -k http://172.17.4.99 -v -H \n'Host: external-auth-01.sample.com'\n\n\n* Rebuilt URL to: http://172.17.4.99/\n\n\n* Trying 172.17.4.99...\n\n\n* Connected to 172.17.4.99 (172.17.4.99) port 80 (#0)\n\n\n>\n GET / HTTP/1.1\n\n>\n Host: external-auth-01.sample.com\n\n>\n User-Agent: curl/7.50.1\n\n>\n Accept: */*\n\n>\n\n\n< HTTP/1.1 401 Unauthorized\n\n\n< Server: nginx/1.11.3\n\n\n< Date: Mon, 03 Oct 2016 14:52:08 GMT\n\n\n< Content-Type: text/html\n\n\n< Content-Length: 195\n\n\n< Connection: keep-alive\n\n\n< WWW-Authenticate: Basic realm=\"Fake Realm\"\n\n\n<\n\n\n\n\n\n401 Authorization Required\n\n\n\n\n\n

        401 Authorization Required

        \n\n\n
        nginx/1.11.3
        \n\n\n\n\n\n\n\n\n* Connection #0 to host 172.17.4.99 left intact\n\n\n\n\n\nTest 2: valid username/password (expect code 200)\n\n$ curl -k http://172.17.4.99 -v -H \n'Host: external-auth-01.sample.com'\n -u \n'user:passwd'\n\n* Rebuilt URL to: http://172.17.4.99/\n* Trying \n172\n.17.4.99...\n* Connected to \n172\n.17.4.99 \n(\n172\n.17.4.99\n)\n port \n80\n \n(\n#0)\n\n* Server auth using Basic with user \n'user'\n\n> GET / HTTP/1.1\n> Host: external-auth-01.sample.com\n> Authorization: Basic \ndXNlcjpwYXNzd2Q\n=\n\n> User-Agent: curl/7.50.1\n> Accept: */*\n>\n< HTTP/1.1 \n200\n OK\n< Server: nginx/1.11.3\n< Date: Mon, \n03\n Oct \n2016\n \n14\n:52:50 GMT\n< Content-Type: text/plain\n< Transfer-Encoding: chunked\n< Connection: keep-alive\n<\nCLIENT VALUES:\n\nclient_address\n=\n10\n.2.60.2\n\ncommand\n=\nGET\nreal \npath\n=\n/\n\nquery\n=\nnil\n\nrequest_version\n=\n1\n.1\n\nrequest_uri\n=\nhttp://external-auth-01.sample.com:8080/\n\nSERVER VALUES:\n\nserver_version\n=\nnginx: \n1\n.9.11 - lua: \n10001\n\n\nHEADERS RECEIVED:\n\naccept\n=\n*/*\n\nauthorization\n=\nBasic \ndXNlcjpwYXNzd2Q\n=\n\n\nconnection\n=\nclose\n\nhost\n=\nexternal-auth-01.sample.com\nuser-agent\n=\ncurl/7.50.1\nx-forwarded-for\n=\n10\n.2.60.1\nx-forwarded-host\n=\nexternal-auth-01.sample.com\nx-forwarded-port\n=\n80\n\nx-forwarded-proto\n=\nhttp\nx-real-ip\n=\n10\n.2.60.1\nBODY:\n* Connection \n#0 to host 172.17.4.99 left intact\n\n-no body in request-\n\n\n\nTest 3: invalid username/password (expect code 401)\n\ncurl -k http://172.17.4.99 -v -H 'Host: external-auth-01.sample.com' -u 'user:user'\n* Rebuilt URL to: http://172.17.4.99/\n* Trying 172.17.4.99...\n* Connected to 172.17.4.99 (172.17.4.99) port 80 (#0)\n* Server auth using Basic with user 'user'\n> GET / HTTP/1.1\n> Host: external-auth-01.sample.com\n> Authorization: Basic dXNlcjp1c2Vy\n> User-Agent: curl/7.50.1\n> Accept: */*\n>\n\n< HTTP\n/1.1\n \n401\n \nUnauthorized\n\n\n<\n \nServer:\n \nnginx/1.11.3\n\n\n<\n \nDate:\n \nMon,\n \n03\n \nOct\n \n2016\n \n14:53:04\n \nGMT\n\n\n<\n \nContent-Type:\n \ntext/html\n\n\n<\n \nContent-Length:\n \n195\n\n\n<\n \nConnection:\n \nkeep-alive\n\n\n*\n \nAuthentication\n \nproblem.\n \nIgnoring\n \nthis.\n\n\n<\n \nWWW-Authenticate:\n \nBasic\n \nrealm=\n\"Fake Realm\"\n\n\n<\n\n\n\n\n\n\n401 Authorization Required\n\n\n\n\n\n\n

        \n401 Authorization Required\n

        \n\n\n
        \nnginx/1.11.3\n
        \n\n\n\n\n\n\n\n* Connection #0 to host 172.17.4.99 left intact", "title": "External Basic Authentication" }, { @@ -1332,12 +1352,12 @@ }, { "location": "/examples/auth/external-auth/README/#example-1", - "text": "Use an external service (Basic Auth) located in https://httpbin.org $ kubectl create -f ingress.yaml\ningress \"external-auth\" created\n\n$ kubectl get ing external-auth\nNAME HOSTS ADDRESS PORTS AGE\nexternal-auth external-auth-01.sample.com 172 .17.4.99 80 13s\n\n$ kubectl get ing external-auth -o yaml\napiVersion: extensions/v1beta1\nkind: Ingress\nmetadata:\n annotations:\n nginx.ingress.kubernetes.io/auth-url: https://httpbin.org/basic-auth/user/passwd\n creationTimestamp: 2016 -10-03T13:50:35Z\n generation: 1 \n name: external-auth\n namespace: default\n resourceVersion: \"2068378\" \n selfLink: /apis/extensions/v1beta1/namespaces/default/ingresses/external-auth\n uid: 5c388f1d-8970-11e6-9004-080027d2dc94\nspec:\n rules:\n - host: external-auth-01.sample.com\n http:\n paths:\n - backend:\n serviceName: http-svc\n servicePort: 80 \n path: /\nstatus:\n loadBalancer:\n ingress:\n - ip: 172 .17.4.99\n$ Test 1: no username/password (expect code 401) $ curl -k http://172.17.4.99 -v -H 'Host: external-auth-01.sample.com' * Rebuilt URL to: http://172.17.4.99/ * Trying 172.17.4.99... * Connected to 172.17.4.99 (172.17.4.99) port 80 (#0) > GET / HTTP/1.1 > Host: external-auth-01.sample.com > User-Agent: curl/7.50.1 > Accept: */* > < HTTP/1.1 401 Unauthorized < Server: nginx/1.11.3 < Date: Mon, 03 Oct 2016 14:52:08 GMT < Content-Type: text/html < Content-Length: 195 < Connection: keep-alive < WWW-Authenticate: Basic realm=\"Fake Realm\" < 401 Authorization Required

        401 Authorization Required


        nginx/1.11.3
        * Connection #0 to host 172.17.4.99 left intact Test 2: valid username/password (expect code 200) $ curl -k http://172.17.4.99 -v -H 'Host: external-auth-01.sample.com' -u 'user:passwd' \n* Rebuilt URL to: http://172.17.4.99/\n* Trying 172 .17.4.99...\n* Connected to 172 .17.4.99 ( 172 .17.4.99 ) port 80 ( #0) \n* Server auth using Basic with user 'user' \n> GET / HTTP/1.1\n> Host: external-auth-01.sample.com\n> Authorization: Basic dXNlcjpwYXNzd2Q = \n> User-Agent: curl/7.50.1\n> Accept: */*\n>\n< HTTP/1.1 200 OK\n< Server: nginx/1.11.3\n< Date: Mon, 03 Oct 2016 14 :52:50 GMT\n< Content-Type: text/plain\n< Transfer-Encoding: chunked\n< Connection: keep-alive\n<\nCLIENT VALUES: client_address = 10 .2.60.2 command = GET\nreal path = / query = nil request_version = 1 .1 request_uri = http://external-auth-01.sample.com:8080/\n\nSERVER VALUES: server_version = nginx: 1 .9.11 - lua: 10001 \n\nHEADERS RECEIVED: accept = */* authorization = Basic dXNlcjpwYXNzd2Q = connection = close host = external-auth-01.sample.com\nuser-agent = curl/7.50.1\nx-forwarded-for = 10 .2.60.1\nx-forwarded-host = external-auth-01.sample.com\nx-forwarded-port = 80 \nx-forwarded-proto = http\nx-real-ip = 10 .2.60.1\nBODY:\n* Connection #0 to host 172.17.4.99 left intact \n-no body in request- Test 3: invalid username/password (expect code 401) curl -k http://172.17.4.99 -v -H 'Host: external-auth-01.sample.com' -u 'user:user'\n* Rebuilt URL to: http://172.17.4.99/\n* Trying 172.17.4.99...\n* Connected to 172.17.4.99 (172.17.4.99) port 80 (#0)\n* Server auth using Basic with user 'user'\n> GET / HTTP/1.1\n> Host: external-auth-01.sample.com\n> Authorization: Basic dXNlcjp1c2Vy\n> User-Agent: curl/7.50.1\n> Accept: */*\n> < HTTP /1.1 401 Unauthorized < Server: nginx/1.11.3 < Date: Mon, 03 Oct 2016 14:53:04 GMT < Content-Type: text/html < Content-Length: 195 < Connection: keep-alive * Authentication problem. Ignoring this. < WWW-Authenticate: Basic realm= \"Fake Realm\" < 401 Authorization Required

        401 Authorization Required


        nginx/1.11.3
        \n* Connection #0 to host 172.17.4.99 left intact", + "text": "Use an external service (Basic Auth) located in https://httpbin.org $ kubectl create -f ingress.yaml\ningress \"external-auth\" created\n\n$ kubectl get ing external-auth\nNAME HOSTS ADDRESS PORTS AGE\nexternal-auth external-auth-01.sample.com 172 .17.4.99 80 13s\n\n$ kubectl get ing external-auth -o yaml\napiVersion: extensions/v1beta1\nkind: Ingress\nmetadata:\n annotations:\n nginx.ingress.kubernetes.io/auth-url: https://httpbin.org/basic-auth/user/passwd\n creationTimestamp: 2016 -10-03T13:50:35Z\n generation: 1 \n name: external-auth\n namespace: default\n resourceVersion: \"2068378\" \n selfLink: /apis/extensions/v1beta1/namespaces/default/ingresses/external-auth\n uid: 5c388f1d-8970-11e6-9004-080027d2dc94\nspec:\n rules:\n - host: external-auth-01.sample.com\n http:\n paths:\n - backend:\n serviceName: http-svc\n servicePort: 80 \n path: /\nstatus:\n loadBalancer:\n ingress:\n - ip: 172 .17.4.99\n$ Test 1: no username/password (expect code 401) $ curl -k http://172.17.4.99 -v -H 'Host: external-auth-01.sample.com' * Rebuilt URL to: http://172.17.4.99/ * Trying 172.17.4.99... * Connected to 172.17.4.99 (172.17.4.99) port 80 (#0) > GET / HTTP/1.1 > Host: external-auth-01.sample.com > User-Agent: curl/7.50.1 > Accept: */* > < HTTP/1.1 401 Unauthorized < Server: nginx/1.11.3 < Date: Mon, 03 Oct 2016 14:52:08 GMT < Content-Type: text/html < Content-Length: 195 < Connection: keep-alive < WWW-Authenticate: Basic realm=\"Fake Realm\" < 401 Authorization Required

        401 Authorization Required


        nginx/1.11.3
        * Connection #0 to host 172.17.4.99 left intact Test 2: valid username/password (expect code 200) $ curl -k http://172.17.4.99 -v -H 'Host: external-auth-01.sample.com' -u 'user:passwd' \n* Rebuilt URL to: http://172.17.4.99/\n* Trying 172 .17.4.99...\n* Connected to 172 .17.4.99 ( 172 .17.4.99 ) port 80 ( #0) \n* Server auth using Basic with user 'user' \n> GET / HTTP/1.1\n> Host: external-auth-01.sample.com\n> Authorization: Basic dXNlcjpwYXNzd2Q = \n> User-Agent: curl/7.50.1\n> Accept: */*\n>\n< HTTP/1.1 200 OK\n< Server: nginx/1.11.3\n< Date: Mon, 03 Oct 2016 14 :52:50 GMT\n< Content-Type: text/plain\n< Transfer-Encoding: chunked\n< Connection: keep-alive\n<\nCLIENT VALUES: client_address = 10 .2.60.2 command = GET\nreal path = / query = nil request_version = 1 .1 request_uri = http://external-auth-01.sample.com:8080/\n\nSERVER VALUES: server_version = nginx: 1 .9.11 - lua: 10001 \n\nHEADERS RECEIVED: accept = */* authorization = Basic dXNlcjpwYXNzd2Q = connection = close host = external-auth-01.sample.com\nuser-agent = curl/7.50.1\nx-forwarded-for = 10 .2.60.1\nx-forwarded-host = external-auth-01.sample.com\nx-forwarded-port = 80 \nx-forwarded-proto = http\nx-real-ip = 10 .2.60.1\nBODY:\n* Connection #0 to host 172.17.4.99 left intact \n-no body in request- Test 3: invalid username/password (expect code 401) curl -k http://172.17.4.99 -v -H 'Host: external-auth-01.sample.com' -u 'user:user'\n* Rebuilt URL to: http://172.17.4.99/\n* Trying 172.17.4.99...\n* Connected to 172.17.4.99 (172.17.4.99) port 80 (#0)\n* Server auth using Basic with user 'user'\n> GET / HTTP/1.1\n> Host: external-auth-01.sample.com\n> Authorization: Basic dXNlcjp1c2Vy\n> User-Agent: curl/7.50.1\n> Accept: */*\n> < HTTP /1.1 401 Unauthorized < Server: nginx/1.11.3 < Date: Mon, 03 Oct 2016 14:53:04 GMT < Content-Type: text/html < Content-Length: 195 < Connection: keep-alive * Authentication problem. Ignoring this. < WWW-Authenticate: Basic realm= \"Fake Realm\" < 401 Authorization Required

        401 Authorization Required


        nginx/1.11.3
        \n* Connection #0 to host 172.17.4.99 left intact", "title": "Example 1:" }, { "location": "/examples/auth/oauth-external-auth/README/", - "text": "External OAUTH Authentication\n\u00b6\n\n\nOverview\n\u00b6\n\n\nThe \nauth-url\n and \nauth-signin\n annotations allow you to use an external\nauthentication provider to protect your Ingress resources.\n\n\n\n\nImportant\n\n\nThis annotation requires \nnginx-ingress-controller v0.9.0\n or greater.)\n\n\n\n\nKey Detail\n\u00b6\n\n\nThis functionality is enabled by deploying multiple Ingress objects for a single host.\nOne Ingress object has no special annotations and handles authentication.\n\n\nOther Ingress objects can then be annotated in such a way that require the user to\nauthenticate against the first Ingress's endpoint, and can redirect \n401\ns to the\nsame endpoint.\n\n\nSample:\n\n\n...\n\n\nmetadata\n:\n\n \nname\n:\n \napplication\n\n \nannotations\n:\n\n \nnginx.ingress.kubernetes.io/auth-url\n:\n \n\"https://$host/oauth2/auth\"\n\n \nnginx.ingress.kubernetes.io/auth-signin\n:\n \n\"https://$host/oauth2/start?rd=$escaped_request_uri\"\n\n\n...\n\n\n\n\n\n\nExample: OAuth2 Proxy + Kubernetes-Dashboard\n\u00b6\n\n\nThis example will show you how to deploy \noauth2_proxy\n\ninto a Kubernetes cluster and use it to protect the Kubernetes Dashboard using github as oAuth2 provider\n\n\nPrepare\n\u00b6\n\n\n\n\nInstall the kubernetes dashboard\n\n\n\n\nkubectl create -f https://raw.githubusercontent.com/kubernetes/kops/master/addons/kubernetes-dashboard/v1.5.0.yaml\n\n\n\n\n\n\n\n\nCreate a \ncustom Github OAuth application\n\n\n\n\n\n\n\n\nHomepage URL is the FQDN in the Ingress rule, like \nhttps://foo.bar.com\n\n\nAuthorization callback URL is the same as the base FQDN plus \n/oauth2\n, like \nhttps://foo.bar.com/oauth2\n\n\n\n\n\n\n\n\n\n\nConfigure oauth2_proxy values in the file oauth2-proxy.yaml with the values:\n\n\n\n\n\n\nOAUTH2_PROXY_CLIENT_ID with the github \n\n\n\n\n\nOAUTH2_PROXY_CLIENT_SECRET with the github \n\n\n\n\n\nOAUTH2_PROXY_COOKIE_SECRET with value of \npython\n \n-\nc\n \n'import os,base64; print base64.b64encode(os.urandom(16))'\n \n\n\n\n\n\n\nCustomize the contents of the file dashboard-ingress.yaml:\n\n\n\n\n\n\nReplace \n__INGRESS_HOST__\n with a valid FQDN and \n__INGRESS_SECRET__\n with a Secret with a valid SSL certificate.\n\n\n\n\nDeploy the oauth2 proxy and the ingress rules running:\n\n\n\n\n$\n kubectl create -f oauth2-proxy.yaml,dashboard-ingress.yaml\n\n\n\n\n\nTest the oauth integration accessing the configured URL, like \nhttps://foo.bar.com", + "text": "External OAUTH Authentication\n\u00b6\n\n\nOverview\n\u00b6\n\n\nThe \nauth-url\n and \nauth-signin\n annotations allow you to use an external\nauthentication provider to protect your Ingress resources.\n\n\n\n\nImportant\n\n\nThis annotation requires \nnginx-ingress-controller v0.9.0\n or greater.)\n\n\n\n\nKey Detail\n\u00b6\n\n\nThis functionality is enabled by deploying multiple Ingress objects for a single host.\nOne Ingress object has no special annotations and handles authentication.\n\n\nOther Ingress objects can then be annotated in such a way that require the user to\nauthenticate against the first Ingress's endpoint, and can redirect \n401\ns to the\nsame endpoint.\n\n\nSample:\n\n\n...\n\n\nmetadata\n:\n\n \nname\n:\n \napplication\n\n \nannotations\n:\n\n \nnginx.ingress.kubernetes.io/auth-url\n:\n \n\"https://$host/oauth2/auth\"\n\n \nnginx.ingress.kubernetes.io/auth-signin\n:\n \n\"https://$host/oauth2/start?rd=$escaped_request_uri\"\n\n\n...\n\n\n\n\n\nExample: OAuth2 Proxy + Kubernetes-Dashboard\n\u00b6\n\n\nThis example will show you how to deploy \noauth2_proxy\n\ninto a Kubernetes cluster and use it to protect the Kubernetes Dashboard using github as oAuth2 provider\n\n\nPrepare\n\u00b6\n\n\n\n\nInstall the kubernetes dashboard\n\n\n\n\nkubectl create -f https://raw.githubusercontent.com/kubernetes/kops/master/addons/kubernetes-dashboard/v1.5.0.yaml\n\n\n\n\n\n\n\nCreate a \ncustom Github OAuth application\n\n\n\n\n\n\n\n\nHomepage URL is the FQDN in the Ingress rule, like \nhttps://foo.bar.com\n\n\nAuthorization callback URL is the same as the base FQDN plus \n/oauth2\n, like \nhttps://foo.bar.com/oauth2\n\n\n\n\n\n\n\n\n\n\nConfigure oauth2_proxy values in the file oauth2-proxy.yaml with the values:\n\n\n\n\n\n\nOAUTH2_PROXY_CLIENT_ID with the github \n\n\n\n\n\nOAUTH2_PROXY_CLIENT_SECRET with the github \n\n\n\n\n\nOAUTH2_PROXY_COOKIE_SECRET with value of \npython\n \n-\nc\n \n'import os,base64; print base64.b64encode(os.urandom(16))'\n \n\n\n\n\n\n\nCustomize the contents of the file dashboard-ingress.yaml:\n\n\n\n\n\n\nReplace \n__INGRESS_HOST__\n with a valid FQDN and \n__INGRESS_SECRET__\n with a Secret with a valid SSL certificate.\n\n\n\n\nDeploy the oauth2 proxy and the ingress rules running:\n\n\n\n\n$\n kubectl create -f oauth2-proxy.yaml,dashboard-ingress.yaml\n\n\n\n\nTest the oauth integration accessing the configured URL, like \nhttps://foo.bar.com", "title": "External OAUTH Authentication" }, { @@ -1367,7 +1387,7 @@ }, { "location": "/examples/customization/configuration-snippets/README/", - "text": "Configuration Snippets\n\u00b6\n\n\nIngress\n\u00b6\n\n\nThe Ingress in this example adds a custom header to Nginx configuration that only applies to that specific Ingress. If you want to add headers that apply globally to all Ingresses, please have a look at \nthis example\n.\n\n\n$\n kubectl apply -f ingress.yaml\n\n\n\n\n\nTest\n\u00b6\n\n\nCheck if the contents of the annotation are present in the nginx.conf file using:\n\nkubectl exec nginx-ingress-controller-873061567-4n3k2 -n kube-system cat /etc/nginx/nginx.conf", + "text": "Configuration Snippets\n\u00b6\n\n\nIngress\n\u00b6\n\n\nThe Ingress in this example adds a custom header to Nginx configuration that only applies to that specific Ingress. If you want to add headers that apply globally to all Ingresses, please have a look at \nthis example\n.\n\n\n$\n kubectl apply -f ingress.yaml\n\n\n\n\nTest\n\u00b6\n\n\nCheck if the contents of the annotation are present in the nginx.conf file using:\n\nkubectl exec nginx-ingress-controller-873061567-4n3k2 -n kube-system cat /etc/nginx/nginx.conf", "title": "Configuration Snippets" }, { @@ -1387,7 +1407,7 @@ }, { "location": "/examples/customization/custom-configuration/README/", - "text": "Custom Configuration\n\u00b6\n\n\nUsing a \nConfigMap\n is possible to customize the NGINX configuration\n\n\nFor example, if we want to change the timeouts we need to create a ConfigMap:\n\n\n$ cat configmap.yaml\napiVersion: v1\ndata:\n proxy-connect-timeout: \n\"10\"\n\n proxy-read-timeout: \n\"120\"\n\n proxy-send-timeout: \n\"120\"\n\nkind: ConfigMap\nmetadata:\n name: nginx-load-balancer-conf\n\n\n\n\n\ncurl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/docs/examples/customization/custom-configuration/configmap.yaml \\\n | kubectl apply -f -\n\n\n\n\n\nIf the Configmap it is updated, NGINX will be reloaded with the new configuration.", + "text": "Custom Configuration\n\u00b6\n\n\nUsing a \nConfigMap\n is possible to customize the NGINX configuration\n\n\nFor example, if we want to change the timeouts we need to create a ConfigMap:\n\n\n$ cat configmap.yaml\napiVersion: v1\ndata:\n proxy-connect-timeout: \n\"10\"\n\n proxy-read-timeout: \n\"120\"\n\n proxy-send-timeout: \n\"120\"\n\nkind: ConfigMap\nmetadata:\n name: nginx-load-balancer-conf\n\n\n\n\ncurl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/docs/examples/customization/custom-configuration/configmap.yaml \\\n | kubectl apply -f -\n\n\n\n\nIf the Configmap it is updated, NGINX will be reloaded with the new configuration.", "title": "Custom Configuration" }, { @@ -1397,7 +1417,7 @@ }, { "location": "/examples/customization/custom-errors/README/", - "text": "Custom Errors\n\u00b6\n\n\nThis example demonstrates how to use a custom backend to render custom error pages.\n\n\nCustomized default backend\n\u00b6\n\n\nFirst, create the custom \ndefault-backend\n. It will be used by the Ingress controller later on.\n\n\n$ kubectl create -f custom-default-backend.yaml\nservice \n\"nginx-errors\"\n created\ndeployment.apps \n\"nginx-errors\"\n created\n\n\n\n\n\nThis should have created a Deployment and a Service with the name \nnginx-errors\n.\n\n\n$ kubectl get deploy,svc\nNAME DESIRED CURRENT READY AGE\ndeployment.apps/nginx-errors \n1\n \n1\n \n1\n 10s\n\nNAME TYPE CLUSTER-IP EXTERNAL-IP PORT\n(\nS\n)\n AGE\nservice/nginx-errors ClusterIP \n10\n.0.0.12 \n80\n/TCP 10s\n\n\n\n\n\nIngress controller configuration\n\u00b6\n\n\nIf you do not already have an instance of the the NGINX Ingress controller running, deploy it according to the\n\ndeployment guide\n, then follow these steps:\n\n\n\n\n\n\nEdit the \nnginx-ingress-controller\n Deployment and set the value of the \n--default-backend\n flag to the name of the\n newly created error backend.\n\n\n\n\n\n\nEdit the \nnginx-configuration\n ConfigMap and create the key \ncustom-http-errors\n with a value of \n404,503\n.\n\n\n\n\n\n\nTake note of the IP address assigned to the NGINX Ingress controller Service.\n \n$ kubectl get svc ingress-nginxNAME TYPE CLUSTER-IP EXTERNAL-IP PORT\n(\nS\n)\n AGEingress-nginx ClusterIP \n10\n.0.0.13 \n80\n/TCP,443/TCP 10m\n\n\n\n\n\n\n\n\nNote\n\n\nThe \ningress-nginx\n Service is of type \nClusterIP\n in this example. This may vary depending on your environment.\nMake sure you can use the Service to reach NGINX before proceeding with the rest of this example.\n\n\n\n\nTesting error pages\n\u00b6\n\n\nLet us send a couple of HTTP requests using cURL and validate everything is working as expected.\n\n\nA request to the default backend returns a 404 error with a custom message:\n\n\n$ curl -D- http://10.0.0.13/\nHTTP/1.1 404 Not Found\nServer: nginx/1.13.12\nDate: Tue, 12 Jun 2018 19:11:24 GMT\nContent-Type: */*\nTransfer-Encoding: chunked\nConnection: keep-alive\n\n\n\nThe page you're looking for could not be found.\n\n\n\n\n\n\n\nA request with a custom \nAccept\n header returns the corresponding document type (JSON):\n\n\n$ curl -D- -H \n'Accept: application/json'\n http://10.0.0.13/\nHTTP/1.1 \n404\n Not Found\nServer: nginx/1.13.12\nDate: Tue, \n12\n Jun \n2018\n \n19\n:12:36 GMT\nContent-Type: application/json\nTransfer-Encoding: chunked\nConnection: keep-alive\nVary: Accept-Encoding\n\n\n{\n \n\"message\"\n: \n\"The page you're looking for could not be found\"\n \n}\n\n\n\n\n\n\nTo go further with this example, feel free to deploy your own applications and Ingress objects, and validate that the\nresponses are still in the correct format when a backend returns 503 (eg. if you scale a Deployment down to 0 replica).", + "text": "Custom Errors\n\u00b6\n\n\nThis example demonstrates how to use a custom backend to render custom error pages.\n\n\nCustomized default backend\n\u00b6\n\n\nFirst, create the custom \ndefault-backend\n. It will be used by the Ingress controller later on.\n\n\n$ kubectl create -f custom-default-backend.yaml\nservice \n\"nginx-errors\"\n created\ndeployment.apps \n\"nginx-errors\"\n created\n\n\n\n\nThis should have created a Deployment and a Service with the name \nnginx-errors\n.\n\n\n$ kubectl get deploy,svc\nNAME DESIRED CURRENT READY AGE\ndeployment.apps/nginx-errors \n1\n \n1\n \n1\n 10s\n\nNAME TYPE CLUSTER-IP EXTERNAL-IP PORT\n(\nS\n)\n AGE\nservice/nginx-errors ClusterIP \n10\n.0.0.12 \n80\n/TCP 10s\n\n\n\n\nIngress controller configuration\n\u00b6\n\n\nIf you do not already have an instance of the the NGINX Ingress controller running, deploy it according to the\n\ndeployment guide\n, then follow these steps:\n\n\n\n\n\n\nEdit the \nnginx-ingress-controller\n Deployment and set the value of the \n--default-backend\n flag to the name of the\n newly created error backend.\n\n\n\n\n\n\nEdit the \nnginx-configuration\n ConfigMap and create the key \ncustom-http-errors\n with a value of \n404,503\n.\n\n\n\n\n\n\nTake note of the IP address assigned to the NGINX Ingress controller Service.\n \n$ kubectl get svc ingress-nginx\nNAME TYPE CLUSTER-IP EXTERNAL-IP PORT\n(\nS\n)\n AGE\ningress-nginx ClusterIP \n10\n.0.0.13 \n80\n/TCP,443/TCP 10m\n\n\n\n\n\n\n\n\n\nNote\n\n\nThe \ningress-nginx\n Service is of type \nClusterIP\n in this example. This may vary depending on your environment.\nMake sure you can use the Service to reach NGINX before proceeding with the rest of this example.\n\n\n\n\nTesting error pages\n\u00b6\n\n\nLet us send a couple of HTTP requests using cURL and validate everything is working as expected.\n\n\nA request to the default backend returns a 404 error with a custom message:\n\n\n$ curl -D- http://10.0.0.13/\nHTTP/1.1 404 Not Found\nServer: nginx/1.13.12\nDate: Tue, 12 Jun 2018 19:11:24 GMT\nContent-Type: */*\nTransfer-Encoding: chunked\nConnection: keep-alive\n\n\n\nThe page you're looking for could not be found.\n\n\n\n\n\n\nA request with a custom \nAccept\n header returns the corresponding document type (JSON):\n\n\n$ curl -D- -H \n'Accept: application/json'\n http://10.0.0.13/\nHTTP/1.1 \n404\n Not Found\nServer: nginx/1.13.12\nDate: Tue, \n12\n Jun \n2018\n \n19\n:12:36 GMT\nContent-Type: application/json\nTransfer-Encoding: chunked\nConnection: keep-alive\nVary: Accept-Encoding\n\n\n{\n \n\"message\"\n: \n\"The page you're looking for could not be found\"\n \n}\n\n\n\n\n\nTo go further with this example, feel free to deploy your own applications and Ingress objects, and validate that the\nresponses are still in the correct format when a backend returns 503 (eg. if you scale a Deployment down to 0 replica).", "title": "Custom Errors" }, { @@ -1412,7 +1432,7 @@ }, { "location": "/examples/customization/custom-errors/README/#ingress-controller-configuration", - "text": "If you do not already have an instance of the the NGINX Ingress controller running, deploy it according to the deployment guide , then follow these steps: Edit the nginx-ingress-controller Deployment and set the value of the --default-backend flag to the name of the\n newly created error backend. Edit the nginx-configuration ConfigMap and create the key custom-http-errors with a value of 404,503 . Take note of the IP address assigned to the NGINX Ingress controller Service.\n $ kubectl get svc ingress-nginxNAME TYPE CLUSTER-IP EXTERNAL-IP PORT ( S ) AGEingress-nginx ClusterIP 10 .0.0.13 80 /TCP,443/TCP 10m Note The ingress-nginx Service is of type ClusterIP in this example. This may vary depending on your environment.\nMake sure you can use the Service to reach NGINX before proceeding with the rest of this example.", + "text": "If you do not already have an instance of the the NGINX Ingress controller running, deploy it according to the deployment guide , then follow these steps: Edit the nginx-ingress-controller Deployment and set the value of the --default-backend flag to the name of the\n newly created error backend. Edit the nginx-configuration ConfigMap and create the key custom-http-errors with a value of 404,503 . Take note of the IP address assigned to the NGINX Ingress controller Service.\n $ kubectl get svc ingress-nginx\nNAME TYPE CLUSTER-IP EXTERNAL-IP PORT ( S ) AGE\ningress-nginx ClusterIP 10 .0.0.13 80 /TCP,443/TCP 10m Note The ingress-nginx Service is of type ClusterIP in this example. This may vary depending on your environment.\nMake sure you can use the Service to reach NGINX before proceeding with the rest of this example.", "title": "Ingress controller configuration" }, { @@ -1422,7 +1442,7 @@ }, { "location": "/examples/customization/custom-headers/README/", - "text": "Custom Headers\n\u00b6\n\n\nThis example aims to demonstrate the deployment of an nginx ingress controller and\nuse a ConfigMap to configure a custom list of headers to be passed to the upstream\nserver\n\n\ncurl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/docs/examples/customization/custom-headers/configmap.yaml \\\n\n\n | kubectl apply -f -\n\n\n\ncurl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/docs/examples/customization/custom-headers/custom-headers.yaml \\\n\n\n | kubectl apply -f -\n\n\n\n\n\n\nTest\n\u00b6\n\n\nCheck the contents of the configmap is present in the nginx.conf file using:\n\nkubectl exec nginx-ingress-controller-873061567-4n3k2 -n kube-system cat /etc/nginx/nginx.conf", + "text": "Custom Headers\n\u00b6\n\n\nThis example aims to demonstrate the deployment of an nginx ingress controller and\nuse a ConfigMap to configure a custom list of headers to be passed to the upstream\nserver\n\n\ncurl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/docs/examples/customization/custom-headers/configmap.yaml \\\n\n\n | kubectl apply -f -\n\n\n\ncurl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/docs/examples/customization/custom-headers/custom-headers.yaml \\\n\n\n | kubectl apply -f -\n\n\n\n\n\nTest\n\u00b6\n\n\nCheck the contents of the configmap is present in the nginx.conf file using:\n\nkubectl exec nginx-ingress-controller-873061567-4n3k2 -n kube-system cat /etc/nginx/nginx.conf", "title": "Custom Headers" }, { @@ -1437,17 +1457,17 @@ }, { "location": "/examples/customization/custom-upstream-check/README/", - "text": "Custom Upstream server checks\n\u00b6\n\n\nThis example shows how is possible to create a custom configuration for a particular upstream associated with an Ingress rule.\n\n\necho \"\napiVersion: extensions/v1beta1\nkind: Ingress\nmetadata:\n name: http-svc\n annotations:\n nginx.ingress.kubernetes.io/upstream-fail-timeout: \"30\"\nspec:\n rules:\n - host: foo.bar.com\n http:\n paths:\n - path: /\n backend:\n serviceName: http-svc\n servicePort: 80\n\" | kubectl create -f -\n\n\n\n\n\nCheck the annotation is present in the Ingress rule:\n\n\nkubectl get ingress http-svc -o yaml\n\n\n\n\n\nCheck the NGINX configuration is updated using kubectl or the status page:\n\n\n$ kubectl \nexec\n nginx-ingress-controller-v1ppm cat /etc/nginx/nginx.conf\n\n\n\n\n\n....\n\n \nupstream\n \ndefault-http-svc-x-80\n \n{\n\n \nleast_conn\n;\n\n \nserver\n \n10.2.92.2:8080\n \nmax_fails=5\n \nfail_timeout=30\n;\n\n\n \n}\n\n\n....", + "text": "Custom Upstream server checks\n\u00b6\n\n\nThis example shows how is possible to create a custom configuration for a particular upstream associated with an Ingress rule.\n\n\necho \"\napiVersion: extensions/v1beta1\nkind: Ingress\nmetadata:\n name: http-svc\n annotations:\n nginx.ingress.kubernetes.io/upstream-fail-timeout: \"30\"\nspec:\n rules:\n - host: foo.bar.com\n http:\n paths:\n - path: /\n backend:\n serviceName: http-svc\n servicePort: 80\n\" | kubectl create -f -\n\n\n\n\nCheck the annotation is present in the Ingress rule:\n\nkubectl get ingress http-svc -o yaml\n\n\n\nCheck the NGINX configuration is updated using kubectl or the status page:\n\n\n$ kubectl \nexec\n nginx-ingress-controller-v1ppm cat /etc/nginx/nginx.conf\n\n\n\n\n....\n\n \nupstream\n \ndefault-http-svc-x-80\n \n{\n\n \nleast_conn\n;\n\n \nserver\n \n10.2.92.2:8080\n \nmax_fails=5\n \nfail_timeout=30\n;\n\n\n \n}\n\n\n....", "title": "Custom Upstream server checks" }, { "location": "/examples/customization/custom-upstream-check/README/#custom-upstream-server-checks", - "text": "This example shows how is possible to create a custom configuration for a particular upstream associated with an Ingress rule. echo \"\napiVersion: extensions/v1beta1\nkind: Ingress\nmetadata:\n name: http-svc\n annotations:\n nginx.ingress.kubernetes.io/upstream-fail-timeout: \"30\"\nspec:\n rules:\n - host: foo.bar.com\n http:\n paths:\n - path: /\n backend:\n serviceName: http-svc\n servicePort: 80\n\" | kubectl create -f - Check the annotation is present in the Ingress rule: kubectl get ingress http-svc -o yaml Check the NGINX configuration is updated using kubectl or the status page: $ kubectl exec nginx-ingress-controller-v1ppm cat /etc/nginx/nginx.conf .... \n upstream default-http-svc-x-80 { \n least_conn ; \n server 10.2.92.2:8080 max_fails=5 fail_timeout=30 ; \n\n } ....", + "text": "This example shows how is possible to create a custom configuration for a particular upstream associated with an Ingress rule. echo \"\napiVersion: extensions/v1beta1\nkind: Ingress\nmetadata:\n name: http-svc\n annotations:\n nginx.ingress.kubernetes.io/upstream-fail-timeout: \"30\"\nspec:\n rules:\n - host: foo.bar.com\n http:\n paths:\n - path: /\n backend:\n serviceName: http-svc\n servicePort: 80\n\" | kubectl create -f - Check the annotation is present in the Ingress rule: kubectl get ingress http-svc -o yaml Check the NGINX configuration is updated using kubectl or the status page: $ kubectl exec nginx-ingress-controller-v1ppm cat /etc/nginx/nginx.conf .... \n upstream default-http-svc-x-80 { \n least_conn ; \n server 10.2.92.2:8080 max_fails=5 fail_timeout=30 ; \n\n } ....", "title": "Custom Upstream server checks" }, { "location": "/examples/customization/external-auth-headers/README/", - "text": "External authentication, authentication service response headers propagation\n\u00b6\n\n\nThis example demonstrates propagation of selected authentication service response headers\nto backend service.\n\n\nSample configuration includes:\n\n\n\n\nSample authentication service producing several response headers\n\n\nAuthentication logic is based on HTTP header: requests with header \nUser\n containing string \ninternal\n are considered authenticated\n\n\nAfter successful authentication service generates response headers \nUserID\n and \nUserRole\n\n\nSample echo service displaying header information\n\n\nTwo ingress objects pointing to echo service\n\n\nPublic, which allows access from unauthenticated users\n\n\nPrivate, which allows access from authenticated users only\n\n\n\n\nYou can deploy the controller as\nfollows:\n\n\n$\n kubectl create -f deploy/\n\ndeployment \"demo-auth-service\" created\n\n\nservice \"demo-auth-service\" created\n\n\ningress \"demo-auth-service\" created\n\n\ndeployment \"demo-echo-service\" created\n\n\nservice \"demo-echo-service\" created\n\n\ningress \"public-demo-echo-service\" created\n\n\ningress \"secure-demo-echo-service\" created\n\n\n\n$\n kubectl get po\n\nNAME READY STATUS RESTARTS AGE\n\n\nNAME READY STATUS RESTARTS AGE\n\n\ndemo-auth-service-2769076528-7g9mh 1/1 Running 0 30s\n\n\ndemo-echo-service-3636052215-3vw8c 1/1 Running 0 29s\n\n\n\nkubectl get ing\n\n\nNAME HOSTS ADDRESS PORTS AGE\n\n\npublic-demo-echo-service public-demo-echo-service.kube.local 80 1m\n\n\nsecure-demo-echo-service secure-demo-echo-service.kube.local 80 1m\n\n\n\n\n\n\nTest 1: public service with no auth header\n\n\n$\n curl -H \n'Host: public-demo-echo-service.kube.local'\n -v \n192\n.168.99.100\n\n* Rebuilt URL to: 192.168.99.100/\n\n\n* Trying 192.168.99.100...\n\n\n* Connected to 192.168.99.100 (192.168.99.100) port 80 (#0)\n\n\n>\n GET / HTTP/1.1\n\n>\n Host: public-demo-echo-service.kube.local\n\n>\n User-Agent: curl/7.43.0\n\n>\n Accept: */*\n\n>\n\n\n< HTTP/1.1 200 OK\n\n\n< Server: nginx/1.11.10\n\n\n< Date: Mon, 13 Mar 2017 20:19:21 GMT\n\n\n< Content-Type: text/plain; charset=utf-8\n\n\n< Content-Length: 20\n\n\n< Connection: keep-alive\n\n\n<\n\n\n* Connection #0 to host 192.168.99.100 left intact\n\n\nUserID: , UserRole:\n\n\n\n\n\n\nTest 2: secure service with no auth header\n\n\n$\n curl -H \n'Host: secure-demo-echo-service.kube.local'\n -v \n192\n.168.99.100\n\n* Rebuilt URL to: 192.168.99.100/\n\n\n* Trying 192.168.99.100...\n\n\n* Connected to 192.168.99.100 (192.168.99.100) port 80 (#0)\n\n\n>\n GET / HTTP/1.1\n\n>\n Host: secure-demo-echo-service.kube.local\n\n>\n User-Agent: curl/7.43.0\n\n>\n Accept: */*\n\n>\n\n\n< HTTP/1.1 403 Forbidden\n\n\n< Server: nginx/1.11.10\n\n\n< Date: Mon, 13 Mar 2017 20:18:48 GMT\n\n\n< Content-Type: text/html\n\n\n< Content-Length: 170\n\n\n< Connection: keep-alive\n\n\n<\n\n\n\n\n\n403 Forbidden\n\n\n\n\n\n

        403 Forbidden

        \n\n\n
        nginx/1.11.10
        \n\n\n\n\n\n\n\n\n* Connection #0 to host 192.168.99.100 left intact\n\n\n\n\n\n\nTest 3: public service with valid auth header\n\n\n$\n curl -H \n'Host: public-demo-echo-service.kube.local'\n -H \n'User:internal'\n -v \n192\n.168.99.100\n\n* Rebuilt URL to: 192.168.99.100/\n\n\n* Trying 192.168.99.100...\n\n\n* Connected to 192.168.99.100 (192.168.99.100) port 80 (#0)\n\n\n>\n GET / HTTP/1.1\n\n>\n Host: public-demo-echo-service.kube.local\n\n>\n User-Agent: curl/7.43.0\n\n>\n Accept: */*\n\n>\n User:internal\n\n>\n\n\n< HTTP/1.1 200 OK\n\n\n< Server: nginx/1.11.10\n\n\n< Date: Mon, 13 Mar 2017 20:19:59 GMT\n\n\n< Content-Type: text/plain; charset=utf-8\n\n\n< Content-Length: 44\n\n\n< Connection: keep-alive\n\n\n<\n\n\n* Connection #0 to host 192.168.99.100 left intact\n\n\nUserID: 1443635317331776148, UserRole: admin\n\n\n\n\n\n\nTest 4: public service with valid auth header\n\n\n$\n curl -H \n'Host: secure-demo-echo-service.kube.local'\n -H \n'User:internal'\n -v \n192\n.168.99.100\n\n* Rebuilt URL to: 192.168.99.100/\n\n\n* Trying 192.168.99.100...\n\n\n* Connected to 192.168.99.100 (192.168.99.100) port 80 (#0)\n\n\n>\n GET / HTTP/1.1\n\n>\n Host: secure-demo-echo-service.kube.local\n\n>\n User-Agent: curl/7.43.0\n\n>\n Accept: */*\n\n>\n User:internal\n\n>\n\n\n< HTTP/1.1 200 OK\n\n\n< Server: nginx/1.11.10\n\n\n< Date: Mon, 13 Mar 2017 20:17:23 GMT\n\n\n< Content-Type: text/plain; charset=utf-8\n\n\n< Content-Length: 43\n\n\n< Connection: keep-alive\n\n\n<\n\n\n* Connection #0 to host 192.168.99.100 left intact\n\n\nUserID: 605394647632969758, UserRole: admin", + "text": "External authentication, authentication service response headers propagation\n\u00b6\n\n\nThis example demonstrates propagation of selected authentication service response headers\nto backend service.\n\n\nSample configuration includes:\n\n\n\n\nSample authentication service producing several response headers\n\n\nAuthentication logic is based on HTTP header: requests with header \nUser\n containing string \ninternal\n are considered authenticated\n\n\nAfter successful authentication service generates response headers \nUserID\n and \nUserRole\n\n\nSample echo service displaying header information\n\n\nTwo ingress objects pointing to echo service\n\n\nPublic, which allows access from unauthenticated users\n\n\nPrivate, which allows access from authenticated users only\n\n\n\n\nYou can deploy the controller as\nfollows:\n\n\n$\n kubectl create -f deploy/\n\ndeployment \"demo-auth-service\" created\n\n\nservice \"demo-auth-service\" created\n\n\ningress \"demo-auth-service\" created\n\n\ndeployment \"demo-echo-service\" created\n\n\nservice \"demo-echo-service\" created\n\n\ningress \"public-demo-echo-service\" created\n\n\ningress \"secure-demo-echo-service\" created\n\n\n\n$\n kubectl get po\n\nNAME READY STATUS RESTARTS AGE\n\n\nNAME READY STATUS RESTARTS AGE\n\n\ndemo-auth-service-2769076528-7g9mh 1/1 Running 0 30s\n\n\ndemo-echo-service-3636052215-3vw8c 1/1 Running 0 29s\n\n\n\nkubectl get ing\n\n\nNAME HOSTS ADDRESS PORTS AGE\n\n\npublic-demo-echo-service public-demo-echo-service.kube.local 80 1m\n\n\nsecure-demo-echo-service secure-demo-echo-service.kube.local 80 1m\n\n\n\n\n\nTest 1: public service with no auth header\n\n\n$\n curl -H \n'Host: public-demo-echo-service.kube.local'\n -v \n192\n.168.99.100\n\n* Rebuilt URL to: 192.168.99.100/\n\n\n* Trying 192.168.99.100...\n\n\n* Connected to 192.168.99.100 (192.168.99.100) port 80 (#0)\n\n\n>\n GET / HTTP/1.1\n\n>\n Host: public-demo-echo-service.kube.local\n\n>\n User-Agent: curl/7.43.0\n\n>\n Accept: */*\n\n>\n\n\n< HTTP/1.1 200 OK\n\n\n< Server: nginx/1.11.10\n\n\n< Date: Mon, 13 Mar 2017 20:19:21 GMT\n\n\n< Content-Type: text/plain; charset=utf-8\n\n\n< Content-Length: 20\n\n\n< Connection: keep-alive\n\n\n<\n\n\n* Connection #0 to host 192.168.99.100 left intact\n\n\nUserID: , UserRole:\n\n\n\n\n\nTest 2: secure service with no auth header\n\n\n$\n curl -H \n'Host: secure-demo-echo-service.kube.local'\n -v \n192\n.168.99.100\n\n* Rebuilt URL to: 192.168.99.100/\n\n\n* Trying 192.168.99.100...\n\n\n* Connected to 192.168.99.100 (192.168.99.100) port 80 (#0)\n\n\n>\n GET / HTTP/1.1\n\n>\n Host: secure-demo-echo-service.kube.local\n\n>\n User-Agent: curl/7.43.0\n\n>\n Accept: */*\n\n>\n\n\n< HTTP/1.1 403 Forbidden\n\n\n< Server: nginx/1.11.10\n\n\n< Date: Mon, 13 Mar 2017 20:18:48 GMT\n\n\n< Content-Type: text/html\n\n\n< Content-Length: 170\n\n\n< Connection: keep-alive\n\n\n<\n\n\n\n\n\n403 Forbidden\n\n\n\n\n\n

        403 Forbidden

        \n\n\n
        nginx/1.11.10
        \n\n\n\n\n\n\n\n\n* Connection #0 to host 192.168.99.100 left intact\n\n\n\n\n\nTest 3: public service with valid auth header\n\n\n$\n curl -H \n'Host: public-demo-echo-service.kube.local'\n -H \n'User:internal'\n -v \n192\n.168.99.100\n\n* Rebuilt URL to: 192.168.99.100/\n\n\n* Trying 192.168.99.100...\n\n\n* Connected to 192.168.99.100 (192.168.99.100) port 80 (#0)\n\n\n>\n GET / HTTP/1.1\n\n>\n Host: public-demo-echo-service.kube.local\n\n>\n User-Agent: curl/7.43.0\n\n>\n Accept: */*\n\n>\n User:internal\n\n>\n\n\n< HTTP/1.1 200 OK\n\n\n< Server: nginx/1.11.10\n\n\n< Date: Mon, 13 Mar 2017 20:19:59 GMT\n\n\n< Content-Type: text/plain; charset=utf-8\n\n\n< Content-Length: 44\n\n\n< Connection: keep-alive\n\n\n<\n\n\n* Connection #0 to host 192.168.99.100 left intact\n\n\nUserID: 1443635317331776148, UserRole: admin\n\n\n\n\n\nTest 4: public service with valid auth header\n\n\n$\n curl -H \n'Host: secure-demo-echo-service.kube.local'\n -H \n'User:internal'\n -v \n192\n.168.99.100\n\n* Rebuilt URL to: 192.168.99.100/\n\n\n* Trying 192.168.99.100...\n\n\n* Connected to 192.168.99.100 (192.168.99.100) port 80 (#0)\n\n\n>\n GET / HTTP/1.1\n\n>\n Host: secure-demo-echo-service.kube.local\n\n>\n User-Agent: curl/7.43.0\n\n>\n Accept: */*\n\n>\n User:internal\n\n>\n\n\n< HTTP/1.1 200 OK\n\n\n< Server: nginx/1.11.10\n\n\n< Date: Mon, 13 Mar 2017 20:17:23 GMT\n\n\n< Content-Type: text/plain; charset=utf-8\n\n\n< Content-Length: 43\n\n\n< Connection: keep-alive\n\n\n<\n\n\n* Connection #0 to host 192.168.99.100 left intact\n\n\nUserID: 605394647632969758, UserRole: admin", "title": "External authentication, authentication service response headers propagation" }, { @@ -1457,7 +1477,7 @@ }, { "location": "/examples/customization/ssl-dh-param/README/", - "text": "Custom DH parameters for perfect forward secrecy\n\u00b6\n\n\nThis example aims to demonstrate the deployment of an nginx ingress controller and\nuse a ConfigMap to configure custom Diffie-Hellman parameters file to help with\n\"Perfect Forward Secrecy\".\n\n\nCustom configuration\n\u00b6\n\n\n$\n cat configmap.yaml\n\napiVersion: v1\n\n\ndata:\n\n\n ssl-dh-param: \"ingress-nginx/lb-dhparam\"\n\n\nkind: ConfigMap\n\n\nmetadata:\n\n\n name: nginx-configuration\n\n\n namespace: ingress-nginx\n\n\n labels:\n\n\n app: ingress-nginx\n\n\n\n\n\n\n$\n kubectl create -f configmap.yaml\n\n\n\n\n\nCustom DH parameters secret\n\u00b6\n\n\n$\n> openssl dhparam \n1024\n \n2\n> /dev/null \n|\n base64\n\nLS0tLS1CRUdJTiBESCBQQVJBTUVURVJ...\n\n\n\n\n\n\n$\n cat ssl-dh-param.yaml\n\napiVersion: v1\n\n\ndata:\n\n\n dhparam.pem: \"LS0tLS1CRUdJTiBESCBQQVJBTUVURVJ...\"\n\n\nkind: ConfigMap\n\n\nmetadata:\n\n\n name: nginx-configuration\n\n\n namespace: ingress-nginx\n\n\n labels:\n\n\n app: ingress-nginx\n\n\n\n\n\n\n$\n kubectl create -f ssl-dh-param.yaml\n\n\n\n\n\nTest\n\u00b6\n\n\nCheck the contents of the configmap is present in the nginx.conf file using:\n\nkubectl exec nginx-ingress-controller-873061567-4n3k2 -n kube-system cat /etc/nginx/nginx.conf", + "text": "Custom DH parameters for perfect forward secrecy\n\u00b6\n\n\nThis example aims to demonstrate the deployment of an nginx ingress controller and\nuse a ConfigMap to configure custom Diffie-Hellman parameters file to help with\n\"Perfect Forward Secrecy\".\n\n\nCustom configuration\n\u00b6\n\n\n$\n cat configmap.yaml\n\napiVersion: v1\n\n\ndata:\n\n\n ssl-dh-param: \"ingress-nginx/lb-dhparam\"\n\n\nkind: ConfigMap\n\n\nmetadata:\n\n\n name: nginx-configuration\n\n\n namespace: ingress-nginx\n\n\n labels:\n\n\n app: ingress-nginx\n\n\n\n\n\n$\n kubectl create -f configmap.yaml\n\n\n\n\nCustom DH parameters secret\n\u00b6\n\n\n$\n> openssl dhparam \n1024\n \n2\n> /dev/null \n|\n base64\n\nLS0tLS1CRUdJTiBESCBQQVJBTUVURVJ...\n\n\n\n\n\n$\n cat ssl-dh-param.yaml\n\napiVersion: v1\n\n\ndata:\n\n\n dhparam.pem: \"LS0tLS1CRUdJTiBESCBQQVJBTUVURVJ...\"\n\n\nkind: ConfigMap\n\n\nmetadata:\n\n\n name: nginx-configuration\n\n\n namespace: ingress-nginx\n\n\n labels:\n\n\n app: ingress-nginx\n\n\n\n\n\n$\n kubectl create -f ssl-dh-param.yaml\n\n\n\n\nTest\n\u00b6\n\n\nCheck the contents of the configmap is present in the nginx.conf file using:\n\nkubectl exec nginx-ingress-controller-873061567-4n3k2 -n kube-system cat /etc/nginx/nginx.conf", "title": "Custom DH parameters for perfect forward secrecy" }, { @@ -1492,7 +1512,7 @@ }, { "location": "/examples/docker-registry/README/", - "text": "Docker registry\n\u00b6\n\n\nThis example demonstrates how to deploy a \ndocker registry\n in the cluster and configure Ingress enable access from Internet\n\n\nDeployment\n\u00b6\n\n\nFirst we deploy the docker registry in the cluster:\n\n\nkubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/docs/examples/docker-registry/deployment.yaml\n\n\n\n\n\n\n\n\nImportant\n\n\nDO NOT RUN THIS IN PRODUCTION\n\n\nThis deployment uses \nemptyDir\n in the \nvolumeMount\n which means the contents of the registry will be deleted when the pod dies.\n\n\n\n\nThe next required step is creation of the ingress rules. To do this we have two options: with and without TLS\n\n\nWithout TLS\n\u00b6\n\n\nDownload and edit the yaml deployment replacing \nregistry.\n with a valid DNS name pointing to the ingress controller:\n\n\nwget https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/docs/examples/docker-registry/ingress-without-tls.yaml\n\n\n\n\n\n\n\n\nImportant\n\n\n\n\nRunning a docker registry without TLS requires we configure our local docker daemon with the insecure registry flag.\n\n\nPlease check \ndeploy a plain http registry\n\n\nWith TLS\n\u00b6\n\n\nDownload and edit the yaml deployment replacing \nregistry.\n with a valid DNS name pointing to the ingress controller:\n\n\nwget https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/docs/examples/docker-registry/ingress-with-tls.yaml\n\n\n\n\n\n\nDeploy \nkube lego\n use \nLet's Encrypt\n certificates or edit the ingress rule to use a secret with an existing SSL certificate.\n\n\nTesting\n\u00b6\n\n\nTo test the registry is working correctly we download a known image from \ndocker hub\n, create a tag pointing to the new registry and upload the image:\n\n\ndocker pull ubuntu:16.04\n\n\ndocker tag ubuntu:16.04 `registry./ubuntu:16.04`\n\n\ndocker push `registry./ubuntu:16.04`\n\n\n\n\n\n\nPlease replace \nregistry.\n with your domain.", + "text": "Docker registry\n\u00b6\n\n\nThis example demonstrates how to deploy a \ndocker registry\n in the cluster and configure Ingress enable access from Internet\n\n\nDeployment\n\u00b6\n\n\nFirst we deploy the docker registry in the cluster:\n\n\nkubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/docs/examples/docker-registry/deployment.yaml\n\n\n\n\n\n\n\nImportant\n\n\nDO NOT RUN THIS IN PRODUCTION\n\n\nThis deployment uses \nemptyDir\n in the \nvolumeMount\n which means the contents of the registry will be deleted when the pod dies.\n\n\n\n\nThe next required step is creation of the ingress rules. To do this we have two options: with and without TLS\n\n\nWithout TLS\n\u00b6\n\n\nDownload and edit the yaml deployment replacing \nregistry.\n with a valid DNS name pointing to the ingress controller:\n\n\nwget https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/docs/examples/docker-registry/ingress-without-tls.yaml\n\n\n\n\n\n\n\nImportant\n\n\n\n\nRunning a docker registry without TLS requires we configure our local docker daemon with the insecure registry flag.\n\n\nPlease check \ndeploy a plain http registry\n\n\nWith TLS\n\u00b6\n\n\nDownload and edit the yaml deployment replacing \nregistry.\n with a valid DNS name pointing to the ingress controller:\n\n\nwget https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/docs/examples/docker-registry/ingress-with-tls.yaml\n\n\n\n\n\nDeploy \nkube lego\n use \nLet's Encrypt\n certificates or edit the ingress rule to use a secret with an existing SSL certificate.\n\n\nTesting\n\u00b6\n\n\nTo test the registry is working correctly we download a known image from \ndocker hub\n, create a tag pointing to the new registry and upload the image:\n\n\ndocker pull ubuntu:16.04\n\n\ndocker tag ubuntu:16.04 `registry./ubuntu:16.04`\n\n\ndocker push `registry./ubuntu:16.04`\n\n\n\n\n\nPlease replace \nregistry.\n with your domain.", "title": "Docker registry" }, { @@ -1522,7 +1542,7 @@ }, { "location": "/examples/grpc/README/", - "text": "gRPC\n\u00b6\n\n\nThis example demonstrates how to route traffic to a gRPC service through the\nnginx controller.\n\n\nPrerequisites\n\u00b6\n\n\n\n\nYou have a kubernetes cluster running.\n\n\nYou have a domain name such as \nexample.com\n that is configured to route\n traffic to the ingress controller. Replace references to\n \nfortune-teller.stack.build\n (the domain name used in this example) to your\n own domain name (you're also responsible for provisioning an SSL certificate\n for the ingress).\n\n\nYou have the nginx-ingress controller installed in typical fashion (must be\n at least\n \nquay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.13.0\n\n for grpc support.\n\n\nYou have a backend application running a gRPC server and listening for TCP\n traffic. If you prefer, you can use the\n \nfortune-teller\n\n application provided here as an example. \n\n\n\n\nStep 1: kubernetes \nDeployment\n\u00b6\n\n\n$ kubectl create -f app.yaml\n\n\n\n\n\nThis is a standard kubernetes deployment object. It is running a grpc service\nlistening on port \n50051\n.\n\n\nThe sample application\n\nfortune-teller-app\n\nis a grpc server implemented in go. Here's the stripped-down implementation:\n\n\nfunc\n \nmain\n()\n \n{\n\n \ngrpcServer\n \n:=\n \ngrpc\n.\nNewServer\n()\n\n \nfortune\n.\nRegisterFortuneTellerServer\n(\ngrpcServer\n,\n \n&\nFortuneTeller\n{})\n\n \nlis\n,\n \n_\n \n:=\n \nnet\n.\nListen\n(\n\"tcp\"\n,\n \n\":50051\"\n)\n\n \ngrpcServer\n.\nServe\n(\nlis\n)\n\n\n}\n\n\n\n\n\n\nThe takeaway is that we are not doing any TLS configuration on the server (as we\nare terminating TLS at the ingress level, grpc traffic will travel unencrypted\ninside the cluster and arrive \"insecure\").\n\n\nFor your own application you may or may not want to do this. If you prefer to\nforward encrypted traffic to your POD and terminate TLS at the gRPC server\nitself, add the ingress annotation \nnginx.ingress.kubernetes.io/secure-backends:\"true\"\n.\n\n\nStep 2: the kubernetes \nService\n\u00b6\n\n\n$ kubectl create -f svc.yaml\n\n\n\n\n\nHere we have a typical service. Nothing special, just routing traffic to the\nbackend application on port \n50051\n.\n\n\nStep 3: the kubernetes \nIngress\n\u00b6\n\n\n$ kubectl create -f ingress.yaml\n\n\n\n\n\nA few things to note:\n\n\n\n\nWe've tagged the ingress with the annotation\n \nnginx.ingress.kubernetes.io/grpc-backend: \"true\"\n. This is the magic\n ingredient that sets up the appropriate nginx configuration to route http/2\n traffic to our service.\n\n\nWe're terminating TLS at the ingress and have configured an SSL certificate\n \nfortune-teller.stack.build\n. The ingress matches traffic arriving as\n \nhttps://fortune-teller.stack.build:443\n and routes unencrypted messages to\n our kubernetes service.\n\n\n\n\nStep 4: test the connection\n\u00b6\n\n\nOnce we've applied our configuration to kubernetes, it's time to test that we\ncan actually talk to the backend. To do this, we'll use the\n\ngrpcurl\n utility:\n\n\n$ grpcurl fortune-teller.stack.build:443 build.stack.fortune.FortuneTeller/Predict\n\n{\n\n \n\"message\"\n: \n\"Let us endeavor so to live that when we come to die even the undertaker will be sorry.\\n\\t\\t-- Mark Twain, \\\"Pudd'nhead Wilson's Calendar\\\"\"\n\n\n}\n\n\n\n\n\n\nDebugging Hints\n\u00b6\n\n\n\n\nObviously, watch the logs on your app.\n\n\nWatch the logs for the nginx-ingress-controller (increasing verbosity as\n needed).\n\n\nDouble-check your address and ports.\n\n\nSet the \nGODEBUG=http2debug=2\n environment variable to get detailed http/2\n logging on the client and/or server.\n\n\nStudy RFC 7540 (http/2) \nhttps://tools.ietf.org/html/rfc7540\n.\n\n\n\n\n\n\nIf you are developing public gRPC endpoints, check out\nhttps://proto.stack.build, a protocol buffer / gRPC build service that can use\nto help make it easier for your users to consume your API.", + "text": "gRPC\n\u00b6\n\n\nThis example demonstrates how to route traffic to a gRPC service through the\nnginx controller.\n\n\nPrerequisites\n\u00b6\n\n\n\n\nYou have a kubernetes cluster running.\n\n\nYou have a domain name such as \nexample.com\n that is configured to route\n traffic to the ingress controller. Replace references to\n \nfortune-teller.stack.build\n (the domain name used in this example) to your\n own domain name (you're also responsible for provisioning an SSL certificate\n for the ingress).\n\n\nYou have the nginx-ingress controller installed in typical fashion (must be\n at least\n \nquay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.13.0\n\n for grpc support.\n\n\nYou have a backend application running a gRPC server and listening for TCP\n traffic. If you prefer, you can use the\n \nfortune-teller\n\n application provided here as an example. \n\n\n\n\nStep 1: kubernetes \nDeployment\n\u00b6\n\n\n$ kubectl create -f app.yaml\n\n\n\n\nThis is a standard kubernetes deployment object. It is running a grpc service\nlistening on port \n50051\n.\n\n\nThe sample application\n\nfortune-teller-app\n\nis a grpc server implemented in go. Here's the stripped-down implementation:\n\n\nfunc\n \nmain\n()\n \n{\n\n \ngrpcServer\n \n:=\n \ngrpc\n.\nNewServer\n()\n\n \nfortune\n.\nRegisterFortuneTellerServer\n(\ngrpcServer\n,\n \n&\nFortuneTeller\n{})\n\n \nlis\n,\n \n_\n \n:=\n \nnet\n.\nListen\n(\n\"tcp\"\n,\n \n\":50051\"\n)\n\n \ngrpcServer\n.\nServe\n(\nlis\n)\n\n\n}\n\n\n\n\n\nThe takeaway is that we are not doing any TLS configuration on the server (as we\nare terminating TLS at the ingress level, grpc traffic will travel unencrypted\ninside the cluster and arrive \"insecure\").\n\n\nFor your own application you may or may not want to do this. If you prefer to\nforward encrypted traffic to your POD and terminate TLS at the gRPC server\nitself, add the ingress annotation \nnginx.ingress.kubernetes.io/secure-backends:\"true\"\n.\n\n\nStep 2: the kubernetes \nService\n\u00b6\n\n\n$ kubectl create -f svc.yaml\n\n\n\n\nHere we have a typical service. Nothing special, just routing traffic to the\nbackend application on port \n50051\n.\n\n\nStep 3: the kubernetes \nIngress\n\u00b6\n\n\n$ kubectl create -f ingress.yaml\n\n\n\n\nA few things to note:\n\n\n\n\nWe've tagged the ingress with the annotation\n \nnginx.ingress.kubernetes.io/grpc-backend: \"true\"\n. This is the magic\n ingredient that sets up the appropriate nginx configuration to route http/2\n traffic to our service.\n\n\nWe're terminating TLS at the ingress and have configured an SSL certificate\n \nfortune-teller.stack.build\n. The ingress matches traffic arriving as\n \nhttps://fortune-teller.stack.build:443\n and routes unencrypted messages to\n our kubernetes service.\n\n\n\n\nStep 4: test the connection\n\u00b6\n\n\nOnce we've applied our configuration to kubernetes, it's time to test that we\ncan actually talk to the backend. To do this, we'll use the\n\ngrpcurl\n utility:\n\n\n$ grpcurl fortune-teller.stack.build:443 build.stack.fortune.FortuneTeller/Predict\n\n{\n\n \n\"message\"\n: \n\"Let us endeavor so to live that when we come to die even the undertaker will be sorry.\\n\\t\\t-- Mark Twain, \\\"Pudd'nhead Wilson's Calendar\\\"\"\n\n\n}\n\n\n\n\n\nDebugging Hints\n\u00b6\n\n\n\n\nObviously, watch the logs on your app.\n\n\nWatch the logs for the nginx-ingress-controller (increasing verbosity as\n needed).\n\n\nDouble-check your address and ports.\n\n\nSet the \nGODEBUG=http2debug=2\n environment variable to get detailed http/2\n logging on the client and/or server.\n\n\nStudy RFC 7540 (http/2) \nhttps://tools.ietf.org/html/rfc7540\n.\n\n\n\n\n\n\nIf you are developing public gRPC endpoints, check out\nhttps://proto.stack.build, a protocol buffer / gRPC build service that can use\nto help make it easier for your users to consume your API.", "title": "gRPC" }, { @@ -1562,17 +1582,17 @@ }, { "location": "/examples/multi-tls/README/", - "text": "Multi TLS certificate termination\n\u00b6\n\n\nThis example uses 2 different certificates to terminate SSL for 2 hostnames.\n\n\n\n\nDeploy the controller by creating the rc in the parent dir\n\n\nCreate tls secrets for foo.bar.com and bar.baz.com as indicated in the yaml\n\n\nCreate multi-tls.yaml\n\n\n\n\nThis should generate a segment like:\n\n\n$\n kubectl \nexec\n -it nginx-ingress-controller-6vwd1 -- cat /etc/nginx/nginx.conf \n|\n grep \n\"foo.bar.com\"\n -B \n7\n -A \n35\n\n\n server {\n\n\n listen 80;\n\n\n listen 443 ssl http2;\n\n\n ssl_certificate /etc/nginx-ssl/default-foobar.pem;\n\n\n ssl_certificate_key /etc/nginx-ssl/default-foobar.pem;\n\n\n\n\n server_name foo.bar.com;\n\n\n\n\n if ($scheme = http) {\n\n\n return 301 https://$host$request_uri;\n\n\n }\n\n\n\n\n\n location / {\n\n\n proxy_set_header Host $host;\n\n\n\n #\n Pass Real IP\n\n proxy_set_header X-Real-IP $remote_addr;\n\n\n\n #\n Allow websocket connections\n\n proxy_set_header Upgrade $http_upgrade;\n\n\n proxy_set_header Connection $connection_upgrade;\n\n\n\n proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n\n\n proxy_set_header X-Forwarded-Host $host;\n\n\n proxy_set_header X-Forwarded-Proto $pass_access_scheme;\n\n\n\n proxy_connect_timeout 5s;\n\n\n proxy_send_timeout 60s;\n\n\n proxy_read_timeout 60s;\n\n\n\n proxy_redirect off;\n\n\n proxy_buffering off;\n\n\n\n proxy_http_version 1.1;\n\n\n\n proxy_pass http://default-http-svc-80;\n\n\n }\n\n\n\n\n\n\nAnd you should be able to reach your nginx service or http-svc service using a hostname switch:\n\n\n$\n kubectl get ing\n\nNAME RULE BACKEND ADDRESS AGE\n\n\nfoo-tls - 104.154.30.67 13m\n\n\n foo.bar.com\n\n\n / http-svc:80\n\n\n bar.baz.com\n\n\n / nginx:80\n\n\n\n$\n curl https://104.154.30.67 -H \n'Host:foo.bar.com'\n -k\n\nCLIENT VALUES:\n\n\nclient_address=10.245.0.6\n\n\ncommand=GET\n\n\nreal path=/\n\n\nquery=nil\n\n\nrequest_version=1.1\n\n\nrequest_uri=http://foo.bar.com:8080/\n\n\n\nSERVER VALUES:\n\n\nserver_version=nginx: 1.9.11 - lua: 10001\n\n\n\nHEADERS RECEIVED:\n\n\naccept=*/*\n\n\nconnection=close\n\n\nhost=foo.bar.com\n\n\nuser-agent=curl/7.35.0\n\n\nx-forwarded-for=10.245.0.1\n\n\nx-forwarded-host=foo.bar.com\n\n\nx-forwarded-proto=https\n\n\n\n$\n curl https://104.154.30.67 -H \n'Host:bar.baz.com'\n -k\n\n\n\n\n\n\n\n\n\n\nWelcome to nginx on Debian!\n\n\n\n$\n curl \n104\n.154.30.67\n\ndefault backend - 404", + "text": "Multi TLS certificate termination\n\u00b6\n\n\nThis example uses 2 different certificates to terminate SSL for 2 hostnames.\n\n\n\n\nDeploy the controller by creating the rc in the parent dir\n\n\nCreate tls secrets for foo.bar.com and bar.baz.com as indicated in the yaml\n\n\nCreate multi-tls.yaml\n\n\n\n\nThis should generate a segment like:\n\n$\n kubectl \nexec\n -it nginx-ingress-controller-6vwd1 -- cat /etc/nginx/nginx.conf \n|\n grep \n\"foo.bar.com\"\n -B \n7\n -A \n35\n\n\n server {\n\n\n listen 80;\n\n\n listen 443 ssl http2;\n\n\n ssl_certificate /etc/nginx-ssl/default-foobar.pem;\n\n\n ssl_certificate_key /etc/nginx-ssl/default-foobar.pem;\n\n\n\n\n server_name foo.bar.com;\n\n\n\n\n if ($scheme = http) {\n\n\n return 301 https://$host$request_uri;\n\n\n }\n\n\n\n\n\n location / {\n\n\n proxy_set_header Host $host;\n\n\n\n #\n Pass Real IP\n\n proxy_set_header X-Real-IP $remote_addr;\n\n\n\n #\n Allow websocket connections\n\n proxy_set_header Upgrade $http_upgrade;\n\n\n proxy_set_header Connection $connection_upgrade;\n\n\n\n proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n\n\n proxy_set_header X-Forwarded-Host $host;\n\n\n proxy_set_header X-Forwarded-Proto $pass_access_scheme;\n\n\n\n proxy_connect_timeout 5s;\n\n\n proxy_send_timeout 60s;\n\n\n proxy_read_timeout 60s;\n\n\n\n proxy_redirect off;\n\n\n proxy_buffering off;\n\n\n\n proxy_http_version 1.1;\n\n\n\n proxy_pass http://default-http-svc-80;\n\n\n }\n\n\n\n\nAnd you should be able to reach your nginx service or http-svc service using a hostname switch:\n\n$\n kubectl get ing\n\nNAME RULE BACKEND ADDRESS AGE\n\n\nfoo-tls - 104.154.30.67 13m\n\n\n foo.bar.com\n\n\n / http-svc:80\n\n\n bar.baz.com\n\n\n / nginx:80\n\n\n\n$\n curl https://104.154.30.67 -H \n'Host:foo.bar.com'\n -k\n\nCLIENT VALUES:\n\n\nclient_address=10.245.0.6\n\n\ncommand=GET\n\n\nreal path=/\n\n\nquery=nil\n\n\nrequest_version=1.1\n\n\nrequest_uri=http://foo.bar.com:8080/\n\n\n\nSERVER VALUES:\n\n\nserver_version=nginx: 1.9.11 - lua: 10001\n\n\n\nHEADERS RECEIVED:\n\n\naccept=*/*\n\n\nconnection=close\n\n\nhost=foo.bar.com\n\n\nuser-agent=curl/7.35.0\n\n\nx-forwarded-for=10.245.0.1\n\n\nx-forwarded-host=foo.bar.com\n\n\nx-forwarded-proto=https\n\n\n\n$\n curl https://104.154.30.67 -H \n'Host:bar.baz.com'\n -k\n\n\n\n\n\n\n\n\n\n\nWelcome to nginx on Debian!\n\n\n\n$\n curl \n104\n.154.30.67\n\ndefault backend - 404", "title": "Multi TLS certificate termination" }, { "location": "/examples/multi-tls/README/#multi-tls-certificate-termination", - "text": "This example uses 2 different certificates to terminate SSL for 2 hostnames. Deploy the controller by creating the rc in the parent dir Create tls secrets for foo.bar.com and bar.baz.com as indicated in the yaml Create multi-tls.yaml This should generate a segment like: $ kubectl exec -it nginx-ingress-controller-6vwd1 -- cat /etc/nginx/nginx.conf | grep \"foo.bar.com\" -B 7 -A 35 server { listen 80; listen 443 ssl http2; ssl_certificate /etc/nginx-ssl/default-foobar.pem; ssl_certificate_key /etc/nginx-ssl/default-foobar.pem; server_name foo.bar.com; if ($scheme = http) { return 301 https://$host$request_uri; } location / { proxy_set_header Host $host; # Pass Real IP proxy_set_header X-Real-IP $remote_addr; # Allow websocket connections proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Proto $pass_access_scheme; proxy_connect_timeout 5s; proxy_send_timeout 60s; proxy_read_timeout 60s; proxy_redirect off; proxy_buffering off; proxy_http_version 1.1; proxy_pass http://default-http-svc-80; } And you should be able to reach your nginx service or http-svc service using a hostname switch: $ kubectl get ing NAME RULE BACKEND ADDRESS AGE foo-tls - 104.154.30.67 13m foo.bar.com / http-svc:80 bar.baz.com / nginx:80 $ curl https://104.154.30.67 -H 'Host:foo.bar.com' -k CLIENT VALUES: client_address=10.245.0.6 command=GET real path=/ query=nil request_version=1.1 request_uri=http://foo.bar.com:8080/ SERVER VALUES: server_version=nginx: 1.9.11 - lua: 10001 HEADERS RECEIVED: accept=*/* connection=close host=foo.bar.com user-agent=curl/7.35.0 x-forwarded-for=10.245.0.1 x-forwarded-host=foo.bar.com x-forwarded-proto=https $ curl https://104.154.30.67 -H 'Host:bar.baz.com' -k Welcome to nginx on Debian! $ curl 104 .154.30.67 default backend - 404", + "text": "This example uses 2 different certificates to terminate SSL for 2 hostnames. Deploy the controller by creating the rc in the parent dir Create tls secrets for foo.bar.com and bar.baz.com as indicated in the yaml Create multi-tls.yaml This should generate a segment like: $ kubectl exec -it nginx-ingress-controller-6vwd1 -- cat /etc/nginx/nginx.conf | grep \"foo.bar.com\" -B 7 -A 35 server { listen 80; listen 443 ssl http2; ssl_certificate /etc/nginx-ssl/default-foobar.pem; ssl_certificate_key /etc/nginx-ssl/default-foobar.pem; server_name foo.bar.com; if ($scheme = http) { return 301 https://$host$request_uri; } location / { proxy_set_header Host $host; # Pass Real IP proxy_set_header X-Real-IP $remote_addr; # Allow websocket connections proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Proto $pass_access_scheme; proxy_connect_timeout 5s; proxy_send_timeout 60s; proxy_read_timeout 60s; proxy_redirect off; proxy_buffering off; proxy_http_version 1.1; proxy_pass http://default-http-svc-80; } And you should be able to reach your nginx service or http-svc service using a hostname switch: $ kubectl get ing NAME RULE BACKEND ADDRESS AGE foo-tls - 104.154.30.67 13m foo.bar.com / http-svc:80 bar.baz.com / nginx:80 $ curl https://104.154.30.67 -H 'Host:foo.bar.com' -k CLIENT VALUES: client_address=10.245.0.6 command=GET real path=/ query=nil request_version=1.1 request_uri=http://foo.bar.com:8080/ SERVER VALUES: server_version=nginx: 1.9.11 - lua: 10001 HEADERS RECEIVED: accept=*/* connection=close host=foo.bar.com user-agent=curl/7.35.0 x-forwarded-for=10.245.0.1 x-forwarded-host=foo.bar.com x-forwarded-proto=https $ curl https://104.154.30.67 -H 'Host:bar.baz.com' -k Welcome to nginx on Debian! $ curl 104 .154.30.67 default backend - 404", "title": "Multi TLS certificate termination" }, { "location": "/examples/rewrite/README/", - "text": "Rewrite\n\u00b6\n\n\nThis example demonstrates how to use the Rewrite annotations\n\n\nPrerequisites\n\u00b6\n\n\nYou will need to make sure your Ingress targets exactly one Ingress\ncontroller by specifying the \ningress.class annotation\n,\nand that you have an ingress controller \nrunning\n in your cluster.\n\n\nDeployment\n\u00b6\n\n\nRewriting can be controlled using the following annotations:\n\n\n\n\n\n\n\n\nName\n\n\nDescription\n\n\nValues\n\n\n\n\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/rewrite-target\n\n\nTarget URI where the traffic must be redirected\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/add-base-url\n\n\nindicates if is required to add a base tag in the head of the responses from the upstream servers\n\n\nbool\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/base-url-scheme\n\n\nOverride for the scheme passed to the base tag\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/ssl-redirect\n\n\nIndicates if the location section is accessible SSL only (defaults to True when Ingress contains a Certificate)\n\n\nbool\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/force-ssl-redirect\n\n\nForces the redirection to HTTPS even if the Ingress is not TLS Enabled\n\n\nbool\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/app-root\n\n\nDefines the Application Root that the Controller must redirect if it's in '/' context\n\n\nstring\n\n\n\n\n\n\n\n\nValidation\n\u00b6\n\n\nRewrite Target\n\u00b6\n\n\nCreate an Ingress rule with a rewrite annotation:\n\n\n$\n \necho\n \n\"\n\n\napiVersion: extensions/v1beta1\n\n\nkind: Ingress\n\n\nmetadata:\n\n\n annotations:\n\n\n nginx.ingress.kubernetes.io/rewrite-target: /\n\n\n name: rewrite\n\n\n namespace: default\n\n\nspec:\n\n\n rules:\n\n\n - host: rewrite.bar.com\n\n\n http:\n\n\n paths:\n\n\n - backend:\n\n\n serviceName: http-svc\n\n\n servicePort: 80\n\n\n path: /something\n\n\n\" | kubectl create -f -\n\n\n\n\n\n\nCheck the rewrite is working\n\n\n$ curl -v http://172.17.4.99/something -H \n'Host: rewrite.bar.com'\n\n* Trying \n172\n.17.4.99...\n* Connected to \n172\n.17.4.99 \n(\n172\n.17.4.99\n)\n port \n80\n \n(\n#0)\n\n> GET /something HTTP/1.1\n> Host: rewrite.bar.com\n> User-Agent: curl/7.43.0\n> Accept: */*\n>\n< HTTP/1.1 \n200\n OK\n< Server: nginx/1.11.0\n< Date: Tue, \n31\n May \n2016\n \n16\n:07:31 GMT\n< Content-Type: text/plain\n< Transfer-Encoding: chunked\n< Connection: keep-alive\n<\nCLIENT VALUES:\n\nclient_address\n=\n10\n.2.56.9\n\ncommand\n=\nGET\nreal \npath\n=\n/\n\nquery\n=\nnil\n\nrequest_version\n=\n1\n.1\n\nrequest_uri\n=\nhttp://rewrite.bar.com:8080/\n\nSERVER VALUES:\n\nserver_version\n=\nnginx: \n1\n.9.11 - lua: \n10001\n\n\nHEADERS RECEIVED:\n\naccept\n=\n*/*\n\nconnection\n=\nclose\n\nhost\n=\nrewrite.bar.com\nuser-agent\n=\ncurl/7.43.0\nx-forwarded-for\n=\n10\n.2.56.1\nx-forwarded-host\n=\nrewrite.bar.com\nx-forwarded-port\n=\n80\n\nx-forwarded-proto\n=\nhttp\nx-real-ip\n=\n10\n.2.56.1\nBODY:\n* Connection \n#0 to host 172.17.4.99 left intact\n\n-no body in request-\n\n\n\n\n\nApp Root\n\u00b6\n\n\nCreate an Ingress rule with a app-root annotation:\n\n\n$ \necho\n \n\"\n\n\napiVersion: extensions/v1beta1\n\n\nkind: Ingress\n\n\nmetadata:\n\n\n annotations:\n\n\n nginx.ingress.kubernetes.io/app-root: /app1\n\n\n name: approot\n\n\n namespace: default\n\n\nspec:\n\n\n rules:\n\n\n - host: approot.bar.com\n\n\n http:\n\n\n paths:\n\n\n - backend:\n\n\n serviceName: http-svc\n\n\n servicePort: 80\n\n\n path: /\n\n\n\"\n \n|\n kubectl create -f -\n\n\n\n\n\nCheck the rewrite is working\n\n\n$ curl -I -k http://approot.bar.com/\nHTTP/1.1 \n302\n Moved Temporarily\nServer: nginx/1.11.10\nDate: Mon, \n13\n Mar \n2017\n \n14\n:57:15 GMT\nContent-Type: text/html\nContent-Length: \n162\n\nLocation: http://stickyingress.example.com/app1\nConnection: keep-alive", + "text": "Rewrite\n\u00b6\n\n\nThis example demonstrates how to use the Rewrite annotations\n\n\nPrerequisites\n\u00b6\n\n\nYou will need to make sure your Ingress targets exactly one Ingress\ncontroller by specifying the \ningress.class annotation\n,\nand that you have an ingress controller \nrunning\n in your cluster.\n\n\nDeployment\n\u00b6\n\n\nRewriting can be controlled using the following annotations:\n\n\n\n\n\n\n\n\nName\n\n\nDescription\n\n\nValues\n\n\n\n\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/rewrite-target\n\n\nTarget URI where the traffic must be redirected\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/add-base-url\n\n\nindicates if is required to add a base tag in the head of the responses from the upstream servers\n\n\nbool\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/base-url-scheme\n\n\nOverride for the scheme passed to the base tag\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/ssl-redirect\n\n\nIndicates if the location section is accessible SSL only (defaults to True when Ingress contains a Certificate)\n\n\nbool\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/force-ssl-redirect\n\n\nForces the redirection to HTTPS even if the Ingress is not TLS Enabled\n\n\nbool\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/app-root\n\n\nDefines the Application Root that the Controller must redirect if it's in '/' context\n\n\nstring\n\n\n\n\n\n\n\n\nValidation\n\u00b6\n\n\nRewrite Target\n\u00b6\n\n\nCreate an Ingress rule with a rewrite annotation:\n\n\n$\n \necho\n \n\"\n\n\napiVersion: extensions/v1beta1\n\n\nkind: Ingress\n\n\nmetadata:\n\n\n annotations:\n\n\n nginx.ingress.kubernetes.io/rewrite-target: /\n\n\n name: rewrite\n\n\n namespace: default\n\n\nspec:\n\n\n rules:\n\n\n - host: rewrite.bar.com\n\n\n http:\n\n\n paths:\n\n\n - backend:\n\n\n serviceName: http-svc\n\n\n servicePort: 80\n\n\n path: /something\n\n\n\" | kubectl create -f -\n\n\n\n\n\nCheck the rewrite is working\n\n\n$ curl -v http://172.17.4.99/something -H \n'Host: rewrite.bar.com'\n\n* Trying \n172\n.17.4.99...\n* Connected to \n172\n.17.4.99 \n(\n172\n.17.4.99\n)\n port \n80\n \n(\n#0)\n\n> GET /something HTTP/1.1\n> Host: rewrite.bar.com\n> User-Agent: curl/7.43.0\n> Accept: */*\n>\n< HTTP/1.1 \n200\n OK\n< Server: nginx/1.11.0\n< Date: Tue, \n31\n May \n2016\n \n16\n:07:31 GMT\n< Content-Type: text/plain\n< Transfer-Encoding: chunked\n< Connection: keep-alive\n<\nCLIENT VALUES:\n\nclient_address\n=\n10\n.2.56.9\n\ncommand\n=\nGET\nreal \npath\n=\n/\n\nquery\n=\nnil\n\nrequest_version\n=\n1\n.1\n\nrequest_uri\n=\nhttp://rewrite.bar.com:8080/\n\nSERVER VALUES:\n\nserver_version\n=\nnginx: \n1\n.9.11 - lua: \n10001\n\n\nHEADERS RECEIVED:\n\naccept\n=\n*/*\n\nconnection\n=\nclose\n\nhost\n=\nrewrite.bar.com\nuser-agent\n=\ncurl/7.43.0\nx-forwarded-for\n=\n10\n.2.56.1\nx-forwarded-host\n=\nrewrite.bar.com\nx-forwarded-port\n=\n80\n\nx-forwarded-proto\n=\nhttp\nx-real-ip\n=\n10\n.2.56.1\nBODY:\n* Connection \n#0 to host 172.17.4.99 left intact\n\n-no body in request-\n\n\n\n\nApp Root\n\u00b6\n\n\nCreate an Ingress rule with a app-root annotation:\n\n$ \necho\n \n\"\n\n\napiVersion: extensions/v1beta1\n\n\nkind: Ingress\n\n\nmetadata:\n\n\n annotations:\n\n\n nginx.ingress.kubernetes.io/app-root: /app1\n\n\n name: approot\n\n\n namespace: default\n\n\nspec:\n\n\n rules:\n\n\n - host: approot.bar.com\n\n\n http:\n\n\n paths:\n\n\n - backend:\n\n\n serviceName: http-svc\n\n\n servicePort: 80\n\n\n path: /\n\n\n\"\n \n|\n kubectl create -f -\n\n\n\nCheck the rewrite is working\n\n\n$ curl -I -k http://approot.bar.com/\nHTTP/1.1 \n302\n Moved Temporarily\nServer: nginx/1.11.10\nDate: Mon, \n13\n Mar \n2017\n \n14\n:57:15 GMT\nContent-Type: text/html\nContent-Length: \n162\n\nLocation: http://stickyingress.example.com/app1\nConnection: keep-alive", "title": "Rewrite" }, { @@ -1602,12 +1622,12 @@ }, { "location": "/examples/rewrite/README/#app-root", - "text": "Create an Ingress rule with a app-root annotation: $ echo \" apiVersion: extensions/v1beta1 kind: Ingress metadata: annotations: nginx.ingress.kubernetes.io/app-root: /app1 name: approot namespace: default spec: rules: - host: approot.bar.com http: paths: - backend: serviceName: http-svc servicePort: 80 path: / \" | kubectl create -f - Check the rewrite is working $ curl -I -k http://approot.bar.com/\nHTTP/1.1 302 Moved Temporarily\nServer: nginx/1.11.10\nDate: Mon, 13 Mar 2017 14 :57:15 GMT\nContent-Type: text/html\nContent-Length: 162 \nLocation: http://stickyingress.example.com/app1\nConnection: keep-alive", + "text": "Create an Ingress rule with a app-root annotation: $ echo \" apiVersion: extensions/v1beta1 kind: Ingress metadata: annotations: nginx.ingress.kubernetes.io/app-root: /app1 name: approot namespace: default spec: rules: - host: approot.bar.com http: paths: - backend: serviceName: http-svc servicePort: 80 path: / \" | kubectl create -f - Check the rewrite is working $ curl -I -k http://approot.bar.com/\nHTTP/1.1 302 Moved Temporarily\nServer: nginx/1.11.10\nDate: Mon, 13 Mar 2017 14 :57:15 GMT\nContent-Type: text/html\nContent-Length: 162 \nLocation: http://stickyingress.example.com/app1\nConnection: keep-alive", "title": "App Root" }, { "location": "/examples/static-ip/README/", - "text": "Static IPs\n\u00b6\n\n\nThis example demonstrates how to assign a static-ip to an Ingress on through the Nginx controller.\n\n\nPrerequisites\n\u00b6\n\n\nYou need a \nTLS cert\n and a \ntest HTTP service\n for this example.\nYou will also need to make sure your Ingress targets exactly one Ingress\ncontroller by specifying the \ningress.class annotation\n,\nand that you have an ingress controller \nrunning\n in your cluster.\n\n\nAcquiring an IP\n\u00b6\n\n\nSince instances of the nginx controller actually run on nodes in your cluster,\nby default nginx Ingresses will only get static IPs if your cloudprovider\nsupports static IP assignments to nodes. On GKE/GCE for example, even though\nnodes get static IPs, the IPs are not retained across upgrade.\n\n\nTo acquire a static IP for the nginx ingress controller, simply put it\nbehind a Service of \nType=LoadBalancer\n.\n\n\nFirst, create a loadbalancer Service and wait for it to acquire an IP\n\n\n$\n kubectl create -f static-ip-svc.yaml\n\nservice \"nginx-ingress-lb\" created\n\n\n\n$\n kubectl get svc nginx-ingress-lb\n\nNAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE\n\n\nnginx-ingress-lb 10.0.138.113 104.154.109.191 80:31457/TCP,443:32240/TCP 15m\n\n\n\n\n\n\nthen, update the ingress controller so it adopts the static IP of the Service\nby passing the \n--publish-service\n flag (the example yaml used in the next step\nalready has it set to \"nginx-ingress-lb\").\n\n\n$\n kubectl create -f nginx-ingress-controller.yaml\n\ndeployment \"nginx-ingress-controller\" created\n\n\n\n\n\n\nAssigning the IP to an Ingress\n\u00b6\n\n\nFrom here on every Ingress created with the \ningress.class\n annotation set to\n\nnginx\n will get the IP allocated in the previous step\n\n\n$\n kubectl create -f nginx-ingress.yaml\n\ningress \"nginx-ingress\" created\n\n\n\n$\n kubectl get ing nginx-ingress\n\nNAME HOSTS ADDRESS PORTS AGE\n\n\nnginx-ingress * 104.154.109.191 80, 443 13m\n\n\n\n$\n curl \n104\n.154.109.191 -kL\n\nCLIENT VALUES:\n\n\nclient_address=10.180.1.25\n\n\ncommand=GET\n\n\nreal path=/\n\n\nquery=nil\n\n\nrequest_version=1.1\n\n\nrequest_uri=http://104.154.109.191:8080/\n\n\n...\n\n\n\n\n\n\nRetaining the IP\n\u00b6\n\n\nYou can test retention by deleting the Ingress\n\n\n$\n kubectl delete ing nginx-ingress\n\ningress \"nginx-ingress\" deleted\n\n\n\n$\n kubectl create -f nginx-ingress.yaml\n\ningress \"nginx-ingress\" created\n\n\n\n$\n kubectl get ing nginx-ingress\n\nNAME HOSTS ADDRESS PORTS AGE\n\n\nnginx-ingress * 104.154.109.191 80, 443 13m\n\n\n\n\n\n\n\n\nNote that unlike the GCE Ingress, the same loadbalancer IP is shared amongst all\nIngresses, because all requests are proxied through the same set of nginx\ncontrollers.\n\n\n\n\nPromote ephemeral to static IP\n\u00b6\n\n\nTo promote the allocated IP to static, you can update the Service manifest\n\n\n$\n kubectl patch svc nginx-ingress-lb -p \n'{\"spec\": {\"loadBalancerIP\": \"104.154.109.191\"}}'\n\n\n\"nginx-ingress-lb\" patched\n\n\n\n\n\n\nand promote the IP to static (promotion works differently for cloudproviders,\nprovided example is for GKE/GCE)\n`\n\n\n$\n gcloud compute addresses create nginx-ingress-lb --addresses \n104\n.154.109.191 --region us-central1\n\nCreated [https://www.googleapis.com/compute/v1/projects/kubernetesdev/regions/us-central1/addresses/nginx-ingress-lb].\n\n\n---\n\n\naddress: 104.154.109.191\n\n\ncreationTimestamp: '2017-01-31T16:34:50.089-08:00'\n\n\ndescription: ''\n\n\nid: '5208037144487826373'\n\n\nkind: compute#address\n\n\nname: nginx-ingress-lb\n\n\nregion: us-central1\n\n\nselfLink: https://www.googleapis.com/compute/v1/projects/kubernetesdev/regions/us-central1/addresses/nginx-ingress-lb\n\n\nstatus: IN_USE\n\n\nusers:\n\n\n- us-central1/forwardingRules/a09f6913ae80e11e6a8c542010af0000\n\n\n\n\n\n\nNow even if the Service is deleted, the IP will persist, so you can recreate the\nService with \nspec.loadBalancerIP\n set to \n104.154.109.191\n.", + "text": "Static IPs\n\u00b6\n\n\nThis example demonstrates how to assign a static-ip to an Ingress on through the Nginx controller.\n\n\nPrerequisites\n\u00b6\n\n\nYou need a \nTLS cert\n and a \ntest HTTP service\n for this example.\nYou will also need to make sure your Ingress targets exactly one Ingress\ncontroller by specifying the \ningress.class annotation\n,\nand that you have an ingress controller \nrunning\n in your cluster.\n\n\nAcquiring an IP\n\u00b6\n\n\nSince instances of the nginx controller actually run on nodes in your cluster,\nby default nginx Ingresses will only get static IPs if your cloudprovider\nsupports static IP assignments to nodes. On GKE/GCE for example, even though\nnodes get static IPs, the IPs are not retained across upgrade.\n\n\nTo acquire a static IP for the nginx ingress controller, simply put it\nbehind a Service of \nType=LoadBalancer\n.\n\n\nFirst, create a loadbalancer Service and wait for it to acquire an IP\n\n\n$\n kubectl create -f static-ip-svc.yaml\n\nservice \"nginx-ingress-lb\" created\n\n\n\n$\n kubectl get svc nginx-ingress-lb\n\nNAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE\n\n\nnginx-ingress-lb 10.0.138.113 104.154.109.191 80:31457/TCP,443:32240/TCP 15m\n\n\n\n\n\nthen, update the ingress controller so it adopts the static IP of the Service\nby passing the \n--publish-service\n flag (the example yaml used in the next step\nalready has it set to \"nginx-ingress-lb\").\n\n\n$\n kubectl create -f nginx-ingress-controller.yaml\n\ndeployment \"nginx-ingress-controller\" created\n\n\n\n\n\nAssigning the IP to an Ingress\n\u00b6\n\n\nFrom here on every Ingress created with the \ningress.class\n annotation set to\n\nnginx\n will get the IP allocated in the previous step\n\n\n$\n kubectl create -f nginx-ingress.yaml\n\ningress \"nginx-ingress\" created\n\n\n\n$\n kubectl get ing nginx-ingress\n\nNAME HOSTS ADDRESS PORTS AGE\n\n\nnginx-ingress * 104.154.109.191 80, 443 13m\n\n\n\n$\n curl \n104\n.154.109.191 -kL\n\nCLIENT VALUES:\n\n\nclient_address=10.180.1.25\n\n\ncommand=GET\n\n\nreal path=/\n\n\nquery=nil\n\n\nrequest_version=1.1\n\n\nrequest_uri=http://104.154.109.191:8080/\n\n\n...\n\n\n\n\n\nRetaining the IP\n\u00b6\n\n\nYou can test retention by deleting the Ingress\n\n\n$\n kubectl delete ing nginx-ingress\n\ningress \"nginx-ingress\" deleted\n\n\n\n$\n kubectl create -f nginx-ingress.yaml\n\ningress \"nginx-ingress\" created\n\n\n\n$\n kubectl get ing nginx-ingress\n\nNAME HOSTS ADDRESS PORTS AGE\n\n\nnginx-ingress * 104.154.109.191 80, 443 13m\n\n\n\n\n\n\n\nNote that unlike the GCE Ingress, the same loadbalancer IP is shared amongst all\nIngresses, because all requests are proxied through the same set of nginx\ncontrollers.\n\n\n\n\nPromote ephemeral to static IP\n\u00b6\n\n\nTo promote the allocated IP to static, you can update the Service manifest\n\n\n$\n kubectl patch svc nginx-ingress-lb -p \n'{\"spec\": {\"loadBalancerIP\": \"104.154.109.191\"}}'\n\n\n\"nginx-ingress-lb\" patched\n\n\n\n\n\nand promote the IP to static (promotion works differently for cloudproviders,\nprovided example is for GKE/GCE)\n`\n\n$\n gcloud compute addresses create nginx-ingress-lb --addresses \n104\n.154.109.191 --region us-central1\n\nCreated [https://www.googleapis.com/compute/v1/projects/kubernetesdev/regions/us-central1/addresses/nginx-ingress-lb].\n\n\n---\n\n\naddress: 104.154.109.191\n\n\ncreationTimestamp: '2017-01-31T16:34:50.089-08:00'\n\n\ndescription: ''\n\n\nid: '5208037144487826373'\n\n\nkind: compute#address\n\n\nname: nginx-ingress-lb\n\n\nregion: us-central1\n\n\nselfLink: https://www.googleapis.com/compute/v1/projects/kubernetesdev/regions/us-central1/addresses/nginx-ingress-lb\n\n\nstatus: IN_USE\n\n\nusers:\n\n\n- us-central1/forwardingRules/a09f6913ae80e11e6a8c542010af0000\n\n\n\n\nNow even if the Service is deleted, the IP will persist, so you can recreate the\nService with \nspec.loadBalancerIP\n set to \n104.154.109.191\n.", "title": "Static IPs" }, { @@ -1637,12 +1657,12 @@ }, { "location": "/examples/static-ip/README/#promote-ephemeral-to-static-ip", - "text": "To promote the allocated IP to static, you can update the Service manifest $ kubectl patch svc nginx-ingress-lb -p '{\"spec\": {\"loadBalancerIP\": \"104.154.109.191\"}}' \"nginx-ingress-lb\" patched and promote the IP to static (promotion works differently for cloudproviders,\nprovided example is for GKE/GCE)\n` $ gcloud compute addresses create nginx-ingress-lb --addresses 104 .154.109.191 --region us-central1 Created [https://www.googleapis.com/compute/v1/projects/kubernetesdev/regions/us-central1/addresses/nginx-ingress-lb]. --- address: 104.154.109.191 creationTimestamp: '2017-01-31T16:34:50.089-08:00' description: '' id: '5208037144487826373' kind: compute#address name: nginx-ingress-lb region: us-central1 selfLink: https://www.googleapis.com/compute/v1/projects/kubernetesdev/regions/us-central1/addresses/nginx-ingress-lb status: IN_USE users: - us-central1/forwardingRules/a09f6913ae80e11e6a8c542010af0000 Now even if the Service is deleted, the IP will persist, so you can recreate the\nService with spec.loadBalancerIP set to 104.154.109.191 .", + "text": "To promote the allocated IP to static, you can update the Service manifest $ kubectl patch svc nginx-ingress-lb -p '{\"spec\": {\"loadBalancerIP\": \"104.154.109.191\"}}' \"nginx-ingress-lb\" patched and promote the IP to static (promotion works differently for cloudproviders,\nprovided example is for GKE/GCE)\n` $ gcloud compute addresses create nginx-ingress-lb --addresses 104 .154.109.191 --region us-central1 Created [https://www.googleapis.com/compute/v1/projects/kubernetesdev/regions/us-central1/addresses/nginx-ingress-lb]. --- address: 104.154.109.191 creationTimestamp: '2017-01-31T16:34:50.089-08:00' description: '' id: '5208037144487826373' kind: compute#address name: nginx-ingress-lb region: us-central1 selfLink: https://www.googleapis.com/compute/v1/projects/kubernetesdev/regions/us-central1/addresses/nginx-ingress-lb status: IN_USE users: - us-central1/forwardingRules/a09f6913ae80e11e6a8c542010af0000 Now even if the Service is deleted, the IP will persist, so you can recreate the\nService with spec.loadBalancerIP set to 104.154.109.191 .", "title": "Promote ephemeral to static IP" }, { "location": "/examples/tls-termination/README/", - "text": "TLS termination\n\u00b6\n\n\nThis example demonstrates how to terminate TLS through the nginx Ingress controller.\n\n\nPrerequisites\n\u00b6\n\n\nYou need a \nTLS cert\n and a \ntest HTTP service\n for this example.\n\n\nDeployment\n\u00b6\n\n\nThe following command instructs the controller to terminate traffic using the provided \nTLS cert, and forward un-encrypted HTTP traffic to the test HTTP service.\n\n\nkubectl apply -f ingress.yaml\n\n\n\n\n\n\nValidation\n\u00b6\n\n\nYou can confirm that the Ingress works.\n\n\n$\n kubectl describe ing nginx-test\n\nName: nginx-test\n\n\nNamespace: default\n\n\nAddress: 104.198.183.6\n\n\nDefault backend: default-http-backend:80 (10.180.0.4:8080,10.240.0.2:8080)\n\n\nTLS:\n\n\n tls-secret terminates\n\n\nRules:\n\n\n Host Path Backends\n\n\n ---- ---- --------\n\n\n *\n\n\n http-svc:80 ()\n\n\nAnnotations:\n\n\nEvents:\n\n\n FirstSeen LastSeen Count From SubObjectPath Type Reason Message\n\n\n --------- -------- ----- ---- ------------- -------- ------ -------\n\n\n 7s 7s 1 {nginx-ingress-controller } Normal CREATE default/nginx-test\n\n\n 7s 7s 1 {nginx-ingress-controller } Normal UPDATE default/nginx-test\n\n\n 7s 7s 1 {nginx-ingress-controller } Normal CREATE ip: 104.198.183.6\n\n\n 7s 7s 1 {nginx-ingress-controller } Warning MAPPING Ingress rule 'default/nginx-test' contains no path definition. Assuming /\n\n\n\n$\n curl \n104\n.198.183.6 -L\n\ncurl: (60) SSL certificate problem: self signed certificate\n\n\nMore details here: http://curl.haxx.se/docs/sslcerts.html\n\n\n\n$\n curl \n104\n.198.183.6 -Lk\n\nCLIENT VALUES:\n\n\nclient_address=10.240.0.4\n\n\ncommand=GET\n\n\nreal path=/\n\n\nquery=nil\n\n\nrequest_version=1.1\n\n\nrequest_uri=http://35.186.221.137:8080/\n\n\n\nSERVER VALUES:\n\n\nserver_version=nginx: 1.9.11 - lua: 10001\n\n\n\nHEADERS RECEIVED:\n\n\naccept=*/*\n\n\nconnection=Keep-Alive\n\n\nhost=35.186.221.137\n\n\nuser-agent=curl/7.46.0\n\n\nvia=1.1 google\n\n\nx-cloud-trace-context=f708ea7e369d4514fc90d51d7e27e91d/13322322294276298106\n\n\nx-forwarded-for=104.132.0.80, 35.186.221.137\n\n\nx-forwarded-proto=https\n\n\nBODY:", + "text": "TLS termination\n\u00b6\n\n\nThis example demonstrates how to terminate TLS through the nginx Ingress controller.\n\n\nPrerequisites\n\u00b6\n\n\nYou need a \nTLS cert\n and a \ntest HTTP service\n for this example.\n\n\nDeployment\n\u00b6\n\n\nThe following command instructs the controller to terminate traffic using the provided \nTLS cert, and forward un-encrypted HTTP traffic to the test HTTP service.\n\n\nkubectl apply -f ingress.yaml\n\n\n\n\n\nValidation\n\u00b6\n\n\nYou can confirm that the Ingress works.\n\n\n$\n kubectl describe ing nginx-test\n\nName: nginx-test\n\n\nNamespace: default\n\n\nAddress: 104.198.183.6\n\n\nDefault backend: default-http-backend:80 (10.180.0.4:8080,10.240.0.2:8080)\n\n\nTLS:\n\n\n tls-secret terminates\n\n\nRules:\n\n\n Host Path Backends\n\n\n ---- ---- --------\n\n\n *\n\n\n http-svc:80 ()\n\n\nAnnotations:\n\n\nEvents:\n\n\n FirstSeen LastSeen Count From SubObjectPath Type Reason Message\n\n\n --------- -------- ----- ---- ------------- -------- ------ -------\n\n\n 7s 7s 1 {nginx-ingress-controller } Normal CREATE default/nginx-test\n\n\n 7s 7s 1 {nginx-ingress-controller } Normal UPDATE default/nginx-test\n\n\n 7s 7s 1 {nginx-ingress-controller } Normal CREATE ip: 104.198.183.6\n\n\n 7s 7s 1 {nginx-ingress-controller } Warning MAPPING Ingress rule 'default/nginx-test' contains no path definition. Assuming /\n\n\n\n$\n curl \n104\n.198.183.6 -L\n\ncurl: (60) SSL certificate problem: self signed certificate\n\n\nMore details here: http://curl.haxx.se/docs/sslcerts.html\n\n\n\n$\n curl \n104\n.198.183.6 -Lk\n\nCLIENT VALUES:\n\n\nclient_address=10.240.0.4\n\n\ncommand=GET\n\n\nreal path=/\n\n\nquery=nil\n\n\nrequest_version=1.1\n\n\nrequest_uri=http://35.186.221.137:8080/\n\n\n\nSERVER VALUES:\n\n\nserver_version=nginx: 1.9.11 - lua: 10001\n\n\n\nHEADERS RECEIVED:\n\n\naccept=*/*\n\n\nconnection=Keep-Alive\n\n\nhost=35.186.221.137\n\n\nuser-agent=curl/7.46.0\n\n\nvia=1.1 google\n\n\nx-cloud-trace-context=f708ea7e369d4514fc90d51d7e27e91d/13322322294276298106\n\n\nx-forwarded-for=104.132.0.80, 35.186.221.137\n\n\nx-forwarded-proto=https\n\n\nBODY:", "title": "TLS termination" }, { @@ -1667,7 +1687,7 @@ }, { "location": "/development/", - "text": "Developing for NGINX Ingress Controller\n\u00b6\n\n\nThis document explains how to get started with developing for NGINX Ingress controller.\nIt includes how to build, test, and release ingress controllers.\n\n\nQuick Start\n\u00b6\n\n\nGetting the code\n\u00b6\n\n\nThe code must be checked out as a subdirectory of k8s.io, and not github.com.\n\n\nmkdir -p $GOPATH/src/k8s.io\ncd $GOPATH/src/k8s.io\n# Replace \"$YOUR_GITHUB_USERNAME\" below with your github username\ngit clone https://github.com/$YOUR_GITHUB_USERNAME/ingress-nginx.git\ncd ingress-nginx\n\n\n\n\n\nInitial developer environment build\n\u00b6\n\n\n\n\nPrequisites\n: Minikube must be installed.\nSee \nreleases\n for installation instructions. \n\n\n\n\nIf you are using \nMacOS\n and deploying to \nminikube\n, 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 \ningress-nginx\n:\n\n\n$ make dev-env\n\n\n\n\n\nUpdating the deployment\n\u00b6\n\n\nThe nginx controller container image can be rebuilt using:\n\n\n$ \nARCH\n=\namd64 \nTAG\n=\ndev \nREGISTRY\n=\n$USER\n/ingress-controller make build container\n\n\n\n\n\nThe image will only be used by pods created after the rebuild. To delete old pods which will cause new ones to spin up:\n\n\n$ kubectl get pods -n ingress-nginx\n$ kubectl delete pod -n ingress-nginx nginx-ingress-controller-\n\n\n\n\n\nDependencies\n\u00b6\n\n\nThe build uses dependencies in the \nvendor\n directory, which\nmust be installed before building a binary/image. Occasionally, you\nmight need to update the dependencies.\n\n\nThis guide requires you to install the \ndep\n dependency tool.\n\n\nCheck the version of \ndep\n you are using and make sure it is up to date.\n\n\n$\n dep version\n\ndep:\n\n\n version : devel\n\n\n build date : \n\n\n git hash : \n\n\n go version : go1.9\n\n\n go compiler : gc\n\n\n platform : linux/amd64\n\n\n\n\n\n\nIf you have an older version of \ndep\n, you can update it as follows:\n\n\n$\n go get -u github.com/golang/dep\n\n\n\n\n\nThis will automatically save the dependencies to the \nvendor/\n directory.\n\n\n$\n \ncd\n \n$GOPATH\n/src/k8s.io/ingress-nginx\n\n$\n dep ensure\n\n$\n dep ensure -update\n\n$\n dep prune\n\n\n\n\n\nBuilding\n\u00b6\n\n\nAll ingress controllers are built through a Makefile. Depending on your\nrequirements you can build a raw server binary, a local container image,\nor push an image to a remote repository.\n\n\nIn order to use your local Docker, you may need to set the following environment variables:\n\n\n#\n \n\"gcloud docker\"\n \n(\ndefault\n)\n or \n\"docker\"\n\n\n$\n \nexport\n \nDOCKER\n=\n\n\n\n#\n \n\"quay.io/kubernetes-ingress-controller\"\n \n(\ndefault\n)\n, \n\"index.docker.io\"\n, or your own registry\n\n$\n \nexport\n \nREGISTRY\n=\n\n\n\n\n\n\nTo find the registry simply run: \ndocker system info | grep Registry\n\n\nNginx Controller\n\u00b6\n\n\nBuild a raw server binary\n\n\n$\n make build\n\n\n\n\n\nTODO\n: add more specific instructions needed for raw server binary.\n\n\nBuild a local container image\n\n\n$\n \nTAG\n=\n \nREGISTRY\n=\n$USER\n/ingress-controller make docker-build\n\n\n\n\n\nPush the container image to a remote repository\n\n\n$\n \nTAG\n=\n \nREGISTRY\n=\n$USER\n/ingress-controller make docker-push\n\n\n\n\n\nDeploying\n\u00b6\n\n\nThere are several ways to deploy the ingress controller onto a cluster.\nPlease check the \ndeployment guide\n\n\nTesting\n\u00b6\n\n\nTo run unit-tests, just run\n\n\n$\n \ncd\n \n$GOPATH\n/src/k8s.io/ingress-nginx\n\n$\n make \ntest\n\n\n\n\n\n\nIf you have access to a Kubernetes cluster, you can also run e2e tests using ginkgo.\n\n\n$\n \ncd\n \n$GOPATH\n/src/k8s.io/ingress-nginx\n\n$\n make e2e-test\n\n\n\n\n\nTo run unit-tests for lua code locally, run:\n\n\n$\n \ncd\n \n$GOPATH\n/src/k8s.io/ingress-nginx\n\n$\n ./rootfs/etc/nginx/lua/test/up.sh\n\n$\n make lua-test\n\n\n\n\n\nLua tests are located in \n$GOPATH/src/k8s.io/ingress-nginx/rootfs/etc/nginx/lua/test\n. When creating a new test file it must follow the naming convention \n_test.lua\n or it will be ignored. \n\n\nReleasing\n\u00b6\n\n\nAll Makefiles will produce a release binary, as shown above. To publish this\nto a wider Kubernetes user base, push the image to a container registry, like\n\ngcr.io\n. All release images are hosted under \ngcr.io/google_containers\n and\ntagged according to a \nsemver\n scheme.\n\n\nAn example release might look like:\n\n\n$ make release\n\n\n\n\n\nPlease follow these guidelines to cut a release:\n\n\n\n\nUpdate the \nrelease\n\npage with a short description of the major changes that correspond to a given\nimage tag.\n\n\nCut a release branch, if appropriate. Release branches follow the format of\n\ncontroller-release-version\n. Typically, pre-releases are cut from HEAD.\nAll major feature work is done in HEAD. Specific bug fixes are\ncherry-picked into a release branch.\n\n\nIf you're not confident about the stability of the code,\n\ntag\n it as alpha or beta.\nTypically, a release branch should have stable code.", + "text": "Developing for NGINX Ingress Controller\n\u00b6\n\n\nThis document explains how to get started with developing for NGINX Ingress controller.\nIt includes how to build, test, and release ingress controllers.\n\n\nQuick Start\n\u00b6\n\n\nGetting the code\n\u00b6\n\n\nThe code must be checked out as a subdirectory of k8s.io, and not github.com.\n\n\nmkdir -p $GOPATH/src/k8s.io\ncd $GOPATH/src/k8s.io\n# Replace \"$YOUR_GITHUB_USERNAME\" below with your github username\ngit clone https://github.com/$YOUR_GITHUB_USERNAME/ingress-nginx.git\ncd ingress-nginx\n\n\n\n\nInitial developer environment build\n\u00b6\n\n\n\n\nPrequisites\n: Minikube must be installed.\nSee \nreleases\n for installation instructions. \n\n\n\n\nIf you are using \nMacOS\n and deploying to \nminikube\n, 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 \ningress-nginx\n:\n\n\n$ make dev-env\n\n\n\n\nUpdating the deployment\n\u00b6\n\n\nThe nginx controller container image can be rebuilt using:\n\n$ \nARCH\n=\namd64 \nTAG\n=\ndev \nREGISTRY\n=\n$USER\n/ingress-controller make build container\n\n\n\nThe image will only be used by pods created after the rebuild. To delete old pods which will cause new ones to spin up:\n\n$ kubectl get pods -n ingress-nginx\n$ kubectl delete pod -n ingress-nginx nginx-ingress-controller-\n\n\n\nDependencies\n\u00b6\n\n\nThe build uses dependencies in the \nvendor\n directory, which\nmust be installed before building a binary/image. Occasionally, you\nmight need to update the dependencies.\n\n\nThis guide requires you to install the \ndep\n dependency tool.\n\n\nCheck the version of \ndep\n you are using and make sure it is up to date.\n\n\n$\n dep version\n\ndep:\n\n\n version : devel\n\n\n build date : \n\n\n git hash : \n\n\n go version : go1.9\n\n\n go compiler : gc\n\n\n platform : linux/amd64\n\n\n\n\n\nIf you have an older version of \ndep\n, you can update it as follows:\n\n\n$\n go get -u github.com/golang/dep\n\n\n\n\nThis will automatically save the dependencies to the \nvendor/\n directory.\n\n\n$\n \ncd\n \n$GOPATH\n/src/k8s.io/ingress-nginx\n\n$\n dep ensure\n\n$\n dep ensure -update\n\n$\n dep prune\n\n\n\n\nBuilding\n\u00b6\n\n\nAll ingress controllers are built through a Makefile. Depending on your\nrequirements you can build a raw server binary, a local container image,\nor push an image to a remote repository.\n\n\nIn order to use your local Docker, you may need to set the following environment variables:\n\n\n#\n \n\"gcloud docker\"\n \n(\ndefault\n)\n or \n\"docker\"\n\n\n$\n \nexport\n \nDOCKER\n=\n\n\n\n#\n \n\"quay.io/kubernetes-ingress-controller\"\n \n(\ndefault\n)\n, \n\"index.docker.io\"\n, or your own registry\n\n$\n \nexport\n \nREGISTRY\n=\n\n\n\n\n\nTo find the registry simply run: \ndocker system info | grep Registry\n\n\nNginx Controller\n\u00b6\n\n\nBuild a raw server binary\n\n$\n make build\n\n\n\nTODO\n: add more specific instructions needed for raw server binary.\n\n\nBuild a local container image\n\n\n$\n \nTAG\n=\n \nREGISTRY\n=\n$USER\n/ingress-controller make docker-build\n\n\n\n\nPush the container image to a remote repository\n\n\n$\n \nTAG\n=\n \nREGISTRY\n=\n$USER\n/ingress-controller make docker-push\n\n\n\n\nDeploying\n\u00b6\n\n\nThere are several ways to deploy the ingress controller onto a cluster.\nPlease check the \ndeployment guide\n\n\nTesting\n\u00b6\n\n\nTo run unit-tests, just run\n\n\n$\n \ncd\n \n$GOPATH\n/src/k8s.io/ingress-nginx\n\n$\n make \ntest\n\n\n\n\n\nIf you have access to a Kubernetes cluster, you can also run e2e tests using ginkgo.\n\n\n$\n \ncd\n \n$GOPATH\n/src/k8s.io/ingress-nginx\n\n$\n make e2e-test\n\n\n\n\nTo run unit-tests for lua code locally, run:\n\n\n$\n \ncd\n \n$GOPATH\n/src/k8s.io/ingress-nginx\n\n$\n ./rootfs/etc/nginx/lua/test/up.sh\n\n$\n make lua-test\n\n\n\n\nLua tests are located in \n$GOPATH/src/k8s.io/ingress-nginx/rootfs/etc/nginx/lua/test\n. When creating a new test file it must follow the naming convention \n_test.lua\n or it will be ignored. \n\n\nReleasing\n\u00b6\n\n\nAll Makefiles will produce a release binary, as shown above. To publish this\nto a wider Kubernetes user base, push the image to a container registry, like\n\ngcr.io\n. All release images are hosted under \ngcr.io/google_containers\n and\ntagged according to a \nsemver\n scheme.\n\n\nAn example release might look like:\n\n$ make release\n\n\n\nPlease follow these guidelines to cut a release:\n\n\n\n\nUpdate the \nrelease\n\npage with a short description of the major changes that correspond to a given\nimage tag.\n\n\nCut a release branch, if appropriate. Release branches follow the format of\n\ncontroller-release-version\n. Typically, pre-releases are cut from HEAD.\nAll major feature work is done in HEAD. Specific bug fixes are\ncherry-picked into a release branch.\n\n\nIf you're not confident about the stability of the code,\n\ntag\n it as alpha or beta.\nTypically, a release branch should have stable code.", "title": "Developing for NGINX Ingress Controller" }, { @@ -1692,7 +1712,7 @@ }, { "location": "/development/#updating-the-deployment", - "text": "The nginx controller container image can be rebuilt using: $ ARCH = amd64 TAG = dev REGISTRY = $USER /ingress-controller make build container The image will only be used by pods created after the rebuild. To delete old pods which will cause new ones to spin up: $ kubectl get pods -n ingress-nginx\n$ kubectl delete pod -n ingress-nginx nginx-ingress-controller-", + "text": "The nginx controller container image can be rebuilt using: $ ARCH = amd64 TAG = dev REGISTRY = $USER /ingress-controller make build container The image will only be used by pods created after the rebuild. To delete old pods which will cause new ones to spin up: $ kubectl get pods -n ingress-nginx\n$ kubectl delete pod -n ingress-nginx nginx-ingress-controller-", "title": "Updating the deployment" }, { @@ -1707,7 +1727,7 @@ }, { "location": "/development/#nginx-controller", - "text": "Build a raw server binary $ make build TODO : add more specific instructions needed for raw server binary. Build a local container image $ TAG = REGISTRY = $USER /ingress-controller make docker-build Push the container image to a remote repository $ TAG = REGISTRY = $USER /ingress-controller make docker-push", + "text": "Build a raw server binary $ make build TODO : add more specific instructions needed for raw server binary. Build a local container image $ TAG = REGISTRY = $USER /ingress-controller make docker-build Push the container image to a remote repository $ TAG = REGISTRY = $USER /ingress-controller make docker-push", "title": "Nginx Controller" }, { @@ -1722,7 +1742,7 @@ }, { "location": "/development/#releasing", - "text": "All Makefiles will produce a release binary, as shown above. To publish this\nto a wider Kubernetes user base, push the image to a container registry, like gcr.io . All release images are hosted under gcr.io/google_containers and\ntagged according to a semver scheme. An example release might look like: $ make release Please follow these guidelines to cut a release: Update the release \npage with a short description of the major changes that correspond to a given\nimage tag. Cut a release branch, if appropriate. Release branches follow the format of controller-release-version . Typically, pre-releases are cut from HEAD.\nAll major feature work is done in HEAD. Specific bug fixes are\ncherry-picked into a release branch. If you're not confident about the stability of the code, tag it as alpha or beta.\nTypically, a release branch should have stable code.", + "text": "All Makefiles will produce a release binary, as shown above. To publish this\nto a wider Kubernetes user base, push the image to a container registry, like gcr.io . All release images are hosted under gcr.io/google_containers and\ntagged according to a semver scheme. An example release might look like: $ make release Please follow these guidelines to cut a release: Update the release \npage with a short description of the major changes that correspond to a given\nimage tag. Cut a release branch, if appropriate. Release branches follow the format of controller-release-version . Typically, pre-releases are cut from HEAD.\nAll major feature work is done in HEAD. Specific bug fixes are\ncherry-picked into a release branch. If you're not confident about the stability of the code, tag it as alpha or beta.\nTypically, a release branch should have stable code.", "title": "Releasing" }, { @@ -1767,7 +1787,7 @@ }, { "location": "/troubleshooting/", - "text": "Troubleshooting\n\u00b6\n\n\nIngress-Controller Logs and Events\n\u00b6\n\n\nThere are many ways to troubleshoot the ingress-controller. The following are basic troubleshooting\nmethods to obtain more information.\n\n\nCheck the Ingress Resource Events\n\n\n$\n kubectl get ing -n \n\nNAME HOSTS ADDRESS PORTS AGE\n\n\ncafe-ingress cafe.com 10.0.2.15 80 25s\n\n\n\n$\n kubectl describe ing -n \n\nName: cafe-ingress\n\n\nNamespace: default\n\n\nAddress: 10.0.2.15\n\n\nDefault backend: default-http-backend:80 (172.17.0.5:8080)\n\n\nRules:\n\n\n Host Path Backends\n\n\n ---- ---- --------\n\n\n cafe.com\n\n\n /tea tea-svc:80 ()\n\n\n /coffee coffee-svc:80 ()\n\n\nAnnotations:\n\n\n kubectl.kubernetes.io/last-applied-configuration: {\"apiVersion\":\"extensions/v1beta1\",\"kind\":\"Ingress\",\"metadata\":{\"annotations\":{},\"name\":\"cafe-ingress\",\"namespace\":\"default\",\"selfLink\":\"/apis/extensions/v1beta1/namespaces/default/ingresses/cafe-ingress\"},\"spec\":{\"rules\":[{\"host\":\"cafe.com\",\"http\":{\"paths\":[{\"backend\":{\"serviceName\":\"tea-svc\",\"servicePort\":80},\"path\":\"/tea\"},{\"backend\":{\"serviceName\":\"coffee-svc\",\"servicePort\":80},\"path\":\"/coffee\"}]}}]},\"status\":{\"loadBalancer\":{\"ingress\":[{\"ip\":\"169.48.142.110\"}]}}}\n\n\n\nEvents:\n\n\n Type Reason Age From Message\n\n\n ---- ------ ---- ---- -------\n\n\n Normal CREATE 1m nginx-ingress-controller Ingress default/cafe-ingress\n\n\n Normal UPDATE 58s nginx-ingress-controller Ingress default/cafe-ingress\n\n\n\n\n\n\nCheck the Ingress Controller Logs\n\n\n$\n kubectl get pods -n \n\nNAME READY STATUS RESTARTS AGE\n\n\nnginx-ingress-controller-67956bf89d-fv58j 1/1 Running 0 1m\n\n\n\n$\n kubectl logs -n nginx-ingress-controller-67956bf89d-fv58j\n\n-------------------------------------------------------------------------------\n\n\nNGINX Ingress controller\n\n\n Release: 0.14.0\n\n\n Build: git-734361d\n\n\n Repository: https://github.com/kubernetes/ingress-nginx\n\n\n-------------------------------------------------------------------------------\n\n\n....\n\n\n\n\n\n\nCheck the Nginx Configuration\n\n\n$\n kubectl get pods -n \n\nNAME READY STATUS RESTARTS AGE\n\n\nnginx-ingress-controller-67956bf89d-fv58j 1/1 Running 0 1m\n\n\n\n$\n kubectl \nexec\n -it -n nginx-ingress-controller-67956bf89d-fv58j cat /etc/nginx/nginx.conf\n\ndaemon off;\n\n\nworker_processes 2;\n\n\npid /run/nginx.pid;\n\n\nworker_rlimit_nofile 523264;\n\n\nworker_shutdown_timeout 10s;\n\n\nevents {\n\n\n multi_accept on;\n\n\n worker_connections 16384;\n\n\n use epoll;\n\n\n}\n\n\nhttp {\n\n\n....\n\n\n\n\n\n\nCheck if used Services Exist\n\n\n$\n kubectl get svc --all-namespaces\n\nNAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE\n\n\ndefault coffee-svc ClusterIP 10.106.154.35 80/TCP 18m\n\n\ndefault kubernetes ClusterIP 10.96.0.1 443/TCP 30m\n\n\ndefault tea-svc ClusterIP 10.104.172.12 80/TCP 18m\n\n\nkube-system default-http-backend NodePort 10.108.189.236 80:30001/TCP 30m\n\n\nkube-system kube-dns ClusterIP 10.96.0.10 53/UDP,53/TCP 30m\n\n\nkube-system kubernetes-dashboard NodePort 10.103.128.17 80:30000/TCP 30m\n\n\n\n\n\n\nDebug Logging\n\u00b6\n\n\nUsing the flag \n--v=XX\n it is possible to increase the level of logging. This is performed by editing\nthe deployment.\n\n\n$\n kubectl get deploy -n \n\nNAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE\n\n\ndefault-http-backend 1 1 1 1 35m\n\n\nnginx-ingress-controller 1 1 1 1 35m\n\n\n\n$\n kubectl edit deploy -n nginx-ingress-controller\n\n#\n Add --v\n=\nX to \n\"- args\"\n, where X is an integer\n\n\n\n\n\n\n\n--v=2\n shows details using \ndiff\n about the changes in the configuration in nginx\n\n\n--v=3\n shows details about the service, Ingress rule, endpoint changes and it dumps the nginx configuration in JSON format\n\n\n--v=5\n configures NGINX in \ndebug mode\n\n\n\n\nAuthentication to the Kubernetes API Server\n\u00b6\n\n\nA number of components are involved in the authentication process and the first step is to narrow\ndown the source of the problem, namely whether it is a problem with service authentication or\nwith the kubeconfig file.\n\n\nBoth authentications must work:\n\n\n+-------------+ service +------------+\n| | authentication | |\n+ apiserver +<-------------------+ ingress |\n| | | controller |\n+-------------+ +------------+\n\n\n\n\n\nService authentication\n\n\nThe Ingress controller needs information from apiserver. Therefore, authentication is required, which can be achieved in two different ways:\n\n\n\n\n\n\nService Account:\n This is recommended, because nothing has to be configured. The Ingress controller will use information provided by the system to communicate with the API server. See 'Service Account' section for details.\n\n\n\n\n\n\nKubeconfig file:\n In some Kubernetes environments service accounts are not available. In this case a manual configuration is required. The Ingress controller binary can be started with the \n--kubeconfig\n flag. The value of the flag is a path to a file specifying how to connect to the API server. Using the \n--kubeconfig\n does not requires the flag \n--apiserver-host\n.\n The format of the file is identical to \n~/.kube/config\n which is used by kubectl to connect to the API server. See 'kubeconfig' section for details.\n\n\n\n\n\n\nUsing the flag \n--apiserver-host\n:\n Using this flag \n--apiserver-host=http://localhost:8080\n it is possible to specify an unsecured API server or reach a remote kubernetes cluster using \nkubectl proxy\n.\n Please do not use this approach in production.\n\n\n\n\n\n\nIn the diagram below you can see the full authentication flow with all options, starting with the browser\non the lower left hand side.\n\n\nKubernetes Workstation\n+---------------------------------------------------+ +------------------+\n| | | |\n| +-----------+ apiserver +------------+ | | +------------+ |\n| | | proxy | | | | | | |\n| | apiserver | | ingress | | | | ingress | |\n| | | | controller | | | | controller | |\n| | | | | | | | | |\n| | | | | | | | | |\n| | | service account/ | | | | | | |\n| | | kubeconfig | | | | | | |\n| | +<-------------------+ | | | | | |\n| | | | | | | | | |\n| +------+----+ kubeconfig +------+-----+ | | +------+-----+ |\n| |<--------------------------------------------------------| |\n| | | |\n+---------------------------------------------------+ +------------------+\n\n\n\n\n\nService Account\n\u00b6\n\n\nIf using a service account to connect to the API server, Dashboard expects the file\n\n/var/run/secrets/kubernetes.io/serviceaccount/token\n to be present. It provides a secret\ntoken that is required to authenticate with the API server.\n\n\nVerify with the following commands:\n\n\n#\n start a container that contains curl\n\n$\n kubectl run \ntest\n --image\n=\ntutum/curl -- sleep \n10000\n\n\n\n#\n check that container is running\n\n$\n kubectl get pods\n\nNAME READY STATUS RESTARTS AGE\n\n\ntest-701078429-s5kca 1/1 Running 0 16s\n\n\n\n#\n check \nif\n secret exists\n\n$\n kubectl \nexec\n test-701078429-s5kca ls /var/run/secrets/kubernetes.io/serviceaccount/\n\nca.crt\n\n\nnamespace\n\n\ntoken\n\n\n\n#\n get service IP of master\n\n$\n kubectl get services\n\nNAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE\n\n\nkubernetes 10.0.0.1 443/TCP 1d\n\n\n\n#\n check base connectivity from cluster inside\n\n$\n kubectl \nexec\n test-701078429-s5kca -- curl -k https://10.0.0.1\n\nUnauthorized\n\n\n\n#\n connect using tokens\n\n$\n \nTOKEN_VALUE\n=\n$(\nkubectl \nexec\n test-701078429-s5kca -- cat /var/run/secrets/kubernetes.io/serviceaccount/token\n)\n\n\n$\n \necho\n \n$TOKEN_VALUE\n\n\neyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3Mi....9A\n\n\n$\n kubectl \nexec\n test-701078429-s5kca -- curl --cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt -H \n\"Authorization: Bearer \n$TOKEN_VALUE\n\"\n https://10.0.0.1\n\n{\n\n\n \"paths\": [\n\n\n \"/api\",\n\n\n \"/api/v1\",\n\n\n \"/apis\",\n\n\n \"/apis/apps\",\n\n\n \"/apis/apps/v1alpha1\",\n\n\n \"/apis/authentication.k8s.io\",\n\n\n \"/apis/authentication.k8s.io/v1beta1\",\n\n\n \"/apis/authorization.k8s.io\",\n\n\n \"/apis/authorization.k8s.io/v1beta1\",\n\n\n \"/apis/autoscaling\",\n\n\n \"/apis/autoscaling/v1\",\n\n\n \"/apis/batch\",\n\n\n \"/apis/batch/v1\",\n\n\n \"/apis/batch/v2alpha1\",\n\n\n \"/apis/certificates.k8s.io\",\n\n\n \"/apis/certificates.k8s.io/v1alpha1\",\n\n\n \"/apis/extensions\",\n\n\n \"/apis/extensions/v1beta1\",\n\n\n \"/apis/policy\",\n\n\n \"/apis/policy/v1alpha1\",\n\n\n \"/apis/rbac.authorization.k8s.io\",\n\n\n \"/apis/rbac.authorization.k8s.io/v1alpha1\",\n\n\n \"/apis/storage.k8s.io\",\n\n\n \"/apis/storage.k8s.io/v1beta1\",\n\n\n \"/healthz\",\n\n\n \"/healthz/ping\",\n\n\n \"/logs\",\n\n\n \"/metrics\",\n\n\n \"/swaggerapi/\",\n\n\n \"/ui/\",\n\n\n \"/version\"\n\n\n ]\n\n\n}\n\n\n\n\n\n\nIf it is not working, there are two possible reasons:\n\n\n\n\n\n\nThe contents of the tokens are invalid. Find the secret name with \nkubectl get secrets | grep service-account\n and\n delete it with \nkubectl delete secret \n. It will automatically be recreated.\n\n\n\n\n\n\nYou have a non-standard Kubernetes installation and the file containing the token may not be present.\n The API server will mount a volume containing this file, but only if the API server is configured to use\n the ServiceAccount admission controller.\n If you experience this error, verify that your API server is using the ServiceAccount admission controller.\n If you are configuring the API server by hand, you can set this with the \n--admission-control\n parameter.\n\n\n\n\nNote that you should use other admission controllers as well. Before configuring this option, you should read about admission controllers.\n\n\n\n\n\n\n\n\nMore information:\n\n\n\n\nUser Guide: Service Accounts\n\n\nCluster Administrator Guide: Managing Service Accounts\n\n\n\n\nKube-Config\n\u00b6\n\n\nIf you want to use a kubeconfig file for authentication, follow the \ndeploy procedure\n and\nadd the flag \n--kubeconfig=/etc/kubernetes/kubeconfig.yaml\n to the args section of the deployment.\n\n\nUsing GDB with Nginx\n\u00b6\n\n\nGdb\n can be used to with nginx to perform a configuration\ndump. This allows us to see which configuration is being used, as well as older configurations.\n\n\nNote: The below is based on the nginx \ndocumentation\n.\n\n\n\n\nSSH into the worker\n\n\n\n\n$\n ssh user@workerIP\n\n\n\n\n\n\n\nObtain the Docker Container Running nginx\n\n\n\n\n$\n docker ps \n|\n grep nginx-ingress-controller\n\nCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES\n\n\nd9e1d243156a quay.io/kubernetes-ingress-controller/nginx-ingress-controller \"/usr/bin/dumb-init \u2026\" 19 minutes ago Up 19 minutes k8s_nginx-ingress-controller_nginx-ingress-controller-67956bf89d-mqxzt_kube-system_079f31ec-aa37-11e8-ad39-080027a227db_0\n\n\n\n\n\n\n\n\nExec into the container\n\n\n\n\n$\n docker \nexec\n -it --user\n=\n0\n --privileged d9e1d243156a bash\n\n\n\n\n\n\n\nMake sure nginx is running in \n--with-debug\n\n\n\n\n$\n nginx -V \n2\n>\n&\n1\n \n|\n grep -- \n'--with-debug'\n\n\n\n\n\n\n\n\nGet list of processes running on container\n\n\n\n\n$\n ps -ef\n\nUID PID PPID C STIME TTY TIME CMD\n\n\nroot 1 0 0 20:23 ? 00:00:00 /usr/bin/dumb-init /nginx-ingres\n\n\nroot 5 1 0 20:23 ? 00:00:05 /nginx-ingress-controller --defa\n\n\nroot 21 5 0 20:23 ? 00:00:00 nginx: master process /usr/sbin/\n\n\nnobody 106 21 0 20:23 ? 00:00:00 nginx: worker process\n\n\nnobody 107 21 0 20:23 ? 00:00:00 nginx: worker process\n\n\nroot 172 0 0 20:43 pts/0 00:00:00 bash\n\n\n\n\n\n\n\n\nAttach gdb to the nginx master process\n\n\n\n\n$\n gdb -p \n21\n\n\n....\n\n\nAttaching to process 21\n\n\nReading symbols from /usr/sbin/nginx...done.\n\n\n....\n\n\n(gdb)\n\n\n\n\n\n\n\n\nCopy and paste the following:\n\n\n\n\nset $cd = ngx_cycle->config_dump\n\n\nset $nelts = $cd.nelts\n\n\nset $elts = (ngx_conf_dump_t*)($cd.elts)\n\n\nwhile ($nelts-- > 0)\n\n\nset $name = $elts[$nelts]->name.data\n\n\nprintf \"Dumping %s to nginx_conf.txt\\n\", $name\n\n\nappend memory nginx_conf.txt \\\n\n\n $\nelts\n[\n$nelts\n]\n->buffer.start \n$elts\n[\n$nelts\n]\n->buffer.end\n\nend\n\n\n\n\n\n\n\n\n\n\nQuit GDB by pressing CTRL+D\n\n\n\n\n\n\nOpen nginx_conf.txt\n\n\n\n\n\n\ncat nginx_conf.txt", + "text": "Troubleshooting\n\u00b6\n\n\nIngress-Controller Logs and Events\n\u00b6\n\n\nThere are many ways to troubleshoot the ingress-controller. The following are basic troubleshooting\nmethods to obtain more information.\n\n\nCheck the Ingress Resource Events\n\n\n$\n kubectl get ing -n \n\nNAME HOSTS ADDRESS PORTS AGE\n\n\ncafe-ingress cafe.com 10.0.2.15 80 25s\n\n\n\n$\n kubectl describe ing -n \n\nName: cafe-ingress\n\n\nNamespace: default\n\n\nAddress: 10.0.2.15\n\n\nDefault backend: default-http-backend:80 (172.17.0.5:8080)\n\n\nRules:\n\n\n Host Path Backends\n\n\n ---- ---- --------\n\n\n cafe.com\n\n\n /tea tea-svc:80 ()\n\n\n /coffee coffee-svc:80 ()\n\n\nAnnotations:\n\n\n kubectl.kubernetes.io/last-applied-configuration: {\"apiVersion\":\"extensions/v1beta1\",\"kind\":\"Ingress\",\"metadata\":{\"annotations\":{},\"name\":\"cafe-ingress\",\"namespace\":\"default\",\"selfLink\":\"/apis/extensions/v1beta1/namespaces/default/ingresses/cafe-ingress\"},\"spec\":{\"rules\":[{\"host\":\"cafe.com\",\"http\":{\"paths\":[{\"backend\":{\"serviceName\":\"tea-svc\",\"servicePort\":80},\"path\":\"/tea\"},{\"backend\":{\"serviceName\":\"coffee-svc\",\"servicePort\":80},\"path\":\"/coffee\"}]}}]},\"status\":{\"loadBalancer\":{\"ingress\":[{\"ip\":\"169.48.142.110\"}]}}}\n\n\n\nEvents:\n\n\n Type Reason Age From Message\n\n\n ---- ------ ---- ---- -------\n\n\n Normal CREATE 1m nginx-ingress-controller Ingress default/cafe-ingress\n\n\n Normal UPDATE 58s nginx-ingress-controller Ingress default/cafe-ingress\n\n\n\n\n\nCheck the Ingress Controller Logs\n\n\n$\n kubectl get pods -n \n\nNAME READY STATUS RESTARTS AGE\n\n\nnginx-ingress-controller-67956bf89d-fv58j 1/1 Running 0 1m\n\n\n\n$\n kubectl logs -n nginx-ingress-controller-67956bf89d-fv58j\n\n-------------------------------------------------------------------------------\n\n\nNGINX Ingress controller\n\n\n Release: 0.14.0\n\n\n Build: git-734361d\n\n\n Repository: https://github.com/kubernetes/ingress-nginx\n\n\n-------------------------------------------------------------------------------\n\n\n....\n\n\n\n\n\nCheck the Nginx Configuration\n\n\n$\n kubectl get pods -n \n\nNAME READY STATUS RESTARTS AGE\n\n\nnginx-ingress-controller-67956bf89d-fv58j 1/1 Running 0 1m\n\n\n\n$\n kubectl \nexec\n -it -n nginx-ingress-controller-67956bf89d-fv58j cat /etc/nginx/nginx.conf\n\ndaemon off;\n\n\nworker_processes 2;\n\n\npid /run/nginx.pid;\n\n\nworker_rlimit_nofile 523264;\n\n\nworker_shutdown_timeout 10s;\n\n\nevents {\n\n\n multi_accept on;\n\n\n worker_connections 16384;\n\n\n use epoll;\n\n\n}\n\n\nhttp {\n\n\n....\n\n\n\n\n\nCheck if used Services Exist\n\n\n$\n kubectl get svc --all-namespaces\n\nNAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE\n\n\ndefault coffee-svc ClusterIP 10.106.154.35 80/TCP 18m\n\n\ndefault kubernetes ClusterIP 10.96.0.1 443/TCP 30m\n\n\ndefault tea-svc ClusterIP 10.104.172.12 80/TCP 18m\n\n\nkube-system default-http-backend NodePort 10.108.189.236 80:30001/TCP 30m\n\n\nkube-system kube-dns ClusterIP 10.96.0.10 53/UDP,53/TCP 30m\n\n\nkube-system kubernetes-dashboard NodePort 10.103.128.17 80:30000/TCP 30m\n\n\n\n\n\nDebug Logging\n\u00b6\n\n\nUsing the flag \n--v=XX\n it is possible to increase the level of logging. This is performed by editing\nthe deployment.\n\n\n$\n kubectl get deploy -n \n\nNAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE\n\n\ndefault-http-backend 1 1 1 1 35m\n\n\nnginx-ingress-controller 1 1 1 1 35m\n\n\n\n$\n kubectl edit deploy -n nginx-ingress-controller\n\n#\n Add --v\n=\nX to \n\"- args\"\n, where X is an integer\n\n\n\n\n\n\n--v=2\n shows details using \ndiff\n about the changes in the configuration in nginx\n\n\n--v=3\n shows details about the service, Ingress rule, endpoint changes and it dumps the nginx configuration in JSON format\n\n\n--v=5\n configures NGINX in \ndebug mode\n\n\n\n\nAuthentication to the Kubernetes API Server\n\u00b6\n\n\nA number of components are involved in the authentication process and the first step is to narrow\ndown the source of the problem, namely whether it is a problem with service authentication or\nwith the kubeconfig file.\n\n\nBoth authentications must work:\n\n\n+-------------+ service +------------+\n| | authentication | |\n+ apiserver +<-------------------+ ingress |\n| | | controller |\n+-------------+ +------------+\n\n\n\n\nService authentication\n\n\nThe Ingress controller needs information from apiserver. Therefore, authentication is required, which can be achieved in two different ways:\n\n\n\n\n\n\nService Account:\n This is recommended, because nothing has to be configured. The Ingress controller will use information provided by the system to communicate with the API server. See 'Service Account' section for details.\n\n\n\n\n\n\nKubeconfig file:\n In some Kubernetes environments service accounts are not available. In this case a manual configuration is required. The Ingress controller binary can be started with the \n--kubeconfig\n flag. The value of the flag is a path to a file specifying how to connect to the API server. Using the \n--kubeconfig\n does not requires the flag \n--apiserver-host\n.\n The format of the file is identical to \n~/.kube/config\n which is used by kubectl to connect to the API server. See 'kubeconfig' section for details.\n\n\n\n\n\n\nUsing the flag \n--apiserver-host\n:\n Using this flag \n--apiserver-host=http://localhost:8080\n it is possible to specify an unsecured API server or reach a remote kubernetes cluster using \nkubectl proxy\n.\n Please do not use this approach in production.\n\n\n\n\n\n\nIn the diagram below you can see the full authentication flow with all options, starting with the browser\non the lower left hand side.\n\n\nKubernetes Workstation\n+---------------------------------------------------+ +------------------+\n| | | |\n| +-----------+ apiserver +------------+ | | +------------+ |\n| | | proxy | | | | | | |\n| | apiserver | | ingress | | | | ingress | |\n| | | | controller | | | | controller | |\n| | | | | | | | | |\n| | | | | | | | | |\n| | | service account/ | | | | | | |\n| | | kubeconfig | | | | | | |\n| | +<-------------------+ | | | | | |\n| | | | | | | | | |\n| +------+----+ kubeconfig +------+-----+ | | +------+-----+ |\n| |<--------------------------------------------------------| |\n| | | |\n+---------------------------------------------------+ +------------------+\n\n\n\n\nService Account\n\u00b6\n\n\nIf using a service account to connect to the API server, Dashboard expects the file\n\n/var/run/secrets/kubernetes.io/serviceaccount/token\n to be present. It provides a secret\ntoken that is required to authenticate with the API server.\n\n\nVerify with the following commands:\n\n\n#\n start a container that contains curl\n\n$\n kubectl run \ntest\n --image\n=\ntutum/curl -- sleep \n10000\n\n\n\n#\n check that container is running\n\n$\n kubectl get pods\n\nNAME READY STATUS RESTARTS AGE\n\n\ntest-701078429-s5kca 1/1 Running 0 16s\n\n\n\n#\n check \nif\n secret exists\n\n$\n kubectl \nexec\n test-701078429-s5kca ls /var/run/secrets/kubernetes.io/serviceaccount/\n\nca.crt\n\n\nnamespace\n\n\ntoken\n\n\n\n#\n get service IP of master\n\n$\n kubectl get services\n\nNAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE\n\n\nkubernetes 10.0.0.1 443/TCP 1d\n\n\n\n#\n check base connectivity from cluster inside\n\n$\n kubectl \nexec\n test-701078429-s5kca -- curl -k https://10.0.0.1\n\nUnauthorized\n\n\n\n#\n connect using tokens\n\n$\n \nTOKEN_VALUE\n=\n$(\nkubectl \nexec\n test-701078429-s5kca -- cat /var/run/secrets/kubernetes.io/serviceaccount/token\n)\n\n\n$\n \necho\n \n$TOKEN_VALUE\n\n\neyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3Mi....9A\n\n\n$\n kubectl \nexec\n test-701078429-s5kca -- curl --cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt -H \n\"Authorization: Bearer \n$TOKEN_VALUE\n\"\n https://10.0.0.1\n\n{\n\n\n \"paths\": [\n\n\n \"/api\",\n\n\n \"/api/v1\",\n\n\n \"/apis\",\n\n\n \"/apis/apps\",\n\n\n \"/apis/apps/v1alpha1\",\n\n\n \"/apis/authentication.k8s.io\",\n\n\n \"/apis/authentication.k8s.io/v1beta1\",\n\n\n \"/apis/authorization.k8s.io\",\n\n\n \"/apis/authorization.k8s.io/v1beta1\",\n\n\n \"/apis/autoscaling\",\n\n\n \"/apis/autoscaling/v1\",\n\n\n \"/apis/batch\",\n\n\n \"/apis/batch/v1\",\n\n\n \"/apis/batch/v2alpha1\",\n\n\n \"/apis/certificates.k8s.io\",\n\n\n \"/apis/certificates.k8s.io/v1alpha1\",\n\n\n \"/apis/extensions\",\n\n\n \"/apis/extensions/v1beta1\",\n\n\n \"/apis/policy\",\n\n\n \"/apis/policy/v1alpha1\",\n\n\n \"/apis/rbac.authorization.k8s.io\",\n\n\n \"/apis/rbac.authorization.k8s.io/v1alpha1\",\n\n\n \"/apis/storage.k8s.io\",\n\n\n \"/apis/storage.k8s.io/v1beta1\",\n\n\n \"/healthz\",\n\n\n \"/healthz/ping\",\n\n\n \"/logs\",\n\n\n \"/metrics\",\n\n\n \"/swaggerapi/\",\n\n\n \"/ui/\",\n\n\n \"/version\"\n\n\n ]\n\n\n}\n\n\n\n\n\nIf it is not working, there are two possible reasons:\n\n\n\n\n\n\nThe contents of the tokens are invalid. Find the secret name with \nkubectl get secrets | grep service-account\n and\n delete it with \nkubectl delete secret \n. It will automatically be recreated.\n\n\n\n\n\n\nYou have a non-standard Kubernetes installation and the file containing the token may not be present.\n The API server will mount a volume containing this file, but only if the API server is configured to use\n the ServiceAccount admission controller.\n If you experience this error, verify that your API server is using the ServiceAccount admission controller.\n If you are configuring the API server by hand, you can set this with the \n--admission-control\n parameter.\n\n\n\n\nNote that you should use other admission controllers as well. Before configuring this option, you should read about admission controllers.\n\n\n\n\n\n\n\n\nMore information:\n\n\n\n\nUser Guide: Service Accounts\n\n\nCluster Administrator Guide: Managing Service Accounts\n\n\n\n\nKube-Config\n\u00b6\n\n\nIf you want to use a kubeconfig file for authentication, follow the \ndeploy procedure\n and\nadd the flag \n--kubeconfig=/etc/kubernetes/kubeconfig.yaml\n to the args section of the deployment.\n\n\nUsing GDB with Nginx\n\u00b6\n\n\nGdb\n can be used to with nginx to perform a configuration\ndump. This allows us to see which configuration is being used, as well as older configurations.\n\n\nNote: The below is based on the nginx \ndocumentation\n.\n\n\n\n\nSSH into the worker\n\n\n\n\n$\n ssh user@workerIP\n\n\n\n\n\n\nObtain the Docker Container Running nginx\n\n\n\n\n$\n docker ps \n|\n grep nginx-ingress-controller\n\nCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES\n\n\nd9e1d243156a quay.io/kubernetes-ingress-controller/nginx-ingress-controller \"/usr/bin/dumb-init \u2026\" 19 minutes ago Up 19 minutes k8s_nginx-ingress-controller_nginx-ingress-controller-67956bf89d-mqxzt_kube-system_079f31ec-aa37-11e8-ad39-080027a227db_0\n\n\n\n\n\n\n\nExec into the container\n\n\n\n\n$\n docker \nexec\n -it --user\n=\n0\n --privileged d9e1d243156a bash\n\n\n\n\n\n\nMake sure nginx is running in \n--with-debug\n\n\n\n\n$\n nginx -V \n2\n>\n&\n1\n \n|\n grep -- \n'--with-debug'\n\n\n\n\n\n\n\nGet list of processes running on container\n\n\n\n\n$\n ps -ef\n\nUID PID PPID C STIME TTY TIME CMD\n\n\nroot 1 0 0 20:23 ? 00:00:00 /usr/bin/dumb-init /nginx-ingres\n\n\nroot 5 1 0 20:23 ? 00:00:05 /nginx-ingress-controller --defa\n\n\nroot 21 5 0 20:23 ? 00:00:00 nginx: master process /usr/sbin/\n\n\nnobody 106 21 0 20:23 ? 00:00:00 nginx: worker process\n\n\nnobody 107 21 0 20:23 ? 00:00:00 nginx: worker process\n\n\nroot 172 0 0 20:43 pts/0 00:00:00 bash\n\n\n\n\n\n\n\nAttach gdb to the nginx master process\n\n\n\n\n$\n gdb -p \n21\n\n\n....\n\n\nAttaching to process 21\n\n\nReading symbols from /usr/sbin/nginx...done.\n\n\n....\n\n\n(gdb)\n\n\n\n\n\n\n\nCopy and paste the following:\n\n\n\n\nset $cd = ngx_cycle->config_dump\n\n\nset $nelts = $cd.nelts\n\n\nset $elts = (ngx_conf_dump_t*)($cd.elts)\n\n\nwhile ($nelts-- > 0)\n\n\nset $name = $elts[$nelts]->name.data\n\n\nprintf \"Dumping %s to nginx_conf.txt\\n\", $name\n\n\nappend memory nginx_conf.txt \\\n\n\n $\nelts\n[\n$nelts\n]\n->buffer.start \n$elts\n[\n$nelts\n]\n->buffer.end\n\nend\n\n\n\n\n\n\n\n\n\nQuit GDB by pressing CTRL+D\n\n\n\n\n\n\nOpen nginx_conf.txt\n\n\n\n\n\n\ncat nginx_conf.txt", "title": "Troubleshooting" }, { diff --git a/sitemap.xml b/sitemap.xml index 96b8bf16c..35f7b5076 100644 --- a/sitemap.xml +++ b/sitemap.xml @@ -2,222 +2,227 @@ / - 2018-08-30 + 2018-09-04 daily /deploy/ - 2018-08-30 + 2018-09-04 + daily + + + /deploy/baremetal/ + 2018-09-04 daily /deploy/rbac/ - 2018-08-30 + 2018-09-04 daily /deploy/upgrade/ - 2018-08-30 + 2018-09-04 daily /user-guide/nginx-configuration/ - 2018-08-30 + 2018-09-04 daily /user-guide/nginx-configuration/annotations/ - 2018-08-30 + 2018-09-04 daily /user-guide/nginx-configuration/configmap/ - 2018-08-30 + 2018-09-04 daily /user-guide/nginx-configuration/custom-template/ - 2018-08-30 + 2018-09-04 daily /user-guide/nginx-configuration/log-format/ - 2018-08-30 + 2018-09-04 daily /user-guide/cli-arguments/ - 2018-08-30 + 2018-09-04 daily /user-guide/custom-errors/ - 2018-08-30 + 2018-09-04 daily /user-guide/default-backend/ - 2018-08-30 + 2018-09-04 daily /user-guide/exposing-tcp-udp-services/ - 2018-08-30 + 2018-09-04 daily /user-guide/external-articles/ - 2018-08-30 + 2018-09-04 daily /user-guide/miscellaneous/ - 2018-08-30 + 2018-09-04 daily /user-guide/monitoring/ - 2018-08-30 + 2018-09-04 daily /user-guide/multiple-ingress/ - 2018-08-30 + 2018-09-04 daily /user-guide/tls/ - 2018-08-30 + 2018-09-04 daily /user-guide/third-party-addons/modsecurity/ - 2018-08-30 + 2018-09-04 daily /user-guide/third-party-addons/opentracing/ - 2018-08-30 + 2018-09-04 daily /examples/ - 2018-08-30 + 2018-09-04 daily /examples/PREREQUISITES/ - 2018-08-30 + 2018-09-04 daily /examples/affinity/cookie/README/ - 2018-08-30 + 2018-09-04 daily /examples/auth/basic/README/ - 2018-08-30 + 2018-09-04 daily /examples/auth/client-certs/README/ - 2018-08-30 + 2018-09-04 daily /examples/auth/external-auth/README/ - 2018-08-30 + 2018-09-04 daily /examples/auth/oauth-external-auth/README/ - 2018-08-30 + 2018-09-04 daily /examples/customization/configuration-snippets/README/ - 2018-08-30 + 2018-09-04 daily /examples/customization/custom-configuration/README/ - 2018-08-30 + 2018-09-04 daily /examples/customization/custom-errors/README/ - 2018-08-30 + 2018-09-04 daily /examples/customization/custom-headers/README/ - 2018-08-30 + 2018-09-04 daily /examples/customization/custom-upstream-check/README/ - 2018-08-30 + 2018-09-04 daily /examples/customization/external-auth-headers/README/ - 2018-08-30 + 2018-09-04 daily /examples/customization/ssl-dh-param/README/ - 2018-08-30 + 2018-09-04 daily /examples/customization/sysctl/README/ - 2018-08-30 + 2018-09-04 daily /examples/docker-registry/README/ - 2018-08-30 + 2018-09-04 daily /examples/grpc/README/ - 2018-08-30 + 2018-09-04 daily /examples/multi-tls/README/ - 2018-08-30 + 2018-09-04 daily /examples/rewrite/README/ - 2018-08-30 + 2018-09-04 daily /examples/static-ip/README/ - 2018-08-30 + 2018-09-04 daily /examples/tls-termination/README/ - 2018-08-30 + 2018-09-04 daily /development/ - 2018-08-30 + 2018-09-04 daily /how-it-works/ - 2018-08-30 + 2018-09-04 daily /troubleshooting/ - 2018-08-30 + 2018-09-04 daily \ No newline at end of file diff --git a/troubleshooting/index.html b/troubleshooting/index.html index 61d65c12e..5d9c0bed8 100644 --- a/troubleshooting/index.html +++ b/troubleshooting/index.html @@ -356,6 +356,18 @@ +
      18. + + Bare-metal considerations + +
      19. + + + + + + +
      20. Role Based Access Control (RBAC) @@ -1208,7 +1220,6 @@ methods to obtain more information.

        Normal UPDATE 58s nginx-ingress-controller Ingress default/cafe-ingress
      21. -

        Check the Ingress Controller Logs

        $ kubectl get pods -n <namespace-of-ingress-controller>
         NAME                                        READY     STATUS    RESTARTS   AGE
        @@ -1224,7 +1235,6 @@ methods to obtain more information.

        ....
        -

        Check the Nginx Configuration

        $ kubectl get pods -n <namespace-of-ingress-controller>
         NAME                                        READY     STATUS    RESTARTS   AGE
        @@ -1245,7 +1255,6 @@ methods to obtain more information.

        ....
        -

        Check if used Services Exist

        $ kubectl get svc --all-namespaces
         NAMESPACE     NAME                   TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)         AGE
        @@ -1257,7 +1266,6 @@ methods to obtain more information.

        kube-system kubernetes-dashboard NodePort 10.103.128.17 <none> 80:30000/TCP 30m
        -

        Debug Logging

        Using the flag --v=XX it is possible to increase the level of logging. This is performed by editing the deployment.

        @@ -1270,7 +1278,6 @@ the deployment.

        # Add --v=X to "- args", where X is an integer -