Young Kbt blog Young Kbt blog
首页
  • java基础

    • Java基础
    • Java集合
    • Java反射
    • JavaJUC
    • JavaJVM
  • Java容器

    • JavaWeb
  • Java版本新特性

    • Java新特性
  • SQL 数据库

    • MySQL
    • Oracle
  • NoSQL 数据库

    • Redis
    • ElasticSearch
  • 数据库

    • MyBatis
    • MyBatis-Plus
  • 消息中间件

    • ActiveMQ
    • RabbitMQ
    • RocketMQ
    • Kafka
  • 进阶服务

    • Nginx
  • Spring
  • Spring Boot
  • Spring Security
  • 设计模式
  • 算法
  • 知识
  • 管理

    • Maven
    • Git
  • 部署

    • Linux
    • Docker
    • Jenkins
    • Kubernetes
  • 进阶

    • TypeScript
  • 框架

    • React
    • Vue2
    • Vue3
  • 轮子工具
  • 项目工程
  • 友情链接
  • 本站

    • 分类
    • 标签
    • 归档
  • 我的

    • 收藏
    • 关于
    • Vue2-Admin (opens new window)
    • Vue3-Admin(完善) (opens new window)
GitHub (opens new window)

Shp Liu

朝圣的使徒,正在走向编程的至高殿堂!
首页
  • java基础

    • Java基础
    • Java集合
    • Java反射
    • JavaJUC
    • JavaJVM
  • Java容器

    • JavaWeb
  • Java版本新特性

    • Java新特性
  • SQL 数据库

    • MySQL
    • Oracle
  • NoSQL 数据库

    • Redis
    • ElasticSearch
  • 数据库

    • MyBatis
    • MyBatis-Plus
  • 消息中间件

    • ActiveMQ
    • RabbitMQ
    • RocketMQ
    • Kafka
  • 进阶服务

    • Nginx
  • Spring
  • Spring Boot
  • Spring Security
  • 设计模式
  • 算法
  • 知识
  • 管理

    • Maven
    • Git
  • 部署

    • Linux
    • Docker
    • Jenkins
    • Kubernetes
  • 进阶

    • TypeScript
  • 框架

    • React
    • Vue2
    • Vue3
  • 轮子工具
  • 项目工程
  • 友情链接
  • 本站

    • 分类
    • 标签
    • 归档
  • 我的

    • 收藏
    • 关于
    • Vue2-Admin (opens new window)
    • Vue3-Admin(完善) (opens new window)
GitHub (opens new window)
  • 关于 - 自我

  • 关于 - 本站

    • 本站 - 介绍
    • 本站 - 规划
    • 本站 - 搭建
    • 本站 - 主题
    • 本站 - 网站部署
    • 本站 - 服务器部署
      • 原理介绍
      • 环境准备
      • 环境安装
      • 环境用户
      • 环境启动
        • Nginx启动
        • PHP启动
      • 环境配置
        • Nginx配置
        • PHP配置
      • 环境重启
      • 环境测试
      • Git环境
        • 宿主机配置Git
        • PHP容器配置Git
        • 项目访问
      • 自动化部署
        • Gitee脚本
        • Github脚本
        • WebHook配置
      • 问答
    • 本站 - 评论模块
    • 本站 - 站点信息模块
    • 本站 - 自定义样式模块
    • 本站 - 记录曾阅读位置模块
    • 本站 - 私密文章模块
    • 本站 - 导航站模块
    • 本站 - 首页大图模块
    • 本站 - 代码块隐藏模块
    • 本站 - 全局时间提示模块
  • 关于 - 首页

  • 关于 - 技巧

  • 关于 - 随笔

  • 关于
  • 关于 - 本站
Young Kbt
2021-12-03
目录

本站 - 服务器部署原创

笔记

如果你不打算部署在 Github Pages 或者 Gitee Pages 上,而是部署在自己的服务器上,又或者三个都想自动同步部署,那么本内容就是带你如何在服务器部署项目,同时也有 Docker 的一次实战。

2021-11-03 @Young Kbt

  • 原理介绍
  • 环境准备
  • 环境安装
  • 环境用户
  • 环境启动
    • Nginx启动
    • PHP启动
  • 环境配置
    • Nginx配置
    • PHP配置
  • 环境重启
  • 环境测试
  • Git环境
    • 宿主机配置Git
    • PHP容器配置Git
    • 项目访问
  • 自动化部署
    • Gitee脚本
    • Github脚本
    • WebHook配置
  • 问答

# 原理介绍

实现服务器自动化部署,我们使用的是 WebHook 技术,这个技术 Github 和 Gitee 都有,不难理解。

首先要知道为什么使用 WebHook?如果我每次克隆项目,需要手动实现 git clone 命令,但是每次别人 push 新代码,我必须手动克隆或者拉取最新的代码,那么有没有一种技术,别人 push 新代码,我发个呆,然后 push 的新代码自动被我的服务器克隆下来呢。这个技术就是 WebHook。

WebHook 可以理解为一个仓库的触发器。

  • 什么时候这个触发器被触发呢:由你决定,可以在 push 新代码之后,可以在分支合并之后

  • 触发的内容是什么:WebHook 会主动发送一个 POST 请求到你配置的地址,这个地址是我们服务器的脚本。一旦请求我们写的脚本,就会触发脚本,脚本里的内容就是执行 git clone 等命令拉取仓库代码

所以总结就是:当我们 push 项目到仓库,仓库触发 WebHook,发送 POST 请求到我们的服务器,这个请求触发我们写的脚本,脚本执行 git clone 等命令拉取项目代码。

image-20211209173735568

所以确保提供给 GitHub 或 Gitee 的请求能访问并触发编写的脚本。而如何访问并触发脚本,就是本内容要介绍的。

# 环境准备

  • CentOS 系统(其他系统也可以)

  • 一个普通用户(强烈建议)

  • Docker 容器(可选)

  • OpenResty,可以理解为 Nginx 和 Lua 的集成,使用 Nginx 也可以

  • PHP 环境(PHP 脚本必须)

注意:这里是使用 Docker 容器进行管理,如果没用过或者不打算用 Docker,也可以参考:Docker 是一个容器,容器里的每一个环境可以理解为一个 CentOS 系统,比如 Docker 里的 Nginx 就是一个安装了 Nginx 的 CentOS 系统,Docker 里的 PHP 就是安装了 PHP 的 CentOS 系统。(实际上不完全是 CentOS 系统,取决于供应商的设计,这里为了解释说明)

image-20211203123853405

有人疑惑了,可不可以在 Docker 里的 Nginx 环境安装 PHP,毕竟 Nginx 所在的也是一个 CentOS 系统,额(⊙﹏⊙),不建议,还是老老实实安装 PHP 吧。Docker 的出现就是为了隔离每一个环境,但是又不影响彼此的联系。

如果你不使用 Docker,请下意识把 Docker 这一层因素去掉即可。关于 Nginx 和 PHP 的步骤是完全一样,不会因为 Docker 而被影响。

我是先进入服务器,然后从服务器进入 Docker,接着从 Docker 进入 Nginx 和 PHP。而你不用 Docker,只需要进入服务器即可,因为不用 Dcoerk,Nginx 和 PHP 就处在服务器里。

# 环境安装

关于 Docker 的安装,我已经写在 Docker 的知识体系中,点击传送。

关于 OpenResty(Nginx)在 Docker 安装,我已经写在 Nginx 的知识体系中,点击传送。

如果你已经安装过 Docker,并且 Docker 里安装了 OpenResty 或者 Nginx,则不需要重新安装。

笔记

这里再次说明,没接触过 OpenResty 的也不慌,这里的它的作用就是 Nginx 的作用,所以本文提到的 OpenResty,请在脑海里替换为 Nginx 即可。

2021-11-03 @Young Kbt

安装完 Docker 和 OpenResty(Nginx)后,我们需要下载 PHP 镜像,服务器部署的脚本是使用 PHP 编写,所以需要 PHP 的运行环境。

查看 PHP 版本 传送门 (opens new window)

建议下载带有 fpm 的版本,我下载的是 7.3-fpm 版本。

docker pull php:7.3.33-fpm
1

# 环境用户

强烈建议 Nginx、PHP 或者其他的容器不要用 root 用户,这里创建一个普通用户来进行操作,这也是实际生产上需要做的。

创建 kbt 普通用户(用户名自己决定)

useradd kbt
passwd kbt
# 然后这里填 kbt 用户的密码
1
2
3

将 kbt 用户放入 docker 组,这样 kbt 用户才能使用 docker 的相关命令(如果不用 docker,请忽略)

usermod -a -G docker kbt  # 将 kbt 用户加入到 docker 用户组中

systemctl restart docker  # 重启 docker
1
2
3

-a 是追加,普通用户加入 docker 组后,不会退出原来所在的组。

-G 是指定组名。

# 环境启动

安装完 Docker、OpenResty 或 Nginx、PHP 后,接下来就启动它们。

Docker 的启动很简单,但是也很麻烦,简单在于命令是固定的,麻烦在于数据卷的考虑,到底放在宿主机的哪个路径下。

如果不用 docker,请忽略。

# Nginx启动

OpenResty 或 Nginx 的启动时,需要将配置文件目录、静态文件目录、日志文件目录给挂载出来,方便备份和修改。

这里只是说明我的路径,你的路径请根据你的需求修改,只需要修改路径即可。

  • Nginx 的配置文件挂载在 /docker/openresty/conf 目录下

  • Nginx 的静态文件目录挂载在 /docker/openresty/html 目录下

  • Nginx 的日志文件目录挂载在 /docker/openresty/logs 目录下

因为我打算把所有的挂载目录都放在 /docker 目录下,如 node 镜像挂载目录是 /docker/node,tomcat 镜像挂载目录在 /docker/tomcat ...... 类推

首先创建根路径:

mkdir /docker/openresty
1

这里说明一下,我们需要把 Nginx 容器里的这些目录拷贝出来,为什么呢?因为一旦挂载成功,宿主机的目录会覆盖容器的目录,想想此时刚刚创建的宿主机的目录都为空,一旦挂载后,容器里的目录被覆盖,也为空。所以我们事先从容器拿出这些目录,放到根路径下,再挂载,这样覆盖的目录就是拷贝出来的目录。

先简单启动一个 OpenResty 容器。容器名叫 nginx,启动的镜像名是 OpenResty,版本为 latest。

docker run -d --name nginx OpenResty:latest
1

将容器需要的挂载目录拷贝出来

docker cp nginx:/etc/nginx/conf.d /docker/openresty/conf
docker cp nginx:/usr/local/openresty/nginx/html /docker/openresty/html
docker cp nginx:/usr/local/openresty/nginx/logs /docker/openresty/logs
1
2
3

我拷贝的 conf.d 目录是 简易版 配置文件所在的目录,并将 conf.d 改为 conf,你可以不改,我只是不喜欢 .d。而静态文件目录和日志文件目录名不变。

完整版 的配置文件在容器的 /usr/local/openresty/nginx/conf 路径下,文件名叫 nginx.conf。

为什么不使用完整版?

「简易版」只能写 server 块,「完整版」不仅可以写 server 块,还能写 http 块。因为「完整版」的 http 块利用 include 指令引入「简易版」配置文件所在的目录,所以我们只需要在「简易版」目录下添加任意 .conf 文件,则自动会被引入到「完整版」,避免直接修改「完整版」引起安全问题。

image-20211209145837681

拿出来三个目录后就可以删除这个容器,为完整版的容器做准备。

docker rm -f nginx
1

启动最终版的 OpenResty 容器前,我们需要创建一个网桥,避免过多的容器积压在默认网桥上,也为了 Nginx 能和 PHP 等容器进行通信。

网桥就是网络,我喜欢称呼网桥

默认网桥无法直接通信,必须使用 IP 或者 --link 进行通信,所以很麻烦,我们就创建一个网桥,解决所有问题。如果还不懂,请看原理:点击跳转

2021-11-09 @Young Kbt

创建一个叫做 web 的网桥

docker network create web
1

最后启动 OpenResty 容器,实现挂载

docker run -d --name nginx -p 80:80 --restart always \
-v /docker/openresty/conf:/etc/nginx/conf.d \
-v /docker/openresty/html:/usr/local/openresty/nginx/html \
-v /docker/openresty/logs:/usr/local/openresty/nginx/logs \
-v /home/kbt:/home/kbt \
--network web --network-alias nginx \
OpenResty:latest
1
2
3
4
5
6
7

/home/kbt 是后面 PHP 环境需要,因为 PHP 不允许 root 用户操作,所以我们使用前面创建的 kbt 用作为操作 PHP 的权限用户。

--network-alias 是给所在的网桥起个别名,这个别名是自己所在网桥的一种标识,方便相同网桥的其他容器如 Nginx 通过别名找到你。尽量和容器名一致。

# PHP启动

PHP 容器启动很简单,我们需要注意的是 PHP 脚本的「住处」,我把脚本放在 /home/kbt 处,因为 PHP 环境使用 kbt 用户,所以脚本也要放在 kbt 用户的目录下,防止外界恶意访问执行脚本,引起严重后果。

如果你是 xxx 用户,则请将脚本放在 /home/xxx 目录下。

docker run -d --name php -v /home/kbt:/home/kbt --network web --network-alias php php:7.3-fpm
1

Ngxin 启动的时候也挂载了这个 /home/kbt 目录。

此时 /home/kbt 目录相当于一个「中转站」,连接着 Nginx 和 PHP,这样 Nginx 就能通过这个「中转站」访问 PHP 的脚本了。当然这样直接访问还远远不够,我们还需要在 Nginx 的配置文件进行配置,指定 PHP 的脚本在 home/kbt 下。

# 环境配置

我们需要修改 Nginx 的用户权限为 kbt,以及 PHP 的用户权限也为 kbt,这样为了防止外界恶意访问 Nginx,植入恶意脚本,因为 root 的权限太大,拥有了 root 权限,容易被植入恶意脚本。所以不要一味的追求 root。

不要忽略这一步,哪怕你不用 docker,你只需要把 docker 相关的命令无视掉。

# Nginx配置

我们需要配置 Nginx 的用户权限、PHP 脚本的访问路径、以及静态资源的缓存等。

配置 PHP 脚本的访问路径

首先打开 /docker/openresty/conf 的「简易版」配置文件,名字叫 default.conf

vim /docker/openresty/conf/default.conf
1

添加如下内容:






 
 
 
 
 
 
 



server {
    listen 80;
    server_name 你的服务器域名;

    # ...... 其他配置
    location ~ \.php$ {   # 访问 .php 后缀的请求
        root           /home/kbt;	# 脚本的根目录
        fastcgi_pass   php:9000;	# 通过 php 网桥别名的 9000 端口连接上 PHP容器
        fastcgi_index  index.php;	# 默认首页
        fastcgi_param  SCRIPT_FILENAME  /home/kbt$fastcgi_script_name;  # 脚本的根目录
        include        fastcgi_params;
    }
    # ...... 其他配置
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

第 7 行改为 /home/kbt 目录,这是我们放置脚本的根目录。

第 8 行的 php 就是我们启动 PHP 容器指定的网桥别名,Nginx 和 PHP 都处于 web 网桥,那么可以通过网桥别名找到彼此。9000 是 PHP 容器的默认端口。

第 9 行的 /home/kbt$fastcgi_script_name 指的是,启动 PHP 环境来运行 /home/kbt 目录下的脚本,否则脚本无法启动。如果你不是 /home/kbt,则自行修改。

注意

不能在 $fastcgi 前加 /。

2021-11-09 @Young Kbt

如果不使用 docker,则内容为

server {
    listen 80;
    server_name 你的服务器域名;
    
    # ...... 其他配置
    location ~ \.php$ {
    	proxy_pass   http://127.0.0.1;
    }

    location ~ \.php$ {
        root           /home/kbt;
        fastcgi_pass   localhost:9000;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  /home/kbt$fastcgi_script_name;  # 脚本的根目录
        include        fastcgi_params;
    }
    # ...... 其他配置
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

先转发到本地(127.0.0.1),然后触发 12 行的 localhost,找到 9000 端口的 PHP 环境。

安装 vim

因为 Nginx 容器并不带 vim 和 vi 命令,所以我们需要安装 vim,安装前需要更新 apt-get(容器没有 yum)

# 进入 Nginx 容器
docker exec -it nginx bash
1
2

下载前需要修改下载源为国内源,默认的国外源太慢。

# 进入 apt-get 配置目录
cd /etc/apt

# 执行备份命令,避免修改失败无法使用
cp sources.list sources.list.bak

# 同时执行 echo下的 4 行命令,修改成国内镜像源
echo "">sources.list \
echo "deb http://ftp2.cn.debian.org/debian/ buster main">>sources.list \
echo "deb http://ftp2.cn.debian.org/debian/debian-security buster/updates main">>sources.list \
echo "deb http://ftp2.cn.debian.org/debian/debian buster-updates main">>sources.list

# 执行更新命令 apt-get update
apt-get update
# 下载 vim
apt-get install -y vim
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

你可以将安装完 vim 的新容器,变成新的镜像,不然每次启动初始的镜像,都要更新 apt-get 和安装 vim

docker commit nginx nginx:1.0
1

第一个 nginx 是打包的容器名,而 nginx:1.0 则是打包成新镜像的名字和版本。构建新镜像后,可以把初始的镜像删除掉,保留也可以。

配置 Nginx 用户权限和缓存等。

进入 Nginx 容器

docker exec -it nginx bash
1

创建 kbt 用户,设置密码,要和宿主机创建的用户保持一致

groupadd kbt;
useradd -g kbt kbt # 创建用户,并加入组,都是 kbt
passwd kbt
# 然后这里填 kbt 用户的密码
1
2
3
4

创建完用户后,接着修改「完整版」配置文件

vim /usr/local/openresty/nginx/conf/nginx.conf
1

将 user 改为 kbt,

user kbt;
1

如图:

image-20211209155655575

顺便配置一下优化代码,提高 Nginx 的访问效率。

在 events 块添加:(已经存在的 events 块)

events{
	worker_connections 1024;	 
    accept_mutex on;			 # 开启 Nginx 网络连接序列化
    multi_accept on;			 # 开启同时接收多个网络连接
    use epoll;					 # 使用 epoll 函数来优化 Nginx
}
1
2
3
4
5
6

image-20211209155935175

在 http 块添加:(已经存在的 http 块)

http {
    # ...... 其他配置
	sendfile on;				 # 开启高效的文件传输模式
    tcp_nopush on;				 # 提升网络包的传输「效率」
    tcp_nodelay on;				 # 高网络包传输的「实时性」
    
    keepalive_timeout 65;		 # 连接超时时间
    
    gzip on;  			   		 # 开启 Gzip 功能
    gzip_types *;		   	 	 # 压缩源文件类型,根据具体的访问资源类型设定
    gzip_comp_level 6;	   		 # Gzip 压缩级别
    gzip_min_length 1k;          # 进行压缩响应页面的最小长度,content-length
    gzip_buffers 4 16K;	         # 缓存空间大小
    gzip_http_version 1.1;       # 指定压缩响应所需要的最低 HTTP 请求版本
    gzip_vary  on;		         # 往头信息中添加压缩标识
    gzip_disable "MSIE [1-6]\."; # 对 IE6 以下的版本都不进行压缩
    gzip_proxied  off;           # Nginx 作为反向代理压缩服务端返回数据的条件
    # ...... 其他配置
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# PHP配置

创建普通用户

首先进入 PHP 容器

docker exec -it php bash
1

创建 kbt 用户,设置密码,要和宿主机创建的用户保持一致

groupadd kbt;
useradd -g kbt kbt # 创建用户,并加入组,都是 kbt
passwd kbt
# 然后这里填 kbt 用户的密码
1
2
3
4

安装 vim

我已经在 Ngixn 配置写了如何安装 vim,请按照 Nginx 配置的安装 vim,进行安装,就在上面不远处。

配置 PHP 环境的用户权限

修改配置文件的用户

vim /usr/local/etc/php-fpm.d/www.conf
1

大概在 23 - 24 行,改为:

user = kbt
group = kbt
1
2

image-20211209161347606

# 环境重启

笔记

重启按顺序:PHP、Nginx,因为 Nginx 配置文件依赖 PHP 脚本,所以先启动 PHP,再启动 Nginx。

2021-11-09 @Younng Kbt

docker restart php
docker restart nginx
1
2

# 环境测试

测试 Nginx 是否能访问 PHP 脚本,我们在宿主机的 /home/kbt,创建 index.php 文件

vim /home/kbt/index.php
1

添加内容:

<?
    echo phpinfo();
?>
1
2
3

然后访问你的网站:ip:port/index.php,如图:

image-20211209163149655

此时 /home/kbt 就是你 PHP 脚本的根路径,如果你想对 PHP 脚本分类,可以在根路径下创建一个文件夹,如我创建 test 文件夹,将 index.php 放入该文件夹里,接着访问的时候,加上文件夹名即可。如下:

image-20211209163414807

# Git环境

环境准备就绪,现在进入正题。我们需要安装 Git,来实现自动部署。

分别在宿主机和 PHP 容器安装 Git

  • 宿主机安装 Git 是为了配置 SSH 公钥

    不理解公钥?我们克隆的项目地址有 HTTPS 方式,也有 SSH 方式。

    image-20211209164353563

    而 SSH 方式需要配置公钥,我们在自己的服务器生成 SSH 公钥,然后交给 Github 或者 Gitee,这样它们才能通过公钥「连接」我们的服务器。才能拉取项目。

  • PHP 容器安装 Git 是因为我们执行 PHP 脚本,然后 PHP 容器会根据脚本使用 Git 拉取仓库的项目。

为什么不在 PHP 容器配置公钥?

一个服务器可以生成一个公钥,尽量不要在容器内生成,因为服务器的公钥是公用的,任何容器都可以使用。但是只在一个容器内生产,其他容器可能出现无法使用的问题。

# 宿主机配置Git

宿主机安装 Git,可以直接使用 yum 来下载

yun -y install git
1

查看 Git 版本

git --version
1

配置全局用户信息

git config --global user.name "你的用户名" 		# 定义全局的用户名
git config --global user.email "你的邮箱" 		 # 定义全局的邮件地址
git config --list 								# 查看配置信息是否成功
1
2
3

切换 kbt 用户

su kbt
1

警告

必须切换 kbt 用户,因为我们 PHP 环境使用的是 kbt 用户,拉取代码时,不仅验证 SSH 公钥,也会验证生成 SSH 公钥的用户名。

如果是 root 用户配置公钥,则 PHP 容器没有权限拉取 Git 项目。

2021-11-09 @Young Kbt

生成公钥(确保已经切换了和 PHP 环境一致的用户)

ssh-keygen -t rsa -C "xxx@xx.com"  # 填写正确的你的邮箱
1

按三次回车即可生成 SSH 公钥。

生成 SSH 公钥后,会告诉你生成的目录:Your public key has been saved in /home/lkbt/.ssh/id_rsa.pub.

cat /home/kbt/.ssh/id_rsa.pub
1

查看文件后获取(复制)SSH 公钥,添加到 Github 或者 Gitee 中。如果不知道如何添加,请看 配置 SSH Key,该内容有三步,配置 SSH 公钥在第二步。

验证是否配置生效

ssh -T git@github.com    # GitHub
ssh -T git@gitee.com	# Gitee
1
2

建议 Github 和 Gitee 都配置 SSH 公钥。

# PHP容器配置Git

首先进入 PHP 容器

docker exec -it php bash
1

确保你的 apt-get 已经是最新的,如果不是,请更新。因为 apt-get 初始版本库里的 Git 版本很低。

apt-get update
1

安装 Git

apt-get -y install git
1

查看 Git 版本

git --version
1

配置全局用户信息

git config --global user.name "你的用户名" 		# 定义全局的用户名
git config --global user.email "你的邮箱" 		 # 定义全局的邮件地址
git config --list 								# 查看配置信息是否成功
1
2
3

初次使用,先克隆一次项目,放在 /home/kbt 目录下

cd /home/kbt
git clone -b ga-pages <仓库 SSH 地址>
1
2

-b 指定克隆的分支。不指定默认是默认分支 master。

警告

建议在 PHP 容器克隆项目,或者在宿主机切换到 kbt 用户再克隆项目,如果在宿主机以 root 用户克隆项目,那么 PHP 容器将没有权限操作这个项目。

2021-11-11 @Young Kbt

# 项目访问

此时你访问你的服务器,会发现访问不了你克隆的项目,因为项目克隆在 /home/kbt 目录下,而这个目录目前仅仅是 PHP 脚本的根路径,不是非 PHP 脚本的路径,我们还需要修改 Nginx 的配置文件,让它跳转到这个目录。

vim /docker/openresty/conf/default.conf
1

假设我的项目名是 notes,则配置一个 localtion。

server {
    listen 80;
    server_name 你的服务器域名;
    
    location /notes {
    	root /home/kbt;		# /notes 会拼接到这后面
        index index.html;	# 默认访问 idnex.html 页面
	}
}
1
2
3
4
5
6
7
8
9

此时访问你的服务器 ip:port/notes,Nginx 就会去 /home/kbt 下找到 notes 目录,然后在这个目录下获取 idnex.html 页面返回,你就会成功看到你的项目页面。

# 自动化部署

我们使用的是 webhook 技术。

这里使用 PHP 脚本进行自动化部署,用到 PHP 的 shell_exec 函数,而开放 shell_exec 这个 PHP 函数是非常危险的,因此切记不要在生产环境开放这个函数,更加不能用 root 权限去执行 PHP。当然我们只是简单的个人博客,不是什么大公司,所以危害很低。

我们首先在 /home/kbt 目录下创建一个文件夹,专门存储 webhook 的 PHP 脚本。比如叫 deploy。

在 deploy 文件夹下创建 PHP 脚本

# Gitee脚本

<?php
 
$git = "git"; // 默认是用 Git 全局变量,有的环境可能要指明具体安装路径
$source = "Gitee";	// 项目仓库源,如 GitHub 或 Gitee
$branch = "gh-pages"; // 指定仓库分支,为空就是 master 分支
$logName = "logs/deploy"; // 本地日志名称,与当前 php 文件在同一目录,不需要加 .log
$savePath = "/home/kbt/deploy"; // 网站根目录,初次克隆确保目录为空
$gitSSHPath  = "git@gitee.com:kele-bingtang/notes-blog.git";// 代码仓库 SSH 地址
$password = "你在 WebHook 设置的密码"; // WebHook 设置的密码
$name  = "你的用户名";// 仓库用户名
$email = "你的邮箱";// 用户仓库邮箱
$isCloned = true;// 设置是否已经 clone 到本地。true:已经 clone,直接 pull,false:先 clone
$is_test = false;// 测试模式,无需密码。true 打开,平时 false 关闭

// 如果已经 clone 过,则直接拉去代码
if ($isCloned) {
    $requestBody = file_get_contents("php://input"); // 获取请求体的数据
    if (empty($requestBody) && empty($is_test)) {   // empty(var) 如果 var 为空或 false,则返回 true
        die('发送到仓库的请求失败');   // die 代表输出一条消息,并退出当前脚本
    }
 
    // 解析发过来的 JSON 信息
    $content = json_decode($requestBody, true);
    // 若是指定的分支且提交数大于 0,且密码正确
    if($content['password'] == $password || !empty($is_test)){
        if($content['total_commits_count'] > 0 || !empty($is_test)) {
            if ($content['ref'] == "refs/heads/$branch" || !$branch || !empty($is_test)) {
                $res_log = "------------------------- [PULL START] -------------------------" . PHP_EOL;  // PHP_EOL 是换行符
                $cmd = "rm -rf $savePath && $git clone -b $branch $gitSSHPath $savePath && echo '拉取项目并部署成功'";
                $result = shell_exec($cmd); // shell_exec 关键命令,执行拉取代码
                if(!empty($is_test)){
                    $res_log .= date('Y-m-d H:i:s') . '执行测试!'. PHP_EOL; // .= 代表追加到后面,不会覆盖前面
                }else{
                    $res_log .= "[" . date('Y-m-d H:i:s', time() + 8 * 60 * 60) . '] - 拉取 ' . $content['repository']['name'] . ' 仓库的 ' . $content['ref'] . ' 分支代码进行部署' . PHP_EOL;
                }
                if(!$result){
                    $result = "拉取项目失败" . PHP_EOL;
                }
                $res_log .= "[项目源] - $source" . PHP_EOL;
                $res_log .= "[执行命令] - " . $cmd . PHP_EOL;
                $res_log .= "[结果] - " . $result;
                $res_log .= "-------------------------- [PULL END] --------------------------" . PHP_EOL;
                $res_log .= PHP_EOL . PHP_EOL;
                file_put_contents($logName.".log", $res_log, FILE_APPEND); // 写入日志
                echo $result;
            }
        }
    } else {
        file_put_contents($logName.".log", '[Gitee] 密码错误!' . PHP_EOL, FILE_APPEND);
        echo '密码错误!';
    }
}else {		// 如果没有 clone,则先克隆代码
    $res = "[ CLONE START ----------------- ]".PHP_EOL;
    // 如果配置全局信息过,则会覆盖
    $res .= shell_exec("$git config --global user.email $email").PHP_EOL;
    $res .= shell_exec("$git config --global user.name $name").PHP_EOL;
    $res .= shell_exec("$git clone $gitSSHPath $savePath").PHP_EOL;
    $res .= "[ CLONE END ----------------- ]".PHP_EOL;
    file_put_contents($logName.".log", $res, FILE_APPEND); // 写入日志
}
?>
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
51
52
53
54
55
56
57
58
59
60
61

具体的内容我已经都注释好了,同时也会生成日志文件,第 39 - 44 都是输入日志的数据,你可以适当根据喜好修改。

相信我,你只需要修改第 3 - 11 行的数据为你的数据即可,我把需要的变量都拿出来了,其他不会出错。

29 行代码是核心命令,该脚本执行这个命令,去克隆仓库代码。所以这也是为什么 PHP 环境要安装 Git,不然无法克隆。

说明一下 29 行代码为什么要这样写,因为我们的博客是打包后生成的一大堆 html、css、js 文件,源码修改一点内容,打包后都会引起这些文件的位置、内容变化,所以我们需要把原来克隆的项目删除掉,再重新克隆。

有人想,能不能执行 git pull 命令,只拉取最新的代码,这里告诉你,我测试过了,哪怕我提交到仓库的打包项目没有任何修改, pull 下来的代码全是和原来的代码冲突,需要手动处理合并。想想就麻烦,所以只能先删除再克隆新的。

如果你 git pull 成功,请留言告诉我,可能我当初的方法不对。

# Github脚本

<?php
 
$git = "git"; // 默认是用 Git 全局变量,有的环境可能要指明具体安装路径
$source = "GitHub";	// 项目仓库源,如 GitHub 或 Gitee
$branch = "gh-pages"; // 指定仓库分支,为空就是 master 分支
$logName = "logs/deploy"; // 本地日志名称,与当前 php 文件在同一目录,不需要加 .log
$savePath = "/home/kbt/deploy"; // 网站根目录,初次克隆确保目录为空
$gitSSHPath  = "git@github.com:Kele-Bingtang/notes-blog.git";// 代码仓库 SSH 地址
$password = "你在 WebHook 设置的密码"; // WebHook 设置的密码
$name  = "你的用户名";// 仓库用户名
$email = "你的邮箱";// 用户仓库邮箱
$isCloned = true;// 设置是否已经 clone 到本地。true:已经 clone,直接 pull,false:先 clone
$is_test = false;// 测试模式,无需密码。true 打开,平时 false 关闭
    
// 如果已经 clone 过,则直接拉去代码
if ($isCloned) {
    $requestBody = file_get_contents("php://input"); // 获取请求体的数据
    if (empty($requestBody) && empty($is_test)) {   // empty(var) 如果 var 为空或 false,则返回 true
        die('发送到仓库的请求失败');   // die 代表输出一条消息,并退出当前脚本
    }
    // 获取 GitHub 的加密令牌 Secret
    $signature = $_SERVER['HTTP_X_HUB_SIGNATURE_256'];
    // GitHub 的令牌被 sha256 加密了,所以对 $secret 相同方式加密
    $encyptSecret = "sha256=" . hash_hmac('sha256', $requestBody, $secret);
    
    // 先对 URL 解码,再解析为 JSON 数组
    $content = json_decode(strstr(urldecode($requestBody),"{"),true);
    // 若是指定的分支且提交数大于 0,且密码正确
    if(strcmp($signature, $encyptSecret) == 0 || !empty($is_test)){  // strcmp 函数比较两个字符串
        if ($content['ref'] == "refs/heads/$branch" || !$branch || !empty($is_test)) {
            $res_log = "------------------------- [PULL START] -------------------------" . PHP_EOL;  // PHP_EOL 是换行符
            $cmd = "rm -rf $savePath && $git clone -b $branch $gitSSHPath $savePath && echo '拉取项目并部署成功'";
            $result = shell_exec($cmd); // shell_exec 关键命令,执行拉取代码
            if(!empty($is_test)){
                $res_log .= "[" . date('Y-m-d H:i:s') . '] 执行测试!'. PHP_EOL; // .= 代表追加到后面,不会覆盖前面
            }else{
                $res_log .= "[" . date('Y-m-d H:i:s', time() + 8 * 60 * 60) . '] - 拉取 ' . $content['repository']['name'] . ' 仓库的 ' . $content['ref'] . ' 分支代码进行部署' . PHP_EOL;
            }
            if(!$result){
                $result = "拉取项目失败" . PHP_EOL;
            }
            $res_log .= "[项目源] - $source" . PHP_EOL;
            $res_log .= "[执行命令] - " . $cmd . PHP_EOL;
            $res_log .= "[结果] - " . $result;
            $res_log .= "-------------------------- [PULL END] --------------------------" . PHP_EOL;
            $res_log .= PHP_EOL . PHP_EOL;
            file_put_contents($logName.".log", $res_log, FILE_APPEND); // 写入日志
            echo $result;
        }
    } else {
        file_put_contents($logName.".log", '[GitHub] 密码错误!' . PHP_EOL, FILE_APPEND);
        echo '密码错误!';
    }
}else {		// 如果没有 clone,则先克隆代码
    $res = "[ CLONE START ----------------- ]".PHP_EOL;
    // 如果配置全局信息过,则会覆盖
    $res .= shell_exec("$git config --global user.email $email").PHP_EOL;
    $res .= shell_exec("$git config --global user.name $name").PHP_EOL;
    $res .= shell_exec("$git clone $gitSSHPath $savePath").PHP_EOL;
    $res .= "[ CLONE END ----------------- ]".PHP_EOL;
    file_put_contents($logName.".log", $res, FILE_APPEND); // 写入日志
}
?>
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
51
52
53
54
55
56
57
58
59
60
61
62
63

GitHub 的脚本和 Gitee 脚本的内容不是一样的,首先 Github 返回的令牌是 sha256 加密的,而 Gitee 返回的是不加密的,所以我们需要对本地的令牌进行 sha256 加密,然后再进行两者的判定,是否相等。

其次 GitHub 返回的请求是经过编码过的,如这种 %7B%22ref%22%3A%22refs%2Fheads%2Fgh-pages%,所以我们获取后需要解码,请看 29 代码。

日志文件如下:

image-20211209193944109

# WebHook配置

讲了那么多,都不懂 WebHook 如何配置,现在开始配置。

Github配置

进入仓库里,然后 Github 点击 setting,找到 Webhooks,然后点击 Add webhook 进行配置。

image-20211209180621356

然后填写 PHP 脚本地址以及令牌。

image-20211209180942101

令牌要对应上我提供脚本的 $secre 变量值。

脚本访问地址:比如脚本放在 /home/kbt/ 下的 deploy 目录下,脚本名叫做 deploy.php,那么地址是 ip:port/deploy/deploy.php。

为什么地址没有 /home/kbt,因为上面我已经配置过了,这个目录是脚本的根路径,所以 ip:port/xxx.php 就是访问根目录下的 xxx.php,有目录则加上目录即可。

Gitee

其实就是中文版的 Github,所以位置完全一样

image-20211209181624596

image-20211209181909263

密码要对应上脚本的密码。

添加 WebHook 后,可以不断发送请求进行测试。

笔记

只需选择 push 事件触发即可,push 事件是指仓库的 任意分支 被 push 了都会触发,并非只有 master 分支触发。

2021-11-09 @Young Kbt

# 问答

Q1 - 能否总结本内容步骤?

  1. 安装 Docker,然后利用 Docker 安装 Nginx 和 PHP 镜像
  2. 创建 kbt 普通用户,加入 docker 组
  3. 启动 Nginx 容器,将配置文件目录、静态文件目录、日志文件目录拷贝出来,然后关闭 Nginx 容器
  4. Docker 创建网桥,给两个容器通信
  5. 启动 Nginx 容器,将拷贝的出来的三个目录和容器的三个目录进行挂载,以及与 kbt 用户的目录挂载
  6. 启动 PHP 容器,与 kbt 用户的目录挂载,PHP 容器的挂载目录和 kbt 用户的目录路径一致
  7. 在 Nginx 容器创建 kbt 普通用户和组,然后修改 nginx.conf 配置文件的 user 为 kbt,即 Nginx 的访问权限仅限于 kbt 的权限
  8. 修改挂载出来的配置文件目录里的 default.conf 文件,指定 PHP 脚本所在的根路径为 kbt 的用户目录
  9. 在 PHP 容器创建 kbt 普通用户和组,然后修改 www.conf 配置文件的 user 和 group 为 kbt,即 PHP 脚本运行权限仅限于 kbt 的权限
  10. 两个容器配置完后,按顺序重启 PHP、Nginx 容器
  11. 宿主机安装 Git,并配置 SSH 公钥给 Github 或者 Gitee。PHP 安装 Git,在 kbt 用户目录克隆项目
  12. 修改挂载出来的配置文件目录里的 default.conf 文件,添加 location,能访问克隆项目的目录
  13. 编写 PHP 脚本,然后在 Github 或者 Gitee 上开启 WebHook,配置脚本的 URL 访问地址和令牌、密码

Q2 - 为什么 Nginx 的静态文件目录、日志文件目录没有用到?

我要求启动 Nginx 容器的时候,将这些目录挂载出来,是因为这是实际生产开发需要的,不一定是本内容需要的,这里只是打好预防针,留个印象。

我当初部署的时候确实是把 PHP 脚本和克隆的项目放在静态文件目录下,但是不安全,这些目录是 root 用户管理的,所以我就创建了普通用户 kbt,将 PHP 脚本和克隆的项目放到该普通用户的目录下,即 /home/kbt。而放到该目录后,就要在 Nginx 和 PHP 创建 kbt 用户,并且挂载到 kbt 用户目录下,实现三者的同一个目录互通。如下图:

image-20211209190214547

Q3 - 一定要在 Nginx 和 PHP 容器创建普通用户 kbt 吗?

如果不创建普通用户 kbt,那么就需要一个目录实现上方图的三者互通,那么这个目录就属于 root 用户。


Q4 - 两个容器创建的 kbt 用户和宿主机的 kbt 用户一样吗?

不一样,但是我现在部署的时候就是这样创建的,我只把我成功的案例说出来。你也可以试试只在宿主机创建 kbt 用户,两个容器使用默认的用户(不创建 kbt 用户),我认为这样也可以。

是可以的,据我了解,在宿主机以普通用户 kbt 启动 Docker 容器,那么容器里虽然显示 root 用户,但是这个 root 用户的权限其实就是宿主机启动的用户权限,所以需要切换到普通用户,并给普通用户使用 Docker 的权限,然后启动。


Q5 - 不使用 Docker 如何操作?

其实熟悉 Docker 了,发现本内容 Docker 操作两个容器,其实就相当于在两台电脑分别安装 Nginx 和 PHP,然后进行操作,Docker 只是实现了两者在同一台电脑的互通(配置同一个网桥)。

不使用 Docker,会发现服务器部署非常方便,步骤大抵如下:

  1. 在服务器安装 Nginx 和 PHP 的环境

  2. 在服务器创建普通用户 kbt,生成 /home/kbt 路径

  3. 修改 Nginx 的配置文件和 PHP 的配置文件,将用户权限改为 kbt

  4. 修改 Nginx 的配置文件,实现于 PHP 的互通,以及设置 PHP 脚本的根路径

  5. 安装 Git,配置信息,生成 SSH 公钥给 Github 或 Gitee

  6. 编写 PHP 脚本,然后在 Github 或 Gitee 开启 WebHook,填写脚本的 URL 访问地址

此时会发现少了 Docker 的网桥配置,因为处于同一个服务器,本身就能通信。少了 Docker,也不需要在两个容器创建普通用户 kbt,只需要在宿主机创建即可。


Q6 - PHP 容器不安装 Git 行吗,只在宿主机安装?

不行的,因为 PHP 脚本执行后,使用的 git 命令是脚本所在的环境存在的,不安装即无法克隆项目代码,说其实的,如果曾经已经配置过宿主机的 SSH 公钥,则不需要在宿主机安装 Git。宿主机安装 Git 的目的仅仅是生成 SSH 公钥,而 PHP 容器才是使用 Git 相关的命令。


Q7 - PHP 容器不挂载出来可以吗?

可以的,但是不建议。Docker 挂载的目的就是实现宿主机和容器的数据同步,也就是说两个挂载目录,只要有一方发生修改,则另一方同步修改。而实际上,我们应该禁止容器的挂载目录能被手动修改数据,这样,只修改宿主机的挂载目录数据,安全大大提高的同时,容器的数据也会同步改变。

而如果不挂载出来,就必须进入到容器内部,创建脚本,修改脚本,违背了容器能修改数据的原则,再想想容器万一不小心删除了,则数据全没了。而服务器只有过期、被入侵。两者相比优势清晰明了。

编辑此页 (opens new window)
#本站
更新时间: 2023/10/23, 10:58:52
本站 - 网站部署
本站 - 评论模块

← 本站 - 网站部署 本站 - 评论模块→

最近更新
01
技术随笔 - Element Plus 修改包名 原创
11-02
02
Reactor - 扩展性
11-02
03
Reactor - 最佳实践
11-02
更多文章>
Theme by Vdoing | Copyright © 2021-2024 Young Kbt | blog
桂ICP备2021009994号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式