Skip to content

Commit

Permalink
Add frontend UI and backend svc as well
Browse files Browse the repository at this point in the history
  • Loading branch information
simonkurtz-MSFT committed Nov 21, 2023
1 parent 82400f0 commit f36af89
Show file tree
Hide file tree
Showing 5 changed files with 251 additions and 3 deletions.
24 changes: 24 additions & 0 deletions docs/aca/99-optimize-containers/Backend.Svc.Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
WORKDIR /app
EXPOSE 5000

ENV ASPNETCORE_URLS=http://+:5000

USER app
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG configuration=Release
WORKDIR /src
COPY ["TasksTracker.Processor.Backend.Svc/TasksTracker.Processor.Backend.Svc.csproj", "TasksTracker.Processor.Backend.Svc/"]
RUN dotnet restore "TasksTracker.Processor.Backend.Svc/TasksTracker.Processor.Backend.Svc.csproj"
COPY . .
WORKDIR "/src/TasksTracker.Processor.Backend.Svc"
RUN dotnet build "TasksTracker.Processor.Backend.Svc.csproj" -c $configuration -o /app/build

FROM build AS publish
ARG configuration=Release
RUN dotnet publish "TasksTracker.Processor.Backend.Svc.csproj" -c $configuration -o /app/publish /p:UseAppHost=false

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "TasksTracker.Processor.Backend.Svc.dll"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
FROM mcr.microsoft.com/dotnet/nightly/runtime-deps:8.0-jammy-chiseled-aot AS base
WORKDIR /app
EXPOSE 5000

ENV ASPNETCORE_URLS=http://+:5000

USER app
FROM mcr.microsoft.com/dotnet/nightly/sdk:8.0-jammy-aot AS build
ARG configuration=Release
WORKDIR /src
COPY ["TasksTracker.Processor.Backend.Svc/TasksTracker.Processor.Backend.Svc.csproj", "TasksTracker.Processor.Backend.Svc/"]
RUN dotnet restore "TasksTracker.Processor.Backend.Svc/TasksTracker.Processor.Backend.Svc.csproj"
COPY . .
WORKDIR "/src/TasksTracker.Processor.Backend.Svc"
RUN dotnet build "TasksTracker.Processor.Backend.Svc.csproj" -c $configuration -o /app/build

FROM build AS publish
ARG configuration=Release
RUN dotnet publish "TasksTracker.Processor.Backend.Svc.csproj" -c $configuration -o /app/publish /p:UseAppHost=false

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "TasksTracker.Processor.Backend.Svc.dll"]
24 changes: 24 additions & 0 deletions docs/aca/99-optimize-containers/Frontend.Ui.Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
WORKDIR /app
EXPOSE 5000

ENV ASPNETCORE_URLS=http://+:5000

USER app
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG configuration=Release
WORKDIR /src
COPY ["TasksTracker.WebPortal.Frontend.Ui/TasksTracker.WebPortal.Frontend.Ui.csproj", "TasksTracker.WebPortal.Frontend.Ui/"]
RUN dotnet restore "TasksTracker.WebPortal.Frontend.Ui/TasksTracker.WebPortal.Frontend.Ui.csproj"
COPY . .
WORKDIR "/src/TasksTracker.WebPortal.Frontend.Ui"
RUN dotnet build "TasksTracker.WebPortal.Frontend.Ui.csproj" -c $configuration -o /app/build

FROM build AS publish
ARG configuration=Release
RUN dotnet publish "TasksTracker.WebPortal.Frontend.Ui.csproj" -c $configuration -o /app/publish /p:UseAppHost=false

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "TasksTracker.WebPortal.Frontend.Ui.dll"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
FROM mcr.microsoft.com/dotnet/nightly/runtime-deps:8.0-jammy-chiseled-aot AS base
WORKDIR /app
EXPOSE 5000

ENV ASPNETCORE_URLS=http://+:5000

USER app
FROM mcr.microsoft.com/dotnet/nightly/sdk:8.0-jammy-aot AS build
ARG configuration=Release
WORKDIR /src
COPY ["TasksTracker.WebPortal.Frontend.Ui/TasksTracker.WebPortal.Frontend.Ui.csproj", "TasksTracker.WebPortal.Frontend.Ui/"]
RUN dotnet restore "TasksTracker.WebPortal.Frontend.Ui/TasksTracker.WebPortal.Frontend.Ui.csproj"
COPY . .
WORKDIR "/src/TasksTracker.WebPortal.Frontend.Ui"
RUN dotnet build "TasksTracker.WebPortal.Frontend.Ui.csproj" -c $configuration -o /app/build

FROM build AS publish
ARG configuration=Release
RUN dotnet publish "TasksTracker.WebPortal.Frontend.Ui.csproj" -c $configuration -o /app/publish /p:UseAppHost=false

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "TasksTracker.WebPortal.Frontend.Ui.dll"]
158 changes: 155 additions & 3 deletions docs/aca/99-optimize-containers/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ This image is comprised of one image, 331 packages, and has five vulnerabilities

![Backend API Status Quo Image Stats](../../assets/images/99-optimize-containers/backend-api-chiseled-image-stats.png)

#### 1.3 Ahead-of-time (AOT) Compilation
#### 1.3 Chiseled & Ahead-of-time (AOT) Compilation

[Ahead-of-time (AOT) compilation](https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot){target_blank} was first introduced with .NET 7. AOT compiles the application to native code instead of Intermediate Language (IL). This means that we must have foresight as to what platform will be hosting the application. Our process is simplified by the fact that containers in Azure Container Apps are only Linux-hosted. By using native code, we will bypass the just-in-time (JIT) compiler when the container executes, which means we will have faster startup and a smaller memory footprint. It also means these images can run in environments where JIT compilation may not be permitted.

Expand Down Expand Up @@ -144,9 +144,161 @@ Verify that the application continues to work:
$FRONTEND_UI_BASE_URL
```

#### 2. Wash/Rinse/Repeat for Frontend UI & Backend Service
### 2. Optimizing Frontend UI & Backend Service Containers

As all three projects use ASP.NET Core, you can follow this same exercise for the other two projects and see how much you are able to reduce!
As all three projects use ASP.NET Core, we can follow the same approach with these two projects as well.how much you are able to reduce!

#### 2.1 Frontend UI

#### 2.1.1 The Status Quo

Our original `Dockerfile` looks like this:

=== "Frontend.Ui Dockerfile"
```Dockerfile
--8<-- "docs/aca/99-optimize-containers/Frontend.Ui.Dockerfile"
```

```shell
cd ~\TasksTracker.ContainerApps
```

```shell
docker build -t frontend-ui-status-quo -f .\TasksTracker.WebPortal.Frontend.Ui\Dockerfile .
docker image list
```

This yields an image size of **227 MB**.

#### 2.1.2 Chiseled & Ahead-of-time (AOT) Compilation

Skipping straight to AOT images:

=== "Frontend.Ui Dockerfile.chiseled.aot"
```Dockerfile hl_lines="1 8"
--8<-- "docs/aca/99-optimize-containers/Frontend.Ui.Dockerfile.chiseled.aot"
```

Create a new file, `Dockerfile.chiseled.aot` in the Frontend Ui root directory, then build the image again:

```shell
docker build -t frontend-ui-chiseled-aot -f .\TasksTracker.WebPortal.Frontend.Ui\Dockerfile.chiseled.aot .
docker image list
```

This much-improved image is now **20.6 MB**.

#### 2.2 Backend Service

#### 2.2.1 The Status Quo

Our original `Dockerfile` looks like this:

=== "Backend.Svc Dockerfile"
```Dockerfile
--8<-- "docs/aca/99-optimize-containers/Backend.Svc.Dockerfile"
```

```shell
cd ~\TasksTracker.ContainerApps
```

```shell
docker build -t backend-svc-status-quo -f .\TasksTracker.Processor.Backend.Svc\Dockerfile .
docker image list
```

This yields an image size of **222 MB**.

#### 2.2.2 Chiseled & Ahead-of-time (AOT) Compilation

Skipping straight to AOT images:

=== "Backend.Svc Dockerfile.chiseled.aot"
```Dockerfile hl_lines="1 8"
--8<-- "docs/aca/99-optimize-containers/Backend.Svc.Dockerfile.chiseled.aot"
```

Create a new file, `Dockerfile.chiseled.aot` in the Backend Svc root directory, then build the image again:

```shell
docker build -t backend-svc-chiseled-aot -f .\TasksTracker.Processor.Backend.Svc\Dockerfile.chiseled.aot .
docker image list
```

This much-improved image is now **16 MB**.

### 3. Optimization Summary

#### 3.1 Table of Improvements

The Backend API and the Backend Svc projects are all but identical while the Frontend UI project is just slightly larger. All three projects were cut down to less than 10% of their original size!

| | Image Size | Size Reduction | Size compared to Original | Packages | CVEs |
|----------------------------|-----------:|---------------:|--------------------------:|---------:|-----:|
| Backend API Original | 222 MB | | | 452 | 19 |
| Backend API Chiseled & AOT | 16 MB | 206 MB | 7.2% | 23 | 9 |
| Frontend UI Original | 226 MB | | | 447 | 19 |
| Frontend UI Chiseled & AOT | 21 MB | 205 MB | 9.3% | 18 | 9 |
| Backend Svc Original | 222 MB | | | 452 | 19 |
| Backend Svc Chiseled & AOT | 16 MB | 206 MB | 7.2% | 23 | 9 |

#### 3.2 Build & Deploy All Services

The last step is to build & deploy updated images. For good measure, let's do the Backend API as well even though we did it earlier already.
```shell hl_lines="5 11 17"
# Build Backend API on ACR and Push to ACR
az acr build `
--registry $AZURE_CONTAINER_REGISTRY_NAME `
--image "tasksmanager/$BACKEND_API_NAME" `
--file 'TasksTracker.TasksManager.Backend.Api/Dockerfile.chiseled.aot' .
# Build Backend Service on ACR and Push to ACR
az acr build `
--registry $AZURE_CONTAINER_REGISTRY_NAME `
--image "tasksmanager/$BACKEND_SERVICE_NAME" `
--file 'TasksTracker.Processor.Backend.Svc/Dockerfile.chiseled.aot' .
# Build Frontend Web App on ACR and Push to ACR
az acr build `
--registry $AZURE_CONTAINER_REGISTRY_NAME `
--image "tasksmanager/$FRONTEND_WEBAPP_NAME" `
--file 'TasksTracker.WebPortal.Frontend.Ui/Dockerfile.chiseled.aot' .
```
```shell
# Update Backend API App container app and create a new revision
az containerapp update `
--name $BACKEND_API_NAME `
--resource-group $RESOURCE_GROUP `
--revision-suffix v$TODAY-7 `
--set-env-vars "ApplicationInsights__InstrumentationKey=secretref:appinsights-key"
# Update Frontend Web App container app and create a new revision
az containerapp update `
--name $FRONTEND_WEBAPP_NAME `
--resource-group $RESOURCE_GROUP `
--revision-suffix v$TODAY-7 `
--set-env-vars "ApplicationInsights__InstrumentationKey=secretref:appinsights-key"
# Update Backend Background Service container app and create a new revision
az containerapp update `
--name $BACKEND_SERVICE_NAME `
--resource-group $RESOURCE_GROUP `
--revision-suffix v$TODAY-7 `
--set-env-vars "ApplicationInsights__InstrumentationKey=secretref:appinsights-key"
```
Verify that the application continues to work with the three much smaller containers:
```shell
$FRONTEND_UI_BASE_URL
```
--8<-- "snippets/persist-state.md:module99"
Expand Down

0 comments on commit f36af89

Please sign in to comment.