实践操作提纲 — 完整步骤与注解

6个阶段 · 18个实验 · 每条命令都有完整写法、预期输出和原理注解

← 返回 CloudOps Master

🔰 P1 · Linux基础实践(第1-4周)

环境:VirtualBox + CentOS 7 Minimal(2核/2G/20G/NAT网络)

实验1:环境搭建与基础命令

1查看系统信息
Terminal
# 查看系统版本
$ cat /etc/os-release
NAME="CentOS Linux"
VERSION="7 (Core)"

# 查看内核
$ uname -r
3.10.0-1160.el7.x86_64

# 修改主机名(永久)
$ hostnamectl set-hostname cloudlab
$ hostname
cloudlab
注解:uname -r 只显内核版本,-a 显全部。hostnamectl 是CentOS7+命令,同时写入 /etc/hostname
2目录导航
Terminal
$ pwd                     # 显示当前目录
/root

$ cd /                    # 切换到根目录
$ ls
bin boot dev etc home lib media mnt opt proc root run sbin srv sys tmp usr var

$ cd ~                    # 回家目录(等同 cd 或 cd $HOME)
$ cd -                    # 回到上次所在目录
注解:重要目录速记 — /etc 配置 | /var 日志数据 | /home 用户家 | /opt 第三方软件 | /dev 设备 | /proc 内核虚拟文件 | /tmp 临时文件
3文件操作
Terminal
# 创建多级目录(-p 自动创建父级)
$ mkdir -p /opt/project/{src,bin,conf,logs}
$ ls /opt/project/
bin  conf  logs  src

# 创建文件 & 写入内容
$ touch /opt/project/src/app.py
$ echo "hello" > /opt/project/src/readme.txt    # > 覆盖写入
$ echo "world" >> /opt/project/src/readme.txt   # >> 追加写入

# 查看详情
$ ls -la /opt/project/src/
-rw-r--r-- 1 root root 12 ... readme.txt
-rw-r--r-- 1 root root  0 ... app.py

# 复制/移动/重命名
$ cp -r /opt/project/src /opt/project/src_bak    # -r 递归复制目录
$ mv /opt/project/src/readme.txt /opt/project/src/README.md  # 移动=重命名

# 删除(危险操作,先ls确认路径!
$ rm -rf /opt/project/src_bak
警告:rm -rf 没有回收站!删除不可恢复。永远不要 rm -rf /。养成习惯:先 ls 确认再删除。
4查看与搜索文件
Terminal
$ cat /etc/hostname                  # 查看全部内容
$ head -10 /etc/passwd               # 前10行
$ tail -f /var/log/messages          # 实时跟踪日志(Ctrl+C退出)
$ less /etc/services                 # 分页看大文件(空格翻页 q退出)

# 搜索文件
$ find /etc -name "*.conf"           # 按名字找
$ find /var/log -size +10M           # 找大于10M的
$ find /tmp -mtime +30 -delete       # 删30天前的文件

# 在文件内容中搜索
$ grep "root" /etc/passwd
root:x:0:0:root:/root:/bin/bash

$ grep -rn "error" /var/log/         # -r递归 -n行号
注解:find 实时搜目录树(慢但准),locate 查数据库(快但可能不新,需先 updatedb)。grep 搜文件内容。

实验2:文件权限与用户管理

1权限详解
权限解读
$ ls -la app.py
-rw-r--r-- 1 root root 0 ...

# 权限位解读:rw- | r-- | r--
#             属主  属组  其他
#             读写  只读  只读
#
# 数字算法:r=4  w=2  x=1
# rw- = 4+2+0 = 6
# r-- = 4+0+0 = 4
# 所以 rw-r--r-- = 644
#
# 常用权限速记:
# 755 = rwxr-xr-x  可执行文件/目录
# 644 = rw-r--r--  普通文件
# 700 = rwx------  私密目录(如.ssh)
# 600 = rw-------  私密文件(如密钥)
2修改权限与属主
Terminal
$ chmod 755 script.sh                # 数字方式
$ chmod +x script.sh                 # 符号方式(加执行权限)
$ chmod -R 755 /opt/project          # -R 递归整个目录

# 创建组和用户
$ groupadd www
$ useradd -m -s /bin/bash -G www webadmin   # -m创建家目录 -G附加组
$ passwd webadmin                            # 设置密码

# 验证
$ id webadmin
uid=1001(webadmin) gid=1001(webadmin) groups=1001(webadmin),1002(www)

# 改属主
$ chown webadmin:www /opt/project/logs
$ chmod 770 /opt/project/logs        # 属主和组可读写执行,其他无权限
注解:useradd 创建 | usermod -aG group user 加组 | userdel -r 删除含家目录 | 查用户 cat /etc/passwd | 查组 cat /etc/group
3打包压缩
Terminal
# 打包压缩(c创建 z用gzip f文件名)
$ tar czf /tmp/backup.tar.gz /opt/project

# 查看内容(不解压)
$ tar tzf /tmp/backup.tar.gz

# 解压到指定目录
$ tar xzf /tmp/backup.tar.gz -C /tmp/restore
注解:速记 — 压缩 czf (Create Zip File),解压 xzf (eXtract Zip File)。.tar.bz2cjf/xjf

实验3:Vim与软链接

1Vim三种模式
Vim速查
# 打开文件
$ vim /etc/hosts

# 命令模式(默认):
#   i  光标前插入    a 光标后插入    o 下方新行插入
#   dd 删除行    yy 复制行    p 粘贴    u 撤销
#   /word 搜索(n下一个 N上一个)
#   gg 到开头    G 到末尾
# 按 Esc 回到命令模式

# 末行模式(命令模式下按 : 进入):
#   :w        保存
#   :q        退出
#   :wq       保存退出
#   :q!       强制退出不保存
#   :set nu   显示行号
#   :%s/old/new/g   全局替换
实操:打开 /etc/hosts → 按 G 到末尾 → 按 o 新行 → 输入 192.168.1.100 myserver → 按 Esc → 输入 :wq 保存退出 → cat /etc/hosts 验证。
2bash别名与软链接
Terminal
# 编辑 ~/.bashrc 添加别名
$ vim ~/.bashrc
# 末尾加:
alias ll='ls -la'
alias grep='grep --color=auto'

$ source ~/.bashrc        # 立即生效
$ ll                      # 测试

# 创建软链接(快捷方式)
$ ln -s /opt/project/src/app.py /usr/local/bin/myapp
$ ls -la /usr/local/bin/myapp
lrwxrwxrwx ... myapp -> /opt/project/src/app.py

# 创建硬链接(共享inode,删源文件链接仍有效)
$ ln /opt/project/src/README.md /tmp/hard_link
$ ls -li /opt/project/src/README.md /tmp/hard_link
262145 ... README.md
262145 ... hard_link    # inode号相同=同一文件
注解:软链接 vs 硬链接 — 软链接可跨分区、可链目录、删源则失效。硬链接不能跨分区、不能链目录、删源仍有效。工作中软链接用得多。

⚙️ P2 · 系统管理实践(第5-8周)

环境:继续P1虚拟机,建议克隆一台做SSH实验(两台互通)。

实验4:服务与进程管理

1Nginx服务管理
Terminal
$ yum install -y epel-release && yum install -y nginx

# systemctl 全流程
$ systemctl start nginx      # 启动
$ systemctl status nginx     # 查状态 → 看到 active (running)
$ systemctl enable nginx     # 开机自启
$ systemctl stop nginx       # 停止
$ systemctl restart nginx    # 重启
$ systemctl reload nginx     # 热加载配置(不断连接)
$ nginx -t                   # 检查配置语法
nginx: configuration file ... test is successful
注解:reloadrestart 优雅 — 不中断现有连接,只重新加载配置文件。生产环境优先用 reload
2进程管理
Terminal
$ ps aux | grep nginx        # 搜索进程
root  1234 ... nginx: master process
nginx 1235 ... nginx: worker process

$ top                        # 实时监控(q退出 M按内存排 P按CPU排)

# 杀进程
$ kill 1234                  # SIGTERM(优雅终止)
$ kill -9 1234               # SIGKILL(强制,最后手段)
$ killall nginx              # 按名字杀

# 后台运行
$ nohup python3 server.py &  # nohup 防止退终端后进程被杀
注解:kill 默认发SIGTERM(15),程序可捕获优雅退出。kill -9 发SIGKILL(9)不可捕获。生产环境先 kill,无效再 kill -9

实验5:磁盘管理

1分区→格式化→挂载全流程
Terminal
$ lsblk                                  # 查看块设备
sda      20G
├─sda1   20G  /
sdb      10G             ← 新磁盘

$ fdisk /dev/sdb                         # 分区
# 交互:n → p → 1 → 回车 → 回车 → w

$ mkfs.xfs /dev/sdb1                     # 格式化
$ mkdir /mnt/data
$ mount /dev/sdb1 /mnt/data              # 挂载

$ df -h | grep sdb
/dev/sdb1  10G  33M  10G  1% /mnt/data

# 永久挂载(写入fstab)
$ echo '/dev/sdb1  /mnt/data  xfs  defaults  0 0' >> /etc/fstab
$ mount -a                               # 验证fstab配置
注意:/etc/fstab 写错会导致系统无法启动!修改前 cp /etc/fstab /etc/fstab.bak 备份。写入后必须 mount -a 测试。

实验6:SSH免密与文件传输

1SSH密钥免密登录
在机器A操作
[A]$ ssh-keygen -t rsa -b 4096     # 生成密钥对(一路回车)
[A]$ ssh-copy-id root@192.168.1.102 # 把公钥复制到B
[A]$ ssh root@192.168.1.102         # 测试免密登录 → 不用输密码
注解:原理 — ssh-keygen 生成私钥 ~/.ssh/id_rsa(保密)和公钥 ~/.ssh/id_rsa.pub(公开)。ssh-copy-id 把公钥追加到对方 ~/.ssh/authorized_keys。登录时用私钥证明身份。
2文件传输
Terminal
# scp 简单复制
$ scp /tmp/backup.tar.gz root@192.168.1.102:/tmp/     # 上传
$ scp root@192.168.1.102:/var/log/nginx.log /tmp/      # 下载
$ scp -r /opt/project root@192.168.1.102:/opt/         # 复制目录

# rsync 增量同步(只传变化的部分,比scp高效)
$ rsync -avz /opt/project/ root@192.168.1.102:/opt/project/
# -a 归档(保权限/时间)  -v 显示过程  -z 压缩传输
建议:小文件用 scp,大量文件或定期同步用 rsync(增量传输+断点续传)。

实验7:定时任务与日志

1编写备份脚本+cron定时
/opt/backup.sh
#!/bin/bash
BACKUP_DIR="/backup"
DATE=$(date +%Y%m%d_%H%M%S)
mkdir -p $BACKUP_DIR
tar czf ${BACKUP_DIR}/project_${DATE}.tar.gz /opt/project
echo "[$(date)] Backup done" >> /var/log/backup.log
find $BACKUP_DIR -name "*.tar.gz" -mtime +30 -delete
Terminal
$ chmod +x /opt/backup.sh
$ /opt/backup.sh                         # 手动测试

# 设置cron定时任务
$ crontab -e
0 2 * * * /opt/backup.sh               # 每天凌晨2点执行

# cron格式:分 时 日 月 周 命令
# ┌───── 分 (0-59)
# │ ┌─── 时 (0-23)
# │ │ ┌─ 日 (1-31)
# │ │ │ ┌ 月 (1-12)
# │ │ │ │ ┌ 周(0-7)
# 0 2 * * *
#
# 更多示例:
# */5 * * * *     每5分钟
# 0 */2 * * *     每2小时
# 0 9 * * 1-5     工作日9点

$ crontab -l                             # 查看任务列表
注解:cron脚本中用绝对路径(cron环境变量和登录shell不同)。crontab -e 编辑,-l 列出,-r 删除全部。

📜 P3 · Shell自动化实践(第9-12周)

环境:/opt/scripts/ 下集中存放脚本

实验8:Shell脚本实战

1系统信息采集脚本
/opt/scripts/sysinfo.sh
#!/bin/bash
echo "===== 系统信息 ====="
echo "主机名: $(hostname)"
echo "IP:     $(hostname -I | awk '{print $1}')"
echo "内核:   $(uname -r)"
echo "运行:   $(uptime -p)"
echo "CPU:    $(nproc) 核 | 负载: $(uptime | awk -F'load average:' '{print $2}')"
free -h | awk '/Mem/{printf "内存: %s/%s (%.0f%%)\n",$3,$2,$3/$2*100}'
df -h | grep '^/dev/' | awk '{printf "磁盘 %s: %s used (%s)\n",$6,$3,$5}'
注解:$(cmd) 命令替换,把命令输出嵌入字符串。awk 提取字段。nproc 显示CPU核数。free -h 显示内存。
2服务监控脚本
/opt/scripts/check_service.sh
#!/bin/bash
# 用法: ./check_service.sh nginx
SERVICE=${1:-nginx}
LOG="/var/log/service_monitor.log"

if systemctl is-active --quiet $SERVICE; then
    echo "[$(date)] $SERVICE OK" >> $LOG
else
    echo "[$(date)] $SERVICE DOWN! Restarting..." >> $LOG
    systemctl restart $SERVICE
    sleep 2
    if systemctl is-active --quiet $SERVICE; then
        echo "[$(date)] $SERVICE restarted OK" >> $LOG
    else
        echo "[$(date)] CRITICAL: $SERVICE restart FAILED!" >> $LOG
    fi
fi
注解:${1:-nginx} 表示取第1个参数,如果没传则默认值为nginx。systemctl is-active --quiet 安静检查,仅通过返回码判断(0=运行中)。建议加入cron每5分钟执行:*/5 * * * * /opt/scripts/check_service.sh nginx
3批量创建用户
/opt/scripts/create_users.sh
#!/bin/bash
USER_FILE=$1
[ -z "$USER_FILE" ] && echo "用法: $0 <用户名文件>" && exit 1
[ ! -f "$USER_FILE" ] && echo "文件不存在: $USER_FILE" && exit 1

while read -r name; do
    [ -z "$name" ] && continue         # 跳过空行
    [[ "$name" =~ ^# ]] && continue    # 跳过注释
    if id "$name" &>/dev/null; then
        echo "[跳过] $name 已存在"
    else
        useradd -m -s /bin/bash "$name"
        echo "$name:Pass@2026" | chpasswd
        echo "[创建] $name 成功"
    fi
done < "$USER_FILE"
运行
$ echo -e "alice\nbob\ncharlie" > /tmp/users.txt
$ bash /opt/scripts/create_users.sh /tmp/users.txt
[创建] alice 成功
[创建] bob 成功
[创建] charlie 成功
注解:while read line; do...done < file 逐行读文件标准写法。id user &>/dev/null 检查用户是否存在。chpasswd 批量设密码。

实验9:grep / sed / awk 三剑客

1grep 搜索
Terminal
$ grep "root" /etc/passwd              # 基本搜索
$ grep -i "error" /var/log/messages    # -i 忽略大小写
$ grep -v "^#" /etc/nginx/nginx.conf   # -v 反选(去掉注释行)
$ grep -c "Failed" /var/log/secure     # -c 统计匹配行数
$ grep -rn "listen" /etc/nginx/        # -r递归 -n行号
$ grep -E "^root|^nginx" /etc/passwd   # -E 扩展正则(多个模式用|)
2sed 替换
Terminal
$ echo "hello world" | sed 's/hello/hi/g'     # 替换
hi world

$ sed -i 's/192.168.1.100/10.0.0.100/g' conf  # -i 直接改文件
$ sed -i '/^#/d' config.txt                    # 删注释行
$ sed -i '/^$/d' config.txt                    # 删空行
$ sed -n '5,10p' file.txt                      # 只打印第5-10行
注意:sed -i 直接改源文件不可撤销!先不加 -i 预览,或用 sed -i.bak 自动备份。
3awk 字段处理
Terminal
$ awk -F: '{print $1}' /etc/passwd       # -F: 以冒号分隔,取第1字段
root
daemon
webadmin

$ awk -F: '$3>=1000{print $1,$3}' /etc/passwd   # 条件:UID>=1000
webadmin 1001

# 实战:Nginx日志TOP10 IP
$ awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -10
   523 192.168.1.50
   312 10.0.0.15
注解:awk逐行处理,按分隔符拆为 $1 $2 $3...$0=整行)。支持条件、运算、BEGIN/END块。本身是一门小型编程语言。

🐳 P4 · Docker容器实践(第13-16周)

环境:4G+内存。安装Docker:yum install -y yum-utils && yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo && yum install -y docker-ce && systemctl start docker && systemctl enable docker

实验11:Docker基础

1容器生命周期
Terminal
$ docker pull nginx:latest                        # 拉镜像
$ docker run -d -p 8080:80 --name web nginx       # 运行(-d后台 -p端口映射)
$ curl http://localhost:8080                       # 验证

$ docker ps                                        # 运行中的容器
$ docker ps -a                                     # 所有容器(含已停止)
$ docker logs -f web                               # 实时日志
$ docker exec -it web bash                         # 进入容器
$ docker stop web && docker rm web                 # 停止并删除
注解:-d=后台 | -p 8080:80=宿主机8080→容器80 | --name=命名 | exec -it=交互终端。容器删除后内部修改丢失,需数据卷持久化。
2数据卷持久化
Terminal
# 绑定挂载
$ mkdir /myhtml && echo "<h1>Hello</h1>" > /myhtml/index.html
$ docker run -d -p 80:80 -v /myhtml:/usr/share/nginx/html nginx
# 修改 /myhtml/index.html → 容器内网页实时变化

# 命名卷
$ docker volume create mydata
$ docker run -d -v mydata:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123 mysql:8
建议:数据库类容器必须用数据卷!否则删容器数据全丢。开发用绑定挂载(方便编辑),生产用命名卷(Docker管理更安全)。

实验12:Dockerfile与Compose

1Dockerfile构建镜像
/opt/myapp/Dockerfile
FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY app.py .
EXPOSE 5000
CMD ["python", "app.py"]
/opt/myapp/app.py
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello(): return 'Hello from Docker!'
if __name__ == '__main__': app.run(host='0.0.0.0', port=5000)
构建运行
$ echo "flask" > requirements.txt
$ docker build -t myflask:v1 .
$ docker run -d -p 5000:5000 myflask:v1
$ curl localhost:5000
Hello from Docker!
注解:Dockerfile每条指令一层。不常变的(pip install)放前面利用缓存,常变的(COPY app.py)放后面。CMD 定义启动命令。
2Docker Compose多容器
docker-compose.yml
version: '3.8'
services:
  web:
    image: nginx
    ports: ["80:80"]
    depends_on: [app]
  app:
    build: .
    expose: ["5000"]
  redis:
    image: redis:alpine
操作
$ docker-compose up -d           # 后台启动
$ docker-compose ps              # 查看状态
$ docker-compose logs -f app     # 看app日志
$ docker-compose down            # 停止删除
$ docker-compose up -d --build   # 重新构建启动
注解:depends_on 控制启动顺序。同一Compose的容器自动在同一网络,可用服务名互访(如 http://app:5000)。expose 仅容器间,ports 映射到宿主机。

🐍 P5 · Python运维实践(第17-20周)

环境:Python 3.8+,pip install psutil paramiko pyyaml

实验14:系统监控脚本

1CPU/内存/磁盘监控
/opt/scripts/monitor.py
#!/usr/bin/env python3
import psutil, socket
from datetime import datetime

CPU_WARN, MEM_WARN, DISK_WARN = 80, 85, 90

cpu = psutil.cpu_percent(interval=1)
mem = psutil.virtual_memory()
print(f"=== {socket.gethostname()} [{datetime.now():%Y-%m-%d %H:%M}] ===")
print(f"CPU: {cpu}%  内存: {mem.percent}% ({mem.used//1024//1024}M/{mem.total//1024//1024}M)")
for p in psutil.disk_partitions():
    u = psutil.disk_usage(p.mountpoint)
    flag = " ⚠️" if u.percent > DISK_WARN else ""
    print(f"磁盘 {p.mountpoint}: {u.percent}%{flag}")
if cpu > CPU_WARN: print(f"⚠️ CPU {cpu}% 超阈值!")
if mem.percent > MEM_WARN: print(f"⚠️ 内存 {mem.percent}% 超阈值!")
注解:psutil 跨平台系统监控库。cpu_percent(interval=1) 采样1秒。virtual_memory() 获取内存信息。生产中可把告警发邮件/钉钉。

实验15:远程批量巡检

1paramiko SSH远程执行
/opt/scripts/remote_check.py
#!/usr/bin/env python3
import paramiko

SERVERS = [
    {"host": "192.168.1.101", "user": "root", "key": "/root/.ssh/id_rsa"},
    {"host": "192.168.1.102", "user": "root", "key": "/root/.ssh/id_rsa"},
]

def run_remote(host, user, key, cmd):
    c = paramiko.SSHClient()
    c.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    c.connect(host, username=user, key_filename=key, timeout=10)
    _, stdout, _ = c.exec_command(cmd)
    result = stdout.read().decode().strip()
    c.close()
    return result

for s in SERVERS:
    print(f"\n{'='*40}\n{s['host']}\n{'='*40}")
    for cmd in ["hostname", "uptime", "df -h|grep '/$'", "free -h|awk '/Mem/{print $3\"/\"$2}'"]:
        print(f"  {cmd}  →  {run_remote(s['host'], s['user'], s['key'], cmd)}")
注解:paramiko 是Python的SSH库。SSHClient.connect() 连接,exec_command() 执行远程命令返回stdout/stderr。前提:已配好SSH密钥免密。AutoAddPolicy 自动接受未知主机(生产环境应使用白名单)。

🏗️ P6 · Ansible与综合冲刺(第21-24周)

环境:3台VM(1管理+2节点),SSH免密已配。管理机 yum install -y ansible

实验16:Ansible自动化

1Inventory与Ad-Hoc
/etc/ansible/hosts
[web]
192.168.1.101
192.168.1.102
[db]
192.168.1.103
[all:vars]
ansible_user=root
Terminal
$ ansible all -m ping                              # 测试连通
192.168.1.101 | SUCCESS => {"ping": "pong"}

$ ansible web -m shell -a "df -h"                  # 查磁盘
$ ansible web -m yum -a "name=nginx state=present" # 安装nginx
$ ansible web -m service -a "name=nginx state=started enabled=yes"
注解:Inventory 定义机器和分组。-m 指定模块 -a 传参数。常用模块:ping shell yum copy service file template
2Playbook部署Nginx
deploy_nginx.yml
---
- name: Deploy Nginx
  hosts: web
  become: yes                       # sudo提权

  vars:
    nginx_port: 80

  tasks:
    - name: Install EPEL
      yum: name=epel-release state=present

    - name: Install Nginx
      yum: name=nginx state=latest

    - name: Deploy config
      template: src=nginx.conf.j2 dest=/etc/nginx/conf.d/mysite.conf
      notify: Restart Nginx         # 配置变了才触发handler

    - name: Start Nginx
      service: name=nginx state=started enabled=yes

  handlers:
    - name: Restart Nginx
      service: name=nginx state=restarted
运行
$ ansible-playbook deploy_nginx.yml
PLAY RECAP ***
192.168.1.101: ok=5 changed=3 failed=0
192.168.1.102: ok=5 changed=3 failed=0
注解:ok=已是期望状态 changed=做了修改。幂等性:再执行一次changed变为0。handler 仅在被notify且task changed时执行,避免不必要重启。template 模块支持Jinja2变量替换(如 {{ nginx_port }})。
CloudOps Master · 6阶段 · 18实验 · 完整命令+输出+注解
← 返回 CloudOps Master