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

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

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

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

儲存體分為三種(正確名稱是 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 可免密碼登入,此處先選密碼登入比較單純。

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

  • 安裝 Docker 與 docker-compose
  • 下載 nginx-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 )

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

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

開好 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 網站:

正式使用時,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/nginx.conf:/etc/nginx/nginx.conf
      - /etc/nginx/conf.d:/etc/nginx/conf.d
      - /etc/letsencrypt:/etc/letsencrypt
    restart: always
    environment:
      - CERTBOT_EMAIL=your-email@mail.com
    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 網站囉! 成功。

Introduce to low-cost Azure B-series VM.


Comments

# by Jackson27462

使用 Google Compute Engine (GCP) 已當了四年的免費仔 QQ https://cloud.google.com/free/docs/free-cloud-features?hl=zh-tw#free-tier [Compute Engine 章節] 每個月可以在下列其中一個美國區域中使用 1 個非先佔 e2-micro VM 執行個體: 奧勒岡州:us-west1 愛荷華州:us-central1 南卡羅來納州:us-east1 .每月 30 GB 的標準永久磁碟 .每月 1 GB 從北美輸出至所有地區的網路流量 (中國和澳洲除外) 在免費方案中,e2-micro 執行個體的限制依據為時間,而非執行個體。每月使用所有符合資格的 e2-micro 執行個體均為免費,直到使用時數達到當月限定的總時數為止。計算用量時會加總所有支援地區的用量。

# by Jackson2716

Google Cloud Platform(GCP) e2-micro = 2 vCPU + 1 GB memory + 30G HDD + 美西(Oregon) = 免費 但要注意流量問題,然後如果在 Azure 能跑的起來 Debian+ASP.net Core,那在GCP一定更沒問題! GOGOGO 想看指令範例

# by C.Y Hung

我是會把User Group 加入在docker 下,這樣在輸入Docker指令就可以不用輸入sudo

# by 007

免費仔來推薦Oracle Cloud Always Free系列 VM.Standard.E2.1.Micro (x86/1 OCPU/1G RAM) VM.Standard.A1.Flex (arm64/4 OCPU/24G RAM)

# by Jakeuj

在免費方案中,e2-micro 執行個體的限制依據為時間,而非執行個體。每月使用所有符合資格的 e2-micro 執行個體均為免費,直到使用時數達到當月限定的總時數為止。 請問這個每月總時數是多少?

Post a comment