遵循小题大做原则,除了将 Hexo 属于在 Docker 中,还将实现,Hexo 托管于代码管理平台,当我们使用 git 发起 push 操作之后,容器可自动部署生成新的 Hexo 博客页面。此番折腾下来,将涉及到 Docker、Nginx、Hexo、pm2、Linux 脚本编写等方面知识。
先将域名解析指向 VPS,然后在进行下面的操作
安装 Docker
Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,然后发布到任何流行的 Linux 或 Windows 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口。
以系统为 CentOS Linux release 8.2.2004 (Core) 的 VPS 为例,安装 Docker
官网教程: https://docs.docker.com/engine/install/
卸载旧版本 不管有没有,先运行一遍就完事了
1 2 3 4 5 6 7 8 sudo yum remove docker \ docker-client \ docker-client-latest \ docker-common \ docker-latest \ docker-latest-logrotate \ docker-logrotate \ docker-engine
安装新版本 接着先安装 yum-utils 软件包,之后设置稳定版仓库
1 2 3 4 5 $ sudo yum install -y yum-utils $ sudo yum-config-manager \ --add-repo \ https://download.docker.com/linux/centos/docker-ce.repo
安装 Docker
1 $ sudo yum install docker-ce docker-ce-cli containerd.io
测试 Docker 这时 Docker 已经安装成功了,为了验证是否正确的安装了 Docker 可以通过下面命令测试一下
1 $ sudo docker run hello-world
如果可以输出参考信息,不报错的话,就表示安装成功了
Docker 信息
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 Client: Docker Engine - Community Version: 19.03.14 API version: 1.40 Go version: go1.13.15 Git commit: 5eb3275d40 Built: Tue Dec 1 19:19:47 2020 OS/Arch: linux/amd64 Experimental: false Server: Docker Engine - Community Engine: Version: 19.03.14 API version: 1.40 (minimum version 1.12) Go version: go1.13.15 Git commit: 5eb3275d40 Built: Tue Dec 1 19:18:24 2020 OS/Arch: linux/amd64 Experimental: false containerd: Version: 1.3.9 GitCommit: ea765aba0d05254012b0b9e595e995c09186427f runc: Version: 1.0.0-rc10 GitCommit: dc9208a3303feef5b3839f4323d9beb36df0a9dd docker-init: Version: 0.18.0 GitCommit: fec3683
安装 Nginx
Nginx 是一款轻量级的 Web 服务器 / 反向代理服务器及电子邮件(IMAP/POP3)代理服务器,在 BSD-like 协议下发行。其特点是占有内存少,并发能力强,事实上 Nginx 的并发能力在同类型的网页服务器中表现较好。
Nginx 在这里主要作用就反向代理,已经 Https 证书配置
Docker_Hub: https://hub.docker.com/_/nginx
Docker Hub 中包含了 Nginx 镜像 ,直接拉取下来,安装即可。但由于需要更改 Nginx 的配置文件,所以还需要创建一个容器里的 nginx.conf 和 VPS 的 nginx.conf 文件映射,如果要使用 Https 协议,也最好简历一个映射文件夹,方便管理证书
文件夹映射 在 /home 目录创建文件
1 $ mkdir /home/nginx /home/nginx/config /home/nginx/logs/ /home/nginx/ssl
安装 Nginx 1 $ docker run -p 443:443 -p 80:80 --name nginx -v /home/nginx/config/nginx.conf:/etc/nginx/nginx.conf -v /home/nginx/logs:/var/log/nginx -v /home/nginx/ssl:/etc/nginx/ssl -v /home/nginx/dhparam.pem:/etc/nginx/dhparam.pem -d nginx
安装 NODE 接下来,这个是重点了,这里将实现自动部署构建,之所以使用 node ,而不是直接使用 Hexo 镜像,是因为需要通过 npm 安装 pm2,管理 hexo,已经自动化部署脚本,所以直接使用 node 镜像了
同样,我们需要有一个映射目录,这样方便管理
安装容器 6666 端口,用来监听 WebHook,4000 端口,用来 Hexo 运行,并给此容器起名为 blog
1 $ docker run -itd --name blog -p 4000:4000 -p6666:6666 -v /home/blog:/etc/blog node
安装 hexo 和 pm2 首先进入运行的容器:
1 $ docerk exec -it blog /bin/bash
然后直接采用全局安装的方式,安装 hexo 和 pm2
1 $ npm install -g hexo-cli pm2
Gitee 准备 我建议,新建一个私人仓库,用来存放 Hexo,我使用的是 Gitee 平台,创建过程就省略了
接着在 blog 容器里,运行下面命令,并敲三次回车,生成 SSH 公钥
xxxxx@xxxxx.com 改为你自己的邮箱
1 $ ssh-keygen -t rsa -C "xxxxx@xxxxx.com"
查看公钥
将生成的公钥复制粘贴到 Gitee 平台的个人账户里
打开这个链接 https://gitee.com/profile/sshkeys 将公钥复制进去,保存即可
WebHook URL 地址,自己填一个地址,然后密码也自己输入一个,最后点击添加
再次进入容器,将项目 GiteeWebHook 复制到 blog 容器里,并安装服务
1 2 3 4 $ cd /etc/blog $ git clone https://gitee.com/geshuyong/GiteeWebHook.git $ cd GiteeWebHook $ npm install
修改 GiteeWebHook 项目配置文件
这里因为容器里没有装 vi 或 vim,可以装一个,也可以新建一个远程终端,在 VPS 里操作,我就新建一个终端,在 VPS 里操作了
以下命令在 VPS 中操作
1 2 $ cd /home/blog/GiteeWebHook $ vim config.js
改为下面配置并保存
1 2 3 4 5 6 module.exports = { os: "linux" , path: "/auto_build" , secret: "123456" , port: 6666 } ;
修改自动部署脚本
1 2 $ cd /home/blog/GiteeWebHook/cmd $ vim WEB-Server.sh
改为下面配置并保存
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #! /bin/bash SITE_PATH='/etc/blog/hexo' WEB_USER='root' WEB_USERGROUP='root' echo "开始部署" echo "停止hexo" pm2 stop blog pm2 delete blog echo "拉取最新代码" cd /etc/blog/hexoecho "当前工作目录" pwd git reset --hard git clean -df git pull origin master echo "构建项目" npm install hexo g echo "运行hexo" pm2 start --name blog hexo -- s echo "部署结束"
修改 index.js
1 $ vim /home/blog/GiteeWebHook/index.js
找到里面的 handler.on 方法改为下面代码
1 2 3 4 5 6 7 8 handler.on('Push Hook', function (event) { logger.info('Received a push event for %s to %s', event.payload.repository.name, event.payload.ref ); logger.info('执行脚本') linux_run_cmd('sh', ['./cmd/WEB-Server.sh']);//需要执行的脚本位置 });
到此 WebHook 的准备工作完成了
安装 Hexo 博客 电脑需安装 Node.js,安装完成之后,打开 CMD 进入到 D 盘,运行下面命令
1 2 $ npm install hexo-cli -g $ hexo init blog
进入到 blog 文件夹,删除里面的.git 文件夹,这样才能关联上面我们的私人的仓库
1 2 3 4 5 $ git init $ git add . $ git commit -m "first commit" $ git remote add origin 仓库地址 $ git push origin master
PM2
PM2 是具有内置负载平衡器的 Node.js 应用程序的生产过程管理器。它使您可以使应用程序永远保持活动状态,无需停机即可重新加载它们,并简化常见的系统管理任务
我们使用 PM2 来管理自动化部署脚本,以及监听 Gitee 的发送过来的 Push 通知
启动监听脚本 以下操作需要进入到 blog 容器里,
1 $ docker exec -it blog /binb/bash
进入之后,启动监听脚本
1 2 $ cd /etc/blog/GiteeWebHook $ pm2 start index.js
克隆 Gitee 仓库
这步很重要,不能跳过
克隆前面的私人仓库
1 2 3 $ mkdir /etc/blog/hexo $ cd /etc/blog/hexo $ git clone 仓库地址
到这里 PM2 的步骤完成了,在脚本里会自动创建 hexo 运行服务,不用手动启动
修改反向代理 此步骤在 VPS 中操作
1 2 $ cd /home/nginx/config $ vim nginx.conf
需要注意的是,在反向代理的配置 proxy_pass ,可以通过下面命令,查看 Docker 容器的 IP 地址,将这个地址,替换 proxy_pass 后面的地址
nginx.conf 的配置,需要在 vps 的 /home/nginx/ssl 目录存放 SSL 证书要然会报错,下面是我的 Nginx 配置
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 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 user www-data; pid /run/nginx.pid; worker_processes auto; worker_rlimit_nofile 65535; events { multi_accept on; worker_connections 65535; } http { charset utf-8; sendfile on; tcp_nopush on; tcp_nodelay on; server_tokens off; log_not_found off; types_hash_max_size 2048; client_max_body_size 16M; include mime.types; default_type application/octet-stream; access_log /var/log/nginx/jenkins.liaocp.cn_access.log; error_log /var/log/nginx/jenkins.liaocp.cn_error.log warn; ssl_session_timeout 1d; ssl_session_cache shared:SSL:10m; ssl_session_tickets off; ssl_dhparam /etc/nginx/dhparam.pem; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; ssl_stapling on; ssl_stapling_verify on; resolver 1.1.1.1 1.0.0.1 8.8.8.8 8.8.4.4 208.67.222.222 208.67.220.220 valid=60s; resolver_timeout 2s; include /etc/nginx/conf.d/*.conf; server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name jenkins.liaocp.cn; ssl_certificate /etc/nginx/ssl/jenkins.liaocp.cn.pem; ssl_certificate_key /etc/nginx/ssl/jenkins.liaocp.cn.key; add_header X-Frame-Options "SAMEORIGIN" always; add_header X-XSS-Protection "1; mode=block" always; add_header X-Content-Type-Options "nosniff" always; add_header Referrer-Policy "no-referrer-when-downgrade" always; add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; location ~ /\.(?!well-known) { deny all; } location / { proxy_pass http://172.17.0.2:4000; proxy_http_version 1.1; proxy_cache_bypass $http_upgrade ; proxy_set_header Upgrade $http_upgrade ; proxy_set_header Connection "upgrade" ; proxy_set_header Host $host ; proxy_set_header X-Real-IP $remote_addr ; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for ; proxy_set_header X-Forwarded-Proto $scheme ; proxy_set_header X-Forwarded-Host $host ; proxy_set_header X-Forwarded-Port $server_port ; proxy_connect_timeout 60s; proxy_send_timeout 60s; proxy_read_timeout 60s; } location = /favicon.ico { log_not_found off; access_log off; } location = /robots.txt { log_not_found off; access_log off; } gzip on; gzip_vary on; gzip_proxied any; gzip_comp_level 6; gzip_types text/plain text/css text/xml application/json application/javascript application/rss+xml application/atom+xml image/svg+xml; } server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name *.jenkins.liaocp.cn; ssl_certificate /etc/nginx/ssl/jenkins.liaocp.cn.pem; ssl_certificate_key /etc/nginx/ssl/jenkins.liaocp.cn.key; return 301 https://jenkins.liaocp.cn$request_uri ; } server { listen 80; listen [::]:80; server_name .jenkins.liaocp.cn; return 301 https://jenkins.liaocp.cn$request_uri ; } server { listen 80; listen [::]:80; server_name jenkins.liaocp.cn; return 301 https://jenkins.liaocp.cn$request_uri ; } server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name www.liaocp.cn; ssl_certificate /etc/nginx/ssl/www.liaocp.cn.pem; ssl_certificate_key /etc/nginx/ssl/www.liaocp.cn.key; add_header X-Frame-Options "SAMEORIGIN" always; add_header X-XSS-Protection "1; mode=block" always; add_header X-Content-Type-Options "nosniff" always; add_header Referrer-Policy "no-referrer-when-downgrade" always; add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; location ~ /\.(?!well-known) { deny all; } location / { proxy_pass http://172.17.0.2:4000; proxy_http_version 1.1; proxy_cache_bypass $http_upgrade ; proxy_set_header Upgrade $http_upgrade ; proxy_set_header Connection "upgrade" ; proxy_set_header Host $host ; proxy_set_header X-Real-IP $remote_addr ; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for ; proxy_set_header X-Forwarded-Proto $scheme ; proxy_set_header X-Forwarded-Host $host ; proxy_set_header X-Forwarded-Port $server_port ; proxy_connect_timeout 60s; proxy_send_timeout 60s; proxy_read_timeout 60s; } location /auto_build { proxy_pass http://172.17.0.2:6666; proxy_http_version 1.1; proxy_cache_bypass $http_upgrade ; proxy_set_header Upgrade $http_upgrade ; proxy_set_header Connection "upgrade" ; proxy_set_header Host $host ; proxy_set_header X-Real-IP $remote_addr ; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for ; proxy_set_header X-Forwarded-Proto $scheme ; proxy_set_header X-Forwarded-Host $host ; proxy_set_header X-Forwarded-Port $server_port ; proxy_connect_timeout 60s; proxy_send_timeout 60s; proxy_read_timeout 60s; } location = /favicon.ico { log_not_found off; access_log off; } location = /robots.txt { log_not_found off; access_log off; } gzip on; gzip_vary on; gzip_proxied any; gzip_comp_level 6; gzip_types text/plain text/css text/xml application/json application/javascript application/rss+xml application/atom+xml image/svg+xml; } server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name *.www.liaocp.cn; ssl_certificate /etc/nginx/ssl/www.liaocp.cn.pem; ssl_certificate_key /etc/nginx/ssl/www.liaocp.cn.key; return 301 https://www.liaocp.cn$request_uri ; } server { listen 80; listen [::]:80; server_name .www.liaocp.cn; return 301 https://www.liaocp.cn$request_uri ; } server { listen 80; listen [::]:80; server_name www.liaocp.cn; return 301 https://www.liaocp.cn$request_uri ; } }
最后 重启下 Nginx 容器,就可以了,当给私人仓库 push 操作时候,VPS 就会自动执行部署脚本,完成 Heox 页面生成并启动