2022. 7. 19. 18:01ใAWS
โ๏ธ To-Be Architecture
Slack Slash commands๋ฅผ ์ด์ฉํ์ฌ API Gateway๋ฅผ ํตํด Lambda ํจ์๋ฅผ ํธ์ถํด๋ณด์.
(Slack Docs: Enabling interactivity with Slash Commands๋ฅผ ๋จผ์ ์ฝ๊ณ Slash Command๊ฐ ์ด๋ค ๊ฒ์ธ์ง, ์ด๋ค ํํ๋ก ๋ฐ์ดํฐ๋ฅผ ๋ณด๋ด๋์ง ํ์ ํ ํ ์์ํ์๋ ๊ฒ์ ์ถ์ฒํฉ๋๋ .)
IAM
Lambda ํจ์์ ์ฐ๊ฒฐํ IAM ์ญํ ์ ์์ฑํ์. API Gateway๊ฐ Lambda ํจ์๋ฅผ invoke ํ ์ ์๋ ๊ถํ์ ์ค๋ค.
1. IAM Policy ์์ฑ
// IAM Policy
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "test",
"Effect": "Allow",
"Action": "lambda:InvokeFunction",
"Resource": "*"
}
]
}
2. IAM Role ๊ตฌ์ฑ
2-1. IAM Role ์์ฑ
- Truested entity type : AWS Service
- Use case : Lambda
- 1์์ ๋ง๋ policy ์ฐ๊ฒฐ
2-2. ์ ๋ขฐ๊ด๊ณ ํธ์ง
- AWS API Gateway๋ ํด๋น role์ assume ํ ์ ์๋๋ก Principal์ Service์ apigateway.amazonaws.com์ ์ถ๊ฐ.
// IAM Role > Trust relationships
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [
"lambda.amazonaws.com",
"apigateway.amazonaws.com"
]
},
"Action": "sts:AssumeRole"
}
]
}
Lambda
1. Lambda ํจ์ ์์ฑ
- ์คํ ์ญํ > ๊ธฐ์กด ์ญํ ์ฌ์ฉ > [IAM]์์ ๋ง๋ ์ญํ ์ ํ
- ์์ฑ๋ ๋๋ค ํจ์์ ๊ตฌ์ฑ ํญ > ๊ถํ์์ ์ญํ ์ด ์ฐ๊ฒฐ๋์์์ ํ์ธํ ์ ์๋ค.
2. ์ฝ๋ ์์ฑ
# ์ํ๋ ๋ก์ง์ ์์ฑํ์๋ฉด ๋ฉ๋๋ค.
def lambda_handler(event, context):
return {
"response_type": "in_channel",
"text": "Success~~~~~~~!"
}
API Gateway
1. ์ ๊ท API ์์ฑ
- ์๋ํฌ์ธํธ ์ ํ
- Regional(์ง์ญ) : ํ์ฌ region์ API๊ฐ ๋ฐฐํฌ๋๋ค.
- Edge Optimized(์ฃ์ง ์ต์ ํ) : Cloudfront ๋คํธ์ํฌ์ API๊ฐ ๋ฐฐํฌ๋๋ค.
- Private(ํ๋ผ์ด๋น) : API Gateway๋ฅผ ์ํ VPC ์๋ํฌ์ธํธ๋ฅผ ํตํด์๋ง ์ ๊ทผ์ด ๊ฐ๋ฅํ๋ค.
2. ๋ฉ์๋ ์์ฑ
- slash command๋ API Gateway Endpoint๋ก HTTP POST๋ฅผ ๋ณด๋ด๊ธฐ ๋๋ฌธ์ request type์ POST๋ก ์ค์ ํ๋ค.
- ์ํ๋ ๊ฒฝ์ฐ, GET ์์ฒญ์ผ๋ก ํธ์ถํ ์๋ ์๋ค.
- Integration : Lambda ํจ์
- Lambda Function : ์์์ ์์ฑํ ๋๋ค ํจ์์ ์ด๋ฆ์ ์ ๋ ฅ.
→ ๋๋ค ์ฝ์์ ๊ฐ์ ํ์ธํด๋ณด์.
ํด๋น ํจ์์์ trigger ํ๋ ์๋น์ค๋ก API Gateway๊ฐ ์ถ๊ฐ๋์์ ํ์ธํ ์ ์๋ค.
Configuration ํญ > (์ฌ์ด๋๋ฐ) Triggers์์๋ ํ์ธํ ์ ์์ผ๋ฉฐ 1์์ ์์ฑํ API(hyeonju-api)๊ฐ ํธ๋ฆฌ๊ฑฐํ ์ ์๋ ์๋น์ค๋ก ์ถ๊ฐ๋์์ ์๋ฏธํ๋ค.
๋, ๋๋ค ํจ์์ Configuration ํญ > (์ฌ์ด๋๋ฐ) Permissions > Resource-based policy ์น์ ์์ ์ ์ฑ ์ด ์ถ๊ฐ๋์์ ํ์ธํ ์ ์๋ค.
์์ฑํ POST ๋ฉ์๋์ ๋ํด ํด๋น ํจ์๋ฅผ invoke ํ ์ ์๋ ๊ถํ์ ๋ถ์ฌํ์์ ์๋ฏธํ๋ค. AWS ์๋น์ค ์ธ์ ๋ค๋ฅธ AWS Account์๊ฒ๋ ํจ์๋ฅผ invokeํ ์ ์๋ ๊ถํ์ ๋ถ์ฌํ ์ ์๋ค.
3. Integration Request ์ค์
๋ค์ API Gateway ์ฝ์๋ก ๋์์ค์.
Integration Request์์๋ ๋ฐฑ์๋์ ๋ฉ์๋๊ฐ ์คํ๋๋ ํ์ (Lambda, HTTP, AWS service ๋๋ Mock)์ ์ด๋ป๊ฒ ์์ฒญ ๋ฐ์ดํฐ๊ฐ ๋ฉ์๋์ ๋ฐฑ์๋๋ก ๋ณด๋ด์ง๊ธฐ ์ ๊น์ง ๋ณํ๋๋์ง๋ฅผ ์ค์ ํ ์ ์๋ค. ์๋ฅผ ๋ค์ด, ๋๋ค ํจ์๋ ํค๋๋ ์ฟผ๋ฆฌ ์คํธ๋ง ํ๋ผ๋ฏธํฐ๋ฅผ ๋ฐ์ง ๋ชปํ์ง๋ง, API Gateway๋ฅผ ์ด์ฉํ์ฌ JSON์ผ๋ก ์์ฒญ ๊ฐ์ ๋ชจ๋ ํฌํจํ ์ ์๋๋ก ์ค์ ํ ์ ์๋ค.
- [Mapping Templates] ํญ ์ ํ > [When there are no templates defined (recommended)] ์ ํ > [Add mapping template] ๋ฒํผ ์ ํ
- application/x-www-form-urlencoded ์
๋ ฅ
- slack slash command์์ POST ๋ฐฉ์์ผ๋ก request๋ฅผ ์ ์กํ ๋ ๋ฐ์ดํฐ์ Content-type ํค๋๋ application/x-www-form-urlencoded์ด๋ค.
- application/x-www-form-urlencoded๋ ์๋ฒ์ ์ ์ก๋๋ HTTP ๋ฉ์์ง๊ฐ ํ๋์ ํฐ ์ฟผ๋ฆฌ ์คํธ๋ง์ด๊ณ ์ด๋ฆ/๊ฐ ์๋ค์ด "&"๋ก ๊ตฌ๋ถ๋์ด ์์ผ๋ฉฐ, ์ด๋ฆ๊ณผ ๊ฐ์ "="์ผ๋ก ๊ตฌ๋ถ๋๋ค.
- Mapping Template์ ์ด์ฉํ์ฌ ์์ฒญ ๋ฐ์ดํฐ์ ํ์ ์ JSON์ผ๋ก ๋ฐ์ดํฐ ํ์ ์ ๋ณํํ๊ณ Lambda์ event ํ๋ผ๋ฏธํฐ๋ก ๋๊ฒจ์ฃผ์.
## convert HTML POST data to JSON
## get the raw post data from the AWS built-in variable and give it a nicer name
#set($rawAPIData = $input.path('$'))
## first we get the number of "&" in the string, this tells us if there is more than one key value pair
#set($countAmpersands = $rawAPIData.length() - $rawAPIData.replace("&", "").length())
## if there are no "&" at all then we have only one key value pair.
## we append an ampersand to the string so that we can tokenise it the same way as multiple kv pairs.
## the "empty" kv pair to the right of the ampersand will be ignored anyway.
#if ($countAmpersands == 0)
#set($rawPostData = $rawAPIData + "&")
#end
## now we tokenise using the ampersand(s)
#set($tokenisedAmpersand = $rawAPIData.split("&"))
## we set up a variable to hold the valid key value pairs
#set($tokenisedEquals = [])
## now we set up a loop to find the valid key value pairs, which must contain only one "="
#foreach( $kvPair in $tokenisedAmpersand )
#set($countEquals = $kvPair.length() - $kvPair.replace("=", "").length())
#if ($countEquals == 1)
#set($kvTokenised = $kvPair.split("="))
#if ($kvTokenised[0].length() > 0)
## we found a valid key value pair. add it to the list.
#set($devNull = $tokenisedEquals.add($kvPair))
#end
#end
#end
## next we set up our loop inside the output structure "{" and "}"
{
#foreach( $kvPair in $tokenisedEquals )
## finally we output the JSON for this pair and append a comma if this isn't the last pair
#set($kvTokenised = $kvPair.split("="))
"$util.urlDecode($kvTokenised[0])" : #if($kvTokenised[1].length() > 0)"$util.urlDecode($kvTokenised[1])"#{else}""#end#if( $foreach.hasNext ),#end
#end
}
4. API ๋ฐฐํฌ
- API๋ ์คํ ์ด์ง์ ๋ฐฐํฌ๋๋ค. ์คํ ์ด์ง๋ API์ ํ๊ฒฝ(dev, prod, beta)๊ณผ ๊ฐ๋ค.
- Stage๋ ๋ฐฐํฌ์ ๋ํ ํ์คํ ๋ฆฌ๋ฅผ ์ ์ฅํ๊ณ ์ธ์ ๋ ๊ทธ ์ ๋ฐฐํฌ๋ก ๋กค๋ฐฑํ ์ ์๋ค. ์ถํ์ ์ฝ๊ฒ ๋กค๋ฐฑํ ์ ์๋๋ก ๊ฐ ๋ฐฐํฌ์ ๋ํ description์ ์์ฑํ๋ ๊ฒ์ด ์ข๋ค.
- API๊ฐ ์ URL๋ก ๋ฐฐํฌ๋์๋ค. ํด๋น URL์ ๋ณต์ฌํ์.
Slack Slash Command
1. ์ํ๋ ์ฑ๋์ Slash Commands ์ฑ ์ถ๊ฐ
2. slash commands ์ค์
- ํตํฉ ์ค์ > URL์ ๋ฐฐํฌํ stage์ URL์ ์ ๋ ฅํ๋ค.
- ์์ ๊ฐ์ ์ค์ ๋๋ก๋ผ๋ฉด, ํด๋น ์ฑ๋์์ /hyeonju๋ฅผ ์ ๋ ฅ ์ ํด๋น URL๋ก request๊ฐ ์ ์ก๋๋ค.
3. ํ ์คํธ
ํ ์คํธ ์ฑ๊ณต~~! ๐
๐จ ์ฃผ์ ๐จ slash command ๋ค ๋ฐ๋์ ํ ์คํธ๋ฅผ ์์ฑํด์ผ ํ๋ค. ex) /hyeonju aaa ํ ์คํธ ์์ฑ ์์ด /hyeonju๋ง ์ ๋ ฅ ์ 500 ์๋ฌ๊ฐ ๋ฐ์ํ๋ค. |
(์ ํ) Cloudwatch๋ก API Gateway ๋ชจ๋ํฐ๋งํ๊ธฐ
slack slash commands ๊ตฌ์ฑ ํ, ์๋์ ๊ฐ์ ์๋ฌ๊ฐ ๋ฐ์ํ๋ค๋ฉด ํธ๋ฌ๋ธ์ํ ๋ฐ ๋ก๊น ์ ์ํด ์ถ๊ฐ๋ก cloudwatch๋ฅผ ๊ตฌ์ฑํ ์ ์๋ค.
1. IAM Role ์์ฑ
API Gateway์ ๊ณ์ ์ CloudWatch Log๋ฅผ ์ฝ๊ณ ์ธ ์ ์๋ ๊ถํ์ ๋ถ์ฌํ๋ค.
- Service : API Gateway
- AWS Managed Policy์ธ [AmazonAPIGatewayPushToCloudWatchLogs] ์ ์ฑ
์ ์ถ๊ฐํ๋ค.
์ด์ ๋จ๊ณ์์ ์๋น์ค๋ก API Gateway ์ ํ ์ ์๋์ผ๋ก ์ถ๊ฐ๋์ด ์๋ค. - ์ด๋ฆ ์ค์ ํ, ๊ทธ๋๋ก ์ญํ ์์ฑ.
- ์์ฑ๋ ์ญํ ์ ARN์ ๋ณต์ฌํ๋ค.
2. AWS API Gateway์ API IAM Role ์ค์
- Settings์ CloudWatch log role ARN ์ ๋ ฅ์ฐฝ์ ๋ณต์ฌํ IAM Role ARN์ ์ ๋ ฅํ๋ค.
3. AWS CloudWatch ๋ก๊ทธ ๊ทธ๋ฃน ์์ฑ
4. Stage์ ๋ํ Logs/Tracing ์ค์
- Enable CloudWatch ํ์ฑํ
- Log full requests/responses data ํ์ฑํ
- Enable Access Logging ํ์ฑํ
- List of Lost Variables๋ฅผ ์ฐธ๊ณ ํ์ฌ ์ํ๋ ๋ก๊น ๋ณ์ ์ ํํ์ฌ ๋ก๊ทธ ํฌ๋งท ๊ตฌ์ฑ
- ์๋ฌ ๋ฐ์ ์ Cloudwatch > Log group์์ ์์ ๊ฐ์ด ๋ก๊ทธ๋ฅผ ํ์ธํ ์ ์๋ค.
๐ ์ฐธ๊ณ ๋ฌธ์
- Slack API Docs: Enabling interactivity with Slash Commands
- Building a Slack Slash Command with C# + AWS Lambda + API Gateway
- ๊ธฐ์ ๋ธ๋ก๊ทธ: Slack Slash Command๋ฅผ ํตํด ์ง ๊ทผ์ฒ ์ฝ๊ตญ ๋ง์คํฌ ์๋ ์์๋ณด๊ธฐ
- AWS Docs: [AWS API Gateway] Cloudwatch ๋ก๊น ์ ๋ํ ๊ถํ
- AWS Docs: Amazon API Gateway์์ ์คํ ์ด์ง ๋ณ์๋ฅผ ์ฌ์ฉํ์ฌ AWS Lambda ํตํฉ์ ์ ์ํ์ต๋๋ค. API ๋ฉ์๋๋ฅผ ํธ์ถํ ๋ "๋ด๋ถ ์๋ฒ ์ค๋ฅ"์ 500 ์ํ ์ฝ๋๊ฐ ํ์๋๋ ์ด์ ๋ ๋ฌด์์ ๋๊น?