Ngrok 内网穿透部署指南

自建内网穿透隧道,安全高效实现公网访问

Ngrok 内网穿透部署方案

📦 项目地址

代码仓库: git@github.com:blowizer/ngrok.git

git clone git@github.com:blowizer/ngrok.git
cd ngrok

🎯 场景使用

实现 ngrok 公网转发访问,用于内网穿透,将本地服务暴露到公网。

🖥️ 服务器环境准备

1. Ubuntu 系统依赖安装

apt-get -y install zlib-devel openssl-devel perl hg cpio expat-devel gettext-devel curl curl-devel perl-ExtUtils-MakeMaker hg wget gcc gcc-c++ git

2. Go 语言环境安装

推荐版本: go version go1.16.3 linux/amd64

# 删除旧版本 golang 依赖包(如果存在)
rpm -qa|grep golang|xargs rpm -e

# 下载安装包
wget https://golang.org/dl/go1.16.3.linux-amd64.tar.gz
tar -C /usr/local -xzf go1.16.3.linux-amd64.tar.gz

# 配置环境变量
vim /etc/profile
# 在文件末尾添加以下内容:
# #go lang
# export GOROOT=/usr/local/go
# export PATH=$PATH:$GOROOT/bin

# 使配置生效
source /etc/profile

# 检测是否安装成功
go version

3. 防火墙端口配置

vim /etc/sysconfig/iptables
# 添加以下内容:
# -A INPUT -m state --state NEW -m tcp -p tcp --dport 4443 -j ACCEPT
# -A INPUT -m state --state NEW -m tcp -p tcp --dport 8080 -j ACCEPT
# -A INPUT -m state --state NEW -m tcp -p tcp --dport 8081 -j ACCEPT
# -A INPUT -m state --state NEW -m tcp -p tcp --dport 2222 -j ACCEPT

# 重新加载防火墙规则
/etc/init.d/iptables reload
/etc/init.d/iptables restart

# 查看开放的端口
iptables -nL

注意: 如果使用云服务器(如阿里云),还需要在安全组中开放相应端口。

Kubernetes 集群部署 - etcd 安装与配置

etcd 作为 Kubernetes 的数据存储核心,稳定可靠的部署至关重要

📋 概述

etcd 是 Kubernetes 集群的核心数据存储组件,负责存储集群的所有配置数据、状态信息和元数据。本文档提供 etcd 集群的完整安装、配置和部署方案。

架构说明

  • 集群模式: 建议至少 3 个节点(奇数个节点,避免脑裂)
  • 数据目录: /var/lib/etcd
  • 配置文件: /etc/etcd/etcd.conf
  • 服务文件: /etc/systemd/system/etcd.service
  • 端口:
    • 2379: 客户端通信端口
    • 2380: 节点间通信端口

🔧 环境准备

节点信息配置

根据实际环境修改以下节点信息:

# 节点格式: 主机名:IP地址:etcd节点名
NODES=(
    "k8s-master-01:192.168.1.100:etcd-01"
    "k8s-node-01:192.168.1.101:etcd-02"
    "k8s-master-02:192.168.1.102:etcd-03"
)

系统要求

  • 操作系统: CentOS 7+ / Ubuntu 18.04+
  • 内存: 至少 2GB(推荐 4GB+)
  • 磁盘: 至少 20GB 可用空间(SSD 推荐)
  • 网络: 节点间网络延迟 < 10ms

📦 安装 etcd

步骤 1: 下载 etcd 二进制文件

#!/bin/bash
# install-etcd.sh - etcd 安装脚本

set -e

ETCD_VERSION="v3.5.9"  # 根据 K8s 版本选择兼容的 etcd 版本
INSTALL_DIR="/usr/local/bin"
DATA_DIR="/var/lib/etcd"
CONFIG_DIR="/etc/etcd"

# 交互式确认
read -p "是否执行 etcd 安装步骤?(y/n) " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
    echo "已跳过 etcd 安装"
    exit 0
fi

echo "=== 开始安装 etcd ${ETCD_VERSION} ==="

# 创建必要目录
sudo mkdir -p ${INSTALL_DIR}
sudo mkdir -p ${DATA_DIR}
sudo mkdir -p ${CONFIG_DIR}

# 下载 etcd
cd /tmp
wget https://github.com/etcd-io/etcd/releases/download/${ETCD_VERSION}/etcd-${ETCD_VERSION}-linux-amd64.tar.gz

# 解压并安装
tar -xzf etcd-${ETCD_VERSION}-linux-amd64.tar.gz
sudo cp etcd-${ETCD_VERSION}-linux-amd64/etcd* ${INSTALL_DIR}/
sudo chmod +x ${INSTALL_DIR}/etcd*

# 验证安装
${INSTALL_DIR}/etcd --version
${INSTALL_DIR}/etcdctl version

echo "✓ etcd 安装完成"

步骤 2: 配置 etcd 集群

#!/bin/bash
# configure-etcd.sh - etcd 集群配置脚本

set -e

NODES=(
    "k8s-master-01:192.168.1.100:etcd-01"
    "k8s-node-01:192.168.1.101:etcd-02"
    "k8s-master-02:192.168.1.102:etcd-03"
)

ETCD_VERSION="v3.5.9"
INSTALL_DIR="/usr/local/bin"
DATA_DIR="/var/lib/etcd"
CONFIG_DIR="/etc/etcd"
CERT_DIR="/etc/etcd/ssl"

# 交互式确认
read -p "是否执行 etcd 集群配置?(y/n) " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
    echo "已跳过 etcd 配置"
    exit 0
fi

echo "=== 开始配置 etcd 集群 ==="

# 生成集群初始成员列表
INITIAL_CLUSTER=""
for NODE_INFO in "${NODES[@]}"; do
    IFS=':' read -r HOSTNAME NODE_IP ETCD_NAME <<< "$NODE_INFO"
    INITIAL_CLUSTER+="${ETCD_NAME}=https://${NODE_IP}:2380,"
done
INITIAL_CLUSTER=${INITIAL_CLUSTER%,}

echo "集群成员列表: ${INITIAL_CLUSTER}"

# 为每个节点配置 etcd
for NODE_INFO in "${NODES[@]}"; do
    IFS=':' read -r HOSTNAME NODE_IP ETCD_NAME <<< "$NODE_INFO"
    
    echo "配置节点: ${HOSTNAME} (${ETCD_NAME})"
    
    ssh root@${NODE_IP} << EOF
        # 创建目录
        mkdir -p ${DATA_DIR}
        mkdir -p ${CONFIG_DIR}
        mkdir -p ${CERT_DIR}
        
        # 创建 etcd 配置文件
        cat > ${CONFIG_DIR}/etcd.conf << EOC
# 节点名称
ETCD_NAME=${ETCD_NAME}
# 数据目录
ETCD_DATA_DIR=${DATA_DIR}
# 监听客户端请求的地址
ETCD_LISTEN_CLIENT_URLS=https://${NODE_IP}:2379,https://127.0.0.1:2379
# 监听对等节点请求的地址
ETCD_LISTEN_PEER_URLS=https://${NODE_IP}:2380
# 客户端访问地址
ETCD_INITIAL_ADVERTISE_PEER_URLS=https://${NODE_IP}:2380
ETCD_ADVERTISE_CLIENT_URLS=https://${NODE_IP}:2379
# 初始集群成员列表
ETCD_INITIAL_CLUSTER=${INITIAL_CLUSTER}
# 集群状态(new 表示新集群,existing 表示加入已有集群)
ETCD_INITIAL_CLUSTER_STATE=new
# 集群 token
ETCD_INITIAL_CLUSTER_TOKEN=k8s-etcd-cluster
# 客户端证书配置(如果使用 TLS)
ETCD_CLIENT_CERT_AUTH=true
ETCD_CERT_FILE=${CERT_DIR}/server.crt
ETCD_KEY_FILE=${CERT_DIR}/server.key
ETCD_TRUSTED_CA_FILE=${CERT_DIR}/ca.crt
# 对等节点证书配置
ETCD_PEER_CLIENT_CERT_AUTH=true
ETCD_PEER_CERT_FILE=${CERT_DIR}/peer.crt
ETCD_PEER_KEY_FILE=${CERT_DIR}/peer.key
ETCD_PEER_TRUSTED_CA_FILE=${CERT_DIR}/ca.crt
EOC
        
        # 设置权限
        chmod 644 ${CONFIG_DIR}/etcd.conf
        chown -R etcd:etcd ${DATA_DIR} ${CONFIG_DIR} 2>/dev/null || true
        
        echo "✓ ${HOSTNAME} 配置完成"
EOF
done

echo "✓ etcd 集群配置完成"

步骤 3: 创建 systemd 服务

#!/bin/bash
# setup-etcd-service.sh - 创建 etcd systemd 服务

set -e

NODES=(
    "k8s-master-01:192.168.1.100:etcd-01"
    "k8s-node-01:192.168.1.101:etcd-02"
    "k8s-master-02:192.168.1.102:etcd-03"
)

INSTALL_DIR="/usr/local/bin"
CONFIG_DIR="/etc/etcd"

# 交互式确认
read -p "是否创建 etcd systemd 服务?(y/n) " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
    echo "已跳过服务创建"
    exit 0
fi

echo "=== 创建 etcd systemd 服务 ==="

for NODE_INFO in "${NODES[@]}"; do
    IFS=':' read -r HOSTNAME NODE_IP ETCD_NAME <<< "$NODE_INFO"
    
    echo "为 ${HOSTNAME} 创建服务..."
    
    ssh root@${NODE_IP} << EOF
        cat > /etc/systemd/system/etcd.service << EOS
[Unit]
Description=Etcd Server
Documentation=https://github.com/coreos/etcd
After=network.target
Wants=network-online.target

[Service]
Type=notify
EnvironmentFile=-${CONFIG_DIR}/etcd.conf
ExecStart=${INSTALL_DIR}/etcd
Restart=on-failure
RestartSec=10
LimitNOFILE=65536
# 关键:增加启动超时时间,避免集群启动时超时
TimeoutStartSec=120

[Install]
WantedBy=multi-user.target
EOS
        
        # 重新加载 systemd
        systemctl daemon-reload
        systemctl enable etcd
        
        echo "✓ ${HOSTNAME} 服务创建完成"
EOF
done

echo "✓ etcd 服务创建完成"

🚀 启动 etcd 集群

步骤 4: 启动集群

#!/bin/bash
# start-etcd-cluster.sh - 启动 etcd 集群

set -e

NODES=(
    "k8s-master-01:192.168.1.100:etcd-01"
    "k8s-node-01:192.168.1.101:etcd-02"
    "k8s-master-02:192.168.1.102:etcd-03"
)

# 交互式确认
read -p "是否启动 etcd 集群?(y/n) " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
    echo "已跳过集群启动"
    exit 0
fi

echo "=== 启动 etcd 集群 ==="

# 按顺序启动节点(避免同时启动导致的问题)
for i in "${!NODES[@]}"; do
    NODE_INFO="${NODES[$i]}"
    IFS=':' read -r HOSTNAME NODE_IP ETCD_NAME <<< "$NODE_INFO"
    
    echo "启动节点 ${HOSTNAME} (第 $((i+1)) 个节点)..."
    
    ssh root@${NODE_IP} "systemctl start etcd"
    
    # 等待节点启动
    sleep 5
    
    # 检查节点状态
    if ssh root@${NODE_IP} "systemctl is-active --quiet etcd"; then
        echo "✓ ${HOSTNAME} 启动成功"
    else
        echo "✗ ${HOSTNAME} 启动失败,请检查日志: journalctl -u etcd -n 50"
    fi
done

echo "=== 检查集群状态 ==="
# 使用第一个节点检查集群状态
FIRST_NODE="${NODES[0]}"
IFS=':' read -r FIRST_HOST FIRST_IP FIRST_NAME <<< "$FIRST_NODE"

ssh root@${FIRST_IP} "/usr/local/bin/etcdctl --endpoints=https://127.0.0.1:2379 --cacert=/etc/etcd/ssl/ca.crt --cert=/etc/etcd/ssl/server.crt --key=/etc/etcd/ssl/server.key endpoint health" || echo "注意: 如果使用 TLS,请确保证书已正确配置"

echo "✓ etcd 集群启动完成"

✅ 验证和监控

检查集群状态

# 检查服务状态
systemctl status etcd

# 查看日志
journalctl -u etcd -f

# 检查集群健康(如果使用 TLS)
etcdctl --endpoints=https://127.0.0.1:2379 \
    --cacert=/etc/etcd/ssl/ca.crt \
    --cert=/etc/etcd/ssl/server.crt \
    --key=/etc/etcd/ssl/server.key \
    endpoint health

# 查看集群成员
etcdctl --endpoints=https://127.0.0.1:2379 \
    --cacert=/etc/etcd/ssl/ca.crt \
    --cert=/etc/etcd/ssl/server.crt \
    --key=/etc/etcd/ssl/server.key \
    member list

常用维护命令

# 备份 etcd 数据
etcdctl snapshot save /backup/etcd-snapshot-$(date +%Y%m%d).db

# 恢复 etcd 数据
etcdctl snapshot restore /backup/etcd-snapshot-20231229.db \
    --data-dir=/var/lib/etcd-restore

# 查看集群统计信息
etcdctl endpoint status --write-out=table

📝 注意事项

  1. 证书配置: 如果使用 TLS,确保所有节点的证书已正确配置
  2. 网络连通性: 确保所有节点间的 2379 和 2380 端口互通
  3. 数据备份: 定期备份 etcd 数据,防止数据丢失
  4. 资源监控: 监控 etcd 的 CPU、内存和磁盘使用情况
  5. 版本兼容: 确保 etcd 版本与 Kubernetes 版本兼容

🔗 相关资源

工单短信触达需求文档

基于DDD领域驱动设计,实现工单短信自动触达、手动回复、回访处理及统计报表功能

📋 需求概述

项目背景

投诉工单系统需要新增短信通知功能,实现工单受理、结案、回访的短信触达,并改造直通率统计报表。

核心目标

  1. 自动发送受理短信:新建工单后自动发送受理通知
  2. 手动短信回复:支持处理人员手动发送结案通知短信
  3. 短信回访:工单结案后自动发送回访短信,处理客户回复
  4. 统计报表改造:基于主办机构计算直通办理率

🏗️ 领域模型设计

核心领域(Core Domain)

1. 投诉工单实体(ComplaintOrder)

// 核心字段
- orderId: 工单ID
- orderType: 工单类型12378监管转办消保转送咨询等
- contactName: 联系人姓名
- contactPhone: 联系人电话
- complainantPhone: 投诉人电话
- mainOrg: 主办机构总行/信用卡中心/分行/其他
- mainOperator: 主办人员
- isSmsReply: 是否短信回复/
- smsReplyTime: 回复时间
- isSmsVisit: 是否短信回访/
- visitDate: 回访日期
- visitTime: 回访时间
- visitResult: 回访效果满意/不满意
- processNotifyType: 处理决定告知方式短信/其他
- processNotifyTime: 处理决定告知时间

2. 短信交互实体(SmsInteraction)

- smsId: 短信记录ID
- orderId: 关联工单
- smsType: 短信类型受理通知/结案通知/回访
- templateId: 短信模板
- phone: 发送手机号
- customerName: 客户姓名
- sendTime: 短信发送时间
- sendOperator: 发送人
- replyContent: 客户回复内容
- replyTime: 客户回复时间

3. 短信模板实体(SmsTemplate)

- templateId: 模板ID
- templateName: 模板名称
- templateContent: 模板内容
- templateType: 类型受理/结案/回访
- approvedStatus: 业务审核状态
- visibleRoles: 可见角色总行/分行
- enabled: 是否启用

🎯 功能需求与开发任务

功能一:新建工单自动发送受理短信

📌 功能描述

投诉工单新建成功后,系统自动发送受理短信给联系人。

工作台

快速访问常用应用和系统

区块链技术核心:典当铺的启示

从沈万三的黄金当票到分布式账本的魔法,探索区块链如何用时间换取不可篡改的空间

📖 引言

比特币作为第一个成功的去中心化数字货币,其核心创新在于解决了**“双花问题”**(Double Spending Problem)。如何用通俗易懂的方式理解这个看似复杂的技术问题?

本文通过一个生动的典当铺比喻,带你深入理解区块链的双花防御机制、51%攻击原理,以及"时间换空间"的核心思想。


🎭 第一幕:古老的漏洞——中心化的困境

故事:沈万三的第一次欺诈

从前,有个叫沈万三的商人,他有一块祖传金砖。他找到"诚信典当铺1号",抵押金砖,换得一张**“当票A”和一笔钱。掌柜的把“沈万三抵押金砖一块”**记录在自己的账本上。

沈万三动了歪心思:他手巧,伪造了一张一模一样的**“当票A’”**。他跑到城另一头的"仁义典当铺2号",声称要典当同一块金砖。2号掌柜没见过这块金砖,查验当票似乎无误,便也给了他钱。

结果:傍晚,两家典当铺掌柜对账时,发现**“同一块金砖被典当了两次”**,大惊失色!虽然最终作废了第二次交易,但沈万三已经卷钱跑路,2号典当铺蒙受了损失。

技术对应:传统中心化系统的双花问题

典当铺场景技术对应问题本质
各家典当铺独立账本银行独立数据库信息不同步
伪造当票A'复制交易记录数据可复制
利用时间差网络延迟缺乏全局一致性
2号铺蒙受损失商家收到假币无法验证资产唯一性

核心问题:在中心化系统中,如果缺乏权威机构的统一验证,同一资产(数字资产)可以被多次花费,这就是**“双花问题”**的根源。


🔄 第二幕:革命性的发明——分布式大账本

故事:典当联盟的诞生

全城的典当铺吃尽苦头,终于联合起来,成立了一个**“典当联盟”**。他们制定了一套全新的规则:

1. 统一账本

全城100家典当铺,每家都持有一本完全相同的、实时同步的超级大账本

技术对应分布式账本(Distributed Ledger)

  • 每个节点(典当铺)维护完整的账本副本
  • 通过共识机制保持数据一致性
  • 去中心化,无单一控制点

2. 当票即交易

任何一笔典当(交易),都不再是简单的当票,而是一条全网广播的**“交易记录”**。

例如:

交易ID:001
沈万三的金砖编号888,从[沈万三地址]抵押至[诚信1号地址]
时间戳:2024-01-01 10:00:00
签名:0x3a5f2b...

技术对应UTXO(未花费交易输出)

  • 每笔交易记录资产的转移
  • 交易用加密签名保证真实性
  • 全网广播,所有节点可见

3. 挖矿竞争(合账)

他们引入一种叫**“合账”的竞赛。每十分钟,各家掌柜会竞相把这段时间收到的交易记录打包成一个“区块”**(相当于一页账)。谁先解出一道超级难的数学题(工作量证明),谁就有权把这一页账(区块)发给所有人。

技术对应工作量证明(Proof of Work)

  • 矿工(掌柜)竞争打包交易
  • 解决哈希难题(数学题)获得记账权
  • 平均10分钟产生一个区块(比特币)

4. 链式记账

新的一页账必须牢牢钉在上一页账的后面,并用数学封印(哈希值)串联起来,形成一条**“区块链”**。想改其中一页,就必须重做后面所有的页,并重新赢得每次的竞赛。

技术对应区块链(Blockchain)

  • 每个区块包含前一个区块的哈希值
  • 形成不可篡改的链式结构
  • 篡改历史记录的成本呈指数级增长

架构对比

传统中心化系统          vs          区块链系统
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
单一账本(易被攻击)             分布式账本(100家店)
独立验证(信息差)               全网共识(统一验证)
可篡改(信任中心)               不可篡改(数学保证)
单点故障                         去中心化容错

⚔️ 第三幕:沈万三的终极挑战——51%攻击

故事:控制多数算力的攻击

沈万三不甘心,他决定挑战整个联盟系统。他想把典当给1号铺的金砖,再偷偷"典当"一次。