Предисловие

Здравствуйте. Я являюсь новичком в сфере it. Идея написать данную статью мне пришла отчасти оттого, что, по моим наблюдениям, тема про пару dotnet и Linux не освещена в больших объёмах (скорее всего из-за ненадобности), но как новичок новичку хотел бы рассказать как можно справиться с этой задачей, что и будем делать вместе.

Задача

Развернуть проект ASP.NET core с шаблоном webapi на Ubuntu в связке с PostgreSQL и положить всё в docker контейнеры, запустив их через docker-compose.

Начало

Для начала нам стоило бы скачать необходимый базис для работы с ASP.NET core и docker, docker-compose в среде Linux под нужный дистрибутив(в моём случае Ubuntu). На это время тратить не буду, так как на просторах интернета данные темы подробно описаны.

Полезный ссылки

После того как всё скачали и проверили на работоспособность: docker -v & docker-compose -v & dotnet --info, можем приступать к работе.

Глава 1

Создадим директрию и вложим в неё файл docker-compose.yml и папку. Я работаю в VS code и данная история выглядит следующим образом.

Итоговый результат выглядит так
Итоговый результат выглядит так

После чего откроем терминал и перейдём по пути в нашу вложенную папку(в моём случае это cd ./app). С помощью команды dotnet -h мы можем просмотреть какие возможности нам доступны. Так как нам нужно развернуть проект, мы выбираем new. Чтобы проверить какие аргументы возможно прописать, прописываем dotnet new -h, после чего видим, чтобы просмотреть какие шаблоны у нас имеются, можем

прописать dotnet new list. Определившись с шаблоном прописываем dotnet new (в моём случае: webapi) --no-https -controllers. Заметим, что все аргументы мы можем просмотреть, прописав -h, что касается не только dotnet.

Запустим приложение и проверим работоспособность. Напишем команду dotnet run и в терминале выведется следующее.Мы можем проверить работоспособность, зайдя по url, но продолжим дальше.

Глава 2

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

Перейдём к dockerfile в папке dotnet и пропишем следующее по желанию. Данный код взят с официальной документации.

Кратко пробежимся по коду:
  1. Скачиваем sdk образ, а также благодаря workdir назначаем папку source в контейнере как папку по умолчанию.

  2. Копируем при запуске контейнера файлы .sln и .csproj. и папку с проектом.

  3. Назначаем по умолчанию папку с проектом.

  4. Запускаем restore, чтобы засунуть в кэш неизменяемые файлы.

  5. Публикуем приложение

  6. Скачиваем образ с runtime etc.

  7. Задаём переменные окружения по желанию.

  8. Настраиваем папку по умолчанию.

  9. Копируем папку с образа выставленного как build.

  10. Запускаем кроссплатформенный файл.

Полезный ссылки

Настроим файл docker-compose

Кратко пробежимся по коду
  1. Укажем версию

  2. Разберёмся со структурой каждого image:

    1. image или build - указываем откуда будет строиться образ

    2. volumes - синхронизация конфигурационных файлов, папок и подобных им

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

    4. environment - переменные среды для настройки того или иного приложения внутри контейнера

    5. ports - прокидываем внутренние порты докер контейнеров во внешние

    6. networks - сеть по которой наши контейнеры будут общаться

      1. ipam управление ip адреса

      2. driver default - bridge

      3. config subnet и gateway- маска подсети и сетевой шлюз

Но всё это можно заменить указав сеть bridge

Настроем файл nginx

Кратко пробежимся по коду

Полезный ссылки

Глава 3

После проделанной работы отправимся в нашу папку с проектом cd app и в терминале укажем следующий код dotnet add package Npgsql.EntityFrameworkCore.PostgreSQL --version 8.0.0этот пакет служит для взаимодействия с PostgreSQL. Также нам необходимо установить инструмент для работы с EF core, и в этом нам поможет команда dotnet tool install --global dotnet-ef.

Просмотреть установленный пакет мы можем благодаря команде dotnet list package
Просмотреть установленный пакет мы можем благодаря команде dotnet list package
Просмотреть установленные инструменты мы можем благодаря команде dotnet tool list -g
Просмотреть установленные инструменты мы можем благодаря команде dotnet tool list -g

Раннее мы запускали контейнеры с бд по порту 54332 и adminer по порту 8080. Зайдя по http://localhost:8080/ нам откроется панель для администрирования бд. Вводим данные в форму, после чего нас переводит в админ панель. Также мы можем администрировать бд благодаря плагину vs code Database или же благодаря pgAdmin.

cat.cs
cat.cs

Так как в бд пусто, продолжим. Создадим файл в папке app: context.cs и cat.cs и заполним следующим кодом

context.cs
context.cs

Так как мы не указали host в параметрах контейнера PostgreSQL, то он нам доступен по дефолтному хосту localhost. Теперь мы можем сделать миграцию. Инициализируем миграции с помощью dotnet ef migrations add initia и dotnet ef database update.Теперь зайдя в нашу среду администрирования, мы увидим, что добавилась таблица Cats.

Теперь мы можем обращаться в controllers к бд.

Останавливаем контейнеры, удаляем контейнер с проектом. Перезапустим контейнеры, так как мы только упаковываем готовое приложение. По адресу http://api.prop.loc/Cat мы можем сделать get запрос на создание и получение котика. Чтобы каждый раз не удалять и не перезапускать контейнеры, при желании мы можем прописать volumes, но это другая история.

Вот так просто и разворачивается проект ASP.NET core в среде Ubuntu в связке с PostgreSQL и дальнейшей контейнеризацией на сервере nginx + kestrel, и котиками.

Благодарю, что дочитали данную статью

Частые ошибки
EF core error

You must install .NET to run this application.App: /home/danis/.dotnet/tools/dotnet-ef Architecture: x64 App host version: 8.0.0 .NET location: Not foundLearn more: https://aka.ms/dotnet/app-launch-failedDownload the .NET runtime: https://aka.ms/dotnet-core-applaunch?missing_runtime=true&arch=x64&rid=linux-x64&os=ubuntu.22.04&apphost_version=8.0.0

Данную ошибку можно решить, прописав export DOTNET_ROOT=/usr/share/dotnet(путь до репозитория dotnet с sdk и runtime(для каждого индивидуально)) Также эту перменную можно установить при каждом входе в систему(отдельная тема).

В случае, если вы указали хост в nginx и по какой-то причине у вас не открывается страница

То скорее всего нужно разрешить для этого хоста доступ через sudo nano /etc/hosts

В случае, если вы делаете docker-compose up и docker выдаёт ошибку по типу: permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get "http://%2Fvar%2Frun%2Fdocker.sock/v1.24/containers/json?all=1&filters=%7B%22label%22%3A%7B%22com.docker.compose.config-hash%22%3Atrue%2C%22com.docker.compose.project%3Dproject%22%3Atrue%7D%7D": dial unix /var/run/docker.sock: connect: permission denied

Скорее всего вам нужно прописать перед docker "sudo"

Комментарии (17)


  1. pavel_raskin
    15.12.2023 18:07

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


    1. nronnie
      15.12.2023 18:07

      Такой код вообще лучше не публиковать. Если уж показываешь код в качестве примеров, то показывай хороший код. А тут все мыслимые шаблоны и практики нарушены. DbContext конфигурируется совершенно непонятным образом. Почему он не передается в контроллер через DI? Почему все вызовы EF синхронные, а не async/await? Я понимаю, что задача была показать сборку образа для докера, но все-таки не стоит показывать это на примере говнокода. И еще - с помощью докерфайлов это делали еще сотню лет назад, если уж хочется написать действительно интересную статью, то можно было бы тогда уж про более новый подход написать.


      1. thePathAlongEpictetus Автор
        15.12.2023 18:07

        Здравствуйте. Благодарю за комментарий. Как было написано вначале, я новичок и статья для новичков. Как вы правильно заметили в своем комментарии, задача была в сборке проекта, но никак не в реализации вывода котиков, ведь статья с применением шаблонов или приципов по типу того, что вы упомянули "внедрение зависимостей", заняла бы больше места. Веб апи я взял в качестве примера, а также я могу заменить в статье на пустой шаблон net core и запустить консольное приложение, что не изменит задачу статьи. Но я приму ваше замечание и изменю код для более наглядной картины. Понимаю, что для вас как для специалиста с опытом данная статья не является чем-то новым, но для юных, вроде меня, это может быть хорошей информацией. И в качестве альтернативы вы также можете скинуть и множество других статей на эту же тему или близкой к ней, чтобы вложиться в общее благо. Надеюсь, мы придем к согласию.


    1. thePathAlongEpictetus Автор
      15.12.2023 18:07

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


  1. 0Bannon
    15.12.2023 18:07

    Вот только вчера начал изучать asp net и искал туторил, как на Gnu/Linux в докер проект задеплоить и вот он. Как это происходит вообще? Мысли материализуются?


    1. thePathAlongEpictetus Автор
      15.12.2023 18:07

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


  1. A1lfeG
    15.12.2023 18:07

    Подскажите, зачем в этом простом примере nginx? И нет, аргумент про производительность тут будет лишний. Зачем хардкодить стороку соединения? Если уж пишете пример докер композа, то нужно писать правильно и передавать конфигурацию приложению извне, тем более что делается это крайне просто. С другой стороны пример излишне усложнили добавлением айпи адресов.


    1. thePathAlongEpictetus Автор
      15.12.2023 18:07

      Здравствуйте. Благодарю за комментарий. Аргументы про производительность можно найти в других источниках в довольно больших объеёмах, чего не скажешь про тему написанную в данной статье, по крайней мере, субъективно. Но nginx я выбрал в случае, если будут микросервисы и т.д. , но понимаю, что для данного приложения это является излишним, но также этот пример может являться одним из вариантов разворачивания приложения. На счёт api адресов вы правы, но в статье я упомянул, что можно сделать легче. Я сделал множество выводов на основе вашего комментария и будьте уверены, что это не пройдет мимо и мы придем к согласию.


      1. nronnie
        15.12.2023 18:07

        Тут уже не раз писали (я в том числе), что использовать nginx как reverse proxy / API gateway это в наше время оверхед. Есть более специализированные для этого решения. Например krakend или envoy.


        1. thePathAlongEpictetus Автор
          15.12.2023 18:07

          Благодарю за информативный комментарий. К сожалению, я не знаком с такими технологиями, но в случае, если же я ознакомлюсь с данным стеком, то обязательно перепишу статью, если же, конечно, это и вправду повысит производительность, но на данный момент, думаю, новичкам скорее всего хватит этого материала, чтобы просто развернуть проект на linux с подключённой бд и изучать net core(в том числе, если будет микросервисная архитектура). Надеюсь, мы придём к согласию.


      1. ColdPhoenix
        15.12.2023 18:07

        Kestrel уже считается довольно взрослым, и ему не нужен nginx впереди.


      1. Atrio23
        15.12.2023 18:07

        В данной ситуации nginx тут не нужен. Зачем? Asp net и сам может работать на 80 порту. А если нужно и 443 если добавить сертификаты.


  1. hVostt
    15.12.2023 18:07

    Совершенно не понял, зачем тут nginx. Это же не PHP какой-нибудь. dotnet сам может рабатать как nginx и даже как контроллер Ingress. Если хочется бекенд для микросервисов, подключаем либу ocelot или yarp, и также nginx здесь как третье колено — совершенно избыточная, лишняя и ненужная сущность.


  1. ColdPhoenix
    15.12.2023 18:07

    Насчёт файла докер, если используете VS, то там его можно создать одним кликом.(добавить поддержку Docker)

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


    1. timoxa_dev
      15.12.2023 18:07

      Насчёт файла докер, если используете VS, то там его можно создать одним кликом.(добавить поддержку Docker)

      Ничего хорошего в этом нет, пока у тебя все работает - это конечно весело и задорно, но если что то пойдет не так, как магия внутри сможет тебе помочь?

      Из забавного, крупный микросервисный проект в VS 2022 + Docker Desktop собирается за 5 минут, а этот же самый проект с тем же самым docker-compose файлом в CODE + docker-ce собирается за час, при этом полностью утилизирует сетку и сжирает под 100 гб диска.

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


      1. ColdPhoenix
        15.12.2023 18:07

        А что там за магия в "добавить поддержку докер?"

        Там создаётся ровно тот же файл что на скрине у автора, вот и все.

        (Я естественно имею в виду именно этап файла, не более, естественно там больше возможностей), тут предлагается его зачем-то брать либо со скрина, либо с сайта MS. Я строго про это.


  1. Validation123
    15.12.2023 18:07

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