5. dockerfile

2019-09-25  本文已影响0人  epiiplus1equal0

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

docker instruction.png
FROM nginx.1.16.1

MAINTANIER和LABEL

docker instruction2.png docker instruction3.png
MAINTAINER "Alex Ti <1054083247@qq.com>"
LABEL maintainer="Alex Ti <1054083247@qq.com>" \
      location="Hangzhou Zhejiang China"

COPY

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

workdir.png

VOLUME

volume.png
VOLUME /data/volume/

EXPOSE

expose.png

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

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进程的子进程

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的进程, 可接收并处理信号
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 ["/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

mkdir ~/img1/
cd img1
cp -a /etc/yum.repos.d/* 
vi index.html # 添加如下内容
<h1>bbox1 httpd server</h1>
# 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
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

HEALTHCHECK

healthcheck.png healthcheck1.png

SHELL

shell.png

STOPSIGNAL

stopsignal.png

ARG

[图片上传失败...(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

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/

上一篇 下一篇

猜你喜欢

热点阅读