Amazon Web Services 한국 블로그

AWS App Runner 신규 기능 – VPC 지원 시작

AWS App Runner를 사용하면 규모에 구애받지 않고 웹 애플리케이션과 API를 신속하게 배포할 수 있습니다. 소스 코드나 컨테이너 이미지를 가지고 시작할 수 있습니다. 애플리케이션에 적합한 서버, 네트워킹 및 로드 밸런싱 등을 포함한 모든 인프라는 App Runner가 완전히 관리합니다. 원한다면 App Runner로 배포 파이프라인도 구성할 수 있습니다.

오늘부터 App Runner가 사용자 서비스와 Amazon Virtual Private Cloud(VPC)에서 호스팅되는 데이터베이스 및 여타 애플리케이션과의 통신을 지원하게 되었습니다. 예를 들어 이제부터는 App Runner 서비스를 Amazon Relational Database Service(RDS), Redis 또는 Amazon ElastiCache의 Memcached 캐시 데이터베이스에 연결할 수도 있고, Amazon Elastic Container Service(Amazon ECS), Amazon Elastic Kubernetes Service(EKS), Amazon Elastic Compute Cloud(Amazon EC2) 또는 온프레미스에서 실행되어 AWS Direct Connect를 통해 연결된 자체 애플리케이션에 연결할 수도 있습니다.

이전에는 App Runner 애플리케이션을 이러한 리소스에 연결하려면 해당 리소스에 인터넷을 통해 공개적으로 액세스할 수 있어야 했습니다. 이 기능이 생기면서 App Runner 애플리케이션을 VPC 내 프라이빗 엔드포인트에 연결하고, 사용자는 이러한 리소스에 대한 퍼블릭 액세스를 제거하여 더욱 안전하고 규정을 준수하는 환경을 지원할 수 있게 됩니다.

이제 App Runner 내에 VPC 커넥터를 만들어 프라이빗 네트워킹에 사용할 VPC, 서브넷과 보안 그룹을 지정할 수 있습니다. 구성을 마친 뒤에는 VPC 커넥터를 하나 이상의 App Runner 서비스와 함께 사용할 수 있습니다.

AppRunner 서비스에서 발신되는 모든 트래픽은 VPC에 연결되면 VPC 라우팅 규칙에 따라 라우팅됩니다. 서비스는 NAT 게이트웨이로 향하는 경로가 허용하지 않은 한 퍼블릭 인터넷(AWS API 포함)에 액세스하지 않습니다. 또한 VPC 엔드포인트Amazon Simple Storage Service(Amazon S3)Amazon DynamoDB와 같은 AWS API에 연결하도록 설정하여 NAT 트래픽을 피할 수도 있습니다.

App Runner의 VPC 커넥터는 AWS LambdaVPC 네트워킹과 비슷하게 작동하며 AWS Hyperplane 기반입니다. 이것은 Network Load Balancer, NAT 게이트웨이AWS PrivateLink와 같은 AWS 서비스 및 리소스 배후의 Amazon 내부 네트워크 함수 가상화 시스템입니다.

이것이 실제로 어떻게 작동하는지 RDS 데이터베이스에 연결된 웹 애플리케이션을 예로 들어 살펴보겠습니다.

Amazon RDS 데이터베이스 준비
우선 애플리케이션에 대하여 데이터베이스를 구성하는 것부터 시작합니다. 이 데이터베이스의 용량 관리를 간소화하기 위해 Amazon Aurora Serverless를 사용합니다. RDS 콘솔에서 Amazon Aurora MySQL-Compatible 데이터베이스를 생성합니다. 용량 유형으로는 서버리스를 선택합니다. 네트워킹에는 기본 VPC기본 보안 그룹을 사용합니다. 프라이빗 VPC 네트워킹을 사용해서 접속할 예정이라 데이터베이스를 공개 액세스 가능하게 설정하지 않아도 됩니다. 나중에 연결을 간소화하기 위해 AWS Identity and Access Management(IAM) 데이터베이스 인증을 활성화합니다.

같은 VPC에서 Amazon Linux EC2 인스턴스를 시작합니다. EC2 인스턴스에서 데이터베이스로 연결하려면 MySQL 클라이언트가 있어야 합니다. 커뮤니티에서 개발한 MySQL 분기인 다음과 같은 MariaDB를 설치합니다.

sudo yum install mariadb

그런 다음 admin 사용자 자격으로 데이터베이스에 연결합니다.

mysql -h <DATABASE_HOST> -u admin -P

admin 사용자 비밀번호를 입력해 로그인합니다. 그런 다음 IAM 인증을 사용하도록 구성된 새 사용자(bookuser)를 생성합니다.

CREATE USER bookuser IDENTIFIED WITH AWSAuthenticationPlugin AS 'RDS'; 

bookcase 데이터베이스를 만들고 bookuser 사용자에게 bookcase 데이터베이스에 쿼리하도록 권한을 부여합니다.

CREATE DATABASE bookcase;
GRANT SELECT ON bookcase.* TO 'bookuser'@'%’;

책에 관한 정보를 저장할 authorsbooks 테이블을 만듭니다.

CREATE TABLE authors (
  authorId INT,
  name varchar(255)
 );

CREATE TABLE books (
  bookId INT,
  authorId INT,
  title varchar(255),
  year INT
);

그런 다음 이 두 테이블에 몇 가지 값을 삽입합니다.

INSERT INTO authors VALUES (1, "Issac Asimov");
INSERT INTO authors VALUES (2, "Robert A. Heinlein");
INSERT INTO books VALUES (1, 1, "Foundation", 1951);
INSERT INTO books VALUES (2, 1, "Foundation and Empire", 1952);
INSERT INTO books VALUES (3, 1, "Second Foundation", 1953);
INSERT INTO books VALUES (4, 2, "Stranger in a Strange Land", 1961);

애플리케이션 소스 코드 리포지토리 준비
App Runner를 사용해 소스 코드 리포지토리에서1 호스팅되는 코드를 사용하거나, 컨테이너 이미지를 사용해 새 서비스를 배포할 수 있습니다. 이 예시에서는 GitHub에 저장해 둔 개인 프로젝트를 사용하겠습니다.

방금 만든 데이터베이스에 연결하는 아주 단순한 Python 웹 애플리케이션입니다. 이것이 앱의 소스 코드입니다(server.py).

from wsgiref.simple_server import make_server
from pyramid.config import Configurator
from pyramid.response import Response
import os
import boto3
import mysql.connector

import os

DATABASE_REGION = 'us-east-1'
DATABASE_CERT = 'cert/us-east-1-bundle.pem'
DATABASE_HOST = os.environ['DATABASE_HOST']
DATABASE_PORT = os.environ['DATABASE_PORT']
DATABASE_USER = os.environ['DATABASE_USER']
DATABASE_NAME = os.environ['DATABASE_NAME']

os.environ['LIBMYSQL_ENABLE_CLEARTEXT_PLUGIN'] = '1'

PORT = int(os.environ.get('PORT'))

rds = boto3.client('rds')

try:
    token = rds.generate_db_auth_token(
        DBHostname=DATABASE_HOST,
        Port=DATABASE_PORT,
        DBUsername=DATABASE_USER,
        Region=DATABASE_REGION
    )
    mydb =  mysql.connector.connect(
        host=DATABASE_HOST,
        user=DATABASE_USER,
        passwd=token,
        port=DATABASE_PORT,
        database=DATABASE_NAME,
        ssl_ca=DATABASE_CERT
    )
except Exception as e:
    print('Database connection failed due to {}'.format(e))          

def all_books(request):
    mycursor = mydb.cursor()
    mycursor.execute('SELECT name, title, year FROM authors, books WHERE authors.authorId = books.authorId ORDER BY year')
    title = 'Books'
    message = '<html><head><title>' + title + '</title></head><body>'
    message += '<h1>' + title + '</h1>'
    message += '<ul>'
    for (name, title, year) in mycursor:
        message += '<li>' + name + ' - ' + title + ' (' + str(year) + ')</li>'
    message += '</ul>'
    message += '</body></html>'
    return Response(message)

if __name__ == '__main__':

    with Configurator() as config:
        config.add_route('all_books', '/')
        config.add_view(all_books, route_name='all_books')
        app = config.make_wsgi_app()
    server = make_server('0.0.0.0', PORT, app)
    server.serve_forever()

이 애플리케이션은 IAM 데이터베이스 인증용으로 AWS SDK for Python(boto3), Pyramid 웹 프레임워크, 그리고 MySQL connector for Python을 사용합니다. requirements.txt 파일에 애플리케이션 종속성이 설명되어 있습니다.

boto3
pyramid==2.0
mysql-connector-python

데이터베이스에 연결할 때 SSL/TLS 암호화를 사용하려면 인증서 번들을 다운로드하여 이것을 소스 코드 리포지토리에 추가하면 됩니다.

AWS App Runner에서 VPC 지원 사용
App Runner 콘솔에서 소스 코드 리포지토리를 선택하고, 사용하고자 하는 분기를 선택합니다.

콘솔 스크린샷.

배포 설정에 수동을 선택합니다. 아니면 자동 배포 트리거를 선택할 수도 있는데, 이렇게 하면 이 분기에 푸시가 발생할 때마다 매번 서비스의 새 버전을 배포하게 됩니다.

콘솔 스크린샷.

그런 다음 빌드를 구성합니다. 이것은 아주 단순한 애플리케이션이므로 콘솔에 빌드와 시작 명령을 전달하기로 하겠습니다.

빌드 명령pip install -r requirements.txt
시작 명령python server.py

더 복잡한 사용 사례라면 리포지토리에 apprunner.yaml 구성 파일을 추가하면 됩니다. 이 샘플 애플리케이션과 마찬가지입니다.

콘솔 스크린샷.

서비스 구성에 애플리케이션이 데이터베이스에 연결하는 데 사용한 것과 같은 환경 변수를 추가합니다. 여기서는 IAM 인증을 사용하고 있으므로 데이터베이스 비밀번호를 전달하지 않아도 됩니다.

콘솔 스크린샷.

보안 섹션에서 IAM 데이터베이스 인증을 사용해 데이터베이스에 연결할 권한을 부여하는 IAM 역할을 선택합니다. IAM 데이터베이스 액세스를 위해 IAM 정책을 생성하고 사용하는 법에 설명된 내용을 참조하세요.

콘솔 스크린샷.

다음은 IAM 역할 구문입니다. 데이터베이스 리소스 ID는 RDS 콘솔의 구성 탭에 있습니다.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "rds-db:connect"
            ],
            "Resource": [
                "arn:aws:rds-db:<REGION>:<ACCOUNT>:dbuser:<DB_RESOURCE_ID>/<DB_USER>"
            ]
        }
    ]
}

신뢰 정책 역할의 경우, App Runner와 IAM의 작동 방식 인스턴스 역할 지침을 따릅니다.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "tasks.apprunner.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

네트워킹의 경우, 발신 네트워크 트래픽에 사용자 지정 VPC를 사용하는 새 옵션을 선택하고 다음으로 새 VPC 커넥터를 하나 추가합니다.

콘솔 스크린샷.

새 VPC 커넥터를 추가하려면 이름을 적어두고, 사용하고자 하는 VPC, 서브넷과 보안 그룹을 선택합니다. 여기에서는 기본 VPC와 기본 보안 그룹의 서브넷을 모두 선택합니다. 이렇게 하면 App Runner 서비스가 RDS 데이터베이스에 연결할 수 있게 됩니다.

콘솔 스크린샷.

다음번에 같은 VPC 네트워킹 요구 사항으로 또 다른 애플리케이션을 구성할 일이 생기면 전에 생성해둔 VPC 커넥터를 선택하기만 하면 됩니다.

콘솔 스크린샷. 설정을 모두 검토한 다음 서비스를 생성하여 배포합니다.

몇 분이 지나면 서비스가 실행되고, 브라우저에서 새 탭을 열 기본 도메인을 선택합니다. 애플리케이션이 VPC 네트워킹을 사용해 데이터베이스에 연결되고, SQL 쿼리를 수행하여 booksauthors 테이블에 조인하며 몇 가지 추천서를 제안합니다. 제대로 작동합니다!

브라우저 스크린샷.

가용성 및 요금
VPC 커넥터는 AWS App Runner를 판매하는 모든 AWS 리전에서 이용할 수 있습니다. 자세한 내용은 리전 서비스 목록을 참조하세요. 이 기능을 사용해도 추가 비용이 부과되지는 않지만, 데이터 전송 표준 요금이나 사용자가 설정한 각종 NAT 게이트웨이 또는 VPC 엔드포인트 요금을 지불해야 합니다. AWS 관리 콘솔, AWS Command Line Interface(CLI), AWS SDKAWS CloudFormation로 VPC 커넥터를 설정할 수 있습니다.

VPC 커넥터를 사용하면 App Runner를 사용하여 애플리케이션을 배포한 다음 이를 프라이빗 데이터베이스, 캐시 및 VPC나 온프레미스에서 실행되며 AWS Direct Connect를 통해 연결된 애플리케이션과 연결할 수 있습니다.

규모에 구애받지 말고 웹 애플리케이션을 빌드하여 실행해 AWS App Runner를 사용해 프라이빗 VPC 리소스에 연결하세요.

Danilo