Skip to content

Commit cf935f3

Browse files
authored
Update .NET guide to .NET 10 (#23729)
<!--Delete sections as needed --> ## Description Errr... I updated the .NET guide to 10. 😆 ## Related issues or tickets The sample .NET repo has a PR as well - docker/docker-dotnet-sample#9 ## Reviews <!-- Notes for reviewers here --> <!-- List applicable reviews (optionally @tag reviewers) --> - [ ] Technical review - [ ] Editorial review - [ ] Product review
1 parent d596044 commit cf935f3

5 files changed

Lines changed: 206 additions & 30 deletions

File tree

content/guides/dotnet/containerize.md

Lines changed: 104 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,31 @@ $ git clone https://github.com/docker/docker-dotnet-sample
3939

4040
## Initialize Docker assets
4141

42-
Now that you have an application, you can use `docker init` to create the
43-
necessary Docker assets to containerize your application. Inside the
44-
`docker-dotnet-sample` directory, run the `docker init` command in a terminal.
45-
`docker init` provides some default configuration, but you'll need to answer a
46-
few questions about your application. Refer to the following example to answer
47-
the prompts from `docker init` and use the same answers for your prompts.
42+
Now that you have an application, you can create the necessary Docker assets to containerize it. You can choose between using the official .NET images or Docker Hardened Images (DHI).
43+
44+
> [Docker Hardened Images (DHIs)](https://docs.docker.com/dhi/) are minimal, secure, and production-ready container base and application images maintained by Docker. DHI images are recommended for better security—they are designed to reduce vulnerabilities and simplify compliance.
45+
46+
{{< tabs >}}
47+
{{< tab name="Using Docker Hardened Images" >}}
48+
49+
Docker Hardened Images (DHIs) for .NET are available in the [Docker Hardened Images catalog](https://hub.docker.com/hardened-images/catalog/dhi/aspnetcore). Docker Hardened Images are freely available to everyone with no subscription required. You can pull and use them like any other Docker image after signing in to the DHI registry. For more information, see the [DHI quickstart](/dhi/get-started/) guide.
50+
51+
1. Sign in to the DHI registry:
52+
```console
53+
$ docker login dhi.io
54+
```
55+
56+
2. Pull the .NET SDK DHI (check the catalog for available versions):
57+
```console
58+
$ docker pull dhi.io/dotnet:10-sdk
59+
```
60+
61+
3. Pull the ASP.NET Core runtime DHI (check the catalog for available versions):
62+
```console
63+
$ docker pull dhi.io/aspnetcore:10
64+
```
65+
66+
You can use `docker init` to generate Docker assets, then modify the Dockerfile to use DHI images:
4867

4968
```console
5069
$ docker init
@@ -60,10 +79,86 @@ Let's get started!
6079

6180
? What application platform does your project use? ASP.NET Core
6281
? What's the name of your solution's main project? myWebApp
63-
? What version of .NET do you want to use? 8.0
82+
? What version of .NET do you want to use? 10.0
6483
? What local port do you want to use to access your server? 8080
6584
```
6685

86+
In the following Dockerfile, the `FROM` instructions use `dhi.io/dotnet:10-sdk` and `dhi.io/aspnetcore:10` as the base images.
87+
88+
```dockerfile {title=Dockerfile}
89+
# syntax=docker/dockerfile:1
90+
91+
FROM --platform=$BUILDPLATFORM dhi.io/dotnet:10-sdk AS build
92+
ARG TARGETARCH
93+
COPY . /source
94+
WORKDIR /source/src
95+
RUN --mount=type=cache,id=nuget,target=/root/.nuget/packages \
96+
dotnet publish -a ${TARGETARCH/amd64/x64} --use-current-runtime --self-contained false -o /app
97+
98+
FROM dhi.io/aspnetcore:10
99+
WORKDIR /app
100+
COPY --from=build /app .
101+
ENTRYPOINT ["dotnet", "myWebApp.dll"]
102+
```
103+
104+
> [!NOTE]
105+
>
106+
> DHI runtime images already run as a non-root user (`nonroot`, UID 65532), so there's no need to create a user or specify `USER` in your Dockerfile. This reduces the attack surface and simplifies your configuration.
107+
108+
{{< /tab >}}
109+
{{< tab name="Using the official .NET 10 image" >}}
110+
111+
You can use `docker init` to create the necessary Docker assets. Inside the `docker-dotnet-sample` directory, run the `docker init` command in a terminal. `docker init` provides some default configuration, but you'll need to answer a few questions about your application. Refer to the following example to answer the prompts from `docker init` and use the same answers for your prompts.
112+
113+
```console
114+
$ docker init
115+
Welcome to the Docker Init CLI!
116+
117+
This utility will walk you through creating the following files with sensible defaults for your project:
118+
- .dockerignore
119+
- Dockerfile
120+
- compose.yaml
121+
- README.Docker.md
122+
123+
Let's get started!
124+
125+
? What application platform does your project use? ASP.NET Core
126+
? What's the name of your solution's main project? myWebApp
127+
? What version of .NET do you want to use? 10.0
128+
? What local port do you want to use to access your server? 8080
129+
```
130+
131+
This generates a Dockerfile using the official .NET 10 images from Microsoft Container Registry:
132+
133+
```dockerfile {title=Dockerfile}
134+
# syntax=docker/dockerfile:1
135+
136+
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:10.0-alpine AS build
137+
ARG TARGETARCH
138+
COPY . /source
139+
WORKDIR /source/src
140+
RUN --mount=type=cache,id=nuget,target=/root/.nuget/packages \
141+
dotnet publish -a ${TARGETARCH/amd64/x64} --use-current-runtime --self-contained false -o /app
142+
143+
FROM mcr.microsoft.com/dotnet/aspnet:10.0-alpine AS final
144+
WORKDIR /app
145+
COPY --from=build /app .
146+
ARG UID=10001
147+
RUN adduser \
148+
--disabled-password \
149+
--gecos "" \
150+
--home "/nonexistent" \
151+
--shell "/sbin/nologin" \
152+
--no-create-home \
153+
--uid "${UID}" \
154+
appuser
155+
USER appuser
156+
ENTRYPOINT ["dotnet", "myWebApp.dll"]
157+
```
158+
159+
{{< /tab >}}
160+
{{< /tabs >}}
161+
67162
You should now have the following contents in your `docker-dotnet-sample`
68163
directory.
69164

@@ -78,7 +173,7 @@ directory.
78173
│ └── README.md
79174
```
80175

81-
To learn more about the files that `docker init` added, see the following:
176+
To learn more about the files, see the following:
82177
- [Dockerfile](/reference/dockerfile.md)
83178
- [.dockerignore](/reference/dockerfile.md#dockerignore-file)
84179
- [compose.yaml](/reference/compose-file/_index.md)
@@ -126,6 +221,7 @@ Related information:
126221
- [Dockerfile reference](/reference/dockerfile.md)
127222
- [.dockerignore file reference](/reference/dockerfile.md#dockerignore-file)
128223
- [Docker Compose overview](/manuals/compose/_index.md)
224+
- [Docker Hardened Images](/dhi/)
129225

130226
## Next steps
131227

content/guides/dotnet/develop.md

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -288,11 +288,11 @@ immediately reflected in the running container.
288288
Open `docker-dotnet-sample/src/Pages/Index.cshtml` in an IDE or text editor and update the student name text on line 13 from `Student name is` to `Student name:`.
289289

290290
```diff
291-
- <p>Student Name is @Model.StudentName</p>
291+
- <p>Student name is @Model.StudentName</p>
292292
+ <p>Student name: @Model.StudentName</p>
293293
```
294294

295-
Save the changes to `Index.cshmtl` and then wait a few seconds for the application to rebuild. Refresh [http://localhost:8080](http://localhost:8080) in your browser and verify that the updated text appears.
295+
Save the changes to `Index.cshtml` and then wait a few seconds for the application to rebuild. Refresh [http://localhost:8080](http://localhost:8080) in your browser and verify that the updated text appears.
296296

297297
Press `ctrl+c` in the terminal to stop your application.
298298

@@ -304,22 +304,49 @@ Add a new development stage to your Dockerfile and update your `compose.yaml` fi
304304

305305
The following is the updated Dockerfile.
306306

307+
{{< tabs >}}
308+
{{< tab name="Using Docker Hardened Images" >}}
309+
307310
```Dockerfile {hl_lines="10-13"}
308311
# syntax=docker/dockerfile:1
309312
310-
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0-alpine AS build
313+
FROM --platform=$BUILDPLATFORM dhi.io/dotnet:10-sdk AS build
311314
ARG TARGETARCH
312315
COPY . /source
313316
WORKDIR /source/src
314317
RUN --mount=type=cache,id=nuget,target=/root/.nuget/packages \
315318
dotnet publish -a ${TARGETARCH/amd64/x64} --use-current-runtime --self-contained false -o /app
316319
317-
FROM mcr.microsoft.com/dotnet/sdk:8.0-alpine AS development
320+
FROM dhi.io/dotnet:10-sdk AS development
318321
COPY . /source
319322
WORKDIR /source/src
320323
CMD dotnet run --no-launch-profile
321324
322-
FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine AS final
325+
FROM dhi.io/aspnetcore:10
326+
WORKDIR /app
327+
COPY --from=build /app .
328+
ENTRYPOINT ["dotnet", "myWebApp.dll"]
329+
```
330+
331+
{{< /tab >}}
332+
{{< tab name="Using the official .NET 10 image" >}}
333+
334+
```Dockerfile {hl_lines="10-13"}
335+
# syntax=docker/dockerfile:1
336+
337+
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:10.0-alpine AS build
338+
ARG TARGETARCH
339+
COPY . /source
340+
WORKDIR /source/src
341+
RUN --mount=type=cache,id=nuget,target=/root/.nuget/packages \
342+
dotnet publish -a ${TARGETARCH/amd64/x64} --use-current-runtime --self-contained false -o /app
343+
344+
FROM mcr.microsoft.com/dotnet/sdk:10.0-alpine AS development
345+
COPY . /source
346+
WORKDIR /source/src
347+
CMD dotnet run --no-launch-profile
348+
349+
FROM mcr.microsoft.com/dotnet/aspnet:10.0-alpine AS final
323350
WORKDIR /app
324351
COPY --from=build /app .
325352
ARG UID=10001
@@ -335,6 +362,9 @@ USER appuser
335362
ENTRYPOINT ["dotnet", "myWebApp.dll"]
336363
```
337364

365+
{{< /tab >}}
366+
{{< /tabs >}}
367+
338368
The following is the updated `compose.yaml` file.
339369

340370
```yaml {hl_lines=[5,15,16]}
@@ -379,7 +409,7 @@ secrets:
379409
file: db/password.txt
380410
```
381411

382-
Your containerized application will now use the `mcr.microsoft.com/dotnet/sdk:8.0-alpine` image, which includes development tools like `dotnet test`. Continue to the next section to learn how you can run `dotnet test`.
412+
Your containerized application will now use the SDK image (either `dhi.io/dotnet:10-sdk` for DHI or `mcr.microsoft.com/dotnet/sdk:10.0-alpine` for official images), which includes development tools like `dotnet test`. Continue to the next section to learn how you can run `dotnet test`.
383413

384414
## Summary
385415

content/guides/dotnet/run-tests.md

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ You should see output that contains the following.
3636
Starting test execution, please wait...
3737
A total of 1 test files matched the specified pattern.
3838

39-
Passed! - Failed: 0, Passed: 1, Skipped: 0, Total: 1, Duration: < 1 ms - /source/tests/bin/Debug/net8.0/tests.dll (net8.0)
39+
Passed! - Failed: 0, Passed: 1, Skipped: 0, Total: 1, Duration: < 1 ms - /source/tests/bin/Debug/net10.0/tests.dll (net10.0)
4040
```
4141

4242
To learn more about the command, see [docker compose run](/reference/cli/docker/compose/run/).
@@ -47,23 +47,51 @@ To run your tests when building, you need to update your Dockerfile. You can cre
4747

4848
The following is the updated Dockerfile.
4949

50+
{{< tabs >}}
51+
{{< tab name="Using Docker Hardened Images" >}}
52+
53+
```dockerfile {hl_lines="9"}
54+
# syntax=docker/dockerfile:1
55+
56+
FROM --platform=$BUILDPLATFORM dhi.io/dotnet:10-sdk AS build
57+
ARG TARGETARCH
58+
COPY . /source
59+
WORKDIR /source/src
60+
RUN --mount=type=cache,id=nuget,target=/root/.nuget/packages \
61+
dotnet publish -a ${TARGETARCH/amd64/x64} --use-current-runtime --self-contained false -o /app
62+
RUN dotnet test /source/tests
63+
64+
FROM dhi.io/dotnet:10-sdk AS development
65+
COPY . /source
66+
WORKDIR /source/src
67+
CMD dotnet run --no-launch-profile
68+
69+
FROM dhi.io/aspnetcore:10
70+
WORKDIR /app
71+
COPY --from=build /app .
72+
ENTRYPOINT ["dotnet", "myWebApp.dll"]
73+
```
74+
75+
{{< /tab >}}
76+
{{< tab name="Using the official .NET 10 image" >}}
77+
5078
```dockerfile {hl_lines="9"}
5179
# syntax=docker/dockerfile:1
5280

53-
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0-alpine AS build
81+
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:10.0-alpine AS build
5482
ARG TARGETARCH
5583
COPY . /source
5684
WORKDIR /source/src
5785
RUN --mount=type=cache,id=nuget,target=/root/.nuget/packages \
5886
dotnet publish -a ${TARGETARCH/amd64/x64} --use-current-runtime --self-contained false -o /app
5987
RUN dotnet test /source/tests
6088

61-
FROM mcr.microsoft.com/dotnet/sdk:8.0-alpine AS development
89+
FROM mcr.microsoft.com/dotnet/sdk:10.0-alpine AS development
6290
COPY . /source
6391
WORKDIR /source/src
6492
CMD dotnet run --no-launch-profile
6593

66-
FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine AS final
94+
FROM mcr.microsoft.com/dotnet/aspnet:10.0-alpine AS final
6795
WORKDIR /app
6896
COPY --from=build /app .
6997
ARG UID=10001
@@ -79,6 +107,9 @@ USER appuser
79107
ENTRYPOINT ["dotnet", "myWebApp.dll"]
80108
```
81109

110+
{{< /tab >}}
111+
{{< /tabs >}}
112+
82113
Run the following command to build an image using the build stage as the target and view the test results. Include `--progress=plain` to view the build output, `--no-cache` to ensure the tests always run, and `--target build` to target the build stage.
83114

84115
```console
@@ -92,16 +123,16 @@ You should see output containing the following.
92123
#11 1.564 Determining projects to restore...
93124
#11 3.421 Restored /source/src/myWebApp.csproj (in 1.02 sec).
94125
#11 19.42 Restored /source/tests/tests.csproj (in 17.05 sec).
95-
#11 27.91 myWebApp -> /source/src/bin/Debug/net8.0/myWebApp.dll
96-
#11 28.47 tests -> /source/tests/bin/Debug/net8.0/tests.dll
97-
#11 28.49 Test run for /source/tests/bin/Debug/net8.0/tests.dll (.NETCoreApp,Version=v8.0)
126+
#11 27.91 myWebApp -> /source/src/bin/Debug/net10.0/myWebApp.dll
127+
#11 28.47 tests -> /source/tests/bin/Debug/net10.0/tests.dll
128+
#11 28.49 Test run for /source/tests/bin/Debug/net10.0/tests.dll (.NETCoreApp,Version=v10.0)
98129
#11 28.67 Microsoft (R) Test Execution Command Line Tool Version 17.3.3 (x64)
99130
#11 28.67 Copyright (c) Microsoft Corporation. All rights reserved.
100131
#11 28.68
101132
#11 28.97 Starting test execution, please wait...
102133
#11 29.03 A total of 1 test files matched the specified pattern.
103134
#11 32.07
104-
#11 32.08 Passed! - Failed: 0, Passed: 1, Skipped: 0, Total: 1, Duration: < 1 ms - /source/tests/bin/Debug/net8.0/tests.dll (net8.0)
135+
#11 32.08 Passed! - Failed: 0, Passed: 1, Skipped: 0, Total: 1, Duration: < 1 ms - /source/tests/bin/Debug/net10.0/tests.dll (net10.0)
105136
#11 DONE 32.2s
106137
```
107138

content/guides/nodejs/containerize.md

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -323,17 +323,25 @@ Choosing DHI offers the advantage of a production-ready image that is lightweigh
323323

324324
{{< tabs >}}
325325
{{< tab name="Using Docker Hardened Images" >}}
326-
Docker Hardened Images (DHIs) are available for Node.js on [Docker Hub](https://hub.docker.com/hardened-images/catalog/dhi/node). Unlike using the Docker Official Image, you must first mirror the Node.js image into your organization and then use it as your base image. Follow the instructions in the [DHI quickstart](/dhi/get-started/) to create a mirrored repository for Node.js.
326+
Docker Hardened Images (DHIs) are available for Node.js in the [Docker Hardened Images catalog](https://hub.docker.com/hardened-images/catalog/dhi/node). Docker Hardened Images are freely available to everyone with no subscription required. You can pull and use them like any other Docker image after signing in to the DHI registry. For more information, see the [DHI quickstart](/dhi/get-started/) guide.
327327

328-
Mirrored repositories must start with `dhi-`, for example: `FROM <your-namespace>/dhi-node:<tag>`. In the following Dockerfile, the `FROM` instruction uses `<your-namespace>/dhi-node:24-alpine3.22-dev` as the base image.
328+
1. Sign in to the DHI registry:
329+
330+
$ docker login dhi.io
331+
332+
2. Pull the Node.js DHI (check the catalog for available versions):
333+
334+
$ docker pull dhi.io/node:24-alpine3.22-dev
335+
336+
In the following Dockerfile, the `FROM` instruction uses `dhi.io/node:24-alpine3.22-dev` as the base image.
329337

330338
```dockerfile
331339
# ========================================
332340
# Optimized Multi-Stage Dockerfile
333341
# Node.js TypeScript Application (Using DHI)
334342
# ========================================
335343
336-
FROM <your-namespace>/dhi-node:24-alpine3.22-dev AS base
344+
FROM dhi.io/node:24-alpine3.22-dev AS base
337345
338346
# Set working directory
339347
WORKDIR /app
@@ -419,7 +427,7 @@ CMD ["npm", "run", "dev:docker"]
419427
# ========================================
420428
# Production Stage
421429
# ========================================
422-
FROM <your-namespace>/dhi-node:24-alpine3.22-dev AS production
430+
FROM dhi.io/node:24-alpine3.22-dev AS production
423431
424432
# Set working directory
425433
WORKDIR /app

0 commit comments

Comments
 (0)