拥塞控制算法
Leaky Bucket Algorithm Computer Network => Leaky bucket algorithm
二进制到文本编码
Percent-encoding
Percent-encoding – Wikipedia
即我们熟知的 URL encoding 方法。[……]
「DSA」- 算法概览(Algorithms Overview)
「Base64」
https://tools.ietf.org/html/rfc3548
https://tools.ietf.org/html/rfc4648%EF%BC%8C%E5%BC%95%E8%87%AA%E7%BB%B4%E5%9F%BA%E7%99%BE%E7%A7%91:l
“This RFC obsoletes RFC 3548 and focuses on Base64/32/16.”
<?php
// 测试
$encode = mbase64_encode(“134dewdqew你好啊”);
echo ‘encode:’ . $encode . PHP_EOL;
$decode = mbase64_decode($encode);
echo ‘decode:’ . $decode;
//base64变形,为解决外部问题
// 编码:base64,已经测试,测试内容为中文字符串和英文字符串;
function mbase64_encode($msg) {
$content = ”;//base64编码后得到的字符串,不包含结尾的 “=”
$end = ”;//结尾的 “=” 部分
$base64_chars = [‘A’, ‘B’, ‘C’, ‘D’, ‘E’, ‘F’, ‘G’, ‘H’, ‘I’, ‘J’, ‘K’, ‘L’, ‘M’, ‘N’, ‘O’, ‘P’, ‘Q’, ‘R’, ‘S’, ‘T’, ‘U’, ‘V’, ‘W’, ‘X’, ‘Y’, ‘Z’, ‘a’, ‘b’, ‘c’, ‘d’, ‘e’, ‘f’, ‘g’, ‘h’, ‘i’, ‘j’, ‘k’, ‘l’, ‘m’, ‘n’, ‘o’, ‘p’, ‘q’, ‘r’, ‘s’, ‘t’, ‘u’, ‘v’, ‘w’, ‘x’, ‘y’, ‘z’, ‘0’, ‘1’, ‘2’, ‘3’, ‘4’, ‘5’, ‘6’, ‘7’, ‘8’, ‘9’, ‘+’, ‘/’];
$msglength = strlen($msg);//要编码的文本的总字节数
$b = $msglength % 3;//不是的
$end = $b == 0 ? ” : str_repeat(‘=’, 3 – $b);//确定base64中‘=’的个数
$msg .= $b == 0 ? ” : str_repeat(“\0”, 3 – $b);//追加空字符,用于for循环处理
//开始处理报文内容,每次处理3Byte,因为3Byte处理起来方便;
for ($index = 0; $index < strlen($msg); $index += 3) {
//获取要处理的序列,此步骤得到的是$msg中的要进行编[……]
「Docker」- 概念术语
需要具备的知识:Git、GitHub、Go
#1 获取帮助
Docker社区
https://forums.docker.com/
使用IRC频道
#docker,讨论用户求助及基本的Docker文件。聊天记录:https://botbot.me/freenode/docker/
#docker-dev,开发者相关的问题。聊天记录:https://botbot.me/freenode/docker-dev/
都在Freenode IRC网络上。
在GitHub上
关注Docker仓库:https://github.com/docker/docker/
distribution – 独立的Docker Registry和分布式工具。 runc – Docker容器格式和CLI工具。 Docker Swarm – Docker的调度框架。 Docker Compose – Docker Compose工具。
#2 报告Docker问题
问题描述要清晰: 包含docker info和docker version的输出; 命令uname -a的输出; 问题的详细描述,及期望的结果; 确认没有同样的问题;
#3 搭建构建环境
构建环境并检出源码
先安装Docker,因为构建环境本身就在Docker容器中。
安装git和make工具。
检出源码然后进行工作。
贡献文档
除了源码之外,文档大家都也参与贡献:
#!/bin/sh
cd docker
make docs
docker run –run -it -e AWS_S3_BUCKET -p 8000:8000 “docker-docs:master” mkdocs serve
# 然后在本地浏览器中打开8080端口
修改源码
#!/bin/sh
# 源码目录中附带了一个Dockerfile,用于构建开发环境
# 构建Docker开发环境
make build
# 该命令创建Docker镜像,里面包含了所有的Go及其他所必须的依赖,之后会基于该镜像启动一个容器。
# 构建可执行程序
make binary
# 构建二进制程序,位于./bundles/<version>-dev/binary/中
# 测试新特性。
# 先停止原有的容器,然后运行新的容器,进行一系列的测试。
# 运行测试。
make test
# 该命令会将当前代码作为构建上下文上传到镜像,并创建一个新的开发镜像。然后使用该镜像启动一个容器,并在容器中运行测试代码。
# 在新开发的容器中运行交互式Shell
make shell
发起PR
略……[……]
「Docker」- 监控
需要监控 Docker 的哪些指标?
1)Service:Docker 服务的自生运行状态,资源占用,负载情况 2)Container:容器的 CPU MEM DISK NETWORK
Service
WIP
Container
使用 Docker 自身提供的 Prometheus Metrices 参数
Collect Docker metrics with Prometheus | Docker Documentation
/etc/docker/daemon.json
{
“metrics-addr” : “127.0.0.1:9323”,
“experimental” : true
}
该方法能够收集服务、容器的总体运行情况,但是无法获取特定容器信息。
使用 cAdvisor 容器收集容器信息
google/cadvisor: Analyzes resource usage and performance characteristics of running containers. cadvisor/prometheus.md at master · google/cadvisor
docker run \
–volume=/:/rootfs:ro \
–volume=/var/run:/var/run:ro \
–volume=/sys:/sys:ro \
–volume=/var/lib/docker/:/var/lib/docker:ro \
–volume=/dev/disk/:/dev/disk:ro \
–publish=8080:8080 \
–detach=true \
–name=cadvisor \
–privileged \
–device=/dev/kmsg \
gcr.io/google-containers/cadvisor:latest
能够收集更多指标,包括每个容器的指标,也包含每个容器的磁盘空间使用(container_fs_*)
但是不包含”挂载到容器的磁盘的“空间的使用情况(我们的特殊场景、特殊需求)
cdewitt/docker-stats-exporter – Docker Hub
https://hub.docker.com/r/cdewitt/docker-stats-exporter
该镜像使用 Docker stats API 将来提供 Prometheus metrics 指标,作为 Prometheus Metrics Exporter 存在。
我们可以基于该项目进行一些改造,以满[……]
「Docker」- 更新配置,但无需重启服务
问题描述
当我们修改配置之后,需要重启服务,使得配置生效。
但是,重启 dockerd 服务,容器会被停止。我们希望容器继续运行,而不是停止。
该笔记将记录:如何重载配置文件,而无需重启 dockerd 服务。
解决方法
方案一、通过 HUP 信号
在 dockerd 中,通过 HUP 信号,可以重载某些选项,而无需重启容器。
受支持选项,参考 dockerd | Docker Documentation / CONFIGURATION RELOAD BEHAVIOR 文档。
例如,设置镜像加速站点,进行 reload 即可:
# vim /etc/docker/daemon.json
{
…
“registry-mirrors”: [“https://xxxxxxx.mirror.aliyuncs.com”],
…
}
# systemctl reload docker
方案二、通过 live-restore 特性
当守护进程 dockerd 不可用时,保持容器继续运行,可以使用如下配置:
# vim /etc/docker/daemon.json
{
…
“live-restore”: true,
…
}
# systemctl reload docker # SIGHUP
在启用 live-restore 特性时,即使重启 Docker 服务,容器也不会退出。
但是,该方法也存在限制,参考 Keep containers alive during daemon downtime | Docker Documentation 文档。
参考文献
Keep containers alive during daemon downtime Reload docker logging configuration without daemon restart – Stack Overflow dockerd | Docker Documentation / CONFIGURATION RELOAD BEHAVIOR[……]
「Docker」- 配置端口监听(以允许 Docker Engine API 访问)
问题描述
我们需要调用 Docker Engine API 以获取某些数据,主要用于调试及查看。(在程序集成时,应该使用类库,而不是直接调用接口)
但是 Docker 默认监听 Unix Domain Socket 文件,因此无法使用 Postman 接口调试工具。解决方法是使 Docker 服务监听 TCP 端口。
该笔记将记录:如何使 Docker 服务监听 TCP 端口。
注意事项
虽然使用 Insomnia Designer 可以访问 Unix Domain Socket 文件,但是开启 Docker 服务的 TCP 监听还是有意义的。
在下面的演示中,我们同时进行 UDS 与 TCP 监听,可以根据实际情况进行调整。
我们使用 Debian GNU/Linux 10 (buster) 作为测试环境,但也应该适用于其他 Linux 发行版。
解决方法
我们有以下几种方案: 1)修改 docker.service 配置;(适用于在安装时设置,此时没有正在运行的容器) 2)启用 docker live-restore 配置,然后再修改;(适用于生产环境) 3)使用 Nginx 反向代理;(该方案对于 docker 的无侵入性,且可操作性强)
方案一、修改 docker.service 配置(常规方法)
// 修改 docker.service 配置,添加如下配置
# systemctl edit docker.service
[Service]
ExecStart=
ExecStart=/usr/sbin/dockerd -H fd:// -H tcp://127.0.0.1:2375 $DOCKER_OPTS
// 重启服务
# systemctl restart docker.service
// 测试接口
# curl http://127.0.0.1:2375/v1.39/containers/json
[]
注意事项: 1)我们只监听 127.0.0.1:2375 端口以测试,所以外部主机无法访问。如果需要外部主机访问,可以修改为 0.0.0.0:2375 地址,但是要做好网络安全设置,或者启用 TLS 认证。 2)在测试主机中,由于没有运行中的容器,所以最后的测试接口返回空数组([]);
方案二、针对生产环境(复杂操作,但推荐)
Enable TCP port 2375 for external connection to Docker dockerd | Docker Documentation Keep containers alive during daemon downtime | Docker Documentatio[……]
「Docker」- 使用 Docker API
「Engine API version history」
之前通过在命令行中调用Docker命令,但是这不是理想的方案。Docker提供了API,可以通过API来操作Docker进行服务集成。
首先将Docker服务绑定到网络端口,然后通过HTTP API来控制Docker服务。
最后使用TLS进行认证。
三种 API 接口
在 Docker Ecosystem 中,有三种 API 接口: 1)Registry API:用于与 Registry 服务集成。 2)Docker Hub API:用于与 Docker Hub 集成。 3)Docker Remote API:用于与 Docker 守护进程进行集成。
这三种 API 都是 RESTful 风格,该笔记将记录:与 Docker Remote API 相关内容。
# 初识「Remote API」
Remote API由Docker守护进程提供。
守护进程默认会绑定到一个本地的套接字上,`unix:///var/run/docker.sock’。守护进程是以root运行,因为要去管理资源。如果系统存在一个Dokcer组,Docker会将套接字的所有者设置为该组,任何属于该组的用户都可以控制Docker,而无需root权限。(这里存在一些安全问题,要做好权限控制。)
但本地的套接字只能用于本地访问,如果要远程访问,则需要使用-H选项绑定到网络接口上。本地可以使用 nc 命令进行测试:
echo -e “GET /info HTTP/1.0/r/n” | nc -U /var/run/docker.sock
绑定到网络接口指定-H选项(docker -d -H tcp://0.0.0.0:2375)既可,但是不同的发行版有不同的配置方式,这里不介绍…………当然,防火墙要允许访问。
使用-H选项来测试(docker -H docker.example.com:2375 info),此时的Docker是作为客户端运行的。或者使用DOKCER_HOST环境变量(DOCKER_HOST=”tcp://docker.example.com:2375″)
# 测试「Remote API」
#!/bin/sh
# 服务状态查看
curl http://docker.example.com:2375/info
# JSON
################################################################################
# 镜像相关
####################################################[……]
「Docker」- 我们 daemon.json 配置
问题描述
在 Docker 中,服务的默认配置并不能满足我们的要求,因此我们需要调整默认配置,以适应我们生产场景的要求。
我们并不希望修改这些配置,但是如果不这样做又会带来其他问题。比如:我们容器时经常忘记指定日志论转选项,这便导致容器的日志不断增加,占用大量磁盘空间;为了提高镜像的拉去速度,我们需要使用镜像仓库的镜像站点(registry-mirror),或者配置网络加速。这写场景都需要我们修改 Docker 服务的配置文件。
该笔记将记录:在生产环境中,我们所使用的 Docker 配置(以及这样配置的原因),以及常见问题处理。
解决方案
cp -v /etc/docker/daemon.json /etc/docker/daemon.json.backup
cat > /etc/docker/daemon.json <<EOF
{
“live-restore”: true,
“max-concurrent-downloads”: 7,
“log-driver”:”json-file”,
“log-opts”: {“max-size”:”500m”, “max-file”:”3″}
}
EOF
# 首先,使配置 live-restore 生效
systemctl reload docker.service
# 然后,重启服务,记载其他配置
systemctl restart docker.service
live-restore:使重启 Docker 服务,而不会导致容器退出; log-opts:修改日志选项,但是容器需要重新创建,才能使日志选项生效; max-concurrent-downloads:并行镜像的连接数,用于提高镜像的下载速度;
registry-mirrors:我们没有使用该选项,原因参考 Proxy configuration 笔记。
修改数据目录
# vim /etc/docker/daemon.json
{
…
“data-root”: “/path/to/your/docker”,
…
}
参考文献
How to move docker data directory to another location on Ubuntu – guguweb.com[……]
「Docker」- 删除镜像
问题描述
该笔记将记录:如何管理本地 Docker 镜像;如何管理远程 Docker 镜像;在管理过程中出现的常见问题的处理;
获取镜像(增)
通过镜像拉取
使用 docker pull 命令拉取镜像;
执行 docker run 命令时,如果镜像不存在,则会先拉取 TAG 为 latest 镜像。可以先使用 docker pull 命令拉取镜像,以减少镜像启动的时间;
通过镜像构建
WIP
删除镜像(删)
删除单个或多个镜像
使用 docker rmi 与 docker image rm 命令来删除本地镜像(只能删除本地镜像,不能删除在镜像仓库中的镜像):
# 通过 Image ID 删除
docker rmi fd484f19954f
# 下面这两个是等价的,因为 latest 是默认的标签
docker rmi test1:latest
docker rmi test1
# 还可以通过 DIGEST 来删除。在 REPOSITORY 与 DIGEST 之间,使用 @ 分隔;
# 因为使用 DIGEST 拉取的镜像是没有 TAG 的,所以会用到这种方法;
docker rmi test/busybox@sha256:cbbf2f9a99b47fc460d422812b6a5adff7dfee951d8fa2e4a98caa0382cfbdbf
1)如果镜像具有多个标签,并且将标签作为删除参数,则命令仅删除标签; 2)如果镜像具有唯一标签,命令将删除标签,然后删除镜像;
删除被容器使用的镜像
如果镜像具有正在使用的容器,则无法删除,需要使用 -f 选项,将删除容器与镜像:
docker image rm –force “REPOSITORY:TAG”
删除所有镜像
如果要删除所有镜像可以使用如下命令(可以使用 docker images 的 –filter 选项进行高级过滤):
# 下面的两个命令是等价的
docker image rm $(docker image ls -a -q)
docker rmi $(docker images -a -q)
# 删除有容器的镜像
docker image rm -f $(docker image ls -a -q)
删除 IMAGE ID 相同的所有镜像
当镜像具有多个标签时,如果使用 IMAGE ID 删除(docker rmi fd484f19954f),会产生如下错误:
Error: Conflict, cannot delete image fd484f19954f because it is tagged in mul[……]
「Docker」- 构建“跨平台”镜像的多种方法(Multi-Arch Images)
问题描述
就目前(11/20/2020)的镜像而言,是不能“跨平台”的(这里的“平台”是指处理器架构)。因为镜像里面包含二进制文件,这些二进制文件是平台相关的。
但是,我们观察到一个现象,当我们从 DockerHub 拉取镜像时,即使使用相同的地址,也会自动获得对应平台的镜像。以拉取 Nginx 镜像为例: 1)在 ARM64 上,执行 docker pull nginx 将返回 ARM64 平台的镜像; 2)在 AMD64 上,执行 docker pull nginx 将返回 AMD64 平台的镜像;
这是个很有用的特性,比如,对于不同平台,我们可以使用同个 docker-compose.yml 文件,而无需针对不同平台使用不同的镜像地址。
该笔记将记录:如何在 Docker Hub 上创建镜像,以实现「相同的 docker pull 命令,在不同平台上执行,获取该平台的镜像」,实现这种“多架构”镜像。
解决方案
目前(11/20/2020),有以下几种方法可以解决该问题: 1)使用 docker manifest 方法,将多个镜像“合并”到同个镜像地址中(这也是该笔记将演示的方法) 2)使用 docker buildx 创建,方便快捷(我们推荐的方法,但是属于实验性质的功能)
方法一、通过 docker manifest 命令
该方法通过创建 manifest list 来包含多个平台镜像的 manifest 信息。解释:
1)每个 Docker 镜像都有自己的 Manifest 信息,可以通过 docker manifest inspect “<Image Name>” 命令查看。
2)而 Manifest List 则是创建这样一个“List”其中包含多个镜像的 Manifest 信息,然后推送到 Docker Hub 仓库,相当与一个“逻辑镜像”。这个“逻辑镜像”中包含所有关联到它的镜像,以及镜像适用的平台。可以执行 docker manifest inspect nginx:latest 命令查看 Nginx 镜像的 Manifest List 信息,里面包含镜像层、系统、架构等等信息,这个信息是直接从 Docker Hub 拉取的(即使本地存在 Nginx 镜像)。
第一步、启用 experimental 特性,修改 ~/.docker/config.json 配置:
{
…
“experimental”: “enabled”,
…
}
第二步、执行如下命令,以创建镜像标签:
# docker manifest create k4nz/manifest-example:0.1.3 \[……]
「Docker Buildx」- 构建“跨平台”镜像(学习笔记)
问题描述
“跨平台镜像”是指什么呢?我们以 nginx:latest 镜像为例,该镜像支持八种架构,比如 x86、arm64、amd64 等等。
神奇的地方是,对于同一个 docker pull 命令,却返回不同平台的镜像。比如: 1)在 amd64 中,执行 docker pull nginx:latest 命令,将返回摘要为 044451886742 的镜像; 2)在 arm64 中,执行 docker pull nginx:latest 命令,将返回摘要为 4f1e67ed43f3 的镜像;
经过一番研究,我们知道使用 Manifest List 创建“这种镜像”,并记录在 Multi-arch build 笔记中。
后来我们又发现 Docker Buildx 也可以用来构建这种镜像,而且更简洁,扩展性更高。
该笔记将记录:如何使用 Docker Buildx 构建多平台镜像,以及常见问题处理。
解决方案
Docker Buildx,是客户端插件,因此扩展 docker 命令,它支持全部 Moby BuildKit 特性。使用方法类同于 docker build 但又支持很多新特性,比如 创建有范围的构建器实例;在多节点中进行并行构建。背地里,还是在使用 BuildKit 工具,有兴趣可以研究 moby/buildkit 工具。
下面是使用 Docker Buildx 构建镜像的示例,比较简单,旨在让我们理解 Docker Buildx 的使用方法。
第一步、安装及启用
安装过程如下(详细内容,参考 README.md/Installing 文档)
# 第一步、下载并安装命令
mkdir -pv ~/.docker/cli-plugins/
wget -O ~/.docker/cli-plugins/docker-buildx \
https://github.com/docker/buildx/releases/download/v0.5.1/buildx-v0.5.1.linux-amd64
chmod a+x ~/.docker/cli-plugins/docker-buildx
# 第二步、设置 experimental 参数
vim ~/.docker/config.json
{
…
“experimental”: “enabled”,
…
}
安装 docker buildx 为默认构建命令。而后,执行 docker build 等同于 docker buildx 命令:
docker buildx install
docker buildx uninstall # 卸载[……]
「Docker」- dockerignore(学习笔记)
在上下文目录中,可以创建 .dockerignore 文件(类似于 .gitignore 文件),防止在 Build Context 中的某些文件被传到 Docker Server 中。
该文件中的匹配模式规则采用 Go 语言中的 filepath.Match() 函数。
参考文献
Do not ignore .dockerignore (it’s expensive and potentially dangerous)[……]
「Docker」- 将代码放入容器中
问题描述
目前,在容器中使用代码有以下几种方式:
容器启动时:CMD git clone …
镜像构建时:COPY . /whatever
容器运行时:docker run -v $(pwd):/whatever/
那到底应该使用那种???
解决方案
目标,这几种方式的优劣:
#「Best practices for getting code into a container (git clone vs. copy vs. data container)」
说了半天,大家都是从使用场景出发的。场景不同问题不同。
#「Do I HAVE to ADD my Code Into the Docker Image When Deploying?」
将代码打包到镜像里具有一些优势。
只有部署工作流是正确的,那挂载代码才是可接受的。
#「Best practices for getting code into a container」
生产COPY,开发MOUNT,以及一些相关的场景。
##「How to Move Code into a Docker Container」
生产COPY,开发MOUNT
最终结论
#1 生产环境(复制代码到容器)
在构建时,将代码放入容器中:
(1)启动速度块;
(2)一次构建,到处运行;(一致性、可移植)
(3)可快速回滚(快速切换到上一版本的镜像)
#2 开发环境(使用绑定挂载)
在进行本地开发时,将代码挂载到容器中:
(1)便于调试。日志文件可以写入绑定挂载的目录中。
(2)立即生效。将代码绑定挂载到容器中,修改后可以立即生效;
「绑定挂载」带来的问题:
(1)容器中的进程可以修改、删除主机中绑定挂载的文件。功能强大,但是也存在安全隐患。
(2)绑定挂载暴露文件到容器,降低了容器的安全和隔离。[……]
「Docker」- 提高镜像拉取速度
问题描述
某些 Docker 镜像,由于网络原因,而出现拉取缓慢的情况。
这需要我们通过网络加速服务或者其他方法进行镜像拉取。
该笔记将记录:在 Docker 中,如何解决镜像拉取慢的问题,以及常见问题处理。
解决方案
目前(01/07/2021),有两种方案解决该问题: 1)使用网络加速服务 2)使用”镜像仓库镜像“(Registry Mirror)
方案一、使用网络加速服务(推荐)
// 添加类似如下配置:
# systemctl edit docker.service
[Service]
Environment=”HTTP_PROXY=http://proxy.example.com:80″
Environment=”HTTPS_PROXY=https://proxy.example.com:443″
Environment=”NO_PROXY=localhost,127.0.0.1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16″
// 显示配置结果:
# systemctl show –property Environment docker.service
// 重新启动服务
# systemctl restart docker.service
更多细节请参考官方文档: docker pull/Proxy configuration Control Docker with systemd/HTTP/HTTPS proxy
方案二、使用 Registry Mirror 服务(废弃)
在配置中,使用 registry-mirrors 地址:
# mkdir -pv /etc/docker
# vim /etc/docker/daemon.json
{
…
“registry-mirrors”: [“https://xxxxxxx.mirror.aliyuncs.com”, “https://hub-mirror.c.163.com”],
…
}
# systemctl reload docker
关于 registry-mirrors 地址: 1)注册阿里云帐号,在 容器镜像服务 / 镜像加速器 中,查看个人地址(每个人的地址前缀都不同); 2)或者,使用其他 Registry Mirror 地址(比如 https://mirror.ccs.tencentyun.com 地址);
# 03/22/2021 这应该是最好的方案,但是事情永远不会那么简单。前些时间 DockerHub 增加拉取频率限制(Increase Rate Limits):匿名用户根据 IP[……]
「Docker」- 清理镜像(Prune images)
内容简介
本文将简单介绍如何“清理”Docker镜像,以释放系统资源(磁盘),以及Docker镜像到底应该如何删除。
什么是「清理镜像」?
我们讨论的是“清理”,而不是“删除”。这二者有什么区别呢?
“删除”更倾向于一个特定的移除动作。比如,删除某个镜像,删除某个标签。我们通常使用docker rmi命令来删除镜像。
“清理”更加的倾向于资源的释放。比如,删除某些未使用的镜像,以释放系统存储空间。可以使用docker image prune命令来清理镜像。
两个词语
# 什么是「未用镜像」?
「未用镜像」表示尚未在容器中分配或使用它。例如,当运行docker ps -a时,该命令将列出所有已退出以及当前正在运行的容器。在任何容器中使用的任何镜像都是“使用过的镜像”,而那些从未被创建过容器的镜像就是「未用镜像」。
# 什么是「悬空镜像」?
官方并没有给出明确的定义(可能是我没找到),但是根据各路大佬的描述和各种实验,「悬空镜像」有如下特征:
没有被其他镜像引用
在docker images的输出中,列TAG为<none>值
在docker images的输出中,列REPOSITORY为可能有值
「悬空镜像」是与任何有标签镜像无关的层。它们不再有用,除了占用磁盘空间。
查看「悬空镜像」命令:
#!/bin/sh
docker images –filter dangling=true
下面是「悬空镜像」示例:
REPOSITORY TAG IMAGE ID CREATED SIZE
<none> <none> 7848fcc70e7b 4 days ago 362MB
其他镜像不会引用「悬空镜像」,因此可以安全的删除「悬空镜像」。
清理镜像
使用docker image prune命令可以清除「悬空镜像」。
使用docker image prune -a命令可以清除「悬空镜像」以及「未用镜像」。
相关链接
除了镜像需要清理之外,容器、卷、网络都需要清理,可以参考「Prune unused Docker objects」文档。
参考文献
docker docs/Reference/docker image prune What is a dangling image and what is an unus[……]
「Docker」- 保存镜像到本地
问题描述
自动有了网络加速,我们再也不担心镜像拉取失败的问题。
但是,有些客户网络隔离无法访问外网,因此需要我们下载并复制镜像到服务器。
该笔记将记录:如何下载镜像到本地,复制到内网服务器,并加载镜像到本地。
解决方法
第一步、下载镜像到本地
docker pull “<image name>” # 必须先 pull 镜像到本地
docker save -o “<path for generated tar file>” “<image name>”
如果没有指定 -o 选项,默认输出到标准输出,可以通过 SSH 传输:
docker save <image> | bzip2 | \
ssh user@host ‘bunzip2 | docker load’
第二步、复制到内网服务器
使用 rsync 或 scp 复制到远程服务器(详细步骤略过)
第三步、加载镜像到本地
docker load -i “<path to image tar file>”
# 导入多个镜像
ls -1 *.tar | xargs –no-run-if-empty -L 1 docker load -i
参考文献
How to copy Docker images from one host to another without using a repository – Stack Overflow docker save | Docker Documentation Docker save without docker pull – Stack Overflow How to do “docker load” for multiple tar files – Stack Overflow[……]
「Docker」- 借助工具,以树形图的形式,查看镜像层
问题描述
在 Docker 中,镜像是以“层”的形式存在的,各个层之间项目依赖。那如何清晰直观的看到这些进行层之间的关系呢?
这正是本文要讨论的内容,通过借助工具,以树形的方式展示镜像层之间的关系;
#(推荐)dockviz – Visualizing Docker Data
-「GitHub/justone/dockviz」
可以以树形结构打印镜像之间的依赖关系,同时还可以配合 Graphviz 使用,生成图;
!!!不一定非要以 Docker 镜像的方式启动,可以直接到「Releases」页面下载二进制程序;
#(推荐)dive
-「GitHub/wagoodman/dive」
这个是真的好用;
# sen
-「GitHub/TomasTomecek/sen」
# Docker Explorer for Windows
-「GitHub/aloneguid/docker-explorer-windows」
!!!在 Windows 7 上,这个我没有运行成功;
# docker_descendants.py
-「GitHub/altaurog/docker_descendants.py」
这个工具也可以查看子镜像;
参考文献
How to get the list of dependent child images in Docker? Docker: Visualizing image hierarchy and container dependency using dockviz Proposal add `docker images –tree` back #17366 How to see tree view of docker images? Visualizing and pruning the docker image tree Digging into Docker layers Docker Images Tree Visualization[……]
「Docker」- 容器(学习笔记)
创建容器
在 Docker 中,使用绑定挂载(挂载主机目录,Use bind mounts):
docker run -d \
-it \
–name devtest \
-v “$(pwd)”/target:/app \
nginx:latest
进入容器
在 Docker 1.2- 前,可以使用 nsenter 工具。这里不再介绍。
从 Docker 1.3+ 后,可以使用 docker exec 命令,现在我们多使用该命令。
容器的各种状态
What does CREATED container mean in docker? docker create
在手册 docker ps 中找到了容器所有可能的状态 created, restarting, running, removing, paused, exited, dead。但是,并没有在文档中找到关于每种状态的详细描述。在各个命令中可能会包含执行改名后容器的状态。[……]
「Docker」- 格式化命令输出
问题描述
在 Docker 中,执行命令会显示大量输出,有时我们希望只显示特定字段,以了解情况。
该笔记将记录:在 Docker 中,使用 –format 选项控制输出的方法。
解决方法
在 Docker 中,大多数的输出命令都支持 –format 选项,用于控制输出。该选项使用 Go Template 语法来处理数据。
常用命令速记
显示所有没有设置 –restart 策略的容器:
docker container inspect $(docker container ls -q) –format ‘{{printf “%-60s” .Name}}{{.HostConfig.RestartPolicy.Name}}’
参考文献
Format command and log output | Docker Documentation template – The Go Programming Language[……]
「Docker Container」- 查看容器资源,限制容器资源
问题描述
在服务上,有很多容器没有做资源限制。在峰值出现时,他们会耗尽服务器资源,影响其他容器的运行。
因此,我们需要对这些容器进行资源限制(批量处理)。
该笔记将记录:1)如何批量对容器进行资源限制,2)并设置可用资源上限为当前已用资源加上”预留资源“
解决方案
查看资源用量(并排序)
docker stats –no-stream –format “table {{.Name}}\t{{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}” \
| sort -k 4 –human-numeric-sort
批量限制容器资源
DOCKER_API_VERSION=v1.39
for container_id in $(docker ps -q)
do
# colorful title
echo “####### Updating Container ${container_id}” | grep –color -E ‘.’
# 我们设置,内存上限 = 当前内存使用 + 500M
memory_limit=$(curl -s –unix-socket /var/run/docker.sock \
“http://ph/${DOCKER_API_VERSION}/containers/${container_id}/stats?stream=false” \
| jq ‘.memory_stats | ((.usage – .stats.cache) + 500 * 1024 * 1024)’)
# 执行设置
docker update –cpu-shares 512 –memory “$memory_limit” “$container_id”
done
相关链接
Runtime options with Memory, CPUs, and GPUs | Docker Documentation x.Miscellanies
参考文献
Runtime options with Memory, CPUs, and GPUs | Docker Documentation x.Miscellanies docker stats | Docker Documentation Sort by memory usage in docker stats – Stack Overflow[……]
「Docker」- 在容器中,运行 systemd 进程(轻量化的虚拟机)
问题背景
1)最开始,我们在笔记本中运行 KVM 虚拟机。当每次休眠恢复时,在 KVM 中的虚拟机就会带来大量的 CPU 负载; 2)另外,我们使用的 Linux 发行版是 Debian Testing 分支。由于某些服务是特定于发行版的,所以这些服务没有办法安装; 3)可以使用 Docker 运行服务,但是最佳时间要求一个容器启动一个服务,那么我们有很多服务,岂不是要启动很多容器;
因此萌生该想法:启动容器,运行 systemd 进程,使用 systemctl 进行服务管理,把容器当作虚拟机使用。(这可能违背容器的最佳实践,但现实问题总是多种多样的)
该笔记将记录:在 Docker Container 中,运行 systemd 进程,来进行系统及服务管理,把容器当作虚拟机来使用。
解决办法
systemd within CentOS
执行如下命令,运行 systemd within CentOS 容器:
docker run -it \
–name vm-centos \
–hostname vm-centos \
–env container=docker \
–tmpfs /run \
–tmpfs /tmp \
–volume /sys/fs/cgroup:/sys/fs/cgroup:ro \
–cap-add SYS_ADMIN \
centos:7 /sbin/init
systemd within Ubuntu
执行如下命令,运行 systemd within Ubuntu 容器:
docker run -d –name vm-ubuntu \
–privileged \
-v /sys/fs/cgroup:/sys/fs/cgroup:ro \
jrei/systemd-ubuntu
# ubuntu-18.04
docker run -d –name vm-ubuntu-18.04 \
–privileged \
-v /sys/fs/cgroup:/sys/fs/cgroup:ro \
jrei/systemd-ubuntu:18.04
参考文献
Is there any concrete and acceptable solution for running systemd inside the docker container?[……]
「Docker」- 查看容器所使用的磁盘空间
问题描述
我们需要了解容器使用的磁盘空间大小,以发现潜在的问题(比如日志直接保存在容器中)。
该笔记将记录:在 Docker 中,如何查看容器所占用的磁盘空间。
解决方案
查看磁盘空间
使用 docker ps –size 命令,可以查看当前容器所占用的磁盘空间:
# docker ps –size
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES SIZE
7c22f8c139cd demo “bash -c /bin/bash” 33 seconds ago Up 32 seconds musing_brahmagupta 12.1kB (virtual 202MB)
命令输出解读
在命令输出中,我们能够看到两个关于数值(12.1kB;202MB): 1)数值 12.1kB 表示“可写层”的总大小,即容器大小; 2)数值 202MB 表示“可写层”加上“镜像大小”,所以镜像大小 =202MB-12.1kB
在容器启动时,会以只读方式挂载“用于启动容器的镜像”。在镜像之上,会挂载“可写层”,用于写入在容器中的任何变化。
注意事项
这里所说的“容器大小”并不包含以下部分: 1)写入标准输出、标准错误的日志文件大小; 2)容器所使用卷大小; 3)容器配置文件(hostname, resolv.conf, …)的大小; 4)以及其他使用磁盘空间的地方。
参考文献
Explain the SIZE column in “docker ps -s” and what “virtual” keyword means #1520 How to analyze disk usage of a Docker container[……]
「Docker」- 常用容器操作、修改容器配置
修改容器参数,实现开机自启动
docker update | Docker Documentation Start containers automatically | Docker Documentation
在启动容器时,通过 –restart=always 选项,来实现容器自启动。
当我们创建容器之后,我们发现没有使用 –restart always 来使容器开机自动启动。但是我们不想重新创建容器(这牵扯很多问题)。
当容器已经创建,除了重新创建容器,我们能够使用 docker update 命令:
# 修改单个容器
docker update –restart always redis
# 修改全部容器
docker update –restart unless-stopped $(docker ps -q)
以 ROOT 用户进入容器
How to login using root user into docker container ? · Issue #1336 · oracle/docker-images
在构建镜像时,使用 USER 命令来控制运行(创建容器)时的默认用户。当我们进入容器时,默认将以 USER 定义的用户身份进入容器。
但是我们需要以 ROOT 用户进入容器,以进行维护。这需要使用 –user 选项:
docker container exec -it –user root jenkins-2.274 /bin/bash
容器无法停止
Cannot stop or restart a docker container – Stack Overflow
执行 docker container stop … 与 docker container kill –signal KILL … 都无法解决进程。
使用系统的 kill 命令来结束:
kill -KILl “<pid>”
找到占用特定端口的容器(或进程)
shell – How to check if a process is running inside docker container? – Stack Overflow Networking using the host network | Docker Documentation docker ps | Docker Documentation docker port | Docker Documentation List Docker Container Names and IPs
我们需要找到占用特定端口的容器或者进[……]
「Docker」- 容器网络(Container Networking)
内容简介
本部分将介绍如何配置容器网络,包括网卡、DNS、主机名等等。
使用Docker Networking将多个容器连接在一起。多个容器服务之间的访问,通过容器名进行访问(这是Docker Networking的功能之一)。[……]
「DOCKER-CONTAINER」- 桥接网络
默认桥接网络 vs 自定义桥接网络
默认桥接网络
通过命令 docker network inspect “bridge” 查看该网络信息,以及使用该网络的容器:
# docker network inspect “bridge”
[
{
“Name”: “bridge”,
“Id”: “d2d6aaa38ce4734dc01cae292a389513ee3e4b312397d39e5f84a0b67e4a59b5”,
“Created”: “2022-06-16T11:11:38.081948369+08:00”,
“Scope”: “local”,
“Driver”: “bridge”,
“EnableIPv6”: false,
“IPAM”: {
…
自定义桥接网络
即用户自动创建的桥接网络,而非默认的桥接网络:
# docker network create –driver bridge alpine-net
# docker network inspect alpine-net
…
桥接网络的 DNS 解析行为
如果使用默认 bridge 网络,则将集成主机的 DNS 服务器: 1)如果系统运行 systemd-resolve 服务,则继承其 DNS 服务器(networkctl status); 2)否则,复制使用 /etc/resolv.conf 配置信息;
如果使用用户自定义的桥接网络: 1)则使用 Docker 内置的 DNS Server 进行域名解析,其将解析转发到主机的 DNS 服务器配置;
指定 –dns-search=. 选项
Container networking | Docker Documentation
指定 –dns-search=. 选项,导致仅进行内部解析:
# docker run -it –network cstm-bridge –dns-search . –rm busybox sh
/ # ping www.baidu.com # 无法进行 DNS 解析,导致 ping 无法执行;
# docker run -it –network cstm-bridge –dns 223.5.5.5 –dns-search . –rm busybox sh
/ # ping www.baidu.com[……]
「Docker」- 配置docker0网桥
问题描述
该笔记将记录:如何调整默认 docker0 网桥,以及相关问题的解决办法。
bridge and docker0
bridge
安装Docker之后,默认会创建桥接网络,网络名为bridge(当然还可以创建其他类型网络,参考「Docker networks feature」手册)
使用命令docker network inspect “bridge”查看该网络信息,以及使用该网络的容器。
docker0
在Docker中,默认会创建docker0网卡,它是网桥设备。如果启动容器时未指定网络,则所有容器会连接到该网桥,容器的所有流量会经过该网桥流向守护进程(Docker),由守护进程代表容器处理路由(此时Docker为网关,而docker0则为网关网卡,但这不是绝对的)。
网桥的网络配置与容器的网络配置
守护进程会为docker0配置网络地址、掩码、地址分配范围(从该地址范围为连接到该网桥的容器分配地址)。
如果有必要,你可以调整该配置,指定不同的最大传送单元(MTU)、网关地址、地址分配范围等等。
调整docker0参数,可以通过命令行指定选项实现,也可以通过修改/etc/docker/daemon.json配置实现。官方建议通过修改配置实现。
配置示例
如下为/etc/docker/daemon.json配置文件的示例内容:
{
// 网桥(docker0)的网络地址及掩码,采用CIDR格式。
“bip”: “192.168.1.5/24”,
// 容器网络地址分配范围,必须是在网桥下的子网
“fixed-cidr”: “192.168.1.5/25”,
“fixed-cidr-v6”: “2001:db8::/64”,
// MTU
“mtu”: 1500,
// 连接到网桥的容器的默认网关,该网关控制流量路由
// 通常无需设置,默认为bip的网络地址。
// 但不能设置为与bip相同的地址,否则会产生「Address already in use」错误。
“default-gateway”: “10.20.1.1”,
“default-gateway-v6”: “2001:db8:abcd::89”,
// DNS
“dns”: [“10.20.1.2″,”10.20.1.3”]
}
(注意,注释用于解释。由于JSON不支持注释,使用时应该去掉)
在修改配置后,需要重启Docker守护进程以生效。
查看网桥
在主机中使用brctl show命令查看网桥信息。
在每次启动容器时,守护进程会使用网桥的配置,选择可用的网络地址作为容器eth0网卡[……]
「Docker」- 日志驱动(Logging Driver)
查看容器日志
使用docker logs命令查看容器日志。
使用docker logs -f命令可以像使用tail -f命令一样查看日志。
使用docker logs -f –tail 10也可以从最近的日志开始看。或者使用docker logs -f –tail 0查看最新的日志。
使用选项-t可以为每条日志显示时间戳。
可以使用–log-driver 指定日志驱动,比如 syslog,将日志写入系统的 syslog 中,或者使用 none,禁用全部日志;
在 Docker 1.8 中,新增了对 Graylog GELF 协议、Fluentd 以及日志轮转启动的支持;
日志驱动(Logging Driver)
在 Docker 中,由多种方式存储应用程序日志,这些存储日志的方式被称为“日志驱动(Logging Driver)”;
它具有多种类型日志驱动,例如 none、local、json-file 等等,还可以实现自己的日志驱动。详细内容可参考官方「Supported logging drivers」与「Use a logging driver plugin」文档;
注意事项
本笔记内容是对官方 19.03/Configure logging drivers 文档的学习与整理,详细内容请参考官方文档;
配置默认日志驱动
默认为 json-file 日志驱动,但是可以修改;
配置全局日志驱动
修改 /etc/docker/daemon.json 配置文件(示例):
{
“log-driver”: “syslog”,
“log-opts”: {
“max-size”: “500m”,
“max-file”: “3”,
“labels”: “production_status”,
“env”: “os,customer”
}
}
log-opts 可用属性取决于日志驱动类型(log-driver),如果日志驱动支持其他选项,则可以进行添加;
配置容器日志驱动
也可以为特定容器配置日志驱动。在启动容器时,指定 –log-driver 选项:
docker run -it –log-driver none alpine ash
配置日志分发模型
日志分发由两种模型:(1)阻塞;(2)非阻塞
“非阻塞”用于防止日志后端压力而导致应用程序崩溃。详细内容可参考官方文档;
使用日志标签
可以使用-e 或–label 选项指定日志标签,在生成的日志中会附加某些标签。详细内容可参考官方文档;
日志驱动限制
企业版支持“[……]
「Docker Context」- 使用 docker 命令管理多个 docker 节点
问题描述
在 Docker 中,通过 Docker Context 特性,可以实现:使用本地 docker 命令,管理多个远程的 Docker 节点。而且不仅如此,还可以管理 Swarm 集群、Kubernetes 集群。当然,由于 Docker Context 在 Swarm 与 Kubernetes 中的应用较少,所以我们内容的重点也放在使用 Docker Context 管理多个 Docker 节点。
该笔记将记录:如何使用 docker context 管理其他 Docker 节点,以及常见问题处理。
# 02/19/2021 注意事项,虽然我们在这里演示使用 Docker Context 管理多个 Docker 节点,但是这只是为了让我们熟悉 Docker Context 的使用方法。而 Docker Context 具有很多其他的实际应用。比如在 Docker Buildx 中,通过 Docker Context 来选择构建节点。因此,不要局限于使用 Docker Context 在多个远程 Docker 节点中执行命令。本质上,它提供了一种连接和管理远程 Docker 服务的方法。
解决方案
首先,我们要检查本地 docker 客户端是否 Docker Context 命令。执行 docker context 命令,产生如下输出表示支持:
# docker context
Usage: docker context COMMAND
Manage contexts
Commands:
create Create a context
export Export a context to a tar or kubeconfig file
import Import a context from a tar or zip file
inspect Display detailed information on one or more contexts
ls List contexts
rm Remove one or more contexts
update Update a context
use Set the current docker context
Run ‘docker context COMMAND –help’ for more information on a command.
在实验环境中,有三台主机: 1)192.168.39.1 => 本地主机,laptop,运行 docker 命令的主机 2)192.168.122.[……]
「Docker Machine」- 快速创建运行 Docker 服务的主机
问题描述
在 GitLab CI 中,我们发现有种 Executor 为 Docker Machine 类型。因此,我们开始了解 Docker Machine 相关的内容,学习它的功能及使用场景,思考它能否解决我们的问题。
该笔记将记录:在 Docker 中,使用 Dcoker Machine 的方法,以及常见问题处理。
解决方案
通过 Docker Machine 工具,能够快速创建运行 Docker 服务的主机。为了快速理解 Docker Machine 的作用,请查看如下示例:
第一步、安装 Docker Machine 命令
它是个工具,因此我们需要安装相关的命令(我们 Linux 环境):
# 下载命令
base=https://github.com/docker/machine/releases/download/v0.16.0
curl -L $base/docker-machine-$(uname -s)-$(uname -m) > /usr/local/bin/docker-machine
# 授权执行
chmod +x /usr/local/bin/docker-machine
# 配置 Bash 补全
base=https://raw.githubusercontent.com/docker/machine/v0.16.0
for i in docker-machine-prompt.bash docker-machine-wrapper.bash docker-machine.bash
do
sudo wget “$base/contrib/completion/bash/${i}” -P /etc/bash_completion.d
done
第二步、使用 Docker Mainche 命令
// 在首次执行时,什么都没有
// 毕竟是第一次执行,我们还没有创建任何东西
# docker-machine ls
NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS
// 执行如下命令,将在本地的 Virtolbox 中创建虚拟机
// 该虚拟机实例中运行 Docker 服务
# docker-machine create –driver virtualbox default
Running pre-create checks…
Creating machine…
(staging) Copying /Users/ripley/.docker/machine/cache/boot2docker.iso to /Users/ripley/.docker/mach[……]
「Docker」- 容器编排与服务发现
编配,大概描述了自动配置、协作、管理服务的过程。
在Docker中,编配用于描述一组实践过程,这个过程会管理运行在多个Docker容器里的“应用”,而这些Docker容器有可能运行在多个宿主机上。
编配工具分为三类:
简单的容器编配工具:比如Docker Compose(前身为Fig)
分布式服务发现:比如Consul,由Go语言开发。
Docker的编配和集群:比如Swarm,由Go语言编写,由Docker公司开发。
后面主要介绍这三类工具。
#2 Consul
演示配合Consul的分布式应用使用
Docker中的DNS由Consul提供。
#3 Docker Swarm
集群管理工具。
将一组Docker主机作为一台单独的Docker主机来管理,将多台主机作为集群,通过Docker API的形式提供服务,不需要新的API。对于与Docker集成的工具,Swarm集群不过是另外的一个Docker主机。
# 创建Swarm集群
安装:Docker 1.4.0+;各个节点的版本要统一:
#!/bin/sh
# 假设我们由两台主机:HostA – 10.0.0.125;HostB – 10.0.0.135;
################################################################################
# 官方提供了镜像
################################################################################
docker pull swarm # on HostA
docker pull swarm # on HostB
################################################################################
# 创建swarm集群
################################################################################
# 「服务发现」:集群发现可以使用多种后端:Consul, Zookeeper, etcd。
# 也可以使用Docker Hub,它允许用户在Dokcer Hub中创建一个集群,返回一个集群ID,使用集群ID向集群中添加额外的节点。
docker run –rm swarm create # 任意主机
# poiefhoiahfdoashfoiehfasohdfisdfo[……]