rest-сервисы на asp.net core под linux в продакшене / Денис Иванов...

112
REST-сервисы на ASP .NET Core под Linux в продакшене Денис Иванов [email protected] @denisivanov 1

Upload: ontico

Post on 21-Jan-2018

564 views

Category:

Engineering


8 download

TRANSCRIPT

Page 1: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

REST-сервисы на ASP.NET Core под Linux в продакшене

Денис Иванов

[email protected]

@denisivanov

1

Page 2: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

Обо мне

2

Page 3: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

Цель

Поделиться опытом разработки и запуска в продакшен REST-сервисов на ASP.NET Core на Kubernetes

3

Page 4: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

План

-Коротко о сервисе-On-premise платформа- .NET Core, ASP.NET Core, базовые фичи-Билд-Деплой-Нагрузочное тестирование-Performance

• Кэширование• Асинхронность и многопоточность

4

Page 5: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

Коротко о сервисе

5

Page 6: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

Сервис видеорекламы

6

Page 7: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

Сервис видеорекламы

-99.99% доступность по миру

-Время ответа 200ms*

7

Page 8: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

Сервис видеорекламы

8

Page 9: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

Сервис видеорекламы

9

Page 10: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

Почему Linux

-Cуществующая on-premise платформа•GitLab CI

•CI starting kit на основе make

•Docker hub & docker images

-Компоненты на любом технологическом стеке

-Kubernetes

10

Page 11: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

The Twelve-Factor App (1-6)

-Одно приложение – один репозиторий

-Зависимости – вместе с приложением

-Конфигурация через окружение

-Используемые сервисы как ресурсы

-Фазы билда, создания образов и исполнения разделены

-Сервисы – отдельные stateless процессы

11https://12factor.net

Page 12: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

The Twelve-Factor App (7-12)

-Port binding

-Масштабирование через процессы

-Быстрая остановка и запуск процессов

-Среды максимально похожи

-Логирование в stdout

-Административные процессы

12https://12factor.net

Page 13: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

Код и презентация

https://github.com/denisivan0v/backend-conf-2017

13

Page 14: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

-Коротко о сервисе

-On-premise платформа

-.NET Core, ASP.NET Core, базовые фичи

-Билд

-Деплой

-Нагрузочное тестирование

-Performance•Кэширование•Асинхронность и многопоточность

14

Page 15: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

.NET Core

15http://www.telerik.com/blogs/the-new-net-core-1-is-here

Page 16: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

.NET Core

16https://blogs.windows.com/buildingapps/2015/04/29/expanding-the-universal-windows-platform-at-build-2015/

Page 17: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

.NET Core

17http://www.telerik.com/blogs/the-new-net-core-1-is-here

Page 18: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

.NET Core

18http://www.c-sharpcorner.com/article/getting-started-with-net-core-on-visual-studio-2017/

Page 19: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

.NET Core. Self-contained deployment

-Полный контроль зависимостей

-Явное указание платформы при билде(win10-x64 / ubuntu.16.04-x64 / osx.10.12-x64)

-Только необходимый фреймворк netstandard1.6•Microsoft.NETCore.Runtime.CoreCLR

•Microsoft.NETCore.DotNetHostPolicy

19

Page 20: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

ASP.NET Core

20

Page 21: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

public sealed class HealthCheckMiddleware{

private const string Path = "/healthcheck";private readonly RequestDelegate _next;

public HealthCheckMiddleware(RequestDelegate next){

_next = next;}

public async Task Invoke(HttpContext context){

if (!context.Request.Path.Equals(Path, StringComparison.OrdinalIgnoreCase)){

await _next(context);}else{

context.Response.ContentType = "text/plain";context.Response.StatusCode = 200;context.Response.Headers.Add(HeaderNames.Connection, "close");await context.Response.WriteAsync("OK");

}}

}21

Page 22: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

public sealed class HealthCheckMiddleware{

private const string Path = "/healthcheck";private readonly RequestDelegate _next;

public HealthCheckMiddleware(RequestDelegate next){

_next = next;}

public async Task Invoke(HttpContext context){

if (!context.Request.Path.Equals(Path, StringComparison.OrdinalIgnoreCase)){

await _next(context);}else{

context.Response.ContentType = "text/plain";context.Response.StatusCode = 200;context.Response.Headers.Add(HeaderNames.Connection, "close");await context.Response.WriteAsync("OK");

}}

}22

Page 23: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

public sealed class HealthCheckMiddleware{

private const string Path = "/healthcheck";private readonly RequestDelegate _next;

public HealthCheckMiddleware(RequestDelegate next){

_next = next;}

public async Task Invoke(HttpContext context){

if (!context.Request.Path.Equals(Path, StringComparison.OrdinalIgnoreCase)){

await _next(context);}else{

context.Response.ContentType = "text/plain";context.Response.StatusCode = 200;context.Response.Headers.Add(HeaderNames.Connection, "close");await context.Response.WriteAsync("OK");

}}

}23

Page 24: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

public sealed class HealthCheckMiddleware{

private const string Path = "/healthcheck";private readonly RequestDelegate _next;

public HealthCheckMiddleware(RequestDelegate next){

_next = next;}

public async Task Invoke(HttpContext context){

if (!context.Request.Path.Equals(Path, StringComparison.OrdinalIgnoreCase)){

await _next(context);}else{

context.Response.ContentType = "text/plain";context.Response.StatusCode = 200;context.Response.Headers.Add(HeaderNames.Connection, "close");await context.Response.WriteAsync("OK");

}}

}24

Page 25: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

public sealed class HealthCheckMiddleware{

private const string Path = "/healthcheck";private readonly RequestDelegate _next;

public HealthCheckMiddleware(RequestDelegate next){

_next = next;}

public async Task Invoke(HttpContext context){

if (!context.Request.Path.Equals(Path, StringComparison.OrdinalIgnoreCase)){

await _next(context);}else{

context.Response.ContentType = "text/plain";context.Response.StatusCode = 200;context.Response.Headers.Add(HeaderNames.Connection, "close");await context.Response.WriteAsync("OK");

}}

}25

Page 26: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

Базовые фичи REST-сервисов

-Логирование•Структурное логирование

-Версионирование API• SemVer

•DateTime

-Формальное описание API• Swagger

26

Page 27: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

Структурное логирование

27

https://serilog.net/

Page 28: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

appsettings.json{

"Serilog": {"MinimumLevel": "Debug","WriteTo": [

{"Name": "Console","Args": {

"formatter":"Serilog.Formatting.Compact.RenderedCompactJsonFormatter, Serilog.Formatting.Compact"

}}

],"Enrich": [ "FromLogContext", "WithThreadId" ]

}}

28

Page 29: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

appsettings.json{

"Serilog": {"MinimumLevel": "Debug","WriteTo": [

{"Name": "Console","Args": {

"formatter":"Serilog.Formatting.Compact.RenderedCompactJsonFormatter, Serilog.Formatting.Compact"

}}

],"Enrich": [ "FromLogContext", "WithThreadId" ]

}}

29

Page 30: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

appsettings.json{

"Serilog": {"MinimumLevel": "Debug","WriteTo": [

{"Name": "Console","Args": {

"formatter":"Serilog.Formatting.Compact.RenderedCompactJsonFormatter, Serilog.Formatting.Compact"

}}

],"Enrich": [ "FromLogContext", "WithThreadId" ]

}}

30

Page 31: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

appsettings.json{

"Serilog": {"MinimumLevel": "Debug","WriteTo": [

{"Name": "Console","Args": {

"formatter":"Serilog.Formatting.Compact.RenderedCompactJsonFormatter, Serilog.Formatting.Compact"

}}

],"Enrich": [ "FromLogContext", "WithThreadId" ]

}}

31

Page 32: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

appsettings.json{

"Serilog": {"MinimumLevel": "Debug","WriteTo": [

{"Name": "Console","Args": {

"formatter":"Serilog.Formatting.Compact.RenderedCompactJsonFormatter, Serilog.Formatting.Compact"

}}

],"Enrich": [ "FromLogContext", "WithThreadId" ]

}}

32

Page 33: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

ASP.NET API versioning

- https://github.com/Microsoft/aspnet-api-versioning- Microsoft REST versioning guidelines

• /api/foo?api-version=1.0• /api/foo?api-version=2.0-Alpha• /api/foo?api-version=2015-05-01.3.0• /api/v1/foo• /api/v2.0-Alpha/foo• /api/v2015-05-01.3.0/foo

33

Page 34: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

[ApiVersion("1.0")][Route(“api/medias")] // /api/medias[Route(“api/{version:apiVersion}/medias")] // /api/1.0/mediaspublic sealed class MediasController : Controller{

// /api/medias/id?api-version=1.0 or /api/1.0/medias/id[HttpGet("{id}")]public async Task<IActionResult> Get(long id){

…}

}

34

Page 35: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

[ApiVersion("1.0")][Route(“api/medias")] // /api/medias[Route(“api/{version:apiVersion}/medias")] // /api/1.0/mediaspublic sealed class MediasController : Controller{

// /api/medias/id?api-version=1.0 or /api/1.0/medias/id[HttpGet("{id}")]public async Task<IActionResult> Get(long id){

…}

}

35

Page 36: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

[ApiVersion("1.0")][Route(“api/medias")] // /api/medias[Route(“api/{version:apiVersion}/medias")] // /api/1.0/mediaspublic sealed class MediasController : Controller{

// /api/medias/id?api-version=1.0 or /api/1.0/medias/id[HttpGet("{id}")]public async Task<IActionResult> Get(long id){

…}

}

36

Page 37: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

[ApiVersion("1.0")][Route(“api/medias")] // /api/medias[Route(“api/{version:apiVersion}/medias")] // /api/1.0/mediaspublic sealed class MediasController : Controller{

// /api/medias/id?api-version=1.0 or /api/1.0/medias/id[HttpGet("{id}")]public async Task<IActionResult> Get(long id){

…}

}

37

Page 38: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

[ApiVersion("1.0")][Route(“api/medias")] // /api/medias[Route(“api/{version:apiVersion}/medias")] // /api/1.0/mediaspublic sealed class MediasController : Controller{

// /api/medias/id?api-version=1.0 or /api/1.0/medias/id[HttpGet("{id}")]public async Task<IActionResult> Get(long id){

…}

}

38

Page 39: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

[ApiVersion("1.0")][ApiVersion(“2.0")][Route(“api/medias")][Route(“api/{version:apiVersion}/medias")] public sealed class MediasController : GatewayController{

// /api/medias/id?api-version=1.0 or /api/1.0/medias/id[HttpGet("{id}")]public async Task<IActionResult> Get(long id){

…}

// /api/medias/id?api-version=2.0 or /api/2.0/medias/id[MapToApiVersion(“2.0")][HttpGet("{id}")]public async Task<IActionResult> GetV2(long id){

…}

} 39

Page 40: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

[ApiVersion("1.0")][ApiVersion(“2.0")][Route(“api/medias")][Route(“api/{version:apiVersion}/medias")]public sealed class MediasController : GatewayController{

// /api/medias/id?api-version=1.0 or /api/1.0/medias/id[HttpGet("{id}")]public async Task<IActionResult> Get(long id){

…}

// /api/medias/id?api-version=2.0 or /api/2.0/medias/id[MapToApiVersion(“2.0")][HttpGet("{id}")]public async Task<IActionResult> GetV2(long id){

…}

} 40

Page 41: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

[ApiVersion("1.0")][ApiVersion(“2.0")][Route(“api/medias")][Route(“api/{version:apiVersion}/medias")] public sealed class MediasController : GatewayController{

// /api/medias/id?api-version=1.0 or /api/1.0/medias/id[HttpGet("{id}")]public async Task<IActionResult> Get(long id){

…}

// /api/medias/id?api-version=2.0 or /api/2.0/medias/id[MapToApiVersion(“2.0")][HttpGet("{id}")]public async Task<IActionResult> GetV2(long id){

…}

} 41

Page 42: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

https://github.com/domaindrivendev/Swashbuckle.AspNetCore

42

Page 43: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

services.AddSwaggerGen(x =>{

IApiVersionDescriptionProvider provider;foreach (var description in provider.ApiVersionDescriptions){

x.SwaggerDoc(description.GroupName, new Info { … });}

});

app.UseSwagger();app.UseSwaggerUI(

c =>{

IApiVersionDescriptionProvider provider;foreach (var description in provider.ApiVersionDescriptions){

options.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json",description.GroupName.ToUpperInvariant());

}});

43

Page 44: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

services.AddSwaggerGen(x =>{

IApiVersionDescriptionProvider provider;foreach (var description in provider.ApiVersionDescriptions){

x.SwaggerDoc(description.GroupName, new Info { … });}

});

app.UseSwagger();app.UseSwaggerUI(

c =>{

IApiVersionDescriptionProvider provider;foreach (var description in provider.ApiVersionDescriptions){

options.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json",description.GroupName.ToUpperInvariant());

}});

44

Page 45: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

services.AddSwaggerGen(x =>{

IApiVersionDescriptionProvider provider;foreach (var description in provider.ApiVersionDescriptions){

x.SwaggerDoc(description.GroupName, new Info { … });}

});

app.UseSwagger();app.UseSwaggerUI(

c =>{

IApiVersionDescriptionProvider provider;foreach (var description in provider.ApiVersionDescriptions){

options.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json",description.GroupName.ToUpperInvariant());

}});

45

Page 46: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

-Коротко о сервисе

-On-premise платформа

-.NET Core, ASP.NET Core, базовые фичи

-Билд

-Деплой

-Нагрузочное тестирование

-Performance•Кэширование•Асинхронность и многопоточность

46

Page 47: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

build:backend-conf-demo:image: $REGISTRY/microsoft/aspnetcore-build:1.1.2stage: build:appscript:

- dotnet restore --runtime ubuntu.16.04-x64 - dotnet test Demo.Tests/Demo.Tests.csproj--configuration Release - dotnet publish Demo --configuration Release --runtime ubuntu.16.04-x64 --output publish/backend-conf

tags: [ 2gis, docker ]artifacts:

paths:- publish/backend-conf/

47

Page 48: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

build:backend-conf-demo:image: $REGISTRY/microsoft/aspnetcore-build:1.1.2stage: build:appscript:

- dotnet restore --runtime ubuntu.16.04-x64 - dotnet test Demo.Tests/Demo.Tests.csproj--configuration Release - dotnet publish Demo --configuration Release --runtime ubuntu.16.04-x64 --output publish/backend-conf

tags: [ 2gis, docker ]artifacts:

paths:- publish/backend-conf/

48

Page 49: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

build:backend-conf-demo:image: $REGISTRY/microsoft/aspnetcore-build:1.1.2stage: build:appscript:

- dotnet restore --runtime ubuntu.16.04-x64 - dotnet test Demo.Tests/Demo.Tests.csproj--configuration Release - dotnet publish Demo --configuration Release --runtime ubuntu.16.04-x64 --output publish/backend-conf

tags: [ 2gis, docker ]artifacts:

paths:- publish/backend-conf/

49

Page 50: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

build:backend-conf-demo:image: $REGISTRY/microsoft/aspnetcore-build:1.1.2stage: build:appscript:

- dotnet restore --runtime ubuntu.16.04-x64 - dotnet test Demo.Tests/Demo.Tests.csproj--configuration Release - dotnet publish Demo --configuration Release --runtime ubuntu.16.04-x64 --output publish/backend-conf

tags: [ 2gis, docker ]artifacts:

paths:- publish/backend-conf/

50

Page 51: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

build:backend-conf-demo:image: $REGISTRY/microsoft/aspnetcore-build:1.1.2stage: build:appscript:

- dotnet restore --runtime ubuntu.16.04-x64 - dotnet test Demo.Tests/Demo.Tests.csproj--configuration Release - dotnet publish Demo --configuration Release --runtime ubuntu.16.04-x64 --output publish/backend-conf

tags: [ 2gis, docker ]artifacts:

paths:- publish/backend-conf/

51

Page 52: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

build:backend-conf-demo-image:stage: build:appscript:- IMAGE=my-namespace/backend-conf TAG=$CI_TAGDOCKER_FILE=publish/backend-conf/DockerfileDOCKER_BUILD_CONTEXT=publish/backend-confmake docker-build

- IMAGE=my-namespace/backend-conf TAG=$CI_TAG make docker-push

tags: [ docker-engine, io ]dependencies:- build:app

52

Page 53: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

build:backend-conf-demo-image:stage: build:appscript:- IMAGE=my-namespace/backend-conf TAG=$CI_TAGDOCKER_FILE=publish/backend-conf/DockerfileDOCKER_BUILD_CONTEXT=publish/backend-confmake docker-build

- IMAGE=my-namespace/backend-conf TAG=$CI_TAG make docker-push

tags: [ docker-engine, io ]dependencies:- build:app

53

Page 54: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

build:backend-conf-demo-image:stage: build:appscript:- IMAGE=my-namespace/backend-conf TAG=$CI_TAGDOCKER_FILE=publish/backend-conf/DockerfileDOCKER_BUILD_CONTEXT=publish/backend-confmake docker-build

- IMAGE=my-namespace/backend-conf TAG=$CI_TAG make docker-push

tags: [ docker-engine, io ]dependencies:- build:app

54

Page 55: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

build:backend-conf-demo-image:stage: build:appscript:- IMAGE=my-namespace/backend-conf TAG=$CI_TAGDOCKER_FILE=publish/backend-conf/DockerfileDOCKER_BUILD_CONTEXT=publish/backend-confmake docker-build

- IMAGE=my-namespace/backend-conf TAG=$CI_TAG make docker-push

tags: [ docker-engine, io ]dependencies:- build:app

55

Page 56: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

-Коротко о сервисе

-On-premise платформа

-.NET Core, ASP.NET Core, базовые фичи

-Билд

-Деплой

-Нагрузочное тестирование

-Performance•Кэширование•Асинхронность и многопоточность

56

Page 57: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

Kubernetes

57

Page 58: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

Kubernetes

58

Page 59: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

Kubernetes

59

Page 60: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

Kubernetes

60

Page 61: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

Kubernetes

61

Page 62: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

62

Page 63: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

apiVersion: extensions/v1beta1kind: Deploymentmetadata:

name: {{ app_name }}spec:

replicas: {{ replicas_count }}template:metadata:

labels:app: {{ app_name }}

spec:containers:- name: backend-confimage: {{ image_path }}:{{ image_version }}ports:- containerPort: {{ app_port }}readinessProbe:httpGet: { path: '{{ app_probe_path }}', port: {{ app_port }} }initialDelaySeconds: 10periodSeconds: 10

env:- name: ASPNETCORE_ENVIRONMENTvalue: {{ env }}

63

Page 64: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

apiVersion: extensions/v1beta1kind: Deploymentmetadata:

name: {{ app_name }}spec:

replicas: {{ replicas_count }}template:metadata:

labels:app: {{ app_name }}

spec:containers:- name: backend-confimage: {{ image_path }}:{{ image_version }}ports:- containerPort: {{ app_port }}readinessProbe:httpGet: { path: '{{ app_probe_path }}', port: {{ app_port }} }initialDelaySeconds: 10periodSeconds: 10

env:- name: ASPNETCORE_ENVIRONMENTvalue: {{ env }}

64

Page 65: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

apiVersion: extensions/v1beta1kind: Deploymentmetadata:

name: {{ app_name }}spec:

replicas: {{ replicas_count }}template:metadata:

labels:app: {{ app_name }}

spec:containers:- name: backend-confimage: {{ image_path }}:{{ image_version }}ports:- containerPort: {{ app_port }}readinessProbe:httpGet: { path: '{{ app_probe_path }}', port: {{ app_port }} }initialDelaySeconds: 10periodSeconds: 10

env:- name: ASPNETCORE_ENVIRONMENTvalue: {{ env }}

65

Page 66: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

apiVersion: extensions/v1beta1kind: Deploymentmetadata:

name: {{ app_name }}spec:

replicas: {{ replicas_count }}template:metadata:

labels:app: {{ app_name }}

spec:containers:- name: backend-confimage: {{ image_path }}:{{ image_version }}ports:- containerPort: {{ app_port }}readinessProbe:httpGet: { path: '{{ app_probe_path }}', port: {{ app_port }} }initialDelaySeconds: 10periodSeconds: 10

env:- name: ASPNETCORE_ENVIRONMENTvalue: {{ env }}

66

Page 67: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

apiVersion: extensions/v1beta1kind: Deploymentmetadata:

name: {{ app_name }}spec:

replicas: {{ replicas_count }}template:metadata:

labels:app: {{ app_name }}

spec:containers:- name: backend-confimage: {{ image_path }}:{{ image_version }}ports:- containerPort: {{ app_port }}readinessProbe:httpGet: { path: '{{ app_probe_path }}', port: {{ app_port }} }initialDelaySeconds: 10periodSeconds: 10

env:- name: ASPNETCORE_ENVIRONMENTvalue: {{ env }}

67

Page 68: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

apiVersion: extensions/v1beta1kind: Deploymentmetadata:

name: {{ app_name }}spec:

replicas: {{ replicas_count }}template:metadata:

labels:app: {{ app_name }}

spec:containers:- name: backend-confimage: {{ image_path }}:{{ image_version }}ports:- containerPort: {{ app_port }}readinessProbe:httpGet: { path: '{{ app_probe_path }}', port: {{ app_port }} }initialDelaySeconds: 10periodSeconds: 10

env:- name: ASPNETCORE_ENVIRONMENTvalue: {{ env }}

68

Page 69: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

apiVersion: v1kind: Servicemetadata:

name: {{ app_name }}annotations:

router.deis.io/domains: "{{ app_name }}"router.deis.io/ssl.enforce: "{{ ssl_enforce | default('False') }}"

spec:ports:

- name: httpport: 80targetPort: {{ app_port }}

selector:app: {{ app_name }}

69

Page 70: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

apiVersion: v1kind: Servicemetadata:

name: {{ app_name }}annotations:

router.deis.io/domains: "{{ app_name }}"router.deis.io/ssl.enforce: "{{ ssl_enforce | default('False') }}"

spec:ports:

- name: httpport: 80targetPort: {{ app_port }}

selector:app: {{ app_name }}

70

Page 71: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

apiVersion: v1kind: Servicemetadata:

name: {{ app_name }}annotations:

router.deis.io/domains: "{{ app_name }}"router.deis.io/ssl.enforce: "{{ ssl_enforce | default('False') }}"

spec:ports:

- name: httpport: 80targetPort: {{ app_port }}

selector:app: {{ app_name }}

71

Page 72: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

common:replicas_count: 1max_unavailable: 0

k8s_master_uri: https://master.staging.dc-nsk1.hw:6443k8s_token: "{{ env='K8S_TOKEN_STAGE' }}"k8s_ca_base64: "{{ env='K8S_CA' }}"k8s_namespace: my-namespacessl_enforce: true

app_port: 5000app_probe_path: /healthcheck

image_version: "{{ env='CI_TAG' }}"image_path: docker-hub.2gis.ru/my-namespace/backend-confenv: Stage

backend-conf-demo:app_name: “backend-conf-demo"

app_limits_cpu: 500mapp_requests_cpu: 100mapp_limits_memory: 800Miapp_requests_memory: 300Mi

kubectl:- template: deployment.yaml.j2- template: service-stage.yaml.j2

72

Page 73: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

common:replicas_count: 1max_unavailable: 0

k8s_master_uri: https://master.staging.dc-nsk1.hw:6443k8s_token: "{{ env='K8S_TOKEN_STAGE' }}"k8s_ca_base64: "{{ env='K8S_CA' }}"k8s_namespace: my-namespacessl_enforce: true

app_port: 5000app_probe_path: /healthcheck

image_version: "{{ env='CI_TAG' }}"image_path: docker-hub.2gis.ru/my-namespace/backend-confenv: Stage

backend-conf-demo:app_name: “backend-conf-demo"

app_limits_cpu: 500mapp_requests_cpu: 100mapp_limits_memory: 800Miapp_requests_memory: 300Mi

kubectl:- template: deployment.yaml.j2- template: service-stage.yaml.j2

73

Page 74: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

common:replicas_count: 1max_unavailable: 0

k8s_master_uri: https://master.staging.dc-nsk1.hw:6443k8s_token: "{{ env='K8S_TOKEN_STAGE' }}"k8s_ca_base64: "{{ env='K8S_CA' }}"k8s_namespace: my-namespacessl_enforce: true

app_port: 5000app_probe_path: /healthcheck

image_version: "{{ env='CI_TAG' }}"image_path: docker-hub.2gis.ru/my-namespace/backend-confenv: Stage

backend-conf-demo:app_name: “backend-conf-demo"

app_limits_cpu: 500mapp_requests_cpu: 100mapp_limits_memory: 800Miapp_requests_memory: 300Mi

kubectl:- template: deployment.yaml.j2- template: service-stage.yaml.j2

74

Page 75: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

common:replicas_count: 1max_unavailable: 0

k8s_master_uri: https://master.staging.dc-nsk1.hw:6443k8s_token: "{{ env='K8S_TOKEN_STAGE' }}"k8s_ca_base64: "{{ env='K8S_CA' }}"k8s_namespace: my-namespacessl_enforce: true

app_port: 5000app_probe_path: /healthcheck

image_version: "{{ env='CI_TAG' }}"image_path: docker-hub.2gis.ru/my-namespace/backend-confenv: Stage

backend-conf-demo:app_name: “backend-conf-demo"

app_limits_cpu: 500mapp_requests_cpu: 100mapp_limits_memory: 800Miapp_requests_memory: 300Mi

kubectl:- template: deployment.yaml.j2- template: service-stage.yaml.j2

75

Page 76: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

deploy:backend-conf-demo-stage:stage: deploy:stagewhen: manualimage: $REGISTRY/2gis-io/k8s-handle:latestscript:

- export ENVIRONMENT=Stage- k8s-handle deploy --config config-stage.yaml--section backend-conf --sync-mode True

only:- tags

tags: [ 2gis, docker ]

76

Page 77: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

deploy:backend-conf-demo-stage:stage: deploy:stagewhen: manualimage: $REGISTRY/2gis-io/k8s-handle:latestscript:

- export ENVIRONMENT=Stage- k8s-handle deploy --config config-stage.yaml--section backend-conf --sync-mode True

only:- tags

tags: [ 2gis, docker ]

77

Page 78: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

-Коротко о сервисе

-On-premise платформа

-.NET Core, ASP.NET Core, базовые фичи

-Билд

-Деплой

-Нагрузочное тестирование

-Performance•Кэширование•Асинхронность и многопоточность

78

Page 79: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

Нагрузочный контур

79

Page 80: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

80

Page 81: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

81

Page 82: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

82

Page 83: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

83

Page 84: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

.perf:template: &perf_templatestage: test:perfenvironment: perfonly:

- master- /^perf.*$/

variables:PERF_TEST_PATH: "tests/perf"PERF_ARTIFACTS: "target/gatling"PERF_GRAPHITE_HOST: "graphite-exporter.perf.os-n3.hw"PERF_GRAPHITE_ROOT_PATH_PREFIX: "gatling.service-prefix"

image: $REGISTRY/perf/tools:1artifacts:

name: perf-reportswhen: alwaysexpire_in: 7 daypaths:

- ${PERF_TEST_PATH}/${PERF_ARTIFACTS}/*tags: [perf-n3-1]

84

Page 85: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

perf:run-tests:<<: *perf_templatescript:

- export PERF_GRAPHITE_ROOT_PATH_PREFIX PERF_GRAPHITE_HOST

- export PERF_APP_HOST=http://${APP_PERF}.web-staging.2gis.ru

- cd ${PERF_TEST_PATH}- ./run_test.sh --capacity- ./run_test.sh --resp_time

after_script:- perfberry-cli logs upload --dir

${PERF_TEST_PATH}/${PERF_ARTIFACTS} --env ${APP_PERF}.web-staging.2gis.ru gatling ${PERFBERRY_PROJECT_ID}

85

Page 86: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

perf:run-tests:<<: *perf_templatescript:

- export PERF_GRAPHITE_ROOT_PATH_PREFIX PERF_GRAPHITE_HOST

- export PERF_APP_HOST=http://${APP_PERF}.web-staging.2gis.ru

- cd ${PERF_TEST_PATH}- ./run_test.sh --capacity- ./run_test.sh --resp_time

after_script:- perfberry-cli logs upload --dir

${PERF_TEST_PATH}/${PERF_ARTIFACTS} --env ${APP_PERF}.web-staging.2gis.ru gatling ${PERFBERRY_PROJECT_ID}

86

Page 87: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

perf:run-tests:<<: *perf_templatescript:

- export PERF_GRAPHITE_ROOT_PATH_PREFIX PERF_GRAPHITE_HOST

- export PERF_APP_HOST=http://${APP_PERF}.web-staging.2gis.ru

- cd ${PERF_TEST_PATH}- ./run_test.sh --capacity- ./run_test.sh --resp_time

after_script:- perfberry-cli logs upload --dir

${PERF_TEST_PATH}/${PERF_ARTIFACTS} --env ${APP_PERF}.web-staging.2gis.ru gatling ${PERFBERRY_PROJECT_ID}

87

Page 88: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

-Коротко о сервисе

-On-premise платформа

-.NET Core, ASP.NET Core, базовые фичи

-Билд

-Деплой

-Нагрузочное тестирование

-Performance•Кэширование•Асинхронность и многопоточность

88

Page 89: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

Кеширование

89

[AllowAnonymous][HttpGet("{id}")][ResponseCache(

VaryByQueryKeys = new[] { "api-version" }, Duration = 3600)]

public async Task<IActionResult> Get(long id){

…}

Page 90: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

Кеширование

-На клиенте•Cache-Control header (HTTP 1.1 Caching)

90

[ResponseCache(VaryByQueryKeys = new[] { "api-version" },Duration = 3600)]

Page 91: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

Кеширование

-На клиенте•Cache-Control header (HTTP 1.1 Caching)

-На сервере•Response Caching Middleware (docs)

91

[ResponseCache(VaryByQueryKeys = new[] { "api-version" },Duration = 3600)]

Page 92: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

Performance

92

Асинхронность Многопоточность

Page 93: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

Performance

93

Thread1

Task1

Асинхронность

Task2

Task1

Thread1

Task1

Многопоточность

Task2

Thread2

Task3

Task4

Page 94: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

94

var data = await _remoteService.IOBoundOperationAsync(timeoutInSec: 1);var result = new List<string>[data.Count];

foreach (var item in data){

var detailed = await _remoteService.IOBoundOperationAsync(timeoutInSec: 5);

result.Add(string.Join(", ", detailed));}

Page 95: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

95

var data = await _remoteService.IOBoundOperationAsync(timeoutInSec: 1);var result = new List<string>[data.Count];

foreach (var item in data){

var detailed = await _remoteService.IOBoundOperationAsync(timeoutInSec: 5);

result.Add(string.Join(", ", detailed));}

Page 96: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

96

var data = await _remoteService.IOBoundOperationAsync(timeoutInSec: 1);var result = new string[data.Count];

var tasks = data.Select(async (item, index) =>{var detailed = await _remoteService.IOBoundOperationAsync(timeoutInSec: 5);

result[index] = string.Join(", ", detailed)});

await Task.WhenAll(tasks);

Page 97: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

97

var data = await _remoteService.IOBoundOperationAsync(timeoutInSec: 1);var result = new string[data.Count];

var tasks = data.Select(async (item, index) =>{var detailed = await _remoteService.IOBoundOperationAsync(timeoutInSec: 5);

result[index] = string.Join(", ", detailed)});

await Task.WhenAll(tasks);

Page 98: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

98

var data = await _remoteService.IOBoundOperationAsync(timeoutInSec: 1);var result = new string[data.Count];

var tasks = data.Select(async (item, index) =>{var detailed = await _remoteService.IOBoundOperationAsync(timeoutInSec: 5);

result[index] = string.Join(", ", detailed)});

await Task.WhenAll(tasks);

Page 99: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

Нагрузочное тестирование

-Лимиты по памяти и процессору•384Mb и 1,5 CPU

99

Page 100: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

Нагрузочное тестирование

-Лимиты по памяти и процессору•384Mb и 1,5 CPU

-Синхронный (capacity) тест•~24 RPS (без кэша)

100

Page 101: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

Нагрузочное тестирование

-Лимиты по памяти и процессору•384Mb и 1,5 CPU

-Синхронный (capacity) тест•~24 RPS (без кэша)

•~400 RPS (включен серверный кэш)

101

Page 102: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

Нагрузочное тестирование

-Лимиты по памяти и процессору•384Mb и 1,5 CPU

-Синхронный (capacity) тест•~24 RPS (без кэша)

•~400 RPS (включен серверный кэш)

-Асинхронный (load) тест•Прошёл

102

Page 103: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

Вместо заключения

103

Page 104: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

Вместо заключения

-Не бойтесь использовать .NET Core в продакшене

104

Page 105: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

Вместо заключения

-Не бойтесь использовать .NET Core в продакшене

-Не бойтесь использовать Linux и .NET Core

105

Page 106: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

Вместо заключения

-Не бойтесь использовать .NET Core в продакшене

-Не бойтесь использовать Linux и .NET Core

-Docker и Kubernetes сильно упрощают жизнь

106

Page 107: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

Вместо заключения

-Не бойтесь использовать .NET Core в продакшене

-Не бойтесь использовать Linux и .NET Core

-Docker и Kubernetes сильно упрощают жизнь

-Оптимизируйте приложения

107

Page 108: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

Вместо заключения

-Не бойтесь использовать .NET Core в продакшене

-Не бойтесь использовать Linux и .NET Core

-Docker и Kubernetes сильно упрощают жизнь

-Оптимизируйте приложения•Многое есть из коробки

•Думать все равно надо

108

Page 109: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

Спасибо!

https://github.com/denisivan0v/backend-conf-2017

109

Page 110: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

Вопросы?

Денис Иванов@denisivanov

[email protected]://github.com/denisivan0v

110

Page 111: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

Эксплуатация

111

Page 112: REST-сервисы на ASP.NET Core под Linux в продакшене / Денис Иванов (2ГИС)

Эксплуатация

-Prometheus server (/metrics)

112