there was awesome talks in .net conf 2023 keynote. one of the videos that i got interested was about new dotnet images. you can watch the talk here.
at the time i was doing some performance optimization on a project. there was a deadline and i was working to make the project production ready. here are some of the improvements that i made:
optimization | description |
---|---|
query optimization | detect the queries that has performance issues and create necessary indexes and check the queries. (important note: do not use select * ) |
update dotnet version | updated the project to dotnet 8 |
remove unnecessary libraries, implementations | this project was cloned from some template. so i had to remove some of the libraries and implementations that is not used |
multi-tenant structure | this project planned to lunch on cloud so many companies would use it so we had to implement multi-tenant structure |
add redis | in order to improve performance i had to add redis. i also used hybrid caching as it results the better performance in some places |
optimize payload size on rabbitmq | for pub/sub mechanism rabbitmq was used in this project. i reduced query size of payload to handle messages faster |
memory/cpu controls | increased memory and cpu sizes of applications and also added multi-node structure to increase availability |
logging structure | there was no general logging structure used in this project. i chose serilog first but for faster results i ended up using nlog |
after these optimizations one of the the things that bothered me was docker size of the project. it was 370mb at the time. so first i reduced the size by 80mb removing unused libraries and implementations. then i watched the talk in .net conf 2023 keynote about dotnet chiseled images. it was good for both performance, security. because in chiseled image there is no root user and there is no unnecessary packages. (there is no package manager so you can't use apt).
you can see the detailed explanations in this article.
also you can check the chiseled images and sizes on microsoft here.
example dockerfile i used first
# 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/aspnet:8.0-jammy-chiseled
EXPOSE 8080
WORKDIR /app
COPY --from=build /app .
ENTRYPOINT ["./aspnetapp"]
but there was an error because the project that i am working has a dependency on libicu70 library. but i found a workaround here
so final dockerfile was similar to this
FROM golang:1.20 as chisel
RUN git clone --depth 1 -b main https://github.com/canonical/chisel /opt/chisel
WORKDIR /opt/chisel
RUN go build ./cmd/chisel
FROM mcr.microsoft.com/dotnet/sdk:8.0-jammy AS build
RUN apt-get update \
&& apt-get install -y fdupes \
&& rm -rf /var/lib/apt/lists/*
COPY --from=chisel /opt/chisel/chisel /usr/bin/
COPY --from=mcr.microsoft.com/dotnet/nightly/runtime:6.0-jammy-chiseled / /runtime-ref
RUN mkdir /rootfs \
&& chisel cut --release "ubuntu-22.04" --root /rootfs \
libicu70_libs \
\
# Remove duplicates from rootfs that exist in runtime-ref
&& fdupes /runtime-ref /rootfs -rdpN \
\
# Delete duplicate symlinks
# Function to find and format symlinks w/o including root dir (format: /path/to/symlink /path/to/target)
&& getsymlinks() { find $1 -type l -printf '%p %l\n' | sed -n "s/^\\$1\\(.*\\)/\\1/p"; } \
# Combine set of symlinks between rootfs and runtime-ref
&& (getsymlinks "/rootfs"; getsymlinks "/runtime-ref") \
# Sort them
| sort \
# Find the duplicates
| uniq -d \
# Extract just the path to the symlink
| cut -d' ' -f1 \
# Prepend the rootfs directory to the paths
| sed -e 's/^/\/rootfs/' \
# Delete the files
| xargs rm \
\
# Delete empty directories
&& find /rootfs -type d -empty -delete
WORKDIR /source
# copy csproj and restore as distinct layers
COPY *.csproj .
RUN dotnet restore
# copy and publish app and libraries
COPY . .
RUN dotnet publish -c release -o /app --no-restore
# final stage/image
FROM mcr.microsoft.com/dotnet/nightly/runtime:8.0-jammy-chiseled
ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=false
COPY --from=build /rootfs /
WORKDIR /app
COPY --from=build /app .
ENTRYPOINT ["dotnet", "dotnetapp.dll"]
after his docker image's size has been reduced by approximately 50% - now it is 180mb. and security benefits comes with it as chiseled images doesn't have a root user.
Top comments (0)