 |
|
난이도 : 중급 Doug Tidwell, Cloud Computing Evangelist, Software Group Strategy, IBM
원문 게재일 : 2009 년 10 월 13 일 번역 게재일 : 2009 년 11 월 03 일 Zend Framework에는 클라우드 기반 스토리지 서비스를 쉽게 사용할 수 있도록
도와주는 여러 가지 클래스가 있습니다. 이 PHP를
사용한 클라우드 컴퓨팅" 시리즈의 Part 1에서는 Zend 클래스를 Amazon의 S3 클라우드 스토리지
서비스와 함께 사용하는 방법을 살펴보았으며 이
두 번째 기사에서는 Amazon EC2(Elastic Compute Cloud)의 가상 시스템을 쉽게 사용할 수 있도록
도와 주는 Zend 클래스에 대해 설명합니다.
클라우드 컴퓨팅의 가장 흥미로운 특징 중 하나는 클라우드 공급자의 데이터 센터에서
가상 시스템을 실행할 수 있다는 것이다. Amazon EC2에서는 아키텍트와 개발자에게 클라우드에서 가상
시스템 이미지를 작성하고 실행할 수 있는 기능을 제공한다. 조직에 필요한 소프트웨어와 데이터가
포함된 사용자 정의 이미지를 작성한 후 필요에 따라 원하는 만큼의 가상 시스템 사본을 실행할 수
있다. 이 기사에서는 EC2 이미지 작업을 쉽게 수행하는 데 도움이 되는 Zend Framework의 일부 클래스에
대해 살펴본다.
EC2는 정교한 제품이기 때문에 이 시리즈에서는 EC2 기능을 두 기사로 나눠서
설명한다. 이 기사에서는 기본적인 이미지 작업, 이미지 인스턴스의 시작과 중지 및 인스턴스
보안을 위한 키 쌍 및 보안 그룹에 대해 설명하며 다른 기사에서는 탄력적 IP 주소, Amazon
CloudWatch 모니터링 및 EBS(Elastic Block Storage)와 같은 주제를 다룬다.
시작
이 기사에서는 다음과 같은 여러 중요한 EC2 작업을 수행하는 방법에 대해 살펴본다.
- 사용자에게 속한 AMI(Amazon Machine Image) 찾기
- 사용자에게 속한 키 쌍 찾기, 새 키 쌍 작성 및 기존 키 쌍 삭제를 포함한 키 쌍 작업
- 가상 시스템의 TCP/IP 포트에 대한 액세스 제어를 포함한 보안 그룹 작업
- AMI 인스턴스 시작
- AMI 인스턴스 재부트 또는 종료
이 시리즈의 모든 기사에서와 마찬가지로 시작하기 전에 Zend Framework를 설치하면
이 예제를 최대한 활용할 수 있다. Zend Framework가 아직 설치되어 있지 않다면 zend.com/community/downloads에서
전체 패키지를 다운로드하고 설치한다. 이 패키지를 설치하면 Zend Framework, PHP 및 Apache 웹
서버가 시스템에 설치된다. 설치가 완료되면 브라우저에서 http://localhost/ZendServer/로
이동한 후 Zend Framework 설치 설명서를 보고 자세한 정보를 확인한다. ZendServer 콘솔에 로그인할 수 있다면 모든 준비가
완료된 것이다.
또한 Amazon 계정을 설정해야 한다(참고자료 참조).
이 기사의 예제에서는 Part
1에서 작성한 PHP Credentials 클래스를 사용한다. 이 클래스는 Amazon 계정에 대한 신임 정보를
관리하며 신임 정보는 .ini 파일에 저장된다.
Listing 1. PHP .ini 파일에 신임 정보 저장하기
; Configuration file to hold secret keys, account numbers and other useful
; strings for Amazon and other cloud accounts.
[amazon]
accessKey=0123456789ABCDEFGHIJ
secretKey=0123456789abcdefghiABCDEFGHI1234567890AB
ownerId=123456789012
|
이 기사에서는 ownerId 값이 중요하다. Amazon에는 수천
개에 달하는 AMI가 있지만 그 중 대부분은 공용이 아니기 때문에 ownerId
값을 사용하여 액세스 권한이 없는 AMI를 제외하게 된다. 소유자 ID는 12자리 Amazon Web Services
계정 번호이다. 이 ID를 확인하려면 http://aws.amazon.com/에서 사용자
계정으로 로그인한 후 Your Account 메뉴와 Security Credentials 항목을 차례로 선택한다.
그림 1. 보안 신임 정보 찾기
페이지의 가운데로 스크롤해서 내려가면 AWS 계정 ID를 볼 수 있다.
그림 2. AWS 계정 ID
계정 ID를 cloud.ini 파일에 입력할 때는 대시 기호를 제외시켜야 한다. 이 그림의
ID가 사용자의 ID라면 ownerId=999999999999를 .ini 파일에 추가해야 한다.
참고:
- AMI 인스턴스를 시작할 때마다 비용을 지불해야 하므로 EC2의 요금이 적절한
경우라도(일부 인스턴스의 경우 시간 당 10센트로 매우 저렴함) AMI를 시작한 다음 계속 실행된 채로
두지 않으려면 작업을 완료한 후에는 인스턴스를 종료해야 한다.
- 이 기사의 예제에서는 적어도 하나의 AMI를 작성했다고 가정한다. 그렇지 않은
경우에는 특수 값인
ownerId=amazon을 사용할 수 있다. 이 값은 100개
이상의 AMI로 구성된 목록을 리턴하지만 그 중에서 일부 이미지만 시작할 수 있다.
ownerId=amazon을 사용할 경우에는 인스턴스 중에
비용이 매우 높은 인스턴스가 있을 수 있다는 점에 유의해야 한다. IBM®에는 엔터프라이즈급
소프트웨어 제품을 지원하는 수많은 AMI가 있으며 이러한 AMI 중 하나를 사용할 경우 인스턴스가
실행되는 한 라이센스 비용을 지불해야 한다. 단순히 EC2를 사용해 보기 위한 목적이라면 간단한 기능을
제공하는 저렴한 AMI를 사용하는 것이 좋다.
샘플 애플리케이션 정보
샘플 애플리케이션은 다음 6개의 PHP 페이지로 구성되어 있다.
amis.php — 사용자 계정에 속한 모든
AMI를 나열한다. 단추를 클릭하여 AMI 인스턴스를 시작할 수 있다.
manage_instance.php — AMI 인스턴스를
작성, 재부트 또는 종료하라는 amis.php의 요청을 처리한다.
instances.php — 사용자의 계정에 의해
제어되는 모든 실행 중인 인스턴스를 나열한다. 단추를 클릭하여 실행 중인 인스턴스를 재부트하거나
종료한다.
keypairs.php — 사용자가 작성한 모든
공용/개인용 키 쌍을 나열한다. 기존 키 쌍을 확인하고, 새 키 쌍을 작성하고, 기존 키 쌍을
삭제한다.
securitygroups.php — 사용자의 계정에
대해 정의된 모든 보안 그룹을 나열한다. 단추를 클릭하여 특정 보안 그룹의 세부 사항을 확인한다.
securitygroup.php — 특정 보안 그룹에
대한 모든 권한을 나열한다. 새 권한을 추가하거나 기존 권한을 삭제한다.
AMI 작업하기
먼저 Zend_Service_Amazon_Ec2_Image 오브젝트를 작성한다.
Listing 2. Zend_Service_Amazon_Ec2_Image 오브젝트 작성하기
require_once 'Credentials.php';
$creds = new Credentials;
$aws_key = $creds->getCredential('amazon', 'accessKey');
$aws_secret = $creds->getCredential('amazon', 'secretKey');
$ec2_img = new Zend_Service_Amazon_Ec2_Image($aws_key, $aws_secret);
|
이 오브젝트는 Amazon에 저장된 AMI와 관련된 작업을 수행하는 데 사용된다.
Zend_Service_Amazon_Ec2_Image->describe() 메소드는 AMI에
대한 메타데이터를 리턴하며 인수를 지정하지 않으면 Amazon에 저장된 모든 AMI의 세부 사항을
리턴한다. 이 경우 많은 양의 데이터가 작성되지만 그 중 대부분은 사용자에게 유용하지
않다. 아쉽게도 현재 구현된 Zend Framework에서는 ownerId를 지정할
수 있는 기능을 제공하는 버전의 describe()가 지원되지 않는다. 이는
곧 사용자와 관련된 AMI를 처음 나열할 때 전체 목록을 정렬하여 원하는 AMI를 찾아야 한다는 것을
의미한다. 이 문제를 해결하기 위해 표시하려는 AMI의 ID를 캐시할 수 있다. 이 작업의 처리 논리는
관련 AMI를 나열하는 파일이 있는 경우 해당 파일을 읽고 각 ID에 대한 describe('ami-id')를
호출하는 것이다. 하지만 이 파일이 없는 경우에는 파일을 작성해야 한다. PHP 파일은 사용자가 원할
경우 AMI 목록을 새로 고칠 수 있는 옵션도 제공한다. 이 작업은 오래 걸리지만 목록과 Amazon에 있는
데이터의 일관성을 유지한다.
Listing 3에서는 AMI 목록을 작성하는 코드를 보여 준다.
Listing 3. AMI ID 캐시하기
if (!file_exists('amis.text') ||
array_key_exists('refresh', $_POST)) {
$imageData = $ec2_img->describe();
$amiFile = fopen('amis.text', 'w');
$myOwnerId = $creds->getCredential('amazon', 'ownerId');
foreach ($imageData as $nextImage) {
if ($nextImage['imageOwnerId'] === $myOwnerId)
fwrite($amiFile, $nextImage['imageId']."\n");
}
fclose($amiFile);
}
|
이 코드는 Amazon의 카탈로그에 있는 모든 AMI를 정렬할 필요가 있는지 여부를
검사한다. 파일이 없거나 파일을 새로 고치라는 명시적인 요청이 있으면 Amazon에 있는 모든
AMI에 대한 세부 사항 목록을 가져온다. 이 코드의 목표는 AMI 테이블을 작성하는 것이다.
그림 3. AMI 목록
테이블의 각 행은 AMI ID, 위치, 상태 및 플랫폼으로 구성되어 있다. 그리고 키 쌍과
보안 그룹을 선택할 수 있는 두 개의 드롭다운 목록도 있다. 테이블의 마지막 열은 현재 선택된 키 쌍과
보안 그룹을 사용하여 AMI를 시작하는 누름 단추이다. 테이블을 작성하려면 PHP file()
메소드를 사용하여 AMI 목록을 배열로 읽어들인다. 배열의 각 항목에 대해 모든 관련 정보가 포함된 테이블
행을 작성한다. 다음은 테이블의 행을 작성하는 코드이다.
Listing 4. AMI 테이블의 행 생성하기
$amiList = file('amis.text', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
foreach ($amiList as $nextAmi) {
echo "<tr>";
// Each table row is a form. Clicking the 'Start this image' button submits
// the data from the current row, which tells instances.php which image to
// start and which key pair and security group to use.
echo "<form action='manage_instance.php' method='POST' ";
echo " onsubmit='return confirm(\"Start image '".$nextAmi."'?\")'>";
echo "<input type='hidden' name='imagetostart' value='".$nextAmi."'/>";
echo "<td>".$nextAmi."</td>";
// Get the description of this AMI
$imageData = $ec2_img->describe(array('imageId' => $nextAmi));
echo "<td>".$imageData[0]['imageLocation']."</td>";
echo "<td>".$imageData[0]['imageState']."</td>";
// If the platform is blank, assume it's some flavor of Linux
if (strlen($imageData[0]['platform']))
echo "<td>".$imageData[0]['platform']."</td>";
else
echo "<td>Linux</td>";
// Insert the lists of key pairs and security groups
echo "<td>".$keypairsForm."</td>";
echo "<td>".$secGroupsForm."</td>";
// If the state of the image is "available," insert a start button.
if ($imageData[0]['imageState'] == 'available')
echo "<td><input type='submit' value='Start this image'/></td>";
else
echo "<td>Not available</td>";
echo "</form>";
echo "</tr>";
}
|
각 테이블 행은 Start 단추를 눌렀을 때 브라우저에서 선택된 키 쌍과
보안 그룹을 인식할 수 있도록 개별 <form> 요소에 있어야
한다. AMI ID 배열을 반복하면서 특정 ID를 사용하여 describe()를
호출하면 해당 AMI에 대한 설명이 리턴된다. 테이블 행의 나머지 부분은 이미지의 위치(이미지가
S3 계정에 저장된 위치), 이미지의 상태, 키 쌍의 드롭다운 목록, 보안 그룹의 드롭다운 목록 및
Start this image 단추로 구성되어 있다. Start 단추는 이미지의 상태가 available일
때만 표시된다. 테이블의 각 행에 대한 양식 컨트롤은 그림 4와 같다.
그림 4. 테이블의 각 행에 대한 양식 컨트롤
키 쌍 및 보안 그룹의 목록은 루프 외부에서 작성된다.
Listing 4. 키 쌍 및 보안 그룹의 목록 생성하기
$ec2_kp = new Zend_Service_Amazon_Ec2_Keypair($aws_key, $aws_secret);
$keypairs = $ec2_kp->describe();
foreach ($keypairs as $key => $row) {
$keyName[$key] = $row['keyName'];
$keyFingerprint[$key] = $row['keyFingerprint'];
}
array_multisort($keyName, $keypairs);
$keypairsList = "<select name='keypair'>";
foreach ($keypairs as $nextKeypair) {
$keypairsList = $keypairsList."<option value='".$nextKeypair['keyName']."'>";
$keypairsList = $keypairsList.$nextKeypair['keyName']."</option>";
}
$keypairsList = $keypairsList."</select>";
$secGroupsList = "<select name='secgroup'>";
$ec2_sg = new Zend_Service_Amazon_Ec2_Securitygroups($aws_key, $aws_secret);
$securityGroups = $ec2_sg->describe();
foreach ($securityGroups as $key => $row) {
$groupName[$key] = $row['groupName'];
$groupDescription[$key] = $row['groupDescription'];
}
array_multisort($groupName, $securityGroups);
foreach ($securityGroups as $nextGroup) {
$secGroupsList = $secGroupsList."<option value='".$nextGroup['groupName']."'>";
$secGroupsList = $secGroupsList.$nextGroup['groupName']."</option>";
}
$secGroupsList = $secGroupsList."</select>";
|
각 목록은 키 쌍 및 보안 그룹에 대한 HTML <select>
및 <option> 요소가 포함된 문자열이다. (이 코드에서는 PHP
array_multisort를 사용하여 키 쌍 및 보안 그룹의 이름을 정렬한다.) AMI
인스턴스를 시작하게 되면 AWS 계정에 대한 비용 계산이 시작되기 때문에 확인 대화 상자가 표시된다.
그림 5. 인스턴스 시작 확인하기
이 화면 캡처에서는 키 쌍 id_rsa-gsg-keypair와
보안 그룹 default가 선택되어 있다.
인스턴스 작업하기
OK 단추를 클릭하여 인스턴스를 시작하면 새 인스턴스에 대한 정보가
manage_instance.php 페이지로 전송된다. 인스턴스 작업에서 가장
먼저 수행할 단계는 Zend_Service_Amazon_Ec2_Instance 오브젝트를
작성하는 것이다.
Listing 6. Zend_Service_Amazon_Ec2_Instance 오브젝트 작성하기
$creds = new Credentials;
$aws_key = $creds->getCredential('amazon', 'accessKey');
$aws_secret = $creds->getCredential('amazon', 'secretKey');
$ec2_instance = new Zend_Service_Amazon_Ec2_Instance($aws_key, $aws_secret);
|
오브젝트를 작성했으므로 이제 요청된 이미지의 인스턴스를 시작할 수 있다.
Listing 7. 새 인스턴스 작성하기
if (strlen($imageIdToStart) && strlen($keypairToStart) && strlen($secgroupToStart)) {
$startResults = $ec2_instance->run(array('imageId' => $imageIdToStart,
'keyName' => $keypairToStart,
'securityGroup' => $secgroupToStart));
echo "<p><b>Status of instance ".$startResults['instances'][0]['instanceId'].": ";
echo $startResults['instances'][0]['instanceState']['name'].".</b></p><hr/>";
}
|
참고: 인스턴스를 시작할 때 인스턴스 수, 인스턴스 크기(메모리 용량 및
CPU 속도), 인스턴스를 호스팅할 지역 등의 다른 매개변수를 지정할 수 있다. 예제를 간단하게
유지하기 위해 인스턴스를 시작하는 모든 요청은 하나의 인스턴스만 시작하며, 이 인스턴스는
최소 크기(Amazon에 대한 실제 요청에서 m1.small로 지정됨)로 설정되고,
사용자 계정의 기본 지역에서 호스팅된다.
이 코드는 AMI의 ID와 amis.php 페이지의 양식에서 선택한
키 쌍 및 보안 그룹의 이름을 사용하여 새 인스턴스의 상태를 표시한다.
그림 6. 새로 작성한 인스턴스의 상태
OK를 클릭하면 instances.php 페이지로 이동한다. 이 페이지에는 현재 인스턴스 목록이 표시된다.
그림 7. 인스턴스 목록
참고: 이미지 ID, 키 이름 및 보안 그룹의 값은 HTTP POST를
통해 manage_instance.php 페이지로 전달된다. 중개 페이지를 사용해서
새 인스턴스를 작성한다는 것은 실수로 다른 인스턴스를 시작하지 않고 instances.php
페이지를 새로 고칠 수 있다는 것을 의미한다. manage_instance.php
페이지에서는 이미지를 재부트하거나 종료하는 요청도 처리한다.
시작된 인스턴스의 초기 상태는 pending이다. 이
상태는 시스템 이미지가 시동 중이기 때문에 아직 실행되고 있지는 않다는 것을 의미한다. 또한
Amazon에서 이 인스턴스에 인스턴스 ID i-373c995f를 할당했다는
것을 알 수 있으며 이 ID는 나중에 인스턴스 작업을 수행할 때 사용된다. "Refresh list of
instances" 단추를 클릭하면 화면이 업데이트된다.
그림 8. 업데이트된 인스턴스 목록
업데이트된 목록을 보면 인스턴스의 상태가 running이고 Amazon에서
DNS 이름 ec2-75-101-220-48.compute-1.amazonaws.com을 이 인스턴스에 할당했다는
것을 알 수 있다. 이는 웹 액세스에 대한 이 인스턴스가 활성화되어 있고 인스턴스가 포트 80에서 웹 서버를 실행
중이라면 http://ec2-75-101-220-48.compute-1.amazonaws.com에서 인스턴스의 홈
페이지를 확인할 수 있음을 뜻한다. (보안 그룹의 규칙을 작성하여 포트 80을 활성화할 수 있으며 여러 보안
그룹에 대해 즉시 적용할 수 있다.)
인스턴스 테이블의 행을 생성하려면 Zend_Service_Amazon_Ec2_Instance->describe() 메소드를 사용한다.
Listing 8. 인스턴스 테이블 작성하기
$instanceDetails = $ec2_instance->describe();
if (count($instanceDetails['instances'])) {
echo "<table border='1' cellpadding='5'>";
echo "<tr style='font-weight: bold;'>";
echo "<td>Status</td><td>Instance ID</td><td>AMI ID</td><td>Public DNS name</td>";
echo "<td>Security Group</td><td>Key Pair</td><td> </td><td> </td>";
echo "</tr>";
foreach ($instanceDetails['instances'] as $nextInstance) {
echo "<tr>";
$status = $nextInstance['instanceState']['name'];
// Make the cell background green if the status is running.
if (strripos('running', $status) === 0)
echo "<td style='background-color: green; color: white; font-weight: bold;'>";
// Make the cell background yellow if the status is shutting-down.
else if (strripos('shutting-down', $status) === 0)
echo "<td style='background-color: yellow; font-weight: bold;'>";
// Make the cell background red if the status is terminated.
else if (strripos('terminated', $status) === 0)
echo "<td style='background-color: red; color: white; font-weight: bold;'>";
// Make the cell background purple for any other status.
else
echo "<td style='background-color: purple; color: white; font-weight: bold;'>";
echo $status."</td>";
echo "<td>".$nextInstance['instanceId']."</td>";
echo "<td>".$nextInstance['imageId']."</td>";
echo "<td>".$nextInstance['dnsName']."</td>";
echo "<td><a href='securitygroup.php?groupname=".$nextInstance['groupSet'][0];
echo "&previous=instances'>".$nextInstance['groupSet'][0]."</a></td>";
echo "<td>".$nextInstance['keyName']."</td>";
. . .
|
이 코드에서는 먼저 인스턴스가 있는지 여부를 검사한다. 적어도 하나의 인스턴스가
있을 경우 각 인스턴스는 테이블의 한 행으로 설명되며 인스턴스 ID와 AMI ID가 공용 DNS 이름, 보안
그룹 및 키 쌍과 함께 표시된다. amis.php 페이지에서와 마찬가지로
테이블의 각 행은 하나의 양식이다.
그림 9. 인스턴스를 관리하는 양식 컨트롤
이 테이블에는 세 개의 인스턴스가 나열되어 있다. 이 중 두 항목의 상태가
running이기 때문에 해당 인스턴스에 Reboot 및 Terminate
단추가 있다. 다른 상태(pending, shutting-down
또는 terminated)에 있는 인스턴스에는 단추가 표시되지 않는다.
Listing 9. 인스턴스 테이블에 대한 양식 컨트롤 작성하기
if (strripos('running', $status) === false) {
echo "<i>[Can't reboot]</i>";
}
else {
echo "<form action='manage_instance.php' method='POST' ";
echo "onsubmit='return confirm(\"Reboot instance '";
echo $nextInstance['instanceId']."'?\")'>";
echo "<input type='hidden' name='imagetoreboot' value='";
echo $nextInstance['instanceId']."'/>";
echo "<input type='submit' value='Reboot'/></form>";
}
echo "</td>";
echo "<td style='text-align: center;'>";
if (strripos('running', $status) === false) {
echo "<i>[Can't terminate]</i>";
}
else {
echo "<form action='manage_instance.php' method='POST' ";
echo "onsubmit='return confirm(\"Terminate instance '";
echo $nextInstance['instanceId']."'?\")'>";
echo "<input type='hidden' name='imagetoterminate' value='";
echo $nextInstance['instanceId']."'/>";
echo "<input type='submit' value='Terminate'/></form>";
}
echo "</td>";
|
인스턴스가 실행 중일 경우 이 코드에서는 인스턴스를 재부트하거나 종료하는 단추가
작성되며 이들 단추를 클릭하면 확인 대화 상자가 표시된다.
그림 10. 확인이 필요한 인스턴스 종료 또는 재부트
OK를 클릭하면 manage_instance.php 페이지로 다시 이동한다.
그림 11. 새로 종료된 인스턴스의 상태
인스턴스 목록으로 돌아오면 업데이트된 상태가 표시된다.
그림 12. 업데이트된 인스턴스 목록
인스턴스의 상태는 언젠가는 terminated로 변경된다.
그림 13. 종료된 인스턴스
참고: 인스턴스가 종료된 후에는 EC2가 인스턴스와 연관된 모든 데이터를
삭제한다. 이 작업은 1시간 이내에 수행되며 인스턴스에 대한 데이터가 삭제된 후에는 더 이상
해당 인스턴스가 결과에 표시되지 않는다.
키 쌍 작업하기
키 쌍은 사용자 인증에 사용되는 공용 및 개인용 키의 쌍이다. 인스턴스를
시작할 때 실행 중인 인스턴스에 액세스하는 데 사용할 수 있는 키 쌍을 지정한다. Amazon에서는
공용 키를 해당 인스턴스와 연결한다. AMI의 구성에 따라 개인용 키가 없을 경우 인스턴스에 액세스하지
못할 수도 있다. keypairs.php 파일은 사용자의 계정에 대해 정의된
모든 키 쌍을 표시한다.
그림 14. 키 쌍 목록
각 키 쌍의 이름 및 핑거프린트가 테이블에 표시된다.
Listing 10. 키 쌍 테이블 작성하기
$creds = new Credentials;
$ec2_kp = new Zend_Service_Amazon_Ec2_Keypair>
($creds->getCredential('amazon', 'accessKey'),
$creds->getCredential('amazon', 'secretKey'));
$keypairs = $ec2_kp->describe();
if (count($keypairs)) {
echo "<p>Here are the key pairs defined for your account:</p>";
echo "<table border='1' cellpadding='5'>";
echo "<tr style='font-weight: bold;'>";
echo "<td>Key Pair Name</td>";
echo "<td>Fingerprint</td>";
echo "<td> </td>";
echo "</tr>";
foreach ($keypairs as $key => $row) {
$keyName[$key] = $row['keyName'];
$keyFingerprint[$key] = $row['keyFingerprint'];
}
array_multisort($keyName, $keypairs);
foreach ($keypairs as $nextKeypair) {
echo "<tr>";
echo "<td> ".$nextKeypair['keyName']."</td>";
echo "<td> ".$nextKeypair['keyFingerprint']."</td>";
echo "<td>";
echo "<form action='".$_SERVER['PHP_SELF']."' method='post'";
echo " onsubmit='return confirm(\"Do you really want to delete the key pair ";
echo "'".$nextKeypair['keyName']."'?\");'>";
echo "<input type='hidden' name='keypairtodelete' ";
echo "value='".$nextKeypair['keyName']."'/>";
echo "<input type='submit' value='Delete'/>";
echo "</form>";
echo "</td>";
echo "</tr>";
}
echo "</table>";
}
else
echo "<p>Sorry, your account doesn't have any key pairs defined.</p>";
|
이 코드에서는 Zend_Service_Amazon_Ec2_Keypair 오브젝트를
작성한 다음 describe() 메소드를 호출하여 사용자의 계정에 대해 정의된
모든 키 쌍의 세부 사항을 가져온다. 각 키 쌍에 대해 AWS는 키 쌍의 이름과 핑거프린트를 리턴한다. 테이블의
각 행에는 HTML 양식과 Delete 단추가 있다. 이 양식을 사용할 경우 삭제 요청 시 반드시 확인을 수행해야 한다.
그림 15. 확인이 필요한 키 쌍 삭제
delete() 메소드를 사용하면 키 쌍을 쉽게 삭제할 수 있다.
Listing 11. 키 쌍 삭제하기
if (strlen($keypairToDelete)) {
echo "<p><b>";
try {
$ec2_kp->delete($keypairToDelete);
echo "The key pair named ".$keypairToDelete." was deleted successfully.";
}
catch (Zend_Service_Amazon_Ec2_Exception $ec2e) {
echo "The key pair could not be deleted. The error message from Amazon is:";
echo "<br/><br/><i>".$ec2e->getMessage()."</i>";
}
echo "</b></p><hr/><br/>";
}
|
keypairs.php 페이지에는 새 키 쌍을 작성할 수 있는
양식도 있으며 유일한 매개변수는 새 키 쌍의 이름이다.
그림 16. 새 키 쌍을 작성하는 양식
키 쌍을 작성하는 작업은 create() 메소드를 호출하는 것처럼 간단하다.
Listing 12. 보안 그룹의 규칙 테이블 작성하기
foreach ($list[0]['ipPermissions'] as $key => $row) {
$ipProtocol[$key] = $row['ipProtocol'];
$startingPort[$key] = $row['fromPort'];
$toPort[$key] = $row['toPort'];
$ipRanges[$key] = $row['ipRanges'];
}
array_multisort($startingPort, SORT_ASC, $list[0]['ipPermissions']);
foreach($list[0]['ipPermissions'] as $rule) {
. . .
echo "<tr>\n";
echo "<td> ".strtoupper($rule['ipProtocol'])."</td>\n";
echo "<td> ".$rule['fromPort']."</td>\n";
echo "<td> ".$rule['toPort']."</td>\n";
if ((is_array($rule['ipRanges']) && count($rule['ipRanges']) == 0) ||
(strlen($rule['ipRanges']) == 0)) {
echo "<td> ---</td>\n";
echo "<td> </td>\n";
}
else {
echo "<td> ".$rule['ipRanges']."</td>\n";
echo "<td style='text-align: center;'>";
echo "<form action='".$_SERVER['PHP_SELF']."' method='POST'";
echo " onsubmit='return confirm(\"Do you really want to revoke access for IP ";
echo " address range '".$rule['ipRanges']."' on this port?\");'>";
echo "<input type='hidden' name='groupname' value='".$groupName."'/>";
echo "<input type='hidden' name='fromport' value='".$rule['fromPort']."'/>";
echo "<input type='hidden' name='toport' value='".$rule['toPort']."'/>";
echo "<input type='hidden' name='iptorevoke' value='".$rule['ipRanges']."'/>";
echo "<input type='submit' value='Revoke'/></form></td>";
} |
Amazon의 응답에 새 키 쌍에 대한 개인용 키가 들어 있다. PHP 페이지에
해당 정보가 사용자에 대한 메시지와 함께 표시된다.
그림 17. 새로 작성된 키 쌍
사용자는 개인용 키 정보를 복사해서 파일에 붙여넣어야 한다. 이 정보는 분실할
경우 다시 작성할 수 없다. (키 쌍 데이터를 파일에 자동으로 기록하는 고급 솔루션을 작성하는
작업은 실습 과제로 남겨 둔다.)
보안 그룹 작업하기
새 인스턴스를 작성하는 양식에서는 시스템 이미지, 키 쌍 및 보안 그룹을
지정해야 한다. 보안 그룹을 사용하면 다른 시스템에서 인스턴스에 액세스할 수 있는 방법을 정의할
수 있다. 예를 들어, 실행 중인 인스턴스를 웹 서버로 사용하려는 경우 포트 80에 대한 연결 요청을
시스템에서 허용해야 한다. 각 규칙에 대해 프로토콜과
포트 범위 그리고 해당 프로토콜을 통해 해당 포트에 액세스할 수 있도록 허용된 IP 주소 범위를
지정한다. 보안 그룹의 화면의 그림 18과 같다.
그림 18. 보안 그룹
이 테이블에는 default 보안 그룹의 보안 정책이 나열되어
있다. 화면의 아래쪽을 보면 67.93.2.12 및 76.182.90.9 호스트에서 포트 80에 액세스할 수 있도록 허용한
정책을 볼 수 있다. 그리고 일반적으로 Windows VM을 사용한 원격 데스크탑 세션에 사용되는 포트 3389의
경우 IP 주소 76.182.90.9에 액세스 권한이 있다는 것을 알 수 있다. 포트의 범위를 지정할 수도 있다. 이
예제에서는 포트 21, 22 및 23에 대한 규칙이 단일 규칙으로 정의되어 있다. 테이블의 각 행에는 개별 규칙을
삭제하는 양식이 있다. 이 테이블을 작성하는 코드는 비교적 단순하다.
Listing 13. 보안 그룹의 규칙 테이블 작성하기
foreach ($list[0]['ipPermissions'] as $key => $row) {
$ipProtocol[$key] = $row['ipProtocol'];
$startingPort[$key] = $row['fromPort'];
$toPort[$key] = $row['toPort'];
$ipRanges[$key] = $row['ipRanges'];
}
array_multisort($startingPort, SORT_ASC, $list[0]['ipPermissions']);
foreach($list[0]['ipPermissions'] as $rule) {
. . .
echo "<tr>\n";
echo "<td> ".strtoupper($rule['ipProtocol'])."</td>\n";
echo "<td> ".$rule['fromPort']."</td>\n";
echo "<td> ".$rule['toPort']."</td>\n";
if ((is_array($rule['ipRanges']) && count($rule['ipRanges']) == 0) ||
(strlen($rule['ipRanges']) == 0)) {
echo "<td> ---</td>\n";
echo "<td> </td>\n";
}
else {
echo "<td> ".$rule['ipRanges']."</td>\n";
if (strripos('0.0.0.0', $rule['ipRanges'][0]) === false) {
echo "<td style='text-align: center;'>";
echo "<form action='".$_SERVER['PHP_SELF']."' method='POST'";
echo " onsubmit='return confirm(\"Do you really want to revoke access for IP ";
echo " address range '".$rule['ipRanges']."' on this port?\");'>";
echo "<input type='hidden' name='groupname' value='".$groupName."'/>";
echo "<input type='hidden' name='fromport' value='".$rule['fromPort']."'/>";
echo "<input type='hidden' name='toport' value='".$rule['toPort']."'/>";
echo "<input type='hidden' name='iptorevoke' value='".$rule['ipRanges']."'/>";
echo "<input type='submit' value='Revoke'/></form></td>";
}
else
echo "<td> </td>"; |
테이블의 행을 작성하기 전에 이 코드에서는 array_multisort
함수를 사용하여 각 규칙의 시작 포트 번호를 기준으로 규칙 배열을 정렬한다. 프로토콜의 이름,
시작 포트 및 종료 포트는 쉽게 표시할 수 있다. 테이블의 마지막 두 열은 IP 주소 범위와 권한을
취소하는 단추이다. 어떤 경우에는 IP 주소 범위가 빈 배열이나 빈 문자열로 리턴되기도 하며 이러한
경우가 발생하면 Revoke 단추 대신 빈 셀이 테이블에 포함된다.
테이블의 마지막 행에는 새 규칙을 작성하는 양식이 있다.
그림 19. 새 규칙을 작성하는 양식
Amazon에서는 IP 주소를 CIDR(Classless Inter-Domain Routing) 표기법에 따라
지정하도록 요청하고 있다. CIDR 표기법은 IP 주소 뒤에 슬래시 기호와 0-32 사이의 숫자 중 하나를
지정하는 방식이다. 슬래시 기호 뒤의 숫자는 접두어에 있는 IP 주소의 비트 수를 지정한다. 예를
들어, CIDR 표기법 9.67.0.0/16은 9.67로 시작하는 모든 주소와 일치한다. IP 범위 0.0.0.0/0은 모든
IP 주소와 일치하는 반면 범위 76.182.90.9/32는 IP 주소 76.182.90.9에만 일치한다. 입력한 IP 주소가
CIDR 표기법을 따르지 않을 경우에는 PHP 페이지가 해당 주소 뒤에 /32를 추가한다. (참고자료에서
CIDR에 대한 자세한 정보를 볼 수 있다.) IP 범위에 권한을 부여하는 코드는 단순하다.
Listing 14. 새 IP 주소 범위에 권한 부여하기
if (strlen($ipToAuthorize) && strripos($ipToAuthorize, '/') === false)
$ipToAuthorize = $ipToAuthorize."/32";
. . .
try {
$ec2_sg->authorizeIp($groupName, $protocol, $fromPort, $toPort, $ipToAuthorize);
echo "IP address ".$ipToAuthorize." is now authorized.";
}
catch (Zend_Service_Amazon_Ec2_Exception $ec2e) {
// We get an exception if this IP address is already authorized, that's okay.
if ($ec2e->getErrorCode() == 'InvalidPermission.Duplicate')
echo "IP address range ".$ipToAuthorize." is already authorized.";
// If the IP address range isn't formatted correctly, tell the user.
else if ($ec2e->getErrorCode() == 'InvalidPermission.Malformed')
echo "The value ".$ipToAuthorize." is not a valid IP address range.";
// For all other exceptions, we just dump the exception to the screen.
else {
echo "<i>Something really bad happened:</i><br/><pre>";
var_dump($ec2e);
echo "</pre>";
}
}
|
authorizeIp 메소드를 호출하면 보안 그룹에 대한
새 규칙이 작성된다. 이 코드에서는 두 가지 일반적인 예외를 처리한다. Zend Framework에서는
이미 권한이 부여된 IP 주소 범위에 권한을 부여할 경우와 IP 주소 범위가 올바르지 않은 경우에
예외가 발생한다. 다른 예외의 경우 이 코드에서는 화면에 오류 메시지만 표시한다.
참고: 특정 포트에 대한 권한이 둘 이상의 주소 범위에 부여된 경우 목록 배열을
리턴하도록 Zend Framework의 버그가 최근에 수정되었다. 사용 중인 Zend Framework의 버전에 이
수정 사항이 없는 경우에는 포트 당 하나의 주소만 표시된다. 모든 권한 부여는 Amazon 클라우드에
저장된 보안 그룹의 일부이기 때문에 Zend의 결과에 표시되지 않는다. 샘플 코드에서는 이 문제가
정상적으로 처리된다.
마지막으로 규칙 옆에 있는 Revoke 단추를 클릭하면 사용자의 확인을 요청하는
대화 상자가 표시된다.
그림 20. 확인이 필요한 보안 규칙 삭제
보안 규칙을 삭제하는 작업은 revokeIp() 메소드를 통해 수행된다.
요약
이 기사에서는 가상 시스템 이미지, 실행 중인 이미지 인스턴스, 인스턴스 관리를
위한 키 쌍 및 보안 그룹 등과 관련된 작업을 수행하는 데 필요한 페이지 세트를 살펴보았다. 다시
한번 말하지만 Zend Framework를 사용하면 클라우드와 손쉽게 상호 작용할 수 있다. 이 시리즈의
후속 기사에서는 Zend Framework를 사용하여 탄력적 IP 주소, EBS(Elastic Block Storage), CloudWatch
등의 고급 EC2 기능과 관련된 작업을 수행하는 방법에 대해 설명한다.
다운로드 하십시오 | 설명 | 이름 | 크기 | 다운로드 방식 |
|---|
| Sample code | os-php-cloud2-source.zip | 13KB | HTTP |
|---|
참고자료 교육
제품 및 기술 얻기
토론
필자소개  | 
|  | Doug Tidwell은 IBM Emerging Technology 그룹의 Senior Software Engineer이며 1997년
1회 XML 컨퍼런스에 연사로 참여한 이후 여러 해 동안 마크업 언어, 웹 서비스 및 SOA 기술과
관련된 활동을 하고 있다. 기술 전도사로서 그는 클라우드 컴퓨팅과 관련된 표준 및 기술을
설명하고 이러한 기술을 전체 비즈니스 아키텍처 및 전략에 통합하는 데 필요한 도움을 고객에게
제공한다. developerWorks에 여러 편의 기사를 기고했으며 XSLT에 관한 다양한 주제를 자세히
다룬 O’Reilly에서 출판한 XSLT(ISBN 0-596-52721-7)의 저자이기도 하다. 노스캐롤라이나의 채펄힐에서
부인과 딸 그리고 애견과 함께 살고 있다. |
기사에 대한 평가
 |
| 이 문서 북마킹 하기
|
|