FROM 指定基础镜像

FROM centos:centos7


MAINTAINER 指定作者信息

MAINTAINER "qiyang <qiyang@email.com>"


LABEL 为一个镜像指定元数据,包括作者信息等

LABEL <key>=<value> <key>=<value>
LABEL maintainer="qiyang <qiyang@email.com>"


RUN 一个RUN命令即构建一层镜像。

RUN buildDeps='gcc libc6-dev make' \      #像shell一样可以定义变量
    && yum install -y $buildDeps \
    && mkdir /tmp


COPY  源路径  镜像中的位置 ,就是把dockerfile上下文位置的文件拷贝到镜像中。

可以用Go语言的通配符

注意:将文件拷贝到目录必须用斜杠“/”结尾。

COPY hom* /usr/local/app/
COPY hom?.txt /usr/local/app/
COPY file1.txt file2.txt /app/data/


ADD 高级复制目录

        可以下载文件,下载的文件位600权限,调整权限或修改文件都需要使用RUN增加一层。如果是gzip2,bzip2、xz 的情况下会自动解压缩这个文件,可以下载远程文件。建议只有在需要解压的的情况下使用ADD,其他情况下都是用COPY。

自动解压:

ADD demo.tar.gz /data/

下载远程文件:

ADD chuxiangyi.com/index.html /data/


CMD  用于指定容器默认主进程的启动命令。

        格式一(shell):CMD command

        格式二(exec):CMD ["command","param","param"...]

        格式三:CMD ["param","param"...] 这些参数传给 ENTRYPOINT 作为你 ENTRYPOINT 命令的参数。

如默认情况下centos镜像默认执行的命令是/bin/bash,我们可以使用CMD命令改变默认执行的命令。

docker run --name ceonts1 -it centos cat /etc/centos-release

        比如说制作centos镜像最后的CMD为:CMD ["/bin/sh","-c"],在docker run 的时候后面的 cat /etc/centos-release 替换的就是CMD括号内的命令。

        格式一与格式二的相同之处:CMD echo $HOME 会被解析成 CMD ["/bin/sh","-c","echo $Home"] ,其中 -c 的意思为从字符串中获取命令。

        运行nginx命令:使用service启动nginx是错误的,因为使用service命令是让进程运行在后台。下面是正确的做法。

CMD ["nginx", "-g", "daemon off;"]


ENTRYPOINT  同CMD。

        格式一(shell):ENTRYPOINT command

        格式二(exec):ENTRYPOINT ["command","param","param"...]

        格式三:ENTRYPOINT CMD,使用方法如下:

CMD ["param","param"...] 
ENTRYPOINT command

        CMD 里面的参数传给 ENTRYPOINT 作为 ENTRYPOINT 命令的参数。也就是说当使用 ENTRYPOINT 命令时 CMD 命令的意义就是为 ENTRYPOINT 传参。

CMD ["-f","-h","/data"]  #传参给下面的命令
ENTRYPOINT ["bin/httpd"]

        如上面这个示例,实际运行的指令是 /bin/httpd -h /data 。

        要想在docker run时替换默认的命令,要使用 --entrypoint 参数。

ENTRYPOINT的作用:

        在命令行使用 docker run name 时,如果后面有参数如:docker run name -h 这个后面的 -h 就可以作为参数传给 ENTRYPOINT。这样就可以在镜像制作好之后改变镜像默认运行的参数。

        在运行默认程序时做一些初始化的工作。如下面的例子,默认情况下-a作为init.sh脚本的参数,可以在运行脚本的时候传入其他参数代替-a这个默认参数。

ENTRYPOINT ["init.sh"]
CMD ["-a"]

示例:

FROM busybox:latest
MAINTAINER "qiyang"
RUN mkdir -p /data1/ &&  mkdir -p /data2/ && echo 'data1' > /data1/index.html && echo 'data2' > /data2/index.html
ENTRYPOINT ["/bin/httpd","-f","-h"]
CMD ["/data1/"]

docker build -t test:1.1 .

docker run --name b1 -it test:1.1 /data1

docker run --name b1 -it test:1.1 /data2

如上所示,当传入不同的目录/data1 或/data2 时就会使用不同的文档目录。


ENV 设置环境变量,同shell。这个变量不能再CMD和ENTRYPOINT中使用。

ENV VERSION=1.0 DEBUG=on \
    NAME="hello world"
ENV NAME hello


ARG  同ENV,不同的是设置的环境变量在实际的容器中不会保留。一个ARG只能设置一个键值对。

可以在创建镜像时修改ARG的值。如下示例,后面的version就是要修改的值。

docker build -t test:1.1 --build-arg version=1.2


VOLUME  定义匿名卷,这个卷指定的是镜像内的位置而不是宿主机的位置。

        VOLUME path

        VOLUME ["path","path"]

在运行容器时可以覆盖这个默认设置 docker run --name b1 -d -v /mydata:/data mysql:latest

        volume 是用来挂载宿主机上的目录到容器的,VOLUME 只能够指定容器中目录的位置,没办法指定宿主机的目录位置,只能在docker run 的时候使用 -v 参数来指定。

        因为只能指定容器中的目录位置,那么宿主机的位置在哪里了呢,使用命令 docker inspect -f {{.Mounts}} container_name 来查看。

        需要注意的是,如果在创建容器时没有使用 --rm 参数,volume是不会被删除的,需要使用 docker container rm -v container_name 来参数容器的同时一起删除 Volume。如果这两种方法都没有使用那么可能有很多 Volume 任然占用着空间。


EXPOSE  声明端口,使用 -P 可以暴露默认端口。

可以在运行容器时使用-p来替换 docker run --name web1 -d -p 8080:80 nginx:latest

-p <宿主IP>:<宿主端口>:<容器端口>

EXPOSE 在 Dockerfile 中的使用:

EXPOSE [port]:[protocol] [port]:[protocol] ...

EXPOSE 80/tcp 80/udp 443/tcp
EXPOSE 80


WORKDIR  指定工作目录

        这个目录必须存在,可以指定多次,影响到后面的层,指定的这个位置是容器内的位置,可用ENV定义。

WORKDIR /usr/local/src/


USER  指定当前用户

切换到指定用户,影响到后面的层,这个用户必须存在。

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


HEALTHCHECK  健康检查

HEALTHCHECK [选项] CMD

        HEALTHCHECK 指令是告诉 Docker 应该如何进行判断容器的状态是否正常。如果程序进入死锁状态,或者死循环状态,应用进程并不退出,但是该容器已经无法提供服务了,通过该指令指定一行命令,用这行命令来判断容器主进程的服务状态是否还正常。

        HEALTHCHECK 只可以出现一次。

        --interval=<间隔>

        --timeout=<时长>

        --retries=<次数>

        命令的返回值决定了该次健康检查的成功与否: 0 :成功; 1 :失败; 2 :保留,不要使用这个值。

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

使用 docker container ls -a 查看状态:

3 seconds ago Up 2 seconds (health: starting) 80/tcp, 443/tcp web

最初的状态为 (health:starting)

健康状态:healthy

不健康状态:unhealthy

健康查询的输出法可以用 docker inspect 来查看。

docker inspect --format '{{json .State.Health}}' web | python -m json.tool


ONBUILD  以当前镜像作为基础制作的镜像才会被执行。

ONBUILD <其它指令> 其他指令为COPY、RUN等。

        将某个镜像作为基础镜像时,以这个镜像构建镜像时构建出来的镜像可以继承基础镜像上的变化。

基础镜像的Dockerfile,命名为my-node

FROM node:slim
RUN "mkdir /app"
WORKDIR /app
ONBUILD COPY ./package.json /app
ONBUILD RUN [ "npm", "install" ]
ONBUILD COPY . /app/
CMD [ "npm", "start" ]


官方写好的常用镜像:

github.com/docker-library


时区问题解决:

FROM centos:7

RUN yum install -y tzdata
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

CMD ["date"]


常见示例:

Java Dockerfile:

FROM centos:7

ADD jdk-8u291-linux-x64.tar.gz /opt/
# 或
# ADD jdk-11.0.12_linux-x64_bin.tar.gz /opt/

ENV JAVA_HOME /opt/jdk1.8.0_291
# 或
# ENV JAVA_HOME /opt/jdk-11.0.12
ENV PATH $JAVA_HOME/bin:$PATH

CMD ["java", "-version"]