.NET程序在Linux容器中的演变
【上海站|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容器中的演变相关推荐
- php 缓冲区溢出漏洞,在Linux 容器中对php-fpm缓冲区溢出漏洞的复现分析 ( CVE-2019-11043 )...
ubuntu@vulnerable:~$ curl http://localhost Hello World ubuntu@vulnerable:~$ 存在漏洞的容器已准备就绪,为容器做个快照,以备将 ...
- qt程序卡死 linux,QtCreator中打开.ui文件时卡死崩溃的解决方法
用Java实现单链表的基本操作 笔试题中经常遇到单链表的考题,下面用java总结一下单链表的基本操作,包括添加删除节点,以及链表转置. package mars; //单链表添加,删除节点 publi ...
- 解决Java程序在Linux系统中创建文件或者文件夹后权限不足的问题
Tomcat 需要 8 以及以上 我在Java程序里面有很多生成文件的功能,比如用户上传文件.将数据生成xml文本等.我发现生成的文件权限全是:-rw-r-,而文件的拥有者是 root,这样就只有ro ...
- 在Linux和Windows的Docker容器中运行ASP.NET Core
译者序:其实过去这周我都在研究这方面的内容,结果周末有事没有来得及总结为文章,Scott Hanselman就捷足先登了.那么我就来翻译一下这篇文章,让更多的中文读者看到.当然Scott遇到的坑我也遇 ...
- 使用Linux docker容器中的集成安全性对SQL Server的.Net Core客户端进行身份验证
目录 面对问题 逐步发现解决方案 先决条件 我们的演示应用 在容器中准备kerberos身份验证 KDC消费所需的包 创建一个合适的krb5.conf文件 生成keytab文件 Docker化演示应用 ...
- docker查看现有容器_如何使用Docker将现有应用程序推送到容器中
docker查看现有容器 by Daniel Newton 丹尼尔·牛顿 如何使用Docker将现有应用程序推送到容器中 (How to shove an existing application i ...
- 浅析linux容器--Docker
最近公司调整微服务架构,有幸开始接触到Docker,刚开始接触到docker的时候我去简单的百度了下docker容器,了解到docker属于linux容器中的一种,通过docker,linux容器发展 ...
- 解决 .NET Core 在 Linux Container 中获取 CurrentCulture 不正确的问题
背景 在将公司一款基于 .NET Framework 的控制台程序迁移到 .NET Core 3.1 时,发现程序中本地化的部分失效,症状类似于对 Thread.CurrentThread.Curre ...
- sigterm信号_详解如何在 docker 容器中捕获信号
概述 玩过docker的朋友可能都使用过 docker stop 命令来停止正在运行的容器,有些会使用 docker kill 命令强行关闭容器或者把某个信号传递给容器中的进程.这些操作的本质都是通过 ...
最新文章
- c语言分段错误空指针,C语言空指针总结 - 祂的小哥哥的个人空间 - OSCHINA - 中文开源技术交流社区...
- vs2017引入mysql_windows+vs2017+C语言 引入mysql.h对MYSQL数据库的操作
- 16年前卖猪肉的北大高材生如今怎么样了?
- Java数字图像处理基础知识 - 必读
- [蓝桥杯]算法提高 道路和航路(spfa+deque+快读优化)
- Oracle Code登录北京 代码盛宴邀你high起来|免费报名
- BTrace:Java开发人员工具箱中的隐藏宝石
- Jmeter5 语言中文
- docker 安装hadoop
- 在弹窗中新建一个遮罩层
- 如何使用Super Vectorizer在 Mac 上将 PDF 转换为 SVG 矢量?
- 做自己的软件的Gallery(一)
- 使用Pspice进行电路仿真
- 三菱plc控制电动推杆
- Struts1 和 Struts2
- const的作用和用法
- Jasper Report 6.8 根据后台数据生成动态报表(JRXML文件实现)(三)JRXML文件生成过程(支持json,bean,map list数据源)
- SCM系统有什么好处?
- java合并word文件
- 编写Linux usb 键盘驱动的笔记
热门文章
- Verilog Design's Tips
- 提交请求输出XML文件的时候出错.解决方法
- bg和fg指令(整理)以及 Linux中Ctrl+C、Ctrl+D等按键操作进程相关命令
- 汇编实验 用表格形式显示字符(附源码详细注释和相关注意的知识)
- MySQL-MMM架构部署(有图)
- 如何让SVN提交时候强制添加注释
- mysql linux版安装
- poj 2247 Humble Numbers
- exchange2013警告The maximum number of concurrent connections has exceeded a limit
- java.lang.NullPointerException错误分析