引言

本文将介绍我在日常使用Docker过程中发现的一些小细节,希望能帮助大家更好地使用Docker。

Docker 命令顺序

Docker 命令中参数的顺序不对会导致莫名其妙的失败!

Docker 命令的格式是固定的,类似于下面的顺序:

docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

例如:

$ docker run cdrx/pyinstaller-windows -v "/root/code/:/src"
-v /root/code/:/src
sh: 1: /root/code/:/src: not found
# 在这条命令中,cdrx/pyinstaller-windows 是镜像,而 -v "/root/code/:/src" 出现在了镜像之后,Docker 会把这个 -v 及其参数视作传递给容器的命令,容器尝试执行这个命令时,自然会出错
$ docker run -v "/root/code/:/src" cdrx/pyinstaller-windows
Collecting PyMySQL==0.9.3
# 运行正常

因此,参数的顺序是很关键的,特别是在 Docker 运行容器时,要确保选项如 -v 在镜像之前,避免它们被错误地当作容器命令来执行。

覆盖掉默认 ENTRYPOINT

docker run --entrypoint "" --rm -it xxx/xxximage bash

或者这样

docker run --rm -it xxx/xxximage bash

这时候就进入容器了, 可以试着执行 ENTRYPOINT 看看有什么效果。这个方法可以在测试 Docker 构建的时候发挥作用。

实时查看 Docker 日志

实时查看docker容器日志

$ sudo docker logs -f -t --tail 行数 容器名

实时查看docker容器名为s12的最后10行日志

$ sudo docker logs -f -t --tail 10 s12

Docker 删除名字为 none 的镜像

要删除名称为none的镜像,必须先删除其包含的容器。要删除镜像中的容器,必须先停止容器。

$ docker stop $(docker ps -a | grep "Exited" | awk '{print $1}') //停止容器
$ docker rm $(docker ps -a | grep "Exited" | awk '{print $1}')  //删除容器
$ docker rmi $(docker images | grep "none" | awk '{print $3}')  //删除镜像

Docker CMD 和 entrypoint

对于一个 Docker 镜像,我们可以这么来理解 ENTRYPOINTCMD 的关系:

  • 如果未定义 ENTRYPOINT,则 CMD 将作为默认的 ENTRYPOINT
  • 定义了 ENTRYPOINT 的话,CMD 只为 ENTRYPOINT 提供参数。
  • CMD 可由 docker run <image> 后的命令覆盖,同时覆盖参数。

    注意命令行参数可以覆盖 CMD 指令的设置,但是只能是重写,却不能给 CMD 中的命令通过命令行传递参数。指定 ENTRYPOINT 指令为 exec 模式时,命令行上指定的参数会作为参数添加到 ENTRYPOINT 指定命令的参数列表中。

不使用 root 启动 Docker

为什么 Docker 命令需要 root 权限,因为要连接 Docker 要使用 Unix Socket 文件 /var/run/docker.sock,而这个连接文件的权限受控。

查看这个文件:

b@ubuntu:~$ sudo ls -l /var/run/docker.sock
[sudo] password for b:
srw-rw---- 1 root docker 0 Apr 24 03:10 /var/run/docker.sock

明显,要对这个 Socket 进行 IO 操作的话,三种方法:

  • 使用 root 权限(切到 root,或 sudo 运行)
  • 使用 Docker 用户组权限(添加当前用户到 Docker 用户组)
  • 修改这个 · 文件的权限设置(chmod o+rw)

对比一下,还是加用户到 Docker 用户组比较稳妥。

cat /etc/group | grep docker # 查找 docker 组,确认其是否存在
groups # 列出自己的用户组,确认自己在不在 docker 组中
# 将当前用户添加到 docker 组
sudo gpasswd -a ${USER} docker
# 重启服务
sudo service docker restart
sudo reboot # 重启

docker run和 start 区别

docker run 只有在第一次运行时使用,将镜像放到容器中,以后再次启动这个容器的时候,只需要使用命令 docker start 就可以。

docker start 的作用是:重新启动已经存在的容器。也就是说,如果使用这个命令,我们必须先要知道这个容器的 ID、或者这个容器的名字,我们可以使用 docker ps 命令找到这个容器的信息。

Docker 进入已运行的容器

利用 exec 命令可以进入已运行的容器

`docker exec -it 775c7c9ee1e1 /bin/bash

Docker exec 与 Docker attach 区别

Docker attach 可以 attach 到一个已经运行的容器的 stdin,然后进行命令执行的动作。

exec 可以开启多个终端实例, exec -i /bin/bash,由此可见 exec 其实是在运行中的容器中执行一个命令,比如 /bin/bash 来达到交互的目的。
attach 开启一个和正在运行的进程交互的终端,如果该进程结束,原 docker container 的进程也会结束。attach 只可以用在以 /bin/bash 命令启动的容器, 比如 docker run ubuntu /bin/bash

attach 将本机的标准输入(键盘)、标准输出(屏幕)、错误输出(屏幕)附加到一个运行的容器,也就是说本机的输入直接输到容器中,容器的输出会直接显示在本机的屏幕上,如果退出容器的 shell,容器会停止运行。

但是需要注意的是,如果从这个 stdinexit,会导致容器的停止。

Docker exec 关于 -i、-t 参数,只用 -i 时,由于没有分配伪终端,看起来像 pipe 执行一样。但是执行结果、命令返回值都可以正确获取。
使用 -it 时,则和我们平常操作 console 界面类似。而且也不会像 attach 方式因为退出,导致整个容器退出。这种方式可以替代 ssh 或者 nsenter、nsinit 方式,在容器内进行操作。

如果只使用 -t 参数,则可以看到一个 console 窗口,但是执行命令会发现由于没有获得 stdin 的输出,无法看到命令执行情况。
docker exec 执行后,会命令执行返回值。

关于 -d 参数,在后台执行一个进程。可以看出,如果一个命令需要长时间进程,使用 -d 参数会很快返回,程序在后台运行。

如果不使用 -d 参数,由于命令需要长时间执行,docker exec 会卡住,一直等命令执行完成才返回。

Docker copy 命令

COPY WCS/ /root/WCS/ # 删除星标,按结构复制文件夹
COPY WCS/* /root/WCS/ # 有星标,默认赋值文件夹下所有的文件到新文件夹中

Docker WORKDIR 命令

WORKDIR 命令可以指定 CMD 命令的工作目录,因为 CMD 指令默认在 根目录 / 上执行,所以需要 WORKDIR 指令指定程序执行的目录。

WORKDIR /root/WCS/

例如上边的指令制定了工作目录为 /root/WCS ,执行命令的时候就会将这个目录当作当前目录来使用。

Docker save和export的区别

docker save 保存的是镜像(image),docker export 保存的是容器(container)。

docker load 用来载入镜像包,docker import 用来载入容器包,但两者都会恢复为镜像。

docker load 不能对载入的镜像重命名,而 docker import 可以为镜像指定新名称。

docker save wcs -o wcs.tar # 导出操作
docker load -i wcs.tar # 导入操作

Docker 启用 tcp 套接字连接支持

编辑/etc/docker/daemon.json文件,加入以下内容,重启 Docker 服务即可。

可用于 idea 这类软件连接 Docker 服务,启用之后可以通过远程的方式操作 Docker。

{
"hosts": ["unix:///var/run/docker.sock", "tcp://0.0.0.0:2375"]
}

Docker 挂载 volume

首先新建好 volume

docker volume create db

docker volume create configdb

然后使用以下命令挂载即可。

docker run -d -p 27017:27017 -v db:/data/db -v configdb:/data/configdb mongo --auth --bind_ip_all

Docker 镜像互连

默认情况下 Docker 容器之间默认连接到 docker0 这块网卡上,通过设置端口转发的方式来访问容器内部。

通过新建网络的方式可以将两个 Docker 容器的所有端口互相连接,但是对其他没有加入到这个网络中的 Docker 容器来说是隔离的,不能相互访问。

docker network create my-net
docker run -d -p 127.0.0.1:33061:3306 --name sql --network my-net sql
docker run -d -p 8080:8080 --name web --network my-net web

Docker 构建命令

目前用到的命令,docker -t test:v1 -f ./Dockerfile . -t 指定名字和版本,-f指定 Dockerfile 文件所在位置,最后一个 . 指定构建上下文。

可以通过 --target=builder 命令指定多阶段构建的某一阶段的镜像。

总结

以上就是之前在互联网公司工作时,刚进部门从头开始一点点搭建起来组内的 CI/CD 流程时,踩过的一些坑。


LLLibra146
35 声望6 粉丝

会修电脑的程序员