取消
显示结果 
搜索替代 
您的意思是: 
cancel
1162
查看次数
0
有帮助
0
评论
julianchen
Spotlight
Spotlight
本帖最后由 julianchen 于 2017-4-27 15:08 编辑
引言:随着.NET开发者现在已经可以无障碍地使用Docker之类的Linux容器,就让我们直接来看看如何以正确的方式配置一个容器吧。

可能本文更为准确的标题应该是“Linux容器的开发者的化。”因为自从.NET技术已经能够在Linux上运行(如同在WindowsmacOS上那样)以来,全世界的Linux容器和microservices(微服务)都向.NET开发者开放了。由于.NET拥有着超大量的开发者群体,长期的成功开发案例和令人印象深刻的性能参数,为全世界的Linux容器向着原Windows为中心的开发者阵营的扩展,提供了一个很好的机会。

虽然在Linux容器里运行.NET代码时,有一些不容错过的运行方面的细微差别,而似乎显得有点冒进,但我还是会脱口而出那句去吧,皮卡丘!这可比要把一些代码推镜像里去完成可容易多了。毕竟,一切都能快速实现,而且是恰到好处地,不是吗?
当然,让你的.NET代码能运行在Linux容器中可并不是一个微不足道的事,正如一个古老的谚语所言:让它先工作起来,然后再让它能快速地工作。

快速,在我们这里是指其在构建、启动镜像以及镜像内代码的性能等方面所花费的时间。本文将涉及前两个部分——构建和启动镜像的时间。我们将从一个简单的.NET程序开始,来运行基于容器的应用,然后观察镜像随其变小的化,并导致构建和加载时间的缩短。

至于代码优化则是另外一方面的话了,市面上有很多可供您参考

横空出世且如此鲜活!

试想一个非常简单的例子:微服务仅给出一个HTTP 类型的“Hello world”响应。也就是说您将浏览器指向一个URL,并获得包含有主机名一个非常简单的响应。记住这是一个简单的例子,我登录到了Linux虚拟机(VM)里,从其repo请参见https://github.com/donschenck/dotnet_docker_msa)中这些下载代码。

就像面对任何新技术的开发者那样,在这种情况下,我想尽快在Linux容器中启动并运行该应用程序。因此我迅速地构造了一个Dockerfile请参见repo中的Dockerfile.attempt1)并使用如下命令构建了一个镜像:

docker build -t attempt1-f Dockerfile.attempt1 .

构建成功完成后,我当然是兴奋的。而当我能用如下命令在容器中运行镜像时,我甚至有些激动

docker run -d -p5000:5000 --name attempt1 attempt1

我将浏览器指向正确的URL,它也是我虚拟机的IP地址。请看下面的截图:

一些数字

我在第一次构建该镜像的时候花了高达95秒的时间,其原因在于需要下载一整个490 MB大小的安装了.NET SDK的红帽子企业版Red Hat Enterprise LinuxRHEL的镜像。这也导致了整个镜像的大小为659 MB

公平地说,后续的构建将会更快些,因为docker格式的容器镜像,现在已经存在我的机器上且可用了。后,我又改变了其源代码,并再次运行了构建过程,这次只花了大约50秒的时间,并产生了相同大小为659 MB的镜像。

其实镜像的大小还是很重要的。虽然您的机器上所使用的存储空间现如今已经是比较便宜的了,但它仍然是一种有限的商品。特别是在您定期使用容器的时侯,那些过期且被遗忘的镜像很容易就“静静”地是待在那里占用消耗了空间。因此您很容易在不小心之间就很快地填满了磁盘的空间。

那么,如何才能让镜像变得更小呢?

删除一些不需要的部分

将一个简单的命令行选项添加到dotnet restore命令中是会有所帮助的。我使用的是:dotnet restore --no-cache (请参见Dockerfile.attempt2)来消除任何缓存,它将镜像的大小降至608.6 MB,也就是缩减了50.6 MB,即省下了百分之七以上的空间。但我对此并不满意,肯定还有更多的办法。

在构建镜像前先构建应用程序

我意识到:当我每次在一个容器里运行镜像的时候,应用程序都会构建.NET应用。虽然这花去1.6秒显然不是什么一个大块的时间,但是我还是觉得这有些浪费。我通过在dotnetretore之间插入命令build,并在构建容器镜像之前先构建其应用程序,这将会使得容器的启动要快得多。这个结果显示在Dockerfile.attempt3中。当然,这是以消耗存储空间为代价的,其镜像的大小升至为610.2 MB了。不过,dotnet build是无论如何都必须运行的,我们不妨现在多花点时间,而以后每次启动容器后都能因此获益了。

Dotnet的发布

接下来,我们的焦点转移到一个问题上:既然容器是一个运行环境,那么为什么不使用dotnet publish命令使得在其被推入镜像之前就发布代码呢?如果我这样做了的话,我就不需要在自己的容器里预先安装好.NET。毕竟,发布允许您构建一个单独的(独立”)应用程序,而该应用程序可以在任何地方运行。这才是dotnet publish 的真正用途!而这将是镜像大小和启动时间上的巨大的成功。

我修改了project.json文件,用以支持发布其间,我删除掉了用以告诉编译器去构建一个平台那段命令行(实际上是将它注释掉了)。可以在下面的截屏上看到:

接下来,我通过使用发布命令发布了代码:dotnet publish -c Release -r rheh.7.2-x64。此举将所有已编译的部分,包括所有运行时所必要的部分,都放到了一个我可以复制到镜像的文件夹里。当然,它可以变得更好一些:由于我不需要.NET 的预安装,所以我可以使用一个没有.NETRHEL基本版本。而之所以这样做,是因为此举肯定会节省更多的空间。

为了将各个部分推到镜像之中,我使用了以下是Dockerfile 请参见repo中的Dockerfile.attempt4):

值得注意的是:两个yum install命令将会安装一些能使得.NET需要在RHEL之上的先决条件。目前尚无绕过这个问题的办法。但是,毕竟也不是什么大不了的。我运行了docker build,结果生成的镜像大小居然是694.6 MB!这到底发生了什么事呢?

谁会需要缓存呢?

原来,两个yum install指令也为未来的yum install命令构建了缓存。所以如果我能在每个命令之后立即清除缓存的话,就会好很多。以下就是我的第五次迭代Dockerfile,请参见Dockerfile.attempt5

我们将运行了docker build与这个Dockerfile所产生的镜像文件大小相比较,可以看到,这次只有293.7 MB, 比第一次的尝试结果少了55%以上。此处该有鼓声。

堆积的是命令而不是杯子

反映在文件Dockerfile中的, 我最后的修改是堆积式的yum install命令,如下:

可见,由此产生的镜像大小为257.5 MB,相比我的第一次尝试,结果可是少了60%以上。最后,请让我以如下图表的形式来和您重温这次所提及的各次尝试:

总结

当我们探索新技术和新模式时,我们必须小心,不要把我们早期的结果与我们最佳实践与努力相混淆。虽然早期的成功会带来了兴奋和鼓励,但它也可能使我们停下前进的脚步。我们应该勤奋、不断尝试并且总对改进建议保持开放的心态。

【原标题】The Evolution of aLinux Container (作者: Don Schenck)

原文链接:https://dzone.com/articles/the-evolution-of-a-linux-container

入门指南

使用上面的搜索栏输入关键字、短语或问题,搜索问题的答案。

我们希望您在这里的旅程尽可能顺利,因此这里有一些链接可以帮助您快速熟悉思科社区:









快捷链接