[Yandex Cloud documentation](../../index.md) > [Tutorials](../index.md) > [Container infrastructure](index.md) > Managed Service for Kubernetes > Using Cloud Marketplace products > Setting up the Gateway API

# Setting up the Gateway API in Yandex Managed Service for Kubernetes

[Gateway API](https://github.com/kubernetes-sigs/gateway-api) is a collection of API resources that model networking in a [Kubernetes cluster](../../managed-kubernetes/concepts/index.md#kubernetes-cluster).

In this tutorial, you will learn how to set up access to the applications deployed in two test environments, `dev` and `prod`, using [Yandex Application Load Balancer](../../application-load-balancer/index.md) via the Gateway API. For this, you will need to create a [public domain zone](../../dns/concepts/dns-zone.md#public-zones) and delegate the domain to [Yandex Cloud DNS](../../dns/index.md).

To integrate the Gateway API and Application Load Balancer:
1. [Create Managed Service for Kubernetes resources](#k8s-create).
1. [Install the Gateway API and set up domain zones](#install-gateway-api).
1. [Prepare test applications](#prepare-apps).
1. [Create test applications](#install-apps).
1. [Test the Gateway API](#check-apps).

If you no longer need the resources you created, [delete them](#clear-out).


## Required paid resources {#paid-resources}

The support cost for this solution includes:

* Fee for a DNS zone and DNS requests (see [Cloud DNS pricing](../../dns/pricing.md)).
* Fee for using the master and outgoing traffic in a Managed Service for Kubernetes cluster (see [Managed Service for Kubernetes pricing](../../managed-kubernetes/pricing.md)).
* Fee for using computing resources, OS, and storage in cluster nodes (VMs) (see [Compute Cloud pricing](../../compute/pricing.md)).
* Fee for using L7 load balancer's computing resources (see [Application Load Balancer pricing](../../application-load-balancer/pricing.md)).
* Fee for public IP addresses (see [Virtual Private Cloud pricing](../../vpc/pricing.md#prices-public-ip)).


## Getting started {#before-you-begin}

1. If you do not have the Yandex Cloud CLI yet, [install and initialize it](../../cli/quickstart.md#install).

   The folder used by default is the one specified when [creating](../../cli/operations/profile/profile-create.md) the CLI profile. To change the default folder, use the `yc config set folder-id <folder_ID>` command. You can also specify a different folder for any command using `--folder-name` or `--folder-id`. If you access a resource by its name, the search will be limited to the default folder. If you access a resource by its ID, the search will be global, i.e., through all folders based on access permissions.

1. [Register a public domain zone and delegate your domain](../../dns/operations/zone-create-public.md).

## Create Managed Service for Kubernetes resources {#k8s-create}

1. Create a Kubernetes cluster and [node group](../../managed-kubernetes/concepts/index.md#node-group).

   {% list tabs group=instructions %}

   - Manually {#manual}

     1. If you do not have a [network](../../vpc/concepts/network.md#network) yet, [create one](../../vpc/operations/network-create.md).
     1. If you do not have any [subnets](../../vpc/concepts/network.md#subnet) yet, [create them](../../vpc/operations/subnet-create.md) in the [availability zones](../../overview/concepts/geo-scope.md) where the new Kubernetes cluster and node group will reside.

     1. [Create security groups](../../managed-kubernetes/operations/connect/security-groups.md) for the Managed Service for Kubernetes cluster and its node groups.

        {% note warning %}
        
        The configuration of security groups determines performance and availability of the cluster and the services and applications running in it.
        
        {% endnote %}

     1. [Create a Kubernetes cluster](../../managed-kubernetes/operations/kubernetes-cluster/kubernetes-cluster-create.md) and [node group](../../managed-kubernetes/operations/node-group/node-group-create.md) with any suitable configuration. When creating, specify the preconfigured security groups.

   - Terraform {#tf}

     1. If you do not have Terraform yet, [install it](../infrastructure-management/terraform-quickstart.md#install-terraform).
     1. [Get the authentication credentials](../infrastructure-management/terraform-quickstart.md#get-credentials). You can add them to environment variables or specify them later in the provider configuration file.
     1. [Configure and initialize a provider](../infrastructure-management/terraform-quickstart.md#configure-provider). There is no need to create a provider configuration file manually, you can [download it](https://github.com/yandex-cloud-examples/yc-terraform-provider-settings/blob/main/provider.tf).
     1. Place the configuration file in a separate working directory and [specify the parameter values](../infrastructure-management/terraform-quickstart.md#configure-provider). If you did not add the authentication credentials to environment variables, specify them in the configuration file.

     1. Download the [k8s-gateway-api.tf](https://github.com/yandex-cloud-examples/yc-mk8s-gateway-api/blob/main/k8s-gateway-api.tf) cluster configuration file to the same working directory. This file describes:
        * Network.
        * Subnet.
        * Kubernetes cluster.
        * Service account for the Kubernetes cluster and node group.
        * [Security groups](../../vpc/concepts/security-groups.md) which contain [rules](../../managed-kubernetes/operations/connect/security-groups.md) required for the Managed Service for Kubernetes cluster and its node groups.

            {% note warning %}
            
            The configuration of security groups determines performance and availability of the cluster and the services and applications running in it.
            
            {% endnote %}

     1. Specify the following in the configuration file:
        * [Folder ID](../../resource-manager/operations/folder/get-id.md).
        * Kubernetes version for the Kubernetes cluster and node groups.
        * Kubernetes cluster CIDR.
     1. Validate your Terraform configuration files using this command:

        ```bash
        terraform validate
        ```

        Terraform will display any configuration errors detected in your files.
     1. Create the required infrastructure:

        1. Run this command to view the planned changes:
        
           ```bash
           terraform plan
           ```
        
           If you described the configuration correctly, the terminal will display a list of the resources to update and their parameters. This is a verification step that does not apply changes to your resources.
        
        1. If everything looks correct, apply the changes:
           1. Run this command:
        
              ```bash
              terraform apply
              ```
        
           1. Confirm updating the resources.
           1. Wait for the operation to complete.

        All the required resources will be created in the specified folder. You can check resource availability and their settings in the [management console](https://console.yandex.cloud).

   {% endlist %}

   {% note warning %}
   
   Do not change or delete Virtual Private Cloud resources used by the Managed Service for Kubernetes cluster. This may cause cluster errors or make it impossible to delete later.
   
   {% endnote %}

1. [Install kubect](https://kubernetes.io/docs/tasks/tools/install-kubectl) and [configure it to work with the new cluster](../../managed-kubernetes/operations/connect/index.md#kubectl-connect).

1. [Create a service account](../../iam/operations/sa/create.md) for Gateway API.
1. [Assign it the following roles](../../iam/operations/sa/assign-role-for-sa.md):
   * `alb.editor`: To create the required resources.
   * `certificate-manager.admin`: To use certificates registered in [Yandex Certificate Manager](../../certificate-manager/index.md).
   * `compute.viewer`: To use Managed Service for Kubernetes cluster nodes in the [load balancer](../../application-load-balancer/concepts/application-load-balancer.md) [target groups](../../application-load-balancer/concepts/target-group.md).
   * `vpc.publicAdmin`: To manage [external connectivity](../../vpc/security/index.md#vpc-public-admin).
1. Create a [static key](../../iam/operations/authentication/manage-access-keys.md#create-access-key) and save it to a file named `sa-key.json`:

   ```bash
   yc iam key create \
     --service-account-name <name_of_service_account_for_Gateway_API> \
     --output sa-key.json
   ```

## Install the Gateway API and set up domain zones {#install-gateway-api}

1. Install the [Gateway API](https://yandex.cloud/en/marketplace/products/yc/gateway-api) by following [this guide](../../managed-kubernetes/operations/applications/gateway-api.md). During the installation, use the service account key you [created earlier](#k8s-create).
1. Reserve [public IP addresses](../../vpc/concepts/address.md#public-addresses) for the `prod` and `dev` test environments:

   ```bash
   yc vpc address create \
     --name=prod \
     --labels reserved=true \
     --external-ipv4 \
     zone=<availability_zone> && \
   yc vpc address create \
     --name=dev \
     --labels reserved=true \
     --external-ipv4 \
     zone=<availability_zone>
   ```

   Where `<availability_zone>` is the [availability zone](../../overview/concepts/geo-scope.md) hosting your Kubernetes cluster.

   Save the public IP addresses, as you will need them in the next configuration steps.
1. Add [resource records](../../dns/concepts/resource-record.md) for your public DNS zone:

   ```bash
   yc dns zone add-records \
     --name <DNS_zone_name> \
     --record '*.prod 60 A <prod_environment_IP_address>' && \
   yc dns zone add-records \
     --name <DNS_zone_name> \
     --record '*.dev 60 A <dev_environment_IP_address>'
   ```

   >Example of a valid command:
   >
   >```bash
   >yc dns zone add-records \
   >  --name my-domain-name \
   >  --record '*.dev 60 A 171.154.241.41'
   >```

1. Create a [namespace](../../managed-kubernetes/concepts/index.md#namespace) for TLS secrets:

   ```bash
   kubectl create namespace gateway-api-tls-secrets
   ```

1. Create OpenSSL certificates:

   ```bash
   openssl req -x509 \
     -newkey rsa:4096 \
     -keyout gateway-key-prod.pem \
     -out gateway-cert-prod.pem \
     -nodes \
     -days 365 \
     -subj '/CN=*.prod.<domain_zone>' && \
   openssl req -x509 \
      -newkey rsa:4096 \
      -keyout gateway-key-dev.pem \
      -out gateway-cert-dev.pem \
      -nodes \
      -days 365 \
      -subj '/CN=*.dev.<domain_zone>'
   ```

   >Example of a valid command:
   >
   >```bash
   >openssl req -x509 \
   >  -newkey rsa:4096 \
   >  -keyout gateway-key-prod.pem \
   >  -out gateway-cert-prod.pem \
   >  -nodes \
   >  -days 365 \
   >  -subj '/CN=*.prod.my-test-domain.com'
   >```

   These certificates will be used to create secrets for the `prod` and `dev` test environments in the Kubernetes cluster.

1. Create the secrets:

   ```bash
   kubectl create -n gateway-api-tls-secrets secret tls gateway-prod-tls \
     --cert=gateway-cert-prod.pem \
     --key=gateway-key-prod.pem && \
   kubectl create -n gateway-api-tls-secrets secret tls gateway-dev-tls \
     --cert=gateway-cert-dev.pem \
     --key=gateway-key-dev.pem
   ```

## Prepare test applications {#prepare-apps}

To test the Gateway API, we will build two applications, `tutum/hello-world` and `nginxdemos/hello`. For each application, you will need to configure and run three YAML files:
* `dev-gw.yaml` and `prod-gw.yaml` with Gateway settings. In these manifests, specify:
  * [Security groups](../../managed-kubernetes/operations/connect/security-groups.md) associated with your Kubernetes cluster in the `metadata.annotations.gateway.alb.yc.io/security-groups` parameter.
  * Domain zone with the `*.dev` and `*.prod` prefixes in the `hostname` parameters.
  * IP addresses for the `dev` and `prod` environments in the `spec.addresses.value` parameter.
* `dev-route.yaml` and `prod-route.yaml` to configure routing for the applications. In these manifests, you need to specify the domain zone with the `app.dev` and `app.prod` prefixes in the `spec.hostnames` parameter.
* `dev-app.yaml` and `prod-app.yaml` with the applications’ settings. These manifests will be used to create:
  * Namespace (unique for each application)
  * [Deployment](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/) for the application
  * [Service](../../managed-kubernetes/concepts/index.md#service)

### Configure the app for the dev environment {#configure-dev}

1. Create `dev-gw.yaml`:

   {% cut "dev-gw.yaml" %}

   ```yaml
   ---
   apiVersion: gateway.networking.k8s.io/v1
   kind: Gateway
   metadata:
     name: gateway-api-dev
     annotations:
       gateway.alb.yc.io/security-groups: <cluster_security_group_IDs>
   spec:
     gatewayClassName: yc-df-class
     listeners:
     - name: gateway-api-dev
       protocol: HTTP
       port: 80
       hostname: "*.dev.<domain_zone>"
       allowedRoutes:
         namespaces:
           from: Selector
           selector:
             matchExpressions:
             - key: kubernetes.io/metadata.name
               operator: In
               values:
               - dev-app
     - name: gateway-api-dev-tls
       protocol: HTTPS
       port: 443
       hostname: "*.dev.<domain_zone>"
       allowedRoutes:
         namespaces:
           from: Selector
           selector:
             matchExpressions:
             - key: kubernetes.io/metadata.name
               operator: In
               values:
               - dev-app
       tls:
         certificateRefs:
         - group: ""
           kind: Secret
           name: gateway-dev-tls
           namespace: gateway-api-tls-secrets
         mode: Terminate
     addresses:
      - type: IPAddress
        value: "<dev_environment_IP_address>"
   ```

   {% endcut %}

1. Create `dev-route.yaml`:

   {% cut "dev-route.yaml" %}

   ```yaml
   ---
   apiVersion: gateway.networking.k8s.io/v1
   kind: HTTPRoute
   metadata:
     name: dev-app-http-route
     namespace: dev-app
   spec:
     hostnames:
     - "app.dev.<domain_zone>"
     parentRefs:
     - name: gateway-api-dev
       namespace: default
     rules:
     - matches:
       - path:
           value: /
       backendRefs:
       - name: app
         port: 80
   ```

   {% endcut %}

1. Create `dev-app.yaml`:

   {% cut "dev-app.yaml" %}

   ```yaml
   ---
   apiVersion: v1
   kind: Namespace
   metadata:
     name: dev-app
   ---
   apiVersion: apps/v1
   kind: Deployment
   metadata:
     name: app
     namespace: dev-app
   spec:
     selector:
       matchLabels:
         app: app
     template:
       metadata:
         labels:
           app: app
       spec:
         containers:
         - name: app
           image: tutum/hello-world
           resources:
             limits:
               memory: "128Mi"
               cpu: "500m"
           ports:
           - containerPort: 80
   ---
   apiVersion: v1
   kind: Service
   metadata:
     name: app
     namespace: dev-app
   spec:
     type: NodePort
     selector:
       app: app
     ports:
     - port: 80
       targetPort: 80
   ```

   {% endcut %}

### Configure the app for the prod environment {#configure-prod}

1. Create `prod-gw.yaml`:

   {% cut "prod-gw.yaml" %}

   ```yaml
   ---
   apiVersion: gateway.networking.k8s.io/v1
   kind: Gateway
   metadata:
     name: gateway-api-prod
     annotations:
       gateway.alb.yc.io/security-groups: <cluster_security_group_IDs>
   spec:
     gatewayClassName: yc-df-class
     listeners:
     - name: gateway-api-prod
       protocol: HTTP
       port: 80
       hostname: "*.prod.<domain_zone>"
       allowedRoutes:
         namespaces:
           from: Selector
           selector:
             matchExpressions:
             - key: kubernetes.io/metadata.name
               operator: In
               values:
               - prod-app
     - name: gateway-api-prod-tls
       protocol: HTTPS
       port: 443
       hostname: "*.prod.<domain_zone>"
       allowedRoutes:
         namespaces:
           from: Selector
           selector:
             matchExpressions:
             - key: kubernetes.io/metadata.name
               operator: In
               values:
               - prod-app
       tls:
         certificateRefs:
         - group: ""
           kind: Secret
           name: gateway-prod-tls
           namespace: gateway-api-tls-secrets
         mode: Terminate
     addresses:
       - type: IPAddress
         value: "<prod_environment_IP_address>"
   ```

   {% endcut %}

1. Create `prod-route.yaml`:

   {% cut "prod-route.yaml" %}

   ```yaml
   ---
   apiVersion: gateway.networking.k8s.io/v1
   kind: HTTPRoute
   metadata:
     name: prod-app-http-route
     namespace: prod-app
   spec:
     hostnames:
     - "app.prod.<domain_zone>"
     parentRefs:
     - name: gateway-api-prod
       namespace: default
     rules:
     - matches:
       - path:
           value: /
       backendRefs:
       - name: app
         port: 80
   ```

   {% endcut %}

1. Create `prod-app.yaml`:

   {% cut "prod-app.yaml" %}

   ```yaml
   ---
   apiVersion: v1
   kind: Namespace
   metadata:
     name: prod-app
   ---
   apiVersion: apps/v1
   kind: Deployment
   metadata:
     name: app
     namespace: prod-app
   spec:
     selector:
       matchLabels:
         app: app
     template:
       metadata:
         labels:
           app: app
       spec:
         containers:
         - name: app
           image: tutum/hello-world
           resources:
             limits:
               memory: "128Mi"
               cpu: "500m"
           ports:
           - containerPort: 80
   ---
   apiVersion: v1
   kind: Service
   metadata:
     name: app
     namespace: prod-app
   spec:
     type: NodePort
     selector:
       app: app
     ports:
     - port: 80
       targetPort: 80
   ```

   {% endcut %}

### Create test applications {#install-apps}

1. To install the applications, run this command:

   ```bash
   kubectl apply -f prod-gw.yaml && \
   kubectl apply -f prod-app.yaml && \
   kubectl apply -f prod-route.yaml && \
   kubectl apply -f dev-gw.yaml && \
   kubectl apply -f dev-app.yaml && \
   kubectl apply -f dev-route.yaml
   ```

1. Make sure the app [pods](../../managed-kubernetes/concepts/index.md#pod) switched to `Running`:

   ```bash
   kubectl get pods --namespace dev-app && \
   kubectl get pods --namespace prod-app
   ```

1. Make sure a load balancer has been created for the Gateway API:

   ```bash
   yc application-load-balancer load-balancer list
   ```

   It may take several minutes to create the load balancer.

   {% note warning %}
   
   Do not modify or delete the network load balancer and its child resources created using Managed Service for Kubernetes via the Yandex Cloud interfaces (the management console, Terraform, CLI, or API). This may cause incorrect operation of the cluster.
   
   {% endnote %}

## Test Gateway API {#check-apps}

To test the Gateway API, open these links in your browser:
* `app.prod.<domain_zone>`.
* `app.dev.<domain_zone>`.

{% note info %}

If you cannot access the resource at the specified URL, [make sure](../../managed-kubernetes/operations/connect/security-groups.md) the security groups for the Managed Service for Kubernetes cluster and its node groups are configured correctly. If a rule is missing, [add it](../../vpc/operations/security-group-add-rule.md).

{% endnote %}

## Delete the resources you created {#clear-out}

Some resources are not free of charge. Delete the resources you no longer need to avoid paying for them:

{% list tabs group=instructions %}

- Manually {#manual}

  1. [Delete the Kubernetes cluster](../../managed-kubernetes/operations/kubernetes-cluster/kubernetes-cluster-delete.md).
  1. [Delete the created subnets](../../vpc/operations/subnet-delete.md) and [networks](../../vpc/operations/network-delete.md).
  1. [Delete the created service account](../../iam/operations/sa/delete.md).

- Terraform {#tf}

  1. In the terminal window, go to the directory containing the infrastructure plan.
  
      {% note warning %}
  
      Make sure the directory has no Terraform manifests with the resources you want to keep. Terraform deletes all resources that were created using the manifests in the current directory.
  
      {% endnote %}
  
  1. Delete resources:
  
      1. Run this command:
  
          ```bash
          terraform destroy
          ```
  
      1. Confirm deleting the resources and wait for the operation to complete.
  
      All the resources described in the Terraform manifests will be deleted.

{% endlist %}