Разворачиваем и демонизируем ASP.NET Core приложение под Linux в виде фонового сервиса

Доброго дня, господа. Сегодня мы затронем тему, за обсуждение которой ещё два года назад сожгли бы на костре — запуск ASP.NET приложения под linux. В данной статье будет использоваться Ubuntu 16.04

Подготовка окружения


Для начала, добавим dotnet-репозиторий:

sudo sh -c 'echo "deb [arch=amd64] https://apt-mo.trafficmanager.net/repos/dotnet-release/ xenial main" > /etc/apt/sources.list.d/dotnetdev.list'

sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 417A0893

На выходе получаем примерно следующее:

image

Теперь обновим индекс наших пакетов:

sudo apt-get update

Далее, мы можем просто установить dotnet-пакет при помощи apt-get:

sudo apt-get install dotnet-dev-1.0.4

Теперь можем смело приступать к созданию приложения

Создание приложения


При помощи команды dotnet new мы можем создать шаблон для нашего приложения, подобно шаблонам из Visual Studio. Подробная документация к команде.

На текущий момент (07.2017), команда dotnet new поддерживает следующие шаблоны:

image

Мы создадим веб-приложение ASP.NET Core:

dotnet new mvc

На выходе консоль выдаст нам следующее сообщение:

image

Чтобы убедиться, что шаблон сгенерировался правильно, заглянем в содержимое папки при помощи команды ls -la.

image

Все необходимые папки для сборки приложения на месте, приступим! Для начала, восстановим все пакеты при помощи dotnet restore.

image

Теперь можем собрать приложение:

dotnet build

image

Запустим приложение с помощью:

dotnet run

image

Консоль говорит нам, что приложение запустилось по адресу localhost:5000/. Проверим:

image

Желающих подробнее узнать, как работает web-сервер отсылаю к официальному источнику.

Теперь убьём процесс нажав Ctrl + C и опубликуем приложение командой dotnet publish. Эта команда упаковывает приложение и все его зависимости для дальнейшего развёртывания (желающим интимных подробностей сюда).

В случае проблем с правами доступа Вам поможет команда sudo chmod и эта страница документации.

Развертывание на сервере.

Если мы хотим развернуть наше приложение под linux-сервером, необходимо настроить прокси и демонизировать процесс запуска приложения. Для проксирования мы будем использовать nginx, для демонизации процесса systemd. Краткое описание утилиты

Создаём прокси-сервер.

Как следует из документации выше, с asp.net core в коробке идет kestrel — веб-сервер для asp.net приложений. Зачем нам тогда нужен прокси-сервер? Ответ даётся на официальной странице Microsoft:

image
Если вы выставляете ваше приложение в интернет, Вы должны использовать IIS, Nginx или Apache как обратный прокси-сервер.

Если Вы не знаете, что такое обратный прокси-сервер

Обратный прокси-сервер получает HTTP запросы из сети и направляет их в Kestrel после первоначальной обработки, как показано на след диаграмме:

image

Главная причина, по которой следует использовать обратный прокси сервер — безопасность. Kestrel относительно нов и ещё не имеет полного комплекта защиты от атак.

Ещё одна причина, по которой следует использовать обратный прокси-сервер — наличие на сервере нескольких приложений, использующих один порт. Kestrel не поддерживает разделение одного порта между несколькими приложениями.

Так же, использование обратного прокси-сервера может облегчить распределение нагрузки и поддержку SSL.

Как говорилось выше, в качестве прокси-сервера мы будем использовать nginx.

Т.к. в качестве прокси-сервера у нас используется не IIS, следует добавить следующие строки в метод Configure файла Startap.cs.

app.UseForwardedHeaders(new ForwardedHeadersOptions
{
    ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});

Здесь мы включаем поддержку ForwardedHeaders мидлвера из пакета. Microsoft.AspNetCore.HttpOverrides, который будет вставлять в Http-запрос заголовки X-Forwarded-For и X-Forwarded-Proto, использующиеся для определения исходного IP адреса клиента и передачи его прокси-серверу. Определение мидлверов и практическое использование так же будет рассмотрено в дальнейших частях этого гайда.

Если у Вас nginx не установлен, выполните следующую команду.

sudo apt-get install nginx

и запустите его командой:

sudo service nginx start

Далее, нам необходимо сконфигурировать nginx для проксирования http-запросов.

Создадим файл /etc/nginx/sites-available/aspnetcore.conf. Папка sites-avalible укахывает nginx-у, какие веб-сайты доступны на текущем сервере для обработки. Добавим в него следующие строки:

server {
    listen 8888; # указываем порт, по которому nginx будет слушать запросы
    location / {
        proxy_pass http://localhost:5000; # указываем порт нашего приложения
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection keep-alive;
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
}

Создадим символическую ссылку на aspnetcore.conf в папку sites-enabled, в которой отражаются запущенные nginx-ом сайты.

sudo ln -s /etc/nginx/sites-available/aspnetcore.conf /etc/nginx/sites-enabled/aspnetcore.conf

Что такое символическая ссылка
(символическая ссылка — специальный файл в файловой системе, в котором вместо пользовательских данных содержится путь к файлу, открываемому при обращении к данной ссылке (файлу)(С) Википедия — прим. авт.)

Nginx настроен на то, чтобы принимать запросы с localhost:8888. Перезапускаем nginx командой sudo service nginx restart, чтобы созданные нами конфигурационные файлы вступили в силу. Проверяем:

image

502-я ошибка говорит, что сервер перенаправляет нас в другое место и в этом месте что-то пошло не так. В нашем случае — я убил процесс с нашим веб-приложением, которое было ранее запущено командой dotnet run. Потому что могу :)

На самом деле, потому что запускать dotnet run в консоли и вечно держать эту вкладку открытой грустно. Именно поэтому процесс будем демонизировать, то есть настроем автозапуск после перезагрузки и автоматическую работу в фоне с помощью systemd.

Для этого создадим файл в директории /etc/systemd/system/ с расширением .service

Назовём его kestrel-test:

sudo nano /etc/systemd/system/kestrel-test.service

И положим в него следующее содержимое:
[Unit]
Description=Example .NET Web API Application running on Ubuntu

[Service]
WorkingDirectory=/home/robounicorn/projects/asp.net/core/test-lesson/bin/Debug/netcoreapp1.1/publish #путь к publish папке вашего приложения
ExecStart=/usr/bin/dotnet /home/robounicorn/projects/asp.net/core/test-lesson/bin/Debug/netcoreapp1.1/publish/test-lesson.dll # путь к опубликованной dll
Restart=always
RestartSec=10 # Перезапускать сервис через 10 секунд при краше приложения
SyslogIdentifier=dotnet-example
User=root # пользователь, под которым следует запускать ваш сервис
Environment=ASPNETCORE_ENVIRONMENT=Production

[Install]
WantedBy=multi-user.target

Теперь включим и запустим сервис при помощи следующих команд:

sudo systemctl enable kestrel-test.service
sudo systemctl start kestrel-test.service

Проверим статус сервиса:

sudo systemctl status kestrel-test.service

Если всё было сделано правильно, на эта команда выдаст нам следующее:

image

Перейдём по ссылке ещё раз:

image

Ну вот, дело в шляпе. Спасибо за внимание!

Похожие публикации

AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама

Комментарии 25

    +2

    Зачем в ExecStart дублируется путь? Разве после указания WorkingDirectory нельзя было написать просто /usr/bin/dotnet ./test-lesson.dll?


    User=root — вот так точно делать не стоит. Особенно так не стоит делать для программ, к которым кто-то кроме рута имеет доступ на запись. Надо включить в инструкцию создание отдельного пользователя для демона.


    И последнее.


    Здесь мы включаем поддержку ForwardedHeaders мидлвера из пакета. Microsoft.AspNetCore.HttpOverrides, который будет вставлять в Http-запрос заголовки X-Forwarded-For и X-Forwarded-Proto, использующиеся для определения исходного IP адреса клиента и передачи его прокси-серверу.

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

      0

      Кстати, если я ничего не путаю, то по умолчанию nginx эти заголовки не добавляет. Надо еще указать ему:


      proxy_set_header X-Forwarded-For $remote_addr;
      proxy_set_header X-Forwarded-Proto $scheme;
        0
        В оригинальной инструкции от Майкрософта указывается пользователь www-data.
        0
        Когда вместо (вместе с) Kestrel будет уже какой-нибудь FastCGI сервер для .net core? Никто не знает, разрабатываются ли подобные проекты?
          0

          А какая в нем необходимость? Все равно сервер приложений .net core (какой бы он ни был) прятать за каким-нибудь nginx.

            0
            В том, что FastCGI общающийся с Nginx производительней, чем полноценный HTTP сервер, стоящий за тем же Nginx-ом.
              0
              А разве будет существовать хоть сколько нибудь значимая разница в производительности между легковесным (inapp?) веб сервером для компилируемых (даже в байт код) приложений?
              Это же не CGI, рожденный чтобы умереть или заранее запущенный процесс интерпретатора. Заморачивался ранее таким же вопросом, даже находил полуживой проект (кажись для моно). Но в основном все забили.
          +1
          Прекратите демонизировать ASP.NET Core!
            +1
            Я бы посоветовал использовать supervisor для запуска dotnet?
            • НЛО прилетело и опубликовало эту надпись здесь
                0
                «Я бы посоветовал использовать supervisor для запуска dotnet» без вопросительного знака в конце.
                • НЛО прилетело и опубликовало эту надпись здесь
              0
              После использования Docker'а, подобные манипуляции вызывают противоречивые ощущения.
                0

                Поделитесь, что вас смущает?

                0
                Не очень понимаю, зачем добавляем ForwardedHeaders:
                Насколько знаю (и использую в своих проектах), можно спокойно вытащить настоящий Ip — Request.HttpContext.Connection.RemoteIpAddress либо из заголовка X-Real-IP, даже если kestrel прячется за прокси.

                В своих проектах используем supervisor, чтобы «демонизировать» asp.net core.
                В итоге выходит как-то так: есть n-контейнеров с asp.net core приложениями, у которых внутри supervisor и само приложение, есть контейнер с nginx, который слушает все входящие запросы на 80 и 443 порты, а потом просто прокидывает в нужный контейнер, ну и всякие контейнеры с базами и прочим.
                Из приятного в таком подходе — можем держать зоопарк приложений с разными версиями dotnet core всего лишь создав несколько образов
                  0

                  Вот для того чтобы вы могли вытащить из Request.HttpContext.Connection.RemoteIpAddress настоящий IP клиента при использовании обратного прокси — и добавляют ForwardedHeaders.

                  0
                  Меня одно очень беспокоит, после билда dotnet проектов в памяти остаются всякие лишние процессы, почему они не заканчиваются, сами не терминатятся?
                  Приходится вручную убивать — но это же не гуд, или это обычное дело для MS?
                    0

                    "Лишние" — это какие именно? Интересуют их имена и переданные им параметры (можно подглядеть в /proc/${pid}/cmdline).

                      0
                      Билд прошел после команд dotnet restore && dotnet build.
                      И остается такое:

                      Все в одну строку, разметка Хабра иначе режет, нету скролинга (

                      /proc/31190/cmdline
                      /usr/share/dotnet/dotnet./usr/share/dotnet/sdk/2.2.401/MSBuild.dll.
                      /usr/share/dotnet/sdk/2.2.401/MSBuild.dll./nologo./nodemode:1./nodeReuse:true.


                      вырзал с htop
                       root       20   0 3797M 88712 55496 S  0.0  1.1  0:01.39 ├─ /usr/share/dotnet/dotnet /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /nologo /nodemode:1 /nodeReuse:true
                       root       20   0 3797M 88712 55496 S  0.0  1.1  0:00.00 │  ├─ /usr/share/dotnet/dotnet /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /nologo /nodemode:1 /nodeReuse:true
                       root       20   0 3797M 88712 55496 S  0.0  1.1  0:00.00 │  ├─ /usr/share/dotnet/dotnet /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /nologo /nodemode:1 /nodeReuse:true
                       root       20   0 3797M 88712 55496 S  0.0  1.1  0:00.00 │  ├─ /usr/share/dotnet/dotnet /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /nologo /nodemode:1 /nodeReuse:true
                       root       20   0 3797M 88712 55496 S  0.0  1.1  0:00.00 │  ├─ /usr/share/dotnet/dotnet /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /nologo /nodemode:1 /nodeReuse:true
                       root       20   0 3797M 88712 55496 S  0.0  1.1  0:00.26 │  ├─ /usr/share/dotnet/dotnet /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /nologo /nodemode:1 /nodeReuse:true
                       root       20   0 3797M 88712 55496 S  0.0  1.1  0:00.25 │  ├─ /usr/share/dotnet/dotnet /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /nologo /nodemode:1 /nodeReuse:true
                       root       20   0 3797M 88712 55496 S  0.0  1.1  0:00.00 │  ├─ /usr/share/dotnet/dotnet /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /nologo /nodemode:1 /nodeReuse:true
                       root       20   0 3797M 88712 55496 S  0.0  1.1  0:00.36 │  ├─ /usr/share/dotnet/dotnet /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /nologo /nodemode:1 /nodeReuse:true
                       root       20   0 3797M 88712 55496 S  0.0  1.1  0:00.00 │  ├─ /usr/share/dotnet/dotnet /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /nologo /nodemode:1 /nodeReuse:true
                       root       20   0 3797M 88712 55496 S  0.0  1.1  0:00.00 │  ├─ /usr/share/dotnet/dotnet /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /nologo /nodemode:1 /nodeReuse:true
                       root       20   0 3797M 88712 55496 S  0.0  1.1  0:00.00 │  ├─ /usr/share/dotnet/dotnet /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /nologo /nodemode:1 /nodeReuse:true
                       root       20   0 3797M 88712 55496 S  0.0  1.1  0:00.00 │  ├─ /usr/share/dotnet/dotnet /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /nologo /nodemode:1 /nodeReuse:true
                       root       20   0 3797M 88712 55496 S  0.0  1.1  0:00.00 │  ├─ /usr/share/dotnet/dotnet /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /nologo /nodemode:1 /nodeReuse:true
                       root       20   0 3797M 88712 55496 S  0.0  1.1  0:00.00 │  ├─ /usr/share/dotnet/dotnet /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /nologo /nodemode:1 /nodeReuse:true
                       root       20   0 3797M 88712 55496 S  0.0  1.1  0:00.00 │  ├─ /usr/share/dotnet/dotnet /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /nologo /nodemode:1 /nodeReuse:true
                       root       20   0 3797M 88712 55496 S  0.0  1.1  0:00.00 │  ├─ /usr/share/dotnet/dotnet /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /nologo /nodemode:1 /nodeReuse:true
                       root       20   0 3797M 88712 55496 S  0.0  1.1  0:00.00 │  └─ /usr/share/dotnet/dotnet /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /nologo /nodemode:1 /nodeReuse:true
                       root       20   0 3525M 83644 53828 S  0.0  1.1  0:01.16 ├─ /usr/share/dotnet/dotnet /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /nologo /nodemode:1 /nodeReuse:true
                       root       20   0 3525M 83644 53828 S  0.0  1.1  0:00.00 │  ├─ /usr/share/dotnet/dotnet /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /nologo /nodemode:1 /nodeReuse:true
                       root       20   0 3525M 83644 53828 S  0.0  1.1  0:00.00 │  ├─ /usr/share/dotnet/dotnet /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /nologo /nodemode:1 /nodeReuse:true
                       root       20   0 20.6G  252M 51764 S  0.0  3.3  0:05.31 │  ├─ /usr/share/dotnet/dotnet exec /usr/share/dotnet/sdk/2.2.401/Roslyn/bincore/VBCSCompiler.dll -pipename:xgicJLh614PpucyV4Nn9s_uL0EDEHYOnMe1l7fuQkb8
                       root       20   0 20.6G  252M 51764 S  0.0  3.3  0:00.00 │  │  ├─ /usr/share/dotnet/dotnet exec /usr/share/dotnet/sdk/2.2.401/Roslyn/bincore/VBCSCompiler.dll -pipename:xgicJLh614PpucyV4Nn9s_uL0EDEHYOnMe1l7fuQkb8
                       root       20   0 20.6G  252M 51764 S  0.0  3.3  0:00.00 │  │  ├─ /usr/share/dotnet/dotnet exec /usr/share/dotnet/sdk/2.2.401/Roslyn/bincore/VBCSCompiler.dll -pipename:xgicJLh614PpucyV4Nn9s_uL0EDEHYOnMe1l7fuQkb8
                       root       20   0 20.6G  252M 51764 S  0.0  3.3  0:00.00 │  │  ├─ /usr/share/dotnet/dotnet exec /usr/share/dotnet/sdk/2.2.401/Roslyn/bincore/VBCSCompiler.dll -pipename:xgicJLh614PpucyV4Nn9s_uL0EDEHYOnMe1l7fuQkb8
                       root       20   0 20.6G  252M 51764 S  0.0  3.3  0:00.00 │  │  ├─ /usr/share/dotnet/dotnet exec /usr/share/dotnet/sdk/2.2.401/Roslyn/bincore/VBCSCompiler.dll -pipename:xgicJLh614PpucyV4Nn9s_uL0EDEHYOnMe1l7fuQkb8
                       root       20   0 20.6G  252M 51764 S  0.0  3.3  0:00.00 │  │  ├─ /usr/share/dotnet/dotnet exec /usr/share/dotnet/sdk/2.2.401/Roslyn/bincore/VBCSCompiler.dll -pipename:xgicJLh614PpucyV4Nn9s_uL0EDEHYOnMe1l7fuQkb8
                       root       20   0 20.6G  252M 51764 S  0.0  3.3  0:00.00 │  │  ├─ /usr/share/dotnet/dotnet exec /usr/share/dotnet/sdk/2.2.401/Roslyn/bincore/VBCSCompiler.dll -pipename:xgicJLh614PpucyV4Nn9s_uL0EDEHYOnMe1l7fuQkb8
                       root       20   0 20.6G  252M 51764 S  0.0  3.3  0:00.00 │  │  ├─ /usr/share/dotnet/dotnet exec /usr/share/dotnet/sdk/2.2.401/Roslyn/bincore/VBCSCompiler.dll -pipename:xgicJLh614PpucyV4Nn9s_uL0EDEHYOnMe1l7fuQkb8
                       root       20   0 20.6G  252M 51764 S  0.0  3.3  0:00.00 │  │  ├─ /usr/share/dotnet/dotnet exec /usr/share/dotnet/sdk/2.2.401/Roslyn/bincore/VBCSCompiler.dll -pipename:xgicJLh614PpucyV4Nn9s_uL0EDEHYOnMe1l7fuQkb8
                       root       20   0 20.6G  252M 51764 S  0.0  3.3  0:00.01 │  │  ├─ /usr/share/dotnet/dotnet exec /usr/share/dotnet/sdk/2.2.401/Roslyn/bincore/VBCSCompiler.dll -pipename:xgicJLh614PpucyV4Nn9s_uL0EDEHYOnMe1l7fuQkb8
                       root       20   0 20.6G  252M 51764 S  0.0  3.3  0:00.36 │  │  ├─ /usr/share/dotnet/dotnet exec /usr/share/dotnet/sdk/2.2.401/Roslyn/bincore/VBCSCompiler.dll -pipename:xgicJLh614PpucyV4Nn9s_uL0EDEHYOnMe1l7fuQkb8
                       root       20   0 20.6G  252M 51764 S  0.0  3.3  0:00.32 │  │  ├─ /usr/share/dotnet/dotnet exec /usr/share/dotnet/sdk/2.2.401/Roslyn/bincore/VBCSCompiler.dll -pipename:xgicJLh614PpucyV4Nn9s_uL0EDEHYOnMe1l7fuQkb8
                       root       20   0 20.6G  252M 51764 S  0.0  3.3  0:00.28 │  │  ├─ /usr/share/dotnet/dotnet exec /usr/share/dotnet/sdk/2.2.401/Roslyn/bincore/VBCSCompiler.dll -pipename:xgicJLh614PpucyV4Nn9s_uL0EDEHYOnMe1l7fuQkb8
                       root       20   0 20.6G  252M 51764 S  0.0  3.3  0:00.30 │  │  ├─ /usr/share/dotnet/dotnet exec /usr/share/dotnet/sdk/2.2.401/Roslyn/bincore/VBCSCompiler.dll -pipename:xgicJLh614PpucyV4Nn9s_uL0EDEHYOnMe1l7fuQkb8
                       root       20   0 20.6G  252M 51764 S  0.0  3.3  0:00.00 │  │  ├─ /usr/share/dotnet/dotnet exec /usr/share/dotnet/sdk/2.2.401/Roslyn/bincore/VBCSCompiler.dll -pipename:xgicJLh614PpucyV4Nn9s_uL0EDEHYOnMe1l7fuQkb8
                       root       20   0 20.6G  252M 51764 S  0.0  3.3  0:00.00 │  │  ├─ /usr/share/dotnet/dotnet exec /usr/share/dotnet/sdk/2.2.401/Roslyn/bincore/VBCSCompiler.dll -pipename:xgicJLh614PpucyV4Nn9s_uL0EDEHYOnMe1l7fuQkb8
                       root       20   0 20.6G  252M 51764 S  0.0  3.3  0:00.00 │  │  ├─ /usr/share/dotnet/dotnet exec /usr/share/dotnet/sdk/2.2.401/Roslyn/bincore/VBCSCompiler.dll -pipename:xgicJLh614PpucyV4Nn9s_uL0EDEHYOnMe1l7fuQkb8
                       root       20   0 20.6G  252M 51764 S  0.0  3.3  0:00.00 │  │  ├─ /usr/share/dotnet/dotnet exec /usr/share/dotnet/sdk/2.2.401/Roslyn/bincore/VBCSCompiler.dll -pipename:xgicJLh614PpucyV4Nn9s_uL0EDEHYOnMe1l7fuQkb8
                       root       20   0 20.6G  252M 51764 S  0.0  3.3  0:00.00 │  │  └─ /usr/share/dotnet/dotnet exec /usr/share/dotnet/sdk/2.2.401/Roslyn/bincore/VBCSCompiler.dll -pipename:xgicJLh614PpucyV4Nn9s_uL0EDEHYOnMe1l7fuQkb8
                       root       20   0 3525M 83644 53828 S  0.0  1.1  0:00.67 │  ├─ /usr/share/dotnet/dotnet /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /nologo /nodemode:1 /nodeReuse:true
                       root       20   0 3525M 83644 53828 S  0.0  1.1  0:00.00 │  ├─ /usr/share/dotnet/dotnet /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /nologo /nodemode:1 /nodeReuse:true
                       root       20   0 3525M 83644 53828 S  0.0  1.1  0:00.00 │  ├─ /usr/share/dotnet/dotnet /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /nologo /nodemode:1 /nodeReuse:true
                       root       20   0 3525M 83644 53828 S  0.0  1.1  0:00.00 │  ├─ /usr/share/dotnet/dotnet /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /nologo /nodemode:1 /nodeReuse:true
                       root       20   0 3525M 83644 53828 S  0.0  1.1  0:00.00 │  ├─ /usr/share/dotnet/dotnet /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /nologo /nodemode:1 /nodeReuse:true
                       root       20   0 3525M 83644 53828 S  0.0  1.1  0:00.00 │  ├─ /usr/share/dotnet/dotnet /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /nologo /nodemode:1 /nodeReuse:true
                       root       20   0 3525M 83644 53828 S  0.0  1.1  0:00.00 │  ├─ /usr/share/dotnet/dotnet /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /nologo /nodemode:1 /nodeReuse:true
                       root       20   0 3525M 83644 53828 S  0.0  1.1  0:00.00 │  ├─ /usr/share/dotnet/dotnet /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /nologo /nodemode:1 /nodeReuse:true
                       root       20   0 3525M 83644 53828 S  0.0  1.1  0:00.00 │  ├─ /usr/share/dotnet/dotnet /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /nologo /nodemode:1 /nodeReuse:true
                       root       20   0 3525M 83644 53828 S  0.0  1.1  0:00.00 │  └─ /usr/share/dotnet/dotnet /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /nologo /nodemode:1 /nodeReuse:true
                       root       20   0 3861M 91876 55668 S  0.0  1.2  0:01.66 ├─ /usr/share/dotnet/dotnet /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /nologo /nodemode:1 /nodeReuse:true
                       root       20   0 3861M 91876 55668 S  0.0  1.2  0:00.00 │  ├─ /usr/share/dotnet/dotnet /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /nologo /nodemode:1 /nodeReuse:true
                       root       20   0 3861M 91876 55668 S  0.0  1.2  0:00.00 │  ├─ /usr/share/dotnet/dotnet /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /nologo /nodemode:1 /nodeReuse:true
                       root       20   0 3861M 91876 55668 S  0.0  1.2  0:00.57 │  ├─ /usr/share/dotnet/dotnet /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /nologo /nodemode:1 /nodeReuse:true
                       root       20   0 3861M 91876 55668 S  0.0  1.2  0:00.12 │  ├─ /usr/share/dotnet/dotnet /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /usr/share/dotnet/sdk/2.2.401/MSBuild.dll /nologo /nodemode:1 /nodeReuse:true
                      


                      P.S. скрин не вставить, формат не схранить, как-то не очень (
                        0

                        Сами эти процессы не заканчиваются, очевидно, из-за ключа /nodeReuse:true. Похоже, это фича такая, для ускорения повторных сборок.


                        Если они вам не нужны — вот так попробуйте: dotnet build /nodeReuse:false. Если процессы останутся — то вот так: MSBUILDDISABLENODEREUSE=1 dotnet build


                        Ах да, судя по документации, дольше 60 секунд эти процессы в состоянии idle не проживут в любом случае; так что специально искать и убивать их точно не стоит.

                          0
                          Хм, это частично помогло (MSBUILDDISABLENODEREUSE=1), часть процесов красиво завершилось, но часть все же осталась.

                          А что по таким посоветуете:
                          /usr/share/dotnet/dotnet exec /usr/share/dotnet/sdk/2.2.401/Roslyn/bincore/VBCSCompiler.dll -pipename:xgicJLh614PpucyV4Nn9s_uL0EDEHYOnMe1l7fuQkb8

                            0

                            А это отключается через -p:UseSharedCompilation=false (ну или UseSharedCompilation=0)
                            Ещё есть UseRazorBuildServer для Razor.


                            Ещё подсказывают команду dotnet build-server shutdown.

                              0
                              В итоге все идеально стало после такого вида:
                              MSBUILDDISABLENODEREUSE=1 UseSharedCompilation=0 dotnet restore
                              MSBUILDDISABLENODEREUSE=1 UseSharedCompilation=0 dotnet build /nodeReuse:false -p:UseSharedCompilation=false

                              Спасибо тебе добрый человек!
                              Жаль не могу карму повысить!
                                0

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

                                  0
                                  Не поверишь! Без него не билдилось выдавало ерор! ))
                                  А сам за минимализм, но как оказалось, минимальная рабочая конструкция такая…

                                  /usr/share/dotnet/sdk/2.2.401/Roslyn/Microsoft.CSharp.Core.targets(126,10): error MSB4030: "0" is an invalid value for the "UseSharedCompilation" parameter of the "Csc" task. The "UseSharedCompilation" parameter is of type "System.Boolean". [/var/www/src-wemine/src/WeMine.Domain/WeMine.Domain.csproj]

                                  Build FAILED.

                                  /usr/share/dotnet/sdk/2.2.401/Roslyn/Microsoft.CSharp.Core.targets(126,10): error MSB4030: "0" is an invalid value for the "UseSharedCompilation" parameter of the "Csc" task. The "UseSharedCompilation" parameter is of type "System.Boolean". [/var/www/src-wemine/src/WeMine.Domain/WeMine.Domain.csproj]
                                  0 Warning(s)
                                  1 Error(s)

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

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