Amazon Elastic File System (AWS EFS) представляет собой гибкое хранилище данных для Amazon EC2.
EFS автоматически меняет размер хранилища, когда вы добавляете и/или удаляете данные.
EFS поддерживает протокол NFS v4.1 (Network File System), и предоставляет возможность одновременного доступа нескольким интсансам EC2.
Оплата EFS зависит только от размера хранимых в неё данных. Подробнее о ценах – тут>>>.
EFS разработан для поддержания высокой скорости доступа к данным, и может менять IOPS в зависимости от размера файловой системы и количества обращений к ней.
- вы можете одновременно смонтировать EFS-шару к интансам только в одной VPC (но при этом – к любому кол-ву машин)
- файловая система и VPC должны находиться в одном и том же регионе
Для доступа к EFS – вы должны создать т.н. mount target в VPC, после чего она монтируется к серверу.
Кроме того – вы можете смонтировать EFS к вашим собственным серверам в другом датацентре, если они подключены к VPC с помощью AWS Direct Connect.
Подробнее об EFS – в документации>>>.
Содержание
Создание окружения
Далее мы создадим 2 EC2 интанса в разных подсетях одной VPC, добавим NFS-шару, и запустим Docker-контейнеры, которые будут использовать данные из этой шары – простой NGINX и тестовый документ.
Создание VPC
Создаём VPC:
$ aws ec2 create-vpc --cidr-block 11.0.0.0/16 { "Vpc": { "VpcId": "vpc-eb38138f", "State": "pending", "CidrBlock": "11.0.0.0/16", "DhcpOptionsId": "dopt-8645a9e3", "Tags": [], "InstanceTenancy": "default", "IsDefault": false, "Ipv6CidrBlockAssociationSet": [] } }
Добавляем теги:
$ aws ec2 create-tags --resources vpc-eb38138f --tags Key=Name,Value=rtfm_efs
Для работы EFS требуется включить DNS host names (хотя можно монтировать через IP).
Обновлем атрибуты VPC:
$ aws ec2 modify-vpc-attribute --vpc-id vpc-eb38138f --enable-dns-support "{\"Value\":true}" $ aws ec2 modify-vpc-attribute --vpc-id vpc-eb38138f --enable-dns-hostnames "{\"Value\":true}"
Подсети
Создаём две посети:
$ aws ec2 create-subnet --vpc-id vpc-eb38138f --cidr-block 11.0.1.0/24 { "Subnet": { "SubnetId": "subnet-9c83baf8", "State": "pending", "VpcId": "vpc-eb38138f", "CidrBlock": "11.0.1.0/24", "Ipv6CidrBlockAssociationSet": [], "AssignIpv6AddressOnCreation": false, "AvailableIpAddressCount": 251, "AvailabilityZone": "eu-west-1c", "DefaultForAz": false, "MapPublicIpOnLaunch": false } }
Теги:
$ aws ec2 create-tags --resources subnet-9c83baf8 --tags Key=Name,Value=rtfm_efs_net_A
Первая посеть создана в:
... "AvailabilityZone": "eu-west-1c" ...
Создаём вторую в eu-west-1a:
$ aws ec2 create-subnet --vpc-id vpc-eb38138f --cidr-block 11.0.2.0/24 --availability-zone eu-west-1a { "Subnet": { "SubnetId": "subnet-12b48864", "State": "pending", "VpcId": "vpc-eb38138f", "CidrBlock": "11.0.2.0/24", "Ipv6CidrBlockAssociationSet": [], "AssignIpv6AddressOnCreation": false, "AvailableIpAddressCount": 251, "AvailabilityZone": "eu-west-1a", "DefaultForAz": false, "MapPublicIpOnLaunch": false } }
Теги:
$ aws ec2 create-tags --resources subnet-12b48864 --tags Key=Name,Value=rtfm_efs_net_B
В security группе этой VPC – открываем доступ по портам 80 и 22:
$ aws ec2 describe-security-groups --filters Name=vpc-id,Values=vpc-eb38138f --query '[SecurityGroups[*].GroupId]' --output text sg-caf5d9ac $ aws ec2 authorize-security-group-ingress --group-id sg-caf5d9ac --protocol tcp --port 80 --cidr 0.0.0.0/0 $ aws ec2 authorize-security-group-ingress --group-id sg-caf5d9ac --protocol tcp --port 22 --cidr 0.0.0.0/0
Создаём Internet Gateway для VPC:
$ aws ec2 create-internet-gateway { "InternetGateway": { "InternetGatewayId": "igw-5d0cac39", "Attachments": [], "Tags": [] } }
Подключаем к VPC:
$ aws ec2 attach-internet-gateway --internet-gateway-id igw-5d0cac39 --vpc-id vpc-eb38138f
Находим таблицу маршрутизации этой VPC:
$ aws ec2 describe-route-tables --filters Name=vpc-id,Values=vpc-eb38138f --query '[RouteTables[*].RouteTableId]' --output text rtb-1d24e47a
Добавляем маршрут в 0.0.0.0/0 через созданный IGW:
$ aws ec2 create-route --route-table-id rtb-1d24e47a --destination-cidr-block 0.0.0.0/0 --gateway-id igw-5d0cac39 { "Return": true }
Сеть готова. Быстро проверим.
Запускаем инстанс:
$ aws ec2 run-instances --image-id ami-cbfcd2b8 --count 1 --instance-type t2.nano --key-name my-cluster --security-group-ids sg-caf5d9ac --subnet-id subnet-12b48864
Подключаем публичный IP:
$ aws ec2 allocate-address --domain vpc { "PublicIp": "34.250.70.64", "Domain": "vpc", "AllocationId": "eipalloc-dde2eab9" }
$ aws ec2 associate-address --public-ip 34.250.70.64 --instance-id i-010c8401c6e5f2374 { "AssociationId": "eipassoc-956cb3ed" }
Ждём, подключаемся, проверяем сеть:
$ ssh [email protected] -i my-cluster.pem ... ubuntu@ip-11-0-2-210:~$ ping ya.ru -c 1 PING ya.ru (93.158.134.3) 56(84) bytes of data. 64 bytes from www.yandex.ru (93.158.134.3): icmp_seq=1 ttl=45 time=62.7 ms --- ya.ru ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 62.730/62.730/62.730/0.000 ms
Готово.
Создание EFS
Следующим шагом – создадим EFS, добавим ещё одну машину в VPC и примонтируем шару к обоим интансам.
Создаём файловую систему:
$ aws efs create-file-system --creation-token rtfm_efs { "OwnerId": "264418146286", "CreationToken": "rtfm_efs", "FileSystemId": "fs-41e32788", "CreationTime": 1485946711.0, "LifeCycleState": "creating", "NumberOfMountTargets": 0, "SizeInBytes": { "Value": 0 }, "PerformanceMode": "generalPurpose" }
Добавляем теги:
$ aws efs create-tags --file-system-id fs-41e32788 --tags Key=Name,Value=rtfm_efs
Создаём две mount target – по одной в каждой из подсетей VPC:
$ aws efs create-mount-target --file-system-id fs-41e32788 --subnet-id subnet-9c83baf8 --security-groups sg-caf5d9ac { "OwnerId": "264418146286", "MountTargetId": "fsmt-097cbcc0", "FileSystemId": "fs-41e32788", "SubnetId": "subnet-9c83baf8", "LifeCycleState": "creating", "IpAddress": "11.0.1.235", "NetworkInterfaceId": "eni-7da7f501" }
$ aws efs create-mount-target --file-system-id fs-41e32788 --subnet-id subnet-12b48864 --security-groups sg-caf5d9ac { "OwnerId": "264418146286", "MountTargetId": "fsmt-0e7cbcc7", "FileSystemId": "fs-41e32788", "SubnetId": "subnet-12b48864", "LifeCycleState": "creating", "IpAddress": "11.0.2.86", "NetworkInterfaceId": "eni-35f54474" }
Пока создаются точки монтирования – запускаем второй интанс, в зоне eu-west-1с, вторая посеть:
$ aws ec2 run-instances --image-id ami-cbfcd2b8 --count 1 --instance-type t2.nano --key-name my-cluster --security-group-ids sg-caf5d9ac --subnet-id subnet-9c83baf8
Повторяем подключение EIP, и всё готово (ага) к монтированию:
$ aws ec2 allocate-address --domain vpc { "PublicIp": "34.249.197.248", "Domain": "vpc", "AllocationId": "eipalloc-b9e5eddd" }
$ aws ec2 associate-address --public-ip 34.249.197.248 --instance-id i-06b49d6e27aceef6f { "AssociationId": "eipassoc-7261be0a" }
На обоих машинах создаём каталог /efs
:
$ ssh [email protected] -i my-cluster.pem ... ubuntu@ip-11-0-2-82:~$ sudo -s root@ip-11-0-2-82:~# mkdir /efs
Проверяем состояние точек монтирования:
$ aws efs describe-mount-targets --file-system-id fs-41e32788 { "MountTargets": [ { "OwnerId": "264418146286", "MountTargetId": "fsmt-097cbcc0", "FileSystemId": "fs-41e32788", "SubnetId": "subnet-9c83baf8", "LifeCycleState": "available", "IpAddress": "11.0.1.235", "NetworkInterfaceId": "eni-7da7f501" }, { "OwnerId": "264418146286", "MountTargetId": "fsmt-0e7cbcc7", "FileSystemId": "fs-41e32788", "SubnetId": "subnet-12b48864", "LifeCycleState": "available", "IpAddress": "11.0.2.86", "NetworkInterfaceId": "eni-35f54474" } ] }
Монтируем файловую систему в /efs
:
root@ip-11-0-1-177:~# mount -t nfs4 -o nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2 fs-41e32788.efs.eu-west-1.amazonaws.com:/ /efs mount: wrong fs type, bad option, bad superblock on fs-41e32788.efs.eu-west-1.amazonaws.com:/, missing codepage or helper program, or other error (for several filesystems (e.g. nfs, cifs) you might need a /sbin/mount.<type> helper program) In some cases useful info is found in syslog - try dmesg | tail or so.
Ooops. Ответ – тут>>>. Данный AMI не имеет предустановленного NFS-клиента.
Устанавливаем nfs-common
:
# apt-get update && apt-get install nfs-common
Монтируем:
root@ip-11-0-1-177:~# mount -t nfs4 -o nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2 fs-41e32788.efs.eu-west-1.amazonaws.com:/ /efs root@ip-11-0-1-177:~# ls -al /efs/ total 8 drwxr-xr-x 2 root root 4096 Feb 1 10:58 . drwxr-xr-x 24 root root 4096 Feb 1 11:21 ..
Повторяем:
root@ip-11-0-2-210:~# mount -t nfs4 -o nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2 fs-41e32788.efs.eu-west-1.amazonaws.com:/ /efs root@ip-11-0-2-210:~# ls -la /efs/ total 8 drwxr-xr-x 2 root root 4096 Feb 1 10:58 . drwxr-xr-x 24 root root 4096 Feb 1 11:11 ..
Создаём файлы:
root@ip-11-0-1-177:~# echo $(ip a s eth0 | grep inet | head -n 1 | awk '{print $2}') > /efs/ip1.tx root@ip-11-0-2-210:~# echo $(ip a s eth0 | grep inet | head -n 1 | awk '{print $2}') > /efs/ip2.txt
Проверяем:
root@ip-11-0-2-210:~# ls -la /efs/ total 16 drwxr-xr-x 2 root root 4096 Feb 1 11:31 . drwxr-xr-x 24 root root 4096 Feb 1 11:11 .. -rw-r--r-- 1 root root 14 Feb 1 11:31 ip1.txt -rw-r--r-- 1 root root 14 Feb 1 11:31 ip2.txt root@ip-11-0-2-210:~# cat /efs/*.txt 11.0.1.177/24 11.0.2.210/24
Docker
Последний штрих – использовать расшаренные ресурсы из Docker-контейнера (для AWS ECS).
Устанавливаем Docker:
# apt-get install curl linux-image-extra-$(uname -r) linux-image-extra-virtual # apt-get install apt-transport-https ca-certificates # curl -fsSL https://yum.dockerproject.org/gpg | sudo apt-key add - # add-apt-repository "deb https://apt.dockerproject.org/repo/ ubuntu-$(lsb_release -cs) main" # apt-get update && apt-get install docker-engine
Запускаем контейнер с NGINX, пробрасываем порты 80 <=> 80, и подключаем каталог /efs
в контейнер по пути /usr/share/nginx/html
:
root@ip-11-0-2-210:~# docker run -tid -v /efs/:/usr/share/nginx/html -p 80:80 nginx e1a8eb6f1a263b3da4c6156fe8141751ce5bf757b684bc279f2c7a98b7fa0b24
Проверяем:
$ curl 34.250.70.64/ip1.txt 11.0.1.177/24 $ curl 34.250.70.64/ip2.txt 11.0.2.210/24
И на второй машине:
$ curl 34.249.197.248/ip1.txt 11.0.1.177/24 $ curl 34.249.197.248/ip2.txt 11.0.2.210/24
Готово.