存储与自动化运维
让数据有处可去,让操作一键完成
一、存储基础概念
1.1 问题:数据放在哪里?怎么放?放多快?
想象你经营一家快递公司,每天要处理上万件包裹。你需要考虑:仓库在哪(DAS/NAS/SAN)、用什么运输方式、每秒钟能处理多少件(IOPS)、每天能处理多少吨(吞吐量)、每件包裹从入库到出库要多久(延迟)。
1.2 DAS vs NAS vs SAN
DAS(直连存储) NAS(网络附加存储) SAN(存储区域网络)
┌──────────┐ ┌──────────┐ ┌──────────┐
│ 服务器 │ │ 服务器A │ │ 服务器A │
│ ┌──────┐ │ │ 服务器B │ │ 服务器B │
│ │ 硬盘 │ │ ←直连 │ 服务器C │ │ 服务器C │
│ └──────┘ │ └────┬─────┘ └────┬─────┘
└──────────┘ │ │
┌───┴────┐ ┌────┴─────┐
│ NAS设备│ │ SAN交换机│
│(文件级) │ │ (块级) │
└────────┘ └────┬─────┘
│
┌────┴─────┐
│ 存储阵列 │
└──────────┘
| 对比项 | DAS | NAS | SAN |
|---|---|---|---|
| 类比 | 家里的移动硬盘 | 百度网盘(共享文件) | 银行金库(高性能专用通道) |
| 连接方式 | 直连服务器(SATA/SAS) | 以太网(NFS/SMB) | 光纤通道/iSCSI |
| 数据级别 | 块级 | 文件级 | 块级 |
| 性能 | 中等 | 较低(受网络限制) | 极高 |
| 共享性 | 差(只能一台用) | 好(多客户端共享) | 好(多服务器共享) |
| 成本 | 低 | 中 | 高 |
| 适用场景 | 单机数据库 | 文件共享/办公 | 大型企业/虚拟化 |
1.3 存储性能三要素
IOPS(每秒I/O操作数)
→ 类比:快递站每秒能处理多少个包裹
→ SSD: 10,000-500,000 IOPS
→ HDD: 100-200 IOPS
→ 关注场景:数据库随机读写
吞吐量(Throughput)
→ 类比:传送带每秒能运多少吨货物
→ 单位:MB/s 或 GB/s
→ 关注场景:视频流、大文件传输
延迟(Latency)
→ 类比:一个包裹从下单到送达的时间
→ SSD: 0.1ms
→ HDD: 5-10ms
→ 网络: 加上传输延迟
→ 关注场景:实时交易系统
互动提问: 你在网上下单买东西,最关心的是"每天能送多少单"(IOPS)、"每单多重"(吞吐量)还是"多久能收到"(延迟)?不同场景关注的指标不一样!
二、iSCSI存储配置
2.1 问题:如何用普通网线实现SAN存储?
传统SAN需要昂贵的光纤通道(FC)交换机。iSCSI让你用普通以太网就能实现块级存储共享——就像用普通电话线也能上网一样。
iSCSI 架构:
┌──────────────┐ ┌──────────────┐
│ Initiator │ iSCSI │ Target │
│ (客户端) │ ───────→ │ (存储端) │
│ │ TCP/IP │ │
│ 使用这块 │ 以太网 │ 提供这块 │
│ "远程硬盘" │ │ "远程硬盘" │
└──────────────┘ └──────────────┘
Target端配置(存储提供方)
# 安装targetcli(iSCSI Target管理工具)
# CentOS:
dnf install targetcli
# Ubuntu:
apt install targetcli-fb
# 启动服务
systemctl enable --now target
# 进入交互式配置(像一个"存储管理Shell")
targetcli
# === targetcli 交互式操作 ===
# 第1步:创建后端存储(backstore)
# 方式一:使用文件
/backstores/fileio create name=store1 file_or_dev=/opt/iscsi_disk.img size=50G
# 方式二:使用块设备
/backstores/block create name=store2 dev=/dev/sdb
# 第2步:创建iSCSI Target
/iscsi create iqn.2024-01.com.example:storage
# 第3步:创建LUN(逻辑单元号)——把后端存储映射给Target
/iscsi/iqn.2024-01.com.example:storage/tpg1/luns create /backstores/fileio/store1
# 第4步:创建ACL(访问控制)
/iscsi/iqn.2024-01.com.example:storage/tpg1/acls create iqn.2024-01.com.example:client1
# 第5步:(可选)配置CHAP认证(用户名密码保护)
/iscsi/iqn.2024-01.com.example:storage/tpg1/acls/iqn.2024-01.com.example:client1 \
set auth userid=admin password=secret123
# 第6步:保存配置并退出
/saveconfig
/exit
# 开放防火墙端口
# CentOS:
firewall-cmd --permanent --add-port=3260/tcp && firewall-cmd --reload
# Ubuntu:
ufw allow 3260/tcp
Initiator端配置(存储使用方)
# 安装iSCSI Initiator
# CentOS:
dnf install iscsi-initiator-utils
# Ubuntu:
apt install open-iscsi
# 第1步:修改Initiator名称
echo "InitiatorName=iqn.2024-01.com.example:client1" > /etc/iscsi/initiatorname.iscsi
# 第2步:发现Target("搜索附近有哪些存储可以连")
iscsiadm -m discovery -t sendtargets -p 10.0.0.200:3260
# 输出:10.0.0.200:3260,1 iqn.2024-01.com.example:storage
# 第3步:登录Target("挂载远程硬盘")
iscsiadm -m node -T iqn.2024-01.com.example:storage -p 10.0.0.200 -l
# 登录成功后,本地会多出一块"硬盘"(如/dev/sdb)
# 第4步:像本地硬盘一样使用
fdisk -l # 可以看到新磁盘
mkfs.xfs /dev/sdb # 格式化
mount /dev/sdb /mnt/iscsi_storage # 挂载
# 第5步:配置开机自动登录
# 编辑 /etc/iscsi/iscsid.conf
# node.startup = automatic
# 常用管理命令
iscsiadm -m session # 查看当前会话
iscsiadm -m node # 查看已发现的节点
iscsiadm -m node -u # 注销所有连接
# 配置CHAP认证(如果Target开启了认证)
# 编辑 /etc/iscsi/iscsid.conf
# node.session.auth.authmethod = CHAP
# node.session.auth.username = admin
# node.session.auth.password = secret123
小贴士: iSCSI挂载的磁盘可以像本地磁盘一样分区、格式化、挂载。对于操作系统来说,它根本分不清这是"远程的"还是"本地的"——这就是块级存储的魅力。
三、多路径(Multipath)
3.1 问题:存储只有一条路径,网线断了数据就丢了?
多路径就像给快递公司修多条公路——一条路堵了自动走另一条。
没有多路径: 有多路径:
服务器 服务器
│ ↗ 路径A ↗
↓ ↘ ↘
单条链路 交换机A 交换机B
│ ↗ ↗
↓ ↘ 路径B ↘
存储阵列 存储阵列
线断了 = 断网 一条断了还有另一条!
# 安装
# CentOS:
dnf install device-mapper-multipath
# Ubuntu:
apt install multipath-tools
# 生成默认配置
mpathconf --enable --with_multipathd y # CentOS
# 或手动创建配置
# 核心配置文件
cat > /etc/multipath.conf << 'EOF'
defaults {
polling_interval 10 # 每10秒检查路径状态
path_selector "round-robin 0" # 路径选择策略
path_grouping_policy multibus # 路径分组策略
failback immediate # 路径恢复后立即切回
no_path_retry fail # 无路径时行为
}
# 针对特定存储设备的配置
devices {
device {
vendor "NETAPP"
product "LUN"
path_grouping_policy group_by_prio
path_selector "round-robin 0"
}
}
EOF
# 启动服务
systemctl enable --now multipathd # CentOS
systemctl enable --now multipathd # Ubuntu
# 管理命令
multipath -ll # 查看多路径设备状态
multipath -F # 清空多路径映射
multipath -v2 # 重新加载配置
dmsetup ls # 查看device-mapper设备
路径选择策略:
| 策略 | 说明 | 适用场景 |
|---|---|---|
| round-robin | 轮询使用所有路径 | 均衡负载 |
| queue-length | 发往队列最短的路径 | 智能均衡 |
| service-time | 发往最快完成的路径 | 性能优先 |
四、Ceph分布式存储
4.1 问题:数据量达到PB级,传统存储阵列扛不住了
Ceph是开源分布式存储的"瑞士军刀"——一套系统同时提供块存储、文件存储和对象存储。
Ceph架构
┌────────────────────────────────────────────────────┐
│ Ceph 架构 │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ RBD │ │ CephFS │ │ RGW │ │
│ │ (块存储) │ │(文件存储) │ │(对象存储) │ ← 接口层│
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
│ └──────────────┼────────────┘ │
│ ↓ │
│ ┌───────────────────────────────────┐ │
│ │ RADOS(核心引擎) │ │
│ │ ┌─────────┐ ┌─────────┐ │ │
│ │ │ CRUSH │ │ OSD │ │ │
│ │ │(数据分布)│ │(数据存储)│ │ │
│ │ │ 算法 │ │ 节点 │ │ │
│ │ └─────────┘ └─────────┘ │ │
│ └───────────────────────────────────┘ │
│ │
│ ┌─────────┐ ← MON(监控节点,维护集群状态) │
│ │ MON-1 │ │
│ │ MON-2 │ ← 至少3个MON(奇数,Paxos共识) │
│ │ MON-3 │ │
│ └─────────┘ │
└────────────────────────────────────────────────────┘
| 组件 | 类比 | 职责 |
|---|---|---|
| MON | 大楼的安保中心 | 维护集群地图(Cluster Map),至少3个 |
| OSD | 每个储物柜 | 实际存储数据的节点,每块盘一个OSD |
| MDS | 图书馆索引管理员 | 管理CephFS的文件元数据 |
| CRUSH | 智能分拣系统 | 算法决定数据放在哪个OSD(无需中心调度!) |
| RBD | 虚拟硬盘 | 块存储接口(给KVM虚拟机用) |
| CephFS | 网络文件夹 | POSIX兼容的分布式文件系统 |
| RGW | S3兼容的API | 对象存储接口(类似AWS S3) |
CRUSH算法的精妙之处: 传统分布式存储需要问"中心节点"数据放在哪里,Ceph通过CRUSH算法让客户端自己算出数据位置——就像每个快递员都自带GPS导航,不需要回总部问路。
4.2 Ceph集群部署(使用ceph-deploy)
# === 准备工作(所有节点) ===
# 配置主机名解析
cat >> /etc/hosts << 'EOF'
10.0.0.11 mon1 ceph-node1
10.0.0.12 mon2 ceph-node2
10.0.0.13 mon3 ceph-node3
EOF
# 关闭防火墙和SELinux(测试环境)
# CentOS:
systemctl stop firewalld && systemctl disable firewalld
setenforce 0
# 安装Ceph
# CentOS:
dnf install -y centos-release-ceph-quincy
dnf install -y ceph ceph-deploy
# Ubuntu:
wget -q -O- 'https://download.ceph.com/keys/release.asc' | apt-key add -
apt install -y ceph-deploy
# 配置SSH免密(部署节点到所有节点)
ssh-keygen -t rsa -N '' -f ~/.ssh/id_rsa
ssh-copy-id ceph-node1
ssh-copy-id ceph-node2
ssh-copy-id ceph-node3
# === 创建集群(在部署节点执行) ===
# 创建工作目录
mkdir ~/ceph-cluster && cd ~/ceph-cluster
# 创建集群(指定MON节点)
ceph-deploy new mon1 mon2 mon3
# 修改ceph.conf添加公共网络
echo "public_network = 10.0.0.0/24" >> ceph.conf
echo "cluster_network = 10.0.1.0/24" >> ceph.conf # 数据复制专用网络
# 安装Ceph到所有节点
ceph-deploy install ceph-node1 ceph-node2 ceph-node3
# 初始化MON节点
ceph-deploy mon create-initial
# 分发admin密钥
ceph-deploy admin ceph-node1 ceph-node2 ceph-node3
# 创建OSD(每个节点添加磁盘)
ceph-deploy osd create --data /dev/sdb ceph-node1
ceph-deploy osd create --data /dev/sdb ceph-node2
ceph-deploy osd create --data /dev/sdb ceph-node3
# 创建MDS(如果需要CephFS)
ceph-deploy mds create ceph-node1
# 检查集群状态
ceph -s # 集群状态
ceph osd tree # OSD拓扑
ceph health # 健康状态
4.3 RBD块存储(给虚拟机用)
# 创建存储池
ceph osd pool create rbd_pool 128
# 创建RBD镜像(100G虚拟磁盘)
rbd create vm_disk --size 102400 --pool rbd_pool
# 查看RBD信息
rbd info rbd_pool/vm_disk
# 映射到本地设备
rbd map rbd_pool/vm_disk
# 现在 /dev/rbd0 就是一块"远程硬盘"
# 格式化并挂载
mkfs.xfs /dev/rbd0
mount /dev/rbd0 /mnt/ceph_rbd
# KVM虚拟机使用RBD(在虚拟机XML中配置)
# <disk type='network' device='disk'>
# <driver name='qemu' type='raw'/>
# <source protocol='rbd' name='rbd_pool/vm_disk'>
# <host name='mon1' port='6789'/>
# </source>
# <target dev='vda' bus='virtio'/>
# </disk>
4.4 CephFS文件系统
# 创建CephFS需要的两个存储池(数据池+元数据池)
ceph osd pool create cephfs_data 64
ceph osd pool create cephfs_metadata 32
# 创建文件系统
ceph fs new cephfs cephfs_metadata cephfs_data
# 创建访问用户
ceph auth get-or-create client.cephfs mon 'allow r' \
osd 'allow rw pool=cephfs_data, allow rw pool=cephfs_metadata'
# 客户端挂载(内核方式,性能好)
mount -t ceph mon1:6789:/ /mnt/cephfs -o name=cephfs,secret=YOUR_KEY
# 客户端挂载(FUSE方式,兼容性好)
ceph-fuse -n client.cephfs /mnt/cephfs
五、GlusterFS分布式文件系统
5.1 问题:需要一个简单的分布式文件共享方案
GlusterFS比Ceph简单得多——没有元数据服务器,数据分布靠哈希算法计算。就像图书馆不用索引管理员,每本书的位置通过书名直接算出来。
GlusterFS 架构:
┌─────────┐ ┌─────────┐ ┌─────────┐
│ Server1 │ │ Server2 │ │ Server3 │
│ ┌─────┐ │ │ ┌─────┐ │ │ ┌─────┐ │
│ │Brick│ │ │ │Brick│ │ │ │Brick│ │ ← 每块磁盘叫Brick(砖块)
│ │ /data│ │ │ │ /data│ │ │ │ /data│ │
│ └─────┘ │ │ └─────┘ │ │ └─────┘ │
└─────────┘ └─────────┘ └─────────┘
└────────────┼────────────┘
↓
┌──────────┐
│ Volume │ ← 多个Brick组成一个Volume(卷)
└──────────┘
↓
┌──────────┐
│ Client │ ← 客户端挂载Volume
└──────────┘
Volume类型
| 类型 | 类比 | 说明 |
|---|---|---|
| Distribute | 把书分散放在多个书架 | 文件按哈希分布,无冗余 |
| Replicate | 同一本书放多个书架 | 每个文件有副本,有冗余 |
| Stripe | 一本书拆成几段放不同书架 | 文件分片存储,提高大文件IO |
| Disperse | RAID5式的纠删码 | 省空间+有冗余 |
部署GlusterFS
# 安装(所有节点)
# CentOS:
dnf install -y centos-release-gluster
dnf install -y glusterfs-server
# Ubuntu:
apt install -y glusterfs-server
# 启动服务(所有节点)
systemctl enable --now glusterd
# 配置主机名解析
cat >> /etc/hosts << 'EOF'
10.0.0.11 gfs1
10.0.0.12 gfs2
10.0.0.13 gfs3
EOF
# === 在任一节点操作 ===
# 添加信任存储池(节点间互相信任)
gluster peer probe gfs2
gluster peer probe gfs3
gluster peer status # 查看信任池状态
# 准备Brick(每个节点)
mkdir -p /data/brick1
# 创建Replicate卷(3副本,数据安全)
gluster volume create data_vol replica 3 \
gfs1:/data/brick1 \
gfs2:/data/brick1 \
gfs3:/data/brick1 \
force
# 启动卷
gluster volume start data_vol
# 查看卷信息
gluster volume info
gluster volume status
# 客户端挂载
# CentOS:
dnf install glusterfs-fuse
# Ubuntu:
apt install glusterfs-client
mount -t glusterfs gfs1:/data_vol /mnt/glusterfs
# 写入测试
echo "Hello GlusterFS" > /mnt/glusterfs/test.txt
# 到每个节点的 /data/brick1 都能看到!
# 设置开机自动挂载
echo "gfs1:/data_vol /mnt/glusterfs glusterfs defaults,_netdev 0 0" >> /etc/fstab
Ceph vs GlusterFS 怎么选?
- 需要块存储(给虚拟机用)→ Ceph
- 需要S3兼容对象存储 → Ceph (RGW)
- 只需要简单的文件共享 → GlusterFS
- 追求简单好维护 → GlusterFS
- 追求功能全面高性能 → Ceph
六、Ansible自动化运维
6.1 问题:100台服务器要执行同一条命令,难道要一个个SSH?
Ansible就像远程遥控器——在控制端写好剧本,所有服务器按剧本自动执行。
Ansible的核心优势:
- 无Agent:不需要在目标机器上装任何软件(靠SSH就够了)
- 幂等性:执行100次和执行1次的结果一样(不会重复操作)
- YAML编写:Playbook用YAML编写,像写说明书一样简单
- 模块丰富:内置几百个模块,几乎什么都能自动化
Ansible 工作原理:
┌──────────────┐ SSH ┌──────────────┐
│ Control │ ──────────────→ │ Server-1 │
│ Node │ ──────────────→ │ Server-2 │
│ (控制端) │ ──────────────→ │ Server-3 │
│ │ SSH │ Server-N │
│ inventory │ └──────────────┘
│ playbook │
│ modules │
└──────────────┘
无需Agent!只需SSH免密登录 + Python(几乎所有Linux自带)
6.2 安装与配置
# 安装Ansible(只在控制端安装!)
# CentOS:
dnf install epel-release -y
dnf install ansible -y
# Ubuntu:
apt install software-properties-common
apt-add-repository ppa:ansible/ansible
apt install ansible -y
# 验证
ansible --version
# 配置SSH免密登录(控制端到所有被控端)
ssh-keygen -t rsa -b 4096 -N '' -f ~/.ssh/id_rsa
ssh-copy-id root@10.0.0.11
ssh-copy-id root@10.0.0.12
ssh-copy-id root@10.0.0.13
6.3 Inventory主机清单
# /etc/ansible/hosts(Ansible的"通讯录")
# 简单写法
[webservers]
10.0.0.11
10.0.0.12
web3.example.com
[dbservers]
db1.example.com ansible_port=2222 ansible_user=deploy
db2.example.com
[all:vars]
ansible_ssh_private_key_file=/root/.ssh/id_rsa
# 高级写法(带变量)
[webservers]
web[01:20].example.com ansible_user=www # 展开为web01到web20
[loadbalancers]
lb1.example.com priority=100
lb2.example.com priority=90
# 组的父子关系
[production:children]
webservers
dbservers
loadbalancers
[production:vars]
env=production
ntp_server=ntp.example.com
6.4 Ad-hoc命令(临时操作)
# 测试连通性(ping所有主机)
ansible all -m ping
# 在webservers组上执行命令
ansible webservers -a "uptime"
ansible webservers -a "free -h"
ansible webservers -a "df -h"
# 并行执行(-f指定并发数)
ansible all -a "yum update -y" -f 10
# 用sudo执行
ansible webservers -a "systemctl restart nginx" -b
# -b = become(提权执行)
# 文件传输
ansible webservers -m copy -a "src=/local/file.txt dest=/tmp/file.txt"
# 安装软件
ansible webservers -m yum -a "name=nginx state=present" # CentOS
ansible webservers -m apt -a "name=nginx state=present" # Ubuntu
6.5 常用模块
# === yum / apt 模块(软件包管理) ===
ansible web -m yum -a "name=httpd state=latest" # CentOS
ansible web -m apt -a "name=nginx state=present update_cache=yes" # Ubuntu
# === service 模块(服务管理) ===
ansible web -m service -a "name=nginx state=started enabled=yes"
# === copy 模块(文件复制) ===
ansible web -m copy -a "src=/etc/nginx/nginx.conf dest=/etc/nginx/nginx.conf \
owner=root group=root mode=0644 backup=yes"
# === template 模块(模板渲染,支持变量替换!) ===
# 模板文件 /templates/motd.j2:
# Welcome to {{ ansible_hostname }}!
# OS: {{ ansible_distribution }} {{ ansible_distribution_version }}
# Memory: {{ ansible_memtotal_mb }}MB
ansible web -m template -a "src=/templates/motd.j2 dest=/etc/motd"
# === file 模块(文件/目录操作) ===
ansible web -m file -a "path=/data/www state=directory owner=www group=www mode=0755"
ansible web -m file -a "path=/tmp/test.txt state=touch"
ansible web -m file -a "path=/tmp/old state=absent" # 删除
# === user 模块(用户管理) ===
ansible web -m user -a "name=deploy state=present \
password={{ 'mypassword' | password_hash('sha512') }} \
groups=wheel shell=/bin/bash"
# === cron 模块(定时任务) ===
ansible web -m cron -a "name='backup db' minute=0 hour=2 \
job='/opt/scripts/backup.sh >> /var/log/backup.log 2>&1'"
6.6 Playbook编写
# deploy_nginx.yml —— Ansible Playbook 就像一份"施工蓝图"
---
- name: 部署Nginx Web服务器
hosts: webservers
become: yes
vars:
nginx_port: 80
server_name: www.example.com
max_connections: 1024
# 任务列表(按顺序执行)
tasks:
- name: 安装Nginx
# CentOS和Ubuntu的包名不同,这里用条件判断
yum:
name: nginx
state: latest
when: ansible_os_family == "RedHat"
- name: 安装Nginx (Debian)
apt:
name: nginx
state: latest
update_cache: yes
when: ansible_os_family == "Debian"
- name: 复制Nginx配置文件(模板渲染)
template:
src: templates/nginx.conf.j2
dest: /etc/nginx/nginx.conf
validate: 'nginx -t -c %s'
notify: 重启Nginx # 配置变更时触发handler
- name: 创建网站目录
file:
path: /var/www/{{ server_name }}
state: directory
owner: nginx
group: nginx
- name: 部署首页
copy:
content: "<h1>Welcome to {{ server_name }}</h1>"
dest: /var/www/{{ server_name }}/index.html
- name: 启动Nginx并设置开机自启
service:
name: nginx
state: started
enabled: yes
- name: 开放防火墙端口 (CentOS)
firewalld:
port: "{{ nginx_port }}/tcp"
permanent: yes
state: enabled
when: ansible_os_family == "RedHat"
- name: 开放防火墙端口 (Ubuntu)
ufw:
rule: allow
port: "{{ nginx_port }}"
proto: tcp
when: ansible_os_family == "Debian"
# Handler:只在被notify触发时执行(避免不必要的重启)
handlers:
- name: 重启Nginx
service:
name: nginx
state: restarted
# 执行Playbook
ansible-playbook deploy_nginx.yml
# 常用参数
ansible-playbook deploy_nginx.yml --check # 模拟运行(不实际执行)
ansible-playbook deploy_nginx.yml --diff # 显示文件差异
ansible-playbook deploy_nginx.yml -l web1 # 只在一台机器上执行
ansible-playbook deploy_nginx.yml -v # 详细输出
ansible-playbook deploy_nginx.yml --step # 逐步确认
6.7 变量、条件与循环
# === 变量(灵活配置) ===
---
- hosts: webservers
vars:
http_port: 80
packages:
- nginx
- openssl
- curl
# 从外部文件加载变量
vars_files:
- vars/common.yml
- vars/{{ ansible_os_family }}.yml
tasks:
# === 条件判断 ===
- name: 安装Apache (仅RedHat)
yum:
name: httpd
state: present
when: ansible_os_family == "RedHat"
- name: 安装Apache (仅Debian)
apt:
name: apache2
state: present
when: ansible_os_family == "Debian"
# 多条件
- name: 特殊配置(生产环境的CentOS 8)
debug:
msg: "这是生产环境的CentOS 8"
when:
- env == "production"
- ansible_distribution == "CentOS"
- ansible_distribution_major_version == "8"
# === 循环 ===
# 循环安装包
- name: 安装多个软件包
yum:
name: "{{ item }}"
state: present
loop:
- nginx
- openssl
- curl
- wget
# 循环创建用户
- name: 创建运维用户
user:
name: "{{ item.name }}"
groups: "{{ item.groups }}"
shell: /bin/bash
loop:
- { name: 'zhangsan', groups: 'wheel' }
- { name: 'lisi', groups: 'docker' }
- { name: 'wangwu', groups: 'www' }
# 循环创建目录
- name: 创建应用目录
file:
path: "{{ item }}"
state: directory
owner: www
mode: '0755'
loop:
- /data/logs
- /data/uploads
- /data/cache
- /data/tmp
# 字典循环
- name: 配置sysctl参数
sysctl:
name: "{{ item.key }}"
value: "{{ item.value }}"
state: present
loop: "{{ sysctl_params | dict2items }}"
vars:
sysctl_params:
net.core.somaxconn: 65535
net.ipv4.tcp_max_syn_backlog: 65535
vm.swappiness: 10
6.8 Roles(角色)——组织大型Playbook
# 当Playbook变得复杂时,用Roles来组织代码
# 就像把一个大项目拆分成多个小模块
deploy_web/
├── site.yml # 入口文件
├── inventory # 主机清单
├── roles/
│ ├── common/ # 通用配置角色
│ │ ├── tasks/main.yml
│ │ ├── handlers/main.yml
│ │ ├── templates/
│ │ ├── files/
│ │ ├── vars/main.yml
│ │ └── defaults/main.yml
│ ├── nginx/ # Nginx角色
│ │ ├── tasks/main.yml
│ │ ├── handlers/main.yml
│ │ └── templates/nginx.conf.j2
│ └── mysql/ # MySQL角色
│ ├── tasks/main.yml
│ └── templates/my.cnf.j2
# site.yml
---
- hosts: all
roles:
- common # 所有机器执行通用配置
- hosts: webservers
roles:
- nginx # Web服务器部署Nginx
- hosts: dbservers
roles:
- mysql # 数据库服务器部署MySQL
# roles/nginx/tasks/main.yml
---
- name: 安装Nginx
package:
name: nginx
state: present
- name: 部署配置文件
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify: restart nginx
- name: 启动服务
service:
name: nginx
state: started
enabled: yes
互动提问: 如果你要管理100台服务器,其中50台Web、30台DB、20台缓存,你会怎么组织Roles?(提示:想想哪些配置是通用的,哪些是专有的)
七、PXE + Kickstart批量部署
7.1 问题:50台新服务器,每台都要手动装系统?
PXE(Preboot Execution Environment)+ Kickstart 就像自动化装机流水线——服务器开机自动从网络启动、自动安装系统、自动配置——你只需要按下电源键。
PXE启动流程:
┌──────────┐ ①DHCP请求 ┌──────────┐
│ 新服务器 │ ──────────────→ │ DHCP服务器│
│ (PXE网卡) │ ←────────────── │ │
└──────────┘ ②返回IP+引导文件 └──────────┘
│ │
│ ③下载引导文件 │ 告诉去哪找TFTP
↓ ↓
┌──────────┐ ④下载内核 ┌──────────┐
│ 新服务器 │ ──────────────→ │ TFTP服务器│
│ │ ←────────────── │ (引导文件) │
└──────────┘ └──────────┘
│
│ ⑤启动安装程序
↓
┌──────────┐ ⑥读取kickstart ┌──────────┐
│ 自动安装 │ ──────────────→ │ HTTP/FTP │
│ 操作系统 │ ←────────────── │ (安装源) │
└──────────┘ ⑦获取安装文件 └──────────┘
DHCP服务器配置
# 安装DHCP服务
# CentOS:
dnf install dhcp-server
# Ubuntu:
apt install isc-dhcp-server
# 配置DHCP(/etc/dhcp/dhcpd.conf)
cat > /etc/dhcp/dhcpd.conf << 'EOF'
default-lease-time 600;
max-lease-time 7200;
authoritative;
subnet 10.0.0.0 netmask 255.255.255.0 {
range 10.0.0.100 10.0.0.200;
option routers 10.0.0.1;
option domain-name-servers 8.8.8.8;
# PXE关键配置:告诉客户端去哪找引导文件
next-server 10.0.0.1; # TFTP服务器地址
filename "pxelinux.0"; # 引导文件名
}
EOF
systemctl enable --now dhcpd
TFTP服务器配置
# 安装TFTP
# CentOS:
dnf install tftp-server
# Ubuntu:
apt install tftpd-hpa
# CentOS:配置TFTP(通过xinetd或systemd socket)
systemctl enable --now tftp.socket
# 准备PXE引导文件
dnf install syslinux-tftpboot # CentOS
# 引导文件会自动放到 /var/lib/tftpboot/
# 创建PXE引导菜单
mkdir -p /var/lib/tftpboot/pxelinux.cfg
cat > /var/lib/tftpboot/pxelinux.cfg/default << 'EOF'
DEFAULT menu.c32
PROMPT 0
TIMEOUT 300
MENU TITLE PXE Boot Menu
LABEL centos8
MENU LABEL Install CentOS 8
KERNEL vmlinuz
APPEND initrd=initrd.img inst.repo=http://10.0.0.1/centos8 \
inst.ks=http://10.0.0.1/ks/centos8.ks
LABEL ubuntu2204
MENU LABEL Install Ubuntu 22.04
KERNEL ubuntu/vmlinuz
APPEND initrd=ubuntu/initrd url=http://10.0.0.1/ubuntu2204 \
auto=true priority=critical ks=http://10.0.0.1/ks/ubuntu2204.preseed
EOF
# 复制安装镜像的内核和initrd
# CentOS:
mount -o loop /opt/CentOS-8-x86_64.iso /mnt
cp /mnt/images/pxeboot/vmlinuz /var/lib/tftpboot/
cp /mnt/images/pxeboot/initrd.img /var/lib/tftpboot/
cp /mnt/isolinux/vesamenu.c32 /var/lib/tftpboot/menu.c32
# Ubuntu:
cp /mnt/casper/vmlinuz /var/lib/tftpboot/ubuntu/
cp /mnt/casper/initrd /var/lib/tftpboot/ubuntu/
Kickstart文件
# /var/www/html/ks/centos8.ks(CentOS自动安装应答文件)
# Kickstart就像一个"安装问卷的标准答案"
#platform=x86, AMD64, or Intel EM64T
#version=CentOS-8
# 安装方式
url --url="http://10.0.0.1/centos8"
# 语言与键盘
lang zh_CN.UTF-8
keyboard us
# 网络配置
network --bootproto=dhcp --device=eth0 --onboot=yes
network --hostname=node-$(hostname)
# 认证
rootpw --plaintext P@ssw0rd123 # 生产环境请使用加密密码!
# 时区
timezone Asia/Shanghai --isUtc
# 磁盘分区
clearpart --all --initlabel
part /boot --fstype=xfs --size=1024
part swap --fstype=swap --size=4096
part / --fstype=xfs --size=20480 --grow
# 引导
bootloader --location=mbr
# 最小安装 + 额外包
%packages
@^minimal-environment
openssh-server
vim
wget
net-tools
%end
# 安装后执行的脚本
%post
# 配置SSH
sed -i 's/#PermitRootLogin yes/PermitRootLogin yes/' /etc/ssh/sshd_config
systemctl enable sshd
# 配置Ansible管理(添加公钥)
mkdir -p /root/.ssh
cat > /root/.ssh/authorized_keys << 'KEYEOF'
ssh-rsa AAAAB3NzaC1yc2E... ansible-control-key
KEYEOF
chmod 600 /root/.ssh/authorized_keys
chmod 700 /root/.ssh
# 更新系统
dnf update -y
%end
# 安装完成后重启
reboot
# 准备HTTP安装源
# CentOS:
dnf install httpd
mount -o loop /opt/CentOS-8-x86_64.iso /var/www/html/centos8
mkdir -p /var/www/html/ks
cp /opt/centos8.ks /var/www/html/ks/
systemctl enable --now httpd
# Ubuntu:
apt install apache2
mount -o loop /opt/ubuntu-22.04.iso /var/www/html/ubuntu2204
systemctl enable --now apache2
完整流程: 新服务器开机 → PXE网卡发DHCP请求 → 获取IP和TFTP地址 → 下载引导文件 → 显示安装菜单 → 选择系统 → 自动安装(读取kickstart)→ 自动分区、装包、配置 → 自动重启 → 一台新服务器就绪!
八、OpenStack简介
8.1 问题:如何搭建一个自己的"云"?
OpenStack是开源的云计算管理平台——让你在自己的数据中心里提供像AWS/阿里云一样的服务。
OpenStack 就像一个"自助餐厅管理系统":
┌─────────────────────────────────────────────────────────┐
│ OpenStack 架构 │
│ │
│ ┌──────────┐ "进门先验证身份" │
│ │ Keystone │ → 认证与授权(所有组件的"门卫") │
│ └──────────┘ │
│ │
│ ┌──────────┐ "给我一台虚拟机" │
│ │ Nova │ → 计算服务(管理虚拟机生命周期) │
│ └──────────┘ │
│ │
│ ┌──────────┐ "给我分配IP和网络" │
│ │ Neutron │ → 网络服务(虚拟网络/路由器/防火墙) │
│ └──────────┘ │
│ │
│ ┌──────────┐ "给我一个系统镜像" │
│ │ Glance │ → 镜像服务(存储和管理虚拟机镜像) │
│ └──────────┘ │
│ │
│ ┌──────────┐ "给我一块数据盘" │
│ │ Cinder │ → 块存储服务(为虚拟机提供云硬盘) │
│ └──────────┘ │
│ │
│ ┌──────────┐ "给我对象存储" │
│ │ Swift │ → 对象存储(类似S3) │
│ └──────────┘ │
│ │
│ ┌──────────┐ "我要看仪表盘" │
│ │ Horizon │ → Web控制台(图形化管理界面) │
│ └──────────┘ │
└─────────────────────────────────────────────────────────┘
核心组件对照表
| 组件 | 项目代号 | 类比 | 职责 |
|---|---|---|---|
| Keystone | 身份认证 | 大楼的门禁系统 | 用户认证、服务目录、Token管理 |
| Nova | 计算 | 工厂的生产线 | 创建/管理/迁移虚拟机 |
| Neutron | 网络 | 大楼的管道系统 | 虚拟网络、子网、路由器、安全组 |
| Glance | 镜像 | 模具仓库 | 存储和分发虚拟机镜像 |
| Cinder | 块存储 | 外接硬盘出租 | 为虚拟机提供持久化块存储 |
| Swift | 对象存储 | 云端文件柜 | 分布式对象存储 |
| Horizon | 仪表盘 | 前台接待 | Web图形化管理界面 |
| Heat | 编排 | 施工队 | 模板化自动部署(类似Terraform) |
创建一个虚拟机的流程
用户请求"创建一台虚拟机"
│
├──① Keystone:验证用户身份,发放Token
│
├──② Nova:接收请求,调度到合适的计算节点
│ ├── 从Glance获取镜像
│ ├── 从Neutron获取网络配置
│ └── 从Cinder获取存储卷
│
├──③ Glance:提供系统镜像(如Ubuntu 22.04)
│
├──④ Neutron:分配虚拟网络、IP地址、安全组规则
│
├──⑤ Cinder:创建并挂载数据盘(如果需要)
│
└──⑥ 计算节点:启动KVM虚拟机,完成创建
用户获得一台可以通过SSH访问的虚拟机!
互动提问: OpenStack的Nova创建虚拟机时,底层用的是什么虚拟化技术?(答案:就是本章前面学的KVM!OpenStack是管理层,KVM是执行层。)
其他组件简介
# OpenStack CLI 示例(了解即可)
# 认证
source openrc.sh # 加载环境变量(用户名、密码、项目)
# 计算
openstack server list # 列出所有虚拟机
openstack server create --flavor m1.small --image ubuntu-22.04 \
--network private-net my-vm # 创建虚拟机
openstack server show my-vm # 查看详情
# 网络
openstack network list # 列出网络
openstack subnet list # 列出子网
openstack router list # 列出路由器
# 镜像
openstack image list # 列出镜像
# 存储
openstack volume create --size 100 data-volume # 创建100G云硬盘
openstack server add volume my-vm data-volume # 挂载到虚拟机
部署建议: OpenStack部署复杂,生产环境通常使用 RDO(CentOS版)或 Ubuntu OpenStack Charms 进行部署。初学者可以使用 DevStack(一键部署开发环境)来学习。
运维常用命令精选
# ===== 存储管理 =====
iscsiadm -m discovery -t st -p 10.0.0.200 # iSCSI发现
iscsiadm -m node -l # iSCSI登录
multipath -ll # 查看多路径状态
ceph -s # Ceph集群状态
ceph osd tree # OSD拓扑
gluster volume info # GlusterFS卷信息
# ===== Ansible =====
ansible all -m ping # 测试连通性
ansible web -m service -a "name=nginx state=started" # 管理服务
ansible-playbook deploy.yml --check # 模拟运行Playbook
ansible-doc -l # 查看所有可用模块
ansible-doc yum # 查看模块帮助
# ===== PXE =====
systemctl status dhcpd # DHCP服务状态
systemctl status tftp # TFTP服务状态
tail -f /var/log/httpd/access_log # HTTP安装源访问日志
趣味命令
# 查看磁盘的实时IO情况(像看心电图)
iostat -x 1 5
# 关注 %util(磁盘利用率)、await(IO等待时间)、r/s w/s(读写IOPS)
# 用dd测试磁盘写入速度(简易版)
dd if=/dev/zero of=/tmp/testfile bs=1M count=1024 oflag=direct
# oflag=direct 绕过缓存,测的是真实磁盘速度
# 用fio进行专业磁盘测试
fio --name=randwrite --ioengine=libaio --iodepth=32 \
--rw=randwrite --bs=4k --direct=0 --size=1G \
--numjobs=4 --runtime=60 --group_reporting
# Ansible一行命令收集所有服务器的系统信息
ansible all -m setup -a "filter=ansible_distribution*"
# 用Ansible给所有服务器发一条"消息"
ansible all -m shell -a 'wall "系统将在10分钟后维护,请保存工作!"' -b
# 查看Ceph的实时数据分布情况(像看数据在跳舞)
ceph osd df tree
# 每个OSD的使用率一目了然
# 一行命令查看所有GlusterFS卷的健康状态
gluster volume heal info
# 用Ansible生成服务器资产清单
ansible all -m setup --tree /tmp/inventory/
# 每台服务器的详细信息保存为独立JSON文件
小结: 存储是运维的"地基"——从简单的DAS到分布式Ceph/GlusterFS,理解存储架构决定了系统的性能和可靠性上限。自动化运维是运维的"加速器"——Ansible让重复工作自动化,PXE+Kickstart让装机自动化,OpenStack让整个数据中心变成自助服务的"云"。从"手动操作"到"代码定义基础设施"(Infrastructure as Code),这是运维工程师最重要的进阶方向。