한국어

EDPS

Amazon 클라우드에 Linux 애플리케이션 마이그레이션하기, Part 1: 초기 마이그레이션

클라우드에 애플리케이션을 마이그레이션하는 방법

Sean A. Walberg, Senior Network Engineer

요약: 클라우드 컴퓨팅과 IaaS(Infrastructure as a Service)에 대해서는 문서화가 잘 되어 있지만 애플리케이션을 클라우드 환경에서 실행하는 방법에 대해서는 다루고 있는 문서가 많지 않습니다. 이 시리즈에서는 애플리케이션을 클라우드로 이동하는 방법과 이 설정이 제공해야 하는 기능을 활용하는 방법에 대해 설명합니다. Part1에서는 실제 서버에서 클라우드 서버로 직접 마이그레이션하는 방법에 대해 살펴봅니다.

이 기사에 테그:  리눅스

원문 게재일:  2010 년 7 월 13 일 
번역 게재일:   2010 년 11 월 02 일 
난이도:  중급 
영어로:  보기 
PDF:  A4 and Letter (79KB | 21 pages)Get Adobe® Reader® 
페이지뷰: 2907 회 
의견: 0 (의견 추가)

1 star2 stars3 stars4 stars5 stars 평균 평가 등급 (총 9표)

이 시리즈의 정보

이 기사 시리즈에서는 단일 실제 서버에 있는 웹 애플리케이션을 Amazon EC2(Amazon Elastic Compute Cloud)로 마이그레이션하는 과정을 설명한다. 또한 애플리케이션을 클라우드 환경에 적합하게 수정하는 방법과 클라우드에서 제공해야 하는 기능을 활용하는 방법에 대해서도 살펴본다.

IaaS(Infrastructure as a Service)는 컴퓨팅 자원을 사용하고 그에 따라 비용을 지불한다는 아주 좋은 개념이다. 더 많은 컴퓨팅 성능이 필요하면 비용을 더 지불하면 된다. 이 모델의 단점은 보지도 못하고 많이 알지도 못하는 컴퓨터를 사용해서 작업한다는 것이다. 하지만 이러한 단점을 극복하고 나면 IaaS를 통해 많은 것을 얻을 수 있다.

IaaS 모델은 서버를 구매하는 일반적인 모델과 매우 다르기 때문에 사용자의 가상 컴퓨터를 관리하는 방법이 바뀌게 된다. 사용자의 애플리케이션을 클라우드에서 실행하는 방법도 바뀐다. 협상 가능한 서버 간 지연 시간과 같이 지금까지 고려했던 사항을 전혀 고려하지 않아도 된다.

Amazon EC2 작업하기

Amazon EC2에서는 API(Application Programming Interface)를 통해 서버를 켜고 끌 수 있으며 사용 시간을 기준으로 서버 사용 비용을 신용 카드로 결제할 수 있다. 다양한 유형의 서버와(주된 관심사인 메모리, 디스크 또는 CPU 성능에 따라) 지속적 디스크부터 로드 밸런서에 이르는 추가 기능 스위트를 선택할 수 있다. 그리고 비용은 사용한 자원에 대해서만 지불한다.

Amazon EC2 오퍼링 외에도 무엇보다도 결제 처리, 데이터베이스 및 메시지 큐잉 등을 제공하는 다양한 서비스가 있다. 이 기사 시리즈에서는 사용량에 따라 비용을 지불하는 디스크 공간에 대한 액세스를 제공하는 Amazon S3(Amazon Simple Storage Service)를 사용한다.

예제 애플리케이션

이 시리즈에서 예제로 사용하는 웹 애플리케이션은 Ruby on Rails 프레임워크와 PostgreSQL 백엔드를 사용하여 작성된 SmallPayroll.ca라는 급여 서비스이다. 일반적인 여러 웹 애플리케이션과 마찬가지로 이 애플리케이션에도 데이터베이스 계층과 애플리케이션 계층이 있고 CSS(Cascading Style Sheet) 및 JavaScript 파일과 같은 정적 파일 세트가 있다. 사용자는 다양한 양식을 이용하여 데이터를 입력 및 조작하고 보고서를 생성한다.

다음과 같은 다양한 컴포넌트가 사용된다.

  • Nginx. 정적 파일을 위한 프론트엔드 서버이며 중간 계층에 대한 밸런서이다.
  • Mongrel. 애플리케이션 서버이다.
  • Ruby. 애플리케이션을 작성하는 데 사용된 언어이다.
  • Gems. 데이터베이스 암호화부터 애플리케이션 레벨 모니터링에 이르는 모든 기능을 위한 써드파티 플러그인 및 라이브러리이다.
  • PostgreSQL. SQL(Structured Query Language) 데이터베이스 엔진이다.

사이트 사용량이 사이트가 있는 단일 서버의 용량을 초과했다면 지금이 바로 새 환경으로의 마이그레이션을 고려할 적절한 시기이며 이는 곧 클라우드로 이동할 수 있는 최상의 기회이기도 하다.

원하는 기능 향상

하지만 단순히 한 서버에서 소수의 클라우드 기반 서버로 이동하는 것은 클라우드에서 수행할 수 있는 기능을 충분히 활용하는 것이 아니며 흥미로운 읽을거리가 되지도 못한다. 따라서 이동하는 동안 다음과 같은 기능 향상 작업을 수행할 것이며, 이러한 기능 중 일부는 클라우드 환경에서만 가능하다.

  • 신뢰성 향상. 클라우드에서 실행할 서버의 크기를 선택할 수 있으므로 여러 개의 작은 서버를 실행하여 중복성을 강화할 수 있다.
  • 확장 및 축소가 가능한 용량. 서비스의 성장에 따라 서버가 점진적으로 풀에 추가된다. 하지만 서버 수를 단기적인 트래픽 폭증에 대비하기 위해 늘리거나 정기적으로 트래픽이 적은 기간 동안 줄일 수도 있다.
  • 클라우드 스토리지. 애플리케이션 데이터를 Amazon S3에 백업할 수 있으며, 이렇게 하면 테이프 스토리지를 사용하지 않아도 된다.
  • 자동화. 서버, 스토리지 및 로드 밸런서를 포함한 Amazon 환경의 모든 것을 자동화할 수 있다. 애플리케이션 관리 시간이 줄어든다는 것은 다른 생산적인 작업에 더 많은 시간을 투자할 수 있다는 것을 의미한다.

이 기사 시리즈에서는 이러한 기능 향상 작업을 점진적으로 수행한다.

테스트 및 마이그레이션 전략

애플리케이션을 처음 배치할 때는 일반적으로 프로덕션 트래픽에 대한 부담 없이 편안하게 테스트하고 수정할 수 있다. 이에 반해 애플리케이션을 마이그레이션할 경우에는 사이트에 로드를 발생시키는 사용자를 고려해야 한다. 새 환경에서 프로덕션 트래픽이 발생하게 되면 사용자는 모든 것이 올바르게 작동하는 것으로 간주한다.

마이그레이션으로 인한 중단 시간이 반드시 0일 필요는 없다. 임시로 서비스를 오프라인 상태로 유지할 수 있다면 작업이 훨씬 더 쉬워진다. 이 중단 시간을 사용하여 최종 데이터 동기화를 수행하고 네트워크 변경 사항을 안정화시킬 수 있다. 새 환경에 처음 배치할 경우에는 이러한 시간을 사용해서는 안 된다. 왜냐하면 새 환경은 애플리케이션 마이그레이션이 시작하기 전에 작동 상태에 있어야 하기 때문이다. 이 점을 염두에 둔 상태에서 핵심 사항은 환경과 네트워크 변경 사항 사이의 데이터 동기화이다.

마이그레이션 전략을 계획할 때는 먼저 현재 환경을 살펴보는 것이 좋다. 다음 질문에 응답해 보자.

  • 애플리케이션을 실행하기 위해 서버에서 사용하는 소프트웨어는 무엇인가?
  • 애플리케이션 및 서버 자원을 관리 및 모니터링하기 위해 서버에서 사용하는 소프트웨어는 무엇인가?
  • 모든 사용자 데이터는 어디에 저장되어 있는가? 데이터베이스? 파일?
  • 이미지, CSS 및 JavaScript 파일과 같은 정적 자원은 어디에 저장되어 있는가?
  • 애플리케이션에 필요한 다른 시스템과의 접점은 무엇인가?
  • 최근에 모든 데이터를 백업했는가?

사용자에게 알리기

중단 시간이 예정되어 있지 않더라도 일반적으로 사용자에게 알리는 것이 좋다. SmallPayroll.ca 애플리케이션의 경우에는 사용자가 2주 결제 주기에 따라 일정한 간격으로 사이트를 사용하는 경향이 있기 때문에 2주 단위 알림이 합리적인 기간이다. Google 광고 플랫폼의 관리 인터페이스인 Google AdWords와 같은 사이트에서는 1주 단위로 알림을 제공한다. 1시간 동안 중단되더라도 사용자의 불만이 크지 않는 뉴스 사이트라면 중단 당일에 알림을 제공할 수도 있다.

또한 알림의 양식은 사이트의 특성과 사용자와 현재 통신하는 방법에 따라 다양하다. SmallPayroll.ca의 경우에는 사용자가 로그인할 때 눈에 띄는 메시지를 표시하는 것만으로도 충분하다. 예를 들어, "2010년 6월 24일 오전 12시 01분부터 오전 1시까지(동부 표준시 기준) 시스템을 사용할 수 없습니다. 이 시각 이전에 입력한 모든 내용은 저장됩니다. 자세한 정보를 보려면 여기를 클릭하십시오."라는 메시지를 표시할 수 있다. 이 메시지는 사용자가 알아야 하는 다음과 같은 세 가지 핵심 정보를 제공한다.

  • 중단이 발생하는 시간(시간대 포함)
  • 데이터가 안전하게 저장될 것임을 알리는 보장
  • 추가 정보에 대한 링크

오전 12시, 오후 12시 또는 자정과 같은 용어는 사용하지 않는 것이 좋다. 많은 사람들이 6월 17일 자정이 이른 아침(오전 12시 1분)인지 아니면 매우 늦은 저녁(오후 11시 59분)인지를 확신하지 못하기 때문에 이러한 용어를 사용하면 혼동할 수 있다. 마찬가지로 정오가 오전 12시인지 오후 12시인지 혼동하는 사람이 많으므로 분을 추가하여 명확한 시간을 알려 주는 것이 훨씬 쉽다.

세부 사항은 다양할 수 있으며 특히, 중단 시간 동안 부분 작동이 예상되는 경우에 더욱 그러하다. 뉴스 사이트처럼 중단 시간 동안에만 알림을 제공하기로 결정한 경우에는 동일한 정보가 도움이 될 것이다. 필자가 자주 사용하는 사이트 중단 화면에는 "유지보수를 위해 사이트가 중단되었으며 오후 3시경에(EST) 다시 시작됩니다. 기다리는 동안 Asteroids 게임을 즐기십시오."라는 메시지가 표시된다.

내부 사용자도 무시해서는 안 된다. 계정 담당자가 있을 경우 클라이언트가 문의할 때 알려 줄 수 있다.

DNS 고려사항

DNS(Domain Name System)는 www.example.com과 같은 이름을 192.0.32.10과 같은 IP 주소로 변환한다. 컴퓨터는 IP 주소에 연결하므로 이 변환이 중요하다. 한 환경에서 다른 환경으로 마이그레이션할 경우 두 환경이 같은 건물에 있지 않는 한 대부분의 경우 다른 IP 주소를 사용해야 한다.

컴퓨터에서는 전체 응답 시간을 줄이기 위해 TTL(Time To Live)이라는 일정 기간 동안 이름-IP 맵핑을 캐싱한다. 한 환경에서 다른 환경으로 전환하게 되면서 IP 주소가 변경될 경우 캐싱된 DNS 항목을 가진 사용자는 계속해서 기존 환경을 사용하려고 시도한다. 애플리케이션의 DNS 항목 및 연관된 TTL은 주의 깊게 관리해야 한다.

TTL은 일반적으로 1시간부터 1일 사이이다. 마이그레이션을 준비할 경우에는 TTL을 5분 정도의 짧은 시간으로 설정해야 한다. 컴퓨터는 이름-IP 맵핑과 함께 TTL을 가져오므로 주소를 변경하려고 예정한 시간보다 적어도 한 번의 TTL 기간 전에 이 변경 작업을 수행해야 한다. 예를 들어, www.example.com의 TTL이 86,400초(1일)라면 적어도 마이그레이션 1일 전에 TTL을 5분으로 다시 설정해야 한다.

기존 환경과 새 환경 분리하기

마이그레이션 전에 새 환경을 완벽하게 테스트해야 한다. 모든 테스트는 프로덕션 환경과 분리된 상태에서 수행되어야 하며 새 환경을 충분히 테스트하기 위해 주로 프로덕션 데이터의 스냅샷을 이용한다.

프로덕션 데이터의 스냅샷을 이용하여 전체 테스트를 수행하는 데는 두 가지 목적이 있다. 첫 번째 목적은 실제 데이터를 사용하면 오류를 더 쉽게 찾아낼 수 있기 때문이다. 왜냐하면 실제 데이터가 개발 중에 사용된 테스트 데이터보다 더 예측할 수 없기 때문이다. 실제 데이터는 사용자가 실수로 복사하지 않은 파일이나 마무리 중에 잊어버린 특정 구성이 필요한 파일을 참조할 수 있다.

두 번째 이유는 프로덕션 데이터를 사용하면 데이터를 로드하는 동시에 마이그레이션을 실습할 수 있기 때문이다. 실제로 환경을 전환하는 것만 제외하면 마이그레이션 계획의 대부분을 검증할 수 있다.

새 환경을 프로덕션 환경인 것처럼 모의 환경으로 만들 수는 있지만 하나의 환경만 애플리케이션의 호스트 이름에 연관시킬 수 있다. 이 요구사항을 가장 쉽게 해결하는 방법은 hosts 파일에서 DNS 대체 항목을 작성하는 것이다. UNIX®의 경우에는 /etc/hosts에 이 파일이 있으며, Windows®의 경우에는 C:\windows\system32\drivers\etc\hosts에 있다. 기존 행의 형식에 따라 애플리케이션의 호스트 이름을 미래의 IP 주소로 가리키는 항목을 추가한다. 한 가지 명심할 점은 이동할 이미지 서버를 비롯한 모든 항목에 대해서도 동일한 작업을 수행해야 한다는 것이다. 아마도 브라우저를 다시 시작해야 하겠지만 그 이후에는 프로덕션 URL을 입력하여 새 환경에 액세스할 수 있다.

Amazon EC2 기초

Amazon EC2 서비스를 사용하면 VM(Virtual Machine)에 대한 비용을 시간 단위로 지불할 수 있다. Amazon에서는 여러 다양한 유형의 시스템을 제공하며 이러한 시스템은 CPU, 메모리 및 디스크 프로파일에 따라 분류된다. Amazon에서는 메모리 및 디스크 사용량을 기가바이트 단위로 측정하며 CPU 사용량을 Amazon ECU(EC2 Compute Units)로 측정한다. 여기서, 1ECU는 대략 1.0 - 1.2GHz 수준의 AMD Opteron 또는 Intel® Xeon® 프로세서이다(2007년 기준). 예를 들어, 표준 소형 인스턴스는 1.7GB의 메모리, 160GB의 디스크 공간 및 1ECU의 CPU를 제공한다. 이 기사를 집필하던 당시 가장 큰 시스템은 68.4GB의 메모리, 1.7TB의 디스크 공간 및 8개의 가상 코어에 분산된 26개의 ECU를 제공하는 High-memory Quadruple Extra Large이다. 가격 범위는 최소형의 경우 시간당 8.5센트이고 최대형의 경우 시간당 2.40달러이다.

Amazon EC2 인스턴스는 VM을 빌드하는 데 사용되는 템플리트인 AMI(Amazon Machine Image)로 시작된다. Amazon에서는 일부 AMI를 게시하고 있으며 사용자가 고유한 AMI를 빌드하여 다른 사용자와 공유할 수도 있다. 이러한 사용자 작성 AMI 중 일부는 무료로 사용할 수 있으며, 일부는 Amazon의 시간당 비용과는 별도로 시간당 비용이 발생할 수 있다. 예를 들어, IBM에서는 시간 단위로 라이센스 비용을 지불하는 여러 개의 유료 AMI를 게시하고 있다.

VM을 부팅하려면 먼저 시스템 유형과 AMI를 선택해야 한다. AMI는 Amazon S3에 저장되어 있으며 사용자가 인스턴스를 시작할 때 VM의 루트 파티션으로 복사된다. 루트 파티션은 항상 10GB이다. 시스템 유형과 연관된 스토리지 공간은 인스턴스 스토리지나 임시 스토리지라고 하며 사용자의 VM에 별도의 드라이브로 제공된다. 임시 스토리지라고 하는 이유는 사용자가 인스턴스를 종료할 때 정보도 영원히 삭제되기 때문이다. 따라서 데이터 손실을 방지하려면 데이터를 주기적으로 백업해야 한다. 이는 또한 인스턴스를 실행하는 실제 호스트에서 충돌이 발생하여 인스턴스가 종료될 경우에도 임시 디스크가 없어진다는 것을 의미한다.

AMI(Amazon Machine Image)

모든 AMI에는 Amazon에서 지정한 ID(예: ami-0bbd5462)가 있다. Amazon에서 일부 공용 AMI를 제공하며 있으며 사용자가 자신의 AMI를 공용으로 설정한 경우도 있다. 처음에 공용 AMI를 선택한 다음 원하는 수정 사항을 적용하거나 처음부터 직접 시작할 수도 있다. AMI의 루트 파일 시스템을 변경할 때마다 루트 파일 시스템을 새 AMI로 저장할 수 있으며, 이를 리번들링이라고 한다.

이 시리즈에서는 다른 이미지를 선택할 수도 있지만 공개적으로 사용할 수 있는 CentOS 이미지를 사용하여 시작한다. 약간의 시간을 투자해서 사용할 이미지를 살펴보면서 추가 계정이 없고 패키지가 업데이트되었는지 확인할 수 있다면 더욱 좋을 것이다. 또한 처음부터 고유한 AMI를 작성할 수도 있겠지만 이 작업은 이 기사의 범위를 벗어난 내용이다.

Amazon API

Amazon EC2 클라우드를 시작, 중지 및 사용하는 데 필요한 모든 기능은 웹 서비스를 통해 사용할 수 있다. Amazon에서는 웹 서비스에 대한 스펙을 게시하고 있으며 명령행 도구 세트도 제공한다. 계속 진행하기 전에 이러한 도구를 다운로드해야 한다(참고자료 참조). 또한 빠른 시작 안내서(참고자료 참조)를 보고 환경을 설정하면 많은 입력 작업을 줄일 수 있다.

보안 신임 정보를 사용하여 API에 인증한다. 이러한 신임 정보는 AWS(Amazon Web Services) Management Console(참고자료 참조) 내의 Account 링크에 있다. 사용자의 X.509 인증서 파일과 액세스 키가 필요하며, 이 파일과 액세스 키는 안전하게 보관해야 한다. 이 파일과 액세스 키만 있으면 누구라도 AWS 자원을 사용할 수 있으며, 이 경우 사용자에게 비용이 부과된다.

첫 번째 인스턴스를 시작하기 전에

첫 번째 인스턴스를 시작하기 전에 새 인스턴스에 인증하기 위해 SSH(Secure Shell) 키를 생성한 다음 인스턴스를 보호하기 위해 가상 방화벽을 설정해야 한다. Listing 1에서는 ec2-add-keypair 명령을 사용하여 SSH 키 쌍을 생성하는 방법을 보여 준다.


Listing 1. SSH 키 쌍 생성하기
	
[sean@sergeant:~]$ ec2-add-keypair main
KEYPAIR main    40:88:59:b1:c5:bc:05:a1:5e:7c:61:23:5f:bc:dd:fe:75:f0:48:01
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAu8cTsq84bHLVhDG3n/fe9FGz0fs0j/FwZiDDovwfpxA/lijaedg6lA7KBzvn
...
-----END RSA PRIVATE KEY-----
[sean@sergeant:~]$ ec2-describe-keypairs
KEYPAIR main    40:88:59:b1:c5:bc:05:a1:5e:7c:61:23:5f:bc:dd:fe:75:f0:48:01

첫 번째 명령은 Amazon에게 main이라는 이름의 키 쌍을 생성하도록 지시한다. 결과의 첫 번째 행에 이 키의 해시 값이 표시된다. 출력의 나머지 부분은 암호화되지 않은 PEM 개인용 키이다. 이 키를 예를 들어, ~/.ssh/main.pem와 같은 위치에 저장해 두어야 한다. Amazon에서는 키의 공용 부분을 보유하며, 이 공용 부분은 사용자가 실행하는 VM에 사용할 수 있다.

두 번째 명령인 ec2-describe-keypairs는 Amazon에 현재 키 쌍 목록을 요청한다. 명령의 결과로 키 쌍의 이름과 해시가 차례로 표시된다.

각 인스턴스는 초기에 아무 것도 허용하지 않는 가상 방화벽에 의해 보호된다. Amazon EC2에서는 이러한 인스턴스를 보안 그룹이라고 하며, 보안 그룹을 조작하는 데 사용할 수 있는 API 호출 및 명령을 제공한다. 앞으로 적절한 시점에 이에 대해 자세히 살펴볼 것이다. 한편 Listing 2에서는 현재 그룹을 보는 방법을 보여 준다.


Listing 2. 현재 보안 그룹 표시하기
	
[sean@sergeant:~]$ ec2-describe-group
GROUP   223110335193    default default group

Listing 2에서는 "default group"이라는 설명이 있는 default라는 그룹을 보여 준다. 이 그룹에 연관된 사용자 ID는 223110335193이다. 이 그룹에는 규칙이 없다. 규칙이 있을 경우에는 왼쪽 열의 GROUP 아래에 PERMISSION이라는 단어를 사용하여 설명된다.

클라우드 환경 준비하기

가장 먼저 수행할 작업은 애플리케이션을 테스트할 클라우드 환경을 준비하는 것이다. 새 환경은 현재 프로덕션 환경을 모방한다.

먼저 ID가 ami-10b55379인 AMI를 실행한다. Listing 3에서는 실행 중인 AMI와 검사 상태를 보여 준다.


Listing 3. CentOS AMI 실행하기
	
[sean@sergeant:~]$ ec2-run-instances ami-10b55379 -k main
RESERVATION  r-750fff1e  223110335193  default
INSTANCE  i-75aaf41e  ami-10b55379  pending  main  0  m1.small
2010-05-15T02:02:57+0000 us-east-1a  aki-3038da59  ari-3238da5b  monitoring-disabled
instance-store  
[sean@sergeant:~]$ ec2-describe-instances i-75aaf41e
RESERVATION  r-750fff1e  223110335193  default
i-75aaf41e  ami-10b55379  pending  main  0  E3D48CEE  m1.small
2010-05-15T02:02:57+0000 us-east-1a  aki-3038da59  ari-3238da5b  monitoring-disabled
instance-store  
[sean@sergeant:~]$ ec2-describe-instances i-75aaf41e
RESERVATION  r-750fff1e  223110335193  default
INSTANCE  i-75aaf41e  ami-10b55379  ec2-184-73-43-141.compute-1.amazonaws.com
domU-12-31-39-00-64-71.compute-1.internal  running  main  0  E3D48CEE  m1.small
2010-05-15T02:02:57+0000  us-east-1a  aki-3038da59  ari-3238da5b  monitoring-disabled
184.73.43.141  10.254.107.127  instance-store  

첫 번째 명령은 ami-10b55379 AMI를 사용하여 인스턴스를 실행하며 Listing 1에서 생성된 키 쌍을 사용하여 시스템에 인증할 것이라고 지정한다. 이 명령은 여러 정보를 제공하지만 그 중에서 가장 중요한 정보는 Amazon EC2 클라우드에 있는 시스템의 ID인 인스턴스 ID(i-750fff1e)이다. 두 번째 명령인 ec2-describe-instances 명령은 실행 중인 모든 인스턴스를 나열한다. Listing 3을 보면 명령행에서 인스턴스 ID가 전달된다. 이렇게 하면 해당 인스턴스에 대한 정보만 표시된다. 인스턴스의 상태는 pending으로 나열된다. 이는 인스턴스가 여전히 시작 중임을 의미한다. IBM AMI는 크기 때문에 일반적으로 시작하는 데 5-10분이 걸린다. 조금 뒤에 동일한 명령을 실행하면 상태가 running으로 표시되며 외부 IP 주소 184.73.43.141이 지정된 것을 볼 수 있다. 10으로 시작하는 내부 IP 주소는 Amazon EC2 클라우드 내에서 통신하는 데 유용하지만 지금은 적합하지 않다.

그런 다음 앞에서 생성한 키를 사용하여 SSH를 통해 서버에 연결한다. 하지만 먼저 SSH(22/TCP)를 허용해야 한다. Listing 4에서는 연결을 인증하고 새 서버에 로그인하는 방법을 보여 준다.

SSH 키 이해하기

SSH 키에 익숙하지 않은 개발자의 경우 SSH를 통해 비밀번호 대신 키를 사용하여 사용자를 인증할 수 있다는 것을 알고 있으면 많은 도움이 될 것이다. 공용 키와 개인용 키로 구성된 키 쌍을 생성한다. 개인용 키는 안전하게 보관하고 공용 키는 $HOME/.ssh 디렉토리에 있는 authorized_keys 파일에 업로드한다. SSH를 통해 서버에 연결하면 클라이언트가 이 키를 사용하여 인증하려고 시도한다. 인증이 성공하면 로그인된다.

키 쌍의 한 가지 특성은 두 키 중 한 키를 사용하여 암호화된 메시지는 나머지 다른 한 키를 사용해서만 암호 해독할 수 있다는 것이다. 서버에 연결할 때 서버는 authorized_keys 파일에 저장된 공용 키를 사용하여 메시지를 암호화할 수 있다. 사용자의 공용 키를 사용하여 메시지를 암호 해독할 수 있으면 서버는 사용자를 비밀번호 없이 로그인할 수 있는 권한이 있는 사용자로 인식한다.

이제 논리적으로 "authorized_keys 파일이 어떻게 Amazon에 저장된 공용 키로 채워졌는가?"라는 질문을 던질 수 있을 것이다. 각 Amazon EC2 인스턴스는 http://169.254.169.254에 있는 Amazon EC2의 웹 서버와 통신하여 인스턴스에 대한 메타데이터를 검색할 수 있다. 이러한 URL 중에는 이미지에 연관된 공용 키를 리턴하는 http://169.254.169.254/latest/meta-data/public-keys/0/openssh-key가 있다.

AMI는 시작할 때 공용 키를 검색하여 authorized_keys에 저장한다. 이 작업은 예제 AMI의 /etc/init.d/getssh에서 수행되며, rc.local에서처럼 쉽게 발생할 수 있다.

인스턴스 메타데이터는 이미지에 정보를 전달하는 데도 사용된다. 웹 서버나 백그라운드 작업 서버 역할을 수행하는 일반 AMI를 사용하면서 인스턴스에서 이미지를 시작할 때 사용자가 전달한 매개변수에 따라 시작할 서비스를 결정할 수 있다.


Listing 4. 인스턴스에 연결하기
	
[sean@sergeant:~]$ ec2-authorize default -p 22 -s $MYIP/32
...
[sean@sergeant:~]$ ssh -i ~/.ssh/main.pem root@184.73.43.141
The authenticity of host '184.73.43.141 (184.73.43.141)' can't be established.
RSA key fingerprint is af:c2:1e:93:3c:16:76:6b:c1:be:47:d5:81:82:89:80.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '184.73.43.141' (RSA) to the list of known hosts.
...

첫 번째 명령은 소스 IP 주소에서 포트 22(TCP가 기본 옵션임)를 사용하도록 허용한다. /32는 호스트만 허용되고 전체 네트워크는 허용되지 않는다는 의미이다. ssh 명령은 개인용 키를 사용하여 서버에 연결한다.

Ruby 설치하기

CentOS에는 구버전의 Ruby가 포함되어 있으므로 1.8.7 버전의 Ruby와 호환되는 고성능 Ruby 인터프리터인 REE(Ruby Enterprise Edition)가 설치된다. 고급스러운 이름에도 불구하고 이 소프트웨어는 오픈 소스이다. Listing 5에서는 REE를 설치하는 방법을 보여 준다.


Listing 5. REE 설치하기
	 
# rpm -e ruby ruby-libs
# yum -y install gcc-c++ zlib-devel openssl-devel readline-devel
...
Complete!
# wget http://rubyforge.org/frs/download.php/71096/ruby-enterprise-1.8.7-2010.02.tar.gz
...
# tar -xzf ruby-enterprise-1.8.7-2010.02.tar.gz
# ruby-enterprise-1.8.7-2010.02/installer -a /opt/ree

Listing 5의 처음 두 명령은 기본 Ruby 설치를 제거하고 C 컴파일러와 몇 가지 필요한 개발 패키지를 설치한다. wget은 최신 REE tarball을 다운로드하며, 이 tarball은 tar에 의해 압축 해제된다. 마지막으로 마지막 명령은 모든 기본값을 승인하고 결과를 /opt/ree에 저장하는 옵션을 사용하여 설치 프로그램을 실행한다. 사용자를 배려하는 설치 프로그램이기 때문에 일부 패키지가 없을 경우 사용자가 실행해야 하는 명령을 알려 준다. 따라서 설치가 진행되지 않을 경우에는 출력을 자세히 살펴보기 바란다.

Ruby를 설치한 후에는 export PATH="/opt/ree/bin:$PATH"를 사용하여 bin 디렉토리를 사용자의 경로에 추가한다. 이렇게 하면 시스템 전체의 /etc/bashrc 디렉토리나 사용자의 홈 디렉토리 내에 있는 .bashrc 디렉토리에 배치할 수 있다.

PostgreSQL 설치하기

PostgreSQL 서버는 CentOS 배포판의 일부이므로 yum 유틸리티를 사용하여 설치하기만 하면 된다. Listing 6에서는 PostgreSQL을 설치하고 부팅 시에 시작되는지 확인하는 방법을 보여 준다.


Listing 6. PostgreSQL 설치하기
	
# yum -y install postgresql-server postgresql-devel
...
Installed: postgresql-devel.i386 0:8.1.21-1.el5_5.1 
   postgresql-server.i386 0:8.1.21-1.el5_5.1
Dependency Installed: postgresql.i386 0:8.1.21-1.el5_5.1 
   postgresql-libs.i386 0:8.1.21-1.el5_5.1
Complete!
# chkconfig postgresql on

yum 명령은 저장소에 있는 패키지를 설치한다. Listing 7에서는 PostgreSQL 서버 컴포넌트와 개발 라이브러리를 설치한다. 이 작업을 수행하면 코어 데이터베이스 유틸리티와 필요한 기타 패키지가 자동으로 설치된다. 아직은 개발 패키지가 필요하지 않지만 Rails와 PostgreSQL을 통합할 때 postgresql-devel 내의 라이브러리가 필요하다.

기본적으로 데이터베이스는 루트 파일 시스템의 일부인 /var/lib/pgsql/data에 해당 파일을 저장한다. Listing 7과 같이 이 디렉토리를 /mnt에 있는 인스턴스 스토리지로 이동한다.


Listing 7. PostgreSQL 데이터 저장소를 /mnt로 이동하기
	 
# mv /var/lib/pgsql/data /mnt
# ln -s /mnt/data /var/lib/pgsql/data
# service postgresql start

Listing 7의 명령을 입력한 후에는 PostgreSQL이 /mnt를 사용하여 실행된다.

다음으로 payroll_prod 데이터베이스(다음 단계에서 작성함)에 대한 비밀번호 로그인을 설정해야 한다. 기본적으로 PostgreSQL은 비밀번호를 사용하지 않고 내부 ID 시스템을 사용한다. /var/lib/pgsql/data/pg_hba.conf의 맨 위에 간단히 다음 구문을 추가한다.

host    "payroll_prod" all  127.0.0.1/32   md5

이제 다음 명령을 실행한다.

su - postgres -c 'pg_ctl reload'

그러면 변경 사항이 적용된다. 이 구성에서 일반적인 PostgreSQL 로그인에는 비밀번호가 필요하지 않다. 따라서 reload 명령이 비밀번호를 요청하지 않는다. 하지만 급여 데이터베이스에 액세스하려면 비밀번호가 필요하다.

마지막 단계는 명령행에서 Rails 데이터베이스를 설정하는 것이다. su - postgres -c psql을 실행한 후 Listing 8의 명령을 실행한다.


Listing 8. 사용자 및 데이터베이스 작성하기
	
postgres=# create user payroll with password 'secret';
CREATE ROLE
postgres=# create database payroll_prod;
CREATE DATABASE
postgres=# grant all privileges on database payroll_prod to payroll;
GRANT

이제 데이터베이스가 작성되었다.

데이터 마이그레이션하기

테스트를 위해 테스트에 사용할 특정 시점의 프로덕션 환경에 대한 데이터베이스 덤프를 작성해야 한다. SmallPayroll 애플리케이션에서는 데이터베이스와 파일 시스템에 데이터를 저장한다. 데이터베이스는 PostgreSQL의 pg_dump 명령을 사용하여 덤프를 작성하며 파일 시스템 데이터는 rsync를 사용한다. 마이그레이션하려면 데이터베이스 덤프의 특성으로 인해 데이터베이스를 정리하고 다시 전송해야 하지만 파일 시스템 데이터는 rsync가 변경되지 않은 파일을 발견할 수 있기 때문에 새 파일과 변경된 파일만 전송하면 된다. 따라서 계획 중 테스트 부분을 수행하면 대부분의 데이터가 미리 준비되기 때문에 마이그레이션 시간을 단축할 수 있다.

데이터베이스를 가장 빠르게 복사하는 방법은 프로덕션 시스템에서 다음 명령을 실행하는 것이다.

pg_dump payroll_prod | gzip -c > /tmp/dbbackup.gz

그런 다음 dbbackup.gz를 클라우드 서버에 복사하고 다음 명령을 실행한다.

zcat dbbackup.gz | psql payroll_prod

이 명령은 단순히 한 서버의 압축된 데이터베이스 덤프를 작성한 다음 다른 서버에서 모든 트랜잭션을 다시 수행한다.

rsync는 매우 간단하다. 프로덕션 서버에서 다음 명령을 실행한다.

rsync -avz -e "ssh -i .ssh/main.pem" /var/uploads/ root@174.129.138.83:/var/uploads/

이 명령은 현재 프로덕션 서버의 /var/uploads에 있는 모든 컨텐츠를 새 서버로 복사한다. 이 명령을 다시 실행하면 변경된 파일만 복사되므로 나중에 동기화 시간을 절약할 수 있다.

데이터베이스를 복사하고 있으므로 Rails 마이그레이션을 먼저 적용하지 않아도 된다. 사용자가 schema_migrations 테이블을 복사했기 때문에 Rails에서는 데이터베이스를 최신 상태로 간주한다.

Rails 애플리케이션 배치하기

지금까지 기본 서버를 설정했지만 애플리케이션을 설정하지는 않았다. 이제 애플리케이션을 실행하기 전에 일부 기본 gem과 애플리케이션에 필요한 gem을 설치해야 한다. Listing 9에서는 gem을 업데이트하는 명령을 보여 준다. 이 경우 Rails 애플리케이션의 루트에 있어야 하며 서버로 먼저 복사해야 한다.


Listing 9. RubyGems 업데이트 및 사용자의 gem 설치하기
	
# gem update --system
Updating RubyGems
Nothing to update
# gem install rails mongrel mongrel-cluster postgres
Successfully installed rails-2.3.8
Building native extensions.  This could take a while...
Successfully installed gem_plugin-0.2.3
Successfully installed daemons-1.1.0
Successfully installed cgi_multipart_eof_fix-2.5.0
Successfully installed mongrel-1.1.5
Successfully installed mongrel_cluster-1.0.5
Building native extensions.  This could take a while...
Successfully installed postgres-0.7.9.2008.01.28
7 gems installed
...
# rake gems:install
(in /home/payroll)
gem install haml
Successfully installed haml-3.0.12
1 gem installed
Installing ri documentation for haml-3.0.12...
Installing RDoc documentation for haml-3.0.12...
gem install money
...

첫 번째 명령은 RubyGems 자체가 최신 상태인지 확인한다. 두 번째 명령은 다음과 같은 일부 유용한 gem을 설치한다.

  • rails. Ruby on Rails 프레임워크이다.
  • postgres. PostgreSQL을 ActiveRecord와 함께 사용할 수 있도록 지원하는 데이터베이스 드라이버이다.
  • mongrel. Rails 애플리케이션을 호스트하는 데 사용되는 애플리케이션 서버이다.
  • mongrel_cluster. mongrel 그룹을 동시에 시작 및 중지하는 기능을 제공하는 유틸리티이다.

마지막 명령은 Rails 태스크를 실행하여 애플리케이션에 필요한 모든 추가 gem을 설치한다. config/environment.rb 파일에 config.gem 지시문이 없는 경우에는 gem install gemname 명령을 직접 실행하여 추가 gem을 설치해야 한다.

RAILS_ENV=production script/console 명령을 사용하여 애플리케이션을 시작한다. 이 명령이 성공하면 애플리케이션을 중지하고 다음 명령을 사용하여 mongrel 팩을 실행한다.

mongrel_rails cluster::start -C /home/payroll/current/config/mongrel_cluster.yml

첫 번째 명령이 실패한 경우에는 문제점을 찾는 데 도움이 되는 여러 오류 메시지가 표시되며, 일반적으로 gem 또는 파일이 없다는 문제점이 발생한다. 이 기회를 살려서 앞으로 gem을 잃어버리지 않도록 누락된 config.gem 지시문을 추가한다.

프론트엔드 웹 서버 설치하기

Nginx는 많은 가상 환경에서 사용하고 있는 웹 서버로, 오버헤드가 낮고 mongrel과 같은 백엔드 서비스에 대한 연결을 프록시하는 데 유용하다. Listing 10에서는 nginx를 설치하는 방법을 보여 준다.


Listing 10. nginx 설치하기
	
# rpm -Uvh http://download.fedora.redhat.com/pub/epel/5/i386/epel-release-5-3.noarch.rpm
...
# yum install nginx
...
Running Transaction
Installing     : nginx                                             [1/1]
Installed: nginx.i386 0:0.6.39-4.el5
Complete!
# chkconfig nginx on

Listing 11에서는 EPEL(Extra Packages for Enterprise Linux®) 저장소를 설치하고 nginx를 설치한 다음 시작 시에 올바르게 시작되는지 확인한다.


Listing 11. Rails 애플리케이션을 위한 nginx 구성
	
# Two mongrels, balanced based on least connections
upstream mongrel-payroll {
	fair;
	server 127.0.0.1:8100;
	server 127.0.0.1:8101;
}

server {
	listen 80;
	server_name  app.smallpayroll.ca;

	root   /home/payroll/current/public;
	gzip_static on;

	access_log  /var/log/nginx/app.smallpayroll.ca_log  main;
	error_page  404       /404.html;

	location / {
		# Because we're proxying, set some environment variables indicating this
		proxy_set_header X-Real-IP  $remote_addr;
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
		proxy_set_header Host $http_host;
		proxy_redirect false;
		proxy_max_temp_file_size 0;


		# Serve static files out of Root (eg public)
		if (-f $request_filename) {
			break;
		}

		# Handle page cached actions by looking for the appropriately named file
		if (-f $request_filename.html) {
			rewrite (.*) $1.html;
			break;
		}

		# Send all other requests to mongrel
		if (!-f $request_filename) {
			proxy_pass http://mongrel-payroll;
			break;
		}
	}
	error_page   500 502 503 504  /500.html;
	location = /500.html {
		root   /home/payroll/current/public;
	}
}


상당히 일반적인 nginx 구성을 보여 주는 Listing 11에서는 Rails 페이지 캐싱을 처리하고 동적 요청을 업스트림 mongrel에 전송하는 몇 가지 요소가 포함되어 있다. 필요한 경우 여기에서 다른 URL을 파일 이름에 맵핑할 수 있다.

구성을 완료한 후 service nginx start를 실행하면 웹 서버가 시작된다.

테스트하기

테스트를 위해서는 애플리케이션의 일반 도메인 이름을 사용하여 클라우드 인스턴스를 참조할 수 있으면 좋다. 왜냐하면 프로덕션 사이트가 아닌 테스트 사이트를 사용 중이라는 것을 보장할 수 있기 때문이다. 이 작업은 로컬 DNS 대체를 통해 수행한다. Windows의 경우 C:\windows\system32\drivers\etc\hosts를 편집하고, UNIX의 경우 /etc/hosts를 편집한다. 다음 행을 추가한다.

x.x.x.x  app.smallpayroll.ca

여기서, x.x.x.x는 클라우드 서버의 IP 주소이고, app.smallpayroll.ca는 애플리케이션의 이름이다. 브라우저를 다시 시작하고 사용자의 웹 사이트로 이동한다. 이제부터 애플리케이션의 클라우드 버전을 사용하고 있다. (프로덕션 버전으로 돌아가려면 방금 전 추가한 행을 주석으로 처리해야 한다.)

이제 프로덕션 버전뿐만 아니라 클라우드 버전의 애플리케이션이 정상적으로 작동하는지 테스트할 수 있으며 발견된 문제점이 있으면 해결한다. 두 번째 서버를 실행할 때도 활용할 수 있으므로 발견된 모든 문제점을 자세히 기록해 둔다. 클라우드 버전의 애플리케이션을 사용하고 있으므로 사용자에게 불편을 주지 않고 데이터베이스를 삭제 및 복원할 수 있다.

새 AMI 번들링하기

마지막으로 수행할 작업은 AMI를 다시 번들링하는 것이다. 새 인스턴스를 시작할 때마다 /mnt의 모든 컨텐츠가 삭제되고 루트 파티션이 AMI에 있는 디렉토리로 다시 설정된다. 아직까지는 /mnt 문제점을 해결할 수 있는 방법이 없지만 리번들링을 수행하여 AMI를 종료 시점의 상태로 유지할 수 있다.

시작 중인 AMI에 AMI 도구가 없는 경우에는 다음 명령을 실행하여 이러한 도구를 설치할 수 있다.

rpm -i --nodeps http://s3.amazonaws.com/ec2-downloads/ec2-ami-tools.noarch.rpm

AMI 번들링은 다음 3단계 프로세스로 진행된다.

  1. 인스턴스 자체에서 이미지를 작성한다.
  2. 이미지를 Amazon S3에 업로드한다.
  3. AMI를 등록한다.

다음 단계를 진행하기 전에 먼저 열려 있는 파일이 올바르게 처리되었는지 확인하기 위해 mongrel 및 PostgreSQL 인스턴스를 종료한다. 또한 Amazon Console에 있는 X.509 키를 서버의 /mnt로 복사해야 한다. Listing 12에서는 VM 자체에서 수행되는 번들링 작업의 처음 두 단계를 보여 준다.


Listing 12. AMI 번들링하기
	
# ec2-bundle-vol -d /mnt -e /mnt --privatekey /mnt/pk-mykey.pem  \
--cert /mnt/cert-mycert.pem --user 223110335193 -p centos-ertw
Please specify a value for arch [i386]:
Copying / into the image file /mnt/centos-ertw...
...
Generating digests for each part...
Digests generated.
Creating bundle manifest...
ec2-bundle-vol complete.
# ec2-upload-bundle -b ertw.com -m /mnt/centos-ertw.manifest.xml \
--secret-key MYSECRETKEY --access-key MYACCESSKEY
Creating bucket...
Uploading bundled image parts to the S3 bucket ertw.com ...
...
Uploaded centos-ertw.part.37
Uploading manifest ...
Uploaded manifest.
Bundle upload completed.

첫 번째 명령은 번들을 생성하며 -e 및 -d 옵션을 사용하여 /mnt를 무시하고 번들을 /mnt에 저장하도록 지정한다. -k--cert 및 --user 옵션은 보안 신임 정보와 AWS 사용자 ID를 가리킨다. 이러한 정보는 모두 AWS Management Console의 계정 설정에 있다. 마지막 옵션인 -p는 다른 AMI와 구별하기 위해 이 AMI의 이름을 지정하는 데 사용된다.

첫 번째 명령은 약 10분 동안 실행되며, 루트 파티션의 사용량에 따라 달라질 수 있다. 두 번째 명령은 번들을 Amazon S3에 업로드한다. -b 옵션은 버켓 이름을 지정하며, 같은 이름의 버켓이 없을 경우 새로 작성된다. -m 옵션은 마지막 단계에서 작성된 매니페스트 파일을 가리킨다. 마지막 두 옵션은 AWS Management Console에서 X.509 신임 정보 오른쪽 옆에 표시되는 Amazon S3 신임 정보이다. X.509 신임 정보는 Amazon EC2 조작에 사용되는 반면 Amazon S3에서는 텍스트 키를 사용한다는 점을 기억하기 바란다.

마지막으로 다음 명령을 실행한다.

ec2-register ertw.com/centos-ertw.manifest.xml

그러면 AMI가 등록되고 지금부터 사용할 수 있는 AMI ID가 표시된다. ec2-register 명령은 AMI와 함께 제공되지 않는다. 따라서 원본 AMI를 시작했던 서버에서 이 명령을 실행하는 것이 가장 쉬운 방법이다. 또한 Amazon EC2 인스턴스에 Amazon EC2 도구를 설치할 수 있다.

마이그레이션 수행하기

지금까지 클라우드 환경을 실행하는 방법을 살펴보았다. 마이그레이션 자체는 훨씬 간단한 작업이다. 모든 기능이 정상적으로 작동하는지 확인했으므로 이제 데이터를 다시 동기화하고 나머지 작업을 차례대로 진행하면 된다.

마이그레이션 전에 수행할 태스크

마이그레이션 전에 도메인 이름 레코드의 TTL을 5분으로 낮추었는지 확인한다. 또한 모든 항목을 이동하는 과정에서 수행할 단계에 대한 점검 목록, 모든 기능이 작동하는지 확인하기 위해 실행할 테스트 및 필요한 경우 변경 사항을 취소할 절차를 마련해 두어야 한다.

사용자에게 마이그레이션을 알렸는지 확인한다.

마이그레이션 직전에 클라우드 환경이 동기화할 준비가 되어 있고 프로덕션 트래픽을 처리할 수 있는지 다시 한번 확인한다.

애플리케이션 마이그레이션하기

애플리케이션을 마이그레이션하려면 다음 단계를 수행한다.

  1. 사이트 특성에 따라 현재 프로덕션 사이트를 사용하지 않도록 설정하거나 읽기 전용 모드로 전환한다.

    대부분의 SmallPayroll 요청에는 데이터베이스나 파일 시스템에 쓰는 작업이 포함되어 있으므로 사이트를 사용할 수 없다. Capistrano 개발 gem에는 유지보수를 위해 사이트가 종료되었음을 사용자에게 알리는 유지보수 페이지를 사이트에 배치하는 cap deploy:web:disable 태스크가 있다.

  2. 데이터 마이그레이션을 준비하기 위해 mongrel 프로세스를 종료하여 클라우드 환경의 애플리케이션 서비스를 중지한다.
  3. 테스트와 동일한 방법으로 데이터베이스를 복사한다.
  4. 필요한 경우 rsync를 다시 실행한다.
  5. 다음 명령을 사용하여 애플리케이션 서버를 다시 시작한다.
    mongrel_rails cluster::start -C /home/payroll/current/config/mongrel_cluster.yml
    

  6. hosts 파일이 클라우드 환경을 가리키고 있는지 확인하고 몇 가지 스모크 테스트를 수행한다. 사용자가 사이트에 로그인하여 탐색할 수 있는지 확인한다.

DNS 업데이트하기

스모크 테스트를 통과한 후에는 클라우드 환경을 가리키도록 DNS 레코드를 변경할 수 있다. 이 시점에서 웹 서버의 로그 파일에 대해 tail -f를 실행 중인 상태로 유지하면 사이트에 액세스하는 사용자를 확인할 수 있기 때문에 유용하다.

로컬 DNS 서버에는 기존 정보가 이후 5분 동안 캐싱된 상태로 유지되어 있으므로 dig 명령을 사용하여 이 정보를 확인할 수 있다(Listing 13 참조).


Listing 13. DNS 서버가 쿼리를 캐싱하고 있는지 확인하기
	
# dig  app.smallpayroll.ca @172.16.0.23

; <<>> DiG 9.3.4 <<>> app.smallpayroll.ca @172.16.0.23
; (1 server found)
;; global options:  printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 38838
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 13, ADDITIONAL: 0

;; QUESTION SECTION:
;app.smallpayroll.ca.           IN      A

;; ANSWER SECTION:
app.smallpayroll.ca.    251     IN      A       69.164.205.185
...

ANSWER 섹션을 보면 항목이 251초 만에 만기된다는 것을 알 수 있다. 현재는 hosts 파일이 DNS를 대체하고 있으므로 dighost 또는 nslookup과 같은 도구를 사용하여 DNS를 확인하는 것이 중요하다. ping을 사용하여 hosts 내의 항목을 확인할 수도 있다.

DNS가 전파하기를 기다리면서 최종 승인 테스트를 수행한다.

결론

지금까지 애플리케이션을 클라우드에 마이그레이션했다. 기본 절차는 다음과 같다.

  1. 새 환경을 설정한다.
  2. 프로덕션 데이터의 사본을 사용하여 테스트한다.
  3. 기존 환경을 끈다.
  4. 프로덕션 데이터를 새 환경에 복사한다.
  5. 새 환경을 가리키도록 DNS를 변경한다.

"클라우드에" 있음에도 불구하고 아마도 애플리케이션의 성능이 예전보다 좋지 않을 것이다. 다음과 같은 사항을 생각해 보자.

  • 애플리케이션이 여전히 하나의 서버에서 실행되고 있다.
  • 서버에서 충돌이 발생할 경우 모든 데이터가 손실된다.
  • 실제 서버를 사용할 때보다 성능을 제어할 수 있는 기능이 적다.
  • 시스템 및 애플리케이션이 잠기지 않는다.
----

Amazon 클라우드에 Linux 애플리케이션 마이그레이션하기, Part 2: 신뢰성 향상시키기

마이그레이션한 Linux 애플리케이션의 신뢰성을 향상시키는 방법

Sean Walberg, Senior Network Engineer, 自由职业者
Sean A. Walberg, Senior Network Engineer

요약: Linux 애플리케이션을 Amazon 클라우드로 마이그레이션하는 방법을 살펴보는 시리즈의 두 번째 기사인 이 기사에서는 로드 밸런서 및 지속적 디스크를 사용하여 애플리케이션의 신뢰성을 향상시키는 방법에 대해 살펴봅니다. 여러 서버를 사용하게 되며 데이터를 안전하게 백업하는 방법을 배울 수 있습니다.

이 연재 자세히 보기

이 기사에 테그:  리눅스마이그레이션

원문 게재일:  2010 년 8 월 03 일 
번역 게재일:   2010 년 11 월 09 일 
난이도:  중급 
영어로:  보기 
페이지뷰: 2883 회 
의견: 0 (의견 추가)

1 star2 stars3 stars4 stars5 stars 평균 평가 등급 (총 6표)

이 시리즈의 첫 번째 기사에서는 단일 실제 서버를 실제 단일 클라우드 서버로 마이그레이션하는 방법을 살펴보았다. 모든 작업을 마치긴 했지만 여러 단일 오류 지점이 발생하여 애플리케이션의 성능이 크게 향상되지 않았다.

단일 실제 서버라고 하더라도 중복 전원 공급장치, 오류 수정 RAM, 중복 디스크 및 오류 전 표시기를 이용한 다양한 모니터링 기능을 사용할 수 있다. 클라우드 서버에서는 사용자가 사용자에게 제공된 기능 더 나아가 사용자가 액세스할 수 있는 기능에 대해 모르고 있다. 클라우드 서버는 일반적으로 신뢰할 수 있지만 주의를 기울이는 것이 현명하다. 특히, Amazon에서는 신뢰성 향상을 위해 추가 서비스를 제공하고 있기 때문이다.

클라우드 환경에 배치할 경우에는 가상 인스턴스가 언제라도 손실될 수 있다는 점을 염두에 두어야 한다. 이는 클라우드 서비스가 신뢰할 수 없는 서비스라는 의미가 아니며, 단지 발생하는 오류의 유형이 실제 환경에서 자주 발생하던 오류와 다르다는 의미이다. 따라서 애플리케이션에 지능을 불어넣어서 통신 손실을 처리하고 여러 서버로 확장해야 한다. 이렇게 생각하면 빌드 중인 환경의 유형에 상관 없이 보다 나은 애플리케이션을 빌드할 수 있다.

이 기사에서는 Amazon EBS(Elastic Block Store)를 사용하여 데이터베이스의 임시 스토리지를 향상시키는 방법에 대해 설명한다. 백업을 설정하여 데이터 보호 성능을 향상시킬 수 있다. 여러 인스턴스를 이용한 로드 밸런싱을 수행하면 다양한 오류로부터 복구할 수 있으며, 결과적으로 애플리케이션 서버 손실을 방지할 수 있다.

그림 1에서는 지난 기사에서 마무리했던 시점의 애플리케이션 아키텍처를 보여 준다.


그림 1. 현재 아키텍처
현재 아키텍처 

모든 기능이 하나의 Amazon EC2(Amazon Elastic Compute Cloud) 인스턴스에 있다. 프론트엔드 웹 서버인 nginx는 여러 mongrel 인스턴스에 대한 요청을 프록시하거나 정적 파일 자체를 제공한다. mongrel 애플리케이션 서버는 같은 호스트에 있는 PostgreSQL 데이터베이스에 액세스한다.

지속적 디스크 구성하기

인스턴스 스토리지는 Amazon EC2와 VMware 및 Xen 같은 가상 기술 사이의 가장 큰 차이점이다. Amazon EC2 인스턴스는 고정된 10GB 용량의 루트 파티션과 실행된 인스턴스의 유형에 따라 크기가 결정되는 인스턴스 디스크를 제공한다. 루트 파티션은 부팅할 때 AMI(Amazon Machine Image)에서 복제되고 인스턴스 저장소는 비어 있다. 서버를 종료하면 인스턴스 저장소가 삭제된다.

Amazon에서는 초기에 사용자에게 서버를 Amazon S3(Amazon Simple Storage Service)에 자주 백업하도록 안내했다. 서버에서 충돌이 발생할 경우 다른 서버를 사용하여 로드를 처리하거나 Amazon S3에서 사용자의 데이터를 가져올 수 있다. 마침내 Amazon에서는 지속적 디스크를 제공하는 서비스인 EBS를 사용하여 이 문제를 해결했다. 서버에서 충돌이 발생할 경우 EBS 볼륨을 다른 서버에 다시 연결할 수 있다. Amazon에서는 백업을 지원하기 위해 스냅샷 메커니즘도 개발했다.

SmallPayroll 애플리케이션에서 데이터베이스 서버와 관련하여 주된 문제점은 데이터베이스 서버가 단일 오류 지점이라는 것이다. 이 문제점을 해결하는 데는 일반적으로 두 가지 방법이 사용된다. 첫 번째 방법은 서로를 대체할 수 있는 두 개의 데이터베이스 서버를 빌드하는 것이며, 두 번째 방법은 잠재적 중단 시간을 합리적인 수준으로 낮추는 것이다. 첫 번째 방법의 경우에는 중단 시간이 최소화되지만 복잡하다. 두 번째 방법은 이 상황에서 훨씬 더 실용적이다. 데이터베이스 서버에서 충돌이 발생할 경우 새 인스턴스가 시작되어 기존 인스턴스를 대체한다. EBS가 데이터를 안전하게 유지한다. 새 데이터베이스 서버를 실행하고 클라이언트를 다시 지정하는 데 걸리는 총 시간은 오류가 통지된 시간부터 10분 미만이어야 한다. 마지막 보너스로 EBS 스토리지는 인스턴스 스토리지보다 높은 I/O 용량을 제공한다.

EBS의 신뢰성은 높은가?

연결된 인스턴스가 종료되더라도 지속적으로 존재하는 EBS 볼륨이지만 100% 신뢰할 수 있는 솔루션은 아니다. EBS 볼륨은 오류에 대처하기 위해 단일 가용성 영역(처음으로 EBS 설정하기 참조) 내에서 복제된다. 하지만 그 이상으로 복제되지는 않는다. 또한 오류가 발생할 수 있을 뿐만 아니라 발생한다.

Amazon에 따르면 EBS 오류 비율은 볼륨의 크기와 변경 빈도에 따라 달라진다. Amazon에 따르면 EBS 볼륨의 신뢰성이 실제 디스크보다 10배 더 높으며, 이는 RAID 1 미러와 거의 동일한 수준의 신뢰성이다.

다행스럽게도 EBS API(Application Programming Interface)는 데이터 스냅샷을 Amazon S3로 이동하는 메커니즘을 제공한다. 이 기능을 사용하면 볼륨의 백업을 빠르게 작성하고 Amazon S3에 저장할 수 있으며, 이 과정 속에서 데이터는 적어도 세 개의 장치를 거치면서 복제된다.

EBS를 사용하려면 다음 단계를 수행한다.

  1. ec2-create-volume 명령을 사용하여 볼륨을 작성한다.
  2. ec2-attach-volume 명령을 사용하여 볼륨을 실행 중인 인스턴스에 연결한다.
  3. 볼륨에 파일 시스템을 작성한다.
  4. 파일 시스템을 디렉토리에 마운트한다.

처음으로 EBS 설정하기

EBS를 설정하려면 먼저 볼륨을 작성하고 싶다는 사용자의 의사를 Amazon에 알려야 한다. 이를 위해서는 두 가지 사항 즉, 이미지 크기(GB 단위)와 이미지를 사용할 가용성 영역을 알아야 한다. 가용성 영역은 서버의 위치를 설명하기 위해 Amazon에서 사용하는 용어이다. us-east로 시작하는 영역은 북 버지니아 주에 있으며 총체적으로 지역이라고 부른다. 현재 us-east 지역에는 us-east-1a, us-east-1b 및 us-east-1c라는 세 개의 영역이 있다. 각 가용성 영역은 다른 가용성 영역의 오류에 영향을 받지 않도록 설계되었다. 동일한 지역 내의 영역은 서로 가깝기 때문에 지연 시간도 짧다.

EBS의 한 가지 제한사항은 볼륨이 작성된 가용성 영역에서만 볼륨을 마운트할 수 있다는 것이다. 여러 가지 방법으로 볼륨을 이동할 수는 있지만 서버와 동일한 가용성 영역에 볼륨을 작성해야 한다.

다음 명령을 실행한다.

ec2-create-volume -s 20 -z us-east-1a

그러면 us-east-1a 영역에 20GB 볼륨이 작성된다. 서버의 위치를 모르는 경우에는 ec2-describe-instances 명령을 실행하여 서버의 위치를 알 수 있다.ec2-run-instance에 동일한 -z 매개변수를 사용하여 서버의 실행 위치를 지정할 수 있다. Listing 1에서는 이 명령과 해당 출력을 보여 준다.


Listing 1. EBS 볼륨 작성하기
	
$ ec2-create-volume -s 20 -z us-east-1a
VOLUME  vol-c8791ca1    20              us-east-1a      creating     
2010-07-01T02:52:52+0000

Listing 1의 출력을 보면 볼륨이 작성 중이고 볼륨 ID가 vol-c8791ca1이라는 것을 알 수 있다. 서버의 인스턴스 ID와 서버에서 볼륨으로 인식할 장치를 알고 있으면 이 정보를 사용하여 볼륨을 실행 중인 Amazon EC2 인스턴스에 연결할 수 있다. 다음 명령을 실행한다.

ec2-attach-volume vol-c8701ca1 -i i-fd15e097 -d /dev/sdj

그러면 새로 작성된 이 볼륨이 서비스 인스턴스 i-fd15e097에 연결된다. 인스턴스 ID는 ec2-describe-instances 명령을 통해 확인할 수 있으며 볼륨 목록은 ec2-describe-volumes를 사용하여 확인할 수 있다.

이제 가상 서버에 일반적인 하드 디스크처럼 보이는 /dev/sdj라는 디스크가 표시된다. 디스크를 사용하려면 먼저 원시 디스크에 파일 시스템을 작성해야 한다. 필요에 따라 다음과 같은 여러 방법을 사용할 수 있다.

  • 표준 ext3(third extended) 파일 시스템을 작성한다.
  • XFS 파일 시스템을 작성한다. 이렇게 하면 파일 시스템을 고정한 상태에서 백업 목적의 스냅샷을 작성할 수 있다.
  • 디스크와 파일 시스템 사이에 LVM(Logical Volume Manager)을 배치한다. 이렇게 하면 EBS 볼륨을 나중에 확장할 수 있다.
  • Linux® 소프트웨어 RAID를 사용하여 여러 EBS 볼륨을 스트라이프하고 RAID 세트 위에 XFS 또는 ext3를 배치한다. 이렇게 하면 디스크 성능이 향상된다.

RAID와 LVM의 기능이 흥미롭기는 하지만 비교적 작은 EBS 볼륨일 경우에는 XFS가 가장 쉬운 옵션이다. XFS의 고정 기능과 EBS 스냅샷을 함께 사용하여 일관된 백업을 작성할 수 있다. Listing 2에서는 XFS 파일 시스템을 작성하고 호스트에 마운트하는 방법을 보여 준다.


Listing 2. XFS 파일 시스템 작성 및 마운트하기
	
# mkfs.xfs /dev/sdj
meta-data=/dev/sdj               isize=256    agcount=8, agsize=32768 blks
         =                       sectsz=512   attr=0
data     =                       bsize=4096   blocks=262144, imaxpct=25
         =                       sunit=0      swidth=0 blks, unwritten=1
naming   =version 2              bsize=4096
log      =internal log           bsize=4096   blocks=2560, version=1
         =                       sectsz=512   sunit=0 blks, lazy-count=0
realtime =none                   extsz=4096   blocks=0, rtextents=0
# mkdir /ebsvol
# mount /dev/sdj /ebsvol

Listing 2에서는 mkfs.xfs 명령을 실행하여 /dev/sdj를 포맷한다. (mkfs.xfs 명령이 없으면 gem install -y xfsprogs를 실행한다.) 이 명령의 출력은 파일 시스템의 매개변수를 설명한다. 출력에 오류가 없으면 무시할 수 있다. Listing 2의 마지막 두 명령은 /ebsvol이라는 마운트 지점을 작성한 다음 파일 시스템을 마운트 지점에 마운트한다.

이제 파일 시스템을 사용할 수 있다. /ebsvol에 있는 모든 파일은 서버가 종료되도 유지된다.

EBS 볼륨 사용하기

이제 EBS 볼륨이 /ebsvol에 마운트되어 있으며 PostgreSQL 데이터를 이동해야 한다. 이 작업을 가장 간단하게 수행하는 방법은 기존 데이터 저장소를 복사한 후 symlink를 사용하여 수정하는 것이다. 이 방법을 사용할 수도 있겠지만 EBS 볼륨의 데이터를 /var/lib/pgsql로 복제하는 것이 가장 확실한 방법이다. Listing 3에서 이 절차를 보여 준다.


Listing 3. PostgreSQL 데이터를 EBS 볼륨으로 이동하기
	
# service postgresql stop
# mv /var/lib/pgsql /ebsvol
# mkdir /var/lib/pgsql
# chown postgres:postgres /var/lib/pgsql
# mount /ebsvol/pgsql /var/lib/pgsql -o bind
# service postgresql start

Listing 3의 명령 시퀀스는 다음과 같다.

  1. 데이터 일관성을 보장하기 위해 PostgreSQL 디먼을 중지한다.
  2. 전체 디렉토리 트리를 EBS 저장소로 이동한다.
  3. PostgreSQL 디렉토리를 다시 작성한다.
  4. PostgreSQL 디렉토리의 소유권을 다시 설정한다.
  5. mount의 bind 옵션을 사용하여 /ebsvol/pgsql을 /var/lib/pgsql에 마운트한다.
  6. 데이터베이스를 다시 시작한다.

mount의 bind 옵션은 첫 번째 디렉토리를 두 번째 디렉토리에 복제한다. 한 디렉토리의 변경 사항이 다른 디렉토리에도 표시된다. 결국, 두 디렉토리는 동일한 디스크에 있는 동일한 블록이다. bind를 사용하는 것은 전체 파일 시스템 대신 서브디렉토리를 마운트할 수 있다는 점에서 동일한 장치를 두 번 마운트하는 것과 다르다.

충돌로부터 복구하기

서버에서 충돌이 발생한 경우 다음 단계를 수행한다.

  1. 사용자의 AMI를 사용하여 새 인스턴스를 시작한다.
  2. ec2-attach-volume을 사용하여 EBS 볼륨을 인스턴스에 연결한다.
  3. EBS 장치를 /ebsvol에 마운트한다.
  4. Listing 3의 마지막 네 개의 명령을 수행한다.

AMI를 최근에 번들링했다면 데이터베이스 시스템도 최신 상태이다.

애플리케이션 서버 작업하기

클라우드 컴퓨터의 장점 중 하나는 서버 용량에 쉽게 액세스할 수 있다는 것이다. 현재 SmallPayroll.ca 환경에서는 데이터베이스 및 애플리케이션 서버가 동일한 가상 인스턴스에 있다. 이는 Amazon EC2로 마이그레이션하기 전과 같다. 다음으로 수행할 단계는 애플리케이션 서버와 데이터베이스 서버를 분리하는 것이다.

확장 및 로드 밸런싱

확장이라는 용어는 일반적으로 용량과 관련된다. 애플리케이션을 확장할 수 있다는 말은 애플리케이션을 확장하여 더 많은 사용자 로드를 처리할 수 있다는 것을 의미한다. 서버를 추가하여 확장하는 경우를 수평적 확장이라고 하며, 서버를 더 큰 서버로 교체하여 로드를 처리하는 경우를 수직적 확장이라고 한다.

수평적 및 수직적 확장은 서로 결합하여 사용할 수 있다. 더 큰 서버와 빠른 디스크를 사용하여 데이터베이스 용량 문제점을 해결하고 여러 서버에 계산 로드를 분산시키는 것이 더 쉬울 것이다. 수평적 또는 수직적 확장의 가능성은 주로 애플리케이션 설계에 달려 있다. 여러 컴퓨터에 분산시킬 수 없는 애플리케이션도 있었으며, 컴퓨터의 속도와 상관 없이 일정 수준의 시간이 소요되는 작업도 있다. 또한 일부 애플리케이션의 경우에는 병목 현상으로 인해 서버 추가의 장점을 얻을 수 없는 수준까지 수평적으로 확장할 수 있다.

애플리케이션을 여러 서버에 분산시킬 경우 수신 요청을 분배하는 방법과 관련된 문제가 발생한다. 이 작업을 수행하는 데 주로 사용되는 장치가 로드 밸런서이다. 이 장치는 외부에서 들어오는 요청을 받아서 사용 가능한 다음 애플리케이션 서버로 전달하는 역할을 수행한다. 이 작업은 집약적인 태스크가 아니기 때문에 단일 장치가 많은 수의 연결을 처리할 수 있으며, 소프트웨어로도 이 기능을 처리할 수 있다.

Amazon EC2에서는 대부분의 용도에 적합한 Elastic Load Balancing이라는 클라우드 로드 밸런서를 제공한다. 이 밸런서는 요청을 분배하고, API를 통해 서버를 추가 또는 제거하도록 재구성할 수 있으며, 백엔드 서버에 대한 상태 검사를 수행한다.

Elastic Load Balancing을 사용하는 대신 Amazon EC2 인스턴스에서 HAProxy 또는 Varnish(자세한 정보는 참고자료의 링크 참조)와 같은 사용자의 로드 밸런싱 소프트웨어를 실행할 수도 있다. 이 프로세스는 Elastic Load Balancing을 사용할 때보다 복잡하지만 사용자의 트래픽에 대해 높은 수준의 제어가 가능하다. Elastic Load Balancing은 SmallPayroll.ca와 같은 애플리케이션에 더 적합하다.

그림 2에서는 SmallPayroll.ca 애플리케이션의 새 설계를 보여 준다.


그림 2. 별도의 애플리케이션 서버가 있는 SmallPayroll.ca 애플리케이션
새로운 SmallPayroll.ca 애플리케이션 

수신 요청은 Elastic Load Balancing을 거쳐서 두 서버 중 하나로 전송된다. 서버 자체에서는 nginx를 실행하여 정적 요청을 처리하고 동적 요청을 mongrel 인스턴스로 프록시한다. mongrel은 단일 데이터베이스 서버에 연결되어 있다.

애플리케이션 서버 중 하나가 작동하지 않으면 Elastic Load Balancing이 모든 트래픽을 다른 서버로 리디렉션한다.

새 인스턴스 실행하기

별도의 애플리케이션 서버를 빌드하려면 두 개 이상의 인스턴스를 실행해야 한다. 이 경우에는 앞에서 사용한 AMI를 사용할 수 있다. 왜냐하면 이 AMI에 필요한 모든 데이터가 포함되어 있기 때문이다. 동시에 두 개 이상의 인스턴스를 실행할 수 있다. Listing 4에서는 하나의 명령으로 두 개의 인스턴스를 실행하는 방법을 보여 준다.


Listing 4. 동시에 두 개의 인스턴스 실행하기
	
$ ec2-run-instances ami-147f977d -k main -z us-east-1a \
-d 'role=web,db=10.201.207.180' -n 2
RESERVATION     r-9cc240f7      223410055806    default
INSTANCE        i-81ee2eeb      ami-147f977d    pending main ...
INSTANCE        i-87ee2eed      ami-147f977d    pending main ...

ec2-run-instances 명령은 과거에 사용했던 명령과 유사하다. 데이터베이스 서버가 같은 지역에 있기 때문에 가용성 영역이 -z us-east-1a로 선택된다. 이 경우 지연 시간과 대역폭 비용을 줄이기 위해 데이터베이스 서버와 애플리케이션 서버를 같은 가용성 영역에 둘 수 있다.

하지만 -d 및 -n 매개변수는 새로운 매개변수이다. -n 2 매개변수는 두 개의 인스턴스를 실행하도록 Amazon에 지시하며, 출력을 통해 결과를 확인할 수 있다. -d 매개변수는 인스턴스에 정보를 전달하는 데 사용된다. Listing 5에서는 새 인스턴스에서 이 정보를 검색하는 방법을 보여 준다.


Listing 5. 인스턴스 메타데이터 검색하기
	
[root@domU-12-31-39-0C-C5-B2 ~]# DATA=`curl -s http://169.254.169.254/latest/user-data`
[root@domU-12-31-39-0C-C5-B2 ~]# echo $DATA
role=web,db=10.201.207.180

curl 명령은 Amazon EC2 서비스에서 사용자 데이터가 포함된 웹 페이지를 검색한다. 이 방법은 이 시리즈의 이전 기사에서 서버의 SSH(Secure Shell) 키를 검색했던 방법과 비슷하다.

애플리케이션 서버 구성하기

복제된 AMI에 로컬 데이터베이스에 대해 애플리케이션을 실행할 수 있는 기능이 이미 갖추어져 있기 때문에 애플리케이션 서버에서 수행할 작업은 많지 않다. Rails 애플리케이션은 애플리케이션에게 사용할 데이터베이스를 알려 주는 config/database.yml에서 데이터베이스 구성을 읽어온다. 기본적으로 애플리케이션은 localhost에 연결한다.

먼저 /etc/hosts에 항목을 추가하여 DNS 별명을 작성한다. 예를 들어, 10.201.207.180 dbserver는 dbserver라는 이름을 IP 주소인 10.201.207.180의 별명으로 설정한다. 여기에서 중요한 점은 사용자가 연결한 공용 주소 대신 eth0에 지정된 개인용 주소를 데이터베이스의 주소로 사용해야 한다는 것이다. 동일한 영역 내에서 Amazon EC2 인스턴스의 개인용 주소 간 트래픽은 무료이지만 Amazon EC2 인스턴스와 다른 인스턴스의 공용 주소 간의 트래픽에는 비용이 부과된다.

다음으로 애플리케이션을 가리키는 database.yml 파일을 앞에서 작성한 DNS 별명에 추가한다. 그러한 구성을 Listing 6에서 보여 준다.


Listing 6. 애플리케이션에게 데이터베이스 서버 알려주기
	
production:
  adapter: postgresql
  encoding: utf8
  database: payroll_prod
  pool: 5
  username: payroll
  password:  secret
  host: dbserver

세션 친화성(Session affinity)

세션 지속성이라고도 하는 세션 친화성은 어느 클라이언트가 어느 서버와 통신 중이었는지 추적하는 로드 밸런서의 기능이다. 다음 번에 해당 클라이언트가 요청을 보내면 동일한 백엔드 웹 서버로 요청이 리디렉션된다. 따라서 이 기능을 사용하면 애플리케이션에서 로컬 RAM 또는 디스크에 항목을 유지할 수 있으며 풀의 모든 멤버가 정보를 공유하지 않아도 된다.

세션 친화성이 정상적으로 작동하지 않을 경우에는 사용자가 애플리케이션에서 임의로 로그아웃되거나 입력이 누락된 것처럼 표시되는 현상이 나타난다. 이러한 경우 요청을 받은 서버에서는 세션 데이터와 같은 정보가 누락된다. 왜냐하면 해당 정보가 다른 컴퓨터에 있기 때문이다.

친화성을 요구하거나 사용자가 직접 문제점을 해결할 수 있다. Memcached와 같은 분산 캐시는 어느 서버에서 액세스하는지를 고려하지 않는다. 세션 데이터를 데이터베이스나 분산 캐시에 저장할 수 있다. 또한 보안 요구에 따라 클라이언트 쿠키 내에 정보를 저장할 수도 있다.

Rails 애플리케이션을 실행하고 애플리케이션 서버의 공용 IP 주소를 통해 이 애플리케이션에 연결할 수 있어야 한다. 오류가 발생할 경우에는 다음을 확인한다.

  • PostgreSQL이 모든 인터페이스에서 청취하고 있는가? postgresql.conf 파일에 listen_addresses="*"와 같은 행이 있어야 한다.
  • pg_hba.conf 파일에서 MD5 인증을 이용한 10/8 주소 연결을 허용하는가?
  • 사용자의 Amazon 보안 그룹에서 데이터베이스 서버에 대한 연결을 허용하는가?

로드 밸런서 작성하기

Elastic Load Balancing은 상당히 단순한 로드 밸런서이다. 이 로드 밸런서는 수신된 요청을 풀에 있는 사용 가능한 서버로 전달한다. Elastic Load Balancing에서는 작동하지 않는 서버에 요청을 전달하는 경우를 피하기 위해 웹 서버에 대한 기본적인 상태 검사를 수행할 수 있다. 또한 사용자를 동일한 백엔드 서버에 유지할 수 있도록 지원하는 기본적인 친화성 메커니즘을 가지고 있다. URL 기반의 리디렉션과 같은 고급 기능은 아직까지 지원되지 않는다.

Elastic Load Balancing은 다음 세 단계 프로세스를 통해 구성한다.

  1. 로드 밸런싱 인스턴스를 작성한다.
  2. 상태 검사를 정의한다.
  3. Elastic Load Balancing 이름을 가리키도록 DNS를 구성한다.

Listing 7에서는 처음 두 단계를 보여 준다.


Listing 7. Elastic Load Balancing 인스턴스 구성하기
	
$ elb-create-lb smallpayroll-http \
	--listener "lb-port=80,instance-port=80,protocol=HTTP" \
	--availability-zones us-east-1a
DNS_NAME  DNS_NAME
DNS_NAME  smallpayroll-http-706414765.us-east-1.elb.amazonaws.com
$ elb-configure-healthcheck smallpayroll-http --target "HTTP:80/" \
     --interval 30 --timeout 3 --unhealthy-threshold 2 --healthy-threshold 2
HEALTH_CHECK  TARGET    INTERVAL  TIMEOUT  HEALTHY_THRESHOLD  UNHEALTHY_THRESHOLD
HEALTH_CHECK  HTTP:80/  30        3        2                  2

Listing 7에서는 두 가지 명령을 보여 준다. 첫 번째 명령인 elb-create-lb는 로드 밸런서를 작성한다. 첫 번째 매개변수는 사용자에게 고유한 로드 밸런서의 이름이다. --listener 매개변수는 공용 포트가 80이고, 인스턴스의 포트 80에 연결되며, 사용 중인 프로토콜이 HTTP임을 알려 준다. 이 명령의 출력은 DNS 이름이며, 이 경우에는 smallpayroll-http-706414765.us-east-1.elb.amazonaws.com이다. 대부분의 로드 밸런서와는 달리 연결할 공용 IP 주소가 제공되지 않는다. Amazon에서 고유한 IP 주소를 지정하며 사용자는 DNS 별명을 통해 연결한다.

두 번째 명령인 elb-configure-healthcheck는 먼저 로드 밸런서의 이름을 참조한 다음 루트 URL을 사용하여 포트 80의 HTTP 프로토콜을 통해 상태 검사를 수행할 것임을 지정한다. 또한 /status와 같은 별도의 제어기와 조치를 작성하여 검사를 처리할 수도 있지만 이 경우에는 루트 URL이 애플리케이션의 올바른 실행을 충분히 보장한다.

두 번째 행의 매개변수에서 지정하는 내용을 차례로 살펴보면 다음과 같다.

  • --interval 30. 30초마다 테스트한다.
  • --timeout 3. 테스트 실패 전까지 애플리케이션에서 응답을 기다려야 하는 시간이다.
  • --unhealthy-threshold 2. 테스트가 두 번 연속 실패하면 해당 서버가 서비스를 제공하지 않는 것으로 표시된다.
  • --healthy-threshold 2. 실패한 서버가 풀에 다시 포함되려면 두 번의 검사에 연속해서 성공해야 한다.

다음으로 수행할 단계는 인스턴스를 로드 밸런서에 연결하는 것이다(Listing 8 참조). 사용자 마음대로 인스턴스를 추가 및 제거할 수 있다.


Listing 8. 로드 밸런서에 두 개의 인스턴스 추가하기
	
$ elb-register-instances-with-lb smallpayroll-http --instances i-87f232ed,i-85f232ef
INSTANCE_ID  INSTANCE_ID
INSTANCE_ID  i-85f232ef
INSTANCE_ID  i-87f232ed
$ elb-describe-instance-health smallpayroll-http --headers
INSTANCE_ID  INSTANCE_ID  STATE      DESCRIPTION  REASON-CODE
INSTANCE_ID  i-85f232ef 	InService  N/A					N/A
INSTANCE_ID  i-87f232ed		InService  N/A					N/A

Listing 8에서는 먼저 두 개의 인스턴스를 smallpayroll-http 로드 밸런서에 추가한다. elb-describe-instance-health 명령을 실행하여 풀에 있는 각 서버의 상태를 확인한다. InService는 서비스가 로드 밸런서를 통해 수신되는 요청을 처리할 수 있다는 것을 의미한다.

마지막으로 로드 밸런서의 DNS 이름으로 이동한다. 두 서버에서 작동 중인 애플리케이션이 보여야 한다. 로드 밸런서가 애플리케이션의 실제 DNS 이름에 해당하는 작업을 수행하도록 하기 위해 애플리케이션의 DNS 레코드를 A 레코드에서 로드 밸런서의 DNS 이름을 가리키는 CNAME으로 변경한다. 일부 경고를 포함하여 DNS 요구사항에 대한 자세한 정보를 보려면 참고자료를 참조한다. DNS 방법이 번거롭기는 하지만 이 방법을 사용하면 Amazon EC2 인스턴스에 로드 밸런서를 빌드하여 예전보다 훨씬 더 많은 수의 요청을 처리할 수 있다. 서비스 중단이 없을 것이므로 DNS 변경이 언제라도 발생할 수 있다.

데이터 백업하기

이제 애플리케이션이 두 노드에 설치되어 있고 30분 이내에 데이터베이스 서버를 처음부터 시작할 수 있다. 이러한 구성은 가용성에 많은 도움이 되지만 관리자가 실수로 중요 데이터를 삭제하거나 EBS 볼륨이 실패할 경우에는 도움이 되지 못한다. 다행스럽게도 이러한 문제점을 해결할 수 있는 솔루션이 있다.

데이터베이스 백업하기

EBS에는 볼륨 사본을 Amazon S3에 저장하는 스냅샷 기능이 있다. 정확히 말해서 EBS 스냅샷은 마지막 스냅샷 이후의 차이점을 저장한다. 데이터베이스는 문제를 복잡하게 만든다. 왜냐하면 데이터베이스는 일부 디스크 쓰기를 캐싱하는데 이로 인해 일관되지 않은 스냅샷이 작성될 수 있기 때문이다. 따라서 모든 내용이 디스크에 일관된 상태로 있는지 확인해야 한다(Listing 9 참조). 백업의 순서는 다음과 같다.

  1. PostgreSQL에게 백업 모드로 전환하도록 지시한다.
  2. 파일 시스템을 고정한다.
  3. Amazon에 스냅샷을 요청한다.
  4. 파일 시스템을 고정 해제한다.
  5. PostgreSQL에게 백업 완료를 알린다.

이 절차는 1-2분 밖에 소요되지 않지만 Amazon에서는 백그라운드로 스냅샷을 Amazon S3에 스풀링한다. 하지만 3단계 이후에 적용된 변경 사항은 스냅샷에 반영되지 않는다.


Listing 9. 데이터베이스 백업하기
	
#!/bin/sh
export EC2_HOME=/usr/local/
export JAVA_HOME=/usr
export EC2_CERT="/root/.ec2/cert.pem"
export EC2_PRIVATE_KEY="/root/.ec2/pk.pem"
echo "select pg_start_backup('snapshot')" | su - postgres -c psql
/usr/sbin/xfs_freeze -f /ebsvol/
/usr/local/bin/ec2-create-snapshot vol-93f77ffa --description "`date`"
/usr/sbin/xfs_freeze -u /ebsvol/
echo "select pg_stop_backup('snapshot')" | su - postgres -c psql

ec2-describe-snapshots 명령을 사용하여 스냅샷의 상태를 확인할 수 있다(Listing 10 참조).


Listing 10. EBS 스냅샷 보기(요약)
	
$ ec2-describe-snapshots --headers
                SnapshotId      VolumeId        Status          StartTime
SNAPSHOT        snap-298cb741   vol-93f77ffa    completed       2010-06-29T02:50:55
SNAPSHOT        snap-a2b959c9   vol-93f77ffa    completed       2010-07-13T15:14:54

Listing 10에서는 두 개의 완성된 스냅샷과 해당 시간을 보여 준다.

cron에서 Listing 9를 실행하여 스냅샷 작성을 자동화해야 한다. 또한 ec2-delete-snapshot 명령을 사용하여 스냅샷 목록을 주기적으로 삭제해야 한다.

데이터베이스 복원하기

EBS 볼륨이 실패하거나 EBS의 기존 데이터를 복원해야 하는 경우에는 마지막 스냅샷을 사용해서 복원해야 한다. EBS 볼륨을 복원하는 절차는 새 볼륨을 작성하는 것과 거의 동일하다. Listing 11에서는 Listing 10의 마지막 스냅샷을 복원하는 방법을 보여 준다.


Listing 11. EBS 스냅샷 복원하기
	
$ ec2-create-volume --snapshot snap-a2b959c9 -z us-east-1a -s 20
VOLUME  vol-d06b06b9    20      snap-a2b959c9   us-east-1a      creating

그런 다음 이 볼륨을 인스턴스에 마운트하여 데이터를 복원할 수 있다.

파일 백업 및 복원하기

서버의 파일을 손쉽게 백업하는 방법은 파일을 Amazon S3에 복사하거나 사용자의 AMI에 포함시키는 것이다. 두 번째 방법은 2진 및 소프트웨어 패키지에 적합한 반면 Amazon S3에 복사하는 방법은 사용자 데이터에 적합하다. S3Sync 도구는 사용하기 쉬운 rsync 형태의 유틸리티와 함께 몇 가지 명령행 Amazon S3 도구를 제공한다.

S3Sync 유틸리티를 다운로드한다(참고자료에서 링크를 볼 수 있다). Listing 12에서는 백업을 위한 버켓을 작성하는 방법과 파일을 Amazon S3에 업로드하는 방법을 보여 준다.


Listing 12. Amazon S3에 데이터 백업하기
	
$ s3cmd.rb  createbucket smallpayroll-backup
$ s3cmd.rb listbuckets
ertw.com
smallpayroll-backup
$ s3sync.rb  -r /var/uploads smallpayroll-backup:`date +%Y-%m-%d`
$ s3cmd.rb list smallpayroll-backup:2010-07-12
--------------------
2010-07-12/uploads
2010-07-12/uploads/file1.txt

Listing 12에서는 먼저 smallpayroll-backup이라는 버켓을 작성한다. 다른 시간에 다른 백업을 같은 버켓에 안전하게 저장할 수 있으므로 이 단계는 한 번만 수행한다. 두 번째 명령은 버켓이 작성되었음을 확인한다. 방금 작성한 버켓과 AMI가 있는 ertw.com bucket 버켓을 볼 수 있다.

s3sync.rb 명령은 /var/uploads 디렉토리를 백업 버켓에 재귀적으로 복사하면서 모든 파일의 접두부에 현재 날짜를 추가한다. 마지막 명령은 버켓 내의 모든 파일을 보여 준다.

파일 복원은 매우 간단하다. 예약된 매개변수와 함께 S3Sync를 사용하거나 Amazon S3 File Manager(참고자료 참조)와 같은 또 다른 도구를 통해 개별 파일을 검색할 수 있다.

결론

SmallPayroll 애플리케이션은 클라우드에서 실행되고 있으며 향후 확장을 고려하여 설계되었다. 하드웨어 오류 간의 평균 시간이 변경되지는 않았지만 백업 및 스크립트가 보강되었으므로 데이터를 안전하게 보호할 수 있고 필요한 경우 환경을 빠르게 다시 빌드할 수도 있다.

클라우드에 직접 마이그레이션하는 작업에서 발견되었던 대부분의 단점이 해결되었다. 하지만 현재는 환경의 상태에 대한 가시성이 없는 상태이며 더 나아가 수요에 따라 서버 자원을 확장할 수 있으면 더욱 좋을 것이다. 이러한 문제점은 이 시리즈의 다음 두 기사에서 해결한다.


----

Amazon 클라우드에 Linux 애플리케이션 마이그레이션하기, Part 3: 확장성 빌드하기

편리하게 추가 트래픽 제공하기

Sean A. Walberg, Senior Network Engineer

요약: 지금까지의 시리즈에 있는 내용을 제대로 수행했다면 샘플 Linux® 애플리케이션이 클라우드로 마이그레이션되었고 일부 기본적인 신뢰성 기능이 구성되었습니다. Amazon 클라우드로의 애플리케이션 마이그레이션에 관한 일련의 기사 중 세 번째인 이 기사에서는 로드에 대한 응답으로 인프라를 늘리고 줄여 클라우드의 동적 특성을 활용하고 정적 자산 중 일부를 클라우드 쪽으로 이동시킵니다.

이 연재 자세히 보기

이 기사에 테그:  cloud_computing리눅스

원문 게재일:  2010 년 10 월 06 일 
번역 게재일:   2011 년 1 월 18 일 
난이도:  중급 
원문:  보기 
PDF:  A4 and Letter (157KB | 16 pages)Get Adobe® Reader® 
페이지뷰: 1985 회 
의견: 0 (의견 추가)

1 star2 stars3 stars4 stars5 stars 평균 평가 등급 (총 5표)

이 시리즈의 Part 1에서는 소프트웨어를 SmallPayroll.ca라는 서비스 오퍼링으로 간주하는 것에서부터 시작했다. 애플리케이션이 선택되어 Amazon EC2(Amazon Elastic Compute Cloud)로 이동되었다. 그런 다음 Part 2에서 해당 애플리케이션은 중복성, 백업 및 신뢰성 높은 디스크를 추가하여 강력해졌다.

이제는 안정성을 넘어 확장성에 대해 살펴본다. 서버는 시간 단위로 임대되기 때문에 필요할 때만 추가 서버를 운영하는 것이 더 합리적이지 않을까? 비동기로 처리되는 작업의 경우는 어떤가?

네트워크의 가장자리에서 정적 컨텐츠를 캐싱하는 CDN(Content Distribution Network)은 비용이 많이 들었다. 클라우드 컴퓨팅을 통해 CDN은 아주 작은 사이트에도 액세스할 수 있게 되었다. CDN을 사용하면 성능이 크게 향상되므로 CDN도 설치해 보자.

자동 전개

인프라의 동적 성장에 있어 중요한 요소는 새로운 인스턴스가 외부 개입 없이 자신을 프로덕션 환경에 접속시켜야 한다는 것이다. 코드 전개나 데이터베이스 변경과 같은 변경이 발생한 후에는 AMI(Amazon Machine Instance)를 계속 재번들링할 수 있다. 하지만 약간의 스크립트를 통해 지나치게 많은 작업 없이도 서버가 전개할 수 있다.

SmallPayroll.ca에는 대부분의 기타 애플리케이션과 마찬가지로 전개 프로세스가 있다.

  1. 저장소에서 코드를 끌어온다(Subversion 또는 git).
  2. 애플리케이션 서버를 시작한다.
  3. 애플리케이션이 제대로 시작되었는지 확인한다.
  4. 로드 밸런서 풀에 새로운 서버를 추가한다.

또한 인스턴스는 /etc/hosts에서 데이터베이스 서버를 구성해야 한다.

저장소에서 코드 끌어오기

SmallPayroll.ca 코드 기반은 Subversion 저장소에 저장된다. Subversion은 코드 기반에 대한 변경사항을 추적하고 개발자가 별도의 환경에서 기능에 대해 작업할 수 있도록 코드를 분기화하고 병합할 수 있게 하는 소스 코드 제어 시스템이다.

가장 쉬운 수준에서 Rails 애플리케이션은 소스 코드의 체크아웃된 사본에서 바로 실행될 수 있다. 변경사항이 작성되면 프로덕션 서버가 업데이트를 수행한 후 다시 시작된다. Capistrano라는 Ruby Gem이 다중 서버의 중앙집중식 제어와 문제점 발생 시 편리한 롤백을 허용하는 방식으로 이러한 전개를 관리한다.

수동으로 코드를 체크아웃하는 대신 새 서버는 Capistrano 프로세스를 시작한다. 여기에는 추가 작업이 필요하지만 Capistrano가 나중에 서버를 매우 쉽게 관리할 수 있다. Listing 1에서는 payroll 사용자의 홈 디렉토리에 배치될 초기 Capfile의 컨텐츠를 보여 준다.


Listing 1. Capistrano 전개를 시작할 Capfile
	
load 'deploy' 

# Where is the code? This will need to be customized!
set :repository,  "http://svn.smallpayroll.ca/svn/payroll/trunk/"
set :scm_username, "DEPLOY_USERNAME"
set :scm_password, "DEPLOY_PASSWORD"

# Deploy to the local server
server "localhost", :app, :web, :db, :primary => true

# By default Capistrano tries to do some things as root through sudo - disable this
set :use_sudo, false

# Define where everything goes
set :home, '/home/payroll'
set :deploy_to, "#{home}"
set :rails_env, "production"

Capfile은 cap 명령에 의해 실행된다. Capistrano는 SSH(Secure Shell)를 사용하여 서버에 연결할 것으로 예상한다(로컬 호스트인 경우에도 마찬가지임). 애플리케이션 사용자로 실행될 Listing 2에서는 애플리케이션 사용자가 SSH를 사용하여 로컬 서버에 연결할 수 있고 Capistrano 태스크가 실행될 수 있도록 서버를 준비한다.


Listing 2. 환경 준비하기
	
# Create the SSH directory and generate a secure key pair
mkdir .ssh
chmod 700 .ssh
ssh-keygen -b 1024 -t dsa -q -f .ssh/id_dsa -N ""

# Allow the user to SSH in to the server without a password
cat .ssh/id_dsa.pub >> .ssh/authorized_keys
# SSH is very fussy about permissions! Nothing should be readable
# by other users
chmod 600 .ssh/*

# SSH in once, ignoring host keys, so that the server will save the host key
ssh 127.0.0.1 -o StrictHostKeyChecking=false /bin/false

Listing 2는 다음과 같은 세 개의 섹션으로 구분된다.

  • 처음 두 명령은 애플리케이션 사용자만 읽을 수 있는 SSH 디렉토리를 작성한다. 세 번째 명령은 1024비트 DSA(Digital Signature Algorithm) 키(-b 1024 -t dsa)를 작성하고 출력(-q)을 종료하고 키의 이름을 지정하고 비밀번호가 없도록 지정한다.
  • 사용자의 공용 키를 authorized_keys 파일에 복사하여 해당 개인 키를 보유하는 사용자가 비밀번호 없이 로그인할 수 있다. 디렉토리에 있는 파일을 다른 사용자가 읽을 수 없도록 한다.
  • 저장된 호스트 키 없이 SSH와 Capistrano는 키를 확인하라는 메시지를 표시하고 이는 자동화된 전개를 중단시킨다. 마지막 명령은 로컬 서버에 로그인(호스트 키는 무시함)하고 /bin/false를 실행한다. 이것으로 충분히 호스트 키를 저장할 수 있다.

프로세스의 최종 단계에서는 환경을 작성하고 애플리케이션의 현재 버전을 전개한다. Listing 3에서는 Capistrano를 사용하여 이러한 태스크를 관리한다.


Listing 3. Capistrano를 사용하여 애플리케이션 전개하기
	
cap deploy:setup
chmod 700 /home/payroll
cap deploy

Listing 3은 shared 및 releases 디렉토리로 구성된 애플리케이션 홈 디렉토리 아래에 디렉토리 구조를 작성하는 deploy:setup 태스크를 실행한다. 각각의 전개는 고유 디렉토리의 releases 폴더로 이동한다. shared 디렉토리는 분리된 전개 사이에서 공유될 수 있는 로그 및 기타 요소에 사용된다.

애플리케이션을 전개하기 전에 두 번째 명령은 홈 디렉토리에 대한 권한이 700이 되도록 변경한다. 그룹 쓰기를 허용하기 위해 설치 태스크가 전개 디렉토리의 권한을 열기 때문에 이는 서브디렉토리 대신 홈 디렉토리에 대한 전개의 아티팩트이다. 사용자 이외의 다른 사용자가 쓸 수 있는 경우에는 홈 디렉토리인 경우 SSH 디먼은 키 기반 인증을 허용하지 않는다.

deploy 태스크가 마지막으로 실행되어 코드를 Subversion에서 체크아웃한 후 release 디렉토리에 저장하고 current라는 기호 링크(symlink)를 작성한다. 이 symlink가 제 위치에 있고 각각의 전개가 별도의 디렉토리에 있으면 애플리케이션의 이전 버전으로 쉽게 롤백할 수 있다.

자동으로 애플리케이션 서버 실행하기

로드가 많아질수록 더 많은 웹 서버를 자동으로 추가하는 시스템을 빌드할 수 있는 경우에도 이것이 언제나 좋은 생각은 아니다. 웹 트래픽은 상당히 변화가 심하므로 다른 서버를 실행하기 전에 트래픽을 유지하기를 원할 것이다. 새로운 서버가 로드에 도움이 되는지를 판별하는 데는 약 10분이 필요하고 인스턴스를 실행하여 새로운 웹 서버를 풀로 가져오기 위해 다시 5 - 10분이 필요하다. 이 프로세스는 웹 서버의 경우에는 효과적이지 않을 수 있지만 작업 서버의 경우에는 효과가 있을 수 있다.

여전히 스케줄에 맞춰 애플리케이션 서버를 늘리거나 줄일 수 있다. 예를 들어, 대부분의 SmallPayroll.ca 애플리케이션 사용자는 주중에 약 8:00 a.m. - 9:00 p.m. 사이에 이를 수행한다. 등록된 사용자에 대한 응답 시간을 개선하고 서버 비용을 줄이기 위해 주중에 8:00 a.m. - 9:00 p.m. 사이에 세 개의 서버가 실행되고 다른 시간에 두 개의 서버가 실행된다. 전개 스크립트는 이미 작성되어 있다. 필요한 작업은 서버를 시작한 후 로드 밸런서에 추가하는 것뿐이다.

cron으로 서버 실행하기

cron 기능은 사전설정된 스케줄에 따라 추가 인스턴스를 설정하고 설정 해제 하기에 자연스럽게 보인다. 이상적인 crontab의 모양은 Listing 4와 같다.


Listing 4. 자동으로 서버를 시작하고 중지하는 crontab
	
0  8 * * 1-5 $BASEDIR/servercontrol launch app
0 21 * * 1-5 $BASEDIR/servercontrol terminate app

가상 환경 외부의 시스템에서 사용자의 crontab에 Listing 4에 있는 코드를 입력한다. 1일부터 5일까지(월요일부터 금요일까지) 8:00 a.m.에 servercontrol이라는 스크립트가 launch app 매개변수를 사용하여 실행된다. 9:00 p.m.에 동일한 명령이 terminate app 매개변수를 사용하여 실행된다. 스크립트는 이러한 매개변수가 연산 및 서버 역할이 되는 것으로 이해한다. 현재로서는 역할은 항상 app가 된다.

제어 스크립트 작성하기

다음 단계는 요청 시 서버를 시작하기 위해 cron으로 실행하는 servercontrol 스크립트를 작성하는 것이다. Listing 5에 스크립트가 표시된다.


Listing 5. servercontrol 스크립트
	
    #!/bin/bash

AMI=ami-ad7e95c4
OP=$1
ROLE=$2

if [ "$OP" == "" -o "$ROLE" == "" ]; then
  echo You\'re doing it wrong.
  echo $0 operation number role
  exit
fi

case "$OP" in
  "launch")

    # Launch the instance and parse the data to get the instance ID
    DATA=`ec2-run-instances -k main -d "DB=10.126.17.1;ROLE=$ROLE" $AMI`
    INSTANCE=`echo $DATA | grep INSTANCE  | cut -f 6 -d ' '`
    echo $INSTANCE is your instance

    # Keep on checking until the state is "running"
    STATE=""
    while [ "$STATE" != "running" ]; do
      STATE=`ec2-describe-instances  $INSTANCE |awk '/^INSTANCE/ {print $6}'`
      echo the state is $STATE
      sleep 10
    done
    # Keep track of which instances were started by this method
    echo $INSTANCE >> $HOME/.ec2-$ROLE

    # Now that the instance is running, grab the IP address
    IP=`ec2-describe-instances $INSTANCE |awk '/^INSTANCE/ {print $13}'`

    # If this is to be an app server...
    if [ "$ROLE" == "app" ]; then
      # Check the web server to make sure it returns our content
      UP=0
      while [ $UP -eq 0 ]; do
        OUTPUT=`curl -s -m 5 http://$IP`
        if [ $? -eq 0 ]; then # curl was successful
          echo $OUTPUT | grep -qi 'welcome'
          if [ $? -eq 0 ]; then
            UP=1
          else
            sleep 5
          fi
        fi
      done

      # Register with the load balancer
      elb-register-instances-with-lb smallpayroll-http --instances $INSTANCE
    fi

  ;;

  "terminate")
     # Grab the instance ID. It's the last line of the file
     FILE=.ec2-$ROLE

     # Assuming the file exists, of course
     if [ ! -f $FILE ]; then
        echo No dynamic instances have been started for the $ROLE role
        exit
     fi

     # The last instance started is the last line of the file
     INSTANCE=`tail -1 $HOME/.ec2-$ROLE`

     # Assuming there's something in that file, that is
     if [ "$INSTANCE" == "" ]; then
         echo No dynamic instances have been started for the $ROLE role
         exit
     fi

     # Terminate the instance
     ec2-terminate-instances $INSTANCE

     # Take the instance out of the load balancer
     elb-deregister-instances-from-lb smallpayroll-http --instances $INSTANCE

     # Delete the last line of the file
     sed -i '$d' $FILE
  ;;

  *)
      echo "You may only launch or terminate"
      exit
  ;;
esac

이 스크립트는 길어 보일 수 있지만 이 스크립트의 대부분은 오류를 검사하는 스크립트이다. 이 스크립트는 매개변수를 구문 분석한 후 launch 및terminate 함수를 case문으로 구분하여 시작한다. 실행을 위해 스크립트는 인스턴스를 시작한 후 인스턴스가 running 상태에 들어갈 때까지 기다린다. 그런 다음 스크립트는 인스턴스의 IP 주소를 가져온 후 서버에 대한 웹 요청이 welcome이라는 단어를 성공적으로 리턴하고 포함할 때까지 기다린다.

인스턴스를 중지하는 것은 훨씬 더 쉽다. 인스턴스 ID는 사용자 홈 디렉토리의 dotfile에 작성되며 새 인스턴스가 파일에 추가되어 있다. 인스턴스를 중지하기 위해 스크립트는 파일의 마지막 행을 읽어 가장 최근에 시작된 인스턴스의 인스턴스 ID를 가져오고 종료 명령을 실행하고 로드 밸런서로부터 인스턴스를 제거한 후 인스턴스가 포함된 파일의 마지막 행을 삭제한다.

각각의 역할에는 고유 파일이 있다. 현재는 웹 역할만 있지만 나중에 확장될 것이다.

Listing 5에서 한 가지 궁금한 항목은 ec2-run-instances에 전달된 -d 매개변수이다. 이 매개변수에는 인스턴스에만 액세스할 수 있는 특수 URI를 방문하여 인스턴스가 읽을 수 있는 정보가 포함되어 있다. 이 정보는 문자열 형식으로 되어 있다. Listing 5에서는 서버의 역할과 데이터베이스 서버가 인스턴스에 전달된다.

init 스크립트 작성하기

init 스크립트는 시스템 부팅 중에 실행되며 적절한 애플리케이션 구성을 시작하면서 애플리케이션의 현재 버전을 사용하여 인스턴스를 구성한다. Listing 6에서는 제어 스크립트에서 전달된 정보를 사용하여 해당 구성 의사결정을 작성한다. 이 목록에 있는 코드는 SYSV 시작 스크립트의 일부가 되거나 부팅 시 한 번 실행되기 위해 rc.local 파일에 저장될 수 있다.


Listing 6. 애플리케이션 시작 스크립트
	
USER=payroll
HOME=/home/payroll
SRC="/etc/smallpayroll

# If this is a fresh AMI, set up the application directories
if [ ! -d $HOME/releases ]; then
  echo "Setting up environment"
  cp $SRC/Capfile $HOME
  # Listing 2
  su - $USER -c "cd $HOME && sh $SRC/setup_environment"
fi

echo "Deploying the application"
su - $USER -c "cd $HOME && /opt/ree/bin/cap deploy"

# Grab the user supplied data. 169.254.169.254 returns data unique to the instance.
USER_DATA=`/usr/bin/curl -s http://169.254.169.254/2007-01-19/user-data`
DBHOST=`echo $USER_DATA | sed 's/.*DB=\([0-9\.]*\).*/\1/'`
ROLE=`echo $USER_DATA | sed 's/.*ROLE=\([a-zA-Z]*\).*/\1/'`
logger "Starting application with DBHOST=$DBHOST and ROLE=$ROLE"

# If available, put the dbhost in /etc/hosts
if [ "$DBHOST" != "" ]; then
  sed -i '/dbhost/d' /etc/hosts
  echo "$DBHOST dbhost" >> /etc/hosts
fi

# Depending on the role...
case "$ROLE" in
  'app')
    # Web server... start up mongrel
    su - $USER -c "mongrel_rails cluster::start \
      -C $HOME/current/config/mongrel_cluster.yml"
  ;;
  *)
    logger "$ROLE doesn't make sense to me"
  ;;
esac

Listing 6은 일부 변수를 초기화하는 것에서부터 시작한다. 다음으로 애플리케이션 사용자의 홈 디렉토리에서 cap deploy:setup 태스크가 이전에 실행된 적이 있는지 확인하며 실행된 적이 없으면 이 태스크가 실행된다. 그런 다음 최신 코드를 사용할 수 있도록 전개가 실행된다.

이제 코드를 사용할 수 있으므로 스크립트에서는 인스턴스에 전달된 메타데이터를 검사하고 일부 sed 매직을 사용하여 컴포넌트를 변수에 추출한다. DBHOST 변수가 설정되면 이 값이 /etc/hosts에 저장되므로 애플리케이션이 데이터베이스를 찾을 위치를 알게 된다. 역할이 검사된다. 서버가 애플리케이션 서버가 되도록 되어 있는 경우에는 Mongrel 서버가 시작된다.

Listing 5와 Listing 6은 합하면 상당한 코드가 되지만 모든 유형의 서버의 시작 및 중지를 자동화하는 데 필요한 기초를 마련한다. Listing 4의 crontab이 제 위치에 있으면 추가 서버는 최대 사용 시간에 온라인 상태가 되고 사이트의 트래픽이 줄어들면 온라인 상태가 해제된다. 다음으로 이 프레임워크를 확장하여 다른 유형의 서버를 실행한다.

비동기 작업 처리

동적 웹 사이트를 더 효율적이게 만들기 위한 한 가지 일반적인 기술은 장기 실행 요청을 백그라운드 프로세스로 이동시키는 것이다. 이러한 장기 실행 작업은 일반적으로 실제 요청만큼 시간적 제한을 받지 않는다. 애플리케이션은 보고서를 실행하기 위한 요청을 작업 처리 시스템에 전송하고 Ajax(Asynchronous JavaScript + Extensible Markup Language)를 사용하여 백그라운드에서 완료를 위해 폴링할 수 있다. 사용자는 애플리케이션이 작동 중임을 나타내는 일종의 스피너를 보게 되지만 대화식 요청을 제공할 수 있는 Mongrel 프로세스를 결합하지 않는다.

이 접근방식을 사용하더라도 작업을 처리하기 위해 사용할 수 있는 충분한 자원을 가지고 있어야 한다. 작업 큐가 지나치게 길어지면 사용자는 보고서를 기다리느라 지치게 될 것이다. 이것은 동적 서버 실행을 위해 이상적인 유스 케이스처럼 보인다. 작업의 백로그가 모니터링된다. 백로그가 특정 임계값을 넘으면 지원을 위해 새로운 서버가 실행된다. 약간의 시간이 지나면 서버의 연결이 끊어진다.

공짜는 없다

새로운 서버를 실행하는 데는 비용이 들기 때문에 새로운 서버의 실행 시기를 결정할 때 고려해야 할 몇 가지 경제적인 고려사항이 있다.

이 시리즈에서 사용해 온 m1.small 인스턴스는 1시간 이하의 시간에 대해서 약 8.5달러(미국)의 비용이 든다. 따라서 인스턴스를 실행할 때는 1분을 사용하더라도 1시간에 대한 비용을 지불한다. 더 큰 인스턴스를 사용하여 더 많은 작업을 수행하려고 하는 경우에는 시간당 비용이 증가한다.

새로운 서버를 실행할 때와 실행하지 않을 때의 비용에 대해 이해하고 있어야 한다. 서비스의 속도가 느리면 고객의 만족도가 낮다. 서비스의 속도가 빠르면 고객의 만족도는 높아지지만 비용이 더 많이 든다.

백그라운드 처리는 탁월한 delayed_job gem(특히 collectiveidea 분기 실행)에 의해 제공된다(참고자료 참조). 이 gem은 하나의 코드 행에서 작업을 시작할 수 있도록 하며 우선순위 큐를 구현하므로 중요한 작업이 루틴 작업 뒤에서 기다리지 않는다. 작업 처리 디먼은 Rails 애플리케이션 디렉토리에서 실행되며 데이터베이스를 사용하여 작업을 요청한다. 이는 현재 스크립트를 확장하여 delayed_job 디먼을 처리할 수 있다는 것을 의미한다.

init 스크립트를 업데이트하여 작업 처리 서버 지원하기

Listing 6에서 스크립트가 인스턴스 메타데이터를 검사하여 servercontrol 스크립트에서 전달된 내용을 확인한 것을 떠올려 본다. ROLE 매개변수는 애플리케이션 서버를 의미하는 app를 사용하여 서버의 작업을 지시한다. 각 서버 유형에 대한 명령어는 case문에 랩핑되어 있다. Listing 7에서는 이 case문을 확장하여 delayed_job 역할을 처리한다.


Listing 7. delayed_job 서버의 시작 처리하기
	
case "$ROLE" in
  'app')
    # For an application server, start the mongrels
    su - payroll -c "/opt/ree/bin/mongrel_rails cluster::start \
      -C /home/payroll/current/config/mongrel_cluster.yml"
  ;;
  'job')
    # For a job server, figure out what kind of machine this is, and run
    # an appropriate number of job processing daemons
    TYPE=`curl -s http://169.254.169.254/2007-08-29/meta-data/instance-type`
    case "$TYPE" in
      'm1.small') NUM=2 ;; # 2 per ECU * 1 ECU
      'm1.large') NUM=8 ;; # 2 per ECU * 4 ECUs
      *) NUM=2 ;;
    esac
    su - payroll -c "RAILS_ENV=production $HOME/current/script/delayed_job -n $NUM start"
  ;;
  *)
  logger "$ROLE doesn't make sense to me"
  ;;
esac

이 스크립트는 서버의 역할을 검사한다. 서버가 애플리케이션 서버인 경우에는 Mongrel이 시작된다. 서버가 작업 서버인 경우에는 스크립트가 실행 중인 인스턴스의 유형을 확인한다. 이 정보는 169.254.169.254 가상 호스트에 있는 다른 URL에서 얻을 수 있다. 대략적으로 스크립트는 ECU(Elastic Compute Unit)당 두 개의 delayed_job 작업자를 실행한다. 워크로드는 다를 수 있다.

여기서 servercontrol 스크립트는 명령행에 launch job을 전달하여 새로운 작업 서버를 실행할 수 있다.

큐 모니터링

몇 가지 방법으로 큐 백로그를 모니터링할 수 있다. 작업과 작업을 처리하는 데 걸리는 시간(시간이 임계값을 벗어난 경우에는 새 서버를 시작하는 데 걸리는 시간)을 추가할 수 있다. 이 방법의 단점은 큐가 실제로 백업되는 경우 사용자가 백업되었는지 판별하는 데 시간이 오래 걸린다는 것이다. 가장 단순한 해결책은 데이터베이스에서 미해결 요청의 수를 쿼리한 후 이를 제어기에서 제공하는 것이다. Listing 8에서는 이러한 제어기를 보여 준다.


Listing 8. 큐의 길이를 보여 주는 제어기
	
class QueueController < ApplicationController
  def length
    render :text => Delayed::Job.count(
      :conditions => "priority > 0 AND failed_at IS NULL").to_s
  end
end

Listing 8에서는 단순히 큐의 길이(특히 우선순위가 0보다 크고 처리된 적이 없어 실패한 적이 없는 작업)를 보여주고 이 숫자를 템플리트에 전달하는 대신 직접 렌더링한다. /queue/length로 이동하면 현재 큐 백로그를 확인할 수 있다.

요청에 대한 응답으로 새로운 작업 서버 실행하기

이제 큐의 길이를 쉽게 판별할 수 있으므로 이 데이터에 대한 조치를 수행할 스크립트가 필요하다. Listing 9에서는 이러한 스크립트를 보여 준다.


Listing 9. 추가 작업 서버 실행하기(필요한 경우)
	
    #!/bin/bash

# What's the length of the queue
QUEUE=`curl -s http://app.smallpayroll.ca/queue/length`
# How many servers are running now? (zero out if file doesn't exist)
SERVERS=`wc -l $HOME/.ec2-job`
if [ "$SERVERS" == "" ]; then SERVERS=0; fi

# launch up to two servers while the queue is over 20
if [ $SERVERS -le 2 -a $QUEUE -gt 20 ]; then
  servercontrol launch job
fi

# Terminate one instance if the queue is under 5
if [ $SERVERS -gt 0 -a $QUEUE -lt 5 ]; then
  export TZ=/usr/share/zoneinfo/UTC 
  LAST=`tail -1 $HOME/.ec2-job`
  # But only if the server has run for at least 45 minutes
  UPTIME=`ec2-describe-instances $LAST | \
    awk '/INSTANCE/ {t=$10; gsub(/[\-:T\+]/, " ", t); print systime() - mktime(t) }'`
  if [ $UPTIME -gt 2700 ]; then
    servercontrol terminate job
  fi
fi

비즈니스 로직

Listing 9에서는 단순 알고리즘을 구현한다. 이 목록은 동적으로 실행되는 서버 뒤에 숨겨진 원칙을 보여주기에 충분하지만 더 많은 정보를 가질 수 있다. 예를 들어, 이 스크립트는 시간 경과에 따른 큐의 길이를 감시하고 지금 존재하는 간단한 버전 대신 일정 기간의 안정화를 거친 서버의 연결을 해제할 수 있다.

Listing 9에 있는 코드는 5분마다 cron에서 실행되어야 한다. 이 코드는 먼저 큐의 길이와 현재 실행 중인 작업 서버의 수를 가져온다. 작업 서버의 수는 동적으로 실행된 서버의 인스턴스 ID가 포함된 .ec2-job 파일의 길이로부터 확보된다. 큐의 길이가 20을 초과하고 실행 중인 추가 작업 서버 수가 2 미만인 경우 서버가 실행된다. 실행 중인 서버의 수가 둘 이상이고 큐가 5 미만인 경우 이 스크립트는 인스턴스를 종료해야 하는지 확인하기 위해 추가로 검사를 수행한다.

스크립트는 먼저 TZ 환경 변수를 설정하여 시간대를 협정 세계시(UTC)로 설정한다. 그런 다음 마지막으로 실행된 작업 서버의 인스턴스 ID를 가져와서 시작 시간을 확보하기 위해 쿼리를 수행한다. 이 시간은 일부 awk 대체에 공급되어 서버가 활성 상태였던 시간(초)에 도달한다. 서버가 46분 넘게 활성 상태였다면 인스턴스를 끌 수 있다. 그렇지 않으면 서버가 계속 활성 상태를 유지한다.

45분이라는 장벽은 서버를 조기에 끄는 것을 예방하기 위해 존재한다. 큐의 활동이 줄어들었다가 다시 증가하면 서버는 여전히 활성 상태이다.

CDN(Content Distribution Network) 사용하기

다른 사용자가 사용자의 웹 사이트를 방문하면 해당 사용자는 이미지, CSS(Cascading Style Sheet) 및 JavaScript 코드도 로딩한다. CDN이라는 서비스는 정적 자산을 캐싱한 후 인터넷의 다수 서버에 분배한다. 그 결과 사용자를 위해 이러한 자산에 대한 빠른 액세스를 제공하여 해당 사용자가 병렬로 복수의 파일을 다운로드하도록 할 수 있다. Amazon에서는 Amazon CloudFront(다른 서비스와 같은 사용량 기준 지불 오퍼링)라는 CDN 서비스를 제공했다.

CDN에서 제공되는 자산은 다른 서버로부터 요청되므로 URL이 변경된다. 예를 들어, http://app.smallpayroll.ca/stylesheets/style.css는 애플리케이션 서버로부터 스타일 시트를 로딩하지만 http://cdn0.smallpayroll.ca/stylesheets/style.css는 CDN으로부터 로딩한다. CDN은 자산이 없는 경우 자산을 캐싱하여 사용자에게 전달하기 전에 오리진으로부터 자산을 끌어온다.

CloudFront는 오리진이 Amazon S3(Amazon Simple Storage Service) 버킷이라는 면에서 다른 CDN과는 약간 다르다. CloudFront를 사용하려면 먼저 Amazon S3 버킷을 정적 자산으로 채운 다음 URL을 다시 작성하여 CloudFront 호스트를 사용해야 한다.

CloudFront 설정하기

CloudFront 기본 페이지(링크는 참고자료 참조)에서 링크를 클릭하여 등록한다. 계속하기 전에 활성화 이메일이 전송되기를 기다려야 한다.

활성화 확인 이메일을 수신하면 Amazon Web Services 콘솔 페이지로 이동하여 Amazon CloudFront 탭을 클릭한다. 그림 1과 같은 페이지가 표시된다.


그림 1. CloudFront Distributions 대시보드
CloudFront Distribution 대시보드 

배포판이 아직 작성되지 않았다. 배포판은 다시 Amazon S3 버킷에 결합될 파일을 위한 단순한 버킷이다. Create Distribution을 클릭하여 그림 2와 같은 페이지를 표시한다.


그림 2. 배포판 작성하기
배포판 작성하기 

다음 태스크를 수행한다.

  1. Delivery Method에 대해 Download를 선택한다.
  2. Origin 드롭 다운 목록에서 Amazon S3 버킷의 이름을 선택하거나 선택하는 Amazon S3 도구로 작성할 버킷을 지금 하나 작성한다.
  3. Logging에 대해 Off를 선택한다(이러한 로그를 사용할 계획이 없는 경우).
  4. CNAMEs 필드에 도메인 아래의 네 가지 이름을 입력한다(예: cdn0.smallpayroll.ca에서 cdn3.smallpayroll.ca까지).
  5. Comments에 원하는 텍스트를 입력한다.
  6. Distribution Status에 대해 Enabled를 선택한다.

Create를 클릭하면 다시 CloudFront 탭으로 돌아가며 여기에는 방금 작성한 배포판이 표시된다(그림 3 참조).


그림 3. 구성된 배포판
구성된 배포판 

이 페이지에는 djdzxdmb99068.cloudfront.net과 같은 도메인 이름이 있다. 이제 DNS 서버로 이동하여 네 개의 CNAME을 구성한 후 이들이 배포판의 도메인 이름을 가리키도록 만들어야 한다. 숫자가 지정된 네 개의 이름을 작성하는 것을 제외하면 Amazon Elastic Load Balancing도 비슷하게 작동한다.

배포판과 연관시킨 Amazon S3 버킷에 테스트 파일을 둔다. 배포판의 도메인 이름(예: http://djdzxdmb99068.cloudfront.net/test.htm)으로 이동하여 버킷 내부에서 test.htm이라는 파일을 확인하여 이 문서를 볼 수 있다. 액세스 거부 오류가 발생하는 경우에는 파일에 대한 공용 액세스를 사용 가능으로 설정했는지 확인한다(Amazon S3 버킷 관리를 위해 사용하는 도구에 따라 지시사항은 다름). 이전의 테스트가 효과가 있었다면 이전에 작성한 CNAME을 사용할 수 있다(예: http://cdn1.smallpayroll.ca/test.htm).

파일 동기화하기

공용 디렉토리의 컨텐츠를 Amazon S3 오리진 버킷에 복사해야 한다. 가장 단순한 방법은 Rails 애플리케이션의 루트 디렉토리에서

s3sync.rb -r -p public/ smallpayroll-cdn:

명령을 실행하는 것이다. -r 옵션은 사본이 반복됨을 의미한다. -p 옵션은 모든 파일을 공개적으로 읽을 수 있게 만든다.

이 절차를 자동화하려면 참고자료에서 이 태스크를 처리하는 gem의 링크를 참조한다.

애플리케이션 업데이트하기

단순한 수준에서는 웹 서버 대신 CDN 링크 중 하나를 가리키도록 모든 이미지, JavaScript 및 CSS 링크를 변경할 수 있다. Rails URL 헬퍼(예: image_tag)를 사용한 경우에는 Rails가 작업을 수행하도록 할 수 있다. 다음 행을 config/environments/production.rb에 추가한다.

ActionController::Base.asset_host = "cdn%d.smallpayroll.ca"

이 코드는 하나의 행을 프로덕션 구성에 추가한다(즉, 정적 자산이 asset_hosts로 정의된 호스트로부터 제공됨). %d는 기본적으로 숫자 0 - 3까지 확장되므로 cdn0.smallpayroll.ca, cdn1.smallpayroll.ca, cdn2.smallpayroll.ca 및 cdn3.smallpayroll.ca 사이에서 회전하도록 Rails에 지시한다. 이들은 CloudFront가 응답하도록 구성한 호스트와 동일한 호스트이다. 이러한 네 가지 호스트가 있는 경우 브라우저는 일반적으로 호스트당 두 개의 연결로 제한되므로 브라우저가 한 번에 최대 8개의 자산을 다운로드하는 것으로 예상할 수 있다.

이제 애플리케이션은 가능한 경우 CDN을 사용할 것이다. 빨라진 속도를 체감해 보자.

결론

애플리케이션에서는 Amazon CloudFront를 CDN으로 사용하여 다운로드 속도를 향상시키고 클라이언트별 병렬 다운로드를 허용하여 페이지 로딩 속도를 빠르게 한다. 또한 애플리케이션을 업데이트하여 컴퓨팅 자원을 동적으로 증가 및 감소시켰다. 일부 실행 및 종료 작업은 스케줄에 맞춰 수행되고 일부는 로드에 대한 응답으로 수행된다. 다수의 추가 케이스를 처리하기 위해 확장할 수 있는 일부 스크립트도 가지고 있다.

한 가지 부족한 점은 관리이다. 특정 지점에서는 실행 중인 컴퓨터 수가 몇 대인지 정확하게 알지 못할 것이다. 서버 목록은 유동적이기 때문에 전개가 아직 자동화되지 않았다. 서버 자체의 성능에 대해서는 정말 모르고 있다. 이 시리즈의 마지막 기사에서 이러한 문제점을 해결해 보자.


----

Amazon 클라우드에 Linux 애플리케이션 마이그레이션하기, Part 4: 관리상 도전 과제 극복하기

성장에 따른 문제 예방

Sean A. Walberg, Senior Network Engineer

요약: 지금까지 사용자는 애플리케이션을 클라우드로 이동시켰으며 요구에 응답하여 자동으로 자원을 사용 및 사용 불가능으로 설정할 수 있습니다. Linux 애플리케이션을 Amazon 클라우드로 마이그레이션하는 방법을 살펴보는 시리즈의 네 번째 기사인 이 기사에서는 이와 같이 변화하는 환경을 제어하여 애플리케이션 및 비즈니스를 지원하는 방법에 대해 살펴봅니다.

이 연재 자세히 보기

이 기사에 테그:  cloud_computingdb2클라우드스케이프

원문 게재일:  2010 년 10 월 27 일 
번역 게재일:   2011 년 2 월 22 일 
난이도:  중급 
원문:  보기 
PDF:  A4 and Letter (51KB | 12 pages)Get Adobe® Reader® 
페이지뷰: 1682 회 
의견: 0 (의견 추가)

1 star2 stars3 stars4 stars5 stars 평균 평가 등급 (총 12표)

이 시리즈의 Part 1에서는 SmallPayroll.ca 애플리케이션을 Amazon 클라우드로 마이그레이션했고 Part 2에서는 이 애플리케이션을 더 강력하게 만들었다.Part 3에서 살펴봤듯이 애플리케이션은 로드에 따라 자체적으로 서버를 추가 및 제거할 수 있다. 현재는 특정 시점에 활성 서버의 수 및 IP 주소를 예측할 수 없어 이러한 서버에 연결하는 것이 힘들 수 있다. 따라서 클라우드 환경은 기존의 데이터 센터와 다르다.

클라우드의 동적 특성 또한 애플리케이션 전개를 어렵게 만든다. 사용자의 서버 목록은 전개 사이에서 다른데 그렇다면 애플리케이션을 어떻게 업데이트하는가? 이 문제에 대해 서버에서 결함을 어떻게 모니터하는가?

일반적인 데이터 센터가 아님

"일반적인" 데이터 센터에서는 컴퓨터에 원하는 모든 이름을 지정하고 사용자에게 적합한 IP 주소를 해당 컴퓨터에 제공하고 원하는 경우 서버로 돌아가 서버가 여전히 해당 위치에 있는지 확인할 수 있다. 서버를 추적하기 위해 스프레드시트를 보관할 수도 있고 또는 소프트웨어를 사용할 수도 있고, 사용자의 머리나 텍스트 파일에 정보를 보관할 수도 있다. 구성의 일관성을 유지하기 위해 필요한 구성 관리를 가지고 있는가?

다수 함수에 대한 제어를 양도하기 때문에 클라우드 환경은 기존 데이터 센터와 상당히 다르다. IP 주소를 예측할 수도 없고 두 서버가 동일한 서브넷에 있을 것이라고 확신할 수도 없다. 자원의 자동 확장으로 진행하는 경우 새로운 노드가 실행되면 수동 구성에서 힘들게 수행한 작업이 모두 손실된다. 사용자에게 예측 가능한 이름을 가진 웹 서버가 20개 있다는 사실에 기반하는 스크립트는 클라우드에서 작동하지 않는다.

다행히도 약간의 훈련으로 이러한 문제점을 해결하고 실제 데이터 센터의 가동 시간을 개선할 수 있다.

IP 주소 지정 및 이름 지정하기

사용자들은 서버에 지정할 이름과 적절한 IP 주소 지정 스키마를 도출하는 방법을 걱정하면서 상당한 시간을 보내기 쉽다. Amazon EC2(Elastic Compute Cloud) 인스턴스는 무작위 IP 주소와 이 주소를 기반으로 하는 이름과 함께 제공된다. 확실하게 서버의 이름을 바꿀 수 있지만 이를 수행하려면 나머지 환경에 대한 지식이 필요하다. 예를 들어, 서버 이름을 webprd42로 지정하려면 실행한 마지막 서버가 webprd41이었음을 알고 있어야 한다.

더 나은 해결책은 이름 또는 IP 주소에 의존하지 않고 이러한 이름이 중요하지 않은 방식으로 소프트웨어를 빌드하는 것이다.

구성 관리

실제 환경에서는 일반적으로 서버에 대한 수동 구성 변경사항 작성을 제대로 수행할 수 있다. 서버가 자동으로 실행되는 경우에는 수동 변경사항이 적용되지 않는다. 각각의 변경 이후 AMI(Amazon Machine Image)를 다시 번들화할 수 있지만 이를 수행해도 이미 실행 중인 다른 서버에 대한 업데이트를 적용하는 문제가 해결되지 않는다. 다행히도 Puppet 및 Cfengine과 같은 탁월한 소프트웨어 패키지가 이러한 변경사항을 자동화할 수 있다(참고자료 참조).

애플리케이션 변경사항을 전개하는 것은 별도로 살펴볼 만한 구성 관리의 또다른 측면이다. 일반 구성 관리 도구가 이 작업을 수행할 수 있지만 이 도구를 사용하여 애플리케이션 전개와 마이그레이션 및 구성 롤백 관리의 특정 단계를 재현하는 것은 어렵다. Rails 커뮤니티는 애플리케이션 전개 태스크를 처리하는 다른 도구(예: Capistrano)를 발표했다(참고자료 참조).

구성 관리를 두 가지 별도의 문제로 간주하는 것이 도움이 된다. 첫 번째는 소프트웨어 패키지의 설치에서부터 다양한 디먼의 구성에 이르기까지 서버를 관리하는 방법이다. 두 번째는 제어된 방식으로 소프트웨어의 새로운 버전을 전개하는 방법이다.

시스템 모니터링

서버가 수행하고 있는 작업에 대해 알고 있는 것이 중요하다. CPU, 디스크 자원, 메모리 및 네트워크는 모니터해야 하는 중요한 컴포넌트이다. 애플리케이션 자체를 포함하여 시스템에서 실행 중인 디먼에는 주시해야 할 기타 메트릭이 있을 수 있다. 예를 들어, 애플리케이션 응답 시간과 웹 서버 및 애플리케이션 서버에 대한 연결 수를 감시하면 문제가 발생하기 전에 경고 통보를 받을 수 있다.

서버를 모니터하고 결과를 그래프로 표시하는 데 사용할 수 있는 도구는 많이 있다. 문제는 새로운 서버가 온라인 상태가 될 때 이러한 서버를 어떻게 모니터하고 서버가 오프라인 상태가 될 때 모니터링을 어떻게 중지하는지에 있다.

클라우드 아키텍처에 적용된 패턴

Amazon EC2와 같은 동적 환경을 관리하는 방법을 살펴보면 세 가지 일반적인 패턴이 드러난다.

  • 클라이언트 폴. 서버가 중앙 서버에서 자원을 쿼리한다. 이 패턴을 사용하는 모든 서버의 주소를 알 필요는 없지만 서버는 자체 스케줄에 따라 작동하므로 사용자는 클라이언트의 폴링 타이밍을 제어할 수 없다.
  • 서버 푸시. 이 패턴은 먼저 클라우드 제공자의 API(Application Programming Interface)를 쿼리하여 현재 서버 목록을 찾은 후 중앙 서버가 각 서버에 접속하여 작업을 수행한다. 이 패턴은 속도가 느리고 이를 수행하려면 관리 도구가 환경의 동적 특성에 대해 이해해야 하지만 이 패턴은 업데이트를 동기화할 수 있는 장점이 있다.
  • 클라이언트 등록. 각 서버가 온라인 상태가 되면 각 서버는 자신을 중앙 서버에 등록한다. 서버는 종료되기 전에 자체적으로 등록을 취소한다. 이 방법은 더 복잡하지만 클라우드 환경에서 클라우드 비인식 도구를 사용할 수 있다.

구성 관리를 위한 클라이언트 폴링

이 패턴은 구현하기 쉽다. 클라이언트는 단순히 미리 결정된 스케줄에 따라 명령어에 대해 잘 알려진 서버를 폴링하면 된다. 클라이언트가 수행할 항목이 서버에 없는 경우 서버는 클라이언트에 이 내용을 알린다. 단점은 클라이언트가 서버를 폴링하는 경우에만 명령어가 실행될 수 있다는 것이다. 변경이 긴박한 경우 다음 폴링을 기다려야 한다.

폴링을 사용하는 탁월한 방법은 서버의 구성 관리이다. Reductive Labs의 Puppet 패키지는 유명한 구성 관리 도구이다. Puppetmaster라는 프로세스가 중앙 서버에서 실행된다. 클라이언트는 Puppet 디먼을 실행하고 이 디먼은 적절한 구성 매니페스트를 위해 Puppetmaster를 폴링한다. 이러한 구성 매니페스트는 "NTP 디먼이 설치되어 실행되도록 보장"하는 것과 같은 특정 컴포넌트의 원하는 종료 상태를 지정한다. Puppet은 이러한 매니페스트를 읽고 문제점을 정정한다.

배포판에 Puppet이 함께 제공되거나 gem install puppet facter를 사용하여 Puppet을 신속하게 설치할 수 있다. 하지만 Puppet은 문제를 복잡하게 하는 보안 시스템을 구현한다. 클라이언트가 Puppetmaster와 대화하려면 서명된 키가 있어야 한다. 연결되는 클라이언트를 위해 자동으로 키에 서명하도록 Puppetmaster에 지시할 수 있지만 이를 수행하면 임의의 사용자가 구성 파일을 다운로드할 수 있다. 대안은 Puppetmaster를 무시하고 메니페스트를 직접 분배한 후 Puppet 도구를 로컬로 실행하는 것이다.

클라이언트가 Puppet 매니페스트를 실행하게 하는 이벤트의 시퀀스는 다음과 같다.

  1. 서버로부터 업데이트된 매니페스트 사본 및 연관된 파일을 다운로드한다.
  2. 매니페스트에 대해 Puppet을 실행한다.

1단계를 위해 선택하는 도구는 변경된 파일만 다운로드하는 rsync이다. 2단계를 위해서는 puppet 명령(Puppet 설치의 일부)이 매니페스트를 실행한다. 이 접근 방식에는 두 가지 주의사항이 있다.

  • 서버는 클라이언트의 SSH(Secure Shell) 공용 키를 승인해야 한다. 이 키는 AMI에서 분배될 수 있다.
  • 매니페스트에서 지정하는 모든 구성 파일은 매니페스트와 함께 복사해야 한다. 기본 제공 Puppet 파일 서버에는 인증서도 필요하므로 이 파일 전송 메소드는 사용할 수 없다.

샘플 매니페스트를 사용하면 클라이언트가 올바른 네트워크 시간 프로토콜 구성을 가진다. 여기에는 소프트웨어가 설치되고 구성 파일이 수정되고 디먼이 실행되도록 하는 것이 포함된다. 목록 1에서는 최상위 레벨 매니페스트를 보여 준다.


목록 1. 최상위 레벨 매니페스트
	
import "classes/*"

node default {
  include ntpclient
}

Puppet 시작하기

Puppet의 장점 중 하나는 적은 규모로 시작한 후 언어를 학습해가면서 Puppet의 제어 하에 더 많은 항목을 추가할 수 있다는 것이다. 예를 들어, 이 기사에서와 같이 NTP로 시작한 후 기타 서비스를 지원하도록 확장할 수 있다. Puppet 매니페스트를 개선할 때마다 시스템의 신뢰성을 높이고 향후 작업을 줄인다.

목록 1에서는 먼저 classes 디렉토리에 있는 모든 파일을 가져오며 각 파일에는 단일 컴포넌트에 대한 정보가 들어 있다. 모든 노드에는 목록 2에 정의된 ntpclient 클래스가 포함된다.


목록 2. ntpclient 클래스
	
class ntpclient {
  package {
    ntp:
      ensure => installed
  }
  service {
    ntpd:
      ensure => true,
      enable => true,
      subscribe => [ Package [ntp], File["ntp.conf"] ],
  }
  file {
    "ntp.conf":
      mode => 644,
      owner => root,
      group => root,
      path => "/etc/ntp.conf",
      source => "/var/puppetstage/files/etc/ntp.conf",
      before => Service["ntpd"]
  }
}

Puppet 언어에 대한 자세한 검토는 이 기사의 범위를 벗어나지만 상위 레벨에서 목록 2는 ntp라는 패키지, ntpd라는 서비스 및 /etc에 있는 ntp.conf라는 파일로 구성되는 ntpclient라는 클래스를 정의한다. ntp 패키지가 설치되지 않은 경우 Puppet에서는 yum 또는 apt-get과 같은 적절한 도구를 사용하여 이를 설치한다. 서비스가 실행되고 있지 않으며 시작 스크립트에 있는 경우 서비스는 고정된다. ntp.conf 파일이 /var/puppetstage/files/etc에 있는 사본과 다른 경우에는 해당 파일이 업데이트된다. before 및 subscribe 행은 구성이 변경되는 경우 디먼이 다시 시작되도록 한다.

서버는 매니페스트 및 파일을 /var/puppetdist에 저장하고 클라이언트는 해당 트리를 /var/puppetstage에 복사한다. 디렉토리 트리의 아웃라인이 목록 3에 표시되어 있다.


목록 3. /var/puppetdist의 컨텐츠
	
/var/puppetdist/
|-- files
|   `-- etc
|       `-- ntp.conf
`-- manifests
    |-- classes
    |   `-- ntp.conf
    `-- site.pp

마지막으로 목록 4에서는 파일을 동기화하고 클라이언트에서 매니페스트를 실행한다.


목록 4. 매니페스트를 동기화하고 실행하는 클라이언트 코드
	
#!/bin/bash
/usr/bin/rsync -avz puppetserver:/var/puppetdist/ /var/puppetstage/ --delete
/usr/bin/puppet /var/puppetstage/manifests/site.pp

이 코드는 cron으로부터 주기적으로 실행되는 경우 매니페스트에서 변경사항을 선택하여 클라우드 서버에 적용한다. 어떻게든 서버의 구성이 변경되면 Puppet에서는 서버를 다시 준수 상태로 돌리는 단계를 수행한다.

애플리케이션 업데이트 적용하기

서버의 구성 업데이트에는 서버 간 동기화가 필요한 경우가 거의 없다. 패키지를 업그레이드해야 하는 경우에는 일반적으로 30분 창이면 충분하다. 하지만 사용자는 애플리케이션 업데이트를 위해 변경사항을 한 번에 롤아웃하고 타이밍을 제어하길 원한다. 이를 위해 적합한 유명한 도구가 Capistrano이다. 사용자는 Capistrano의 도메인 특정 언어를 사용하는 스크립트를 작성하고 다양한 태스크를 실행한다. 목록 5에서는 애플리케이션을 알려진 서버 세트에 푸시하는 최소 Capistrano 스크립트를 보여 준다.


목록 5. 단순 Capistrano 스크립트
	
set :application, "payroll"
set :repository,  "https://svn.smallpayroll.ca/svn/app/trunk/"
set :user, 'payroll'
set :home, '/home/payroll'
set :deploy_to, "#{home}"
set :rails_env, "production"

role :db, "174.129.174.213", :primary => true
role :web, "174.129.174.213", "184.73.3.169"

목록 5에 있는 대부분의 행은 Capistrano의 기본 동작을 변경하는 변수를 설정하며 이는 SSH를 사용하여 모든 서버에 액세스하고 소스 코드 관리 도구를 사용하여 애플리케이션의 사본을 체크아웃하기 위한 것이다. 마지막 두 행은 사용 중인 서버(특히 데이터베이스 및 웹 서버)를 정의한다. 이러한 역할은 Capistrano에 알려져 있으며 자체 목적을 위해 확장될 수 있다.

목록 5의 문제점은 서버를 사전정의해야 한다는 것이다. 하지만 Capistrano가 런타임 시 AWS(Amazon Web Services) API를 사용하여 서버 목록을 판별하게 할 수 있다. 먼저 다음을 실행한다.

gem install amazon-ec2

이를 실행하여 API를 구현하는 라이브러리를 설치한다. 그런 다음 목록 6과 같이 Capistrano 레서피(deploy.rb)를 수정한다.


목록 6. 런타임 시 서버 목록을 동적으로 로드하도록 Capistrano 수정하기
	
# Put this at the beginning of your deploy.rb
require 'AWS'

# Change your role :web definition to this
role(:web) { my_instances }

# This goes at the bottom of the recipe
def my_instances
  @ec2 = AWS::EC2::Base.new(  :access_key_id => ENV['AWS_ACCESS_KEY_ID'],
                              :secret_access_key => ENV['AWS_SECRET_ACCESS_KEY'])
  servers = @ec2.describe_instances.reservationSet.item.collect do |itemgroup|
    itemgroup.instancesSet.item.collect {|item| item.ipAddress}
  end
  servers.flatten
end

목록 6에서는 웹 역할을 정적 정의에서 my_instances 함수로부터 리턴된 동적 서버 목록으로 변경한다. 이 함수는 Amazon EC2 APIDescribeInstances 호출을 사용하여 서버 목록을 리턴한다. API는 동일한 예약 ID 아래에서 함께 실행된 인스턴스를 그룹화하는 형식으로 데이터를 리턴한다. 외부 collect 루프는 이러한 예약 그룹을 반복하고 내부 collect 루프는 각 제한 그룹 내에 포함된 서버를 반복한다. 결과는 배열의 배열이 발생하며 이 배열은 서버 IP 주소의 단일 차원 배열로 변환되어 다시 호출자에게 전달된다.

Capistrano가 동적 서버 목록에서 작동하는 방법을 제공한 것은 다행이다. 이러한 연결 고리가 제공되지 않았다면 또다른 접근 방식을 이용해야 했을 것이다.

관리 서버에 등록하기

동적 서버 목록의 사용을 쉽게 허용하지 않는 애플리케이션의 경우에는 클라우드 서버 자체가 다른 애플리케이션에 등록되도록 하여 문제를 해결할 수 있다. 이 프로세스는 일반적으로 다음 두 가지 양식 중 하나를 사용한다.

  • 클라우드 서버는 또다른 서버에 연결하여 스크립트를 실행하며 이를 통해 관리 애플리케이션이 직접 업데이트된다.
  • 클라우드 서버는 다른 스크립트가 구성 파일을 다시 빌드할 공통 위치(예: Amazon S3(Simple Storage Service))에 일부 메타 데이터가 포함된 파일을 놓는다.

직접 업데이트

Cacti는 스크립트 또는 SNMP(Simple Network Management Protocol)를 통해 다양한 메트릭을 그래프로 표시하고 이러한 그래프를 대시보드 또는 메타 그래프로 결합할 수 있는 유명한 성능 관리 도구이다(참고자료 참조). Cacti에 대한 제한은 명령행 스크립트를 통하거나 Cacti 웹 인터페이스 내에서 관리에 적합하게 서버를 구성해야 한다는 것이다. 이 예제에서 클라우드 서버는 Cacti 서버에 다시 연결하여 자신을 구성한다.

Cacti는 템플리트의 시스템을 기반으로 하여 그래프에 대한 대량 변경을 훨씬 더 쉽게 만든다. 하지만 모든 명령행 도구는 템플리트 ID에 대해 작동하므로 먼저 사용할 ID를 파악해야 한다. 목록 7에서는 일부 데이터 요소를 미리 채우는 호스트 템플리트를 찾는 방법을 보여 준다.


목록 7. 호스트 템플리트 나열하기
	
$ php -q /var/lib/cacti/cli/add_device.php --list-host-templates
Valid Host Templates: (id, name)
0       None
1       Generic SNMP-enabled Host
3       ucd/net SNMP Host
4       Karlnet Wireless Bridge
5       Cisco Router
6       Netware 4/5 Server
7       Windows 2000/XP Host
8       Local Linux Machine

템플리트 번호 3은 대부분의 Linux® 배포판과 함께 사용할 수 있는 Net-SNMP 디먼을 실행 중인 호스트를 위한 것이다. 더 일반적인 버전 대신 이 특정 디먼을 사용하면 일부 Linux 특정 카운터를 쉽게 모니터할 수 있다.

사용자가 호스트 템플리트 3을 사용한다는 것을 알고 있으므로 사용 가능한 그래프 목록이 목록 8에 표시된다.


목록 8. 그래프 템플리트 나열하기
	
$ php -q /var/lib/cacti/cli/add_graphs.php --list-graph-templates --host-template-id=3
Known Graph Templates:(id, name)
4       ucd/net - CPU Usage
11      ucd/net - Load Average
13      ucd/net - Memory Usage

목록 8에 있는 세 가지 그래프는 기본 Cacti 배포판과 함께 제공되는 그래프이다. 더 많은 수를 추가하거나 --host-template-id 옵션을 사용하지 않거나 인터넷의 소스에서 그래프를 가져올 수 있다.

목록 9에서는 새로운 디바이스를 추가한 후 CPU 그래프를 추가하는 방법을 보여 준다.


목록 9. 그래프와 함께 새로운 디바이스 추가하기
	
$ php -q /var/lib/cacti/cli/add_device.php --description="EC2-1.2.3.4" \
  --ip=1.2.3.4 --template=3
Adding EC2-1.2.3.4 (1.2.3.4) as "ucd/net SNMP Host" using SNMP v1 with community "public"
Success - new device-id: (5)
php -q /var/lib/cacti/cli/add_graphs.php --host-id=5 --graph-type=cg \
  --graph-template-id=4
Graph Added - graph-id: (6) - data-source-ids: (11, 12, 13)

목록 9에서는 먼저 IP 주소가 1.2.3.4인 호스트를 추가한다. 리턴되는 디바이스 ID는 5이며 이는 CPU 사용량에 대한 그래프를 추가한다(그래프 유형 cg 및 템플리트 4). 결과는 그래프의 ID와 현재 모니터 중인 다양한 데이터 소스의 ID이다.

이제 매우 편리하게 목록 9에 있는 프로시저를 스크립트화할 수 있다. 목록 10에서는 이러한 스크립트를 보여 준다.


목록 10. add_to_cacti.sh
	
#!/bin/bash

IP=$1

# Add a new device and parse the output to only return the id
DEVICEID=`php -q /var/lib/cacti/cli/add_device.php --description="EC2-$IP" \
  --ip=$IP --template=3 | grep device-id | sed 's/[^0-9]//g'`
# CPU graph
php -q /var/lib/cacti/cli/add_graphs.php --host-id=$DEVICEID --graph-type=cg \
    --graph-template-id=4

스크립트에 대한 첫 번째 매개변수는 $IP라는 변수에 저장된다. add_device.php 스크립트는 이 IP 주소를 사용하여 실행되며 grep 명령을 사용하여 ID가 포함된 행만 출력되도록 필터링된다. 이 출력은 숫자만 출력하는 sed 스크립트에 피드된다. 이 값은 $DEVICEID라는 변수에 저장된다.

디바이스 ID가 저장되면 그래프를 추가하는 것이 add_graphs.php 스크립트를 호출하는 것만큼 단순해진다. CPU 그래프가 가장 단순한 경우이며 일부 다른 유형의 그래프에는 더 많은 매개변수가 필요하다.

add_to_cacti.sh 스크립트가 Cacti 서버에 있으면 클라우드 서버가 이를 실행하기만 하면 된다. 목록 11에서는 스크립트 호출 방법을 보여 준다.


Listing 11. 클라우드 서버에서 cacti 스크립트 호출하기
	
#!/bin/bash

MYIP=`/usr/bin/curl -s http://169.254.169.254/2007-01-19/meta-data/public-ipv4`
ssh cacti@cacti.example.com "/usr/local/bin/add_to_cacti.sh $MYIP"

목록 11에서는 먼저 Amazon EC2 메타 데이터 서버를 호출하여 공용 IP 주소를 리턴한 후 Cacti 서버에서 원격으로 명령을 실행한다.

Puppet으로 돌아가기

앞서 자세히 설명한 rsync 대신 Puppet 서버와 인증 기관을 사용하려는 경우 이 패턴이 유용하다.

결론

이 일련의 기사에서는 단일 서버에서 AWS 클라우드로의 애플리케이션 마이그레이션에 대해 살펴봤다. 새로운 서버의 실행에서 로드 밸런서에 이르기까지 Amazon EC2 오퍼링을 활용하기 위한 개선이 점점 많이 진행되었다. 이 마지막 기사에서는 동적 클라우드 환경 관리에 대해 살펴보고 사용할 수 있는 일부 패턴을 제공했다.

클라우드 자원을 사용하기 위한 초기 비용이 많지 않다는 것을 고려하면 실제로 마이그레이션을 수행해 봐야 한다. 클라우드를 사용하는 프로덕션에서 애플리케이션을 실행하지 않도록 결정하는 경우에도 클라우드에서 수행될 수 있는 사항에 대해 많이 알게 되고 시스템 관리 스킬을 개선할 수도 있을 것이다.

List of Articles
번호 제목 글쓴이 날짜 조회 수
47 “개발자라면 즉시 설치!” 크롬 확장 프로그램 10가지 WindBoy 2015-03-23 108
46 Dell의 교육용 크롬북 11 “거칠게 뛰노는 아이들을 위한 튼튼한 노트북" WindBoy 2015-02-24 101
45 클라우드에서 동작하는 빅 데이터 애널리틱스 ‘조이엔트 만타’ WindBoy 2013-06-29 1553
44 무료 아마존 웹 서비스, 100% 알뜰하게 사용하는 방법 WindBoy 2013-04-14 2961
43 고해상도 크롬북의 사향 WindBoy 2013-02-24 2277
42 3년차 N드라이브, 네이버 촘촘히 엮었네 [1] WindBoy 2013-01-24 2893
41 클라우스 보안 WindBoy 2012-12-10 2361
40 뜬구름 같던 클라우드를 KT에서 현실화 하고 있네 WindBoy 2012-10-15 2362
39 오라클 “늦게 배운 클라우드, 자신 있다” WindBoy 2012-07-24 2482
38 국정원과 방통위의 황당한 클라우드 이야기 WindBoy 2012-07-04 2484
37 코앞에 다가온 웹하드 등록제, 알고 있나요 WindBoy 2012-05-02 2781
36 아마존 클라우드에 대한 오해 5가지 WindBoy 2012-04-25 2852
35 아마존이 말하는 클라우드의 5대 조건 WindBoy 2012-04-25 2980
34 간단하게 알아본 클라우드로 스마트한 문서관리, 하나도 어렵지 않아요~ WindBoy 2012-02-20 5265
33 최적의 클라우드 컴퓨팅 플랫폼 찾기 WindBoy 2012-01-06 2967
32 클라우드 컴퓨팅 – 비즈니스 전략에 큰 영향을 미치는 플랫폼 WindBoy 2012-01-06 3034
31 Amazon Web Services를 사용한 클라우드 컴퓨팅 Part 1~5 WindBoy 2012-01-06 3805
» Amazon 클라우드에 Linux 애플리케이션 마이그레이션하기 WindBoy 2012-01-06 5706
29 Cultured Perl: Amazon S3의 스토리지 관리 WindBoy 2012-01-06 3943
28 Cultured Perl: Perl and the Amazon cloud Part1~5 WindBoy 2012-01-06 6343