본문 바로가기

AWS

Mysql Aurora 네이티브 함수로 - Lambda 호출 ( feat. golang)

1. RDS 클러스터에 람다 역할 추가

  • IAM 에서 람다 최소권한을 줄수 있는 InvokeFunction 권한 정책 생성 
  • 위에서 만든 정책을 IAM 역할을 새로 만들어서 역할에 정책 부여
  • 이후 RDS 클러스터에 IAM 역할 관리에서 위에서 만든 역할을 할당 


2. 람다 함수 생성

  • RDS 와 같은 VPC 안에 동일한 서브넷 할당
  • 보안그룹 생성 혹은 기존에 있던 RDS 에 할당된 보안그룹 재귀로 받아서 연결

3. RDS 클러스터 파라미터 그룹 생성 및 aws_default_lambda_role 역할 부여

  • 파라미터 그룹 Type 에서 DB Cluser Parameter Group 을 선택해 파라미터 그룹 새로 생성

  • 파라미터 설정에 aws_default_lambda_role 값에 
  • 생성한 람다 함수의 ARN role 기입


4. RDS 환경 설정

  • AWS 공식문서 참고
  • SELECT user,host FROM mysql.user; 쿼리문에 아래처럼 설정되어 있는지 확인 


5. 람다 호출 테스트

  • SELECT lambda_async('람다ARN','');

정상적으로 호출되면 빈 JSON이 반환됨


6. 트러블 슈팅

  • Lambda API returned error: Missing IAM Credentials for specified aws_default_lambda_role
    • 1,3 번에 대해 제대로 설정이 안되었을 때 발생
  • Lambda API returned error: Network Connection. curlCode: 28, Timeout was reached
    • 보안그룹 아웃바운드룰 443 포트 열어줘야 함
  • Lambda API returned error: Invalid Request Content. Could not parse request body into json: 
    Could not parse payload into json: 
    Illegal unquoted character ((CTRLCHAR, code 10)): has to be escaped using backslash to be included in string value
    • 인코딩 할때 줄바꿈 이스케이프 문제
    • 아래에서 TO_BASE64()를 사용할때 REPLACE 로 개행제거
SET @data = TO_BASE64(CONCAT(
'{
	"ID": "', NEW.ID,'",
	"NAME": "', NEW.NAME,'",
	"DESCRIPTION": "', NEW.DESCRIPTION,'",		
}'
));

--

SET @data = REPLACE(TO_BASE64(CONCAT(
'{
	"ID": "', NEW.ID,'",
	"NAME": "', NEW.NAME,'",
	"DESCRIPTION": "', NEW.DESCRIPTION,'",		
}'
)),'\n,'');
    • MYSQL 컬럼 데이터 타입이 CHAR 인 경우에 null 이 찍히면 키네시스에 아무런 정보도 담기지 않음
      • lambda 에서 오류도 내 뱉지 않고 키네시스 for 문이 돌아가지도 않아 하나하나 컬럼 테스트 해본결과
      • 고정형 문자열(CHAR) 인 경우 null 말고 해당 길이의 데이터를 기입해야 키네시스가 제대로 돌아감
    • Unknown trigger has an error in its body: ‘Access denied; you need (at least one of) the Invoke Lambda privilege(s) for this operation’
      • 시발 이거 삽질을 몇일동안 한건지 좆같은년들 chatGPT 도 개소리하고 구글링해도 안나옴 ㅡㅡ
      • rds 클러스터 파라미터 그룹에 activate_all_roles_on_login 1 저장
      • 이후 아래 sql 문 실행후 trigger 테스트
# activate_all_roles_on_login 1 로 바꾸고 나서 아래 권한 부여 
-----

SELECT CURRENT_ROLE()

# 오로라 버전 3이상
GRANT AWS_LAMBDA_ACCESS TO 사용할디비계정@'%';

# 오로라 버전 2이상
GRANT INVOKE LAMBDA ON *.* TO 사용할디비계정@'%';

SET ROLE ALL ;
 
FLUSH PRIVILEGES;

------

코드 스니펫 (mysql + golang)

 

MySQL

# 키네시스로 넘기려면 base64 encoding 필요함 
SET @data = TO_BASE64(CONCAT('{"operation":"ping"}'));

# 아래 템플릿에 맞춰서 encoding 한 변수 CONCAT 으로 JSON payload 에 넘겨줌
SELECT lambda_async('람다함수ARN',CONCAT('{
	"Records":[
		{
			"kinesis":{
				"data":"',@data,'"
			}
		}
	]
}'));

# Trigger 

DELIMITER //
CREATE TRIGGER `test_lambda` 
AFTER INSERT ON 
`사용되어질 테이블 이름` FOR EACH ROW 
BEGIN 
	SET @data = TO_BASE64(CONCAT(
'{
	"ID": "', NEW.ID,'",
	"NAME": "', NEW.NAME,'",
	"DESCRIPTION": "', NEW.DESCRIPTION,'",		
}'
));
	SELECT lambda_async('ARN람다함수',CONCAT('{
	"Records":[
		{
			"kinesis":{
				"data":"',REPLACE(@data,'\n',''),'"
			}
		}
	]
}')) INTO @result;
END;
DELIMITER ;

 

패키지 설치

  • go get github.com/aws/aws-lambda-go
  • 아래 코드 zip 파일로 람다에 배포
package main

import (
	"context"
	"encoding/json"
	"fmt"
	"github.com/aws/aws-lambda-go/events"
	"github.com/aws/aws-lambda-go/lambda"
	"log"
	"os"
)

func init() {
	log.Println("테스트 시작")
}

type Payload struct {
	Operation string `json:"operation"`
}

func pingTest(ctx context.Context, event events.KinesisEvent) {

	for _, record := range event.Records {
		fmt.Printf("lambda_async 로부터 들어온 데이터", record)

		if record.Kinesis.Data == nil {
			fmt.Println("데이터가 Null")
			continue
		}

		var payload Payload
		if err := json.Unmarshal(record.Kinesis.Data, &payload); err != nil {
			fmt.Println("페이로드 디코딩 실패:", err.Error())
			continue
		}
		fmt.Println(payload)
	}

}

func main() {
	lambda.Start(pingTest)
}

 

'AWS' 카테고리의 다른 글

쉘 프로그래밍 자동화  (0) 2022.12.12
VPC 피어링  (0) 2022.11.03
aws ec2 ssh 접속 오류  (0) 2022.10.23
AWS Cognito 소셜로그인 인증 구현 (golang)  (2) 2022.06.17
S3 영상이 재생이 안되고 다운로드가 된다?  (0) 2022.04.27