iT邦幫忙

2025 iThome 鐵人賽

DAY 11
0
DevOps

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

Day11 - 我們都應該站在巨人的肩膀上:Ansible Galaxy

  • 分享至 

  • xImage
  •  

今日目標

  • 理解 Galaxy 生態(Role/Collection)
  • 學會如何評估哪些 Role 可以使用
  • 以 Role 快速部署一個可用流程

什麼是 Galaxy

Ansible Galaxy 是社群共享的 Role/Collection 平台,換句話說可以把它想像成類似類似 PyPI、npm、RubyGems,讓我們可以直接重用別人寫好的模組,避免重新造輪子。

舉的例子:

  • 不用 Galaxy 的話
- name: Install nginx
  package: name=nginx
- name: Configure nginx
  template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
  • 用 Galaxy 的話
roles:
  - geerlingguy.nginx

可以發現使用社群好心人士寫好的 Role,可以大幅降低開發成本,提升開發效率。

廢話不多上馬上來看該怎麼使用

  • 安裝 Role
# 這邊以一個社區很有名的 Role 為例
ansible-galaxy install geerlingguy.nginx              # 安裝最新版本
ansible-galaxy install geerlingguy.nginx,3.2.0        # 安裝指定版本
ansible-galaxy install -r requirements.yml -p ./roles # 下載到專案內
ansible-galaxy install git+https://github.com/geerlingguy/ansible-role-nginx.git
ansible-galaxy install file:///path/to/local/role # 從本地安裝
  • 在 Playbook 中使用
- hosts: web
  become: yes
  roles:
    - geerlingguy.nginx # 直接導入即可
nginx_vhosts:
  - listen: "80"
    server_name: "example.com"
    root: "/var/www/html"

那社群中這麼多 Role 我該如何挑選好 Role

其實這問題不外乎就跟我們在選 opensource 專案時的概念一樣:

  1. 作者本身的評價。
  2. 這個專案的活躍度,是不是還有在維護或者是開發。
  3. 下載量、Github Repository Stars。
  4. 筆者覺得最重要的就是文件到底有沒有寫好。

依賴與版本管理(requirements.yml)

roles:
  - name: geerlingguy.nginx
    version: "3.2.0"
  - name: geerlingguy.mysql
    version: "5.1.0"
collections:
  - name: community.general
    version: ">=11.0.0"

進階用法,像是:變數、標籤、條件判斷

- hosts: web
  become: yes
  roles:
    - role: geerlingguy.nginx
      vars:
        nginx_vhosts:
          - listen: "80"
            server_name: "example.com"
            root: "/var/www/html"
      tags: [nginx]
  tasks:
    - name: Optionally install Docker
      include_role:
        name: geerlingguy.docker
      when: install_docker | default(false)

整理一下比較常用的 Role

  • Web:geerlingguy.nginx, geerlingguy.apache
  • DB:geerlingguy.mysql, bertvv.mariadb, geerlingguy.postgresql, geerlingguy.redis
  • Runtime:geerlingguy.php, geerlingguy.composer, geerlingguy.nodejs, geerlingguy.java
  • 容器/編排:geerlingguy.docker, kubernetes-sigs.kubespray
  • 監控/日誌:cloudalchemy.{prometheus,grafana,alertmanager}, elastic.elasticsearch
  • 安全/網路:geerlingguy.certbot, geerlingguy.firewall

常見問題與解法

  • 版本衝突:檢查 min_ansible_version,於 requirements.yml 鎖定版本
  • 變數衝突:用 Role 專屬變數名,或於 role 區塊內設定
  • 角色路徑:專案使用 ./rolesansible.cfgroles_path=./roles
  • 網路問題:設定代理,或改用 Git 來源或離線安裝

團隊/企業實務

  • 版本策略:production 環境要記得鎖定準確版本,測試的環境則可以允許小版更新
  • 客製化:不直接改第三方 Role,使用變數覆蓋 pre/post tasks 或 wrapper role
  • 依賴管理:一律透過 requirements.yml,並且 CI 要執行 ansible-lintyamllint--syntax-check

作業練習時間

我們今天換來實戰看看,10 分鐘搞定部署 FastAPI 和 Nginx。

  • 建立需求與安裝
# 先來建置個資料夾
mkdir fastapi-stack && cd fastapi-stack
# 創建一個 requirements.yaml
cat > requirements.yaml << 'EOF'
roles:
  - name: geerlingguy.nginx
  - name: geerlingguy.pip
EOF
ansible-galaxy install -r requirements.yml -p roles
# inventory.ini
[app_servers]
web01 ansible_host=192.168.1.10
web02 ansible_host=192.168.1.11

[app_servers:vars]
ansible_user=ubuntu
ansible_ssh_private_key_file=~/.ssh/id_rsa
# group_vars/app_servers.yaml
app_user: fastapi
app_dir: /opt/fastapi-app
app_port: 8000

nginx_remove_default_vhost: true
nginx_vhosts:
  - listen: "80"
    server_name: "{{ inventory_hostname }}"
    root: "/var/www/html"
    extra_parameters: |
      location / {
        proxy_pass http://127.0.0.1:{{ app_port }};
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      }
# site.yml
- hosts: app_servers
  become: yes

  pre_tasks:
    - name: Ensure app user and directory
      block:
        - user:
            name: "{{ app_user }}"
        - file:
            path: "{{ app_dir }}"
            state: directory
            owner: "{{ app_user }}"
            group: "{{ app_user }}"
            mode: '0755'

  roles:
    - role: geerlingguy.pip
      vars:
        pip_install_packages:
          - name: "fastapi"
            virtualenv: "{{ app_dir }}/venv"
          - name: "uvicorn[standard]"
            virtualenv: "{{ app_dir }}/venv"
    - role: geerlingguy.nginx

  tasks:
    - name: Create sample FastAPI app
      copy:
        dest: "{{ app_dir }}/main.py"
        owner: "{{ app_user }}"
        group: "{{ app_user }}"
        mode: '0644'
        content: |
          from fastapi import FastAPI
          app = FastAPI()
          @app.get("/")
          def read_root():
              return {"hello": "world"}

    - name: Create systemd service for FastAPI (uvicorn)
      copy:
        dest: /etc/systemd/system/fastapi.service
        mode: '0644'
        content: |
          [Unit]
          Description=FastAPI app
          After=network.target

          [Service]
          User={{ app_user }}
          WorkingDirectory={{ app_dir }}
          ExecStart={{ app_dir }}/venv/bin/uvicorn main:app --host 127.0.0.1 --port {{ app_port }}
          Restart=always
          Environment=PATH={{ app_dir }}/venv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin

          [Install]
          WantedBy=multi-user.target

    - name: Reload systemd and enable service
      shell: |
        systemctl daemon-reload
        systemctl enable --now fastapi.service
      args:
        warn: false

  • 下指令執行
# 執行
ansible-playbook -i inventory.ini site.yml
ansible-playbook -i inventory.ini site.yml --tags nginx   # 單獨部署 Nginx
ansible-playbook -i inventory.ini site.yml --check        # dry-run

明日預告

明天我們換來玩玩 Templates 與 Jinja2。


上一篇
Day10 - 蛤!Ansible 也有錯誤處理嗎?
下一篇
Day12 - 善用 Jinja2 template 製作動態設定檔
系列文
不爆肝學習 Ansible 的短暫30天12
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言