深色模式
云 CLI 与 SDK
摘要:控制台适合探索和一次性操作,批量、定时、可复现的操作必须走 CLI 与 SDK。本文讲清 CLI 的安装配置与凭证方式、常用查询技巧(
--query与jq),以及用 SDK 写脚本时必须处理的分页、重试与限速。
适用环境
bash
# Python 3 环境 + 云 CLI
python3 --version
pip3 --version
which jq || sudo apt install -y jq1
2
3
4
2
3
4
操作步骤
一、安装与配置凭证
bash
# 安装 AWS CLI v2(Linux x86_64)
curl -sSL "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o awscliv2.zip
unzip -q awscliv2.zip && sudo ./aws/install
aws --version
# 交互式配置(凭证写入 ~/.aws/credentials)
aws configure1
2
3
4
5
6
7
2
3
4
5
6
7
凭证的优先级顺序(重要):命令行参数 > 环境变量 > 实例角色/配置文件。生产机器优先用实例角色,避免任何 AK 落盘。
bash
# 用环境变量临时指定(CI 场景常用)
export AWS_ACCESS_KEY_ID=...
export AWS_SECRET_ACCESS_KEY=...
export AWS_DEFAULT_REGION=ap-east-1
# 多账号切换:使用 named profile
aws configure --profile prod
aws s3 ls --profile prod1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
二、用 --query 精确取字段
CLI 输出默认是 JSON,配合 --query(JMESPath)能让输出直接可读:
bash
# 列出所有运行中的实例:ID / 类型 / 私网 IP / 名称标签
aws ec2 describe-instances \
--filters Name=instance-state-name,Values=running \
--query 'Reservations[].Instances[].[InstanceId,InstanceType,PrivateIpAddress,Tags[?Key==`Name`]|[0].Value]' \
--output table
# 找出所有没有 env 标签的实例
aws ec2 describe-instances \
--query 'Reservations[].Instances[?!not_null(Tags[?Key==`env`])].InstanceId' --output text
# 组合 jq 做更复杂的处理
aws ec2 describe-instances | jq -r '.Reservations[].Instances[] | [.InstanceId, .InstanceType, (.Tags[]?|select(.Key=="Name")|.Value)] | @tsv'1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
三、用 CLI 写批量运维
bash
#!/usr/bin/env bash
set -euo pipefail
# 批量给所有实例打上 owner 标签
for id in $(aws ec2 describe-instances --filters Name=instance-state-name,Values=running \
--query 'Reservations[].Instances[].InstanceId' --output text); do
echo "tagging $id"
aws ec2 create-tags --resources "$id" \
--tags Key=owner,Value=ops Key=managed_by,Value=cli
done1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
四、用 SDK 写脚本(Python + boto3)
bash
pip3 install boto31
python
import boto3
from botocore.exceptions import ClientError
ec2 = boto3.client("ec2", region_name="ap-east-1")
def list_instances():
"""分页拉取全部实例,避免只拿到第一页"""
paginator = ec2.get_paginator("describe_instances")
for page in paginator.paginate(
Filters=[{"Name": "instance-state-name", "Values": ["running"]}]
):
for r in page["Reservations"]:
for i in r["Instances"]:
name = next(
(t["Value"] for t in i.get("Tags", []) if t["Key"] == "Name"), "-"
)
yield i["InstanceId"], i["InstanceType"], name
def stop_instance(instance_id):
"""带错误处理的停实例操作"""
try:
ec2.stop_instances(InstanceIds=[instance_id])
print(f"stopped {instance_id}")
except ClientError as e:
code = e.response["Error"]["Code"]
if code == "IncorrectInstanceState":
print(f"{instance_id} 状态不允许停止,跳过")
else:
raise
if __name__ == "__main__":
for iid, itype, name in list_instances():
print(iid, itype, name)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
注意
云 API 几乎都是分页返回的。直接调用 describe_* 只拿第一页是脚本最常见的 bug,务必使用 paginator 或手写 NextToken 循环。
五、重试与限速(Throttling)
python
from botocore.config import Config
# SDK 自带标准重试模式,建议显式配置
cfg = Config(
retries={"max_attempts": 10, "mode": "adaptive"},
connect_timeout=5,
read_timeout=30,
)
client = boto3.client("ec2", region_name="ap-east-1", config=cfg)1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
批量操作时遇到限速(HTTP 429 / ThrottlingException),应采用带退避的重试,而不是一味加大并发。
六、Dry Run:先验证权限与参数
bash
# 加 --dry-run 只校验权限与参数,不真正执行
aws ec2 stop-instances --instance-id i-0abc --dry-run
# 返回 DryRunOperation 说明有权限且参数正确;返回 UnauthorizedOperation 说明权限不足1
2
3
2
3
验证
- [ ]
aws sts get-caller-identity正常返回,确认身份与账号正确 - [ ] 一条
--query命令能输出可读的表格结果 - [ ] Python 脚本用 paginator 拉取的结果数量 > 单次调用上限(例如实例数超过 1000 时验证)
- [ ]
--dry-run在不执行的前提下能验证权限
常见坑
- 凭证写在脚本里:脚本一旦进 Git 就等于泄露,必须用实例角色或环境变量注入。
- 忘记指定地域:默认地域可能不是你要操作的地域,导致「明明有资源却查不到」。
- 不处理分页:脚本在小规模测试时正常,上生产后只处理了一部分资源。
- 忽略限速重试:批量操作半夜跑失败,第二天才发现只跑了一半。
- CLI 版本过旧:新 API 参数在旧版本上不识别,应定期升级并在脚本里固定版本要求。