Sổ tay kỹ thuật

Backup cấu hình router vào Git

how-to#backup#git#ansible#oxidized· cập nhật 2026-11-06

Dùng khi cần backup config IOS XR/Junos định kỳ bằng Oxidized hoặc Ansible, lưu vào Git để xem lịch sử và diff giữa các lần thay đổi.

Sửa trang này
Mục lục

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):

oxidized/config
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: 2
oxidized/router.db
pe1-hni:198.51.100.11:iosxr
pe2-hcm:198.51.100.12:iosxr
mx1-hcm:198.51.100.21:junos
docker 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 HEAD

Model 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

backup.yml
- 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 20

Lị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

Tham khảo