引言
本文将介绍我在日常使用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 镜像,我们可以这么来理解 ENTRYPOINT
与 CMD
的关系:
- 如果未定义
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
,容器会停止运行。
但是需要注意的是,如果从这个 stdin
中 exit
,会导致容器的停止。
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 流程时,踩过的一些坑。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。