【运维趟坑回忆录】vpc迁移 - 吃螃蟹之路

探路

前篇列出的都是缓兵之计, 大部分问题还是存在, 在前几个月懵逼和饱受白名单问题煎熬后, 慢慢打起了vpc迁移的算盘.

这个迁移很大的一个问题就是, 如何将VPC和经典资源打通呢?

VPC经典互通的第一次尝试

在16年底, 风控准备上第一版服务, 将服务放在了vpc内. 以此为契机尝试打通vpc和经典的服务,但是这个时候阿里云vpc刚上没多久, 基本没有任何对这方面的支持.
第一次尝试方案如下

  • 在vpc内创建了一个openvpn server把端口暴露给经典网络
  • 在经典环境以一台空闲节点作为client保持和openvpn server的连接
  • vpn server给经典client下发vpc网段路由下一跳指向vpn server
  • 在vpn server上对vpn和经典网段分别进行SNAT
  • vpc路由器上将经典网段的10路由下一跳指向vpn server
  • 经典节点上对vpc和vpn网段SNAT

其他的经典节点由于路由不可控无法主动访问vpc, 经典client节点可以openvpn server的身份访问其他vpc所有节点.这样经典client的节点相当于和vpc完全互通了.
而vpc内的节点则可以通过vpn client访问所有经典节点, 由于是在路由器上加的路由这个访问是对于vpc节点来说是无需配置, 无感知的.

不过由于阿里云有一个神奇的100.64.0.0/10网段(RDS,DRDS,redis,部分SLB), 这个路由是无法控制的, 为了让vpc能访问到阿里云的这些资源, 只能不停在将各种不同的资源在经典的vpn client做DNAT.
DNAT规则大致如下.

firewall { '100 snat for vpn':
  chain    => 'POSTROUTING',
  jump     => 'SNAT',
  proto    => 'all',
  source   => '192.168.0.0/24',
  table    => 'nat',
  tosource => '10.165.69.144',
}
firewall { '101 snat for vpn':
  chain    => 'POSTROUTING',
  jump     => 'SNAT',
  proto    => 'all',
  source   => '172.31.255.0/24',
  table    => 'nat',
  tosource => '10.165.69.144',
}
firewall { '102 dnat for drds xxx':
  chain    => 'PREROUTING',
  table    => 'nat',
  jump     => 'DNAT',
  source   => '!10.0.0.0/8',
  destination => '10.165.69.144',
  proto    => 'tcp',
  dport    => '3306',
  todest   => '100.98.69.136',
}
firewall { '103 dnat for rds xxx.mysql.rds.aliyuncs.com':
  chain    => 'PREROUTING',
  table    => 'nat',
  jump     => 'DNAT',
  source   => '!10.0.0.0/8',
  destination => '10.165.69.144',
  dport    => '3307',
  proto    => 'tcp',
  todest   => '100.114.46.162:3306',
}
firewall { '104 dnat for redis xxxx.m.cnbja.kvstore.aliyuncs.com':
  chain    => 'PREROUTING',
  table    => 'nat',
  jump     => 'DNAT',
  source   => '!10.0.0.0/8',
  destination => '10.165.69.144',
  proto    => 'tcp',
  dport    => '6379',
  todest   => '100.99.94.201',
}
firewall { '105 dnat for slb xxx':
  chain    => 'PREROUTING',
  table    => 'nat',
  jump     => 'DNAT',
  source   => '!10.0.0.0/8',
  destination => '10.165.69.144',
  proto    => 'tcp',
  dport    => '80',
  todest   => '100.114.31.148',
}

整个结构的简单图示:
【运维趟坑回忆录】vpc迁移 - 吃螃蟹之路

这样勉强达到了互通的要求, 但是问题也很明显, vpn client和vpn server都是单点的. 期间分别准备好了备机以防止意外随时切换, 这种状态跑了半年, 除了有时经典节点公网带宽跑满, 并未出现过其他问题, 升级过带宽后也好了. iptables的转发还是很给力的, 不过现在阿里云在互通方面做了很多支持,没必要这样做了.

正式上路

阿里云推出经典与vpc互联支持后

阿里云文档: https://help.aliyun.com/document_detail/55051.html

主要支持了 ClassicLink, 混访混挂, 单ECS迁移, 既有的java应用也是在推出上述实际支持后开始的.

迁移问题

提前规划

  • 迁移到vpc后, 自然不希望再和以前一样看着经典ip一脸懵逼. 希望看到ip就能知道是哪个集群里的, 策略可以直接根据预先设定的网段来设置. 下面是之前规划时整理的部分文档(2017年4月写的, 具体请以阿里云最新文档为准)

限制:

  • 【运维趟坑回忆录】vpc迁移 - 吃螃蟹之路

注意事项:

  • VPC 的交换机是一个 3 层交换机,不支持 2 层广播和组播。
  • 每个交换机的第1个和最后3个 IP 地址为系统保留地址。以 192.168.1.0/24 为例,192.168.1.0、 192.168.1.253、 192.168.1.254 和 192.168.1.255 这些地址是系统保留地址。
  • 专有网络内的 ECS 使用安全组防火墙进行三层网络访问控制。

划分原则

  • 每个分组对应至少一个或多个(可用区)交换机, 每个交换机绑定至少一个分组命名的安全组.
  • 每个分组对应至少一个分组命名的容器集群.
  • 每个分组对应单独的SNAT表或者SNAT IP POOL.
  • 每个分组之间默认完全隔离. 由安全组控制访问.访问
  • 每个分组保证至少2个可用区,核心业务三个可用区. 以可用区字母结尾, 例如 common-a 表示common分组, A可用区
  • 生产和测试vpc独立, 完全隔离
    【运维趟坑回忆录】vpc迁移 - 吃螃蟹之路

其实不太建议用 192.168.0.0/16 网段, 可用ip相对会少一些, 而且后续如果办公网或者经典互联容易出现问题.

路由问题

这里需要注意2个问题

  • 默认情况路由表条目是有限制的, 默认是48, 如果后续容器化(阿里云为了打通容器网段, 会在路由表上自动添加路由条目, 容器网段下一跳指向对应宿主机节点), 很容易达到限制配额. 可以手动控台申请配额, 或者工单申请.
  • 正常情况classiclink后, 经典网络节点可以直接访问vpc节点, 但是如果vpc网段是 192.168.0.0/16 就比较特殊了, 需要手动在经典节点上加下路由. 脚本参考这里 添加路由

新老服务交互

我们应用主要是dubbo + http方式来进行应用间的互相访问, 涉及数十个应用, 不会是一波进去, 就会存在一段时间需要vpc和经典互访的情况.

dubbo服务
  • 利用classic将zk集群和provider端链入vpc
  • vpc内新建一个zk集群
  • consumer端先迁入, 同时注册新老zk集群, 因为后续使用的容器化, 直接在启动entrypoint的脚本里做一些处理即可, 应用无需改动.
# add dubbo vpc registry
# find  /data/ -name "*.xml" -exec grep -Hn 'registry' {} \; | awk -F: '{print $1}' | xargs -i -t sed -i -r '/zookeeper.vpc.cluster/d' {}
# find  /data/ -name "*.xml" -exec grep -Hn 'registry' {} \; | awk -F: '{print $1}' | xargs -i -t sed -i -r '/registry/{h;s/dubbo:registry/& id="vpc"/;s/(address=")(.*)(")/\1${zookeeper.vpc.cluster}\3/;G}' {}
  • 后续provider迁入, 同理. 直至相关服务迁移完成后将主zk直接指向vpc的zk集群, 老zk集群下线.
http服务

这个比较简单了, 因为我们内部服务也通过slb暴露, 这里主要通过slb混挂来做.

  • vpc内起一个新的服务, 将相关节点挂入原有的经典内网slb.
  • 调整权重, 观察服务正常逐渐替换老的节点即可.
  • 一般会在vpc内也再开一个vpc内网slb提供vpc内调用, 后续迁移完成后确认老的经典slb无流量后释放即可.

公网slb其实同理. 不过由于在迁移vpc同时进行了容器化, 这里稍微有些处理(下篇专门介绍容器化会说到)

阿里云相关资源调用

后续迁移过程中阿里云其实都已经提供了相当方便的支持, 在这之前我们都是使用的相当粗暴的走公网链接方式(很不推荐, 受公网带宽限制, 而且有一定风险, 虽然traceroute测试下来公网路径貌似都是经过的阿里云节点,但终究心里没底)

  • oss, ots, ons等等直接换成vpc的endpoint即可
  • drds,rds, redis稍微麻烦一点, 需要迁移vpc后选择保留经典链接, 最多可以同时维持vpc,经典内网,公网三个链接地址, 而且经典地址保留时间可以工单延长. vpc内的应用直接使用vpc内网地址即可.

基本上在阿里云实际提供支持后, vpc和经典网络这块并没有太多的障碍, 主要根据应用状态, 逐个迁移观察, 就是一些细心的活了. 更多踩到的坑还是在容器化中, 下篇继续介绍vpc迁移同时容器化踩到的一些坑.

上一篇:冬季实战营学习报告


下一篇:LeetCode第136题:只出现一次的数字