# 2023 Windows & VMware IaC 開發及使用手冊 <style> .indent-title-1{ margin-left: 1em; } .indent-title-2{ margin-left: 2em; } .indent-title-3{ margin-left: 3em; } </style> ## 緣由 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;要**手動部屬**多台虛擬主機時,有高機率造成 **Human Error** ,會**產生大量時間成本** &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;虛擬化技術中,一個資料夾代表一台電腦,要設定每一台虛擬主機的 hostname, IP 位址, 名稱解析檔...等,此時容易發生 Human Error。 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;當每一台虛擬主機手動做好以上設定時,要將每一台虛擬主機先壓縮,此時必須坐在電腦前面,手動將每一台虛擬主機都壓縮,壓縮完後,再手動將每一個壓縮檔,派送到對應的實體 Windows 電腦,再手動將每一台虛擬主機的壓縮檔解壓縮,最後再進到每一台虛擬主機的目錄,將虛擬主機啟動。 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;以上動作,如果沒有事先規劃好,壓縮檔的檔名,要放在哪個目錄,哪一台虛擬機要派送到哪一台實體 Windows 電腦,要解壓縮到哪一個目錄,當叢集需要用到的 虛擬主機數量越大時,會造成管理上的不方便。 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;當以上動作完成,將已派送到對應 Windows 主機裡的虛擬主機都啟動後,又發現與當初規劃的規格不符,此時又要跳回第一步,會耗用大量時間成本。 ## 認識 IaC 伺服器環境的手動配置給 IT 專業人員帶來了一些挑戰,例如,由於不斷增加的複雜性和對 IT 基礎架構的相關需求。 Infrastructure as Code,中文翻為 "基礎架構程式碼" ,提供了一種替代方法,將基礎架構的提供、配置與管理方式自動化。 Infrastructure 以實體比喻的話,就是機房裡的 Server Iac 分為兩種方法,分別是 Declarative (聲明式) 和 Imperative (宣告式) 1. 聲明式主要說明基礎系統架構要完成甚麼目標、需要的資源或任何狀態 2. 宣告式定義了實現基礎系統架構所需的特定命令,並以正確的順序執行這些命令。 執行它的**好處**不僅可以**降低 Human Error** 、**縮短建置系統的時間**,還可以**確保每次都建立出一模一樣的基礎架構**。 舉例,在 `CNT.2023.v4.6` 的套件包裡面的 `docker.bat`, `k8s.bat`, `dt.bat` …等批次檔案,都能快速建立起,對應的基礎架構。 註解:IaC 技術幫我們從落地雲主機自動產生以及複製虛擬主機,並派送至多台不同的實體 Windows 10 主機 參考文章連結 : - [Understanding Infrastructure as Code (IaC) in less than 10 minutes](https://www.novatec-gmbh.de/en/blog/understanding-infrastructure-as-code-iac-in-less-than-10-minutes/) - [何謂基礎架構程式碼 (IaC)?](https://www.trendmicro.com/zh_tw/what-is/cloud-security/infrastructure-as-code.html) - [What is Infrastructure as Code (IaC)?](https://www.redhat.com/en/topics/automation/what-is-infrastructure-as-code-iac) --- # <font color=red>Windows & VMware IaC 平台設計</font> ## <font color=blue>平台目標</font> ### **自動化建置與管理分散型叢集系統基礎架構** 以 Kubernetes 架構範例 : - 一台 Master 主機 - 三台 Worker 主機 以 Hadoop 架構範例 : - 一台 Admin 機器 - 兩台 Master 機器 - M1 跑 Name Node, Secondary Name Node - M2 跑 Resource Manager, Jobhistory Server - 三台 Worker 機器 - 每一台機器都會跑 Data Node, Node Manager ## <font color=blue>重要操作步驟</font> 1. 設計叢集架構 (`mactohost`) 2. 產生虛擬電腦資料夾 3. 壓縮虛擬電腦資料夾 4. 派送虛擬電腦資料夾 5. 解壓縮所有虛擬主機壓縮檔 6. 啟動與檢視所有虛擬主機 7. 關閉所有虛擬主機 8. 備份與還原所有虛擬主機 9. 清除所有虛擬主機 ## <font color=blue>實體電腦硬體規格</font> - 多台實體 Windows 10 電腦 - 記憶體至少 24 G - CPU: 4 C / 2 HT 以上 - 須為靜態 IPv4 的 IP 位址 - 每台實體 Windows 10 電腦會分別跑一台或多台不同的虛擬電腦 ## <font color=blue>虛擬電腦硬體規格</font> - Linux 作業系統 - 記憶體 : 依建置叢集需求設定 - CPU : 依建置叢集需求設定 - 網路模式 : bridge ## <font color=blue>虛擬電腦網路設定</font> 根據叢集的大小來規劃 IP 位址、 Subnetmask 以及 Default Gateway --- # <font color=red>開始建置 C1 Cluster (1M3W)</font> ## <font color=blue>建置叢集系統前準備</font> <div class="indent-title-"> 1. **關閉防火牆** :::spoiler 步驟一 : 打開"檔案總管",滑鼠右鍵點選"網路",選擇 "內容" ![](https://i.imgur.com/dFF9CmH.png) ::: :::spoiler 步驟二 : 點選 "Windows Defender 防火牆" ![](https://i.imgur.com/rG9lAlg.png) ::: :::spoiler 步驟三 : 點選 "開啟或關閉 Windows Defender 防火牆" ![](https://i.imgur.com/DP0whdG.png) ::: :::spoiler 步驟四 : 在私人網路 和 公用網路 下,兩個都點選 "關閉 Windows Defender 防火牆(不建議)",再按確定 ![](https://i.imgur.com/13RxLl3.png) ::: 2. **確認實體 Windows 10 主機之間可用 `SSH` 連接** **測試命令** : ``` > ssh bigred@<要派送的實體 Windows 10 電腦 的 IP 位址> ``` 無法連線,請用滑鼠右鍵點選 Windows Powershell 圖示,選擇"以系統管理員身分執行",並執行以下命令 - **檢查 OpenSSH 目前的狀態** ``` PS > Get-WindowsCapability -Online | Where-Object Name -like 'OpenSSH*' ``` 如果 OpenSSH Server 沒有安裝,命令應返回以下輸出 : ``` Name : OpenSSH.Client~~~~0.0.1.0 State : Installed Name : OpenSSH.Server~~~~0.0.1.0 State : NotPresent ``` - **安裝 OpenSSH Server 命令** : ``` PS > Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0 ``` 螢幕輸出 : ``` Path : Online : True RestartNeeded : False ``` - **啟動 sshd 服務命令** ``` PS > Start-Service sshd ``` - **將 sshd 服務設為開機自動啟動** ``` PS > Set-Service -Name sshd -StartupType 'Automatic' ``` - **連線要派送虛擬主機壓縮檔的實體 Windows 10 電腦 的 IP 位址 測試** ``` > ssh bigred@<要派送的實體 Windows 10 電腦 的 IP 位址> ``` [註] [Install OpenSSH Server on Windows 10 官網連結](https://learn.microsoft.com/en-us/windows-server/administration/openssh/openssh_install_firstuse?tabs=powershell#install-openssh-for-windows) 3. **將連接 Windows 實體主機 使用者的密碼存入 `passwd` 檔案** ``` > notepad %USERPROFILE%\CNT.2023.v4.6\C1-1M3W\passwd ``` 4. **將連接 模板 虛擬主機 使用者的密碼存入 `passwd_vm` 檔案** ``` > notepad %USERPROFILE%\CNT.2023.v4.6\C1-1M3W\passwd_vm ``` 5. **請執行 VMware Player 這軟體以下設定** 步驟一 : `Player` > `File` > `Preferences...` 步驟二 : In the "`Software updates`" group > uncheck the "`Check for software components as needed`" option. 6. **確認被遠端控制的實體 Windows 主機,開放讓 psexec 遠端連接權限 用系統管理員身份打開 CMD,並執行以下命令** ``` reg add HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\system /v LocalAccountTokenFilterPolicy /t REG_DWORD /d 1 /f ``` [註] 1. 機碼修改後,需重啟電腦 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2. 如有安裝 F-Secure,請關閉 F-Secure 防火牆 參考文章連結 : [PsTools 於 Windows 10 的環境設定](http://pejslin.blogspot.com/2019/11/pstools-windows-10.html) 7. 確認 Windows 主機上當前的使用者家目錄下 ssh 的私鑰 `%USERPROFILE%\.ssh\id_rsa` 權限是否太開放, :::spoiler 示意圖 ![](https://i.imgur.com/4az6V2n.png) ::: 如果在群組或其他使用者這個欄位下,有其他人,那麼請執行以下命令 : ``` > cd %USERPROFILE%\CNT.2023.v4.6\C1-1M3W && sshsetup.bat ``` 螢幕輸出 : ``` SSH key Setup ok ! ``` :::spoiler 示意圖 ![](https://i.imgur.com/wgqDyZb.png) ::: </div> ## <div class="indent-title-1"><font color=blue>1. 設計 c1 叢集架構</font></div> ### <div class="indent-title-2">設定 c1 叢集架構檔 - `mactohost`</div> <div class="indent-title-3"> 在 Windows 中,打開 CMD ,執行以下命令 切換至工作目錄 ``` > cd CNT.2023.v4.6\C1-3M3W ``` 編輯 `c1mactohost` ``` > notepad c1mactohost ``` 檔案內容 : ```bash= # Default Cluster 00:00 x1 none 00:01 x2 VMware 00:02 x3 VMware 00:03 a1 admin 00:04 m1 master 00:05 m2 master 00:06 m3 master 00:07 w1 worker 00:08 w2 worker 00:09 w3 worker # K8S c1 Cluster ALP.K8S 10:f0 c1a1 admin 10:f1 c1m1 master c1m1.241.zip c1/alp.c1m1 120.96.143.170 10:f2 c1m2 master 10:f3 c1m3 master 10:f4 c1e1 etcd 10:f5 c1w1 worker c1w1.245.zip c1/alp.c1w1 120.96.143.170 10:f6 c1w2 worker c1w2.246.zip c1/alp.c1w2 120.96.143.171 10:f7 c1w3 worker c1w3.247.zip c1/alp.c1w3 120.96.143.171 10:f8 c1w4 worker 10:f9 c1w5 worker ``` ### **欄位說明 (用 空格 做切割)** : - 先單獨看第 12 行內容, <pre># K8S <font color=red>c1</font> Cluster <font color=red>ALP.K8S</font></pre> - 第三欄 <font color=red>`c1`</font> 會與 `CNT.2023.V4.6\C1-1A3M\c1mactohost` 這個檔案的前兩個字 `c1` 比較,所以不能亂設定 - 第五欄 <font color=red>`ALP.K8S`</font> 設定 模板機的目錄名稱 - 模板機必須放在 `%USERPROFILE%\CNT.2023.v4.6\`目錄下 - 第一欄為 設定 VM 主機 的 Mac Address 最後兩個位元 (byte) - 用冒號分隔的格式 : 前半部是 c1 = 10, c2 = 20... 依此類推 **後半部是 VM 的 IP 位址尾數換算為 16 進位** - 舉例 : 假設現在要設定的是 c1 叢集裡面 IP 位址尾數 `.210` 的 VM, 依照上述規則,得到的答案 : `10:d2` :::danger **Note:** &nbsp; &nbsp; **1. 16 進位中的英文需設為小寫** &nbsp; &nbsp; **2. 不能設為 : `10:xx` ,會導致虛擬機器的 `/etc/hosts` 無法正常解析 ! &nbsp; &nbsp; 3. 在此檔案中的任何一台 VM 的 Mac Address 不可重複** ::: - 第二欄為 設定 VM 主機名稱 - 格式 : 叢集名稱 + mactohost 第三欄位的第一個字 + 序號(從 1 開始) - 第三欄為 各 VM 的角色扮演 - 第四欄為 VM 目錄壓縮檔名 - 格式 : VM 主機名稱 + VM IP 位址的尾數 + 壓縮檔的附檔名 (.zip) - 第五欄為 VM 存放的目錄名稱 - 格式 : `叢集名稱/us.主機名稱` (us = Ubuntu Server 的縮寫) - 格式 : `叢集名稱/alp.主機名稱` (alp = Alpine Linux 的縮寫) - 第六欄為 VM 要分配到哪一台實體電腦的 IP 位址 </div> ## <div class="indent-title-1"><font color=blue>2. 建立 c1 叢集所有虛擬主機</font></div> <div class="indent-title-3"> create.bat 程式概述 : 在落地雲主機的 `C:\Users\bigred\CNT.2023.v4.6\C1-1M3W` 目錄下,做出 c1 的資料夾,並在 c1 目錄下建立 4 台虛擬機 **[重要] 根據實體電腦的記憶體來修改 vmcreate.bat 中 RSMMAX 變數直的大小** :::spoiler 完整程式內容 ```bash! @echo off REM 設定 Cluster Name for /f "tokens=1" %%y in ('dir /B ^| findstr "mactohost"') do ( set mactohost=%%y ) for /f "tokens=3 delims= " %%z in ('type %mactohost% ^| more +11 ^| findstr "#"') do ( set CN=%%z ) REM 判斷 Cluster Name 有沒有設定錯誤 if NOT %mactohost:~0,2% == %CN% ( echo "Cluster Name Error !" GOTO:eof ) if exist %CN%\ ( echo "%CN% Folder existed !" GOTO:eof ) REM 設定 模板機所在目錄名稱 和 模板機的 vmx 檔案位置 變數 for /f "skip=1 tokens=5 delims= " %%a in ('type %mactohost% ^| findstr Cluster') do ( set vmfolder=%%a for /f "tokens=1" %%g in ('dir /S /B ..\%%a\ ^| findstr vmx$') do ( set vmx=%%g ) ) REM 將 c*mactohost 中 實體 Windows 主機的 IP 匯入 ip.txt 檔案中 if exist ip.txt (del ip.txt) for /f "skip=12 tokens=6 delims= " %%y in (%mactohost%) do ( echo %%y >> ip.txt ) REM 判斷要派送的主機 22 port 有沒有開, psexec 功能是否正常 setlocal EnableDelayedExpansion for /f "tokens=1 delims= " %%h in ('type ip.txt ^| sort.exe /unique') do ( for /f "tokens=1" %%p in ('powershell -command "& {(New-Object System.Net.Sockets.TcpClient).ConnectAsync('%%h', 22).Wait(100)}"') do ( if %%p == False echo "%%h SSH Error" && GOTO:eof ) REM 設定本機 IP 變數 for /f "delims=[] tokens=2" %%e in ('ping -4 -n 1 %ComputerName% ^| findstr [') do ( set HostIP=%%e ) if not defined HostIP "echo !HostIP! should manual configuration in %~nx0" if not !HostIP! == %%h ( psexec -accepteula -nobanner \\%%h -s "hostname" > nul 2> nul ) if !ERRORLEVEL! NEQ 0 ( echo "%%h psexec Error" && GOTO:eof ) ) del ip.txt 2> nul > nul REM 判斷 VM 使用的 IP 目前有無被占用 for /f "skip=12 tokens=4,6 delims= " %%a in (%mactohost%) do ( for /f "tokens=1-3 delims=." %%x in ('echo %%b') do ( for /f "tokens=2 delims=." %%i in ('echo %%a') do ( ping -n 1 %%x.%%y.%%z.%%i | find "TTL" 2> nul >nul if !ERRORLEVEL! EQU 0 echo "%%x.%%y.%%z.%%i is already being used." && GOTO:eof ) ) ) ) REM 判斷 10 進位轉 16 進位有沒有算錯 for /f "tokens=1,2 delims=." %%k in ('type %mactohost% ^| findstr zip') do ( for /f "tokens=2 delims=:" %%s in ("%%k") do ( for /f "tokens=1" %%o in ("%%s") do ( set "h=%%o" set "DEC=%%l" cmd /C exit !DEC! set "HEX=!=ExitCode!" for /F "tokens=* delims=0" %%Z in ("!HEX!") do ( if /I !DEC! LSS 16 ( set "HEX=0%%Z" for /F "delims=" %%r in ('powershell -command " '!HEX!'.ToLower() "') do ( set "SHEX=%%r" if NOT "!h!" EQU "!SHEX!" echo The hexadecimal representation of !DEC! is !SHEX!, not !h!. && GOTO:eof ) ) else ( set "HEX=%%Z" for /F "delims=" %%r in ('powershell -command " '!HEX!'.ToLower() "') do ( set "SHEX=%%r" if NOT "!h!" EQU "!SHEX!" echo The hexadecimal representation of !DEC! is !SHEX!, not !h!. && GOTO:eof ) ) ) ) ) ) REM 設定 VM 可用記憶體範圍 powershell -Command "(Get-CimInstance Win32_PhysicalMemory | Measure-Object -Property capacity -Sum).sum /8Mb" > max.txt powershell -Command "(Get-CimInstance Win32_PhysicalMemory | Measure-Object -Property capacity -Sum).sum /8Mb" > min.txt set /P MAX=<max.txt set /P MIN=<min.txt for /f "tokens=2 delims==" %%a in ('type %vmx% ^| findstr memsize') do ( set mem=%%a ) set RSMMAX='memsize = \"%mem:~2,-1%\"', 'memsize = \"%MAX%\"' set RSMMIN='memsize = \"%mem:~2,-1%\"', 'memsize = \"%MIN%\"' set RSADR1='ethernet0.generatedAddressOffset = \"0\"' set RSADR2='ethernet0.addressType = \"generated\"' , 'ethernet0.addressType = \"static\"' set RSTYPE='ethernet0.connectionType = \"nat\"' , 'ethernet0.connectionType = \"bridge\"' for %%i in (vmfolder vmx mem) do ( if not defined %%i ( echo %%i not defined && GOTO:eof ) ) REM 上載 mactohosts 至 模板 虛擬主機 "C:\Program Files (x86)\VMware\VMware Player\vmrun" start "%vmx%" > nul timeout /t 60 > nul "C:\Program Files (x86)\VMware\VMware Player\vmrun" getGuestIPAddress "%vmx%" > admip.txt set /P admip=<admip.txt echo y | pscp -pwfile "passwd_vm" ".\%CN%mactohost" bigred@%admip%:/home/bigred/bin/mactohost 2> nul > nul if %ERRORLEVEL% EQU 0 echo "%CN%mactohost scp ok" echo y | pscp -pwfile "passwd_vm" bigred@%admip%:/home/bigred/.ssh/* %USERPROFILE%\.ssh\ 2> nul > nul if %ERRORLEVEL% EQU 0 echo "%admip% .ssh/* scp ok" del %USERPROFILE%\.ssh\known_hosts 2> nul del %USERPROFILE%\.ssh\known_hosts.old 2> nul type %vmx% | findstr Ubuntu > nul 2> nul if %ERRORLEVEL% NEQ 0 ( ssh -o "ConnectTimeout=5" -o "StrictHostKeyChecking=no" bigred@%admip% "sudo apk update; sudo apk upgrade" > nul 2>nul if !ERRORLEVEL! EQU 0 echo "System upgrade ok" ) else ( ssh -o "ConnectTimeout=5" -o "StrictHostKeyChecking=no" bigred@%admip% "sudo apt update; sudo apt -y upgrade; sudo apt -y autoremove" > nul 2>nul if !ERRORLEVEL! EQU 0 echo "System upgrade ok" ) "C:\Program Files (x86)\VMware\VMware Player\vmrun" stop "%vmx%" > nul timeout /t 60 > nul REM 設定模板機 displayName 變數 for /f "tokens=2 delims==" %%a in ('type %vmx% ^| findstr displayName') do ( set odn=%%a ) REM 設定模板機 mac address 變數 for /f "tokens=2 delims==" %%a in ('type %vmx% ^| findstr "ethernet0.generatedAddress" ^| findstr ":"') do ( set vmac=%%a ) for %%j in (odn vmac) do ( if not defined %%j ( echo %%j not defined && GOTO:eof ) ) REM 建立 Cluster 的所有 VM if exist %mactohost% ( if not exist %CN%\ ( mkdir %CN% > nul if %ERRORLEVEL% EQU 0 ( for /f "tokens=1-6 delims= " %%a in ('findstr zip %mactohost%') do ( set x=%%~nxe set RS='displayName = \"%odn:~2,-1%\"', 'displayName = \"!x!\"' set y=%%a set RSMAC='ethernet0.generatedAddress = \"%vmac:~2,-1%\"' , 'ethernet0.address = \"00:50:56:ab:!y!\"' mkdir %CN%\!x! > nul xcopy /E /Y ..\%vmfolder% %CN%\!x!\ > nul for /f "tokens=1" %%p in ('dir %CN%\!x! /B /S ^| findstr vmx$') do set nvmx=%%p powershell -Command "(gc !nvmx!) -replace "!RS!" -replace "!RSMAC!" -replace "%RSMMAX%" -replace "%RSTYPE%" -replace "%RSADR1%" -replace "%RSADR2%" | Out-File -Encoding "UTF8" vm.temp" del /Q !nvmx! copy /Y vm.temp !nvmx! > nul if !ERRORLEVEL! EQU 0 echo "%CN%\!x!\ (%MAX%) ok" ) del *.txt > nul del vm.temp > nul ) ) ) ``` ::: ### 執行建立 c1 叢集命令 在執行命令前,請先確定是否已完成 [叢集系統準備](https://hackmd.io/NyMWv5u5Rlm-ip-9CHi3Tg?both#%E5%8F%A2%E9%9B%86%E7%B3%BB%E7%B5%B1%E6%BA%96%E5%82%99) 在 Windows 工作目錄 `CNT.2023.v4.6\c1-1M3W` 下,執行程式 ```bash! > vmcreate.bat ``` 螢幕輸出 ```! "c1mactohost scp ok" "192.168.61.131 .ssh/* scp ok" "System upgrade ok" "c1\alp.c1m1\ (4096) ok" "c1\alp.c1w1\ (4096) ok" "c1\alp.c1w2\ (4096) ok" "c1\alp.c1w3\ (4096) ok" ``` [註] 如遇到需要輸入密碼,請參考以下連結 : &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[Windows SSH: Permissions for 'private-key' are too open](https://superuser.com/questions/1296024/windows-ssh-permissions-for-private-key-are-too-open) </div> ## <div class="indent-title-1"><font color=blue>3. 壓縮 c1 叢集所有虛擬主機</font></div> <div class="indent-title-3"> zip.bat 程式概述 : 此程式使用 7z 作為虛擬主機目錄的壓縮命令 :::spoiler 完整程式內容 ```bash! @echo off REM 設定 Cluster Name for /f "tokens=1" %%y in ('dir /B ^| findstr "mactohost"') do ( set CN=%%y ) REM 在 mactohost 中抓取壓縮時需要的字串 if exist %CN:~0,2%zip.txt (del %CN:~0,2%zip.txt > nul) for /f "tokens=3,* delims= " %%a in (%CN:~0,2%mactohost) do echo %%b | findstr zip >> %CN:~0,2%zip.txt REM 透過 For 迴圈,逐行代變數壓縮 VM 所在的資料夾 setlocal EnableDelayedExpansion for /f "tokens=1,2 delims= " %%a in (%CN:~0,2%zip.txt) do ( 7z\7z -mx1 a %CN:~0,2%\%%a %%b > nul if !ERRORLEVEL! EQU 0 (echo "%%a ok") ) del %CN:~0,2%zip.txt > nul ``` ::: ### 執行壓縮程式 ```bash! > vmzip.bat ``` 螢幕輸出 ```! "c1m1.141.zip ok" "c1w1.145.zip ok" "c1w2.146.zip ok" "c1w3.147.zip ok" ``` </div> ## <div class="indent-title-1"><font color=blue>4. 派送 c1 叢集所有虛擬主機</font></div> <div class="indent-title-3"> scp.bat 概述 : 使用 pscp.exe 命令,將 c1 叢集每一台虛擬主機的壓縮檔派送到 mactohost 中設定對應的各台實體 Windows 主機 :::spoiler 完整程式內容 ```bash! @echo off REM 判斷叢集名稱 for /f "tokens=1" %%y in ('dir /B ^| findstr "mactohost"') do ( set CN=%%y ) REM 設定本機 IP 變數 for /f "delims=[] tokens=2" %%e in ('ping -4 -n 1 %ComputerName% ^| findstr [') do ( set HostIP=%%e ) REM 抓取在 d*mactohost 中,每一台虛擬主機的相關資訊,並將資料逐行匯入 d*scp.txt if exist %CN:~0,2%scp.txt (del %CN:~0,2%scp.txt > nul) for /f "tokens=1* delims= " %%a in (%CN:~0,2%mactohost) do echo %%b | findstr zip >> %CN:~0,2%scp.txt REM 將每一台虛擬主機的壓縮檔透過 pscp 命令,派送至對應的實體 Windows 主機的使用者家目錄 setlocal EnableDelayedExpansion for /f "tokens=3,5 delims= " %%a in (%CN:~0,2%scp.txt) do ( if %%b == %HostIP% ( xcopy /Y %CN:~0,2%\%%a %USERPROFILE%\ > nul if !ERRORLEVEL! EQU 0 ( echo "%%a to %%b ok" ) else ( echo "%%a to %%b failed" ) ) else ( echo y | pscp -scp -q -pwfile passwd "%CN:~0,2%\%%a" %USERNAME%@%%b:"%%a" 2> nul > nul if !ERRORLEVEL! EQU 0 ( echo "%%a to %%b ok" ) else ( echo "%%a to %%b failed" ) ) ) del %CN:~0,2%scp.txt > nul ``` ::: ### 執行程式 ```bash! > vmscp.bat ``` 螢幕輸出 ```! "c1m1.141.zip to 120.96.143.152 ok" "c1w1.145.zip to 120.96.143.152 ok" "c1w2.146.zip to 120.96.143.153 ok" "c1w3.147.zip to 120.96.143.153 ok" ``` </div> ## <div class="indent-title-1"><font color=blue>5. 解壓縮所有虛擬主機壓縮檔至落地雲主機</font></div> <div class="indent-title-3"> unzip.bat 程式概述 : 本程式在本機使用 7z 將 虛擬主機的壓縮檔解壓縮,遠端的主機使用 Windows Powershell 的 Expand-Archive 命令 :::spoiler 完整程式內容 ```bash! @echo off REM 判斷叢集名稱 for /f "tokens=1" %%y in ('dir /B ^| findstr "mactohost"') do ( set CN=%%y ) REM 設定本機 IP 變數 for /f "delims=[] tokens=2" %%a in ('ping -4 -n 1 %ComputerName% ^| findstr [') do ( set HostIP=%%a ) REM 解壓縮在本地或遠端的虛擬主機壓縮檔 for /f "skip=12 tokens=4-6 delims= " %%a in (%CN:~0,2%mactohost) do ( if %%c == %HostIP% ( setlocal EnableDelayedExpansion "%ProgramFiles%\7-Zip\7z" "x" "C:\Users\%USERNAME%\%%a" "-oC:\Users\%USERNAME%" > nul 2> nul if !ERRORLEVEL! EQU 0 ( echo "%%c %CN:~0,2%\%%~nxb unzip ok !" ) else ( echo "%%c %CN:~0,2%\%%~nxb unzip Failed !" ) setlocal DisableDelayedExpansion ) else ( for /f "tokens=1 delims= " %%i in ('PsExec.exe -accepteula -nobanner \\%%c -s "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" "-Command" "Test-Path" "-Path" "C:\Users\%USERNAME%\%CN:~0,2%\%%~nxb" ^2^>nul') do ( if %%i == True ( psexec -accepteula -nobanner \\%%c -s "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" "-Command" "Remove-Item" "C:\Users\%USERNAME%\%CN:~0,2%\%%~nxb" "-Recurse" 2> nul psexec -accepteula -nobanner \\%%c -s "powershell" "-Command" "Expand-Archive" "-LiteralPath" "C:\Users\%USERNAME%\%%a" "-DestinationPath" "C:\Users\%USERNAME%" 2> nul ) else ( psexec -accepteula -nobanner \\%%c -s "powershell" "-Command" "Expand-Archive" "-LiteralPath" "C:\Users\%USERNAME%\%%a" "-DestinationPath" "C:\Users\%USERNAME%" 2> nul ) ) for /f "tokens=1 delims= " %%i in ('PsExec.exe -accepteula -nobanner \\%%c -s "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" "-Command" "Test-Path" "-Path" "C:\Users\%USERNAME%\%CN:~0,2%\%%~nxb" ^2^>nul') do ( if %%i == True ( echo "%%c %CN:~0,2%\%%~nxb unzip ok !" ) else ( echo "%%c %CN:~0,2%\%%~nxb unzip Failed !" ) ) ) ) ``` ::: [註] `%%~nxb`,在範例中 `%%b` 為包含目錄的檔案名稱 : `c1/alp.c1w1`, `%%~nb` - 顯示 `alp` (`%%b` 的 檔名) `%%~xb` - 顯示 `.c1w1` ( `%%b` 的副檔名,包含 `.`) ### 執行解壓縮程式 ```bash! > vmunzip.bat ``` 螢幕輸出 ```! "120.96.143.152 c1\alp.c1m1 unzip ok !" "120.96.143.152 c1\alp.c1w1 unzip ok !" "120.96.143.153 c1\alp.c1w2 unzip ok !" "120.96.143.153 c1\alp.c1w3 unzip ok !" ``` </div> ## <div class="indent-title-1"><font color=blue>6. 啟動與檢視 c1 叢集所有虛擬主機</font></div> <div class="indent-title-3"> start.bat 程式概述 : 使用 VMware 的 vmrun 命令,配合 psexec 命令將 遠端 Windows 實體主機中的 虛擬主機啟動 :::spoiler 完整程式內容 ```bash! @echo off REM 判斷叢集名稱 for /f "tokens=1" %%y in ('dir /B ^| findstr "mactohost"') do ( set CN=%%y ) REM 設定本機 IP 變數 for /f "delims=[] tokens=2" %%a in ('ping -4 -n 1 %ComputerName% ^| findstr [') do ( set HostIP=%%a ) setlocal EnableDelayedExpansion for /f "tokens=6 delims= " %%a in (%CN:~0,2%mactohost) do ( for /f "tokens=1" %%k in ('dir %USERPROFILE%\%CN:~0,2% /S /B ^| findstr vmx$') do ( for /f "tokens=5,* delims=\" %%l in ("%%k") do ( set hostvmx=%%m ) ) for /f "tokens=1" %%x in ('PsExec.exe -accepteula -nobanner \\%%a -s "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" "-Command" "Get-ChildItem" "-Path" "%USERPROFILE%\%CN:~0,2%" "-Name" "-Recurse" "-Force" ^2^>nul ^| findstr vmx$') do ( for /f "tokens=1,* delims=\" %%y in ("%%x") do ( set remotevmx=%%z ) ) ) REM 啟動每一台虛擬主機 for /f "skip=12 tokens=4-6 delims= " %%a in (%CN:~0,2%mactohost) do ( if %%c == %HostIP% ( "C:\Program Files (x86)\VMware\VMware Player\vmrun" start "C:\Users\%USERNAME%\%CN:~0,2%\%%~nxb\%hostvmx%" nogui 2> nul > nul if !ERRORLEVEL! EQU 0 ( echo "%CN:~0,2%\%%~nxb started" ) else ( echo "%CN:~0,2%\%%~nxb failed" ) timeout /t 5 > nul ) else ( psexec \\%%c -accepteula -nobanner -s "C:\Program Files (x86)\VMware\VMware Player\vmrun" "start" "C:\Users\%USERNAME%\%CN:~0,2%\%%~nxb\%remotevmx%" "nogui" 2> nul > nul if !ERRORLEVEL! EQU 0 ( echo "%CN:~0,2%\%%~nxb started" ) else ( echo "%CN:~0,2%\%%~nxb failed" ) timeout /t 5 > nul ) ) ``` ::: ### 1. 執行啟動 c1 叢集所有虛擬主機命令 ```bash! > vmstart.bat ``` 螢幕輸出 ```! "c1\alp.c1m1 started" "c1\alp.c1w1 started" "c1\alp.c1w2 started" "c1\alp.c1w3 started" ``` ### 2. 在 Windows 檢視已開啟的虛擬電腦 list.bat 程式概述 : 透過 ssh 遠端對虛擬主機執行命令,並檢視 虛擬主機的狀態 :::spoiler 完整程式 : ``` @echo off REM 判斷叢集名稱 for /f "tokens=1" %%y in ('dir /B ^| findstr "mactohost"') do ( set CN=%%y ) REM 先用 ping 命令,檢測每一台虛擬主機網路,有回應則用 ssh 命令遠端對虛擬主機執行命令 for /f "skip=12 tokens=4,6 delims= " %%a in (%CN:~0,2%mactohost) do ( for /f "tokens=1-3 delims=." %%x in ('echo %%b') do ( for /f "tokens=2 delims=." %%i in ('echo %%a') do ( ping -n 2 "%%x.%%y.%%z.%%i" | find "TTL" 2> nul > nul if errorlevel 1 ( echo "%%x.%%y.%%z.%%i not running" ) else ( ssh -o "ConnectTimeout=5" -o "StrictHostKeyChecking=no" bigred@"%%x.%%y.%%z.%%i" "n=$(hostname;hostname -i); echo $n running" 2> nul ) ) ) ) ``` ::: ### 執行檢測命令 ``` > vmlist.bat ``` 螢幕輸出 : ``` c1m1 120.96.143.141 running c1w1 120.96.143.145 running c1w2 120.96.143.146 running c1w3 120.96.143.147 running ``` [註] 如將 VM 開機後,遇到類似以下錯誤訊息 ``` `8f: value too great for base (error token is "8f")` ``` 請將 `/home/bigred/bin/chnameip` 程式中原本的 51 行命令 `ip=$((16#$v))` ,修改為 `ip=$(printf "%d\n" 0x"$v")` </div> ## <div class="indent-title-1"><font color=blue>7. 關閉 c1 叢集所有虛擬主機</font></div> <div class="indent-title-3"> stop.bat 程式概述 : 利用 ssh 遠端對虛擬主機執行 sudo poweroff 的命令,將虛擬主機關閉 :::spoiler 完整程式內容 ```bash! @echo off REM 判斷叢集名稱 for /f "tokens=1" %%y in ('dir /B ^| findstr "mactohost"') do ( set CN=%%y ) REM 利用 ssh 遠端對每一台虛擬主機執行關機命令 setlocal EnableDelayedExpansion for /f "skip=12 tokens=4,6 delims= " %%a in (%CN:~0,2%mactohost) do ( for /f "tokens=1-3 delims=." %%x in ('echo %%b') do ( for /f "tokens=2 delims=." %%i in ('echo %%a') do ( ping -n 2 "%%x.%%y.%%z.%%i" | find "TTL" 2> nul > nul if errorlevel 1 ( echo "%%x.%%y.%%z.%%i not running" ) else ( ssh -o "ConnectTimeout=5" -o "StrictHostKeyChecking=no" bigred@"%%x.%%y.%%z.%%i" "sudo poweroff; exit" 2> nul > nul if !ERRORLEVEL! EQU 0 ( echo "%%x.%%y.%%z.%%i stoped" ) else ( if !ERRORLEVEL! EQU -1 echo "%%x.%%y.%%z.%%i stoped" ) ) ) ) ) ``` ::: ### 執行關機 c1 叢集所有虛擬主機 命令 ```bash! > vmstop.bat ``` 螢幕輸出 ```! "120.96.143.141 stoped" "120.96.143.145 stoped" "120.96.143.146 stoped" "120.96.143.147 stoped" ``` </div> ## <div class="indent-title-1"><font color=blue>8. 備份與還原 c1 叢集所有虛擬主機</font></div> <div class="indent-title-3"> backup.bat 程式概述 : 如果虛擬主機在本機,會透過 7z 壓縮,如果在遠端,會配合 psexec 命令,壓縮遠端的虛擬主機 :::spoiler 完整程式內容 ```bash! @echo off REM 判斷叢集名稱 for /f "tokens=1" %%y in ('dir /B ^| findstr "mactohost"') do ( set CN=%%y ) REM 設定本機 IP 變數 for /f "delims=[] tokens=2" %%e in ('ping -4 -n 1 %ComputerName% ^| findstr [') do ( set HostIP=%%e ) REM 先用 ping 命令,檢測每一台虛擬主機是否已關機 setlocal EnableDelayedExpansion for /f "skip=12 tokens=4,6 delims= " %%a in (%CN:~0,2%mactohost) do ( for /f "tokens=1-3 delims=." %%x in ('echo %%b') do ( for /f "tokens=1,2 delims=." %%i in ('echo %%a') do ( ping -n 2 "%%x.%%y.%%z.%%j" | find "TTL" 2> nul > nul if !ERRORLEVEL! == 0 ( echo "Please Execute vmstop.bat" && GOTO:eof ) ) ) ) for /f "skip=12 tokens=4-6 delims= " %%a in (%CN:~0,2%mactohost) do ( if %%c == %HostIP% ( if not exist "%USERPROFILE%\7-Zip" ( xcopy /E /Y ".\7z" "%USERPROFILE%\7-Zip\" > nul ) "%USERPROFILE%\7-Zip\7z" -mx1 a "C:\Users\%USERNAME%\%%a.bak" "C:\Users\%USERNAME%\%%b" 2> nul > nul if !ERRORLEVEL! EQU 0 ( echo "%%c %%a.bak backup ok !" ) else ( echo "%%c %%a.bak backup failed !" ) ) else ( for /f "tokens=1 delims= " %%i in ('PsExec.exe -accepteula -nobanner \\%%c -s "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" "-Command" "Test-Path" "-Path" "%USERPROFILE%\7-Zip" ^2^>nul') do ( if %%i == False ( echo y | pscp -scp -pwfile passwd -q -r ".\7z" %USERNAME%@%%c:"%USERPROFILE%\7-Zip\" ) ) for /f "tokens=1 delims= " %%i in ('PsExec.exe -accepteula -nobanner \\%%c -s "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" "-Command" "Test-Path" "-Path" "C:\Users\%USERNAME%\%CN:~0,2%\%%~nxb" ^2^>nul') do ( if %%i == True ( psexec -accepteula -nobanner \\%%c -s "%USERPROFILE%\7-Zip\7z" "-mx1" "a" "C:\Users\%USERNAME%\%%a.bak" "C:\Users\%USERNAME%\%%b" 2> nul > nul if !ERRORLEVEL! EQU 0 ( echo "%%c %%a.bak backup ok !" ) else ( echo "%%c %%a.bak backup failed !" ) ) else ( echo "C:\Users\%USERNAME%\%CN:~0,2%\%%~nxb VM folder not found !" GOTO:eof ) ) ) ) ``` ::: ### 執行備份 c1 叢集所有虛擬主機 命令 ``` > vmbackup.bat ``` 螢幕輸出 : ``` "120.96.143.152 c1m1.141.zip.bak backup ok " "120.96.143.152 c1w1.145.zip.bak backup ok " "120.96.143.153 c1w2.146.zip.bak backup ok " "120.96.143.153 c1w3.147.zip.bak backup ok " ``` 執行失敗的螢幕輸出 ```! "Please Execute vmstop.bat" ``` 可能原因 : 只要有一台 c1 cluster VM 沒關,就會噴出此錯誤訊息 **[註] 新的備份檔會直接覆蓋掉舊的備份檔** ### 執行還原 c1 叢集所有虛擬主機命令 restore.bat 程式概述 : 如果虛擬主機在本機,會透過 7z 解壓縮,如果在遠端,會配合 psexec 命令,解壓縮遠端的虛擬主機 :::spoiler 完整程式內容 ```bash! @echo off REM 判斷叢集名稱 for /f "tokens=1" %%y in ('dir /B ^| findstr "mactohost"') do ( set CN=%%y ) REM 設定本機 IP 變數 for /f "delims=[] tokens=2" %%e in ('ping -4 -n 1 %ComputerName% ^| findstr [') do ( set HostIP=%%e ) REM 先用 ping 命令,檢測每一台虛擬主機是否已關機 setlocal EnableDelayedExpansion for /f "skip=12 tokens=4,6 delims= " %%a in (%CN:~0,2%mactohost) do ( for /f "tokens=1-3 delims=." %%x in ('echo %%b') do ( for /f "tokens=1,2 delims=." %%i in ('echo %%a') do ( ping -n 2 "%%x.%%y.%%z.%%j" | find "TTL" 2> nul > nul if !ERRORLEVEL! == 0 ( echo "Please Execute vmstop.bat" && GOTO:eof ) ) ) ) for /f "skip=12 tokens=4-6 delims= " %%a in (%CN:~0,2%mactohost) do ( if %%c == %HostIP% ( if exist "C:\Users\%USERNAME%\%CN:~0,2%\%%~nxb" ( RD /S /Q "C:\Users\%USERNAME%\%CN:~0,2%\%%~nxb" > nul 2> nul "%USERPROFILE%\7-Zip\7z" x "C:\Users\%USERNAME%\%%a.bak" "-oC:\Users\%USERNAME%\%CN:~0,2%" > nul 2> nul ) else ( "%USERPROFILE%\7-Zip\7z" x "C:\Users\%USERNAME%\%%a.bak" "-oC:\Users\%USERNAME%\%CN:~0,2%" > nul 2> nul ) if exist "C:\Users\%USERNAME%\%CN:~0,2%\%%~nxb" ( echo "%%c %CN:~0,2%\%%~nxb restore ok !" ) else ( echo "%%c %CN:~0,2%\%%~nxb restore Failed !" ) ) else ( for /f "tokens=1 delims= " %%i in ('PsExec.exe -accepteula -nobanner \\%%c -s "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" "-Command" "Test-Path" "-Path" "C:\Users\%USERNAME%\%CN:~0,2%\%%~nxb" ^2^>nul') do ( if %%i == True ( psexec -accepteula -nobanner \\%%c -s "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" "-Command" "Remove-Item" "C:\Users\%USERNAME%\%CN:~0,2%\%%~nxb" "-Recurse" 2> nul psexec -accepteula -nobanner \\%%c -s "%USERPROFILE%\7-Zip\7z" "x" "C:\Users\%USERNAME%\%%a.bak" "-oC:\Users\%USERNAME%\%CN:~0,2%" > nul 2> nul ) else ( psexec -accepteula -nobanner \\%%c -s "%USERPROFILE%\7-Zip\7z" "x" "C:\Users\%USERNAME%\%%a.bak" "-oC:\Users\%USERNAME%\%CN:~0,2%" > nul 2> nul ) ) for /f "tokens=1 delims= " %%i in ('PsExec.exe -accepteula -nobanner \\%%c -s "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" "-Command" "Test-Path" "-Path" "C:\Users\%USERNAME%\%CN:~0,2%\%%~nxb" ^2^>nul') do ( if %%i == True ( echo "%%c %CN:~0,2%\%%~nxb restore ok !" ) else ( echo "%%c %CN:~0,2%\%%~nxb restore Failed !" ) ) ) ) ``` ::: ``` > vmrestore.bat ``` 螢幕輸出 : ``` "120.96.143.152 c1\alp.c1m1 restore ok " "120.96.143.152 c1\alp.c1w1 restore ok " "120.96.143.153 c1\alp.c1w2 restore ok " "120.96.143.153 c1\alp.c1w3 restore ok " ``` 執行失敗的螢幕輸出 ```! "Please Execute vmstop.bat" ``` 可能原因 : 只要有一台 c1 cluster VM 沒關,就會噴出此錯誤訊息 </div> ## <div class="indent-title-1"><font color=blue>9. 清除 c1 叢集所有虛擬主機</font></div> <div class="indent-title-3"> del.bat 程式概述 : 如果虛擬主機在本地,會利用 Windows Powershell 的 Remove-Item 命令,刪除 c1 叢集所有虛擬主機、壓縮檔、本地的 c1 目錄,如果虛擬主機在遠端,會利用 Remove-Item 命令 配合 psexec 命令刪除 :::spoiler 完整程式內容 : ```bash! @echo off REM 設定 Cluster Name for /f "tokens=1" %%y in ('dir /B ^| findstr "mactohost"') do ( set CN=%%y ) REM 設定本機 IP 變數 for /f "delims=[] tokens=2" %%a in ('ping -4 -n 1 %ComputerName% ^| findstr [') do ( set HostIP=%%a ) REM 判斷是否已備份 for /f "tokens=4-6 delims= " %%a in ('type %CN:~0,2%mactohost ^| findstr zip') do ( if %%c == %HostIP% ( if not exist %HOMEPATH%\%%a.bak ( echo "Please Execute vmbackup.bat first" && GOTO:eof ) ) else ( for /f "tokens=1 delims= " %%i in ('PsExec.exe -accepteula -nobanner \\%%c -s "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" "-Command" "Test-Path" "-Path" "C:\Users\%USERNAME%\%%a.bak" ^2^>nul') do ( if %%i == False ( echo "Please Execute vmbackup.bat first" && GOTO:eof ) ) ) ) REM 先用 ping 命令,檢測每一台虛擬主機是否已關機 setlocal EnableDelayedExpansion for /f "skip=12 tokens=4,6 delims= " %%a in (%CN:~0,2%mactohost) do ( for /f "tokens=1-3 delims=." %%x in ('echo %%b') do ( for /f "tokens=1,2 delims=." %%i in ('echo %%a') do ( ping -n 2 "%%x.%%y.%%z.%%j" | find "TTL" 2> nul > nul if !ERRORLEVEL! == 0 ( echo "Please Execute vmstop.bat" && GOTO:eof ) ) ) ) REM 將 d*mactohost 中 實體 Windows 主機的 IP 匯入 ip.txt 檔案中 if exist ip.txt (del ip.txt) for /f "skip=12 tokens=6 delims= " %%y in (%CN:~0,2%mactohost) do echo %%y >> ip.txt REM 刪除 ip.txt 檔案中每一台實體 Windows 電腦 使用者家目錄中以叢集為名稱的目錄 setlocal EnableDelayedExpansion for /f "tokens=1 delims= " %%x in ('type ip.txt ^| sort.exe /unique') do ( if %%x == %HostIP% ( "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -Command Remove-Item C:\Users\%USERNAME%\%CN:~0,2% -Recurse 2> nul if !ERRORLEVEL! EQU 0 ( echo "%%x %CN:~0,2% folder deleted !" ) else ( echo "%%x %CN:~0,2% folder does not exist !" ) ) else ( psexec -accepteula -nobanner \\%%x -s "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" "-Command" "Remove-Item" "C:\Users\%USERNAME%\%CN:~0,2%" "-Recurse" 2> nul if !ERRORLEVEL! EQU 0 ( echo "%%x %CN:~0,2% folder deleted !" ) else ( echo "%%x %CN:~0,2% folder does not exist !" ) ) ) REM 刪除在本地或遠端的虛擬主機壓縮檔 for /f "skip=12 tokens=4-6 delims= " %%a in (%CN:~0,2%mactohost) do ( if %%c == %HostIP% ( "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -Command Remove-Item C:\Users\%USERNAME%\%%a 2> nul if !ERRORLEVEL! EQU 0 ( echo "%%c %%a deleted !" ) else ( echo "%%c %%a does not exist !" ) ) else ( psexec -accepteula -nobanner \\%%c -s "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" "-Command" "Remove-Item" "C:\Users\%USERNAME%\%%a" 2> nul if !ERRORLEVEL! EQU 0 ( echo "%%c %%a deleted !" ) else ( echo "%%c %%a does not exist !" ) ) ) del ip.txt 2> nul > nul REM 刪除執行程式所在的目錄 (例如 : %USERPROFILE%\CNT.2023.v4.6\D9-1A2M3W\) 中的 d9 目錄 "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -Command Remove-Item %CN:~0,2% -Recurse 2> nul if %ERRORLEVEL% == 0 ( echo "%HostIP% %CD%\%CN:~0,2% folder deleted !" ) else ( echo "%HostIP% %CD%\%CN:~0,2% folder does not exist !" ) ``` ::: ### 執行清除 c1 叢集所有虛擬主機命令 ``` > vmdel.bat ``` 螢幕輸出 : ``` "120.96.143.152 c1 folder deleted " "120.96.143.153 c1 folder deleted " "120.96.143.152 c1m1.141.zip deleted " "120.96.143.152 c1w1.145.zip deleted " "120.96.143.153 c1w2.146.zip deleted " "120.96.143.153 c1w3.147.zip deleted " "120.96.143.170 C:\Users\bigred\CNT.2023.v4.6\C1-1M3W\c1 folder deleted " ``` 執行失敗的螢幕輸出 ```! "Please Execute vmbackup.bat first" ``` 可能原因 : 程式一開始會檢查每一台 VM 對應的實體 Windows 主機的使用者家目錄,有無 `*.bak` 的備份檔,只要少一個備份檔,此程式就會噴出此錯誤訊息 **[註] 會保留在本地或遠端實體主機的虛擬主機備份 (`*.bak`) 檔** </div> --- # <font color=red>IaC 平臺 開發關鍵技術 </font> ## <font color=blue>技術重點 1 - Windows batch script - 透過 `FOR` 命令可以將文字檔中的欄位資料取出</font> <div class="indent-title-1"> :star: 首先要注意 ! 如果要在批次程式中使用 `FOR` 命令,請指定 <font color=red>`%%variable`</font>,而不要指定<font color=red>`%variable`</font>。變數名稱有大小寫的區分,所以 <font color=red>`%i`</font> 不同於 <font color=red>`%I`</font>。 </div> ### 逐行讀取文字檔的 `for /F` 迴圈 <div class="indent-title-1"> `/f` ,可以對 for 迴圈傳入的檔案、字串或命令,進行解析,以下為讀取檔案的範例 : ```bash! for /f "tokens=3,* delims= " %%a in (c1mactohost) do echo %%b ``` - 概述:逐行讀取 `k1mactohost` 檔案的內容,然後依照分隔符號 (空格) 將檔案內容的值分別設為指定的變數,再將指定的變數內容輸出在螢幕上。 - `tokens=x,y,m-n` 用來決定一次要取出幾個欄位,第一個欄位會存放在第一個自動變數,第二個欄位會存放在第二個自動變數裡,依此類推。在範例中為`tokens=3,*`,代表將第三個欄位的值存放在變數 `a` ,其他剩餘欄位的值會放在變數 `b` 註: `x, x, m, n` 都為數字,只是 `m-n` 是一種特別的表示法,代表一個解析欄位的範圍。例如 `tokens=2-4` 就代表取得第2、第 3 與第 4 個欄位的值並分別塞指定的變數裡 - `delims=xxx` 用來決定欄位的分隔符號,預設為`空格與 TAB 符號`,並可自訂多個符號。在範例中,將欄位的分隔符號設為空格 註: `xxx` 代表多個字元,如果要同時設定小數點 `.` 與逗號 `,` 就要輸入`delims=.,` </div> ### 練習 <div class="indent-title-1"> 啟動一個文字檔 tip.txt ``` > notepad tip.txt ``` 內容是 ``` 10:6e d8a5 120.96.143.22 10:6f d8a6 120.96.143.22 ``` 寫一隻程式 (tip.bat)用冒號分割顯示以下的結果: ``` 6e 6f ``` 答案: 先編輯一個批次檔 ``` $ notepad tip.bat ``` 內容是 ``` @echo off for /f "tokens=1 delims= " %%a in (tip.txt) do echo %%a ``` 將 a 變數匯入一個檔案 ``` @echo off for /f "tokens=1 delims= " %%a in (tip.txt) do echo %%a >> t1.txt for /f "tokens=2 delims=:" %%b in (t1.txt) do echo %%b ``` 執行批次檔 ``` $ tip.bat ``` 螢幕輸出 ``` 6e 6f ``` 另一種答案,雙迴圈 ``` @echo off for /f "tokens=1 delims= " %%a in (tip.txt) do ( for /f "tokens=1,2 delims=:" %%b in ('echo %%a') do echo %%b %%c ) ``` </div> ### 甚麼是 `@echo off` ? <div class="indent-title-1"> #### 認識 echo on <div class="indent-title-1"> 在 Windows batch script 中,預設是 `echo on`,當 Windows 電腦在執行批次程式中的每一行命令時,會先顯示其解析後的結果,才會再顯示執行後的結果 範例 : 編輯一個 test.bat 批次檔 ``` > notepad test.bat ``` 檔案內容 ``` set a=b echo %a% ``` 執行程式 ``` > test.bat ``` 螢幕輸出 ``` >set a=b >echo b b ``` 可以看到它在執行程式中的每一行命令時,會先顯示其解析後的結果,才會再顯示執行後的結果 </div> #### 認識 @echo off <div class="indent-title-1"> `@echo off` 可以分為兩個部分,最前面的 `@` 和 後面的`echo off` - `@` 是針對特定命令,讓它不要顯示被解析後的結果,直接顯示命令執行後的結果 - `echo off` 通常會被加在 Windows 批次檔的最上面,它的作用是,**程式在執行時,只顯示命令執行結果**。 所以 `@echo off` ,它會不顯示自己被解析後的結果,且程式的每一行命令在執行時,只顯示命令執行結果。 延續上一個範例 : 編輯 test.bat 批次檔 ``` > notepad test.bat ``` 檔案內容的最上面新增 `@echo off` ``` @echo off set a=b echo %a% ``` 執行程式 ``` > test.bat ``` 螢幕輸出 ``` b ``` </div> </div> ### 甚麼是 setlocal EnableDelayedExpansion ? <div class="indent-title-1"> 在了解 甚麼是 setlocal EnableDelayedExpansion 之前,先來看看以下一段批次程式的內容 ``` set VAR=before if "%VAR%" == "before" ( set VAR=after if "%VAR%" == "after" @echo "If you see this, it worked" ) ``` 看完以後您覺得執行這隻程式的結果會顯示 `"If you see this, it worked"` 這段字串嗎? 來看看程式執行結果 ``` > set VAR=before > if "before" == "before" ( set VAR=after if "before" == "after" ) ``` **在預設情況下,每行命令被執行之前,變數擴展成值,只會發生一次,即使你在 if 的括號之中,把它分成兩行。** 通過 SETLOCAL EnableDelayedExpansion 命令打開 延遲擴展可以讓批次檔中的變數,**在執行時擴展變成值,而不是在命令被解析的時後**。 **使用 FOR 迴圈 或是 if 括號表達式等循環命令,延遲擴展將允許您始終讀取變數的當前值**。 現在我們在程式的最上面加上 `SETLOCAL EnableDelayedExpansion` ``` > notepad test.bat ``` 檔案內容 ``` SETLOCAL EnableDelayedExpansion set VAR=before if "%VAR%" == "before" ( set VAR=after if "%VAR%" == "after" @echo "If you see this, it worked" ) ``` 執行程式 ``` > test.bat ``` 螢幕輸出 ``` >test.bat >SETLOCAL EnableDelayedExpansion >set VAR=before >if "before" == "before" ( set VAR=after if "before" == "after" ) ``` 奇怪 ??? 為甚麼還是沒有在螢幕上輸出 "If you see this, it worked" 這段字串 ? 答案是因為 : 要讓延遲擴展生效,必須使用`!variable_name!`,在變數的前後都加驚嘆號,來立即讀取變數的值。 修改程式 ``` > notepad test.bat ``` 編輯程式內容,將 第二個 `%VAR%` 改成 `!VAR!` ``` @echo off SETLOCAL EnableDelayedExpansion set VAR=before if "%VAR%" == "before" ( set VAR=after if "!VAR!" == "after" @echo "If you see this, it worked" ) ``` 執行程式 ``` > test.bat ``` 螢幕輸出 ``` "If you see this, it worked" ``` 成功 ~ </div> ### 參考文章 1. [如何利用批次檔(Batch)讀取指令執行的結果或文字檔案內容](https://blog.miniasp.com/post/2010/09/24/How-to-parse-text-from-file-or-command-using-Batch) 2. [for 迴圈](https://peterju.gitbooks.io/cmddoc/content/loop.html) 3. [延遲變數展開 (EnableDelayedExpansion)](https://ss64.com/nt/delayedexpansion.html) ## <font color=blue>技術重點 2 - Windows 遠端啟動 VMware 虛擬電腦</font> ### 1. 使用 psexec 必須使用此設定 <div class="indent-title-2"> 開放遠端連線權限,用系統管理員身份打開 CMD,並執行以下命令 ``` reg add HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\system /v LocalAccountTokenFilterPolicy /t REG_DWORD /d 1 /f ``` [註] 1. 機碼修改後,需重啟電腦 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2. 如有安裝 F-Secure,請關閉 F-Secure 防火牆 參考文章連結 : [PsTools 於 Windows 10 的環境設定](http://pejslin.blogspot.com/2019/11/pstools-windows-10.html) </div> ### 2. 執行 `psexec` 簡易命令 <div class="indent-title-2"> 打開 CMD ,切換到 `CNT.2023.v4.5\D9-1A2M3W`工作目錄,執行以下測試命令 ``` psexec \\192.168.39.55 -s "hostname" ``` 螢幕輸出 ``` PsExec v2.4 - Execute processes remotely Copyright (C) 2001-2022 Mark Russinovich Sysinternals - www.sysinternals.com DESKTOP-VNDI6BN hostname exited on 192.168.39.55 with error code 0. ``` </div> ### 3. 啟動虛擬機器 <div class="indent-title-2"> ```bash! $ psexec \\120.96.143.3 -s -d "C:\Program Files (x86)\VMware\VMware Player\vmrun" "start" "C:\Users\bigred\alp.k1a1\alpine64.vmwarevm\alpine64.vmx" "nogui" ``` 參數解釋 : - `-s`,遠端執行的命令將會由 System account 執行 - `-d`,我們連線的實體主機即使斷線,所執行的命令不會因此中斷。您無法獲得任何退出代碼或輸出,因為遠程 PsExec 服務只是啟動程序,將新程序 ID 告知原始 PsExec 程序,而不再關心新程序的作用。 [stackoverflow 參考文章] [What does psexec -s do?](https://stackoverflow.com/questions/48981961/what-does-psexec-s-do) </div> ### 4. 如何知道執行 `psexec` 成功 <div class="indent-title-2"> 打開工作管理員,確認有沒有以下的顯示 ![](https://i.imgur.com/yWEHf8A.png) </div> ### 5. 關閉虛擬機器 <div class="indent-title-2"> 方法一 : 直接下命令 ```bash! psexec \\120.96.143.5 -s -d "C:\Program Files (x86)\VMware\VMware Player\vmrun" "stop" "C:\Users\bigred\alp.k1w3\alpine64.vmwarevm\alpine64.vmx" ``` 方法二 : 使用工作管理員在 vmware-vmx.exe 按右鍵結束工作 :::spoiler 參考圖片 ![](https://i.imgur.com/GjGVrhL.png) ::: 將 `*.lck`檔和類型是 `VMEM檔案` 的三個檔案刪掉 :::spoiler 參考圖片 ![](https://i.imgur.com/92cfxEy.png) ::: </div> ### psexec 參考連結 - [Everything You Wanted to know About Psexec](https://adamtheautomator.com/psexec/) ## <font color=blue>技術參考連結</font> - [Compress-Archive - Microsoft 官網連結](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.archive/compress-archive?view=powershell-7.3) - [Understanding Infrastructure as Code (IaC) in less than 10 minutes](https://www.novatec-gmbh.de/en/blog/understanding-infrastructure-as-code-iac-in-less-than-10-minutes/) - [Running Remote Commands](https://learn.microsoft.com/en-us/powershell/scripting/learn/remoting/running-remote-commands?view=powershell-7.3) - [Using PsExec to Run Commands Remotely](https://theitbros.com/using-psexec-to-run-commands-remotely/)