Dockerising .NET Core & Svelte
Tags: dotnet, svelte, docker, webdev
Published: 2021-01-23 19:09:55

---
series: .NET Core and Svelte
---

The previous post covered how to set up a web application with a .NET Core backend and Svelte frontend.

In this post we'll package it up into a single Docker image ready to be deployed somewhere.

# Prerequisites

- [Docker](https://www.docker.com/products/docker-desktop)

# Approach

We'll be taking advantage of Docker's [multi-stage builds](https://docs.docker.com/develop/develop-images/multistage-build/) to:

- build the frontend using Node
- then the backend using .NET Core SDK
- copy the results to an image containing only the ASP.NET Core runtime

# Dockerfile

Create a file named `Dockerfile`. I usually do this with:

```bash
touch Dockerfile
```

## Frontend Build Stage

We'll start the file off with the below snippet. I've added comments to describe each step:

```dockerfile
# Use Node.js 14, name this stage 'frontend'
FROM node:14 AS frontend

# Our working directory within the image
WORKDIR /build

# Copy package and lock files then install dependencies
COPY package.json .             
COPY package-lock.json .
RUN npm install

# Copy the rest of the files for the frontend
COPY rollup.config.js .
COPY svelte-app ./svelte-app

# Build - this'll output files to /build/wwwroot
RUN npm run build
```

_If you're wondering "why copy the package and lock files first?": it's so Docker creates and caches an intermediate layer containing your dependencies (in node_modules). This gets reused in subsequent builds if those files remain unchanged and saves having to redownload dependencies on each build._

## Backend Build Stage

Now add:

```dockerfile
# Use .NET Core SDK, name this stage 'backend'
FROM mcr.microsoft.com/dotnet/sdk:5.0-alpine AS backend
WORKDIR /build

# Copy the csproj file then install dependencies
COPY dotnet-svelte.csproj .
RUN dotnet restore dotnet-svelte.csproj

# Copy everything else
COPY . .

# Publish, and output the results to /publish
RUN dotnet publish -c Release -o /publish
```

Similar to the frontend stage, we copy the `csproj` file first and restore dependencies to create an intermediate layer.

## Combine the Results

We named our stages in the earlier snippets with `AS frontend` and `AS backend`. In our final stage we can reference the earlier stages and copy files from them. Add to the file:

```dockerfile
# ASP.NET Core Runtime
FROM mcr.microsoft.com/dotnet/aspnet:5.0-alpine

# Where our application will live
WORKDIR /app

# Copy the build results of the frontend stage
COPY --from=frontend /build/wwwroot ./wwwroot

# Copy the build results of the backend stage
COPY --from=backend /publish .

# Run our web application on startup (will listen on port 80 by default)
ENTRYPOINT /app/dotnet-svelte
```

# Final Dockerfile

Should look like this (comments omitted):

```dockerfile
FROM node:14 AS frontend
WORKDIR /build
COPY package.json .             
COPY package-lock.json .
RUN npm install
COPY rollup.config.js .
COPY svelte-app ./svelte-app
RUN npm run build

FROM mcr.microsoft.com/dotnet/sdk:5.0-alpine AS backend
WORKDIR /build
COPY dotnet-svelte.csproj .
RUN dotnet restore dotnet-svelte.csproj
COPY . .
RUN dotnet publish -c Release -o /publish

FROM mcr.microsoft.com/dotnet/aspnet:5.0-alpine
WORKDIR /app
COPY --from=frontend /build/wwwroot ./wwwroot
COPY --from=backend /publish .
ENTRYPOINT /app/dotnet-svelte
```

# Building & Running

Builds an image from the Dockerfile, and name it `dotnet-svelte`:

```bash
docker build -t dotnet-svelte .
```

Then run with:

```bash
docker run --rm -p 5000:80 dotnet-svelte
```

- `--rm` tells docker to automatically remove the container once stopped
- `-p 5000:80` maps your local port 5000 to the container's port 80

Finally, browse to http://localhost:5000 and once again you will see:

![xh38glfcl8lh8za52im9](https://dev-to-uploads.s3.amazonaws.com/i/c4u79jube1czqekf1m14.png)

Congratulations! You now have an image ready to be deployed somewhere.

# Summary

This post was really more about Docker and multi-stage builds than anything else. We:

- Used a Node image to build the Svelte application
- Used a .NET Core SDK image to build the ASP.NET application
- Copied the results of both to an ASP.NET runtime image

The resulting image contains only the parts we need: static files for the frontend, binary files for the backend and the runtime required to run it.