在有了之前的Dockerfile基础知识后,我们知道该如何编写一个简单的Dockfile,那么如果通过docker client命令来进行Image的构建呢,本节就来阐述一些docker client的一些使用;
在介绍docker client的各个操作命令之前先说明一下docker client操作的分类,按照操作的对象不同,可以分为以下几个大类:
docker image COMMAND
:docker的Image对象的相关操作;docker container COMMAND
:docker的Container对象的相关操作;docker network COMMAND
:docker node COMMAND
:
你会发现docker client的很多命令的功能是重复的,例如docker build
和docker image build
,docker run
和docker container run
,参考Stack Overflow得知,这是由于历史原因导致的;最早docker的命令并没有按照操作对象进行分类管理,例如docker ps
,docker build
等,后来,docker client变得更加结构化,收敛到了几大类,同时为了向后兼容,所以看上去docker client的命令看上去比较乱;
1. docker镜像管理
docker build
前面在「基于Dockerfile的镜像构建」一节中,已经简单的说明了如何通过docker build
进行镜像的构建,这里参考docker build
手册再详细说明一下:
docker build
的语法,如下:
1 | docker build [OPTIONS] PATH | URL |
docker build
通过Dockerfile和构建上下文进行镜像的构建;构建的上下文是由PATH
或URL
指定位置的一个文件列表集合;所有构建过程都可以访问构建上下文的任何文件;
基于本地上下文构建
PATH
用来指定本地文件系统的路径,会将该路径的文件列表作为构建上下文发送到docker daemon
进行构建;如果没有指定Dockerfile
会在PATH
路径的根路径下查找;构建上下文是递归处理的,所以PATH
会包含其所有的子目录,所以一般都是将Dockerfile放入一个空目录中,只添加构建所有需要的文件;
不要将根目录
/
作为PATH来进行构建,这将会把文件系统所有文件全部作为构建上下文传递给Docker daemon进行构建
基于远端上下文构建
URL
指向远端的上下文资源,URL
可以指向三种资源:
- Git Repo
URL
可以指向Git仓库;构建开始之前,Git Repo会被git pull拉取到本地的临时目录,Git仓库的所有的submodule会自动recursively拉取;当然提交历史会被忽略;然后,Git仓库的整个目录会被发送到docker daemon
作为上下文进行镜像的构建;
Git Repo的URL
的格式可以包含三个部分:仓库地址,分支名和用于构建上下文的仓库相对路径;如下是Repo URL的语法:
Build Syntax Suffix | Commit Used | Build Context Used |
---|---|---|
myrepo.git |
refs/heads/master |
/ |
myrepo.git#mytag |
refs/tags/mytag |
/ |
myrepo.git#mybranch |
refs/heads/mybranch |
/ |
myrepo.git#pull/42/head |
refs/pull/42/head |
/ |
myrepo.git#:myfolder |
refs/heads/master |
/myfolder |
myrepo.git#master:myfolder |
refs/heads/master |
/myfolder |
myrepo.git#mytag:myfolder |
refs/tags/mytag |
/myfolder |
myrepo.git#mybranch:myfolder |
refs/heads/mybranch |
/myfolder |
- Tarball 文件
URL
可以指向远端的压缩文件,docker build
的时候会将URL
发送到docker daemon
,由Docker daemon负责压缩包的下载和解压,并将其作为docker build
的构建上下文进行构建;Tarbal文件必须是标准的tar
文件格式,且压缩格式为xz
,bzip2
,gzip
或者无压缩;使用语法格式如下:
1 | $ docker build http://server/context.tar.gz |
- 文本文件
如果 URL
指向一个纯文本文件,那么该文本文件会被当做Dockerfile
发送给docker daemon
用来进行镜像构建,且这种情况的构建是没有任何上下文的;
1 | $ docker build http://server/Dockerfile.txt |
这里和传入文本文件类似的,**docker build
支持从STDIN中
读取数据**,将其作为Dockerfile
进行镜像的构建;如下:
1 | $ docker build - < Dockerfile |
docker build
在将PATH
所有文件列表,发送构建上下文的时候,如果根路径有.dockerignore
文件,会将其中的文件忽略,不发送到docker daemon
,以加速构建过程;
构建参数说明
下面简单的介绍一下docker build
常用的OPTIONS
选项,支持的所有OPTIONS
列表可参考官方手册:
这里需要注意的是:对container有影响的参数,在docker build
过程中只影响构建过程,并不会对最终构建的镜像有何影响;与之相对应的docker run
可以对运行时的container的系统参数进行实际修改;
-f, --file
指定Dockerfile的路径,如果不指定,默认为PATH/Dockerfile
,如果构建上下文为URL
,那么Dockerfile就是相对URL
构建上下文的根路径;如下:
1 | ls . |
-t, --tag
为构建生成的镜像指定仓库名和tag,格式为name:tag
, tag不写默认是latest
;如果在镜像构建的时候不指定-t
选项,构建的镜像的仓库名和tag都是<none>
,如下,是上面执行docker build .
构建的镜像的信息:
1 | docker images |
如下在构建镜像的时候,指定镜像的仓库名和tag:
1 | docker build -t ccr.ccs.tencentyun.com/ns_gz_walkerdu/helloworld:v1 . |
--ulimit
用来将构建过程中的每个step的container都设置ulimit
系统资源的限制参数,参数的格式如下:
1 | <type>=<soft limit>[:<hard limit>] |
如下,设置镜像中资源的栈大小,不过变更只影响构建过程,并不会对最终构建的镜像有何影响:
1 | docker build -t test/helloworld --ulimit stack=10240:10240 . |
各种资源的类型名,在系统的/etc/security/limits.conf
中有定义,如下:
1 | vim /etc/security/limits.conf |
--build-arg
前面在构建指令里有一个ARG
指令,用来申明一个变量可以在后面的构建过程中使用的,该变量值,可以通过docker build
命令在Image构建过程中进行修改; --build-arg
传入的变量必须已经在Dockfile中通过ARG
指令定义,否则会在构建过程中触发Warning;具体可见ARG
指令介绍的一节;
--add-host
在构建过程中,向构建的container的/etc/hosts
中写入一个静态的host解析记录,注意:这里host的变更只影响构建过程,并不会对最终构建的镜像有何影响;可以参考github issue,如下:
1 | docker build -t test/helloworld --add-host=walkerdu:1.1.1.1 . |
运行容器后,查看/etc/hosts
的结果如下,docker build
添加的host并没有影响到最终的镜像:
1 | docker run -d test/helloworld |
--target
在含有多个构建stage的Dockerfile构建的时候,可以使用--target
选项来指定只进行某个stage的构建,其他的构建stage会被丢弃,如下:
1 | FROM debian AS build-env |
执行只构建第一个build-env
stage的构建指令如下:
1 | docker build -t mybuildimage --target build-env . |
docker tag
docker tag
用于为一个Image对象打一个tag,其实就是给一个Image起另一个名字而已,格式如下:
1 | docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG] |
Image的名字是格式一般有两部分组成:注册中心和镜像名;中间用斜线分隔;注册中心名字是标准的DNS格式,可以包含主机的端口号;
Image的tag必须是由ASCII组成,可以包含:大小写字母,数字,下划线,点号,破折号;但是不能以点号,破折号开始,且长度不能超过128个字符长度;
打tag可以使用source image的Image ID,Image Name,如下简单示例:
1 | 通过Image Name进行打tag操作 |
docker save
docker的Image是由docker daemon集中化进行管理的,我们可以通过docker save/docker load
进行镜像的迁移工作;docker save
用于将Image的各个层的数据输出到一个tar的归档文件中;然后在需要的地方进行恢复;docker save
的语法格式如下:
1 | docker save [OPTIONS] IMAGE [IMAGE...] |
docker save
默认会将tarred的镜像数据(所有layer的数据)输出到STDOUT中,可以通过-o, --output
指定输出的tar文件名,也可以用重定向,管道进行操作,如下:
1 | docker save test/helloworld > helloworld.tar |
docker load
和docker save
相对的是docker load
,用于从tar归档文件中加载Image到docker host中进行集中化管理;docker load
的语法格式如下:
1 | docker load [OPTIONS] |
docker load
支持从tar归档文件(支持gzip,bzip2,xz的压缩格式)或者STDIN进行镜像的恢复,恢复的Images信息包括repo名字和tag信息;docker load
支持的OPTIONS有两个,如下:
-i, --input
:输入的tar归档文件;-q, --quiet
:忽略load过程的输出信息
如下测试:
1 | docker load -i helloworld.tar |
当load的时候出现Image的repo和tag和docker host存在重复的时候,会覆盖之前旧的Images;
docker export
docker export
是将一个Container的文件系统导出为一个tar归档文件,命令格式如下,OPTION只支持-o, --output
选项:
1 | docker export [OPTIONS] CONTAINER |
和docker save
的差别是:
docker save
的操作对象是一个Image,docker export
的操作对象是一个Container;docker save
会将Image的所有Layer信息,repo和tag信息都保存为tar归档文件;dokcer export
会将Container的平铺开的整个文件系统进行归档打包,打包内容不包含任何的对应Image的结构信息;
下面是docker export
测试,我们可以看到导出的归档文件就是整个文件系统,而docker save
导出的结果在前面一节我们看了是包含Image层级信息的归档文件;
1 | docker export 7bd9f0152dff > helloworld_container.tar |
docker export
导出的时候,不会将Container的volumes挂载的数据进行归档,只会归档底层挂载的目录;可以参考如何备份,恢复和迁移数据volumes
docker import
docker import
用于从tar归档文件或者标准输入中创建一个新的Image;这里和docker load
的区别是docker save & docker export
之间的区别导致的;stackoverflow上也有关于docker load and import difference的讨论;
docker load
会加载归档文件中的镜像,包括repo和tag名字,不做任何修改,而docker import
会创建新的Image,如果不指定repo和tag名字,会默认为none;docker image
支持从docker save
和docker export
两类导出的归档数据中进行Image的创建;
docker import
的格式如下:
1 | docker import [OPTIONS] file|URL|- [REPOSITORY[:TAG]] |
docker import
支持从三种源进行Image的构建,分别是:本地文件,URL,STDIN;
1 | docker import helloworld.tar |
docker history
docker history
用于查看一个Image的各个Layer的信息,Image是由一个个的Layer叠加而成的;每一层Layer都是上层Layer的Parent,docker history
就可以展示这些Layer信息,及其是如何构建的,如下是命令的格式:
1 | docker history [OPTIONS] IMAGE |
支持的选项有:
--format
:格式化输出每一层的Image信息;具体参数值可以参考官方文档;-H, --human
:每一层的Image大小的输出用可读格式,默认为true;--no-trunc
:输出不截断,显示Image的完整的所有信息;-q, --quiet
:只输出每层的Image ID;
如下测试:
1 | docker history test/helloworld |
docker rmi
docker rmi
用于从docker host的本地镜像仓库中删除指定Image,如果一个Image含有多个tags,必须指定对应的repo:tag进行指定删除;如果一个image只有一个tag,那么可以直接通过ImageID进行删除;docker rmi
不会删除远端注册中心的镜像;docker rmi
的命令格式如下:
1 | docker rmi [OPTIONS] IMAGE [IMAGE...] |
OPTION支持的选项如下:
-f, --force
:当Image有关联运行的Container,可以通过此选项强制删除;--no-prune
:不删除没有打tag的父镜像;
docker images
docker images
用于列出docker host上所有的Image列表;命令格式如下:
1 | docker images [OPTIONS] [REPOSITORY[:TAG]] |
可以指定显示特定repo和tag的Image;默认docker images
会显示所有的顶层的Image,以及对应的repo,tags和对应的size;docker images
支持的选项列表如下:
-a, --all
:显示所有Images,包括中间层的Image,默认只会显示顶层的Image,不会展示中间层的Image,我们现在知道image
的构造是一层一层堆叠的,为了加速Image的构建过程和减少Image的所占用大小;--digests
:显示Image的digest信息,也就是hash值;-f, --filter
:用于过滤特殊条件的Image,--filter
支持的参数格式为”key=value”对,匹配多个参数需要多个--filter
选项来标识,例如--filter "foo=bar" --filter "bob=alice"
,目前--filter
支持的选项参数有以下几种:dangling
:取值为true/false;用来筛选没有打tag的Image;label
:使用方式为:label=<key>
或者label=<key>=<value>
,用来筛选特定label的Image;before
:使用方式为:before=<image-name>[:<tag>]
或者before=<image-id>
或者before=<image-name@digest>
,用来过滤创建比指定Image早的Image;after
:使用方式和before
一样,用来过滤比指定Image创建晚的Image;reference
:用来匹配特定repo和tag的Image;
--format
:格式化输出Image的信息;--no-trunc
:输出不截断,显示Image的完整的所有信息;-q, --quiet
:只输出所有的Image ID;
2. docker容器生命管理
docker run
docker run
用来运行一个container,其格式语法如下:
1 | docker run [OPTIONS] IMAGE [COMMAND] [ARG...] |
docker run
命令运行一个container,其过程其实分了两步:
- 基于一个image之上,创建一个可修改的container layer;
- 然后通过特殊命令启动该container layer;
docker run
等价于先调用API/containers/create
,然后再调用/containers/(id)/start
;且已经stop的container,可以通过docker start
进行恢复,包括只之前running时发生的修改;具体相关docker run
的手册说明可以详见官方指引;
docker run
的构建参数OPTIONS
选项列表,具体可参考官方文档,有一些是和docker build
重合的,区别在于,他们在docker build
中只影响构建镜像的过程,而docekr run
的修改会影响运行的container;下面介绍一些比较重要的参数:
--name
给要运行的container,指定一个名字;如下:
1 | docker run -d --name walker test/helloworld |
如果运行container的时候,不指定名字,默认会生成一个随机的名字,但是这个随机的名字,看上去又有点生成规则。如下:
1 | docker ps |
经过请教Claude.AI得知,Docker生成的默认容器名称是两个英文单词拼接而成的。规则如下:
- 前缀单词,是从Docker内置的一个adjective(形容词)词库中随机选取的。这个词库包含许多常用的形容词,例如:admiring、desperate、silly、jovial、awesome等等。
- 后缀单词则,从Docker的另一个著名科学家名字词库中随机选取。这个词库包含众多著名科学家的名字,比如:einstein、feynman、hawking、curie等。
具体实现可以参考Docker的官方实现:moby names-generator.go
-it, --interactive, --tty
-it
这两个选项一般会一起使用,--interactive
选项是保持container的STDIN开启,这样运行的container才可以进行shell指令交互,进行相关调试;--tty
选项为container提供一个伪终端(pseudo-TTY)绑定STDIN,这样才可以进行容器登录,并通过shell交互进行操作;
-d, -detach
:后台运行容器,一般服务都是以后台daemon的方式运行;--cidfile
运行container的时候,尝试创建一个新文件,并将container id写入其中,如果文件已经存在,将会返回错误,不会启动container,此cidfile在docker run
执行结果后,就会关闭;该功能的目的是为了防止container多开,类似于进程通过pid文件来防多开的设计;如下测试:
1 | docker run --cidfile hw.cid -d test/helloworld |
-w, --workdir
设置container的工作目录,如果路径不存在,则会自动创建一个;这个参数会覆盖docker build
镜像构建时,指定的container的工作目录;如下:
1 | 修改镜像的工作目录,会发现CMD找不到容器启动要执行的exec文件了 |
此选项的用途是创建一个特权容器;默认权限的容器运行时对宿主机来说是一个普通用户,无法访问很多资源,例如硬件资源;特权权限允许容器拥有宿主机的root权限;常用在Docker-in-Docker
,在一个容器中允许另一个容器,但是有很多安全问题;参考文档;下面是关于特权权限的开启示例:
1 | docker run -it test/helloworld bash |
-v, --volume
将宿主机的目录挂载到Container的对应的目录中;在前面docker build的VOLUME
指令中,我们知道VOLUME
指令用来持久化数据的;前已经介绍了关于volume的使用有两种方法,现在又多了一种,可以挂载本地目录:
docker run
的时候不显示挂载volume,对于docker build
中的挂载点,会使用匿名的volume,VOLUME
指令默认在Container运行的时候创建的匿名Volume,虽然是持久化的,但是无法与其他Container共享;docker run
显示指定有名的volume挂载,这种时候会在宿主机的指定路径下/var/lib/docker/volumes/vol_name/_data
创建对应的名字的volume挂载到Container中;既做到了持久化,也可以和其他Container共享数据;docker run
在volume挂载还可以指定本地目录挂载到Container中,如下:
1 | docker run -v /tmp/helloworld_dir:/walkerdu -w /walkerdu -it test/helloworld bash |
当要挂载的本地目录不存在时候会自动创建,我们可以看到通过volume来挂载目录到Container中的方式,也可以进行数据的持久化;
--mount
mount
选项支持在Container中挂载volumes
,宿主机目录,tmpfs
;它的功能覆盖了上面介绍的--volume
选项,只是语法格式不一样而已;详见官方关于VOLUME的说明;如下,mount
指令由一组用逗号分隔的<key>=<value>
组成;
1 | --mount '<key>=<value>, <key>=<value>...' |
虽然官方没有计划弃用--volume
(毕竟要向后兼容),但是官方建议使用--mount
来进行volume挂载进行数据持久化;
--read-only
:让Container的整个根文件系统变成只读,除了--volume
和--mount
指定挂载的目录;-p, --expose
用于绑定本地主机端口和Container的端口,详见Docker NetWorking;格式如下:
1 | -p [host_ip:]host_port:container_port |
主机IP可以不填,默认对所有网卡生效;在前面EXPOSE
指令也有介绍,这里不再赘述;
--pull
选项用于指定在准备运行Container的时候,如何拉取所需的镜像,如下三个选项参数:
参数值 | 说明 |
---|---|
missing | 如果docker deamon中不存在需要的Image,则进行拉取,否则使用已经cache的Image;默认采用此种方式 |
never | 不拉取Image,如果docker deamon中没有,则报错 |
always | 创建Container前,总是拉取最新的Image |
用来在Container中设置环境变量,可以用来覆盖Image中docker build
设置的同名环境变量,使用如下:
1 | cat env.txt |
注意:当选项只设置了环境变量的名字,没有设置value,不会覆盖Container中的环境变量;
用来设置Container的元数据即标签;语法格式和环境变量类似;详细参考官方Label说明;如下:
1 | cat label.txt |
注意:label可以只设置key,没有value,默认label的值为空串””,如果label的key有重复,那么后面的label会覆盖前面设置的label;
该参数用于设置Container在退出之后的重启策略,如下:
参数 | 说明 |
---|---|
no | Container退出后,不自动重启,默认选项 |
on-failure[:max-retries] | 在Container退出后的exit code非0时,尝试进行重启,可以设置重试次数 |
unless-stopped | 除非显示的stop Container,其他情况都重启 |
always | 只要Container退出,就一直尝试重启 |
--add-host
:在docker build
中已经说明这里不再赘述;--ulimit
:在docker build
中已经说明这里不再赘述;--stop-signal
该选项用来docker stop
Container的时候,发送给Container的信号,可以是信号名SIG<NAME>
,也可以是信号值;如果不设置,默认是SIGTERM
;
该选项用来设置在向Container发送stop信号后,等待多少秒超时还没有完成stop的话,就执行强杀,即发送SIGKILL
信号;
如果--stop-timeout
被设置为-1,那么会永远等待Container的结束;默认缺省值是有docker deamon决定的,Linux Container 10s,Windows Container 30s;
此参数用于限制Container最大允许使用的内存,Linux上是通过设置cgroup来实现;可以查看/sys/fs/cgroup/memory/memory.limit_in_bytes
;
--cpus
:使用的cpu核数--sysctl
:设置Container运行时的一些内核参数;
docker create
docker create
用于创建一个Container,在前面docker run
介绍时,我们知道运行一个Container分为两步,第一步就是调用/containers/create
的API在一个image之上,创建一个可修改的container layer;docker create
就是干这个事情的:创建一个containr layer,然后不运行;
docker create
创建完Container后,会在标准输出输出一个Container ID,此Container在创建完后的状态为Created
,如下:
1 | $ docker create -e A=B test/helloworld |
docker create
等价于docker run -d
,除了它创建的Container不会自动启动运行;此种方式对于想要事先配置好Container,然后按需启动很有用处;
后面可以通过docker start
命令来启动容器,如下:
1 | docker start -ai e05febc25ab2 |
docker create
的命令格式如下,和docker run
的OPTIONS基本是一样的,具体OPTIONS列表可以参考前一节,或者docker run指引
;
1 | docker create [OPTIONS] IMAGE [COMMAND] [ARG...] |
docker start
docker start
用于启动没有运行(例如Created,Exited状态)的Container ,docker start
的格式如下:
1 | docker start [OPTIONS] CONTAINER [CONTAINER...] |
docker start
的OPTIONS比较少,因为Container的相关参数在其创建的时候已经写入了Container中,docker start
相对只是负责启动,有一些简单的输入输出的选项,可以参考docker start
的手册说明;
需要注意的是:如上面命令格式,**docker start
后面除了OPTIONS的参数,只支持传入Container的名字**,不支持其他的参数传入,可以传入多个Container,批量操作;
docker stop
docker stop
用于stop处于running状态的Container,同样支持操作多个容器;命令格式如下:
1 | docker stop [OPTIONS] CONTAINER [CONTAINER...] |
docker stop
后,默认会向Container的主进程发送一个SIGTERM
信号,如果在规定的优雅退出时间内,容器没有Stop,则会继续发送SIGKILL
进行强杀;默认发送的信号在介绍docker run
的时候已经介绍,可以通过两种方式进行修改:
STOPSIGNAL
在docker build
的时候设置--stop-signal
在docker run
或者docker create
的时候设置,会覆盖Dockfile
的STOPSIGNAL
设置;
docker stop
支持的选项只有一个-t, --time
,设置Container在收到停止信号后的优雅退出超时时间;我们知道docker run
或者docker create
的时候,可以通过--stop-timeout
选项来设置Container的优雅退出超时时间;docker stop
的超时时间设置优先级高于docker run
设置的超时时间;如下测试:
1 | 设置退出超时时间为20s |
docker restart
docker restart
用于重启一个Container,等价于先docker stop
,然后再docker start
;格式 如下:
1 | docker restart [OPTIONS] CONTAINER [CONTAINER...] |
目前支持的参数只有一个-t, --time
,和docker stop
一样,用于指定Container优雅退出的的超时时间;
docker pause/unpause
pause
用于暂停容器中的所有进程,格式如下:
1 | docker pause CONTAINER [CONTAINER...] |
docker pause
,在Linux中,通过cgroups的freezer cgroup来实现进程的暂停和恢复;Linux中,
- 一般暂停进程都是通过发送
SIGSTOP
信号进行来实现,此信号会被进程观察到,虽然其不能忽略此信号也不能捕获该信号; - 另外一种方式暂停进程是通过
freeze cgroup
来实现,是进程无法感知的,也是不能被捕获的;
如下,登录容器查看输出结果,然后进行pause/unpause
,输出如下:
1 | docker exec -it 68c0539616cb bash |
docker kill
docker kill
用于kill正在运行的Container,格式如下:
1 | docker kill [OPTIONS] CONTAINER [CONTAINER...] |
docker kill
默认会向Container的主进程发送SIGKILL
信号;可以通过--signal
选项来设置发送给Container的信号值;这里的CONTAINER
可以是Container ID,Container ID的前缀,也可以是Container Name;Container ID前缀匹配如果存在唯一的Container ID,则执行docker kill
操作;
docker kill
目前只支持--signal
选项;
docker kill
的使用方式和linux的kill命令很像,--signal
可以传递任何预定义的信号值,让Container的主进程决定如何进行信号处理;这里需要注意:ENTERPOINT
和CMD
指令在shell模式运行的时候,是作为/bin/sh -c
的子进程运行的,这种情况是无法接受docker
命令的信号的;信号只会发送给Container的主进程(PID=1);
docker rm
docker rm
用于删除Container,正常情况下Container在stop之后,是一直存在的,可以被再次运行,我们可以通过docker rm
可以最终删除该Container,格式如下:
1 | docker rm [OPTIONS] CONTAINER [CONTAINER...] |
docker rm
支持的选项有如下三种:
-f, --force
:强制(通过发送SIGKILL信号)将running的Container销毁;-l, --link
:用于删除Container之间默认的underlying桥接网络;-v, --volumes
:删除Container的时候,删除匿名volumes;
和git版本管理类似,可以通过docker container prune
命令来移除所有已经stop的Container;docker system prune
可以移除整个docker
无用的资源,例如stoped的Container, 未使用的images,以及网络;
3. docker容器操作
docker ps
docker ps
用于查看Container的信息;名字类似linux中的ps命令,格式如下:
1 | docker ps [OPTIONS] |
docker ps
支持的OPTIONS列表如下:
-a, --all
:列出所有Containers,默认只会列出running状态的Containers;--foramt
:格式化输出Container的信息;-n, --last
:最新的n个创建的Container;-l, --latest
:最新创建的容器;--no-trunc
:输出的容器信息不截断;-q, --quiet
:只输出Container ID信息;-s, --size
:显示总的文件大小;-f, --filter
:根据条件过滤出特定的Container列表,和docker images
的--filter
功能是一样的,不过Container的ps支持的filter参数值更多,同样--filter
选项的参数格式为”key=value”对,匹配多个参数需要多个--filter
选项来标识,例如--filter "foo=bar" --filter "bob=alice"
,docker ps --filter
支持的选项参数有以下几种:如下:id
:显示指定的Container ID的Container;name
:显示指定的Container Name的Container;label
:过滤指定label的Container,label
的值可以是一个key
,也可以是key=value
,例如--filter "label=color"
或者--filter "label=color=blue"
;exited
:显示特定exit code的Container,需要结合--all
选项一起使用;status
:显示特定状态的Container,Container的状态包括:created
,restarting
,running
,removing
,paused
,exited
,dead
;ancestor
:查找祖先为给定Image的Containers,Image的参数可以为:<image-name>[:<tag>]
或者<image-id>
或者<image-name@digest>
;before
:在特定Container之前创建的容器;since
:在特定Container之后创建的容器;volume
:查找挂载特定volume的Containers;network
:查找连接特定网络的的Containers;publish
或expose
:查找暴露特定端口的Container;health
:查找特定健康检测状态的Container,健康状态分为以下几类:startig
,healthy
,unhealthy
,none
;is-task
:判断是否某个服务的task;
docker top
docker top
用于输出指定指定容器中运行的进程,命令格式如下,支持docker ps
的选项:
1 | docker top CONTAINER [ps OPTIONS] |
docker attach
docker attach
用于attach到运行中的Container本地的标准输入,输出,错误流;格式如下:
1 | docker attach [OPTIONS] CONTAINER |
通过docker attach
可以查看到正在运行Container的输出,也可以通过交互的方式控制Container的1号进程;可以对同一个Container进行同时多个attach操作;
attach命令只会显示
ENTRYPOINT/CMD
入口进程的输出,attach命令挂载到Container上后,看上去会把自己挂住,其实只是没有和终端交互而已
可以通过CTRL-C
来停止一个Container,CTRL-C
会默认向Container发送SIGKILL
信号,如果--sig-proxy
选项置为true,那么CTRL-C
会发送SIGINT
信号;如果Container以-it
方式启动,那么可以通过发送CTRL-p CTRL-q
来detach一个Container,Container任然会继续运行;
1 | attach到容器后,CTRL-C终止容器 |
docker attach
支持的选项列表如下:
--detach-keys
:覆盖detach的Container时候的按键序列;--no-stdin
:attach的时候不attach STDIN;sig-proxy
:attach后,将所有终端的控制信号直接发送给Container的1号进程;例如CTRL-C
按照正常的SIGINT
信号发送给Container;
docker commit
docker commit
用于从Container中创建一个新的Image,命令格式如下:
1 | docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]] |
docker commit
可以从Writeable Layer的Container上进行Image的构建,基于此创建的Image会包含Container中的文件修改和设置,这样可以很方便的以交互的方式进行Container的调试,或者将工作环境切换到其他服务器;
需要注意的是:基于Container构建的Image,并不会包含挂载的volumes;
默认情况下:在执行docker commit
构建的时候,Container会被暂停,以降低数据损坏的可能性;可以通过选项--pause=false
来不暂停Container;
docker commit
支持的选项有以下几种:
-a, --author
,指定作者;-c, --change
:在创建Image的时候,通过该参数来使用Dockerfile
支持的指令进行Image构建结果的修改;,支持的Dockerfile
的指令有:CMD
|ENTRYPOINT
|ENV
|EXPOSE
|LABEL
|ONBUILD
|USER
|VOLUME
|WORKDIR
;-m, --message
:commit消息;-p, --pause
:构建进项的时候是否暂停Container,默认为true;
4. docker registry操作
下面是一些对于Docker的注册中心的相关操作;
docker login
docker login
用于登录指定的docker registry,命令格式如下:
1 | docker login [OPTIONS] [SERVER] |
支持的选项如下:
-u, --username
:登录用户名;-p, --password
:登录密码;--password-stdin
:从标准输入接收密码;
1 | cat ~/my_password.txt | docker login --username foo --password-stdin |
默认不指定SERVER,会登录到官方的Docker Hub注册中心;我们可以指定登录到任何公开或者私有的注册中心,登录后默认会将凭证以base64编码方式保存在$HOME/.docker/config.json
(Linux)对应的auth字段中;Docker支持将登录的凭证存储在其他的凭证仓库,例如:操作系统本地的keychain,相对于Docker的本地config,将凭证存储在远端的仓库中会更加安全;
如果需要将凭证存储在远端仓库中,需要对应的远端仓库的helper或者说client程序来负责和Docker client进行存储和读取交互,目前支持的第三方凭证工具列表如下:
凭证的远端helper程序的配置如下:$HOME/.docker/config.json
,对应的helper程序需要在$PATH
路径中可以查找;
1 | { |
对应的helper程序的配置需要以docker-credential-
为前缀,加上helper程序名字,例如上面的helper程序的配置文件需命名为:docker-credential-osxkeychain
docker pull
docker pull
用于从registry拉取一个Images或者一整个repo;命令格式如下:
1 | docker pull [OPTIONS] NAME[:TAG|@DIGEST] |
我们大部分的Images的最顶层都是从 Docker Hub注册中心拉取获得的,Docker Hub中包含了很多已经构建好的基础Images,我们都可以进行拉取使用,不需要我们自己进行单独的构建;docker pull
拉取的时候Docker daemon默认会同时并发的拉取一个Image的三层镜像;如果要修改该设置,需要设置dockerd的--max-concurrent-downloads
参数;
docker pull
支持的选项如下:
-a, --all-tags
:拉取一个repo下面的所有tag的Image;--disable-content-trust
:忽略Image的校验;--platform
:拉取特定平台的镜像,默认是根据Docker daemon的OS来自动匹配拉取;-q, --quiet
:隐藏详细信息输出;
如下测试,
1 | 默认拉取ubuntu:latest的镜像 |
等价于:
1 | docker pull ubuntu:latest |
默认情况,docker pull
从Docker Hub中拉取Images,也可以显示的指定从特定的注册中心拉取镜像,如下从AWS的注册中心拉取ubuntu镜像:
1 | docker pull public.ecr.aws/lts/ubuntu |
Docker daemon通过https://
协议和注册中心通信,除非注册中心被设置允许通过不安全的http协议进行通信;具体可以参考如何设置insecure registries;
docker push
docker push
用于向registry推送一个Images或者一整个repo;命令格式如下:
1 | docker push [OPTIONS] NAME[:TAG] |
docker push
和docker pull
功能是一对,使用格式和语法基本一致,这里不再详述了;
docker push
推送的时候Docker daemon默认会同时并发的推送一个Image的五层镜像;如果要修改该设置,需要设置dockerd的--max-concurrent-uploads
参数;
docker search
docker search
用从Docker Hub
中搜索Images;不像docker pull/push
可以从其他注册中心进行镜像操作,docker search
只能从官方的Docker Hub进行Image的搜索;docker search
命令的格式如下:
1 | docker search [OPTIONS] TERM |
支持的OPTION列表如下:
-f, --filter
:按照指定的flag进行过滤搜索;--format
:按照Go Template进行结果输出;--limit
:最大搜索结果,默认25个;--no-trunc
:输出结果不截断;
5. docker其他操作
docker inspect
docker inspect
用于查看Docker对象的详细底层结构控制信息;指令的格式如下:
1 | docker inspect [OPTIONS] NAME|ID [NAME|ID...] |
docker inspect
默认输出的信息是JSON数组格式化的;它支持的OPTIONS列表如下:
-f, --format
:按照指定的Go模板进行格式化输出;这个还是比较常用的,关于Go模块,这篇翻译Go Template不错,可以参考;-s, --size
:针对Container对象,输出总文件的大小;--type
:如果出现相同名的对象,需要指定要查看对象的类型,例如--type=container
或者--type=image
,当然最好的还是通过归类的对象的inspect命令进行信息的查看,例如docker container inspect
;
docker events
docker events
用于从docker deamon中获取实时的事件消息;对于不同的Docker对象会有不同种类的事件类型,具体的事件类型可以参考官方手册关于各种对象的事件列表;
问题汇总
docker.sock权限问题
1 | $docker run -d -it --rm --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3-management |
我们看一下docker.sock文件的权限如下:
1 | $ll /var/run/docker.sock |
该文件是docker安装时创建的sock文件,它的用途是:
Docker.sock is a Unix socket that enables the Docker server-side daemon, dockerd, to communicate with its command-line interface via a REST API.
比较安全的解决方法是,参考Stack Overflow,docker默认只能以root权限运行,如果想以普通用户运行docker进程,需要将该用户加入docker group,如下流程:
1 | # Create the docker group if it does not exist |