현재 CI/CD는 AWS의 codePipline을 구축해서 자동으로 배포가 있습니다. 이전의 Filezila를 통해 수동하던 거에 비해서 훨씬 편하게 배포가 되고 있지만 하나의 불편한점이 있었습니다!!
그것은 바로,
배포 성공 여부를 aws 사이트에 직접 접속해 과정을 확인해야 한다는 것이었습니다.
메신저로 사용하는 slack을 활용해서 아래의 효과를 이루고 싶었습니다.
CodePipeline(CodeCommit & CodeBuild) 시작/종료(성공/실패) 시 Amazon CloudWatch Events에서 해당 이벤트를 감지한 후 AWS Lambda로 트리거 신호를 보내면 AWS Lambda에서 Slack채널로 알람을 보내는 프로세스로 구성했습니다.
AWS 서비스와 사용자 지정 애플리케이션 간의 시스템 이벤트를 추적하고 응답할 수 있는 기능을 제공하는 서비스입니다. 이를 통해 다양한 AWS 리소스에서 발생하는 이벤트에 대한 실시간 모니터링과 대응이 가능해집니다. 다음은 AWS CloudWatch Events의 주요 기능과 개념입니다.
주요 기능
사용 예시
밑줄 친 기능과 예시를 활용하였습니다. codepipile의 이벤트를 트리거로 설정하고 특정 이름에 해당하는 경우 알림을 보내는 AWS Lambda를 실행하게 할 것입니다.
AWS에서 제공하는 서버리스 컴퓨팅 서비스로, 서버를 관리하지 않고도 코드를 실행할 수 있게 해줍니다. 사용자는 특정 이벤트에 반응하여 자동으로 실행되는 함수를 작성할 수 있습니다. Lambda는 다음과 같은 특징을 가지고 있습니다.
Lambda는 사용한 만큼 비용이 지불되고 Node.js, Python, C#, Ruby, Go등 다양한 프로그래밍 언어를 지원합니다.
Slack Incoming Webhook 2가지 방법 블로그를 참고하여 만들었습니다.
충분히 자세한 설명으로 따라만가면 되지만 하나 막혔던 부분만 추가하자면
4) Incoming Webhooks 선택 > On > Add New Webhook to Workspace > 채널 선택 > 허용
의 채널을 선택하는 과정이었습니다.
저는 기존의 채널을 사용하는 것이 아니라 CI/CD 전용 채널을 따로 개설하고 싶었기때문에 채널의 추가로 생성해주었습니다.
#
모양의 채널 버튼을 클릭합니다.
원하는 이름을 작성하면 됩니다. 참~~ 쉽죠? 😘
[AWS Management Console] -> [Lambda] -> [함수] -> [함수생성] 으로 가서 함수를 생성합니다.
새로 작성 을 선택하고 함수 이름을 작성합니다. 런타임에는 자신이 사용할 언어를 선택합니다.
(프런트엔드 개발자로 Node.js를 선택했습니다.)
간단하게 Lambda 함수를 생성할 수 있습니다.
Slack Webhook을 호출하는 소스 코드를 작성해봅시다.
cloudWatch에서 보내는 이벤트는 상태 변경 메시지를 참고해서 작성하시면 됩니다.
파이프라인 실행이 시작되면 다음 내용이 포함된 알림을 보내는 이벤트를 내보냅니다. 이는 us-east-1 리전의 "myPipeline"이라는 파이프라인에 대한 예제입니다.
{
"version": "0",
"id": "01234567-EXAMPLE",
"detail-type": "CodePipeline Pipeline Execution State Change",
"source": "aws.codepipeline",
"account": "123456789012",
"time": "2020-01-24T22:03:07Z",
"region": "us-east-1",
"resources": [
"arn:aws:codepipeline:us-east-1:123456789012:myPipeline"
],
"detail": {
"pipeline": "myPipeline",
"execution-id": "12345678-1234-5678-abcd-12345678abcd",
"start-time": "2023-10-26T13:49:39.208Z",
"execution-trigger": {
"trigger-type": "StartPipelineExecution",
"trigger-detail": "arn:aws:sts::123456789012:assumed-role/Admin/my-user"
},
"state": "STARTED",
"version": 1.0,
"pipeline-execution-attempt": 1.0
}
}
이벤트 메시지를 참고해서 작성한 코드 예시입니다.
블로그에서 가져온 예시입니다. 여기에 의도에 맞게 추가로 코드를 수정했습니다.
var services = process.env.SERVICES; // Slack webhook url의 /services/ 다음 문자열
var channel = process.env.CHANNEL; // 알람을 전송할 Slack channel
var https = require('https');
var util = require('util');
// 타임존을 UTC -> KST로 변경
function toYyyymmddhhmmss(date) {
if(!date){
return '';
}
function utcToKst(utcDate) {
return new Date(utcDate.getTime() + 32400000);
}
function pad2(n) { return n < 10 ? '0' + n : n }
var kstDate = utcToKst(date);
return kstDate.getFullYear().toString()
+ '-'+ pad2(kstDate.getMonth() + 1)
+ '-'+ pad2(kstDate.getDate())
+ ' '+ pad2(kstDate.getHours())
+ ':'+ pad2(kstDate.getMinutes())
+ ':'+ pad2(kstDate.getSeconds());
}
// Slack 메시지 필드 정의
var formatFields = function(event) {
var fields = [];
// Make sure we have a valid response
if (event) {
fields = [
{
"title" : "type",
"value" : event['detail-type'],
"short" : true
},
{
"title" : "time",
"value" : toYyyymmddhhmmss(new Date(event.time)),
"short" : true
},
{
"title" : "region",
"value" : event.region,
"short" : true
},
{
"title" : "link",
"value" : "https://"+event.region+".console.aws.amazon.com/codesuite/codepipeline/pipelines/"+event.detail.pipeline+"/executions/"+event.detail['execution-id']+"/timeline?region="+event.region,
"short" : true
},
{
"title" : "pipeline",
"value" : event.detail.pipeline,
"short" : true
},
{
"title" : "execution_id",
"value" : event.detail['execution-id'],
"short" : true
},
{
"title" : "state",
"value" : event.detail.state,
"short" : true
}
];
}
return fields;
};
// Slack 으로 알람 보내는 부분
exports.handler = function(event, context) {
var postData = {
"channel": channel, // Slack 알람 받는 채널
"text": "*" + event.detail.pipeline + " Notify" + "*" // Slack 알람 제목
};
var fields = formatFields(event);
// Slack color와 메시지 필드
postData.attachments = [
{
"color": event.detail.state == "SUCCESS" ? "good" : (event.detail.state == "STARTED" ? "good" : "danger"),
"fields": fields
}
];
var options = {
method: 'POST',
hostname: 'hooks.slack.com',
port: 443,
path: services // Slack webhook url의 /services/ 다음 문자열. 위에서 정의됨
};
var req = https.request(options, function(res) {
res.setEncoding('utf8');
res.on('data', function (chunk) {
context.done(null);
});
});
req.on('error', function(e) {
console.log('problem with request: ' + e.message);
});
req.write(util.format("%j", postData));
req.end();
};
process.env
는 Lambd 탭중에 [구성] -> [환경변수] 에서 설정할 수 있습니다.
이제 Lambda 함수를 실행할 트리거를 만들어야 합니다.
[CloudWatch] -> [이벤트] -> [규칙] -> [규칙생성 버튼]을 통해 만들 수 있습니다.
1. 2단계 이벤트 패턴 작성 : 이벤트 패턴 작성을 통해 트리거가 발생살 이벤트를 작성해 줍니다. CodePipeline 의 실행 상태가 바뀔때 마다 트리거가 작동되어야 하기 때문에 source와 detail-type을 목적에 맞게 작성해줍니다.
추가로 저는 pipeline의 접두사로 "dmp-"
혹은 "mi-f-"
가 있을 때만 트리거가 실행되기를 원했때문에 추가 조건을 설정해주었습니다.
관련 문법은 공식 홈페이지에서 확인할 수 있습니다.
2. 이번트 대상 선택에서 아까 저희가 만들었던 Lambda를 선택해줍니다.
[테스트] 탭을 통해 원하는 이벤트를 작성하고 테스트를 해 볼 수 있습니다.
Lambda의 테스트는 이벤트가 발생이 된 후 실행되기 때문에 여기서의 테스트는 이미 트리거가 발생된 후 입니다. 테스트의 용도로는 슬랙으로 메시지가 잘 간다면 잘 완성 된 것입니다! ㅎㅎ
지금까지 CodePipeline의 상태가 변경될 때마다 Slack으로 메시지 보내기를 만들어보았습니다. 확실히 기존의 프로세스보다 메시지로 간편하게 상태를 확인할 수 있고 실패를 하더라고 링크를 통해 빠르게 문제점을 볼수 있게 되었습니다.
또한 팀원과 함께 상태를 공유하면서 문제가 생기면 모두가 빠르게 상태를 알 수 있어 협업에도 좋다고 느껴졌습니다!
저와 같은 고민을 하고 해결방법을 찾는 분들에게 부디 도움이 되었기를 바랍니다!!! 😎
https://twofootdog.tistory.com/49
https://velog.io/@king/slack-incoming-webhook