Docker 分为客户端和服务端两部分, docker
为客户端调用的命令, dockerd
为服务端调用的命令, 本文着重介绍客户端的用法。
特此声明,下面大部分内容来自于这位大佬,除此之外,还添加了一些自己的理解。
概览
主要用法:docker [ docker命令选项 ] [ 子命令 ] [ 子命令选项 ]
docker [ 子命令 ] —help 可查看每个子命令的详细用法。
Docker 命令选项列表
选项 | 说明 | 其他 |
---|---|---|
—config [string] | 客户端本地配置文件路径 | 默认为 ~/.docker |
-D, —debug | 启用调试模式 | |
—help | 打印用法 | |
-H, —host list | 通过 socket 访问指定的 docker 守护进程 ( 服务端 ) | unix:// , fd:// , tcp:// |
-l, —log-level [string] | 设置日志级别 ( debug 、info 、warn 、error 、fatal ) | 默认为 info |
—tls | 启用 TLS 加密 | |
—tlscacert [string] | 指定信任的 CA 根证书 路径 | 默认为 ~/.docker/ca.pem |
—tlscert [string] | 客户端证书路径 | 默认为 ~/.docker/cert.pem |
—tlskey [string] | 客户端证书私钥路径 | 默认为 ~/.docker/key.pem |
—tlsverify | 启用 TLS 加密并验证客户端证书 | |
-v, —version | 打印 docker 客户端版本信息 |
镜像仓库相关
查找镜像
1 | docker search [ 条件 ] |
例如
1 | # 查询三颗星及以上名字包含alpine的镜像 |
获取镜像
1 | docker pull [选项] [Docker Registry 地址[:端口号]/]仓库名[:标签] |
具体的选项可以通过 docker pull --help
命令看到,这里我们说一下镜像名称的格式。
- 除了官方仓库外的第三方仓库要指定 url,格式一般是
<域名/IP>[:端口号]
。默认地址是 Docker Hub。 - 仓库名:这里的仓库名是两段式名称,即
<用户名>/<软件名>
。对于 Docker Hub,如果不给出用户名,则默认为library
,也就是官方镜像。 标签
表示镜像的版本号,不指定时默认为latest
比如:
1 | docker pull ubuntu:18.04 |
上面的命令中没有给出 Docker 镜像仓库地址,因此将会从 Docker Hub 获取镜像。而镜像名称是 ubuntu:18.04
,也就是用户名为默认的library
,软件名为ubuntu
,标签为18.04
。因此将会获取官方镜像 library/ubuntu
仓库中标签为 18.04
的镜像。docker pull
命令的输出结果最后一行给出了镜像的完整名称,即: docker.io/library/ubuntu:18.04
。注意这个链接前面是不需要加http://
的。
推送镜像到仓库
1 | docker push [ 镜像名 ]:[ tag ] |
当然,需要先登录
1 | ubuntu@VM-84-201-ubuntu:~$ docker push alpine |
登录/退出第三方仓库
1 | docker [ login/logout ] [ 仓库地址 ] |
例如:
1 | 登录 |
本地镜像
查看本地镜像
1 | docker images |
例如:
1 | ubuntu@VM-84-201-ubuntu:~$ docker images |
删除本地镜像
1 | docker rmi [ 镜像名 or 镜像 id ] |
如果用 镜像 id 作为参数,可以只输入前几位, 能唯一确定即可 ( 可以同时删除多个镜像, 空格隔开 )。此外, 如果已经使用该 镜像 启动了 容器 需要先删除 容器。
1 | ubuntu@VM-84-201-ubuntu:~$ docker rmi a41 |
若遇到错误Error response from daemon: conflict: unable to delete a9aad2420ea3 (must be forced) - image is being used by stopped container 4b42ead3973b
,则先使用docker stop $(docker ps -a -q)
停止所有的container,这样才能够删除其中的images。
若还是不行的话,先删除对应的docker。因为该image被对应的container引用,所以image删除失败。
1 | [root@vm000949 redis]# docker images |
主要希望删除这两个imgae,根据image的id到container中找
1 | [root@vm000949 redis]# docker ps -a |
然后删除它们
1 | [root@vm000949 redis]# docker rm 65e94723f0ed |
再删除镜像:
1 | [root@vm000949 redis]# docker rmi a061cf8c12b8 |
也可以根据提示来的,加-f
强制删除镜像。
值得注意的是,若遇到错误Error response from daemon: conflict: unable to delete cc6f00f7df14 (cannot be forced) - image has dependent child images
,则可以使用docker image inspect --format='{ {.RepoTags} } { {.Id} } { {.Parent} }' $(docker image ls -q --filter since=cc6f00f7df14)
查看到有另外的 image FROM 了这个 image。可以通过删除子镜像来删除该镜像。
查看镜像详情
1 | docker inspect [ 镜像名 or 镜像 id ] |
例如:
1 | ubuntu@VM-84-201-ubuntu:~$ docker inspect a41 |
查看容器映射路径,container_name 是容器的名字,也可以写容器的ID。
1 | $ docker inspect container_name | grep Mounts -A 20 |
另外,还可以通过指令,查看该镜像的环境变量,如下所示:
1 | "Env": [ |
若
NVIDIA_VISIBLE_DEVICES=all
则可能会导致在k8s集群中,实例可以看到该节点所有的显卡。解决方法是在dockerfile中取消该变量。
打包本地镜像, 使用压缩包来完成迁移
1 | docker save [ 镜像名 ] > [ 文件路径 ] |
例如:
1 | # 默认为文件流输出 |
值得注意的是,若是跨系统打包docker,要使用
-o
的方式打包,用-i
的方式解压。
导入镜像压缩包
1 | # 当文件流输出的时候 |
例如
1 | # 默认从标准输入读取 |
修改镜像tag
1 | docker tag [ 镜像名 or 镜像 id ] [ 新镜像名 ]:[ 新 tag ] |
例如:
1 | ubuntu@VM-84-201-ubuntu:~$ docker tag a41 anyesu/alpine:1.0 |
容器相关
创建、启动容器并执行相应的命令
1 | docker run [ 参数 ] [ 镜像名 or 镜像 id ] [ 命令 ] |
如果没有指定命令时就执行 镜像 中默认的命令, 创建 镜像 的时候可设置默认命令。另外要注意的一点,启动 容器 后要执行一个前台进程 ( 就是能在控制台不断输出的或者一直等待的那种程序,如 tomcat 的 catalina.sh ) 才能使 容器 保持运行状态,否则,命令执行完 容器 就关闭了,像下面这个例子执行完就直接结束了。
1 | ubuntu@VM-84-201-ubuntu:~$ docker run hello-world |
run 命令常用选项
选项 | 说明 |
---|---|
-d | 后台运行容器, 并返回容器ID;不指定时, 启动后开始打印日志, Ctrl + C 退出命令同时会关闭容器 |
-i | 以交互模式运行容器, 通常与 -t 同时使用; |
-t | 为容器重新分配一个伪输入终端, 通常与 -i 同时使用 |
—name “anyesu-container” | 为容器指定一个别名, 不指定时随机生成 |
-h docker-anyesu | 设置容器的主机名, 默认随机生成 |
—dns 8.8.8.8 | 指定容器使用的 DNS 服务器, 默认和宿主机一致 |
-e docker_host=172.17.0.1 | 设置环境变量 |
—cpuset=”0-2” or —cpuset=”0,1,2” | 绑定容器到指定 CPU 运行 |
-m 100M | 设置容器使用内存最大值 |
—net bridge | 指定容器的网络连接类型, 支持 bridge / host / none / container 四种类型 |
—ip 172.18.0.13 | 为容器分配固定 ip ( 需要使用自定义网络 ) |
—expose 8081 —expose 8082 | 开放一个端口或一组端口, 会覆盖镜像设置中开放的端口 |
-p [宿主机端口]:[容器内端口] | 宿主机到容器的端口映射, 可指定宿主机的要监听的 ip, 默认为 0.0.0.0 |
-P | 注意是大写的, 宿主机随机指定一组可用的端口映射容器 expose 的所有端口 |
-v [宿主机目录路径]:[容器内目录路径] | 挂载宿主机的指定目录 ( 或文件 ) 到容器内的指定目录 ( 或文件 ) |
—add-host [主机名]:[ip] | 为容器 hosts 文件追加 host , 默认会在 hosts 文件最后追加内容:[主机名]:[容器ip] |
—volumes-from [其他容器名] | 将其他容器的数据卷添加到此容器 |
—link [其他容器名]:[在该容器中的别名] | 添加链接到另一个容器, 在本容器 hosts 文件中加入关联容器的记录, 效果类似于 —add-host |
一个较完整的例子:
1 | # 创建一个名为anyesu_net、网段为172.18.0.0的网桥(docker默认创建的网段为172.17.0.0) |
单字符选项可以合并, 如
-i -t
可以合并为-it
另一个完整的例子:
使用docker images
查看当前的docker镜像如下。
则启动docker镜像的命令可以是:
1 | # 将/data6/zhaodali映射到/workspace文件夹 |
想要退出的话,直接按下ctrl + D
指令。
若想在docker内连接内网源安装软件和Python包,则需要运行下面指令,然后更改镜像内的apt软件源和pip源为内网源。
1 | docker run --gpus all -v /dev/dri:/dev/dri --ipc=host -it --add-host mirrors.tencent.com:100.115.83.221 --add-host mirrors.cloud.tencent.com:100.115.83.221 -v /data6/zhaodali:/workspace -ti ubuntu-opencv-torch:latest /bin/bash |
若进入docker后还是连不上内网,则将
--ipc=host
改为--network=host
。若出现错误
ERROR: Unexpected bus error encountered in worker. This might be caused by insufficient shared memory (shm)
,则在开启docker的时候加上--ipc=host
指令,让docker容器共享主机内存。
查看运行中的容器
1 | # 查看运行中的容器 |
开启/停止/重启容器
1 | 关闭容器(发送SIGTERM信号,做一些'退出前工作',再发送SIGKILL信号) |
删除容器
1 | docker rm [ 容器名 or 容器 id ] |
可以指定多个容器一起删除, 加 -f
选项可强制删除正在运行的 容器
1 | ubuntu@VM-84-201-ubuntu:~$ docker ps |
查看容器详情
1 | docker inspect [ 容器名 or 容器 id ] |
比如
1 | docker inspect anyesu-container |
查看容器中正在运行的进程
1 | docker top [ 容器名 or 容器 id ] |
比如:
1 | ubuntu@VM-84-201-ubuntu:~$ docker top anyesu-container |
保存容器
1 | docker commit [ 容器名 or 容器 id ] [ 镜像名 ]:[ tag ] |
比如:
1 | ubuntu@VM-84-201-ubuntu:~$ docker commit anyesu-container anyesu/tomcat:1.0 |
再比如:
1 | (base) [zhaodali@TENCENT64 /data6/zhaodali]$ docker ps -l |
重命名容器
1 | # 当得知容器名时 |
开启新终端进入同一个docker
可以先通过docker ps
获取container id
,然后通过docker exec -it ${container_id} /bin/bash
进入,如果不是/bin/bash
环境,可以使用/bin/sh
进入。
使用 Dockerfile 构建镜像
1 | docker build -t [ 镜像名 ]:[ tag ] -f [ DockerFile 名 ] [ DockerFile 所在目录 ] |
数据是实时更新的,点击 查看详细用法。
若在构建镜像时,出现了无法连接网络安装依赖时,可以在上面指令后面添加--network=host
。
映射jupyter-notebook
启动Docker:
1 | NV_GPU=0 nvidia-docker run -it -p 7777:8888 -ti --ipc=host a9aad2420ea3 |
使用docker ps
查看刚启动的container实例:
1 | $ docker ps |
可以看到,这里container实例开放了6006和8888两个端口,其中8888端口映射到了主机的7777端口。此时进入Docker,在需要执行jupyter notebook
的文件夹内打开终端运行如下命令:
1 | (solaris) root@cc56fc116249:/opt/conda/pkgs# jupyter notebook --ip 0.0.0.0 --no-browser --allow-root & |
回到主机,在浏览器中打开http://127.0.0.1:7777/?token=dcb8fd9afd7f4182fa3f2c4ecf39df2a1090bd62599e20f1
(注意需要将上面链接中的8888端口替换为7777端口)。如果需要输入token,则输入后面的dcb8fd9afd7f4182fa3f2c4ecf39df2a1090bd62599e20f1
即可。
硬件资源相关
显示容器硬件资源使用情况
1 | docker stats [ 选项 ] [ 0个或多个正在运行容器 ] |
比如:
1 | 不指定容器时显示所有正在运行的容器 |
更新容器的硬件资源限制
1 | docker update [ 选项 ] |
这个操作可能会输出下面的错误内容:
1 | Your kernel does not support swap limit capabilities or the cgroup is not mounted. Memory limited without swap |
1 | /etc/default/grub |
注意是在 GRUB_CMDLINE_LINUX 项 追加 上述参数内容, 我试过简单粗暴的在文件末尾添加下面内容, 这么做会覆盖原有的启动参数, 导致网络连接失败。网络坏了, ssh 都连不上了, 幸好可以在 腾讯云 的网页控制台登录, 修改内容重启就好了。所以呢, 这一步操作一定要慎重。
使用压力测试工具 stress
验证效果
使用已有的 stress 镜像 progrium/stress, 开两个终端, 在其中一个终端中执行下面的命令
1 | docker run -m 100m --rm -it progrium/stress --cpu 2 --io 1 --vm 10 --vm-bytes 9M |
在另一个终端执行 docker stats
进行监控
1 | CONTAINER CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS |
再开一个终端执行
1 | 9eb0为容器id开头, 请根据实际情况替换。内存限制只能调大不能调小 |
基础子命令列表
选项 | 说明 |
---|---|
attach | 进入运行中的容器, 显示该容器的控制台界面。注意, 从该指令退出会导致容器关闭 |
build | 根据 Dockerfile 文件构建镜像 |
commit | 提交容器所做的改为为一个新的镜像 |
cp | 在容器和宿主机之间复制文件 |
create | 根据镜像生成一个新的容器 |
diff | 展示容器相对于构建它的镜像内容所做的改变 |
events | 实时打印服务端执行的事件 |
exec | 在已运行的容器中执行命令 |
export | 导出容器到本地快照文件 |
history | 显示镜像每层的变更内容 |
images | 列出本地所有镜像 |
import | 导入本地容器快照文件为镜像 |
info | 显示 Docker 详细的系统信息 |
inspect | 查看容器或镜像的配置信息, 默认为 json 数据 |
kill | -s 选项向容器发送信号, 默认为 SIGKILL 信号 ( 强制关闭 ) |
load | 导入镜像压缩包 |
login | 登录第三方仓库 |
logout | 退出第三方仓库 |
logs | 打印容器的控制台输出内容, -f 选项可以持续输出 |
pause | 暂停容器 |
port | 容器端口映射列表 |
ps | 列出正在运行的容器, -a 选项显示所有容器 |
pull | 从镜像仓库拉取镜像 |
push | 将镜像推送到镜像仓库 |
rename | 重命名容器名 |
restart | 重启容器 |
rm | 删除已停止的容器, -f 选项可强制删除正在运行的容器 |
rmi | 删除镜像 ( 必须先删除该镜像构建的所有容器 ) |
run | 根据镜像生成并进入一个新的容器 |
save | 打包本地镜像, 使用压缩包来完成迁移 |
search | 查找镜像 |
start | 启动关闭的容器 |
stats | 显示容器对资源的使用情况 ( 内存、CPU、磁盘等 ) |
stop | 关闭正在运行的容器 |
tag | 修改镜像 tag |
top | 显示容器中正在运行的进程 ( 相当于容器内执行 ps -ef 命令 ) |
unpause | 恢复暂停的容器 |
update | 更新容器的硬件资源限制 ( 内存、CPU 等 ) |
version | 显示 Docker 客户端和服务端版本信息 |
wait | 阻塞当前命令直到对应的容器被关闭, 容器关闭后打印结束代码 |
daemon | 这个子命令已 过期, 将在 Docker 17.12 之后的版本中移出, 直接使用 dockerd |
用于管理的子命令列表
选项 | 说明 |
---|---|
container | 管理容器 |
image | 管理镜像 |
network | 管理容器网络 ( 默认为 bridge、host、none 三个网络配置) |
plugin | 管理插件 |
system | 管理系统资源。其中, docker system prune 命令用于清理没有使用的镜像、容器、数据卷以及网络 |
volume | 管理数据卷 |
swarm | 管理 Swarm 模式 |
service | 管理 Swarm 模式下的服务 |
node | 管理 Swarm 模式下的 Docker 集群中的节点 |
secret | 管理 Swarm 模式下的敏感数据 |
stack | Swarm 模式下利用 compose-file 管理服务 |
说明:
其中 container 、image 、system 一般用前面的简化指令即可。Swarm 模式用来管理 Docker 集群, 它将一群 Docker 宿主机变成一个单一的虚拟的主机, 实现对多台物理机的集群管理。
Docker空间扩容
docker默认是把数据(images、containers等)保存在/var/lib/docker
中,有的人根目录空间很有限,想给docker扩容,怎么办呢?
可以使用
docker info
指令查看存储的位置,例如Docker Root Dir: /var/lib/docker
,
一种办法是先停止docker daemon,然后把上述目录移动到/opt/data或者其他的有空间的目录下,最后在/var/lib下做个同名的docker软连接,指向/opt/data/docker:
1 | service docker stop(或者/etc/init.d/docker stop) |
若遇到/var/lib/docker
无法删除时,可以参考https://github.com/moby/moby/issues/6077。
1 | cat /proc/mounts |grep docker |
参考
Docker 常用指令详解
获取镜像
Can’t install pip packages inside a docker container with Ubuntu
删除镜像
如何解决 image has dependent child images 错误
怎么在 docker 中开启多个终端
在 docker 中运行 Jupyter notebook
Docker load and save: “archive/tar: invalid tar header”
ERROR: Unexpected bus error encountered in worker. This might be caused by insufficient shared memory (shm). #283
Cannot remove /var/lib/docker after changing docker runtime root to /home/docker after a fresh install with no containers / images #6077
给docker扩容、删除/var/lib/docker
Docker 查看容器映射路径
Docker how to change repository name or rename image?