Rootop 服务器运维与web架构

phpstudy服务器面板

phpstudy最早做本地php开发环境,现在出了服务器版。
phpstudy面板官方说是基于docker容器实现的,会创建一个容器用于运行面板服务。
此面板适用于不熟悉服务器操作的初学者用。

根据官方文档安装好后开始查看运行环境。

[root@VM_0_4_centos ~]# docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED              STATUS                   PORTS                  NAMES
8d3fcc05a239        centos_ssl:v1       "/bin/bash"         4 hours ago          Exited (0) 3 hours ago                          centos_ssl
23403cc60eb8        centos:v4           "/bin/bash"         4 hours ago          Up 4 hours                                      centos_env

发现有一个容器名为 centos_env 的在运行。

# 然后有个疑问

[root@VM_0_4_centos ~]# netstat -tnlp # 宿主机上执行

看到不少监听的进程而且有进程名,而不像以前用的docker都是docker-proxy监听的端口。
进入容器name为centos_env的容器,netstat也发现有同样的进程。这就表明了容器内的服务直接寄宿在宿主机上
也就意味着容器是跑在host网络模式下。这样容器内监听了什么地址,宿主机上直接就能看到,不需要桥接网络方式的映射端口。

docker网络有4中模式,分别为:

none模式,使用--net=none指定,该模式关闭了容器的网络功能。
host模式,使用--net=host指定,容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。
bridge模式,使用--net=bridge指定,默认设置 ,此模式会为每一个容器分配、设置IP等,并将容器连接到一个docker0虚拟网桥,通过docker0网桥以及Iptables nat表配置与宿主机通信。
container模式,使用--net=container:NAME_or_ID指定,创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围。

# 查phpstudy的安装脚本发现,运行了2个容器,都指定了host网络模式

docker create -it --name centos_env --network=host -v /usr/local/phpstudy:/usr/local/phpstudy -v /www:/www  centos:v4
docker create -it --name centos_ssl --network=host -v /usr/local/phpstudy:/usr/local/phpstudy -v /www:/www  centos_ssl:v1

# 运行一个自己的容器

[root@VM_0_4_centos ~]# docker run -dit --name test --net=bridge -p 8888:80 centos:v4
204d5854d4bd91167f33c54ef732adb58d11a1eea743a4a0f39374547f4026e3
docker: Error response from daemon: driver failed programming external connectivity on endpoint test (800abef340ef085a242ca05f98e2e6d8cbf400ea634dfd9ff05a96fd2f0a09a6):  (iptables failed: iptables --wait -t nat -A DOCKER -p tcp -d 0/0 --dport 8888 -j DNAT --to-destination 172.18.0.2:80 ! -i docker0: iptables: No chain/target/match by that name.

提示找不到规则链

这个问题好一顿排查,之前都是直接yum安装docker,没遇到过此问题。

# 手动查nat表是没有DOCKER这条链的,目前还不知道链是由什么服务去生成的。

[root@VM_0_4_centos ~]# iptables -t nat -L -n | grep DOCKER
[root@VM_0_4_centos ~]# #没有返回信息

# 通过ps查看有两个关于docker服务的进程

[root@VM_0_4_centos ~]# ps aux | grep docker
root      6996  0.2  1.9 348624 35976 ?        Sl   14:14   0:00 dockerd
root      7000  0.1  0.9 375516 17532 ?        Ssl  14:14   0:00 containerd --config /var/run/docker/containerd/containerd.toml --log-level info

dockerd # docker守护进程 docker daemon
containerd # 容器虚拟化技术,从docker中剥离出来,形成开放容器接口(OCI)标准的一部分。

可以参考:https://www.cnblogs.com/embedded-linux/p/10850491.html

[root@VM_0_4_centos ~]# containerd --help | grep iptables
[root@VM_0_4_centos ~]# 
[root@VM_0_4_centos ~]# dockerd --help | grep iptables
      --iptables                                Enable addition of iptables rules (default true)

对这2个命令查帮助文档,只在dockerd中发现有关于iptables的信息。

现在试试对dockerd加上参数启动

[root@VM_0_4_centos ~]# ps aux | grep docker
root     14107  0.6  1.8 419964 34060 pts/0    Sl   14:21   0:07 dockerd
root     14112  0.0  0.9 376576 18764 ?        Ssl  14:21   0:00 containerd --config /var/run/docker/containerd/containerd.toml --log-level info
root     14577  0.0  0.2  11780  4484 ?        Sl   14:22   0:00 containerd-shim -namespace moby -workdir /var/lib/docker/containerd/daemon/io.containerd.runtime.v1.linux/moby/287264f03a04ce0f30af6f0b8f73923ca563eba5862a09f6df179f978ac5dd25 -address /var/run/docker/containerd/containerd.sock -containerd-binary /usr/local/phpstudy/docker-18.09.6/containerd -runtime-root /var/run/docker/runtime-runc
root     18451  0.0  0.0 112708   976 pts/0    R+   14:40   0:00 grep --color=auto docker
[root@VM_0_4_centos ~]# kill -9 14107
[root@VM_0_4_centos ~]# docker ps
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
[root@VM_0_4_centos ~]# dockerd --iptables & 

# 再去查看是否有DOCKER这条链

[root@VM_0_4_centos ~]# iptables -t nat -L -n | grep DOCKER
DOCKER     all  --  0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL
DOCKER     all  --  0.0.0.0/0           !127.0.0.0/8          ADDRTYPE match dst-type LOCAL
Chain DOCKER (2 references)

发现有了DOCKER链

# 再次创建容器并映射端口测试

[root@VM_0_4_centos ~]# docker run -dit --name test --net=bridge -p 8888:80 centos:v4
ef23d213b1685d4e4e1fb1b4a6d6b39d3ca3d2455b33d0de175e734ccb7e3d72
INFO[2019-12-20T14:54:54.889562578+08:00] shim containerd-shim started                  address="/containerd-shim/moby/ef23d213b1685d4e4e1fb1b4a6d6b39d3ca3d2455b33d0de175e734ccb7e3d72/shim.sock" debug=false pid=20626
[root@VM_0_4_centos ~]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                  NAMES
ef23d213b168        centos:v4           "/bin/bash"         4 seconds ago       Up 3 seconds        0.0.0.0:8888->80/tcp   test
287264f03a04        centos:v4           "/bin/bash"         32 minutes ago      Up 32 minutes                              centos_env

# PS

dockerd --iptables & # 只有这么启动守护进程,重启机器才能创建对应链,不带的话,重启机器还是没有DOCKER链。

所以要实现使用docker,需要修改phpstudy服务启动脚本

/usr/local/phpstudy/system/phpstudyctl
找到dockerd改为dockerd --iptables

# 关于容器里的 WorkerMan 怎么启动的(web面板服务)
通过docker inspect centos_env 也没找到CMD或者ENTRYPOINT设置启动服务。就很无奈不知道怎么启动的
在物理机的rc.local中发现启动脚本

[root@VM_0_6_centos ~]# cat /etc/rc.local 
部分略·
/usr/local/phpstudy/system/phpstudyctl -start

然后去查 phpstudyctl 这个脚本发现 start 参数对应执行的函数为 Start_Phpstudy
在此函数里才找到启动WorkerMan的方法

#start webpanel
nCount=20
pid=`/usr/local/phpstudy/system/module/getPidByExe /usr/local/phpstudy/web/php-7.3.8/bin/php`
while [[ $pid == "0" ]] && [[ $nCount>0 ]]
do
	docker exec centos_env $SHELL /usr/local/phpstudy/web/start > /dev/null 2>&1 &
	((nCount-=1))
	sleep 1
	pid=`/usr/local/phpstudy/system/module/getPidByExe /usr/local/phpstudy/web/php-7.3.8/bin/php`
done

才发现是通过执行docker exec 执行容器内命令实现的启动。

# 关于服务器防火墙配置
面板是运行在docker中,那么是怎么实现配置物理机的防火墙规则?
在 /usr/local/phpstudy/web/service/app/ 下找到 security.php 文件,部分代码如下:

<?php // 防火墙管理 require_once __DIR__.'/../app/base.php'; $user = Auth::doauth(); $type = get('type'); $req_data = json_encode(array('command'=>$type,'data'=>'','uid'=>$user['uid']));

// 防火墙状态
if($type == 'security_firwall_open' || $type== 'security_firwall_close'){
        $res = Socket::request($req_data);
        $res = json_decode($res,true);
        if($res['result']==0){
                xpexit(json_encode(array('code'=>1,'msg'=>$res['msg'])));
        }
        xpexit(json_encode(array('code'=>0,'msg'=>'操作成功')));
}

发现是调用了 Socket 类的 request 方法
最后找到是在 /usr/local/phpstudy/web/service/app/lib/socket.php 中通过socket实现。

<?php
/**
 * 网络通信模块
 */
class Socket{

        public static function request($data){
                error_reporting(E_ALL);
                set_time_limit(0);
                $host = "127.0.0.1";
                $port = 8090;

发现是连接的127.0.0.1的8090端口。也就是宿主机本身。

查看 /usr/local/phpstudy/system/phpstudyctl 脚本中的 Start_Phpstudy 函数的部分代码

#start phpstudy
pid=`/usr/local/phpstudy/system/module/getPidByExe /usr/local/phpstudy/system/phpstudy`
if [[ $pid == "0" ]];then
		/usr/local/phpstudy/system/phpstudy -d > /dev/null 2>&1 &
fi

phpstudy 这个服务就监听在8090端口。可以推测是这个服务去配置了防火墙规则。

因为容器启动时用的是host网络模式,所以可以用127.0.0.1直接访问。
这也就解释了面板虽然在容器中,但是可以操纵宿主机防火墙规则的原因。

# 关于容器的几个服务及命令
containerd
dockerd
containerd-shim
docker-proxy # 只要映射了端口,就会启动proxy
ctr
runc

root@rootop:~# /usr/bin/dockerd -h | grep config
      --config-file string                      Daemon configuration file (default "/etc/docker/daemon.json")

原创文章,转载请注明。本文链接地址: https://www.rootop.org/pages/4664.html

赞赏

微信赞赏支付宝赞赏

作者:Venus

专注于 服务器运维与web架构 E-mail:venus#rootop.org

评论已关闭。