Tóm tắt: Hai cách phổ biến. Oxidized: daemon chuyên backup, tự poll theo chu kỳ, mỗi thay đổi là một commit Git, có REST/Web UI. Ansible: playbook chạy show running-config / show configuration | display set, ghi mỗi router một file, rồi git commit nếu có thay đổi. Dù cách nào, phải lọc bỏ dòng thay đổi theo thời gian (timestamp, "Last configuration change") để Git chỉ ghi nhận thay đổi thật.
Luồng hoạt động
flowchart LR A["cron / systemd timer"] --> B["Ansible playbook"] C["Oxidized (interval)"] --> D[("Router IOS XR / Junos")] B --> D D -->|"running config"| E["lọc dòng timestamp"] E --> F["configs/host.cfg"] F --> G["git commit nếu có diff"] G --> H["git push lên GitLab/GitHub"]
Cấu hình
Cách 1: Oxidized
Chạy bằng Docker, config nằm trong ~/.config/oxidized/ của user oxidized (thư mục được mount):
interval: 3600 # giây giữa hai lần backup một node
use_syslog: false
threads: 20
timeout: 30
retries: 2
rest: 127.0.0.1:8888 # REST + web UI (cần oxidized-web), chỉ bind localhost
username: backup
password: "***" # file này chứa mật khẩu: chmod 600, không commit
model: junos
vars:
remove_secret: true # thay secret trong config bằng <secret hidden>
input:
default: ssh
output:
default: git
git:
user: oxidized
email: oxidized@example.com
repo: "/home/oxidized/.config/oxidized/configs.git"
source:
default: csv
csv:
file: "/home/oxidized/.config/oxidized/router.db"
delimiter: !ruby/regexp /:/
map:
name: 0
ip: 1
model: 2pe1-hni:198.51.100.11:iosxr
pe2-hcm:198.51.100.12:iosxr
mx1-hcm:198.51.100.21:junosdocker run -d --name oxidized --restart unless-stopped \
-v "$PWD/oxidized:/home/oxidized/.config/oxidized" \
-p 127.0.0.1:8888:8888 oxidized/oxidized:latest
# Bắt backup ngay một node qua REST
curl -s http://127.0.0.1:8888/node/next/pe1-hni
# Xem lịch sử trong repo (bare repo, đọc bằng git --git-dir)
git --git-dir oxidized/configs.git log --oneline -5
git --git-dir oxidized/configs.git show HEADModel iosxr và junos của Oxidized đã tự bỏ các dòng thay đổi theo thời gian. Nguồn node có thể đổi sang http để đọc từ NetBox (xem NetBox REST API và pynetbox). Muốn tự push lên GitLab thì cấu hình hooks loại githubrepo.
Cách 2: Ansible + Git
- name: Backup running config
hosts: iosxr:junos
gather_facts: false
vars:
ansible_connection: ansible.netcommon.network_cli
backup_cmd:
cisco.iosxr.iosxr: show running-config
junipernetworks.junos.junos: show configuration | display set
volatile_re: '^(Building configuration|!! Last configuration change|## Last commit|\w{3} \w{3} +\d+ [\d:.]+ \w+$).*\n'
tasks:
- name: Lấy config
ansible.netcommon.cli_command:
command: "{{ backup_cmd[ansible_network_os] }}"
register: cfg
- name: Ghi file, bỏ dòng timestamp
ansible.builtin.copy:
content: "{{ cfg.stdout | regex_replace(volatile_re, '', multiline=True) }}\n"
dest: "configs/{{ inventory_hostname }}.cfg"
delegate_to: localhost
- name: Commit vào Git
hosts: localhost
gather_facts: false
tasks:
- name: git add + commit nếu có thay đổi
ansible.builtin.shell: |
cd configs
git add -A
if git diff --cached --quiet; then echo nochange
else git commit -q -m "backup $(date -u +%Y-%m-%dT%H:%MZ)"; fi
register: git_out
changed_when: "'nochange' not in git_out.stdout"# Lần đầu
mkdir -p configs && git -C configs init
# Chạy định kỳ (cron hoặc systemd timer)
ansible-playbook -i inventory backup.yml -f 20Lịch chạy bằng systemd timer: systemd service và timer.
Xem diff
| Mục đích | Lệnh |
|---|---|
| Lịch sử của một router | git -C configs log --oneline -- pe1-hni.cfg |
| Diff lần gần nhất | git -C configs log -p -1 -- pe1-hni.cfg |
| So với 1 tuần trước | git -C configs diff $(git -C configs rev-list -1 --before='1 week ago' HEAD) HEAD -- pe1-hni.cfg |
| Ai/khi nào đổi dòng nào | git -C configs blame pe1-hni.cfg |
| Tìm commit có chuỗi | git -C configs log -S "neighbor 203.0.113.1" --oneline |
| Diff theo từ (description, IP) | git -C configs diff --word-diff HEAD~1 |
Running config chứa secret: hash mật khẩu, SNMP community, key TACACS/BGP MD5. Repo backup phải private, giới hạn người đọc. Muốn đẩy lên nơi rộng hơn thì lọc thêm các dòng này (Oxidized: vars: remove_secret: true như ví dụ trên).
Lỗi thường gặp
| Triệu chứng | Nguyên nhân | Cách xử lý |
|---|---|---|
| Mỗi lần chạy đều có commit dù không ai đổi config | Còn dòng timestamp / counter trong output | Bổ sung regex lọc, so git diff để thấy dòng nào đổi |
Oxidized log no node ... model hoặc sai prompt |
Tên model sai (ios cho XR) |
Dùng iosxr, junos; kiểm tra cột model trong router.db |
| Junos backup ra dạng ngoặc nhọn dài, khó diff | Dùng show configuration |
Dùng | display set (mỗi dòng một lệnh, diff gọn) |
command timeout triggered với chassis lớn |
Running config dài | ansible_command_timeout: 300 |
| File backup bị rỗng nhưng vẫn commit | Lệnh lỗi quyền (AAA), output là thông báo lỗi | Kiểm tra cfg.stdout có độ dài hợp lý trước khi ghi, task-group đọc config trên XR |
git commit báo Please tell me who you are |
User chạy cron chưa cấu hình Git | git -C configs config user.name backup và user.email |