在Amazon ElasticBeanstalk的Django项目中创建文件遇权限拒绝问题
我之前在Elastic Beanstalk上部署Django应用时,也碰到过完全一样的权限拒绝问题!咱们来一步步拆解原因和解决方案:
问题根源
Elastic Beanstalk上运行Django的Web服务器进程(比如WSGI进程),通常是以受限用户身份运行的(Amazon Linux 1是ec2-user,Amazon Linux 2是webapp),而默认的应用根目录/opt/python/current/app/的所有者是root或者其他高权限用户,所以这个进程没有权限在根目录下直接创建文件,就会抛出IOError: [Errno 13] Permission denied。
解决方案
给你几个靠谱的解决办法,按推荐优先级排序:
1. 使用EB默认可写的临时目录
最简单的办法是把文件写到系统临时目录/tmp/,这个目录对所有进程都开放读写权限,适合存放临时文件。修改你的代码:
input_filename = '/tmp/testing.txt' input_file = open(input_filename, "w")
注意:/tmp/里的文件会在实例重启或回收时被清空,如果需要持久化存储,别用这个方法。
2. 配置应用目录的读写权限
如果必须在应用目录下创建文件,可以通过EB的配置文件修改目录权限。在你的Django项目根目录下创建.ebextensions文件夹(如果没有的话),然后新建一个00_set_app_permissions.config文件,内容如下:
- 如果你用的是Amazon Linux 1环境:
container_commands: 01_chown_app_dir: command: "chown -R ec2-user:ec2-user /opt/python/current/app"
- 如果是Amazon Linux 2环境:
container_commands: 01_chown_app_dir: command: "chown -R webapp:webapp /opt/python/current/app"
部署这个配置文件后,EB会在容器启动时自动修改应用目录的所有者,让运行Django的进程拥有读写权限。
3. 用媒体目录或S3存储持久化文件
如果是要创建用户上传的媒体文件这类需要持久化的内容,推荐两种方式:
- 配置Django的
MEDIA_ROOT指向应用目录下的media文件夹,然后通过上面的配置文件给media目录设置权限:
# settings.py MEDIA_ROOT = os.path.join(BASE_DIR, 'media') MEDIA_URL = '/media/'
然后在.ebextensions的配置文件里加上:
container_commands: 01_create_media_dir: command: "mkdir -p /opt/python/current/app/media" 02_chown_media_dir: command: "chown -R webapp:webapp /opt/python/current/app/media" # 对应你的EB环境用户
- 更推荐的做法是把媒体文件存储到Amazon S3,因为EB的实例是临时的,一旦实例被替换,本地文件会丢失。你可以用
django-storages库来集成S3,这样所有文件操作都会直接指向S3,完全避开本地权限问题。
额外提醒
本地开发环境里你是用自己的用户运行Django,所以权限没问题,但线上EB的运行用户是受限的,一定要测试线上环境的文件操作逻辑,或者尽量避免在实例本地存储文件。
内容的提问来源于stack exchange,提问作者balgam

