Разработка .NET Web приложения на Yandex Cloud Functions

Введение

Яндекс Облако предоставляет возможность разворачивания .NET приложений разными способами, типичным из которых является docker контейнеры, развернутые на созданных вычислительных ресурсах, что подразумевают оплату за выделенные процессоры и память. Более экономный вариант предоставляют serverless сервисы Cloud Functions и Serverless Containers, где оплата идет по фактически потребленным ресурсам, масштабирование осуществляется самим облаком. Контейнеры это хороший вариант разработки, но более простым и легковесным является Cloud Functions.

Инструменты

Visual Studio предоставляет возможность создавать любые Web приложения, но разворачиваться они должны на хостах, которые открывают порты для взаимодействия с пользователями. Вариант для Cloud Functions это создать модуль, который имеет предопределенную точку входа. Метод-обработчик должен быть публичным, иметь имя FunctionHandler и один входной параметр. Но хотелось бы создавать полноценные Web Api, где под капотом midlware и вся мощь внедрения зависимостей созданное MS. Такого инструмента у Яндекс нет, но это есть у Amazon. AWS SDK для .NET дает возможность создавать и переносить существующие Web приложения на облако, и интегрируется с Visual Studio, чем мы просто и воспользуемся. Данная технология дает возможность запускать и отлаживать локально средствами Visual Studio.

Шаблоны проектов AWS

a6ed016166b3aa02f3024f365448cd2a.jpg

Компоненты

AWS SDK реализует IHostBuilder, но при запуске заменяет сервис IServer пустой заглушкой, потому хост при запуске не открывает порты и т.д., но цепочка обработки midleware работает. Точка входа и сигнатура вызова не совпадает с Яндекс, но это не проблема, open source дает возможность доделать проект, и вот сразу появляется наш AWS SDK с поддержкой Яндекс.

Разработка

Скачаем и локально установим nuget packet Amazon.Lambda.Yandex.0.0.1.nupkg, который мы создали, запустив команду nuget add с параметрами локального репозитория, который можно посмотреть в настройках VS.

Создадим на Visual Studio проект Web Api:

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

namespace WebApplication
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }


        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            app.UseRouting();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
                endpoints.MapGet("/", () => "Welcome to running ASP.NET Core Minimal API");
                endpoints.MapGet("/test", () => "Welcome to Yandex");
            });
        }
    }
}
using Amazon.Lambda.AspNetCoreServer;
using Microsoft.AspNetCore.Hosting;

namespace WebApplication
{
    public class YandexFunction : YandexGatewayProxyFunction
    {
        protected override void Init(IWebHostBuilder builder)
        {
            builder.UseStartup();
        }
    }
}
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using WebApplication.Model;

namespace WebApplication.Controllers
{
    [ApiController]
    [Route("api/test")]
    public class ApiController : ControllerBase
    {
        private static readonly string[] Summaries = new[]
        {
            "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
        };

        private readonly ILogger _logger;

        public ApiController(ILogger logger)
        {
            _logger = logger;
        }

        [HttpGet]
        public IEnumerable Get()
        {
            var rng = new Random();
            return Enumerable.Range(1, 5).Select(index => new WeatherForecast
            {
                Date = DateTime.Now.AddDays(index),
                TemperatureC = rng.Next(-20, 55),
                Summary = Summaries[rng.Next(Summaries.Length)]
            })
            .ToArray();
        }
    }
}

Развертывание

Яндекс наверно оптимизировал и урезал среду исполнения net6, потому придется делать сборку Self-contained, иначе загрузчик ругается на отсутствие библиотек ядра, потом удалим системные библиотеки.

Делаем локальное разворачивание Publish, ставим параметры:

  • linuх-x64

  • net6.0

  • Self-contained

  • Trim unused code

Удаляем System.*.dll и файлы *.so кроме System.Diagnostics.*.dll System.IO.*.dll System.Text.*.dll
Упакуем в .zip, грузим в облако.

Точка входа: WebApplication.YandexFunction

Создаем для функции отдельный Yandex API Gateway:

openapi: 3.0.0
info:
  title: Sample Web API
  version: 1.0.0
servers:
- url: https://....apigw.yandexcloud.net
paths:
  /test:
    get:
      summary: Get Test
      operationId: gettest10
      tags:
        - example
      x-yc-apigateway-integration:
        type: cloud_functions
        function_id: ...
        payload_format_version: "1.0"
        tag: "$latest"
      responses:
        '200':
          description: Ok
  /api/{param+}:
    x-yc-apigateway-any-method:
      summary: Get Controllers
      parameters:
        - name: param
          in: path
          required: true
          schema:
            type: string
      operationId: getcontrollers
      tags:
        - example
      x-yc-apigateway-integration:
        type: cloud_functions
        function_id: ...
        payload_format_version: "1.0"
        tag: "$latest"
      responses:
        '200':
          description: Ok

Наше приложение готово и доступно в интернете по адресу шлюза.

Ссылки на исходники:

© Habrahabr.ru