Dockerfile 入门实践
一些事项
- 书写Dockerfile文件时,设定工作目录时,如果要忽略工作目录下的一些文件,可以使用
.dockerignore
文件 - 变量设定默认值:
${variable:-word}
,当variable
不存在或者为空是,最后的值为word
- 还有另一种格式:
${variable:+word}
,它表示当variable
存在或者为真时,则返回word
指令
FROM
- FROM <registry>:<tag>
COPY
- COPY <src> <dest>
- 其中src是上下文中的目录(工作目录或工作子目录);dest表示镜像中的目标路径
- 目录自身不会复制过去,但其内容会全部复制过去(下方会做实践)
- dest必须以
/
结尾,以表示目录 - 先来个简单的Dockerfile:
FROM docker.io/nginx:1.15-alpine
MAINTAINER "SUHANYU <suhanyujie@qq.com>"
COPY index.html /mydata/
- 此时进行构建:
docker build -t testnginx:v0.1.0 .
- 接着可以启动容器,并查看对应的目录
/mydata
下的文件index.html
是否存在:docker run --name myinginx1 --rm testnginx:v0.1.0 cat /mydata/index.html
- 接下来做个试验:将/etc/yum.repos.d目录下的文件复制到镜像中
- 在之前的Dockerfile内容基础上继续写:
FROM docker.io/nginx:1.15-alpine
MAINTAINER "SUHANYU <suhanyujie@qq.com>"
COPY index.html /mydata/
COPY yum.repos.d /mydata/yumRepos/
- 构建镜像:
docker build -t testnginx:v0.1.2 .
- 启动容器并查看:
docker run --name myinginx1 --rm testnginx:v0.1.2 ls /mydata/yumRepos
- 可以看到
yum.repos.d
目录本身并没有被拷贝进入/mydata/yumRepos
中
ADD
ADD <src> <dest>
- 向目标镜像文件中打包文件,如果
src
是上下文目录下的文件,并且是tar.gz之类的压缩文件,会进行解压到目标路径下。 src
如果是网络地址,则只会下载该文件,而不会解压。dest
代表目标路径,路径必须以/
结尾
ADD实践
- 在Dockerfile中使用ADD:
FROM docker.io/nginx:1.15-alpine
MAINTAINER "SUHANYU <suhanyujie@qq.com>"
COPY index.html /mydata/
COPY yum.repos.d /mydata/yumRepos/
ADD http://nginx.org/download/nginx-1.15.8.tar.gz /usr/local/nginx/
- 构建:
docker build -t testnginx:v0.1.3 .
,不要忘记后边有个.
- 启动容器,验证容器中是否存在下载后的文件:
docker run --name myinginx1 --rm testnginx:v0.1.3 ls /usr/local/nginx
[root@localhost t0117]# docker run --name myinginx1 --rm testnginx:v0.1.3 ls /usr/local/nginx
nginx-1.15.8.tar.gz
WORKDIR
- WORKDIR <dirpath>
- 用于为Dockerfile中所有的RUN、CMD、ENTRYPOINT、COPY、ADD等指令设定工作目录
实践WORKDIR
- 在Dockerfile中使用WORKDIR:
FROM docker.io/nginx:1.15-alpine
MAINTAINER "SUHANYU <suhanyujie@qq.com>"
COPY index.html /mydata/
COPY yum.repos.d /mydata/yumRepos/
WORKDIR /usr/local/nginx
ADD http://nginx.org/download/nginx-1.15.8.tar.gz ./src/
- 在上面的指令中,在镜像里,先将工作目录切换到
/usr/local/nginx
,然后下载nginx-1.15.8.tar.gz
文件到基于工作目录/usr/local/nginx
下的src
目录下 - 构建镜像:
docker build -t testnginx:v0.1.4 .
- 启动容器,验证容器中是否存在下载后的文件:
docker run --name myinginx1 --rm testnginx:v0.1.4 ls /usr/local/nginx/src
VOLUME
- VOLUME <mountPoint>
- 挂载数据卷
实践VOLUME
FROM docker.io/nginx:1.15-alpine
MAINTAINER "SUHANYU <suhanyujie@qq.com>"
COPY index.html /mydata/
COPY yum.repos.d /mydata/yumRepos/
WORKDIR /usr/local/nginx
ADD http://nginx.org/download/nginx-1.15.8.tar.gz ./src/
VOLUME /data/mysql
- 构建镜像:
docker build -t testnginx:v0.1.5 .
- 启动容器,并查看挂载的情况:
docker run --name myinginx1 --rm testnginx:v0.1.5 mount
- 此时可以看到显示的结果中有一行如下:
/dev/mapper/centos-root on /data/mysql type xfs (rw,relatime,attr2,inode64,noquota)
- 也可以使用
docker inspect {container}
的方式,查看挂载卷情况: - 启动容器:
docker run --name myinginx1 --rm testnginx:v0.1.5 sleep 60
- 此时,新开一个shell窗口,用命令行查看:
docker inspect testginx:v0.1.5
- 或者进入容器内部查看:
docker exec -it myinginx1 sh
- 可以看到存在文件夹:
/data/mysql
EXPOSE
- EXPOSE <port>[/protocol]
- 其中protocol是指协议,值为:tcp或udp,默认为tcp
- 也可暴露多个端口:
EXPOSE 80/tcp 91/udp
EXPOSE实践
- 编写Dockerfile:
FROM docker.io/nginx:1.15-alpine
MAINTAINER "SUHANYU <suhanyujie@qq.com>"
COPY index.html /mydata/
COPY yum.repos.d /mydata/yumRepos/
WORKDIR /usr/local/nginx
ADD nginx-1.15.8.tar.gz ./src/
VOLUME /data/mysql
EXPOSE 80/tcp
- 构建:
docker build -t testnginx:v0.1.6.1
- 运行:
docker run --name myinginx1 -P --rm testnginx:v0.1.6.1 sleep 60
-P
的作用就是暴露镜像中设定好的对外端口,而不用则命令行中额外指定- 此时可以查看
docker port myinginx1
,显示的是容器的端口对应宿主机上的端口
ENV
- ENV <key> <value>
- ENV <key>=<value>
- 为镜像定义所需的环境变量
- 第一种方式只能设置一个变量。第2中可以设置多个,如果value中包含空格,可以使用
\
转义
实践ENV
- 编写Dockerfile
FROM docker.io/nginx:1.15-alpine
MAINTAINER "SUHANYU <suhanyujie@qq.com>"
COPY index.html /mydata/
COPY yum.repos.d /mydata/yumRepos/
ENV PACKAGE_NAME=/nginx-1.15.8
WORKDIR /usr/local/nginx
ADD ${PACKAGE_NAME}.tar.gz ./src/
VOLUME /data/mysql
EXPOSE 80/tcp
- 构建:
docker build -t testnginx:v0.1.7 .
- 启动:
docker run --name myinginx1 -P --rm testnginx:v0.1.7 ls /usr/local/nginx/src/nginx-1.15.8
- 此时之前的将nginx包放入镜像中的操作还是正常运行的。
- 以上,是在build阶段,设定好环境变量,实际上在容器启动阶段,也可以进行设定环境变量,可以通过
docker run --help
查看命令,其中有一个-e
参数,可以在run阶段设定环境变量
CMD
- CMD <command>
- CMD ["<executable>","<param1>","<param2>"]
- CMD ["<param1>","<param2>"]
- Dockerfile中可以有多个CMD指令,但只有最后一个会生效
- 第3种方式,没有命令只有参数,它的作用可以用于为
ENTRYPOINT
提供参数
ENTRYPOINT
- ENTRYPOINT [<"excutable","param1","param2">]
- 启动容器时,可以使用自定义的命令覆盖镜像中默认的命令
ENTRYPOINT实践
- 编写Dockerfile
FROM docker.io/nginx:1.15-alpine
MAINTAINER "SUHANYU <suhanyujie@qq.com>"
COPY index.html /mydata/
COPY yum.repos.d /mydata/yumRepos/
ENV PACKAGE_NAME=nginx-1.15.8
WORKDIR /usr/local/nginx
#ADD ${PACKAGE_NAME}.tar.gz ./src/
COPY ${PACKAGE_NAME}.tar.gz ./src/
#ADD http://nginx.org/download/${PACKAGE_NAME}.tar.gz ./src/
RUN mkdir -p /data/nginx && \
tar xf ./src/${PACKAGE_NAME}.tar.gz -C /data/nginx
ADD entrypoint.sh /bin/
VOLUME /data/mysql
EXPOSE 80/tcp
CMD ["/usr/sbin/nginx","-g","daemon off;"]
ENTRYPOINT ["/bin/entrypoint.sh"]
- 其中entrypoint.sh的内容如下:
#!/bin/sh
#
cat > /etc/nginx/conf.d/www.conf << EOF
server{
server_name $HOSTNAME;
listen ${IP:-0.0.0.0}:${PORT:-80};
root ${NGX_DOC_ROOT:-/usr/share/nginx/html};
}
EOF
exec "$@";
- 注意,在ENTRYPOINT的命令里,不可写成
ENTRYPOINT ["/bin/entrypoint.sh;"]
,也即是不能加上分号 - 构建:
docker build -t testnginx:v0.1.9.14 .
- 启动容器查看:
docker run --name myinginx1 -P --rm testnginx:v0.1.9.14 ls /bin
USER
- USER <uid>/<userName>
- 运行容器时指定用户名或用户id
HEALTHCHECK
- HEALTHCHECK <option> <command>
- 健康检查,检查容器的状态是否正常
- 例如:
HEALTHCHECK --start-period=3s CMD wget -0 - -q http://${IP:-0.0.0.0}:${PORT:-80}/
ARG
- ARG <name>[=<default value>]
- 适用于build时
- 在构建的命令中,可以使用
--build-arg <name>=<value>
进行设定
ARG实践
- 例如在编写Dockerfile时:
FROM docker.io/nginx:1.15-alpine
#MAINTAINER "SUHANYU <suhanyujie@qq.com>"
ARG maintainer="SUHANYU <suhanyujie@qq.com>"
LABEL "maintainer ${maintainer}"
COPY index.html /mydata/
COPY yum.repos.d /mydata/yumRepos/
ENV PACKAGE_NAME=nginx-1.15.8
WORKDIR /usr/local/nginx
#ADD ${PACKAGE_NAME}.tar.gz ./src/
COPY ${PACKAGE_NAME}.tar.gz ./src/
#ADD http://nginx.org/download/${PACKAGE_NAME}.tar.gz ./src/
RUN mkdir -p /data/nginx && \
tar xf ./src/${PACKAGE_NAME}.tar.gz -C /data/nginx
ADD entrypoint.sh /bin/
VOLUME /data/mysql
EXPOSE 80/tcp
CMD ["/usr/sbin/nginx","-g","daemon off;"]
ENTRYPOINT ["/bin/entrypoint.sh"]
- 构建:
docker build -t testnginx:v.0.1.10.1 .
- 查看:
docker image inspect testnginx:v0.1.10.1
- 此时,可以看到其中的LABEL中有所设定的值
- 重新构建,在构建的命令中设定arg:
docker build --build-arg maintainer="<suhanyujie@qq.com>" -t testnginx:v0.1.10.2 .
- 查看:
docker image inspect testnginx:v0.1.10.2
- 此时,可以在输出中看到,包含如下的LABEL内容:
"Labels": {
"maintainer": "<suhanyujie@qq.com>"
},
ONBUILD
- ONBUILD <instruction>
- 在Dockerfile中定义一个触发器
- 例如你已经构建了一个镜像
testnginx:v0.1.10.1
,并且在你构建testnginx:v0.1.10.1
时,你使用了ONBUILD
。在此基础上,如果构建一个新的镜像是,并且是FROM testnginx:v0.1.10.1
,此时构建这个新镜像时就会触发执行上一个镜像的ONBUILD
所对应的指令。
RUN
RUN
* RUN <command>
* RUN ["<executable>","<param1>","<param2>"]
* 第1中方式中,command通常是一个shell命令,以 `/bin/sh -c` 的方式运行
- RUN <command>
- RUN ["<executable>","<param1>","<param2>"]
- 如果要运行的命令依赖于shell特性,可以使用如下的方式:
RUN ["/bin/sh","-c","<executable>","<param1>"]
其他
- 运行在docker容器中的服务,一般是shell的子进程
- 在linux系统中,后台运行的服务程序一般是init的子进程,也就是管理进程的子进程