一 docker镜像构建说明

A. 两种构建方式

  1. 手动构建docker镜像
  2. 自动构建docker镜像[dockerfile]

B. 构建步骤

  • 手工构建步骤
    1. 启动容器安装软件服务
    2. 将安装好服务的容器commit提交为镜像
    3. 启动新容器来测试新提交的镜像
  • 自动构建步骤
    1. 编写dockerfile文件
    2. 通过build命令使用该dockerfile构建镜像
    3. 启动新容器来测试新提交的镜像

C. dockerfile命令集

指令 功能 特殊说明
FROM 指定基础镜像 必须有
MAINTAINER 指定维护者信息 可以没有
ENV 设置环境变量 可被后面的指令使用
COPY 复制文件到容器
ADD 复制文件到容器 压缩文件会自动解压
WORKDIR 设置当前工作目录 类似linux的cd命令
VOLUME 设置卷,挂载主机目录 需’-v’配合
EXPOSE 指定对外的端口 默认不暴露,需"-P"配合
RUN 运行指定的命令 在用于容器创建过程中执行命令
CMD 容器启动后执行的命令 容易被替换
ENTRYPOINT 容器启动后执行的命令 无法被替换

两种命令方式以及run,cmd,ENTRYPOINT的关系说明

二 手动构建docker镜像

案例以cnetos6.9为基础镜像,制作含有nginx的镜像

A. 环境准备

1
2
3
docker container rm `docker container ls -q -a`
docker volume rm `docker volume ls -q`
docker run -it --name noah-nginx centos:7.4

B. 在容器中执行操作

1
2
3
4
5
6
rm /etc/yum.repos.d/* -f
curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
yum install -y nginx
echo 'this nginx test pag' >/usr/share/nginx/html/index.html
exit

C. 打包为新镜像conmit

1
2
3
4
docker commit noah-nginx c7-nginx:v1
[root@docker01 ~]# docker image ls c7-nginx
REPOSITORY TAG IMAGE ID CREATED SIZE
c7-nginx v1 f823aff3828d 39 seconds ago 388MB

D. 以新镜像创建容器

1
2
3
docker run -d --name nginx-test -p 880:80 c7-nginx:v1 nginx -g "daemon off;"
[root@docker01 ~]# curl 127.0.0.1:880
this nginx test pag

已经通过自己手动构建的镜像创建了新容器,并且成功运行和访问

三 自动构建docker镜像[dockerfile]

相对于手动制作的docker镜像,使用dockerfile构建的镜像有以下优点:

  1. dockerfile只有几kb,便于传输
  2. 使用dockerfile构建出来的镜像,在运行容器的时候,不用指定容器的初始命令
  3. 支持更多的自定义操作

接下来通过dockerfile构建一个nginx镜像

A. 环境准备

1
2
3
4
docker container rm `docker container ls -q -a`
docker volume rm `docker volume ls -q`
mkdir -p /data/docker-file/c7-nginx/
cd /data/docker-file/c7-nginx/

B. 编写dockerfile镜像

1.编写dockerfile

1
2
3
4
5
6
7
8
9
10
cat >dockerfile <<EOF
FROM centos:7.4
RUN rm -f /etc/yum.repos.d/*.repo
RUN curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
RUN curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
RUN yum clean all && yum makecache
RUN yum install -y nginx
RUN echo 'this nginx test pag' >/usr/share/nginx/html/index.html
CMD nginx -g "daemon off;"
EOF

2.docker build构建镜像
docker build -t c7-nginx:v2 .

3.启动新容器来测试新构建的镜像

1
2
3
docker run -d --name nginx-test -p 980:80 c7-nginx:v2 nginx -g "daemon off;"
[root@docker01 ~]# curl 127.0.0.1:980
this nginx test pag

四 CMD|ENTRYPOINT和两种格式

RUN、CMD 和 ENTRYPOINT 这三个 Dockerfile 指令看上去很类似,很容易混淆。简单的说他们的区别:

  1. RUN 执行命令并创建新的镜像层,RUN 经常用于安装软件包。
  2. CMD 设置容器启动后默认执行的命令及其参数.
    但 CMD 能够被 docker run 后面跟的命令行参数替换。
  3. ENTRYPOINT 配置容器启动时运行的命令。
  4. 都可以使用两种命令格式:Shell 和 Exec

A. Shell 和 Exec 命令格式

可用两种方式指定 RUN、CMD 和 ENTRYPOINT 要运行的命令:Shell 格式和 Exec 格式
CMD 和 ENTRYPOINT 推荐使用 Exec 格式,因为指令可读性更强,更容易理解。RUN 则两种格式都可以。

  1. 两种格式语法
    • hell 格式: <instruction> <command>
1
2
3
RUN apt-get install python3  
CMD echo "Hello world"
ENTRYPOINT echo "Hello world"
* Exec 格式: `<instruction> ["executable", "param1", "param2", ...]`
1
2
3
RUN ["apt-get", "install", "python3"]  
CMD ["/bin/echo", "Hello world"]
ENTRYPOINT ["/bin/echo", "Hello world"]
  1. Shell格式详解
    当指令执行时,shell 格式底层会调用 /bin/sh -c ,例如下面的 Dockerfile 片段:
1
2
ENV name Noah luo  
ENTRYPOINT echo "Hello, $name"

执行 docker run 将输出:“Hello, Noah luo”
注意环境变量 name 已经被值 Noah luo 替换。

  1. Exec格式详解
    当指令执行时,会直接调用 ,不会被 shell 解析, 例如下面的 Dockerfile 片段:
1
2
ENV name Noah luo  
ENTRYPOINT ["/bin/echo", "Hello, $name"]

运行容器将输出: “Hello, $name”
注意环境变量“name”没有被替换,如果希望使用环境变量,照如下修改

1
2
ENV name Noah luo  
ENTRYPOINT ["/bin/sh", "-c", "echo Hello, $name"]

运行容器将输出: ‘Hello, Noah luo’

B. CMD命令详解

CMD 指令允许用户指定容器的默认执行的命令,此命令会在容器启动且 docker run 没有指定其他命令时运行。

  • 如果 docker run 指定了其他命令,CMD 指定的默认命令将被忽略。
  • 如果 Dockerfile 中有多个 CMD 指令,只有最后一个 CMD 有效。
  1. CMD 有三种格式:

    1. Exec 格式:CMD [“executable”,“param1”,“param2”]
    2. Shell 格式:CMD command param1 param2
    3. ENTRYPOINT参数格式:CMD [“param1”,“param2”]
      专为 ENTRYPOINT 提供额外的参数,此时 ENTRYPOINT 必须使用 Exec 格式,详见 ENTRYPOINT部分说明。
  2. 使用举例
    Dockerfile 片段:CMD echo “Hello world”,运行容器 docker run -it [image]将输出:Hello world.
    但当后面加上一个命令,比如docker run -it [image] /bin/bash,CMD 会被忽略掉,命令 bash 将被执行

C. ENTRYPOINT命令详解

ENTRYPOINT 指令可让容器以应用程序或者服务的形式运行,
与 CMD都可以指定要执行的命令及其参数.
不同的地方在于 ENTRYPOINT 不会被忽略,一定会被执行,即使运行 docker run 时指定了其他命令。

  1. ENTRYPOINT 有两种格式:
    两种格式的效果差别很大
    • Exec 格式:ENTRYPOINT [“executable”, “param1”, “param2”]
    • Shell 格式:ENTRYPOINT command param1 param2
  2. Exec 格式详解
    ENTRYPOINT 的 Exec 格式用于设置要执行的命令及其参数,同时可通过 CMD 提供额外的参数。
    ENTRYPOINT 中的参数始终会被使用,而 CMD 的额外参数可以在容器启动时动态替换掉。
    Dockerfile 片段如下:
1
2
ENTRYPOINT ["/bin/echo", "Hello"]  
CMD ["world"]

当容器通过 docker run -it [image]启动时,输出为:Hello world
而如果通过 docker run -it [image] noah 启动,则输出为:Hello noah
3. Shell 格式
ENTRYPOINT 的 Shell 格式会忽略任何 CMD 或 docker run 提供的参数。

D. 最佳实践总结

  1. 如果 Docker 镜像的用途是运行应用程序或服务,如运行MySQL,优先使用 Exec 格式的 ENTRYPOINT 指令。
    CMD 可为 ENTRYPOINT 提供额外的默认参数,同时可利用 docker run 命令行替换默认参数。
  2. 如果想为容器设置默认的启动命令,可使用 CMD 指令。用户可在 docker run 命令行中替换此默认命令。