The Will Will Web

記載著 Will 在網路世界的學習心得與技術分享

如何透過 cloud-init 自動化部署 Azure 虛擬機器 (VM)

最近要幫客戶在 Azure 架設一台 Nginx 反向代理伺服器 (Ubuntu 20.04 LTS),我想透過 cloud-init 將整台 VM 從無到有全自動安裝設定完畢,經過幾個小時的努力,終於達成全自動化建置的目標,實在非常令人振奮。這篇文章我就來說說部署的過程與技術細節。

部署方法

以下就是我的最終成果,日後照著 SOP 就可以快速的建立出完全相同需求的 Nginx 反向代理伺服器 VM,而且只要經過一些微調,就可以應用在完全不同的情境上。

  1. 先準備好一份 cloud-init 設定檔 (cloud-init.yml)

    由於我是要架設「反向代理伺服器」,因此其中 proxy_pass 指向的網站要先決定好目標網址,以及 proxy_set_header Host 的標頭內容也要先依據需求設定好。

    #cloud-config
    apt_update: true
    apt_upgrade: true
    package_upgrade: true
    packages:
      - nginx
    write_files:
      - owner: www-data:www-data
        path: /etc/nginx/sites-available/default
        content: |
          server {
            listen 80;
            location / {
              proxy_pass https://duotify-itblog.azurewebsites.net;
              proxy_http_version 1.1;
              proxy_set_header Upgrade $http_upgrade;
              proxy_set_header Connection keep-alive;
              # proxy_set_header Host $host;
              proxy_set_header Host duotify-itblog.azurewebsites.net;
              proxy_cache_bypass $http_upgrade;
            }
          }
    runcmd:
      - service nginx restart
    
  2. 建立 Azure 資源群組 & 虛擬機器 & 開啟防火牆

    執行以下命令之前,要先準備好遠端 SSH 連線所需的 SSH 公開金鑰檔 (id_rsa.pub)!

    PowerShell

    az group create -n VM -l japaneast
    
    az vm create -g VM -n FrontNode `
        --image UbuntuLTS `
        --size Standard_DS1_v2 `
        --admin-username azureuser `
        --ssh-key-values '@id_rsa.pub' `
        --custom-data 'cloud-init.yml'
    
    az vm open-port -g VM -n FrontNode --port 80 --priority 900
    
    $IP=(az vm show -d -g VM -n FrontNode --query publicIps -o tsv)
    echo "SSH Login: ssh -l azureuser $IP"
    echo "Nginx URL: http://$IP"
    echo "cURL Test: curl http://$IP -D -"
    

    Bash

    az group create -n VM -l japaneast
    
    az vm create -g VM -n FrontNode \
        --image UbuntuLTS \
        --size Standard_DS1_v2 \
        --admin-username azureuser \
        --ssh-key-values @id_rsa.pub \
        --custom-data cloud-init.yml
    
    az vm open-port -g VM -n FrontNode --port 80 --priority 900
    
    IP=$(az vm show -d -g VM -n FrontNode --query publicIps -o tsv)
    echo "SSH Login: ssh -l azureuser $IP"
    echo "Nginx URL: http://$IP"
    echo "cURL Test: curl http://$IP -D -"
    

就醬,兩個步驟就輕鬆完成部署! 😎

技術細節講解: cloud-init.yml

  1. 該檔案第一行必須為 #cloud-config 開頭 (詳見 Cloud Config Data 文件)

    #cloud-config
    
  2. 設定 VM 自動更新套件到最新版

    apt_update: true
    apt_upgrade: true
    package_upgrade: true
    
  3. 自動安裝 nginx 套件

    packages:
      - nginx
    
  4. 寫入實體檔案並指定檔案擁有者

    write_files:
      - owner: www-data:www-data
        path: /etc/nginx/sites-available/default
        content: |
          server {
            listen 80;
            location / {
              proxy_pass https://duotify-itblog.azurewebsites.net;
              proxy_http_version 1.1;
              proxy_set_header Upgrade $http_upgrade;
              proxy_set_header Connection keep-alive;
              # proxy_set_header Host $host;
              proxy_set_header Host duotify-itblog.azurewebsites.net;
              proxy_cache_bypass $http_upgrade;
            }
          }
    
  5. 部署完成後自動執行命令

    runcmd:
      - service nginx restart
    

技術細節講解: Azure CLI

  1. 建立資源群組

    az group create -n VM -l japaneast
    
  2. 建立 UbuntuLTS 的虛擬機器

    az vm create -g VM -n FrontNode `
        --image UbuntuLTS `
        --size Standard_DS1_v2 `
        --admin-username azureuser `
        --ssh-key-values '@id_rsa.pub' `
        --custom-data 'cloud-init.yml'
    

    這裡有好幾個重要的參數:

    --image 指定你要建立的 VM Image 的名稱,而 UbuntuLTS 是一個通用的 Image 名稱,他會自動找到 Ubuntu 最新 LTS 的 Image 來用。以下是查詢完整 VM Image 清單的命令:

    # 列出所有 Image 的發行商 (Ubuntu 的發行商為 Canonical)
    az vm image list-publishers --location japaneast --output table
    
    # 列出 VM 發行商的提供方案 (Offers) (UbuntuLTS 來自 0001-com-ubuntu-server-focal 方案)
    az vm image list-offers -l japaneast --publisher Canonical --output table
    
    # 列出 VM 發行商的方案中所有可用的 Image 清單 (輸出結果中的 Urn 欄位,就是可以讓你用來指定建立的 Image 名稱)
    az vm image list -l japaneast --offer 0001-com-ubuntu-server-focal --publisher Canonical --all --output table | grep "2019-Datacenter-with-Containers"
    

    --size 指定你的 VM 規格,想列出完整的 VM 規格清單 (相當多),可以用以下命令查詢:

    az vm list-sizes --location japaneast -o table
    

    --admin-username 指定預設登入的使用者名稱,預設值就是 azureuser

    --ssh-key-values 指定用來 SSH 遠端登入的 SSH Public Key 檔案。不過,在使用 PowerShell 執行時要特別注意 @ 符號的使用,你必須在 @id_rsa.pub 的前後加上單引號,確保命令可以正確傳入參數!如果在 Bash 環境的話,就比較沒這個問題。

    --custom-data 主要用來指定 cloud-init 的設定檔路徑,當 VM 部署後第一次開機,這個 Custom Data 會被自動複製到 /var/lib/waagent/ 目錄中,並儲存在 ovf-env.xml 檔案裡。

  3. 開啟防火牆設定

    以下命令主要用來開放特定 Port 可以讓 Internet 完全公開的存取:

    az vm open-port -g VM -n FrontNode --priority 900 --port 80
    
  4. 取得 Azure VM 的實體 IP 地址

    az vm show -d -g VM -n FrontNode --query publicIps -o tsv
    

常見問題解答

  1. 重新執行 cloud-init 自訂腳本

    我剛開始在嘗試 cloud-init 的時候,遇過幾次沒有全自動部署的情況,此時如果你要將 cloud-init 的設定檔重新在已經開機的 VM 上重新執行一遍,可以在 VM 中執行以下命令:

    sudo cloud-init clean
    sudo cloud-init init
    

相關連結

留言評論