一、先看最简单的例子,定制nginx镜像,打印出 <h1>Hello, Docker!</h1>

Dockerfile文件:

FROM nginx
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html

在该Dockerfile目录下运行

docker build -t nginx:v1 .

则将生成一个 nginx:v1 的新镜像,运行该镜像

docker run -p : nginx:v1

在浏览器直接访问地址 localhost,可以看到nginx的主页已被修改

二、RUN 命令关键解析

Dockerfile 中每一个指令都会建立一层, RUN 也不例外。每一个 RUN 的行为,新建立一层,在其上执行这些命令,执行结束后, commit 这一层的修改,构成新的镜像。

FROM debian:jessie
RUN apt-get update
RUN apt-get install -y gcc libc6-dev make
RUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-3.2.5.tar.gz"
RUN mkdir -p /usr/src/redis
RUN tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=
RUN make -C /usr/src/redis
RUN make -C /usr/src/redis install

如上dockerfile所示,创建了 7 层镜像,这是完全没有意义的,而且很多运行时不需要的东西,都被装进了镜像里,比如编译环境、更新的软件包等等。结果就是产生非常臃肿、非常多层的镜像,不仅仅增加了构建部署的时间,也很容易出错。

正确的写法:

FROM debian:jessie
RUN buildDeps='gcc libc6-dev make' \
&& apt-get update \
&& apt-get install -y $buildDeps \
&& wget -O redis.tar.gz "http://download.redis.io/releases/redis-3.2.5.tar.gz" \
&& mkdir -p /usr/src/redis \
&& tar -xzf redis.tar.gz -C /usr/src/redis --strip-components= \
&& make -C /usr/src/redis \
&& make -C /usr/src/redis install \
&& rm -rf /var/lib/apt/lists/* \
&& rm redis.tar.gz \
&& rm -r /usr/src/redis \
&& apt-get purge -y --auto-remove $buildDeps

三、CMD 与 ENTRYPOINT对比

场景1、让镜像变成像命令一样使用

假设我们需要一个得知自己当前公网 IP 的镜像,那么可以先用 CMD 来实现:

FROM ubuntu:16.04
RUN apt-get update \
&& apt-get install -y curl \
&& rm -rf /var/lib/apt/lists/*
CMD [ "curl", "-s", "http://ip.cn" ]

使用docker build -t myip . 来构建镜像的话,如果我们需要查询当前公网 IP,只需要执行:

docker run myip

可以打印出当前的ip地址

这么看起来好像可以直接把镜像当做命令使用了,不过命令总有参数,如果我们希望加参数呢?比如从上面的 CMD 中可以看到实质的命令是 curl ,那么如果我们希望显示 HTTP头信息,就需要加上 -i 参数。那么我们可以直接加 -i 参数给 docker run myip 么?

$ docker run myip -i
docker: Error response from daemon: invalid header field value "oci runtime error: con
tainer_linux.go:: starting container process caused \"exec: \\\"-i\\\": executable
file not found in $PATH\"\n".

可以看到可执行文件找不到的报错, executable file not found 。之前我们说过,跟在镜像名后面的是 command ,运行时会替换 CMD 的默认值。因此这里的 -i 替换了远了的CMD ,而不是添加在原来的 curl -s http://ip.cn 后面。而 -i 根本不是命令,所以自然找不到。
那么如果我们希望加入 -i 这参数,我们就必须重新完整的输入这个命令:

$ docker run myip curl -s http://ip.cn -i

这显然不是很好的解决方案,而使用 ENTRYPOINT 就可以解决这个问题。现在我们重新用ENTRYPOINT 来实现这个镜像:

FROM ubuntu:16.04
RUN apt-get update \
&& apt-get install -y curl \
&& rm -rf /var/lib/apt/lists/*
ENTRYPOINT [ "curl", "-s", "http://ip.cn" ]

这次我们再来尝试直接使用 docker run myip -i

成功!这是因为当存在 ENTRYPOINT 后, CMD 的内容将会作为参数传给ENTRYPOINT ,而这里 -i 就是新的 CMD ,因此会作为参数传给 curl ,从而达到了我们预期的效果

场景2:应用运行前的准备工作

启动容器就是启动主进程,但有些时候,启动主进程前,需要一些准备工作。
比如 mysql 类的数据库,可能需要一些数据库配置、初始化的工作,这些工作要在最终的mysql 服务器运行之前解决。
此外,可能希望避免使用 root 用户去启动服务,从而提高安全性,而在启动服务前还需要以 root 身份执行一些必要的准备工作,最后切换到服务用户身份启动服务。或者除了服务外,其它命令依旧可以使用 root 身份执行,方便调试等。
这些准备工作是和容器 CMD 无关的,无论 CMD 为什么,都需要事先进行一个预处理的工作。这种情况下,可以写一个脚本,然后放入 ENTRYPOINT 中去执行,而这个脚本会将接到的参数(也就是 <CMD> )作为命令,在脚本最后执行。

四、HEALTHCHECK 健康检查

HEALTHCHECK 指令是告诉 Docker 应该如何进行判断容器的状态是否正常,这是 Docker 1.12引入的新指令

HEALTHCHECK 支持下列选项:
--interval=<时长> :两次健康检查的间隔,默认为 30 秒;
--timeout=<时长> :健康检查命令运行超时时间,如果超过这个时间,本次健康检查就被
视为失败,默认 30 秒;
--retries=<次数> :当连续失败指定次数后,则将容器状态视为 unhealthy ,默认 3
次。

FROM nginx
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
HEALTHCHECK --interval=5s --timeout=3s \
CMD curl -fs http://localhost/ || exit 1

这里我们设置了每 5 秒检查一次(这里为了试验所以间隔非常短,实际应该相对较长),如果健康检查命令超过 3 秒没响应就视为失败,并且使用 curl -fs http://localhost/ || exit 1 作为健康检查命令。

构建镜像,并且启动容器

$ docker build -t myweb:v1 .

$ docker run -d --name web -p 80:80 myweb:v1

当运行该镜像后,可以通过 docker ps 看到最初的状态为 (health: starting)

在等待几秒钟后,再次 docker ps ,就会看到健康状态变化为了 (healthy)

如果健康检查连续失败超过了重试次数,状态就会变为 (unhealthy) 。
为了帮助排障,健康检查命令的输出(包括 stdout 以及 stderr )都会被存储于健康状态里,可以用 docker inspect 来查看。

$ docker inspect --format '{{json .State.Health}}' web | python -m json.tool
{
"FailingStreak": ,
"Log": [
{
"End": "2016-11-25T14:35:37.940957051Z",
"ExitCode": ,
"Output": "<!DOCTYPE html>\n<html>\n<head>\n<title>Welcome to nginx!</titl
e>\n<style>\n body {\n width: 35em;\n margin: auto;\n font-f
amily: Tahoma, Verdana, Arial, sans-serif;\n }\n</style>\n</head>\n<body>\n<h1>Welc
ome to nginx!</h1>\n<p>If you see this page, the nginx web server is successfully inst
alled and\nworking. Further configuration is required.</p>\n\n<p>For online documentat
ion and support please refer to\n<a href=\"http://nginx.org/\">nginx.org</a>.<br/>\nCo
mmercial support is available at\n<a href=\"http://nginx.com/\">nginx.com</a>.</p>\n\n
<p><em>Thank you for using nginx.</em></p>\n</body>\n</html>\n",
"Start": "2016-11-25T14:35:37.780192565Z"
}
],
"Status": "healthy"
}

五、COPY与ADD区别

在 Docker 官方的最佳实践文档中要求,尽可能的使用 COPY ,因为 COPY 的语义很明确,就是复制文件而已,而 ADD 则包含了更复杂的功能,其行为也不一定很清晰。最适合使用ADD 的场合,就是所提及的需要自动解压缩的场合。
另外需要注意的是, ADD 指令会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。
因此在 COPY 和 ADD 指令中选择的时候,可以遵循这样的原则,所有的文件复制均使用COPY 指令,仅在需要自动解压缩的场合使用 ADD 。

Dockerfile实例的更多相关文章

  1. 安装Nginx的Dockerfile实例

    #################################################Dockerfile to build Nginx Installed Containers##Bas ...

  2. dockerfile实例--安装nginx

    [root@localhost ~]# vi Dockerfile //ADD FROM centos_with_net MAINTAINER frankie onez0714@.com RUN yu ...

  3. 老司机实战Windows Server Docker:5 Windows Server Dockerfile葵花宝典

    前面两篇(简单运维1.简单运维2)介绍了一些Windows Server Docker相关的基本运维知识.今天这一篇,Windows Server Dockerfile葵花宝典,涵盖了许多典型场景的W ...

  4. 使用Dockerfile构建镜像

    Dockerfile是一个文本格式的配置文件,用户可以使用Dockerfile快速创建自定义的镜像.它类似shell脚本,由一行行命令组成,支持以#开头的注释行.一般而言,Dockerfile分为四部 ...

  5. 使用Dockerfile来构建镜像

    Dockerfile原理 创建Dockerfile Dockerfile实例 Dockerfile指令 注释 FROM MAINTAINER RUN ADD WORKDIR ENV USER COPY ...

  6. Docker容器学习梳理 - Dockerfile构建镜像

    在Docker的运用中,从下载镜像,启动容器,在容器中输入命令来运行程序,这些命令都是手工一条条往里输入的,无法重复利用,而且效率很低.所以就需要一 种文件或脚本,我们把想执行的操作以命令的方式写入其 ...

  7. Dockerfile语法解析

    Dockfile介绍 从上到下依次执行 每次执行一条指令就创建一个镜像层 第一条指令必须是FROM    表示需要构建的镜像是由哪个镜像为基础镜像   后续的指令运行于此基准镜像所提供的运行环境 可以 ...

  8. 如何运用多阶构建编写优雅的Dockerfile

    导读 Kubernetes要从容器化开始,而容器又需要从Dockerfile开始,本文将介绍如何写出一个优雅的Dockerfile文件. 文章主要内容包括: Docker容器 Dockerfile 使 ...

  9. web项目docker化的两种方法

    标题所讲的两种方法其实就是创建docker镜像的两种方法 第一种:启动镜像后进入容器中操作,将需要的软件或者项目移动到容器中,安装或者部署,然后退出即可 第二种:编写dockerfile,将需要的镜像 ...

随机推荐

  1. uiautomator2+python自动化测试1-环境准备

    前言 uiautomator是Google提供的用来做安卓自动化测试的一个Java库.功能很强,可以对第三方App进行测试,获取屏幕上任意一个APP的任意一个控件属性,并对其进行任意操作,但有两个缺点 ...

  2. 项目Alpha冲刺 7

    作业描述 课程: 软件工程1916|W(福州大学) 作业要求: 项目Alpha冲刺(团队) 团队名称: 火鸡堂 作业目标: 介绍第7天冲刺的项目进展.问题困难和心得体会 1.团队信息 队名:火鸡堂 队 ...

  3. destoon下动态链接301到伪静态(ngnix)

    分享一个destoon6.0/7.0下动态链接301到伪静态上面,实现权重提升. if ($request_uri ~* "^/index.php\?itemid=(\d+)&mod ...

  4. dt框架自定义url规则

    destoon的列表的地址规则是定义在/api/url.inc.php,然后又是在include/global.func.php中进行的listpages这个函数调用实现 if($page < ...

  5. wordpress调用指定post type文章怎么操作

    我们有时会用wordpress创建好几种post type文章,比如默认的post文章和product文章,如果我们要在每个页面的底部调用post type类型为post最新文章要如何操作呢?那我们就 ...

  6. 【Servlet】基于Jsp的微信Oauth2认证

    作者:yongh701 挂载到微信服务器上的应用程序,能够通过微信Oauth2认证,能够抓取到用户的微信信息,当然,你首先要通过微信的帐号资质审核. 一.基本思想 二.基本过程 1.登陆微信的公众平台 ...

  7. node 日志 log4js 错误日志记录

    SET DEBUG=mylog:* & npm start 原文出处:http://blog.fens.me/nodejs-log4js/ 1. 默认的控制台输出 我们使用express框架时 ...

  8. OLED液晶屏幕(2)取模软件

    https://blog.csdn.net/ling3ye/article/details/53399305 文件夹说明: Adafruit_SSD1306-master   ——SSD1306库(O ...

  9. win7虚拟机安装

    https://blog.csdn.net/qq_16503045/article/details/81904986 iso下载地址 https://msdn.itellyou.cn/

  10. 一篇来自hasura graphql-engine 百万级别live query 的实践

    转自:https://github.com/hasura/graphql-engine/blob/master/architecture/live-queries.md Scaling to 1 mi ...