diff --git a/README.samples.md b/README.samples.md index dd21f03fda..f6cc5a8f5c 100644 --- a/README.samples.md +++ b/README.samples.md @@ -60,32 +60,32 @@ See [Hosting ASP.NET Core Images with Docker over HTTPS](https://github.com/dotn ## Linux amd64 Tags Tags | Dockerfile | OS Version -----------| -------------| ------------- -dotnetapp-alpine-slim-amd64, dotnetapp, latest | [Dockerfile](https://github.com/dotnet/dotnet-docker/blob/main/samples/dotnetapp/Dockerfile.alpine-slim) | Alpine -aspnetapp-alpine-slim-amd64, aspnetapp | [Dockerfile](https://github.com/dotnet/dotnet-docker/blob/main/samples/aspnetapp/Dockerfile.alpine-slim) | Alpine +dotnetapp-jammy-chiseled-amd64, dotnetapp, latest | [Dockerfile](https://github.com/dotnet/dotnet-docker/blob/main/samples/dotnetapp/Dockerfile.chiseled) | Ubuntu +aspnetapp-jammy-chiseled-composite-amd64, aspnetapp | [Dockerfile](https://github.com/dotnet/dotnet-docker/blob/main/samples/aspnetapp/Dockerfile.chiseled) | Ubuntu ## Linux arm32 Tags Tags | Dockerfile | OS Version -----------| -------------| ------------- -dotnetapp-alpine-slim-arm32v7, dotnetapp, latest | [Dockerfile](https://github.com/dotnet/dotnet-docker/blob/main/samples/dotnetapp/Dockerfile.alpine-slim) | Alpine -aspnetapp-alpine-slim-arm32v7, aspnetapp | [Dockerfile](https://github.com/dotnet/dotnet-docker/blob/main/samples/aspnetapp/Dockerfile.alpine-slim) | Alpine +dotnetapp-jammy-chiseled-arm32v7, dotnetapp, latest | [Dockerfile](https://github.com/dotnet/dotnet-docker/blob/main/samples/dotnetapp/Dockerfile.chiseled) | Ubuntu +aspnetapp-jammy-chiseled-composite-arm32v7, aspnetapp | [Dockerfile](https://github.com/dotnet/dotnet-docker/blob/main/samples/aspnetapp/Dockerfile.chiseled-composite) | Ubuntu ## Linux arm64 Tags Tags | Dockerfile | OS Version -----------| -------------| ------------- -dotnetapp-alpine-slim-arm64v8, dotnetapp, latest | [Dockerfile](https://github.com/dotnet/dotnet-docker/blob/main/samples/dotnetapp/Dockerfile.alpine-slim) | Alpine -aspnetapp-alpine-slim-arm64v8, aspnetapp | [Dockerfile](https://github.com/dotnet/dotnet-docker/blob/main/samples/aspnetapp/Dockerfile.alpine-slim) | Alpine +dotnetapp-jammy-chiseled-arm64v8, dotnetapp, latest | [Dockerfile](https://github.com/dotnet/dotnet-docker/blob/main/samples/dotnetapp/Dockerfile.chiseled) | Ubuntu +aspnetapp-jammy-chiseled-composite-arm64v8, aspnetapp | [Dockerfile](https://github.com/dotnet/dotnet-docker/blob/main/samples/aspnetapp/Dockerfile.chiseled-composite) | Ubuntu ## Nano Server 2022 amd64 Tags Tag | Dockerfile ---------| --------------- -dotnetapp-nanoserver-ltsc2022, dotnetapp, latest | [Dockerfile](https://github.com/dotnet/dotnet-docker/blob/main/samples/dotnetapp/Dockerfile) -aspnetapp-nanoserver-ltsc2022, aspnetapp | [Dockerfile](https://github.com/dotnet/dotnet-docker/blob/main/samples/aspnetapp/Dockerfile.nanoserver-slim) +dotnetapp-nanoserver-ltsc2022, dotnetapp, latest | [Dockerfile](https://github.com/dotnet/dotnet-docker/blob/main/samples/dotnetapp/Dockerfile.nanoserver) +aspnetapp-nanoserver-ltsc2022, aspnetapp | [Dockerfile](https://github.com/dotnet/dotnet-docker/blob/main/samples/aspnetapp/Dockerfile.nanoserver) ## Nano Server, version 1809 amd64 Tags Tag | Dockerfile ---------| --------------- -dotnetapp-nanoserver-1809, dotnetapp, latest | [Dockerfile](https://github.com/dotnet/dotnet-docker/blob/main/samples/dotnetapp/Dockerfile) -aspnetapp-nanoserver-1809, aspnetapp | [Dockerfile](https://github.com/dotnet/dotnet-docker/blob/main/samples/aspnetapp/Dockerfile.nanoserver-slim) +dotnetapp-nanoserver-1809, dotnetapp, latest | [Dockerfile](https://github.com/dotnet/dotnet-docker/blob/main/samples/dotnetapp/Dockerfile.nanoserver) +aspnetapp-nanoserver-1809, aspnetapp | [Dockerfile](https://github.com/dotnet/dotnet-docker/blob/main/samples/aspnetapp/Dockerfile.nanoserver) You can retrieve a list of all available tags for dotnet/samples at https://mcr.microsoft.com/v2/dotnet/samples/tags/list. diff --git a/eng/common/templates/steps/init-docker-linux.yml b/eng/common/templates/steps/init-docker-linux.yml index 4bf9ae77aa..aa6bbe6743 100644 --- a/eng/common/templates/steps/init-docker-linux.yml +++ b/eng/common/templates/steps/init-docker-linux.yml @@ -36,7 +36,7 @@ steps: condition: and(succeeded(), ${{ parameters.condition }}) - script: > echo "##vso[task.setvariable variable=runImageBuilderCmd] - docker run --rm + \$env:DOCKER_BUILDKIT=1; docker run --rm -v /var/run/docker.sock:/var/run/docker.sock -v $(Build.ArtifactStagingDirectory):$(artifactsPath) -w /repo diff --git a/eng/mcr-tags-metadata-templates/samples-tags.yml b/eng/mcr-tags-metadata-templates/samples-tags.yml index 6c25d4a20b..74e1a1fcb2 100644 --- a/eng/mcr-tags-metadata-templates/samples-tags.yml +++ b/eng/mcr-tags-metadata-templates/samples-tags.yml @@ -1,10 +1,10 @@ $(McrTagsYmlRepo:samples) -$(McrTagsYmlTagGroup:dotnetapp-alpine-slim-amd64) -$(McrTagsYmlTagGroup:aspnetapp-alpine-slim-amd64) -$(McrTagsYmlTagGroup:dotnetapp-alpine-slim-arm32v7) -$(McrTagsYmlTagGroup:aspnetapp-alpine-slim-arm32v7) -$(McrTagsYmlTagGroup:dotnetapp-alpine-slim-arm64v8) -$(McrTagsYmlTagGroup:aspnetapp-alpine-slim-arm64v8) +$(McrTagsYmlTagGroup:dotnetapp-jammy-chiseled-amd64) +$(McrTagsYmlTagGroup:aspnetapp-jammy-chiseled-composite-amd64) +$(McrTagsYmlTagGroup:dotnetapp-jammy-chiseled-arm32v7) +$(McrTagsYmlTagGroup:aspnetapp-jammy-chiseled-composite-arm32v7) +$(McrTagsYmlTagGroup:dotnetapp-jammy-chiseled-arm64v8) +$(McrTagsYmlTagGroup:aspnetapp-jammy-chiseled-composite-arm64v8) $(McrTagsYmlTagGroup:dotnetapp-nanoserver-ltsc2022) $(McrTagsYmlTagGroup:aspnetapp-nanoserver-ltsc2022) $(McrTagsYmlTagGroup:dotnetapp-nanoserver-1809) diff --git a/manifest.samples.json b/manifest.samples.json index c8233b409b..e6200fd7a9 100644 --- a/manifest.samples.json +++ b/manifest.samples.json @@ -31,35 +31,38 @@ }, "platforms": [ { - "dockerfile": "samples/dotnetapp/Dockerfile.alpine-slim", + "dockerfile": "samples/dotnetapp/Dockerfile.chiseled", "os": "linux", - "osVersion": "alpine", + "osVersion": "ubuntu", "tags": { - "dotnetapp-alpine-slim-amd64": {} + "dotnetapp-jammy-chiseled-amd64": {} } }, { "architecture": "arm", - "dockerfile": "samples/dotnetapp/Dockerfile.alpine-slim", + "dockerfile": "samples/dotnetapp/Dockerfile.chiseled", "os": "linux", - "osVersion": "alpine", + "osVersion": "ubuntu", "tags": { - "dotnetapp-alpine-slim-arm32v7": {} + "dotnetapp-jammy-chiseled-arm32v7": {} }, "variant": "v7" }, { "architecture": "arm64", - "dockerfile": "samples/dotnetapp/Dockerfile.alpine-slim", + "dockerfile": "samples/dotnetapp/Dockerfile.chiseled", "os": "linux", - "osVersion": "alpine", + "osVersion": "ubuntu", "tags": { - "dotnetapp-alpine-slim-arm64v8": {} + "dotnetapp-jammy-chiseled-arm64v8": {} }, "variant": "v8" }, { - "dockerfile": "samples/dotnetapp", + "buildArgs": { + "TAG": "1809" + }, + "dockerfile": "samples/dotnetapp/Dockerfile.nanoserver", "os": "windows", "osVersion": "nanoserver-1809", "tags": { @@ -71,7 +74,10 @@ } }, { - "dockerfile": "samples/dotnetapp", + "buildArgs": { + "TAG": "ltsc2022" + }, + "dockerfile": "samples/dotnetapp/Dockerfile.nanoserver", "os": "windows", "osVersion": "nanoserver-ltsc2022", "tags": { @@ -90,29 +96,29 @@ }, "platforms": [ { - "dockerfile": "samples/aspnetapp/Dockerfile.alpine-slim", + "dockerfile": "samples/aspnetapp/Dockerfile.chiseled", "os": "linux", - "osVersion": "alpine", + "osVersion": "ubuntu", "tags": { - "aspnetapp-alpine-slim-amd64": {} + "aspnetapp-jammy-chiseled-composite-amd64": {} }, "customBuildLegGroups": [ { "name": "test-dependencies", "type": "Integral", "dependencies": [ - "$(Repo:samples):dotnetapp-alpine-slim-amd64" + "$(Repo:samples):dotnetapp-jammy-chiseled-amd64" ] } ] }, { "architecture": "arm", - "dockerfile": "samples/aspnetapp/Dockerfile.alpine-slim", + "dockerfile": "samples/aspnetapp/Dockerfile.chiseled-composite", "os": "linux", - "osVersion": "alpine", + "osVersion": "ubuntu", "tags": { - "aspnetapp-alpine-slim-arm32v7": {} + "aspnetapp-jammy-chiseled-composite-arm32v7": {} }, "variant": "v7", "customBuildLegGroups": [ @@ -120,18 +126,18 @@ "name": "test-dependencies", "type": "Integral", "dependencies": [ - "$(Repo:samples):dotnetapp-alpine-slim-arm32v7" + "$(Repo:samples):dotnetapp-jammy-chiseled-arm32v7" ] } ] }, { "architecture": "arm64", - "dockerfile": "samples/aspnetapp/Dockerfile.alpine-slim", + "dockerfile": "samples/aspnetapp/Dockerfile.chiseled-composite", "os": "linux", - "osVersion": "alpine", + "osVersion": "ubuntu", "tags": { - "aspnetapp-alpine-slim-arm64v8": {} + "aspnetapp-jammy-chiseled-composite-arm64v8": {} }, "variant": "v8", "customBuildLegGroups": [ @@ -139,7 +145,7 @@ "name": "test-dependencies", "type": "Integral", "dependencies": [ - "$(Repo:samples):dotnetapp-alpine-slim-arm64v8" + "$(Repo:samples):dotnetapp-jammy-chiseled-arm64v8" ] } ] @@ -148,7 +154,7 @@ "buildArgs": { "TAG": "1809" }, - "dockerfile": "samples/aspnetapp/Dockerfile.nanoserver-slim", + "dockerfile": "samples/aspnetapp/Dockerfile.nanoserver", "os": "windows", "osVersion": "nanoserver-1809", "tags": { @@ -172,7 +178,7 @@ "buildArgs": { "TAG": "ltsc2022" }, - "dockerfile": "samples/aspnetapp/Dockerfile.nanoserver-slim", + "dockerfile": "samples/aspnetapp/Dockerfile.nanoserver", "os": "windows", "osVersion": "nanoserver-ltsc2022", "tags": { diff --git a/samples/README.md b/samples/README.md index 1a60bf37e3..efbfe1aaed 100644 --- a/samples/README.md +++ b/samples/README.md @@ -1,6 +1,6 @@ # .NET container samples -The following samples and guidance demonstrate how to use .NET and Docker for development, testing and production. You can equally use the samples for learning about containers or as the basis of your own container images. +The following samples and guidance demonstrate how to use .NET and Docker for development, testing and production. You can use the samples for learning about containers or as the basis of your own container images. Kubernetes samples are provided in the [kubernetes](kubernetes/README.md) directory. @@ -11,6 +11,8 @@ Kubernetes samples are provided in the [kubernetes](kubernetes/README.md) direct * [Build a .NET container image](dotnetapp/README.md) * [Build an ASP.NET Core container image](aspnetapp/README.md) +* [Build a single file app](releasesapp/README.md) +* [Build a native AOT app](releasesapi/README.md) * [Building a globalization and time zone aware (or unaware) image](globalapp/README.md) * [Build for a platform](build-for-a-platform.md) diff --git a/samples/aspnetapp/Dockerfile b/samples/aspnetapp/Dockerfile index 36050e1f55..28dafc28d5 100644 --- a/samples/aspnetapp/Dockerfile +++ b/samples/aspnetapp/Dockerfile @@ -1,19 +1,21 @@ # Learn about building .NET container images: # https://github.com/dotnet/dotnet-docker/blob/main/samples/README.md -FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build +FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0 AS build +ARG TARGETARCH WORKDIR /source # copy csproj and restore as distinct layers COPY aspnetapp/*.csproj . -RUN dotnet restore --use-current-runtime +RUN dotnet restore -a $TARGETARCH -# copy everything else and build app +# copy and publish app and libraries COPY aspnetapp/. . -RUN dotnet publish --use-current-runtime --self-contained false --no-restore -o /app +RUN dotnet publish -a $TARGETARCH --no-restore -o /app # final stage/image -FROM mcr.microsoft.com/dotnet/aspnet:7.0 +FROM mcr.microsoft.com/dotnet/aspnet:8.0 WORKDIR /app COPY --from=build /app . -ENTRYPOINT ["dotnet", "aspnetapp.dll"] +USER $APP_UID +ENTRYPOINT ["./aspnetapp"] diff --git a/samples/aspnetapp/Dockerfile.alpine b/samples/aspnetapp/Dockerfile.alpine index 85b4b31aab..d778724a95 100644 --- a/samples/aspnetapp/Dockerfile.alpine +++ b/samples/aspnetapp/Dockerfile.alpine @@ -1,22 +1,24 @@ # Learn about building .NET container images: # https://github.com/dotnet/dotnet-docker/blob/main/samples/README.md -FROM mcr.microsoft.com/dotnet/sdk:7.0-alpine AS build - +FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0-alpine AS build +ARG TARGETARCH WORKDIR /source -# copy csproj and restore as distinct layers -COPY aspnetapp/*.csproj . -RUN dotnet restore --use-current-runtime +# optimize +RUN --mount=type=bind,source=aspnetapp/aspnetapp.csproj,target=aspnetapp.csproj \ + --mount=type=cache,target=/root/.nuget/ \ + dotnet restore -a $TARGETARCH -# copy everything else and build app +# copy and publish app and libraries COPY aspnetapp/. . -RUN dotnet publish --use-current-runtime --self-contained false --no-restore -o /app +RUN dotnet publish -a $TARGETARCH --no-restore -o /app # Enable globalization and time zones: # https://github.com/dotnet/dotnet-docker/blob/main/samples/enable-globalization.md # final stage/image -FROM mcr.microsoft.com/dotnet/aspnet:7.0-alpine +FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine WORKDIR /app COPY --from=build /app . +USER $APP_UID ENTRYPOINT ["./aspnetapp"] diff --git a/samples/aspnetapp/Dockerfile.alpine-non-root b/samples/aspnetapp/Dockerfile.alpine-composite similarity index 74% rename from samples/aspnetapp/Dockerfile.alpine-non-root rename to samples/aspnetapp/Dockerfile.alpine-composite index 8e3c3133ba..3d091f39c2 100644 --- a/samples/aspnetapp/Dockerfile.alpine-non-root +++ b/samples/aspnetapp/Dockerfile.alpine-composite @@ -8,7 +8,7 @@ WORKDIR /source COPY aspnetapp/*.csproj . RUN dotnet restore -a $TARGETARCH -# copy everything else and build app +# copy and publish app and libraries COPY aspnetapp/. . RUN dotnet publish -a $TARGETARCH --no-restore -o /app @@ -16,14 +16,8 @@ RUN dotnet publish -a $TARGETARCH --no-restore -o /app # Enable globalization and time zones: # https://github.com/dotnet/dotnet-docker/blob/main/samples/enable-globalization.md # final stage/image -FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine - -# These ENVs are only needed because the sample uses .NET 7 -ENV DOTNET_ROLL_FORWARD=Major -ENV DOTNET_ROLL_FORWARD_PRE_RELEASE=1 - +FROM mcr.microsoft.com/dotnet/nightly/aspnet:8.0-alpine-composite WORKDIR /app COPY --from=build /app . - USER $APP_UID ENTRYPOINT ["./aspnetapp"] diff --git a/samples/aspnetapp/Dockerfile.alpine-icu b/samples/aspnetapp/Dockerfile.alpine-icu index 08f50de9e0..78b96217d7 100644 --- a/samples/aspnetapp/Dockerfile.alpine-icu +++ b/samples/aspnetapp/Dockerfile.alpine-icu @@ -1,22 +1,22 @@ # Learn about building .NET container images: # https://github.com/dotnet/dotnet-docker/blob/main/samples/README.md -FROM mcr.microsoft.com/dotnet/sdk:7.0-alpine AS build - +FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0-alpine AS build +ARG TARGETARCH WORKDIR /source # copy csproj and restore as distinct layers COPY aspnetapp/*.csproj . -RUN dotnet restore --use-current-runtime +RUN dotnet restore -a $TARGETARCH -# copy everything else and build app +# copy and publish app and libraries COPY aspnetapp/. . -RUN dotnet publish --use-current-runtime --self-contained false --no-restore -o /app +RUN dotnet publish -a $TARGETARCH --no-restore -o /app # Enable globalization and time zones: # https://github.com/dotnet/dotnet-docker/blob/main/samples/enable-globalization.md # final stage/image -FROM mcr.microsoft.com/dotnet/aspnet:7.0-alpine +FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine ENV \ DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=false \ @@ -28,4 +28,5 @@ RUN apk add --no-cache \ WORKDIR /app COPY --from=build /app . +USER $APP_UID ENTRYPOINT ["./aspnetapp"] diff --git a/samples/aspnetapp/Dockerfile.alpine-slim b/samples/aspnetapp/Dockerfile.alpine-slim deleted file mode 100644 index c0734f8095..0000000000 --- a/samples/aspnetapp/Dockerfile.alpine-slim +++ /dev/null @@ -1,24 +0,0 @@ -# Learn about building .NET container images: -# https://github.com/dotnet/dotnet-docker/blob/main/samples/README.md -FROM mcr.microsoft.com/dotnet/sdk:7.0-alpine AS build -WORKDIR /source - -# copy csproj and restore as distinct layers -COPY aspnetapp/*.csproj . -RUN dotnet restore --use-current-runtime /p:PublishReadyToRun=true - -# copy everything else and build app -COPY aspnetapp/. . -RUN dotnet publish --use-current-runtime --no-restore -o /app /p:PublishTrimmed=true /p:PublishReadyToRun=true - - -# Enable globalization and time zones: -# https://github.com/dotnet/dotnet-docker/blob/main/samples/enable-globalization.md -# final stage/image -FROM mcr.microsoft.com/dotnet/runtime-deps:7.0-alpine -WORKDIR /app -COPY --from=build /app . - -# This port needs to match the port being used -HEALTHCHECK CMD wget -qO- -t1 http://localhost:80/healthz || exit 1 -ENTRYPOINT ["./aspnetapp"] diff --git a/samples/aspnetapp/Dockerfile.chiseled b/samples/aspnetapp/Dockerfile.chiseled index f4735a973f..9f8b5a5675 100644 --- a/samples/aspnetapp/Dockerfile.chiseled +++ b/samples/aspnetapp/Dockerfile.chiseled @@ -1,19 +1,20 @@ # Learn about building .NET container images: # https://github.com/dotnet/dotnet-docker/blob/main/samples/README.md -FROM mcr.microsoft.com/dotnet/sdk:7.0-jammy AS build +FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0-jammy AS build +ARG TARGETARCH WORKDIR /source # copy csproj and restore as distinct layers COPY aspnetapp/*.csproj . -RUN dotnet restore --use-current-runtime +RUN dotnet restore -a $TARGETARCH # copy everything else and build app COPY aspnetapp/. . -RUN dotnet publish --use-current-runtime --self-contained false --no-restore -o /app +RUN dotnet publish -a $TARGETARCH --no-restore -o /app # final stage/image -FROM mcr.microsoft.com/dotnet/nightly/aspnet:7.0-jammy-chiseled +FROM mcr.microsoft.com/dotnet/aspnet:8.0-jammy-chiseled WORKDIR /app COPY --from=build /app . ENTRYPOINT ["./aspnetapp"] diff --git a/samples/aspnetapp/Dockerfile.chiseled-composite b/samples/aspnetapp/Dockerfile.chiseled-composite new file mode 100644 index 0000000000..abbe22f640 --- /dev/null +++ b/samples/aspnetapp/Dockerfile.chiseled-composite @@ -0,0 +1,20 @@ +# Learn about building .NET container images: +# https://github.com/dotnet/dotnet-docker/blob/main/samples/README.md +FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0-jammy AS build +ARG TARGETARCH +WORKDIR /source + +# copy csproj and restore as distinct layers +COPY aspnetapp/*.csproj . +RUN dotnet restore -a $TARGETARCH + +# copy everything else and build app +COPY aspnetapp/. . +RUN dotnet publish -a $TARGETARCH --no-restore -o /app + + +# final stage/image +FROM mcr.microsoft.com/dotnet/nightly/aspnet:8.0-jammy-chiseled-composite +WORKDIR /app +COPY --from=build /app . +ENTRYPOINT ["./aspnetapp"] diff --git a/samples/aspnetapp/Dockerfile.debian b/samples/aspnetapp/Dockerfile.debian index 53de577a22..5d59624d6b 100644 --- a/samples/aspnetapp/Dockerfile.debian +++ b/samples/aspnetapp/Dockerfile.debian @@ -1,19 +1,21 @@ # Learn about building .NET container images: # https://github.com/dotnet/dotnet-docker/blob/main/samples/README.md -FROM mcr.microsoft.com/dotnet/sdk:7.0-bullseye-slim AS build +FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0-bookworm-slim AS build +ARG TARGETARCH WORKDIR /source # copy csproj and restore as distinct layers COPY aspnetapp/*.csproj . -RUN dotnet restore --use-current-runtime +RUN dotnet restore -a $TARGETARCH # copy everything else and build app COPY aspnetapp/. . -RUN dotnet publish --use-current-runtime --self-contained false --no-restore -o /app +RUN dotnet publish -a $TARGETARCH --no-restore -o /app # final stage/image -FROM mcr.microsoft.com/dotnet/aspnet:7.0-bullseye-slim +FROM mcr.microsoft.com/dotnet/aspnet:8.0-bookworm-slim WORKDIR /app COPY --from=build /app . +USER $APP_UID ENTRYPOINT ["./aspnetapp"] diff --git a/samples/aspnetapp/Dockerfile.nanoserver b/samples/aspnetapp/Dockerfile.nanoserver index a5cd60efd9..59a27cbffa 100644 --- a/samples/aspnetapp/Dockerfile.nanoserver +++ b/samples/aspnetapp/Dockerfile.nanoserver @@ -2,20 +2,20 @@ # Learn about building .NET container images: # https://github.com/dotnet/dotnet-docker/blob/main/samples/README.md ARG TAG=ltsc2022 -FROM mcr.microsoft.com/dotnet/sdk:7.0-nanoserver-$TAG AS build +FROM mcr.microsoft.com/dotnet/sdk:8.0-nanoserver-$TAG AS build WORKDIR /source # copy csproj and restore as distinct layers COPY aspnetapp/*.csproj . -RUN dotnet restore --use-current-runtime +RUN dotnet restore --ucr # copy everything else and build app COPY aspnetapp/. . -RUN dotnet publish --use-current-runtime --no-restore -o /app +RUN dotnet publish --ucr --no-restore -o /app # final stage/image -FROM mcr.microsoft.com/dotnet/aspnet:7.0-nanoserver-$TAG +FROM mcr.microsoft.com/dotnet/aspnet:8.0-nanoserver-$TAG WORKDIR /app COPY --from=build /app . HEALTHCHECK CMD curl -sf --show-error http://localhost:80/healthz || exit 1 diff --git a/samples/aspnetapp/Dockerfile.nanoserver-slim b/samples/aspnetapp/Dockerfile.nanoserver-slim deleted file mode 100644 index 282c8d1b88..0000000000 --- a/samples/aspnetapp/Dockerfile.nanoserver-slim +++ /dev/null @@ -1,28 +0,0 @@ -# escape=` -# Learn about building .NET container images: -# https://github.com/dotnet/dotnet-docker/blob/main/samples/README.md -ARG TAG=ltsc2022 -FROM mcr.microsoft.com/dotnet/sdk:7.0-nanoserver-$TAG AS build -WORKDIR /source - -# copy csproj and restore as distinct layers -COPY aspnetapp/*.csproj . -RUN dotnet restore --use-current-runtime /p:PublishReadyToRun=true - -# copy everything else and build app -COPY aspnetapp/. . -RUN dotnet publish --use-current-runtime --no-restore -o /app /p:PublishTrimmed=true /p:PublishReadyToRun=true - - -# final stage/image -FROM mcr.microsoft.com/windows/nanoserver:$TAG -WORKDIR /app -COPY --from=build /app . -HEALTHCHECK CMD curl -sf --show-error http://localhost:80/healthz || exit 1 -ENV ` - # Configure web servers to bind to port 80 when present - ASPNETCORE_URLS=http://+:80 ` - # Enable detection of running in a container - DOTNET_RUNNING_IN_CONTAINER=true - -ENTRYPOINT ["aspnetapp"] diff --git a/samples/aspnetapp/Dockerfile.ubuntu b/samples/aspnetapp/Dockerfile.ubuntu index bddb0cda83..e5406dc839 100644 --- a/samples/aspnetapp/Dockerfile.ubuntu +++ b/samples/aspnetapp/Dockerfile.ubuntu @@ -1,19 +1,21 @@ # Learn about building .NET container images: # https://github.com/dotnet/dotnet-docker/blob/main/samples/README.md -FROM mcr.microsoft.com/dotnet/sdk:7.0-jammy AS build +FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0-jammy AS build +ARG TARGETARCH WORKDIR /source # copy csproj and restore as distinct layers COPY aspnetapp/*.csproj . -RUN dotnet restore --use-current-runtime +RUN dotnet restore -a $TARGETARCH # copy everything else and build app COPY aspnetapp/. . -RUN dotnet publish --use-current-runtime --self-contained false --no-restore -o /app +RUN dotnet publish -a $TARGETARCH --no-restore -o /app # final stage/image -FROM mcr.microsoft.com/dotnet/aspnet:7.0-jammy +FROM mcr.microsoft.com/dotnet/aspnet:8.0-jammy WORKDIR /app COPY --from=build /app . +USER $APP_UID ENTRYPOINT ["./aspnetapp"] diff --git a/samples/aspnetapp/Dockerfile.windowsservercore b/samples/aspnetapp/Dockerfile.windowsservercore index fe923d915c..dde2e53e33 100644 --- a/samples/aspnetapp/Dockerfile.windowsservercore +++ b/samples/aspnetapp/Dockerfile.windowsservercore @@ -1,18 +1,18 @@ # Learn about building .NET container images: # https://github.com/dotnet/dotnet-docker/blob/main/samples/README.md -FROM mcr.microsoft.com/dotnet/sdk:7.0-windowsservercore-ltsc2022 AS build +FROM mcr.microsoft.com/dotnet/sdk:8.0-windowsservercore-ltsc2022 AS build WORKDIR /source # copy csproj and restore as distinct layers COPY aspnetapp/*.csproj . -RUN dotnet restore --use-current-runtime +RUN dotnet restore --ucr # copy everything else and build app COPY aspnetapp/. . -RUN dotnet publish --use-current-runtime --self-contained false --no-restore -o /app +RUN dotnet publish --ucr --no-restore -o /app # final stage/image -FROM mcr.microsoft.com/dotnet/aspnet:7.0-windowsservercore-ltsc2022 AS runtime +FROM mcr.microsoft.com/dotnet/aspnet:8.0-windowsservercore-ltsc2022 WORKDIR /app COPY --from=build /app . USER ContainerUser diff --git a/samples/aspnetapp/Dockerfile.windowsservercore-iis b/samples/aspnetapp/Dockerfile.windowsservercore-iis index 910ff54bb8..6e84690f37 100644 --- a/samples/aspnetapp/Dockerfile.windowsservercore-iis +++ b/samples/aspnetapp/Dockerfile.windowsservercore-iis @@ -1,19 +1,8 @@ # escape=` # Learn about building .NET container images: # https://github.com/dotnet/dotnet-docker/blob/main/samples/README.md -FROM mcr.microsoft.com/dotnet/sdk:7.0-windowsservercore-ltsc2022 AS build -WORKDIR /source - -# copy csproj and restore as distinct layers -COPY aspnetapp/*.csproj . -RUN dotnet restore --use-current-runtime - -# copy everything else and build app -COPY aspnetapp/. . -RUN dotnet publish --use-current-runtime --self-contained false --no-restore -o /app - # final stage/image -FROM mcr.microsoft.com/dotnet/aspnet:7.0-windowsservercore-ltsc2022 +FROM mcr.microsoft.com/dotnet/aspnet:8.0-windowsservercore-ltsc2022 AS final RUN powershell -Command ` $ErrorActionPreference = 'Stop'; ` @@ -27,7 +16,7 @@ RUN powershell -Command ` Invoke-WebRequest -OutFile C:\ServiceMonitor.exe -Uri https://dotnetbinaries.blob.core.windows.net/servicemonitor/2.0.1.10/ServiceMonitor.exe; ` ` # Install the ASP.NET Core Module - Invoke-WebRequest -OutFile c:\dotnet-hosting-win.exe https://aka.ms/dotnet/6.0/preview/dotnet-hosting-win.exe; ` + Invoke-WebRequest -OutFile c:\dotnet-hosting-win.exe https://aka.ms/dotnet/8.0/preview/dotnet-hosting-win.exe; ` $process = Start-Process -Filepath C:\dotnet-hosting-win.exe -ArgumentList @('/install', '/q', '/norestart', 'OPT_NO_RUNTIME=1', 'OPT_NO_X86=1', 'OPT_NO_SHAREDFX=1') -Wait -PassThru ; ` if ($process.ExitCode -ne 0) { ` exit $process.ExitCode; ` @@ -35,9 +24,21 @@ RUN powershell -Command ` Remove-Item -Force C:\dotnet-hosting-win.exe; ` Remove-Item -Force -Recurse $Env:Temp\* +FROM mcr.microsoft.com/dotnet/sdk:8.0-windowsservercore-ltsc2022 AS build +WORKDIR /source + +# copy csproj and restore as distinct layers +COPY aspnetapp/*.csproj . +RUN dotnet restore --ucr + +# copy everything else and build app +COPY aspnetapp/. . +RUN dotnet publish --ucr --no-restore -o /app + + +FROM final WORKDIR /inetpub/wwwroot COPY --from=build /app . EXPOSE 80 - ENTRYPOINT ["C:\\ServiceMonitor.exe", "w3svc"] diff --git a/samples/aspnetapp/README.md b/samples/aspnetapp/README.md index 66cc5740f5..25271af5f2 100644 --- a/samples/aspnetapp/README.md +++ b/samples/aspnetapp/README.md @@ -2,54 +2,94 @@ This sample demonstrates how to build container images for ASP.NET Core web apps. See [.NET Docker Samples](../README.md) for more samples. -## Try a pre-built version of the sample +> Note: .NET 8 container images use port `8080`, by default. Previous .NET versions used port `80`. The instructions for the sample assume the use of port `8080`. + +## Run the sample image You can start by launching a sample from our [container registry](https://mcr.microsoft.com/) and access it in your web browser at `http://localhost:8000`. ```console -docker run --rm -it -p 8000:80 mcr.microsoft.com/dotnet/samples:aspnetapp +docker run --rm -it -p 8000:8080 mcr.microsoft.com/dotnet/samples:aspnetapp ``` You can also call an endpoint that the app exposes: ```bash $ curl http://localhost:8000/Environment -{"runtimeVersion":".NET 7.0.2","osVersion":"Linux 5.15.79.1-microsoft-standard-WSL2 #1 SMP Wed Nov 23 01:01:46 UTC 2022","osArchitecture":"X64","user":"root","processorCount":16,"totalAvailableMemoryBytes":67430023168,"memoryLimit":9223372036854771712,"memoryUsage":100577280} +{"runtimeVersion":".NET 8.0.0-preview.6.23329.7","osVersion":"Ubuntu 22.04.2 LTS","osArchitecture":"Arm64","user":"app","processorCount":4,"totalAvailableMemoryBytes":4124442624,"memoryLimit":0,"memoryUsage":31518720,"hostName":"78e2b2cfc0e8"} ``` -## Build an ASP.NET Core image +This container image is built with [Ubuntu Chiseled](https://devblogs.microsoft.com/dotnet/dotnet-6-is-now-in-ubuntu-2204/#net-in-chiseled-ubuntu-containers), with [Dockerfile](Dockerfile.chiseled-composite). + +## Change port + +You can change the port ASP.NET Core uses with one of the following environment variables. However, port `8080` (set by default) is recommended. + +The following examples change the port to port `80`. + +Supported with .NET 8+: + +```bash +ASPNETCORE_HTTP_PORTS=80 +``` + +Supported with .NET Core 1.0+ + +```bash +ASPNETCORE_URLS=http://+:80 +``` + +Note: `ASPNETCORE_URLS` overwrites `ASPNETCORE_HTTP_PORTS`` if set. + +These environment variables are used in [.NET 8](https://github.com/dotnet/dotnet-docker/blob/6da64f31944bb16ecde5495b6a53fc170fbe100d/src/runtime-deps/8.0/bookworm-slim/amd64/Dockerfile#L7C5-L7C31) and [.NET 6](https://github.com/dotnet/dotnet-docker/blob/6da64f31944bb16ecde5495b6a53fc170fbe100d/src/runtime-deps/6.0/bookworm-slim/amd64/Dockerfile#L5) Dockerfiles, respectively. + +## Build image -You can build and run an image using the following instructions (if you've cloned this repo): +You can built an image using one of the provided Dockerfiles. ```console docker build --pull -t aspnetapp . -docker run --rm -it -p 8000:80 aspnetapp +docker run --rm -it -p 8000:8080 aspnetapp ``` You should see the following console output as the application starts: ```console -> docker run --rm -it -p 8000:80 aspnetapp -Hosting environment: Production -Content root path: /app -Now listening on: http://[::]:80 -Application started. Press Ctrl+C to shut down. +> docker run --rm -it -p 8000:8080 aspnetapp +info: Microsoft.Hosting.Lifetime[14] + Now listening on: http://[::]:8080 +info: Microsoft.Hosting.Lifetime[0] + Application started. Press Ctrl+C to shut down. ``` After the application starts, navigate to `http://localhost:8000` in your web browser. You can also view the ASP.NET Core site running in the container from another machine with a local IP address such as `http://192.168.1.18:8000`. -> Note: ASP.NET Core apps (in our official images) listen to [port 80 by default](https://github.com/dotnet/dotnet-docker/blob/d5df3f0710c43b14aacdac1e30ceed666699ea69/src/runtime-deps/6.0/jammy/amd64/Dockerfile#L19). The [`-p` argument](https://docs.docker.com/engine/reference/commandline/run/#publish) in these examples maps host port `8000` to container port `80` (`host:container` mapping). The container will not be accessible without this mapping. ASP.NET Core can be [configured to listen on a different or additional port](https://learn.microsoft.com/aspnet/core/fundamentals/servers/kestrel/endpoints). +> Note: ASP.NET Core apps (in official images) listen to [port 8080 by default](https://github.com/dotnet/dotnet-docker/blob/6da64f31944bb16ecde5495b6a53fc170fbe100d/src/runtime-deps/8.0/bookworm-slim/amd64/Dockerfile#L7), starting with .NET 8. The [`-p` argument](https://docs.docker.com/engine/reference/commandline/run/#publish) in these examples maps host port `8000` to container port `8080` (`host:container` mapping). The container will not be accessible without this mapping. ASP.NET Core can be [configured to listen on a different or additional port](https://learn.microsoft.com/aspnet/core/fundamentals/servers/kestrel/endpoints). You can see the app running via `docker ps`. ```bash $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES -d79edc6bfcb6 mcr.microsoft.com/dotnet/samples:aspnetapp "./aspnetapp" 35 seconds ago Up 34 seconds (healthy) 0.0.0.0:8080->80/tcp nice_curran +d79edc6bfcb6 mcr.microsoft.com/dotnet/samples:aspnetapp "./aspnetapp" 35 seconds ago Up 34 seconds (healthy) 0.0.0.0:8080->8080/tcp nice_curran ``` You may notice that the sample includes a [health check](../enable-healthchecks.md), indicated in the "STATUS" column. +## Build image with the SDK + +The easiest way to [build images is with the SDK](https://github.com/dotnet/sdk-container-builds). + +```console +dotnet publish /p:PublishProfile=DefaultContainer +``` + +That command can be further customized to use a different base image and publish to a container registry. You must first use `docker login` to login to the registry. + +```console +dotnet publish /p:PublishProfile=DefaultContainer /p:ContainerBaseImage=mcr.microsoft.com/dotnet/aspnet:8.0-jammy-chiseled /p:ContainerRegistry=docker.io /p:ContainerRepository=youraccount/aspnetapp +``` + ## Supported Linux distros The .NET Team publishes images for [multiple distros](../../documentation/supported-platforms.md). @@ -57,18 +97,12 @@ The .NET Team publishes images for [multiple distros](../../documentation/suppor Samples are provided for: - [Alpine](Dockerfile.alpine) +- [Alpine with Composite ready-to-run image](Dockerfile.alpine-composite) +- [Alpine with ICU installed](Dockerfile.alpine-icu) - [Debian](Dockerfile.debian) - [Ubuntu](Dockerfile.ubuntu) - [Ubuntu Chiseled](Dockerfile.chiseled) - -The default [Dockerfile](Dockerfile) uses a major.minor version tag, which references a multi-platform image that provides Debian and Windows Nano Server images (depending on the requesting client). - -More extensive samples are provided for Alpine: - -- [Alpine with ICU (for globalization)](Dockerfile.alpine-icu) -- [Alpine with trimming, ready-to-run compilation, and self-contained publishing](Dockerfile.alpine-slim) - -These patterns can be applied to other distros. +- [Ubuntu Chiseled with Composite ready-to-run image](Dockerfile.chiseled-composite) ## Supported Windows versions @@ -77,6 +111,10 @@ The .NET Team publishes images for [multiple Windows versions](../../documentati Samples are provided for - [Nano Server](Dockerfile.nanoserver) -- [Nano Server with trimming, ready-to-run compilation, and self-contained publishing](Dockerfile.nanoserver-slim) - [Windows Server Core](Dockerfile.windowsservercore) - [Windows Server Core with IIS](Dockerfile.windowsservercore-iis) + +Windows variants of the sample can be pulled via one the following registry addresses: + +- `mcr.microsoft.com/dotnet/samples:aspnetapp-nanoserver-1809` +- `mcr.microsoft.com/dotnet/samples:aspnetapp-nanoserver-ltsc2022` diff --git a/samples/aspnetapp/aspnetapp/Controllers/HomeController.cs b/samples/aspnetapp/aspnetapp/Controllers/HomeController.cs deleted file mode 100644 index f874e8d4c2..0000000000 --- a/samples/aspnetapp/aspnetapp/Controllers/HomeController.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System.Diagnostics; -using Microsoft.AspNetCore.Mvc; -using aspnetapp.Models; - -namespace aspnetapp.Controllers; - -public class HomeController : Controller -{ - private readonly ILogger _logger; - - public HomeController(ILogger logger) - { - _logger = logger; - } - - public IActionResult Index() - { - return View(); - } - - public IActionResult Privacy() - { - return View(); - } - - [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] - public IActionResult Error() - { - return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier }); - } -} diff --git a/samples/aspnetapp/aspnetapp/Models/ErrorViewModel.cs b/samples/aspnetapp/aspnetapp/Models/ErrorViewModel.cs deleted file mode 100644 index 54d8c39ebc..0000000000 --- a/samples/aspnetapp/aspnetapp/Models/ErrorViewModel.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace aspnetapp.Models; - -public class ErrorViewModel -{ - public string? RequestId { get; set; } - - public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); -} diff --git a/samples/aspnetapp/aspnetapp/Views/Shared/Error.cshtml b/samples/aspnetapp/aspnetapp/Pages/Error.cshtml similarity index 82% rename from samples/aspnetapp/aspnetapp/Views/Shared/Error.cshtml rename to samples/aspnetapp/aspnetapp/Pages/Error.cshtml index a1e04783c6..6f92b95655 100644 --- a/samples/aspnetapp/aspnetapp/Views/Shared/Error.cshtml +++ b/samples/aspnetapp/aspnetapp/Pages/Error.cshtml @@ -1,4 +1,5 @@ -@model ErrorViewModel +@page +@model ErrorModel @{ ViewData["Title"] = "Error"; } @@ -15,7 +16,7 @@

Development Mode

- Swapping to Development environment will display more detailed information about the error that occurred. + Swapping to the Development environment displays detailed information about the error that occurred.

The Development environment shouldn't be enabled for deployed applications. diff --git a/samples/aspnetapp/aspnetapp/Pages/Error.cshtml.cs b/samples/aspnetapp/aspnetapp/Pages/Error.cshtml.cs new file mode 100644 index 0000000000..ff368111dd --- /dev/null +++ b/samples/aspnetapp/aspnetapp/Pages/Error.cshtml.cs @@ -0,0 +1,27 @@ +using System.Diagnostics; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; + +namespace aspnetapp.Pages; + +[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] +[IgnoreAntiforgeryToken] +public class ErrorModel : PageModel +{ + public string? RequestId { get; set; } + + public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); + + private readonly ILogger _logger; + + public ErrorModel(ILogger logger) + { + _logger = logger; + } + + public void OnGet() + { + RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier; + } +} + diff --git a/samples/aspnetapp/aspnetapp/Views/Home/Index.cshtml b/samples/aspnetapp/aspnetapp/Pages/Index.cshtml similarity index 97% rename from samples/aspnetapp/aspnetapp/Views/Home/Index.cshtml rename to samples/aspnetapp/aspnetapp/Pages/Index.cshtml index c6144bd72a..3286abe629 100644 --- a/samples/aspnetapp/aspnetapp/Views/Home/Index.cshtml +++ b/samples/aspnetapp/aspnetapp/Pages/Index.cshtml @@ -1,4 +1,6 @@ -@using System.Runtime.InteropServices +@page +@model IndexModel +@using System.Runtime.InteropServices @using System.IO @using System.Diagnostics @{ diff --git a/samples/aspnetapp/aspnetapp/Pages/Index.cshtml.cs b/samples/aspnetapp/aspnetapp/Pages/Index.cshtml.cs new file mode 100644 index 0000000000..28b627f6b6 --- /dev/null +++ b/samples/aspnetapp/aspnetapp/Pages/Index.cshtml.cs @@ -0,0 +1,19 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; + +namespace aspnetapp.Pages; + +public class IndexModel : PageModel +{ + private readonly ILogger _logger; + + public IndexModel(ILogger logger) + { + _logger = logger; + } + + public void OnGet() + { + + } +} diff --git a/samples/aspnetapp/aspnetapp/Views/Home/Privacy.cshtml b/samples/aspnetapp/aspnetapp/Pages/Privacy.cshtml similarity index 80% rename from samples/aspnetapp/aspnetapp/Views/Home/Privacy.cshtml rename to samples/aspnetapp/aspnetapp/Pages/Privacy.cshtml index af4fb195a3..46ba96612e 100644 --- a/samples/aspnetapp/aspnetapp/Views/Home/Privacy.cshtml +++ b/samples/aspnetapp/aspnetapp/Pages/Privacy.cshtml @@ -1,4 +1,6 @@ -@{ +@page +@model PrivacyModel +@{ ViewData["Title"] = "Privacy Policy"; }

@ViewData["Title"]

diff --git a/samples/aspnetapp/aspnetapp/Pages/Privacy.cshtml.cs b/samples/aspnetapp/aspnetapp/Pages/Privacy.cshtml.cs new file mode 100644 index 0000000000..a2e7989f80 --- /dev/null +++ b/samples/aspnetapp/aspnetapp/Pages/Privacy.cshtml.cs @@ -0,0 +1,19 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; + +namespace aspnetapp.Pages; + +public class PrivacyModel : PageModel +{ + private readonly ILogger _logger; + + public PrivacyModel(ILogger logger) + { + _logger = logger; + } + + public void OnGet() + { + } +} + diff --git a/samples/aspnetapp/aspnetapp/Views/Shared/_Layout.cshtml b/samples/aspnetapp/aspnetapp/Pages/Shared/_Layout.cshtml similarity index 83% rename from samples/aspnetapp/aspnetapp/Views/Shared/_Layout.cshtml rename to samples/aspnetapp/aspnetapp/Pages/Shared/_Layout.cshtml index 3d323bfa98..c0ae8b2602 100644 --- a/samples/aspnetapp/aspnetapp/Views/Shared/_Layout.cshtml +++ b/samples/aspnetapp/aspnetapp/Pages/Shared/_Layout.cshtml @@ -11,8 +11,8 @@