美文网首页
5. dockerfile

5. dockerfile

作者: epiiplus1equal0 | 来源:发表于2019-09-25 22:54 被阅读0次

dockerfile

本文基于马哥的docker和k8s视频总结, 在此致谢马哥.

  • 惜字如金! 尽量减少新增行, 因为每新增一行, 都会多一层封装, 从而降低容器性能
  • 尽量减少不必要的文件以缩小容器体积
about dockerfile.png dockerfile format.png

指令不区分大小写, 不过一般预定俗成使用大写

指令顺序执行

第一个非注释行必须使用 FROM 指令: 用于指定制作的当前进行基于哪个基础镜像实现

mkdir ~/img1     # 制作镜像时需要使用专门工作目录
vim Dockerfile # Dockfile文件的文件名首字母必须大写!
  • 排除名单, 支持通配:
.dockerignore file.png
  • 制作镜像时可以使用环境变量:
environment replacement.png
${variable:-word} # 如果变量未设置或者变量存在但是值为空, 则将引用默认值word
${variable:+word} # 如果变量有值且非空, 则改值为tom, 无值则不设置, 相当于满足条件才做修改

docker指令制作docker镜像

docker image build --help

Usage:  docker build [OPTIONS] PATH | URL | - # PATH: Dockerfile文件所在目录
Build an image from a Dockerfile

Options:
  -q, --quiet   Suppress the build output and print image ID on success
      --rm      Remove intermediate containers after a successful build (default true)
  -t, --tag list    Name and optionally a tag in the 'name:tag' format
docker image build -t tianjunchang/nginx:v0.1 ./ # 用从当前的Dockerfile制作镜像

FROM

  • 建议使用hash码的方式制作镜像
docker instruction.png
FROM nginx.1.16.1

MAINTANIER和LABEL

  • 用于标注作者信息, MAINTAINER方式已被废弃
docker instruction2.png docker instruction3.png
MAINTAINER "Alex Ti <1054083247@qq.com>"
LABEL maintainer="Alex Ti <1054083247@qq.com>" \
      location="Hangzhou Zhejiang China"

COPY

  • 目录后面一定要加 "/", 语法强制要求
  • 来源目录只能来自于Dockerfile的父目录, 即制作镜像时专门的工作目录及其子目录, 需要使用的文件或目录必须拷贝到工作目录中, Dockerfile中才能引用
docker instruction4.png
COPY "yum.repo.d/" "/etc/yum.repo.d/"
COPY "index.html" "${DOC_ROOT:-/data/web/html/}"
 # 将工作目录的子目录yum.repo.d中的所有内容复制到镜像的/etc/yum.repo.d/目录下
 # 将index.html复制到变量DOC_ROOT所引用的目录下, 如果目录不存在时复制到/data/web/html目录下
 # 目标目录不存在时会被自动创建

ADD

add.png
ADD "http://nginx.org/download/nginx-1.16.1.tar.gz" "/usr/local/src/"
# 注意下载的gz文件没有被解压! 想要解压归档文件时还需要使用其他命令
WORKDIR /usr/local/src/ # 也可以直接 RUN cd /usr/local/src/
RUN tar xf nginx-1.16.1.tar.gz && \
    mv nginx-1.16.1 webserver

WORKDIR

  • 相当于shell脚本中通过cd命令进入到某个目录中进行工作
workdir.png

VOLUME

  • 只能被用于由docker管理的存储卷的情形中
volume.png
VOLUME /data/volume/

EXPOSE

expose.png

expose: vt. 暴露; 揭露; 揭发; 曝光; 使显示

  • docker container run时加上"-P" 选项才会真正暴露端口, 在Dockerfile文件中写EXPOSE规则只是开启了暴露端口这个功能

ENV

env.png
ENV DOC_ROOT="/data/web/html/" \
    WEB_SERVER_PACKAGE="nginx-1.16.1.tar.gz"
# 也可以在运行命令时传递变量
docker container run --help
 -e, --env list       Set environment variables 
     --env-file list  Read in a file of environment variables

RUN

run.png
RUN echo "test" > test.txt # 没加中括号, 会自动运行为shell进程的子进程
  • Dockerfile构建镜像时使用的命令
  • RUN基于基础镜像的环境运行, 因此基础镜像的环境内没有的命令或程序, RUN命令中指定的命令无法运行!
  • json数组中要使用双引号!!!

CMD

cmd.png
CMD /usr/local/src/webserver/bin/nginx 
# 此为第一种CMD语法, 先启动一个shell进程, 然后nginx作为shell进程的子进程启动
# 这种配置方法最简单, 但是有一个极大的坏处, 就是在容器中启动的nginx进程的PID不是1
# 使用docker container stop对应容器时, nginx进程不会被关闭, 因为它接收不到新号,
# 接收到信号的是PID为1的进程
CMD ["<executable>","<param1>","<param2>"]
# 直接启动PID为1的进程, 可接收并处理信号
  • CMD用于定义把镜像启动为容器时, 若没有指定命令, 而默认启动的命令
  • RUN与CMD的区别:
run与cmd的区别.png

ENTRYPOINT

entrypoint.png
docker container run --name tinyweb1 -it --rm -P nginx \
                     /bin/httpd -f -h /data/web/html/
                     # 可以自行指定容器启动时运行命令覆盖原有CMD中的命令
                     # 但由ENTRYPOINT启动的程序不会被命令行启动参数覆盖
                     # 除非在命令行再指定entrypoint参数, 
                     # 才会覆盖原有ENTRYPOINT指定的内容:
  --entrypoint string  Overwrite the default ENTRYPOINT of the image

docker container run --name tinyweb2 -it --rm -P \ 
                     --entrypoint "ls /data/" \
                     nginx
  • 当CMD与ENTRYPOINT同时存在时, CMD中的内容将被当做默认参数传递给ENTRYPOINT, 但是会被docker container run所指定的参数所覆盖
  • 这里要特别强调覆盖参数的区别!!!
    • --entrypoint覆盖的是Dockerfile文件中ENTRYPOINT所指定的参数
    • 而使用docker container run所覆盖的是CMD传过来的命令默认参数
CMD ["/bin/httpd","-f","-h","/data/web/html/"]
ENTRYPOINT /bin/sh -c
# 用这个Dockerfile创建镜像时, 用docker image inspect查看信息时会发现镜像
# 中的Entrypoint信息如下:
"Entrypoint": [
    "/bin/sh",
    "-c",
    "/bin/sh -c"
]
# 之所有有两个/bin/sh -c, 是因为第2行的ENTRYPOINT指定为/bin/sh -c,
# 实际上是先启动了一个/bin/sh -c进程, 然后在shell进程中又创建了/bin/sh -c的子进程
# 如果要运行自定义的/bin/sh -c, 可修改为如下:
ENTRYPOINT ["/bin/sh","-c"]

例: 向脚本传递参数并启动容器

ADD entrypoint.sh /bin/ # 将自定义的脚本放到容器的/bin/目录下

CMD ["/usr/sbin/nginx","-g","daemon off;"] 
  # 注意一定要用双引号!
  # 这里之所以加分号因为运行docker container run时后面还可能有命令参数传过来
ENTRYPOINT ["/bin/entrypoint.sh"]
vi entrypoint.sh

#!/bin/sh
cat > /etc/nginx/conf.d/www.conf << EOF # 后面一定要用两个<
server {
    server_name ${HOSTNAME};
    lister ${IP:-0.0.0.0}:${PORT:-80};
    root ${NGX_DOC_ROOT:-/usr/share/nginx/html/};
}
EOF

exec "$@" # 让CMD中传过来的nginx命令执行的程序替换当前shell进程作为主进程

实例1

  • 1.做好准备工作:
mkdir ~/img1/
cd img1
cp -a /etc/yum.repos.d/* 
vi index.html # 添加如下内容
<h1>bbox1 httpd server</h1>
  • 2.创建并编辑Dockerfile文件, 添加内容如下:
# Description: test Dockerfile
FROM busybox:latest
LABEL maintainer="Alex Ti <1054083247@qq.com>" \
      location="Hangzhou Zhejiang China"
ENV DOC_ROOT="/usr/local/src/" \
    WEBSERVER_PACKAGE="nginx-1.16.1.tar.gz" \
    WEB_DOC_ROOT="/data/web/html/"

COPY yum.repos.d /etc/yum.repos.d/
COPY index.html ${WEB_DOC_ROOT}
ADD "http://nginx.org/download/nginx-1.16.1.tar.gz" ${DOC_ROOT:-/tmp/}
VOLUME ${WEB_DOC_ROOT}
EXPOSE 80/tcp 11211/udp

WORKDIR ${DOC_ROOT}
RUN tar xf ${WEBSERVER_PACKAGE} && \
    mv "nginx-1.16.1" "webserver"

CMD /bin/httpd -f -h ${WEB_DOC_ROOT}
CMD ["/bin/httpd","-f","-h","${WEB_DOC_ROOT}"] 
# 第20行代码有错, 在最后启动容器时会报错, 因为/bin/httpd没有被运行
# 为shell进程的子进程, 所以无法识别传入的参数${WEB_DOC_ROOT},
# 不过可以修正为如下:
CMD ["/bin/sh","-c","/bin/httpd","-f","-h ${WEB_DOC_ROOT}"]

补充: sh命令

sh命令是shell命令语言解释器,执行命令从标准输入读取或从一个文件中读取。通过用户输入命令,和内核进行沟通!

bash [options] [file]
  -c string: 命令从-c后的字符串读取
  -i: 实现脚本交互
  -n: 进行shell脚本的语法检查
  -x: 实现shell脚本逐条语句的跟踪

sh -c "echo 1" # 执行的结果为1, 说明先开了一个shell进程, 
               # 在shell进程下执行了子进程echo
  • 3.创建自制的镜像并用自制的镜像启动容器
docker image build -t tianjunchang/nginx:v0.1 ./ # 注意创建过程中是否有报错

docker image ls # 查看自制的镜像
REPOSITORY           TAG       IMAGE ID            CREATED            SIZE
tianjunchang/nginx   v0.4      8ab31e28ed44        5 seconds ago      8.47MB

docker container run --name b1 --rm -it tianjunchang/nginx:v0.1 
# 运行此命令时只有光标闪烁, 没有交互界面, 虽然Dockerfile文件中指定的CMD,
# 即容器启动时运行的命令/bin/httpd运行为shell进程的子进程, 但是容器启动时会自动
# 做替换(即exec), 将/bin/httpd进程的PID改为1, 此时如果想要使用shell登录容器, 则
docker container exec -it b1 /bin/sh

# 可以在启动容器时指定需要执行的命令, 例如你要运行的服务
docker container run --name b2 --rm tianjunchang/nginx:v0.2 ls -l /usr/local/src/
# docker container exec --help
Usage:  docker container exec [OPTIONS] CONTAINER COMMAND [ARG...]
Run a command in a running container

Options:
  -d, --detach        Detached mode: run command in the background
  -e, --env list      Set environment variables
  -i, --interactive   Keep STDIN open even if not attached
  -t, --tty           Allocate a pseudo-TTY

USER

user.png
  • 容器启动时, 其主进程以USER指定的用户身份运行

HEALTHCHECK

healthcheck.png healthcheck1.png
  • --interval: 健康监测的时间间隔

  • --start-period: 容器初始化启动成功, 此时容器内的进程可能未启动成功, 因此是否在容器初始化启动成功时立即进行health check还是设定的--start-period时间之后进行health check

  • --timeout: 检测服务超时的时间, 如果超过这个时间就判定为失败

  • --reties: 检测失败时重新检测次数

  • 注意使用关键词 CMD !

SHELL

shell.png

STOPSIGNAL

  • 容器中PID为1的进程可以接收docker container stop命令从而停止主进程, 从而停止容器
stopsignal.png

ARG

  • 只在 docker build 中使用
  • 此功能使得一个Dockerfile能够适用于多种场景, 尤其是应用程序版本变化时, 直接传递参数即可

[图片上传失败...(image-c2fd94-1567102998883)]

FROM nginx:1.14.1-alpine # 每次版本变化时都需要去修改nginx版本号, 比较麻烦, 修改:
FROM nginx:${NGX_TAG}    # 此命令在编译时会出错, 仅用于示例说明该
FROM nginx:1.14.1-alpine

ARG author="Alex Ti <1054083247@qq.com>"
LABEL maintainer="${author}"
# 定义好Dockerfile文件后测试:
docker build --build-arg author="tianjunchang" -t tianjunchang/myweb:v0.1-1
docker image inspect tianjunchang/myweb # 查看作者信息是否被传入的参数修改

ONBUILD

  • 做成镜像时, 被别人用作基础镜像, 在别人docker build时被触发执行
  • COPY可能会有问题, 因为别人执行时工作目录可能没有你指定的源文件
onbuild.png
FROM nginx:1.14.1-alpine

HEALTHCHECK --start-period=1m \ 
            CMD wget -O - -q http://${IP:-0.0.0.0}:10080/

ONBUILD ADD "http://nginx.org/download/nginx-1.16.1.tar.gz" \
            "/usr/local/src/"

(1) 基于上面这个Dockerfile, docker build一个名为 myimg:v0.1 的镜像

(2) 再基于 myimg:v0.1 镜像写一个Dockerfile文件, 再次docker build一个名为 myimg:v0.2 镜像:

FROM myimg:v0.1

RUN mkdir /test

会发现在docker build的时候会触发第一个Dockerfile中的ONBUILD, 下载一个nginx的tar包至/usr/local/src/

相关文章

网友评论

      本文标题:5. dockerfile

      本文链接:https://www.haomeiwen.com/subject/ykwgectx.html