Road to growth of rookie

Meaningful life is called life

0%

MAC 环境下构建 PHP 自动化环境工具

Docker 还没有在国内流行起来的早期开发中, 关于 PHP 本地开发环境的搭建, 我尝试过使用本机安装 Nginx + PHP, 也尝试过使用虚拟机的方式. 各有各的优缺点.

因为我们之前生产环境使用的是 Docker 进行部署, 所以为了模拟生产环境需要使用线上的 Docker 镜像; 但是每个项目都写一个给本地开发环境使用的 docker-compose.yml 我又觉得很麻烦, 就花了一点时间写了一个自动化工具

之前有尝试过 Laravel Valet 虽然它的实现对现在来说, 已经有些老旧了, 但是它的运行方式我很喜欢, 所以我打算按照它的方式来写这个自动化工具

项目地址: https://gogs.ijunj.com/common/php-link-tool

构建自动化工具脚本

本来这个脚本打算用 Go 去实现, 但是写到一半又觉得有点麻烦且过于繁琐, 都是一些 Shell 命令, 有点脱裤子放屁的感觉, 还不如直接用 Shell 来实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#!/bin/bash

set -o errexit

helpTips="Usage: php-link-tool [options] [path]
php-link-tool link [path] Link to a new project
php-link-tool unlink [name] Unlink a project"

if [ $# -lt 1 ]; then echo "$helpTips" && exit 1; fi
if [ "$1" != "link" ] && [ "$1" != "unlink" ]; then echo "$helpTips" && exit 1; fi

case $1 in
"link")
if [ "$(docker images -q base/php-openresty:2.0.1)" = "" ]; then
echo "Run install.sh to initialize the environment" && exit 1;
fi

if [ $# -gt 1 ]; then path=$2; else path=$(pwd); fi
containerName=${path##*/}
if [ "$(docker ps -aq -f name="$containerName")" != "" ]; then
if [ "$(docker inspect --format '{{.State.Running}}' "$containerName")" = "false" ]; then
docker rm "$containerName"
else
echo "The $containerName project is already running, To disable this function, run the php-link-tool unlink <name> command" && exit 1
fi
fi

port=$(python -c 'import socket; s=socket.socket(); s.bind(("", 0)); print(s.getsockname()[1]); s.close()')

docker run --name="$containerName" -d -p "$port":80 -v "$path":/www base/php-openresty:2.0.1
echo "127.0.0.1 $containerName.local" | sudo tee -a /etc/hosts > /dev/null
sudo touch /private/etc/apache2/vhosts/"$containerName".conf
echo "<VirtualHost *:80>
ServerName $containerName.local
ProxyPass / http://127.0.0.1:$port/
ProxyPassReverse / http://127.0.0.1:$port/
</VirtualHost>" | sudo tee -a /private/etc/apache2/vhosts/"$containerName".conf > /dev/null

sudo apachectl restart
;;
"unlink")
if [ $# -gt 1 ]; then containerName=$2; else path=$(pwd); containerName=${path##*/}; fi
if [ "$(docker ps -aq -f name="$containerName")" != "" ]; then
docker stop "$containerName" && docker rm "$containerName"
sudo sed -i '' -e "s/^127.*$containerName.local$//g" /etc/hosts
vhostFile="/private/etc/apache2/vhosts/$containerName.conf"
if [ -f "$vhostFile" ]; then sudo rm -f "$vhostFile"; fi
fi
;;
esac
环境初始化脚本 install.sh

因为自动化脚本对 Apache 有依赖, 只有一个工具脚本还不够, 需要一个脚本去初始化 Mac 自带的 Apache; 这里我还把需要使用到的 Docker 镜像初始化也放到了里面

有跟朋友聊起这个工具, 他提供了一个全平台的解决方案, 在本地拉起一个 80 端口的 Nginx, 然后通过这个 Nginx 转发到其他项目的端口上; 这样就可以和宿主机完全隔离开, 后面如果有时间的话, 会有这一部分优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/bin/bash

set -o errexit

if [ "$(docker images -q base/php-openresty:2.0.1)" = "" ]; then
docker build -t base/php-openresty:2.0.1 --no-cache .
fi

sudo mkdir -p /private/etc/apache2/vhosts
sudo cp /private/etc/apache2/httpd.conf /private/etc/apache2/httpd.conf.bak

sudo sed -i '' -e 's/^#\(LoadModule.*mod_proxy_http.so\)$/\1/g' /private/etc/apache2/httpd.conf
sudo sed -i '' -e 's/^#\(LoadModule.*mod_proxy.so\)$/\1/g' /private/etc/apache2/httpd.conf
sudo sed -i '' -e 's/^#\(LoadModule.*mod_ssl.so\)$/\1/g' /private/etc/apache2/httpd.conf
sudo sed -i '' -e 's/^#\(LoadModule.*mod_vhost_alias.so\)$/\1/g' /private/etc/apache2/httpd.conf
sudo sed -i '' -e 's/^#\(Include.*vhosts.conf\)$/\1/g' /private/etc/apache2/httpd.conf

echo 'Include /private/etc/apache2/vhosts/*.conf' | sudo tee -a /private/etc/apache2/httpd.conf > /dev/null
echo 'SSLProxyEngine on' | sudo tee -a /private/etc/apache2/httpd.conf > /dev/null

sudo apachectl restart
cp php-link-tool.sh /usr/local/bin/php-link-tool

演示

1
2
# 创建一个新的 Lravel 项目
composer create-project --prefer-dist laravel/laravel php-test "5.*"

进入到项目文件夹执行 php-link-tool link 然后通过 docker ps 查看所有容器, 就能看到一个新的 php-test 容器在运行, 通过浏览器请求 http://php-test.local 也是可以正常请求的

image
image

然后通过 php-link-tool unlink 就能移除这个项目

image