반응형

상황

AWS의 lambda 안에서 git 명령을 사용하여(execSync를 이용) Run하면,

아래와 같이 '/bin/sh: git: command not found'가 발생한다.

 

2022-07-04T04:21:23.997Z a8ab8b4b-6f54-4775-90a9-1076ba630dc8 INFO proxy: undefined
/bin/sh: git: command not found

 

해결

람다 메인에서 계층에 'Add a layer'로 lambda layer를 추가해준다.

단, 해당 람다와 동일한 리즌에 있는 계층과 연결해야 하므로

아래 github 링크에서 언급한 arn의 리즌을 us-east-1 --> ap-northeast-2(서울)로 바꿔주고 저장한다.

 

 

 

출처

https://github.com/lambci/git-lambda-layer

 

GitHub - lambci/git-lambda-layer: A layer for AWS Lambda that allows your functions to use `git` and `ssh` binaries

A layer for AWS Lambda that allows your functions to use `git` and `ssh` binaries - GitHub - lambci/git-lambda-layer: A layer for AWS Lambda that allows your functions to use `git` and `ssh` binaries

github.com

 

반응형
반응형

CI/CD 구축을 위한 단계

  0. ECS fargate 생성 (Cluster, Service, task-definition, task)

1-1. Bitbucket에 코드 업로드 (git)

1-2. Bitbucket <-> slack 연동 (PR 알람 노티를 위함)

2-1. Bitbucket <-> AWS API Gateway 연동 with Webhook

2-2. API gateway -> Lambda 호출 

3. Lambda -> S3로 패키지 업로드

4. AWS Codepipeline: S3 -> Codebuild + ECR 연동

5. Codebuild -> Deploy(ECS fargate)

6. ECS <-> LB(ALB) 연동하여 동작 테스트 


이제 bitbucket으로부터 /POST가 올 때 lambda까지 호출하는 절차를 구현했으므로,

Lambda에서 S3로 코드를 올리는 함수를 구현해보자.

 

로컬에서 사용할 함수들을 간단히 정의한 후, npm init -y으로 package.json을 생성했고

index.js와 pkg.json, node_modules를 zip으로 묶어 lambda에 upload 했다.

const AWS = require('aws-sdk');
const s3 = new AWS.S3();
const crypto = require('crypto');
const axios = require('axios');

exports.handler = async (event) => {
    try {
        console.log(`Incoming event: ${JSON.stringify(event)}`);
        const eventBody = JSON.parse(event.body);

일단 사용할 함수들을 정의하고, event를 JSON.stringiy로 찍어본다.

로그를 보면 아래와 같은 event가 들어온다.

 

2022-05-26T22:51:32.181Z 399fc240-aa51-411b-8537-26dbe8d6d578 INFO
{
   "resource":"/",
   "path":"/",
   "httpMethod":"POST",
   "headers":{
      "Accept":"*/*",
      "Content-Type":"application/json; charset=UTF-8",
      "Host":"ㅁㄴㅇㄹㅁㄴxecute-api.ap-northeast-2.amazonaws.com",
      "User-Agent":"Atlassian HttpClient 1.1.0 / Bitbucket-5.10.0 (5010000) / Default",
      "Via":"1.1 localhost (Apache-HttpClient/4.5.5 (cache))",
      "X-Amzn-Trace-Id":"Root=1-62900473-046a3026764d32b66cc4f0c5",
      ”X-Event-Key":"pr:comment:edited",   
      "X-Forwarded-For":"ㅁㄴㅇㄹ.201",
      "X-Forwarded-Port":"443",
      "X-Forwarded-Proto":"https",
      "X-Request-Id":"ㅁㄴㅇㄹㅁ7ffac28c454d"
      "X-Hub-Signature": "sha256=ㅁㄴㅇㄹㅁㅁㄴㅇㄹbㅁㅇㄹa20b",
   },
   "multiValueHeaders":{
      "Accept":[
         "*/*"
      ],
      "Content-Type":[
         "application/json; charset=UTF-8"
      ],
      "Host":[
         "ㅁㄴㄹㅇs.com"
      ],
      "User-Agent":[
         "Atlassian HttpClient 1.1.0 / Bitbucket-5.10.0 (5010000) / Default"
      ],
      "Via":[
         "1.1 localhost (Apache-HttpClient/4.5.5 (cache))"
      ],
      "X-Amzn-Trace-Id":[
         "Root=ㅁㄴㅇㄹㄴㅇㄹㅁㄴㄹㅇ66cc4f0c5"
      ],
      "X-Event-Key":[
         "pr:comment:edited"
      ],
      "X-Forwarded-For":[
         "ㅁㄴㄹㅇㅇㅇ1"
      ],
      "X-Forwarded-Port":[
         "443"
      ],
      "X-Forwarded-Proto":[
         "https"
      ],
      "X-Request-Id":[
         "ㅁㄴㄹㅁ8c454d"
      ]
   },
   "queryStringParameters":null,
   "multiValueQueryStringParameters":null,
   "pathParameters":null,
   "stageVariables":null,
   "requestContext":{
      "resourceId":"ㅁㄹㅇㄹak",
      "resourcePath":"/",
      "httpMethod":"POST",
      "extendedRequestId":"SㅁㄴㄹㅇTA=",
      "requestTime":"26/May/2022:22:51:31 +0000",
      "path":"/prod/",
      "accountId":"ㅁㄴㅇㄹㅁㄴ",
      "protocol":"HTTP/1.1",
      "stage":"prod",
      "domainPrefix":"ㅁㄴㅇㅇㄹh",
      "requestTimeEpoch":ㅁㅇㄹ353,
      "requestId":"ㅁㄴㄹㅇㄹ15ㅁㅇㄹb672d3f5ee",
      "identity":{
         "cognitoIdentityPoolId":null,
         "accountId":null,
         "cognitoIdentityId":null,
         "caller":null,
         "sourceIp":"ㅁㄹㄴㅇㅁㅇㄴ",
         "principalOrgId":null,
         "accessKey":null,
         "cognitoAuthenticationType":null,
         "cognitoAuthenticationProvider":null,
         "userArn":null,
         "userAgent":"Atlassian HttpClient 1.1.0 / Bitbucket-ㅁㄴㄹㅇ(ㅁㄴㄹ) / Default",
         "user":null
      },
      "domainName":"ㅁㄹㄹㅇ2.amazonaws.com",
      "apiId":"ㅁㄹㄴㅇvㅁㄴㄹh"
   },
   "body":"{\"eventKey\":\"pr:comment:edited\",\"date\":\"2022-05-27T07:51:31+0900\",\"actor\":{\"name\":\"jane\",\"emailAddress\":\"

중략.

 

이를 가지고, 헤더를 정규화해주고 (key를 소문자화) 인증서도 체크하고, 코드도 다운받고, 이를 s3로도 올린다.

코드는 아래 링크에 잘 설명되어 있으므로, 자세한 건 이로 대체하고

https://devlog-wjdrbs96.tistory.com/331

        const repoConfig = {
            serverUrl: process.env.BITBUCKET_SERVER_URL, 
            projectName: eventBody.pullRequest.toRef.repository.project.key, 
            repoName: eventBody.pullRequest.toRef.repository.name, 
            branch: eventBody.pullRequest.toRef.displayId, 
            token: process.env.BITBUCKET_TOKEN, 
        };


        // Upload the repository package to S3 bucket
        const s3Upload = await s3.upload({
            Bucket: process.env.S3BUCKET,
            ServerSideEncryption: 'AES256',
            Key: `${repoConfig.projectName}/${repoConfig.repoName}/${repoConfig.branch}.zip`,
            Body: file
        }).promise();
        console.log(s3Upload);

        console.log('Exiting successfully');
        return responseToApiGw(200, 'success');

업로드 하는 부분만 다뤄보자면, key를 event에서 받아온 정보들로 담은 후(projectName, repoName 등)

s3에 zip형태로 올린다.

여기서 말하는 Body: file은, 코드를 다운로드할 때 axios.req로 코드를 bitbucket으로부터 다운받은 뒤,

그의 응답data(=file)를 가져온 부분이다. 

 

 

그러면, 코드에서 언급한 디렉토리가 생성되고 그 아래에 zip파일까지 업로드되는 것을 확인할 수 있다.

 

 

끝.

다음 포스팅은 본격적으로 codepipeline을 생성해보자.

4. AWS Codepipeline: S3 -> Codebuild + ECR 연동

5. Codebuild -> Deploy(ECS fargate)

6. ECS <-> LB(ALB) 연동하여 동작 테스트 

반응형
반응형

1. slack에서 app을 생성한다.

 1) slack에 접속하여 메뉴 중 앱 > 앱 디렉터리를 클릭하면 된다.

https://api.slack.com/apps?new_app=1

 

 

2) 그럼 아래 창이 나오는데, 오른쪽 상단의 '구축'을 누르면 된다.

 

 

3) Create an app을 클릭한다.

 

 

4) From scratch 후 이름 및 workspace 생성

 

5) 기능추가: Incoming Webhooks 클릭.

 

6) Activate Incoming Webhooks을 On 설정한 후, 아래에 있는 Webhook URI에 워크스페이스 추가를 클릭한다.

 

 

7) 이 app이 동작될 채널을 선택한다.

 

8) 그럼 이렇게 webhook URL이 생겼고, 이건 이따가 index.js에서 사용한다.

 

9) jane_bot2가 #clone-prision에 초대되었다.

 

 

2. 자 다음, AWS로 이동한다.

1) Amazon SNS > 주제 > 주제생성

설정에서는 표준선택 및 이름 외 별도 설정할 게 없고, lambda에서 설정한다.

 

 

2) blueprint로 sns를 검색해서 lambda를 생성한다.

 

3) 아까 생성한 sns를 여기서 선택해준다. (jane-test-sns2) 

그리고 함수 생성.

 

4) 함수를 생성하면 이와 같이 출력되는데, 코드는 로컬에서 작성 후 zip파일으로 압축 해 업로드 해준다. 

코드 수정 전

 

 

5) 로컬에서 생성한 코드를 zip으로 압축해 업로드 했다.

slack-node를 설치해야하기 때문에 node_modules까지 가져와야 한다.

webhookUri는 아까 1 -> 8)에 있었던 Webhook URI를 그대로 복붙해주면 된다.

 

6) Test를 클릭하면 아까 설정한 워크스페이스 > 채널로 jane_bot2가 동작한다 :)

반응형
반응형

1. Trigger를 S3로 설정한 lambda를 만든다.

   (S3는 미리 만들어놔야 함)

   

1) Lambda > 함수생성 > 블루프린트 사용(aws에서 제공하는 템플릿) > s3 검색 > nodejs의 경우 s3-get-object

 

 2) 구성 누른 후 나머지 설정은 기존 사용하던 값으로 설정,

     S3 트리거에서 버킷을 만들어놓은 버킷으로 설정 + 이벤트 유형: 모든 객체 생성 이벤트

     // 이렇게 하면, 모든 객체 생성 이벤트(생성삭제수정 등)가 일어날 때마다 lambda 함수가 호출된다.

 

3) 만들어진 람다

 

2. index.js 코드

const aws = require('aws-sdk');
const fs = require('fs');
var s3 = new aws.S3({ apiVersion: '2006-03-01' });

exports.handler = async(event, context,  callback) => {
    const bucket = event.Records[0].s3.bucket.name;
    const key = decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, ' '));
    const params = {
        Bucket: bucket,
        Key: key,
    };

// json 파일을 읽어와서 json 형태로 출력
    var theObject = await s3.getObject(params).promise();
    const data = JSON.parse(theObject.Body);
    console.log(data);
   // console.log(theObject.Body.toString('utf8'));  // 보기 예쁜 형태로
        

 

 // S3에서 이벤트가 발생할 때마다 로그에 찍어줄 값.

  try {
        const { ContentType } = await s3.getObject(params).promise();
        console.log('CONTENT TYPE:', ContentType);
        console.log('********** Event generated by S3 ************* ');
        return ContentType;
        
    } catch (err) {
        console.log(err);
        const message = `Error getting object ${key} from bucket ${bucket}. Make sure they exist and your bucket is in the same region as this function.`;
        console.log(message);
        throw new Error(message);
    }
};

 

3. 람다의 테스트에서 awsRegion, bucket-name, arn, key를 바꾸어주어야 정상 테스팅됨.

람다 테스트

      "awsRegion": “ap-northeast-2",

      "s3": {

        "s3SchemaVersion": "1.0",

        "configurationId": "testConfigRule",

        "bucket": {

          "name": "jane-bkt”,

          "ownerIdentity": {

            "principalId": "EXAMPLE"

          },

          "arn": "arn:aws:s3:::jane-bkt"

        },

        "object": {

          "key": "s3test.json",

          "size": 1024,

          "eTag": "0123456789abcdef0123456789abcdef",

          "sequencer": "0A1B2C3D4E5F678901"

        }

 

 

4. 테스팅 결과

1) json 파일이 예쁘게 나온다.

2) S3의 해당 버킷에 새로운 파일을 업로드할 경우, 람다가 실행되어 Cloudwatch에서 로그를 확인할 수도 있다.

 

반응형

+ Recent posts