How to Docker with .NET: Getting Started

How to Docker with .NET: Getting Started

An introduction on Docker, core concepts, and accessing a base ASP.NET Core image. .NET Core can easily run in a Docker container. Containers provide a lightweight way to isolate your application from the rest of the host system, sharing just the kernel, and using resources given to your application.

As a developer, do you ever think about all the time you spend … not developing? Among the work we do to get things working—I like to call it _meta-work_—infrastructure is the most frustrating and the biggest headache. It takes so much of our time and impacts our ability to deliver value quickly.

Thanks to software containerization—and, specifically, Docker—we can improve our workflow significantly. We can think of containers as isolated environments that allow us to run our software quickly. These containers allow us to package running images that include all our code and dependencies on any environment.

To be clear, I am tremendously late to this party. (Like, dinner is over and people are starting to ask “where’s Dave?” as if I got in an accident on the way there.) While I’ve always known about Docker from a high level—the value it brings, how to get an image, and so on—my new job responsibilities have forced me to understand it on a tremendously deeper level.

While I’ve seen a lot of great posts on this topic (such as Steve Gordon’s wonderful series from 2017), I wanted to write about all I’m learning—and hopefully it can help you, too.

I’ll be walking through Docker containers in three posts:

  • This post: Getting started (core concepts, run a pre-built image)
  • Next post: Diving deep (create image from existing app, considerations)
  • Last post: Publishing to Azure Kubernetes Service (AKS)

Armed with this knowledge, I’ll then be writing about container orchestration using Kubernetes.

Ensure Docker and Git is installed

Before starting this post, make sure you have the following installed:

Confirm your Docker install by executing docker -v in your terminal.

How Docker works

When we talk about packaging our software, we’re not just talking about code (if only it was that simple). There’s our operating system, the code itself, packages, libraries, binaries, and more. For example, you might be developing a .NET Core app on Linux with a database, while using a reverse proxy configuration. That sentence alone should be rationale enough for standardized environments.

When we’re running an image, that’s our container. If an image is our blueprint, the container is an instance of it running in memory. These images are immutable: you can’t change them once they’re built. This guarantees isolation, consistency, and performance.

What is a host?

A host is the OS where Docker is run. If you’re running Linux containers like most of the world, Docker shares the host kernel if the binary can access the kernel directly—preventing a need for a container OS.

Windows containers do need a container OS that is part of the packaged image, however, for file system access and memory management. Windows containers come in handy (and are essential) if you’re running things dependent on Windows APIs, like legacy .NET Framework apps. If you don’t have those needs, Linux containers are almost always the way to go.

Base images and parent images

To Docker, a base image utilizes their minimal image, called scratch. It’s an empty container image. It’s the equivalent of a piece of white paper: you’ve got something to draw with, but you’ll need to do the sketching.

Typically, you’ll instead build from a parent image, an image you can use as a starting point for your images—in developer language, a base class. Instead of using a base image to install an OS and a runtime, you can use a parent image instead.

Much like the IaaS vs. PaaS arguments in the cloud space, it comes down to control and how dirty you want your hands to get.

Using a Dockerfile

Docker uses a Dockerfile, a file that contains instructions on how to build an image. In a Dockerfile you’ll specify the image to use, commands to run, artifacts (your app and its dependencies), exposed ports, and what to run when the container starts running.

We’ll get into much more detail in the next post, but here’s a sample Dockerfile:

## Step 1: Specify your base image
FROM mcr.microsoft.com/dotnet/core/sdk:3.1

## Step 2: Copy project file to the /src container folder
WORKDIR /src
COPY ["MyCoolApp/MyCoolApp.csproj", "MyCoolApp/"]

## Step 3: Run a restore to download dependencies
RUN dotnet restore "MyCoolApp/MyCoolApp.csproj"

## Step 4: Copy app code to the container
COPY . .
WORKDIR "/src/MyCoolApp"

## Step 5: Build the app in Release mode
RUN dotnet build "MyCoolApp.csproj" -c Release -o /app

## Step 6: Publish the application
RUN dotnet publish "MyCoolApp.csproj" -c Release -o /app

## Step 7: Expose port 80 in the container
EXPOSE 80

## Step 8: Move the /app folder and run the compiled app
WORKDIR /app
ENTRYPOINT ["dotnet", "MyCoolApp.dll"]

With this Dockerfile, you’ll then be able to run something like docker build -t mycoolapp . to build your image.

docker dotnet devops

Bootstrap 5 Complete Course with Examples

Bootstrap 5 Tutorial - Bootstrap 5 Crash Course for Beginners

Nest.JS Tutorial for Beginners

Hello Vue 3: A First Look at Vue 3 and the Composition API

Building a simple Applications with Vue 3

Deno Crash Course: Explore Deno and Create a full REST API with Deno

How to Build a Real-time Chat App with Deno and WebSockets

Convert HTML to Markdown Online

HTML entity encoder decoder Online

Ever Wondered Why We Use Containers In DevOps?

At some point we've all said the words, "But it works on my machine." It usually happens during testing or when you're trying to get a new project set up. Sometimes it happens when you pull down changes from an updated branch.

Docker manifest - A peek into image's manifest.json files

The docker manifest command does not work independently to perform any action. In order to work with the docker manifest or manifest list, we use sub-commands along with it. This manifest sub-command can enable us to interact with the image manifests. Furthermore, it also gives information about the OS and the architecture, that a particular image was built for. The image manifest provides a configuration and a set of layers for a container image. This is an experimenta

Docker Explained: Docker Architecture | Docker Registries

Following the second video about Docker basics, in this video, I explain Docker architecture and explain the different building blocks of the docker engine; docker client, API, Docker Daemon. I also explain what a docker registry is and I finish the video with a demo explaining and illustrating how to use Docker hub.

How to Extend your DevOps Strategy For Success in the Cloud?

DevOps and Cloud computing are joined at the hip, now that fact is well appreciated by the organizations that engaged in SaaS cloud and developed applications in the Cloud. During the COVID crisis period, most of the organizations have started using cloud computing services and implementing a cloud-first strategy to establish their remote operations. Similarly, the extended DevOps strategy will make the development process more agile with automated test cases.

What Is DevOps and Is Enterprise DevOps Any Good?

What is DevOps? How are organizations transitioning to DevOps? Is it possible for organizations to shift to enterprise DevOps? Read more to find out!