Perl 개발자에게는 CPAN(Comprehensive Perl Archive Network)이라는 훌륭한 자원이 있다. Amazon에도 S3(Simple Storage Service)라는 훌륭한 자원이 있다. CPAN에 공식적인 Amazon S3 Perl 라이브러리("S3"라고 함)가 있음에도 S3에 대해 이야기하려면 최소한 5 - 6개의 모듈(일부는 완전히 독립적이지 않음)을 언급해야 한다. 이는 칠레 요리 경연대회에 200명이 출전할 것으로 예상했는데 2,000명이 나타난 것과 같다.
하지만 요리 경연대회 다음 날인 지금은 대걸레와 양동이로 청소를 하면서 최고의 비법을 함께 나누고 있다. 이러한 모듈과 도구는 CPAN에 있으며 무료로 사용할 수 있고 지금 바로 사용할 수 있다. 필자가 추천하는 세 가지 비법은 Net::Amazon::S3, Amazon::S3 및 SOAP::Amazon::S3라는 세 가지 모듈에 있다.
developerWorks 일련의 Cultured Perl: Perl and the Amazon cloud 기사에서 S3의 장단점에 대한 의견을 살펴보자. 여기서는 이에 대해 다시 논의할 필요가 없지만 간단한 요약을 제공한다.
S3는 Amazon에서 제공하고 관리하는 스토리지 서비스이다. Amazon은 사용자에게 액세스 요금을 부과하므로 사용자는 서버, 백업, 지리적 대역폭 가용성 및 분포 등에 대해 걱정하지 않아도 된다. 따라서 S3는 비용에 비해 편리하며 비즈니스 또는 개인적인 용도에 적합한지 여부는 사용자만 결정할 수 있다.
S3 데이터는 버킷(도메인 이름과 대충 연결됨)과 이러한 버킷에 있는 데이터 항목으로 구성된다. 업로드 시 MIME 유형을 포함하는 것도 중요하다. 이를 포함하지 않으면 원시 바이너리 데이터가 발생하는데 이 데이터는 특히 이미지의 경우 적합하지 않다. MIME 유형과 기타 메타데이터는 일단 작성된 후에는 변경할 수 없으며 항목을 삭제한 후 다시 작성해야 한다.
자세히 살펴보기 전에 이 기사는 중급 레벨의 Perl 프로그래머를 대상으로 작성되었다는 것을 염두에 둔다. 이 기사에서는 기본적인 Perl 기술에 대해서는 자세히 설명하지 않는다. Amazon의 S3가 무엇인지와 CPAN 모듈을 설치하는 방법도 알고 있어야 한다. 그렇지 않은 경우에는 참고자료 섹션에서 배경 지식을 얻는다.
필자는 세 가지 모듈(Net::Amazon::S3, Amazon::S3 및 SOAP::Amazon::S3)을 사용하여 다음과 같이 일련의 기본적인 S3 조작을 수행하고 소스 코드를 표시하는 방법에 대해 설명한다.
- 버킷 나열, 작성 및 삭제
- 버킷에 있는 항목 나열, 작성, 검색 및 삭제
- 항목의 메타데이터 가져오기
모듈 사이에서 태스크의 경쟁력을 유지하기 위해 필자는 동일한 명령행 옵션 및 일반 구조를 재사용했다.
Net::Amazon::S3 모듈은 잘 알려진 모듈이자 지원도 잘 되고 포괄적이다. 이 모듈에 대해 익숙하다면 Moose와 같이 엉뚱한 몇 가지 선수조건이 있다.
S3 키를 환경에 S3KEY 및 S3SECRET으로
저장한다. 이 방식으로 Perl로부터 $ENV{S3KEY} 및
$ENV{S3SECRET}로 이들에 액세스할 수 있다.
이 방식으로 데이터를 파일에 저장하는 것은 비밀 값을 보호하는 매우 안전한
방법이다(S3 키가 도용된 경우에는 다른 사용자의 대역폭에 대해 요금을 지불한다는
것을 기억함).
따라서 Net::Amazon::S3가 설치된다. (Net::Amazon::S3는 "레거시 인터페이스"로 평가되기 때문에 실제로는 제안된 Net::Amazon::S3::Client 인터페이스를 사용하길 원하지만 본 기사 작성 시 Net::Amazon::S3::Client 버전 0.50에는 이의 사용을 방해한 Moose 모듈로 인한 버그가 있었다. 이러한 버그는 버전 0.51에서 수정되었고 현재 버전은 0.52이다.) 예제를 계속 진행한다. 평소대로 모든 스크립트는 다운로드 섹션에 있다.
Listing 1. net-amazon-s3.pl 예비 단계
#!/usr/bin/perl use warnings; use strict; use Data::Dumper; use Getopt::Long; use Net::Amazon::S3; use MIME::Types; my $mime = MIME::Types->new(); |
이는 디버깅을 위한 Data::Dumper를 포함한
표준 항목이다. 일반 MIME 오브젝트가 작성되며 이 오브젝트는 업로드를
위해서만 사용된다.
Listing 2. net-amazon-s3.pl 옵션, 헬퍼 및 초기 S3 연결
my %opts = (
key => $ENV{S3KEY},
secret => $ENV{S3SECRET},
separator => '/',
);
GetOptions(
\%opts,
"create|c=s",
"delete|d=s",
"list|l:s", # the parameter is optional
"keys|k",
"metadata|m",
"get=s",
"put=s",
"separator=s",
"help|h",
);
unless ($opts{key} && $opts{secret} )
{
die "$0 requires the S3KEY and S3SECRET environment variables to be set.";
}
# handle -h
usage() if exists $opts{help};
my $s3 = Net::Amazon::S3->new(
aws_access_key_id => $opts{key},
aws_secret_access_key => $opts{secret},
retry => 1,
);
die "Could not connect to S3" unless defined $s3;
sub read_filename
{
print "\nEnter filename: ";
my $name = <>;
chomp $name;
return $name;
}
sub usage
{
print lt;<EOHIPPUS;
$0 [OPTIONS]
Pass your S3 key and secret in the S3KEY and S3SECRET environment entries.
Options:
--help or -h : this help
--separator $opts{separator} : BUCKET and KEY separator character
(for --get and --put)
--create BUCKET (or -c BUCKET) : create BUCKET
--delete BUCKET (or -d BUCKET) : delete BUCKET
--delete BUCKET$opts{separator}KEY : delete KEY in BUCKET
--list [BUCKET] (or -l) : list a specific bucket or all buckets
--keys (or -k) : list the keys in each bucket (requires --list)
--metadata (or -m) : show the keys' metadata
(requires --keys and --list)
--get BUCKET$opts{separator}KEY : download KEY from BUCKET
--put BUCKET$opts{separator}KEY : upload a file to KEY in BUCKET
EOHIPPUS
exit 0;
}
|
더욱 표준적인 항목이다. 옵션은 여기서 설정된다. usage()
함수는 매우 포괄적이어서 프로그램에 유용성을 부여한다. 모든 옵션이 나열되고
간단하게 설명된다.
Listing 3. net-amazon-s3.pl create 및 delete 조작
if (exists $opts{create})
{
my $bucket = $s3->add_bucket( { bucket => $opts{create}} )
or die sprintf ("%s: %s", $s3->err, $s3->errstr);
print "Created bucket '$opts{create}' successfully.\n";
}
elsif (exists $opts{delete})
{
my ($b, $key) = split $opts{separator}, $opts{delete};
my $bucket = $s3->bucket($b);
die "Could not retrieve bucket $b" unless $bucket;
if (defined $key)
{
$bucket->delete_key($key)
or die sprintf ("%s: %s", $s3->err, $s3->errstr);
print "Deleted key '$key' in bucket '$b' successfully.\n";
}
else
{
$bucket->delete_bucket()
or die sprintf ("%s: %s", $s3->err, $s3->errstr);
print "Deleted bucket '$b' successfully.\n";
}
}
|
--create 옵션은 매우 단순하다. 버킷을 작성한 후
돌아가기만 하면 된다.
--delete의 경우 버킷 삭제(반복되지 않으므로
사용자는 먼저 버킷에 있는 모든 키를 제거해야 함) 또는 버킷에서의 키 삭제를
처리한다. 여기서 분리 문자는 버킷 이름과 키 이름 사이의 분할 지점 역할을
한다.
Listing 4. net-amazon-s3.pl get 및 put 조작
...
elsif (exists $opts{get})
{
my ($b, $key) = split $opts{separator}, $opts{get};
my $bucket = $s3->bucket($b);
die "Could not get the bucket $b" unless $bucket;
my $where = read_filename();
my $response = $bucket->get_key_filename( $key, 'GET', $where )
or die sprintf ("%s: %s", $s3->err, $s3->errstr);
die "Could not create file $where" unless -f $where;
print "Successfully downloaded $key from bucket $b into $where\n";
}
elsif (exists $opts{put})
{
my ($b, $key) = split $opts{separator}, $opts{put};
my $bucket = $s3->bucket($b);
die "Could not get the bucket $b" unless $bucket;
my $where = read_filename();
die "File $where does not exist or is not readable" unless -f $where && -r $where;
my $response = $bucket->add_key_filename(
$key,
$where,
{ content_type => $mime->mimeTypeOf($where), },
)
or die sprintf ("%s: %s", $s3->err, $s3->errstr);
print "Successfully uploaded $where into $key in bucket $b\n";
}
|
Get과 put은
매우 비슷하며 둘 다 파일 이름 및 키 이름에 대해 조작을 수행한다.
여기서 유일하게 흥미로운 부분은 컨텐츠 유형을 가져오기 위해 사용하는
MIME::Types $mime 오브젝트 이다. 이 오브젝트는
일단 업로드하고 나면 변경할 수 없다는 것을 기억한다.
Listing 5. net-amazon-s3.pl list 조작
...
elsif (exists $opts{list})
{
print "Available buckets:\n";
my @todo;
if ($opts{list})
{
push @todo, map { $s3->bucket($_) } $opts{list};
}
else
{
print "(Getting all buckets)\n";
my $response = $s3->buckets;
die "Could not get the bucket list" unless $response;
@todo = @{$response->{buckets}};
}
foreach my $bucket ( @todo )
{
printf "\t%s\n", $bucket->bucket;
if (exists $opts{keys})
{
my $response = $bucket->list_all
or die sprintf ("%s: %s", $s3->err, $s3->errstr);
foreach my $key (@{$response->{keys}})
{
printf "\t\t%10s\t%s\n", $key->{size}, $key->{key};
if (exists $opts{metadata})
{
my $detail = $bucket->get_key($key->{key});
foreach my $entry (qw/content_length content_type etag/)
{
printf "\t\t\t%20s=%s\n", $entry, ($detail->{$entry}||'UNDEFINED');
}
}
}
}
}
}
|
마지막으로 가장 긴 --list 핸들러는 단일
버킷 또는 다중 버킷을 처리한다. 이 핸들러는 키와 키의 메타데이터의
목록을 적절한 스위치와 함께 표시한다.
\t 문자는 탭으로 변환되며 출력에 들여쓰기를
적용하는 세련되지 않은 방법이므로 텍스트 터미널에서는 정상적으로 표시된다.
여기서 알 수 있듯이 Net::Amazon::S3는 매우 깔끔한 모듈이다. 일부 메소드는
약간 낯설지만 정상적으로 작동된다. 항목을 가져오는 작업과 추가 get_key()
호출이 필요한 메타데이터에 이를 사용하는 작업은 구분된다. 어디서나 이 코드는
단순하고 간결하다.
Amazon::S3 모듈은 Net::Amazon::S3를 임시로 대체한다. 해시 참조를
사용하기 위해 new() 호출을 변경해야
했지만 이것이 유일한 변경사항이었다(Amazon::S3에 대한 모든
Net::Amazon::S3 참조도 명백히 변경됨).
Listing 6. net-amazon-s3.pl로부터의 amazon-s3.pl 변경
my $s3 = Amazon::S3->new({
aws_access_key_id => $opts{key},
aws_secret_access_key => $opts{secret},
retry => 1,
});
|
Amazon::S3는 다수의 옵션을 지원하므로 사용자가 이러한 옵션을 사용할 수 있다고 생각하는 경우 문서를 참조해야 한다. 일반적으로 Amazon::S3는 Net::Amazon::S3와 목적이 약간 다르지만 개발자의 입장에서는 API가 동일하다. 이는 라이브러리 상호 운용성을 위해 매우 유용한 특징이다.
Amazon::S3의 유용한 특성 중 하나는 Net::Amazon::S3만큼 많은 수의 모듈에 의존하지 않는다는 점이다. Amazon::S3의 작성자는 이식 가능성을 강조한다.
SOAP::Amazon::S3 모듈을 사용하려면 약간의 배경지식이 필요하며 이 기사를 위해 이러한 배경지식에 대해 간단하게 설명한다. SOAP는 경로를 사용하여 자원을 나타내는 일반적인 HTTP 요청과는 다르게 HTTP(웹)를 통해 정보에 액세스하는 방법이다. 이러한 요청은 일반적으로 REST 스타일이라고 부르며 많은 URL 변형으로 확장되는 경향이 있다. 반면 SOAP는 몇 개의 URL로만 변형되며 많은 XML을 서버에 전달한다.
SOAP에 대해 더 설명하고 싶지만 너무 광범위한 주제이므로 관심 있는 사용자는 직접 서적이나 검색 엔진을 통해 확인한다. 중요한 특징 면에서는 SOAP와 REST가 그다지 다르지 않다. 각각을 사용하여 우수한 코드를 작성할 수도 있고 잘못된 코드를 작성할 수도 있다.
안타깝게도 SOAP::Amazon::S3는 문서에서 시험적인 것으로 표시된다. 사용자에게 적합한지 여부는 직접 테스트해서 결정해야 한다.
변경사항에 대해 계속 진행한다. 무엇보다도 SOAP::Amazon::S3에는 Net::Amazon::S3 및 Amazon::S3가 수행하는 파일 저장 및 가져오기를 위한 편의 메소드가 없기 때문에 File::Slurp 모듈이 필요하다.
Listing 7. soap-amazon-s3.pl 예비 단계
# set Debug to 0 if you don't want to see all the XML
my $s3 = SOAP::Amazon::S3->new( $opts{key}, $opts{secret},
{ Debug => 1, RaiseError => 1 } );
|
사용자가 SOAP::Amazon::S3가 생성하는 모든 SOAP 트래픽을 보고 궁금해할 것이기
때문에 필자는 Debug=1을 벗어났다. RaiseError=1로
인해 Net::Amazon::S3에 대해 필자가 수행한 모든 오류 검사는 불필요한 것이었지만
이는 프로덕션 환경을 위해서는 좋은 생각이 아닐 수 있다.
버킷 작성(my $bucket = $s3->createbucket($opts{create});)은
버킷 삭제($bucket->delete()) 또는 오브젝트
삭제($bucket->object($key)->delete();)와
마찬가지로 Net::Amazon::S3를 사용한 버킷 작성과 다르다.
필자가 언급했듯이 SOAP::Amazon::S3에는 Net::Amazon::S3에 있는 편의 함수가 없기 때문에 파일에 쓰기는 약간 더 복잡하다.
Listing 8. soap-amazon-s3.pl 파일 쓰기
open W, '>', $where or die "Could not write to $where: $!"; print W $bucket->object($key)->getdata(); close W; |
파일로부터 업로드를 위해 반복한다.
Listing 9. soap-amazon-s3.pl 파일 업로드
my $type = ''.$mime->mimeTypeOf($where); # force $type to be a string
# use File::Slurp::read_file in scalar context to grab the whole file's contents
my $data = read_file($where);
$bucket->putobject($key, $data, { 'Content-Type' => $type });
|
MIME 유형은 문자열이어야 하며 그렇지 않으면 XML 헬퍼 모듈이 불만을 제기한다. 또한 컨텐츠 유형은 Net::Amazon::S3와 다르게 대문자로 작성된다.
마지막으로 항목 나열에 대해 설명한다. 여기서는 오브젝트 메타데이터를
사용할 수 없어 SOAP::Amazon::S3가 Net::Amazon::S3만큼 강력하지 않았다.
SOAP::Amazon::S3에는 우수한 $object->url()
메소드가 있지만 이 메소드는 예를 들어, 공간을 %20으로
변환하지 않으므로 이 메소드가 작동하는지 사용해 봐야 한다. 필자는 버그(시험
모듈인 것을 기억한다)를 제출했지만 지금은 프로덕션 환경에서 $object->url()
메소드의 사용을 피한다.
Listing 10. soap-amazon-s3.pl 버킷과 버킷에 있는 오브젝트 나열하기
...
elsif (exists $opts{list})
{
print "Available buckets:\n";
my @todo;
if ($opts{list})
{
push @todo, map { $s3->bucket($_) } $opts{list};
}
else
{
print "(Getting all buckets)\n";
@todo = $s3->listbuckets;
}
foreach my $bucket ( @todo )
{
printf "\t%s\n", $bucket->name;
if (exists $opts{keys})
{
foreach my $key ($bucket->list())
{
printf "\t\t%10s\t%-30s\t%s\n", $key->{Size}, $key->name, $key->url;
if (exists $opts{metadata})
{
foreach my $entry (qw/Size ETag LastModified/)
{
printf "\t\t\t%20s=%s\n", $entry, ($key->{$entry}||'UNDEFINED');
}
}
}
}
}
}
|
여기서 알 수 있듯이 SOAP::Amazon::S3는 메타데이터를 가져오지 않으므로 예를 들어, 오브젝트의 컨텐츠 유형을 확인할 수 없다. 메타데이터를 사용하여 오브젝트에 대한 중요 정보를 저장하는 경우에는 이것이 달갑지 않은 제한사항이 될 수 있다. 그렇지 않으면 SOAP::Amazon::S3는 버킷과 버킷의 요소를 나열하는 것에 대해 Net::Amazon::S3와 비교된다.
두 개의 기타 S3 CPAN 모듈에 대해서는 자세히 평가하지 않았지만 간단한 요약을 다음과 같이 제공한다.
- Net::Amazon::S3::Tools는 S3에 대한 명령행 액세스를 원하는 경우에 유용하다. 사용자가 자체적으로 작성하는 것보다 나으므로 미리 작성된 툴킷의 경우 확인해야 한다.
- Tie::Amazon::S3는 단일 버킷에 대해 작업하는 데 필요한 유용한 모듈이다. 해시 항목을 삭제 또는 수정하고 새 항목을 추가하는 등의 작업을 수행할 수 있다. 안타깝게도 버킷 레벨 조작(버킷 작성, 버킷 삭제 등) 또는 메타데이터 조작(특히 새 키에 대한 컨텐츠 유형 설정)은 허용하지 않는다. 따라서 Tie::Amazon::S3는 S3에서 순수 데이터를 저장하려는 경우 유용하지만 이미지의 경우에는 그다지 도움이 되지 않는다.
전반적으로 Net::Amazon::S3와 Amazon::S3는 현재 S3 작업을 위한 최적의 선택이다. 교환 가능한 API를 사용하면 필요할 때 쉽게 전환할 수 있다. 이들은 버킷 조작에서 항목 메타데이터 검색에 이르기까지 모든 조작을 지원한다. 이들의 API는 약간 낯설지만 일단 설정하고 나면 쉽게 사용할 수 있다.
상당한 잠재력을 가진 SOAP::Amazon::S3를 주시한다. 단일 버킷에 있는 순수 데이터에 대해 작업하는 경우에는 확실히 더 편리한 Tie::Amazon::S3를 사용해야 한다.
S3를 사용하여 좋은 결과가 있기를 빈다.
| 설명 | 이름 | 크기 | 다운로드 방식 |
|---|---|---|---|
| Sample scripts | amazon-s3-scripts.zip | 5KB | HTTP |
교육
- Amazon S3에
대해 자세히 알아보자.
- Cultured Perl: Perl and the Amazon
cloud 시리즈(developerWorks, 2009년 3월 - 6월)에서는 Perl 및 Apache를
사용하여 Amazon의 S3(Simple Storage Service) 및 SimpleDB에 액세스하여
단순한 사진 공유 웹 사이트를 빌드하는 것에 대해 안내한다.
- Part 1에서는 아키텍처에 대해 살펴보면서 S3 및 SimpleDB의 장단점에 대해 소개한다.
- Part 2에서는 서버의 로드를 최소화하고 엄격한 보안 정책을 유지하기 위해 HTML 형식을 통해 웹 페이지로부터 파일을 S3에 업로드하는 방법에 대해 설명한다.
- Part 3에서는 URL이 업로드된 파일에 대한 SimpleDB 레코드를 작성하는 방법과 특정 사용자의 사진에 대한 SimpleDB 레코드로서 주석을 작성, 편집 및 삭제하는 방법에 대해 자세히 설명한다.
- Part 4에서는
최상위 레벨 구성 방법, 핸들러를 사용하여 수행할 작업 및 외부 종속성 설정
방법을 포함한 전체
mod_perl사이트의 코드 기반을 검사한다. - Part 5에서는
색인화를 위한 템플리트 하나, 업로드를 위한 템플리트 셋(일반,
S3 양식 및 URL 추가), 이미지 및 주석 찾아보기를 위한 템플리트
하나, 주석에서 반복적으로 이미지를 찾아보기 위한 템플리트 하나를
포함하여 전체
mod_perl사이트의 템플리트를 검사한다.
- Moose에
흥미를 가지게 되었는가? 확인해 보자. File::Slurp를
반복해 보자.
- SOAP 및 REST에 대한 자세한 내용은
developerWorks SOA and Web services
영역을 살펴보자.
- developerWorks
Linux 영역에서는 Linux 개발자에게 도움이 되는 여러 가지 리소스를 제공하고 있으며
가장 인기 있는 기사와 튜토리얼도 볼 수 있다.
- developerWorks에 있는
Linux 기사와
Linux 튜토리얼을
모두 볼 수 있다.
- developerWorks 기술 행사 및 웹 캐스트를 통해 최신 정보를 얻을 수 있다.
제품 및 기술 얻기
- CPAN(Comprehensive Perl Archive Network)
사이트에서는 많은 수의 모듈과 모듈 문서를 찾을 수 있다. 여기에는
Net-Amazon-S3-0.current modules,
Amazon-S3-0.current modules 및
SOAP-Amazon-S3-0.current modules가 있다.
필자가 제대로 다루지 않은 Net-Amazon-S3-Tools-0.current와
Tie-Amazon-S3-0.current도 있다.
- developerWorks에서 직접 다운로드할 수 있는 IBM
시험판 소프트웨어를 사용하여 Linux와 관련된 후속 개발 프로젝트를 구현해 볼 수 있다.
토론
- My developerWorks 커뮤니티에 참여하자.
개발자 중심 블로그, 포럼, 그룹 및 Wiki 검색 중에 다른 developerWorks
사용자와 의견을 교환해 보자.
