寫到今天突然發現筆者竟然沒介紹到 Ansible 最重要的一個東西,那就是 ansible.cfg
,這個檔案是負責 Ansible 的主要配置,通常會將其放在專案目錄裡,或者是系統的 etc/ansible/ansible.cfg
。
# ansible.cfg
[defaults]
# inventory file 的位置
inventory = ./inventories
# role file 的位置
roles_path = ./roles
# Ansible 用 SSH 連線到遠端主機時,會檢查主機的 SSH host key,確保遠端主機沒有被冒充
host_key_checking = False
# SSH 連線超時時間,單位為秒
timeout = 600
# 這個設定筆者蠻建議大家可以打開的,因為可以很清楚看到什麼 task 執行了多少時間
callbacks_enabled = profile_tasks
# 並行執行的數量 (default: 5)
forks = 20
# 設定輸出格式 (預設是 default,可改成 yaml 或 json,yaml 比較容易閱讀)
stdout_callback = yaml
[ssh_connection]
# ControlMaster=auto 允許多個 SSH 連線共用一個控制連線
# ControlPersist=60s 在最後一個連線結束後,仍保留控制連線 60 秒,避免重複建立 SSH
ssh_args = -o ControlMaster=auto -o ControlPersist=60s
# 預設 Ansible 會先將模組傳到遠端再執行,開啟 pipelining 後改為透過單一管道直接執行
pipelining = True
以上內容是筆者比較常用的設定,其餘大家可以參考一下文件
# 把剛剛創建好的機器資訊填入,請確保可以 ssh 連線到機器
---
web_servers:
hosts:
vultr:
ansible_host: your_ip
ansible_port: 22
ansible_user: your_user_name
ansible_python_interpreter: /usr/bin/python3
# templates/fastapi.service.j2
# Managed by Ansible – DO NOT EDIT
[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
# templates/nginx_fastapi.conf.j2
# Managed by Ansible – DO NOT EDIT
server {
listen 80;
server_name {{ inventory_hostname | default('_') }};
location / {
proxy_pass http://127.0.0.1:{{ app_port }};
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
---
# fastapi-stack.yml
- name: Day14 FastAPI deployment
# 因為筆者的 host.yaml 有定義成 web_servers,這邊就看各位的定義去做設定即可
hosts: web_servers
# 讓我們可以使用 sudo 權限
become: yes
# 搜集機器資訊
gather_facts: true
vars:
# 設定變數,像是 port 之類的
app_user: fastapi
app_dir: /opt/fastapi-app
app_port: 8000
# 若不需反向代理改為 false
enable_nginx: true
packages:
Debian: [python3, python3-venv, python3-pip]
RedHat: [python3, python3-virtualenv, python3-pip]
nginx_pkg:
Debian: nginx
RedHat: nginx
# 在執行這份 Playbook 前會做的任務
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'
tasks:
- name: Install base packages
package:
name: "{{ packages[ansible_facts['os_family']] | default(packages['Debian']) }}"
state: present
- name: Create virtualenv
command: python3 -m venv {{ app_dir }}/venv
args:
creates: "{{ app_dir }}/venv/bin/python"
- name: Install FastAPI and Uvicorn
pip:
name:
- fastapi
- "uvicorn[standard]"
virtualenv: "{{ app_dir }}/venv"
- 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: Install nginx (optional)
package:
name: "{{ nginx_pkg[ansible_facts['os_family']] | default(nginx_pkg['Debian']) }}"
state: present
when: enable_nginx
- name: Deploy systemd service for FastAPI
template:
src: templates/fastapi.service.j2
dest: /etc/systemd/system/fastapi.service
mode: '0644'
notify: Reload systemd
- name: Deploy nginx reverse proxy (optional)
template:
src: templates/nginx_fastapi.conf.j2
dest: /etc/nginx/conf.d/fastapi.conf
mode: '0644'
validate: 'nginx -t -c %s'
when: enable_nginx
notify: Reload nginx
- name: Enable and start services
service:
name: "{{ 'nginx' if enable_nginx else 'fastapi' }}"
state: started
enabled: yes
- name: Ensure FastAPI service is started
service:
name: fastapi
state: started
enabled: yes
handlers:
- name: Reload systemd
systemd:
daemon_reload: yes
- name: Reload nginx
service:
name: nginx
state: reloaded
# Run Playbook
# 若已在 ansible.cfg 設定 inventory 的話就不需要指定
ansible-playbook fastapi-stack.yml
# 若未設定,或想手動指定
ansible-playbook -i snippets/host.yaml fastapi-stack.yml
app_port
、enable_nginx
放到 group_vars/all.yaml
EnvironmentFile
)明天讓我們來深入了解 Role 的概念吧!