.NET Core容器化@Docker

舒适提示:本文略长,预计读完本文需耗时8mins。若要一步一步跟随实操演练,预计耗时30mins,请泡上一杯咖啡,找个安静的角落,打开电脑动手演练,效果更佳。 html

# 1. 引言 咱们知道. NET Core最大的特性之一就是跨平台,而对于跨平台,彷佛你们印象中就是能够在非Windows系统上部署运行。而至于如何操做,可能就有所欠缺。那这一节咱们就结合简单实例一步一步教你如何借助Docker来容器化 .NET Core应用,以完成跨平台的构建和部署。linux

# 2. 环境准备 自从玩.NET就一直和Windows系统打交道,若是还基于Windows来展开本节内容,不就跑题了吗?!那我们就切换到Linux系统。 若是没有Linux基础和Docker基础,请自觉完成如下两个实验: 腾讯云开发者实验室:Linux 基础入门 腾讯云开发者实验室:搭建 Docker 环境git

完成了以上两个实验后,咱们就离Linux的世界更近一步。 由于后续是基于Linux-CentOS系统进行实操演练,没有Linux上机环境的,能够考虑从腾讯云实验室列表找一个CentOS相关的实验项目做为本文的演练环境。web

# 3. Docker简介 在开始以前,有必要对Docker作一下简单了解,能够参考个人上一篇文章Hello Docker。 这里就简要的再重复一下。 Docker是用Go语言编写基于Linux操做系统的一些特性开发的,其提供了操做系统级别的抽象,是一种容器管理技术,它隔离了应用程序对基础架构(操做系统等)的依赖。相较于虚拟机而言,Docker共享的是宿主机的硬件资源,使用容器来提供独立的运行环境来运行应用。虚拟机则是基于Supervisor(虚拟机管理程序)使用虚拟化技术来提供隔离的虚拟机,在虚拟机的操做系统上提供运行环境!虽然二者都提供了很好的资源隔离,但很明显Docker的虚拟化开销更低! Docker涉及了三个核心概念:Register、Image、Container。docker

1. Registry:仓库。用来存储Docker镜像,好比Docker官方的Docker Hub就是一个公开的仓库,在上面咱们能够下载咱们须要的镜像。 2. Image:镜像。开发人员建立一个应用程序或服务,并将它及其依赖关系打包到一个容器镜像中。镜像是应用程序的配置及其依赖关系的静态形式。 3. Container:容器。Container是镜像的运行实例,它是一个隔离的、资源受控的可移植的运行时环境,其中包含操做系统、须要运行的程序、运行程序的相关依赖、环境变量等。json

它们三者的相互做用关系是: 当咱们执行Docker pull或Docker run命令时,若本地无所需的镜像,那么将会从仓库(通常为DockerHub)下载(pull)一个镜像。Docker执行run方法获得一个容器,用户在容器里执行各类操做。Docker执行commit方法将一个容器转化为镜像。Docker利用login、push等命令将本地镜像推送(push)到仓库。其余机器或服务器上就可使用该镜像去生成容器,进而运行相应的应用程序。ubuntu

4. 安装Docker

4.1. 使用脚本自动安装Docker

在测试或开发环境中 Docker 官方为了简化安装流程,提供了一套便捷的安装脚本,CentOS系统上可使用这套脚本安装:浏览器

//使用脚本自动化安装Docker
$ curl -fsSL get.docker.com -o get-docker.sh
$ sudo sh get-docker.sh --mirror Aliyun
复制代码

4.2. 启动Docker

执行这个命令后,脚本就会自动的将一切准备工做作好,而且把 Docker CE 的 Edge 版本安装在系统中。bash

//启动 Docker CE
$ sudo systemctl enable docker
$ sudo systemctl start docker
//查看docker版本
$ sudo docker -v
Docker version 1.12.6, build ec8512b/1.12.6
复制代码

4.3 测试Docker是否正确安装

命令行执行docker run hello-world服务器

$ docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
ca4f61b1923c: Pull complete
Digest: sha256:be0cd392e45be79ffeffa6b05338b98ebb16c87b255f48e297ec7f98e123905c
Status: Downloaded newer image for hello-world:latest
Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
(amd64)
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.
To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash
Share images, automate workflows, and more with a free Docker ID:
https://cloud.docker.com/
For more examples and ideas, visit:
https://docs.docker.com/engine/userguide/
复制代码

当执行docker run hello-world时,docker首先会从本地找hello-world的镜像,若是本地没有,它将会从默认的镜像仓库Docker Hub上拉取镜像。镜像拉取到本地后,就实例化镜像获得容器,输出Hello from Docker!

4.4. 配置镜像加速

由于默认的镜像仓库远在国外,拉取一个小的镜像时间还能够忍受,若拉取一个上G的镜像就有点太折磨人了,咱们使用DaoCloud镜像加速器来进行镜像加速。Linux上配置方法以下:

$ curl -sSL https://get.daocloud.io/daotools/set_mirror.sh | sh -s http://37bb3af1.m.daocloud.io`
$ sudo systemctl restart docker
复制代码

5. Hello Docker With .NET Core

Docker安装完毕,咱们来结合.NET Core玩一玩吧。

5.1. 拉取microsoft/dotnet镜像

命令行执行docker pull microsoft/dotnet,等几分钟后便可安装完毕,执行docker images能够看到本地已经包含microsoft/dotnetdocker.io/hello-world两个镜像。

5.2. 运行microsoft/dotnet镜像

使用docker run <image>能够启动镜像,经过指定参数-it以交互模式(进入容器内部)启动。依次执行如下命令:

//启动一个dotnet镜像
$ docker run -it microsoft/dotnet
//建立项目名为HelloDocker.Web的.NET Core MVC项目
dotnet new mvc -n HelloDocker.Web
//进入HelloDocker.Web文件夹
cd HelloDocker.Web
//启动.NET Core MVC项目
dotnet run
复制代码

运行结果以下所示:

[root@iZ288a3qazlZ ~]# docker run -it microsoft/dotnet
root@816b4e94de67:/# dotnet new mvc -n HelloDocker.Web
The template "ASP.NET Core Web App (Model-View-Controller)" was created successfully.
This template contains technologies from parties other than Microsoft, see https://aka.ms/template-3pn for details.

Processing post-creation actions...
Running 'dotnet restore' on HelloDocker.Web/HelloDocker.Web.csproj...
  Restoring packages for /HelloDocker.Web/HelloDocker.Web.csproj...
  Generating MSBuild file /HelloDocker.Web/obj/HelloDocker.Web.csproj.nuget.g.props.
  Generating MSBuild file /HelloDocker.Web/obj/HelloDocker.Web.csproj.nuget.g.targets.
  Restore completed in 1.83 sec for /HelloDocker.Web/HelloDocker.Web.csproj.
  Restoring packages for /HelloDocker.Web/HelloDocker.Web.csproj...
  Restore completed in 376.14 ms for /HelloDocker.Web/HelloDocker.Web.csproj.

Restore succeeded.

root@816b4e94de67:/# cd HelloDocker.Web
root@816b4e94de67:/HelloDocker.Web# dotnet run
warn: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[35]
      No XML encryptor configured. Key {727df196-978f-4df8-b3d3-e92a77e410ee} may be persisted to storage in unencrypted form.
Hosting environment: Production
Content root path: /HelloDocker.Web
Now listening on: http://localhost:5000
Application started. Press Ctrl+C to shut down.
复制代码

键盘按住Ctrl+C便可关闭应用,输入exit便可退出当前容器。

是否是简单的几步就完成了一个.NET Core MVC项目的建立和运行?!这个时候你可能会好奇,Linux宿主机上并无安装.NET Core SDK啊,MVC项目是如何建立的呢?这就是Docker神奇的地方,咱们从镜像仓库中拉取的dotnet镜像,包含了建立、构建、运行.NET Core项目所需的一切依赖和运行时环境。

退出容器以后,执行find -name HelloDocker.Web(查找HelloDocker.Web文件),咱们发现并无找到。这说明咱们刚才建立的.NET Core MVC项目是在容器内部建立的,是与宿主机彻底隔离的。这个时候你可能会想,每次都要在容器中安装源代码太不方便了,咱们能不能让容器运行咱们宿主机的源代码项目?嗯,这是个好问题。下面咱们就来解答这个问题。

5.3. 挂载源代码

为了在宿主机上建立.NET Core 项目,这个时候咱们就须要在Linux宿主机上安装.NET Core SDK。

5.3.1. 宿主机安装.NET Core SDK

步骤以下:

sudo rpm --import https://packages.microsoft.com/keys/microsoft.asc
sudo sh -c 'echo -e "[packages-microsoft-com-prod]\nname=packages-microsoft-com-prod \nbaseurl= https://packages.microsoft.com/yumrepos/microsoft-rhel7.3-prod\nenabled=1\ngpgcheck=1\ngpgkey=https://packages.microsoft.com/keys/microsoft.asc" > /etc/yum.repos.d/dotnetdev.repo'
sudo yum update
sudo yum install libunwind libicu
sudo yum install dotnet-sdk-2.1.3
复制代码

安装完毕后,咱们依次执行如下命令建立一个.NET Core MVC项目:

//回到根目录
$ cd $HOME
//建立demo文件夹
$ mkdir demo
$ cd demo
//建立项目名为HelloDocker.Web的.NET Core MVC项目
dotnet new mvc -n HelloDocker.Web
//进入HelloDocker.Web文件夹
cd HelloDocker.Web
//启动.NET Core MVC项目
dotnet run
复制代码

若是知道本机的ip地址的话(可使用ifconfig命令查询),直接浏览器访问http://<ip address>:5000便可访问咱们刚刚运行的MVC项目。

这一步咱们就在$HOME/demo/HelloDocker.Web目录下成功建立了MVC项目,下一步咱们就将该目录下的源码项目经过挂载的方式共享到容器中去。

5.3.2. 挂载宿主机项目到容器中

在启动Docker镜像时,Docker容许咱们经过使用-v参数挂载宿主机的文件到容器的指定目录下。换句话说,就至关于宿主机共享指定文件供容器去访问。废话很少说,实践出真知。

// 命令中的`\`结合`Enter`键构成换行符,容许咱们换行输入一个长命令。
$ docker run -it \
-v $HOME/demo/HelloDocker.Web:/app \
microsoft/dotnet:latest
复制代码

上面的命令就是把$HOME/demo/HelloDocker.Web文件夹下的文件挂载到容器的\app目录下。

[root@iZ288a3qazlZ HelloDocker.Web]# docker run -it \
> -v $HOME/demo/HelloDocker.Web:/app \
> microsoft/dotnet:latest
root@d70b327f4b7e:/# ls
app  bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
root@d70b327f4b7e:/# cd app
root@d70b327f4b7e:/app# ls
Controllers  HelloDocker.Web.csproj  Models  Program.cs  Startup.cs  Views  appsettings.Development.json  appsettings.json  bundleconfig.json  obj  wwwroot
root@d70b327f4b7e:/app# dotnet run
warn: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[35]
      No XML encryptor configured. Key {09a69edf-c1c5-4909-ad24-15a43a572fca} may be persisted to storage in unencrypted form.
Hosting environment: Production
Content root path: /app
Now listening on: http://localhost:5000
Application started. Press Ctrl+C to shut down.
复制代码

从上面的执行结果来看,容器内部中的app目录下包含了宿主机上的源码项目。 上面说到是以共享的形式,而不是容器拥有一份宿主机目录的拷贝,意味着,在宿主机上对目录的更改,会即时反应到容器中。但反过来,容器中对共享目录的更改,不会反应到宿主机上,否则就打破了容器具备的隔离特性。

经过这样一个简单场景,聪明的你是否会联想到这一场景在咱们平常编码的应用之处呢?是的,咱们能够用来持续构建(CI)。基本思路是,经过git clone源码到宿主机上,而后将源码目录挂载到容器中去进行构建。

5.4. 借助Dockerfile

Dockerfile用来定义你将要在容器中执行的系列操做。咱们来建立第一个Dockerfile:

//确保进入咱们建立的MVC项目目录中去
$ cd $HOME/demo/HelloDocker.Web
//使用touch命令建立Dockerfile
$ touch Dockerfile
//使用vi命令编辑Dockerfile
vi Dockerfile
复制代码

进入VI编辑界面后,复制如下代码,使用shift + Ins命令便可粘贴。而后按ESE退出编辑模式,按shift + :,输入wq便可保存并退出编辑界面。

FROM microsoft/dotnet:latest
WORKDIR /app
COPY . /app
RUN dotnet restore
EXPOSE 5000
ENV ASPNETCORE_URLS http://*:5000
ENTRYPOINT ["dotnet","run"]
复制代码

上面的命令我依次解释一下:

  1. 使用FROM指定容器使用的镜像
  2. 使用WORKDIR指定工做目录
  3. 使用COPY指令,复制当前目录(其中.即表明当前目录)到容器中的/app目录下
  4. 使用RUN命令指定容器中执行的命令
  5. 使用EXPOSE指定容器暴露的端口号
  6. 使用ENV指定环境参数,上面用来告诉.NETCore项目在全部网络接口上监听5000端口
  7. 使用ENTRYPOINT制定容器的入口点

Dockerfile就绪,咱们就能够将咱们当前项目打包成镜像以分发部署。 使用docker build -t <name> <path>指令打包镜像:

$ docker build -t hellodocker.web .
复制代码

以上命令就是告诉docker将当前目录打包成镜像,并命名为hellodocker.web。命令执行完毕,输入docker images便可看到咱们新打包的镜像。镜像建立完毕咱们就能够直接运行了:

docker run -d -p 80:5000 hellodocker.web
复制代码

上面的指令就是运行咱们新打包的镜像,并经过-p参数映射容器的5000到宿主机的80端口,其中-d参数告诉docker之后台任务形式运行镜像。由于80是默认的web端口,因此咱们经过浏览器直接访问ip便可访问到咱们容器中运行的MVC网站。或者经过curl -i http://localhost来验证。操做示例以下:

[root@iZ288a3qazlZ HelloDocker.Web]# docker build -t hellodocker.web .
Sending build context to Docker daemon   3.3 MB
Step 1 : FROM microsoft/dotnet:latest
 ---> 7d4dc5c258eb
Step 2 : WORKDIR /app
 ---> Using cache
 ---> 98d48a4e278c
Step 3 : COPY . /app
 ---> d5df216b274a
Removing intermediate container 0a70f0f2b681
Step 4 : RUN dotnet restore
 ---> Running in 0c8a9c4d5ba1
  Restore completed in 939.01 ms for /app/HelloDocker.Web.csproj.
  Restoring packages for /app/HelloDocker.Web.csproj...
  Restore completed in 1.38 sec for /app/HelloDocker.Web.csproj.
 ---> 479f6b5cc7f0
Removing intermediate container 0c8a9c4d5ba1
Step 5 : EXPOSE 5000
 ---> Running in f97feceb7f1b
 ---> 562a95328196
Removing intermediate container f97feceb7f1b
Step 6 : ENV ASPNETCORE_URLS http://*:5000
 ---> Running in 403d8e2e25a6
 ---> 16b7bd572410
Removing intermediate container 403d8e2e25a6
Step 7 : ENTRYPOINT dotnet run
 ---> Running in 0294f87ce3fd
 ---> 532e44a7fd54
Removing intermediate container 0294f87ce3fd
Successfully built 532e44a7fd54
[root@iZ288a3qazlZ HelloDocker.Web]# docker run -d -p 80:5000 hellodocker.web
9d28bb3fa553653e4c26bf727715c82a837a2c224a0942107f3fab08c0a2686d
[root@iZ288a3qazlZ HelloDocker.Web]# curl -i http://localhost
HTTP/1.1 200 OK
Date: Sat, 23 Dec 2017 14:23:15 GMT
Content-Type: text/html; charset=utf-8
Server: Kestrel
Transfer-Encoding: chunked
复制代码

至此,咱们借助Docker就完美的完成了.NET Core项目的容器化部署。

结束了?尚未!

我打包的镜像是保存在本地的,我如何把镜像部署到其余机器上呢?请继续看。

6. 推送镜像到仓库

在第三节中,咱们就简要介绍了,有个Registry是专门用来存储镜像的。请自行到Docker Hub注册个帐号,而后咱们把本地打包的镜像放到本身帐号下的仓库下不就得了?! 注册完毕后,执行docker login

[root@iZ288a3qazlZ HelloDocker.Web]# docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one. Username: shengjie Password: Login Succeeded [root@iZ288a3qazlZ HelloDocker.Web]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE hellodocker.web latest 532e44a7fd54 13 minutes ago 1.745 GB 复制代码

再执行docker push

$ docker push hellodocker.web
Error response from daemon: You cannot push a "root" repository. Please rename your repository to docker.io/<user>/<repo> (ex: docker.io/shengjie/hellodocker.web)
复制代码

推送失败,提示咱们的镜像命名不符规范。原来在推送以前要把镜像按<user>/<repo>格式来命名。那如何重命名呢,咱们用打标签的方式重命名:

$ docker tag hellodocker.web shengjie/hellodocker.web:v1
$ docker images
REPOSITORY                           TAG                 IMAGE ID            CREATED             SIZE
hellodocker.web                      latest              532e44a7fd54        35 minutes ago      1.745 GB
yanshengjie/hellodocker.web          v1                  532e44a7fd54        35 minutes ago      1.745 GB
$ docker push shengjie/hellodocker.web
The push refers to a repository [docker.io/shengjie/hellodocker.web]
774b128a8c4f: Pushed
7bf42a9b5527: Pushed
bd7f01c2dc6f: Pushed
....
复制代码

换一台机器,咱们直接执行如下命令,就完成了多重部署。

docker run -p 80:5000 <username>/hellodocker.web:v1
复制代码

7.最后

若是你一步一步跟着练习的话,相信你对Docker以及.NET Core的跨平台特性有了初步的理解,也相信你对Docker的Build, Ship, and Run Any App, Anywhere有了更深的体会。

本文的实战演练就先到这里,下一篇,咱们来看如何借助Docker完成.NET Core Web项目的分布式部署!!!

参考资料

Hello Docker HOSTING .NET CORE ON LINUX WITH DOCKER - A NOOB'S GUIDE Docker命令收集 Linux经常使用命令

相关文章
相关标签/搜索