在Cloud Formation管理实例中,如何用EBS/EFS在docker-compose绑定Django代码卷?
我来帮你拆解这个问题,分EFS和EBS两种场景给你具体操作步骤,毕竟这俩AWS存储在Docker Swarm里的用法差异不小:
一、用EFS(多节点共享首选)
EFS是AWS的分布式共享存储,适合Docker Swarm多节点集群,所有节点都能访问同一份Django代码,步骤如下:
通过CloudFormation创建EFS资源
在你的CloudFormation模板里定义EFS文件系统和挂载目标:Resources: DjangoEFS: Type: AWS::EFS::FileSystem Properties: PerformanceMode: generalPurpose EFSMountTarget: Type: AWS::EFS::MountTarget Properties: FileSystemId: !Ref DjangoEFS SecurityGroups: [!Ref EFSSecurityGroup] # 允许NFS 2049端口访问 SubnetId: !Ref SwarmNodeSubnet # 和Swarm节点在同一个子网安全组要开放**入站NFS(2049端口)**给Swarm节点的安全组。
在Swarm节点自动挂载EFS
在CloudFormation的EC2实例(Swarm管理/工作节点)的UserData里添加挂载命令,启动时自动挂载:#!/bin/bash mkdir -p /mnt/efs/django-code mount -t nfs4 -o nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2 ${EFS_DNS_NAME}:/ /mnt/efs/django-code # 写入fstab确保重启后自动挂载 echo "${EFS_DNS_NAME}:/ /mnt/efs/django-code nfs4 nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2 0 0" >> /etc/fstab这里的
${EFS_DNS_NAME}可以通过CloudFormation的!GetAtt DjangoEFS.DnsName传递。上传Django代码到EFS
挂载完成后,你可以通过scp把本地代码传到Swarm节点的/mnt/efs/django-code目录,或者直接在节点上git clone你的项目仓库。在docker-compose.yml中绑定卷
直接用bind挂载,把EFS的本地挂载目录映射到容器内的Django代码目录:version: '3.8' services: django-app: image: python:3.11-slim volumes: - /mnt/efs/django-code:/app # 本地EFS目录 -> 容器内代码目录 working_dir: /app command: ["python", "manage.py", "runserver", "0.0.0.0:8000"] ports: - "8000:8000"部署栈时执行
docker stack deploy -c docker-compose.yml django-stack即可,Swarm所有节点都能访问这份共享代码。
二、用EBS(单节点场景)
EBS是单AZ的块存储,只能挂载到单个EC2实例,适合单节点Swarm或不需要多节点共享代码的场景:
CloudFormation创建并附加EBS卷
在模板里定义EBS卷并附加到Swarm管理节点:Resources: DjangoEBSVolume: Type: AWS::EC2::Volume Properties: AvailabilityZone: !GetAtt SwarmManagerInstance.AvailabilityZone Size: 20 # 根据代码大小调整 VolumeType: gp3 EBSVolumeAttachment: Type: AWS::EC2::VolumeAttachment Properties: InstanceId: !Ref SwarmManagerInstance VolumeId: !Ref DjangoEBSVolume Device: /dev/xvdf格式化并挂载EBS到节点
同样在Swarm节点的UserData里添加格式化和挂载命令(第一次挂载需要格式化):#!/bin/bash mkdir -p /mnt/ebs/django-code # 检查是否已格式化,避免重复格式化 if ! blkid /dev/xvdf; then mkfs.ext4 /dev/xvdf fi mount /dev/xvdf /mnt/ebs/django-code # 写入fstab echo "/dev/xvdf /mnt/ebs/django-code ext4 defaults 0 0" >> /etc/fstab上传Django代码
把代码传到/mnt/ebs/django-code目录即可。docker-compose.yml配置(加节点约束)
因为EBS只挂载在单个节点,必须约束Swarm服务只能调度到这个节点:version: '3.8' services: django-app: image: python:3.11-slim volumes: - /mnt/ebs/django-code:/app working_dir: /app command: ["python", "manage.py", "runserver", "0.0.0.0:8000"] ports: - "8000:8000" deploy: placement: constraints: [node.hostname == swarm-manager-01] # 替换成你的节点 hostname
关键注意事项
- 权限问题:确保容器内的用户(比如
www-data或python用户)对挂载目录有读写权限,必要时在容器启动前执行chown命令。 - Swarm集群场景优先EFS:如果你的Swarm有多个工作节点,EBS无法跨节点共享代码,会导致不同节点上的容器访问到不同的代码版本,EFS是共享存储,能避免这个问题。
- CloudFormation权限:确保EC2实例的IAM角色有
elasticfilesystem:ClientMount、ec2:AttachVolume等相关权限,否则挂载会失败。
内容的提问来源于stack exchange,提问作者Naitik Shah

