Tự động hóa mạngNetwork Automation
Thuộc bộ kiến thức Network Engineer Roadmap.
Tổng quan
Network automation (tự động hóa mạng) là việc dùng phần mềm — script, API, dữ liệu có cấu trúc và các công cụ — để cấu hình, quản lý, kiểm thử và vận hành thiết bị cùng dịch vụ mạng, thay vì gõ lệnh bằng tay vào CLI trên từng thiết bị một.
Suốt nhiều thập kỷ, giao diện chính của network engineer là terminal: SSH vào một switch, dán một khối config, save, rồi chuyển sang thiết bị tiếp theo. Cách làm đó không trụ được khi quy mô tăng lên. Khi bạn có 5 thiết bị, bạn có thể đăng nhập từng cái. Khi có 500, 5.000, hoặc một fleet trải rộng qua các cloud VPC và data center on-prem, cấu hình thủ công trở nên chậm, thiếu nhất quán và nguy hiểm — chỉ một dòng ACL gõ nhầm hay một subnet mask sai lúc 2 giờ sáng có thể black-hole toàn bộ traffic của cả một region.
Những lý do để automate rất cụ thể:
| Động lực | Thủ công (CLI) | Automated |
|---|---|---|
| Consistency | Mỗi thiết bị drift một kiểu; config “snowflake” không cái nào giống cái nào | Một template render ra config giống hệt nhau ở mọi nơi |
| Tốc độ | Vài phút mỗi thiết bị, tuần tự | Hàng trăm thiết bị song song, tính bằng giây |
| Ít lỗi hơn | Gõ sai, sót bước, lỗi copy-paste | Code idempotent, đã test, đã review |
| Scale | Công sức tuyến tính — 10× thiết bị = 10× công | Công sức gần như không đổi bất kể fleet lớn cỡ nào |
| Auditability | ”Ai đổi cái gì?” tan biến trong trí nhớ | Mọi thay đổi là một Git commit có author và diff |
| Repeatability | Runbook nằm trong wiki, thực thi không nhất quán | Cùng một playbook, cùng kết quả, mọi lần |
Xu hướng của ngành là dịch chuyển từ CLI sang Infrastructure as Code (IaC): trạng thái mạng được mô tả trong các file text (YAML, HCL, Jinja2 template, YANG model), lưu trong version control, review qua pull request, và áp dụng bằng công cụ. Tư duy này — đối xử với mạng theo cách các đội phần mềm đối xử với ứng dụng — thường được gọi là NetDevOps: mang văn hóa và công cụ DevOps (Git, CI/CD, testing, code review, một source of truth duy nhất) vào network engineering.
Ghi chú này đi từ nền tảng (Linux, shell, API) qua các công cụ cốt lõi (Python, Ansible, Terraform) đến các thực hành vận hành (CI/CD, version control, drift detection, source of truth) giúp automation trở nên đáng tin cậy trong production. Nó gắn chặt với các ghi chú DevOps về Infrastructure as Code và Configuration Management, và giả định bạn đã quen với core protocols cùng cloud networking ở các phần trước.
Kiến thức nền tảng
Linux và shell: nền tảng không thể thiếu
Gần như mọi công cụ automation đều chạy trên Linux, phần lớn network operating system bên dưới là Linux (Cumulus, SONiC, Arista EOS, Cisco NX-OS, IOS-XR đều expose một Linux shell), và mọi CI runner cùng container đều là một máy Linux. Bạn không cần phải là kernel hacker, nhưng bạn phải thoải mái với:
- Điều hướng và xử lý text —
grep,sed,awk,cut,sort,uniq, pipe (|), và redirection. Parse một bảng interface hay lọc dòng log là việc hằng ngày. - File permission, SSH key và
ssh_config— automation xác thực tới thiết bị qua SSH; quản lý key và cấu hình jump-host trong~/.ssh/configrất quan trọng. - Package management và virtual environment —
apt/yum, và với Python làpip+venv/virtualenvđể cô lập dependency theo từng project. - Shell scripting — một script
bashnhỏ để loop qua danh sách thiết bị, backup config bằngscp, hay kích hoạt một pipeline. Shell là chất keo; Python làm phần nặng. - Networking từ chính host —
ip addr,ip route,ss,tcpdump,dig,curl— chính những công cụ bạn dùng để debug host cũng dùng để debug xem automation của bạn đang làm gì trên đường truyền.
Một ví dụ nhanh — backup running config của mọi thiết bị trong một danh sách, song song:
#!/usr/bin/env bash
# backup-configs.sh — pull running-config from each device over SSH
set -euo pipefail
DEVICES_FILE="devices.txt" # one host per line
BACKUP_DIR="backups/$(date +%F)"
mkdir -p "$BACKUP_DIR"
while read -r host; do
[[ -z "$host" || "$host" == \#* ]] && continue
echo "Backing up $host ..."
ssh -o ConnectTimeout=10 "netadmin@${host}" 'show running-config' \
> "${BACKUP_DIR}/${host}.cfg" &
done < "$DEVICES_FILE"
wait # let all background SSH jobs finish
echo "Done. Configs saved to ${BACKUP_DIR}/"
Đây là automation ở mức đơn giản nhất, và nó đã cho bạn các snapshot có ngày tháng, có thể đưa vào version control của mọi thiết bị.
API cho networking
CLI được thiết kế cho con người; API (Application Programming Interface) được thiết kế cho máy. Thiết bị mạng hiện đại expose một hoặc nhiều interface lập trình được, trả về dữ liệu có cấu trúc (JSON hoặc XML) thay vì text tự do như lệnh show xuất ra. Dữ liệu có cấu trúc chính là điểm mấu chốt — bạn không còn phải viết những regular expression mong manh để cào một giá trị ra khỏi output CLI; bạn hỏi interfaces.GigabitEthernet0/1.oper-status và nhận về một field sạch sẽ.
Các interface chính bạn sẽ gặp:
| Interface | Transport | Encoding | Data model | Dùng điển hình |
|---|---|---|---|---|
| REST / RESTCONF | HTTP(S) | JSON / XML | YANG (RESTCONF) | CRUD trên URL resource; dễ dùng từ mọi ngôn ngữ |
| NETCONF | SSH (port 830) | XML | YANG | Config management chắc chắn, transaction, candidate/commit |
| gNMI | gRPC trên HTTP/2 | Protobuf | YANG (OpenConfig) | Streaming telemetry + config; hiệu năng cao |
| SNMP | UDP (161/162) | BER (ASN.1) | MIB (OID) | Monitoring legacy, trap; poll counter |
| Vendor REST (vd. Meraki, DNAC) | HTTP(S) | JSON | Do vendor định nghĩa | Fabric quản lý qua controller/cloud |
- REST là mẫu web phổ quát: các HTTP verb (
GET,POST,PUT,PATCH,DELETE) tác động lên resource được định địa chỉ bằng URL, với body JSON. Phần lớn API cloud và controller là REST. - NETCONF (RFC 6241) được xây riêng cho cấu hình mạng. Nó chạy trên SSH, mã hóa mọi thứ bằng XML, và — quan trọng nhất — hỗ trợ candidate configuration với commit/rollback tường minh cùng transaction, nên một thay đổi trên nhiều thiết bị có thể được validate và áp dụng atomic hoặc rút lại sạch sẽ.
- RESTCONF (RFC 8040) là một mặt trước REST/HTTP đặt lên cùng các cây dữ liệu YANG mà NETCONF expose — thân thiện hơn cho developer thích JSON và URL hơn XML và RPC.
- gNMI (gRPC Network Management Interface) là lựa chọn hiệu năng cao hiện đại, xây trên gRPC/Protobuf, và là chuẩn cho streaming telemetry (subscribe một lần, nhận về một luồng push các thay đổi counter) cũng như cho config.
YANG data model
YANG (RFC 7950) là một ngôn ngữ modeling mô tả cấu trúc của configuration và operational state — những field nào tồn tại, kiểu của chúng, ràng buộc và phân cấp — độc lập với wire encoding. NETCONF, RESTCONF và gNMI đều mang dữ liệu được định hình bởi YANG model. Hai họ đáng chú ý:
- Vendor/native model — mỗi vendor ship YANG model cho các tính năng riêng của mình.
- OpenConfig — một tập YANG model trung lập với vendor, do các nhà vận hành mạng (Google, AT&T và những bên khác) dẫn dắt, để cùng một model chạy được trên Cisco, Juniper, Arista và Nokia. Đây là giấc mơ “viết một lần, chạy trên mọi vendor”.
SNMP so với API cho cấu hình
SNMP tuyệt vời trong việc đọc counter và gửi trap, nhưng nó chưa bao giờ giỏi ghi cấu hình — SNMP SET cồng kềnh, hỗ trợ config kém, và ngữ nghĩa transaction yếu. Đồng thuận của ngành là: dùng SNMP (hoặc tốt hơn là gNMI streaming telemetry) cho monitoring, và dùng NETCONF/RESTCONF/gNMI hay một REST API cho cấu hình. SNMP là legacy đối với config; hãy coi nó chủ yếu để đọc.
Idempotency: mô hình tư duy cốt lõi
Khái niệm quan trọng nhất trong config automation là idempotency (tính lũy đẳng): áp dụng cùng một thao tác nhiều lần cho ra cùng kết quả như áp dụng một lần, và chỉ thực hiện thay đổi khi trạng thái hiện tại khác với trạng thái mong muốn.
Một script CLI imperative chạy interface Gi0/1 / ip address 10.0.0.1 255.255.255.0 sẽ phát lại những lệnh đó ở mỗi lần chạy bất kể chúng đã có sẵn hay chưa. Một công cụ idempotent thay vào đó đọc trạng thái hiện tại, so sánh với desired state được khai báo, và chỉ phát lệnh khi cần — báo changed=0 khi thiết bị đã đúng. Idempotency là thứ khiến việc chạy automation lặp lại nhiều lần (vd. ở mỗi lần chạy CI) trở nên an toàn mà không gây xáo trộn, và nó là nền tảng của drift detection bàn ở phần sau.
Khái niệm chính
Python cho network automation
Python là ngôn ngữ chung của network automation: dễ đọc, đầy đủ pin sẵn, và được hậu thuẫn bởi một hệ sinh thái thư viện phong phú cài qua pip (thường vào một virtual environment riêng cho từng project). Các thư viện chính:
| Thư viện | Làm gì | Cấp độ |
|---|---|---|
| Netmiko | SSH tới thiết bị mạng, gửi lệnh CLI, xử lý prompt/paging của vendor | Cào màn hình CLI |
| NAPALM | API trung lập vendor: get_facts, get_interfaces, config diff/merge/replace/rollback | Có cấu trúc, đa vendor |
| Nornir | Framework automation thuần Python: inventory + task runner song song (dùng Netmiko/NAPALM làm plugin) | Orchestration |
| ncclient | Thư viện NETCONF client (XML/RPC trên SSH) | NETCONF |
| Scapy | Tạo, gửi, sniff và mổ xẻ packet ở mọi layer | Test cấp packet |
| pyATS / Genie | Framework test/validation của Cisco với parser có cấu trúc | Testing |
| requests | HTTP client tổng quát cho mọi REST/RESTCONF API | REST |
- Netmiko là nơi hầu hết mọi người bắt đầu: nó trừu tượng hóa những chi tiết rối rắm của SSH, enable mode, terminal paging và các quirk theo từng vendor, cho phép bạn gửi lệnh và nhận lại output dạng text.
- NAPALM (Network Automation and Programmability Abstraction Layer with Multivendor support) đứng cao hơn một cấp — nó cho bạn các getter có cấu trúc trả về cùng dạng dict bất kể vendor, cộng thêm một workflow thay config an toàn với diff và rollback.
- Nornir cung cấp inventory và một task runner đa luồng bằng Python thuần, để bạn chạy các task Netmiko/NAPALM trên hàng trăm thiết bị đồng thời mà không phải tự viết thread pool.
- Scapy dành cho người “thợ ống nước packet” — dựng packet tùy biến để test firewall rule, khả năng reachability, hay hành vi protocol.
Một ví dụ Netmiko nhỏ, thực tế — kết nối tới một switch, push một VLAN, rồi đọc lại:
#!/usr/bin/env python3
"""Create a VLAN on a Cisco IOS switch and verify it, using Netmiko."""
from netmiko import ConnectHandler
device = {
"device_type": "cisco_ios",
"host": "192.0.2.10",
"username": "netadmin",
"password": "s3cret", # in practice: read from a vault / env var
"secret": "enablepass", # enable-mode password
}
vlan_id = 42
vlan_name = "AUTOMATION-LAB"
with ConnectHandler(**device) as conn:
conn.enable() # enter privileged EXEC
# Idempotent-ish: send_config_set only changes what it needs to
config_commands = [
f"vlan {vlan_id}",
f"name {vlan_name}",
]
output = conn.send_config_set(config_commands)
print(output)
conn.save_config() # write mem
# Read it back as verification
result = conn.send_command("show vlan brief", use_textfsm=True)
print(result) # with TextFSM, this is structured data (list of dicts)
Cờ use_textfsm=True đáng chú ý: nó cho output CLI thô đi qua một template TextFSM để bạn nhận về một list các dictionary thay vì một khối text — một cây cầu thực dụng từ cào màn hình hướng tới dữ liệu có cấu trúc khi chưa có API thật.
Một ví dụ NAPALM cho thấy lợi thế đa vendor, có cấu trúc:
import napalm
driver = napalm.get_network_driver("eos") # or "ios", "junos", "nxos_ssh"
device = driver(hostname="192.0.2.20", username="netadmin", password="s3cret")
device.open()
facts = device.get_facts() # same keys on every platform
print(facts["hostname"], facts["os_version"], facts["uptime"])
interfaces = device.get_interfaces() # structured dict, not text
for name, data in interfaces.items():
state = "up" if data["is_up"] else "down"
print(f"{name:20} {state}")
device.close()
Ansible cho thiết bị mạng
Ansible là công cụ configuration management được dùng rộng rãi nhất cho mạng. Các đặc tính định danh nó cho công việc mạng:
- Agentless — không cần cài phần mềm trên thiết bị. Nó kết nối qua SSH (hoặc API của thiết bị) từ một control node và push thay đổi. Điều này cực kỳ quan trọng với thiết bị mạng, nơi bạn thường không thể cài agent lên một switch hay router.
- Declarative và idempotent — bạn mô tả desired state trong một playbook (YAML); các network module của Ansible tự tìm ra cần chạy lệnh nào và bỏ qua những thiết bị đã ở trạng thái đích.
- Dựa trên inventory — thiết bị cùng nhóm/biến của chúng nằm trong một inventory (INI hoặc YAML), nên cùng một playbook nhắm tới một thiết bị hay một nghìn.
- Hệ sinh thái module khổng lồ — các collection như
cisco.ios,arista.eos,juniper.junos,cisco.nxos, cùng các moduleansible.netcommontổng quát cho NETCONF/CLI.
Một inventory tối giản (inventory.yml):
all:
children:
ios_switches:
hosts:
sw1: { ansible_host: 192.0.2.10 }
sw2: { ansible_host: 192.0.2.11 }
vars:
ansible_network_os: cisco.ios.ios
ansible_connection: network_cli
ansible_user: netadmin
Một playbook thực tế (configure-vlans.yml) cấu hình VLAN, một interface, rồi save — theo cách idempotent:
---
- name: Configure access VLANs on IOS switches
hosts: ios_switches
gather_facts: false
vars:
vlans:
- { id: 42, name: AUTOMATION-LAB }
- { id: 50, name: VOICE }
tasks:
- name: Ensure VLANs exist
cisco.ios.ios_vlans:
config: "{{ vlans | map('combine', {'state': 'active'}) | list }}"
state: merged # merged = idempotent add, no wipe
- name: Configure access port Gi0/1 into VLAN 42
cisco.ios.ios_l2_interfaces:
config:
- name: GigabitEthernet0/1
mode: access
access:
vlan: 42
state: merged
- name: Save running-config to startup-config
cisco.ios.ios_config:
save_when: modified # only writes mem if something changed
- name: Verify VLAN 42 is present
cisco.ios.ios_command:
commands: show vlan id 42
register: vlan_check
- name: Show verification output
ansible.builtin.debug:
var: vlan_check.stdout_lines
Chạy nó bằng ansible-playbook -i inventory.yml configure-vlans.yml. Ở lần chạy đầu Ansible báo changed; chạy lại lần nữa nó báo ok với changed=0 — đó là idempotency trong thực tế. Từ khóa state: merged là động từ idempotent: nó thêm/cập nhật những gì bạn khai báo mà không xóa phần còn lại của config (đối lập với replaced hay overridden).
Terraform và Infrastructure as Code
Nơi Ansible tỏa sáng là configuration management các thiết bị đã tồn tại, còn Terraform tỏa sáng ở provisioning — khai báo và tạo ra chính hạ tầng. Trong networking điều này thường có nghĩa là tài nguyên cloud networking: VPC/VNet, subnet, route table, security group/firewall rule, load balancer, DNS zone và record, VPN gateway, và Transit Gateway (xem cloud networking).
Terraform là:
- Declarative — bạn viết HCL mô tả trạng thái cuối mong muốn, không phải các bước. Terraform tính diff giữa hiện tại và mong muốn rồi chỉ thực thi phần cần thiết. (Đối lập với imperative: một script nói “tạo X, rồi Y” — bạn tự lo thứ tự và xử lý lỗi.)
- Dựa trên state — Terraform giữ một state file ghi lại những gì nó quản lý, nên nó biết cần thêm, đổi hay hủy gì ở lần
applytiếp theo. - Dựa trên provider — có provider cho AWS, Azure, GCP, Cloudflare, Infoblox, Cisco ACI, Palo Alto, NetBox và nhiều nữa, nên cùng một công cụ provision xuyên cloud và controller.
Một snippet thực tế — một AWS VPC với subnet, một security group và một DNS record:
terraform {
required_providers {
aws = { source = "hashicorp/aws", version = "~> 5.0" }
}
}
provider "aws" {
region = "ap-southeast-1"
}
resource "aws_vpc" "main" {
cidr_block = "10.20.0.0/16"
enable_dns_hostnames = true
tags = { Name = "prod-vpc" }
}
resource "aws_subnet" "app" {
vpc_id = aws_vpc.main.id
cidr_block = "10.20.1.0/24"
availability_zone = "ap-southeast-1a"
tags = { Name = "prod-app-subnet" }
}
resource "aws_security_group" "web" {
name = "web-sg"
vpc_id = aws_vpc.main.id
ingress {
description = "HTTPS from anywhere"
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
resource "aws_route53_record" "app" {
zone_id = var.hosted_zone_id
name = "app.example.com"
type = "A"
ttl = 300
records = ["10.20.1.10"]
}
variable "hosted_zone_id" { type = string }
Workflow là terraform init → terraform plan (hiển thị diff chính xác, một lần chạy thử) → terraform apply (thực thi nó). Bước plan là lưới an toàn: bạn review chính xác những gì sẽ được tạo, đổi hay hủy trước khi bất cứ điều gì xảy ra — tương đương với code review cho hạ tầng. Xem ghi chú DevOps Infrastructure as Code để hiểu sâu hơn về state, module và remote backend.
Configuration management so với provisioning, và drift detection
Hai từ này mô tả hai công việc khác nhau và các công cụ phản ánh sự phân chia đó:
- Provisioning — tạo hạ tầng chưa tồn tại: dựng một VPC, cấp một subnet, khởi tạo một firewall. Terraform (cùng CloudFormation, Pulumi) làm việc này.
- Configuration management — quản lý trạng thái của những thứ đã tồn tại: switch có những VLAN nào, những dòng ACL nào, những NTP server nào, community SNMP nào. Ansible (cùng Nornir, Salt) làm việc này.
Ranh giới đôi khi mờ đi — Ansible có thể provision tài nguyên cloud, Terraform có thể push một số config — nhưng mô hình tư duy vẫn đúng: provision bằng Terraform, configure bằng Ansible là một sự phân chia phổ biến, rõ ràng.
Configuration drift là khi trạng thái thực đang chạy của thiết bị lệch khỏi trạng thái dự định được định nghĩa trong code của bạn — ai đó thực hiện một thay đổi khẩn cấp ở CLI, một bản “tạm thời” thủ công không bao giờ được gỡ, hay một thiết bị reboot về config cũ. Drift là kẻ thù của một mạng đáng tin cậy. Automation cho bạn hai cách chống lại nó:
- Detection — chạy automation ở chế độ
--check/--diff(Ansible) hoặcterraform plantheo lịch. Bất kỳ diff khác rỗng nào cũng là drift; hãy alert về nó. - Remediation / enforcement — vì công cụ của bạn idempotent, chỉ cần chạy lại playbook hoặc
terraform applylà kéo thiết bị về đúng trạng thái khai báo. Khi code là source of truth, drift tự chữa lành.
CI/CD, version control, và source of truth
Mảnh ghép cuối cùng là đối xử với config mạng theo cách các đội phần mềm đối xử với code — trái tim của cách tiếp cận NetDevOps.
- Version control (Git) — mọi playbook, template, file Terraform và inventory đều nằm trong Git. Bạn có lịch sử (“ai đổi config BGP, khi nào, và tại sao”), diff, branch, và khả năng rollback về bất kỳ trạng thái known-good nào trong quá khứ.
- Code review qua pull request — không thay đổi nào chạm production mà không qua một cặp mắt thứ hai. PR chính là bản ghi change-management.
- CI/CD pipeline — một pipeline (GitHub Actions, GitLab CI, Jenkins) chạy ở mỗi PR và merge:
- Lint —
yamllint,ansible-lint,terraform fmt -check,terraform validate. - Validate / test — render template, chạy
ansible-playbook --check(dry run) hoặcterraform planvới một lab hay thiết bị thật ở check mode; chạypyATS/Batfishđể validate config kết quả offline. - Deploy — khi merge vào
main, apply lên production, thường có một cổng phê duyệt thủ công.
- Lint —
- Source of truth (SoT) — một cơ sở dữ liệu có thẩm quyền duy nhất về trạng thái mạng dự định — thiết bị, interface, IP address (IPAM), VLAN, circuit, cabling. NetBox là SoT mã nguồn mở de-facto. Automation đọc SoT để sinh config (dữ liệu thiết bị → Jinja2 template → config), thay vì config được viết tay. Điều này đảo ngược mô hình truyền thống: database là chân lý, config thiết bị là một artifact được render, và drift được đo so với SoT.
Vòng lặp NetDevOps đầu-cuối: NetBox (intent) → Jinja2/template → Git (PR + review) → CI (lint + test) → Ansible/Terraform (apply) → thiết bị → telemetry/plan (verify + phát hiện drift) → quay về intent.
Bảng so sánh công cụ
| Công cụ | Việc chính | Ngôn ngữ | Mô hình agent | Paradigm cấu hình | Hợp nhất với |
|---|---|---|---|---|---|
| Bash / shell | Keo dán, loop nhanh | Bash | Agentless (SSH) | Imperative | Script một lần, backup, keo orchestration |
| Netmiko | Automation CLI qua SSH | Python | Agentless (SSH) | Imperative | Cào màn hình, push CLI tới mọi vendor |
| NAPALM | API có cấu trúc đa vendor | Python | Agentless (SSH/API) | Gần declarative (config replace) | Getter xuyên vendor, replace/rollback config an toàn |
| Nornir | Framework automation | Python (thuần) | Agentless | Imperative (bạn code task) | Scale task Python trên inventory lớn |
| Ansible | Configuration management | YAML (+ module Python) | Agentless (SSH/API) | Declarative, idempotent | Config fleet, playbook, hỗ trợ vendor rộng |
| Terraform | Provisioning (IaC) | HCL | Agentless (API) | Declarative, dựa trên state | Cloud VPC, DNS, firewall rule, load balancer |
| SNMP | Monitoring/polling | (qua lib) | Agent (SNMP daemon) | Chủ yếu đọc | Counter, trap (config legacy) |
| gNMI / OpenConfig | Telemetry + config | Protobuf/gRPC | Agentless | Declarative (YANG) | Streaming telemetry, thiết bị hiện đại quy mô lớn |
Best Practices
- Bắt đầu nhỏ và idempotent. Automate trước một task an toàn, lặp đi lặp lại, chỉ đọc (backup config, thu thập
show). Xây niềm tin, rồi mới chuyển sang ghi. Luôn ưu tiên công cụ/động từ idempotent (state: merged,terraform plan) hơn là push CLI mù quáng. - Mọi thứ vào Git. Playbook, template, Terraform, inventory, và lý tưởng là cả config đã render. Nếu nó không nằm trong version control, nó không tồn tại. Đừng bao giờ sửa production bằng tay ngoài pipeline — điều đó tạo ra drift.
- Không bao giờ hard-code secret. Dùng Ansible Vault, HashiCorp Vault, environment variable, hoặc secret store của CI. Password và API token tuyệt đối không được lọt vào một Git commit.
- Luôn dry-run trước khi apply.
terraform planvàansible-playbook --check --diffcho thấy chính xác những gì sẽ đổi. Review diff như review code. Biếnplanthành một stage CI bắt buộc, không bỏ qua được. - Test trong lab trước. Dùng virtual lab — Containerlab, GNS3, EVE-NG, Cisco CML, hay cloud sandbox — để validate playbook trước khi nó chạm production. Validation offline với Batfish có thể bắt lỗi reachability/ACL mà không cần thiết bị nào.
- Bắt buộc review và CI ở mọi thay đổi. Không merge nếu pipeline (lint + validate) chưa pass và chưa có ít nhất một reviewer. PR là change ticket của bạn.
- Áp dụng một source of truth duy nhất. Sinh config từ NetBox (hoặc tương đương) để intent nằm ở một nơi và thiết bị trở thành artifact được render. Điều này khiến drift detection trở nên có ý nghĩa.
- Phát hiện drift liên tục. Lên lịch chạy
--check/planđịnh kỳ và alert khi có bất kỳ diff nào. Quyết định có chủ đích xem drift kích hoạt một alert (con người quyết định) hay auto-remediation (pipeline apply lại). - Ưu tiên API có cấu trúc hơn cào màn hình khi có thể. NETCONF/RESTCONF/gNMI với YANG cho bạn dữ liệu tin cậy, có kiểu; chỉ lùi về Netmiko + TextFSM ở nơi không có API.
- Làm thay đổi nhỏ và có thể đảo ngược. Thay đổi nhỏ, thường xuyên, có review thắng những đợt rollout big-bang. Luôn giữ sẵn đường rollback (Terraform state, candidate+commit của NAPALM/NETCONF, config backup).
- Xây verification vào trong. Mỗi task thay đổi nên đi kèm một task kiểm tra xác nhận trạng thái cuối dự định (vd. VLAN tồn tại, route có mặt, neighbor lên). Tự động hóa câu hỏi “nó có chạy không?”.
Tài liệu tham khảo
- Ansible Network Automation documentation
- Terraform documentation
- Netmiko (GitHub) và NAPALM documentation
- Nornir documentation
- RFC 6241 — NETCONF Configuration Protocol
- RFC 8040 — RESTCONF Protocol và RFC 7950 — The YANG 1.1 Data Modeling Language
- OpenConfig và gNMI specification
- NetBox — Network Source of Truth
Part of the Network Engineer Roadmap knowledge base.
Overview
Network automation is the practice of using software — scripts, APIs, structured data, and tooling — to configure, manage, test, and operate network devices and services instead of typing commands by hand into a CLI, one box at a time.
For decades the network engineer’s primary interface was the terminal: SSH into a switch, paste a block of config, save, move on to the next device. That workflow does not survive contact with scale. When you have 5 devices you can log in to each one. When you have 500, or 5,000, or a fleet spread across cloud VPCs and on-prem data centres, manual configuration becomes slow, inconsistent, and dangerous — a single fat-fingered ACL or a subnet mask typed wrong at 2 a.m. can black-hole traffic for an entire region.
The reasons to automate are concrete:
| Driver | Manual (CLI) | Automated |
|---|---|---|
| Consistency | Each device drifts; “snowflake” configs no two alike | One template renders identical config everywhere |
| Speed | Minutes per device, serial | Hundreds of devices in parallel, seconds |
| Fewer errors | Human typos, missed steps, copy-paste mistakes | Idempotent, tested, reviewed code |
| Scale | Linear effort — 10× devices = 10× work | Near-constant effort regardless of fleet size |
| Auditability | ”Who changed what?” lost in memory | Every change is a Git commit with an author and diff |
| Repeatability | Runbooks in a wiki, executed inconsistently | Same playbook, same result, every time |
The trajectory of the industry is a move from the CLI to Infrastructure as Code (IaC): network state is described in text files (YAML, HCL, Jinja2 templates, YANG models), stored in version control, reviewed via pull requests, and applied by tooling. This mindset — treating the network the way software teams treat applications — is often called NetDevOps: bringing DevOps culture and tooling (Git, CI/CD, testing, code review, a single source of truth) to network engineering.
This note builds up from the foundations (Linux, shell, APIs) through the core tools (Python, Ansible, Terraform) to the operational practices (CI/CD, version control, drift detection, source of truth) that make automation reliable in production. It pairs closely with the DevOps notes on Infrastructure as Code and Configuration Management, and assumes familiarity with the core protocols and cloud networking covered earlier.
Fundamentals
Linux and the shell: the non-negotiable foundation
Almost every automation tool runs on Linux, most network operating systems are Linux under the hood (Cumulus, SONiC, Arista EOS, Cisco NX-OS, IOS-XR all expose a Linux shell), and every CI runner and container is a Linux box. You do not need to be a kernel hacker, but you must be comfortable with:
- Navigating and text processing —
grep,sed,awk,cut,sort,uniq, pipes (|), and redirection. Parsing a table of interfaces or filtering log lines is a daily task. - File permissions, SSH keys, and
ssh_config— automation authenticates to devices over SSH; key management and~/.ssh/configjump-host settings matter. - Package management and virtual environments —
apt/yum, and for Pythonpip+venv/virtualenvto isolate dependencies per project. - Shell scripting — a small
bashscript to loop over a device list, back up configs withscp, or trigger a pipeline. Shell is the glue; Python is the heavy lifting. - Networking from the host —
ip addr,ip route,ss,tcpdump,dig,curl— the same tools you use to debug the host also debug what your automation is doing on the wire.
A quick example — back up the running config of every device in a list, in parallel:
#!/usr/bin/env bash
# backup-configs.sh — pull running-config from each device over SSH
set -euo pipefail
DEVICES_FILE="devices.txt" # one host per line
BACKUP_DIR="backups/$(date +%F)"
mkdir -p "$BACKUP_DIR"
while read -r host; do
[[ -z "$host" || "$host" == \#* ]] && continue
echo "Backing up $host ..."
ssh -o ConnectTimeout=10 "netadmin@${host}" 'show running-config' \
> "${BACKUP_DIR}/${host}.cfg" &
done < "$DEVICES_FILE"
wait # let all background SSH jobs finish
echo "Done. Configs saved to ${BACKUP_DIR}/"
This is automation at its simplest, and it already gives you dated, version-controllable snapshots of every device.
APIs for networking
The CLI was designed for humans; APIs (Application Programming Interfaces) are designed for machines. Modern network devices expose one or more programmatic interfaces that return structured data (JSON or XML) instead of the free-form text a show command emits. Structured data is the whole point — you no longer have to write brittle regular expressions to scrape a value out of CLI output; you ask for interfaces.GigabitEthernet0/1.oper-status and get back a clean field.
The main interfaces you will meet:
| Interface | Transport | Encoding | Data model | Typical use |
|---|---|---|---|---|
| REST / RESTCONF | HTTP(S) | JSON / XML | YANG (RESTCONF) | CRUD over resource URLs; easy from any language |
| NETCONF | SSH (port 830) | XML | YANG | Robust config management, transactions, candidate/commit |
| gNMI | gRPC over HTTP/2 | Protobuf | YANG (OpenConfig) | Streaming telemetry + config; high performance |
| SNMP | UDP (161/162) | BER (ASN.1) | MIBs (OIDs) | Legacy monitoring, traps; polling counters |
| Vendor REST (e.g. Meraki, DNAC) | HTTP(S) | JSON | Vendor-defined | Controller/cloud-managed fabrics |
- REST is the general web pattern: HTTP verbs (
GET,POST,PUT,PATCH,DELETE) act on resources addressed by URLs, with a JSON body. Most cloud and controller APIs are REST. - NETCONF (RFC 6241) is purpose-built for network configuration. It runs over SSH, encodes everything in XML, and — crucially — supports a candidate configuration with explicit commit/rollback and transactions, so a multi-device change can be validated and applied atomically or backed out cleanly.
- RESTCONF (RFC 8040) is a REST/HTTP front end onto the same YANG data trees that NETCONF exposes — friendlier for developers who prefer JSON and URLs to XML and RPCs.
- gNMI (gRPC Network Management Interface) is the modern high-performance option, built on gRPC/Protobuf, and is the standard for streaming telemetry (subscribe once, receive a push stream of counter changes) as well as config.
YANG data models
YANG (RFC 7950) is a modelling language that describes the structure of configuration and operational state — what fields exist, their types, constraints, and hierarchy — independently of the wire encoding. NETCONF, RESTCONF, and gNMI all carry data shaped by YANG models. Two families matter:
- Vendor/native models — each vendor ships YANG models for its own features.
- OpenConfig — a vendor-neutral set of YANG models driven by network operators (Google, AT&T, and others) so the same model works across Cisco, Juniper, Arista, and Nokia. This is the dream of “write once, run on any vendor.”
SNMP vs API for configuration
SNMP is excellent at reading counters and sending traps, but it was never good at writing configuration — SNMP SET is clunky, poorly supported for config, and has weak transactional semantics. The industry consensus is: use SNMP (or better, gNMI streaming telemetry) for monitoring, and use NETCONF/RESTCONF/gNMI or a REST API for configuration. SNMP is legacy for config; treat it as read-mostly.
Idempotency: the core mental model
The single most important concept in configuration automation is idempotency: applying the same operation multiple times produces the same result as applying it once, and only makes a change when the current state differs from the desired state.
An imperative CLI script that runs interface Gi0/1 / ip address 10.0.0.1 255.255.255.0 will re-issue those commands every run whether or not they are already in place. An idempotent tool instead reads the current state, compares it to the declared desired state, and issues commands only if needed — reporting changed=0 when the device is already correct. Idempotency is what makes it safe to run your automation repeatedly (e.g. on every CI run) without causing churn, and it is the foundation of drift detection discussed later.
Key Concepts
Python for network automation
Python is the lingua franca of network automation: readable, batteries-included, and backed by a rich ecosystem of libraries installed via pip (usually into a per-project virtual environment). The key libraries:
| Library | What it does | Level |
|---|---|---|
| Netmiko | SSH to network devices, send CLI commands, handle vendor prompts/paging | Screen-scraping the CLI |
| NAPALM | Vendor-agnostic API: get_facts, get_interfaces, config diff/merge/replace/rollback | Structured, multi-vendor |
| Nornir | Pure-Python automation framework: inventory + parallel task runner (uses Netmiko/NAPALM as plugins) | Orchestration |
| ncclient | NETCONF client library (XML/RPC over SSH) | NETCONF |
| Scapy | Craft, send, sniff, and dissect packets at any layer | Packet-level testing |
| pyATS / Genie | Cisco’s test/validation framework with structured parsers | Testing |
| requests | Generic HTTP client for any REST/RESTCONF API | REST |
- Netmiko is where most people start: it abstracts away the messy details of SSH, enable mode, terminal paging, and per-vendor quirks, and lets you send commands and get output back as text.
- NAPALM (Network Automation and Programmability Abstraction Layer with Multivendor support) sits one level higher — it gives you structured getters that return the same dict shape regardless of vendor, plus a safe config-replacement workflow with diff and rollback.
- Nornir provides inventory and a threaded task runner in pure Python, so you can run Netmiko/NAPALM tasks across hundreds of devices concurrently without writing your own thread pool.
- Scapy is for the packet plumber — building custom packets to test firewall rules, reachability, or protocol behaviour.
A small, real Netmiko example — connect to a switch, push a VLAN, and read it back:
#!/usr/bin/env python3
"""Create a VLAN on a Cisco IOS switch and verify it, using Netmiko."""
from netmiko import ConnectHandler
device = {
"device_type": "cisco_ios",
"host": "192.0.2.10",
"username": "netadmin",
"password": "s3cret", # in practice: read from a vault / env var
"secret": "enablepass", # enable-mode password
}
vlan_id = 42
vlan_name = "AUTOMATION-LAB"
with ConnectHandler(**device) as conn:
conn.enable() # enter privileged EXEC
# Idempotent-ish: send_config_set only changes what it needs to
config_commands = [
f"vlan {vlan_id}",
f"name {vlan_name}",
]
output = conn.send_config_set(config_commands)
print(output)
conn.save_config() # write mem
# Read it back as verification
result = conn.send_command("show vlan brief", use_textfsm=True)
print(result) # with TextFSM, this is structured data (list of dicts)
The use_textfsm=True flag is worth noting: it runs the raw CLI output through a TextFSM template so you get back a list of dictionaries instead of a text blob — a pragmatic bridge from screen-scraping toward structured data when a real API is not available.
A NAPALM example showing the multi-vendor, structured advantage:
import napalm
driver = napalm.get_network_driver("eos") # or "ios", "junos", "nxos_ssh"
device = driver(hostname="192.0.2.20", username="netadmin", password="s3cret")
device.open()
facts = device.get_facts() # same keys on every platform
print(facts["hostname"], facts["os_version"], facts["uptime"])
interfaces = device.get_interfaces() # structured dict, not text
for name, data in interfaces.items():
state = "up" if data["is_up"] else "down"
print(f"{name:20} {state}")
device.close()
Ansible for network devices
Ansible is the most widely used configuration-management tool for networks. Its defining properties for network work:
- Agentless — it does not require software installed on the device. It connects over SSH (or the device’s API) from a control node and pushes changes. This matters enormously for network gear, where you often cannot install an agent on a switch or router.
- Declarative and idempotent — you describe the desired state in a playbook (YAML); Ansible’s network modules figure out what commands to run and skip devices already in the target state.
- Inventory-driven — devices and their groupings/variables live in an inventory (INI or YAML), so the same playbook targets one device or a thousand.
- Huge module ecosystem — collections like
cisco.ios,arista.eos,juniper.junos,cisco.nxos, plus genericansible.netcommonmodules for NETCONF/CLI.
A minimal inventory (inventory.yml):
all:
children:
ios_switches:
hosts:
sw1: { ansible_host: 192.0.2.10 }
sw2: { ansible_host: 192.0.2.11 }
vars:
ansible_network_os: cisco.ios.ios
ansible_connection: network_cli
ansible_user: netadmin
A real playbook (configure-vlans.yml) that configures VLANs, an interface, and saves — idempotently:
---
- name: Configure access VLANs on IOS switches
hosts: ios_switches
gather_facts: false
vars:
vlans:
- { id: 42, name: AUTOMATION-LAB }
- { id: 50, name: VOICE }
tasks:
- name: Ensure VLANs exist
cisco.ios.ios_vlans:
config: "{{ vlans | map('combine', {'state': 'active'}) | list }}"
state: merged # merged = idempotent add, no wipe
- name: Configure access port Gi0/1 into VLAN 42
cisco.ios.ios_l2_interfaces:
config:
- name: GigabitEthernet0/1
mode: access
access:
vlan: 42
state: merged
- name: Save running-config to startup-config
cisco.ios.ios_config:
save_when: modified # only writes mem if something changed
- name: Verify VLAN 42 is present
cisco.ios.ios_command:
commands: show vlan id 42
register: vlan_check
- name: Show verification output
ansible.builtin.debug:
var: vlan_check.stdout_lines
Run it with ansible-playbook -i inventory.yml configure-vlans.yml. On the first run Ansible reports changed; run it again and it reports ok with changed=0 — that is idempotency in action. The state: merged keyword is the idempotent verb: it adds/updates what you declared without deleting the rest of the config (contrast with replaced or overridden).
Terraform and Infrastructure as Code
Where Ansible shines at configuration management of existing devices, Terraform shines at provisioning — declaring and creating the infrastructure itself. In networking this most often means cloud networking resources: VPCs/VNets, subnets, route tables, security groups/firewall rules, load balancers, DNS zones and records, VPN gateways, and Transit Gateways (see cloud networking).
Terraform is:
- Declarative — you write HCL describing the desired end state, not the steps. Terraform computes the diff between current and desired and executes only what is needed. (Contrast imperative: a script that says “create X, then Y” — you own the ordering and the error handling.)
- State-based — Terraform keeps a state file recording what it manages, so it knows what to add, change, or destroy on the next
apply. - Provider-based — providers exist for AWS, Azure, GCP, Cloudflare, Infoblox, Cisco ACI, Palo Alto, NetBox, and more, so the same tool provisions across clouds and controllers.
A real snippet — an AWS VPC with a subnet, a security group, and a DNS record:
terraform {
required_providers {
aws = { source = "hashicorp/aws", version = "~> 5.0" }
}
}
provider "aws" {
region = "ap-southeast-1"
}
resource "aws_vpc" "main" {
cidr_block = "10.20.0.0/16"
enable_dns_hostnames = true
tags = { Name = "prod-vpc" }
}
resource "aws_subnet" "app" {
vpc_id = aws_vpc.main.id
cidr_block = "10.20.1.0/24"
availability_zone = "ap-southeast-1a"
tags = { Name = "prod-app-subnet" }
}
resource "aws_security_group" "web" {
name = "web-sg"
vpc_id = aws_vpc.main.id
ingress {
description = "HTTPS from anywhere"
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
resource "aws_route53_record" "app" {
zone_id = var.hosted_zone_id
name = "app.example.com"
type = "A"
ttl = 300
records = ["10.20.1.10"]
}
variable "hosted_zone_id" { type = string }
The workflow is terraform init → terraform plan (shows the exact diff, a dry run) → terraform apply (executes it). The plan step is the safety net: you review precisely what will be created, changed, or destroyed before anything happens — the network equivalent of code review for infrastructure. See the DevOps Infrastructure as Code note for a deeper treatment of state, modules, and remote backends.
Configuration management vs provisioning, and drift detection
These two words describe different jobs and the tools reflect that split:
- Provisioning — creating infrastructure that did not exist: spin up a VPC, allocate a subnet, instantiate a firewall. Terraform (and CloudFormation, Pulumi) own this.
- Configuration management — managing the state of things that already exist: which VLANs are on a switch, which ACL lines, which NTP servers, which SNMP community. Ansible (and Nornir, Salt) own this.
The line blurs — Ansible can provision cloud resources, Terraform can push some config — but the mental model holds: provision with Terraform, configure with Ansible is a common, clean division.
Configuration drift is when the real, running state of a device diverges from the intended state defined in your code — someone made an emergency change at the CLI, a manual “temporary” fix that was never removed, or a device rebooted to an old config. Drift is the enemy of a reliable network. Automation gives you two ways to fight it:
- Detection — run your automation in
--check/--diff(Ansible) orterraform planmode on a schedule. Any non-empty diff is drift; alert on it. - Remediation / enforcement — because your tooling is idempotent, simply re-running the playbook or
terraform applysnaps the device back to the declared state. When the code is the source of truth, drift is self-healing.
CI/CD, version control, and source of truth
The final piece is treating network config the way software teams treat code — the heart of the NetDevOps approach.
- Version control (Git) — every playbook, template, Terraform file, and inventory lives in Git. You get history (“who changed the BGP config, when, and why”), diffs, branches, and the ability to roll back to any past known-good state.
- Code review via pull requests — no change reaches production without a second set of eyes. The PR is the change-management record.
- CI/CD pipelines — a pipeline (GitHub Actions, GitLab CI, Jenkins) runs on every PR and merge:
- Lint —
yamllint,ansible-lint,terraform fmt -check,terraform validate. - Validate / test — render templates, run
ansible-playbook --check(dry run) orterraform planagainst a lab or the live device in check mode; runpyATS/Batfishto validate the resulting config offline. - Deploy — on merge to
main, apply to production, often gated by a manual approval.
- Lint —
- Source of truth (SoT) — a single authoritative database of intended network state — devices, interfaces, IP addresses (IPAM), VLANs, circuits, cabling. NetBox is the de-facto open-source SoT. Automation reads the SoT to generate config (device data → Jinja2 template → config), rather than config being hand-written. This inverts the traditional model: the database is the truth, the device config is a rendered artifact, and drift is measured against the SoT.
The end-to-end NetDevOps loop: NetBox (intent) → Jinja2/templates → Git (PR + review) → CI (lint + test) → Ansible/Terraform (apply) → device → telemetry/plan (verify + detect drift) → back to intent.
Tool comparison
| Tool | Primary job | Language | Agent model | Config paradigm | Best for |
|---|---|---|---|---|---|
| Bash / shell | Glue, quick loops | Bash | Agentless (SSH) | Imperative | One-off scripts, backups, orchestration glue |
| Netmiko | SSH CLI automation | Python | Agentless (SSH) | Imperative | Screen-scraping, pushing CLI to any vendor |
| NAPALM | Multi-vendor structured API | Python | Agentless (SSH/API) | Declarative-ish (config replace) | Cross-vendor getters, safe config replace/rollback |
| Nornir | Automation framework | Python (pure) | Agentless | Imperative (you code tasks) | Scaling Python tasks over big inventories |
| Ansible | Configuration management | YAML (+ Python modules) | Agentless (SSH/API) | Declarative, idempotent | Fleet config, playbooks, broad vendor support |
| Terraform | Provisioning (IaC) | HCL | Agentless (API) | Declarative, state-based | Cloud VPCs, DNS, firewall rules, load balancers |
| SNMP | Monitoring/polling | (via libs) | Agent (SNMP daemon) | Read-mostly | Counters, traps (legacy config) |
| gNMI / OpenConfig | Telemetry + config | Protobuf/gRPC | Agentless | Declarative (YANG) | Streaming telemetry, high-scale modern devices |
Best Practices
- Start small and idempotent. Automate one safe, repetitive, read-only task first (config backups,
showcollection). Build confidence, then move to writes. Always prefer idempotent tools/verbs (state: merged,terraform plan) over blind CLI pushes. - Everything in Git. Playbooks, templates, Terraform, inventories, and ideally rendered configs. If it is not in version control, it does not exist. Never edit production by hand outside the pipeline — that creates drift.
- Never hard-code secrets. Use Ansible Vault, HashiCorp Vault, environment variables, or your CI’s secret store. Passwords and API tokens must never land in a Git commit.
- Always dry-run before applying.
terraform planandansible-playbook --check --diffshow exactly what will change. Review the diff like you would review code. Makeplana required, non-skippable CI stage. - Test in a lab first. Use virtual labs — Containerlab, GNS3, EVE-NG, Cisco CML, or cloud sandboxes — to validate playbooks before they touch production. Offline validation with Batfish can catch reachability/ACL mistakes without any device.
- Enforce review and CI on every change. No merge without a passing pipeline (lint + validate) and at least one reviewer. The PR is your change ticket.
- Adopt a single source of truth. Drive config generation from NetBox (or equivalent) so intent lives in one place and devices become rendered artifacts. This makes drift detection meaningful.
- Detect drift continuously. Schedule periodic
--check/planruns and alert on any diff. Decide deliberately whether drift triggers an alert (human decides) or auto-remediation (pipeline re-applies). - Prefer structured APIs over screen-scraping when available. NETCONF/RESTCONF/gNMI with YANG give you reliable, typed data; fall back to Netmiko + TextFSM only where no API exists.
- Make changes small and reversible. Small, frequent, reviewed changes beat big-bang rollouts. Keep rollback paths (Terraform state, NAPALM/NETCONF candidate+commit, config backups) ready.
- Build in verification. Every change task should be followed by a check task that confirms the intended end state (e.g. the VLAN exists, the route is present, the neighbour is up). Automate the “did it work?” question.
References
- Ansible Network Automation documentation
- Terraform documentation
- Netmiko (GitHub) and NAPALM documentation
- Nornir documentation
- RFC 6241 — NETCONF Configuration Protocol
- RFC 8040 — RESTCONF Protocol and RFC 7950 — The YANG 1.1 Data Modeling Language
- OpenConfig and gNMI specification
- NetBox — Network Source of Truth