iT邦幫忙

2025 iThome 鐵人賽

DAY 22
0
DevOps

不爆肝學習 Ansible 的短暫30天系列 第 22

Day22 - Ansible 要如何有效管理多個環境呢?

  • 分享至 

  • xImage
  •  

今日目標

  • 了解如何透過 Ansible 管理多個環境
  • 建立可靠的多環境部署流程

為什麼需要多環境管理?

在實務上我們通常會有多個環境,分別是:

  • 開發環境 (Development):開發人員日常開發和測試
  • 測試環境 (Staging):模擬生產環境進行整合測試
  • 生產環境 (Production):實際提供服務給使用者

每個環境都有不同的需求:

  • 不同的硬體規格和容量需求
  • 不同的安全性和合規要求
  • 不同的配置參數和秘密資訊
  • 不同的部署頻率和風險容忍度

環境隔離設計原則

1. 物理隔離 vs 邏輯隔離

物理隔離

# 不同環境使用完全不同的基礎設施
inventories/
├── dev/
│   └── inventory.ini        # 開發環境主機
├── staging/
│   └── inventory.ini        # 測試環境主機
└── prod/
    └── inventory.ini        # 生產環境主機

邏輯隔離

# 同一套基礎設施,使用不同的 namespace 或標籤
[webservers:children]
webservers_dev
webservers_staging
webservers_prod

[webservers_dev]
web01-dev.example.com
web02-dev.example.com

[webservers_staging]
web01-staging.example.com

[webservers_prod]
web01-prod.example.com
web02-prod.example.com
web03-prod.example.com

2. 專案目錄結構設計

筆者比較推薦的多環境專案結構:

ansible-project/
├── inventories/
│   ├── dev/
│   │   ├── inventory.ini
│   │   └── group_vars/
│   │       ├── all.yml
│   │       └── webservers.yml
│   ├── staging/
│   │   ├── inventory.ini
│   │   └── group_vars/
│   │       ├── all.yml
│   │       └── webservers.yml
│   └── prod/
│       ├── inventory.ini
│       └── group_vars/
│           ├── all.yml
│           └── webservers.yml
├── roles/
│   └── webapp/
│       ├── tasks/main.yml
│       ├── templates/
│       └── defaults/main.yml
├── playbooks/
│   ├── site.yml
│   ├── deploy.yml
│   └── rollback.yml
└── ansible.cfg

環境特定配置管理

group_vars 配置範例

開發環境配置 (inventories/dev/group_vars/all.yml):

---
# 開發環境配置
environment: development
debug_mode: true
log_level: debug

# 資料庫配置
database:
  host: dev-db.internal
  port: 5432
  name: webapp_dev
  user: webapp_dev
  pool_size: 5

# 應用程式配置
app:
  replicas: 1
  cpu_limit: "500m"
  memory_limit: "512Mi"
  features:
    - debug_toolbar
    - test_mode

# 外部服務
redis:
  host: dev-redis.internal
  port: 6379
  db: 0

# 安全設定(開發環境較寬鬆)
security:
  ssl_enabled: false
  cors_origins: "*"
  rate_limit: 1000

生產環境配置 (inventories/prod/group_vars/all.yml):

---
# 生產環境配置
environment: production
debug_mode: false
log_level: warning

# 資料庫配置
database:
  host: prod-db-cluster.internal
  port: 5432
  name: webapp_prod
  user: webapp_prod
  pool_size: 20

# 應用程式配置
app:
  replicas: 3
  cpu_limit: "2"
  memory_limit: "2Gi"
  features: []

# 外部服務
redis:
  host: prod-redis-cluster.internal
  port: 6379
  db: 0

# 安全設定(生產環境嚴格)
security:
  ssl_enabled: true
  cors_origins: "https://webapp.example.com"
  rate_limit: 100

敏感資訊管理

使用 Ansible Vault 管理環境特定的秘密:

# 為不同環境建立不同的 vault 檔案
ansible-vault create inventories/dev/group_vars/vault.yml
ansible-vault create inventories/staging/group_vars/vault.yml
ansible-vault create inventories/prod/group_vars/vault.yml

生產環境 vault (inventories/prod/group_vars/vault.yml):

---
vault_database_password: "super_secure_prod_password"
vault_api_key: "prod_api_key_12345"
vault_ssl_cert: |
  -----BEGIN CERTIFICATE-----
  MIIDXTCCAkWgAwIBAgIJAKoK/heBjcOuMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV
  ...
  -----END CERTIFICATE-----
vault_ssl_key: |
  -----BEGIN PRIVATE KEY-----
  MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDXVg8+
  ...
  -----END PRIVATE KEY-----

group_vars/all.yml 中引用:

---
database_password: "{{ vault_database_password }}"
api_key: "{{ vault_api_key }}"
ssl_certificate: "{{ vault_ssl_cert }}"
ssl_private_key: "{{ vault_ssl_key }}"

部署策略與流程

1. 環境特定 Playbook

主部署 Playbook (playbooks/site.yml):

---
- name: Deploy webapp to all environments
  hosts: webservers
  become: yes
  vars:
    deployment_timestamp: "{{ ansible_date_time.epoch }}"

  pre_tasks:
    - name: Validate environment configuration
      assert:
        that:
          - environment is defined
          - environment in ['development', 'staging', 'production']
        fail_msg: "Invalid or undefined environment"

    - name: Backup current application (production only)
      include_tasks: tasks/backup.yml
      when: environment == 'production'

  roles:
    - role: webapp
      vars:
        app_version: "{{ deployment_version | default('latest') }}"

  post_tasks:
    - name: Verify application health
      uri:
        url: "http://{{ inventory_hostname }}:{{ app_port }}/health"
        status_code: 200
      retries: 5
      delay: 10

    - name: Send deployment notification
      include_tasks: tasks/notify.yml
      when: environment == 'production'

2. 漸進式部署策略

藍綠部署 (Blue-Green Deployment):

---
- name: Blue-Green Deployment
  hosts: webservers
  become: yes
  serial: "{{ deployment_batch_size | default('50%') }}"
  vars:
    blue_version: "{{ current_version }}"
    green_version: "{{ new_version }}"

  tasks:
    - name: Deploy green version
      include_role:
        name: webapp
      vars:
        app_version: "{{ green_version }}"
        app_port: "{{ green_port }}"

    - name: Health check green version
      uri:
        url: "http://{{ inventory_hostname }}:{{ green_port }}/health"
        status_code: 200
      retries: 10
      delay: 30

    - name: Switch traffic to green
      template:
        src: nginx_proxy.conf.j2
        dest: /etc/nginx/conf.d/app.conf
      notify: reload nginx

    - name: Stop blue version
      service:
        name: "webapp-{{ blue_version }}"
        state: stopped
      when: green_health_check is succeeded

金絲雀發布 (Canary Deployment):

---
- name: Canary Deployment
  hosts: webservers
  become: yes
  vars:
    canary_percentage: "{{ canary_traffic | default(10) }}"

  tasks:
    - name: Deploy canary version to subset
      include_role:
        name: webapp
      vars:
        app_version: "{{ canary_version }}"
      when: inventory_hostname in groups['canary_servers']

    - name: Configure load balancer for canary
      template:
        src: lb_canary.conf.j2
        dest: /etc/nginx/conf.d/canary.conf
      vars:
        canary_weight: "{{ canary_percentage }}"

    - name: Monitor canary metrics
      uri:
        url: "http://{{ monitoring_host }}/api/canary/metrics"
        method: GET
      register: canary_metrics
      until: canary_metrics.json.error_rate < 0.01
      retries: 30
      delay: 60

3. 環境特定執行指令

# 開發環境部署
ansible-playbook -i inventories/dev playbooks/site.yml

# 測試環境部署
ansible-playbook -i inventories/staging playbooks/site.yml \
  --ask-vault-pass

# 生產環境部署(需要額外確認)
ansible-playbook -i inventories/prod playbooks/site.yml \
  --ask-vault-pass \
  --extra-vars "deployment_version=v2.1.0" \
  --check  # 先檢查不實際執行

# 生產環境實際部署
ansible-playbook -i inventories/prod playbooks/site.yml \
  --ask-vault-pass \
  --extra-vars "deployment_version=v2.1.0"

作業練習時間

練習一:建立多環境結構

  1. 建立包含 dev、staging、prod 的專案目錄結構
  2. 為每個環境配置不同的 inventory 和 group_vars
  3. 使用 Ansible Vault 管理各環境的敏感資訊

練習二:環境配置差異化

設計以下環境特定配置:

  1. 開發環境:一個 instance、debug mode、SQLite 資料庫
  2. 測試環境:兩個 instance、日誌記錄、PostgreSQL 資料庫
  3. 生產環境:三個 instance、SSL 啟用、高可用資料庫集群

練習三:部署策略實作

  1. 實作藍綠部署策略
  2. 建立金絲雀發布流程
  3. 設計自動回滾機制

明日預告

明天來聊聊如何跟 CI/CD 流程做整合!


上一篇
Day21 - Ansible 也有測試要寫!
下一篇
Day23 - CI/CD 整合 Ansible 流程
系列文
不爆肝學習 Ansible 的短暫30天23
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言