写点什么

Docker 使用中没人注意的小细节

作者:LLLibra146
  • 2024-10-15
    北京
  • 本文字数:3155 字

    阅读完需:约 10 分钟

引言

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


Docker 命令顺序

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


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


docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
复制代码


例如:


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


$ docker run -v "/root/code/:/src" cdrx/pyinstaller-windowsCollecting 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 restartsudo 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-netdocker run -d -p 127.0.0.1:33061:3306 --name sql --network my-net sqldocker 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 流程时,踩过的一些坑。

发布于: 刚刚阅读数: 3
用户头像

LLLibra146

关注

还未添加个人签名 2018-09-17 加入

还未添加个人简介

评论

发布
暂无评论
Docker使用中没人注意的小细节_Docker_LLLibra146_InfoQ写作社区