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 输出包含 Account、UserId、Arn 三个字段,证明凭证有效。
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):多次执行结果相同,不产生副作用。dnf、systemd、copy 等官方模块均天然幂等——已安装就不再安装,已运行就不重启。command/shell 模块不幂等,应配合 creates、changed_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_user 和 ansible_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 实践任务
- 登录
linuxdc(SecureCRT 端口 2222,ops用户,密钥认证,sudo -i切换 root)。 -
安装 Ansible,配置
/etc/ansible/hosts,对本机执行连通性测试:ansible local -m ping ansible local -m setup | grep ansible_distribution -
编写并执行
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 -
执行
baseline.yml基线配置 Playbook,查看执行结果摘要(ok、changed、failed计数)。 - 创建含 Jinja2 模板的 Playbook,渲染并部署自定义首页,验证内容正确。
- 使用
ansible-galaxy init初始化commonRole 结构,在tasks/main.yml中添加一个确保chronyd运行的任务。 - (可选)安装 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、高可用、容器/虚拟化和云混合管理的完整能力,具备进入第五阶段自动化运维与系统演进的全部基础条件。