Как стать автором
Обновить

Развертывание ASP.NET Core приложения в Kubernetes

Время на прочтение6 мин
Количество просмотров11K

Данная статья является краткой инструкцией по развертыванию ASP.NET Core приложения в Kubernetes с написанием Dockerfile для формирования образа (Docker image) и минимального манифеста для создания деплоймента и объекта, предоставляющего доступ к нему, – в статье будет использован ingress в исполнении nginx.

Используемые инструменты:

  • Microsoft Visual Studio Community 2022 17.4.2

  • Postman v9.14.14

  • Docker Desktop 4.15.0

  • Kubernetes v1.25.2

Описание приложения

Развертываемым приложением будет минимальное веб-приложение ASP.NET Core. Оно представляет собой простейшее API, которые содержит следующие команды:

  • ‘api/’ – возвращает ответ ‘online’, что используется для проверки работоспособности приложения;

  • ‘api/authors’ – возвращает список авторов статьи;

  • ‘api/info’ – возвращает информацию об окружении: переменные, NetBIOS имя сервера, имя пользователя, под которым работает приложение, имя хоста и IP адреса всех интерфейсов хоста.

Исходный код можно найти тут.

Построение образа

Dockerfile к приложению ASP.NET Core можно составлять как вручную, так и автоматически, воспользовавшись встроенным в VS генератором. Для этого при создании проекта ASP.NET Core во вкладке с дополнительным конфигурированием нужно поставить галочку в пункте «Enable Docker» и выбрать используемую докером OS (см. рисунок).

Окно дополнительной конфигурации
Окно дополнительной конфигурации

Очень удобно перекладывать генерацию Dockerfile на VS. Но не стоит всецело полагаться на неё, и лучше понимать, какие именно инструкции генерируются, их аргументы и общую структуру полученного Dockerfile. Это может пригодиться, например, при переходе на более свежую версию .NET – учитывая скорость выхода последних версий (5.0, 6.0, 7.0), такая ситуация вполне реальная.

Сгенерированный Dockerfile для приложения выглядит следующим образом:

FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
WORKDIR /app
EXPOSE 80

FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["HabrWebApi/HabrWebApi.csproj", "HabrWebApi/"]
RUN dotnet restore "HabrWebApi/HabrWebApi.csproj"
COPY . .
WORKDIR /src/HabrWebApi
RUN dotnet build "HabrWebApi.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "HabrWebApi.csproj" -c Release -o /app/publish /p:UseAppHost=false

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "HabrWebApi.dll"]

Для только что познакомившихся с Docker пользователей такая структура с множеством инструкций ‘FROM’ может ввести в ступор. Данный файл является приближенным к «боевым» Dockerfile’ам и построен с помощью технологии многоэтапной сборки (см. тут).

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

На первой в нашем Dockerfile стадии «base» подтягивается образ ASP.NET из Microsoft Container Registry (MCR) и открывается порт 80. Этот образ содержит все необходимое для запуска приложения ASP.NET Core. Тег образа указывает на версию .NET.

Далее, вторая стадия «build» основывается на образе sdk, который содержит необходимые инструменты для построения приложения. Именно на этой стадии происходит компиляция приложения, восстановления его зависимостей, генерация необходимых исполняемый файлов.

Следующая стадия «publish» расширяет предыдущую стадию «build», добавляя команду «dotnet publish». В результате получаются файлы приложения, готовые к выполнению в среде ASP.NET.

Финальная стадия «final» основывается на первой стадии и использует результаты стадии «publish», т.е. совмещает среду развертывания ASP.NET и файлы нашего приложения, которые будут исполняться в ней. Финальная строка Dockerfile будет выполнена при старте контейнера, созданного по нашему образу, - она запускает наше приложение.

После создания Dockerfile можно приступать к созданию образа нашего будущего контейнера. Для этого необходимо перейти в папку с файлом решения приложения (.sln), открыть терминал в этот папке и выполнить команду: «docker build -f [путь к Dockerfile] --force-rm --tag [тег] .». Данная команда собирает образ контейнера по указанному Dockerfile, при этом назначает образу указанный тег, удаляет все образы контейнеров, созданные на промежуточных стадиях (опция ‘--force-rm’), из указанного контекста (текущая директория). Построение образа должно быть выполнено без ошибок. Готовый образ можно взять тут.

На данном этапе необходимо проверить работоспособность контейнера, создаваемого по нашему образу. Для этого выполним команду: «docker run -d -P --name [имя контейнера] [тег образа или его id]». Результат выполнения команды должен быть такой:

Как видно, контейнер был успешно создан и запущен. Теперь можно перейти к проверке работоспособности запущенного в нем приложения. Для этого в Postman отправим запросы к каждому методу нашего приложения. Порт, который был привязан к контейнеру можно узнать с помощью команды «docker container ls»:

Отправим запросы к нашему приложению:

  • /api

  • /api/authors

  • /api/info

Развертывание приложения в Kubernetes

Развертывание приложения в Kubernetes начинается с написания манифеста, содержащего описание деплоймента (Deployment). Ключевым плюсом деплоймента является встроенная поддержка нужного количества экземпляров приложения (подов). Также деплоймент отслеживает все изменения в своей конфигурации, например, изменение образа контейнеров в подах. Это дает возможность «путешествовать» по истории изменения деплоймента, и в случае применения фатальных изменений легко вернуться к последней стабильной версии.

Минимальный деплоймент содержит количество реплик (подов/экземпляров приложения) и конфигурацию подов: описание контейнеров (образ, порты, переменные окружения, используемые хранилища (volumes)). В нашем приложении используется один контейнер на под с портом 80 со стандартной для ASP.NET переменной окружения «ASPNETCORE_ENVIRONMENT». Приложение не использует хранилища. Минимальный манифест деплоймента выглядит следующим образом:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: habrwebapi-deployment # Имя деплоймента
spec:
  replicas: 2 # Количество реплик
  selector:
    matchLabels: # Определение меток и их значений, по которым будет определяться принадлежность пода деплойменту
      app: habrwebapi-pod
  template: # Описание конфигурации подов
    metadata:
      labels:
        app: habrwebapi-pod # Специальная метка для подов, по которой определяется их принадлежность данному деплойменту
    spec:
      containers: # Описание контейнеров, создаваемых в поде
      - name: habrwepapi-container # Имя контейнера внутри пода
        image: hrenaki/habrwebapi-image:1.0 # Название образа контейнера с указанием репозитория
        ports: # Описание портов контейнера
        - name: pod-port
          containerPort: 80
        env: # Перечисление переменных окружения и их значений
        - name: "ASPNETCORE_ENVIRONMENT"
          value: "Kubernetes"

Проверить состояние созданного деплоймента можно вызвав команду «kubectl get all». Результат выполнения:

Как видно, был создан деплоймент, replicaset и два пода со статусом «Running». Это означает, что наше приложение развернуто и готово к работе. Осталось создать объект, который будет предоставлять доступ к нашему приложению. В данной статье, следуя best practice, для этой цели будет использован ingress.

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

apiVersion: v1
kind: Service
metadata:
  name: habrwebapi-service
spec:
  selector:
    app: habrwebapi-pod
  ports:
  - targetPort: pod-port
    port: 80

Теперь можно переходить к написанию манифеста ingress. Ingress управляет маршрутизацией трафика, приходящего извне, к сервисам, находящимся внутри кластера Kubernetes. В нашем кластере всего один сервис, поэтому направим весь трафик, который приходит по пути «/» на него. В результате манифест для ingress выглядит следующим образом:

apiVersion: networking.k8s.io/v1
kind: Ingress 
metadata:
  name: webapp-ingress
spec:
  ingressClassName: nginx
  rules:
  - http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name:  habrwebapi-service
            port:
              number: 80

Перед тем, как создавать ingress объекты, необходимо в кластер установить nginx контроллер, выполнив команду:

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.5.1/deploy/static/provider/cloud/deploy.yaml

После создания всех объектов, ingress доступен по адресу localhost. Сделаем запрос к нашему приложению, используя адрес «http://localhost/api/info»:

Итоги

В статье был изложен путь быстрого развертывания примитивного ASP.NET Core приложения. Рассмотрены минимальные версии образа и манифестов k8s. Вышеперечисленный материал может служить основой для развертывания более серьезных приложений.

Теги:
Хабы:
Всего голосов 16: ↑14 и ↓2+12
Комментарии15

Публикации