Docker通过dockerfile
创建镜像时,RUN
和CMD
是相当重要的命令,本文对这RUN
指令进行解析。
RUN 语法
# shell形式,命令在shell中运行,默认情况下,Linux是/bin/sh -c、Windows是cmd /S /C .
RUN <command>
# exec形式.
RUN ["executable", "param1", "param2"]
RUN 语义
· RUN指令在当前镜像的顶层上新建层执行命令,同时提交执行结果。提交的结果会在接下来的dockerfile处理。
· 分层RUN
指令和生成提交符合Docker的核心理念,即:提交便利,容器可以依据任意历史镜像构建,像源代码管理一样。
· exec
形式能够避免shell
形式表达含义模糊的问题,同时能够在一个不包含shell
命令的基础镜像上执行RUN
指令。
· shell
形式的默认shell
可以通过SHELL
修改。
· shell
形式中,若是指令参数过长,可以使用\
换行显示。
# RUN 参数不换行.
RUN /bin/bash -c 'source $HOME/.bashrc; echo $HOME'
# RUN 参数换行.
RUN /bin/bash -c 'source $HOME/.bashrc; \
echo $HOME'
· exec
形式是按照JSON Array格式解析,意味着必须是使用双引号(")包含参数,而不能使用单引号(’)。
· 与shell
形式不同,exec
形式不会调用shell
命令行,意味着不会进行shell
处理。例如:运行RUN [ "echo", "$HOME" ]
不会对$HOME
进行变量替换。如果需要shell
处理,那么可以使用shell
形式或直接执行shell
,例如:RUN["sh","-c","echo $HOME"]
。当使用exec
形式直接执行shell
时,与shell
形式类似,应用的shell
是宿主机而非Docker。
· JSON形式,必须转义反斜杠\
。Windows系统中,反斜杠\
是路径分隔符,是需要特别关注的。否则,由于不是有效的JSON,执行时会出现异常从而失败。
RUN ["c:\windows\system32\tasklist.exe"]
此示例的正确语法是:
RUN ["c:\\windows\\system32\\tasklist.exe"]
· RUN
指令的缓存不会在下次构建时自动失效。RUN apt-get dist-upgrade -y
指令的缓存将在下次构建时重用。RUN
指令的缓存可以通过使用--no-cache
标志置为无效,例如:docker build --no-cache
。
· RUN
指令的缓存可由ADD
和COPY
指令置为无效。
RUN 示例
· 公共仓库中nginx:latest
镜像默认不包含vim
软件包。
1) 拉取nginx:latest镜像。
docker pull nginx
2) 查看镜像信息。
docker images
3) 指定镜像启动容器。
docker run --name securitit-nginx -d -p 80:80 nginx:latest
4) 查看容器信息。
docker ps -a
5) 进入容器内部,并输出vim
命令,确认vim
是否安装。
docker exec -it 1c8022c90ec4 /bin/bash
· 通过RUN指令构建新的镜像,使镜像带有vim命令。
1) 进入/securitit/dockerfile/目录(根据个人选择,这是本文使用的目录),创建dockerfile
文件。
FROM nginx:latest
MAINTAINER Securitit
RUN /bin/bash -c 'apt-get update && apt-get -y install vim'
CMD /bin/bash
2) 执行如下的构建命令,基于dockerfile
构建镜像。
docker build -f /securitit/dockerfile/dockerfile -t securitit-nginx-run:1.0.0.1 .
3) 查看镜像信息。
docker images
4) 指定通过dockerfile生成的镜像启动容器。
docker run --name securitit-nginx-run -it -d -p 10081:80 securitit-nginx-run:1.0.0.1
5) 查看容器信息。
docker ps -a
6) 进入容器内部,输出vim -version
,可以看到vim
命令已成功安装。
docker exec -it e518babc044e /bin/bash
总结
通过文中的两个例子,可以看到,通过RUN
指令可以对基础镜像进行一层改造,例如安装软件、修改配置等等内容,使得最终生成的镜像具有构建过程中涉及RUN
的内容。
若文中存在错误和不足,欢迎指正!。