Dockerfile指令详解

Dockerfile指令详解

FROM指定基础镜像

  • 定制镜像一定是以一个镜像为基础的,FROM就是指定基础镜像的指令,它是必备的第一条指令。
  • 基础镜像可以是
    • 服务类镜像:nginx、redis、mongo、mysql、httpd、tomcat
    • 也可以是语言运行环境镜像:node、openjdk、python、ruby、golang
    • 还可以是更基础操作系统镜像:ubuntu、debian、centos、fedora、alpine
    • 还可以是scratch,表示空白镜像

RUN执行命令

  • RUN是用来执行命令行命令的,其有两种格式:

    • shell格式:RUN <命令>,如RUN apt-get install -y gcc

    • exec格式:RUN ["可执行文件或命令", "参数1", "参数2", ...],如RUN ["apt-get", "install", "-y", "gcc"]

    • 每写一个RUN,镜像就会多一层,

      建议写成

      RUN 命令1&&命令2&&命令3
      

      而不是

      RUN 命令1
      RUN 命令2
      RUN 命令3
      

COPY复制文件

  • COPY有两种格式:

    • shell格式:RUN [--chown=<user>:<group>] <源路径>... <目标路径>

    • exec格式:COPY [--chown=<user>:<group>] ["<源路径1>",... "<目标路径>"]

    • 其中--chown=<user>:<group>是可选参数,会改变复制到镜像内的拥有者和所属组

    • 源文件可以是通配符表达式,规则要满足于 Gofilepath.Match

      COPY hom* /mydir/
      COPY hom?.txt /mydir/
      
    • 目标路径可以是容器内的绝对路径,也可以是相对于工作目录的相对路径(工作目录可以用WORKDIR指令来指定)。目标路径不需要事先创建,如果目标目录不存在会在复制文件前先行创建

ADD更高级的复制文件

  • ADD和COPY的格式和性质基本一致,但是在COPY基础上增加了一些功能,既如果源路径为一个tar压缩文件,压缩格式为gzipbzip2以及xz时,ADD指令会将其解压到目标路径,如

    FROM scratch
    ADD ubuntu-xenial-core-clouding-amd64-root.tar.gz /
    

CMD容器启动命令

  • 类似于RUN指令,但二者运行的时间点不同
    • CMDdocker run时运行(docker start不运行也会运行,即容器启动就会运行)
    • RUN是在docker build时运行
  • CMDdocker run启动的容器指定默认要运行的程序,程序运行结束,容器也就结束了
  • CMD指令指定的程序可被docker run命令行参数中指定要运行的程序所覆盖
  • 如果Dockerfile中存在多个CMD指令,仅最后一个生效
  • CMD有三种格式,分别是:
    • shell格式:CMD <shell命令>
    • exec格式:CMD ["可执行文件或命令", "参数1", "参数2", ...]
    • 参数列表格式:CMD ["参数1", "参数2", ...] #该写法是为ENTRYPOINT指令指定的程序提供默认参数

ENTRYPOINT

  • 类似于CMD指令,但不会被docker run的命令行参数指定的指令所覆盖,而且这些命令行参数会被当做参数送给ENTRYPOINT指令指定的程序。只有使用了--entrypoint才可以覆盖ENTRYPOINT指令指定的程序
  • Dockerfile中有多个ENTRYPOINT时,仅最后一个生效
  • 可以搭配CMD使用,此时CMD相当于是在给ENTRYPOINT传参,当在docker run中指定参数时,docker run中的参数会取代CMD的参数传递给ENTRYPOINT指定的命令

ENV设置环境变量

  • 用于设置环境变量,定义了环境变量,在后续的指令中就可以使用这个环境变量

  • 格式

    • ENV <key> <value>
    • ENV <key1>=<value1> <key2>=<value2>
  • 使用示例

    ENV NODE_VERSION 7.2.0
    RUN curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-  x64.tar.xz" && curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc"
    

ARG构建参数

  • 构建参数,与ENV作用一致,但作用域不相同。ARG设置的环境变量仅在docker build的过程中有效,构建好的镜像内不存在此变量
  • ARG指定的参数值在docker build时可以用--build-arg <参数名>=<值>来覆盖
  • 格式:ARG <参数名>[=<默认值>]

VOLUMN定义匿名卷

  • 格式为:
    • VOLUMN ["<路径1>", "路径2"...]
    • VOLUMN <路径>
  • 为了防止容器内的重要数据因为容器重启而丢失,且避免容器不断变大,应该将容器内的某些目录挂载到宿主机上。
  • Dockerfile中,我们可以事先指定某些目录挂载为匿名卷,这样在docker run时若用户不用-v指定挂载,那么就会将Dockerfile中用VOLUMN指定的目录挂载为匿名卷,否则按-v的指定进行挂载

EXPOSE声明端口

  • 格式:EXPOSE <端口1> [<端口2> ...]

  • EXPOSE指定了该镜像生成容器时提供服务的端口,可以配合docker run -P(大写)使用,也可以配合docker run --net=host使用

    • 举例

      FROM nginx
      EXPOSE 80
      

      docker build -t nginx:test .

      • 以上指令指定了该镜像生成容器时,容器内提供服务的端口为80

      • 当执行命令docker run --name nginxtest -d -P nginx:test时,会随机将宿主机上某个端口映射到容器的80端口

      • 当执行命令docker run --name nginxtest -d --net=host nginx:test时,会将宿主机上的80端口映射到容器的80端口(可以暂时这么理解)

  • 要将EXPOSE和-p <宿主机端口>:<容器端口>区分开来,前者只是声明了容器将用什么端口提供服务,后者则是手动指定了宿主机和容器端口的映射

WORKDIR指定工作目录

  • 格式:WORKDIR <工作目录路径(必须是提前创建好的)>

  • 比较

    • # 示例1
      RUN cd /app
      RUN echo "hello" > hello.txt
      
    • # 示例2
      WORKDIR /app
      RUN echo "hello" > hello.txt
      
    • 示例1中因为两个RUN是不同层,所以hello.txt文件并不会出现在/app目录下

    • 示例2中用WORKDIR指定了工作路径,之后所有指令中的当前目录都是/app

USER指定当前用户

  • 格式:USER <用户名>[:<用户组>]

  • USER指令和WORKDIR相似,都是改变环境并影响以后的层。WORKDIR是改变工作目录,USER是改变之后各层中命令(由RUNCMDENTRYPOINT指令指定)的执行用户

    • 举例

      RUN groupadd -r redis && useradd -r -g redis redis
      USER redis
      RUN [ "redis-server" ]
      

      由于USER redis指令,所以redis-server这个命令由redis用户执行的

  • USER指令指定的用户必须是事先建立好的

HEALTHCHECK健康检查

  • 格式:

    • HEALTHCHECK [选项] CMD <命令>:设置检查容器健康状况的命令
    • HEALTHCHECK NONE:如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令
  • HEALTHCHECK指令是告诉Docker应该如何判断容器的状态是否正常,这是Docker1.12引入的新指令

  • 在没有HEALTHCHECK指令之前,Docker引擎只可以通过容器内主进程是否退出来判断容器状态是否异常。很多情况这没问题,但是当程序进入死锁或死循环状态,应用进程不退出,但已经无法提供服务了。在Docker1.12之前,Docker对此并无办法。

  • Docker1.12之后,Docker提供了HEALTHCHECK指令,通过该指令指定一行命令,用这行命令来判断容器主进程是否服务正常,可以更真实的反应容器实际状态

  • 当在Dockerfile中指定了HEALTHCHECK指令后,用其镜像启动的容器初始状态会为starting,在HEALTHCHECK指令检查成功后变为healthy,如果连续失败一定次数,则会变为unhealthy

  • HEALTHCHECK支持下列指令

    • --interval=<间隔>:两次健康检查的间隔,默认为30秒
    • --timeout=<时长>:健康检查命令执行后,等待响应的超时时间,如果超过这个时间,本次健康检查视为失败,默认为30秒
    • --retries=<次数>:当连续失败指定的次数后,则将容器状态视为unhealthy,默认3次
  • CMDENTRYPOINT一样,HEALTHCHECK只可以出现一次,如果写了多个,只有最后一个生效

  • HEALTHCHECK [选项] CMD后面的命令,格式和ENTRYPOINT一样,分为shellexec格式。命令的返回值决定了该次健康检查的成功与否:0-成功;1-失败;2-保留,不要使用2这个值。

  • 举例

    • 假设我们有个镜像是个最简单的Web服务,我们希望增加健康检查来判断其Web服务是否在正常工作,我们可以用curl来帮助判断,其DockerfileHEALTHCHECK可以这么写:

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

      这里设置了每5秒检查一次,如果健康检查命令超过3秒没响应就视为失败,并且使用curl -fs http://localhost/ || exit 1作为健康检查命令

      使用docker build来构建这个镜像

      $ docker build -t myweb:v1 .
      

      构建好之后,启动容器:

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

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

      $ docker container ls
      CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                            PORTS               NAMES
      03e28eb00bd0        myweb:v1            "nginx -g 'daemon off"   3 seconds ago       Up 2 seconds (health: starting)   80/tcp, 443/tcp     web
      

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

      $ docker container ls
      CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                    PORTS               NAMES
      03e28eb00bd0        myweb:v1            "nginx -g 'daemon off"   18 seconds ago      Up 16 seconds (healthy)   80/tcp, 443/tcp     web
      

      如果健康检查连续失败超过了重试次数,状态就会变为(unhealthy)

      为了帮助排障,健康检查命令的输出(包括stdoutstderr)都会被存储在健康状态里,可以用docker inspect查看

      $ docker inspect --format '{{json .State.Health}}' web | python -m json.tool
      {
          "FailingStreak": 0,
          "Log": [
              {
                  "End": "2016-11-25T14:35:37.940957051Z",
                  "ExitCode": 0,
                  "Output": "<!DOCTYPE html>\n<html>\n<head>\n<title>Welcome to nginx!</title>\n<style>\n    body {\n        width: 35em;\n        margin: 0 auto;\n        font-family: Tahoma, Verdana, Arial, sans-serif;\n    }\n</style>\n</head>\n<body>\n<h1>Welcome to nginx!</h1>\n<p>If you see this page, the nginx web server is successfully installed and\nworking. Further configuration is required.</p>\n\n<p>For online documentation and support please refer to\n<a href=\"http://nginx.org/\">nginx.org</a>.<br/>\nCommercial 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"
      }
      

ONBUILD为他人做嫁衣

  • 格式:ONBUILD <其他指令>
  • ONBUILD是一个特殊的命令,它后面跟的是其他指令,比如RUN,COPY等,而这些指令,在当前镜像构建时并不会被执行。只有当以当前镜像为基础,去构建新镜像时才被执行

参考

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容