Knative — превосходная платформа для создания, развертывания и управления безсерверными рабочими нагрузками в Kubernetes. В Порции ресурсов Knative расширить Istio для поддержки бессерверных приложений. Другой класс ресурсов Knative называется троеборью расширить Istio для поддержки производства и потребления облачных событий .
Knative снимает с себя ответственность за масштабирование рабочих нагрузок пользователей, активируя модули только при получении запроса. Он масштабирует модули рабочей нагрузки на основе количества запросов и уменьшает их до нуля, когда они простаивают. Еще одна замечательная особенность Knative — это способность понимать ревизии кода и конфигураций. Если развертывание кода или конфигурации нарушает работу приложения, Knative автоматически откатывает обновление. Обслуживающий компонент Knative может постепенно развертывать версии приложений и обеспечивает гибкое распределение трафика между версиями. Knative Eventing добавляет возможность создания сервисов, управляемых событиями, для платформы. Это позволяет объявлять привязки между производителями событий и потребителями, используя конфигурации, которые отделяют производителей от потребителей событий.
Вам также может понравиться: Knative Serving — сервисный звонок
В Knative есть несколько встроенных источников событий, которые могут генерировать облачные события из таких источников, как Kubernetes, GitHub и AWS SQS. Существует две модели доставки событий, сгенерированных источником, в службу Knative.
- Прямая доставка : в этой модели источник может напрямую доставить событие в один сервис. Служба может быть либо службой Knative, либо службой Kubernetes. Источник отвечает за повторную доставку, если служба недоступна.
- Разветвленная доставка . В этой модели события из источника направляются в другой компонент Knative, известный как канал. Все сервисы, которые заинтересованы в прослушивании событий, предоставляют подписки на каналы и, таким образом, могут асинхронно получать события. Модель разветвленной доставки — это реализация Knative популярного шаблона Pub \ Sub.
В этой статье мы разработаем собственный источник событий с ядром .NET и доставим события в другой пользовательский сервис Knative, используя модель прямой доставки.
Контейнер Источник
Самый простой подход к созданию пользовательского источника событий заключается в использовании вспомогательного объекта Knative ContainerSource. Контейнерный источник генерирует события и отправляет события в URI приемника. Приемник может быть либо сервисом Knative, либо каналом. Knative гарантирует, что источник контейнера всегда будет работать, пока не будет удален. Любое приложение может выступать в качестве источника контейнера, если оно удовлетворяет следующим требованиям.
-
Приложение может быть упаковано в контейнер и определено как ENTRYPOINT .
-
Ожидается получение
--sink
параметра CLI или чтениеsink
переменной окружения, реализации которой предоставляет Knative.
--sink
Параметр или sink
переменная среды содержит адрес раковине , в которой контейнер с источником должны вывесить события.
Прочный контейнерный источник
Knative гарантирует, что источник контейнера всегда выполняется, перезапуская контейнер в случае его сбоя. Однако источники контейнеров по умолчанию не имеют состояния и, следовательно, не могут управлять рабочими процессами с отслеживанием состояния. Войдите в Azure Durable Task Framework , которая является средой для написания долговременных постоянных рабочих процессов на C #. В Прочных функциях Azure являются одним из наиболее распространенных реализаций рамок , которые используются для работы с сохранением состояния функции в лазури.
В этой статье мы обсудим, как можно объединить платформу долгосрочных задач Azure с Knative Container Source для создания облачных событий и выполнения рабочего процесса с сохранением состояния. Мы будем использовать следующее для создания нашего приложения, которое впоследствии вы сможете развернуть в своей любимой облачной службе Kubernetes, такой как Azure (AKS) и AWS (EKS). Я использовал варианты Windows следующих приложений.
- Docker Desktop с включенным Kubernetes
- Visual Studio
- Эмулятор хранилища Azure (или фактическая учетная запись хранения в Azure)
Монтаж
Используйте это справочное руководство для установки Knative на вашей платформе. Для Windows шаги, упомянутые для Minikube и Docker Desktop для Mac, работают отлично. Вот скрипт, который я использовал для установки Knative на Docker Desktop для Windows. Я предполагаю, что следующий скрипт будет работать в любой среде.
Оболочка
xxxxxxxxxx
1
$ kubectl delete svc knative-ingressgateway -n istio-system
2
$ kubectl delete deploy knative-ingressgateway -n istio-system
3
$ kubectl delete statefulset/controller-manager -n knative-sources
4
$ kubectl apply --selector knative.dev/crd-install=true --filename https://github.com/knative/serving/releases/download/v0.11.0/serving.yaml --filename https://github.com/knative/eventing/releases/download/v0.11.0/release.yaml --filename https://github.com/knative/serving/releases/download/v0.11.0/monitoring.yaml
5
$ kubectl apply --filename https://github.com/knative/serving/releases/download/v0.11.0/serving.yaml --filename https://github.com/knative/eventing/releases/download/v0.11.0/release.yaml --filename https://github.com/knative/serving/releases/download/v0.11.0/monitoring.yaml
Позвольте мне указать вам на известную проблему с Knative Eventing, которая некоторое время сбивала меня с толку, пока я не наткнулся на эту статью . Knative требует дополнительного локального шлюза кластера Istio для разрешения адреса служб в вашем кластере (с именем хоста .svc.cluster.local ). Сценарии для установки локального шлюза надстройки по версии Istio установлено в кластере присутствует здесь . На момент написания этой статьи я использовал следующие версии Kubernetes, Istio и Knative.
- Кубернетес: 1.14.8
- Istio: 1.4.0
- Knative: 0.11.0
Чтобы установить кластерный локальный шлюз для версии 1.4 Istio, примените конфигурацию istio-knative-extras.yaml к вашему кластеру.
Обзор приложения и исходный код
Демо состоит из следующих приложений.
- Hello Orchestrator : Это приложение представляет собой простой повторяющийся рабочий процесс, который выполняется в бесконечном цикле. Рабочий процесс состоит из одного действия, которое отправляет облачное событие в службу Knative, Hello Events.
- События Hello . Это простой сервис Knative HTTP, имеющий две конечные точки. Конечная точка GET этого сервиса возвращает текст «Hello World». Конечная точка POST этой службы печатает полученное событие в стандартный поток вывода и возвращает ответ HTTP OK с текстом «Обработано».
Следующая диаграмма иллюстрирует различные компоненты архитектуры и их ассоциации.
Исходный код приложения доступен на GitHub .
Давайте обсудим каждый компонент приложения сейчас.
Привет События Служба
Служба Hello Events представлена как решение Hello-Events в решении. Это консольное приложение .NET core 3.1, которое может прослушивать HTTP-запросы на порту 80. Перейдите к файлу Program.cs проекта, который содержит метод с именем CreateHostBuilder
, который отвечает за подключение прослушивателя к порту 80 процесса.
C #
xxxxxxxxxx
1
public static IHostBuilder CreateHostBuilder(string[] args)
2
{
3
var url = string.Concat("http://0.0.0.0:", "80");
4
return Host.CreateDefaultBuilder(args)
5
.ConfigureWebHostDefaults(webBuilder =>
6
{
7
webBuilder.UseStartup<Startup>().UseUrls(url);
8
});
9
}
Конечные точки, которые обрабатывают запросы GET и POST, сделанные для этой службы, присутствуют в файле Startup.cs . Конечная точка GET возвращает текст «Hello World» в ответ, а конечная точка POST печатает запрос на консоли и возвращает текст «Обработано».
C #
xxxxxxxxxx
1
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
2
{
3
app.UseRouting();
4
app.UseEndpoints(endpoints =>
5
{
6
endpoints.MapGet("/", async context =>
7
{
8
await context.Response.WriteAsync($"Hello World!\n");
9
});
10
endpoints.MapPost("/", async context =>
12
{
13
string body;
14
using (var sr = new StreamReader(context.Request.Body))
15
{
16
body = await sr.ReadToEndAsync();
17
}
18
Console.WriteLine($"Received {body}");
20
await context.Response.WriteAsync("Processed");
21
});
22
});
23
}
Наконец, Dockerfile, присутствующий в проекте, можно использовать для упаковки и публикации этого приложения в реестре контейнеров.
Привет оркестр
Источник контейнера Hello Orchestrator представлен как решение Hello-Orchestrator в решении. Это консольное приложение .NET core 3.1, которое может выполняться неограниченное время без прерывания. Main
Метод программы отвечает за инициализацию Durable задач Orchestrator и долговечный Task активность и удар от рабочего процесса. Как обсуждалось в предыдущем разделе, наш рабочий процесс состоит из оркестратора и одного действия, которые работают совместно следующим образом.
- CronOrchestration (TaskOrchestrator): выполняется в бесконечном цикле и при каждом расписании цикла выполнения и ожидает завершения CronTask. Оркестратор передает инкрементный номер в качестве идентификатора задания в действие CronTask.
- CronTask (TaskActivity): генерирует новое облачное событие при каждом вызове и отправляет запрос POST по URL-адресу, указанному в переменной среды SINK . Значение переменной среды SINK указывает либо на службу (прямая доставка), либо на канал (разнесенная доставка), и оно устанавливается Knative. В этом случае мы доставим облачные события в службу Hello Events (прямая доставка).
Давайте обсудим код в Main
методе, который отвечает за настройку и запуск рабочего процесса.
C #
xxxxxxxxxx
1
var storageConnectionString = Environment.GetEnvironmentVariable("StorageConnectionString");
2
var taskHubName = Environment.GetEnvironmentVariable("TaskHubName");
3
var durationInSeconds = Environment.GetEnvironmentVariable("DurationInSeconds");
4
var mre = new ManualResetEvent(false);
5
var settings = new AzureStorageOrchestrationServiceSettings
7
{
8
StorageConnectionString = storageConnectionString,
9
TaskHubName = taskHubName
10
};
11
var orchestrationServiceAndClient = new AzureStorageOrchestrationService(settings);
12
var taskHubClient = new TaskHubClient(orchestrationServiceAndClient);
14
var taskHub = new TaskHubWorker(orchestrationServiceAndClient);
15
orchestrationServiceAndClient.CreateIfNotExistsAsync().Wait();
17
try
18
{
19
await taskHub
20
.AddTaskOrchestrations(typeof(CronOrchestration))
21
.AddTaskActivities(new CronTask())
22
.StartAsync();
23
var orchestrationInstance = await taskHubClient.CreateOrchestrationInstanceAsync(
25
typeof(CronOrchestration),
26
TimeSpan.FromSeconds(double.Parse(durationInSeconds ?? "5")));
27
Console.WriteLine($"ExecutionId: {orchestrationInstance.ExecutionId}. Blocking main thread.");
29
mre.WaitOne();
30
await taskHub.StopAsync(true);
31
Console.WriteLine("Done!!");
32
}
33
catch (Exception e)
34
{
35
Console.WriteLine($"worker exception: {e}");
36
}
Вы можете использовать служебную шину Azure или хранилище Azure, чтобы сохранить состояние долгосрочной задачи. В этом примере я использовал хранилище Azure для сохранения состояния. Затем мы создали новые экземпляры клиента Task Hub и Task Hub, которые необходимы для взаимодействия с экземплярами Task Orchestration и чтения состояния из хранилища Azure. Если некоторые термины фреймворка кажутся вам запутанными, вам следует прочитать эту небольшую вики-документацию по ключевым словам, используемым в фреймворке.
Наконец, мы начали рабочий процесс, создав новый экземпляр оркестровки и заблокировав основной поток. Давайте теперь посетим код CronOrchestration
класса и обсудим его подробно.
C #
xxxxxxxxxx
1
public override async Task<string> RunTask(OrchestrationContext context, TimeSpan duration)
2
{
3
try
4
{
5
while (true)
6
{
7
var currentTime = context.CurrentUtcDateTime;
8
var fireAt = currentTime.Add(duration);
9
_jobNumber += 1;
10
if (!context.IsReplaying)
11
{
12
Console.WriteLine(
13
$"{context.OrchestrationInstance.InstanceId}: Attempting to queue job {_jobNumber}.");
14
}
15
Console.WriteLine(
17
$"{context.OrchestrationInstance.InstanceId}: Job {_jobNumber} scheduled to run at {fireAt}.");
18
await context.CreateTimer(fireAt, _jobNumber.ToString());
19
Console.WriteLine(await context.ScheduleTask<string>(typeof(CronTask), _jobNumber.ToString()));
20
}
21
}
22
catch (Exception e)
23
{
24
Console.WriteLine(e);
25
throw;
26
}
27
}
Оркестратор выполняется в бесконечном цикле и на каждом цикле выполнения планирует и ожидает выполнения CronTask
. Он передает возрастающее число в качестве аргумента для задачи.
Давайте теперь обсудим окончательный компонент кода приложения, CronTask
класс.
C #
xxxxxxxxxx
1
protected override string Execute(TaskContext context, string input)
2
{
3
try
4
{
5
Result++;
6
var cloudEvent = new CloudEvent("com.hello.cron-event", new Uri("urn:hello-com:cron-source"))
8
{
9
DataContentType = new ContentType(MediaTypeNames.Application.Json),
10
Data = JsonConvert.SerializeObject(new
11
{
12
Id = context.OrchestrationInstance.InstanceId,
13
JobId = input,
14
Result
15
})
16
};
17
var content = new CloudEventContent(cloudEvent, ContentMode.Structured, new JsonEventFormatter());
19
Console.WriteLine($"Going to post data: {JsonConvert.SerializeObject(cloudEvent.Data)} to Url: {Environment.GetEnvironmentVariable("SINK")}");
20
var result = _httpClient.PostAsync(Environment.GetEnvironmentVariable("SINK"), content).Result;
21
return
22
$"Cron Job '{input}' Completed... @{DateTime.UtcNow} Response: {result} Event: {JsonConvert.SerializeObject(cloudEvent.Data)}";
23
}
24
catch (Exception e)
25
{
26
Console.WriteLine(e);
27
throw;
28
}
29
}
CronTask
Класс достаточно прост. Он создает новое облачное событие и отправляет его в качестве полезной нагрузки запроса POST на URL-адрес, представленный в качестве значения SINK
переменной среды.
Вы можете использовать вспомогательный сценарий, расположенный в корне решения, build-push-run.cmd , чтобы создавать образы контейнеров, передавать их в реестр и, наконец, выполнять их в локальной системе.
Развертывание приложения
Спецификация для развертывания приложения называется appspec.yaml, и она находится в корне решения. Давайте обсудим каждую спецификацию в этом файле, начиная с пространства имен.
YAML
xxxxxxxxxx
1
apiVersion v1
2
kind Namespace
3
metadata
4
name kn-app
5
labels
6
knative-eventing-injection enabled
7
istio-injection enabled
Эта спецификация инструктирует Istio вводить коляску для наших сервисов и инструктирует Knative добавить брокера по умолчанию для пространства имен. Давайте теперь настроим наш контейнерный источник.
YAML
xxxxxxxxxx
1
apiVersion sources.eventing.knative.dev/v1alpha1
2
kind ContainerSource
3
metadata
4
name hello-orchestrator
5
namespace kn-app
6
spec
7
image rahulrai/hello-orchestrator
8
env
9
name StorageConnectionString
10
value"DefaultEndpointsProtocol=https;AccountName={account name};AccountKey={account key};EndpointSuffix=core.windows.net"
11
name TaskHubName
12
value"DTFHub"
13
name DurationInSeconds
14
value"10"
15
sink
16
apiVersion serving.knative.dev/v1alpha1
17
kind Service
18
name hello-events
19
namespace kn-app
Чтобы выполнить контейнер hello-orchestrator в качестве источника событий, нам нужно создать конкретный ContainerSource и указать аргументы и соответствующие параметры среды. Переменные среды, установленные в спецификациях, передаются в контейнер.
SinkBinding
Связывает производитель событий для потребителя событий. В предыдущей спецификации мы указали приемник, в который источник-контейнер должен отправлять события. В нашем случае это hello-events
служба, которую мы развернем в том же пространстве имен.
Наконец, давайте перейдем к спецификации, отвечающей за публикацию hello-events
сервиса в качестве сервиса Knative.
YAML
xxxxxxxxxx
1
apiVersion serving.knative.dev/v1
2
kind Service
3
metadata
4
name hello-events
5
namespace kn-app
6
spec
7
template
8
spec
9
containers
10
image rahulrai/hello-events
11
ports
12
name http1
13
containerPort80
Для предоставления услуги Knative вам необходимо указать название службы, образ службы и порт, по которому клиенты могут обращаться к вашей службе.
Чтобы развернуть приложение, выполните следующую команду.
Оболочка
xxxxxxxxxx
1
$ kubectl apply -f appspec.yaml
2
namespace/kn-app created
4
containersource.sources.eventing.knative.dev/hello-orchestrator created
5
service.serving.knative.dev/hello-events created
Родной Контейнер Источник и Сервис в Действии
hello-events
Обслуживание просто обычный Knative сервис, и он может отвечать на запросы HTTP , выданные клиентам. Чтобы получить имя хоста, которое распознает ваша служба, выполните следующую команду.
Оболочка
1
$ kubectl get ksvc -n kn-app
2
NAME URL LATESTCREATED LATESTREADY READY
4
hello-events http://hello-events.kn-app.example.com hello-events-zlh78 hello-events-zlh78 True
Затем выполните HTTP-запрос, передавая имя хоста, которое вы получили в выходных данных, следующим образом.
Оболочка
xxxxxxxxxx
1
$ curl -H "Host: hello-events.kn-app.example.com" http://localhost
2
Hello World!
Обратите внимание, что при развертывании службы Knative в облаке вам не нужно передавать имя хоста в заголовке запроса.
Давайте проверим журналы источника контейнера и службы Knative, выполнив следующую команду, чтобы проследить журналы hello-orchestrator
.
Оболочка
xxxxxxxxxx
1
$ kubectl logs -l sources.eventing.knative.dev/containerSource=hello-orchestrator -n kn-app -c source -f
Следующая команда выполнит потоковую передачу журналов, созданных hello-event
службой.
Оболочка
xxxxxxxxxx
1
$ kubectl logs -l serving.knative.dev/service=hello-events -n kn-app -c user-container -f
На следующем снимке экрана представлен экземпляр потока журнала, созданного обоими компонентами, которые я записал при выполнении предыдущих команд.
Заключение
Хотя Knative находится на ранних стадиях, его документация очень обширна. Существует множество примеров и демонстраций, которые вы можете использовать, чтобы начать работу с Knative. Я пару раз колебался при создании этой демонстрации. Тем не менее, сообщество Knative очень активно и полезно, и они с радостью помогли мне преодолеть эти проблемы. Эта статья - мой небольшой вклад в растущее сообщество Knative.
Дальнейшее чтение
Knative Serving - сервисный звонок
Объясненный контроль, ведение журнала и трассировка