在Docker中使用AWS EFS

我正在使用由Amazon提供的新弹性文件系统,在我的单个容器EB部署上。 我无法弄清楚为什么挂载的EFS不能映射到容器中。

EFS挂载在/ efs-mount-point的主机上成功执行。

提供给Dockerrun.aws.json是

{ "AWSEBDockerrunVersion": "1" "Volumes": [ { "HostDirectory": "/efs-mount-point", "ContainerDirectory": "/efs-mount-point" } ] } 

一旦开始运行,容器就会在容器中创build。 但它已映射主机目录/ efs-mount-point,而不是实际的EFS挂载点。 我不知道如何让Docker映射到挂载在/ efs-mount-point而不是主机目录的EFS卷中。

NFS卷对Docker有好处吗?

在主机EC2实例中挂载EFS卷之后,需要重新启动docker 。

这是一个例子, .ebextensions/efs.config

 commands: 01mkdir: command: "mkdir -p /efs-mount-point" 02mount: command: "mountpoint -q /efs-mount-point || mount -t nfs4 -o nfsvers=4.1 $(curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone).fs-fa35c253.efs.us-west-2.amazonaws.com:/ /efs-mount-point" 03restart: command: "service docker restart" 

EFS与AWS Beanstalk – 多容器Docker将工作。 但是很多东西都会停止工作,因为在安装EFS之后必须重新启动docker。

实例命令

在你周围search可能会发现你需要在安装EFS后执行“docker restart”。 这并不简单。 在发生自动缩放和/或部署应用程序的新版本时,您将遇到麻烦。

以下是我用于将EFS挂载到docker实例的脚本,需要执行以下步骤:

  1. 停止ECS经理。 需要60秒。
  2. 停止Docker服务
  3. 杀死剩下的docker的东西
  4. 删除networking以前的绑定。 查看问题https://github.com/docker/docker/issues/7856#issuecomment-239100381
  5. 挂载EFS
  6. 开始docker服务。
  7. 启动ECS服务
  8. 等待120秒。 使ECS进入正确的开始/ *状态。 否则,例如00enact脚本将失败。 注意这个显示是强制性的,真的很难find任何文件。

这是我的脚本:

.ebextensions/commands.config

 commands: 01stopdocker: command: "sudo stop ecs > /dev/null 2>&1 || /bin/true && sudo service docker stop" 02killallnetworkbindings: command: 'sudo killall docker > /dev/null 2>&1 || /bin/true' 03removenetworkinterface: command: "rm -f /var/lib/docker/network/files/local-kv.db" test: test -f /var/lib/docker/network/files/local-kv.db # Mount the EFS created in .ebextensions/media.config 04mount: command: "/tmp/mount-efs.sh" # On new instances, delay needs to be added because of 00task enact script. It tests for start/ but it can be various states of start... # Basically, "start ecs" takes some time to run, and it runs async - so we sleep for some time. # So basically let the ECS manager take it's time to boot before going on to enact scritps and post deploy scripts. 09restart: command: "service docker start && sudo start ecs && sleep 120s" 

装载脚本和环境variables

.ebextensions/mount-config.config

 # efs-mount.config # Copy this file to the .ebextensions folder in the root of your app source folder option_settings: aws:elasticbeanstalk:application:environment: EFS_REGION: '`{"Ref": "AWS::Region"}`' # Replace with the required mount directory EFS_MOUNT_DIR: '/efs_volume' # Use in conjunction with efs_volume.config or replace with EFS volume ID of an existing EFS volume EFS_VOLUME_ID: '`{"Ref" : "FileSystem"}`' packages: yum: nfs-utils: [] files: "/tmp/mount-efs.sh": mode: "000755" content : | #!/bin/bash EFS_REGION=$(/opt/elasticbeanstalk/bin/get-config environment | jq -r '.EFS_REGION') EFS_MOUNT_DIR=$(/opt/elasticbeanstalk/bin/get-config environment | jq -r '.EFS_MOUNT_DIR') EFS_VOLUME_ID=$(/opt/elasticbeanstalk/bin/get-config environment | jq -r '.EFS_VOLUME_ID') echo "Mounting EFS filesystem ${EFS_DNS_NAME} to directory ${EFS_MOUNT_DIR} ..." echo 'Stopping NFS ID Mapper...' service rpcidmapd status &> /dev/null if [ $? -ne 0 ] ; then echo 'rpc.idmapd is already stopped!' else service rpcidmapd stop if [ $? -ne 0 ] ; then echo 'ERROR: Failed to stop NFS ID Mapper!' exit 1 fi fi echo 'Checking if EFS mount directory exists...' if [ ! -d ${EFS_MOUNT_DIR} ]; then echo "Creating directory ${EFS_MOUNT_DIR} ..." mkdir -p ${EFS_MOUNT_DIR} if [ $? -ne 0 ]; then echo 'ERROR: Directory creation failed!' exit 1 fi chmod 777 ${EFS_MOUNT_DIR} if [ $? -ne 0 ]; then echo 'ERROR: Permission update failed!' exit 1 fi else echo "Directory ${EFS_MOUNT_DIR} already exists!" fi mountpoint -q ${EFS_MOUNT_DIR} if [ $? -ne 0 ]; then AZ=$(curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone) echo "mount -t nfs4 -o nfsvers=4.1 ${AZ}.${EFS_VOLUME_ID}.efs.${EFS_REGION}.amazonaws.com:/ ${EFS_MOUNT_DIR}" mount -t nfs4 -o nfsvers=4.1 ${AZ}.${EFS_VOLUME_ID}.efs.${EFS_REGION}.amazonaws.com:/ ${EFS_MOUNT_DIR} if [ $? -ne 0 ] ; then echo 'ERROR: Mount command failed!' exit 1 fi else echo "Directory ${EFS_MOUNT_DIR} is already a valid mountpoint!" fi echo 'EFS mount complete.' 

资源和configuration

你将不得不改变下面的option_settings。 要查找您必须在下面的option_settings下定义的VPC和子网,请查看AWS Web Console – > VPC,您必须find默认VPC ID和3个默认子网ID。 如果您的beanstalk使用自定义VPC,则必须使用这些设置。

.ebextensions/efs-volume.config

 # efs-volume.config # Copy this file to the .ebextensions folder in the root of your app source folder option_settings: aws:elasticbeanstalk:customoption: EFSVolumeName: "EB-EFS-Volume" VPCId: "vpc-xxxxxxxx" SubnetUSWest2a: "subnet-xxxxxxxx" SubnetUSWest2b: "subnet-xxxxxxxx" SubnetUSWest2c: "subnet-xxxxxxxx" Resources: FileSystem: Type: AWS::EFS::FileSystem Properties: FileSystemTags: - Key: Name Value: Fn::GetOptionSetting: {OptionName: EFSVolumeName, DefaultValue: "EB_EFS_Volume"} MountTargetSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Security group for mount target SecurityGroupIngress: - FromPort: '2049' IpProtocol: tcp SourceSecurityGroupId: Fn::GetAtt: [AWSEBSecurityGroup, GroupId] ToPort: '2049' VpcId: Fn::GetOptionSetting: {OptionName: VPCId} MountTargetUSWest2a: Type: AWS::EFS::MountTarget Properties: FileSystemId: {Ref: FileSystem} SecurityGroups: - {Ref: MountTargetSecurityGroup} SubnetId: Fn::GetOptionSetting: {OptionName: SubnetUSWest2a} MountTargetUSWest2b: Type: AWS::EFS::MountTarget Properties: FileSystemId: {Ref: FileSystem} SecurityGroups: - {Ref: MountTargetSecurityGroup} SubnetId: Fn::GetOptionSetting: {OptionName: SubnetUSWest2b} MountTargetUSWest2c: Type: AWS::EFS::MountTarget Properties: FileSystemId: {Ref: FileSystem} SecurityGroups: - {Ref: MountTargetSecurityGroup} SubnetId: Fn::GetOptionSetting: {OptionName: SubnetUSWest2c} 

资源:

  • 对于安装问题: https : //forums.aws.amazon.com/message.jspa?messageID=730288#730555
  • 对于networking端口映射问题: https : //github.com/docker/docker/issues/7856
  • 对于EFS装载脚本: https : //forums.aws.amazon.com/thread.jspa? messageID =733181

AWS提供了在弹性beanstalk上自动创build和挂载EFS的说明。 他们可以在这里find

这些说明链接到两个要configuration的configuration文件,并放在部署包的.ebextensions文件夹中。

  1. 存储EFS-createfilesystem.config
  2. 存储EFS-mountfilesystem.config

文件storage-efs-mountfilesystem.config需要进一步修改以使用Docker容器。 添加以下命令:

 02_restart: command: "service docker restart" 

而对于多容器环境,弹性容器服务也必须重新启动(当docker重新启动时,它被杀死):

 03_start_eb: command: | start ecs start eb-docker-events sleep 120 test: sh -c "[ -f /etc/init/ecs.conf ]" 

所以storage-efs-mountfilesystem.config的完整命令部分是:

 commands: 01_mount: command: "/tmp/mount-efs.sh" 02_restart: command: "service docker restart" 03_start_eb: command: | start ecs start eb-docker-events sleep 120 test: sh -c "[ -f /etc/init/ecs.conf ]" 

之所以不起作用,是因为在运行.ebextensions中的命令之前,docker守护程序是由EC2实例启动的。 启动顺序是:

  1. 启动docker守护进程
  2. 在多容器泊坞窗环境中,启动弹性容器服务代理
  3. 在.ebextensions中运行命令
  4. 运行容器应用程序

在第一步,docker守护进程提供给容器的文件系统视图是固定的。 因此,在步骤3中进行的主机文件系统中的更改不会反映在容器的视图中。

一个奇怪的结果是容器在主机上安装文件系统之前看到一个安装点。 主机看到已挂载的文件系统。 因此,容器写入的文件将被写入挂载的目录下的主机目录,而不是挂载的文件系统。 卸载EC2主机上的文件系统将显示写入安装目录的容器文件。