.NET Core容器化@Docker
温馨提示:本文适合动手演练,效果更佳。
1. 引言
我们知道. NET Core最大的特性之一就是跨平台,而对于跨平台,似乎大家印象中就是可以在非Windows系统上部署运行。而至于如何操作,可能就有所欠缺。那这一节我们就结合简单实例一步一步教你如何借助Docker来容器化 .NET Core应用,以完成跨平台的构建和部署。
2. 环境准备
自从玩.NET就一直和Windows系统打交道,如果还基于Windows来展开本节内容,不就跑题了吗?!那咱们就切换到Linux系统。
如果没有Linux基础和Docker基础,请自觉完成以下两个实验:
腾讯云开发者实验室:Linux 基础入门
腾讯云开发者实验室:搭建 Docker 环境
完成了以上两个实验后,我们就离Linux的世界更近一步。
因为后续是基于Linux-CentOS系统进行实操演练,没有Linux上机环境的,可以考虑从腾讯云实验室列表找一个CentOS相关的实验项目作为本文的演练环境。
3. Docker简介
在开始之前,有必要对Docker做一下简单了解,可以参考我的上一篇文章Hello Docker。
这里就简要的再重复一下。
Docker是用Go语言编写基于Linux操作系统的一些特性开发的,其提供了操作系统级别的抽象,是一种容器管理技术,它隔离了应用程序对基础架构(操作系统等)的依赖。相较于虚拟机而言,Docker共享的是宿主机的硬件资源,使用容器来提供独立的运行环境来运行应用。虚拟机则是基于Supervisor(虚拟机管理程序)使用虚拟化技术来提供隔离的虚拟机,在虚拟机的操作系统上提供运行环境!虽然两者都提供了很好的资源隔离,但很明显Docker的虚拟化开销更低!
Docker涉及了三个核心概念:Register、Image、Container。
1. Registry:仓库。用来存储Docker镜像,比如Docker官方的Docker Hub就是一个公开的仓库,在上面我们可以下载我们需要的镜像。
2. Image:镜像。开发人员创建一个应用程序或服务,并将它及其依赖关系打包到一个容器镜像中。镜像是应用程序的配置及其依赖关系的静态形式。
3. Container:容器。Container是镜像的运行实例,它是一个隔离的、资源受控的可移植的运行时环境,其中包含操作系统、需要运行的程序、运行程序的相关依赖、环境变量等。
它们三者的相互作用关系是:
当我们执行Docker pull或Docker run命令时,若本地无所需的镜像,那么将会从仓库(一般为DockerHub)下载(pull)一个镜像。Docker执行run方法得到一个容器,用户在容器里执行各种操作。Docker执行commit方法将一个容器转化为镜像。Docker利用login、push等命令将本地镜像推送(push)到仓库。其他机器或服务器上就可以使用该镜像去生成容器,进而运行相应的应用程序。
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 版本安装在系统中。
//启动 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/dotnet
、docker.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"]
上面的命令我依次解释一下:
- 使用
FROM
指定容器使用的镜像 - 使用
WORKDIR
指定工作目录 - 使用
COPY
指令,复制当前目录(其中.
即代表当前目录)到容器中的/app目录下 - 使用
RUN
命令指定容器中执行的命令 - 使用
EXPOSE
指定容器暴露的端口号 - 使用
ENV
指定环境参数,上面用来告诉.NETCore项目在所有网络接口上监听5000端口 - 使用
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
shengjie/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使用Nginx完成.NET Core Web项目的反向代理!!!
参考资料
Hello Docker
HOSTING .NET CORE ON LINUX WITH DOCKER - A NOOB'S GUIDE
Docker命令收集
Linux常用命令
.NET Core容器化@Docker的更多相关文章
- .NET Core容器化之多容器应用部署@Docker-Compose
1.引言 紧接上篇.NET Core容器化@Docker,这一节我们先来介绍如何使用Nginx来完成.NET Core应用的反向代理,然后再介绍多容器应用的部署问题. 2. Why Need Ngin ...
- .NET Core容器化之多容器应用部署-使用Docker-Compose
原文补充: -- docker-compose.ymlversion: ' services: mvc-web: container_name: mvc.web.compose build: . re ...
- .NET Core容器化开发系列(零)——计划
.NET Core相当完善的跨平台特性以及其轻量化的底层接口为我们能顺畅进行微服务开发提供了非常棒的基础. 作为支撑微服务最常见的基础技术--容器化将是本系列的核心内容. 接下来我计划用一个月左右的时 ...
- AspNetCore容器化(Docker)部署(三) —— Docker Compose容器编排
一.前言 上一篇部署了一个最基础的helloworld应用,创建了两个容器和一个network,还算应付得过来. 如果该应用继续引入mysql.redis.job等若干服务,到时候发布一次得工作量之大 ...
- AspNetCore容器化(Docker)部署(一) —— 入门
一.docker注册安装 Windows Docker Desktop https://www.docker.com/products/docker-desktop Linux Docker CE h ...
- AspNetCore容器化(Docker)部署(二) —— 多容器通信
一.前言 着上一篇 AspNetCore容器化(Docker)部署(一) —— 入门,在单个容器helloworld的基础上引入nginx反向代理服务器组成多容器应用. 二.配置反向代理转接 配置转接 ...
- AspNetCore容器化(Docker)部署(四) —— Jenkins自动化部署
一.前言 (Jenkins.Docker.Git/Svn组建一套简单的自动化发布流程) 文章中用到的相关服务器角色 角色 环境 功能 开发机 Win10.Docker(Linux OS) 编码.调试 ...
- .NETCore 实现容器化Docker与私有镜像仓库管理
原文:.NETCore 实现容器化Docker与私有镜像仓库管理 一.Docker介绍 Docker是用Go语言编写基于Linux操作系统的一些特性开发的,其提供了操作系统级别的抽象,是一种容器管理技 ...
- .NET Core容器化开发系列(一)——Docker里面跑个.NET Core
前言 博客园中已经有很多如何在Docker里面运行ASP.NET Core的介绍了.本篇主要介绍一些细节,帮助初学的朋友更加深入地理解如何在Docker中运行ASP.NET Core. 安装Docke ...
随机推荐
- RE : 球体波浪倒计时
背景: 移动端需要做一个倒计时球体水波的效果.主要用到了CSS的SVG瞄点动画和JS的计时器.该动画原型来自于 使用球体水面波动显示进度动画 http://wow.techbrood.com/fid ...
- Ajax之路
第一部分: Ajax全称Asynchronous Javascript and XML,中文意思为"异步的Javascript 和XML".Ajax这组技术是web2.0的核心之一 ...
- 一:Tomcat 服务器 在45秒内未启动成功
myeclipse或者eclipse中 tomcat 启动超时怎么办? 修改文件 找到Eclipse的工作空间\.metadata\.plugins\org.eclipse.wst.s ...
- PHP设计模式之工厂模式
工厂模式(Factory pattern)和单例模式一样,是另外一种创建型模式. 和单例模式不同的是,单例模式会创建和管理一个单独的类型的单一对象,工厂模式则是用于创建多种不同类型的类的多个对象. 工 ...
- Java 操作 Json
1. 使用Gson构建Json 初始化 JsonObject jsonObject = new JsonObject(); 添加属性 jsonObject.addProperty("name ...
- Android APK反编译 apktool使用教程
2017年棋牌游戏突然就火了,正所谓春江水暖鸭先知本猿处在软件行业中就能清晰的感受到市场的变化,最近老家那边也是玩的风生水起,于是最近闲暇时光想到反编译下这些棋牌软件,看看代码实现的思路 (注:反编译 ...
- 迷宫问题-POJ 3984
迷宫问题 Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 24348 Accepted: 14206 Descriptio ...
- 2733:判断闰年-poj
2733:判断闰年 总时间限制: 1000ms 内存限制: 65536kB 描述 判断某年是否是闰年. 输入 输入只有一行,包含一个整数a(0 < a < 3000) 输出 一行,如果 ...
- dnsmasq服务的安装与配置
在ubuntu16.04上安装dnsmasq服务,在本地做泛域名解析 安装 $ apt-get install dnsmasq -y $ /etc/init.d/dnsmasq start 配置 Dn ...
- IPv6 VS IPv4,谈谈升级 IPv6 的必要性
11月26日,中办.国办印发了<推进互联网协议第六版(IPv6)规模部署行动计划>,提出国内要在 5~10 年的时间形成下一代互联网自主技术体系和产业生态,建成全球最大规模的 IPv6 商 ...