소개
업로드 애플리케이션이 두 서버에서 실행됩니다. 각 서버는 로컬 디스크에 파일을 저장하므로 한 서버에서 업로드한 파일을 다른 서버에서는 찾지 못할 수 있습니다. Amazon Elastic File System(EFS)으로 두 서버에 공유 파일 접근을 제공합니다.
먼저 AWS VPC for Beginners와 AWS EC2 and EBS for Beginners를 완료하세요. 이 독립 환경은 애플리케이션, 세 호스트와 네트워크를 제공합니다. Terminal에서 AWS CLI와 SSH를 사용하고 AWS View에서 실제 응답을 비교합니다. CLI는 설정되어 있으며 개인 AWS 계정이나 이전 실습 리소스는 필요하지 않습니다. 파일 공유와 연결을 다루며 운영 환경의 성능이나 가용성은 평가하지 않습니다.
자격증 연계
| 자격증 | 시험 항목 | 실습 |
|---|---|---|
| Cloud Practitioner (CLF-C02) | Task 3.6 | EFS 공유 파일 서비스와 마운트된 파일 인터페이스를 이해하고 개별 로컬 업로드 디렉터리와 구별합니다. |

개념도입니다. 실제 식별자는 새 환경에서 확인하세요.
업로드 애플리케이션의 저장소 만들기
이 단계에서는 로컬 업로드 문제를 확인하고 공유 파일 시스템을 만듭니다.
/home/labex/project에서 작업합니다. 자격 증명을 출력하지 않고 설정된 신원을 확인하세요.
cd /home/labex/project
aws sts \
get-caller-identity
사용자 ARN은 labex-fs01-operator로 끝납니다. resources.json에는 준비된 서브넷과 애플리케이션 보안 그룹이 있습니다. 현재 환경의 실제 리소스를 사용하도록 식별자를 읽습니다.
SUBNET_ID=$(jq -r .subnet_id resources.json)
APP_GROUP_ID=$(jq -r .application_group_id resources.json)
VPC_ID=$(jq -r .vpc_id resources.json)
echo "$SUBNET_ID"
echo "$APP_GROUP_ID"
echo "$VPC_ID"
aws ec2 \
describe-instances \
--filters Name=tag:Name,Values=application-a,application-b \
--query 'Reservations[].Instances[].{Name:Tags[?Key==`Name`].Value|[0],IP:PrivateIpAddress,State:State.Name}'
먼저 로컬 저장 문제를 관찰합니다. HTTP PUT은 업로드를 저장하고 GET은 파일을 읽습니다. 다음 주소는 준비된 애플리케이션 서버에 연결됩니다.
curl -i -X PUT --data-binary 'A local upload' \
http://127.0.0.1:8081/uploads/local-example.txt
curl -i http://127.0.0.1:8082/uploads/local-example.txt
A는 201 Created, B는 404 Not Found를 반환합니다. B의 로컬 디렉터리는 다른 파일을 담고 있기 때문입니다. AWS View의 두 카드에서도 같은 파일명을 쓰고 읽을 수 있습니다.
EFS는 공유 파일 시스템입니다. 두 애플리케이션은 Network File System(NFS) 프로토콜로 같은 디렉터리와 파일에 접근합니다. 먼저 파일 시스템을 만드세요. 생성 토큰은 요청을 식별하며 Name 태그는 점검과 삭제에 도움이 됩니다. --encrypted는 서비스의 저장 시 암호화 설정을 활성화합니다. 전송 암호화는 마운트할 때 별도로 설정합니다.
FS_ID=$(aws efs \
create-file-system \
--creation-token fs01-shared-uploads \
--encrypted \
--tags Key=Name,Value=fs01-shared-uploads \
--query FileSystemId --output text)
echo "$FS_ID"
aws efs \
describe-file-systems \
--file-system-id "$FS_ID" \
--query 'FileSystems[].{ID:FileSystemId,State:LifeCycleState,Encrypted:Encrypted}'
상태가 available이 될 때까지 기다립니다. 리소스가 존재해도 애플리케이션에는 연결 가능한 마운트 대상과 실제 마운트가 필요합니다.
파일 시스템을 애플리케이션 서브넷에 연결하기
이 단계에서는 접근 가능한 NFS 연결 지점을 만들고 애플리케이션 서버로 접근을 제한합니다.
마운트 대상은 서브넷 내부의 파일 시스템 네트워크 연결 지점입니다. NFS는 TCP 2049를 사용합니다. 전용 저장소 보안 그룹을 만들고 준비된 애플리케이션 그룹에서 이 포트로 접근하도록 허용합니다. 소스 그룹 규칙은 두 서버를 포함하지만 모든 주소에 NFS를 개방하지 않습니다. 다른 그룹의 참조 서버는 계속 제외해야 합니다.
EFS_GROUP_ID=$(aws ec2 \
create-security-group \
--group-name fs01-efs-access \
--description 'NFS from the upload application servers' \
--vpc-id "$VPC_ID" \
--query GroupId --output text)
echo "$EFS_GROUP_ID"
aws ec2 \
authorize-security-group-ingress \
--group-id "$EFS_GROUP_ID" \
--ip-permissions "IpProtocol=tcp,FromPort=2049,ToPort=2049,UserIdGroupPairs=[{GroupId=$APP_GROUP_ID}]"
준비된 서브넷에 마운트 대상을 만들고 새 그룹을 연결합니다.
MOUNT_TARGET_ID=$(aws efs \
create-mount-target \
--file-system-id "$FS_ID" \
--subnet-id "$SUBNET_ID" \
--security-groups "$EFS_GROUP_ID" \
--query MountTargetId --output text)
echo "$MOUNT_TARGET_ID"
aws efs \
describe-mount-targets \
--file-system-id "$FS_ID" \
--query 'MountTargets[].{ID:MountTargetId,IP:IpAddress,State:LifeCycleState,AZ:AvailabilityZoneName}'
aws efs \
describe-mount-target-security-groups \
--mount-target-id "$MOUNT_TARGET_ID"
마운트 대상이 available이 될 때까지 기다립니다. 이 환경의 두 애플리케이션은 같은 가용 영역에 있으므로 대상 하나를 사용합니다. 운영 환경에서는 클라이언트가 있는 각 가용 영역에 대상을 계획하세요.
두 애플리케이션을 마운트하고 공유 파일 확인하기
이 단계에서는 두 애플리케이션을 EFS에 연결하고 양방향 업로드를 테스트합니다.
ssh_config는 각 호스트로 연결합니다. 마운트 지점은 원격 파일 시스템에 접근하는 로컬 디렉터리입니다. 두 호스트에 /srv/shared를 만들고 EFS 루트를 마운트합니다.
ssh -F ssh_config application-a \
"sudo mkdir -p /srv/shared && sudo mount -t efs -o tls,stunnel,lookupcache=positive ${FS_ID}:/ /srv/shared"
ssh -F ssh_config application-b \
"sudo mkdir -p /srv/shared && sudo mount -t efs -o tls,stunnel,lookupcache=positive ${FS_ID}:/ /srv/shared"
lookupcache=positive는 다른 애플리케이션이 새 파일을 만들면 이전에 없던 파일명을 서버에 다시 조회하게 합니다. 짧은 실습에서 새 업로드를 바로 확인할 수 있습니다. 운영 환경의 캐시 변경은 성능을 별도로 평가해야 합니다. Linux NFS 디렉터리 캐시 옵션을 참고하세요.
-t efs는 공식 마운트 도우미를 선택하고 tls는 연결을 암호화하며 stunnel은 지원되는 TLS 전송 방식을 선택합니다. ${FS_ID}:/는 파일 시스템 루트입니다. 필요한 클라이언트 도구는 준비되어 있습니다.
새 디렉터리는 처음에는 root 소유입니다. 애플리케이션의 labex 사용자용 업로드 하위 디렉터리를 만들고 두 애플리케이션이 사용하도록 설정합니다.
ssh -F ssh_config application-a \
'sudo mkdir -p /srv/shared/uploads && sudo chown labex:labex /srv/shared/uploads'
ssh -F ssh_config application-a \
'printf "{\"upload_directory\":\"/srv/shared/uploads\"}\n" | sudo tee /etc/uploads-app/config.json'
ssh -F ssh_config application-b \
'printf "{\"upload_directory\":\"/srv/shared/uploads\"}\n" | sudo tee /etc/uploads-app/config.json'
애플리케이션은 요청마다 설정을 읽으므로 재시작하지 않아도 됩니다. 실제 마운트를 확인하세요.
ssh -F ssh_config application-a 'findmnt -t nfs4 /srv/shared'
ssh -F ssh_config application-b 'findmnt -t nfs4 /srv/shared'
두 호스트 모두 /srv/shared에서 NFS 4 마운트를 표시합니다. TLS에서는 도우미가 로컬 암호화 터널로 NFS를 전달하므로 커널의 소스가 127.0.0.1:/로 보일 수 있습니다.
A에서 업로드한 다음 B에서 읽습니다.
curl -i -X PUT --data-binary 'Shared upload version 1' \
http://127.0.0.1:8081/uploads/shared.txt
curl -i http://127.0.0.1:8082/uploads/shared.txt
B는 200 OK와 Shared upload version 1을 반환합니다. B에서 업데이트하고 A에서 읽어 반대 방향도 확인합니다.
curl -i -X PUT --data-binary 'Shared upload version 2' \
http://127.0.0.1:8082/uploads/shared.txt
curl -i http://127.0.0.1:8081/uploads/shared.txt
ssh -F ssh_config application-a 'stat -c "%i %u:%g" /srv/shared/uploads/shared.txt'
ssh -F ssh_config application-b 'stat -c "%i %u:%g" /srv/shared/uploads/shared.txt'
두 애플리케이션은 버전 2를 읽고 stat는 같은 inode를 보여 줍니다. 독립된 마운트가 동일한 EFS 파일을 제공하며 로컬 디렉터리를 복사하거나 동기화한 결과가 아닙니다. AWS View에서도 비교하세요.

두 애플리케이션이 같은 업데이트된 파일을 읽습니다. 식별자는 환경마다 다릅니다.
마운트 해제와 자신의 저장소 삭제하기
이 단계에서는 공유 디렉터리 사용을 중지하고 직접 만든 저장소만 삭제합니다.
연결 지점을 삭제하기 전에 각 애플리케이션을 준비된 로컬 디렉터리로 복원하고 EFS 마운트를 해제합니다.
ssh -F ssh_config application-a \
'printf "{\"upload_directory\":\"/srv/uploads\"}\n" | sudo tee /etc/uploads-app/config.json'
ssh -F ssh_config application-b \
'printf "{\"upload_directory\":\"/srv/uploads\"}\n" | sudo tee /etc/uploads-app/config.json'
ssh -F ssh_config application-a 'sudo umount /srv/shared'
ssh -F ssh_config application-b 'sudo umount /srv/shared'
umount가 사용 중이라고 하면 /srv/shared를 사용하는 셸에서 나와 다시 시도하세요. 마운트가 없어졌는지 확인합니다.
ssh -F ssh_config application-a 'findmnt -t nfs4'
ssh -F ssh_config application-b 'findmnt -t nfs4'
NFS 마운트가 남아 있지 않아야 합니다. 일치 항목이 없는 findmnt는 상태 1을 반환하며 여기서는 예상된 결과입니다.
마운트 대상, 파일 시스템, 자신의 전용 저장소 보안 그룹 순서로 삭제합니다.
aws efs \
delete-mount-target --mount-target-id "$MOUNT_TARGET_ID"
aws efs \
describe-mount-targets --file-system-id "$FS_ID"
MountTargets가 빈 목록이 될 때까지 기다린 후 계속합니다.
aws efs \
delete-file-system --file-system-id "$FS_ID"
aws ec2 \
delete-security-group --group-id "$EFS_GROUP_ID"
aws efs \
describe-file-systems \
--query 'FileSystems[?Name==`fs01-shared-uploads`].FileSystemId'
aws ec2 \
describe-security-groups \
--filters Name=group-name,Values=fs01-efs-access \
--query 'SecurityGroups[].GroupId'
두 조회는 빈 목록을 반환합니다. 성공한 권한 있는 조회만 삭제를 증명합니다. 연결이나 인증 오류는 삭제 증거가 아닙니다. 준비된 서버, 기존 그룹과 서브넷은 남겨 둡니다.
단계 검사를 실행하여 저장소 삭제와 준비된 리소스 보존을 확인하세요. 이후 실습도 각각 독립된 새 환경에서 시작합니다.
요약
마운트 대상, 제한된 NFS 접근, TLS 마운트로 두 애플리케이션을 같은 EFS 파일 시스템에 연결했습니다. 양방향 업로드와 동일한 파일 식별자로 실제 공유를 확인했습니다. 이후 로컬 저장소로 복원하고 마운트를 해제한 뒤 종속성 순서로 자신의 리소스를 삭제했습니다.
공유 파일 시스템이 애플리케이션 디렉터리나 POSIX 신원을 자동으로 분리하지는 않습니다. 다음 실습에서는 EFS 액세스 포인트로 이 경계를 설정합니다.
자세한 내용은 AWS 공식 문서를 참고하세요: EFS 마운트 도우미 및 TLS 전송; 클라이언트 및 마운트 대상 네트워크 규칙.



