docker进阶

官网:https://docs.docker.com/engine/reference/builder/

Docker的CMD 和 ENTRYPOINT

​ CMD 和 ENTRYPOINT 指令都是用来指定容器启动时运行的命令。大多数情况下基本功能相同。

exec 模式和 shell 模式

​ CMD 和 ENTRYPOINT 指令都支持 exec 模式和 shell 模式的写法,所以要理解 CMD 和 ENTRYPOINT 指令的用法,就得先区分 exec 模式和 shell 模式。这两种模式主要用来指定容器中的不同进程为 1 号进程。

exec 模式

​ 使用 exec 模式时,容器中的任务进程就是容器内的 1 号进程

​ exec 模式是建议的使用模式,因为当运行任务的进程作为容器中的 1 号进程时,我们可以通过 docker 的 stop 命令优雅的结束容器。

​ exec 模式的特点是不会通过 shell 执行相关的命令,所以像 $HOME 这样的环境变量是取不到的:

CMD [ "echo", "$HOME" ]

​ 通过 exec 模式执行 shell 可以获得环境变量:

CMD [ "sh", "-c", "echo $HOME" ]

shell 模式

使用 shell 模式时,docker 会以 /bin/sh -c “task command” 的方式执行任务命令。也就是说容器中的 1 号进程不是任务进程而是 bash 进程

CMD top

1 号进程执行的命令居然是 /bin/sh -c top。而指定的 top 命令的进程 ID 为 7。这是由 docker 内部决定的,目的是让我们执行的命令或者脚本可以取到环境变量。

CMD 指令

CMD 指令的目的是:为容器提供默认的执行命令。
CMD 指令有三种使用方式,其中的一种是为 ENTRYPOINT 提供默认的参数:

CMD ["param1","param2"]

另外两种使用方式分别是 exec 模式和 shell 模式:

CMD ["executable","param1","param2"]    # 这是 exec 模式的写法,注意需要使用双引号。
CMD command param1 param2                 # 这是 shell 模式的写法。

注意命令行参数(即通过docker run 指定的)可以覆盖 CMD 指令的设置,但是只能是重写,却不能给 CMD 中的命令通过命令行传递参数。实际上,命令行上的命令同样会覆盖 shell 模式的 CMD 指令。

ENTRYPOINT 指令

ENTRYPOINT 指令的目的也是为容器指定默认执行的任务。
ENTRYPOINT 指令有两种使用方式,就是我们前面介绍的 exec 模式和 shell 模式:

ENTRYPOINT ["executable", "param1", "param2"]   # 这是 exec 模式的写法,注意需要使用双引号。
ENTRYPOINT command param1 param2                 # 这是 shell 模式的写法。

exec 模式和 shell 模式的基本用法和 CMD 指令是一样的。

指定 ENTRYPOINT 指令为 exec 模式时,命令行(docker run)上指定的参数会作为参数添加到 ENTRYPOINT 指定命令的参数列表中。所以写entrypoint文件时,要考虑输入各种参数问题。

覆盖默认的 ENTRYPOINT 指令

ENTRYPOINT 指令也是可以被命令行覆盖的,只不过不是默认的命令行参数,而是需要显式的指定 --entrypoint 参数。

docker run --rm --entrypoint command

Dockerfile 中至少要有一个

如果镜像中既没有指定 CMD 也没有指定 ENTRYPOINT 那么在启动容器时会报错。这不算是什么问题,因为现在能见到的绝大多数镜像都默认添加了 CMD 或 ENTRYPOINT 指令。

同时使用 CMD 和 ENTRYPOINT 的情况

对于 CMD 和 ENTRYPOINT 的设计而言,多数情况下它们应该是单独使用的。当然,有一个例外是 CMD 为 ENTRYPOINT 提供默认的可选参数。
大概可以总结出下面几条规律:
• 如果 ENTRYPOINT 使用了 shell 模式,CMD 指令会被忽略。
• 如果 ENTRYPOINT 使用了 exec 模式,CMD 指定的内容被追加为 ENTRYPOINT 指定命令的参数。
• 如果 ENTRYPOINT 使用了 exec 模式,CMD 也应该使用 exec 模式。

CMD和ENTRYPOINT差异:

No ENTRYPOINTENTRYPOINT exec_entry p1_entryENTRYPOINT [“exec_entry”, “p1_entry”]
No CMDerror, not allowed/bin/sh -c exec_entry p1_entryexec_entry p1_entry
CMD [“exec_cmd”, “p1_cmd”]exec_cmd p1_cmd/bin/sh -c exec_entry p1_entryexec_entry p1_entry exec_cmd p1_cmd
CMD [“p1_cmd”, “p2_cmd”]p1_cmd p2_cmd/bin/sh -c exec_entry p1_entryexec_entry p1_entry p1_cmd p2_cmd
CMD exec_cmd p1_cmd/bin/sh -c exec_cmd p1_cmd/bin/sh -c exec_entry p1_entryexec_entry p1_entry /bin/sh -c exec_cmd p1_cmd

entrypoint入口文件详解

#!/bin/bash
set -eo pipefail
shopt -s nullglob

# if command starts with an option, prepend mysqld
if [ "${1:0:1}" = '-' ]; then
	set -- mysqld "$@"
fi
  • set -e

bash如果任何语句的执行结果不是true则应该退出 。 set -o errexit 等同

  • set -o pipefail

管道执行过程中出现错误立即退出

  • shopt -s nullglob

在使用 Linux 中的通配符时 * ?等 如果没有匹配到任何文件, 不会报 No such file or directory 而是将命令后面的参数去掉执行

  • set –

set --会将他后面所有以空格区分的字符串, 按顺序分别存储到$1, $2, $3 变量中

  • exec "$@"

执行了你没有预料到的可执行命令时, 将会走到脚本的这最后一行, 去执行用户新的可执行命令

ADD和COPY的区别

ADD

ADD指令的功能是将主机构建环境(上下文)目录中的文件和目录、以及一个URL标记的文件 拷贝到镜像中。

其格式是: ADD 源路径 目标路径

1、如果源路径是个文件,且目标路径是以 / 结尾, 则docker会把目标路径当作一个目录,会把源文件拷贝到该目录下。如果目标路径不存在,则会自动创建目标路径。

2、如果源路径是个文件,且目标路径是不是以 / 结尾,则docker会把目标路径当作一个文件。
如果目标路径不存在,会以目标路径为名创建一个文件,内容同源文件;
如果目标文件是个存在的文件,会用源文件覆盖它,当然只是内容覆盖,文件名还是目标文件名。
如果目标文件实际是个存在的目录,则会源文件拷贝到该目录下。 注意,这种情况下,最好显示的以 / 结尾,以避免混淆。

3、如果源路径是个目录,且目标路径不存在,则docker会自动以目标路径创建一个目录,把源路径目录下的文件拷贝进来 ( 如果有子目录,不会拷贝子目录,仅拷贝子目录下的文件,不分层级)。如果目标路径是个已经存在的目录,则docker会把源路径目录下的文件拷贝到该目录下。

4、如果源文件是个归档文件(压缩文件),则docker会自动帮解压。

5、如果源路径是url,则会下载文件到目标。

COPY

COPY是ADD的简化版本,只是拷贝文件到指定位置。

COPY/ADD 复制文件夹的诡异行为

1、使用 * 作为 COPY/ADD 命令的源时候表示的是 ./*

2、cp 命令在执行 cp * target 时会把文件夹当成文件一股脑的复制到目标路径下,可以认为复制了文件本身,而 docker 的 COPY/ADD 在复制文件夹时复制的是其内容

3、如果要递归拷贝目录(包含子目录),不要带*

COPY ./scripts/    /workspace/scripts/

这样scripts下的目录递归拷贝到目标目录下。

.dockerignore

忽略在构造docker镜像文件时,不发送给 docker daemon 的文件。用于减少传送量。

Docker 维护

yum install docker
vi /etc/docker/daemon.json

{
    "insecure-registries": ["192.168.1.XX"],
    "registry-mirrors": ["http://hub-mirror.c.163.com"]
}
systemctl start docker
systemctl stop docker
systemctl restart docker
systemctl status docker
systemctl enable docker

Docker问题

挂载宿主机已存在目录后,在容器内对其进行操作,报“Permission denied”。

可通过两种方式解决:
1> 关闭selinux。
临时关闭:# setenforce 0
永久关闭:修改/etc/sysconfig/selinux文件,将SELINUX的值设置为disabled。
2> 以特权方式启动容器
指定–privileged参数
如:# docker run -it --privileged=true -v /test:/soft centos /bin/bash

network被占用

提示1:service endpoint with name xxx already exists

docker network list
docker network inspect xxx 
docker network disconnect --force  XXX-network  api-gateway
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值