简介

NetBox 是专为网络运维人员管理数据中心资产而打造的开源工具。和 iTop (iTop 是完全基于 ITIL 的工具,CMDB 仅是其中的部分功能)相比,它的功能更聚焦,对应的功能更简洁,并且原生提供了自定义设备组件配置的功能(iTop 需要自定义,当然也更灵活)

中小型规模的使用 NetBox,规模较大且管理要求高的还是推荐 iTop。

与通用CMDB不同,NetBox策划了一个专门满足网络工程师和运营商需求的数据模型。它提供了精心设计的各种对象类型,以最好地满足基础架构设计和文档的需求。这些涵盖了网络技术的所有方面,从 IP 地址管理到布线再到覆盖层等等:

  • 分层地区、数据中心和物理位置
  • 机架、设备和设备组件
  • 线路连接和无线连接管理
  • 供电跟踪
  • 虚拟线路和提供商
  • 虚拟机和群集
  • IP 网段、汇聚和地址
  • VRF 和 RT
  • FHRP组(VRRP,HSRP等)
  • AS 编号
  • VLAN 和作用域 VLAN 组
  • L2VPN 虚拟网络
  • 租户分配

联系人管理

架构图

安装步骤

安装环境介绍

  • 使用Rocky Linux 9.2 (关闭SE Linux和防火墙)(也适用于RHEL 9系列及其衍生发行版)
  • 使用Python 3.9
  • 使用PostgreSQL 15
  • 使用Redis 6
  • NetBox版本:3.5.6
  • 硬件配置:建议4C8G以上,100G存储空间。

关闭 Selinux 和防火墙

systemctl disable --now firewalld
sed -i 's/^SELINUX=enforcing$/SELINUX=disabled/' /etc/selinux/config && setenforce 0

dnf install tree vim bash-completion -y

# 安装一些工具

安装和配置数据库

更具体的数据库安装配置操作可以参考:PGSQL 安装配置指南 https://wiki.waringid.me/x/RAES

dnf module install postgresql:15 -y


# 指定安装15版本

postgresql-setup --initdb

# 初始化数据库

vim /var/lib/pgsql/data/pg_hba.conf

# "local" is for Unix domain socket connections only
local   all             all                                     peer
# IPv4 local connections:
host    all             all             127.0.0.1/32            scram-sha-256
# IPv6 local connections:
host    all             all             ::1/128                 scram-sha-256

# 将主机连接的加密方式将ident改为scram-sha-256即可。

systemctl enable --now postgresql

# 启动并设置开机启动

systemctl status postgresql
ss -an | grep 5432

# 查看是否正常启动

修改密码并创建数据库

sudo -u postgres psql

# 登录到PostgreSQL shell

ALTER USER postgres WITH PASSWORD 'waringid.com';

# 运行查询,为默认的PostgreSQL用户“postgres”设置新密码。

CREATE DATABASE netboxdb;

# 创建数据库

quit

# 退出

PS: 优化配置生成器:https://pgtune.leopard.in.ua/

安装和配置 Redis

Redis 更详细的配置可以参照:redis 常用操作指令 https://wiki.waringid.me/x/pgMS

dnf install redis -y
vim /etc/redis/redis.conf

requirepass waringid.com

# 打开配置文件,找到被注释的requirepass行,修改密码为waringid.com。保存文件并退出
systemctl enable --now redis

# 配置启动并开机启动

systemctl status redis
ss -an | grep 6379

# 验证启动

redis-cli 
127.0.0.1:6379> AUTH waringid.com
OK
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> exit

# 输入密码登录验证是否正常

前期环境配置

dnf install gcc libxml2-devel libxslt-devel libffi-devel libpq-devel openssl-devel redhat-rpm-config git -y

# 安装环境,系统默认有Python3.9
useradd -r -d /opt/netbox -s /usr/sbin/nologin netbox

# 创建netbox用户

mkdir -p /opt/netbox; cd /opt/netbox

# 创建netbox所属权限的文件,作为安装主文件夹。并CD过去。

git clone -b master --depth 1 https://github.com/netbox-community/netbox.git .

# 下载最新源代码,如果网络不允许,可以手动下载,上传到服务器。

chown -R netbox:netbox /opt/netbox

cd /opt/netbox/netbox/netbox

# 配置netbox文件夹权限所属。

tree  -L 3 /opt/
/opt/
└── netbox
    ├── base_requirements.txt
    ├── CHANGELOG.md
    ├── contrib
    │   ├── apache.conf
    │   ├── gunicorn.py
    │   ├── netbox-housekeeping.service
    │   ├── netbox-housekeeping.sh
    │   ├── netbox-housekeeping.timer
    │   ├── netbox-rq.service
    │   ├── netbox.service
    │   ├── nginx.conf
    │   ├── openapi2.json
    │   └── openapi2.yaml
    ├── CONTRIBUTING.md
    ├── docs
    │   ├── administration
    │   ├── configuration
    │   ├── customization
    │   ├── development
    │   ├── extra.css
    │   ├── features
    │   ├── getting-started
    │   ├── index.md
    │   ├── installation
    │   ├── integrations
    │   ├── introduction.md
    │   ├── media
    │   ├── models
    │   ├── netbox_logo.png
    │   ├── netbox_logo.svg
    │   ├── plugins
    │   ├── reference
    │   ├── release-notes
    │   └── _theme
    ├── LICENSE.txt
    ├── mkdocs.yml
    ├── netbox
    │   ├── circuits
    │   ├── core
    │   ├── dcim
    │   ├── extras
    │   ├── generate_secret_key.py
    │   ├── ipam
    │   ├── manage.py
    │   ├── media
    │   ├── netbox
    │   ├── project-static
    │   ├── reports
    │   ├── scripts
    │   ├── templates
    │   ├── tenancy
    │   ├── users
    │   ├── utilities
    │   ├── virtualization
    │   └── wireless
    ├── NOTICE
    ├── pyproject.toml
    ├── README.md
    ├── requirements.txt
    ├── scripts
    │   ├── git-hooks
    │   └── verify-bundles.sh
    ├── SECURITY.md
    └── upgrade.sh

# 查看当前目录结构 

生成并配置密钥

cd /opt/netbox/netbox/netbox

# 确保进入到此目录

sudo -u netbox cp configuration_example.py configuration.py

# 创建配置文件,指定用户权限

sudo -u netbox python3 ../generate_secret_key.py

# 生成密钥,生成的密钥示例:SOGo0)YKa^RMGs&b=4p1AtnB-5nZq(!N#2-cah$q972DPCf&%F

sudo -u netbox vim configuration.py

SECRET_KEY = 'SOGo0)YKa^RMGs&b=4p1AtnB-5nZq(!N#2-cah$q972DPCf&%F'

# 打开配置文件,将生成的密钥写入进去。

配置数据库连接

cd /opt/netbox/netbox/netbox

sudo -u netbox vim configuration.py

ALLOWED_HOSTS = ["*"]

# 代表可以通过任意域名访问Netbox

DATABASE = {
    'ENGINE': 'django.db.backends.postgresql',  # Database engine
    'NAME': 'netboxdb',               # 配置数据库名字
    'USER': 'postgres',               # 数据库用户
    'PASSWORD': 'Songxwn.com',            # 数据库用户密码
    'HOST': 'localhost',      # Database server
    'PORT': '',               # Database port (leave blank for default)
    'CONN_MAX_AGE': 300,      # Max database connection age
}


REDIS = {
    'tasks': {
        'HOST': 'localhost',
        'PORT': 6379,
        'USERNAME': '',
        'PASSWORD': 'waringid.com',  #配置数据库密码
        'DATABASE': 0,
        'SSL': False,
    },
    'caching': {
        'HOST': 'localhost',
        'PORT': 6379,
        'USERNAME': '',
        'PASSWORD': 'Songxwn.com',  #配置数据库密码
        'DATABASE': 1,
        'SSL': False,

    }
}

SECRET_KEY = 'SOGo0)YKa^RMGs&b=4p1AtnB-5nZq(!N#2-cah$q972DPCf&%F'

# 加密密钥

ENABLE_LOCALIZATION = True

# 开启本地化,让一些选项中文。

TIME_ZONE = 'Asia/Shanghai'

# 配置时区

PAGINATE_COUNT = 60

# 配置查看的时候默认分页数量

初始化数据库和环境

sed -i 'pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple' /opt/netbox/upgrade.sh

# 配置安装环境的时候,使用清华源的pypi。(可不配置)

sudo -u netbox /opt/netbox/upgrade.sh

# 执行安装,需要较久时间。

Completed.
Removing expired user sessions (python3 netbox/manage.py clearsessions)...
Clearing the cache (python3 netbox/manage.py clearcache)...
Cache has been cleared.
Upgrade complete! Don't forget to restart the NetBox services:
  > sudo systemctl restart netbox netbox-rq

# 出现以上字符代表成功。

创建管理员账户

source /opt/netbox/venv/bin/activate

# 进入虚拟环境

cd /opt/netbox/netbox
python3 manage.py createsuperuser

Username (leave blank to use 'root'): admin
Email address: me@songxwn.com
Password: 
Password (again): 
Superuser created successfully.

# 创建管理员 admin,输入邮箱和两遍密码。

配置每天的清理任务

sudo ln -s /opt/netbox/contrib/netbox-housekeeping.sh /etc/cron.daily/netbox-housekeeping

配置Gunicorn WSGI

Gunicorn 是一个 Python 的 WSGI HTTP 服务器。

sudo -u netbox cp /opt/netbox/contrib/gunicorn.py /opt/netbox/gunicorn.py

# 复制创建配置文件

sudo -u netbox vim /opt/netbox/gunicorn.py

# 可修改配置文件,更改监听端口,默认8001

cp -v /opt/netbox/contrib/*.service /etc/systemd/system/

# 复制到系统服务

systemctl daemon-reload

# 重新加载系统服务

systemctl enable --now netbox netbox-rq

# 配置启动并开机启动

systemctl status netbox
systemctl status netbox-rq

# 查看状态

配置 nginx 反向代理

dnf install nginx -y

# 安装Nginx

vim /etc/nginx/conf.d/netbox.conf

# 创建配置文件,注意修改netbox.waringid.com 为自己的域名。反向代理到8001端口

server {
    listen 80;
    # CHANGE THIS TO YOUR SERVER'S NAME
    server_name netbox.waringid.com;
    client_max_body_size 25m;
    fastcgi_connect_timeout 1200s;
    fastcgi_send_timeout 1200s;
    fastcgi_read_timeout 1200s;
    fastcgi_buffer_size 64k;
    fastcgi_buffers 4 64k;
    fastcgi_busy_buffers_size 128k;
    fastcgi_temp_file_write_size 256k;

    location /static/ {
        alias /opt/netbox/netbox/static/;
    }

    location / {
        proxy_pass http://127.0.0.1:8001;
        proxy_set_header X-Forwarded-Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
		proxy_connect_timeout       600;
        proxy_send_timeout          600;
        proxy_read_timeout          600;
        send_timeout                600;

    }

}

systemctl enable --now nginx

# 配置启动并开机启动

systemctl status nginx

# 查看状态

菜单汉化

文件路径:vim /opt/netbox/netbox/netbox/navigation/menu.py

from django.utils.translation import gettext as _

from netbox.registry import registry
from . import *

#
# Nav menus
#

ORGANIZATION_MENU = Menu(
    label=_('组织机构'),
    icon_class='mdi mdi-domain',
    groups=(
        MenuGroup(
            label=_('机房'),
            items=(
                get_model_item('dcim', 'site', _('数据中心')),
                get_model_item('dcim', 'region', _('地区')),
                get_model_item('dcim', 'sitegroup', _('数据中心组')),
                get_model_item('dcim', 'location', _('具体地点')),
            ),
        ),
        MenuGroup(
            label=_('机架'),
            items=(
                get_model_item('dcim', 'rack', _('机柜')),
                get_model_item('dcim', 'rackrole', _('机柜角色')),
                get_model_item('dcim', 'rackreservation', _('预留')),
                MenuItem(
                    link='dcim:rack_elevation_list',
                    link_text=_('立面图'),
                    permissions=['dcim.view_rack']
                ),
            ),
        ),
        MenuGroup(
            label=_('租凭'),
            items=(
                get_model_item('tenancy', 'tenant', _('租户')),
                get_model_item('tenancy', 'tenantgroup', _('租户组')),
            ),
        ),
        MenuGroup(
            label=_('联系方式'),
            items=(
                get_model_item('tenancy', 'contact', _('联系人')),
                get_model_item('tenancy', 'contactgroup', _('联系人组')),
                get_model_item('tenancy', 'contactrole', _('联系人角色')),
                get_model_item('tenancy', 'contactassignment', _('联系方式分配'), actions=[]),
            ),
        ),
    ),
)

DEVICES_MENU = Menu(
    label=_('设备'),
    icon_class='mdi mdi-server',
    groups=(
        MenuGroup(
            label=_('Devices'),
            items=(
                get_model_item('dcim', 'device', _('设备')),
                get_model_item('dcim', 'module', _('模块组件')),
                get_model_item('dcim', 'devicerole', _('设备角色')),
                get_model_item('dcim', 'platform', _('平台')),
                get_model_item('dcim', 'virtualchassis', _('虚拟机箱')),
                get_model_item('dcim', 'virtualdevicecontext', _('Virtual Device Contexts')),
            ),
        ),
        MenuGroup(
            label=_('类型'),
            items=(
                get_model_item('dcim', 'devicetype', _('设备型号')),
                get_model_item('dcim', 'moduletype', _('模块类型')),
                get_model_item('dcim', 'manufacturer', _('制造商')),
            ),
        ),
        MenuGroup(
            label=_('设备组件'),
            items=(
                get_model_item('dcim', 'interface', _('接口')),
                get_model_item('dcim', 'frontport', _('前端口')),
                get_model_item('dcim', 'rearport', _('后端口')),
                get_model_item('dcim', 'consoleport', _('Console 端口')),
                get_model_item('dcim', 'consoleserverport', _('Console 服务器端口')),
                get_model_item('dcim', 'powerport', _('电力接口')),
                get_model_item('dcim', 'poweroutlet', _('电源插座PDU')),
                get_model_item('dcim', 'modulebay', _('模块组件托架')),
                get_model_item('dcim', 'devicebay', _('设备托架')),
                get_model_item('dcim', 'inventoryitem', _('库存物品')),
                get_model_item('dcim', 'inventoryitemrole', _('库存项目角色')),
            ),
        ),
    ),
)

CONNECTIONS_MENU = Menu(
    label=_('连接'),
    icon_class='mdi mdi-connection',
    groups=(
        MenuGroup(
            label=_('Connections'),
            items=(
                get_model_item('dcim', 'cable', _('线缆'), actions=['import']),
                get_model_item('wireless', 'wirelesslink', _('无线连接')),
                MenuItem(
                    link='dcim:interface_connections_list',
                    link_text=_('接口连接'),
                    permissions=['dcim.view_interface']
                ),
                MenuItem(
                    link='dcim:console_connections_list',
                    link_text=_('Console 连接'),
                    permissions=['dcim.view_consoleport']
                ),
                MenuItem(
                    link='dcim:power_connections_list',
                    link_text=_('电源连接'),
                    permissions=['dcim.view_powerport']
                ),
            ),
        ),
    ),
)

WIRELESS_MENU = Menu(
    label=_('无线'),
    icon_class='mdi mdi-wifi',
    groups=(
        MenuGroup(
            label=_('Wireless'),
            items=(
                get_model_item('wireless', 'wirelesslan', _('无线局域网')),
                get_model_item('wireless', 'wirelesslangroup', _('无线局域网组')),
            ),
        ),
    ),
)

IPAM_MENU = Menu(
    label=_('IP地址管理'),
    icon_class='mdi mdi-counter',
    groups=(
        MenuGroup(
            label=_('IP Addresses'),
            items=(
                get_model_item('ipam', 'ipaddress', _('IP 地址')),
                get_model_item('ipam', 'iprange', _('IP 范围')),
            ),
        ),
        MenuGroup(
            label=_('Prefixes'),
            items=(
                get_model_item('ipam', 'prefix', _('IP网段')),
                get_model_item('ipam', 'role', _('网段和VLAN 角色')),
            ),
        ),
        MenuGroup(
            label=_('ASNs'),
            items=(
                get_model_item('ipam', 'asnrange', _('ASN Ranges')),
                get_model_item('ipam', 'asn', _('ASNs')),
            ),
        ),
        MenuGroup(
            label=_('Aggregates'),
            items=(
                get_model_item('ipam', 'aggregate', _('Aggregates')),
                get_model_item('ipam', 'rir', _('RIRs')),
            ),
        ),
        MenuGroup(
            label=_('VRFs'),
            items=(
                get_model_item('ipam', 'vrf', _('VRFs')),
                get_model_item('ipam', 'routetarget', _('Route Targets')),
            ),
        ),
        MenuGroup(
            label=_('VLANs'),
            items=(
                get_model_item('ipam', 'vlan', _('VLANs')),
                get_model_item('ipam', 'vlangroup', _('VLAN Groups')),
            ),
        ),
        MenuGroup(
            label=_('Other'),
            items=(
                get_model_item('ipam', 'fhrpgroup', _('FHRP Groups')),
                get_model_item('ipam', 'servicetemplate', _('Service Templates')),
                get_model_item('ipam', 'service', _('Services')),
            ),
        ),
    ),
)

OVERLAY_MENU = Menu(
    label=_('网络虚拟化Overlay'),
    icon_class='mdi mdi-graph-outline',
    groups=(
        MenuGroup(
            label='L2VPNs',
            items=(
                get_model_item('ipam', 'l2vpn', _('L2VPNs')),
                get_model_item('ipam', 'l2vpntermination', _('Terminations')),
            ),
        ),
    ),
)

VIRTUALIZATION_MENU = Menu(
    label=_('裸金属虚拟化'),
    icon_class='mdi mdi-monitor',
    groups=(
        MenuGroup(
            label=_('Virtual Machines'),
            items=(
                get_model_item('virtualization', 'virtualmachine', _('虚拟机')),
                get_model_item('virtualization', 'vminterface', _('虚拟机接口')),
            ),
        ),
        MenuGroup(
            label=_('Clusters'),
            items=(
                get_model_item('virtualization', 'cluster', _('虚拟化集群')),
                get_model_item('virtualization', 'clustertype', _('虚拟化集群类型')),
                get_model_item('virtualization', 'clustergroup', _('集群组')),
            ),
        ),
    ),
)

CIRCUITS_MENU = Menu(
    label=_('线路'),
    icon_class='mdi mdi-transit-connection-variant',
    groups=(
        MenuGroup(
            label=_('Circuits'),
            items=(
                get_model_item('circuits', 'circuit', _('线路')),
                get_model_item('circuits', 'circuittype', _('线路类型')),
            ),
        ),
        MenuGroup(
            label=_('Providers'),
            items=(
                get_model_item('circuits', 'provider', _('供应商')),
                get_model_item('circuits', 'provideraccount', _('供应商账号')),
                get_model_item('circuits', 'providernetwork', _('供应商网络')),
            ),
        ),
    ),
)

POWER_MENU = Menu(
    label=_('电力'),
    icon_class='mdi mdi-flash',
    groups=(
        MenuGroup(
            label=_('Power'),
            items=(
                get_model_item('dcim', 'powerfeed', _('电源线')),
                get_model_item('dcim', 'powerpanel', _('电源插座')),
            ),
        ),
    ),
)

PROVISIONING_MENU = Menu(
    label=_('设备配置'),
    icon_class='mdi mdi-file-document-multiple-outline',
    groups=(
        MenuGroup(
            label=_('Configurations'),
            items=(
                get_model_item('extras', 'configcontext', _('Config Contexts'), actions=['add']),
                get_model_item('extras', 'configtemplate', _('Config Templates'), actions=['add']),
            ),
        ),
    ),
)

CUSTOMIZATION_MENU = Menu(
    label=_('自定义'),
    icon_class='mdi mdi-toolbox-outline',
    groups=(
        MenuGroup(
            label=_('Customization'),
            items=(
                get_model_item('extras', 'customfield', _('自定义字段')),
                get_model_item('extras', 'customlink', _('自定义链接')),
                get_model_item('extras', 'exporttemplate', _('自定义验证')),
                get_model_item('extras', 'savedfilter', _('已保存的筛选条件')),
                get_model_item('extras', 'tag', 'Tags'),
                get_model_item('extras', 'imageattachment', _('图片附件'), actions=()),
            ),
        ),
        MenuGroup(
            label=_('Reports & Scripts'),
            items=(
                MenuItem(
                    link='extras:report_list',
                    link_text=_('报告'),
                    permissions=['extras.view_report'],
                    buttons=get_model_buttons('extras', "reportmodule", actions=['add'])
                ),
                MenuItem(
                    link='extras:script_list',
                    link_text=_('脚本'),
                    permissions=['extras.view_script'],
                    buttons=get_model_buttons('extras', "scriptmodule", actions=['add'])
                ),
            ),
        ),
    ),
)

OPERATIONS_MENU = Menu(
    label=_('运营'),
    icon_class='mdi mdi-cogs',
    groups=(
        MenuGroup(
            label=_('Integrations'),
            items=(
                get_model_item('core', 'datasource', _('Data Sources')),
                get_model_item('extras', 'webhook', _('Webhooks')),
            ),
        ),
        MenuGroup(
            label=_('Jobs'),
            items=(
                MenuItem(
                    link='core:job_list',
                    link_text=_('Jobs'),
                    permissions=['core.view_job'],
                ),
            ),
        ),
        MenuGroup(
            label=_('Logging'),
            items=(
                get_model_item('extras', 'journalentry', _('日记列表'), actions=['import']),
                get_model_item('extras', 'objectchange', _('操作日志'), actions=[]),
            ),
        ),
    ),
)


MENUS = [
    ORGANIZATION_MENU,
    DEVICES_MENU,
    CONNECTIONS_MENU,
    WIRELESS_MENU,
    IPAM_MENU,
    OVERLAY_MENU,
    VIRTUALIZATION_MENU,
    CIRCUITS_MENU,
    POWER_MENU,
    PROVISIONING_MENU,
    CUSTOMIZATION_MENU,
    OPERATIONS_MENU,
]

#
# Add plugin menus
#

for menu in registry['plugins']['menus']:
    MENUS.append(menu)

if registry['plugins']['menu_items']:

    # Build the default plugins menu
    groups = [
        MenuGroup(label=label, items=items)
        for label, items in registry['plugins']['menu_items'].items()
    ]
    plugins_menu = Menu(
        label=_("Plugins"),
        icon_class="mdi mdi-puzzle",
        groups=groups
    )
    MENUS.append(plugins_menu) 

NetBox CSV导出中文乱码问题

NetBox 在导出CSV的时候,会是使用UTF-8编码,而不是UTF-8-SIG编码。

这样会导致导出的文件,在微软的Excel打开中会乱码。(使用Notepad ++不会)

思路

直接修改Netbox 虚拟环境的 django_tables2 库的默认编码,这样只要不升级或重装此库就不会失效。

修改

vim /opt/netbox/venv/lib/python3.9/site-packages/django_tables2/export/export.py

# 修改库文件,路径看自己的实际情况。


    FORMATS = {
        CSV: "text/csv; charset=utf-8-sig",
        JSON: "application/json",
        LATEX: "text/plain",
        ODS: "application/vnd.oasis.opendocument.spreadsheet",
        TSV: "text/tsv; charset=utf-8",
        XLS: "application/vnd.ms-excel",
        XLSX: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
        YAML: "text/yaml; charset=utf-8",
    }
    
在第37行,直接修改为utf-8-sig,然后重启NetBox即可。

systemctl restart netbox netbox-rq

参考

  • 无标签
写评论...