Введение

Яндекс Облако предоставляет возможность разворачивания .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

Компоненты

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<Startup>();
        }
    }
}
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<WeatherForecastController> _logger;

        public ApiController(ILogger<WeatherForecastController> logger)
        {
            _logger = logger;
        }

        [HttpGet]
        public IEnumerable<WeatherForecast> 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

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

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

Комментарии (0)