От разработки и тестирования до развертывания мы рассмотрим, что такое функции Azure и как начать работу с ними.

Недавно я работал с несколькими функциями Azure и только сейчас начинаю понимать, насколько они хороши.

Раньше я думал, что мне понадобится определенный набор навыков, чтобы создать достойную функцию Azure, но когда я действительно в нее вник, все оказалось очень, очень просто. Можете ли вы написать конечную точку API? Затем вы можете создать функцию Azure. Но даже если у вас нет большого опыта работы с .NET или Azure, мы рассмотрим все в этой статье, чтобы вы могли сами решить, подходит ли функция Azure для того, что вы пытаетесь сделать, и как заставить вас работать с ним.

Итак, сначала давайте посмотрим, для чего можно использовать функции Azure, прежде чем мы углубимся в то, как их создавать и развертывать.

Что такое функция Azure?

Функция Azure — это некоторый код, работающий в Azure, который можно активировать вручную или путем прослушивания определенного события.

Вы можете настроить целую кучу различных триггеров для своей функции, включая (но не ограничиваясь):

  • HTTP-вызовы
  • Файл загружается в хранилище BLOB-объектов
  • Таймер для запуска через равные промежутки времени
  • Сообщение считывается из очереди сообщений

Вы можете настроить свою функцию на прослушивание любого из этих триггеров, который затем запустит ваш код.

Возможно, вы захотите, чтобы ваша функция принимала какие-то входные данные и отвечала ответом. Или вы можете поместить новое сообщение в очередь сообщений. Или вы можете где-то вызвать другой API. Это полностью зависит от вас.

Зачем использовать функцию Azure?

Вы можете спросить, зачем использовать функцию Azure вместо чего-то вроде стандартного веб-приложения или API? Ну, конечно, есть пересечения, но есть несколько проблем, для решения которых были специально разработаны функции Azure.

Во-первых, их очень легко разрабатывать и развертывать. Функции Azure — это «бессерверное» решение, то есть вам не нужно беспокоиться о предоставлении серверов для размещения ваших функций, но вы можете просто развернуть свой код где-нибудь, и Azure запустит его за вас.

Далее, вы не ограничены написанием своей функции на C#. Вы можете использовать JavaScript. Или Питон. Или PowerShell. Или что-то другое. Используйте то, что наиболее подходит вам и вашей команде.

Наконец, легко настроить стоимость и производительность ваших функций. У вас есть варианты платить только за ваши функции, пока они фактически выполняются, или вы можете заплатить больше, чтобы получить доступ к более высокой вычислительной мощности и большему объему памяти. Хотя внести эти изменения очень просто, функция Azure не обязательно будет для вас самым дешевым вариантом, в зависимости от того, насколько интенсивными будут ваши функции. Например, функция, над которой я недавно работал, требовала огромного объема памяти (ОЗУ), и единственным вариантом, который у нас был, было выбрать самый высокий уровень Premium, который, хотя и обеспечивал идеальную работу функции, был очень дорогим. . Так что определенно стоит быстро проверить, каковы ограничения ресурсов для каждого ценового уровня, прежде чем зайти слишком далеко, на случай, если вы знаете, что это будет полностью вне вашего бюджета.

Поскольку функции Azure были разработаны, чтобы предоставить решение для более узкого набора требований, многие процессы разработки и развертывания были значительно упрощены по сравнению с другими вариантами. На самом деле функция Azure может сделать очень немногое из того, что нельзя воспроизвести с помощью другого решения, но она делает это таким образом, что действительно может ускорить время разработки и потенциально намного дешевле.

Давайте посмотрим, как создать функцию Azure, и, надеюсь, вы получите лучшее представление о том, что происходит.

Создание функции Azure

Как мы упоминали выше, существует множество различных способов создания функции Azure. Здесь мы будем использовать C# для создания функции, отвечающей на HTTP-запрос, но просто помните, что у вас есть другие языки и триггеры, которые вы также можете использовать.

Откройте Visual Studio и выберите создание нового проекта. Поиск функций Azure:

Нажмите «Далее», дайте вашей функции имя и снова нажмите «Далее», и у вас будет несколько вариантов для вашей функции:

Любой из этих параметров можно изменить после создания функции, но стоит знать, что они из себя представляют, чтобы сэкономить вам немного времени.

Во-первых, «Работник функций»:

Здесь мы можем решить, какого работника мы хотим использовать. На момент написания у нас были .NET 6 и .NET 7 в качестве основных вариантов. .NET 7 великолепен, но единственный доступный в настоящее время вариант — использовать его как изолированный процесс, поэтому в настоящее время я бы придерживался .NET 6. У изолированных процессов есть свои преимущества (например, если вы хотите запустить свой собственный промежуточное ПО), но до сих пор я считаю, что внутрипроцессные параметры являются лучшим вариантом для моих функций. Вы можете ознакомиться с различиями между изолированными и внутрипроцессными рабочими процессами здесь.

Далее у нас есть тип функции, которую мы хотим добавить:

Вы можете либо выбрать «Пустой», если хотите написать свою функцию полностью с нуля, либо выбрать один из существующих типов, чтобы получить для него предопределенный шаблон. В нашем примере функции мы пишем функцию, которая отвечает на HTTP-запрос, поэтому мы выберем «HTTP-триггер».

Когда мы выбираем это, мы получаем новую опцию для установки уровня авторизации:

Это может быть «Функция», «Анонимный» или «Администратор». Сейчас мы хотим выбрать «Анонимный» — авторизация — это тема для другого дня!

Далее у нас есть возможность использовать Азурит:

Функции предназначены для работы в хранилище Azure, но мы не всегда хотим подключать нашу локальную среду разработки к Azure только для того, чтобы все заработало. Азурите — это эмулятор службы хранилища Azure, который мы можем использовать для локального запуска функции. Мы оставим это включенным, хотя я обнаружил, что работать с азуритом может быть сложно. В большинстве случаев это работает идеально, и вам не нужно об этом думать. Пока он не перестанет работать, и ваши функции не перестанут работать локально, в этом случае вы отлаживаете, почему он не работает. Надеюсь, со временем это станет более надежным, но просто имейте в виду, что если вы начнете получать ошибки о локальном хранилище, то, вероятно, это Азурите.

Наконец, у нас есть возможность использовать Docker. Это круто, но мы не будем этого делать для этой демонстрации.

Хорошо, нажимаем «Создать» и давайте посмотрим, что у нас получилось.

public static class Function1
{
    [FunctionName("Function1")]
    public static async Task<IActionResult> Run(
        [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
        ILogger log)
    {
        log.LogInformation("C# HTTP trigger function processed a request.");

        string name = req.Query["name"];

        string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
        dynamic data = JsonConvert.DeserializeObject(requestBody);
        name = name ?? data?.name;

        string responseMessage = string.IsNullOrEmpty(name)
            ? "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response."
            : $"Hello, {name}. This HTTP triggered function executed successfully.";

        return new OkObjectResult(responseMessage);
    }
}

У нас есть класс с именем Function1 и внутри него метод с именем Run. К этой функции применены несколько атрибутов и пара параметров. Внутри метода у нас есть некоторая логика, которая считывает объект запроса и формирует возвращаемый ответ.

Давайте разберем это и посмотрим, что происходит.

[FunctionName("Function1")]
public static async Task<IActionResult> Run(
  [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
  ILogger log)

Вот сигнатура метода для функции. Атрибут FunctionName указывает, каким будет имя функции. Для такой HTTP-функции это то, что мы собираемся использовать в URL-адресе.

Есть два параметра — HttpRequest и ILogger. HttpRequest — это содержимое запроса, отправляемого при запуске функции. Мы можем использовать это для извлечения данных, необходимых для запуска функции. ILogger используется, чтобы мы могли писать сообщения журнала.

Обратите внимание, что к параметру HttpRequest применен еще один атрибут — это атрибут HttpTrigger. Это контролирует, как должна запускаться функция. В нашем случае мы говорим, что авторизация Anonymous, что означает, что любой может активировать функцию. Мы также передаем get и post, что говорит о том, что мы можем использовать HTTP-запросы GET и POST.

Как и во всех хороших шаблонах .NET, сгенерированный для нас здесь код готов к тестированию, поэтому давайте запустим его локально и посмотрим, сможем ли мы его вызвать.

Локальный запуск функции Azure

Написав функцию Azure, вы можете запустить ее локально, чтобы вызвать ее и убедиться, что она ведет себя так, как вы ожидаете.

У вас есть несколько вариантов. Если вы используете Visual Studio, вы можете запустить его из самой Visual Studio. Просто перейдите в Debug -> Start Debugging (или Debug -> Start Without Debugging):

Запуск функции таким образом открывает новое окно терминала и должно сообщить вам, когда функция запущена и работает:

Кроме того, вы можете запустить функцию непосредственно из командной строки. Это мой предпочтительный способ запуска процессов .NET, особенно если у меня есть несколько разных проектов, работающих одновременно. Для этого откройте новое окно терминала и перейдите в папку, содержащую файл .csproj вашей функции, и выполните следующую команду:

func start — csharp

Каким бы способом вы ни запускали функцию, в выводе будет список доступных функций:

Для функций HTTP мы получаем URL-адрес, который мы можем использовать для тестирования нашей функции.

Давайте сделаем GET-запрос к этому и посмотрим, что произойдет.

Мне нравится использовать почтальон для таких вещей:

Мы получаем такой ответ:

Эта функция, активируемая HTTP, выполнена успешно. Передайте имя в строке запроса или в тексте запроса для персонализированного ответа.

Отлично, наша функция работает. И это говорит нам, что мы можем с этим сделать.

Давайте изменим наш запрос, чтобы включить имя в строку запроса. Итак, мы назовем http://localhost:7071/api/Function1?name=Jamie

Теперь это наш ответ:

Привет, Джейми. Эта функция, активируемая HTTP, выполнена успешно.

Отличный.

Мы знаем, что наша функция также принимает сообщения POST, поэтому давайте изменим наш запрос, чтобы он имел тело JSON, подобное этому:

{
  "name": "Brian"
}

Когда мы отправляем этот запрос на наш исходный URL-адрес http://localhost:7071/api/Function1 как POST, мы получаем такой ответ:

Привет, Брайан. Эта функция, активируемая HTTP, выполнена успешно.

Блестящий. Кажется, все работает.

Давайте теперь посмотрим, как расширить нашу функцию, чтобы она была немного больше похожа на то, что мы использовали бы в реальном мире.

Внедрение зависимостей в функцию Azure

Если вы какое-то время работали с .NET, скорее всего, вы сталкивались с необходимостью внедрения зависимостей (DI). DI позволяет вам разделить ваш код на логические разделы и объединить их все вместе, когда вам это нужно.

DI легко настроить для функций Azure, но может быть не сразу понятно, как это сделать.

Скажем, у нас есть MessageBuilder, который был написан для создания возвращаемого сообщения, и мы хотим внедрить его. У нас может быть этот код в нашем проекте:

namespace DemoFunction.Logic;

public interface IMessageBuilder
{
    string Build(string name);
}
public class MessageBuilder : IMessageBuilder
{
    public string Build(string name) => $"Hello {name}";
}

Как внедрить IMessageBuilder в нашу функцию?

Глядя на наш существующий код, вы заметите, что и класс функции, и метод были сделаны static:

public static class Function1
{
    [FunctionName("Function1")]
    public static async Task<IActionResult> Run(
        [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
        ILogger log)
    {

Это связано с тем, что функции Azure в первую очередь предназначены для работы без сохранения состояния, поэтому наличие кода в статических блоках способствует этому.

Если вы можете написать свой код таким образом, то это здорово. Однако в большинстве случаев вы не можете этого сделать, поэтому вам может потребоваться заставить функции использовать методы экземпляра.

Хорошая новость заключается в том, что функции Azure работают точно так же с классами экземпляров, поэтому мы можем легко обновить нашу функцию, чтобы она не была статической, просто удалив модификаторы static:

public class Function1
{
    [FunctionName("Function1")]
    public async Task<IActionResult> Run(
        [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
        ILogger log)

Теперь вернемся к внедрению зависимостей. Мы видим, что у нас есть обычный класс, и если бы мы использовали внедрение зависимостей, как в других местах, мы бы использовали внедрение конструктора (поэтому мы не могли использовать статический класс). Итак, что мы будем делать:

public class Function1
{
    private readonly IMessageBuilder _messageBuilder;

    public Function1(IMessageBuilder messageBuilder)
    {
        _messageBuilder = messageBuilder;
    }

Затем мы можем обновить нашу функцию, чтобы использовать эту зависимость при построении ответного сообщения:

string responseMessage = string.IsNullOrEmpty(name)
    ? "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response."
    : _messageBuilder.Build(name);

Если мы соберем решение, оно соберется без ошибок, и мы сможем запустить процесс, но если мы попробуем вызвать функцию, то получим ошибку:

Это потому, что мы еще не подключили зависимости. Давайте сделаем это сейчас.

Вернувшись к своему решению, добавьте класс Startup.cs в корень проекта.

public class Startup
{

}

Здесь мы все настроим.

Во-первых, измените этот класс, чтобы он наследовался от FunctionsStartup, то есть из пакета Microsoft.Azure.Functions.Extensions NuGet. Затем вы можете переопределить метод Configure:

using Microsoft.Azure.Functions.Extensions.DependencyInjection;

namespace DemoFunction;

public class Startup : FunctionsStartup
{
    public override void Configure(IFunctionsHostBuilder builder)
    {
        throw new System.NotImplementedException();
    }
}

Этот параметр построителя можно использовать для настройки зависимостей. Мы настроим наш IMessageBuilder как синглтон, поскольку он не содержит никакого состояния, поэтому его можно разделить между всеми процессами:

public override void Configure(IFunctionsHostBuilder builder)
{
    builder.Services.AddSingleton<IMessageBuilder, MessageBuilder>();
}

Последнее, что нам нужно сделать, это сообщить проекту, что мы хотим использовать этот класс Startup во время запуска. Мы делаем это, добавляя атрибут уровня сборки где-то в нашем приложении, но имеет смысл включить его в начало этого файла:

using DemoFunction.Logic;
using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;

[assembly: FunctionsStartup(typeof(DemoFunction.Startup))]
namespace DemoFunction;

public class Startup : FunctionsStartup
{
    public override void Configure(IFunctionsHostBuilder builder)
    {
        builder.Services.AddSingleton<IMessageBuilder, MessageBuilder>();
    }
}

Здесь мы сообщаем проекту, что хотим использовать наш новый класс как класс FunctionsStartup.

Давайте перестроим, запустим функцию и вызовем ее.

Это наш новый вывод:

Привет Джейми

Так что это работает. Большой.

После того, как вы внедрили свою первую зависимость, должно быть легко увидеть, как этот проект можно развивать дальше, добавляя дополнительные зависимости, когда это необходимо.

Чтение appsettings.json из функций Azure.

Очень часто требуется чтение из файла настроек, и при написании функций Azure это ничем не отличается. Если вы хотите установить значения там, чтобы, по крайней мере, они не были жестко запрограммированы в самом коде, или это значения, которые вы захотите изменить во время развертывания, appsettings.json — это хорошее место для размещения подобных вещей для . NET-приложений.

Давайте посмотрим, как прочитать значение из этого файла в нашей функции Azure.

Для начала добавим в корень проекта файл appsettings.json с нашим значением:

{
 "MaxNameLength":  10
}

Здесь мы будем хранить максимальную длину имени, поэтому мы можем добавить немного проверки нашей функции.

Не забудьте настроить файл для включения в выходные данные сборки, иначе он не будет найден:

Как только мы добавили наш файл appsettings.json, нам нужно обновить наш класс Startup, чтобы прочитать его. Лучшее место для настройки этих параметров — новый переопределенный метод в Startup, который называется ConfigureAppConfiguration.

public class Startup : FunctionsStartup
{
    public override void Configure(IFunctionsHostBuilder builder)
    {
        builder.Services.AddSingleton<IMessageBuilder, MessageBuilder>();
    }

    public override void ConfigureAppConfiguration(IFunctionsConfigurationBuilder builder)
    {
        FunctionsHostBuilderContext context = builder.GetContext();

        builder.ConfigurationBuilder
            .AddJsonFile(Path.Combine(context.ApplicationRootPath, "appsettings.json"), optional: true, reloadOnChange: true)
            .AddEnvironmentVariables();
    }
}

В этом новом методе мы добавляем новый файл JSON в наш построитель конфигурации, создавая путь к нашему файлу appsettings.json, используя свойство ApplicationRootPath нашего контекста.

Если мы хотим внедрить эту конфигурацию в остальную часть нашего кода (используя объект IConfiguration), нам также необходимо зарегистрировать это. Мы делаем это внутри нашего существующего метода Configure :

public override void Configure(IFunctionsHostBuilder builder)
{
    builder.Services.AddSingleton<IMessageBuilder, MessageBuilder>();

    IConfiguration configuration = builder.GetContext().Configuration;
    builder.Services.AddSingleton(configuration);
}

Теперь мы можем внедрить IConfiguration в один из наших классов. А пока давайте добавим его в наш класс MessageBuilder и проведем небольшую элементарную проверку:

public class MessageBuilder : IMessageBuilder
{
    private readonly IConfiguration _configuration;

    public MessageBuilder(IConfiguration configuration)
    {
        _configuration = configuration;
    }

    public string Build(string name)
    {
        if (name?.Length > _configuration.GetValue<int>("MaxNameLength"))
        {
            return "Name is too long";
        }
        return $"Hello {name}";
    }
}

Мы вызываем .GetValue для нашего введенного свойства IConfiguration и проверяем, не слишком ли длинна длина имени.

Давайте построим, запустим и попробуем.

Во-первых, давайте проверим небольшое имя, чтобы убедиться, что сообщение все еще возвращается.

Мы отправим это тело:

{
  "name": "Jamie"
}

И получаем ответ:

Привет Джейми

Теперь давайте попробуем что-нибудь подлиннее:

{
  "name": JamieJamieJamie"
}

Наш ответ сейчас:

Имя слишком длинное

Отлично, мы читаем это значение MaxNameLength из нашего файла appsettings.json.

Примечание об использовании метода ConfigureAppConfiguration для настройки конфигурации. Если мы сделаем это так, как мы сделали выше, мы сможем внедрить и использовать IConfiguration где угодно. Однако, если бы мы настроили файл appsettings.json в существующем методе Configure, тогда IConfiguration не будет заполнен правильными значениями до тех пор, пока не будут настроены все службы, что означает, что если вы попытаетесь получить значение конфигурации в конструкторе внедренной зависимости , то вы получите неправильное значение. Итак, пока вы используете ConfigureAppConfiguration, вы избежите этой проблемы.

Итак, теперь у нас есть функция, которая использует внедрение зависимостей и может использовать файл appsettings.json. Большой!

Развертывание функций Azure

После того, как вы настроите и запустите функцию Azure, вы захотите развернуть ее в Azure.

Есть несколько способов сделать это, но мы рассмотрим, как это сделать с помощью сборок и конвейеров Azure DevOps.

Основные этапы, которые мы пройдем:

  • Создание приложения-функции в Azure
  • Добавление сборки CI в Azure DevOps
  • Добавление конвейера выпуска в Azure DevOps

Создание приложения-функции в Azure

Нам нужно создать функцию в самой Azure, чтобы мы знали, куда мы развертываем. Это можно сделать разными способами, но мы будем использовать пользовательский интерфейс Azure.

Нажмите, чтобы создать приложение-функцию, и вы запустите мастер:

Убедитесь, что вы добавляете то, что нужно, затем нажмите «Создать»:

Выберите свою подписку и выберите (или создайте) группу ресурсов. Дайте вашей функции имя — в нашем случае мы назовем ее Jamie-FunctionDemo. Мы развертываем функцию как код и используем .NET 6. Я на юге Великобритании, поэтому буду использовать этот регион. И я доволен использованием Windows в качестве ОС.

Затем мы можем установить параметры хостинга:

Эта функция крошечная, поэтому я выбираю план потребления, который бесплатный. Стоит проверить, что предлагают разные планы, поэтому, когда вы правильно используете свою функцию в производстве, вы выбираете лучший вариант.

На следующей странице у нас есть варианты хранения:

Я создаю новый здесь.

Далее у нас есть параметры сети:

Значения по умолчанию здесь подходят для этого — мне нужен публичный доступ к функции (чтобы я мог вызывать ее напрямую).

Далее в мониторинге:

Это всего лишь демонстрация, поэтому я отключу Application Insights, но настоятельно рекомендую включить его для ваших реальных функций — это значительно упрощает отладку.

Далее развертывание:

Я не использую GitHub для этого, так что это может оставаться отключенным.

Далее идут теги, которые мне не нужны, поэтому я могу их пропустить, и, наконец, мы добираемся до страницы обзора. Дважды проверьте, что все правильно, затем мы можем нажать кнопку «Создать». После создания вы должны увидеть сводную страницу, показывающую, что все было развернуто:

Добавление сборки CI

Следующим шагом будет настройка конвейера сборки в Azure DevOps. Добавьте файл azure-pipelines.yml в корень вашего решения и поместите в него что-то вроде этого:

trigger:
- main

variables:
  buildConfiguration: 'Release'

pool:
  vmImage: ubuntu-latest

steps:
- task: DotNetCoreCLI@2
  displayName: Build
  inputs:
    projects: '**/*.csproj'
    arguments: '--configuration $(BuildConfiguration)'

- task: DotNetCoreCLI@2
  displayName: Test
  inputs:
    command: test
    projects: '**/*Tests/*Tests.csproj'
    arguments: '--configuration $(BuildConfiguration)'

- task: DotNetCoreCLI@2
  displayName: Publish
  inputs:
    command: publish
    arguments: '--configuration Release --output publish_output'
    projects: '**/*Function.csproj'
    publishWebProjects: false
    modifyOutputPath: false
    zipAfterPublish: false

- task: ArchiveFiles@2
  displayName: Archive
  inputs:
    rootFolderOrFile: "$(System.DefaultWorkingDirectory)/publish_output"
    includeRootFolder: false
    archiveFile: "$(System.DefaultWorkingDirectory)/build$(Build.BuildId).zip"

- task: PublishBuildArtifacts@1
  displayName: 'Publish Artifact'
  inputs:
    PathtoPublish: '$(System.DefaultWorkingDirectory)/build$(Build.BuildId).zip'
    artifactName: 'drop'

Там много чего происходит, но давайте кратко разберем это.

Во-первых, мы устанавливаем триггер для ветки main, что означает, что эта сборка будет запускаться при каждом обновлении ветки main. После настройки некоторого конфига перед нами стоит ряд задач:

  • Сборка — запускает сборку фактического решения.
  • Тест – запускает любые модульные тесты, которые есть в вашем проекте. В настоящее время он ищет в папке «Тесты» любые проекты, которые заканчиваются на «Тесты».
  • Опубликовать: решение публикуется в пакете, который можно развернуть и предназначен для всех проектов, оканчивающихся на «Функция».
  • Архивировать: публикуемые файлы сжимаются в один файл, что упрощает и ускоряет развертывание.
  • Опубликовать артефакт — заархивированный файл публикуется как часть сборки, чтобы его можно было использовать в релизе.

В Azure DevOps создайте новый конвейер сборки для репозитория, в котором был зафиксирован этот проект:

Когда вам будет предложено выбрать, где находится ваш код, выберите «Azure Repos Git» (или где находится ваш код):

После выбора вам будет предоставлена ​​возможность выбрать свой репозиторий:

В моем случае репозиторий называется «Демо», поэтому я выберу его.

Далее меня попросят настроить конвейер:

Поскольку у меня уже есть конвейер, определенный в файле yaml, я могу выбрать «Существующий файл YAML Azure Pipelines» внизу. Затем у меня будет возможность выбрать, где находится этот файл:

Итак, я выбрал свой файл azure-pipelines.yml из выпадающего списка.

Затем мне показывают этот пайплайн, так что я могу перепроверить, что он правильный:

Это все хорошо, поэтому я могу нажать кнопку «Сохранить» под кнопкой «Выполнить», чтобы сохранить его:

После создания я запущу его, нажав кнопку «Запустить конвейер»:

После запуска вы увидите сводную страницу:

Вы можете нажать «Задание» внизу, чтобы просмотреть его ход, или дождаться его завершения:

Я заметил, что получаю предупреждение — это от задачи «Тест», потому что она не может найти никаких тестов для запуска, и это нормально, потому что я еще ничего не добавил.

Несмотря на это, конвейер успешно завершен, поэтому мы можем перейти к этапу развертывания.

Создание конвейера выпуска

После создания сборки CI нам нужно настроить конвейер выпуска, который берет выходные данные нашей сборки и развертывает их в Azure:

Нажмите, чтобы добавить новый конвейер, и когда вас спросят, какой шаблон использовать, просто выберите «Пустое задание» — мы настроим это вручную:

Во-первых, нам нужно добавить выходные данные сборки CI, которую мы только что настроили, в качестве артефакта. Слева у нас есть кнопка «Добавить» для артефактов:

Нажмите «Добавить», и мы получим несколько вариантов:

Наш артефакт — результат сборки, поэтому здесь уже выбран правильный источник. В списке конвейеров выберите новую сборку, которую мы только что добавили, и нажмите «Добавить».

Теперь мы видим этот артефакт в списке:

Затем щелкните ссылку «1 задание, 0 задач» в разделе «Этап 1», чтобы мы могли добавить задачу развертывания к этому первому этапу:

В разделе «Работа агента» у нас есть значок плюса — щелкните его, чтобы добавить задачу:

Найдите «Функция Azure» и нажмите кнопку «Добавить» для «Развертывание функций Azure»:

Выберите добавленную задачу, и нам нужно заполнить некоторые данные:

Во-первых, выберите свою подписку в первом раскрывающемся списке. Вы можете получить предупреждение об авторизации:

Предполагая, что у вас есть правильные разрешения, вы можете нажать кнопку «Авторизовать», чтобы настроить его. Просто имейте в виду, что иногда это может занять пару минут.

После утверждения мы можем заполнить остальные настройки. Следующие два параметра выбираются из раскрывающихся списков, поэтому выберите тип приложения и функцию, которые вы уже добавили:

Остальные значения по умолчанию здесь должны быть в порядке.

Теперь вы можете переименовать воронку (наведя указатель мыши на заголовок и нажав кнопку редактирования) и сохранить воронку, нажав кнопку «Сохранить» в верхней части страницы:

После сохранения вы можете активировать его для запуска нового выпуска. Нажмите кнопку «Создать релиз» вверху:

Вам дается еще несколько вариантов, но все значения по умолчанию должны быть в порядке:

Нажмите «Создать», и вам сообщат, что релиз создан:

Нажмите на эту ссылку в сообщении, и вы увидите его прогресс:

Вы можете нажать на сцену, чтобы найти журналы, чтобы увидеть, что она делает.

После завершения вы должны увидеть, что этап помечен как «Успешно»:

И он развернут в Azure!

Теперь мы можем протестировать его, вызвав наш URL-адрес, точно так же, как мы тестировали его локально.

С помощью Postman обновите URL-адрес до того, который мы установили в качестве URL-адреса функции, когда добавляли его в Azure. Так что я могу использовать jamie-functiondemo.azurewebsites.net:

Запустите его и посмотрите, что произойдет:

Оно работает!

Теперь вы настроили основные части вашего процесса CI/CD, поэтому всякий раз, когда вам нужно повторно развернуть свою функцию, вы можете сделать это всего за пару кликов.

Краткое содержание

Надеюсь, вы видели, какие проблемы решают функции Azure, и мы надеемся, что эта статья станет хорошей отправной точкой для их дальнейшего изучения.

Мы рассмотрели, почему мы можем захотеть использовать функцию Azure, и увидели, как мы можем создать и запустить ее локально. Мы также рассмотрели шаги, необходимые для развертывания этого в Azure.

Я думаю, что функции Azure великолепны, и я определенно буду искать способы их использования в будущих решениях. Я надеюсь, что это поможет и вам!