阅读更多

1顶
0踩

编程语言

转载新闻 九个编写Dockerfiles的常见错误

2016-06-22 14:37 by 副主编 mengyidan1988 评论(0) 有4032人浏览
【编者的话】我们每天基于Dockerfiles工作;所有运行的代码都来自一系列的Dockerfiles。这篇文章将会讨论编写Dockerfile时人们经常犯的错误以及如何改进。对于Docker专家说,这篇文章里的许多技巧可能会非常明显进而会得到很多的认同。但是对于初级到中级开发者,该文章将会是一份很有用的指南,它有助于理清以及加速你们的工作流程。
1. 执行 apt-get

执行apt-get install是每一个Dockerfile都有的东西之一。你需要安装一些外部的包来运行代码。但使用apt-get相应地会带来一些问题。

一个是运行apt-get upgrade 会更新所有包到最新版本 —— 不能这样做的理由是它会妨碍Dockerfile构建的持久与一致性。

另一个是在不同的行之间运行apt-get update与apt-get install命令。不能这样做的原因是,只有apt-get update的代码会在构建过程中被缓存,而且你需要运行apt-get install命令的时候不会每次都被执行。因此,你需要将apt-get update跟所要安装的包都在同一行执行,来确保它们正确的更新。

在以下Golang Dockerfile中apt-install命令就是一个不错的例子:
# From https://github.com/docker-library/golang
RUN apt-get update && \
apt-get install -y --no-install-recommends \
g++ \
gcc \
libc6-dev \
make \
&& rm -rf /var/lib/apt/lists/*

2. 使用ADD而非COPY

ADD与COPY是完全不同的命令。COPY是这两个中最简单的,它只是从主机复制一份文件或者目录到镜像里。ADD同样可以这么做,但是它还有更神奇的功能,像解压TAR文件或从远程URLs获取文件。为了降低Dockerfile的复杂度以及防止意外的操作,最好用COPY来复制文件。
FROM busybox:1.24

ADD example.tar.gz /add #解压缩文件到add目录
COPY example.tar.gz /copy #直接复制文件

3. 在一行内添加整个应用目录

明确代码的哪些部分以及什么时候应该放在构建镜像内或许是最重要的事了,它可以显著加快构建速度。

Dockerfile里经常会看到如下这些内容:
# !!! ANTIPATTERN !!!
COPY ./my-app/ /home/app/
RUN npm install # or RUN pip install or RUN bundle install
# !!! ANTIPATTERN !!!

这就意味着每次修改文件之后都需要重新构建那行以下的所有东西。多数情况下(包括上面的例子),它意味着重新安装应用依赖。为了尽可能地使用Docker的缓存,首先复制所有安装依赖所需要的文件,然后执行命令安装这些依赖。在复制剩余文件(这一步尽可能放到最后一行)之前先做这两个步骤,会使代码的变更被快速的重建。
COPY ./my-app/package.json /home/app/package.json # Node/npm packages
WORKDIR /home/app/
RUN npm install
或许还要安装python依赖?

COPY ./my-app/requirements.txt /home/app/requirements.txt
RUN pip install -r requirements.txt
COPY ./my-app/ /home/app/

这样做会确保构建尽可能快的执行。
4. 使用:latest标签

许多Dockerfiles在开头都使用FROM node:latest模板,用来从Docker registry拉取最新的镜像。简单地说,使用latest标签的镜像意味着如果这个镜像得到更新,那么Dockerfile的构建可能会突然中断。弄清这件事可能会非常难,因为Dockerfile的维护者实际上并没做任何修改。为了防止这种情况,只需要确保镜像使用特定的标签(例如:node:6.2.1)。这样就可以确保Dockerfile的一致性。
5. 构建镜像时使用外部服务

很多人会忽视构建Docker镜像与运行一个Docker容器的区别。在构建镜像时,Docker读取Dockerfile里的命令并创建镜像。在依赖或代码修改之前,镜像是保持不变以及可重复使用的。这个过程完全独立于其它容器。需要与其它容器或服务(如数据库)进行交互则会在容器运行的时候发生。

举一个例子,执行数据库迁移。很多人试图在构建镜像时执行此操作。这样做会导致许多问题。首先,在构建时数据库可能不可用,因为它可能没建在它将要运行的服务器上。其次,你可能想使用同一个镜像来连接不同的数据库(在开发或生产环境中),在这种情况下,如果它在构建过程中,迁移是不能进行的。
# !!! ANTIPATTERN !!!
COPY /YOUR-PROJECT /YOUR-PROJECT
RUN python manage.py migrate
# 尝试迁移数据,但是并不能
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]
# !!! ANTIPATTERN !!!

6. 在Dockerfile开始部分加入EXPOSE和ENV

EXPOSE和ENV是廉价的执行命令。如果你破坏它们的缓存,几乎瞬时就可以重建。所以,最好尽可能晚地声明这些命令。在构建过程中应该直到需要的时候才声明ENV。如果在构建的时候不需要他们,那么应该在Dockerfile的末尾附加EXPOSE。

再次查看Golang的Dockerfile,你会看到,所有ENVS都是在使用前声明的,并且在最后声明其余的:
ENV GOLANG_VERSION 1.7beta1
ENV GOLANG_DOWNLOAD_URL https://golang.org/dl/go$GOLANG_VERSION.linux-amd64.tar.gz
ENV GOLANG_DOWNLOAD_SHA256 a55e718935e2be1d5b920ed262fd06885d2d7fc4eab7722aa02c205d80532e3b
RUN curl -fsSL "$GOLANG_DOWNLOAD_URL" -o golang.tar.gz \
&& echo "$GOLANG_DOWNLOAD_SHA256  golang.tar.gz" | sha256sum -c - \
&& tar -C /usr/local -xzf golang.tar.gz \
&& rm golang.tar.gz
ENV GOPATH /go
ENV PATH $GOPATH/bin:/usr/local/go/bin:$PATH

如需修改ENV GOPATH或ENV PATH,镜像几乎会马上重建成功。
7. 多个FROM声明

尝试使用多个FROM声明来将不同的镜像组合到一起,这样不会起任何作用。Docker仅使用最后一个FROM并且忽略前面所有的。

所以如果你有这样的Dockerfile:
# !!! ANTIPATTERN !!!
FROM node:6.2.1
FROM python:3.5
CMD ["sleep", "infinity"]
# !!! ANTIPATTERN !!! 

那么docker exec进入运行的容器中,会得到下面的结果:
$ docker exec -it d86fcf0775d3 bash
root@d86fcf0775d3:/# which python
/usr/local/bin/python
root@d86fcf0775d3:/# which node
root@d86fcf0775d3:/#

这其实是GitHub上的一个问题:合并不同的镜像,但它看起来不会很快就增加的功能。
8. 多个服务运行在同一个容器内

这可能是了解Docker的开发者遇到的最大问题。而公认的最佳实践是:每个不同的服务,包括应用,应该在它自己的容器中运行。在一个Docker镜像里面加入多个服务非常容易,但是有一定的负面影响。

首先,横向扩展应用会变得很困难。其次,额外的依赖和层次会使镜像构建变慢。最终,增大了Dockerfile的编写、维护以及调试难度。

当然,像所有的技术建议一样,你需要用你的最佳判断。如果想快速安装一个Django+Nginx的应用的开发环境,那么让它们运行在同一个容器里面,同时生产环境中有一个不同的Dockerfile,让他们分开运行,是合理可行的。
9. 在构建过程中使用VOLUME

Volume是在运行容器时候加入的,而不是构建的时候。与第五个误区类似,在构建过程中不应该与你声明的volume有交互。相反地,你只是在运行容器的时候使用它。例如,如果在以下构建过程中创建文件并且在运行那个镜像时候使用它,一切正常:
FROM busybox:1.24
RUN echo "hello-world!!!!" > /myfile.txt
CMD ["cat", "/myfile.txt"]
...
$ docker run volume-in-build
hello-world!!!!

但是,如果我对一个存储在volume上的文件做同样的事,就不会起作用。
FROM busybox:1.24
VOLUME /data
RUN echo "hello-world!!!!" > /data/myfile.txt
CMD ["cat", "/data/myfile.txt"]
...
$ docker run volume-in-build
cat: can't open '/data/myfile.txt': No such file or directory

一个有趣的问题是:如果你前面的任何一个层次声明了一个VOLUME(也可能是几个FROMS)依然会遇到同样的问题。因此,最好留意一下父类镜像都声明了什么volume。如果遇到问题,请使用docker inspect检查。
结论

理解怎样写好一个Dockerfile将会是一个漫长的路程,它会带你理解Docker是如何工作的,同时也帮助你建立你的基础架构。理解Docker缓存会为你节省好多等待构建完成的时间!

原文链接:9 Common Dockerfile Mistakes (翻译:陈晏娥 校对:田浩浩
来自: dockone
1
0
评论 共 0 条 请登录后发表评论

发表评论

您还没有登录,请您登录后再发表评论

相关推荐

  • 最常用的英语口语900句.pdf

    最常用的英语口语900句 日常口语,应该熟记的

  • 生活在美国:最常有用的英语口语900句

    1. I see. 我明白了。 2. I quit! 我不干了! 3. Let go! 放手! 4. Me too. 我也是。 5. My god! 天哪! 6. No way! 不行! 7. Come on. 来吧(赶快) 8. Hold on. 等一等。 9. I agree。 我同意。 10. Not bad. 还不错。 11. Not yet. 还没。 12. See you. 再见。

  • 英语口语900句

    <br /><br />特色:极力推崇人性化服务!让您最便捷的在最短时间内得到对您最有价值考试信息!坚持每日更新!!!<br />1. Hello.你好!  <br /> 2. Good morning.早晨好!  <br /> 3. I’m John Smith.我是约翰、史密斯。  <br /> 4. Are you Bill Jones?你是比尔、琼斯吗?  <br /> 5. Yes,I am.是的,我是。 <br /> 6. How are you?你好吗?  <br /> 7. Fi

  • AM4系统前端探究-npm包的使用

    Please enter the password to read the blog. Incorrect Password! No content to display! U2FsdGVkX1+T1mQ2PgpYXNF+2CxVkngCnIIXoWHj1Nph/cyf3ANuyMskD2ldHjnOUZ0WKe62AHsR1w...

  • 新英语900句

    新英语900句 1 Greetings 问候语 1. Hello. 你好! 2. Good morning. 早上好。 3. I am Kate Green. 我是凯特·格林。 4. Are you Tom Brown? 你是汤姆·布朗吗? 5. Yes, I am. 是的,我是。 6. How do you do? 你好!How do you do? 你...

  • 英语900句

    1 Greetings 问候语  15 2 Expression In Class 15 3Identifying Objects 4About Belongings 5 Identifying People 6About Introduction 7 Year, Month And Day 8 Talking About Objects 9 Talking About Time

  • composer - No business network has been specified for this connection 解决方案

    I have installed hyperledger composer locally. But on localhost it gives error : Error : Error trying to ping. Error: No business network has been specified for this connection. I am no...

  • 树莓派2 ssh设置_在树莓派上设置ssh和2fa

    树莓派2 ssh设置I recently used some spare hardware to create a little file server on a Raspberry Pi, and I wanted to be able to log in to the Pi when I am away from home to check on things. This little doc...

  • nvidia 驱动重装踩坑之路

    背景:本来用gpu用的好好的,有一天系统软件自动更新手贱点了确定,里面包含nvidia字眼,当时看到就感觉有点不妥,仍然点了确定。 恩,直觉真准,但是手快啊!!于是开启了踩坑之路。报错:使用gpu版本的tensorflow,运行session时会出现如下问题: 于是乎gpu就不能用了,nvidia-smi也报错说类似版本不匹配的意思。查看当天的系统更新内容: 可以发现驱动被更新了,但是由错误可

  • 上传自己库到Cocoapods和遇见的各种问题解决

    第一步,上传自己写好的代码让别人去下载。先安装Cocoapods 端口输入:sudo gem install cocoapods 安装完成后。开始注册trunk 第二步,注册trunk最好账户和邮箱和github账户和绑定邮箱一致,代码如下 端口输入:pod trunk register xxxxxx@qq.com '账户名' --verbose 回车 第三步,去你上一步...

  • 解决极值中的神奇设k法_神奇宝贝Go拥有对您的Google帐户的完全访问权限。 这是解决方法[更新]...

    解决极值中的神奇设k法To sayPokémon GO is wildly popular would be a vast understatement. To say the app’s use of your Google Account is wildly insecure would also be a vast understatement. Youshouldrevoke its...

  • 06 Frequently Asked Questions (FAQ) 常见问题解答 (常见问题)

    Frequently Asked Questions (FAQ) Origins起源What is the purpose of the project?What is the history of the project?What's the origin of the gopher mascot?Why did you create a new language?What ...

  • pip 安装老出错,原来是网络问题,换镜像源!

    pip 安装老出错,原来是网络问题,换镜像源! 虽然网上资料有介绍很多的,为了不要忘记,还是做了记录; 出现问题是安装mxnet 和 chainer 时出现的,那时安装老安装不上. 所以尝试改一下: 配置清华PyPI镜像,将pip版本升级到&gt;=10.0.0) pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/s...

  • 记录的Android开发过程中遇到的问题。

    180508  更新  网上下载demo 本地studio版本和demo版本不一致处理方式  修改两处 1 项目的build.gradle 里面classpath2修改项目目录下 gradle--&amp;gt;wrapper--&amp;gt;gradle-wrapper.properties文件的distributionUrl地址然后 clean build  rebuild  即可1.在一个XML中能否使用...

  • 英语口语必备900句

    I’m home. 我回来了。 I quit! 我不干了! Let go! 放手! Me too. 我也是。 My god! 天哪! No way! 不行! Come on. 来吧(赶快) Hold on. 等一等。 I agree。 我同意。 Not bad. 还不错。 Not yet. 还没。 See you. 再见。 Shut up! 闭嘴! So long. 再见。

  • [转载]2012 年 4 月,rating排行榜

    2012年 4月 Rating 排行榜排名昵称(QQ)Rating1白衣少年(253****83)21472[BISTU]神nakami(501****8)21413飞鱼(303****77)20664[蒟蒻]Konjac(303****74)19655[NEU]yangzhe1991(490****1)18826Izayoi Sakuya(122****02)17707黑暗中的撸者(237***...

  • vertical-align 与 line-height 傻傻分不清??

      要说吧,咱家是个菜鸟,以前遇见垂直居中的东东,也是现查现用,其中最长遇到的东西就是 vertical-align 和 line-height,似乎这俩个兄弟都可以实现居中对齐,不过窃以为二者还是有区别的,所有 本着成为大牛的精神,不停的百度、百度,遇见的文章都像是老太太的裹脚布一样,又臭又长!实在让人难以理解,今天我在这里要说的简单一点,既然简化了,可能就不全,不过对于应付常用的开发,足矣!!...

  • 英语九百句 English900(含录音下载)

    第一册一、 Greetings 问候语1. Hello! / Hi! 你好!2. Good morning / afternoon / evening! 早晨(下午/晚上)好!3. Im Kathy King. 我是凯西·金。4. Are you Peter Smith? 你是彼得·史密斯吗?5. Yes, I am. / No, Im not. 是,我是。/ 不,我不是。6. How are

Global site tag (gtag.js) - Google Analytics