Создание приложения на .NET Core и Kubernetes: наш опыт

    Всем привет!

    Сегодня расскажем об опыте одного из наших DevOps проектов. Мы решили реализовать новое приложение под Linux с использованием .Net Core на микросервисной архитектуре.

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

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

    Поэтому использовали такие технологии:

    • .Net Core для реализации микросервисов. В нашем проекте использовалась версия 2.0,
    • Kubernetes для оркестрации микросервисов,
    • Docker для создания образов микросервисов,
    • шина интеграции Rabbit MQ и Mass Transit,
    • Elasticsearch и Kibana для логирования,
    • TFS для реализации конвейера CI/CD.

    В этой статье поделимся подробностями нашего решения.



    Это расшифровка нашего выступления на .NET-митапе, вот ссылка на видео выступления.

    Наша бизнес-задача


    Наш заказчик — это федеральная компания, где есть мерчендайзеры — это люди, которые отвечают за то, как представлены товары в магазинах. А ещё есть супервайзеры – это руководители мерчендайзеров.

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



    Вот как работает наше решение:

    1. Супервайзер составляет анкету – это чеклист того, что нужно проверить в работе мерчендайзера.
    2. Далее супервайзер выбирает сотрудника, чью работу будет проверять. Назначается дата анкетирования.
    3. Далее активность отправляется на мобильное устройство супервайзера.
    4. Затем анкета заполняется и отправляется на портал.
    5. На портале формируются результаты и различные отчеты.

    Микросервисы помогут нам решить три задачи:


    1. Мы в перспективе хотим легко расширять функционал, так как подобных бизнес-процессов в компании много.
    2. Мы хотим, чтобы решение было отказоустойчивым. Если какая-то часть перестанет функционировать, решение сможет самостоятельно восстановить свою работу, а отказ одной части не сильно повлияет на работу решения в целом.
    3. Компания, для которого мы реализуем решение, имеет много филиалов. Соответственно, количество пользователей решения постоянно растёт. Поэтому хотелось, чтобы это не повлияло на производительность.

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

    Какие технологии помогли реализовать это решение:


    • Docker упрощает распространение дистрибутива решения. Дистрибутив в нашем случае — это набор образов микросервисов
    • Поскольку микросервисов в нашем решении много, нам необходимо ими управлять. Для этого мы используем Kubernetes.
    • Сами микросервисы мы реализуем с помощью .Net Core.
    • Чтобы быстро обновлять решение у заказчика, мы должны реализовать удобную непрерывную интеграцию и доставку.

    Вот наш набор технологий в целом:

    • .Net Core мы используем для создания микросервисов,
    • Микросервис упаковывается в Docker-образ,
    • Непрерывная интеграция и непрерывная доставка реализуется с помощью TFS,
    • Фронтэндная часть реализована на Angular,
    • Для мониторинга и логирования мы используем Elasticsearch и Kibana,
    • RabbitMQ и MassTransit используются как шина интеграции.

    .NET Core для решений под Linux


    Все мы знаем, что такое классический .Net Framework. Основным минусом платформы является то, что она не кроссплатформенная. Соответственно, мы не можем запустить в Docker решения на платформе .Net Framework под Linux.

    Чтобы предоставить возможность использования C# в Docker, Microsoft переосмыслил .Net Framework и создал .Net Core. А чтобы использовать одни и те же библиотеки, Microsoft создал спецификацию .Net Standard Library. Сборки .Net Standart Library могут использоваться и в .Net Framework, и в .Net Core.



    Kubernetes – для оркестрации микросервисов


    Kubernetes используется для управления и кластеризации Docker-контейнеров. Вот главные преимущества Kubernetes, которыми мы воспользовались:

    — предоставляет возможность легкой настройки окружения микросервисов,
    — упрощает управление окружением (Dev, QA, Stage),
    — из коробки предоставляет возможность репликации микросервисов и балансировки нагрузки на реплики.



    Архитектура решения


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

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



    Варианты взаимодействия с внешними потребителями


    Microsoft в своей книге о микросервисах «Микросервисы .NET. Архитектура контейнерных приложений .NET» предлагает три возможные реализации взаимодействия с микросервисами. Мы рассмотрели все три и выбрали наиболее подходящий.

    • API Gateway service
    API Gateway service — это реализация фасада для запросов пользователей к другим сервисам. Проблема решения в том, что если фасад не будет работать, то всё решение перестанет функционировать. От этого подхода решили отказаться ради отказоустойчивости.

    • API Gateway with Azure API Management
    Microsoft предоставляет возможность использования облачного фасада в Azure. Но это решение не подошло, поскольку мы собирались развернуть решение не в облаке, а на серверах заказчика.

    • Direct Client-To-Microservice communication
    В итоге у нас остался последний вариант — непосредственное взаимодействие пользователей с микросервисами. Его мы и выбрали.



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

    Конечно, возникает вопрос, каким образом будем балансироваться нагрузка и каким образом осуществляется отказоустойчивость. Тут все просто — этим занимается Ingress Controller Kubernetes.



    Node 1, node 2 и node 3 – это реплики одного микросервиса. Если одна из реплик перестанет работать, то load balancer автоматически перенаправит нагрузку на другие микросервисы.

    Физическая архитектура


    Вот как мы организовали инфраструктуру нашего решения:

    • Каждый микросервис имеет свою БД (если она ему, конечно, нужна), другие сервисы к БД другого микросервиса не обращаются.
    • Микросервисы общаются между собой только по шине RabbitMQ + Mass Transit, а также с помощью HTTP запросов.
    • Каждый сервис имеет свою четко обозначенную ответственность.
    • Для логирования мы используем Elasticsearch и Kibana и библиотеку для работы с ним Serilog.



    Сервис баз данных был развернут на отдельной виртуальной машине, а не в Kubernetes, потому что СУБД Microsoft не рекомендует использовать Docker на продуктовых средах.

    Сервис логирования тоже был развернут на отдельной виртуалке из соображений отказоустойчивости — если у нас будут неполадки с Kubernetes, то мы сможем разобраться, в чем проблема.

    Развертывание: как мы организовали разработческие и продуктовые окружения


    На нашей инфраструктуре создано 3 неймспейса в Kubernetes. Все три окружения обращаются к одному сервису баз данных и одному сервису логирования. И, конечно, каждая среда смотрит на свой БД.



    На инфраструктуре заказчика у нас также есть две среды — это предпрод и продакшн. На продакшене у нас есть отдельные серверы баз данных для предпрода и продуктовой среды. Для логирования у нас выделено по одному серверу ELK на нашей инфраструктуре и на инфраструктуре заказчика.

    Как развернуть 5 сред с 10 микросервисами в каждом?


    В среднем у нас 10 сервисов на проект и три среды: QA, DEV, Stage, на которых развернуто в сумме около 30 микросервисов. Причем это только на инфраструктуре разработки! Добавим ещё 2 среды на инфраструктуре заказчика, и у нас получается 50 микросервисов.



    Понятно, что такое таким количеством сервисов необходимо как-то управлять. В этом нам помогает Kubernetes.

    Для того, чтобы развернуть микросервис, необходимо
    • Развернуть secret,
    • Развернуть deployement,
    • Развернуть service.

    Про secret напишем ниже.
    Деплоймент — это инструкция для Kubernetes, на основе которой он запустит Docker контейнер нашего микросервиса. Вот команда, которой развёртывается deployment:

    kubectl apply -f .\(yaml конфигурация deployment-а) --namespace=DEV

    apiVersion: apps/v1beta1
    kind: Deployment
    metadata:
      name: imtob-etr-it-dictionary-api
    spec:
      replicas: 1
      template:
        metadata:
          labels:
            name: imtob-etr-it-dictionary-api
        spec:
          containers:
            - name: imtob-etr-it-dictionary-api
              image: nexus3.company.ru:18085/etr-it-dictionary-api:18289
              resources:
                requests:
                  memory: "256Mi"
                limits:
                  memory: "512Mi"
              volumeMounts:
              - name: secrets
                mountPath: /app/secrets
                readOnly: true
          volumes:
          - name: secrets
            secret:
              secretName: secret-appsettings-dictionary
    


    Этот файл описывает, как называется деплоймент (imtob-etr-it-dictionary-api), какой образ ему необходимо использовать для исполнения, плюс другие настройки. В секции secret мы будем настраивать наше окружение.

    После развертывания deployment нам необходимо развернуть service, если это необходимо.

    Сервисы нужны тогда, когда необходим доступ к микросервису извне. Например, когда нужно, чтобы пользователь или другой микросервис смог сделать Get запрос другому микросервису.

    kubectl apply -f .\imtob-etr-it-dictionary-api.yml --namespace=DEV

    apiVersion: v1
    kind: Service
    metadata:
      name: imtob-etr-it-dictionary-api-services
    spec:
      ports:
      - name: http
        port: 80
        targetPort: 80
        protocol: TCP
      selector:
        name: imtob-etr-it-dictionary-api


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

    В итоге для развертывания среды нам нужны

    • набор файлов с secret-ами для всех микросервисов,
    • набор файлов с deployment-ами всех микросервисов,
    • набор файлов с service-ами всех микросервисов.

    Все эти скрипты мы храним в git репозитории.

    Для развертывания решения у нас получился набор из трех видов скриптов:

    • папка с сикретами — это конфигурации для каждой среды,
    • папка с deployment-ами для всех микросервисов,
    • папка с service-ами для некоторых микросервисов,

    в каждой – примерно по десять команд, по одной на каждый микросервис. Для удобства мы завели страницу со скриптами в Confluence, которая помогает нам быстро развернуть новое окружение.

    Тут представлен скрипт развертывания deployment (подобные наборы есть для secret и для service):

    Скрипт развертывания deployment
    kubectl apply -f .\imtob-etr-it-image-api.yml --namespace=DEV
    kubectl apply -f .\imtob-etr-it-mobile-api.yml --namespace=DEV
    kubectl apply -f .\imtob-etr-it-planning-api.yml --namespace=DEV
    kubectl apply -f .\imtob-etr-it-result-api.yml --namespace=DEV
    kubectl apply -f .\imtob-etr-it-web.yml --namespace=DEV
    kubectl apply -f .\imtob-etr-it-report-api.yml --namespace=DEV
    kubectl apply -f .\imtob-etr-it-template-constructor-api.yml --namespace=DEV
    kubectl apply -f .\imtob-etr-it-dictionary-api.yml --namespace=DEV
    kubectl apply -f .\imtob-etr-it-integration-api.yml --namespace=DEV
    kubectl apply -f .\imtob-etr-it-identity-api.yml --namespace=DEV


    Реализация CI/CD



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



    Также для каждого микросервиса есть Build Definition и Release Definition. Мы настроили запуск Build Definion при коммите в соответствующий сервис или при коммите в соответствующую папку. Если обновляется содержимое папки с общими компонентами, то разворачиваются все микросервисы.

    Какие плюсы от такой организации Build-а мы видим:

    1. Решение находится в одном git-репозитории,
    2. При изменении в нескольких микросервисах сборка запускается параллельно при наличии свободных агентов сборки,
    3. Каждый Build Definition представляет простой сценарий из сборки образа и его push-а в Nexus Registry.

    Build definition и Release Definition


    Как развернуть VSTS-агент, мы ранее описали в этой статье.



    Сначала идёт Build Definition. По команде TFS VSTS агент запускает билд Dockerfile. В результате у нас получается образ микросервиса. Этот образ сохраняется локально на той среде, где запущен VSTS агент.

    После билда запускается Push, который отправляет образ, который мы получили в предыдущем шаге, в Nexus Registry. Теперь его можно использовать извне. Nexus Registry — это своего рода Nuget, только не для библиотек, а для образов Docker и не только.

    После того, как образ готов и доступен извне, его нужно развернуть. Для этого у нас есть Release Definition. Здесь все просто — мы выполняем команду set image:

    kubectl set image deployment/imtob-etr-it-dictionary-api imtob-etr-it-dictionary-api=nexus3.company.ru:18085/etr-it-dictionary-api:$(Build.BuildId)

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

    Давайте теперь сравним сборку с Dockerfile и без него.



    Без Dockerfile у нас получается много шагов, в которой много специфики .Net-а. Справа мы видим билд образа Docker. Все стало намного проще.

    Весь процесс сборки образа описан в Dockerfile. Эту сборку можно отлаживать у себя локально.



    Итого: мы получили простой и прозрачный CI/CD



    1. Разделение разработки и развертывания. Сборка описывается в Dockerfile и лежит на плечах разработчика.
    2. При настройке CI/CD не нужно знать о деталях и особенностях сборки — работа ведется только с Dockerfile-ом.
    3. Обновляем только измененные микросервисы.

    Далее требуется настрить RabbitMQ в K8S: об этом мы написали отдельную статью.

    Настройка окружения


    Так или иначе, нам необходимо конфигурировать микросервисы. Основная часть окружения настраивается в корневом файле конфигурации Appsettings.json. В этом файле хранятся настройки, которые не зависят от среды.

    Те настройки, которые зависят от среды, мы храним в папке secrets в файле appsettings.secret.json. Мы взяли подход, описанный в статье Managing ASP.NET Core App Settings on Kubernetes.

    var configuration = new ConfigurationBuilder()
       .AddJsonFile($"appsettings.json", true)
          .AddJsonFile("secrets/appsettings.secrets.json", optional: true)
          .Build();


    В файле appsettings.secrets.json хранятся настройки индексов Elastic Search и строка подключения к БД.
    {
      "Serilog": {
        "WriteTo": [
          {
            "Name": "Elasticsearch",
            "Args": {
              "nodeUris": "http://192.168.150.114:9200",
              "indexFormat": "dev.etr.it.ifield.api.dictionary-{0:yyyy.MM.dd}",
              "templateName": "dev.etr.it.ifield.api.dictionary",
              "typeName": "dev.etr.it.ifield.api.dictionary.event"
            }
          }
        ]
      },
      "ConnectionStrings": {
        "DictionaryDbContext": "Server=192.168.154.162;Database=DEV.ETR.IT.iField.Dictionary;User Id=it_user;Password=PASSWORD;"
      }
    }
    


    Добавляем файл конфигурации в Kubernetes


    Для того, чтобы добавить этот файл, его нужно развернуть в Docker-контейнере. Это делается в файле deployment-а кубернетиса. В deployment-е описывается в какой папке нужно создать файл c secret и с каким secret-ом нужно ассоциировать файл.

    apiVersion: apps/v1beta1
    kind: Deployment
    metadata:
      name: imtob-etr-it-dictionary-api
    spec:
      replicas: 1
      template:
        metadata:
          labels:
            name: imtob-etr-it-dictionary-api
        spec:
          containers:
            - name: imtob-etr-it-dictionary-api
              image: nexus3.company.ru:18085/etr-it-dictionary-api:18289
              resources:
                requests:
                  memory: "256Mi"
                limits:
                  memory: "512Mi"
              volumeMounts:
              - name: secrets
                mountPath: /app/secrets
                readOnly: true
          volumes:
          - name: secrets
            secret:
              secretName: secret-appsettings-dictionary
    


    Создать secret в Kubernetes можно с помощью утилиты kubectl. Мы видим тут название secret-а и путь до файла. Также мы тут указываем название окружения, для которого создаем secret.

    kubectl create secret generic secret-appsettings-dictionary
    --from-file=./Dictionary/appsettings.secrets.json --namespace=DEMO


    Выводы


    Минусы выбранного подхода


    1. Высокий порог входа. Если делаете подобный проект впервые, будет много новой информации.
    2. Микросервисы → более сложное проектирование. Необходимо применять много неочевидных решений из-за того, что у нас не монолитное решение, а микросервисное.
    3. Не все реализовано для Docker. Не все можно запустить в микросервисной архитектуре. Например, пока SSRS нет в докере.

    Плюсы подхода, проверенные на себе


    1. Инфраструктура как код
    Описание инфраструктуры хранится в source control. В момент развертывания не нужно адаптировать окружение.
    2. Масштабирование как на уровне функционала, так и на уровне производительности из коробки.
    3. Микросервисы хорошо изолированы
    Практически нет критичных частей, отказ которых приводит к неработоспособности системы в целом.
    4. Быстрая доставка изменений
    Обновляются только те микросервисы, в которых были изменения. Если не учитывать время на согласования и другие вещи, связанные с человеческим фактором, то обновление одного микросервиса у нас происходит за 2 минуты и меньше.

    Выводы для нас


    1. На .NET Core можно и нужно реализовывать промышленные решения.
    2. K8S действительно облегчил жизнь, упростил обновление сред, облегчает конфигурирование сервисов.
    3. TFS можно использовать для реализации CI/CD для Linux.

    EastBanc Technologies

    123,00

    Специалисты по цифровой трансформации бизнеса

    Поделиться публикацией
    Комментарии 44
      –3
      Когда это RabbitMQ стал шиной?
        +1

        Да, вы правы, не хватает упоминания Mass Transit. Внесли правки в текст.

        0
        Elasticsearch тоже в Кубере? На сколько критичные в нём данные? Как-то пока стремаюсь ES в оркестрацию пулять, с ним всё таки грамотно надо обращаться без спонтанных рестартов.
          0
          там только логи судя по статье
            0

            Elasticsearch и Kibana развернуты на отдельной виртуалке, не в Kubernetes.

            +3
            А что с версионностью контрактов?
              0

              Это хороший вопрос и достаточно обширный! Хотим ответить в отдельной статье на Хабре.

              0

              А я вот только начал изучать Core, написал простенький сайтец и… встрял.
              Дефолтная сборка докера падает на скачивании пакетов и желание искать причину почему-то не возникает (

                +1
                Core все таки лучше для бэка брать, а фронт на каком нибудь SPA(например Angular)
                  +1
                  Скорее всего base image для docker не правильный. Проверь что версия имеджа не ниже, чем версия ASP.Net пакетов.
                  +5
                  С технической точки знения выглядит прекрасно, но…
                  Интересно насколько оно оптимально для заказчика, другими словами сколько он переплатил.

                  Как я понял из статьи это корпоративное приложение, значит пользователей совсем не много. О каких порядках идет речь — сотни или тысячи? Врятли даже десятки тысяч, т.к. пользоваться будут не все, а только мерчандайзеры и супервайзоры.

                  Мы рассчитываем, что проект будет активно развиваться, а пользователей будет всё больше и больше.

                  Было бы интересно узнать больше о причиных выбора такой архитектуры. Сколько пользователей на старте, какой прирост по месяцам. Какая планируемая нагрузка и планируемый рост. Планируемый объем хранимых данных и сложность их обработки, ну и т.д.

                  Например почему классика WebApp + DB не подходит? Я понимаю, что скучно, но работает отлично и прекрасно масштабируется, легче вносить изменения, легче деплоймент, меньше точек отказа и т.д.
                    0

                    Поскольку компания крупная, и мы собираемся расширять функционал, решением будут пользоваться десятки тысяч человек.


                    О причинах выбора архитектуры подробно описали в этой статье. СУБД развернута на отдельной виртуальной машине без Kubernetes, поэтому объем хранимых данных не сказывается на производительности сервера с приложением, это больше вопрос к структуре БД.

                      +1
                      У нас 20к пользователей на подобные бизнес-аппы спокойно тащат аппы на одном серваке вместе с БД.

                      Если диаграмма про Service.Planning, Service.Report, и т.п. — это то, как вы порезали систему, то скорее всего вы слишком мелко ее нарезали. И скорее всего, с ростом сложности, у вас начнутся проблемы.

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

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

                      Потом вы поймете, что с перформансом беда, и добавление инстансов не помогает — все упирается в стоимость API-коллов.

                      Дальше, вы поймете, что правильнее делить систему на сервисы вообще иначе — резать надо не по техническим границам, а так, как устроен бизнес. Один начальник/отдел/бизнес-процесс — это скорее всего один кусок.

                      Хороший вопрос, кстати, чтобы выяснить правильно ли вы делаете — это соотношение бекенд/фронтенд девелоперов. Если фронта меньше половины — вы точно переусложнили бекэнд.
                        +3
                        image

                        Безысходность
                          0
                          А если фронта больше половины — вы переусложнили UI, получается?
                            0
                            Надо смотреть тогда дальше как фронт делают.

                            Возможно там взяли Redux какой, и на каждое поле каждой формы каждого скрина пишут по редьюсеру. Или там 10 скринов с табличками, и вся общая логика накопипастана. Или лид заставляет писать тесты типа «кликнули кнопочку — ушел AJAX», делать тройной кросс-ревью через пулл-реквесты на фиксы «я подвинул кнопку», и какой-нибудь еще такой херней вместо работы заставляет людей заниматься.

                            А может быть там и действительно делают красоту. Но вообще, для типичной бизнес-аппы, даже с выкрутасами типа всяких кастомных календариков и прочих пыщ-пыщ красивостей, 50/50 — норм баланс.
                              0
                              А вы рассматриваете вариант, когда бизнес сам по себе сложный? Ну например какая-нибудь универсальная ERP или биллинг? Задача UI — быть простым, а для бизнеса (который представляет backend) таких требований обычно не ставится.
                                0
                                Если только у тебя какая-нибудь готовая ERP (1С та же), которая по метаданным рисует гриды — типа там бекендеры вместо фронтов плачут и гнут ее как получится.

                                Но если UI свой — то чем сложнее бизнес, тем сложнее и UI. В тех же ERP — всюду гриды и формы. А на вебе не то что их встроенных нет, нет даже библиотек нормальных чтобы из коробки их сделать. Там от входа «слепляем свою UI-библиотеку из хипсторских поделок в NPM, пота, и слёз».
                          0
                          решением будут пользоваться десятки тысяч человек

                          Такое количество пользователей называется — «полтора человека».

                          Я перечитал данную статью и статью ссылку на которую вы указали, но эти статьи, к сожалению, не отвечают на вопрос — почему нужно было выбирать именно такую архитектуру.

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

                        Авторизация по jwt? Один токен на все сервисы?

                          0

                          У нас реализован отдельный микросервис авторизации, который отвечает за генерацию jwt токенов по SAML Assertion, который нам отдает ADFS 3.0. Этот jwt токен принимается всеми микросервисами. Реализацию мы подсмотрели здесь и здесь.

                            0
                            Т.е. если встанет сервис авторизации, то встанет все. Тонкое место микросервисной архитектуры.
                              0

                              Именно поэтому микросервис авторизации имеет минимум связей с другими системами. Он зависит только от работы ADFS.

                          0
                          Все мы знаем, что такое классический .Net Framework. Основным минусом платформы является то, что она не кроссплатформенная. Соответственно, мы не можем запустить в Docker решения на платформе .Net Framework.
                          это неверно. докер замечательно поддерживает контейнеры windows 2016 server, более того, даже два вида контейнеров в windows. в кластере docker swarm или k8s могут быть ноды как под linux так и под windows, причем оба типа нод в одном кластере. и у ms оооооогромный набор контейнеризованного софта. даже sql server есть.
                            0
                            Правда размер контейнера слегка не микросервисный…
                              +1

                              И зачем платить за лицензии Windows и тратить больше ресурсов вм? Зачем грузить громадную ОС обновы которой без спроса ребутают сервер (и без wsus от этого не избавиться)? Про размер "докеров" в Windows вам тоже уже сказали выше.

                                0
                                ребутают сервер без спросу? как-то не сталкивался с таким, не наговаривайте. По остальным пунктам справедливо.
                                  0
                                  у меня у заказщика в AWS поднимал Win2016 — ребут обычное дело посреди ночи по системному времени. То же самое и с серверами на голом железе: стоит нотификейшен на почту в IPMI если сервер уходит в ребут — приходит письмо, класика посреди ночи раз в месяц. P.S. Win2012 так себя не ведет, это катается только Win2016+
                                    0
                                    ну это специфика AWS всё таки. И да, буквально на днях один Win2016 инстанс вдруг устарел и был пересоздан, с Win2012 даже не припомню бывало ли такое.
                                +1
                                можно и в Windows, но это все таки для очень конкретных решений.
                                Microsoft молодцы что сделали поддержку Docker Windows, но гораздо большие молодцы, что они выпустили .net core!
                                  0
                                  ой, ну да, ну да, советчиков таких много, только стоило бы самому попробовать для начала, после чего давать советы про виндовые контейнеры
                                    0

                                    Спасибо, поправили это предложение в статье. Теперь фраза звучит так:


                                    Соответственно, мы не можем запустить в Docker решения на платформе .Net Framework под Linux.

                                    +3
                                    В итоге мы решили использовать микросервисы на этом проекте, что потребовало принять ряд нетривиальных решений.

                                    А что за «ряд нетривиальных решений»?
                                      0

                                      Мы считаем нетривиальным следующие решения:


                                      • Которые позволили организовать способ взаимодействия между клиентами и микросервисами, которые размещены в K8S. Мы реализовали собственный сервис авторизации,
                                      • Выбрать сервисы, которые нужно было разместить в K8S, а какие нет,
                                      • Настройка Rabbit MQ,
                                      • Организовать билды и релизы в TFS, и многое другое.
                                      0
                                      Спасибо за статью.
                                      Хороший стэк, хотя мне больше с MongoDb нравится работать и драйвер для .net там шикарный.
                                      Но вопрос необходимости микросервисов конечно открытый. Почему не просто горизонтальное масшабирование бэкенда?
                                      Ну и мне лично Gitlab пока ближе.
                                        0

                                        В нашей компании TFS — это корпоративный стандарт, поэтому использовали его.

                                          0
                                          C MongoDb ещё и может быть проще разносить данные по базам если используется database per service.
                                            0
                                            из моего опыта могу сказать что микросервисы могут быть полезны, например мне достался проект от говнокодеров которые не понимали как фреймворки работают и всё было сделано мало эффективно, но зато куча сервисов, чтоб юзеры не страдали от того что импорт данных написан криво и забирает под себя почти все ресурсы я его взял и тупо перенёс на другую машину вернее даже на 2(до этого всё стояло на одном жирном сервере) и юзерам стало жить легче пока сервисы оптимизировал, если писать монолит то программисты начнут срезать углы и вместо модуля может получиться трудно выделяемая хрень, так что микросервисы могут быть полезны если уровень программистов и архитекта так себе, иногда даже хочется на функциональном языке таких застявлять писать, там много ограничений которые не позволят писать совсем криво
                                            0
                                            Три вопроса
                                            1.Много кто рассказывает как устроена инфраструктура, однако я не находил про то как организуется процесс разработки. Ведь одно из заявляемый преимуществ контейнеров — то, что среда в проде и в деве одна и та же. Однако как вообще идёт процесс отладки, ведь, как я понимаю, чтобы сохранялась концепция неизменности среды выполнения, нужно отлаживать в контейнере. Как Вы делали?
                                            2. Чем руководствовались при выделении микросервисов?
                                            3. Как разбивали на участки: где должен быть асинхронный обмен, а где синхронные команды?
                                              0
                                              1. По поводу отладки: дебажим локально. Visual studio предоставляет возможность локально дебажить контейнеры. На других средах мы не дебажим. Для этого мы используем Elasticsearch и Kibana.


                                              2. Мы руководствовались двумя книгами: "Микросервисы .NET. Архитектура контейнерных приложений .NET" и "Микросервисы на платформе .NET". Лучше, чем там описано, мы не сможем объяснить. Главная идея: каждый микросервис должен отвечать за специализированную функциональность.


                                              3. Асинхронный обмен у нас практически везде, кроме тех мест, где нужно гарантировать, что действие выполнено на другом микросервисе. Например, что результат, полученный с мобильного приложения, обработан другим микросервисом. Также мы руководствовались принципом, что микросервис должен иметь все данные в своей БД, которые ему нужны для работы.


                                              0
                                              Возникло несколько вопросов:
                                              1. Почему для фасада базы используется отдельный сервис, если у каждого сервиса своя база? Выглядит как непонятный оверхед на пустом месте + слабое место в перспективе (и сложнее будет разносить базы в случае чего)
                                              2. Вы точно уверены что жизенно необходимы по несколько нод каждого микросервиса? Я недавно замерял простые запросы к netcore серверу (вытащить данные из Redis кэша) — он тысячу запросов в секунду пережевывает спокойно. На рабочем ноутбуке, где сам Редис в докере и SQL Express подняты. Т.е. вероятность упереться в базу и/или кривой код на порядок выше. А там без горизонтального масштабирования уже не выйдет. Впрочем, уверен на 99% что это излишне. Вон stackoverflow живут без горизонтального масштабирования, а у них скорее всего нагрузки будут на порядки выше чем у практически любого приложения.
                                              3. Вы точно уврены что данные у микросервисов действительно не пересекаются? Не выйдет ли так что завтра захотят получить агрегат данных из нескольких сервисов?
                                              4. Подключать файл с секретами как-то сложно на вид. Не рассматривали иные альтернативы? Почему файлы секретов в сорс контроле хранятся, если вы всё равно их подключаете отдельно?
                                              5. Давать прямой доступ к микросервисам — на мой взгляд сомнительное решение (в т.ч. с т.з. безопасности). Как я понял, у вас есть клиенты на мобильных приложениях = поддержка разных версий API, т.к. клиентов так просто не заставить обновить приложение. Как вообще реализовано версионирование АПИ (даже не внутри микросервисов, а именно для мобильных клиентов)? Это один из самых волнующих меня вопросов, т.к. универсального рецепта я не знаю.
                                              6. Rabbit MQ используется для всех коммуникаций или нет? Из предложения в статье совсем непонятно. Субъективно, это нужно для асинхронных сообщений (возможно даже с отложенной доставкой) и тех, где важна устойчивость. Для всего остального более чем достаточно обычного хттп.
                                                0
                                                1. Да, у каждого сервиса своя база.


                                                2. Это решение на перспективу, когда количество пользователей и функциональности станет больше.


                                                3. Да, на этом этапе уверены. На практике убедились, что мы правильно разбили проект на микросервисы, и это даёт результат.


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


                                                5. Версионность API нам пока не понадобилась.


                                                6. Rabbit MQ почти используется для всех коммуникаций, частично ответили на этот вопрос в другом комментарии https://habr.com/company/eastbanctech/blog/420665/#comment_19037049


                                                  0
                                                  1. Но зачем тогда отдельный сервис который рулит базами? Не лучше ли обращаться в свою базу непосредственно из сервиса, без прослоек? Меньше оверхед, меньше проблем при последующем разнесении базы на разные сервера
                                                  2. А сколько пользователей и какие нагрузки вы ожидаете, чтобы их одновременно не могли потянуть сервисы (при должном уровне написания) способные прожевать тысячи запросов в секунду, но при этом потянула база без горизонтального шардирования. По моему опыту, всё это куда быстрее упрётся в базу.
                                                  3. Понятно, спасибо
                                                  4. Понятно, спасибо.
                                                  5. А как жить с мобильными клиентами? Вы же не можете заставить их всех обновиться в одну секунду
                                                  6. А как быть в простом, но крайне реалистичном сценарии «послать в сервис какие-то параметры и получить от него результат». Может у вас своя специфика, но обычно это самый распространённый сценарий использования микросервисов
                                                0
                                                1. Но зачем тогда отдельный сервис который рулит базами? Не лучше ли обращаться в свою базу непосредственно из сервиса, без прослоек? Меньше оверхед, меньше проблем при последующем разнесении базы на разные сервера
                                                2. А сколько пользователей и какие нагрузки вы ожидаете, чтобы их одновременно не могли потянуть сервисы (при должном уровне написания) способные прожевать тысячи запросов в секунду, но при этом потянула база без горизонтального шардирования. По моему опыту, всё это куда быстрее упрётся в базу.
                                                3. Понятно, спасибо
                                                4. Понятно, спасибо.
                                                5. А как жить с мобильными клиентами? Вы же не можете заставить их всех обновиться в одну секунду
                                                6. А как быть в простом, но крайне реалистичном сценарии «послать в сервис какие-то параметры и получить от него результат». Может у вас своя специфика, но обычно это самый распространённый сценарий использования микросервисов.

                                                Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                                Самое читаемое