⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 juejin.im/post/5ade8a37f265da0b8d418dff 「邵磊」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注**微信公众号:【芋道源码】**有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言将得到认真回复。甚至不知道如何读源码也可以请教噢
  4. 新的源码解析文章实时收到通知。每周更新一篇左右
  5. 认真的源码交流微信群。

前言

在环境部署问题上,我们经历了3个阶段:传统安装、镜像恢复、自动发现注册+指令下达。目前镜像恢复后,启动虚拟机,一旦能ping通我们公司地址,就会自动注册这台机器(即使没有其他外网访问权限、也未开放任何对外端口),我们也就有了这台机器的管理权限,可批量群控下发指令。(第二阶段、第三阶段均为我自主设计。)

背景

我们是一家产品+定制化需求公司,项目做好之后会直接部署到客户服务器上。而客户很少选择云服务器,因为他们有自己的机房,部署前会提供给我们1-2台虚拟机,然后整个环境部署问题就交给我们了。

演变

第一阶段:传统安装

使用时间:?~2016年

  1. 需甲方提供windows或linux服务器远程连接方式(这里各个甲方提供都不一样,有堡垒机、vpn、直接定向开放端口、vpn+堡垒机等)非常复杂,只能case by case
  2. 远程到服务器上
  3. 上传数据库、jdk、tomcat各类安装包(受限带宽因素,往往很耗时)
  4. 安装安装数据库
  5. 安装jdk、tomcat、nginx(linux环境下,使用写好的sh脚本直接运行,依然比较耗时)
  6. 人工部署war包等 等

此方式缺点太多,往往需要3-5人天才能完成所有部署,但我们只有一位运维人员,所以当项目冲突时,极为被动。而且因为各个软件版本发生变动、甲方提供的虚拟机3个盘符、2个盘符,或者没有D盘(虽然可以通过计算机管理更改驱动器显示号,但可能导致其他软件无法运行)所以环境比较乱。

这种方式比较老,我也不介绍更多。当然,据我了解,目前还有一些小公司在沿用这种部署方式,所以在这里劝采用这种方式的公司尽快完成转型。

第二阶段:镜像恢复

使用时间:2016年~2017年

  1. 需甲方提供windows或linux服务器远程连接方式(这里各个甲方提供都不一样,有堡垒机、vpn、直接定向开放端口、vpn+堡垒机等)非常复杂,只能case by case
  2. 使用vm镜像恢复虚拟机并设置好ip(内含docker)
  3. 通过deploy模块一键部署war包

deloy模块

此方式,我们将第一阶段的2、3、4、5封装成vm虚拟机镜像、开发了deploy模块、抽取项目无状态。

这时我们对运维人员依赖大大减少,工作量大大减少至2-6小时。(这个阶段起,我们公司没有运维人员,进入DevOps时代。事实上,此阶段初我们运维人员离职,使得我不得不加快设计)

第三阶段:自动发现注册+指令下达

使用时间:2017年~2018年

  1. 甲方使用我们vm镜像恢复并设置好ip,保证能ping通我们公司地址
  2. 自动发现注册+指令下达
  3. 通过deploy模块一键部署war包

此阶段,我们部署耗时在5-10分钟,而且我们不再需要甲方提供远程,我们还可以批量管理所有机器,不仅满足了此时的需求,并为后面扩展做了铺垫。

具体技术

这里主要讲二、三两个阶段

因为传统方式缺点特别多,所以在我向领导介绍方案后,领导很感兴趣,很快就安排我着手去干。为了提高效率,期间选型多款工具或框架组成的方案,本文只介绍最终选型的设计。

frp

frp是一款内网穿透软件,可以使得没有外网ip的机器暴露在外网里,但本文利用它将一台内网机器端口暴露在另外一个内网中的特性。

安装frp服务端

选择一台内网机器比如172.0.0.2,需临时保证这台服务器走公网固定ip线路

wget --no-check-certificate https://raw.githubusercontent.com/clangcn/onekey-install-shell/master/frps/install-frps.sh -O ./install-frps.sh
chmod 700 ./install-frps.sh
./install-frps.sh install

全部参数都有默认值,直接回车就是输入默认值:

Please input frps bind_port [1-65535](Default Server Port: 5443): #输入frp提供服务的端口,用于服务器端和客户端通信,默认即可
Please input frps vhost_http_port [1-65535](Default vhost_http_port: 80): #输入frp进行http穿透的http服务端口,建议不用默认
Please input frps vhost_https_port [1-65535](Default vhost_https_port: 443): #输入frp进行https穿透的https服务端口,建议不用默认
Please input frps dashboard_port [1-65535](Default dashboard_port: 6443):#输入frp的控制台服务端口,用于查看frp工作状态,默认即可
Please input dashboard_user (Default: admin):#登录控制台的用户名,默认即可
Please input dashboard_pwd (Default: kpkpM7VZ):#登录控制台的密码,如果记不住默认的建议修改
Please input privilege_token (Default: 9m2UAOWa6hx5Eise):#输入frp服务器和客户端通信的密码,默认是随机生成的,默认即可
Please input frps max_pool_count [1-200](Default max_pool_count: 50):#设置每个代理可以创建的连接池上限,默认50
##### Please select log_level #####
1: info
2: warn
3: error
4: debug
#####################################################
Enter your choice (1, 2, 3, 4 or exit. default [1]): 默认即可
Please input frps log_max_days [1-30](Default log_max_days: 3 day):
##### Please select log_file #####
1: enable
2: disable
#####################################################
Enter your choice (1, 2 or exit. default [1]):默认即可

至此frp服务端就搭建好了

客户端

这里我们以linux为例

打开http://diannaobos.iok.la:81/frp/frp-v0.14.0/

下载frp_0.14.0_linux_amd64.tar.gz文件,只保留frpc开头的文件(frp客户端)

以frp文件夹形式解压到linux的home目录

编写reg.sh脚本

reg.sh也放在linux的home目录

UUID=$(cat /sys/class/dmi/id/product_uuid)
wget -O frpc.ini http://114.114.114.114/frp.php?file=$UUID;
a=`du -s frpc.ini | awk '{print $1}'`
if [ $a -lt 1 ]
then
echo "none"
else
echo "action"
pkill frpc
sleep 2s
rm -rf ~/frp/frpc.ini
cp frpc.ini ~/frp/frpc.ini
~/frp/./frp.sh
fi

其中UUID为服务器唯一标识,即使vm虚拟机镜像相同,但uuid不会相同。

其中114.114.114.114为公司对外注册中心

编写crontab

crontab -e
*/5 * * * * ~/reg.sh

每隔5分钟执行一次,意思是每隔5分钟去注册一次或者说是拉取一次变更请求,当服务端配置不改变时不会重启服务。

frp开机自启

linux

chmod +x ~/frp/frp.sh
vi /etc/rc.d/rc.local
#文件底部追加
bash ~/frp/frp.sh

chmod +x /etc/rc.d/rc.local
#重启即可

frp.php简易版内容如下

<?php
$filename=$_GET['file'].'.ini';
$filename='frp/'.$filename;

if(!file_exists($filename)){
file_put_contents($filename,"");
file_put_contents($filename.'.update',$_SERVER['REMOTE_ADDR']);
}else{
if (!file_exists($filename.'.update')){
$str = file_get_contents($filename);
echo $str;
file_put_contents($filename.'.update',$_SERVER['REMOTE_ADDR']);
}
}
?>

当有机器注册时,frp文件夹下会有id对应的文件名,我们只需要在.ini中写入配置,再删除.update文件即可,待服务端收到frp新配置后,会自动再创建一个.update文件,并且将ip写入.update文件。

.ini例子

[common]
server_addr = 114.114.114.114
server_port = 5443
privilege_token =密钥

[webserver]
type = tcp
local_ip = 127.0.0.1
local_port = 22
use_encryption = false
use_compression = false
remote_port = 7001


[a-web]
type = http
local_ip = 127.0.0.1
local_port = 80
use_encryption = false
use_compression = true
custom_domains = a.a.com

common为公共部分

webserver是将本地22端口使用隧道技术穿透到公司的172.0.0.2机器里

内网机器远程只需访问172.0.0.2的7001端口

a-web是本机80端口在公司内网中的直接访问url:a.a.com

通过frp管理后台,可以实时查看到各个机器连接情况。

至此,我们可以远程机器、访问该机器80端口,理论上可以访问该机器所有端口,如新增端口穿透,只需要去修改.ini,这是一简易版的介绍。

再接入ansible即可远程群控。

ansible

ansible 是一款自动化运维工具,具体使用可参考我另外一篇博文《自动化运维工具ansible的实践》

外网映射

假设公司外网为114.114.114.114 需将114.114.114.114的5443端口映射到172.0.0.2的5443上,其他端口均不要映射,

docker

前两年docker很火,DevOps很火,所以我们选择了docker,以便我们docker镜像快速部署我们系统。可参考我另外一篇博文《我是如何重构整个研发项目,促进自动化运维DevOps的落地?》

Portainer

可参考我的另外一篇博文《Docker的web端管理平台对比(DockerUI 、Shipyard、Portainer、Daocloud)》

deploy

deploy为我们自研,底层原理可参考《java web项目war包自动升级部署方案》

总结

本文主要讲利用frp内网穿透、构建隧道的技术实现对无外网、无端口机器的运维部署;利用ansible工具实现群控;利用docker进行快速部署;通过自研deploy进行版本控制等。

该套方案极大的节省了我们的运维成本,使我们这样的小公司跑步进入了一个无运维人员、DevOps时代。

如果你有类似场景,希望本文对你有所帮助。

文章目录
  1. 1. 前言
  2. 2. 背景
  3. 3. 演变
    1. 3.1. 第一阶段:传统安装
    2. 3.2. 第二阶段:镜像恢复
    3. 3.3. 第三阶段:自动发现注册+指令下达
  4. 4. 具体技术
    1. 4.1. frp
      1. 4.1.1. 安装frp服务端
      2. 4.1.2. 客户端
      3. 4.1.3. 编写reg.sh脚本
      4. 4.1.4. 编写crontab
      5. 4.1.5. frp开机自启
      6. 4.1.6. frp.php简易版内容如下
      7. 4.1.7. .ini例子
    2. 4.2. ansible
    3. 4.3. 外网映射
    4. 4.4. docker
    5. 4.5. Portainer
    6. 4.6. deploy
    7. 4.7. 总结