Scott Hanselman

Trying out new .NET Core Alpine Docker Images

November 22, '17 Comments [20] Posted in Docker | DotNetCore | Open Source
Sponsored By

Docker ContainersI blogged recently about optimizing .NET and ASP.NET Docker files sizes. .NET Core 2.0 has previously been built on a Debian image but today there is preview image with .NET Core 2.1 nightlies using Alpine. You can read about the announcement here about this new Alpine preview image. There's also a good rollup post on .NET and Docker.

They have added two new images:

  • 2.1-runtime-alpine
  • 2.1-runtime-deps-alpine

Alpine support is part of the .NET Core 2.1 release. .NET Core 2.1 images are currently provided at the microsoft/dotnet-nightly repo, including the new Alpine images. .NET Core 2.1 images will be promoted to the microsoft/dotnet repo when released in 2018.

NOTE: The -runtime-deps- image contains the dependancies needed for a .NET Core application, but NOT the .NET Core runtime itself. This is the image you'd use if your app was a self-contained application that included a copy of the .NET Core runtime. This is apps published with -r [runtimeid]. Most folks will use the -runtime- image that included the full .NET Core runtime. To be clear:

- The runtime image contains the .NET Core runtime and is intended to run Framework-Dependent Deployed applications - see sample

- The runtime-deps image contains just the native dependencies needed by .NET Core and is intended to run Self-Contained Deployed applications - see sample

It's best with .NET Core to use multi-stage build files, so you have one container that builds your app and one that contains the results of that build. That way you don't end up shipping an image with a bunch of SDKs and compilers you don't need.

NOTE: Read this to learn more about image versions in Dockerfiles so you can pick the right tag and digest for your needs. Ideally you'll pick a docker file that rolls forward to include the latest servicing patches.

Given this docker file, we build with the SDK image, then publish, and the result is about 219megs.

FROM microsoft/dotnet:2.0-sdk as builder  

RUN mkdir -p /root/src/app/dockertest
WORKDIR /root/src/app/dockertest

COPY dockertest.csproj .
RUN dotnet restore ./dockertest.csproj

COPY . .
RUN dotnet publish -c release -o published

FROM microsoft/dotnet:2.0.0-runtime

WORKDIR /root/
COPY --from=builder /root/src/app/dockertest/published .
ENV ASPNETCORE_URLS=http://+:5000
EXPOSE 5000/tcp
CMD ["dotnet", "./dockertest.dll"]

Then I'll save this as Dockerfile.debian and build like this:

> docker build . -t shanselman/dockertestdeb:0.1 -f dockerfile.debian

With a standard ASP.NET app this image ends up being 219 megs.

Now I'll just change one line, and use the 2.1 alpine runtime

FROM microsoft/dotnet-nightly:2.1-runtime-alpine

And build like this:

> docker build . -t shanselman/dockertestalp:0.1 -f dockerfile.alpine

and compare the two:

> docker images | find /i "dockertest"
shanselman/dockertestalp 0.1 3f2595a6833d 16 minutes ago 82.8MB
shanselman/dockertestdeb 0.1 0d62455c4944 30 minutes ago 219MB

Nice. About 83 megs now rather than 219 megs for a Hello World web app. Now the idea of a microservice is more feasible!

Please do head over to the GitHub issue here https://github.com/dotnet/dotnet-docker-nightly/issues/500 and offer your thoughts and results as you test these Alpine images. Also, are you interested in a "-debian-slim?" It would be halfway to Alpine but not as heavy as just -debian.

Lots of great stuff happening around .NET and Docker. Be sure to also check out Jeff Fritz's post on creating a minimal ASP.NET Core Windows Container to see how you can squish .(full) Framework applications running on Windows containers as well. For example, the Windows Nano Server images are just 93 megs compressed.


Sponsor: Get the latest JetBrains Rider preview for .NET Core 2.0 support, Value Tracking and Call Tracking, MSTest runner, new code inspections and refactorings, and the Parallel Stacks view in debugger.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

Docker and Linux Containers on Windows, with or without Hyper-V Virtual Machines

November 20, '17 Comments [38] Posted in Docker | Win10
Sponsored By

Containers are lovely, in case you haven't heard. They are a nice and clean way to get a reliable and guaranteed deployment, no matter the host system.

If I want to run my my ASP.NET Core application, I can just type "docker run -p 5000:80 shanselman/demos" at the command line, and it'll start up! I don't have any concerns that it won't run. It'll run, and run well.

Some containers naysayers say , sure, we could do the same thing with Virtual Machines, but even today, a VHD (virtual hard drive) is rather an unruly thing and includes a ton of overhead that a container doesn't have. Containers are happening and you should be looking hard at them for your deployments.

docker run shanselman/demos

Historically on Windows, however, Linux Containers run inside a Hyper-V virtual machine. This can be a good thing or a bad thing, depending on what your goals are. Running Containers inside a VM gives you significant isolation with some overhead. This is nice for Servers but less so for my laptop. Docker for Windows hides the VM for the most part, but it's there. Your Container runs inside a Linux VM that runs within Hyper-V on Windows proper.

HyperV on Windows

With the latest version of Windows 10 (or 10 Server) and the beta of Docker for Windows, there's native Linux Container support on Windows. That means there's no Virtual Machine or Hyper-V involved (unless you want), so Linux Containers run on Windows itself using Windows 10's built in container support.

For now you have to switch "modes" between Hyper V and native Containers, and you can't (yet) run Linux and Windows Containers side by side. The word on the street is that this is just a point in time thing, and that Docker will at some point support running Linux and Windows Containers in parallel. That's pretty sweet because it opens up all kinds of cool hybrid scenarios. I could run a Windows Server container with an .NET Framework ASP.NET app that talks to a Linux Container running Redis or Postgres. I could then put them all up into Kubernetes in Azure, for example.

Once I've turned Linux Containers on Windows on within Docker, everything just works and has one less moving part.

Linux Containers on Docker

I can easily and quickly run busybox or real Ubuntu (although Windows 10 already supports Ubuntu natively with WSL):

docker run -ti busybox sh

More useful even is to run the Azure Command Line with no install! Just "docker run -it microsoft/azure-cli" and it's running in a Linux Container.

Azure CLI in a Container

I can even run nyancat! (Thanks Thomas!)

docker run -it supertest2014/nyan

nyancat!

Speculating - I look forward to the day I can run "minikube start --vm-driver="windows" (or something) and easily set up a Kubernetes development system locally using Windows native Linux Container support rather than using Hyper-V Virtual Machines, if I choose to.


Sponsor: Why miss out on version controlling your database? It’s easier than you think because SQL Source Control connects your database to the same version control tools you use for applications. Find out how.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

Optimizing ASP.NET Core Docker Image sizes

October 31, '17 Comments [8] Posted in Docker | DotNetCore | Open Source
Sponsored By

ASP.NET Core on KubernetesThere is a great post from Steve Laster in 2016 about optimizing ASP.NET Docker Image sizes. Since then Docker has added multi-stage build files so you can do more in one Dockerfile...which feels like one step even though it's not. Containers are about easy and reliable deployment, and they're also about density. You want to use as little memory as possible, sure, but it also is nice to make them as small as possible so you're not spending time moving them around the network. The size of the image file can also affect startup time for the container. Plus it's just tidy.

I've been building a little 6 node Raspberry Pi (ARM) Kubenetes Cluster on my desk - like you do - this week, and I noticed that my image sizes were a little larger than I'd like. This is a bigger issue because it's a relatively low-powered system, but again, why carry around x unnecessary megabytes if you don't have to?

Alex Ellis has a great blog on building .NET Core apps for Raspberry Pi along with a YouTube video. In his video and blog he builds a "Console.WriteLine()" console app, which is great for OpenFaas (open source serverless platform) but I wanted to also have ASP.NET Core apps on my Raspberry Pi k8s cluster. He included this as a "challenge" in his blog, so challenge accepted! Thanks for all your help and support, Alex!

ASP.NET Core on Docker (on ARM)

First I make a basic ASP.NET Core app. I could do a Web API, but this time I'll do an MVC one with Razor Pages. To be clear, they are the same thing just with different starting points. I can always add pages or add JSON to either, later.

I start with "dotnet new mvc" (or dotnet new razor, etc). I'm going to be running this in Docker, managed by Kuberenetes, and while I can always change the WebHost in Program.cs to change how the Kestrel web server starts up like this:

WebHost.CreateDefaultBuilder(args)
.UseUrls(http://*:5000;http://localhost:5001;https://hostname:5002)

For Docker use cases it's easier to change the listening URL with an Environment Variable. Sure, it could be 80, but I like 5000. I'll set the ASPNETCORE_URLS environment variable to http://+:5000 when I make the Dockerfile.

Optimized MultiStage Dockerfile for ASP.NET

There's a number of "right" ways to do this, so you'll want to think about your scenarios. You'll see below that I'm using ARM (because Raspberry Pi) so if you see errors running your container like "qemu: Unsupported syscall: 345" then you're trying to run an ARM image on x86/x64. I'm going to be building an ARM container from Windows but I can't run it here. I have to push it to a container registry and then tell my Raspberry Pi cluster to pull it down and THEN it'll run, over there.

Here's what I have so far. NOTE there are some things commented out, so be conscious. This is/was a learning exercise for me. Don't you copy/paste unless you know what's up! And if there's a mistake, here's a GitHub Gist of my Dockerfile for you to change and improve.

It's important to understand that .NET Core has an SDK with build tools and development kits and compilers and stuff, and then it has a runtime. The runtime doesn't have the "make an app" stuff, it only has the "run an app stuff." There is not currently an SDK for ARM so that's a limitation that we are (somewhat elegantly) working around with the multistage build file. But, even if there WAS an SDK for ARM, we'd still want to use a Dockerfile like this because it's more efficient with space and makes a smaller image.

Let's break this down. There are two stages. The first FROM is the SDK image that builds the code. We're doing the build inside Docker - which is lovely, and  great reliable way to do builds.

PRO TIP: Docker is smart about making intermediate images and doing the least work, but it's useful if we (the authors) do the right thing as well to help it out.

For example, see where we COPY the .csproj over and then do a "dotnet restore"? Often you'll see folks do a "COPY . ." and then do a restore. That doesn't allow Docker to detect what's changed and you'll end up paying for the restore on EVERY BUILD.

By making this two steps - copy the project, restore, copy the code, this means your "dotnet restore" intermediate step will be cached by Docker and things will be WAY faster.

After you build, you'll do a publish. If you know the destination like I do (linux-arm) you can do a RID (runtime id) publish that is self-contained with -r linux-arm (or debian, or whatever) and you'll get a complete self-contained version of your app.

Otherwise, you can just publish your app's code and use a .NET Core runtime image to run it. Since I'm using a complete self-contained build for this image, it would be overkill to ALSO include the .NET runtime. If you look at the Docker hub for Microsoft/dotnet You'll see images called "deps" for "dependencies." Those are images that sit on top of debian that include the things .NET needs to run - but not .NET itself.

The stack of images looks generally like this (for example)

  • FROM debian:stretch
  • FROM microsoft/dotnet:2.0-runtime-deps
  • FROM microsoft/dotnet:2.0-runtime

So you have your base image, your dependencies, and your .NET runtime. The SDK image would include even more stuff since it needs to build code. Again, that's why we use that for the "as builder" image and then copy out the results of the compile and put them in another runtime image. You get the best of all worlds.

FROM microsoft/dotnet:2.0-sdk as builder  

RUN mkdir -p /root/src/app/aspnetcoreapp
WORKDIR /root/src/app/aspnetcoreapp

#copy just the project file over
# this prevents additional extraneous restores
# and allows us to re-use the intermediate layer
# This only happens again if we change the csproj.
# This means WAY faster builds!
COPY aspnetcoreapp.csproj .
#Because we have a custom nuget.config, copy it in
COPY nuget.config .
RUN dotnet restore ./aspnetcoreapp.csproj

COPY . .
RUN dotnet publish -c release -o published -r linux-arm

#Smaller - Best for apps with self-contained .NETs, as it doesn't include the runtime
# It has the *dependencies* to run .NET Apps. The .NET runtime image sits on this
FROM microsoft/dotnet:2.0.0-runtime-deps-stretch-arm32v7

#Bigger - Best for apps .NETs that aren't self-contained.
#FROM microsoft/dotnet:2.0.0-runtime-stretch-arm32v7

# These are the non-ARM images.
#FROM microsoft/dotnet:2.0.0-runtime-deps
#FROM microsoft/dotnet:2.0.0-runtime

WORKDIR /root/
COPY --from=builder /root/src/app/aspnetcoreapp/published .
ENV ASPNETCORE_URLS=http://+:5000
EXPOSE 5000/tcp
# This runs your app with the dotnet exe included with the runtime or SDK
#CMD ["dotnet", "./aspnetcoreapp.dll"]
# This runs your self-contained .NET Core app. You built with -r to get this
CMD ["./aspnetcoreapp"]

Notice also that I have a custom nuget.config, so if you do also you'll need to make sure that's available at build time for dotnet restore to pick up all packages.

I've included by commented out a bunch of the FROMs in the second stage. I'm using just the ARM one, but I wanted you to see the others.

Once we have the code we build copied into our runtime image, we set our environment variable so our all listens on port 5000 internally (remember that from above?) Then we run our app. Notice that you can run it with "dotnet foo.dll" if you have the runtime, but if you are like me and using a self-contained build, then you'll just run "foo."

To sum up:

  • Build with FROM microsoft/dotnet:2.0-sdk as builder
  • Copy the results out to a runtime
  • Use the right runtime FROM for you
    • Right CPU architecture?
    • Using the .NET Runtime (typical) or using a self-contained build (less so)
  • Listening on the right port (if a web app)?
  • Running your app successfully and correctly?
  • Do you have a .dockerignore? Super important for .NET Builds, as you don't' want to copy over /obj, /bin, etc, but you do want /published.
    obj/
    bin/
    !published/

Optimizing a little more

There are a few pre-release "Tree Trimming" tools that can look at your app and remove code and binaries that you are not calling. I included Microsoft.Packaging.Tools.Trimming as well to try it out and get even more unused code out of my final image by just adding a package to my project.

Step 8/14 : RUN dotnet publish -c release -o published -r linux-arm /p:LinkDuringPublish=true
---> Running in 39404479945f
Microsoft (R) Build Engine version 15.4.8.50001 for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.

Trimmed 152 out of 347 files for a savings of 20.54 MB
Final app size is 33.56 MB
aspnetcoreapp -> /root/src/app/aspnetcoreapp/bin/release/netcoreapp2.0/linux-arm/aspnetcoreapp.dll
Trimmed 152 out of 347 files for a savings of 20.54 MB
Final app size is 33.56 MB

If you run docker history on your final image you can see exactly where the size comes from. If/when Microsoft switches from a Debian base image to an Alpine one, this should get even smaller.

C:\Users\scott\Desktop\k8s for pi\aspnetcoreapp>docker history c60
IMAGE CREATED CREATED BY SIZE COMMENT
c6094ca46c3b 3 minutes ago /bin/sh -c #(nop) CMD ["dotnet" "./aspnet... 0B
b7dfcf137587 3 minutes ago /bin/sh -c #(nop) EXPOSE 5000/tcp 0B
a5ba51b91d9d 3 minutes ago /bin/sh -c #(nop) ENV ASPNETCORE_URLS=htt... 0B
8742269735bc 3 minutes ago /bin/sh -c #(nop) COPY dir:cc64bd3b9bacaeb... 56.5MB
28c008e38973 3 minutes ago /bin/sh -c #(nop) WORKDIR /root/ 0B
4bafd6e2811a 4 hours ago /bin/sh -c apt-get update && apt-get i... 45.4MB
<missing> 3 weeks ago /bin/sh -c #(nop) CMD ["bash"] 0B
<missing> 3 weeks ago /bin/sh -c #(nop) ADD file:8b7cf813a113aa2... 85.7MB

Here is the evolution of my Dockerfile as I made changes and the final result got smaller and smaller. Looks like 45 megs trimmed with a little work or about 20% smaller.

C:\Users\scott\Desktop\k8s for pi\aspnetcoreapp>docker images | find /i "aspnetcoreapp"
shanselman/aspnetcoreapp 0.5 c6094ca46c3b About a minute ago 188MB
shanselman/aspnetcoreapp 0.4 083bfbdc4e01 12 minutes ago 196MB
shanselman/aspnetcoreapp 0.3 fa053b4ee2b4 About an hour ago 199MB
shanselman/aspnetcoreapp 0.2 ba73f14e29aa 4 hours ago 207MB
shanselman/aspnetcoreapp 0.1 cac2f0e3826c 3 hours ago 233MB

Later I'll do a blog post where I put this standard ASP.NET Core web app into Kubernetes using this YAML description and scale it out on the Raspberry Pi. I'm learning a lot! Thanks to Alex Ellis and Glenn Condron and Jessie Frazelle for their time!


Sponsor: Create powerful Web applications to manage each step of a document’s life cycle with DocuVieware HTML5 Viewer and Document Management Kit. Check our demos to acquire, scan, edit, annotate 100+ formats, and customize your UI!

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

.NET and Docker

June 6, '17 Comments [17] Posted in Docker | DotNetCore
Sponsored By

“Container Ship” by NOAA's National Ocean Service is licensed under CC BY 2.0.NET and .NET Core (and Windows!) have been getting better and better with Docker. I run Docker for Windows as it supports both Linux Containers and Windows Containers. They have both a Stable and Edge channel. The Edge (Beta) channel is regularly updated and, as a rule, gets better and better in the year I've been running it.

As a slightly unrelated side note, I'm also running Docker on my Synology NAS with a number of containers, as well as .NET Core (my Nas is an Intel chip), Minecraft Server, Plex Server, and CrashPlan.

NOTE: Docker for Windows requires 64bit Windows 10 Pro and Microsoft Hyper-V. Please see What to know before you install for a full list of prerequisites.

The .NET Team at Microsoft has been getting their dockerfiles in order and organized. It can seem initially the opposite, with lots of cryptic tags and names, but there's a clear method you can read about here.

They publish their Docker images in a few different repositories on Docker Hub. It’s important to segment images so that they are easier to find, both on the Docker Hub website as well as with the docker search command.

There's also some samples at:

The samples are super easy to try out - STOP READING AND TRY THIS NOW. ;)

I'm always impressed with a nice asynchronous ASCII Progress bar. I'm easy to impress. This is a "hello world" sample with a surprise ASCII art. I won't spoil for you.

C:\Users\scott\Desktop> docker run microsoft/dotnet-samples
Unable to find image 'microsoft/dotnet-samples:latest' locally
latest: Pulling from microsoft/dotnet-samples
10a267c67f42: Downloading [========> ] 9.19MB/52.58MB
7e1a7ec87c21: Downloading [======================> ] 10.8MB/18.59MB
923d0cd2ed37: Download complete
7c523004cf83: Downloading [=========> ] 6.144MB/33.07MB
f3582118a43a: Waiting
c27ef6b597a0: Waiting

All the images are managed and maintained on GitHub so you can get involved if you're not digging the images or files.

One interesting thing to point out is the difference between dev images and production images, as well as images you'd use in CI/CD (Build Server) situations to build other images. Here are some examples from GitHub:

Development

  • dotnetapp-dev - This sample is good for development and building since it relies on the .NET Core SDK image. It performs dotnet commands on your behalf, reducing the time it takes to create Docker images (assuming you make changes and then test them in a container, iteratively).

Production

  • dotnetapp-prod - This sample is good for production since it relies on the .NET Core Runtime image, not the larger .NET Core SDK image. Most apps only need the runtime, reducing the size of your application image.
  • dotnetapp-selfcontained - This sample is also good for production scenarios since it relies on an operating system image (without .NET Core). Self-contained .NET Core apps include .NET Core as part of the app and not as a centrally installed component in a base image.
  • dotnetapp-current - This sample demonstrates how to configure an application to use the .NET Core 1.1 image. Both the .csproj and the Dockerfile have been updated to depend on .NET Core 1.1. This sample is the same as dotnetapp-prod with the exception of relying on a later .NET Core version.
  • aspnetapp - This samples demonstrates a Dockerized ASP.NET Core Web App

There's great Docker support in VS Code, Visual Studio 2017, and Visual Studio for Mac (the Preview channel). With VS and Docker on Windows you can even F5 (debug) into a Linux Container.

Some of you may have .NET Framework apps running in Virtual Machines that you'd love to get moved over to a container infrastructure. There's a tool called Image2Docker that Docker maintains that might help. It helps migrate VMs to Containers. Check out the Image2Docker DockerCon talk or read Docker’s Convert ASP.NET Web Servers To Docker with ImageDocker to learn more.

“Container Ship” by NOAA's National Ocean Service is licensed under CC BY 2.0


Sponsor: Check out Seq: simple centralized logging, on your infrastructure, with great support for ASP.NET Core and Serilog. Download version 4.0.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

ZEIT now deployments of open source ASP.NET Core web apps with Docker

March 15, '17 Comments [13] Posted in ASP.NET | Docker | DotNetCore
Sponsored By

ZEIT is a new cloud service and "now" is the name of their deployment tool. ZEIT World is their DNS service. If you head over to https://zeit.co/ you'll see a somewhat cryptic animated gif that shows how almost impossibly simple it is to deploy a web app with ZEIT now.

ZEIT works with .NET Core and ASP.NET

You can make a folder, put an index.html (for example) in it and just run "now." You'll automatically get a website with an autogenerated name and it'll be live. It's probably the fastest and easiest deploy I've ever seen. Remember when Heroku (then Azure, then literally everyone) started using git for deployment? Clearly being able to type "now" and just get a web site on the public internet was the next step. (Next someone will make "up" which will then get replaced with just pressing ENTER on an empty line! ;) )

Jokes aside, now is clean and easy. I appreciate their organizational willpower to make an elegant and simple command line tool. I suspect it's harder than it looks to keep things simple.

All of their examples use JavaScript and node.js, but they also support Docker, which means they support open source ASP.NET Core on .NET Core! But do they know they do? ;) Let's find out.

And more importantly, how easy is it? Can I take a site from concept to production in minutes? Darn tootin' I can.

First, make a quick ASP.NET Core app. I'll use the MVC template with Bootstrap.

C:\Users\scott\zeitdotnet>dotnet new mvc
Content generation time: 419.5337 ms
The template "ASP.NET Core Web App" created successfully.

I'll do a quick dotnet restore to get the packages for my project.

C:\Users\scott\zeitdotnet>dotnet restore
Restoring packages for C:\Users\scott\zeitdotnet\zeitdotnet.csproj...
Generating MSBuild file C:\Users\scott\zeitdotnet\obj\zeitdotnet.csproj.nuget.g.props.
Generating MSBuild file C:\Users\scott\zeitdotnet\obj\zeitdotnet.csproj.nuget.g.targets.
Writing lock file to disk. Path: C:\Users\scott\zeitdotnet\obj\project.assets.json
Restore completed in 2.93 sec for C:\Users\scott\zeitdotnet\zeitdotnet.csproj.

NuGet Config files used:
C:\Users\scott\AppData\Roaming\NuGet\NuGet.Config
C:\Program Files (x86)\NuGet\Config\Microsoft.VisualStudio.Offline.config

Feeds used:
https://api.nuget.org/v3/index.json
C:\LocalNuGet
C:\Program Files (x86)\Microsoft SDKs\NuGetPackages\

Now I need to add a Dockerfile. I'll make one in the root that looks like this:

FROM microsoft/aspnetcore
LABEL name="zeitdotnet"
ENTRYPOINT ["dotnet", "zeitdotnet.dll"]
ARG source=.
WORKDIR /app
EXPOSE 80
COPY $source .

Note that I could have ZEIT build my app for me if I used the aspnetcore Dockerfile that includes the .NET Core SDK, but that would not only make my deployment longer, it would also make my docker images a LOT larger. I want to include JUST the .NET Core runtime in my image, so I'll build and publish locally.

ZEIT now is going to need to see my Dockerfile, and since I want my app to include the binaries (I don't want to ship my source in the Docker image up to ZEIT) I need to mark my Dockerfile as "Content" and make sure it's copied to the publish folder when my app is built and published.

<ItemGroup>
  <None Remove="Dockerfile" />
</ItemGroup>

<ItemGroup>
  <Content Include="Dockerfile">
    <CopyToOutputDirectory>Always</CopyToOutputDirectory>
  </Content>
</ItemGroup>

I'll add this my project's csproj file. If I was using Visual Studio, this is the same as right clicking on the Properties of the Dockerfile, setting it to Content and then "Always Copy to Output Directory."

Now I'll just build and publish to a folder with one command:

C:\Users\scott\zeitdotnet>dotnet publish
Microsoft (R) Build Engine version 15.1.548.43366
Copyright (C) Microsoft Corporation. All rights reserved.

zeitdotnet -> C:\Users\scott\zeitdotnet\bin\Debug\netcoreapp1.1\zeitdotnet.dll

And finally, from the .\bin\Debug\netcoreapp1.1\ folder I run "now." (Note that I've installed now and signed up for their service, of course.)

C:\Users\scott\zeitdotnet\bin\Debug\netcoreapp1.1\publish>now
> Deploying ~\zeitdotnet\bin\Debug\netcoreapp1.1\publish
> Ready! https://zeitdotnet-gmhcxevqkf.now.sh (copied to clipboard) [3s]
> Upload [====================] 100% 0.0s
> Sync complete (196.18kB) [2s]
> Initializing…
> Building
> ▲ docker build
> ---> 035a0a1401c3
> Removing intermediate container 289b9e4ce5d9
> Step 6 : EXPOSE 80
> ---> Running in efb817308333
> ---> fbac2aaa3039
> Removing intermediate container efb817308333
> Step 7 : COPY $source .
> ---> ff009cfc48ea
> Removing intermediate container 8d650c1867cd
> Successfully built ff009cfc48ea
> ▲ Storing image
> ▲ Deploying image
> Deployment complete!

Now has put the generated URL in my clipboard (during deployment you'll get redirected to a lovely status page) and when it's deployed I can visit my live site. But, that URL is not what I want. I want to use a custom URL.

I can take one of my domains and set it up with ZEIT World's DNS but I like DNSimple (ref).

I can add my domain as an external one after adding a TXT record to my DNS to verify I own it. Then I setup a CNAME to point my subdomain to alias.zeit.co.

C:\Users\scott\Desktop\zeitdotnet>now alias https://zeitdotnet-gmhcxevqkf.now.sh http://zeitdotnet.hanselman.com
> zeitdotnet.hanselman.com is a custom domain.
> Verifying the DNS settings for zeitdotnet.hanselman.com (see https://zeit.world for help)
> Verification OK!
> Provisioning certificate for zeitdotnet.hanselman.com
> Success! Alias created:
https://zeitdotnet.hanselman.com now points to https://zeitdotnet-gmhcxevqkf.now.sh [copied to clipboard]

And that's it. It even has a nice SSL certificate that they applied for me. It doesn't terminate to SSL all the way into the docker container's Kestral web server, but for most things that aren't banking it'll be just fine.

All in all, a lovely experience. Here's my Hello World ASP.NE Core app running in ZEIT and deployed with now  at http://zeitdotnet.hanselman.com (if you are visiting this long after this was published, this sample MAY be gone.)

I am still learning about this (this whole exercise was about 30 total minutes and asking Glenn Condron a docker question) so I'm not clear how this would work in a large multi-container deployment, but as long as your site is immutable (don't write to the container's local disk!) ZEIT says it will scale your single containers. Perhaps docker-compose support is coming?


Sponsor: Did you know VSTS can integrate closely with Octopus Deploy? Join Damian Brady and Brian A. Randell as they show you how to automate deployments from VSTS to Octopus Deploy, and demo the new VSTS Octopus Deploy dashboard widget. Register now!

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb
Page 1 of 2 in the Docker category Next Page

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.