我之前在折腾无服务器应用的时候,第一次接触AWS SAM就被它的安装流程折腾了一晚上。Ubuntu环境、Python版本、Docker依赖、权限配置,看起来都是小问题,叠在一起却能逼疯人。这篇东西就把我从零安装AWS SAM的完整过程整理出来,包括版本选型、依赖处理、本地调试、部署流程和常见问题排查,照着走一遍就能把环境跑起来,避免你重复踩坑。
如果你第一次听说SAM,我先用一句话说清楚它是什么:AWS SAM(Serverless Application Model)是AWS官方提供的无服务器应用模型,用一套简化后的模板语法描述Lambda函数、API Gateway、DynamoDB这些资源,让开发者可以用接近本地开发的方式去编写、调试和部署无服务器应用。简单理解,它就是CloudFormation的“化简版”,专门为Lambda这类事件驱动场景优化。在Ubuntu上把它装好,你的开发机才算真正具备无服务器应用的完整开发能力。
1. 安装前准备:Ubuntu环境与依赖梳理
1.1 为什么先确认系统版本和架构
很多人上来就执行安装命令,结果装完一跑就报错,然后开始怀疑人生。其实问题多半出在系统版本和CPU架构不匹配上。AWS SAM CLI的安装包区分x86_64和arm64,Ubuntu系统也有20.04、22.04、24.04等不同版本。版本差距影响Python版本和依赖库的兼容性,架构不匹配则直接决定你该下载哪个安装包。
先执行这两条命令,摸清楚自己的底子:
bash复制lsb_release -a
uname -m
lsb_release -a查看系统版本,uname -m查看CPU架构。绝大多数PC和服务器是x86_64,树莓派或部分ARM云服务器会输出aarch64。下载时对应选择x86_64或arm64的包,这一步错了后面全是坑。我遇到过有人拿arm64的笔记本下了x86_64的SAM CLI包,安装倒是没报错,真正执行sam init的时候直接提示无法执行二进制文件,排查半天才发现是架构问题。
系统版本方面,Ubuntu 20.04及以上带Python 3.8+,完全满足SAM CLI的要求。如果你还在用18.04这种老版本,建议先升级系统或者用pyenv管理Python版本,别在旧版系统上死磕。
1.2 安装Python与pip,版本锁定别贪新
SAM CLI本身是用Python编写的工具,虽然现在官方提供了独立的二进制发行包,系统里依然需要一个可用的Python环境来支撑构建流程和插件机制。我这里说的是推荐方案:直接用官方二进制包安装SAM CLI,但Python的pip还是要在系统里备好,因为后续你可能需要安装一些辅助工具。
bash复制sudo apt update
sudo apt install python3 python3-pip -y
python3 --version
pip3 --version
执行完确认Python版本在3.7以上即可。这里我不建议你为了追求“最新”去装Python 3.12或者3.13之类,因为AWS SAM在构建Node.js或Python运行时环境的镜像时,对系统Python版本并没有硬性要求,但pip版本过新反而可能在某些情况下跟系统包管理器冲突。稳妥起见,系统自带版本够用就行。
有一个细节需要注意:Ubuntu 22.04默认有python3命令,但pip3可能没有随python3一起安装。如果提示找不到pip3,手动执行sudo apt install python3-pip就行。安装完之后,我不建议直接sudo pip3 install全局装东西,最好用pip3 install --user把工具装在用户目录下,避免污染系统环境。这个习惯能帮你省掉很多版本冲突的麻烦。
1.3 Docker是绕不开的依赖,别偷懒
SAM CLI本地调试的核心机制是通过Docker拉起一个Lambda运行时的模拟环境,所以Docker不是可选项,是必选项。如果只想写模板不调试,那可以不装;但只要你打算用sam local invoke或sam local start-api,Docker就必须先跑起来。
安装Docker的方式很多,Ubuntu上最简单的就是直接装发行版自带的docker.io包:
bash复制sudo apt install docker.io -y
sudo systemctl start docker
sudo systemctl enable docker
docker --version
装完之后把当前用户加入docker组,这样不用每次敲sudo:
bash复制sudo usermod -aG docker $USER
newgrp docker
注意,执行完usermod之后当前终端要执行newgrp docker重新加载用户组,或者干脆注销重新登录。我早期就是没做这一步,直接去跑sam local invoke,白白为权限问题折腾了半小时。如果你不想用docker.io,也可以按Docker官方文档添加apt源安装Docker Engine,但那种方式在Ubuntu上需要额外配置源和GPG密钥,对新手来说必要性不大。
Docker版本方面,官方源里的版本通常不会太老,足够支撑SAM CLI的运行。安装完成后用docker run hello-world验证一下能否正常拉取镜像和运行容器,这一步过了后面基本就顺了。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. AWS CLI与SAM CLI安装实战
2.1 AWS CLI的安装方式与选择
SAM CLI和AWS服务打交道时,底层要调用AWS CLI的能力来处理认证和API请求。所以顺序是先把AWS CLI装好,再装SAM CLI。AWS CLI现在有v1和v2两个大版本,v2是官方推荐的,性能更好、安装更干净、更新也方便。v1是pip包的方式安装,混在Python全局环境里,容易跟其他包互相影响,我强烈建议直接用v2。
AWS CLI v2的官方推荐安装方式是通过zip包解压安装:
bash复制curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install
执行前确认系统里装了unzip,没有的话先sudo apt install unzip。如果是arm64架构,把下载链接中的x86_64替换成aarch64即可。官方也提供了apt源安装方式,但需要额外添加AWS的apt源,步骤稍微多点,好处是后续apt update时能自动升级。我个人更喜欢zip包的方式,因为安装路径清晰,卸载也干净,直接删掉/usr/local/aws-cli和/usr/local/bin/aws两个路径就行。
安装完成后执行aws --version验证,应该能看到类似aws-cli/2.17.0 Python/3.11.8 Linux/5.15.0这样的输出。
有人会问,为什么不能用apt install awscli?能用,但apt里的版本长期停留在v1,而且版本号滞后得厉害。v1和v2在命令输出格式和某些参数上都有差异,SAM CLI有些功能依赖v2的特性,统一用v2省心。
2.2 SAM CLI安装步骤详解
AWS SAM CLI同样提供了独立的zip安装包,从GitHub的release页面下载对应架构的包即可。这里我直接给x86_64的安装命令:
bash复制wget https://github.com/aws/aws-sam-cli/releases/latest/download/aws-sam-cli-linux-x86_64.zip
unzip aws-sam-cli-linux-x86_64.zip -d sam-installation
sudo ./sam-installation/install
这个过程会把SAM CLI安装到/usr/local/bin/sam。安装完执行sam --version验证,输出类似SAM CLI, version 1.122.0就说明成功了。
这里有几个细节值得强调。第一,下载链接使用latest/download会自动重定向到最新release,省得去GitHub页面手动找版本号。第二,整个安装过程对Python没有额外系统级依赖,因为二进制包内部已经打包好了运行时。第三,安装路径是/usr/local/bin,这个是用户级系统目录,所有用户都能直接执行,不用额外配置PATH。
如果下载慢,可以试试用wget --continue断点续传,或者直接在浏览器里下载zip包再传到服务器上。现实中很多问题不是安装步骤不对,而是网络中断导致zip包解压失败,装到一半报错。解压前可以用unzip -t检查压缩包完整性,这一步能排除大半“装不上”的伪故障。
2.3 配置AWS凭据,最小权限原则
装完CLI,下一步是配置凭据。执行aws configure,交互式输入Access Key ID、Secret Access Key、默认区域(比如us-east-1)和输出格式(json):
bash复制aws configure
这是最直接的方式,配置会写到~/.aws/credentials和~/.aws/config。但我建议你至少在IAM里创建一个专用用户,只给必要的权限,别用根用户的密钥。无服务器应用部署至少需要IAM、Lambda、CloudFormation、S3、API Gateway等服务的权限,具体可以从AdministratorAccess这个托管策略开始,等熟悉了再收敛到自定义策略。
另外有个安全细节:凭据文件默认是明文存储的,确保~/.aws/credentials的文件权限是600。如果你在多台机器上工作,用aws configure --profile dev这种方式管理不同环境的凭据会更清爽。SAM CLI支持--profile参数,部署时指定profile就行,不用反复改配置文件。
配置完可以用aws sts get-caller-identity检查身份是否生效,这条命令会返回账号ID和当前IAM用户信息,是验证凭据最快的方式。
3. 创建首个SAM应用,走通初始化流程
3.1 sam init初始化项目,模板选择的心得
安装配置都就绪后,用sam init创建第一个项目。这个命令是交互式的,会先问你要不要用快速启动模板还是自定义模板,这里选1用官方模板,然后选择运行时(Node.js 18.x、Python 3.11等),最后选择包类型和基础项目名称。
bash复制sam init
按提示选择示例模板后,SAM CLI会在当前目录创建出一个标准的无服务器项目结构。以Python为例,结构大概是:
code复制sam-app/
├── events/
│ └── event.json
├── hello_world/
│ ├── __init__.py
│ ├── app.py
│ └── requirements.txt
├── template.yaml
├── README.md
├── .gitignore
└── .aws-sam/
template.yaml是SAM的核心文件,所有资源都在这份模板里声明。hello_world/目录放函数代码。events/目录放测试事件样本。.aws-sam/是构建时的临时目录。第一次看到这个结构的人很容易懵,其实它遵循的是“基础设施即代码”的思路,代码和资源定义放一起,部署时一起打包交给CloudFormation处理。
打开template.yaml,你会看到类似这样的内容:
yaml复制AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Resources:
HelloWorldFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: hello_world/
Handler: app.lambda_handler
Runtime: python3.11
这段模版声明了一个Lambda函数资源,CodeUri指向函数代码目录,Handler指定入口函数,Runtime指定运行语言。这里不用看得太深,先跑通流程,后面再逐渐增加API Gateway等资源。
3.2 sam build构建,理解打包逻辑
项目初始化完成,执行sam build构建。这个命令会读取template.yaml,把每个函数的代码和依赖打包到.aws-sam目录,生成一个构建后的模板。
bash复制sam build
以Python函数为例,sam build会读取requirements.txt,把依赖安装到.aws-sam/build/HelloWorldFunction/目录下。这个过程是在本地做的,所以需要网络访问PyPI。如果你在构建时遇到网络问题,可以试试配置国内pip镜像,在~/.pip/pip.conf里加上:
ini复制[global]
index-url = https://mirrors.aliyun.com/pypi/simple/
构建完成后.aws-sam目录下会出现完整的部署产物。官方文档说得很清楚,sam build本质上是优化打包流程,让本地调试和云端部署用同一套构建产物,避免“本地能跑、线上挂掉”的尴尬。
3.3 sam local start-api本地调试
构建完就能本地调试了。sam local start-api会在本地启动一个模拟API Gateway的服务,默认监听3000端口:
bash复制sam local start-api
启动后访问http://127.0.0.1:3000/hello,就能触发HelloWorld函数的本地调用。这个过程依赖Docker,SAM CLI会拉取对应运行时(比如python3.11)的Lambda模拟镜像,在容器里执行你的函数代码。
我第一次跑通的时候还挺意外的,它真的是在本地完整模拟了Lambda的执行环境,包括运行环境变量、事件结构、日志输出格式。这对于迭代调试联调太有用了,不用每次改代码都跑去云端部署一遍,本地改完直接刷新就能看到效果。
sam local invoke是另一种更直接的调试方式,它只调用一次函数并传入事件数据,适合测试单个函数的逻辑:
bash复制sam local invoke HelloWorldFunction --event events/event.json
events/event.json里存放的是模拟的Lambda事件数据,比如API Gateway请求、S3事件通知。调试时可以根据业务场景修改事件内容,模拟不同类型的触发源。
4. 部署到AWS,从模板到真实环境
4.1 sam deploy --guided交互式部署
本地验证通过后,真正部署到云端。SAM CLI的部署命令是sam deploy --guided,它会引导你完成整个部署配置:
bash复制sam deploy --guided
交互过程中要确认几个参数。第一个是堆栈名称,比如sam-app,CloudFormation会以这个名称创建一个堆栈来管理所有资源。第二个是部署区域,选择离你业务最近的区域。第三个是确认SAM模板中声明的资源是否有IAM权限变更,这里输入y确认。第四个是保存部署配置到samconfig.toml,方便后续直接sam deploy复用参数。
期间还会询问是否允许SAM CLI为你创建S3 bucket来存放构建产物。选y让它自动创建即可,这是SAM部署的标准路径,先把代码上传到S3,再通过CloudFormation创建或更新资源。
sam deploy --guided首次部署比较慢,因为要创建一堆资源。部署完成后,终端会输出API Gateway的Endpoint地址,类似https://xxxxxxxxxx.execute-api.us-east-1.amazonaws.com/Prod/hello/。用浏览器或curl访问这个地址,能看到函数的真实响应,这就真正跑通了从本地到云端的完整流程。
4.2 部署后的资源管理与更新
部署完成后,登录AWS管理控制台,在CloudFormation页面能看到名为sam-app的堆栈。堆栈的资源列表里包括了Lambda函数、API Gateway、IAM角色等所有资源。这里有个重要的点:后续更新代码和资源定义,只需要改完再执行:
bash复制sam build
sam deploy
sam deploy会对比本地模板和线上堆栈的差异,只更新变化的部分。这个增量更新机制比直接操作控制台灵活得多,也是基础设施即代码的核心价值。
如果不需要这个环境了,用sam delete命令清理全部资源:
bash复制sam delete --stack-name sam-app
它会把CloudFormation堆栈连同关联的S3 bucket、Lambda函数全部删除,避免产生不必要的费用。我给团队做培训时发现,很多人会忽略清理这一步,无服务器应用虽然单价低,但长期闲置也会产生成本。
4.3 SAM模板进阶:加入API Gateway和DynamoDB
跑通最简单的Hello World之后,值得再进一步理解SAM模板的扩展方式。以API Gateway为例,在template.yaml里给函数加一个Events属性:
yaml复制Resources:
HelloWorldFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: hello_world/
Handler: app.lambda_handler
Runtime: python3.11
Events:
HelloWorldApi:
Type: Api
Properties:
Path: /hello
Method: get
这段配置声明了一个GET /hello接口,SAM会自动创建API Gateway,并把请求路由到Lambda函数。写到这里就能体会到SAM对比CloudFormation的优势:CloudFormation写一套API Gateway配置至少要三四十行,SAM用几行就描述清楚了。
如果需要持久化数据,可以加DynamoDB表:
yaml复制 SampleTable:
Type: AWS::Serverless::SimpleTable
然后在函数环境变量里配置表名,通过boto3(Python的AWS SDK)读写数据。这些扩展示例说明了一个核心思想:SAM模板的语法是声明式的,你描述最终状态,剩下的编排由框架完成。
5. 常见问题与排查技巧实录
5.1 Docker相关报错排查
我实际使用中遇到最多的问题都出在Docker上。典型报错一是Cannot connect to the Docker daemon,说明Docker服务没启动,执行sudo systemctl start docker即可。
典型报错二是docker: permission denied,这说明当前用户不在docker组里。按前面说的执行sudo usermod -aG docker $USER && newgrp docker解决。如果还不行,检查一下是否加入了错误的组名——有的系统docker组名可能是docker-root,在极少见的情况下需要自己创建。
典型报错三是Error: Docker is required for local invocation,这说明SAM CLI检测不到Docker。除了确认服务在运行,还要确认docker ps这条命令能不能正常执行。SAM CLI是通过Docker socket来检测的,如果你用的是Docker Desktop,要确保它是启动状态。
5.2 凭据和权限问题排查
另一个高频问题是部署时报Unable to locate credentials。这说明SAM CLI找不到AWS凭据。按顺序排查:先执行aws sts get-caller-identity看CLI能不能正常识别身份;如果这个命令报错,就是aws configure的凭据没配好;如果这个命令正常但sam deploy报错,检查是不是用了--profile参数指向了不存在的配置。
权限不足的报错也常见,比如AccessDeniedException。这时候要看IAM策略是否覆盖了SAM部署所需的所有服务。最直接的排查方式是缩小范围,先在IAM里给这个用户临时绑定AdministratorAccess,部署通了再逐项收紧权限。这个方法论很重要:先把链路跑通,再优化安全策略,而不是一开始就追求最严格的权限配置。
5.3 Python与依赖版本冲突
SAM CLI运行时和函数代码的Python环境是两回事。SAM CLI使用自带的Python运行时,不受系统Python版本影响。但函数代码的依赖安装依赖pip和系统的Python环境,所以如果你在sam build时遇到依赖安装失败,多半是pip版本和Python版本不匹配。
遇到这类问题,我的处理顺序是:先升级pip,pip3 install --upgrade pip;再清掉构建缓存,rm -rf .aws-sam,重新sam build。多数情况下这样能解决。如果还不行,检查requirements.txt里的包版本是否存在冲突,比如某些包对Python版本有要求。
另外提醒一句,如果系统里同时存在Python 3.8和Python 3.10,别让pip装混了。用python3 -m pip代替裸pip3,可以确保用的是同一个解释器。这个技巧治好了我多年的“依赖装到了别的Python里”的毛病。
5.4 版本过旧与升级策略
AWS SAM CLI更新频率不算慢,老版本在几个月后可能会因为API变化或者Docker镜像更新出现各种诡异问题。如果你遇到sam build或sam deploy报一些“看不懂”的错误,先检查版本是不是过旧:
bash复制sam --version
升级方式是把新版zip包下载下来,直接重新跑一遍安装脚本,它会覆盖旧版本。SAM CLI官方没有提供自动更新命令,这点确实不太方便。我的习惯是每隔一两个月主动检查一次GitHub release,看到大版本变动就升级,避免项目做到一半被CLI版本坑到。
5.5 网络相关问题
国内网络环境下,SAM CLI下载Docker镜像可能非常慢,甚至超时。Lambda运行时的模拟镜像名形如public.ecr.aws/lambda/python:3.11,拉取地址是Amazon ECR Public。如果拉取超时,可以试试配置Docker的镜像加速器,在/etc/docker/daemon.json里配置:
json复制{
"registry-mirrors": ["https://docker.mirrors.ustc.edu.cn"]
}
配置完重启Docker服务:sudo systemctl restart docker。这个镜像加速器对ECR Public有一定加速效果。如果拉取依然失败,最稳妥的做法是确认网络能正常访问Docker Hub和ECR后重试。这个问题没有万能解法,但多试几次或者换个网络环境通常能解决。
6. 我的一些实操心得
用了大半年AWS SAM,最大的感受是:无服务器应用开发的体验门槛被这个工具大幅拉低了。以前写Lambda函数,要自己在控制台创建函数、配置触发器、设置角色权限,改一版代码要经历上传、配置、测试三个环节。现在本地一套SAM环境,模板声明、代码编写、本地调试、一键部署,链条完整且顺畅。
有几个越用越好用的习惯分享给大家。一是坚持用sam build后的构建产物做本地调试和部署,不要直接用源码目录,这样保证两边环境一致。二是把samconfig.toml纳入版本管理,团队其他人clone代码后直接sam deploy就能复用相同的部署参数。三是时刻留意CloudFormation堆栈里的资源变化,SAM虽然简化了声明方式,但最后产生的还是标准的云端资源,该收费的依然收费。
最后一个建议,不要一上来就往template.yaml里堆资源。先跑通一个最小的HelloWorld,理解构建、部署、清理的完整生命周期,再逐步往上加API Gateway、DynamoDB、SNS这些组件。基础链路通畅了,后面的扩展就是查文档的事。
