瑞克
Published on 2026-07-16 / 0 Visits
0
0

存储与自动化运维

存储与自动化运维

让数据有处可去,让操作一键完成


一、存储基础概念

1.1 问题:数据放在哪里?怎么放?放多快?

想象你经营一家快递公司,每天要处理上万件包裹。你需要考虑:仓库在哪(DAS/NAS/SAN)、用什么运输方式、每秒钟能处理多少件(IOPS)、每天能处理多少吨(吞吐量)、每件包裹从入库到出库要多久(延迟)。

1.2 DAS vs NAS vs SAN

DAS(直连存储)               NAS(网络附加存储)             SAN(存储区域网络)
┌──────────┐                 ┌──────────┐                  ┌──────────┐
│ 服务器    │                 │ 服务器A  │                  │ 服务器A  │
│ ┌──────┐ │                 │ 服务器B  │                  │ 服务器B  │
│ │ 硬盘 │ │  ←直连           │ 服务器C  │                  │ 服务器C  │
│ └──────┘ │                 └────┬─────┘                  └────┬─────┘
└──────────┘                      │                              │
                              ┌───┴────┐                    ┌────┴─────┐
                              │ NAS设备│                    │ SAN交换机│
                              │(文件级) │                    │ (块级)   │
                              └────────┘                    └────┬─────┘
                                                                 │
                                                            ┌────┴─────┐
                                                            │ 存储阵列 │
                                                            └──────────┘
对比项DASNASSAN
类比家里的移动硬盘百度网盘(共享文件)银行金库(高性能专用通道)
连接方式直连服务器(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兼容的分布式文件系统
RGWS3兼容的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
DisperseRAID5式的纠删码省空间+有冗余

部署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),这是运维工程师最重要的进阶方向。


Comment