티스토리 뷰

 

지난 블로깅을 통해 Amazon Linux 1 환경의 Elastic Beanstalk 어플리케이션을 새로운 Amazon Linux2 환경으로 마이그레이션 하는 과정을 소개하였다. 이번 포스팅에서는 Elastic Beanstalk 웹 콘솔과 Amazon Cloudwatch 를 통해서 내가 원하는 로그를 볼 수 있는 기능을 소개하려고 한다.

우리의 API 서버인 sachiel 은 모니터링을 위해 API 호출과 exception 로그를 분리해서 저장하고 있었다. 각각 /var/log/sachiel/info\_api\_call.log/var/log/sachiel/exception.log경로로 저장하고 있었는데, 아무런 설정을 하지 않는다면 Amazon Cloudwatch 와 Elastic Beanstalk 웹 콘솔을 통해 확인할 수 없다. 이 서비스들로 로그를 열람하기 위해 했던 세팅을 소개한다.

 

 

🏗 삽질을 위한 준비물 — EC2 Session Manager

물론 VPN과 pem 키를 통해 인스턴스에 접근할 수 있겠지만, 실험하기 은근 귀찮다. elastic beanstalk 의 인스턴스를 웹콘솔의 Session Manager를 통해 접속한다면 더 효율적인 실험이 가능하다. aws elastic beanstalk 로 만드는 ec2 의 iam role 에 아래의 policy를 추가하도록 하자.

aws iam attach-role-policy --role-name <EC2-ROLE-NAME> --policy-arn arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore

 

CLI 기준으로 적어뒀지만, 어떤 방식으로 하던 상관없다. 적용되었다면 아래와 같은 화면을 확인할 수 있다.

💭 삽질 #1 — Amazon Linux 2 환경에서는 기본으로 awslogs 가 없네 - amazon-cloudwatch-agent

Amazon Linux 1 환경에서는 awslogs 라는 데몬이 default 로 사용되었지만, Amazon Linux 2 에서는 아니었다. 배포 과정 로그를 살펴보니 amazon-cloudwatch-agent 라는 어플리케이션이 로그를 스트리밍하고 있음을 파악할 수 있었다. 덕분에(??) 기존에 사용하던 .ebextensions 안의 /etc/awslogs/config/ 관련 files 옵션이 무의미해졌다.

2021/05/21 06:40:42.583724 [INFO] Executing instruction: configure log streaming
2021/05/21 06:40:42.583734 [INFO] start to get cloudwatch log client
2021/05/21 06:40:42.583834 [INFO] start to config log streaming
2021/05/21 06:40:42.583840 [INFO] start to configure log streaming config file
2021/05/21 06:40:42.584026 [INFO] start to create cloudwatch log stream
2021/05/21 06:40:42.584030 [INFO] start to create log streaming
2021/05/21 06:40:42.742418 [INFO] start to fetch config
2021/05/21 06:40:42.742449 [INFO] Running command /bin/sh -c /opt/aws/amazon-cloudwatch-agent/bin/amazon--ctl -a fetch-config -c file:/opt/aws/amazon-cloudwatch-agent/etc/beanstalk.json -s
2021/05/21 06:40:43.421586 [INFO] ****** processing amazon-cloudwatch-agent ******
/opt/aws/amazon-cloudwatch-agent/bin/config-downloader --output-dir /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.d --download-source file:/opt/aws/amazon-cloudwatch-agent/etc/beanstalk.json --mode ec2 --config /opt/aws/amazon-cloudwatch-agent/etc/common-config.toml --multi-config default
Successfully fetched the config and saved in /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.d/file_beanstalk.json.tmp
Start configuration validation...
/opt/aws/amazon-cloudwatch-agent/bin/config-translator --input /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json --input-dir /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.d --output /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.toml --mode ec2 --config /opt/aws/amazon-cloudwatch-agent/etc/common-config.toml --multi-config default
Valid Json input schema.
I! Detecting run_as_user...
No csm configuration found.
No metric configuration found.
Configuration validation first phase succeeded
/opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent -schematest -config /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.toml
Configuration validation second phase succeeded
Configuration validation succeeded
amazon-cloudwatch-agent has already been stopped

/opt/aws/amazon-cloudwatch-agent/etc/file_beanstalk.json 을 직접 수정해보기로 했다. 이 작업을 위해 나는 새로운 기능인 .platform/hooks/postdeploy 훅을 시도해봤다. 전 포스팅에서 짧게 소개했지만, 배포 이후의 시점에서 커스터마이징할 수 있는 hook이다. 아래의 구조로 구성했다. (chmod 는 필수다.)

.platform/
└── hooks
    └── postdeploy
        ├── 01_edit_amazon_cloudwatch_agent_conf.py (chmod +x)
        └── 02_restart_amazon_cloudwatch_agent.sh   (chmod +x)

01_edit_amazon_cloudwatch_agent_conf.py 는 아래와 같이 작성했다. 데몬의 config파일을 직접 수정하는 스크립트다.

 

#!/usr/bin/env python3
import json
file_path = '/opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.d/file_beanstalk.json'
with open(file_path, 'r') as f:
    jj = json.load(f)
    collect_list = jj['logs']['logs_collected']['files']['collect_list']
    one_entity = collect_list[0]
    one_entity_log_group_name = one_entity['log_group_name']
    path = '/'.join(one_entity_log_group_name.split('/')[:-1])
    new_collect_list = [
        {
            'file_path': '/var/log/sachiel/info.log',
            'log_group_name': path + '/sachiel/info.log',
            'log_stream_name': '{instance_id}'
        },
        {
            'file_path': '/var/log/sachiel/info_api_call.log',
            'log_group_name': path + '/sachiel/info_api_call.log',
            'log_stream_name': '{instance_id}'
        },
        {
            'file_path': '/var/log/sachiel/info_payment.log',
            'log_group_name': path + '/sachiel/info_payment.log',
            'log_stream_name': '{instance_id}'
        },
        {
            'file_path': '/var/log/sachiel/exception.log',
            'log_group_name': path + '/sachiel/exception.log',
            'log_stream_name': '{instance_id}'
        },
    ]
    collect_list += new_collect_list
    new_cloudwatch_logs = {
        'logs': {
            'logs_collected': {
                'files': {
                    'collect_list': collect_list
                }
            }
        }
    }
with open(file_path, 'w') as f:
    json.dump(new_cloudwatch_logs, f)

02_restart_amazon_cloudwatch_agent.sh 는 아래와 같이 작성했다. 데몬의 config 파일을 수정했으니, 데몬을 리스타트하는 것 뿐이다.

#!/bin/bash
service amazon-cloudwatch-agent restart

그래서 원하는 목적을 달성했다. Cloudwatch 의 로그 그룹에서 드디어 내가 원하는 로그를 확인할 수 있었다.

하지만 지금은 사용하지 않는다. 배포 시간도 좀 더 잡아먹었고, 내가 작성한 python 스크립트가 Elastic Beanstalk 판올림 같은 피치 못할 이유로 언제 터질지 모르는 불안정한방법이라고 생각했기 때문이다. (그럼에도 불구하고 AWS 포럼에서 이런 비슷한 식으로 사용하는 사람들이 있었다.)

 

💭 삽질 #2 — awslogs 를 쓸 수 있다고?

yum 을 통해 기존에 쓰던 awslogs 를 설치하고 사용할 수 있음을 인스턴스 안에서 확인했다. Amazon Linux 1 인스턴스에서 얻은 정보와 로그를 통해 많은 정보를 알아냈고, 새로운 Amazon Linux 2 인스턴스에서 아래의 과정을 거쳤다.

yum install awslogs -y
systemctl enable awslogsd.service
systemctl restart awslogsd

원하는 대로 작동하는 것을 확인하고나서 .ebextensions 를 수정하였다. 아래와 같은 항목들을 추가했다.

packages:
  yum:
    awslogs: []
commands:
  02-awslog:
    command: systemctl enable awslogsd.service
  03-awslog:
    command: systemctl restart awslogsd
files:
"/etc/awslogs/awslogs.conf" :
    mode: "000600"
    owner: root
    group: root
    content: |
      [general]
      state_file = /var/lib/awslogs/agent-state
  "/etc/awslogs/config/sachiel.conf":
    mode: "000600"
    owner: root
    group: root
    content: |
      [info.log]
      log_group_name = `{"Fn::Join":["/", ["/aws/elasticbeanstalk", "sachiel", "var/log/sachiel/info.log"]]}`
      log_stream_name = `{"Fn::Join":["/", [{ "Ref":"AWSEBEnvironmentName" }, "{instance_id}"]]}`
      file = /var/log/sachiel/info.log
      [info_api_call.log]
      log_group_name = `{"Fn::Join":["/", ["/aws/elasticbeanstalk", "sachiel", "var/log/sachiel/info_api_call.log"]]}`
      log_stream_name = `{"Fn::Join":["/", [{ "Ref":"AWSEBEnvironmentName" }, "{instance_id}"]]}`
      file = /var/log/sachiel/info_api_call.log
      [exception.log]
      log_group_name = `{"Fn::Join":["/", ["/aws/elasticbeanstalk", "sachiel", "var/log/sachiel/exception.log"]]}`
      log_stream_name = `{"Fn::Join":["/", [{ "Ref":"AWSEBEnvironmentName" }, "{instance_id}"]]}`
      file = /var/log/sachiel/exception.log

/etc/awslogs/config 안에 .conf 파일을 추가하면 그 추가 config 파일도 같이 추가되어 로그를 스트리밍하는 구조로 파악했다. 근거는 아래와 같다.

[root@dv-sachiel-ap-northeast-2b-046f bin]# systemctl status awslogsd
● awslogsd.service - awslogs daemon
   Loaded: loaded (/usr/lib/systemd/system/awslogsd.service; enabled; vendor preset: disabled)
   Active: active (running) since Fri 2021-05-21 06:39:56 UTC; 56min ago
 Main PID: 2749 (aws)
   CGroup: /system.slice/awslogsd.service
           └─2749 /usr/bin/python2 -s /usr/bin/aws logs push --config-file /etc/awslogs/awslogs.conf --additional-configs-dir /etc/awslogs/config
May 21 06:39:56 ip-10-210-35-80.ap-northeast-2.compute.internal systemd[1]: Started awslogs daemon.
May 21 06:39:56 ip-10-210-35-80.ap-northeast-2.compute.internal systemd[1]: Starting awslogs daemon...

그리고 프로비저닝을 새롭게 시도하였다. 원하는대로 프로비저닝에 성공하였음을 알 수 있었다. 웹 콘솔에서 로그 그룹을 진입하면 현재 로그 스트림을 확인할 수 있었다.

💭 삽질 #3 — /opt/elasticbeanstalk 에 파일을 작성하자.

Elastic Beanstalk 웹 콘솔에서도 로그를 보는 기능이 있다. 전체 로그를 다운받는 기능과, 마지막 tail 로그를 가져오는 기능이 있는데 이 기능들을 통해서 커스텀 로그 파일들을 가져오려면 .ebextensions 안에 아래와 같이 등록하면 된다.

"/opt/elasticbeanstalk/tasks/bundlelogs.d/sachiel.conf" :
    mode: "000755"
    owner: root
    group: root
    content: |
      /var/log/sachiel/*.log
  "/opt/elasticbeanstalk/tasks/taillogs.d/sachiel.conf" :
    mode: "000755"
    owner: root
    group: root
    content: |
      /var/log/sachiel/*.log

https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/using-features.logging.html#health-logs-extend 를 참고하였으며, 파일이 잘 들어오는 것을 확인할 수 있다.

var 15 라는건 15번 다운받아봤다는… 이야기 🤯

요약

Elastic Beanstalk 가 Amazon Linux 2 환경을 발표하면서 일관성을 갖추려는 시도가 있었던 것 같다. 저번 포스팅을 통해서도 이야기했지만, Amazon Linux 2 환경으로 업그레이드하며 알려지지 않은 변경점들이 많다. 문서에 나와있지 않은 많은 부분들을 직접 알아내야 했다.

실제로 한 번 직접 마이그레이션을 겪어보니 다른 어플리케이션의 두 번째 마이그레이션은 생각보다 오래걸리지 않았다. 나의 두 포스트를 통해 많은 도움이 되길 바란다.

Reference

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함