伺服器映像即程式碼:自動化建置與管理
在前面的內容中,我們討論了從單一來源建立多個伺服器例項的概念,並建議使用乾淨建置的伺服器映像。本文將探討如何有效實作這些建議,透過程式碼化方式管理伺服器映像的整個生命週期。
伺服器映像的程式碼化管理
就像系統中的其他元素一樣,伺服器映像的建置和更新應該透過程式碼以可重複的方式進行。當你需要對映像進行變更(例如安裝最新的作業系統補丁)時,程式碼化確保了建置過程的一致性。
透過自動化、程式碼驅動的流程來建置、測試、交付和更新伺服器映像,你可以更輕鬆地保持伺服器的最新狀態,並確保其合規性和品質。基本的伺服器映像生命週期涉及從原始來源建置自訂映像。
伺服器映像生命週期
伺服器映像的生命週期通常包含以下階段:
- 從基礎映像開始
- 自動化建置過程
- 測試與驗證
- 發布與分發
- 佈署到生產環境
- 監控與更新
建置伺服器映像
大多數基礎設施管理平台都有用於建立伺服器例項的映像格式。Amazon 有 AMIs (Amazon Machine Images),Azure 有受管映像 (Managed Images),VMware 有 VM 範本。這些託管平台提供預先封裝的標準映像,包含常見的作業系統和發行版,讓你無需自行建置映像即可建立伺服器。
為什麼要建置自訂伺服器映像?
大多數團隊最終會建置自訂映像,而不使用平台供應商提供的標準映像。常見原因包括:
符合組織治理規範
許多組織,特別是受監管行業中的組織,需要確保他們按照更嚴格的準則建置伺服器。例如,金融機構可能需要確保所有伺服器符合特定的安全標準和稽核要求。
安全強化
標準伺服器映像通常安裝了許多不同的套件和工具,以適應各種使用情境。透過建置自訂映像,你可以將系統精簡到最低必要元素。安全強化可以包括:
- 停用或移除未使用的使用者帳戶和系統服務
- 停用所有非嚴格需要的網路埠
- 鎖設定檔案系統和資料夾許可權
- 實施強化的密碼政策
- 設定入侵檢測系統
效能最佳化
為安全而採取的許多強化步驟,如停止或移除不需要的系統服務,也能減少伺服器使用的 CPU 和記憶體資源。最小化伺服器映像的大小也使建立伺服器例項的速度更快,這在擴充套件和復原情境中特別有用。
在玄貓的實踐中,我發現將不必要的服務移除後,系統啟動時間可以減少 30% 以上,而記憶體佔用可以減少高達 25%。這在大規模佈署時能帶來顯著的資源節省。
安裝通用套件
你可以在伺服器映像上安裝標準的服務、代理程式和工具,確保它們在所有例項上都可用。例如:
- 監控代理程式
- 系統使用者帳戶
- 團隊特定的工具和維護指令碼
- 安全掃描工具
- 日誌收集代理程式
為伺服器角色建置映像
本文中的許多範例不僅是建置標準的通用映像。你可以建置針對特定用途量身定製的伺服器映像,例如:
- 容器叢集節點
- 應用程式伺服器
- CI 伺服器代理程式
- 資料函式庫伺服器
- 負載平衡器
Netflix 就採用了這種方法,為不同的應用程式角色建置專用的 AMI,以最佳化效能和安全性。
如何建置伺服器映像
建置伺服器映像有多種方法,但最佳實踐是使用程式碼化、自動化的流程。以下是一個基本的建置流程:
graph TD A[基礎映像] --> B[自動化建置指令碼] B --> C[安裝必要套件] C --> D[設定系統引數] D --> E[安全強化] E --> F[安裝監控工具] F --> G[測試與驗證] G --> H[最終映像]
使用 Packer 自動化建置
Hashicorp 的 Packer 是一個開放原始碼工具,可以自動化建置多種平台的伺服器映像。以下是一個基本的 Packer 設定範例:
{
"variables": {
"aws_access_key": "{{env `AWS_ACCESS_KEY_ID`}}",
"aws_secret_key": "{{env `AWS_SECRET_ACCESS_KEY`}}",
"region": "ap-northeast-1"
},
"builders": [
{
"type": "amazon-ebs",
"access_key": "{{user `aws_access_key`}}",
"secret_key": "{{user `aws_secret_key`}}",
"region": "{{user `region`}}",
"source_ami_filter": {
"filters": {
"virtualization-type": "hvm",
"name": "ubuntu/images/*ubuntu-focal-20.04-amd64-server-*",
"root-device-type": "ebs"
},
"owners": ["099720109477"],
"most_recent": true
},
"instance_type": "t2.micro",
"ssh_username": "ubuntu",
"ami_name": "packer-example-{{timestamp}}"
}
],
"provisioners": [
{
"type": "shell",
"script": "scripts/update.sh"
},
{
"type": "shell",
"script": "scripts/install_packages.sh"
},
{
"type": "shell",
"script": "scripts/security_hardening.sh"
}
]
}
這個 Packer 設定案定義瞭如何在 AWS 上建立自訂 AMI。它包含三個主要部分:
變數 (variables) - 定義建置過程中使用的變數,如 AWS 認證和區域,這些值從環境變數中取得,增強了安全性。
建置器 (builders) - 指定使用 amazon-ebs 建置器,從 Ubuntu 20.04 的基礎映像開始,並設定建置環境的引數。
source_ami_filter
使用篩選條件找到最新的 Ubuntu 20.04 映像,而不是硬編碼特定映像 ID,確保始終使用最新的基礎映像。佈建器 (provisioners) - 定義一系列指令碼,按順序執行以設定映像:更新系統、安裝必要套件和實施安全強化措施。
這種方法的優勢在於整個建置過程被程式碼化,可以版本控制,並且可以在 CI/CD 管道中自動執行。
佈建指令碼範例
以下是 security_hardening.sh
指令碼的範例內容:
#!/bin/bash
set -e
echo "Performing security hardening..."
# 更新所有套件
apt-get update && apt-get upgrade -y
# 移除不必要的套件
apt-get remove -y telnet rsh-server rsh-redone-server
# 設定強化的密碼政策
sed -i 's/PASS_MAX_DAYS\t99999/PASS_MAX_DAYS\t90/' /etc/login.defs
sed -i 's/PASS_MIN_DAYS\t0/PASS_MIN_DAYS\t1/' /etc/login.defs
# 設定 SSH 安全設定
sed -i 's/#PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config
sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
# 設定防火牆規則
ufw default deny incoming
ufw default allow outgoing
ufw allow ssh
ufw enable
# 設定系統稽核
apt-get install -y auditd
systemctl enable auditd
systemctl start auditd
echo "Security hardening completed."
這個指令碼執行多項安全強化措施:
首先使用
set -e
確保任何命令失敗時指令碼會立即停止,避免在錯誤狀態下繼續執行。更新所有系統套件,確保安裝最新的安全補丁。
移除不安全的遠端存取工具,如 telnet 和 rsh,這些工具傳輸資料時不加密。
強化密碼政策,設定密碼最長有效期為 90 天,最短使用期為 1 天,促使用者定期更換密碼。
設定 SSH 安全設定,禁止 root 直接登入並停用密碼認證,強制使用 SSH 金鑰。
設定 UFW 防火牆,預設拒絕所有入站連線,只允許 SSH 連線。
安裝並啟用 auditd 稽核系統,記錄系統活動以便後續分析。
這個指令碼實施了基本的安全最佳實踐,但在實際佈署前應根據組織的安全政策進行調整。在玄貓的經驗中,這些基本措施可以防止大約 80% 的常見攻擊向量。
映像建置流程的整合
將伺服器映像建置整合到 CI/CD 流程中是最佳實踐。每當基礎映像有更新或安全補丁發布時,自動觸發建置流程,確保你的映像始終是最新的。
以下是一個使用 GitHub Actions 自動建置 AMI 的工作流程範例:
name: Build AMI
on:
schedule:
- cron: '0 0 * * 0' # 每週日執行
push:
paths:
- 'packer/**'
- '.github/workflows/build-ami.yml'
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Setup Packer
uses: hashicorp/setup-packer@v1
with:
version: '1.7.4'
- name: Validate Packer Template
run: packer validate packer/template.json
- name: Build AMI
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
run: packer build packer/template.json
這個 GitHub Actions 工作流程自動化了 AMI 建置過程:
它在兩種情況下觸發:每週日自動執行(透過 cron 表示式設定)或當 Packer 設定案有變更時。
工作流程包含三個主要步驟:
- 簽出程式碼函式庫
- 設定 Packer 工具
- 驗證 Packer 範本以確保語法正確
- 執行 Packer 建置,使用儲存在 GitHub Secrets 中的 AWS 認證
這種方法確保了伺服器映像的建置過程是自動化的、可重複的,並且與程式碼變更同步。當團隊成員提交對映像設定的變更時,CI/CD 系統會自動建置新映像,減少手動錯誤並加速交付。
映像測試與驗證
建置伺服器映像後,測試和驗證步驟至關重要。這確保映像符合所有安全和功能要求。
自動化測試策略
有效的映像測試策略應包括:
- 結構測試:驗證映像包含所有必要的檔案、套件和設定。
- 安全掃描:檢查已知漏洞和安全問題。
- 功能測試:確保映像可以正確啟動並執行預期功能。
- 合規檢查:驗證映像符合組織的政策和法規要求。
以下是使用 InSpec 進行伺服器映像合規測試的範例:
# 檢查 SSH 設定
control 'ssh-01' do
impact 1.0
title 'SSH 伺服器設定'
desc '確保 SSH 伺服器安全設定正確'
describe sshd_config do
its('PermitRootLogin') { should eq 'no' }
its('PasswordAuthentication') { should eq 'no' }
its('Protocol') { should eq '2' }
end
end
# 檢查防火牆狀態
control 'firewall-01' do
impact 1.0
title '防火牆啟用狀態'
desc '確保防火牆已啟用並正確設定'
describe service('ufw') do
it { should be_enabled }
it { should be_running }
end
describe command('ufw status') do
its('stdout') { should match /Status: active/ }
end
end
這個 InSpec 測試檔案定義了兩個控制項,用於驗證伺服器映像的安全設定:
SSH 伺服器設定檢查:驗證 SSH 設定符合安全最佳實踐,包括禁止 root 登入、停用密碼認證,以及使用 SSH 協定版本 2。
防火牆狀態檢查:確認 UFW 防火牆服務已啟用並正在執行,與狀態為 active。
InSpec 使用宣告式語法,讓測試易於閲讀和理解。這些測試可以整合到 CI/CD 管道中,在建置映像後自動執行,確保每個映像都符合安全標準。
在玄貓的實踐中,我發現自動化測試可以捕捉到約 95% 的設定問題,大減少了生產環境中的意外情況。特別是在大型團隊中,當多人可能修改映像設定時,自動化測試成為確保一致性的關鍵。
映像版本管理與分發
有效管理伺服器映像的版本和分發是確保基礎設施一致性的關鍵。
版本命名策略
採用清晰的版本命名策略對於追蹤和管理映像至關重要。一個有效的命名模式可能包括:
flowchart LR A[應用程式] --> B[環境] --> C[日期] --> D[版本號]
例如:webserver-prod-20230324-v1
映像分發與分享
在多區域或多帳戶環境中,需要考慮如何分發和分享映像。AWS 提供了 AMI 複製和分享功能,可以透過程式碼自動化:
import boto3
def copy_ami_to_regions(source_ami_id, source_region, target_regions):
"""將 AMI 複製到多個區域"""
results = {}
for region in target_regions:
if region == source_region:
results[region] = source_ami_id
continue
ec2_client = boto3.client('ec2', region_name=region)
response = ec2_client.copy_image(
SourceRegion=source_region,
SourceImageId=source_ami_id,
Name=f"Copy of {source_ami_id} from {source_region}",
Description=f"AMI copied from {source_region}"
)
results[region] = response['ImageId']
return results
# 使用範例
source_ami = "ami-0abcdef1234567890"
source_region = "ap-northeast-1"
target_regions = ["us-east-1", "eu-west-1", "ap-southeast-1"]
ami_mapping = copy_ami_to_regions(source_ami, source_region, target_regions)
print(ami_mapping)
這個 Python 指令碼實作了跨區域 AMI 複製功能:
定義了一個函式
copy_ami_to_regions
,接受源 AMI ID、源區域和目標區域列表作為引數。函式遍歷每個目標區域,如果目標區域與源區域相同,則直接使用源 AMI ID。
對於不同的區域,使用 boto3 (AWS SDK for Python) 建立 EC2 客戶端,並呼叫
copy_image
API 將 AMI 複製到該區域。函式回傳一個字典,對映每個區域到相應的 AMI ID。
這種自動化方法確保了在全球多區域佈署中保持映像的一致性,同時避免了手動複製過程中的錯誤。在實際應用中,你可能還需要增加錯誤處理、重試邏輯和狀態檢查,以確保複製過程的可靠性。
映像更新與生命週期管理
伺服器映像不是一次性建立的資產,而是需要持續維護和更新的元件。
定期更新策略
建立定期更新映像的策略,確保安全補丁和軟體更新得到應用:
- 定期建置:設定每週或每月自動建置新映像
- 安全補丁應用:當關鍵安全補丁發布時觸發建置
- 軟體更新:當基礎套件有重要更新時更新映像
映像淘汰流程
隨著時間推移,舊映像應該被淘汰以減少維護負擔和安全風險:
import boto3
from datetime import datetime, timedelta
def deregister_old_amis(owner_id, days_old=90, dry_run=True):
"""淘汰超過指定天數的 AMI"""
ec2_client = boto3.client('ec2')
# 取得所有擁有的 AMI
response = ec2_client.describe_images(Owners=[owner_id])
# 計算截止日期
cutoff_date = datetime.now() - timedelta(days=days_old)
deregistered = []
for image in response['Images']:
# 解析建立日期
creation_date = datetime.strptime(
image['CreationDate'], '%Y-%m-%dT%H:%M:%S.%fZ'
)
# 檢查是否超過截止日期
if creation_date < cutoff_date:
ami_id = image['ImageId']
if not dry_run:
ec2_client.deregister_image(ImageId=ami_id)
print(f"已淘汰 AMI: {ami_id}")
deregistered.append(ami_id)
return deregistered
# 使用範例
owner_id = '123456789012' # AWS 帳戶 ID
old_amis = deregister_old_amis(owner_id, days_old=90, dry_run=True)
print(f"將淘汰 {len(old_amis)} 個 AMI: {old_amis}")
這個 Python 指令碼實作了 AMI 淘汰功能:
定義了一個函式
deregister_old_amis
,接受擁有者 ID、天數閾值和乾執行標誌作為引數。使用 boto3 取得指定擁有者的所有 AMI。
計算截止日期(當前日期減去指定的天數)。
遍歷每個 AMI,解析其建立日期並且截止日期比較。
如果 AMI 超過截止日期與不是乾執行模式,則淘汰該 AMI。
回傳已淘汰的 AMI ID 列表。
這種自動化淘汰流程確保了環境中不會累積過多過時的映像,減少了管理負擔和潛在的安全風險。dry_run
引數允許先預覽將被淘汰的映像,然後再實際執行淘汰操作。
伺服器映像程式碼化的最佳實踐
總結一些伺服器映像程式碼化的最佳實踐:
版本控制
將所有映像定義和設定指令碼儲存在版本控制系統中,如 Git。這確保了變更的可追蹤性和協作能力。
模組化設計
將映像建置過程分解為模組化的指令碼或設定,使其更易於維護和重用。例如,將安全強化、監控設定和應用程式安裝分開。
測試自動化
實施自動化測試,確保每個映像符合功能和安全要求。這包括結構測試、安全掃描和功能驗證。
檔案化
維護詳細的檔案,描述映像的內容、用途和使用方法。這對於團隊協作和知識傳承至關重要。
持續整合
將映像建置整合到 CI/CD 管道中,實作自動化建置、測試和佈署。這減少了手動錯誤並加速了交付。
不可變基礎設施
採用不可變基礎設施原則,即不直接修改現有伺服器,而是佈署新的伺服器映像。這提高了一致性和可靠性。
伺服器映像程式碼化是現代基礎設施管理的關鍵實踐。透過自動化建置、測試和佈署過程,你可以確保伺服器的一致性、安全性和可靠性。這種方法不僅提高了效率,還減少了人為錯誤,使團隊能夠更快地交付高品質的基礎設施。
在玄貓的經驗中,實施伺服器映像程式碼化後,團隊能夠將新環境的佈署時間從數天減少到數小時,同時大幅提高了系統的安全性和可靠性。無論是在雲端還是本地環境,這種方法都能帶來顯著的效益。
隨著基礎設施即程式碼實踐的不斷發展,伺服器映像程式碼化將繼續成為確保系統一致性和安全性的根本。透過採用本文中描述的技術和最佳實踐,你可以建立更強大、更可靠的基礎設施管理流程。
伺服器映像檔作為程式碼:開發高效能基礎設施的關鍵
在現代雲端環境中,伺服器映像檔已成為基礎設施自動化的核心元素。透過將伺服器設定轉化為程式碼,我們能夠實作更一致、更可靠與更安全的系統佈署。本文將探討如何有效地建立、管理和更新伺服器映像檔,以及如何將其整合到現代開發流程中。
伺服器映像檔建立方法:線上與離線策略
建立伺服器映像檔有兩種主要方法,每種方法各有其優缺點。選擇哪種方法取決於你的需求、時間限制和技術環境。
線上映像檔建立:直觀但較慢
線上映像檔建立是最常見與最直觀的方法。這個過程包括:
- 啟動一個全新的伺服器例項
- 設定該例項以滿足需求
- 將設定好的例項轉換為映像檔
這種方法的主要優點是簡單直接,不需要特殊的技術知識。然而,它的缺點是速度較慢,因為需要完整啟動伺服器並等待設定完成,這可能需要數分鐘甚至數十分鐘。
離線映像檔建立:快速但技術要求較高
離線映像檔建立方法則是:
- 掛載一個磁碟區
- 直接將必要的檔案複製到該磁碟區
- 將該磁碟區轉換為可啟動的映像檔
這種方法通常快得多,因為它跳過了完整啟動伺服器的步驟。然而,它需要更多的技術知識和工作,特別是在確保所有必要的檔案和設定都正確安裝方面。
伺服器映像檔建立工具
市場上有多種工具可用於建立伺服器映像檔,它們通常透過協調建立伺服器例項或磁碟區、執行設定工具或指令碼進行自定義,然後使用基礎設施平台API將伺服器例項轉換為映像檔。
主流工具概覽
HashiCorp的Packer:目前最流行的映像檔建立工具,支援多種作業系統和基礎設施平台。
Netflix的Aminator:Netflix開放原始碼的工具,專為AWS EC2上的CentOS和Red Hat映像檔設計。
雲端平台原生服務:如AWS Image Builder和Azure Image Builder等。
這些工具的共同點是它們都允許你將映像檔建立過程定義為程式碼,這符合基礎設施即程式碼的理念。
線上映像檔建立流程詳解
線上映像檔建立過程涉及啟動一個新的、乾淨的伺服器例項,設定它,然後將其轉換為基礎設施平台的伺服器映像檔格式。
從原始映像檔啟動
首先,我們需要從一個原始映像檔啟動新的伺服器例項。以下是一個使用虛構雲端服務的映像檔建立程式碼範例:
image:
name: shopspinner-linux-image
platform: fictional-cloud-service
origin: fci-12345678
region: europe
instance_size: small
這段程式碼定義了一個名為shopspinner-linux-image
的映像檔,它從ID為fci-12345678
的現有映像檔啟動。這個原始映像檔通常是雲端供應商提供的標準Linux發行版。
為建立者例項提供基礎設施
在建立映像檔時,我們需要為建立者例項提供適當的基礎設施資源,例如網路子網和SSH金鑰:
image:
name: shopspinner-linux-image
origin: fci-12345678
region: europe
size: small
subnet: ${IMAGE_BUILDER_SUBNET_ID}
ssh_key: ${IMAGE_BUILDER_SSH_KEY}
這些值使用引數,可以自動生成並傳遞給映像檔建立工具。重要的是,我們應該最小化為映像檔建立者伺服器例項提供的資源和存取許可權,只允許必要的入站和出站存取。
設定建立者例項
一旦伺服器例項執行,我們就可以應用伺服器設定。大多數伺服器映像檔建立工具支援執行常見的伺服器設定工具:
image:
name: shopspinner-linux-image
origin: fci-12345678
region: europe
instance_size: small
subnet: ${IMAGE_BUILDER_SUBNET_ID}
configure:
tool: servermaker
code_repo: servermaker.shopspinner.xyz
server_role: appserver
這段程式碼應用了一個伺服器角色,可能會安裝應用伺服器和相關元素。
使用簡單指令碼建立伺服器映像檔
對於那些烘焙更完整伺服器映像檔的團隊,完整的伺服器設定工具可能過於複雜。在這種情況下,使用更簡單的指令碼語言(如Bash、批處理指令碼或PowerShell)可能更合適:
image:
name: shopspinner-linux-image
origin: fci-12345678
configure:
commands:
- 10-install-monitoring-agent.sh
- 20-install-jdk.sh
- 30-install-tomcat.sh
我個人喜歡在指令碼前加上數字,以便清楚地知道它們的執行順序。這種方法使維護和理解設定過程變得更加簡單。
離線映像檔建立流程詳解
啟動伺服器例項、應用設定然後關閉例項以建立伺服器映像檔的過程可能很慢。一個替代方案是使用可以作為磁碟區掛載的源映像檔。
離線建立的技術挑戰
離線建立映像檔需要解決幾個技術挑戰:
掛載磁碟區:需要將磁碟區掛載到執行映像檔建立工具的計算例項上。
設定工具適配:伺服器設定工具通常應用於它們正在執行的伺服器例項。當我們想要設定掛載的磁碟區時,這可能會變得棘手。
有兩種主要方法可以解決這個問題:
使用路徑字首:許多工具有命令列或設定選項,可以設定為將檔案安裝到不同的路徑。例如:
yum install --prefix /mnt/image_builder/ java
使用chroot命令:這會執行一個命令,使用不同的檔案系統根目錄:
chroot /mnt/image_builder/ yum install java
使用chroot
命令的優勢在於它適用於任何工具或命令。流行的映像檔建立工具如Packer內建支援chroot。
伺服器映像檔的原始內容
建立伺服器映像檔時,有幾個元素需要考慮:
映像檔建立者程式碼:定義映像檔的程式碼,如Packer範本檔案。
原始源映像檔:可能是平台格式的源映像檔(如AMI)、作業系統安裝映像檔(如ISO映像檔)或從頭開始建立。
伺服器設定程式碼:用於自定義映像檔的伺服器設定工具或指令碼。
其他伺服器元素:如來自公共或內部儲存函式庫的套件。
從現成伺服器映像檔建立
基礎設施平台供應商、作業系統供應商和開放原始碼專案通常會建立伺服器映像檔並提供給使用者。這些映像檔通常是建立自己的映像檔的良好起點。
然而,許多現成映像檔都過度設定了。製造商通常安裝各種工具和套件,以便立即對最廣泛的使用者有用。但我們應該最小化安裝在自定義伺服器映像檔上的內容,以提高安全性和效能。
我們可以從原始映像檔中剝離不需要的內容,或者尋找更小的原始映像檔。一些供應商和組織建立JEOS(Just Enough Operating System,剛好足夠的作業系統)映像檔。在最小基礎映像檔上增加所需的東西是保持映像檔最小化的更可靠方法。
從頭開始建立伺服器映像檔
如果基礎設施平台不提供現成映像檔,或者團隊不想使用現成映像檔,可以從頭開始建立自定義伺服器映像檔。
作業系統安裝映像檔為建立伺服器範本提供了一個乾淨、一致的起點。範本建立過程從作業系統映像檔啟動伺服器例項並執行指令碼化安裝過程開始。
伺服器映像檔及其內容的來源
對於基礎映像檔,與任何來自第三方的內容一樣,我們需要關注其來源和安全性。應該確保瞭解誰提供了映像檔,以及他們用來確保安全建立映像檔的過程。一些考慮因素包括:
- 映像檔和套件是否包含已知漏洞的軟體?
- 供應商採取了哪些步驟來掃描其程式碼以發現潛在問題?
- 如何知道任何包含的軟體或工具是否以違反組織政策或當地法律的方式收集資料?
- 供應商使用什麼流程來檢測和防止非法篡改?
我們不應該完全信任來自供應商或第三方的內容,因此應該實施自己的檢查。
更新伺服器映像檔
隨著時間的推移,伺服器映像檔會變得過時,因為會發布更新的套件和設定。雖然可以在每次建立新伺服器時應用補丁和更新,但隨著時間的推移,這個過程會變得更長,減少了使用伺服器映像檔的好處。定期更新映像檔可以保持一切順利執行。
重新加熱或重新烘焙映像檔
當我們想要建立伺服器映像檔的新版本時(例如,用最新的作業系統補丁更新它),可以使用與建立第一個版本相同的工具和流程。
我們可以使用前一個版本的映像檔作為原始源映像檔——重新加熱映像檔。這確保新版本與前一個版本一致,因為唯一的變化是在應用伺服器設定到新映像檔時明確做出的變化。
另一種選擇是烘焙新鮮映像檔,從原始源建立映像檔的新版本。雖然重新加熱映像檔可能會限制從一個版本到下一個版本的變化,但烘焙新鮮映像檔應該給出相同的結果,因為我們使用的是相同的源。
新鮮建立更乾淨,更可靠地可重現,因為它們不包括可能由先前建立留下的任何東西。例如,伺服器設定可能安裝了一個後來決定移除的套件。如果從舊映像檔重新加熱,該套件仍然存在於較新的伺服器映像檔上。我們需要增加程式碼來明確移除該套件,這會留下多餘的程式碼需要維護和清理。如果每次都烘焙新鮮映像檔,該套件將根本不存在於較新的伺服器映像檔上,因此不需要編寫任何程式碼來移除它。
伺服器映像檔的版本控制
對於使用伺服器映像檔和從中建立的伺服器的每個人來説,能夠追蹤版本是至關重要的。他們應該能夠瞭解用於建立任何給定伺服器例項的版本,給定映像檔的最新版本,以及用於建立映像檔的源內容和設定程式碼。
多映像檔版本管理
許多團隊使用不同的伺服器映像檔。例如,可能會為應用伺服器、容器主機節點和通用Linux作業系統映像檔建立單獨的映像檔。在這種情況下,每個映像檔都作為一個單獨的元件進行管理,每個都有其單獨的版本歷史。
大多數基礎設施平台不直接支援伺服器映像檔的版本編號。在許多情況下,可以在伺服器映像檔的名稱中嵌入版本號。例如,可能有名為appserver-3
、basic-linux-2
和container-node-3
的映像檔。
另一個選項是在標籤中放置版本號和映像檔名稱(如果平台支援)。映像檔可以有一個名為Name=appserver
的標籤和另一個名為Version=3
的標籤。
使用任何使搜尋、發現和報告映像檔名稱和版本最容易的機制。我合作過的大多數團隊都使用這兩種方法,因為標籤易於搜尋,而名稱易於人類檢視。
映像檔更新時更新伺服器例項
當建立伺服器映像檔的新版本時,可以替換根據該映像檔的所有伺服器例項,或等待它們隨著時間的推移自然替換。
重建現有伺服器以替換舊映像檔版本的政策可能會造成中斷並且耗時。但它也確保了伺服器的一致性,並持續鍛煉系統的彈性。良好的管道使管理這個過程變得更容易,零停機時間變更使其不那麼具有破壞性。因此,這種政策受到許多具有成熟和普遍自動化的團隊的青睞。
等待在出於其他原因重建伺服器時用新映像檔版本替換伺服器更容易。如果透過重建伺服器例項來佈署軟體更新或其他變更,這可能是這種情況。
等待用新映像檔版本更新伺服器的缺點是這可能需要一段時間,並使你的環境中有從各種映像檔版本建立的伺服器。
這種情況造成了不一致。例如,可能有具有不同版本的作業系統套件更新和設定的應用伺服器,導致神秘的不一致行為。在某些情況下,較舊的映像檔版本和從中建立的伺服器可能存在安全漏洞或其他問題。
有幾種策略可以緩解這些問題。一種是跟蹤執行例項與用於建立它們的映像檔版本。這可以是儀錶板或報告,顯示每個映像檔版本的例項數量。
如果這些訊息隨時可用,並且可以深入檢視特定伺服器的列表,那麼可以識別迫切需要重建的伺服器例項。例如,瞭解到在Linux發行版的最新更新中修復了一個安全漏洞。在basic-linux-2
、appserver-3
和container-node-2
中包含了該補丁。報告顯示需要重建19個伺服器例項(4個版本1的基本Linux伺服器,13個版本1和2的應用伺服器,以及2個版本1的容器節點)。
跨團隊提供和使用伺服器映像檔
在許多組織中,中央團隊建立伺服器映像檔並使其可供其他團隊使用。這種情況為管理伺服器映像檔更新增加了一些複雜性。
版本釘定與更新策略
使用映像檔的團隊需要確保它已準備好使用映像檔的新版本。例如,內部應用團隊可能在計算團隊提供的基本Linux映像檔上安裝錯誤追蹤軟體。計算團隊可能會生成一個帶有與錯誤追蹤軟體不相容的更新的基本Linux映像檔的新版本。
理想情況下,伺服器映像檔會進入每個團隊的基礎設施管道。當擁有映像檔的團隊透過其管道發布新版本時,每個團隊的基礎設施管道都會提取該版本並更新其伺服器例項。內部團隊的管道應該在重建其使用者依賴的伺服器之前自動測試錯誤追蹤軟體是否與新映像檔版本一起工作。
一些團隊可能採取更保守的方法,固定他們使用的映像檔版本號。內部應用團隊可以將其基礎設施固定為使用版本1的基本Linux映像檔。當計算團隊發布映像檔的版本2時,內部應用團隊繼續使用版本1,直到他們準備好測試和推出版本2。
處理映像檔的重大變更
對伺服器映像檔的一些變更為重要,因此更可能需要手動努力來測試和修改下游依賴項。例如,應用伺服器映像檔的新版本可能包括應用伺服器軟體的主要版本升級。
與其將其視為伺服器映像檔的次要更新,不如使用語義版本控制來表明它是一個更重要的變更,或者甚至完全建立一個不同的伺服器映像檔。
當使用語義版本控制時,大多數變更會增加版本的最低位數,例如從1.2.5到1.2.6。透過增加第二位或第一位數字來表示重大變更。對於不應該為應用程式建立相容性問題的次要應用伺服器軟體更新,可能會將伺服器映像檔的版本1.2.6增加到1.3.0。對於可能破壞應用程式的重大變更,增加最高位數,因此1.3.0將被替換為2.0.0。
在某些情況下,特別是當預期團隊會在一段時間內使用較舊的映像檔版本時,可能會完全建立一個新映像檔。例如,如果基本Linux映像檔使用Centos 9.x,但想要開始測試和推出Centos 10.x,與其增加映像檔的版本號,不如建立一個新映像檔,basic-linux10-1.0.0
。這使得遷移到新的作業系統版本比例行映像檔更新更明確。
伺服器映像檔作為程式碼是現代基礎設施自動化的關鍵組成部分。透過將伺服器設定轉化為程式碼,我們能夠實作更一致、更可靠與更安全的系統佈署。無論是選擇線上還是離線建立方法,使用適當的工具和流程,或是實施有效的版本控制和更新策略,都能幫助我們建立和維護高效能的基礎設施。
在實施伺服器映像檔策略時,我們應該考慮團隊的需求、技術環境和時間限制。透過選擇適合的方法和工具,我們可以確保伺服器映像檔的建立和管理過程既高效又可靠,從而為整個組織提供穩定的基礎設施基礎。