微信公众号:有田菜也香
作者:AcidGo
内容目录
前言1. docker 介绍1.1 cgroup1.2 namespace2. docker 维护命令尾记
前言
本人水平有限,也荣幸在这块公众号的田地里为大家开荒,小小献丑,欢迎各位读者指正与提议。
我们有了一个分布式数据库,更确切地说应该是一个分布式数据库中间件,我想就从这个系统开始说起,以系列的方式展开。这么做,并不是让大家去更加喜欢这个系统,这个玩意我觉得嘛,emmm,主要是因为它是个大杂烩,可以讲很长时间。嘿嘿嘿,这个系列就叫《funny-D》,懂的自然懂。
1. docker 介绍
进入这个开篇的主题,那就是 docker
,但是这里并不是介绍 docker
怎么使用,因为现在 docker
的部署都依赖给编排平台,后续的内容会分享编排平台,这里只是介绍下 docker
的细节和维护方式。docker
主要是使用了 Linux
中的 namespace
(命名空间)和 cgroup
(资源隔离)的技术,实现进程能运行在自己的一套命名空间下,从而与其他进程进行隔离,同时使用 cgroup
对各命名空间下的资源权重配重。其实,docker
更像是一个客户端或脚手架,它由 Golang
编写,把 Linux
的特性封装为相关命令,并且提供了远程连接、镜像管理、容器导出等便捷接口。如果想跟多的了解 docker
,可以阅读入门级的《第一本 docker 书》或是进阶级的《docker 与容器云》。
1.1 cgroup
cgroups
(control groups,cgroups)为每种可以控制的资源定义了一个子系统,并可实现对其的资源做控制。docker
使用该特性对容器运行做了资源限制与隔离。
典型的子系统介绍如下:
cpu: 主要限制进程的 cpu 使用率。
cpuacct: 可以统计 cgroups 中的进程的 cpu 使用报告。
cpuset: 可以为 cgroups 中的进程分配单独的 cpu 节点或者内存节点。
memory: 限制进程的 memory 使用量。
blkio: 限制进程的块设备 io。
devices: 控制进程能够访问某些设备。
net_cls: 标记 cgroups 中进程的网络数据包,然后可以使用 tc 模块(traffic control)对数据包进行控制。
freezer: 挂起或者恢复 cgroups 中的进程。
ns: 使不同 cgroups 下面的进程使用不同的 namespace。
其中常用的 systemctl
里就有 cgroup
的使用,如下限制了某服务的 CPU 占比在cpu.cfs_period_us
(如 1000)的500权重:
sudo systemctl set-property zabbix-server CPUShares=500
如果是再稍微底层一些,就是使用 Linux
上作为临时文件系统的 cgroup
来演示一下例如 docker
中 --cpu-period
和 --cpu-quota
的 limit 限制的相同原型操作。如下为一个斐波那契的 Python
demo:
def fib(n):
return 1 if n in (1, 2) else fib(n-1) + fib(n-1)
import sys
print(fib(int(sys.argv[1])))
然后如下则是在 cgroup
挂载区新建目录,并配置一个 cg
,向其设置 CPU
的时间使用周期和配额,然后使用该 cg
来测试代码运行时间:
① 进入 cgroup 的挂载目录。
② 当创建了目录后,会自动创建配套参数。
③ 配置需要统计的 CPU 使用时间周期。
④ 运行占用的 CPU 时间。
⑤ 使用该 cg 后,每10000毫秒使用1000毫秒的 CPU 时间执行 demo,执行时间延长。
1.2 namespace
容器之间共用宿主机的内核态 ,除了有资源的隔离,仍需要保证容器内的进程运行在自己的空间里,而不会受容器外用户态进程影响,进而实现开箱即用。这种属于自己的空间,就是命名空间。这个有点像编程中的全局命名和本地命名,如下一个不太恰当但可以帮助理解的 Python
小程序,pp 在全局环境中提供必要的功能函数,既可以理解为内核态;a 和 b 中的 cnf 处于不同的本地环境,因此不会互相干扰,拥有了自己命名的 cnf:
pp = print
def a():
cnf = "inner a"
# 输出:inner a
globals()["pp"](cnf)
def b():
cnf = "inner b"
# 输出:inner b
globals()["pp"](cnf)
真正的 namespace 有如下六种:
由于后续会讲到网络虚拟化的一套解决方案,因此这里讲讲 network-namespace
,开启个 netns
然后对其添加网口并配置 IP。
① 创建了一个 network-namespace。
② 创建了一对 veth,现在可以理解为准备的一个虚拟网线,后续细说。
③ 这时进入 ns1 这个 namespace,发现里面没有网口。
④ 将 veth1 接入 ns1。
⑥ 此时查看 ns1,发现内部多了一张网卡。
⑦ 对那张网卡配完 ip 后,发现符合预期。
从上述可见,这个网络是与宿主机隔离开来的,运行在 ns1 里面的程序也是只能看到分配给他的网络配置。
2. docker 维护命令
上面扯了一堆,其实仅是让大家了解一下 docker
某些底层特性,这里也不是为了学习容器,如果朋友们感兴趣,可以去全方面的了解容器技术。这里是 funnyD,也结合有田的身份,主要讲讲 docker
相关的维护命令,方便日常操作。
查看端口映射
如果是使用host
的网络方案,就是将端口映射至宿主机的某个端口上暴露出去,这个时候可以使用如下命令查看映射端口,从而定位对应容器的网络问题。
sudo docker port ${container}
查看网络
由于容器的网络解决方案众多,因此在通过容器 IP 定位容器的时候,会比较苦恼,对于 D 系统使用的是ovs
的网络方案,这里列举一种常用的方法。
这里主要操作是查看网络配置 vlan154,并查找匹配到 IP 的上下4行,这几行就是该持有该 IP 的容器的信息,可以直接定位宿主机和容器名等。
sudo docker network inspect vlan154 | grep -C 4 10.10.33.123
通过宿主机进程
PID
查找该进程所在容器
当监控系统发现某台宿主机的一个java
进程的swap
过高需要排查,而你登录宿主机发现上面十几个容器,如何定位该进程所在容器而针对其进行重启呢?一个推荐方法如下。$(sudo docker ps -q)
执行将返回当前宿主机容器 ID 列表,然后逐个使用docker inpect
输出容器详细信息,并使用Golang
的输出命名格式输出容器包含的宿主机进程。
sudo docker inspect -f '{{.State.Pid}} {{.Id}}' $(sudo docker ps -q) | grep ${PID}
健康检查
容器运行时并不是说里面的进程死绝才会让容器挂掉,docker
提供了容器检查的机制,既可以自行设定对每个容器设定检查命令,来判断容器运行正常,执行结果为0则表示health
,非0则表示unhealth
。如下则定义了容器必须保证自身 http 服务可用。
因此很多容器都是在内部实现了一个 healthcheck 的脚本,类似 D 系统。所以,如果有该脚本存在,判断容器运行是否正常的第一步,就是执行该脚本确认。
docker run -d --health-cmd="curl --fail http://127.1:80/fu || exit 1" myhttpd
关闭、开启、重启容器
废话一堆,忘了说怎么重启容器,在确认单独关停容器不会触发编排的调度,则可以执行如下操作。
# 关闭容器 ${container}
sudo docker stop ${container}
# 开启容器 ${container}
sudo docker start ${container}
# 重启容器 ${container}
sudo docker restart ${container}
${container}
是容器的标志,可以是容器名、容器ID等,由于 docker
实现了最短匹配,即输入能匹配到的最短字符都可以定位,这样方便在登录终端时不需要在不能复制的情况下手动输入全部字符,如下说明:
# 加入有如下容器ID
3aa5a6828ac4
3aads0028ac4
2c042c81dd21
# 如下都是进入 3aa5a6828ac4 容器的方式
sudo docker exec -it 3aa5 bash
sudo docker exec -it 3aa5a bash
# 如下都是进入 2c042c81dd21 容器的方式
sudo docker exec -it 2 bash
如下可以关闭当前宿主机所有运行容器:
sudo docker stop $(sudo docker ps -q)
列举容器名
不需要使用一大串的awk
和tr
来单独输出容器名,docker
使用format
支持。
sudo docker ps --format="{{.Names}}"
查看容器日志
如果要查看容器日志,可以使用如下:
# 查看容器 ${container} 所有标准输出日志
sudo docker logs ${container}
# tailf 方式查看容器 ${container} 所有标准输出日志
sudo docker logs -f ${container}
# tail -n 10 方式查看容器 ${container} 所有标准输出日志
sudo docker logs --tail 10 ${container}
# 打印时间戳
sudo docker logs -ft ${container}
查看容器进程表
top
类似Linux
的top
(table of process),docker
也可以生成每个容器的top
:
sudo docker top ${c}
查看资源使用和性能参数
动态刷新容器的 CPU%、MEM USAGE、NET I/O、BLOCK I/O 等。
sudo docker stats ${c}
尾记
试试水,体验下公众号的制作流程,略微粗糙,继续努力。
下一篇会是吸取此次制作经验、不定期之后的《funnyD-2:multi-manager swarm 的架构部署与高可用测试》。