本文讲的是.NET程序在Linux容器中的演变【编者的话】Linux容器技术已被开发人员所熟知,现在.NET程序可以跑在Docker容器中,这为以Windows中心的开发人员带来了好处。

【上海站|3天烧脑式微服务架构训练营】培训内容包括:DevOps、微服务、Spring Cloud、Eureka、Ribbon、Feign、Hystrix、Zuul、Spring Cloud Config、Spring Cloud Sleuth等。

本文将首先讨论镜像的构建时间和启动时间,接着会将一个简单的.NET程序运行在基于容器的应用上,然后观察镜像大小的变化,最终缩短镜像的构建和加载时间。此外,代码优化是本文的另一个主题。

现在,.NET开发人员可以无障碍地使用如Docker这样的Linux容器,那么让我们来尝试如何以正确的方式配置一个容器。

可能,文章的标题改成“Linux容器开发人员的演变”会更好。由于.NET可在Linux(以及Windows和macOS)上运行,所以整个世界的Linux容器和微服务已经开放给了.NET开发人员。

有着大量的开发人员,长期的运行记录和优异性能指标的.NET,现在给以Windows为中心的开发人员提供了一个使用Linux容器的机会。

虽然在Linux容器中尝试运行.NET代码是诱人的,同时也会产生一些细微差别,但是这样做是不会错的。你可以很容易地将一些.NET代码推送到镜像中。

毕竟,一切都发生的这么快,一定都很好。 对不对?

事实并非如此。让.NET代码运行在Linux容器中并不是一件简单的事情,但请记住:“先让它工作,然后让它工作得很快。”

在下面的例子中,上文说的“很快”指的是构建镜像所需的时间,启动镜像所需的时间和镜像内部代码的性能。本文将首先讨论镜像的构建时间和启动时间,接着会将一个简单的.NET程序运行在基于容器的应用上,然后观察镜像大小的变化,最终缩短镜像的构建和加载时间。此外,代码优化是本文的另一个主题。

短暂的停留

考虑一个非常简单的微服务示例,它只给出一个“Hello world”类型的HTTP响应。也就是说,当在浏览器中填写URL,你就会得到一个包括主机名的Web页面。

我们可从这个代码库中下载源码,并制作第一个Dockerfile(Dockerfile.attempt1),接着使用以下命令构建镜像:

#  docker  build  -t  attempt1   -f   Dockerfile.attempt1   .

然后在容器中运行镜像:

#  docker  run   -d   -p   5000:5000   --name   attempt1   attempt1

将浏览器的URL指向主机的IP地址,情况如下:

数字

第一次构建镜像,一共耗时95秒。其中,下载红帽企业Linux(简称RHEL)镜像与安装.NET SDK,这些文件一共490MB。最终,镜像大小为659MB。

一般而言,镜像的后续构建将更快,因为Docker化的镜像已经在主机上可用。改变源码后,我们再次运行构建。这一次构建镜像,大约耗时50秒,得到了相同大小的镜像,也是659MB。

镜像的大小很重要。因为镜像使用操作系统的存储空间,虽然空间便宜,但它仍然是有限的商品。当定期使用容器时,我们很容易忽略过时的镜像,然而它仍然在占用磁盘。如果你不注意的话,磁盘空间将很快用尽。

如何使镜像尽可能的小?

移除镜像不需要的部分

使用命令dotnet restore --no-cache可以消除任何缓存,这样镜像的大小下降到608.6MB,减少了50.6 MB,同比缩小超过7%。

在构建镜像之前构建应用

应用是在容器中运行镜像时构建.NET程序的。这耗时大约1.6秒——虽然时间不长,但却是在浪费时间。

在恢复之前插入的dotnet build命令,并在构建镜像之前构建应用,这样的话容器将会更快地启动。这个结果可在Dockerfile.attempt3中实现。

与此同时,镜像大小却增加到610.2MB,而我们还得运行dotnet build,虽然现在花这个时间,但却可在每次启动容器时受益。

运行Dotnet Publish命令

因为容器是一个运行时环境,那我们为什么不使用dotnet publish命令发布代码,然后把代码放入镜像呢?如果这样做的话,我们就没必要在镜像中安装.NET程序了。毕竟,我们需要的是一个可在任何地方独立运行的应用。

使用dotnet发布代码,会减少镜像大小和缩短容器启动时间。更改project.json文件,注释掉下图中红框的内容,这告诉编译器此文件为一个平台构建。您可以在下图中看到它:

接下来,我们使用dotnet publish -c Release -r rheh.7.2-x64发布代码,这会把所有的编译文件和运行时文件,放入一个文件夹,我们把此文件夹复制到镜像中。

因为我们不再需要安装.NET程序,只要一个包含RHEL文件的基础镜像即可,这样就减少了镜像的大小。这是Dockerfile的第四次迭代——Dockerfile.attempt4:

FROM registry.access.redhat.com/rhel7
RUN yum install -y libunwind
RUN yum install -y libicu
ADD bin/Release/netcoreapp1.0/rhel.7.2-x64/publish/. /opt/app-root/src/
WORKDIR /opt/app-root/src/
EXPOSE 5000
CMD ["/bin/bash", "-c", "/opt/app-root/src/dotnet_docker_msa"]

请注意,yum install命令将安装一些.NET需要的依赖文件,然后运行docker build命令,最终生成一个694.6MB的镜像。

谁需要缓存?

多次运行yum install命令,前一次操作将为后一次构建缓存。如果在每个yum install命令之后,我们立即清除缓存,效果将会很好。下面是Dockerfile的第五次迭代———Dockerfile.attempt5:

FROM registry.access.redhat.com/rhel7
RUN yum install -y libunwind && yum clean all
RUN yum install -y libicu && yum clean all
ADD bin/Release/netcoreapp1.0/rhel.7.2-x64/publish/. /opt/app-root/src/
WORKDIR /opt/app-root/src/
EXPOSE 5000
CMD ["/bin/bash", "-c", "/opt/app-root/src/dotnet_docker_msa"]

基于Dockerfile.attempt5构建的镜像,其大小减少到293.7MB,这比第一次构建缩小了55%。

堆叠命令

对Dockerfile做最后更改,我们需要堆叠yum install命令,具体内容如下所示:

FROM registry.access.redhat.com/rhel7
`RUN yum install -y libunwind libicu && yum clean all
`ADD bin/Release/netcoreapp1.0/rhel.7.2-x64/publish/. /opt/app-root/src/
`WORKDIR /opt/app-root/src/
`EXPOSE 5000
`CMD ["/bin/bash", "-c", "/opt/app-root/src/dotnet_docker_msa"]

最终得到的镜像大小为257.5MB,这比第一次构建缩小了60%。

下面是各个Dockerfile构建的镜像大小对比图:

总结

在探索新技术与新模式时,我们不能将早期的结果与最优做法相混淆。虽然早期的成功会给我们带来兴奋和鼓励,但它也可能使我们丧失进步的动力。勤奋,然后不断尝试,并且始终接受改进的建议,会帮助我们走的更远。

原文链接:The Evolution of a Linux Container(译者:Jack)

===========================================
译者介绍

Jack,开源软件爱好者,研究方向是云计算PaaS平台与深度学习,现积极活跃于Docker,Kubernetes,Tensorflow社区。

原文发布时间为:2017-03-17

本文作者:Jack

本文来自云栖社区合作伙伴Dockerone.io,了解相关信息可以关注Dockerone.io。

原文标题:.NET程序在Linux容器中的演变

.NET程序在Linux容器中的演变相关推荐

  1. php 缓冲区溢出漏洞,在Linux 容器中对php-fpm缓冲区溢出漏洞的复现分析 ( CVE-2019-11043 )...

    ubuntu@vulnerable:~$ curl http://localhost Hello World ubuntu@vulnerable:~$ 存在漏洞的容器已准备就绪,为容器做个快照,以备将 ...

  2. qt程序卡死 linux,QtCreator中打开.ui文件时卡死崩溃的解决方法

    用Java实现单链表的基本操作 笔试题中经常遇到单链表的考题,下面用java总结一下单链表的基本操作,包括添加删除节点,以及链表转置. package mars; //单链表添加,删除节点 publi ...

  3. 解决Java程序在Linux系统中创建文件或者文件夹后权限不足的问题

    Tomcat 需要 8 以及以上 我在Java程序里面有很多生成文件的功能,比如用户上传文件.将数据生成xml文本等.我发现生成的文件权限全是:-rw-r-,而文件的拥有者是 root,这样就只有ro ...

  4. 在Linux和Windows的Docker容器中运行ASP.NET Core

    译者序:其实过去这周我都在研究这方面的内容,结果周末有事没有来得及总结为文章,Scott Hanselman就捷足先登了.那么我就来翻译一下这篇文章,让更多的中文读者看到.当然Scott遇到的坑我也遇 ...

  5. 使用Linux docker容器中的集成安全性对SQL Server的.Net Core客户端进行身份验证

    目录 面对问题 逐步发现解决方案 先决条件 我们的演示应用 在容器中准备kerberos身份验证 KDC消费所需的包 创建一个合适的krb5.conf文件 生成keytab文件 Docker化演示应用 ...

  6. docker查看现有容器_如何使用Docker将现有应用程序推送到容器中

    docker查看现有容器 by Daniel Newton 丹尼尔·牛顿 如何使用Docker将现有应用程序推送到容器中 (How to shove an existing application i ...

  7. 浅析linux容器--Docker

    最近公司调整微服务架构,有幸开始接触到Docker,刚开始接触到docker的时候我去简单的百度了下docker容器,了解到docker属于linux容器中的一种,通过docker,linux容器发展 ...

  8. 解决 .NET Core 在 Linux Container 中获取 CurrentCulture 不正确的问题

    背景 在将公司一款基于 .NET Framework 的控制台程序迁移到 .NET Core 3.1 时,发现程序中本地化的部分失效,症状类似于对 Thread.CurrentThread.Curre ...

  9. sigterm信号_详解如何在 docker 容器中捕获信号

    概述 玩过docker的朋友可能都使用过 docker stop 命令来停止正在运行的容器,有些会使用 docker kill 命令强行关闭容器或者把某个信号传递给容器中的进程.这些操作的本质都是通过 ...

最新文章

  1. c语言分段错误空指针,C语言空指针总结 - 祂的小哥哥的个人空间 - OSCHINA - 中文开源技术交流社区...
  2. vs2017引入mysql_windows+vs2017+C语言 引入mysql.h对MYSQL数据库的操作
  3. 16年前卖猪肉的北大高材生如今怎么样了?
  4. Java数字图像处理基础知识 - 必读
  5. [蓝桥杯]算法提高 道路和航路(spfa+deque+快读优化)
  6. Oracle Code登录北京 代码盛宴邀你high起来|免费报名
  7. BTrace:Java开发人员工具箱中的隐藏宝石
  8. Jmeter5 语言中文
  9. docker 安装hadoop
  10. 在弹窗中新建一个遮罩层
  11. 如何使用Super Vectorizer在 Mac 上将 PDF 转换为 SVG 矢量?
  12. 做自己的软件的Gallery(一)
  13. 使用Pspice进行电路仿真
  14. 三菱plc控制电动推杆
  15. Struts1 和 Struts2
  16. const的作用和用法
  17. Jasper Report 6.8 根据后台数据生成动态报表(JRXML文件实现)(三)JRXML文件生成过程(支持json,bean,map list数据源)
  18. SCM系统有什么好处?
  19. java合并word文件
  20. 编写Linux usb 键盘驱动的笔记

热门文章

  1. Verilog Design's Tips
  2. 提交请求输出XML文件的时候出错.解决方法
  3. bg和fg指令(整理)以及 Linux中Ctrl+C、Ctrl+D等按键操作进程相关命令
  4. 汇编实验 用表格形式显示字符(附源码详细注释和相关注意的知识)
  5. MySQL-MMM架构部署(有图)
  6. 如何让SVN提交时候强制添加注释
  7. mysql linux版安装
  8. poj 2247 Humble Numbers
  9. exchange2013警告The maximum number of concurrent connections has exceeded a limit
  10. java.lang.NullPointerException错误分析