Vue normale

Il y a de nouveaux articles disponibles, cliquez pour rafraîchir la page.
À partir d’avant-hierFlux principal

How To Chat with a Local AI Model using Ollama and .NET on MacOS

Par : Adesoji Alu
19 février 2025 à 20:40
Overview This guide will walk you through creating a simple chat application in .NET that interacts with a locally hosted AI model. Using the Microsoft.Extensions.AI library, you can communicate with an AI model without relying on cloud services. This provides better privacy, reduced latency, and cost efficiency. Prerequisites Install .NET 8.0 or a later version. […]

Experimenting with .NET 5 and 6 using Docker containers

21 février 2021 à 20:38
Experimenting with .NET 5 and 6 using Docker containers

The .NET team publish Docker images for every release of the .NET SDK and runtime. Running .NET in containers is a great way to experiment with a new release or try out an upgrade of an existing project, without deploying any new runtimes onto your machine.

In case you missed it, .NET 5 is the latest version of .NET and it's the end of the ".NET Core" and ".NET Framework" names. .NET Framework ends with 4.8 which is the last supported version. and .NET Core ends with 3.1 - and evolves into straight ".NET". The first release is .NET 5 and the next version - .NET 6 - will be a long-term support release.

If you're new to the SDK/runtime distinction, check my blog post on the .NET Docker images for Windows and Linux.

Run a .NET 5 development environment in a Docker container

You can use the .NET 5.0 SDK image to run a container with all the build and dev tools installed. These are official Microsoft images, published to MCR (the Microsoft Container Registry).

Create a local folder for the source code and mount it inside a container:

mkdir -p /tmp/dotnet-5-docker

docker run -it --rm \
  -p 5000:5000 \
  -v /tmp/dotnet-5-docker:/src \
  mcr.microsoft.com/dotnet/sdk:5.0

All you need to run this command is Docker Desktop on Windows or macOS, or Docker Community Edition on Linux.

Docker will pull the .NET 5.0 SDK image the first time you use it, and start running a container. If you're new to Docker this is what the options mean:

  • -it connects you to an interactive session inside the container
  • -p publishes a network port, so you can send traffic into the container from your machine
  • --rm deletes the container and its storage when you exit the session
  • -v mounts a local folder from your machine into the container filesystem - when you use /src inside the container it's actually using the /tmp/dotnet-5-docker folder on your machine
  • mcr.microsoft.com/dotnet/sdk:5.0 is the full image name for the 5.0 release of the SDK

And this is how it looks:

Experimenting with .NET 5 and 6 using Docker containers

When the container starts you'll drop into a shell session inside the container, which has the .NET 5.0 runtime and developer tools installed. Now you can start playing with .NET 5, using the Docker container to run commands but working with the source code on your local machine.

In the container session, run this to check the version of the SDK:

dotnet --list-sdks

Run a quickstart project

The dotnet new command creates a new project from a template. There are plenty of templates to choose from, we'll start with a nice simple REST service, using ASP.NET WebAPI.

Initialize and run a new project:

# create a WebAPI project without HTTPS or Swagger:
dotnet new webapi \
  -o /src/api \
  --no-openapi --no-https

# configure ASP.NET to listen on port 5000:
export ASPNETCORE_URLS=http://+:5000

# run the new project:
dotnet run \
  --no-launch-profile \
  --project /src/api/api.csproj

When you run this you'll see lots of output from the build process - NuGet packages being restored and the C# project being compiled. The output ends with the ASP.NET runtime showing the address where it's listening for requests.

Now your .NET 5 app is running inside Docker, and because the container has a published port to the host machine, you can browse to http://localhost:5000/weatherforecast on your machine. Docker sends the request into the container, and the ASP.NET app processes it and sends the response.

Package your app into a Docker image

What you have now isn't fit to ship and run in another environment, but it's easy to get there by building your own Docker image to package your app.

I cover the path to production in my Udemy course Docker for .NET Apps

To ship your app you can use this .NET 5 sample Dockerfile to package it up. You'll do this from your host machine, so you can stop the .NET app in the container with Ctrl-C and then run exit to get back to your command line.

Use Docker to publish and package your WebAPI app:

# verify the source code is on your machine: 
ls /tmp/dotnet-5-docker/api

# switch to your local source code folder:
cd /tmp/dotnet-5-docker

# download the sample Dockerfile:
curl -o Dockerfile https://raw.githubusercontent.com/sixeyed/blog/master/dotnet-5-with-docker/Dockerfile

# use Docker to package from source code:
docker build -t dotnet-api:5.0 .

Now you have your own Docker image, with your .NET 5 app packaged and ready to run. You can edit the code on your local machine and repeat the docker build command to package a new version.

Run your app in a new container

The SDK container you ran is gone, but now you have an application image so you can run your app without any additional setup. Your image is configured with the ASP.NET runtime and when you start a container from the image it will run your app.

Start a new container listening on a different port:

# run a container from your .NET 5 API image:
docker run -d -p 8010:80 --name api dotnet-api:5.0

# check the container logs:
docker logs api

In the logs you'll see the usual ASP.NET startup log entries, telling you the app is listening on port 80. That's port 80 inside the container though, which is published to port 8010 on the host.

The container is running in the bckground, waiting for traffic. You can try your app again, running this on the host:

curl http://localhost:8010/weatherforecast

When you're done fetching fictional weather forecasts, you can stop and remove your container with a single command:

docker rm -f api

And if you're done experimenting, you can remove your image and the .NET 5 images:

docker image rm dotnet-api:5.0

docker image rm mcr.microsoft.com/dotnet/sdk:5.0

docker image rm mcr.microsoft.com/dotnet/aspnet:5.0

Now your machine is back to the exact same state before you tried .NET 5.

What about .NET 6?

You can do exactly the same thing for .NET 6, just changing the version number in the image tags. .NET 6 is in preview right now but the 6.0 tag is a moving target which gets updated with each new release (check the .NET SDK repository and the ASP.NET runtime repository on Docker Hub for the full version names).

To try .NET 6 you're going to run this for your dev environment:

mkdir -p /tmp/dotnet-6-docker

docker run -it --rm \
  -p 5000:5000 \
  -v /tmp/dotnet-6-docker:/src \
  mcr.microsoft.com/dotnet/sdk:6.0

Then you can repeat the steps to create a new .NET 6 app and run it inside a container.

And in your Dockerfile you'll use the mcr.microsoft.com/dotnet/sdk:6.0 image for the builder stage and the mcr.microsoft.com/dotnet/aspnet:6.0 image for the final application image.

It's a nice workflow to try out a new major or minor version of .NET with no dependencies (other than Docker). You can even put your docker build command into a GitHub workflow and build and package your app from your cource code repo - check my YouTube show Continuous Deployment with Docker and GitHub for more information on that.

Understanding Microsoft's Docker Images for .NET Apps

14 janvier 2021 à 09:04
Understanding Microsoft's Docker Images for .NET Apps

To run .NET apps in containers you need to have the .NET Framework or .NET Core runtime installed in the container image. That's not something you need to manage yourself, because Microsoft provide Docker images with the runtimes already installed, and you'll use those as the base image to package your own apps.

There are several variations of .NET images, covering different versions and different runtimes. This is your guide to picking the right image for your applications.

I cover this in plenty of detail in my Udemy course Docker for .NET Apps

Using a Base Image

Your app has a bunch of pre-requisites it needs to run, things like an operating system and the language runtime. Typically the owners of the platform package an image with all the pre-reqs installed and publish it on Docker Hub - you'll see Go, Node.js, Java etc. all as official images.

Microsoft do the same for .NET apps, so you can use one of their images as the base image for your container images. They're regularly updated so you can patch your images just by rebuilding them using the latest Microsoft image.

The Docker images for .NET apps are hosted on Microsoft's own container registry, mcr.microsoft.com, but they're still listed on Docker Hub, so that's where you'll go to find them:

Those are umbrella pages which list lots of different variants of the .NET images, splitting them between SDK images and runtime images.

Runtime and SDK Images

You can package .NET apps using a runtime image with a simple Dockerfile like this:

FROM mcr.microsoft.com/dotnet/framework/aspnet:4.8
SHELL ["powershell"]

COPY app.msi /
RUN Start-Process msiexec.exe -ArgumentList '/i', 'C:\app.msi', '/quiet', '/norestart' -NoNewWindow -Wait

(see the full ASP.NET 4.8 app Dockerfile on GitHub).

That's an easy way to get into Docker, taking an existing deployment package (an MSI installer in this case) and installing it using a PowerShell command running in the container.

This example uses the ASP.NET 4.8 base image, so the image you build from this Dockerfile:

  • has IIS, .NET Framework 4.8 and ASP.NET already configured
  • deploys your app from the MSI, which hopefully is an ASP.NET app
  • requires you to have an existing process to create the MSI.

It's a simple approach but its problematic because the Dockerfile is the packaging format and it should have all the details about the deployment, but all the installation steps are hidden in the MSI - which is a redundant additional artifact.

Instead you can compile the app from source code using Docker, which is where the SDK images come in. Those SDK images have all the build tools for your apps: MSBuild and NuGet or the dotnet CLI. You use them in a multi-stage Docker build, where stage 1 compiles from source and stage 2 packages the compiled build from stage 1:

# the build stage uses the SDK image:
FROM mcr.microsoft.com/dotnet/core/sdk:3.1 as builder
COPY src /src
RUN dotnet publish -c Release -o /out app.csproj

# the final app uses the runtime image:
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1
COPY --from=builder /out/ .
ENTRYPOINT ["dotnet", "app.dll"]

(see the full ASP.NET Core app Dockerfile on GitHub).

This approach is much better because:

  • the whole build is portable, you just need Docker and the source code to build and run the app, you don't need any .NET SDKs or runtimes installed on your machine
  • your Dockerfile is the deployment script, every step is clear and it's in one place with no additional deployment artifacts
  • your final image has all the runtime pre-reqs it needs, but none of the extra tools - MSBuild etc. are only used in the builder stage

I show you how to use GitHub actions with multi-stage Docker builds in my YouTube show ECS-C2: Continuous Deployment with Docker and GitHub.

There are still lots of variants of the .NET Docker images, so the next job is to work out which ones to use for different apps.

Docker Images for .NET Framework Apps

.NET Framework apps are the simplest because they only run on Windows, and they need the full Windows Server Core feature set (you can't run .NET fx apps on the minimal Nano Server OS). You'll use these for any .NET Framework apps you want to containerize - you can run them using Windows containers in Docker, Docker Swarm and Kubernetes.

All the current .NET Framework Docker images use mcr.microsoft.com/windows/servercore:lts2019 as the base image - that's the latest long-term support version of Windows Server Core 2019. Then the .NET images extend from the base Windows image in a hierarchy:

Understanding Microsoft's Docker Images for .NET Apps

The Docker image names are shortened in that graphic, they're all hosted on MCR so they all need to be prefixed with mcr.microsoft.com/. The tag for each is the latest release, so that's a moving target - the :ltsc2019 Windows image is updated every month with new OS patches, so if you use that in your FROM instruction you'll always get the current release.

Microsoft also publish images with more specific tags, so you can pin to a particular release and you know that image won't change in the future. The .NET 4.8 SDK image was updated last year to include .NET 5 updates, and that broke some builds - so you could use mcr.microsoft.com/dotnet/framework/sdk:4.8-20201013-windowsservercore-ltsc2019 in your builder stage, which is pinned to the version before the change.

Here's how you'll choose between the images:

  • windows/servercore:lts2019 comes with .NET 4.7, so you can use it for .NET Console apps, but not ASP.NET or .NET Core apps;
  • dotnet/framework/runtime:4.8 has the last supported version of .NET Framework which you can use to run containerized console apps;
  • dotnet/framework/sdk:4.8 has MSBuild, NuGet and all the targeting packs installed, so you should be able to build pretty much any .NET Framework app - you'll use this in the builder stage only;
  • dotnet/framework/aspnet:4.8 has ASP.NET 4.8 installed and configured with IIS, so you can use it for any web apps - WebForms, MVC, Web API etc.

There's also dotnet/framework/wcf:4.8 for running WCF apps. All the Dockerfiles for those images are on GitHub at microsoft/dotnet-framework-docker in the src folder, and there are also a whole bunch of .NET Framework Docker sample apps.

Those images have the 4.x runtime installed, so they can run most .NET Framework apps - everything from 1.x to 4.x but not 3.5. The 3.5 runtime adds another gigabyte or so and it's only needed for some apps, so they have their own set of images:

  • dotnet/framework/runtime:3.5
  • dotnet/framework/sdk:3.5
  • dotnet/framework/aspnet:3.5

Docker Images for .NET Core Apps

.NET Core gets a bit more complicated, because it's a cross-platform framework with different images available for Windows and Linux containers. You'll use the Linux variants as a preference because they're leaner and you don't need to pay OS licences for the host machine.

If you're not sure on the difference with Docker on Windows and Linux, check out ECS-W1: We Need to Talk About Windows Containers on YouTube or enrol on Docker for .NET Apps on Udemy.

The Linux variants are derived from Debian, and they use a similar hierarchical build approach and have the same naming standards as the .NET Framework images:

Understanding Microsoft's Docker Images for .NET Apps

Again those image names need to be prefixed with mcr.microsoft.com/, and the tags are for the latest LTS release so they're moving targets - right now aspnet:3.1 is an alias for aspnet:3.1.11, but next month the same 3.1 tag will be used for an updated release.

  • dotnet/core/runtime:3.1 has the .NET Core runtime, so you can use it for console apps;
  • dotnet/core/sdk:3.1 has the SDK installed so you'll use it in the builder stage to compile .NET Core apps;
  • dotnet/core/aspnet:3.1 has ASP.NET Core 3.1 installed, so you can use it to run web apps (they're still console apps in .NET Core, but the web runtime has extra dependencies).

.NET Core 3.1 will be supported until December 2022; 2.1 is also an LTS release with support until August 2021, and there are images available for the 2.1 runtime using the same image names and the tag :2.1. You'll find all the Dockerfiles and some sample apps on GitHub in the dotnet/dotnet-docker repo.

There are also Alpine Linux variants of the .NET Core images, which are smaller and leaner still. If you're building images to run on Linux and you're not interested in cross-platform running on Windows, these are preferable - but some dependencies don't work correctly in Alpine (Sqlite is one), so you'll need to test your apps:

  • dotnet/core/runtime:3.1-alpine
  • dotnet/core/sdk:3.1-alpine
  • dotnet/core/aspnet:3.1-alpine

If you do want to build images for Linux and Windows from the same source code and the same Dockerfiles, stick with the generic :3.1 tags - these are multi-architecture images, so there are versions published for Linux, Windows, Intel and Arm 64.

The Windows variants are all based on Nano Server:

Understanding Microsoft's Docker Images for .NET Apps

Note that they have the same image names - with multi-architecture images Docker will pull the correct version to match the OS and CPU you're using. You can check all the available variants by looking at the manifest (you need experimental features enabled in the Docker CLI for this):

docker manifest inspect mcr.microsoft.com/dotnet/core/runtime:3.1

You'll see a chunk of JSON in the response, which includes details of all the variants - here's a trimmed version:

"manifests": [
      {        
         "digest": "sha256:6c67be...",
         "platform": {
            "architecture": "amd64",
            "os": "linux"
         }
      },
      {
         "digest": "sha256:d50e61...",
         "platform": {
            "architecture": "arm64",
            "os": "linux",
            "variant": "v8"
         }
      },
      {
         "digest": "sha256:3eb5f6...",
         "platform": {
            "architecture": "amd64",
            "os": "windows",
            "os.version": "10.0.17763.1697"
         }
      },
      {
         "digest": "sha256:4d53d2d...",
         "platform": {
            "architecture": "amd64",
            "os": "windows",
            "os.version": "10.0.18363.1316"
         }
      }
]

You can see in there that the single image tag dotnet/core/runtime:3.1 has image variants available for Linux on Intel, Linux on Arm and multiple versions of Windows on Intel. As long as you keep your Dockerfiles generic - and don't include OS-specific commands in RUN instructions - you can build your own multi-arch .NET Core apps based on Microsoft's images.

Going Forward - Docker Images for .NET 5

.NET 5 is the new evolution of .NET Core, and there are Docker images for the usual variants on MCR:

  • dotnet/runtime:5.0
  • dotnet/sdk:5.0
  • dotnet/aspnet:5.0

Note that "core" has been dropped from the image name - there's more information in this issue .NET Docker Repo Name Change.

Migrating .NET Core apps to .NET 5 should be a simple change, but remember that 5 is not an LTS version - you'll need to wait for .NET 6, which is LTS (see Microsoft's .NET Core and .NET 5 Support Policy.

Adventures in Docker: Coding on a Remote Browser

10 avril 2019 à 15:08
Adventures in Docker: Coding on a Remote Browser

This adventure lets you code on your normal dev machine from some other machine, using the browser. It's powered by Docker plus:

  • code-server - VS Code running in a container with browser access
  • ngrok - a public HTTP tunnel

And it's very simple. You just run code-server in a Docker container on your dev machine, mapping volumes for the data you want to be able to access and publishing a port. Then you expose that port to the Internet using ngrok, make a note of the URL and walk out the door.

Headless VS Code in Docker

code-server has done all the hard work here. They publish images to codercom/code-server on Docker Hub. There are only x64 Linux images right now.

Run the latest version with:

docker container run \
 -d -p 8443:8443 \
 -v /scm:/scm \
 codercom/code-server:1.621 \
 --allow-http --no-auth

That command runs VS Code as a headless server in a background container. The options:

  • publish port 8443 on your local machine into the container
  • mount the local /scm directory into /scm on the container
  • run insecure with plain HTTP and no authentication.

You can run insecure on your home network (if you trust folks who can access your network), because you'll add security with ngrok.

Now you can browse to http://localhost:8443 and you have VS Code running in the browser:

Adventures in Docker: Coding on a Remote Browser

That volume mount means all of the code in the scm folder on my machine is accessible from the VS Code instance. And you can fire up a terminal in VS Code in the browser, which means you can do pretty much anything else you need to do. But remember the terminal is executing inside the container, so the environment is the container.

The code-server images comes with a few dev tools installed, like Git and OpenSSL. But there are no dev toolkits, so you can't actually compile or run any code... Unless you're using multi-stage Dockerfiles and official images with SDKs installed. Then all you need is Docker.

Headless VS Code with Docker

code-server doesn't have the Docker CLI installed, but I've added that in my fork. So you can run my version and mount the local Docker socket as a volume, meaning you can use docker commands inside the browser-based VS Code instance:

docker container run \
 -d -p 8443:8443 \
 -v /scm:/scm \
 -v /var/run/docker.sock:/var/run/docker.sock \
 --network code-server \
 sixeyed/code-server:1.621 \
 --allow-http --no-auth

(I'm also using an explicit Docker network here which I created with docker network create code-server. You'll see why in a moment).

Now you can refresh your browser at http://localhost:8443, open up a terminal and run all the docker commands you like (with sudo). The Docker CLI inside the container is connected to the Docker Engine which is running the container.

Let's try out the .NET Core 3.0 preview. You can run these commands in VS Code on the browser. They all execute inside the container:

git clone https://github.com/sixeyed/whoami-dotnet.git
cd whoami-dotnet
sudo docker image build -t sixeyed/whoami-dotnet:3.0-linux-amd64 .
sudo docker container run -d \
 --network code-server --name whoami \
 sixeyed/whoami-dotnet:3.0-linux-amd64

Now the whoami container is running in the same Docker network as the code-server container, so you can reach it by the container name:

curl http://whoami

And here it is for real:

Adventures in Docker: Coding on a Remote Browser

Now this is a usable development environment. The multi-stage Dockerfile I've built starts with a build stage that uses an image with the .NET Core SDK, so there's no need to install any tools in the dev environment. You can do the same with Java, Go etc. - they all have official build images on Docker Hub.

And the final step is to make it publicly available through ngrok.

Remote Headless VS Code with Docker

Sign up for an ngrok account, and follow the setup instructions to install the software and apply your credentials. Now you can expose any local port through a public Internet tunnel - just by running something like ngrok http 8443.

But you can do more with ngrok. This command sets up a tunnel for my VS Code server with HTTPS and basic authentication:

ngrok http -bind-tls=true -auth="elton:DockerCon" 8443

You'll see output like this, telling you the public URL for your tunnel and some stats about who's using it:

Adventures in Docker: Coding on a Remote Browser

The Forwarding line tells you the public URL and the local port it's forwarding. Mine is https://112f7fb1.ngrok.io (you can use custom domains instead of the random ones). That endpoint is HTTPS so it's secure, and it's using basic auth so you'll need the username and password you specified in the ngrok command:

Adventures in Docker: Coding on a Remote Browser

Now you can access the headless VS Code instance running on your dev machine from anywhere on the Internet. Browser sessions are separate, so you can even have multiple people doing different things on the same remote code server:

Adventures in Docker: Coding on a Remote Browser

ngrok collects metrics while it's running, and there's an admin portal you can browse to locally - it shows you all the requests and responses the tunnel has handled:

Adventures in Docker: Coding on a Remote Browser

What about Windows?

I've only had a quick look, but it seems like this could work on Windows. ngrok already has Windows support, and it should just mean packaging code-server with a different Dockerfile.

Sounds like a nice weekend project for someone. Docker on Windows - second edition! will help :)

Experimenting with .NET 5 and 6 using Docker containers

21 février 2021 à 20:38
Experimenting with .NET 5 and 6 using Docker containers

The .NET team publish Docker images for every release of the .NET SDK and runtime. Running .NET in containers is a great way to experiment with a new release or try out an upgrade of an existing project, without deploying any new runtimes onto your machine.

In case you missed it, .NET 5 is the latest version of .NET and it's the end of the ".NET Core" and ".NET Framework" names. .NET Framework ends with 4.8 which is the last supported version. and .NET Core ends with 3.1 - and evolves into straight ".NET". The first release is .NET 5 and the next version - .NET 6 - will be a long-term support release.

If you're new to the SDK/runtime distinction, check my blog post on the .NET Docker images for Windows and Linux.

Run a .NET 5 development environment in a Docker container

You can use the .NET 5.0 SDK image to run a container with all the build and dev tools installed. These are official Microsoft images, published to MCR (the Microsoft Container Registry).

Create a local folder for the source code and mount it inside a container:

mkdir -p /tmp/dotnet-5-docker

docker run -it --rm \  
  -p 5000:5000 \
  -v /tmp/dotnet-5-docker:/src \
  mcr.microsoft.com/dotnet/sdk:5.0

All you need to run this command is Docker Desktop on Windows or macOS, or Docker Community Edition on Linux.

Docker will pull the .NET 5.0 SDK image the first time you use it, and start running a container. If you're new to Docker this is what the options mean:

  • -it connects you to an interactive session inside the container
  • -p publishes a network port, so you can send traffic into the container from your machine
  • --rm deletes the container and its storage when you exit the session
  • -v mounts a local folder from your machine into the container filesystem - when you use /src inside the container it's actually using the /tmp/dotnet-5-docker folder on your machine
  • mcr.microsoft.com/dotnet/sdk:5.0 is the full image name for the 5.0 release of the SDK

And this is how it looks:

Experimenting with .NET 5 and 6 using Docker containers

When the container starts you'll drop into a shell session inside the container, which has the .NET 5.0 runtime and developer tools installed. Now you can start playing with .NET 5, using the Docker container to run commands but working with the source code on your local machine.

In the container session, run this to check the version of the SDK:

dotnet --list-sdks  

Run a quickstart project

The dotnet new command creates a new project from a template. There are plenty of templates to choose from, we'll start with a nice simple REST service, using ASP.NET WebAPI.

Initialize and run a new project:

# create a WebAPI project without HTTPS or Swagger:
dotnet new webapi \  
  -o /src/api \
  --no-openapi --no-https

# configure ASP.NET to listen on port 5000:
export ASPNETCORE_URLS=http://+:5000

# run the new project:
dotnet run \  
  --no-launch-profile \
  --project /src/api/api.csproj

When you run this you'll see lots of output from the build process - NuGet packages being restored and the C# project being compiled. The output ends with the ASP.NET runtime showing the address where it's listening for requests.

Now your .NET 5 app is running inside Docker, and because the container has a published port to the host machine, you can browse to http://localhost:5000/weatherforecast on your machine. Docker sends the request into the container, and the ASP.NET app processes it and sends the response.

Package your app into a Docker image

What you have now isn't fit to ship and run in another environment, but it's easy to get there by building your own Docker image to package your app.

I cover the path to production in my Udemy course Docker for .NET Apps

To ship your app you can use this .NET 5 sample Dockerfile to package it up. You'll do this from your host machine, so you can stop the .NET app in the container with Ctrl-C and then run exit to get back to your command line.

Use Docker to publish and package your WebAPI app:

# verify the source code is on your machine: 
ls /tmp/dotnet-5-docker/api

# switch to your local source code folder:
cd /tmp/dotnet-5-docker

# download the sample Dockerfile:
curl -o Dockerfile https://raw.githubusercontent.com/sixeyed/blog/master/dotnet-5-with-docker/Dockerfile

# use Docker to package from source code:
docker build -t dotnet-api:5.0 .  

Now you have your own Docker image, with your .NET 5 app packaged and ready to run. You can edit the code on your local machine and repeat the docker build command to package a new version.

Run your app in a new container

The SDK container you ran is gone, but now you have an application image so you can run your app without any additional setup. Your image is configured with the ASP.NET runtime and when you start a container from the image it will run your app.

Start a new container listening on a different port:

# run a container from your .NET 5 API image:
docker run -d -p 8010:80 --name api dotnet-api:5.0

# check the container logs:
docker logs api  

In the logs you'll see the usual ASP.NET startup log entries, telling you the app is listening on port 80. That's port 80 inside the container though, which is published to port 8010 on the host.

The container is running in the bckground, waiting for traffic. You can try your app again, running this on the host:

curl http://localhost:8010/weatherforecast  

When you're done fetching fictional weather forecasts, you can stop and remove your container with a single command:

docker rm -f api  

And if you're done experimenting, you can remove your image and the .NET 5 images:

docker image rm dotnet-api:5.0

docker image rm mcr.microsoft.com/dotnet/sdk:5.0

docker image rm mcr.microsoft.com/dotnet/aspnet:5.0  

Now your machine is back to the exact same state before you tried .NET 5.

What about .NET 6?

You can do exactly the same thing for .NET 6, just changing the version number in the image tags. .NET 6 is in preview right now but the 6.0 tag is a moving target which gets updated with each new release (check the .NET SDK repository and the ASP.NET runtime repository on Docker Hub for the full version names).

To try .NET 6 you're going to run this for your dev environment:

mkdir -p /tmp/dotnet-6-docker

docker run -it --rm \  
  -p 5000:5000 \
  -v /tmp/dotnet-6-docker:/src \
  mcr.microsoft.com/dotnet/sdk:6.0

Then you can repeat the steps to create a new .NET 6 app and run it inside a container.

And in your Dockerfile you'll use the mcr.microsoft.com/dotnet/sdk:6.0 image for the builder stage and the mcr.microsoft.com/dotnet/aspnet:6.0 image for the final application image.

It's a nice workflow to try out a new major or minor version of .NET with no dependencies (other than Docker). You can even put your docker build command into a GitHub workflow and build and package your app from your cource code repo - check my YouTube show Continuous Deployment with Docker and GitHub for more information on that.

Understanding Microsoft's Docker Images for .NET Apps

14 janvier 2021 à 09:04
Understanding Microsoft's Docker Images for .NET Apps

To run .NET apps in containers you need to have the .NET Framework or .NET Core runtime installed in the container image. That's not something you need to manage yourself, because Microsoft provide Docker images with the runtimes already installed, and you'll use those as the base image to package your own apps.

There are several variations of .NET images, covering different versions and different runtimes. This is your guide to picking the right image for your applications.

I cover this in plenty of detail in my Udemy course Docker for .NET Apps

Using a Base Image

Your app has a bunch of pre-requisites it needs to run, things like an operating system and the language runtime. Typically the owners of the platform package an image with all the pre-reqs installed and publish it on Docker Hub - you'll see Go, Node.js, Java etc. all as official images.

Microsoft do the same for .NET apps, so you can use one of their images as the base image for your container images. They're regularly updated so you can patch your images just by rebuilding them using the latest Microsoft image.

The Docker images for .NET apps are hosted on Microsoft's own container registry, mcr.microsoft.com, but they're still listed on Docker Hub, so that's where you'll go to find them:

Those are umbrella pages which list lots of different variants of the .NET images, splitting them between SDK images and runtime images.

Runtime and SDK Images

You can package .NET apps using a runtime image with a simple Dockerfile like this:

FROM mcr.microsoft.com/dotnet/framework/aspnet:4.8  
SHELL ["powershell"]

COPY app.msi /  
RUN Start-Process msiexec.exe -ArgumentList '/i', 'C:\app.msi', '/quiet', '/norestart' -NoNewWindow -Wait  

(see the full ASP.NET 4.8 app Dockerfile on GitHub).

That's an easy way to get into Docker, taking an existing deployment package (an MSI installer in this case) and installing it using a PowerShell command running in the container.

This example uses the ASP.NET 4.8 base image, so the image you build from this Dockerfile:

  • has IIS, .NET Framework 4.8 and ASP.NET already configured
  • deploys your app from the MSI, which hopefully is an ASP.NET app
  • requires you to have an existing process to create the MSI.

It's a simple approach but its problematic because the Dockerfile is the packaging format and it should have all the details about the deployment, but all the installation steps are hidden in the MSI - which is a redundant additional artifact.

Instead you can compile the app from source code using Docker, which is where the SDK images come in. Those SDK images have all the build tools for your apps: MSBuild and NuGet or the dotnet CLI. You use them in a multi-stage Docker build, where stage 1 compiles from source and stage 2 packages the compiled build from stage 1:

# the build stage uses the SDK image:
FROM mcr.microsoft.com/dotnet/core/sdk:3.1 as builder  
COPY src /src  
RUN dotnet publish -c Release -o /out app.csproj

# the final app uses the runtime image:
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1  
COPY --from=builder /out/ .  
ENTRYPOINT ["dotnet", "app.dll"]  

(see the full ASP.NET Core app Dockerfile on GitHub).

This approach is much better because:

  • the whole build is portable, you just need Docker and the source code to build and run the app, you don't need any .NET SDKs or runtimes installed on your machine
  • your Dockerfile is the deployment script, every step is clear and it's in one place with no additional deployment artifacts
  • your final image has all the runtime pre-reqs it needs, but none of the extra tools - MSBuild etc. are only used in the builder stage

I show you how to use GitHub actions with multi-stage Docker builds in my YouTube show ECS-C2: Continuous Deployment with Docker and GitHub.

There are still lots of variants of the .NET Docker images, so the next job is to work out which ones to use for different apps.

Docker Images for .NET Framework Apps

.NET Framework apps are the simplest because they only run on Windows, and they need the full Windows Server Core feature set (you can't run .NET fx apps on the minimal Nano Server OS). You'll use these for any .NET Framework apps you want to containerize - you can run them using Windows containers in Docker, Docker Swarm and Kubernetes.

All the current .NET Framework Docker images use mcr.microsoft.com/windows/servercore:lts2019 as the base image - that's the latest long-term support version of Windows Server Core 2019. Then the .NET images extend from the base Windows image in a hierarchy:

Understanding Microsoft's Docker Images for .NET Apps

The Docker image names are shortened in that graphic, they're all hosted on MCR so they all need to be prefixed with mcr.microsoft.com/. The tag for each is the latest release, so that's a moving target - the :ltsc2019 Windows image is updated every month with new OS patches, so if you use that in your FROM instruction you'll always get the current release.

Microsoft also publish images with more specific tags, so you can pin to a particular release and you know that image won't change in the future. The .NET 4.8 SDK image was updated last year to include .NET 5 updates, and that broke some builds - so you could use mcr.microsoft.com/dotnet/framework/sdk:4.8-20201013-windowsservercore-ltsc2019 in your builder stage, which is pinned to the version before the change.

Here's how you'll choose between the images:

  • windows/servercore:lts2019 comes with .NET 4.7, so you can use it for .NET Console apps, but not ASP.NET or .NET Core apps;
  • dotnet/framework/runtime:4.8 has the last supported version of .NET Framework which you can use to run containerized console apps;
  • dotnet/framework/sdk:4.8 has MSBuild, NuGet and all the targeting packs installed, so you should be able to build pretty much any .NET Framework app - you'll use this in the builder stage only;
  • dotnet/framework/aspnet:4.8 has ASP.NET 4.8 installed and configured with IIS, so you can use it for any web apps - WebForms, MVC, Web API etc.

There's also dotnet/framework/wcf:4.8 for running WCF apps. All the Dockerfiles for those images are on GitHub at microsoft/dotnet-framework-docker in the src folder, and there are also a whole bunch of .NET Framework Docker sample apps.

Those images have the 4.x runtime installed, so they can run most .NET Framework apps - everything from 1.x to 4.x but not 3.5. The 3.5 runtime adds another gigabyte or so and it's only needed for some apps, so they have their own set of images:

  • dotnet/framework/runtime:3.5
  • dotnet/framework/sdk:3.5
  • dotnet/framework/aspnet:3.5

Docker Images for .NET Core Apps

.NET Core gets a bit more complicated, because it's a cross-platform framework with different images available for Windows and Linux containers. You'll use the Linux variants as a preference because they're leaner and you don't need to pay OS licences for the host machine.

If you're not sure on the difference with Docker on Windows and Linux, check out ECS-W1: We Need to Talk About Windows Containers on YouTube or enrol on Docker for .NET Apps on Udemy.

The Linux variants are derived from Debian, and they use a similar hierarchical build approach and have the same naming standards as the .NET Framework images:

Understanding Microsoft's Docker Images for .NET Apps

Again those image names need to be prefixed with mcr.microsoft.com/, and the tags are for the latest LTS release so they're moving targets - right now aspnet:3.1 is an alias for aspnet:3.1.11, but next month the same 3.1 tag will be used for an updated release.

  • dotnet/core/runtime:3.1 has the .NET Core runtime, so you can use it for console apps;
  • dotnet/core/sdk:3.1 has the SDK installed so you'll use it in the builder stage to compile .NET Core apps;
  • dotnet/core/aspnet:3.1 has ASP.NET Core 3.1 installed, so you can use it to run web apps (they're still console apps in .NET Core, but the web runtime has extra dependencies).

.NET Core 3.1 will be supported until December 2022; 2.1 is also an LTS release with support until August 2021, and there are images available for the 2.1 runtime using the same image names and the tag :2.1. You'll find all the Dockerfiles and some sample apps on GitHub in the dotnet/dotnet-docker repo.

There are also Alpine Linux variants of the .NET Core images, which are smaller and leaner still. If you're building images to run on Linux and you're not interested in cross-platform running on Windows, these are preferable - but some dependencies don't work correctly in Alpine (Sqlite is one), so you'll need to test your apps:

  • dotnet/core/runtime:3.1-alpine
  • dotnet/core/sdk:3.1-alpine
  • dotnet/core/aspnet:3.1-alpine

If you do want to build images for Linux and Windows from the same source code and the same Dockerfiles, stick with the generic :3.1 tags - these are multi-architecture images, so there are versions published for Linux, Windows, Intel and Arm 64.

The Windows variants are all based on Nano Server:

Understanding Microsoft's Docker Images for .NET Apps

Note that they have the same image names - with multi-architecture images Docker will pull the correct version to match the OS and CPU you're using. You can check all the available variants by looking at the manifest (you need experimental features enabled in the Docker CLI for this):

docker manifest inspect mcr.microsoft.com/dotnet/core/runtime:3.1  

You'll see a chunk of JSON in the response, which includes details of all the variants - here's a trimmed version:

"manifests": [
      {        
         "digest": "sha256:6c67be...",
         "platform": {
            "architecture": "amd64",
            "os": "linux"
         }
      },
      {
         "digest": "sha256:d50e61...",
         "platform": {
            "architecture": "arm64",
            "os": "linux",
            "variant": "v8"
         }
      },
      {
         "digest": "sha256:3eb5f6...",
         "platform": {
            "architecture": "amd64",
            "os": "windows",
            "os.version": "10.0.17763.1697"
         }
      },
      {
         "digest": "sha256:4d53d2d...",
         "platform": {
            "architecture": "amd64",
            "os": "windows",
            "os.version": "10.0.18363.1316"
         }
      }
]

You can see in there that the single image tag dotnet/core/runtime:3.1 has image variants available for Linux on Intel, Linux on Arm and multiple versions of Windows on Intel. As long as you keep your Dockerfiles generic - and don't include OS-specific commands in RUN instructions - you can build your own multi-arch .NET Core apps based on Microsoft's images.

Going Forward - Docker Images for .NET 5

.NET 5 is the new evolution of .NET Core, and there are Docker images for the usual variants on MCR:

  • dotnet/runtime:5.0
  • dotnet/sdk:5.0
  • dotnet/aspnet:5.0

Note that "core" has been dropped from the image name - there's more information in this issue .NET Docker Repo Name Change.

Migrating .NET Core apps to .NET 5 should be a simple change, but remember that 5 is not an LTS version - you'll need to wait for .NET 6, which is LTS (see Microsoft's .NET Core and .NET 5 Support Policy.

Adventures in Docker: Coding on a Remote Browser

10 avril 2019 à 15:08
Adventures in Docker: Coding on a Remote Browser

This adventure lets you code on your normal dev machine from some other machine, using the browser. It's powered by Docker plus:

  • code-server - VS Code running in a container with browser access
  • ngrok - a public HTTP tunnel

And it's very simple. You just run code-server in a Docker container on your dev machine, mapping volumes for the data you want to be able to access and publishing a port. Then you expose that port to the Internet using ngrok, make a note of the URL and walk out the door.

Headless VS Code in Docker

code-server has done all the hard work here. They publish images to codercom/code-server on Docker Hub. There are only x64 Linux images right now.

Run the latest version with:

docker container run \  
 -d -p 8443:8443 \
 -v /scm:/scm \
 codercom/code-server:1.621 \
 --allow-http --no-auth

That command runs VS Code as a headless server in a background container. The options:

  • publish port 8443 on your local machine into the container
  • mount the local /scm directory into /scm on the container
  • run insecure with plain HTTP and no authentication.

You can run insecure on your home network (if you trust folks who can access your network), because you'll add security with ngrok.

Now you can browse to http://localhost:8443 and you have VS Code running in the browser:

Adventures in Docker: Coding on a Remote Browser

That volume mount means all of the code in the scm folder on my machine is accessible from the VS Code instance. And you can fire up a terminal in VS Code in the browser, which means you can do pretty much anything else you need to do. But remember the terminal is executing inside the container, so the environment is the container.

The code-server images comes with a few dev tools installed, like Git and OpenSSL. But there are no dev toolkits, so you can't actually compile or run any code... Unless you're using multi-stage Dockerfiles and official images with SDKs installed. Then all you need is Docker.

Headless VS Code with Docker

code-server doesn't have the Docker CLI installed, but I've added that in my fork. So you can run my version and mount the local Docker socket as a volume, meaning you can use docker commands inside the browser-based VS Code instance:

docker container run \  
 -d -p 8443:8443 \
 -v /scm:/scm \
 -v /var/run/docker.sock:/var/run/docker.sock \
 --network code-server \
 sixeyed/code-server:1.621 \
 --allow-http --no-auth

(I'm also using an explicit Docker network here which I created with docker network create code-server. You'll see why in a moment).

Now you can refresh your browser at http://localhost:8443, open up a terminal and run all the docker commands you like (with sudo). The Docker CLI inside the container is connected to the Docker Engine which is running the container.

Let's try out the .NET Core 3.0 preview. You can run these commands in VS Code on the browser. They all execute inside the container:

git clone https://github.com/sixeyed/whoami-dotnet.git  
cd whoami-dotnet  
sudo docker image build -t sixeyed/whoami-dotnet:3.0-linux-amd64 .  
sudo docker container run -d \  
 --network code-server --name whoami \
 sixeyed/whoami-dotnet:3.0-linux-amd64

Now the whoami container is running in the same Docker network as the code-server container, so you can reach it by the container name:

curl http://whoami  

And here it is for real:

Adventures in Docker: Coding on a Remote Browser

Now this is a usable development environment. The multi-stage Dockerfile I've built starts with a build stage that uses an image with the .NET Core SDK, so there's no need to install any tools in the dev environment. You can do the same with Java, Go etc. - they all have official build images on Docker Hub.

And the final step is to make it publicly available through ngrok.

Remote Headless VS Code with Docker

Sign up for an ngrok account, and follow the setup instructions to install the software and apply your credentials. Now you can expose any local port through a public Internet tunnel - just by running something like ngrok http 8443.

But you can do more with ngrok. This command sets up a tunnel for my VS Code server with HTTPS and basic authentication:

ngrok http -bind-tls=true -auth="elton:DockerCon" 8443  

You'll see output like this, telling you the public URL for your tunnel and some stats about who's using it:

Adventures in Docker: Coding on a Remote Browser

The Forwarding line tells you the public URL and the local port it's forwarding. Mine is https://112f7fb1.ngrok.io (you can use custom domains instead of the random ones). That endpoint is HTTPS so it's secure, and it's using basic auth so you'll need the username and password you specified in the ngrok command:

Adventures in Docker: Coding on a Remote Browser

Now you can access the headless VS Code instance running on your dev machine from anywhere on the Internet. Browser sessions are separate, so you can even have multiple people doing different things on the same remote code server:

Adventures in Docker: Coding on a Remote Browser

ngrok collects metrics while it's running, and there's an admin portal you can browse to locally - it shows you all the requests and responses the tunnel has handled:

Adventures in Docker: Coding on a Remote Browser

What about Windows?

I've only had a quick look, but it seems like this could work on Windows. ngrok already has Windows support, and it should just mean packaging code-server with a different Dockerfile.

Sounds like a nice weekend project for someone. Docker on Windows - second edition! will help :)

❌
❌