奇妙的 Docker Inspect

原创 2016年05月30日 15:37:00


奇妙的 Docker Inspect 模版

概述

很多 Docker 用户都知道 docker inspect 命令,该命令用于获取容器/镜像的元数据,其中 -f 参数可以用于获取指定的数据,例如使用 docker inspect -f {{.IPAddress}} 来获取容器的 IP 地址。不过很多用户容易被该特性的语法搞晕,并很少有人能将它的优势发挥出来(大部分人都是通过 grep 来获取指定数据,虽然有效但比较零散混乱)。本文将详细介绍 -f 参数,并给出一些例子来说明如何使用它。

docker inspect 

简单地说,-f 的实参是个 Go 模版,并在容器/镜像的元数据上以该 Go 模版作为输入,最终返回模版指定的数据。第一个问题就是该命令说明文档中的用词“Go 模版”对于没有 Go 开发经验的人来说很模糊——我的第一感觉就是它类似恐怖的 C++ 模版。还好 Go 模版和 C++ 模版/泛型毫不相干,Go 模版是一种模板引擎,让数据以指定的模式输出。这个概念对于 Web 开发者是非常熟悉的,Web 领域有很多模版引擎,比如 Jinga2(用于 Python 和 Flask)、Mustache、JSP 等等,看下面的简单示例:

$ docker inspect -f 'Hello from container {{.Name}}' jenkins
Hello from container /jenkins

我们可以看到,-f 指定了一个简单的模式(或称之为模版)并应用于容器的元数据。当然,对于元数据,我们也可以什么都不指定:

$ docker inspect -f "This is a bit pointless" jenkins
This is a bit pointless

下面让我们来进一步看看 Go 模版的奇妙之处,例如我们可以通过模版来查找所有退出码为非 0 的容器名:

$ docker inspect -f '{{if ne 0.0 .State.ExitCode }}{{.Name}} {{.State.ExitCode}}{{ end }}' $(docker ps -aq)

/tender_colden 1
/clever_mcclintock 126

/grave_bartik 1

(无论是否匹配到,对于每个容器都会输出一行)

或者在 jenkins-data 容器中查找卷 /var/jenkins_home 对应在 host 的目录:

docker inspect -f '{{index .Volumes "/var/jenkins_home"}}' jenkins-data
/var/lib/docker/vfs/dir/5a6f7b306b96af38723fc4d31def1cc515a0d75c785f3462482f60b730533b1a

上面的例子可能稍微有点难理解,不过没关系,我们先来了解一下 Go 模版的基本用法。

模版指令

{{ }} 语法用于处理模版指令,大括号外的任何字符都将直接输出。

上下文

“.” 表示“当前上下文”。大多数情况下表示了容器元数据的整个数据结构,但在某些情况下可以重新规定上下文,比如使用 with 函数:

$ docker inspect -f '{{.State.Pid}}' jenkins
6331
$ docker inspect -f '{{with .State}} {{.Pid}} {{end}}' jenkins
6331

可以使用 $ 来获取根上下文,例如:

$ docker inspect -f '{{with .State}} {{$.Name}} has pid {{.Pid}} {{end}}' jenkins
 /jenkins has pid 6331

注意,单独使用 “.” 本身也是可以的,将输出未格式化的完整元数据:

$ docker inspect -f '{{.}}' jenkins
...

数据类型

inspect 数据可以由浮点数、字符串和布尔组成,可以使用 Go 模版内置函数进行比较判断。虽然 Go 模版支持整数,但目前 inspect 数据中的数值类型都是浮点数,而整数应该对于大多数场景更方便(详见该Issue)。使用字符串时可以使用双引号。

数据中不存在的值是不可以用来比较的:

$ docker inspect -f '{{.ExecIDs}}' jenkins
<no value>
$ docker inspect -f '{{eq .ExecIDs .ExecIDs}}' jenkins
FATA[0000] template: :1:2: executing "" at <eq .ExecIDs .ExecIDs>: error calling eq: invalid type for comparison

数据结构

inspect 数据使用 map 以及数组保存。Map 结构非常简单,前面我们曾经展示过,可以通过 . 的链式来访问 map 内部数据:

$ docker inspect -f '{{.State.ExitCode}}' jenkins
0

不过有些情况(比如 map 的键不是字符串)是不能直接使用 . 方式来获取 map 值的,此时我们可以使用index 函数,前面卷的例子可以这样写:

docker inspect -f '{{index .Volumes "/var/jenkins_home"}}' jenkins-data
/var/lib/docker/vfs/dir/5a6f7b306b96af38723fc4d31def1cc515a0d75c785f3462482f60b730533b1a

我们也可以使用 index 来获取指定下标的数组值:

$ docker inspect -f '{{.HostConfig.Binds}}' jenkins
[/var/run/docker.sock:/var/run/docker.sock /usr/bin/docker:/usr/bin/docker]
$ docker inspect -f '{{index .HostConfig.Binds 1}}' jenkins
/usr/bin/docker:/usr/bin/docker

函数

除了 index  函数,其他很多函数也很常用。比如逻辑函数 andor 可以返回布尔结果。注意,函数是不能放在中间:

$ docker inspect -f '{{and true true}}' jenkins
true

而不是:

$ docker inspect -f '{{true and true}}' jenkins
FATA[0000] template: :1:2: executing "" at <true>: can't give argument to non-function true 

下面是一些常用的比较函数:

  • eq (等于)
  • ne (不等于)
  • lt (小于)
  • le (小于等于)
  • gt (大于)
  • ge (大于等于)

我们可以用这些函数来比较字符串、浮点数或整数:

$ docker inspect -f '{{eq "abc" "abc"}}' jenkins
true
$ docker inspect -f '{{ge 1 -1}}' jenkins
true
$ docker inspect -f '{{lt 4.5 4.6}}' jenkins
true
$ docker inspect -f '{{ne 4.5 4.5}}' jenkins
false

要注意的是操作数类型必须匹配,数字比较时使用浮点数:

$ docker inspect -f '{{eq "4.5" 4.5}}' jenkins
FATA[0000] template: :1:2: executing "" at <eq "4.5" 4.5>: error calling eq: incompatible types for comparison
$ docker inspect -f '{{gt .State.Pid 1}}' jenkins
FATA[0000] template: :1:2: executing "" at <gt .State.Pid 1>: error calling gt: incompatible types for comparison 
$ docker inspect -f '{{gt .State.Pid 1.0}}' jenkins
true

另外,可以使用 json 函数来生成 JSON 输出:

$ docker inspect -f '{{json .NetworkSettings.Ports}}' jenkins
{"50000/tcp":null,"8080/tcp":[{"HostIp":"0.0.0.0","HostPort":"8080"}]}

我们也可以使用 jq 工具来组合结果:

$ docker inspect -f '{{json .State}}' jenkins-data | jq '.StartedAt'
"2015-03-15T20:26:30.526796706Z"

当然,docker inspect 的默认输出结果就是 JSON,所以下面这样也可以:

$ docker inspect jenkins-data | jq '.[] | .State.StartedAt'
"2015-03-15T20:26:30.526796706Z"

更多函数请参考 Go 官方文档,不过很奇怪的是官方文档中并没有描述 json 函数(我是从 Nathan LeClaire’s blog 中学到的),你如果知道其中原因,记得告诉我!

If 语句

条件语句 if 可以和前面的比较函数一起使用:

$ docker inspect -f '{{if eq .State.ExitCode 0.0}} 
Normal Exit
{{else if eq .State.ExitCode 1.0}} 
Not a Normal Exit 
{{else}} 
Still Not a Normal Exit 
{{end}}' jenkins

Normal Exit

注意,{{end}} 语句必须有,else if 和 else 按需使用。

结论

我想本文应该涵盖了 docker inspect -f 使用模版时的大部分内容,不过另外还有一些很常用的特性,比如使用 range 来迭代数据、自定义函数、使用管道等需要你来自己摸索实践。

我还没找到一份全面的使用 Go 模版的参考文档,目前我觉得这份还不错:chapter from a the free e-book “Network programming with Go” by Jan Newmarch。

当然,你可以参考 Go 官方文档,但是它太精简了,特别是对于非 Go 程序员来说比较难理解。


Docker学习笔记之top,inspect,exec,export命令

查看容器进程 docker top可以查看运行容器中运行的进程 一般用于查看后台型,交互型的需要到其他终端下查看 首先创建一个后台型容器并处于始终睡眠 docker run -d --name...

docker常用命令详解

本文只记录docker命令在大部分情境下的使用,如果想了解每一个选项的细节,请参考官方文档,这里只作为自己以后的备忘记录下来。 根据自己的理解,总的来说分为以下几种: 容器生命周期管理 —...
  • permike
  • permike
  • 2016年07月11日 11:35
  • 42323

Docker 命令详解 命令示例

Docker 子命令: attach   commit  diff     export   history import   insert   kill    login    port     ...

Docker技术的使用

Docker是一种基于容器的虚拟化技术,Docker应用场景1、面向产品,2、面向开发,3、面向测试,4、面向运维,5、面向自定化,6、面向微服务,7、面向大规模的分布式架构。 一、Docker的命...

Docker常用命令

又把官方文档过了一遍,总结一下常用命令 镜像管理 docker images:列出本地所有镜像 docker search :查找image docker pull :下载image doc...

docker基础知识之挂载本地目录

https://my.oschina.net/piorcn/blog/324202 http://blog.csdn.net/yangzhenping/article/details/4366778...
  • huludan
  • huludan
  • 2016年09月23日 18:11
  • 11398

docker实践入门之三

文件系统说完了网络,现在来说存储。对于redis这样的应用来说,我们通常并不需要它的持久化存储,只是拿它做缓存而已,所以存储问题并不重要,但是对于mysql这样的数据库来说,存储就非常重要了。前面说到...
  • Raptor
  • Raptor
  • 2016年05月02日 23:00
  • 8943

Docker network命令

docker network命令及其用法

docker 报错集锦

1.demo:/etc/udev/rules.d# pipework br0 centos6 192.168.32.106/24@192.168.32.254 报错:Docker inspe...

nginx 多站点,多域名,多目录配置

Windows 下配置 worker_processes  1; events {     worker_connections  1024; } http {     inclu...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:奇妙的 Docker Inspect
举报原因:
原因补充:

(最多只允许输入30个字)