跨雲端的 Zero Downtime 轉移

看到「Ask HN: Have you ever switched cloud?」這個討論,在講雲端之間的搬遷,其中 vidarh 的回答可以翻一下...

首先是他提到原因的部份,基本上都是因為錢的關係,從雲搬到另外一個雲,然後再搬到 Dedicated Hosting 上:

Yes. I once did zero downtime migration first from AWS to Google, then from Google to Hetzner for a client. Mostly for cost reasons: they had a lot of free credits, and moved to Hetzner when they ran out.

Their savings from using the credits were at least 20x what the migrations cost.

然後他也直接把整理的資料丟出來,首先是在兩端上都先建立 load balancer 類的服務:

* Set up haproxy, nginx or similar as reverse proxy and carefully decide if you can handle retries on failed queries. If you want true zero-downtime migration there's a challenge here in making sure you have a setup that lets you add and remove backends transparently. There are many ways of doing this of various complexity. I've tended to favour using dynamic dns updates for this; in this specific instance we used Hashicorp's Consul to keep dns updated w/services. I've also used ngx_mruby for instances where I needed more complex backend selection (allows writing Ruby code to execute within nginx)

再來是打通內網,其實就是 site-to-site VPN:

* Set up a VPN (or more depending on your networking setup) between the locations so that the reverse proxy can reach backends in both/all locations, and so that the backends can reach databases both places.

然後建立資料庫的 replication server 以及相關的機制:

* Replicate the database to the new location.

* Ensure your app has a mechanism for determining which database to use as the master. Just as for the reverse proxy we used Consul to select. All backends would switch on promoting a replica to master.

* Ensure you have a fast method to promote a database replica to a master. You don't want to be in a situation of having to fiddle with this. We had fully automated scripts to do the failover.

然後是確認 application 端可以切換自如:

* Ensure your app gracefully handles database failure of whatever it thinks the current master is. This is the trickiest bit in some cases, as you either need to make sure updates are idempotent, or you need to make sure updates during the switchover either reliably fail or reliably succeed. In the case I mentioned we were able to safely retry requests, but in many cases it'll be safer to just punt on true zero downtime migration assuming your setup can handle promotion of the new master fast enough (in our case the promotion of the new Postgres master took literally a couple of seconds, during which any failing updates would just translate to some page loads being slow as they retried, but if we hadn't been able to retry it'd have meant a few seconds downtime).

然後確認新的雲端有足夠的 capacity 撐住流量後,就是要轉移了,首先是降低 DNS TTL:

Once you have the new environment running and capable of handling requests (but using the database in the old environment):

* Reduce DNS record TTL.

然後把舊的 load balancer 指到新的後端,這時候如果發現問題可以快速 rollback 回來:

* Ensure the new backends are added to the reverse proxy. You should start seeing requests flow through the new backends and can verify error rates aren't increasing. This should be quick to undo if you see errors.

接著把 DNS 指到新的 load balancer,理論上應該不會有太大問題:

* Update DNS to add the new environment reverse proxy. You should start seeing requests hit the new reverse proxy, and some of it should flow through the new backends. Wait to see if any issues.

接著把資料庫切到新的機房,有問題時可以趕快切回去再確認哪邊有狀況:

* Promote the replica in the new location to master and verify everything still works. Ensure whatever replication you need from the new master works. You should now see all database requests hitting the new master.

最後的階段就是拔掉舊的架構:

* Drain connections from the old backends (remove them from the pool, but leave them running until they're not handling any requests). You should now have all traffic past the reverse proxy going via the new environment.

* Update DNS to remove the old environment reverse proxy. Wait for all traffic to stop hitting the old reverse proxy.

* When you're confident everything is fine, you can disable the old environment and bring DNS TTL back up.

其實這個方法跟雲端沒什麼關係,以前搞機房搬遷的時候應該都會規劃過類似的方案,大方向也都類似 (把 stateful services 與 stateless services 拆開來分析),只是不像雲端的彈性租賃,硬體要準備比較多...

我記得當年 Instagram 搬進 Facebook 機房的時候也有類似的計畫,之前有提過:「Instagram 從 AWS 搬到 Facebook 機房」。

台灣最近的話,好像是 PChome 24h 有把機房搬到 GCP 上面?看看他們之後會不會到 GCP 的場子上發表他們搬遷的過程...

透過 SOCKS5 界面連進 WireGuard 網段的軟體 wireproxy

Hacker News 上看到「A userspace WireGuard client that exposes itself as a proxy (github.com/octeep)」看到這個有趣的東西,可以把自己當作是一個 WireGuard client,然後透過 SOCKS5 界面讓使用者使用... 專案則是在 GitHub 上的「Wireguard client that exposes itself as a socks5 proxy」這邊可以看到。

除了軟體本身有支援 SOCKS5 的可以用以外,另外可以搭配透過 LD_PRELOAD 把 TCP 連線都轉進 SOCKS5 服務的套件來用,像是 tsocks 或是 redsocks 這種工具。

然後這包東西是用 Golang 寫的,好像剛好可以拿來練手包 Ubuntu PPA...

用 Tailscale 取代個人的 VPN

Tailscale 是個基於 WireGuard 的 VPN 服務,基本的邏輯是所有的機器都連上 VPN,然後 Tailscale 建立一組 CGNAT 網段的內部網路讓你可以互連,另外也可以透過這些 VPN 設定 exit node 連外:

另外的一個特點是他把 Hole punching 的方式包好了,可以打通兩個都在 NAT 後面的機器 (大多數的狀態都可以成功),不需要透過 VPN hub 代轉流量,於是 latency 會低很多 (因為大多數在台灣都沒有 VPN hub)。

也因為不太需要 VPN hub,對 Tailscale 來說營運的成本就沒那麼高,所以 Tailscale 有提供個人可以用的免費版本,提供 20 個 devices 連上同一個內部網段。

以前在外面的咖啡廳用網路會習慣透過 VPN server 稍微保護一下連線,現在看起來可以用 Tailscale 取代掉... 家裡的 HiNet 桌機或是 VPS 的機器都可以拿來當 exit node。

另外還有 open source 的 headscale 專案可以看,如果想要完全更高的安全性,完全自己 host 的話...

Amazon EC2 的網路效能

前一篇「在 AWS 上面的 OpenVPN Server 效能」最後的問題就是 EC2 instance 本身的網路效能,畢竟是公司要用的,還是實際測一下數字,之後有人接手的時候也比較清楚是怎麼選這個大小的...

這邊拿的是 AWSap-southeast-1 (Singapore) 的 EC2 測試,直接在同一個 subnet 裡面開兩台一樣的機器跑 iperf 測試。

機器開機後會先跑這串指令 (除了安裝 iperf 的指令,其他的是出自我自己 wiki 上的 Ubuntu 這頁),然後再重開機:

sudo fallocate -l 512M /swapfile; sudo chmod 600 /swapfile; sudo mkswap /swapfile; sudo swapon /swapfile; echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab; echo -e "net.core.default_qdisc=fq\nnet.ipv4.tcp_congestion_control=bbr" | sudo tee /etc/sysctl.d/99-tcp.conf; sudo sysctl -p /etc/sysctl.d/99-tcp.conf; sudo apt update; sudo apt dist-upgrade -y; sudo apt install -y apache2-utils apt-transport-https build-essential curl dnsutils dstat git jq locales moreutils most mtr-tiny net-tools p7zip-full pigz prometheus-node-exporter rsync sharutils software-properties-common sysstat unrar unzip vim-nox wget zsh zsh-syntax-highlighting zstd; sudo apt install -y iperf; sudo apt clean

接下來就是一台跑 iperf -s,另外一台跑 iperf -c 10.x.x.x -i 1 -t 3600 讓他跑一個小時看結果了。

我都有跑 tmux 再連到這些機器上,這樣可以捲回去看每一秒的傳輸速度,就可以看出來變化了,不過這邊還是簡單的只列出最高速度 (burstable) 與穩定輸出的速度 (baseline):

EC2 instance Baseline Burstable vCPU RAM Pricing (USD$)
c6g.medium 500Mbps 10Gbps 1 2GB 0.0392
c6g.large 750Mbps 5Gbps (claimed 10Gbps) 2 4GB 0.0784
c6g.xlarge 1.25Gbps 10Gbps 4 8GB 0.1568
t4g.small 125Mbps 5Gbps 2 2GB 0.0212
t4g.medium 255Mbps 5Gbps 2 4GB 0.0424
t4g.large 510Mbps 5Gbps 2 8GB 0.0848
t4g.xlarge 1Gbps 5Gbps 4 16GB 0.1696

這邊沒列出來的是 burstable 可以持續的時間,但這跟你機器吃的網路資源有關,我就決定只用 baseline 來做決策了,這樣可能會多花一點錢,但會少很多麻煩。

另外這次在處理的過程有被同事提醒各種 bandwidth overhead,所以就順便查了一下資料:

  • OpenVPN 本身的 overhead 大約是 5% (跑 UDP 的時候):「OpenVPN performance」。
  • SSH 也有些 overhead,大約是 6% (把來回的封包都算進去):「What is the overhead of SSH compared to telnet?」。
  • rsync 的部份鐵定也有 overhead,但這邊就沒找到現成的文章有統計過了。
  • 另外我自己之前做實驗發現 TCP BBR 的 retransmission algorithm 還蠻激進的,會有 10% packet loss,改用預設的 CUBIC 會好很多,大約 1% 到 2% 左右。

綜合這些測試,我自己抓了 35% 的 overhead 來推估,最後是用 c6g.large 來養 VPN server。750Mbps 的實際流量大約可以包進 550Mbps 的原始流量,大約是 68MB/sec。

不過新加坡與印尼之間的 internet bandwidth 好像還是不太夠,有時候深夜跑也跑不滿... 不過之後 VPN 上的 client 會愈來愈多,應該是不需要降...

在 AWS 上面的 OpenVPN Server 效能

這篇的後續可以參考「Amazon EC2 的網路效能」這篇。

最近在在調整跑在 Amazon EC2OpenVPN server 的效能,要想辦法把 network throughput 拉高,當作在導入 WireGuard 之前的 workaround,但看起來還是頗有用,記錄一下可以調整的部份...

在還沒灌大量流量前是用 t3a.nano (開 Unlimited mode),然後會觀察到的瓶頸是 OpenVPN 的 daemon 吃了 100% CPU loading,最高速度卡在 42MB/sec 左右。

第一個想到的是看看 OpenVPN server 有沒有可以使用多 CPU 的方式,但查了資料發現 OpenVPN server 無法使用 threading 或是 fork 之類的方法善用多顆 CPU,所以就開始想其他方法...

接著看到我們目前用的是 AES-256-CBC 了,網路上很多文章都有提到 AES-128-CBC 會快一些,但我們的 OpenVPN client 已經是設死都用 AES-256-CBC 了,這個就沒辦法了...

而第一個可行的解法是把 AMD-based 的 t3a.nano 換成 ARM-based 的 t4g.nano,還是 100% 的 CPU loading,但直接多了 50%+ 的效能,到了 69MB/sec。

第二個解法是找資料時發現的 fast-io 參數,加上去以後可以再快一些,到 77MB/sec。

有了這兩個 workaround 應該就堪用了,接下來是發現在傳大量資料跑一陣子後速度會掉下來,於是開了兩台 t4g.nanoiperf 對測了一下,發現會逐步掉速:

  • 前 15 秒可以直接到 5Gbps,就是 AWS 網頁上宣稱的最高速度,接下來降到 800Mbps 左右。
  • 到 180 秒左右後降到 300Mbps。
  • 到 210 秒左右後回到 800Mbps。
  • 到 300 秒左右後降到 500Mbps。
  • 到 300 秒左右後降到 300Mbps。
  • 到 1260 秒左右後降到 30Mbps,後面就一直維持這個速度了。

看起來 network bandwidth credit 是分階段的,但 30Mbps 真的有點低...

在換成四倍大的 t4g.small 測試後發現也只能到 40MB/sec 左右 (比較疑惑的是,居然不是四倍?),目前上了 c6g.medium,但看起來網路的部份也還是有瓶頸,在 46MB/sec 左右,要再想一下下一步要怎麼調整...

但以目前看到的情況總結,如果能用 ARM 架構就儘量用,效率與價錢真的是好 x86-64 不少...

Amazon VPC 允許直接把整個網段配到某台 EC2 Instance 上了

看到「Amazon Virtual Private Cloud (VPC) customers can now assign IP prefixes to their EC2 instances」這邊的消息,VPC 可以把整個網段配到某台 EC2 Instance 上了。

之前也有其他方法可以做到類似的事情:

  • 用 VPC 提供的 Routing Table 把網段指到某台 EC2 的機器上。
  • 把這台 EC2 機器的「Enable Source/Destination Check」關閉。

目前就是用這個方法搞定 VPN server 的:我們希望機器連上 VPN 後拿到 10.x.x.x 的 IP address,而且可以被 VPC 內直接存取,而不要被 NAT 掉。

好像該開張票轉移過去...

FreeBSD & pfSense 上的 WireGuard 問題

FreeBSDpfSense 上的 WireGuard 實做問題前幾天被 Ars 的人整理出來:「Buffer overruns, license violations, and bad code: FreeBSD 13’s close call」,文章有點長度,但整個劇情有種在看八點檔的感覺... 在 Hacker News 上的「Buffer overruns, license violations, and bad code: FreeBSD 13’s close call (arstechnica.com)」與後續的「In-kernel WireGuard is on its way to FreeBSD and the pfSense router (arstechnica.com)」都值得翻翻。

目前 FreeBSD 與 pfSense 都已經把現有的 WireGuard 實做拿掉,主要原因是實做本身的品質很差 (以及安全性問題),而且沒有將 WireGuard 的功能實做完整。

文章裡面有提到兩個組織面上的問題 (還有攻擊個人的部份,這邊就不提了),第一個是 FreeBSD 的 review process,看起來比較像是系統面的問題,目前還是缺乏人力。

另外一個是 Netgate 本身 (pfSense 後面的公司),本來沒有太多背景知識,但這次事件發生後跑去翻了一下資料,發現原來之前就有一些「記錄」了,像是註冊競爭對手的產品 OPNsense 沒有註冊的網域 opnsense.com,然後導去 pfSense 家的事情,最後使得 Deciso (OPNsense 後面的公司) 到 WIPO 上搶回來:「WIPO Domain Name Decision: D2017-1828」。

可以花些時間來看看替代方案...

NordVPN 綁架使用者的方式...

Hacker News Daily 上看到「NordVpn disables features when you turn off auto-renew」這個,這也太厲害了:

NordVPN 設計成只要關掉 auto-renewal 就直接拔掉一些功能,一臉 WTF...

Hacker News 的「NordVPN disables features when you turn off auto-renew (reddit.com)」看到這段提出來的論點蠻有趣的,當作一個參考觀點:

By now these VPN providers are like toothpaste, diapers or soft drinks: completely undifferentiated between competitors, and so only able to maintain their market share by spending loads on marketing. Of course the company with most egregious dark patterns and aggressive churn dampening wins.

Thankfully a tube of toothpaste doesn't allow implementing dark patterns like this... yet.

AWS Site-to-Site VPN 支援 AES-GCM 了

AWS 更新了 Site-to-Site VPN:「AWS Site-to-Site VPN now supports additional encryption, integrity and key exchange algorithms」。

這次更新支援了一些新的演算法,其中 AES-GCM 的部份看起來是這次這波最重要的:

Encryption: AES128-GCM-16, AES256-GCM-16.
Integrity: SHA2-384, SHA2-512.
Diffie-Hellman groups: 19, 20, 21.

傳統的方式是 encryption algorithm + hash algorithm 搭配,所以就會出現各種排列組合,而不同的方式在實做上很容易出現安全問題,也就是這篇在討論的:「Should we MAC-then-encrypt or encrypt-then-MAC?」。

AEAD 試著用一包解決,對於實做的安全性好不少...

前陣子爆出「不保留記錄的 VPN」保留了大量的客戶與連線資訊

前陣子 comparitech 發現了宣稱不保留記錄的 VPN 廠商 UFO VPNElasticsearch 伺服器沒有設定好,造成外部可以直接存取,然後發現裡面包含了大量記錄:「“Zero logs” VPN exposes millions of logs including user passwords, claims data is anonymous」,這篇文章的小標把重點先說完了:

UFO VPN exposed millions of log files about users of its service, including their account passwords and IP addresses, despite claiming that it keeps no logs.

目前還是建議在有能力的情況下都自己架,一般常見就是用 OpenVPN,但設定上會比較麻煩一些。如果要方便的話可以用 Openconnect VPN Server (ocserv) 架 server,然後在手機上可以直接用 Cisco 官方提供的用戶端接,像是 Cisco AnyConnect (iOS) 與 AnyConnect (Android),在桌機上一般則是用 OpenConnect 自家的軟體連接。

家裡有 HiNet 的網路的話,可以申請一個固定 IP (透過 PPPoE 的),然後用一台 Raspberry Pi 之類的設備架設。

倒不是說這些 VPN 廠商的服務不能用,只是你必須認知這些 VPN 是拿來繞過地區限制的,而不是為了安全性或是隱私,所以如果是人在外面使用網路,想要避免被商家或是外面的 ISP 看到流量內容,透過自己架設的 VPN 應該會好不少。