跳转至

26. 云与混合环境集成

本章介绍 RHEL 9 与主流云平台(AWS、Azure、GCP)的 CLI 工具配置与常用操作,以及 Ansible 自动化部署基础。掌握这些技能,能将本地 RHEL 运维能力延伸至云端,实现本地与云端的统一管理,构建真正的混合云运维体系。

实验范围说明

云平台操作需要有效的云账户和访问凭证。无云账户的读者可重点学习 CLI 安装、配置语法和命令结构,以及 Ansible 部分(完全本地执行,无需云账户)。Ansible 是本章核心内容,推荐所有读者完成。


26.1 前提条件

  • 已完成第四阶段前序配置(第 20–25 章)。
  • 通过 SecureCRT(SSH 端口 2222)以 ops 用户、密钥认证方式登录 192.168.1.100,执行 sudo -i 切换至 root 环境。
  • 官方仓库已启用(第 7 章)。
  • 网络可访问公网(云 CLI 需要连接各云服务 API 端点)。

本章全局参数

参数
主机名 / IP linuxdc / 192.168.1.100
Ansible Inventory /etc/ansible/hosts
Playbook 目录 ~/ansible-playbooks/
Role 目录 ~/ansible-roles/
SSH 端口(Ansible) 2222
SSH 密钥(Ansible) ~/.ssh/id_ed25519

26.2 AWS CLI 配置

26.2.1 安装 AWS CLI v2

# 下载官方安装包(AWS CLI v2 以二进制分发,不在 dnf 仓库)
curl -fsSL "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" \
  -o /tmp/awscliv2.zip

unzip /tmp/awscliv2.zip -d /tmp/
/tmp/aws/install

# 清理临时文件
rm -rf /tmp/aws /tmp/awscliv2.zip

# 验证安装
aws --version

26.2.2 配置访问凭证

aws configure

按提示输入以下信息(凭证从 AWS IAM 控制台的"安全凭证"页面获取):

AWS Access Key ID:     <AccessKeyId>
AWS Secret Access Key: <SecretAccessKey>
Default region name:   ap-northeast-1    (东京区域,按实际选择)
Default output format: json

凭证存储于 ~/.aws/credentials(权限自动设为 600);区域与格式存储于 ~/.aws/config

验证:

# 显示当前凭证对应的 AWS 账户信息
aws sts get-caller-identity

# 列出所有可用区域(表格格式)
aws ec2 describe-regions --output table

检查点

aws sts get-caller-identity 输出包含 AccountUserIdArn 三个字段,证明凭证有效。

26.2.3 常用 EC2 操作

# 查询可用的 RHEL 9 官方 AMI(Red Hat 的 AWS 账户 ID 为 309956199498)
aws ec2 describe-images \
  --owners 309956199498 \
  --filters "Name=name,Values=RHEL-9*" \
  --query 'Images[*].[ImageId,Name,CreationDate]' \
  --output table

# 启动 EC2 实例(替换实际的 AMI ID、密钥对名称、安全组和子网)
aws ec2 run-instances \
  --image-id ami-xxxxxxxxxxxxxxxxx \
  --instance-type t3.micro \
  --key-name my-keypair \
  --security-group-ids sg-xxxxxxxxxxxxxxxxx \
  --subnet-id subnet-xxxxxxxxxxxxxxxxx \
  --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=linuxdc-cloud}]'

# 查询实例状态
aws ec2 describe-instances \
  --filters "Name=tag:Name,Values=linuxdc-cloud" \
  --query 'Reservations[*].Instances[*].[InstanceId,State.Name,PublicIpAddress]' \
  --output table

# SSH 连接(使用 AWS 密钥对的 PEM 文件)
ssh -i ~/.ssh/my-keypair.pem ec2-user@<PublicIpAddress>

# 停止实例(保留磁盘数据,停止按小时计费)
aws ec2 stop-instances --instance-ids i-xxxxxxxxxxxxxxxxx

# 终止实例(销毁并释放所有关联资源)
aws ec2 terminate-instances --instance-ids i-xxxxxxxxxxxxxxxxx

26.2.4 S3 存储桶操作

# 创建存储桶(名称全球唯一,添加时间戳避免冲突)
BUCKET="linuxdc-backup-$(date +%s)"
aws s3 mb s3://${BUCKET}

# 将本地备份目录增量同步到 S3(服务端加密,排除临时文件)
aws s3 sync /backup/ s3://${BUCKET}/ \
  --exclude "*.tmp" \
  --sse AES256 \
  --delete

# 列出存储桶内对象
aws s3 ls s3://${BUCKET}/

# 下载特定文件
aws s3 cp s3://${BUCKET}/mariadb-all-$(date +%F).sql /tmp/

# 清理:先删除对象,再删除存储桶
aws s3 rm s3://${BUCKET}/ --recursive
aws s3 rb s3://${BUCKET}/

26.3 Azure CLI 配置

26.3.1 安装 Azure CLI

# 导入 Microsoft RPM 包签名密钥和仓库
rpm --import https://packages.microsoft.com/keys/microsoft.asc

dnf install -y \
  https://packages.microsoft.com/config/rhel/9/packages-microsoft-prod.rpm

dnf install -y azure-cli

# 验证
az --version

26.3.2 登录与订阅配置

# 设备码登录(适合无图形浏览器的服务器环境)
az login --use-device-code
# 按提示在浏览器访问 https://microsoft.com/devicelogin,输入显示的代码

# 查看当前订阅信息
az account show

# 列出所有可用订阅
az account list --output table

# 切换到指定订阅
az account set --subscription "<subscription-id>"

26.3.3 常用虚拟机操作

# 创建资源组(逻辑容器,用于统一管理一组 Azure 资源)
az group create --name linuxdc-rg --location eastasia

# 创建 RHEL 9 虚拟机(自动生成 SSH 密钥)
az vm create \
  --resource-group linuxdc-rg \
  --name linuxdc-cloud \
  --image RedHat:RHEL:9-lvm-gen2:latest \
  --size Standard_B1s \
  --admin-username azops \
  --generate-ssh-keys \
  --output json

# 查看资源组内所有虚拟机
az vm list --resource-group linuxdc-rg --output table

# 获取虚拟机公网 IP
az vm show \
  --resource-group linuxdc-rg \
  --name linuxdc-cloud \
  --show-details \
  --query publicIps \
  --output tsv

# SSH 连接(密钥自动保存到 ~/.ssh/)
ssh azops@<PublicIpAddress>

# 停止虚拟机(释放计算资源,停止计费,磁盘保留)
az vm deallocate --resource-group linuxdc-rg --name linuxdc-cloud

# 删除整个资源组(清理所有关联资源)
az group delete --name linuxdc-rg --yes --no-wait

26.4 GCP CLI 配置

26.4.1 安装 Google Cloud CLI

tee /etc/yum.repos.d/google-cloud-sdk.repo << 'EOF'
[google-cloud-cli]
name=Google Cloud CLI
baseurl=https://packages.cloud.google.com/yum/repos/cloud-sdk-el9-x86_64
enabled=1
gpgcheck=1
repo_gpgcheck=0
gpgkey=https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
EOF

dnf install -y google-cloud-cli

# 验证
gcloud --version

26.4.2 认证与项目配置

# 设备码方式登录(服务器环境)
gcloud auth login --no-launch-browser

# 设置默认项目
gcloud config set project <your-project-id>

# 设置默认区域(亚太东北 1 = 东京)
gcloud config set compute/region asia-northeast1
gcloud config set compute/zone asia-northeast1-a

# 查看当前配置
gcloud config list

26.4.3 常用 Compute Engine 操作

# 查询可用的 RHEL 9 公共镜像
gcloud compute images list \
  --filter="family:rhel-9" \
  --project=rhel-cloud

# 创建 VM 实例
gcloud compute instances create linuxdc-cloud \
  --machine-type=e2-micro \
  --image-family=rhel-9 \
  --image-project=rhel-cloud \
  --boot-disk-size=20GB \
  --tags=http-server,https-server

# 查看所有实例
gcloud compute instances list

# SSH 连接(gcloud 自动管理 OS Login 密钥)
gcloud compute ssh linuxdc-cloud

# 停止实例
gcloud compute instances stop linuxdc-cloud

# 删除实例(不可逆)
gcloud compute instances delete linuxdc-cloud --quiet

26.5 Ansible 自动化部署

Ansible 是 Red Hat 官方支持的无代理(Agentless)自动化运维工具,通过 SSH 对目标主机执行配置管理、应用部署和编排任务,是混合云环境统一运维的核心工具,也是后续第 28 章自动化部署(Ansible + Kickstart)的基础。

26.5.1 安装 Ansible

dnf install -y ansible-core

# 验证版本
ansible --version

# 查看已安装的模块集合
ansible-galaxy collection list

26.5.2 配置 Inventory(主机清单)

Inventory 是 Ansible 的目标主机列表,支持 INI 和 YAML 两种格式,支持静态文件和动态脚本(云平台动态 Inventory)。

mkdir -p /etc/ansible

tee /etc/ansible/hosts << 'EOF'
# 本机组(使用本地连接,无需 SSH)
[local]
linuxdc ansible_host=127.0.0.1 ansible_connection=local

# Web 服务器组
[webservers]
192.168.1.100 ansible_user=ops ansible_ssh_private_key_file=~/.ssh/id_ed25519 ansible_port=2222

# 数据库服务器组
[dbservers]
192.168.1.101 ansible_user=ops ansible_ssh_private_key_file=~/.ssh/id_ed25519 ansible_port=2222

# 全局变量(适用于所有主机)
[all:vars]
ansible_python_interpreter=/usr/bin/python3
EOF

验证连通性:

# 对所有主机执行 ping 模块(非 ICMP ping,而是 Ansible 连接测试)
ansible all -m ping

# 对 webservers 组执行命令
ansible webservers -m command -a "uptime"

# 收集主机信息(Facts)
ansible linuxdc -m setup | grep -E "ansible_os|ansible_distribution"

检查点

ansible local -m ping 返回 pong,证明 Ansible 与目标主机的连接和 Python 环境均正常。

26.5.3 编写 Playbook

Playbook 是 Ansible 的核心执行单元,以 YAML 格式描述对目标主机执行的一系列任务。

mkdir -p ~/ansible-playbooks

Playbook 一:部署 Apache Web 服务

tee ~/ansible-playbooks/deploy-apache.yml << 'EOF'
---
- name: 部署 Apache Web 服务
  hosts: webservers
  become: yes        # 相当于 sudo,以 root 权限执行

  vars:
    http_port: 80
    site_content: "<h1>Deployed by Ansible on linuxdc</h1>"

  tasks:
    - name: 安装 httpd
      dnf:
        name: httpd
        state: present

    - name: 创建测试页面
      copy:
        content: "{{ site_content }}"
        dest: /var/www/html/index.html
        owner: apache
        group: apache
        mode: '0644'

    - name: 修复 SELinux 上下文
      command: restorecon -Rv /var/www/html/
      changed_when: false

    - name: 启动 httpd 并设置开机自启
      systemd:
        name: httpd
        state: started
        enabled: yes

    - name: 防火墙放行 HTTP
      firewalld:
        service: http
        permanent: yes
        state: enabled
        immediate: yes
EOF

Playbook 二:系统安全基线配置

tee ~/ansible-playbooks/baseline.yml << 'EOF'
---
- name: 系统安全基线配置
  hosts: all
  become: yes

  tasks:
    - name: 仅安装安全更新
      dnf:
        update_only: yes
        security: yes
        state: latest

    - name: 确保 chronyd 运行并开机自启
      systemd:
        name: chronyd
        state: started
        enabled: yes

    - name: 设置时区为 Asia/Shanghai
      timezone:
        name: Asia/Shanghai

    - name: 确保 SELinux 处于 Enforcing 模式
      selinux:
        policy: targeted
        state: enforcing

    - name: 确保 firewalld 运行并开机自启
      systemd:
        name: firewalld
        state: started
        enabled: yes
EOF

执行 Playbook:

# 第一步:语法检查(不连接目标主机)
ansible-playbook ~/ansible-playbooks/deploy-apache.yml --syntax-check

# 第二步:模拟执行(dry-run,连接主机但不实际修改)
ansible-playbook ~/ansible-playbooks/deploy-apache.yml --check

# 第三步:正式执行(限定 local 组,-v 显示任务详情)
ansible-playbook ~/ansible-playbooks/deploy-apache.yml \
  --limit local -v

# 验证结果
curl http://localhost

Playbook 幂等性设计

Ansible 模块应设计为幂等(Idempotent):多次执行结果相同,不产生副作用。dnfsystemdcopy 等官方模块均天然幂等——已安装就不再安装,已运行就不重启。command/shell 模块不幂等,应配合 createschanged_when 参数控制执行条件。

26.5.4 使用变量和模板(Jinja2)

# 创建变量文件
tee ~/ansible-playbooks/vars/webserver.yml << 'EOF'
http_port: 80
server_admin: ops@linuxdc.local
site_title: "linuxdc Web Server"
EOF

# 创建 Jinja2 模板(.j2 后缀)
mkdir -p ~/ansible-playbooks/templates
tee ~/ansible-playbooks/templates/index.html.j2 << 'EOF'
<!DOCTYPE html>
<html>
<head><title>{{ site_title }}</title></head>
<body>
  <h1>{{ site_title }}</h1>
  <p>Deployed by Ansible | Host: {{ inventory_hostname }}</p>
  <p>Server Admin: {{ server_admin }}</p>
</body>
</html>
EOF

# 在 Playbook 中使用模板
tee ~/ansible-playbooks/deploy-with-template.yml << 'EOF'
---
- name: 使用模板部署 Web 服务
  hosts: webservers
  become: yes
  vars_files:
    - vars/webserver.yml

  tasks:
    - name: 从模板渲染首页
      template:
        src: templates/index.html.j2
        dest: /var/www/html/index.html
        owner: apache
        group: apache
        mode: '0644'
EOF

26.5.5 Handlers(触发器)

Handlers 是一种特殊任务,只在被 notify 触发时执行,且同一次 play 中无论被触发多少次,只执行一次(在 play 末尾),常用于配置变更后重启服务。

tee ~/ansible-playbooks/deploy-nginx.yml << 'EOF'
---
- name: 部署并配置 Nginx
  hosts: webservers
  become: yes

  tasks:
    - name: 安装 Nginx
      dnf:
        name: nginx
        state: present

    - name: 部署 Nginx 配置
      copy:
        content: |
          server {
              listen 80;
              server_name linuxdc.local;
              root /usr/share/nginx/html;
          }
        dest: /etc/nginx/conf.d/linuxdc.conf
      notify: 重载 Nginx    # 配置变化时触发 handler

    - name: 启动 Nginx
      systemd:
        name: nginx
        state: started
        enabled: yes

  handlers:
    - name: 重载 Nginx
      systemd:
        name: nginx
        state: reloaded
EOF

26.5.6 Ansible Roles(模块化组织)

Role 提供标准化目录结构,将相关任务、变量、模板、文件按功能组织为可复用单元,是大规模自动化项目的最佳实践。

# 初始化 Role 结构
mkdir -p ~/ansible-roles
ansible-galaxy init ~/ansible-roles/common

# 查看 Role 目录结构
find ~/ansible-roles/common -type f | sort

Role 标准目录结构:

common/
├── tasks/
│   └── main.yml       核心任务列表(必须)
├── handlers/
│   └── main.yml       触发器定义
├── vars/
│   └── main.yml       高优先级变量(不建议被覆盖)
├── defaults/
│   └── main.yml       低优先级默认变量(设计为可被覆盖)
├── templates/
│   └── *.j2           Jinja2 模板文件
├── files/
│   └── *              静态文件(copy 模块使用)
├── meta/
│   └── main.yml       Role 元数据(依赖声明)
└── README.md          Role 说明文档

在 Playbook 中使用 Role:

tee ~/ansible-playbooks/site.yml << 'EOF'
---
- name: 应用通用基线配置
  hosts: all
  become: yes
  roles:
    - common
EOF

从 Ansible Galaxy 安装社区 Role:

# 搜索可用 Role
ansible-galaxy search nginx

# 安装指定 Role
ansible-galaxy install geerlingguy.nginx

# 查看已安装 Role
ansible-galaxy list

26.6 混合云运维最佳实践

26.6.1 Ansible 动态 Inventory(云平台集成)

# 安装 AWS 动态 Inventory 插件
ansible-galaxy collection install amazon.aws

# 创建 AWS 动态 Inventory 配置
tee ~/ansible-playbooks/aws_inventory.yml << 'EOF'
plugin: amazon.aws.aws_ec2
regions:
  - ap-northeast-1
filters:
  instance-state-name: running
  tag:Project: linuxdc
keyed_groups:
  - key: tags.Environment
    prefix: env
compose:
  ansible_host: public_ip_address
EOF

# 使用动态 Inventory 查看 AWS 主机
ansible-inventory -i ~/ansible-playbooks/aws_inventory.yml --list

26.6.2 Ansible Vault(敏感信息加密)

# 创建加密的变量文件(存储数据库密码等敏感信息)
ansible-vault create ~/ansible-playbooks/vars/secrets.yml
# 输入 Vault 密码,然后在编辑器中添加:
# db_password: "App@Pass2025!"
# api_key: "xxxxxxxxxxxxxxxxx"

# 在 Playbook 中引用加密变量
# vars_files:
#   - vars/secrets.yml

# 执行含加密变量的 Playbook
ansible-playbook site.yml --ask-vault-pass

# 查看加密文件内容(需 Vault 密码)
ansible-vault view ~/ansible-playbooks/vars/secrets.yml

# 修改加密文件
ansible-vault edit ~/ansible-playbooks/vars/secrets.yml

26.7 常见问题与排查

问题现象 排查步骤
AWS CLI 认证失败 aws sts get-caller-identity;检查 ~/.aws/credentials(权限应为 600);确认 Access Key 未过期
Azure az login 超时 使用 --use-device-code 参数;检查网络代理:echo $https_proxy
Ansible ping 失败 手动验证 SSH:ssh -p 2222 ops@<target> -i ~/.ssh/id_ed25519;检查 inventory 中 ansible_useransible_port
Ansible 任务执行报权限不足 确认 Playbook 中 become: yes;确认目标主机 ops 用户的 sudo 配置(第 4 章)
--check 模式报错但实际执行成功 部分模块不支持 check 模式;command/shell 模块无法预测执行结果,属正常现象
# Ansible 详细调试模式
ansible-playbook site.yml -vvv

# 查看目标主机收集的所有 Facts
ansible linuxdc -m setup

# 列出 Inventory 中所有主机及分组
ansible all --list-hosts
ansible-inventory --list

26.8 实践任务

  1. 登录 linuxdc(SecureCRT 端口 2222,ops 用户,密钥认证,sudo -i 切换 root)。
  2. 安装 Ansible,配置 /etc/ansible/hosts,对本机执行连通性测试:

    ansible local -m ping
    ansible local -m setup | grep ansible_distribution
    
  3. 编写并执行 deploy-apache.yml,验证 Apache 已部署:

    ansible-playbook ~/ansible-playbooks/deploy-apache.yml \
      --limit local --syntax-check
    ansible-playbook ~/ansible-playbooks/deploy-apache.yml \
      --limit local -v
    curl http://localhost
    
  4. 执行 baseline.yml 基线配置 Playbook,查看执行结果摘要(okchangedfailed 计数)。

  5. 创建含 Jinja2 模板的 Playbook,渲染并部署自定义首页,验证内容正确。
  6. 使用 ansible-galaxy init 初始化 common Role 结构,在 tasks/main.yml 中添加一个确保 chronyd 运行的任务。
  7. (可选)安装 AWS CLI v2,执行 aws configure,验证 aws sts get-caller-identity 返回账户信息。

26.9 自测问题

Q1:Ansible 的"无代理"(Agentless)设计有哪些核心优势?

传统配置管理工具(Chef、Puppet)需要在每台被管节点安装并持续运行代理程序,增加了部署复杂度、维护成本和潜在攻击面。Ansible 仅通过 SSH 连接目标主机,只要目标主机有 Python 环境(RHEL 9 默认包含)即可,无需安装任何额外软件。核心优势体现在三方面:零部署成本(对存量服务器无需改造);无单点故障(无守护进程,控制节点故障不影响已完成的配置);天然安全(SSH 加密通信,无额外监听端口,减少攻击面)。

Q2:Ansible Playbook 中 --check 模式有何作用和局限性?

--check 模式(dry-run)使 Ansible 模拟执行任务并报告"将会做什么",但不实际修改目标系统状态,是上线前验证 Playbook 逻辑的重要手段,尤其适合审查变更影响范围。主要局限:command/shell 模块无法预测实际输出,check 模式直接跳过;若某任务依赖前序任务的输出(如注册变量 register),check 模式中该变量值缺失,可能导致后续任务误报失败;云平台资源创建类操作(如 amazon.aws.ec2_instance)通常不支持 check 模式。因此 check 模式只能作为辅助验证手段,不能完全替代测试环境验证。

Q3:ansible-galaxy 和 Ansible Role 解决了什么工程问题?

随着自动化覆盖面扩大,Playbook 数量增多后面临两个核心问题:代码重复(相同的 Nginx 安装逻辑在不同 Playbook 中重写多遍)和维护困难(修复一个 bug 需要更新多处)。Role 提供了标准化的目录结构,将任务、变量、模板、文件按功能封装为可独立版本管理的单元(如 nginx Role、mysql Role),Playbook 通过 roles: 声明引用,实现代码复用和单点维护。ansible-galaxy 是 Role 和 Collection 的公共仓库,提供数万个社区和官方维护的模块,ansible-galaxy install <role> 一行命令即可引入成熟的自动化逻辑,避免重复造轮子。


26.10 章节总结

本章完成了 RHEL 9 与云平台的集成:AWS CLI v2(EC2 实例管理、S3 存储同步)、Azure CLI(资源组与虚拟机生命周期管理)、GCP CLI(Compute Engine 操作),以及 Ansible 无代理自动化部署的完整体系(Inventory 配置、Playbook 编写与执行、变量与 Jinja2 模板、Handlers 触发机制、Role 模块化封装、Vault 敏感信息加密、云平台动态 Inventory)。云 CLI 工具将本地 RHEL 运维能力延伸至云端;Ansible 实现本地与云端的统一自动化管理。

至此,第四阶段业务应用集成与部署全部完成。系统已具备 Web 服务、数据库、邮件、VPN、高可用、容器/虚拟化和云混合管理的完整能力,具备进入第五阶段自动化运维与系统演进的全部基础条件。