Dockerfile 入门实践

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的子进程,也就是管理进程的子进程
原文地址:https://www.cnblogs.com/wxwgk/p/11695949.html