寫一個 Linux 環境初始化腳本 文章首圖

寫一個 Linux 環境初始化腳本

寫一個 Linux 環境初始化腳本

在現代 DevOps 與系統管理的實務中,重複手動設定伺服器環境不僅效率低落,更容易因人為疏失導致環境不一致。無論是新伺服器上架、CI/CD 流程中的環境準備,還是開發者的本地端設定,撰寫一個健壯的 Shell 腳本來自動化這些步驟,是提升生產力的關鍵。本文將引導你撰寫一個適用於 Ubuntu 22.04 與 Debian 12 的通用環境初始化腳本,並探討其中的實戰技巧。

為什麼需要環境初始化腳本?

一個標準的 Linux 初始化腳本通常涵蓋三個核心階段:

  1. 系統更新與安全加固:更新套件庫並安裝基礎安全工具。
  2. 基礎軟體安裝:根據需求安裝程式語言執行環境(如 Node.js, Python, Go)或開發工具(如 Git, Curl)。
  3. 使用者環境配置:設定 SSH、防火牆、時區等系統級參數。

透過腳本化,我們能確保每次執行的結果都是可預測且一致的。

腳本設計與實作

在撰寫腳本時,我們必須考慮錯誤處理、執行權限以及環境的兼容性。以下是一個結構完整、可直接在 Ubuntu 22.04 或 Debian 12 上執行的初始化腳本範例。

#!/bin/bash

# 環境初始化腳本範例
# 適用系統: Ubuntu 22.04 / Debian 12
# 用途: 自動化基礎環境設定

# 1. 設定錯誤處理
# -e: 若指令回傳非零值(錯誤),立即終止腳本
# -u: 使用未設定的變數時報錯
# -o pipefail: 管線中任一指令失敗即視為失敗
set -euo pipefail

# 2. 定義變數
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
LOG_FILE="/var/log/env-init.log"
REQUIRED_PACKAGES=("git" "curl" "wget" "vim" "htop" "unzip" "zip")
TIMEZONE="Asia/Taipei"

# 3. 記錄開始時間與日誌
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 開始執行環境初始化..." | tee -a "$LOG_FILE"

# 4. 權限檢查
if [[ $EUID -ne 0 ]]; then
   echo "此腳本需要 root 權限執行,請使用 sudo" >&2
   exit 1
fi

# 5. 系統更新與基礎套件安裝
echo ">>> 更新套件庫並安裝基礎工具..."
apt-get update -y >> "$LOG_FILE" 2>&1
apt-get upgrade -y >> "$LOG_FILE" 2>&1

# 安裝必要的基礎套件,若已安裝則跳過
for pkg in "${REQUIRED_PACKAGES[@]}"; do
    if ! dpkg -s "$pkg" &>/dev/null; then
        echo "安裝 $pkg..."
        apt-get install -y "$pkg" >> "$LOG_FILE" 2>&1
    else
        echo "$pkg 已安裝,跳過。"
    fi
done

# 6. 系統時區設定
echo ">>> 設定系統時區為 $TIMEZONE..."
ln -sf /usr/share/zoneinfo/$TIMEZONE /etc/localtime
dpkg-reconfigure -f noninteractive tzdata >> "$LOG_FILE" 2>&1

# 7. 防火牆設定 (假設使用 ufw)
echo ">>> 設定防火牆規則..."
apt-get install -y ufw >> "$LOG_FILE" 2>&1
ufw allow OpenSSH >> "$LOG_FILE" 2>&1
ufw --force enable >> "$LOG_FILE" 2>&1

# 8. 建立一般使用者 (可選,視需求調整)
# 若使用者已存在則跳過
if ! id -u "developer" >/dev/null 2>&1; then
    echo ">>> 建立一般使用者 developer..."
    adduser --disabled-password --gecos "" developer
    usermod -aG sudo developer
    echo "developer ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
else
    echo "使用者 developer 已存在,跳過建立。"
fi

# 9. 完成
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 環境初始化完成!" | tee -a "$LOG_FILE"
echo "請重新登入以套用時區與權限變更。"

腳本技巧解析

這段腳本展現了幾個重要的 Shell 程式設計技巧:

  • set -euo pipefail:這是撰寫健壯腳本的黃金準則。-e 確保任何錯誤發生時腳本立即停止,避免後續錯誤疊加;-u 防止因變數未定義而產生的隱蔽錯誤;-o pipefail 則確保管線中的錯誤不會被忽略。
  • 權限檢查:透過 $EUID 變數檢查是否為 root 使用者。許多系統設定(如修改時區、安裝系統套件)需要最高權限,提前檢查可避免執行到一半才報錯。
  • 條件式安裝:使用 dpkg -s 檢查套件是否已存在,避免重複執行 apt-get install 造成的效能浪費與日誌雜訊。
  • 日誌記錄:使用 tee 指令同時將輸出顯示在終端並寫入日誌檔案,方便後續除錯與稽核。

常見問題與注意事項

1. 腳本執行後時區未生效? Linux 系統在執行期間讀取 /etc/localtime 的連結。雖然腳本中更新了該連結,但正在運行的進程(包括 SSH 會話)可能仍使用舊的時區快取。因此,執行完腳本後,務必重新登入 SSH 或重啟相關服務(如 systemctl restart cron),才能確保新時區全面生效。

2. 在 CI/CD 環境中執行時失敗? 許多雲端虛擬機器或容器環境預設未安裝 sudoadduser。若此腳本用於 Dockerfile 或 Jenkins Pipeline,請確認基礎映像檔已包含必要工具,並移除建立使用者的步驟(因為容器通常以 root 運行)。此外,ufw 在部分容器環境中可能無法正常運作,建議根據實際部署環境調整防火牆相關指令。

小結

撰寫環境初始化腳本並非單純將指令堆疊,而是要考慮錯誤處理、環境兼容性以及可維護性。透過上述範本,你可以快速建立一個穩固的基礎環境。建議將此腳本版本控制(Git),並根據專案需求擴充套件安裝或服務設定部分,將其作為團隊共享的基礎設施即程式碼(IaC)起點,從而大幅提升系統部署的標準化與效率。