Руководство. Контейнеризация приложения .NET
В этом руководстве описано, как контейнеризировать приложение .NET с помощью Docker. Контейнеры имеют множество функций и преимуществ, таких как неизменяемая инфраструктура, предоставление переносимой архитектуры и включение масштабируемости. Образ можно использовать для создания контейнеров для локальной среды разработки, частного облака или общедоступного облака.
В этом руководстве вы:
- Создание и публикация простого приложения .NET
- Создание и настройка Dockerfile для .NET
- Создание образа Docker
- Создание и запуск контейнера Docker
Вы изучите задачи сборки и развертывания контейнеров Docker для приложения .NET. Платформа Docker
Совет
Если вы заинтересованы в публикации приложения .NET в виде контейнера без необходимости использования Docker или Podman, см. Контейнеризация приложения .NET с помощью dotnet publish.
Заметка
Данное учебное пособие не предназначено для приложений ASP.NET Core. Если вы используете ASP.NET Core, ознакомьтесь с руководством по контейнеризации приложения ASP.NET Core.
Необходимые условия
Установите следующие предварительные требования:
-
.NET 8+ SDK.
Если вы установили .NET, используйте командуdotnet --info
, чтобы определить, какой пакет SDK вы используете. - Docker Community Edition.
- Временная рабочая папка для Dockerfile и примерного приложения на .NET. В этом руководстве имя docker-working используется в качестве рабочей папки.
Создание приложения .NET
Вам нужно приложение .NET, которое запускает контейнер Docker. Откройте терминал, создайте рабочую папку, если вы еще не сделали этого, и введите ее. В рабочей папке выполните следующую команду, чтобы создать проект в подкаталоге с именем App:
dotnet new console -o App -n DotNet.Docker
Дерево папок выглядит примерно так, как показано в следующей структуре каталогов:
📁 docker-working
└──📂 App
├──DotNet.Docker.csproj
├──Program.cs
└──📂 obj
├── DotNet.Docker.csproj.nuget.dgspec.json
├── DotNet.Docker.csproj.nuget.g.props
├── DotNet.Docker.csproj.nuget.g.targets
├── project.assets.json
└── project.nuget.cache
Команда dotnet new
создает новую папку с именем App и создает консольное приложение Hello World. Теперь вы изменяете каталоги и переходите в папку приложения dotnet run
для запуска приложения. Приложение запускается и выводит Hello World!
ниже команды:
cd App
dotnet run
Hello World!
Шаблон по умолчанию создает приложение, которое выводится в терминал, а затем немедленно завершает работу. В этом руководстве используется приложение, которое циклит бесконечно. Откройте файл Program.cs в текстовом редакторе.
Совет
Если вы используете Visual Studio Code, в предыдущем сеансе терминала введите следующую команду:
code .
Эта команда открывает папку приложения
Program.cs должен выглядеть как следующий код на языке C#:
Console.WriteLine("Hello World!");
Замените файл следующим кодом, который подсчитывает числа каждые секунды:
var counter = 0;
var max = args.Length is not 0 ? Convert.ToInt32(args[0]) : -1;
while (max is -1 || counter < max)
{
Console.WriteLine($"Counter: {++counter}");
await Task.Delay(TimeSpan.FromMilliseconds(1_000));
}
var counter = 0;
var max = args.Length is not 0 ? Convert.ToInt32(args[0]) : -1;
while (max is -1 || counter < max)
{
Console.WriteLine($"Counter: {++counter}");
await Task.Delay(TimeSpan.FromMilliseconds(1_000));
}
Сохраните файл и проверьте программу еще раз с помощью dotnet run
. Учтите, что это приложение работает бесконечно. Чтобы остановить её, используйте команду отмены Ctrl+C. Рассмотрим следующий пример выходных данных:
dotnet run
Counter: 1
Counter: 2
Counter: 3
Counter: 4
^C
Если вы передаете номер в командной строке приложению, оно ограничивает количество этой суммы, а затем завершает работу. Попробуйте использовать dotnet run -- 5
, чтобы подсчитать до пяти.
Важный
Все параметры после --
не передаются в команду dotnet run
и вместо этого передаются в приложение.
Публикация приложения .NET
Чтобы приложение было подходящим для создания образа, его необходимо скомпилировать. Команда dotnet publish
наиболее подходит для этого, так как она создает и публикует приложение. См. подробные сведения в документации по командам dotnet build и dotnet publish.
dotnet publish -c Release
Совет
Если вы заинтересованы в упаковке вашего приложения .NET в контейнер без использования Docker, ознакомьтесь с контейнеризацией приложения .NET с помощью dotnet publish.
Команда dotnet publish
компилирует приложение в папку для публикации . Путь к папке публикации из рабочей папки должен быть ./App/bin/Release/<TFM>/publish/:
В папке App получите список каталогов папки публикации, чтобы убедиться, что файл DotNet.Docker.dll был создан.
dir .\bin\Release\net9.0\publish\
Directory: C:\Users\default\docker-working\App\bin\Release\net9.0\publish
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 1/6/2025 10:11 AM 431 DotNet.Docker.deps.json
-a---- 1/6/2025 10:11 AM 6144 DotNet.Docker.dll
-a---- 1/6/2025 10:11 AM 145408 DotNet.Docker.exe
-a---- 1/6/2025 10:11 AM 11716 DotNet.Docker.pdb
-a---- 1/6/2025 10:11 AM 340 DotNet.Docker.runtimeconfig.json
dir .\bin\Release\net8.0\publish\
Directory: C:\Users\default\docker-working\App\bin\Release\net8.0\publish
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 9/22/2023 9:17 AM 431 DotNet.Docker.deps.json
-a--- 9/22/2023 9:17 AM 6144 DotNet.Docker.dll
-a--- 9/22/2023 9:17 AM 157696 DotNet.Docker.exe
-a--- 9/22/2023 9:17 AM 11688 DotNet.Docker.pdb
-a--- 9/22/2023 9:17 AM 353 DotNet.Docker.runtimeconfig.json
Создайте Dockerfile
Файл Dockerfile
Создайте файл с именем Dockerfile в каталоге, содержащий CSPROJ и откройте его в текстовом редакторе. В этом руководстве используется образ среды выполнения ASP.NET Core (который содержит образ среды выполнения .NET) и соответствует консольному приложению .NET.
FROM mcr.microsoft.com/dotnet/sdk:9.0@sha256:3fcf6f1e809c0553f9feb222369f58749af314af6f063f389cbd2f913b4ad556 AS build
WORKDIR /App
# Copy everything
COPY . ./
# Restore as distinct layers
RUN dotnet restore
# Build and publish a release
RUN dotnet publish -o out
# Build runtime image
FROM mcr.microsoft.com/dotnet/aspnet:9.0@sha256:b4bea3a52a0a77317fa93c5bbdb076623f81e3e2f201078d89914da71318b5d8
WORKDIR /App
COPY --from=build /App/out .
ENTRYPOINT ["dotnet", "DotNet.Docker.dll"]
Заметка
Образ среды выполнения ASP.NET Core используется намеренно здесь, хотя вместо этого можно использовать образ mcr.microsoft.com/dotnet/runtime:9.0
.
FROM mcr.microsoft.com/dotnet/sdk:8.0@sha256:35792ea4ad1db051981f62b313f1be3b46b1f45cadbaa3c288cd0d3056eefb83 AS build
WORKDIR /App
# Copy everything
COPY . ./
# Restore as distinct layers
RUN dotnet restore
# Build and publish a release
RUN dotnet publish -o out
# Build runtime image
FROM mcr.microsoft.com/dotnet/aspnet:8.0@sha256:6c4df091e4e531bb93bdbfe7e7f0998e7ced344f54426b7e874116a3dc3233ff
WORKDIR /App
COPY --from=build /App/out .
ENTRYPOINT ["dotnet", "DotNet.Docker.dll"]
Заметка
Образ среды выполнения ASP.NET Core используется намеренно здесь, хотя вместо этого можно использовать образ mcr.microsoft.com/dotnet/runtime:8.0
.
Важный
Включение безопасного хэш-алгоритма (SHA) после тега изображения в Dockerfile рекомендуется. Это гарантирует, что изображение не изменено и что изображение совпадает с ожидаемым. SHA — это уникальный идентификатор изображения. Дополнительные сведения см. в статье Документация Docker: загрузка изображения по дайджесту.
Совет
В этом Dockerfile используются многоэтапные сборки, которые оптимизируют окончательный размер образа путем создания слоя сборки и оставляя только необходимые артефакты. Дополнительные сведения см. в документации Docker: многоэтапные сборки.
Ключевое слово FROM
требует полного квалифицированного имени образа контейнера Docker. Реестр контейнеров Майкрософт (MCR, mcr.microsoft.com) — это синдикат Docker Hub, на котором размещаются общедоступные контейнеры. Сегмент dotnet
— это репозиторий контейнеров, а сегмент sdk
или aspnet
— имя образа контейнера. Изображение помечено тегом 9.0
, который используется для версионирования. Таким образом, mcr.microsoft.com/dotnet/aspnet:9.0
— это среда выполнения .NET 9.0. Убедитесь, что вы извлеките версию среды выполнения, соответствующую среде выполнения, предназначенной для пакета SDK. Например, приложение, созданное в предыдущем разделе, использовал пакет SDK для .NET 9.0, а базовый образ, указанный в Dockerfile, помечен как 9.0.
Важный
При использовании образов контейнеров под управлением Windows необходимо указать тег изображения, кроме 9.0
, например, mcr.microsoft.com/dotnet/aspnet:9.0-nanoserver-1809
вместо mcr.microsoft.com/dotnet/aspnet:9.0
. Выберите имя образа в зависимости от того, используете ли вы Nano Server или Windows Server Core и какую версию этой ОС. Полный список всех поддерживаемых тегов можно найти на странице Docker Hub .NET .
Сохраните файл Dockerfile. Структура каталогов рабочей папки должна выглядеть следующим образом. Некоторые из более глубоких файлов и папок опущены для экономии места в статье:
📁 docker-working
└──📂 App
├── Dockerfile
├── DotNet.Docker.csproj
├── Program.cs
├──📂 bin
│ └───📂 Release
│ └───📂 net9.0
│ ├───📂 publish
│ │ ├─── DotNet.Docker.deps.json
│ │ ├─── DotNet.Docker.dll
│ │ ├─── DotNet.Docker.exe
│ │ ├─── DotNet.Docker.pdb
│ │ └─── DotNet.Docker.runtimeconfig.json
│ ├─── DotNet.Docker.deps.json
│ ├─── DotNet.Docker.dll
│ ├─── DotNet.Docker.exe
│ ├─── DotNet.Docker.pdb
│ └─── DotNet.Docker.runtimeconfig.json
└──📁 obj
└──...
Ключевое слово FROM
требует полностью квалифицированного имени образа контейнера Docker. Реестр контейнеров Майкрософт (MCR, mcr.microsoft.com) — это синдикат Docker Hub, на котором размещаются общедоступные контейнеры. Сегмент dotnet
— это репозиторий контейнеров, а сегмент sdk
или aspnet
— имя образа контейнера. Изображение помечено 8.0
, которое используется для контроля версий. Таким образом, mcr.microsoft.com/dotnet/aspnet:8.0
— это среда выполнения .NET 8.0. Убедитесь, что вы извлеките версию среды выполнения, соответствующую среде выполнения, предназначенной для пакета SDK. Например, приложение, созданное в предыдущем разделе, использовал пакет SDK для .NET 8.0, а базовый образ, упомянутый в Dockerfile, помечен как 8.0.
Важный
При использовании образов контейнеров под управлением Windows необходимо указать тег изображения, кроме 8.0
, например, mcr.microsoft.com/dotnet/aspnet:8.0-nanoserver-1809
вместо mcr.microsoft.com/dotnet/aspnet:8.0
. Выберите имя образа в зависимости от того, используете ли вы Nano Server или Windows Server Core и какую версию этой ОС. Полный список всех поддерживаемых тегов можно найти на странице Docker Hub .NET .
Сохраните файл Dockerfile. Структура каталогов рабочей папки должна выглядеть следующим образом. Некоторые из более глубоких файлов и папок опущены для экономии места в статье:
📁 docker-working
└──📂 App
├── Dockerfile
├── DotNet.Docker.csproj
├── Program.cs
├──📂 bin
│ └──📂 Release
│ └──📂 net8.0
│ └──📂 publish
│ ├── DotNet.Docker.deps.json
│ ├── DotNet.Docker.exe
│ ├── DotNet.Docker.dll
│ ├── DotNet.Docker.pdb
│ └── DotNet.Docker.runtimeconfig.json
└──📁 obj
└──...
Инструкция ENTRYPOINT
устанавливает dotnet
в качестве узла для DotNet.Docker.dll
. Однако вместо этого можно определить ENTRYPOINT
как исполняемый файл приложения, опираясь на ОС в качестве узла приложения:
ENTRYPOINT ["./DotNet.Docker"]
Это приводит к выполнению приложения непосредственно, без dotnet
, вместо этого полагаясь на хост приложения и базовую ОС. Дополнительные сведения о развертывании кроссплатформенных двоичных файлов см. в разделе Создание кроссплатформенного двоичного файла.
Чтобы создать контейнер, выполните следующую команду:
docker build -t counter-image -f Dockerfile .
Docker обрабатывает каждую строку в Dockerfile.
.
в команде docker build
задает контекст сборки образа. Переключатель -f
— это путь к Dockerfile . Эта команда создает образ и локальный репозиторий с именем counter-image, который указывает на этот образ. После завершения этой команды запустите docker images
, чтобы просмотреть список установленных образов:
REPOSITORY TAG IMAGE ID CREATED SIZE
counter-image latest 1c1f1433e51d 32 seconds ago 223MB
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
counter-image latest 2f15637dc1f6 10 minutes ago 217MB
Репозиторий counter-image
— это имя образа. Кроме того, тег изображения, идентификатор изображения, размер и когда он был создан, являются частью выходных данных. Последние шаги Dockerfile — создать контейнер из образа и запустить приложение, скопировать опубликованное приложение в контейнер и определить точку входа:
FROM mcr.microsoft.com/dotnet/aspnet:9.0
WORKDIR /App
COPY --from=build /App/out .
ENTRYPOINT ["dotnet", "DotNet.Docker.dll"]
FROM mcr.microsoft.com/dotnet/aspnet:8.0
WORKDIR /App
COPY --from=build /App/out .
ENTRYPOINT ["dotnet", "DotNet.Docker.dll"]
Команда FROM
указывает базовый образ и тег для использования. Команда WORKDIR
изменяет текущий каталог внутри контейнера на каталог приложения App.
Команда COPY
сообщает Docker скопировать указанный исходный каталог в целевую папку. В этом примере содержимое
Следующая команда, ENTRYPOINT
, сообщает Docker настроить контейнер для запуска в качестве исполняемого файла. При запуске контейнера выполняется команда ENTRYPOINT
. После завершения этой команды контейнер автоматически останавливается.
Совет
До .NET 8 контейнеры, настроенные для запуска только для чтения, могли завершиться ошибкой с Failed to create CoreCLR, HRESULT: 0x8007000E
. Чтобы устранить эту проблему, укажите переменную среды DOTNET_EnableDiagnostics
как 0
(непосредственно перед шагом ENTRYPOINT
):
ENV DOTNET_EnableDiagnostics=0
Дополнительные сведения о различных переменных среды .NET см. в разделе переменных среды .NET.
Заметка
.NET 6 стандартизирует префикс DOTNET_
вместо COMPlus_
переменных среды, которые настраивают поведение во время выполнения .NET. Однако префикс COMPlus_
продолжит работать. Если вы используете предыдущую версию среды выполнения .NET, необходимо по-прежнему использовать префикс COMPlus_
для переменных среды.
Создание контейнера
Теперь, когда у вас есть образ, содержащий приложение, можно создать контейнер. Контейнер можно создать двумя способами. Сначала создайте остановленный контейнер.
docker create --name core-counter counter-image
Эта команда docker create
создает контейнер на основе контр-образа изображения. Выходные данные команды docker create
показывают идентификатор контейнера (ваш идентификатор будет иным):
d0be06126f7db6dd1cee369d911262a353c9b7fb4829a0c11b4b2eb7b2d429cf
Чтобы просмотреть список всех контейнеров, используйте команду docker ps -a
:
docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d0be06126f7d counter-image "dotnet DotNet.Docke…" 12 seconds ago Created core-counter
Управление контейнером
Контейнер был создан с определенным именем core-counter
. Это имя используется для управления контейнером. В следующем примере команда docker start
используется для запуска контейнера, а затем использует команду docker ps
для отображения только запущенных контейнеров:
docker start core-counter
core-counter
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
cf01364df453 counter-image "dotnet DotNet.Docke…" 53 seconds ago Up 10 seconds core-counter
Аналогичным образом команда docker stop
останавливает контейнер. В следующем примере команда docker stop
используется для остановки контейнера, а затем командой docker ps
показывается, что контейнеры не запущены:
docker stop core-counter
core-counter
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
Подключение к контейнеру
После запуска контейнера вы можете подключиться к нему, чтобы просмотреть выходные данные. Используйте команды docker start
и docker attach
, чтобы запустить контейнер и просмотреть выходной поток. В этом примере клавиши Ctrl+C используются для отключения от запущенного контейнера. Это нажатие клавиши завершает процесс в контейнере, если не указано иное, что приведёт к остановке контейнера. Параметр --sig-proxy=false
гарантирует, что CTRL+C не останавливает процесс в контейнере.
После отсоединения от контейнера повторно подключитесь, чтобы убедиться, что он все еще работает и подсчитывает.
docker start core-counter
core-counter
docker attach --sig-proxy=false core-counter
Counter: 7
Counter: 8
Counter: 9
^C
docker attach --sig-proxy=false core-counter
Counter: 17
Counter: 18
Counter: 19
^C
Удаление контейнера
Для этой статьи вы не хотите, чтобы контейнеры простаивали без дела и не выполняли никакой функции. Удалите созданный ранее контейнер. Если контейнер запущен, остановите его.
docker stop core-counter
В следующем примере перечислены все контейнеры. Затем она использует команду docker rm
для удаления контейнера, а затем проверяет второй раз для всех запущенных контейнеров.
docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2f6424a7ddce counter-image "dotnet DotNet.Dock…" 7 minutes ago Exited (143) 20 seconds ago core-counter
docker rm core-counter
core-counter
docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
Одиночный запуск
Docker предоставляет команду docker run
для создания и запуска контейнера в качестве одной команды. Эта команда устраняет необходимость запуска docker create
, а затем docker start
. Эту команду можно также настроить для автоматического удаления контейнера при остановке контейнера. Например, используйте docker run -it --rm
для выполнения двух действий, сначала автоматически используйте текущий терминал для подключения к контейнеру, а затем, когда контейнер завершит работу, удалите его:
docker run -it --rm counter-image
Counter: 1
Counter: 2
Counter: 3
Counter: 4
Counter: 5
^C
Контейнер также передает параметры в выполнение приложения .NET. Чтобы приложение .NET считало только до трех, передайте 3.
docker run -it --rm counter-image 3
Counter: 1
Counter: 2
Counter: 3
При docker run -it
команда CTRL+C останавливает процесс, выполняемый в контейнере, который, в свою очередь, останавливает контейнер. Так как был предоставлен параметр --rm
, контейнер автоматически удаляется при остановке процесса. Убедитесь, что он не существует:
docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
Изменение ТОЧКИ ВХОДА
Команда docker run
также позволяет изменить команду ENTRYPOINT
из Dockerfile и выполнить что-то другое, но только для этого контейнера. Например, выполните следующую команду, чтобы запустить bash
или cmd.exe
. При необходимости измените команду.
В этом примере ENTRYPOINT
изменяется на cmd.exe
.
Нажмите Ctrl+C, чтобы завершить процесс и остановить контейнер.
docker run -it --rm --entrypoint "cmd.exe" counter-image
Microsoft Windows [Version 10.0.17763.379]
(c) 2018 Microsoft Corporation. All rights reserved.
C:\>dir
Volume in drive C has no label.
Volume Serial Number is 3005-1E84
Directory of C:\
04/09/2019 08:46 AM <DIR> app
03/07/2019 10:25 AM 5,510 License.txt
04/02/2019 01:35 PM <DIR> Program Files
04/09/2019 01:06 PM <DIR> Users
04/02/2019 01:35 PM <DIR> Windows
1 File(s) 5,510 bytes
4 Dir(s) 21,246,517,248 bytes free
C:\>^C
Заметка
Этот пример работает только в контейнерах Windows. Контейнеры Linux не имеют cmd.exe
.
Основные команды
Docker имеет множество различных команд, которые создают, управляют и взаимодействуют с контейнерами и изображениями. Эти команды Docker необходимы для управления контейнерами:
- сборки Docker
- docker run
- docker ps
- docker stop
- docker rm
- docker rmi
- образа docker
Очистка ресурсов
В этом руководстве вы создали контейнеры и образы. Если вы хотите, удалите эти ресурсы. Используйте следующие команды, чтобы
Список всех контейнеров
docker ps -a
Остановите контейнеры, работающие с указанным именем.
docker stop core-counter
Удаление контейнера
docker rm core-counter
Затем удалите все изображения, которые больше не нужны на компьютере. Удалите образ, созданный вашим Dockerfile, а затем удалите образ .NET, на основе которого был создан Dockerfile. Можно использовать идентификатор IMAGE или строку в формате РЕПОЗИТОРИЯ:TAG.
docker rmi counter-image:latest
docker rmi mcr.microsoft.com/dotnet/aspnet:9.0
docker rmi counter-image:latest
docker rmi mcr.microsoft.com/dotnet/aspnet:8.0
Используйте команду docker images
, чтобы просмотреть список установленных образов.
Совет / Чаевые
Файлы изображений могут быть большими. Как правило, при тестировании и разработке приложения будут удалены временные контейнеры. Обычно вы храните базовые образы с установленной средой выполнения, если планируете создавать на их основе другие образы.
Дальнейшие действия
- Контейнеризация приложения .NET с помощью dotnet publish
- образы контейнеров .NET
- Контейнеризация приложения ASP.NET Core
- службы Azure, поддерживающие контейнеры
- команды Dockerfile
- Средства контейнеров для Visual Studio