<a id="i-mergeable-ingress"></a>

# Объединяемые типы Ingress-ресурсов

Вы можете распространить конфигурацию Ingress на несколько ресурсов Ingress на одном хосте,
используя аннотацию `angie.software/mergeable-ingress-type`.
Ресурсы могут находиться в одном или в разных пространствах имен,
что упрощает управление при большом количестве путей.

## Синтаксис и правила

### Ресурс Master Ingress

Ресурс Master Ingress задается с помощью аннотации `angie.software/mergeable-ingress-type: master`.
Master будет обрабатывать все конфигурации на уровне хоста, включая TLS-настройки и аннотации,
применяемые ко всему хосту. У одного хоста может быть только один Ingress-ресурс типа Master.
В ресурсе Master нельзя указывать пути. У одного Master-ресурса может быть
несколько ресурсов Minion, при условии, что их пути не конфликтуют.
При конфликте будет выбран путь, который задан в самом старом ресурсе Minion.

Ресурс Master не может содержать следующие аннотации:

- `angie.software/rewrites`
- `angie.software/ssl-services`
- `angie.software/grpc-services`
- `angie.software/websocket-services`
- `angie.software/sticky-cookie-services`
- `angie.software/health-checks`
- `angie.software/health-checks-mandatory`
- `angie.software/health-checks-mandatory-queue`

### Ресурс Minion Ingress

Ресурс Minion Ingress задается с помощью аннотации `angie.software/mergeable-ingress-type: minion`.
Ресурс Minion добавляет разные пути к Ingress-ресурсу типа Master.
В Minion Ingress нельзя задать TLS-настройки.

Ресурс Minion не может содержать следующие аннотации:

- `angie.software/proxy-hide-headers`
- `angie.software/proxy-pass-headers`
- `angie.software/redirect-to-https`
- `ingress.kubernetes.io/ssl-redirect`
- `angie.software/hsts`
- `angie.software/hsts-max-age`
- `angie.software/hsts-include-subdomains`
- `angie.software/server-tokens`
- `angie.software/listen-ports`
- `angie.software/listen-ports-ssl`
- `angie.software/server-snippets`

Ресурс Minion наследует следующие аннотации от Master-ресурса, если они в нем не переопределены:

- `angie.software/proxy-connect-timeout`
- `angie.software/proxy-read-timeout`
- `angie.software/client-max-body-size`
- `angie.software/proxy-buffering`
- `angie.software/proxy-buffers`
- `angie.software/proxy-buffer-size`
- `angie.software/proxy-max-temp-file-size`
- `angie.software/location-snippets`
- `angie.software/lb-method`
- `angie.software/keepalive`
- `angie.software/max-fails`
- `angie.software/fail-timeout`

#### NOTE
Нельзя использовать ресурсы Ingress, у которых больше одного хоста.

## Пример

В этом примере разворачивается ANIC и простое веб-приложение, а также создаются ресурсы
Master и Minion для настройки балансировщика нагрузки с помощью аннотации `angie.software/mergeable-ingress-type`.

1. Установите ANIC.
2. Сохраните публичный IP-адрес ANIC в переменной оболочки:
   ```console
   $ IC_IP=<ваш_IP-адрес>
   ```
3. Сохраните HTTP-порт ANIC в переменную оболочки:
   ```console
   $ IC_HTTP_PORT=<номер_порта>
   ```
4. Создайте Deployment и Service приложения Cafe для компонентов `coffee` и `tea`:

   ### Пример

   ```yaml
   apiVersion: apps/v1
   kind: Deployment
   metadata:
     name: coffee
   spec:
     replicas: 2
     selector:
       matchLabels:
         app: coffee
     template:
       metadata:
         labels:
           app: coffee
       spec:
         containers:
         - name: coffee
           image: angiesoftware/angie-hello:plain-text
           ports:
           - containerPort: 8080
   ---
   apiVersion: v1
   kind: Service
   metadata:
     name: coffee-svc
   spec:
     ports:
     - port: 80
       targetPort: 8080
       protocol: TCP
       name: http
     selector:
       app: coffee
   ---
   apiVersion: apps/v1
   kind: Deployment
   metadata:
     name: tea
   spec:
     replicas: 3
     selector:
       matchLabels:
         app: tea
     template:
       metadata:
         labels:
           app: tea
       spec:
         containers:
         - name: tea
           image: angiesoftware/angie-hello:plain-text
           ports:
           - containerPort: 8080
   ---
   apiVersion: v1
   kind: Service
   metadata:
     name: tea-svc
     labels:
   spec:
     ports:
     - port: 80
       targetPort: 8080
       protocol: TCP
       name: http
     selector:
       app: tea
   ```

   Примените настройки:
   ```console
   $ kubectl create -f cafe.yaml
   ```
5. Создайте секрет с SSL-сертификатом:

   ### Пример

   ```yaml
   apiVersion: v1
   kind: Secret
   metadata:
     name: cafe-secret
   type: kubernetes.io/tls
   data:
     tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURMakNDQWhZQ0NRREFPRjl0THNhWFdqQU5CZ2txaGtpRzl3MEJBUXNGQURCYU1Rc3dDUVlEVlFRR0V3SlYKVXpFTE1Ba0dBMVVFQ0F3Q1EwRXhJVEFmQmdOVkJBb01HRWx1ZEdWeWJtVjBJRmRwWkdkcGRITWdVSFI1SUV4MApaREViTUJrR0ExVUVBd3dTWTJGbVpTNWxlR0Z0Y0d4bExtTnZiU0FnTUI0WERURTRNRGt4TWpFMk1UVXpOVm9YCkRUSXpNRGt4TVRFMk1UVXpOVm93V0RFTE1Ba0dBMVVFQmhNQ1ZWTXhDekFKQmdOVkJBZ01Ba05CTVNFd0h3WUQKVlFRS0RCaEpiblJsY201bGRDQlhhV1JuYVhSeklGQjBlU0JNZEdReEdUQVhCZ05WQkFNTUVHTmhabVV1WlhoaApiWEJzWlM1amIyMHdnZ0VpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElCRHdBd2dnRUtBb0lCQVFDcDZLbjdzeTgxCnAwanVKL2N5ayt2Q0FtbHNmanRGTTJtdVpOSzBLdGVjcUcyZmpXUWI1NXhRMVlGQTJYT1N3SEFZdlNkd0kyaloKcnVXOHFYWENMMnJiNENaQ0Z4d3BWRUNyY3hkam0zdGVWaVJYVnNZSW1tSkhQUFN5UWdwaW9iczl4N0RsTGM2SQpCQTBaalVPeWwwUHFHOVNKZXhNVjczV0lJYTVyRFZTRjJyNGtTa2JBajREY2o3TFhlRmxWWEgySTVYd1hDcHRDCm42N0pDZzQyZitrOHdnemNSVnA4WFprWldaVmp3cTlSVUtEWG1GQjJZeU4xWEVXZFowZXdSdUtZVUpsc202OTIKc2tPcktRajB2a29QbjQxRUUvK1RhVkVwcUxUUm9VWTNyemc3RGtkemZkQml6Rk8yZHNQTkZ4MkNXMGpYa05MdgpLbzI1Q1pyT2hYQUhBZ01CQUFFd0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFLSEZDY3lPalp2b0hzd1VCTWRMClJkSEliMzgzcFdGeW5acS9MdVVvdnNWQTU4QjBDZzdCRWZ5NXZXVlZycTVSSWt2NGxaODFOMjl4MjFkMUpINnIKalNuUXgrRFhDTy9USkVWNWxTQ1VwSUd6RVVZYVVQZ1J5anNNL05VZENKOHVIVmhaSitTNkZBK0NuT0Q5cm4yaQpaQmVQQ0k1ckh3RVh3bm5sOHl3aWozdnZRNXpISXV5QmdsV3IvUXl1aTlmalBwd1dVdlVtNG52NVNNRzl6Q1Y3ClBwdXd2dWF0cWpPMTIwOEJqZkUvY1pISWc4SHc5bXZXOXg5QytJUU1JTURFN2IvZzZPY0s3TEdUTHdsRnh2QTgKN1dqRWVxdW5heUlwaE1oS1JYVmYxTjM0OWVOOThFejM4Zk9USFRQYmRKakZBL1BjQytHeW1lK2lHdDVPUWRGaAp5UkU9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
     tls.key: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFb3dJQkFBS0NBUUVBcWVpcCs3TXZOYWRJN2lmM01wUHJ3Z0pwYkg0N1JUTnBybVRTdENyWG5LaHRuNDFrCkcrZWNVTldCUU5semtzQndHTDBuY0NObzJhN2x2S2wxd2k5cTIrQW1RaGNjS1ZSQXEzTVhZNXQ3WGxZa1YxYkcKQ0pwaVJ6ejBza0lLWXFHN1BjZXc1UzNPaUFRTkdZMURzcGRENmh2VWlYc1RGZTkxaUNHdWF3MVVoZHErSkVwRwp3SStBM0kreTEzaFpWVng5aU9WOEZ3cWJRcCt1eVFvT05uL3BQTUlNM0VWYWZGMlpHVm1WWThLdlVWQ2cxNWhRCmRtTWpkVnhGbldkSHNFYmltRkNaYkp1dmRySkRxeWtJOUw1S0Q1K05SQlAvazJsUkthaTAwYUZHTjY4NE93NUgKYzMzUVlzeFR0bmJEelJjZGdsdEkxNURTN3lxTnVRbWF6b1Z3QndJREFRQUJBb0lCQVFDUFNkU1luUXRTUHlxbApGZlZGcFRPc29PWVJoZjhzSStpYkZ4SU91UmF1V2VoaEp4ZG01Uk9ScEF6bUNMeUw1VmhqdEptZTIyM2dMcncyCk45OUVqVUtiL1ZPbVp1RHNCYzZvQ0Y2UU5SNThkejhjbk9SVGV3Y290c0pSMXBuMWhobG5SNUhxSkpCSmFzazEKWkVuVVFmY1hackw5NGxvOUpIM0UrVXFqbzFGRnM4eHhFOHdvUEJxalpzVjdwUlVaZ0MzTGh4bndMU0V4eUZvNApjeGI5U09HNU9tQUpvelN0Rm9RMkdKT2VzOHJKNXFmZHZ5dGdnOXhiTGFRTC94MGtwUTYyQm9GTUJEZHFPZVBXCktmUDV6WjYvMDcvdnBqNDh5QTFRMzJQem9idWJzQkxkM0tjbjMyamZtMUU3cHJ0V2wrSmVPRmlPem5CUUZKYk4KNHFQVlJ6NWhBb0dCQU50V3l4aE5DU0x1NFArWGdLeWNrbGpKNkY1NjY4Zk5qNUN6Z0ZScUowOXpuMFRsc05ybwpGVExaY3hEcW5SM0hQWU00MkpFUmgySi9xREZaeW5SUW8zY2czb2VpdlVkQlZHWTgrRkkxVzBxZHViL0w5K3l1CmVkT1pUUTVYbUdHcDZyNmpleHltY0ppbS9Pc0IzWm5ZT3BPcmxEN1NQbUJ2ek5MazRNRjZneGJYQW9HQkFNWk8KMHA2SGJCbWNQMHRqRlhmY0tFNzdJbUxtMHNBRzR1SG9VeDBlUGovMnFyblRuT0JCTkU0TXZnRHVUSnp5K2NhVQprOFJxbWRIQ2JIelRlNmZ6WXEvOWl0OHNaNzdLVk4xcWtiSWN1YytSVHhBOW5OaDFUanNSbmU3NFowajFGQ0xrCmhIY3FIMHJpN1BZU0tIVEU4RnZGQ3haWWRidUI4NENtWmlodnhicFJBb0dBSWJqcWFNWVBUWXVrbENkYTVTNzkKWVNGSjFKelplMUtqYS8vdER3MXpGY2dWQ0thMzFqQXdjaXowZi9sU1JxM0hTMUdHR21lemhQVlRpcUxmZVpxYwpSMGlLYmhnYk9jVlZrSkozSzB5QXlLd1BUdW14S0haNnpJbVpTMGMwYW0rUlk5WUdxNVQ3WXJ6cHpjZnZwaU9VCmZmZTNSeUZUN2NmQ21mb09oREN0enVrQ2dZQjMwb0xDMVJMRk9ycW40M3ZDUzUxemM1em9ZNDR1QnpzcHd3WU4KVHd2UC9FeFdNZjNWSnJEakJDSCtULzZzeXNlUGJKRUltbHpNK0l3eXRGcEFOZmlJWEV0LzQ4WGY2ME54OGdXTQp1SHl4Wlp4L05LdER3MFY4dlgxUE9ucTJBNWVpS2ErOGpSQVJZS0pMWU5kZkR1d29seHZHNmJaaGtQaS80RXRUCjNZMThzUUtCZ0h0S2JrKzdsTkpWZXN3WEU1Y1VHNkVEVXNEZS8yVWE3ZlhwN0ZjanFCRW9hcDFMU3crNlRYcDAKWmdybUtFOEFSek00NytFSkhVdmlpcS9udXBFMTVnMGtKVzNzeWhwVTl6WkxPN2x0QjBLSWtPOVpSY21Vam84UQpjcExsSE1BcWJMSjhXWUdKQ2toaVd4eWFsNmhZVHlXWTRjVmtDMHh0VGwvaFVFOUllTktvCi0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg==
   ```

   Примените настройки:
   ```console
   $ kubectl create -f cafe-secret.yaml
   ```
6. Создайте Master-ресурс Ingress:

   ### Пример

   ```yaml
   apiVersion: networking.k8s.io/v1
   kind: Ingress
   metadata:
     name: cafe-ingress-master
     annotations:
       angie.software/mergeable-ingress-type: "master"
   spec:
     ingressClassName: angie
     tls:
     - hosts:
       - cafe.example.com
       secretName: cafe-secret
     rules:
     - host: cafe.example.com
   ```

   Примените настройки:
   ```console
   $ kubectl create -f cafe-master.yaml
   ```
7. Создайте Minion-ресурсы Ingress:

   ### Пример coffee-minion

   ```yaml
   apiVersion: networking.k8s.io/v1
   kind: Ingress
   metadata:
     name: cafe-ingress-coffee-minion
     annotations:
       angie.software/mergeable-ingress-type: "minion"
   spec:
     ingressClassName: angie
     rules:
     - host: cafe.example.com
       http:
         paths:
         - path: /coffee
           pathType: Prefix
           backend:
             service:
               name: coffee-svc
               port:
                 number: 80
   ```

   ### Пример tea-minion

   ```yaml
   apiVersion: networking.k8s.io/v1
   kind: Ingress
   metadata:
     name: cafe-ingress-tea-minion
     annotations:
       angie.software/mergeable-ingress-type: "minion"
   spec:
     ingressClassName: angie
     rules:
     - host: cafe.example.com
       http:
         paths:
         - path: /tea
           pathType: Prefix
           backend:
             service:
               name: tea-svc
               port:
                 number: 80
   ```

   Примените настройки:
   ```console
   $ kubectl create -f coffee-minion.yaml
   $ kubectl create -f tea-minion.yaml
   ```
8. Протестируйте конфигурацию.

   Чтобы получить `coffee`:
   ```console
   $ curl --resolve cafe.example.com:$IC_HTTPS_PORT:$IC_IP https://cafe.example.com:$IC_HTTPS_PORT/coffee --insecure
   Server address: 10.12.0.18:80
   Server name: coffee-7586895968-r26zn
   ```

   Чтобы получить `tea`:
   ```console
   $ curl --resolve cafe.example.com:$IC_HTTPS_PORT:$IC_IP https://cafe.example.com:$IC_HTTPS_PORT/tea --insecure
   Server address: 10.12.0.19:80
   Server name: tea-7cd44fcb4d-xfw2x
   ```
9. Просмотрите сгенерированную конфигурацию.

   Для этого получите имя пода Ingress:
   ```console
   $ kubectl get pods -n angie-ingress
   NAME                             READY     STATUS    RESTARTS   AGE
   angie-ingress-66bc44674b-hrcx8   1/1       Running   0          4m
   ```

   Посмотрите сгенерированную конфигурацию:
   ```console
   $ kubectl exec -it angie-ingress-66bc44674b-hrcx8 -n angie-ingress -- cat /etc/angie/conf.d/default-cafe-ingress-master.conf
   ```

   Пример содержимого:
   ```nginx
   upstream default-cafe-ingress-coffee-minion-cafe.example.com-coffee-svc {
       server 172.17.0.5:80;
       server 172.17.0.6:80;
   }
   upstream default-cafe-ingress-tea-minion-cafe.example.com-tea-svc {
       server 172.17.0.7:80;
       server 172.17.0.8:80;
       server 172.17.0.9:80;
   }

   server {
       listen 80;
       listen 443 ssl;
       ssl_certificate /etc/angie/secrets/default-cafe-secret;
       ssl_certificate_key /etc/angie/secrets/default-cafe-secret;
       server_tokens on;
       server_name cafe.example.com;

       if ($scheme = http) {
           return 301 https://$host:443$request_uri;
       }

       location /coffee {
           proxy_http_version 1.1;
           proxy_connect_timeout 60s;
           proxy_read_timeout 60s;
           client_max_body_size 1m;
           proxy_set_header Host $host;
           proxy_set_header X-Real-IP $remote_addr;
           proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
           proxy_set_header X-Forwarded-Host $host;
           proxy_set_header X-Forwarded-Port $server_port;
           proxy_set_header X-Forwarded-Proto $scheme;
           proxy_buffering on;
           proxy_pass http://default-cafe-ingress-coffee-minion-cafe.example.com-coffee-svc;
       }

       location /tea {
           proxy_http_version 1.1;
           proxy_connect_timeout 60s;
           proxy_read_timeout 60s;
           client_max_body_size 1m;
           proxy_set_header Host $host;
           proxy_set_header X-Real-IP $remote_addr;
           proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
           proxy_set_header X-Forwarded-Host $host;
           proxy_set_header X-Forwarded-Port $server_port;
           proxy_set_header X-Forwarded-Proto $scheme;
           proxy_buffering on;
           proxy_pass http://default-cafe-ingress-tea-minion-cafe.example.com-tea-svc;
       }
   }
   ```
