[TOC]

more information: https://docs.docker.com/engine/security/security/#docker-daemon-attack-surface

0x00 前言简述

描述:本文是笔者在学习或者应用Docker时候,对Docker第三方的工具使用的一个简单总结, 使其为了更好的使用docker应用以及优化和异常的快速定位;


0x01 镜像相关工具

1.Dive - Docker 镜像分析工具

描述:Dive用来分析 docker 镜像层信息的一个工具,该工具主要用于探索 docker 镜像层内容以及发现减小 docker 镜像大小的方法。
官方地址:https://github.com/wagoodman/dive
基本功能:

  • 1.显示Docker图像内容按层分解: 当您在左侧选择一个层时,将在右侧线上显示该层的所有内容,此外,您可以使用箭头按键来浏览整个文件树内容。
  • 2.指出每层中发生了哪些变化:在文件树中标明已修改、添加或删除的文件,可以调整此值以显示特定层的更改。
  • 3.估计”镜像效率”:左下方窗格显示基本层信息和一个实验指标,用于猜测图像所包含的空间浪费。这可能是跨层的一些重复文件,跨层移动文件或不完全删除的文件。提供了一个百分比的“得分”和总浪费的文件空间。
  • 4.快速构建/分析周期:您可以构建 docker 镜像并使用一个命令立即进行分析dive build -t some-tag .您只需要将docker build命令用相同的dive build命令替换即可。
  • 5.CI集成: 根据图像的效率和浪费的空间,分析图像并得到通过/失败的结果。在调用任何有效的dive命令时,只需在环境中设置CI=true
  • 6.支持多个图像源和容器引擎使用—source选项,您可以选择从哪里获取容器图像:dive <your-image> --source <source>

我们常常使用inspect与history来查看镜像的相关信息,但是确实不是很直观遍历,我们需要的是一个简单直白的展示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# inspect 方式看见镜像各层ID
docker inspect gcc -f "{{.RootFS}}{{println}}{{.Metadata}}"
{layers [sha256:6086e1b289d997dfd19df1ec9366541c49f5545520f9dc65ebd4cd64071497b4 sha256:c53d956ebfec691504fc18c964352728214665e7090e4161ed791979cf200ccf sha256:cf47dfabe08113e9ff7d61d096752678caa00a0b861f673c2577ca2fdf55cfe9 sha256:46a297e68c473255e515971ffcb2dc78f724e60214df479a66bb9b04892afc1b sha256:cfb4ccdac2588557024f7741ba447707fc26304e7d84cf53d481671cb4a23f1c sha256:1be02b7a0bbbc4ff6353fe53cf22cefb4a0849a070d032b900dcbf8700a89b9a sha256:8262cc809f2b0add9b633ab30664f95dbb7761fc857ecfaddfa5654ef602fb9a sha256:00e5a2edc2d269fc9e1465be8a3b572d5d0a62cea4510fa5e941f42653287198 sha256:4d619c17b6de41f14d6742dcb6c3ba679ed53bff4ca43e22686a81b4aa8236bd] }
{0001-01-01 00:00:00 +0000 UTC}

# history 镜像各层构建时候执行命令查看
docker history gcc
# IMAGE CREATED CREATED BY SIZE
# 21f378ba43ec 4 days ago /bin/sh -c set -ex; dpkg-divert --divert /u… 12.7kB
# <missing> 4 days ago /bin/sh -c set -ex; echo '/usr/local/lib64'… 53.8kB
# <missing> 4 days ago /bin/sh -c set -ex; savedAptMark="$(apt-ma… 382MB
# <missing> 4 days ago /bin/sh -c #(nop) ENV GCC_VERSION=10.2.0 0B
# <missing> 5 days ago /bin/sh -c #(nop) ENV GCC_MIRRORS=https://f… 0B
# <missing> 5 days ago /bin/sh -c set -ex; for key in $GPG_KEYS; d… 29.5kB
# <missing> 5 days ago /bin/sh -c #(nop) ENV GPG_KEYS=B215C1633BCA… 0B
# <missing> 5 days ago /bin/sh -c set -ex; if ! command -v gpg > /… 0B
# <missing> 5 days ago /bin/sh -c set -ex; apt-get update; DEBIAN… 510MB
# <missing> 5 days ago /bin/sh -c apt-get update && apt-get install… 146MB
# <missing> 5 days ago /bin/sh -c set -ex; if ! command -v gpg > /… 17.5MB
# <missing> 5 days ago /bin/sh -c apt-get update && apt-get install… 16.5MB
# <missing> 6 days ago /bin/sh -c #(nop) CMD ["bash"] 0B
# <missing> 6 days ago /bin/sh -c #(nop) ADD file:89dfd7d3ed77fd5e0… 114MB

Install & Syntax

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#rpm安装方式
#Ubuntu/Debian
wget https://github.com/wagoodman/dive/releases/download/v0.9.2/dive_0.9.2_linux_amd64.deb
sudo apt install ./dive_0.9.2_linux_amd64.deb
#RHEL/Centos
curl -OL https://github.com/wagoodman/dive/releases/download/v0.9.2/dive_0.9.2_linux_amd64.rpm
rpm -i dive_0.9.2_linux_amd64.rpm
#Arch Linux
#Available as dive in the Arch User Repository (AUR).
yay -S dive
# mac
brew install dive

#镜像安装方式
$ docker pull wagoodman/dive

# 基础用法
# 分析一个 docker 镜像,只需要在 dive 工具后面添加上镜像的 tag 即可:
$ dive <镜像TAG>
# 除此之外还可以通过 build 命令去构建 docker 镜像后,直接进入分析结果:
$ dive build -t <镜像TAG> .

# 按键绑定
Ctrl + C Exit
Tab Switch between the layer and filetree views
Ctrl + F Filter files
PageUp Scroll up a page
PageDown Scroll down a page
Ctrl + A Layer view: see aggregated image modifications
Ctrl + L Layer view: see current layer modifications
Space Filetree view: collapse/uncollapse a directory
Ctrl + Space Filetree view: collapse/uncollapse all directories
Ctrl + A Filetree view: show/hide added files
Ctrl + R Filetree view: show/hide removed files
Ctrl + M Filetree view: show/hide modified files
Ctrl + U Filetree view: show/hide unmodified files
Ctrl + B Filetree view: show/hide file attributes
PageUp Filetree view: scroll up a page
PageDown Filetree view: scroll down a page

注意事项:

  • 注意:根据您在本地运行的docker版本,您可能需要指定docker API版本作为环境变量:
    1
    2
    3
    4
    docker run --rm -it \
    -v /var/run/docker.sock:/var/run/docker.sock \
    -e DOCKER_API_VERSION=1.37 \
    wagoodman/dive:latest <dive arguments...>

实际案例:

1
2
3
4
5
6
7
8
9
10
11
# 1.简单分析实例
$docker images
# REPOSITORY TAG IMAGE ID CREATED SIZE
# go-hello latest d1bb1eb974f4 19 hours ago 812MB
$docker run --rm -it \
-v /var/run/docker.sock:/var/run/docker.sock \
wagoodman/dive:latest go-hello:latest
# Image Source: docker://go-hello:latest
# Fetching image... (this can take a while for large images)
# Analyzing image...
# Building cache...

WeiyiGeek.dive

WeiyiGeek.dive

2.CI集成
描述:当运行环境变量CI=true的dive时dive UI将被绕过,取而代之的是分析你的docker图像,通过返回代码给它一个通过/失败的指示。目前有三个指标支持通过。
下面是dive-ci文件,可以采用--ci-config option指定配置文件

1
2
3
4
5
6
7
8
9
10
11
12
rules:
# If the efficiency is measured below X%, mark as failed.
# Expressed as a ratio between 0-1.
lowestEfficiency: 0.95

# If the amount of wasted space is at least X or larger than X, mark as failed.
# Expressed in B, KB, MB, and GB.
highestWastedBytes: 20MB

# If the amount of wasted space makes up for X% or more of the image, mark as failed.
# Note: the base image layer is NOT included in the total image size.
# Expressed as a ratio between 0-1; fails if the threshold is met or crossed.


2.Skopeo - 镜像同步工具

描述: 我们从以下的两个利用场景中可以看见看见此工具妙用;

应用场景1.如何在机器上pull拉取Registry A Harbor中的镜像,然后构造完成后重新打上Tag然后再Push到另外一个 registry B Harbor 上去,相当于一个同步镜像操作,但和 harbor 里在带的那个镜像同步还有很大的不同,我们仅仅需要同步特定 tag 的镜像,而不是整个 harbor 或者 project 里的全部镜像;目前我们的做法还是最简单的方式,使用 docker 命令行的方式来 pull 镜像,然后打 tag 接着 push 到 B harbor。但是啊,当同步二三百个的镜像,或者镜像的总大小几十 GB 的时候这种原始的方法速度还是太慢了,于是就思考有没有另一个工具可以直接将 registry A 中的某个镜像同步到 registry B 中去。简单的说使用 skopeo copy 两个 registry 中的镜像时,skopeo 请求两个 registry API 直接 copy original blob 到另一个 registry ,这样免去了像docker pull –> docker tag –> docker push 那样 pull 镜像对镜像进行解压缩,push 镜像进行压缩。尤其是在搬运一些较大的镜像(几GB 或者几十 GB的镜像,比如 nvidia/cuda ),使用 skopeo copy 的加速效果十分明显。

应用场景2.由于国内拉取某些镜像太不友好,则此时采用外网的VPS先进行下载然后再从我们VPS上拉取下载镜像,但是由于VPS本地存储太小而默认docker pull在下载镜像时候利用docker-untar将下载的镜像进行解压并保存在本地docker家目录之中会导致存储不够,想象一哈只下载而不解压即减小了包的大小又解压下载传输速度何乐而不为呢?所以得请出本章节的主人公Skopeo镜像工具;

学习了前面的Docker容器镜像仓库存储原理(前世今身)与搬运技巧,我们知道registry 中存储的镜像 layer 压缩包格式是 vnd.docker.image.rootfs.diff.tar.gzip它是一个 tar.gz 类型的文件;

下面是镜像在Harbor中的存储路径我们可以利用其开探究镜像在Registry中存储的;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# (1) harbor 的存储目录
tree
`-- registry
`-- v2 # registry V2 版本
|-- blobs # blobs 目录下存储镜像的 raw 数据,存储的最小单元为 layer
| `-- sha256
| |-- 39
| |-- cb
| `-- f7
`-- repositories # 镜像的元数据信息
`-- library
`-- alpine


# (2) 镜像的 manifest 是针对registry服务端的配置信息
{
"schemaVersion": 2,
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"config": {
"mediaType": "application/vnd.docker.container.image.v1+json",
"size": 1507,
"digest": "sha256:f70734b6a266dcb5f44c383274821207885b549b75c8e119404917a61335981a"
},
"layers": [
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 2813316,
"digest": "sha256:cbdbe7a5bc2a134ca8ec91be58565ec07d037386d1f1d8385412d224deafca08"
}
]
}

# (3) 仔细看一下 digest 和下面文件夹的名称,他们是一一对应的,因为 manifest 信息就是镜像在 registry 中存储的信息。
tree
|-- [ 20] blobs
| `-- [ 36] sha256
| |-- [ 78] 39
| | `-- [ 18] 39eda93d15866957feaee28f8fc5adb545276a64147445c64992ef69804dbf01
| | `-- [ 528] data
| |-- [ 78] cb
| | `-- [ 18] cbdbe7a5bc2a134ca8ec91be58565ec07d037386d1f1d8385412d224deafca08
| | `-- [2.7M] data
| `-- [ 78] f7
| `-- [ 18] f70734b6a266dcb5f44c383274821207885b549b75c8e119404917a61335981a
| `-- [1.5K] data
`-- [ 21] repositories
`-- [ 20] library
`-- [ 55] alpine
|-- [ 20] _layers
| `-- [ 150] sha256
| |-- [ 18] cbdbe7a5bc2a134ca8ec91be58565ec07d037386d1f1d8385412d224deafca08
| | `-- [ 71] link
| `-- [ 18] f70734b6a266dcb5f44c383274821207885b549b75c8e119404917a61335981a
| `-- [ 71] link
|-- [ 35] _manifests
| |-- [ 20] revisions
| | `-- [ 78] sha256
| | `-- [ 18] 39eda93d15866957feaee28f8fc5adb545276a64147445c64992ef69804dbf01
| | `-- [ 71] link
| `-- [ 20] tags
| `-- [ 34] latest
| |-- [ 18] current
| | `-- [ 71] link
| `-- [ 20] index
| `-- [ 78] sha256
| `-- [ 18] 39eda93d15866957feaee28f8fc5adb545276a64147445c64992ef69804dbf01
| `-- [ 71] link
`-- [ 6] _uploads
26 directories, 8 files

上述中的 2.7 MB data 文件是一个 gzip 压缩格式文件,我们可以使用 tar 命令将其解压开来;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
cd registry/v2/blobs/sha256/cb/cbdbe7a5bc2a134ca8ec91be58565ec07d037386d1f1d8385412d224deafca08
sh-4.2# file data
data: gzip compressed data
sh-4.2# mkdir layer
sh-4.2# tar -xvf data -C layer/ #解压到 layer 目录下
sh-4.2# tree -L 1 -d layer # alpine 镜像查看其解压目录您会发现他是一个文件系统
layer
|-- bin
|-- dev
|-- etc
|-- home
|-- lib
|-- media
|-- mnt
|-- opt
|-- proc
|-- root
|-- run
|-- sbin
|-- srv
|-- sys
|-- tmp
|-- usr
`-- var

看了上面的流程此时您或许能够明白在当前仅仅为了同步两个 registry 上的镜像使用 docker pull –> docker tag –> docker push 操作的弊端; 在Docker pull 时镜像会对Registry上的 Layer进行下载到本地然后解压,在使用 docker pull 拉取镜像的时候使用 ps 查看一下进程就会找到 docker-untar 这个进程,它的目的是为了减少网络传输的流量以及节约时间;

1
2
# 对于一些较大的镜像比如2G以上,有时候镜像 layer 已经 download 完了,但是还在进行镜像的解压缩,性能的瓶颈也就在了解压镜像这一块。
docker-untar /var/lib/docker/overlay2/a076db6567c7306f3cdab6040cd7d083ef6a39d125171353eedbb8bde7f203b4/diff

而 Skopeo 就是一个可以直接将Registry上的Blob复制到另外一个Registry 仓库里,中间不涉及对镜像的Layer的解压缩;
Skopeo 官网地址: https://github.com/containers/skopeo


特点:

  • skopeo是一个命令行实用程序,执行对容器的图像和图像库的各种操作。
  • skopeo不要求用户运行,作为根用户做它的大部分操作。
  • skopeo不需要守护进程来运行,以执行其操作。
  • skopeo可以用OCI图像以及原来的码头工人V2图像工作,如docker.io和quay.io登记,私人注册,本地目录和本地OCI布局目录。

Skopeo可以执行如下的操作:

  • 从和到各种存储机制复制的图像。例如,你可以从一个注册表复制到另一个图像,而不需要特权。
  • 检查显示出其特性,包括其的层的远程图像,而无需将Images拉到主机。
  • 从图像库中删除图像。
  • 当需要存放库,skopeo可以通过身份验证适当凭据和证书。


Install && Syntax
多操作系统安装方式:

  • (1) 仓库软件安装

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # yum/dnf/zypper/brew
    sudo dnf install skopeo || sudo yum install skopeo

    # openSUSE
    sudo zypper install skopeo

    # alpine
    sudo apk add skopeo

    # macOS
    brew install skopeo
  • (2) 源码build安装但是需要注意要构建skopeo二进制文件,您至少需要Go 1.12。

    1
    2
    3
    4
    5
    6
    git clone https://github.com/containers/skopeo skopeo
    cd !$ && git checkout v1.0.0
    make binary
    # Ubuntu上构建:参数使其构建的二进制可执行文件可以在各Linux发行版正常运行
    # make binary-static DISABLE_CGO=1
    cp skopeo /usr/bin/

Tips:如果在Ubuntu构建时候没有为make加上指定参数时候然后将生成的二进制文件发送都centOS机器下进行运行时候会产生动态链接库异常;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 问题描述:
skopeo: error while loading shared libraries: libdevmapper.so.1.02.1: cannot open shared object file: No such file or directory

# 解决办法在编译的时候加上 DISABLE_CGO=1 参数为程序s静态链接库:
ldd skopeo_d #
linux-vdso.so.1 (0x00007ffed9e66000)
libgpgme.so.11 => /usr/lib/x86_64-linux-gnu/libgpgme.so.11 (0x00007f94aed2e000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f94aeb0f000)
libdevmapper.so.1.02.1 => /lib/x86_64-linux-gnu/libdevmapper.so.1.02.1 (0x00007f94ae8a4000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f94ae4b3000)
libassuan.so.0 => /usr/lib/x86_64-linux-gnu/libassuan.so.0 (0x00007f94ae2a0000)
libgpg-error.so.0 => /lib/x86_64-linux-gnu/libgpg-error.so.0 (0x00007f94ae08b000)
/lib64/ld-linux-x86-64.so.2 (0x00007f94b0ac4000)
libselinux.so.1 => /lib/x86_64-linux-gnu/libselinux.so.1 (0x00007f94ade63000)
libudev.so.1 => /lib/x86_64-linux-gnu/libudev.so.1 (0x00007f94adc45000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f94ad8a7000)
libpcre.so.3 => /lib/x86_64-linux-gnu/libpcre.so.3 (0x00007f94ad635000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f94ad431000)
librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f94ad229000)

# 加上 DISABLE_CGO=1 编译后的二进制可执行文件
ldd skopeo_s #
not a dynamic executable

  • (3) 语法参数
    描述:对容器映像和容器映像注册表的各种操作;
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    Usage:
    skopeo [command]

    Available Commands:
    # 复制一个镜像从 A 到 B,这里的 A 和 B 可以为本地 docker 镜像或者 registry 上的镜像。
    copy Copy an IMAGE-NAME from one location to another

    # 删除一个镜像,可以是本地 docker 镜像或者 registry 上的镜像
    delete Delete image IMAGE-NAME
    help Help about any command

    # 查看一个镜像的 manifest 火车 image config 详细信息
    inspect Inspect image

    IMAGE-NAME
    # 列出一个 registry 上某个镜像的所有 tag,在某些脚本中可以进行使用;
    list-tags List tags in the transport/repository specified by the

    # 登录到某个 registry,和 docker login 类似
    login Login to a container registry
    # 退出已经登录到某个 registry 的 auth 信息,和 docker logout 类似
    logout Logout of a container registry

    # 同步一个镜像从 A 到 B,感觉和 copy 一样,但 sync 支持的参数更多,功能更强大。在 0.14.0 版本的时候是没有 sync 选项的,到了 0.14.2 才有,现在是 1.0.0
    sync Synchronize one or more images from one location to another
    manifest-digest Compute a manifest digest of a file # 计算文件的清单摘要
    standalone-sign Create a signature using local files # 使用本地文件创建签名
    standalone-verify Verify a signature using local files # 验证本地文件的签名

    # 选项
    --insecure-policy 选项用于忽略安全策略配置文件


skopeo支持的镜像格式
描述: 无论我们的 src 镜像还是 desc 镜像都要满足以下格式才可以。

1
2
3
4
5
6
7
8
9
10
11
containers-storage: #docker引用位于本地容器/存储映像存储中的映像。位置和映像存储都在/etc/containers/storage.conf中指定;

dir: #一个现有的本地目录路径,将清单、层tarballs和签名存储为单独的文件。这是一种非标准化格式,主要用于调试或非侵入式容器检查。

docker://docker-reference #注册表中的图像实现了“Docker注册HTTP API V2”。默认情况下,使用$XDG_RUNTIME_DIR/containers/auth中的授权状态。json,使用skopeo登录设置。

docker-archive:path[:docker-reference] #图像存储在docker保存格式的文件中。docker-reference只在创建这样的文件时使用,并且不能包含摘要。

docker-daemon:docker-reference #docker引用必须包含标签或摘要。另外,在读取图像时,格式也可以docker-daemon:algo:digest(一个映像ID)。

oci:path:tag #目录中的图像标签符合“开放容器图像布局规范”的路径。

值得注意的事上面这几种镜像名称对应着镜像存在的方式,并且不同存在的方式对镜像的 layer 处理的方式也不一样,

  • 比如 docker:// 这种方式是存在 registry 上的。
  • 比如 docker-daemon 是存在本地 docker pull 下来的。
  • 比如 docker-archive 是通过 docker save 出来的镜像。

上述表达的是同一个镜像,只不过是存在的方式不一样而已,即同一个镜像有这几种存在的方式就像水有气体、液体、固体一样。

IMAGE NAMES example 说明
containers-storage: containers-storage:
dir: dir:/PATH
docker:// docker://k8s.gcr.io/kube-apiserver:v1.17.5 其名称即为 src 或 dest 镜像名称的前缀
docker-daemon: docker-daemon:alpine:latest
docker-archive: docker-archive:alpine.tar (docker save)
oci: oci:alpine:latest


基础实例
login && logout 命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
## (1) 配置文件认证
# 与 配置 Docker registry 一样需要在
/etc/docker/deamon.json
# 或者~/.docker/config.json中配置
jq "." ~/.docker/config.json
{
"auths": {
"https://index.docker.io/v1/": {
"auth": "d2sddaqWM7bSVlJFpmQE43Sw=="
}
},
"HttpHeaders": {
"User-Agent": "Docker-Client/19.03.5 (linux)"
},
"experimental": "enabled"
}

## (2) 对注册表进行身份验证
$ skopeo login --user USER docker://myregistrydomain.com:5000
# Password:
$ skopeo inspect --creds=testuser:testpassword docker://myregistrydomain.com:5000/busybox
$ skopeo copy --src-creds=testuser:testpassword docker://myregistrydomain.com:5000/private oci:local_oci_image
# $ skopeo inspect docker://myregistrydomain.com:5000/busybox
$ skopeo logout docker://myregistrydomain.com:5000


inspect 命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# 1.skopeo能够检查容器注册表上的存储库并获取图像层(检查存储库)
$ skopeo inspect docker://registry.fedoraproject.org/fedora:latest
$ skopeo inspect docker-daemon:alpine:latest --raw | jq "."
{
"Name": "registry.fedoraproject.org/fedora",
"Digest": "sha256:58de585a231aca14a511347bc85b912a6f000159b49bc2b0582032911e5d3a6c",
"RepoTags": [
"30-aarch64",
"30-ppc64le",
"30-s390x",
"30-x86_64",
"30",
"latest",
"rawhide",
"30-armhfp",
"31-aarch64",
"31-x86_64",
"31",
"31-armhfp",
"31-s390x",
"31-ppc64le",
"32-aarch64",
"32-ppc64le",
"32-s390x",
"32-x86_64",
"32",
"33-aarch64",
"33-ppc64le",
"33-s390x",
"33-x86_64",
"33"
],
"Created": "2020-07-09T06:49:06Z",
"DockerVersion": "1.10.1",
"Labels": {
"license": "MIT",
"name": "fedora",
"vendor": "Fedora Project",
"version": "32"
},
"Architecture": "amd64",
"Os": "linux",
"Layers": [
"sha256:dd9f43919ba05f05d4f783c31e83e5e776c4f5d29dd72b9ec5056b9576c10053"
],
"Env": [
"DISTTAG=f32container",
"FGC=f32",
"container=oci"
]
}


# (2) 显示来自fedora的容器配置:latest
$ skopeo inspect --config docker://registry.fedoraproject.org/fedora:latest | jq
$ skopeo inspect --config docker-daemon:alpine:latest | jq "."
{
"created": "2020-05-29T21:19:46.363518345Z",
"architecture": "amd64",
"os": "linux",
"config": {
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"/bin/sh"
]
},
"rootfs": {
"type": "layers",
"diff_ids": [
"sha256:50644c29ef5a27c9a40c393a73ece2479de78325cae7d762ef3cdc19bf42dd0a"
]
},
"history": [
{
"created": "2020-05-29T21:19:46.192045972Z",
"created_by": "/bin/sh -c #(nop) ADD file:c92c248239f8c7b9b3c067650954815f391b7bcb09023f984972c082ace2a8d0 in / "
},
{
"created": "2020-05-29T21:19:46.363518345Z",
"created_by": "/bin/sh -c #(nop) CMD [\"/bin/sh\"]",
"empty_layer": true
}
]
}


# (3) 显示未验证的图像摘要
$ skopeo inspect docker://registry.fedoraproject.org/fedora:latest | jq '.Digest'
"sha256:655721ff613ee766a4126cb5e0d5ae81598e1b0c3bcf7017c36c4d72cb092fe9"


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# copy-命令可以在各种存储机制之间复制容器图像,包括:
* Container registries: The Quay, Docker Hub, OpenShift, GCR, Artifactory ...
* Container Storage backends: github.com/containers/storage (Backend for Podman, CRI-O, Buildah and friends)
* Docker daemon storage
* Local directories
* Local OCI-layout directories
# 实际上 skopeo 可以导出为其他格式比如 oci、oci-archive、ostree 等

$ skopeo copy docker-daemon:alpine:latest oci:alpine
$ skopeo copy oci:busybox_ocilayout:latest dir:existingemptydirectory
$ tree -h alpine
# alpine
# ├── [4.0K] blobs
# │ └── [4.0K] sha256
# 是否感觉很相似实际上对应着Overlay2中digest中data文件
# 镜像的 mainfaet 文件
# │ ├── [ 348] 1c6f747c933450c5169f349f2a57b9d31e833c0452e1ec712b8aab0cbfea4d2c
# │ # 镜像文件系统gzip压缩文件
# ├── [2.8M] 3eee30c545e47333e6fe551863f6f29c3dcd850187ae3f37c606adb991444886
# 镜像的 image config 文件
# │ └── [ 583] af88fdb253aac46693de7883c9c55244327908c77248d7654841503f744aae8b
# ├── [ 186] index.json
# └── [ 31] oci-layout


# (0) 从 docker daemon 复制导出镜像到本地
# 直接通过 http 下载目标镜像并存储为 /tmp/nginx.tar,此文件可以直接通过 docker load 命令导入
$ skopeo --insecure-policy copy docker-daemon:nginx:1.17.6 docker-archive:/tmp/nginx.tar # 将会从 docker daemon 导出镜像到 /tmp/nginx.tar


# (1) 从一个Registry A 复制 Registry B 之中;
$ skopeo copy docker://quay.io/buildah/stable docker://registry.internal.company.com/buildah


# (2) 该命令将会直接通过 http 下载目标镜像并存储为 /tmp/nginx.tar,此文件可以直接通过 docker load 命令导
skopeo --insecure-policy copy docker://nginx:1.17.9 docker-archive:/tmp/nginx.tar


# (3) 从 k8s.gcr.io/kube-apiserver:v1.17.5 复制镜像到 index.docker.io/webpsh/kube-apiserver:v1.17.5
$ skopeo copy docker://k8s.gcr.io/kube-apiserver:v1.17.5 docker://index.docker.io/webpsh/kube-apiserver:v1.17.5 --dest-authfile /root/.docker/config.json
# Getting image source signatures
# Copying blob 597de8ba0c30 done # 直接 copy 镜像 layer 的 blob 它是在 registry 进行压缩存储的格式
# Copying blob e13a88fa950c done
# Copying config f640481f6d done
# Writing manifest to image destination
# Storing signatures
# pull 下载利用skopeo同步上传的镜像验证是否正确
$ docker pull webpsh/kube-apiserver:v1.17.5
# v1.17.5: Pulling from webpsh/kube-apiserver
# Digest: sha256:5ddc5c77f52767f2f225a531a257259228d74b32d8aac9cfe087251f998c42f3
# Status: Downloaded newer image for webpsh/kube-apiserver:v1.17.5
# docker.io/webpsh/kube-apiserver:v1.17.5


# delete - 删除镜像命令
# 该命令非常有帮助可以直接调用Registry的API来进行删除镜像;
$ skopeo delete docker://localhost:5000/imagename:latest

补充说明:

  • (1) 此处为了方便在使用 skopeo 的时候不用加一堆额外的参数,以OpenSSL生成客户端证书(客户端认证的证书、私钥)为例:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    #!/bin/sh
    set -e
    set -o nounset
    cat >ca.conf <<EOF
    [ req ]
    default_bits = 2048
    distinguished_name = req_distinguished_name
    prompt = no
    encrypt_key = no
    x509_extensions = v3_ca
    [ req_distinguished_name ]
    CN = localhost
    [ CA_default ]
    copy_extensions = copy
    [ alternate_names ]
    DNS.2=localhost
    [ v3_ca ]
    [email protected]_names
    subjectKeyIdentifier=hash
    authorityKeyIdentifier=keyid:always,issuer:always
    basicConstraints = critical,CA:true
    keyUsage=keyCertSign,cRLSign,digitalSignature,keyEncipherment,nonRepudiation
    EOF

    # 证书签名申请
    mkdir -p certs
    openssl req -days 365 -x509 -config ca.conf \
    -new -keyout certs/domain.key -out certs/domain.crt

添加信任证书到系统中,根据不同的发行版选择相应的路径和命令行即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
# CentOS
update-ca-trust force-enable
cp certs/domain.crt /etc/pki/ca-trust/source/anchors/localhost.crt
update-ca-trust

# Ubuntu
cp certs/domain.crt /usr/local/share/ca-certificates/localhost.crt
$ update-ca-certificates

# Debian
cp certs/domain.crt /usr/share/ca-certificates/localhost.crt
echo localhost.crt >> /etc/ca-certificates.conf
update-ca-certificates


0x02 容器相关工具

1.容器启动参数查看

假如我使用docker run启动了了一个redis容器,而docker run的参数有很多,由于时间太久,我已经忘记了当初的启动参数,也并没有使用docker-compose这样的编排工具。

现在我如何进行重启,如何找回此前的启动命令,有没有解决办法?
答案: 当然是有的如下几种方式:

  • docker inpsect
  • reckecod
  • runlike

方式1:docker inpsect
描述:此种方式只是大概知道有哪些参数并不是完整的,而且需要使用者自己生成启动docker容器参数;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
docker inspect -f "{{.Name}}{{println}}{{.Path}} {{.Args}} {{.Config.Cmd}} {{.Config.Env}} {{.Config.Volumes}} {{.Config.Entrypoint}} {{.NetworkSettings.Networks}}" $(docker ps -aq)
/linuxea_redis
/Initialization.sh [] []
[REDIS_CONF=on
REQUIRE_PASS=OTdmOWI4ZTM4NTY1M2M4OTZh
MASTER_AUTH=OTdmOWI4ZTM4NTY1M2M4OTZh
MAXCLIENTS_NUM=30
MAXMEMORY_SIZE=1024M
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
RS_VSON=5.0.0
RS_USER=redis
RS_VSON_URL=http://download.redis.io/releases/redis-5.0.0.tar.gz
BATADIR=/usr/local/redis
DATADIR=/data/redis
DATALOG=/data/logs
DATACIG=/etc/redis]
map[linuxea_volume:{}]
[/Initialization.sh]
map[host:0xc420182000]


方式2:rekcod
描述:借助rekcod打印出更易读的格式docker inspect → docker run ,docker run从现有容器(via docker inspect)反向设计命令。
rekcod可以将以下任何内容转换为docker run命令:

  1. 容器ID /名称(rekcod将调用docker inspect
  2. 包含docker inspect输出的文件的路径
  3. 原始JSON(docker inspect直接传递输出)
1
2
3
4
5
6
7
8
9
10
#(1) 系统安装 rekcod
$ yum install npm -y && npm i -g rekcod
$ docker ps -qa|rekcod
$ rekcod linuxea_redis
docker run --name linuxea_redis --runtime runc -p 6379:6379/tcp --net host --restart no -h LinuxEA-Node172_25_50_250.cluster.com --expose 26379/tcp --expose 6379/tcp -e 'REDIS_CONF=on' -e 'REQUIRE_PASS=OTdmOWI4ZTM4NTY1M2M4OTZh' -e 'MASTER_AUTH=OTdmOWI4ZTM4NTY1M2M4OTZh' -e 'MAXCLIENTS_NUM=30' -e 'MAXMEMORY_SIZE=1024M' -e 'PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin' -e 'RS_VSON=5.0.0' -e 'RS_USER=redis' -e 'RS_VSON_URL=http://download.redis.io/releases/redis-5.0.0.tar.gz' -e 'BATADIR=/usr/local/redis' -e 'DATADIR=/data/redis' -e 'DATALOG=/data/logs' -e 'DATACIG=/etc/redis' -d -t -i --entrypoint "/Initialization.sh" marksugar/redis:5.0.0

#(2) Docker 安装 rekcod
$ docker pull nexdrew/rekcod
$ alias rekcod="docker run --rm -v /var/run/docker.sock:/var/run/docker.sock nexdrew/rekcod"
$ docker run --rm -v /var/run/docker.sock:/var/run/docker.sock nexdrew/rekcod <container>


方式3:runlike
描述:实际runlike被封装为一个名为assaflavie / runlike 的Docker镜像。

1
2
3
4
5
6
7
8
9
# 常规语法
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock assaflavie/runlike YOUR-CONTAINER
# 使用别名运行它,例如,将其保存在~/.profile或中~/.bashrc
alias runlike="docker run --rm -v /var/run/docker.sock:/var/run/docker.sock assaflavie/runlike"
runlike YOUR-CONTAINER #以本地命令运行

# 实际案例
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock assaflavie/runlike eager_saha
# docker run --name=eager_saha --hostname=e35b0d451122 --env=PATH=/go/bin:/usr/local/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin --env=GOLANG_VERSION=1.14.6 --env=GOPATH=/go --log-driver=none --detach=true sha256:7da3d4d2918fc630aca3c4c011df3c9b30d7b79cd7be691718807cfb62bce554 /bin/sh -c 'go build hello.go'

安装使用流程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#安装
yum install -y python-pip && pip install runlike #Python2
yum install -y python3 && pip3 install runlike

#用法:
runlike -q <container-name> #使用-q自动换行

#实例
runlike -p linuxea_redis
docker run \
--name=linuxea_redis \
--hostname=LinuxEA-Node172_25_50_250.cluster.com \
--env=REDIS_CONF=on \
--env=REQUIRE_PASS=OTdmOWI4ZTM4NTY1M2M4OTZh \
--env=MASTER_AUTH=OTdmOWI4ZTM4NTY1M2M4OTZh \
--env=MAXCLIENTS_NUM=30 \
--env=MAXMEMORY_SIZE=1024M \
--env=PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin \
--env=RS_VSON=5.0.0 \



0x03 UI管理

1. dockerui

描述:Dockerui是基于docker API提供图形化页面简单的容器管理系统,支持容器管理和镜像管理;容器信息查看只是画面比较酷,不怎么实用用来看看为以后造轮子也是极好;

1
2
3
4
$docker pull abh1nav/dockerui
#两种启动方法一种是sock,另外一种是是rest API
$docker run -d -p 9000:9000 -v /var/run/docker.sock:/docker.sock \
--name dockerui abh1nav/dockerui:latest -e="/docker.sock"

WeiyiGeek.dockerui

WeiyiGeek.dockerui


2. shipyard

等待补充中……