Pages

Sunday, 30 July 2017

docker的不足之处

docker,这个美好的东西,自15年入坑,如今已经是使用它的第三个年头。docker ps里面的一个个容器,见证着这些年摆弄过的技术和应用。曾几何时,对docker的痴迷让我开始研究起docker的源码,结果还没看到一半就发现它改架构了。我也尝试学习k8s,但除了在VPS上搭了一套用于自high外就没有什么后文了。后来学业压力如期而至,研究方向也转向KVM和QEMU,也就没有再折腾docker了。
随着热度的褪去,敲下docker系列的指令的频率也就越来越低。我逐渐发现,我对docker的依赖并没有想象中的那么强。
课程Lab,老师直接扔下一个虚拟机镜像。折腾软件,直接跑一个Ubuntu 16.04 Server的虚拟机,启动时间也不比小鲸鱼的“装箱”长多少。后来,老板提供了一台48核的server,于是日常的学习和研究更是直接ssh到server上来做,那种频繁更换kernel,插module的工作,也是docker无法胜任的
于是乎到后来,我在自己的电脑几乎就没有再用到docker了。想到这里,我吸了一口气,然后决然地将docker和所有的image、container都移除了。直到两周后的今天,写下此文的今天,我回想起这件事,感慨已经成功“戒docker"。
当然,在大洋对岸的两台VPS依然欢快地跑着docker。但回想起来,似乎自己当初是为了docker而docker:
其中一台专门用来跑SS:我在一台新机器上先安装docker,然后登录我的dockerhub账号,把自己的ss镜像拉下来,然后创建一个专门跑ss的容器,在跑的时候网络还要host mode,然后把配置文件挂载进去,把日志目录挂载出来。现在回想起来,真有一种脱裤子放屁的感受。
于是后来也就没这么干了。直接裸装ss,换VPS直接重复安装流程,发现流程竟然比docker还简单。
另一台专门用来跑网站和一些乱七八糟的服务。因此上面的软件也就比上一台要复杂一些,nginx,db,业务server等等一大锅,因此经过一番折腾把它们都做成dockerfile,并将有依赖的服务搞成docker-compose一键拉起。看似很酷炫,然而蛋疼的事情也经常发生:
  • 有些没有重定向到输出的log,只能通过docker log去查看,结果发现从容器启动到现在的日志如黄河之水般倾泻而出,一下就把终端塞爆了
  • 默认情况下,docker会直接对外暴露端口,而无视系统防火墙.
  • docker hub构建一个镜像往往需要10分钟,可能是因为没交钱所以优先级比较低
  • docker compose在down时有莫名其妙的问题,往往会漏那么一两个container杀不掉,也没办法手动杀掉,怎么办?只能重启宿主机
于是这样折腾下来,发现自己的生产力不仅没有提高,反而常常会因为一些莫名其妙的问题搞掉一晚上。于是乎,VPS上的去docker化也提上日程。
跑到油管上看了今年的DockerCon,发现 Docker 变成了 Moby?LinuxKIT ?docker公司的野心已经路人皆知,其打造的 上游组件(containerd/linuxkit/...)=> Moby => Docker CE => Docker EE 生态系统已经呼之欲出。如果docker公司成功了,那么它将是下一个RedHat。
不可否认的是,docker在生产环境中有不可取代的优势,但对于我个人而言,已经成为鸡肋。是时候跟它说再见了。
也许有一天,我又会回到终端前,敲下 moby run...
------------

无视系统的防火墙的docker

祸起

一直以来,我都对server暴露的端口进行了严格的限制,只开放少数对外服务的端口,像什么mysql这种端口肯定是不能开放的。
而各个平台都提供了方便的工具来设置防火墙,如Ubuntu的ufw,CentOS的firewalld。
我也很放心地用工具来配置防火墙,直到有一天发现:系统防火墙对docker根本不起作用!
可以看到docker直接在iptables开了几个大洞:
$ sudo iptables -L DOCKER
Chain DOCKER (2 references)
target prot opt source destination
ACCEPT tcp -- anywhere 172.18.0.2 tcp dpt:mysql
ACCEPT tcp -- anywhere 172.18.0.100 tcp dpt:8888
ACCEPT tcp -- anywhere 172.18.0.3 tcp dpt:https
瞬间冷汗就流了下来,是谁给你的胆子直接操作iptables的?愤怒的我取消了docker修改iptables的权限。

BAN

Ubuntu (upstart)

$ sudo vim /etc/default/docker
加入行
DOCKER_OPTS="--iptables=false"
重启
$ sudo restart docker

CentOS 7 (systemd)

$ sudo mkdir /etc/systemd/system/docker.service.d
$ sudo vim /etc/systemd/system/docker.service.d/docker.conf
加入行
ExecStart=
ExecStart=/usr/bin/dockerd --iptables=false
重启
sudo systemctl daemon-reload
sudo systemctl restart docker
修改完后,检验一下:
$ ps aux | grep docker | grep -v grep
root 2150 1.2 2.8 504416 28608 ? Ssl 23:33 0:00 /usr/bin/dockerd --iptables=false
看到生效后我就愉快地洗洗睡了。

在处理了这个问题后,我逐渐忘了这件事。直至几天前对binsite进行升级时,发现为何有一些请求特别慢?
查看ufw的log
Jan 22 16:36:05 ubuntu kernel: [5528848.005381] [UFW BLOCK] IN=web OUT=eth0 PHYSIN=vethbfec0a1 MAC=02:42:70:f6:b9:bf:02:42:ac:12:00:02:08:00 SRC=172.18.0.2 DST=106.187.95.5 LEN=59 TOS=0x00 PREC=0x00 TTL=63 ID=3966 DF PROTO=UDP SPT=54112 DPT=53 LEN=39
...
Jan 22 17:13:44 ubuntu kernel: [5531106.548557] [UFW BLOCK] IN=web OUT=web PHYSIN=vetha2fb979 PHYSOUT=veth1c712b5 MAC=33:33:00:00:00:02:02:42:ac:12:00:03:86:dd SRC=fe80:0000:0000:0000:0042:acff:fe12:0003 DST=ff02:0000:0000:0000:0000:0000:0000:0002 LEN=56 TC=0 HOPLIMIT=255 FLOWLBL=0 PROTO=ICMPv6 TYPE=133 CODE=0
发现容器无法访问外网了,也无法进行容器间通信了,根据https://github.com/docker/docker/issues/4737,解决办法如下(Ubuntu):
启用封包转发
ufw default allow routed
添加转发规则:
sudo vim /etc/ufw/before.rules
在最后加上以下内容:
*nat
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING ! -o net -s 172.18.0.0/16 -j MASQUERADE
COMMIT
net为当前网桥的名称,可通过ifconfig查看,172.18.0.0/16为网桥的子网段,可用过
docker network inspect net | grep Subnet
查看。
然后重启ufw:
sudo ufw disable
sudo ufw enable

吐槽

就像https://github.com/docker/docker/issues/4737里说到的那样,这已经不是什么小问题了,而是事关server安全的大问题。
这时docker说了,你不想暴露到外网可以在指定port的时候加127.0.0.1啊~
但问题是大家在使用时几乎不会手动指定为127.0.0.1,于是按照默认规则端口就被暴露到外网了,我觉得docker这种绕过系统防火墙直接操作iptables的做法非常不合理。
截止至目前版本,docker官方都没有要fix的意思,而这个issue已经存在了快三年了.

No comments:

Post a Comment