Chào các bạn hôm nay mình xin giới thiệu bài về sử dụng Cloudwatch Events để thông báo về Slack khi AWS ECS task gặp sự cố
CloudWatch Events là gì ?
Khi sử dụng CloudWatch Events, bạn sẽ định nghĩa một event pattern cho một AWS resources. Theo đó khi mà resources đó có hành động giống như trong pattern mình đã định nghĩa thì trigger sẽ được kích hoạt.
Hôm nay mình sẽ giới thiệu sử dụng Lambda để gửi tin nhắn đến Slack thông báo khi mà ECS task bị Stopped vì một lý do nào đó (Có thể healthcheck Load Balancer failed, do user cố ý stop ECS task, …)Cấu trúc tổng quát
handler.js
1234567891011121314151617181920212223242526<span class="token keyword">const</span> axios <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'axios'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// Search GG để lấy webhook url</span><span class="token keyword">const</span> <span class="token constant">SLACK_WEBHOOK</span> <span class="token operator">=</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">SLACK_WEBHOOK</span><span class="token punctuation">;</span><span class="token keyword">const</span> <span class="token constant">AWS_REGION</span> <span class="token operator">=</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">AWS_REGION</span><span class="token punctuation">;</span>module<span class="token punctuation">.</span>exports<span class="token punctuation">.</span><span class="token function-variable function">notification</span> <span class="token operator">=</span> <span class="token parameter">event</span> <span class="token operator">=></span> <span class="token punctuation">{</span><span class="token keyword">if</span><span class="token punctuation">(</span>event<span class="token punctuation">[</span><span class="token string">'source'</span><span class="token punctuation">]</span> <span class="token operator">&&</span> event<span class="token punctuation">[</span><span class="token string">'source'</span><span class="token punctuation">]</span> <span class="token operator">===</span> <span class="token string">'aws.ecs'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token keyword">const</span> detail <span class="token operator">=</span> event<span class="token punctuation">[</span><span class="token string">'detail'</span><span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token keyword">const</span> header <span class="token operator">=</span> <span class="token string">'ECS task bị stop rồi đại ca ơi!!!'</span><span class="token punctuation">;</span><span class="token keyword">let</span> clusterName <span class="token operator">=</span> detail<span class="token punctuation">[</span><span class="token string">'clusterArn'</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">'/'</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token keyword">let</span> taskId <span class="token operator">=</span> detail<span class="token punctuation">[</span><span class="token string">'taskArn'</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">'/'</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token keyword">let</span> taskDefinition <span class="token operator">=</span> detail<span class="token punctuation">[</span><span class="token string">'taskDefinitionArn'</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">'/'</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token keyword">let</span> detailJson <span class="token operator">=</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span>detail<span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">let</span> url <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">https://</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token constant">AWS_REGION</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">.console.aws.amazon.com/ecs/home?region=</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token constant">AWS_REGION</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">#/clusters/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>clusterName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">/tasks/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>taskId<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">/details</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span><span class="token keyword">let</span> attachments <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token string">'text'</span><span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>header<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> n Cluster: *</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>clusterName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">* n Task Definition: *</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>taskDefinition<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">* n </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>url<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">n </span><span class="token template-punctuation string">`</span></span> <span class="token operator">+</span> <span class="token string">"```"</span> <span class="token operator">+</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>detailJson<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span> <span class="token operator">+</span> <span class="token string">"```"</span><span class="token punctuation">,</span><span class="token string">'color'</span><span class="token operator">:</span> <span class="token string">'danger'</span><span class="token punctuation">}</span><span class="token punctuation">;</span>axios<span class="token punctuation">.</span><span class="token function">post</span><span class="token punctuation">(</span><span class="token constant">SLACK_WEBHOOK</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>attachments<span class="token operator">:</span> <span class="token punctuation">[</span>attachments<span class="token punctuation">]</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token punctuation">;</span>serverless.yml
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859<span class="token key atrule">service</span><span class="token punctuation">:</span> notification<span class="token punctuation">-</span>ecs<span class="token key atrule">provider</span><span class="token punctuation">:</span><span class="token key atrule">name</span><span class="token punctuation">:</span> aws<span class="token key atrule">stackName</span><span class="token punctuation">:</span> ecs<span class="token punctuation">-</span>$<span class="token punctuation">{</span>self<span class="token punctuation">:</span>provider.stageName<span class="token punctuation">}</span><span class="token punctuation">-</span>notification<span class="token punctuation">-</span>lambda<span class="token key atrule">runtime</span><span class="token punctuation">:</span> nodejs12.x<span class="token key atrule">region</span><span class="token punctuation">:</span> ap<span class="token punctuation">-</span>northeast<span class="token punctuation">-</span><span class="token number">1</span><span class="token key atrule">stageName</span><span class="token punctuation">:</span> $<span class="token punctuation">{</span>opt<span class="token punctuation">:</span>stageName<span class="token punctuation">,</span>self<span class="token punctuation">:</span>custom.stageName<span class="token punctuation">}</span><span class="token key atrule">timeout</span><span class="token punctuation">:</span> <span class="token number">30</span><span class="token key atrule">memorySize</span><span class="token punctuation">:</span> <span class="token number">128</span><span class="token key atrule">custom</span><span class="token punctuation">:</span><span class="token key atrule">stageName</span><span class="token punctuation">:</span> dev<span class="token key atrule">accounts</span><span class="token punctuation">:</span> XXXXXXXXX<span class="token key atrule">resources</span><span class="token punctuation">:</span><span class="token key atrule">Resources</span><span class="token punctuation">:</span><span class="token key atrule">IamRoleLambdaExecution</span><span class="token punctuation">:</span><span class="token key atrule">Type</span><span class="token punctuation">:</span> AWS<span class="token punctuation">:</span><span class="token punctuation">:</span>IAM<span class="token punctuation">:</span><span class="token punctuation">:</span>Role<span class="token key atrule">Properties</span><span class="token punctuation">:</span><span class="token key atrule">RoleName</span><span class="token punctuation">:</span> EcsNotificationRole<span class="token key atrule">AssumeRolePolicyDocument</span><span class="token punctuation">:</span><span class="token key atrule">Version</span><span class="token punctuation">:</span> <span class="token string">'2012-10-17'</span><span class="token key atrule">Statement</span><span class="token punctuation">:</span><span class="token punctuation">-</span> <span class="token key atrule">Effect</span><span class="token punctuation">:</span> Allow<span class="token key atrule">Principal</span><span class="token punctuation">:</span><span class="token key atrule">Service</span><span class="token punctuation">:</span><span class="token punctuation">-</span> lambda.amazonaws.com<span class="token key atrule">Action</span><span class="token punctuation">:</span> sts<span class="token punctuation">:</span>AssumeRole<span class="token key atrule">Policies</span><span class="token punctuation">:</span><span class="token punctuation">-</span> <span class="token key atrule">PolicyName</span><span class="token punctuation">:</span> myPolicyName<span class="token key atrule">PolicyDocument</span><span class="token punctuation">:</span><span class="token key atrule">Version</span><span class="token punctuation">:</span> <span class="token string">'2012-10-17'</span><span class="token key atrule">Statement</span><span class="token punctuation">:</span><span class="token punctuation">-</span> <span class="token key atrule">Effect</span><span class="token punctuation">:</span> <span class="token string">"Allow"</span><span class="token key atrule">Action</span><span class="token punctuation">:</span><span class="token punctuation">-</span> <span class="token string">"s3:*"</span><span class="token punctuation">-</span> <span class="token string">"logs:CreateLogGroup"</span><span class="token punctuation">-</span> <span class="token string">"logs:CreateLogStream"</span><span class="token punctuation">-</span> <span class="token string">"logs:PutLogEvents"</span><span class="token key atrule">Resource</span><span class="token punctuation">:</span> <span class="token string">"*"</span><span class="token key atrule">functions</span><span class="token punctuation">:</span><span class="token key atrule">notificationECS</span><span class="token punctuation">:</span><span class="token key atrule">handler</span><span class="token punctuation">:</span> handler.notification<span class="token key atrule">environment</span><span class="token punctuation">:</span><span class="token key atrule">SLACK_WEBHOOK</span><span class="token punctuation">:</span> <span class="token string">'https://hooks.slack.com/services/XXXXXXXX/YYYYYYYYY/VVVVVVVVVVVVVVVVVVVVVVVV'</span><span class="token key atrule">events</span><span class="token punctuation">:</span><span class="token punctuation">-</span> <span class="token key atrule">eventBridge</span><span class="token punctuation">:</span><span class="token key atrule">pattern</span><span class="token punctuation">:</span><span class="token key atrule">source</span><span class="token punctuation">:</span><span class="token punctuation">-</span> <span class="token string">"aws.ecs"</span><span class="token key atrule">detail-type</span><span class="token punctuation">:</span><span class="token punctuation">-</span> <span class="token string">"ECS Task State Change"</span><span class="token key atrule">detail</span><span class="token punctuation">:</span><span class="token key atrule">clusterArn</span><span class="token punctuation">:</span><span class="token punctuation">-</span> <span class="token tag">!Sub</span> <span class="token string">"arn:aws:ecs:${self:provider.region}:${self:custom.accounts.${self:provider.stageName}}:cluster/ecs-${self:provider.stageName}-cluster"</span><span class="token key atrule">lastStatus</span><span class="token punctuation">:</span><span class="token punctuation">-</span> <span class="token string">"STOPPED"</span>Deploy
12$ sls deploy --profile xxxxxx --region aa-bbbbbb-ZTest
Thử stop ECS task để xem tin nhắn đã về chưa !!
Cảm ơn các bạn đã đọc tới đây. Nếu có gì thắc mắc hãy comment dưới bài mình sẽ trả lời trong tầm hiểu biết của mình.
Hẹn gặp lại các bạn ở bài tiếp theo!!!