Разработка .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
Компоненты
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
Наше приложение готово и доступно в интернете по адресу шлюза.
Ссылки на исходники: