背景
在我使用pyrogram重构了YouTube Download之后,bot的SLA从9个6变为6个9,同时也迎来了使用量上的增加。这样的结果是,每天我的服务器都会跑掉100-200G的流量。
(这段统计信息是从docker stats拿到的,为了方便复用,我发布了一个wrapper到pypi,同样也可以go get,代码可以看这里 https://github.com/tgbot-collection/tgbot_ping)
于是我就想,我一定要想办法记录这个容器每天究竟跑了多少流量,不能每次都亲自指挥,亲自部署吧。那咋办呢……
宿主机上使用vnstat
在宿主机上使用vnstat,就可以看到本机一共跑了多少流量,不过这个数值通常来讲是会大于YouTube Download的流量的,当然也有一些例外情况,比如容器之间通信,那么自然不会被记录到宿主机的外网网卡。
直接用宿主机的vnstat做参考,对于我的场景也没什么大问题,因为这个bot是单独跑在一台机器上的,没有太多的影响因素。那么如何在容器中执行宿主机上的某个命令呢?
坏消息是,这个恐怕是没办法的。容器的namespace是隔离的,看不到宿主机上的信息。
非想搞呢,在宿主机上跑一个web程序,用于调用vnstat,然后容器访问宿主机的web程序好了……
docker stats
docker stats可以用于获取容器的运行时统计信息,比如CPU、RAM等。
比如在某台机器上,我执行下stats,能看到这样的结果
本质上docker是C/S架构的一个东西,所以其实这东西是有一个REST API的。
对于 docker stats,是这个接口
http://socat:2375/containers/dreamy_hugle/stats?stream=0
哦我预先用了下socat,在实际部署中,我有一个名为socat的容器,专门干这事的。当然这也意味着容器可以控制宿主机上的docker engine,有一定的风险。
socat tcp-listen:2375,fork,reuseaddr unix-connect:/var/run/docker.sock
拿到的响应是json,其中有一段networks
那么我只要去解析这个json,然后定时算diff,这样就可以啦!只不过实现难度 🌟🌟🌟🌟🌟,万一以后想看小时、月的呢,容器重启了怎么办,数据存哪,这代码怎么维护呀……
vnstat
在统计流量这方面,已经有了成熟的vnstat,在容器里怎么就不行了?容器也是能跑很多个进程的啊,我还见过容器跑sshd的呢。
vnstat其实也是个C/S架构的东西,vnstatd
负责存储流量信息到SQLite,vnstat
用于读取显示信息,还有一个vnstati
,能够生成图表。在某些廉价VPS厂商能看到如下简陋的流量图,那么很有可能就是vnstati
生成的。
在容器里用vnstat并不复杂,先开启vnstatd,然后再开我们的应用程序。
那么就先搞一段shell脚本,为了避免问题使用绝对路径吧
/usr/sbin/vnstatd -d /usr/local/bin/python ytdl.py
然后把入口从 python xxx.py
改成sh xxx.sh
看进程树是这样子的
需要的时候,写代码调用vnstat就可以了。为了避免干扰,代码中可以用 /usr/bin/vnstat -i eth
0 排除其他网卡哦。
一个示例Dockerfile
如下,使用了多阶段构建,所以vnstat要安装在运行时而不是构建时:
FROM python:alpine as builder RUN apk update && apk add --no-cache tzdata alpine-sdk libffi-dev ca-certificates ADD requirements.txt /tmp/ RUN pip3 install --user -r /tmp/requirements.txt && rm /tmp/requirements.txt FROM python:alpine WORKDIR /ytdlbot ENV TZ=Asia/Shanghai RUN apk update && apk add --no-cache ffmpeg vnstat COPY --from=builder /root/.local /usr/local COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ COPY --from=builder /usr/share/zoneinfo /usr/share/zoneinfo COPY . /ytdlbot RUN echo "/usr/sbin/vnstatd -d;/usr/local/bin/python ytdl.py"> /ytdlbot/start.sh CMD ["sh", "start.sh"]
需要注意的是,为了避免容器重启后数据丢失,记得做个volume到 /var/lib/vnstat
哦。
完美!结果如下图
当然了,在容器中运行多个进程有很多种办法,使用shell脚本是一种,缺点很多,比如进程崩溃了,那shell脚本也没法给守护起来……更好的更优雅的方案就是用supervisor,或者是一些好用的init,那些想用systemd的还是劝您放弃
supervisor可以参考这个配置,会把log重定向到stdout中
[supervisord] nodaemon=true logfile=/dev/null logfile_maxbytes=0 user=root [program:vnstat] command=vnstatd -n autorestart=true [program:ytdl] directory=/ytdlbot command=python ytdl.py autorestart=true stdout_logfile=/dev/fd/1 stdout_logfile_maxbytes=0 redirect_stderr=true
总结
我不知道你们是怎么想的,反正我感觉我快要被薅🐰了。
尽管我已经开启了VIP模式,试图通过10G/24h来产生一定威慑效果,但是依旧架不住人多啊🤣