Docker --format 引數提供了基於 Go模板 的日誌格式化輸出輔助功能,並提供了一些內建的增強函式。
什麼是模板?
上圖是大家熟悉的 MVC 框架(Model View Controller): Model(模型,通常在服務端)用於處理資料、View(檢視,客戶端程式碼)用於展現結果、Controller(控制器)用於控制資料流,確保 M 和 V 的同步,即一旦 M 改變,V 也應該同步更新。
而對於 View 端的處理,在很多動態語言中是通過在靜態 HTML 程式碼中插入動態資料來實現的。例如 JSP 的 <%=....=%> 和 PHP 的 <?php.....?> 語法。
由於最終展示給使用者的資訊大部分是靜態不變的,只有少部分資料會根據使用者的不同而動態生成。比如,對於 docker ls 的輸出資訊會根據附加引數的不同而不同,但其表頭資訊是固定的。所以,將靜態資訊固化為模板可以複用程式碼,提高展示效率。
Go語言提供了簡單靈活的模板支援,而基於 Go 開發的 Docker 繼承了該強大能力,使其可以脫離 Shell 的相關操作,直接對結果進行格式化輸出。所有支援 --format 擴充套件的 Docker CLI 指令均支援該操作。
Go模板常用語法
註釋
格式: {{/*註釋內容*/}}
示例:
docker network inspect --format='{{/*檢視容器的預設閘道器*/}}{{range .IPAM.Config}}{{.Gateway}}{{end}}' $INSTANCE_ID
變數
系統變數 {{.}}
點號表示當前物件及上下文,和 Java、C++ 中的 this 類似。可以直接通過{{.}}獲取當前物件。
另外,如果返回結果也是一個 Struct 物件(Json 中以花括號/大括號包含),則可以直接通過點號級聯呼叫,獲取子物件的指定屬性值。
示例程式碼:
#可以通過級聯呼叫直接讀取子物件 State 的 Status 屬性,以獲取容器的狀態資訊: docker inspect --format '{{/*讀取容器狀態*/}}{{.State.Status}}' $INSTANCE_ID
注意: 如果需要獲取的屬性名稱包含點號(比如下列示例資料)或者以數字開頭,則不能直接通過級聯呼叫獲取資訊。因為屬性名稱中的點號會被解析成級聯資訊,進而導致返回錯誤結果。即便使用引號將其包含也會提示語法格式錯誤。此時,需要通過 index 來讀取指定屬性資訊。
"Options": { "com.docker.network.bridge.default_bridge": "true", "com.docker.network.bridge.enable_icc": "true", "com.docker.network.bridge.enable_ip_masquerade": "true", "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0", "com.docker.network.bridge.name": "docker0", "com.docker.network.driver.mtu": "1500" },
示例操作:
# 直接級聯呼叫會提示找不到資料: docker inspect --format '{{.Options.com.docker.network.driver.mtu}}' bridge <no value> # 用引號括起來會提示語法錯誤: docker inspect --format '{{.Options."com.docker.network.driver.mtu"}}' bridge Template parsing error: template: :1: bad character U+0022 '"' # 正確的用法,必須用 index 讀取指定屬性名稱的屬性值: docker inspect --format '{{/*讀取網路在hosts上的名稱*/}}{{index .Options "com.docker.network.bridge.name"}}' bridge docker0
自定義變數
可以在處理過程中設定自定義變數,然後結合自定義變數做更復雜的處理。 如果自定義變數的返回值是物件,則可以通過點號進一步級聯訪問其屬性。比如 {{$Myvar.Field1}}。
示例操作:
# 結合變數的使用,對輸出結果進行組裝展現,以輸出容器的所有繫結埠列表: docker inspect --format '{{/*通過變數組合展示容器繫結埠列表*/}}已繫結埠列表:{{println}}{{range $p,$conf := .NetworkSettings.Ports}}{{$p}} -> {{(index $conf 0).HostPort}}{{println}}{{end}}' Web_web_1 # 示例輸出資訊 已繫結埠列表: 80/tcp -> 32770 8081/tcp -> 8081
遍歷(迴圈):range
格式:
{{range pipeline}}{{.}}{{end}} {{range pipeline}}{{.}}{{else}}{{.}}{{end}}
range 用於遍歷結構內返回值的所有資料。支援的型別包括 array, slice, map 和 channel。使用要點:
- 對應的值長度為 0 時,range 不會執行。
- 結構內部如要使用外部的變數,需要在前面加 引用,比如Var2。
- range 也支援 else 操作。效果是:當返回值為空或長度為 0 時執行 else 內的內容。
示例操作:
# 檢視容器網路下已掛載的所有容器名稱,如果沒有掛載任何容器,則輸出 "With No Containers" docker inspect --format '{{range .Containers}}{{.Name}}{{println}}{{else}}With No Containers{{end}}' bridge brtest peaceful_brown test docker inspect --format '{{range .Containers}}{{.Name}}{{println}}{{else}}With No Containers{{end}}' none With No Containers
索引: index
如果返回結果是一個 map, slice, array 或 string,則可以使用 index 加索引序號(從零開始計數)來讀取屬性值。
示例程式碼:
# docker inspect $INSTANCE_ID 檢視容器繫結的埠資訊,其 Config 屬性就是一個 Map,包含了所有子網資訊。 ... "IPAM": { "Driver": "default", "Options": null, "Config": [ { "Subnet": "172.31.254.1/24", "Gateway": "172.31.254.1" } ] }, ...
示例操作:
# 通過索引序號讀取預設閘道器 docker inspect bridge --format '{{/*檢視網路的預設閘道器*/}}{{(index .IPAM.Config 0).Gateway}}'
判斷:if … else … end
基本判斷
1) not
返回單一引數的布林否定值,即返回輸入引數的否定值。
示例:
# 如果容器的 restarting 設定為 false,則返回資訊“容器沒有配置重啟策略” docker inspect --format '{{if not .State.Restarting}}容器沒有配置重啟策略{{end}}' $(docker ps -q)
2) or
- {{or x y}}: 表示如果 x 為真返回 x,否則返回 y。
- {{or x y z}}:後面跟多個引數時會逐一判斷每個引數,並返回第一個非空的引數。如果都為 false,則返回最後一個引數。
- 除了 null(空)和 false 被識別為 false,其它值(字串、數字、物件等)均被識別為 true。
示例:
docker inspect --format '{{or .State.Status .State.Restarting}}' $INSTANCE_ID
判斷條件
判斷語句通常需要結合判斷條件一起使用,使用格式基本相同:
{{if 判斷條件 .Var1 .Var2}}{{end}}
go模板支援如下判斷方式:
1) eq: 相等,即 arg1 == arg2。比較特殊的是,它支援多個引數進行與比較,此時,它會將第一個引數和其餘引數依次比較,返回下式的結果:
{{if eq true .Var1 .Var2 .Var3}}{{end}} # 效果等同於: arg1==arg2 || arg1==arg3 || arg1==arg4 ...
2) ne: 不等,即 arg1 != arg2。
3) lt: 小於,即 arg1 < arg2。
4) le: 小於等於,即 arg1 <= arg2。
5) gt: 大於,即 arg1 > arg2。
6) ge: 大於等於,即 arg1 >= arg2。
判斷的使用
格式:
{{if pipeline}}{{end}} {{if pipeline}}{{else}}{{if pipeline}}{{end}}{{end}} {{if pipeline}}{{else if pipeline}}{{else}}{{end}}
示例:
# 輸出所有已停止的容器名稱: docker inspect --format '{{if ne 0.0 .State.ExitCode}}{{.Name}}{{end}}' $(docker ps -aq) docker inspect --format '{{if ne 0.0 .State.ExitCode}}{{.Name}}{{else}}該容器還在執行{{end}}' $(docker ps -aq) docker inspect --format '{{if ne 0.0 .State.ExitCode}}{{.Name}}{{else if .}}該容器還在執行{{end}}' $(docker ps -aq) # 輸出所有已停止或配置了 Restarting 策略的容器名稱 docker inspect --format '{{if ne 0.0 .State.ExitCode}}{{.Name}}{{else if eq .State.Restarting true}}容器{{.Name}}配置了Restarting策略.{{else}}{{end}}' $(docker ps -aq)
列印資訊
docker --format 預設呼叫 go語言的 print 函式對模板中的字串進行輸出。而 go語言還有另外 2 種相似的內建函式,對比說明如下:
print: 將傳入的物件轉換為字串並寫入到標準輸出中。如果後跟多個引數,輸出結果之間會自動填充空格進行分隔。
println: 功能和 print 類似,但會在結尾新增一個換行符。也可以直接使用 {{println}} 來換行。
printf: 與 shell 等環境一致,可配合佔位符用於格式化輸出。
對比示例輸出:
docker inspect --format '{{.State.Pid}}{{.State.ExitCode}}' $INSTANCE_ID 240390 docker inspect --format '{{print .State.Pid .State.ExitCode}}' $INSTANCE_ID 24039 0 docker inspect --format '{{.State.Pid}}{{println " 從這換行"}}{{.State.ExitCode}}' $INSTANCE_ID 24039 從這換行 0 docker inspect --format '{{printf "Pid:%d ExitCode:%d" .State.Pid .State.ExitCode}}' $INSTANCE_ID Pid:24039 ExitCode:0
管道
管道 即 pipeline ,與 shell 中類似,可以是上下文的變數輸出,也可以是函式通過管道傳遞的返回值。
示例:
{{.Con | markdown | addlinks}} {{.Name | printf "%s"}}
內建函式 len
內建函式 len 返回相應物件的長度。
示例:
docker inspect --format '{{len .Name}}' $INSTANCE_ID
Docker 增強模板及函式
Docker 基於 go模板的基礎上,構建了一些內建函式。
json
Docker 預設以字串顯示返回結果。而該函式可以將結果格式化為壓縮後的 json 格式資料。
示例:
# 獲取 Config 欄位對應的 json 資料 docker inspect --format='{{json .Config}}' $INSTANCE_ID
join
用指定的字串將返回結果連線後一起展示。操作物件必須是字串陣列。
示例:
# 輸出容器配置的所有 Entrypoint 引數,以 " , " 分隔: docker inspect --format '{{join .Config.Entrypoint " , "}}' $INSTANCE_ID
lower
將返回結果中的字母全部轉換為小寫。操作物件必須是字串。
docker inspect --format "{{lower .Name}}" $INSTANCE_ID
upper
將返回結果中的字母全部轉換為大寫。操作物件必須是字串。
docker inspect --format "{{upper .Name}}" $INSTANCE_ID
title
將返回結果的首字母轉換為大寫。操作物件必須是字串,而且不能是純數字。
docker inspect --format "{{title .State.Status}}" $INSTANCE_ID
split
使用指定分隔符將返回結果拆分為字串列表。操作物件必須是字串且不能是純數字。同時,字串中必須包含相應的分隔符,否則會直接忽略操作。
docker inspect --format '{{split .HostsPath "/"}}' $INSTANCE_ID
============================常用docker inspect --format 輸出示例========================
[root@node1 ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 2ed603e52896 172.16.60.214:5000/kevin_nginx "/bin/sh -c '/usr/..." 13 minutes ago Up 13 minutes docker-test111 24e6607534f1 172.16.60.214:5000/kevin_nginx "/bin/sh -c '/usr/..." 13 minutes ago Up 13 minutes docker-test11 19be6b264b6e 172.16.60.214:5000/kevin_nginx "/bin/sh -c '/usr/..." 13 minutes ago Up 13 minutes docker-test1 1) 獲取容器的IP (後面使用容器名或容器ID都可以) [root@node1 ~]# docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $(docker ps -q) 192.10.160.193 173.20.19.128 17.16.10.128 [root@node1 ~]# docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' docker-test1 17.16.10.128 2) 獲取容器的MAC地址 [root@node1 ~]# docker inspect --format='{{range .NetworkSettings.Networks}}{{.MacAddress}}{{end}}' $(docker ps -a -q) ee:ee:ee:ee:ee:ee ee:ee:ee:ee:ee:ee ee:ee:ee:ee:ee:ee [root@node1 ~]# docker inspect --format='{{range .NetworkSettings.Networks}}{{.MacAddress}}{{end}}' docker-test1 ee:ee:ee:ee:ee:ee 3) 獲取容器Name [root@node1 ~]# docker inspect --format='{{.Name}}' $(docker ps -aq) /docker-test111 /docker-test11 /docker-test1 /calico-node [root@node1 ~]# docker inspect --format='{{.Name}}' $(docker ps -aq)|cut -d"/" -f2 docker-test111 docker-test11 docker-test1 [root@node1 ~]# docker inspect --format='{{.Name}}' docker-test1 /docker-test1 [root@node1 ~]# docker inspect --format='{{.Name}}' docker-test1|cut -d"/" -f2 docker-test1 4) 獲取容器Hostname [root@node1 ~]# docker inspect --format '{{ .Config.Hostname }}' $(docker ps -q) 2ed603e52896 24e6607534f1 19be6b264b6e [root@node1 ~]# docker inspect --format '{{ .Config.Hostname }}' docker-test1 19be6b264b6e 5) Hostname Name IP [root@node1 ~]# docker inspect --format 'Hostname:{{ .Config.Hostname }} Name:{{.Name}} IP:{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $(docker ps -q) Hostname:2ed603e52896 Name:/docker-test111 IP:192.10.160.193 Hostname:24e6607534f1 Name:/docker-test11 IP:173.20.19.128 Hostname:19be6b264b6e Name:/docker-test1 IP:17.16.10.128 [root@node1 ~]# docker inspect --format 'Hostname:{{ .Config.Hostname }} Name:{{.Name}} IP:{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' docker-test1 Hostname:19be6b264b6e Name:/docker-test1 IP:17.16.10.128 6) 獲取容器的log path [root@node1 ~]# docker inspect --format='{{.LogPath}}' `docker ps -a -q` [root@node1 ~]# docker inspect --format='{{.LogPath}}' docker-test1 7) 獲取容器的image映象名稱 [root@node1 ~]# docker inspect --format='{{.Config.Image}}' `docker ps -a -q` 172.16.60.214:5000/kevin_nginx 172.16.60.214:5000/kevin_nginx 172.16.60.214:5000/kevin_nginx quay.io/calico/node:v2.6.10 [root@node1 ~]# docker inspect --format='{{.Config.Image}}' docker-test1 172.16.60.214:5000/kevin_nginx 8) 獲取容器繫結的埠(port bindings) [root@node1 ~]# docker inspect --format='{{range $p, $conf := .NetworkSettings.Ports}} {{$p}} -> {{(index $conf 0).HostPort}} {{end}}' `docker ps -a -q` [root@node1 ~]# docker inspect --format='{{range $p, $conf := .NetworkSettings.Ports}} {{$p}} -> {{(index $conf 0).HostPort}} {{end}}' docker-test1 9) 獲取service例項的Ip [root@swarm-manager-node ~]# docker service ps my-test ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS t71gqufekv2o my-test.1 172.16.60.214:5000/kevin_nginx:latest swarm-node2 Running Running 16 seconds ago 9cuq2yf10d60 my-test.2 172.16.60.214:5000/kevin_nginx:latest swarm-manager-node Running Running 16 seconds ago srt2yo817kpv my-test.3 172.16.60.214:5000/kevin_nginx:latest swarm-node1 Running Running 16 seconds ago [root@swarm-manager-node ~]# docker inspect ` docker service ps my-test -q` --format '{{range .NetworksAttachments}}{{.Addresses}}{{end}}' | cut -d '[' -f2|cut -d ']' -f1 10.255.0.7/16 10.255.0.8/16 10.255.0.9/16 10) 獲取service示例的container ID (獲取的是ID的全稱,一般只要取ID前面12個字元就可以了) [root@swarm-manager-node ~]# docker inspect ` docker service ps my-test -q` --format '{{ .Status.ContainerStatus.ContainerID }}' c6c18a74a465163757fe928fec9e633223200f92d1c59e5d2d77eabfaa5ae93a 5f558bb014ea3d3eef5c8d4bd70e2e3048d7fc6725538303be960ac658d93b32 dde578bf60190a63ed5c8c4a9f5a3044566a159e8debe8717342e263c6199f26