github.com/projectcontour/contour@v1.28.2/site/content/posts/2019-10-23-httpproxy-in-action.md (about)

     1  ---
     2  title: HTTPProxy in Action
     3  image: /img/posts/proxyinaction.png
     4  excerpt: This blog post covers a practical demonstration of how HTTPProxy works.
     5  author_name: Steve Sloka
     6  author_avatar: /img/contributors/steve-sloka.png
     7  categories: [kubernetes]
     8  # Tag should match author to drive author pages
     9  tags: ['Contour Team', 'Steve Sloka', 'tutorial']
    10  date: 2019-10-23
    11  slug: httpproxy-in-action
    12  ---
    13  
    14  In our previous [blog post][1], Dave Cheney walked through Contour’s evolution from `IngressRoute` to `HTTPProxy` and explained how & why the move happened.
    15  
    16  Now with `HTTPProxy`, Contour allows for additional routing configuration outside of just supporting a `path prefix`.
    17  
    18  This post demonstrates a practical implementation of `HTTPProxy` and reviews some examples that explain how you can use it in your cluster today. 
    19  
    20  [![img][2]][3]
    21  *Here's a quick video demonstration walking through the rest of the blog post.*
    22  
    23  ## Prerequisites
    24  If you’d like to follow along in your own cluster, you’ll need a working Kubernetes cluster as well as Contour deployed. There are a number of ways to get these up and working. A simple way to test this locally is to use Kubernetes in Docker (Kind); you can check out our previous blog post on how to get this up and running on your local machine: [https://projectcontour.io/kindly-running-contour/][4]
    25  
    26  ## Demo Time
    27  Let’s walk through a simple scenario to quickly demonstrate how these new features work with `HTTPProxy`. This demo will progress through various features of `HTTPProxy` by starting off with a set of prerequisite services and deployments. Then it will move to implement `conditions` on routes to further specify request route matching. Finally, we’ll introduce `includes`, which will allow us to delegate path and header conditions to other `HTTPProxy` resources in different namespaces. 
    28  
    29  ## Setup and Prerequisites
    30  We’ll start by creating a sample set of applications and services, which we will use to set up some routing with `HTTPProxy`:
    31  
    32  ```bash
    33  $ kubectl apply -f https://projectcontour.io/examples/proxydemo/01-prereq.yaml 
    34  ```
    35  
    36  ## Basic HTTPProxy
    37  Next, we’ll apply our root HTTPProxy. This proxy is unique since it defines the `fqdn` for the requests. In our example, the FQDN is `local.projectcontour.io`. It configures two routes, one for `/` and another for `/secure`. 
    38  
    39  _Note: If you’re running this in your own cluster, update the `fqdn` value in the spec.virtualhost section of the HTTPProxy before applying each HTTPProxy update. `local.projectcontour.io` points to 127.0.0.1 and works well if you’re running a `kind` setup._
    40  
    41  ```bash
    42  $ kubectl apply -f https://projectcontour.io/examples/proxydemo/02-proxy-basic.yaml
    43  
    44  apiVersion: projectcontour.io/v1
    45  kind: HTTPProxy
    46  metadata:
    47    name: root
    48    namespace: projectcontour-roots
    49  spec:
    50    virtualhost:
    51      fqdn: local.projectcontour.io
    52    routes:
    53    - services:
    54      - name: rootapp
    55        port: 80
    56      conditions:
    57        - prefix: /
    58    - services:
    59      - name: secureapp-default
    60        port: 80
    61      conditions:
    62        - prefix: /secure
    63  ``` 
    64  
    65  This proxy configures any request to `projectcontour.io/` to be handled by the service `rootapp`. Requests to `/secure` will be handled by the service `secureapp-default`.
    66  
    67  At this point, the following requests map like this:
    68  
    69  - GET projectcontour.io/ → `rootapp:80` service
    70  - GET projectcontour.io/secure → `secureapp-default:80` service
    71  
    72  ### Sample Requests
    73  ```bash
    74  $ curl http://local.projectcontour.io/ 
    75  
    76  ECHO Request Server: 
    77  --------------------
    78  App: 
    79      This is the default app site!
    80  Request: 
    81      http://local.projectcontour.io/
    82  
    83  $ curl http://local.projectcontour.io/secure
    84  
    85  ECHO Request Server: 
    86  --------------------
    87  App: 
    88      This is the secure app site!
    89  Request: 
    90      http://local.projectcontour.io/secure
    91  ```
    92  ## Conditions
    93  New in `HTTPProxy` is a concept called `conditions`, which allows you to define a set of request parameters that need to match for a route to receive requests. Contour allows for a `prefix` condition as well as a set of `header` conditions to be defined on requests. 
    94  
    95  Let’s reconfigure the `root` proxy to handle requests with HTTP headers. We will target any request to `local.projectcontour.io/secure` that matches the header `User-Agent` containing the value of `Chrome` to route to the `secureapp` backend. Any other requests to `local.projectcontour.io/secure` that do not match the header we defined should route to `secureapp-default`.
    96  
    97  In the previous example, we added `prefix` conditions to the route. In this example, we add a new type called `header`, which allows us to define a header key and value that must match the request. Header conditions can use `exact` to match  the value exactly, or  they can use `contains` to match  a specified value that exists somewhere in the header value. (We can also specify `notexact` and `notcontains`, which inverse the match.) 
    98  
    99  ```bash
   100  $ kubectl apply -f https://projectcontour.io/examples/proxydemo/03-proxy-conditions.yaml
   101  
   102  apiVersion: projectcontour.io/v1
   103  kind: HTTPProxy
   104  metadata:
   105    name: root
   106    namespace: projectcontour-roots
   107  spec:
   108    virtualhost:
   109      fqdn: local.projectcontour.io
   110    routes:
   111      - services:
   112          - name: rootapp
   113            port: 80
   114        conditions:
   115          - prefix: /
   116      - services:
   117          - name: secureapp-default
   118            port: 80
   119        conditions:
   120          - prefix: /secure
   121      - services:
   122          - name: secureapp
   123            port: 80
   124        conditions:
   125          - prefix: /secure
   126          - header:
   127              name: User-Agent
   128              contains: Chrome
   129  ```
   130  
   131  It’s important to call out that for a request to match a route, all `conditions` defined must match. In the example we just applied, for the request to route to the `secreapp` service, it must have a path prefix of `/secure` as well as have a header `User-Agent` containing the value `Chrome`. Adding additional header conditions would extend the match requirements for that route. 
   132  
   133  At this point the following requests map as follows:
   134  
   135  - GET local.projectcontour.io/ → `rootapp:80` service
   136  - GET local.projectcontour.io/secure → `secureapp-default:80` service
   137  - GET local.projectcontour.io/secure + Header[User-Agent: Chrome] → `secureapp:80` service
   138  
   139  ### Sample Requests
   140  ```
   141  $ curl http://local.projectcontour.io/secure                                                                                                
   142  
   143  ECHO Request Server: 
   144  --------------------
   145  App: 
   146      This is the DEFAULT secure app site!
   147  Request: 
   148      http://local.projectcontour.io/secure
   149  
   150  $ curl -H "User-Agent: Chrome" http://local.projectcontour.io/secure                                                                           
   151  
   152  ECHO Request Server: 
   153  --------------------
   154  App: 
   155      This is the secure app site!
   156  Request: 
   157      http://local.projectcontour.io/secure
   158  ```
   159  
   160  ## Includes across Namespaces
   161  Also new in `HTTPProxy` is the concept of `includes` for a resource. Defining an `include` on an `HTTPProxy` causes Contour to prepend any `conditions` defined in the include to the conditions of the child proxy referenced. This can be used to delegate path prefixes to teams in different namespaces or require specific headers to be present on requests. There isn’t a limit to the number of times a proxy can reference an `include`.
   162  
   163  First, let’s set up a new marketing team namespace allowing them to self-manage its `HTTPProxy` resources as well as deploy a sample app/service. The marketing team will be in charge of managing the `/blog` path from the  `local.projectcontour.io` domain.
   164  
   165  ```bash
   166  $ kubectl apply -f https://projectcontour.io/examples/proxydemo/04-marketing-prereq.yaml 
   167  ```
   168  
   169  Next, let’s update our `root` proxy to pass off a path to the marketing team working in the `projectcontour-marketing` namespace. We’ll also create the marketing team’s `HTTPProxy`, which is referenced from the `root` HTTPProxy and will include the path condition of `/blog` to the marketing team’s proxy named `blogsite`.
   170  
   171  ```bash
   172  $ kubectl apply -f https://projectcontour.io/examples/proxydemo/04-proxy-include-basic.yaml
   173  
   174  apiVersion: projectcontour.io/v1
   175  kind: HTTPProxy
   176  metadata:
   177    name: root
   178    namespace: projectcontour-roots
   179  spec:
   180    virtualhost:
   181      fqdn: local.projectcontour.io
   182    includes:
   183      - name: blogsite
   184        namespace: projectcontour-marketing
   185        conditions:
   186          - prefix: /blog
   187    routes:
   188      - services:
   189          - name: rootapp
   190            port: 80
   191        conditions:
   192          - prefix: /
   193      - services:
   194          - name: secureapp-default
   195            port: 80
   196        conditions:
   197          - prefix: /secure
   198      - services:
   199          - name: secureapp
   200            port: 80
   201        conditions:
   202          - prefix: /secure
   203          - header:
   204              name: User-Agent
   205              contains: Chrome
   206  ---
   207  apiVersion: projectcontour.io/v1
   208  kind: HTTPProxy
   209  metadata:
   210    name: blogsite
   211    namespace: projectcontour-marketing
   212  spec:
   213    routes:
   214      - services:
   215          - name: wwwblog
   216            port: 80
   217  ```
   218  
   219  Since the `root` proxy included the path of `/blog`, requests that match `local.projectcontour.io/blog` will route to the marketing team’s service named `wwwblog` in the `projectcontour-marketing` namespace. You will notice we didn’t define any `conditions` on the marketing teams proxy. We don’t need to define them because the root proxy passed the path prefix condition to this HTTPProxy through the include. 
   220  
   221  It’s important to note that no one else in the cluster can now utilize this path prefix. If another team would create an HTTPProxy referencing the same path, Contour would reject it because it is not part of a delegation chain. 
   222  
   223  ### Sample Requests
   224  ```
   225  $ curl http://local.projectcontour.io/blog                                                                                                    
   226  
   227  ECHO Request Server: 
   228  --------------------
   229  App: 
   230      This is the blog site!
   231  Request: 
   232      http://local.projectcontour.io/blog
   233  ```
   234  
   235  ## Includes to the same Namespace
   236  Just as we learned in the first example of how conditions are applied to routes, the same logic is applied to conditions on an include. Currently, the marketing team is responsible for the path `/blog`, but let’s add a few more requirements. 
   237  
   238  The marketing team wants to create an `information` site, which will be served by the path `/blog/info`. We will create another HTTPProxy to define how the information application should be accessed. This new `HTTPProxy` will be included in the path `/info` from the `blogsite` `HTTPProxy` in the `projectcontour-marketing` namespace. 
   239  
   240  Since `Conditions` are appended to the `HTTPProxy` when Contour processes them, the result for the information site will have the path `/blog/info`.   
   241  
   242  ```bash
   243  $ kubectl apply -f https://projectcontour.io/examples/proxydemo/05-proxy-include-info.yaml
   244  
   245  apiVersion: projectcontour.io/v1
   246  kind: HTTPProxy
   247  metadata:
   248    name: blogsite
   249    namespace: projectcontour-marketing
   250  spec:
   251    includes:
   252      - name: infosite
   253        conditions:
   254        - prefix: /info
   255    routes:
   256      - services:
   257          - name: wwwblog
   258            port: 80
   259  ---
   260  apiVersion: projectcontour.io/v1
   261  kind: HTTPProxy
   262  metadata:
   263    name: infosite
   264    namespace: projectcontour-marketing
   265  spec:
   266    routes:
   267      - services:
   268          - name: info
   269            port: 80
   270  ```
   271  
   272  ### Sample Requests
   273  ```
   274  $ curl http://local.projectcontour.io/blog/info                                                                                               
   275  
   276  ECHO Request Server: 
   277  --------------------
   278  App: 
   279      This is the blog site!
   280  Request: 
   281      http://local.projectcontour.io/blog/info
   282  ```
   283  
   284  ## Includes with Headers
   285  Finally to complete our example, the administrative team now doesn’t want the marketing site to be served by Chrome or Firefox browsers. This rule needs to apply to all applications in the `projectcontour-marketing` namespace. 
   286  
   287  We can easily implement this requirement by just adding another set of conditions to the `root` HTTPProxy. Once we add those, they will take effect across all the children of the root HTTPProxy defined in the `projectcontour-marketing` namespace. 
   288  
   289  ```bash
   290  $ kubectl apply -f https://projectcontour.io/examples/proxydemo/06-proxy-include-headers.yaml
   291  
   292  apiVersion: projectcontour.io/v1
   293  kind: HTTPProxy
   294  metadata:
   295    name: root
   296    namespace: projectcontour-roots
   297  spec:
   298    virtualhost:
   299      fqdn: local.projectcontour.io
   300    includes:
   301      - name: blogsite
   302        namespace: projectcontour-marketing
   303        conditions:
   304          - prefix: /blog
   305          - header:
   306              name: User-Agent
   307              notcontains: Chrome
   308          - header:
   309              name: User-Agent
   310              notcontains: Firefox
   311    routes:
   312      - services:
   313          - name: rootapp
   314            port: 80
   315        conditions:
   316          - prefix: /
   317      - services:
   318          - name: secureapp-default
   319            port: 80
   320        conditions:
   321          - prefix: /secure
   322      - services:
   323          - name: secureapp
   324            port: 80
   325        conditions:
   326          - prefix: /secure
   327          - header:
   328              name: User-Agent
   329              contains: Chrome
   330  ```
   331  
   332  Requests to `local.projectcontour.io/blog/*` that do not match the `User-Agent` header of `Chrome` or `Firefox` will now route to the appropriate services in the marketing team’s namespace. Any other requests will be handled by the `rootapp` service because it matches the other requests. 
   333  
   334  ### Sample Requests
   335  ```bash
   336  $ curl -H "User-Agent: Safari" http://local.projectcontour.io/blog/info                                                                       
   337  
   338  ECHO Request Server: 
   339  --------------------
   340  App: 
   341      This is the INFO site!
   342  Request: 
   343      http://local.projectcontour.io/blog/info
   344  
   345  $ curl -H "User-Agent: Firefox" http://local.projectcontour.io/blog/info                                                                      
   346  
   347  ECHO Request Server: 
   348  --------------------
   349  App: 
   350      This is the default app site!
   351  Request: 
   352      http://local.projectcontour.io/blog/info
   353  ```
   354  
   355  [1]: {% post_url 2019-09-27-from-ingressroute-to-httpproxy %}
   356  [2]: {% link img/posts/kind-contour-video.png %}
   357  [3]: https://youtu.be/YA82A4Rcs_A
   358  [4]: {% post_url 2019-07-11-kindly-running-contour %}