https://galid1.tistory.com/746 Jenkins와 CodeDeploy를 이용한 CICD 구축하기 - 1 (아키텍처, 과정 소개)
https://galid1.tistory.com/747 CodeDeploy를 이용한 CICD 구축하기 - 2 (구축)
지난 포스팅에 이어 이번 시간에는 CodeDeploy
의 배포상태에 따라서, Slack의 개발팀에 메시지를 전송하는 과정을 진행하려고 합니다.
목차
목차1. 메시지 전달과정2. SNS 주제 생성3. Code Deploy에서 SNS주제에 트리거하도록 설정4. 메시지를 전달받을 Slack Workspace & App 생성4.1 Workspace 생성4.2 Slack App 생성5. Lambda 생성5.1 함수생성5.2 SNS 주제 구독5.3 Slack에 메시지를 전송하는 Python 스크립트 생성6. 테스트lambda 동작 확인Slack 채널 확인
1. 메시지 전달과정
- SNS에서 주제를 생성합니다.
CodeDeploy
에서 배포상태에(배포 생성,성공,실패,취소) 따라서,1
에서 생성한SNS
의 주제에 트리거를 합니다.1
에서 생성한 주제를 구독하고 있던 lambda가 트리거되고, Slack에 메시지를 전송합니다.
2. SNS 주제 생성
Lambda를 트리거 하기위해, 주제를 생성합니다.
AWS SNS -> 주제 -> 주제 생성을 클릭합니다
적절한 이름을 부여하고, 나머지 선택사항은 건너띕니다.
3. Code Deploy에서 SNS주제에 트리거하도록 설정
지난 포스팅에서 생성한 Code Deploy에서 배포시, 2.
에서 생성한 SNS주제에 트리거하도록 변경해야 합니다.
AWS CodeDeploy -> 애플리케이션 -> 애플리케이션 -> 배포그룹탭을 클릭한뒤, 지난 포스팅에서 생성한 배포그룹을 선택합니다.
우측 상단의 편집을 클릭합니다.
하단으로 스크롤하여, 고급
탭을 확장한 뒤, 트리거 생성을 클릭합니다.
적절한 이름을 부여하고, 이벤트에서는 배포시작, 성공, 실패, 중지
를 선택합니다.
SNS주제에서는 앞서 생성한 cicd-deploy-complete를 선택합니다.
4. 메시지를 전달받을 Slack Workspace & App 생성
Lambda를 생성하기전, 메시지를 전달받을 Slack workpacke & App을 생성합니다.
4.1 Workspace 생성
slack.com
으로 접속하여 + Create a Slack Workspace
를 클릭합니다.
workspace의 계정을 생성합니다.
자신이 입력한 이메일로 이동하면 위와 같이 확인 코드를 확인할 수 있습니다. 확인 코드를 입력합니다.
Slack Workspace가 생성되었습니다.
4.2 Slack App 생성
https://api.slack.com/messaging/webhooks 로 이동합니다. app이 없으실테니 Create yout Slack app을 클릭합니다.
App이름을 정하고, Slack Workspace에는 3.1
에서 생성한 workspace를 지정합니다.
Incoming Webhooks
탭을 클릭한뒤, On
으로 만든뒤, 하단의 Add New Webhook to Workspace
를 클릭합니다.
post를 요청할 workspace의 channel을 선택합니다.
생성된 Webhook URL을 복사합니다.
5. Lambda 생성
5.1 함수생성
이제 2.
에서 생성한 SNS주제를 구독하고, Slack에 메시지를 전송할 Lambda 함수를 생성합니다.
AWS Lambda -> 함수를 선택합니다.
새로 작성을 체크하고, 런타임에는 Python 3.6
을 선택합니다.
5.2 SNS 주제 구독
트리거 추가를 클릭합니다.
SNS
를 선택하고, cicd-deploy-complete
주제를 선택합니다.
5.3 Slack에 메시지를 전송하는 Python 스크립트 생성
https://github.com/beibeiyang/sns-to-slack
위의 링크를 참고하시면, slack에 메시지를 전송하는 python script를 찾을 수 있습니다.
하지만, aws에서 업데이트를 했는지, 몇가지 설정이 달라져서 직접 스크립트를 작성했습니다.
lambda.cfg
[SLACK]
hostname = hooks.slack.com
port = 443
endpoint = /services/T015X24D68M/B015RMB20K0/ZrRmWJos8NKOL5ZjsoSHRaAK
channel = project
username = galid
icon_emoji = :email:
endpoint를 앞서 복사한 WebHookUrl의 /services~ 이하로 변경합니다. channel은 project로 변경합니다.
*위 파일의 이름은 꼭 lambda.cfg
어야 합니다.
lambda_function.py
ximport configparser
import logging
import os
import sys
from urllib.request import urlopen, Request
from urllib.error import URLError, HTTPError
import json
class LambdaConfig:
def __init__(self, configfile, logger):
try:
logger.info("{}{}{}".format("#" * 10, "READ LAMBDA CONFIG", "#" * 10))
logger.info("Reading config from file: {}".format(configfile))
cp = configparser.ConfigParser()
cp.read(configfile)
# read Slack config
self.slack_host = cp.get("SLACK", "hostname")
self.slack_port = cp.get("SLACK", "port")
self.slack_endpoint = cp.get("SLACK", "endpoint")
self.slack_channel = cp.get("SLACK", "channel")
self.slack_username = cp.get("SLACK", "username")
self.slack_icon_emoji = cp.get("SLACK", "icon_emoji")
# log Slack config
logger.info("Slack host: {}".format(self.slack_host))
logger.info("Slack port: {}".format(self.slack_port))
logger.info("Slack endpoint: {}".format(self.slack_endpoint))
logger.info("Slack channel: {}".format(self.slack_channel))
logger.info("Slack username: {}".format(self.slack_username))
logger.info("Slack icon emoji: {}".format(self.slack_icon_emoji))
logger.info("#" * 30)
except Exception as e:
logger.exception("Error parsing the user-provided config file. Script will terminate. {}".format(repr(e)))
sys.exit(-1)
def lambda_handler(event, context):
# Set logging level
log_level = os.environ.get('LOG_LEVEL', 'DEBUG').upper()
logger = logging.getLogger()
logger.setLevel(log_level)
config = LambdaConfig(configfile="lambda.cfg", logger=logger)
logger.debug("Received event: {}".format(event))
logger.info("{} SNS to Slack process starts {}".format("*" * 10, "*" * 10))
try:
message = event["Records"][0]["Sns"]["Message"]
logger.info("From SNS: {}".format(message))
except TypeError as e:
logger.exception("Unable to retrieve message from event", repr(e))
return
post_data = {
"channel": config.slack_channel,
"username": config.slack_username,
"text": "*{}*".format(event["Records"][0]["Sns"]["Subject"]),
"icon_emoji": config.slack_icon_emoji
}
# SNS 메시지에 담긴 배포상태에 따라 slack에 표시될 메시지의 색상을 정함
json_message = json.loads(message)
deploy_status = json_message['status']
if deploy_status == "CREATED":
severity = "good"
elif deploy_status == "SUCCEEDED":
severity = "good"
elif deploy_status == "ABORTED":
severity = "warning"
else:
severity = "danger"
post_data["attachments"] = [
{
"color": severity,
"text": message
}
]
hook_url = "https://{}:{}{}".format(config.slack_host, config.slack_port,
config.slack_endpoint)
logger.info("Slack Hook URL: {}".format(hook_url))
logger.info("post_data: {}".format(post_data))
try:
data = json.dumps(post_data).encode("utf-8")
req = Request(hook_url, data=data, method="POST")
req.add_header(
"Content-Type",
"application/x-www-form-urlencoded"
)
logger.debug("data: {}".format(data))
response = urlopen(req)
logger.info("Message posted to channel {}".format(config.slack_channel))
logger.info("Response: {}".format(response.read()))
except HTTPError as e:
logger.exception("Request failed: {] {}".format(e.code, e.reason))
except URLError as e:
logger.exception("Server connection failed: {]".format(e.reason))
except Exception as e:
logger.exception("Unknown exception: {}".format(repr(e)))
init
은 위의 lambda.cfg
파일을 로드하여, url, host, channel등을 설정합니다.
lambda가 트리거되어 실질적으로 slack에 메시지를 전송하는 메소드는 lambda_handler
입니다.
앞서 3.
에서 SNS에 트리거할 이벤트로 배포 시작, 성공, 중지, 실패
를 선택했는데요, 이 이벤트들은 lambda_handler 메소드의 매개변수인 event에 담겨있습니다.
이 각 배포의 상태값은 event["Records"][0]["Sns"]["Message"]
로 가져온 데이터를 json으로 변경하여, json_message['status']로 가져올수 있습니다.
확인한 결과 아래와 같습니다.
배포 시작 - CREATED
배포 성공 - SUCCEEDED
배포 중지 - ABORTED
배포 실패 - FAILED
6. 테스트
code를 GitHub Repository에 push하여, Jenkins 서버를 동작시킵니다. 우선 appspec.yml을 조작하여 고의적으로 배포가 실패되도록 합니다.
lambda 동작 확인
lambda에 모니터링 탭에서 CloudWatch에서 로그보기
를 클릭합니다.
LogStream이 생성되었다면 lambda가 동작된 것입니다. 클릭하면, python 스크립트에서 작성한 log들을 자세히 확인하실 수 있습니다.
Slack 채널 확인
project채널에 메시지가 전달되었음을 볼 수 있습니다.
'Software Engineering > CICD (jenkins, etc)' 카테고리의 다른 글
CICD - Jenkins와 CodeDeploy를 이용한 CICD 구축하기 - 2 (구축) (2) | 2020.06.23 |
---|---|
CICD - Jenkins와 CodeDeploy를 이용한 CICD 구축하기 - 1 (아키텍처, 과정 소개) (0) | 2020.06.23 |
CICD - Codedeploy란? (Codedeploy를 이용한 자동배포(CD) 환경 구축하기) (1) | 2020.06.22 |
CICD - 로컬 PC에 CICD환경 구축하기 (Jenkins, Ngrok, docker) (3) | 2020.06.17 |
Jenkins - AmazonLinux2 에서 Jenkins 구축 및 gitlab 연동 (push 시 자동 빌드) (0) | 2019.07.12 |