- Aws的密钥只能下载一次,下载后请小心保存
- AWS的命令行或者代码的环境变量是:
AWS_ACCESS_KEY_ID(或AWS_ACCESS_KEY)/AWS_SECRET_ACCESS_KEY(或AWS_SECRET_KEY)/AWS_DEFAULT_REGION/AWS_REGION
,除了放到环境变量,它一般也可以存储在~/.ssh/aws/credentials
文件里 - AWS现在的API版本是V3了,感觉文档清晰了不少:https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/ec2/
AWS CLI
不同操作系统安装方式见Installing, updating, and uninstalling the AWS CLI version 2 on Linux,包括mac都可以直接安装的
可以在
~/.aws/config
中配置多个profile1
2
3
4
5
6
7
8[default]
aws_access_key_id =
aws_secret_access_key =
[profile user1]
aws_access_key_id =
aws_secret_access_key =
region = us-east-1使用的时候可以这样指定
1
aws ec2 describe-instances --profile user1
EC2
- ubuntu系统默认用户为ubuntu,amazon系统默认的用户名为ec2-user
- 新用户默认会有750小时的免费套餐,但是仅限个别低配类型
- 要想查看在所有region下的所有的ec2实例,可以在VPC dashboard中查看,
Running Instances -> See all regions
- EC2实力类型列表,注意t2、t3是突发性能实例,CPU的使用采用积分制(CPU credits),如果某一时间发现CPU不行或者网站很卡,有可能是因为CPU资源无法使用了,这种情况要么等积分恢复,要么升级实例
如何删除EC2实例
- 先选中要删除的实例,Stop,再Terminate(终止实例),这个时候虽然实例还在,但其实已经删除了,大概等个10分钟左右就没了
EC2实例升级/修改实例类型
- IP会变更,请注意是否启用弹性IP或者负载均衡器
- 关机,需要接近一分钟
操作->实例设置->更改实例类型
- 开机
EC2实例扩容
关机扩容
- 关机扩容很简单,但是IP会变更,请注意是否启用弹性IP或者负载均衡器
- 首先关机
Actions -> Instance State -> Stop
- 进入卷管理:
Elastic Block Store -> Volumes
- 选择需要更改的磁盘:
Modify Volume
,然后输入大小 - 重启实例,并进入终端
- 使用
df -h
查看当前磁盘容量
不关机扩容
在实例详里面找到root volumn,进入volumn详情
Actions -> Modify Volume
,输入扩容后的大小点击确定进入实例,此时用
df -h
查看依然是原来的大小,使用lsblk
命令可以查看有新的大小,该命令用于查看是否具有必须扩展的分区,例如:1
2xvda 202:0 0 30G 0 disk
└─xvda1 202:1 0 20G 0 part / # df -h只能看到这个分区执行扩容命令
1
2
3
4
5
6有时候lsblk看到的磁盘名称和df -h显示的磁盘名称不一致,没关系,下面的命令按照lsblk的来就行
sudo growpart /dev/xvda 1
lsblk # 验证xvda1的大小是否已经变化,不过此时用df -h依然看不出变化
sudo resize2fs /dev/xvda1 # 此时用df -h就能看到变化了,扩容过程也完成了
EC2增加磁盘
步骤
创建卷
操作->连接卷
,默认会挂载到/dev/sdf
进入实例,执行
lsblk
可以看到附加的卷(磁盘)新卷默认是没有文件系统的,可以这样确定:
1
2sudo file -s /dev/xvdf # 如果输出是/dev/xvdf: data表示没有文件系统
sudo mkfs -t xfs /dev/xvdf # 创建文件系统,如果找不到mkfs命令,可以安装xfsprogs挂载
1
2
3sudo mkdir /data # 创建挂载点
sudo mount /dev/xvdf /data # 挂载
df -h # 确认是否挂载成功
Ec2绑定Elastic IP弹性IP
- 弹性IP只要是绑定在运行中的ec2实例上就是免费的,所以如果仅仅是要一个不会随着机器状态变化的IP那么推荐用弹性IP而不是用负载均衡器
- 当一个新建的弹性IP被关联到一个实例上的时候,该实例的公有IP地址也会变成一样的,不过之后如果实例重启公有IP会改变,弹性IP则不会了
- 一个账号最多绑定5个弹性IP,超过了需要单独提交申请,所以有时候还是用elb代替吧
安全组
- 注意如果安全组的target设置为另外一个安全组,那么在访问另外一个安全组的实例的时候不能使用外网IP,只能用内网IP才行
EC2配置Cloudwatch监控
添加自定义指标
- 需要在服务器安装aws CLI工具,在创建用户权限的时候选择Cloudwatch下的
PutMetricData
- Metric的历史数据不是一直保留的,而是会根据采集间隔来确定不同的保留时间,参考Metrics retention
- 对于服务的监控,ELB自带了监控指标的,不需要使用下面脚本中的
http_status_code
,可以在创建监控的时候搜索5xx
即可看到 - 还需要编写自定一个脚本实现自定义的监控,例如服务健康状态检测,脚本如下:
1 | !/bin/bash |
- 编写完自定义脚本后添加可执行权限
chmod +x watch.sh
,然后可以手动执行一下看看能不能成功,执行完一次过后cloudwatch后台在创建指标的时候就能选择这些指标了。如果执行过程中提示需要cloudwatch:putMetricData
权限,那么需要去AWS IAM
里面去分配cloudwatch
相关的策略,错误信息里面有指定哪个IAM
用户 - 我们可以定时执行这个脚本:
1 | crontab -e |
- 使用aws cli手动提交一条日志:
1
aws logs put-log-events --log-group-name BestRingPOS --log-stream-name Debug --profile bestring-prod --cli-input-json '{"logGroupName":"MyGroup","logStreamName":"Debug","logEvents":[{"timestamp":1709016343000,"message":"{\"abc\":\"def\"}"}]}'
EC2开机脚本
- 在EC2启动的时候执行
- AWS的概念叫User Data
磁盘清理
- 默认磁盘都很小,并且aws好像会放很多snap的大文件在系统里面,可以尝试使用下面的脚本来清理一下
1 | from https://superuser.com/questions/1310825/how-to-remove-old-version-of-installed-snaps |
S3
- S3的生命周期管理,有点绕,还没搞懂
- 通过
Bucket
的Metrics
可以查看桶的总容量和总的文件数量 - 通过文件夹的
Actions->Calculate total size
可以查看指定文件夹的容量和文件数量
使用js sdk操作AWS3
1 | const AWS = require('aws-sdk') |
开放S3桶的公共访问权限
- 需要在Bucket的
Permissions
上进行以下设置
1 | Block public access (bucket settings)关闭以下几个权限 |
用S3部署静态站点
如果要用自定义域名,bucket的名字需要和域名一样
设置Bucket policy,允许所有人访问:
1
2
3
4
5
6
7
8
9
10
11
12{
"Version":"2012-10-17",
"Statement":[
{
"Sid":"AddPerm",
"Effect":"Allow",
"Principal": "*",
"Action":["s3:GetObject"],
"Resource":["arn:aws:s3:::<your bucket name here>/*"]
}
]
}开启静态站点功能Bucket -> Properties -> Static Website Hosting,开启后就会有一个aws的域名了,但是没有ssl证书
自己在AWS上申请证书
创建CloudFront -> Distribution,origin domain设置为自己的域名,Alternate domain (CNAME)选择自己的域名
最后将域名的DNS设置A记录到cloudfront的域名即可
命令行操作S3
1 | aws s3 cp README.md s3://mybucket/README.md # 上传文件 |
Cloudfront
- 还有中缓存站点的方式是不使用S3,直接用CloudFront来代理缓存,参考文档: How to use CloudFront to do WordPress page caching
CloudWatch
- 注意只有上传的data为json的时候才能支持json字段直接查询
- 如果是lambda函数,
console.log
输出对象的时候层级多了的时候会输出成Object
字符串,这时候只需要在console.log
最外层加一个JSON.stringify(data, null, '')
即可,注意只能加在最外层,否则里面那个字段就是字符串了 - 日志查询语法
1 | fields @timestamp, extra_data.type as type # 指定需要显示的字段 |
ACM/AWS Certificate Manager
- AWS的公有SSL/TLS证书是免费的,不过因为ACM管理私钥,所以只能在AWS上面使用。获取步骤还算简单,添加一个CNAME记录,一会儿就好了(真遇到了等一个小时才生效的情况)
- 只能用于集成了ACM服务的EC2实例,例如(ElasticLoad Balancing [ELB]或Amazon CloudFront分配),也只有满足这些条件才能自动续订
Route 53
- AWS的域名管理
- 第一次添加DNS的时候默认时间是
1h
,最好设置成1m
,否则缓存更新太慢了 - 可以为同一个域名设置多个托管区域(hosted zone),例如针对同一个域名在测试环境和生产环境分别配置不同的DNS,只需要更改本地的名称服务器就能切换到不同的DNS上去,这样使用感觉有点复杂了
- 如果要用
Route 53
去管理域名的DNS,需要新建托管区域(hosted zone),然后在域名购买地设置NS记录指向hosted zone
的四个NS
记录即可
ELB/Elastic Load Balancing负载均衡器
- ELB支持多种负载均衡器(ELB产品比较)
- 应用负载均衡器(Application Load Balancer):对HTTP/HTTPS请求进行负载均衡
- 网络负载均衡器(Network Load Balancer):对网络/传输协议(第4层-TCP、UDP、TLS)以及极端性能/低延迟的应用程序进行负载均衡
- 网关负载均衡器(Gateway Load Balancer):IP层
(Classic Load Balancer):应用程序在EC2 Classic网络中构建而成,AWS上已经变成灰色了,看来已经放弃了
- 可以直接在EC2管理页面创建负载均衡器,点击
Load Balancer
即可进行创建,如果需要选择ACM管理的SSL证书,可以直接在第二步选择。如果是外部的证书也可以直接在这里添加,无需在ACM添加 - 需要注意的是,创建后需要将域名的DNS记录指向负载均衡器的DNS名称,这样才能正确到负载均衡器上
- 负载均衡器默认超时时间是60秒,如果出现504网关超时错误可能是这个引起的
- 负载均衡器的目标组可以只选择80端口,服务器上也可以只开启80端口,只有在负载均衡器的监听器上面需要监听443,转发到目标组就行了
- 如果是非
Route 53
管理的域名需要指向elb
需要设置的是CNAME记录 - 价格表: 0.0225美元/小时,差不多3.5元/天,简单的还是用弹性IP吧,毕竟是免费的
- ELB -> ALB(Application Load Balancer)是原生支持websocket的,无论是
ws
还是wss
协议,做法如下- 创建新的目标群组,端口为websocket的端口,协议选择
HTTP
(不过需要注意的是,健康检查一直都不会通过),创建成功后将属性->粘性
选项打开 - 在之前监听了80、443端口的ALB上添加新的侦听器,协议选择
HTTPS
,证书用之前的证书,转发到上面的目标群组即可 - 一定要检查下安全组看是否允许websocket端口的TCP协议,另外需要增加ELB的空闲超时时间
- 创建新的目标群组,端口为websocket的端口,协议选择
- 注意负载均衡器一般都会添加要给80自动跳转到443的规则,但是有时候前端却无法跳转,这时因为负载均衡器本身也有安全组,必须把80和443端口都开放才行
API Gateway
- Creating a Serverless Contact Form on AWS: 使用API Gateway + SES服务创建一个serverless API用于网页的用户表单搜集
- 如何启用 CloudWatch Logs 以对 API Gateway REST API 或 WebSocket API 进行问题排查:
映射模板语法
1 | 这是一个使用EMS发送email的模板 |
API Gateway权限设置/Resource Policy
- 有多种访问策略:AWS Account Allowlist/IP Range Denylist/Source VPC Allowlist
- 如何排查API Gateway中的HTTP 403禁止访问错误
- 如何排查与 API Gateway 私有 API 终端节点的连接问题?
- 我从 VPC 连接到 API Gateway API 时,为什么会收到 HTTP 403 禁止错误?
实现仅自己的EC2(指定的VPC)能访问接口其他地方不能访问接口
Resource Policy添加如下策略:
1
2
3
4
5
6
7
8
9
10
11{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": "execute-api:Invoke",
"Resource": "arn:aws:execute-api:us-west-2:账户ID:API的ID/APi的Stage/*/*"
}
]
}进入我们想配置的EC2绑定的VPC的配置页面选择左侧菜单栏的
Endpoints(终端节点)
,创建一个新的终端节点。服务类别选择AWS服务,服务名称选择API Gateway的执行服务com.amazonaws.us-west-2.execute-api
,终端节点类型为Interface
,然后VPC就是我们需要的VPC,子网可以全选,取消选择Enable DNS name
禁用私有DNS,其他默认。创建完成后需要等几分钟才能生效
Lambda
通过
process.env.MY_ENV
获取环境变量注意如果有异步函数,一定要await它的返回,否则可能会在下一次触发的时候才执行
发现一个比较好用的库,可以实现打包、部署等操作: motdotla/node-lambda
- 但是不是每种nodejs的库都能直接打包,比如nestjs,可以使用nextjs-lambda打包成lambda,但是它会生成多个layers,并且同样会用到cloudfront和S3,我不如直接把生成的静态站点out目录上传到S3,然后用cloudfronted代理静态站点
nestjs转换为aws lambda 可以参考Nestjs 使用手册,但是最好别用nestjs做lambda,性能真的不行。简单点,用koa.js就行了
如果需要安装依赖,要么创建
层
,要么就将node_modules
一起压缩为.zip
文件然后上传,可以使用adm-zip
等方式压缩,但是这样会因为程序包太大而无法使用在线的内联编辑器1
2
3
4
5
6import AdmZip from 'adm-zip';
const zip = new AdmZip();
zip.addLocalFolder('./dist');
zip.writeZip('./lambda.zip');使用
cloudwatch
触发lambda
,需要在CloudWatch
控制台创建规则Events -> Create rule
,Event Source
可以定时或者选择警告,目标target
则选择我们创建的Lambda
函数
实例
1 | exports.handler = async (event, context) => { |
RDS
MySQL
- 开启创建存储过程的功能
- RDS MySQL中各种日志事件的详解
- RDS出现too many connections错误: 默认情况下,rds的最大连接数是根据内存计算得出的,可以在参数组里查看其计算方式,另外可以在mysql里执行
select @@max_connections
得到具体的数值。默认情况1核2G的实例我这边看最大值是45。可以自己创建一个新的参数组进行修改
IAM权限
- 用户权限凭证管理
- 如果要为aws sdk的api调用创建新的access key、access secret的话最好这样做:
- 最好单独创建一个用户:
IAM -> 用户 -> 添加用户
,在创建的时候不要选择任何的策略权限 - 创建完成后
添加内联策略
,然后选择需要的服务、操作、资源即可
- 最好单独创建一个用户:
- 可以将创建好的Role直接绑定到EC2,这样在EC2里面的某些服务就不需要提供key和secret即可直接访问指定服务接口
aws_access_key_id/aws_secret_access_key
- 申请的地方在右上角-> Security credentials->Access keys
- 但是一个用户只能申请两个
- 如果在用,但是忘记了内容,可以尝试在
~/.aws/credentials
中查找试试
DocumentDB (MongoDB)
- 默认启用了tls安全登录设置的,必须下载他们的pem文件才能进行连接,可以在
Amazon DocumentDB -> 参数组
中新建参数组,因为default开头的参数组无法修改,然后在新建的参数组里面将tls给disabled掉,然后再修改集群的参数组即可 - 它是创建在VPC之上的,目前居然不支持公网访问,不同的region之间要访问得给VPC创建对等连接,并且还不支持us-west-1 region,所以最简单的方法是在另外的region创建ec2和documentdb
- 居然不支持
Capped Collections
,可能之后会支持,其他不支持的可以参考这里
Amazon MemoryDB for Redis
SES/Simple Email Service电子邮件发送和接收服务
AWS Systems Manager(SSM)
- 管理ec2系统内部的东西,例如通过api或cli向服务器发送命令并执行
- SSM未发现管理的ec2实例: 可能是因为
ssm agent
在实例内部未安装或者未安装成功(即使在运行中也可能没有安装成功,还是得看其日志/var/log/amazon/ssm下),ssm agent安装文档,当然ssm agent
默认是安装了的,可以通过这些命令查看ssm运行状态
SNS
- 通知系统,可以用于发送邮件
- 注意新添加的邮件必须要Confirm才行,并且Confirm后可能还要等5分钟左右才能收到邮件
使用js sdk发送sns
1 | AWS.config.update({ region: config.oneRoster.awsRegion }); |
SQS消息队列
- 有两种消息队列
- 标准队列
- FIFO队列
- 注意两种队列的消息在消费者获取到后都不会自动出队的,消费者需要在指定时间删除消息,否则消息会被其他消费者看到。可以在后台或者在接收消息的时候设置消息可见性时间,默认是30秒,即消费者在接收了消息后的30秒内如果没有删除消息,那么30秒后该消息同样能被其他的消费者获取到
1 | import {SQS} from 'aws-sdk' |
- SQS的客户端默认并不是一个监听者,如果想要持续监听一个队列,要么自己写
while true
循环,要么可以使用sqs-consumer - 默认的重复检测时间是5分钟,即5分钟内发送相同内容的消息会被认定为重复,不会入队。但是必须有检测重复的功能,要么基于内容要么基于group,否则会报错
The queue should either have ContentBasedDeduplication enabled or MessageDeduplicationId provided explicitly
CodeDeploy/Pipeline
CodeDeploy日志位置:
/var/log/aws/codedeploy-agent/codedeploy-agent.log
部署日志位置:
/opt/codedeploy-agent/deployment-root/deployment-logs/codedeploy-agent-deployments.log
CodeDeply Agent
安装方式见https://docs.aws.amazon.com/zh_cn/codedeploy/latest/userguide/codedeploy-agent-operations-install-ubuntu.html服务器上保留的副本的数量设置
/etc/codedeploy-agent/conf/codedeployagent.yml
里面的max_revisions
,默认是10,服务器总共才8G,保留不了那么多副本CodeDeploy
拉取的源码和构建后的代码都会自动存储到S3上面去,这些文件可能占用很大的存储,我暂时还不清楚其费用和自动清理的方式,网上有人说用S3的生命周期管理,可是那样不能保证至少保留N个副本官方建议将敏感的环境变量放在AWS Secrets Manager或AWS Systems Manager Parameter Store参数中
对于新版系统里面的CodeDeploy agent,它是支持Ruby3的,并且系统安装的也是Ruby3,但是有时候仍然提示当前用的是ruby2,不兼容。在这里有一个方法可以用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14!/bin/bash
This installs the CodeDeploy agent and its prerequisites on Ubuntu 22.04.
sudo apt-get update
sudo apt-get install ruby-full ruby-webrick wget -y
cd /tmp
wget https://aws-codedeploy-us-east-1.s3.us-east-1.amazonaws.com/releases/codedeploy-agent_1.3.2-1902_all.deb
mkdir codedeploy-agent_1.3.2-1902_ubuntu22
dpkg-deb -R codedeploy-agent_1.3.2-1902_all.deb codedeploy-agent_1.3.2-1902_ubuntu22
sed 's/Depends:.*/Depends:ruby3.0/' -i ./codedeploy-agent_1.3.2-1902_ubuntu22/DEBIAN/control
dpkg-deb -b codedeploy-agent_1.3.2-1902_ubuntu22/
sudo dpkg -i codedeploy-agent_1.3.2-1902_ubuntu22.deb
systemctl list-units --type=service | grep codedeploy
sudo service codedeploy-agent status另外如果ruby出现
cannot load such file -- webrick/httputil
错误,可以安装apt install ruby-webrick -y
deploy的生命周期hook: BeforeInstall、AfterInstall、AfterAllowTestTraffic、BeforeAllowTraffic、AfterAllowTraffic
需要在项目根目录添加这些文件
1 | # buildspec.yml |
以及
1 | # appspec.yml |
对应的脚本可以这样
1 | scripts/start_service.sh |
ASM(AWS Systems Manager)
Parameter Store
可以用于存储一些密码等环境变量,只有高级参数才收费,标准参数免费的,调用量极高才会收费
注意Type选择SecureString
如果要指定Role访问指定前缀的变量,可以这样设置Role的inline policy:
1
2
3
4
5
6
7
8
9
10
11{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": "ssm:GetParameters",
"Resource": "arn:aws:ssm:*:xxxxxxxxx:parameter/PRODUCTION_*"
}
]
}代码示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22const ssm = new AWS.SSM({ region: 'us-east-2'})
await ssm.getParameters({
Names: names, // 注意一次最多只能取10个,并且不能模糊搜索
WithDecryption: false
}).promise()
await ssm.describeParameters({ // 获取参数列表,但是结果是没有Value的,注意这里的IAM权限需要的是设置到ssm上,而不是parameter上,arn:aws:ssm:us-east-1:xxxxx:*而不是arn:aws:ssm:us-east-1:xxxxx:parameter/*
"Filters": [
{
"Key": "Name",
"Values": [ "HAO" ] // 这里就是模糊搜索
}
],
"MaxResults": 50, // 一次最多获取50个
}).promise()
// 更新Parameter,可以更新Type,在web是不能更新Type的
await ssm.putParameter({
Name: parameter.Name,
Type: 'SecureString',
Value: parameter.Value,
Overwrite: true,
}).promise();
Cron定时任务表达式
- 很多地方都会用到cron表达式,比如cloudwatch、ebs生命周期管理器(lifecycle)
- 和我们常规的linux的用法有点不一样,没有隔几天执行的方法,如果要实现只能在日期那里把一个月的写上
- 使用的是UTC时间
- 对于EBS的生命周期管理,最小精度只能是小时,第一位没有用,且可能发生在那个小时里面的任意一分钟
1 | 分钟 小时 日期 月 星期几 年份 |
开发
权限验证方式
- 设置环境变量
export AWS_ACCESS_KEY_ID=xxx AWS_SECRET_ACCESS_KEY=xxx
- Lambda,参考下一条tips
- 设置环境变量
如果是在aws lambda中运行,可以不需要
access key
和access id
,只需要在lambda
的配置中给角色role
分配权限即可,默认就有一个CloudWatch
的权限,有一点需要注意的是在lambda
中需要提前new instance
然后将函数转换为promise
的方式,否则函数不会被执行,很奇怪的问题1
2
3
4
5
6const AWS = require('aws-sdk');
const ec2 = new AWS.EC2({apiVersion: '2016-11-15'});
exports.handler = async () => {
const re = await ec2.describeInstances({DryRun: false}).promise();
}
APIs
1 | // 获取实例列表 |
TroubleShooting
InstanceAgent::Plugins::CodeDeployPlugin::CommandPoller: Missing credentials : 需要重启一下agent:
sudo service codedeploy-agent restart
connect EHOSTUNREACH 169.254.169.254:80: 可能的原因:
- 网络问题
- 没有设置
AWS_ACCESS_KEY_ID
和AWS_SECRET_ACCESS_KEY
环境变量
wordpress无限重定向: 可能是在aws的elb中只发了http请求到后端,但是url访问的却是https,导致wordpress搞不清楚了,可以在nginx这边加上一个fastcgi配置:
1
fastcgi_param HTTPS on;
The authorization mechanism you have provided is not supported. Please use AWS4-HMAC-SHA256: 要么手动设置access_key_id和secret_access_key两个环境变量,要么参考上文创建Role然后绑定到Ec2
Unable to find a region via the region provider chain. Must provide an explicit region in the builder or setup environment to supply a region. 原因是没有添加环境变量AWS_REGION
Lambda@Edge报错execution role must be assumable: 参考https://stackoverflow.com/questions/53796032/why-do-i-get-execution-role-must-be-assumable-error-when-trying-to-deploy-to-l/53796764#53796764的前两条回答
SequelizeConnectionError: connect ETIMEDOUT 10.0.5.64:3306: 首先应该检查VPC、subnet(是否同一网段)、AZ、安全组等配置是否正确
我的安全凭证,但是只能创建两个访问密钥,lambda函数不需要创建凭据https://docs.aws.amazon.com/zh_cn/sdk-for-javascript/v3/developer-guide/loading-node-credentials-lambda.html