4

Azure 學習筆記 - 使用小資族首選 B1s VM 跑 ASP.NET Core 小服務

 1 year ago
source link: https://blog.darkthread.net/blog/azure-b1s-vm/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

使用小資族首選 B1s VM 跑 ASP.NET Core 小服務-黑暗執行緒

B1s 是 Azure 的實用小 VM,1 顆 CPU + 1G RAM (更小的 B1ls RAM 只有 512MB,有點吃緊),裝 Linux 每個月成本不到 250 塊台幣,若在 Azure 開新帳號,它包含在前 12 個月免費的範圍,很適合拿來跑小排程或聊天機器人之類的應用。

Fig1_638057678740778433.png

不過要留意一點,B 系列之所以便宜是因為它是蓄發型(Burstable),意味著不是 100% 擁有整顆 CPU。大量運算需求平時要先儲蓄,平常先存下 CPU 時間(Credits),需要大量運算再領取花用。如下表所示,不同大小的 CPU 數(嚴格來說是 vCPU,為求簡便我視同實體的一核,直接叫它 CPU)、記憶體大小、暫存磁碟大小、基準 CPU 使用率、最大 CPU 使用率都不同。

Fig2_638057678742622693.png

簡單說一下 CPU Credit 的存提規則。以 B2s 為例,CPU 有兩核,使用率為兩核加總,例如:兩個 CPU 各跑 60%,則 CPU% = 120%。B2s 的基準 CPU 使用率是 40%,意思是當機器的 CPU 使用率低於 40%,例如,CPU 跑 20%,則每分鐘可存下 0.4 - 0.2 = 0.2 Credits;若跑 10% 每分鐘可存 0.3。換言之一個小時有 24 Credit,以分鐘為單位,沒用完的就會存下來,而儲蓄上限是 576 Credits,但總可用量還要加上開始附贈的 CPU * 30 Credits,故 B2s 戶頭的上限為 576 + 60 = 636 Credits。當執行複雜運算 CPU 超過 40%,就需提領存款支付,例如 CPU 120% 跑五分鐘,扣除基準 40%,每分鐘要從銀行提領 1.2 - 0.4 = 0.8 Credit,5 分鐘會花掉 4 Credits 存款。若一直入不敷出銀行戶頭就會歸零,此時需要 CPU 100% 也只能得到 40%,如同 CPU 不夠力,將會感受程式變慢或卡頓。關於蓄發型詳細說明可參考官方文件

以中低流量網站來說,我自己的經驗是 CPU 常常只有 2 ~ 3% 而已,B1s 儲蓄基準為 10%,最大 Credit 數為 144 (CPU 100%,144/(1-10%) 約可跑 160 分鐘),非熱門服務幾乎都是存到滿,沒什麼機會用。B1s 的另一個限制是記憶體只有 1GB,跑 Windows Server 有點吃緊,此時 ASP.NET Core + Linux 的優勢就出現了。好東西,不學嗎?

值得一提的是,Azure 虛擬機大小可事後調整,你可以先開台小機器,事業做大發現不夠力再調大;或是網站門可羅雀曲高和寡機器閒得發慌,則可以改小省點錢,杜絕浪費。調整機器大小直接在網頁改設定就好了,但要注意改完機器會自動重開,網站將暫時中斷。

Fig4_638057678744572092.png

除了虛擬主機費用外,還有兩項費用要納入考量:儲存體及網路流量。

儲存體分為三種(正確名稱是 Storage,但求順口好懂,姑且稱之磁碟吧):OS碟暫存磁碟及額外加掛的資料碟

先講暫存磁碟,不同大小虛擬主機配置不同大小的暫存碟,以 B 系列為例為 4-64 GB,暫存碟使用完全免費。暫存碟使用上跟一般磁碟空間相同,但在上面放資料要有重開機後消失的心理準備,遇到系統故障或虛擬機移轉實體主機時,暫存碟便會刪除重建,故 Azure 不保證暫存磁資料完好也無備份,故它只適合放記憶體 Page File、Swap File 或一些消失就算了檔案。更多細節可參考官方文件

至於 OS 碟及外掛資料碟需依容量計費,專有名稱為受控磁碟(Managed Disks)。OS 碟 Linux 預設為 30GB(可加大)、Windows 則為 127GB。受控磁碟依等級及其大小定價,等級分為高階 SSD、標準 SSD、標準 HDD、Ultra SSD 四種,另外對磁碟的 I/O 存取(交易成本)也需計費,但費率不高就是了,以 Linux B1s OS 碟採 P4 Primium SSD Managed Disk(32GB 高階受控 SSD) 為例,每月費用約 NTD 163 (美東) ~ 180 (香港) 參考,前 12 個月免費項目包含。Windows 預設 OS 碟為 127GB,每月成本約 610 ~ 670 元,但可選擇 smalldisk 版映象檔開 OS 碟 30GB 的 Windows Server,但需要另掛資料碟放資料並將 Page File 指向暫存碟,程序較麻煩。故要求精省,Linux 還是佔優勢。

這裡有個小眉角,B1s Linux 預設的 OS 碟是 P4 32G,但前 12 月的免費磁碟項是兩顆 P6 64G SSD 碟( 32G 要收費,64G 反而不用,登楞!)。VM 建立時 OS 碟大小是配好的不能選,但我們可以停機改大小,調成 P6 64G 免費版。操作方式可參考這篇:Create Free Tier Windows/Linux Virtual Machines in Azure Cloud

備份方案則分為 LRS(本地備援儲存體)、ZRS(區域備援儲存體)、GRS(異地備援儲存體)、RA GRS(讀取權限異地備援儲存體),LRS 備在同一資料中心、ZRS 會同步到同地區的多個資料中心、GRS 會非同步備到另一個地區、RA GRS 則有最高的可用性 99.9999....99% (16個9),如果有安排定期備分到本地端,選 LRS 就夠了。

網路流量部分,流入主機的傳輸量不計費,傳出去部分才計費(例如:使用者由網站下載),每月有 100GB 免費額度,如超過,100GB - 10TB 部分每 GB 2.48 ~ 3.72 元,10TB - 40TB 每 GB 2.02 ~ 2.63 元,再超過的部分就不講了,會為如此高流量傷腦筋的人不是本文的目標讀者。另外,在不同區域間傳輸(例如:美東到亞洲機房),費率約 0.6~4.9 元 / GB。參考

Heroku 已在 11/28 關閉免費方案,跟 Fly.io 相比,Azure B1s VM 有完整的 Linux 操作環境,管理彈性高,成本能壓到很低甚至免費,也可當成跑迷你服務的選項之一。如果有 VS 訂閱或學生方案額度(細節可參考上回說明),要涵蓋 B1s 相關費用沒什麼問題。

以下是我在 B1s 機器上裝 Docker 執行自帶 Let's Encrypt TLS 憑證的 ASP.NET Core 網站的記錄。

首先用 Azure Portal 建立一台 B1s VM,我習慣新建一個 Group 將 VM 相關的網路、磁碟放一起方便管理,VM 不用時刪除 Group 可一次將相關資源清乾淨。輸入 VM 名稱、選區域、決定 Image (這篇以 Debian 為例,預設安裝比 Ubuntu 輕巧),Size 選 B1s,認證方式選 SSH public key 可免密碼登入,此處先選密碼登入比較單純。

Fig3_638057678746538148.png

花幾分鐘等 VM 建好,就可以使用 ssh 登入準備環境,重點工作包含:

  • 設定 root 密碼
  • 安裝 sudo
  • 安裝 Docker 與 docker-compose
  • 下載 docker-certbot 容器

ssh VM-IP 登入後執行以下安裝及設定指令:

# 安裝 Docker
sudo apt-get install \
    ca-certificates \
    curl \
    gnupg \
    lsb-release
sudo mkdir -p /etc/apt/keyrings	
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg    
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin 
# 安裝 docker-compose
sudo apt update
sudo apt install -y curl wget
curl -s https://api.github.com/repos/docker/compose/releases/latest | grep browser_download_url  | grep docker-compose-linux-x86_64 | cut -d '"' -f 4 | wget -qi -
chmod +x docker-compose-linux-x86_64
sudo mv docker-compose-linux-x86_64 /usr/local/bin/docker-compose
# 將使用者加入 docker 群組
sudo usermod -aG docker $USER
# 啟動 Docker 服務
sudo systemctl enable docker
# 安裝 nginx+certbot 容器
sudo docker pull staticfloat/nginx-certbot
# 安裝 ASP.NET Core 範例網站容器
# https://hub.docker.com/_/microsoft-dotnet-samples/
sudo docker pull mcr.microsoft.com/dotnet/samples:aspnetapp

這年頭網站沒 HTTPS 根本沒人承認,要裝憑證需有 DNS 名稱,如果沒有買自己的網域可透過 Azure Portal 管理介面設定,用 Azure 預設的 DNS 名稱 (尾巴為 .region-name.cloudapp.azure.com )

Fig5_638057678748403890.png

註:這裡假設大家已經對 Linux、nginx、Docker 跑 ASP.NET Core 操作已有基本概念,若對原理不熟可參考舊文,:

VM 裝好時預設只對外開放 SSH 22 Port,要跑網站需在 *-nsg (Network Security Group) 加開 80,443 Port 連入。若要防止不明人士連 SSH Try 密碼,還可順便限定來源 IP 提升安全性。

Fig6_638057678750291700.png

開好 80,443 Port,我們試跑一下範例 ASP.NET Core Docker 容器:

sudo docker run -it --rm -p 80:80 --name aspnetcore_sample mcr.microsoft.com/dotnet/samples:aspnetapp

若一切順利,用瀏覽器連上 B1s VM 的 80 Port,應可看到 ASP.NET Core 網站:

Fig7_638057678752144832.png

正式使用時,ASP.NET Core Kestrel Host 強韌度及功能不適合讓外界直接存取,外面要套一層 Reverse Proxy,我偏好用 Nginx。Nginx + CertBot 容器內建自動申請 Let's Encrypt 憑證功能,三個月到期還會自動更新,真正實現「設後不理」,是我心中最完美的解決方案,但一開始要花點功夫,以下是設定方法:

在 /etc/nginx/nginx.conf 放入以下內容,宣告各站台定義放在 /etc/nginx/conf.d 下的 *.conf 檔:

user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    gzip  on;
    gzip_min_length 1000;
    gzip_buffers 4 16k;
    gzip_comp_level 5;
    gzip_types text/plain application/x-javascript text/css application/xml text/javascript;

    include /etc/nginx/conf.d/*.conf;
}

宣告預設規則 /etc/nginx/conf.d/00.default.conf,80 Port 只用於接收 Let's Encrypt 的 /.well-known/acme-challenge 請求導向 Certbot 完成自動驗證,其餘一律導向 HTTPS:

server {
    # Listen on plain old HTTP
    listen 80 default_server;

    # Pass this particular URL off to certbot, to authenticate HTTPS certificates
    location '/.well-known/acme-challenge' {
        default_type "text/plain";
        proxy_pass http://localhost:1337;
    }

    # Everything else gets shunted over to HTTPS
    location / {
        return 301 https://$http_host$request_uri;
    }
}

/etc/nginx/conf.d/01.aspnetcore.conf 宣告指定 DNS 名稱之 443 Port 導向未來的 ASP.NET Core 站台 :(server_name 及 ssl_certificate* 設定記得改)

server {
    listen              443 ssl http2;
    server_name         my-dns-name.southeastasia.cloudapp.azure.com;
    ssl_certificate     /etc/letsencrypt/live/my-dns-name.southeastasia.cloudapp.azure.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/my-dns-name.southeastasia.cloudapp.azure.com/privkey.pem;

    location / {
        proxy_pass         http://localhost:5000;
        proxy_http_version 1.1;
        proxy_set_header   Upgrade $http_upgrade;
        proxy_set_header   Connection keep-alive;
        proxy_set_header   Host $host;
        proxy_cache_bypass $http_upgrade;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Proto $scheme;
    }
}

Nginx + Certbot 的 docker-compose.yml 如下:(CERTBOT_EMAIL 記得改)

version: "3"
services:
  nginx:
    image: docker.io/staticfloat/nginx-certbot
    container_name: nginx
    ports:
      - 80:80
      - 443:443
    volumes:
      - /var/log/nginx:/var/log/nginx
      - /var/log/letsencrypt:/var/log/letsencrypt
      - /etc/nginx:/etc/nginx
      - /etc/letsencrypt:/etc/letsencrypt
    restart: always
    environment:
      - [email protected]
    network_mode: "host"

ASP.NET Core 範例容器的 docker-compose.yml 如下:

version: "3"
services:
  nginx:
    image: mcr.microsoft.com/dotnet/samples:aspnetapp
    container_name: aspnetcore_sample 
    ports:
      - 5000:80
    network_mode: "host"

若一切順利,用 sudo docker-compose up -d 把兩個 Docker 容器跑起來,就可以用 HTTPS 連上 ASP.NET Core 網站囉! 成功。

Fig8_638057678753955949.png


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK