はじめに
ある案件でAppSyncを使うことになったが、商用利用の事例が少なくデプロイ方法がわからなかった。
自動でデプロイできる仕組みを探したところ、Serverless FrameworkのAppSyncプラグインがあったので使ってみた。
AppSyncとは
AppSyncはAWSで利用できるGraphQLベースのマネージドサービスである。
特徴として
- バックエンドサービスを自由に切り替えることができる
- GraphQLベースのため、フロントエンドに必要なデータを定義できる
などがある。
特にバックエンドにはLambdaやDynamoDB、HTTPなど多様なリソースを選択できる。
前提
今回の案件では以下の条件があった。
- AppSyncをLambdaバックエンドとHTTPバックエンドの二種類を実装
- フロントエンドはアプリ(iOS, Android) とWebアプリ(JavaScript)
- 環境は開発環境・検証環境・本番環境の3つ
- CloudFormation経験は薄く、Sceptreを使ってECS(Fargate)を作成した経験のみ
デプロイ方法の選定
現状AppSyncを商用利用して、デプロイするためには以下の手段が考えられた。
- CloudFormationを書く
- Amplify CLIを使う
CloudFormationを使ってデプロイするためにはYaml地獄と戦い、トライアンドエラーを繰り返す必要がある。
時間的猶予がなかったため却下した。
Amplify CLIはコマンド一つでAWSリソースを作ることができる強者である。
しかし、以下の懸念点があった。
- 開発当初は
env
機能がなかったため、環境を複数設定できない
- 複数のフロントエンドで共有することが難しい
そのため、リソースの作成にAmplify CLIを使用しなかった。
他に良いデプロイ方法はないか探していたら、以下の記事に遭遇し、ServerlessFrameworkのAppSyncプラグインを知った。
read.acloud.guru
Serverless Frameworkを使う予定があったので、試してみたら思いのほか手軽だった。
ここからは実際にデプロイした手順を記録していく。
Serverless FrameworkでAppSyncデプロイ
今回はAppSyncのバックエンドにLambdaを使用する。
GraphQL SchemaにはブログWebアプリケーションを想定に実装する。
サンプルはGitHubにもあげているので併せてみていただきたい。
github.com
NPMでインストールする。
$ npm install -g serverless
プロジェクト初期化
プロジェクトを初期化する。
このタイミングでは package.json
は作成されていない。
$ serverless create --template aws-nodejs --path appsync-deploy
$ cd appsync-deploy
$ ls -a
.gitignore handler.js serverless.yml
create
コマンドを実行するには template
オプションが必要である。
template
の種類は以下に詳細が記載されている。
serverless.com
成果物のうち serverless.yml
はCloudFormationのもとになるYaml定義。
handler.js
はAWS Lambdaを使用する場合の実行ファイルのため、AppSyncのデプロイだけでは不要である。
ServerlessFrameworkのプラグインはNPMパッケージでまとめられているため、 package.json
でプラグインを管理していく。
Node環境がまだないので、改めてNPM初期化を実施する
$ git init
$ npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.
See `npm help json` for definitive documentation on these fields
and exactly what they do.
Use `npm install <pkg>` afterwards to install a package and
save it as a dependency in the package.json file.
Press ^C at any time to quit.
package name: (appsync-deploy)
version: (1.0.0)
description:
entry point: (handler.js)
test command:
git repository:
keywords:
author:
license: (ISC)
About to write to appsync-deploy/package.json:
{
"name": "appsync-deploy",
"version": "1.0.0",
"description": "",
"main": "handler.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
AppSyncプラグインをインストールする。
$ npm i serverless serverless-appsync-plugin
デプロイコマンドをNPMの scripts
に定義する。
"scripts": {
"deploy": "serverless deploy -v"
},
これでデプロイを実行する準備が整った。
serverless.yml
を整えながら、AppSyncの設定を加えていく。
Serverless Framework共通設定
はじめに基本設定を記述していく。
serverless.yml
を開くと例が記載されているが、今回必要な部分は少ないので消す。
service: appsync-deploy
provider:
name: aws
region: ap-northeast-1
plugins:
- serverless-appsync-plugin
service
はCloudFormationのStack Nameに使用される部分であり、
デプロイ環境の総称となる。今回はプロジェクトのディレクトリ名を使用する。
provider
はCloud Providers(AWS)およびリージョンの設定をする。
plugins
にはインストールしたAppSyncのプラグインを記述する。
AppSyncの基本設定
このサンプルではAppSyncの認証に Amazon Cognitoを選択する。
Schemaは簡易的にするために Query
と Mutation
を一つずつにした。
Schemaの詳細を以下に記載する。
schema {
query: Query
mutation: Mutation
}
type Query {
listArticle: ArticlesResponse
}
type Mutation {
createArticle(title: String, content: String): ArticlesResponse
}
type Article {
id: Int
title: String
content: String
}
type ArticlesResponse {
errorCode: String
articles: [Article]
}
Schemaと認証設定を serverless.yml
に追記する。
custom:
accountId: ${env:AWS_ACCOUNT_ID}
appSync:
name: BlogApp
authenticationType: AMAZON_COGNITO_USER_POOLS
userPoolConfig:
awsRegion: ap-northeast-1
defaultAction: ALLOW
userPoolId: ap-northeast-1_XXXXX
schema: schema.graphql
Data Sources
バックエンドにはLambdaを使用するため、二つのARNが必要になる。
- LambdaそのもののARN
- AppSyncがLambdaを実行するRoleのARN
Roleはデフォルトの設定で作成されないため、事前にコンソールから作るか、
Serverless Frameworkの resources
機能で作る。
DataSourcesを serverless.yml
に反映すると以下になる。
custom:
accountId: ${env:AWS_ACCOUNT_ID}
appSync:
name: BlogApp
authenticationType: AMAZON_COGNITO_USER_POOLS
userPoolConfig:
awsRegion: ap-northeast-1
defaultAction: ALLOW
userPoolId: ap-northeast-1_XXXXX
schema: schema.graphql
dataSources:
- type: AWS_LAMBDA
name: BlogAppResolver
config:
functionName: blog-app-resolver
lambdaFunctionArn: "arn:aws:lambda:ap-northeast-1:${env:AWS_ACCOUNT_ID}:function:blog-app-resolver"
serviceRoleArn: "arn:aws:iam::${env:AWS_ACCOUNT_ID}:role/service-role/appsync-ds-lam-xxxxxxxxxxxxx
Mapping Templates
最後にMapping Templatesを整える。
Mapping Templatesのリクエストとレスポンスそれぞれをファイル化し、 mapping-templates
ディレクトリに格納することでAppSyncに反映する仕組みになっている。
レスポンスのMapping Templatesは共通化させて設定した。
レスポンス
common-response.vtl
$util.toJson($context.result)
Queryのリクエスト
query-list-blog-request.vtl
{
"version" : "2017-02-28",
"operation": "Invoke",
"payload": {
"path": "list_blog",
"data": $util.toJson($context.args)
}
}
Mutationのリクエスト
mutation-create-blog-request.vtl
{
"version" : "2017-02-28",
"operation": "Invoke",
"payload": {
"path": "create_blog",
"data": $util.toJson($context.args)
}
}
これらを mapping-templates
ディレクトリ以下に格納する。ディレクトリ名は変更することもできる。
Mapping Templatesの設定を serverless.yml
に反映すると以下のようになる。
custom:
accountId: ${env:AWS_ACCOUNT_ID}
appSync:
name: BlogApp
authenticationType: AMAZON_COGNITO_USER_POOLS
userPoolConfig:
awsRegion: ap-northeast-1
defaultAction: ALLOW
userPoolId: ap-northeast-1_H8OHxpYAa
schema: schema.graphql
dataSources:
- type: AWS_LAMBDA
name: BlogAppResolber
config:
functionName: blog-app-resolver
lambdaFunctionArn: "arn:aws:lambda:ap-northeast-1:${env:AWS_ACCOUNT_ID}:function:blog-app-resolver"
serviceRoleArn: "arn:aws:iam::${env:AWS_ACCOUNT_ID}:role/service-role/appsync-ds-lam-ln4jdz-blog-app-resolver"
mappingTemplates:
- dataSources: BlogAppResolber
type: Query
field: listArticle
request: "query-list-blog-request.vtl"
response: "common-response.vtl"
- dataSources: BlogAppResolber
type: Mutation
field: createArticle
request: "mutation-create-blog-request.vtl"
response: "common-response.vtl"
デプロイ実行
package.json
に登録したコマンドでデプロイを実行する。
サンプルはCognitoやRole ARNを仮で記載しているので、編集してから実行する。
$ npm run deploy
エラーが出る場合は環境変数に SLS_DEBUG
を追加することで、実行の詳細を確認することができる。
$ export SLS_DEBUG=*
Serverless Frameworkは最初に、 serverless.yml
ファイルをコンパイルして、CloudFormationに変換し、S3バケットに格納する。
成果物は .serverless
ディレクトリにも保存される。
S3に格納されたら、CloudFormationが実行され、定義したAWSリソースが生成される。
まとめ
- AppSyncの情報は少ない
- デプロイはServerless Frameworkが便利
参考
github.com