docker笔记

docker概念

镜像与容器

docker镜像是一个统一文件系统,由一系列只读层堆叠而成。容器则是在只读层堆顶加上一个读写层。而当一个容器被分配给隔离的进程空间后即可转为运行态。

thin pool的概念

传统的存储空间分配方式成为fat provisioning,要求多少空间就分配多少空间,即使只使用了其中很小一部分。而thin provisioning则是在需要的时候才实际分配空间。thin pool建立在thin provisioning的思想上,它分配的是虚拟的chunk,而不是物理的block。
当docker使用Device Mapper作为存储驱动,可以配置成direct-lvm模式,这种情况下存储使用一个块设备作为thin pool,thin pool由存储实际数据的data space和存储指针的metadata space组成。

OCI

Open Container Initiative,开放容器倡议(标准)。主要有两个标准文档:容器运行时标准 (runtime spec)和 容器镜像标准(image spec)。这两个协议通过 OCI runtime filesytem bundle 的标准格式连接在一起,OCI 镜像可以通过工具转换成 bundle,然后 OCI 容器引擎能够识别这个 bundle 来运行容器。

OCI bundle

所谓bundle是指一个根文件系统和一个config.json文件,runc可以用这两个输入建立一个容器。

OCI state

OCI定义了容器的5种状态,creating, created, running, stopped, paused.

—————————————————————————————————————————————————————————————————————
|       | ---start--> |       | ---error,exit,crash,kill--> |       |
|created|             |running| ---pause---> |paused|       |       |
|       |             |       | <--resume--- |      |       |stopped|
|       | ------------------create failed-----------------> |       |
—————————————————————————————————————————————————————————————————————
repository和registry

repository存储一种特定的镜像,其中可以包含多个版本(tag),例如docker.io/busybox是一个repository。
registry则是存有大量repository的服务器,例如docker.io是官方的registry。

docker组件间的交互

dockerd通过监听unix、tcp socket接收请求,对外的API接口是REST方式,可以用curl直接发送GET或者POST请求来模拟通过docker调用指令的效果,例如:
curl '127.0.0.1:2375/v1.37/images/create?fromImage=hello-world&tag=latest' -X POST
与docker pull等效。
dockerd与containerd之间通过grpc协议通信,containerd与containerd-shim之间使用ttrpc协议通信(早期版本似乎用过其他通信方式)。

docker配置

daemon启动参数配置文件

可以在/etc/sysconfig/docker中的OPTIONS中添加参数(这是默认位置,具体以docker service的状态信息中的environment file为准),或者在/etc/docker/daemon.json中添加。

仓库配置文件

/etc/containers/registries.conf,虽然是新版本的推荐配置方法,但单独在这里添加似乎不能正常使用。
其他方法:在/etc/docker/daemon.json中添加如 "insecure-registries": ["***"],此配置不影响首选仓库,不指定仓库的情况下依然搜索官方仓库docker.io,需要另外配置registry-mirror来修改默认的镜像仓库。

存储配置文件

/etc/sysconfig/docker-storage,但同样可以在daemon.json中设置。

网络代理配置文件

/etc/systemd/system/docker.service.d/* 初始状态下需要手动创建该目录,配置文件名无限制,例如proxy.conf。

# 内容示例
[Service]
Environment="HTTPS_PROXY=https://***"
Environment="HTTP_PROXY=http://****"
Environment="NO_PROXY=localhost,huawei.com,athuawei.com,huaweidevice.com,hw3static.com,euleros-obs"

docker daemon会根据其启动环境中的HTTP_PROXY,HTTPS_PROXY,NO_PROXY变量来决定代理行为,注意daemon的启动环境中的变量和linux系统环境变量是两回事,需要单独设置。

docker服务的启动参数

systemctl show docker可以查看docker服务的各种信息,其中EnvironmentFile项目设置的文件包含有环境变量的设置,例如/etc/sysconfig/docker-storage中的DOCKER_STORAGE_OPTIONS,然后在ExecStart项目的启动命令中引用这些变量。
修改服务环境变量后需要systemctl daemon-reload之后再重启服务。

配置DeviceMapper的direct lvm模式

https://docs.docker.com/storage/storagedriver/device-mapper-driver/
注意配成direct lvm后如果要删除逻辑卷,需要先取消逻辑卷的激活状态:lvchange -an docker/thinpool
删除逻辑卷后如果要再重建逻辑卷使用docker,需要删掉docker原来的/var/lib/docker/devicemapper目录,因为其中存有原来的文件系统数据,与新建的逻辑卷不匹配,文件系统校验会失败。

cgroup目录

在/var/run/docker/libcontainerd/xxxxx/config.json(可以用管道转接python -m json.tool再转接less格式化显示内容)中找到容器的cgroup目录,docker run可以用--cgroup-parent参数设置目录路径。

docker服务无法启动时查看容器配置

可以查看/var/lib/docker/container/[container_id]/config.v2.json

容器扩容

docker info中有Base Device Size项显示容器的默认容量,可以通过在docker-storage或daemon.json中添加storage-opt dm.basesize=**G调整,注意daemon.json中的格式要求,以及daemon.json和/etc/sysconfig/docker之间可能存在的配置冲突。修改后需要重启docker服务,并且原有的images不会发生变化,如需调整只能删掉后重下载镜像。另外缩小容量需要删除/var/lib/docker目录,否则重启服务时会报错。

docker存储位置

docker info中的Docker Root Dir项目是docker存储的根目录。创建的容器存储在containers/下,下载的镜像信息记录在image/目录下,但实际的数据存在于${Storage_Driver}目录下。例如使用devicemapper存储驱动,在容器运行着的情况下在devicemapper/mnt/[device_name_ID]下面可以直接看到容器中的统一文件系统。其中的device_name_ID可以在docker inspect中的DeviceName项查到。

日志

docker服务日志

通过以下rsyslog配置修改docker服务日志输出目的地

/etc/rsyslog.d/docker.conf

$FileCreateMode 0644
template(name="DockerLogFileName" type="list") {
   constant(value="/var/log/docker/")
   property(name="syslogtag" securepath="replace" \
            regex.expression="docker/\\(.*\\)\\[" regex.submatch="1")
   constant(value="/docker.log")
}
if $programname == 'dockerd' then \
  /var/log/docker/combined.log
if $programname == 'dockerd' then \
  if $syslogtag contains 'docker/' then \
    ?DockerLogFileName
  else
    /var/log/docker/no_tag/docker.log
$FileCreateMode 0600
容器业务日志

docker run启动容器时可以用--log-driver指定日志记录方式。
docker默认的logging driver是json-file,在该模式下日志会被记录在/var/lib/docker/<containerID>/<containerID>-json.log中。
如果指定journald作为logging driver,日志会被记录到linux系统日志中,可以用journalctl -u docker来筛选查看。
如果指定syslog作为logging driver,日志会根据/etc/rsyslog.conf的配置写入指定的文件中。

shim日志

默认情况下不打开,需要docker daemon设置debug级别的日志等级才会输出到messages中。

常用操作

导入导出

docker save 将image保存成tar包,并且保留镜像的分层信息;docker export 将容器保存成tar包,不保留分层信息。
docker load 可以将save产生的包导入成镜像,还原出分层信息;docker import 导入的tar包甚至不是一个镜像,仅仅是一个文件系统。

容器内外的文件传输

docker cp host_file container_ID:container_file 将外部的文件复制到容器中,两个参数反过来也可以将文件从容器中取出。相当于cp -r,可以复制整个文件夹。目标路径是已存在的文件夹时,会将源拷贝到该文件夹下,如果要让源文件夹和目标文件夹合并,需要把源文件夹写成source_dir/.的形式。

关于exec的umask

docker exec执行指令的时候无视容器内的umask设置,固定使用自己的umask,官方版本是022。

exec的等效操作

利用nsenter进入后台容器,先用docker inspect --format "{{.State.Pid}}" container_ID查找容器的pid,然后nsenter --target $PID --mount --uts --ipc --net --pid -- env --ignore-environment -- /bin/bash即可进入容器环境。

容器权限

docker run的--cap-add和--cap-drop用以赋予、取消容器权限,权限类型参考ttp://man7.org/linux/man-pages/man7/capabilities.7.html

shm共享内存

/dev/shm是从内存中映射出来的虚拟文件系统,对应一块内存空间。默认情况下各个容器的/dev/shm是独立的,但可以在docker run参数中设置--ipc指定共享另一个容器的shm(ipc命名空间隔离进程间通信,而共享内存正是进程间通信手段)。
此设置也可在inspect信息中查询IpcMode来确认。

查找被占用的挂载路径

find /proc/*/mountinfo | xargs grep [****]

从mnt路径反向查容器

docker ps -a -q | xargs docker inspect -f "{{.Id}} {{.GraphDriver.Data.DeviceName}}" | grep *****

镜像相关

镜像的各种ID
  • 镜像id码
    manifest.json的config字段是镜像id,这是对镜像配置文件进行sha256计算得到的。镜像配置文件是tar包解压后manifest.json以外的另一个json文件,文件名就是这个id本身。镜像载入后配置文件存放在环境的/var/lib/docker/image/[graph_driver]/imagedb/content/sha256下。
  • 镜像tar包分层路径码
    镜像tar包解压出来的manifest.json中记录了各层的路径码,也是解压出来各个存有layer.tar的目录的路径名。这是对分层的config.json数据结构做256校验得到的。
    image/v1/imagev1.go: CreateID()创建此路径码
    路径码按照从上到下依次为最底层到最新层。
  • 镜像分层DiffID
    在代码中被称为DiffID的编号是对各分层文件layer.tar进行256校验得到的,分层的diffid可以在镜像配置文件中查看,也可以docker inspect镜像查看各分层的sha256码。
    diffid按照从上到下依次为最底层到最新层。
  • 镜像分层ChainID
    chainID:docker内容寻址机制采用的索引ID,其值根据当前层diffID和祖先层的chainID算得:
    若该镜像层是最底层,那么其chainID 和 diffID 相同
    否则,chainID=sha256(父层chainID+" "+本层diffID)
    layer/layer.go: CreateChainID()创建此ID,注意代码中ChainID是包含sha256:前缀的字符串,计算新层ID时是把前缀一起带进去计算256码的。
    镜像存在于本地的情况下/var/lib/docker/image/overlay2/layerdb/sha256下面各个分层的路径名就是该层的chainID。
  • 镜像分层parent
    父镜像层的chainID
查询第三方仓库中的镜像

docker search默认只访问官方仓库docker.io,要搜索第三方仓库需要加仓库地址,如docker search rnd-dockerhub.huawei.com/busybox

secure registry的认证

registry本质上是server端的一个容器,拉起该容器时需要制定使用的证书(crt)和私钥(key),其中crt是根据key生成的,包含registry信息和公钥。这两个文件的规范获取方式是由CA签发,下游环境应该是自签。
用户端pull/push镜像使用的证书需要放在/etc/docker/certs.d下面,以registry域名和端口作为目录名,例如/etc/docker/certs.d/hub.myreg.com:2121/。目录下应该有key,cert,crt三个文件。其中crt文件就是registry端使用的那个证书,需要手动复制到用户端,用户端使用该文件验证registry的身份;key是client端的私钥,cert是根据私钥生成的证书,证书中包含client的个体信息和公钥,此证书会提供给registry端用于验证用户身份。
参考文档:https://docs.docker.com/registry/insecure/https://docs.docker.com/engine/security/certificates/
另外docker login进行的认证是有别于上述TLS安全上的另一种认证,用于限制特定的用户访问仓库。

运行时目录相关

检查exec运行的任务

可以通过/var/run/docker/containerd/[container_id]下的stdin,stdout等文件来判断有没有exec任务

runc相关

用runc查看容器状态

比docker ps更准确
runc --root /var/run/docker/runtime-runc/moby list
其中root参数可以ps查看容器shim进程的-runtime-root参数

健康检查

健康检查可以在dockerfile中用HEALTHCHECK配置,这样做出来的镜像自带健康检查,也可以在docker run的时候用--health-cmd参数添加。
dockerfile中相关指令:
  HEALTHCHECK [option] CMD *****
option可用选项:
  --interval=DURATION (default: 30s)
  --timeout=DURATION (default: 30s)
  --start-period=DURATION (default: 0s)
  --retries=N (default: 3)
run指令中的相关参数:
  --health-cmd      Command to run to check health
  --health-interval    Time between running the check
  --health-retries    Consecutive failures needed to report unhealthy
  --health-timeout    Maximum time to allow one check to run
  --health-start-period  Start period for the container to initialize before starting health-retries countdown
  --no-healthcheck    Disable any container-specified HEALTHCHECK
注意检查CMD只应该返回0或者1,返回值规定:
  0: success - the container is healthy and ready for use
  1: unhealthy - the container is not working correctly
  2: reserved - do not use this exit code

容器网络

ethtool -S veth*** 可以查看veth网卡另一端的设备号,然后可以在ip link list中查看是什么设备。

ip_forward功能

容器网络需要系统开启ip_forward功能
sysctl net.ipv4.ip_forward 检查系统ip_forward是否开启
如果没有开启,修改/etc/sysctl.conf配置文件中的net.ipv4.ip_forward参数,然后sysctl -p使之生效;向/etc/sysconfig/network添加FORWARD_IPV4=YES,然后重启network服务。

ipv6支持

docker默认关闭ipv6功能,需要在daemon配置中添加"ipv6": true,如果添加后报"could not find an available, non-overlapping IPv6 address",需要进一步添加"fixed-cidr-v6": "****"。

docker代码

client与daemon的交互

docker daemon端接收到client端发送的API请求后,处理入口代码在api/server/router/下,和容器相关的请求在container下,和镜像相关的请求在image下。

daemon与containerd的交互

以grpc方式交互,api定义在api/grpc/types/api.proto中,该文件生成了api.pb.go,是go语言层面上的代码定义。

docker-toolkit

app image

docker_load使用-i参数指定的APP_IMAGE实际上就是原本的镜像名,即docker build制作镜像时用-t参数指定的命名(和tag),如果不知道原本的镜像名,可以查看manifest内容,第一层元素就是镜像名。

hash

docker_save会计算各个tar包的hash值保存在manifest中,docker_load会校验tar包hash值是否和manifest的记录匹配,不匹配则会报诸如Invalid base image tarball的信息。

其他

删除docker逻辑卷

dmsetup remove docker-thinpool
dmsetup remove docker-thinpool_tdata
dmsetup remove docker-thinpool_tmeta
lvremove /dev/docker/thinpool
如果要重建thinpool,重建后可能需要激活 lvchange -ay /dev/[vg_name]/[lv_name]

核对IO高的可能性

/var/log/sa下面有记录io情况的日志,但时间很稀疏。

用curl直接发http请求

例如curl -XGET --unix-socket /var/run/docker.sock http://localhost/images/json,相当于docker images请求
curl -XGET --unix-socket /var/run/docker.sock http://localhost/containers/json?all=true,相当于docker ps -a请求
docker的http api可以查阅https://docs.docker.com/engine/api/v1.40/

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,378评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,356评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,702评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,259评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,263评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,036评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,349评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,979评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,469评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,938评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,059评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,703评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,257评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,262评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,501评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,792评论 2 345