Dockerfile 作用
定制自己的镜像,明确的把修改,安装,构建操作等指定都写入其中,描述该层是如何创建的
docker commit可以实现同样的功能(在容器中安装某些软件之后,提交到基础镜像中形成新的镜像),但是commit安装了什么,如何安装的都是黑盒,后面使用该镜像的人无从得知执行了哪些指令
Dockerfile指令
docker build 其他用法
标准用法
docker build -t image_name PATH
在PATH目录下,按照Dockerfile建立一个新的image_name镜像
path指的是上下文环境,当构建的时候,用户会指定构建镜像上下文的路径,docker build 命令得知这个路径后,会将路径下的所有内容打包,然后上传给 Docker 引擎,这样 Docker 引擎收到这个上下文包后,展开就会获得构建镜像所需的一切文件
直接用 Git repo 进行构建
docker build https://github.com/twang2218/gitlab-ce-zh.git#:8.14
指定了构建所需的 Git repo,并且指定默认的 master 分支,构建目录为 /8.14/,然后 Docker 就会自己去 git clone 这个项目、切换到指定分支、并进入到指定目录后开始构建
用给定的 tar 压缩包构建
docker build http://server/context.tar.gz
Docker 引擎会下载这个包,并自动解压缩,以其作为上下文,开始构建
从标准输入中读取 Dockerfile 进行构建
docker build - < Dockerfile或者cat Dockerfile | docker build -
如果标准输入传入的是文本文件,则将其视为 Dockerfile,并开始构建。这种形式由于直接从标准输入中读取 Dockerfile 的内容,它没有上下文,因此不可以像其他方法那样可以将本地文件 COPY 进镜像之类的事情
从标准输入中读取上下文压缩包进行构建
docker build - < context.tar.gz
如果发现标准输入的文件格式是 gzip、bzip2 以及 xz 的话,将会使其为上下文压缩包,直接将其展开,将里面视为上下文,并开始构建
From
指定基础镜像,在其上进行定制
RUN
执行命令行的命令,比如:RUN apt-get update是执行apt-get update命令
执行此命令的时候需要注意,在Dockerfile中没执行一个指令都会新建一层(目前有个最大层的限制是127层),所以每执行一个RUN就会和我们在执行安装软件然后执行commit一样,苟静一层镜像。因此在执行多个命令的时候使用"&"符连接,用一个RUN执行,这样就只会新建一个层
不可这样:
RUN apt-get update
RUN apt-get -y install vim
应当改为:
RUN apt-get update \
&& apt-get -y install vim
COPY source_path target_path
将本地的source_path复制到新的一层镜像内的target_path位置(如果source_path是相对路径,那么需要注意的是他是相对于docker build -t image_name PATH时指定的PATH也就是上下文环境)
source_path支持通配符
target_path可以是容器的绝对路径,也可以是相对于工作目录的相对路径(工作目录用WORKDIR指令来指定)
需要注意的是所有的source_path的文件属性都会保留(包含读写执行权限等)
ADD source_path target_path
使用方式和COPY一样,但是添加了一些新的功能
source_path可以是一个 URL,这种情况下,Docker 引擎会试图去下载这个链接的文件放到 target_path去。下载后的文件权限自动设置为 600,另外,如果下载的是个压缩包,需要解压缩,如果对权限不满足或者需要进行解压缩,那就需要再使用RUN命令调整
如果source_path是一个tar压缩文件的话,ADD会将文件解压缩后到target_path中
CMD
CMD与RUN类似
shell格式:CMD 命令
exec格式:CMD ["可执行文件", "参数1", "参数2"...]
参数列表格式:CMD ["参数1", "参数2"...]。在指定了 ENTRYPOINT 指令后,用 CMD 指定具体的参数
需要注意的是:Docker 不是虚拟机,容器就是进程,容器就是为了主进程而存在的,主进程退出,容器就失去了存在的意义,从而退出,其它辅助进程不是它需要关心的东西(这块实验并没有成功,暂时忽略,有坑能想到这块就行)
什么意思呢?重启nginx的时候可能会写成这样:CMD service nginx start
在执行的时候会被理解为:CMD [ "sh", "-c", "service nginx start"],因此主进程实际是sh,当service nginx start结束之后,sh也就结束了,sh作为主进程退出,自然容器也就退出了
正确的做法是直接执行nginx可执行文件
CMD ["nginx", "-g", "daemon off;"]
ENTRYPOINT
和cmd的命令差不多,两个应用场景
1、启动一个服务前的准备工作
FROM alpine:3.4
...
RUN addgroup -S redis && adduser -S -G redis redis
...
ENTRYPOINT ["docker-entrypoint.sh"]
EXPOSE 6379
CMD [ "redis-server" ]
docker-entrypoint.sh的脚本
#!/bin/sh
...
# allow the container to be started with `--user`
if [ "$1" = 'redis-server' -a "$(id -u)" = '0' ]; then
chown -R redis .
exec su-exec redis "$0" "$@"
fi
exec "$@"
这时候的ENTRYPOINT会判断CMD的内容,如果是redis-server就切换redis用户身份启动服务器,否则用root身份执行
2、让镜像像命令一样
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 run container_name就会执行curl http://ip.cn
如果这个时候我想显示当前的http头信息,就需要加上-i的参数了,假如我们执行docker run container_name -I 命令会变成curl -I http://ip.cn?
记住在镜像的后面只能跟command,运行时会替换CMD的默认值,所以在这里的-i是把整个的CMD给替换了,而-I这个命令是不存在的,显然我们需要docker run container_name curl -I http://ip.cn这么写
如果我们换成这种写法
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 container_name就能获取header信息
因为CMD的内容将会作为参数传给ENTRYPOINT,因此原本命令是curl http://ip.cn,CMD命令是-I所以最终执行的命令是curl -I http://ip.cn
ENV设置环境变量
ENV key val
ENV key1=val1 key2=val2
ENV VERSION=1.01 NAME="TEST"
ARG构建参数
ARG key=val
和ENV一样是设置环境变量,ARG构建的环境变量,在容器运行时不会存在这些环境变量(貌似就是一个临时的环境变量的概念,但是他能用docker history查看,所以不要以为真的是临时变量,直接传入账号密码)
VOLUME定义匿名卷
容器运行的时候,我们应该尽量保持容器存储层不发生写操作,对于数据库类需要动态保存数据的应用/或者上传文件的目录,我们应该把这些文件保存在卷中,比如在Dockerfile中,我们事先指定 /data/mysqldata为匿名卷,这样做会保证容器存储层无变化,说白了就是你把当前的容器做build的时候不会把mysqldata文件给打包进去
VOLUME /data/mysqldata
在执行:docker run -d -v mydata:/data/mysqldata container_name的时候是可以覆盖掉匿名卷的
EXPOSE暴露端口
EXPOSE 端口1 端口2
这样写在容器运行的时候也不会开启这个端口的服务
他有两个作用:提醒,告诉镜像使用者理解这个服务的使用的端口;占用随机应用端口,
WORKDIR指定工作目录
指定工作目录,以后各层的当前目录就改为指定的目录
USER指定当前用户
切换到指定用户,该用户必须事先存在
HEALTHCHECK健康检查
--interval 两次健康检查的间隔时间
--timeout 监看检查命令运行超时时间,如果超过这个时间,本次健康检查视为失败,默认30s
--retries 当连续失败命令运行
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
这里设置每隔5s检查一次,如果健康检查命令超过3s没响应就视为失败,并使用curl -fs http://localhost/ || exit 1作为健康检查命令
onbulid
他后面跟其他的指令,例如RUN,COPY等,而这些指令,在当前镜像构建时并不会被执行,只有当以当前镜像为基础镜像,去构建下一级镜像的时候才会被执行
1、先编写一个Dockerfile文件,内容如下:
FROM web1
ONBUILD RUN mkdir /test
2、利用上面的Dockerfile构建镜像:docker build -t web1
这个时候你在web1镜像中不会看到有/test文件夹
3、在编写一个Dockerfile,内容如下
FROM web1
4、构建镜像:docker build -t web2
这个时候你会看到镜像web2中有/test文件夹
.dockerignore
如果在docker build指定的上下文环境中有不需要COPY的文件,可以像.gitignore这样的语法写在.dockerignore
.path/*
.file_name