올해 초, 컨테이너 오케스트레이션 환경으로 ECS
를 도입했다.
마음은 k8s
를 사용하고 싶었지만 아래의 이유로 ECS
를 도입하게 되었다.
- 나 자신이
k8s
에 대한 이해도가 부족하다.- 우리 서비스가
k8s
가 필요한 만큼 방대하지 않다.- 회사 인프라 환경이 AWS 의존도가 높다.
k8s
의 러닝 커브가 높으므로 팀원들에게 부담이 된다.- 서버리스 환경인
Fargate
를 통해 손쉽게 컨테이너를 관리할 수 있다.
혼자 인프라를 구축해야 하는 상황이었기 때문에 😢
여러가지 삽질 끝에 운영환경을 ECS
로 전환했다. (해당 삽질 내용은 후에 써볼....수 있을까?)
서버리스로 전환하여 얻게된 이득이 상당했다.
AWS 콘솔을 통해 매우 쉽게 배포된 컨테이너들의 상태를 확인 할 수 있었고,
CPU나 메모리 사용량도 대시보드를 통해 손쉽게 모니터링 할 수 있었다.
물론 이후에 APM 툴로 Pinpoint
를 붙여서 모니터링을 했다.
(ECS
환경에서 Pinpoint
구축하는 것도 삽질을 했었다. 이 내용도 가능하다면 추후에 기록해 볼 예정)
ECS
환경으로 배포된 컨테이너 로깅이 매우 힘들었다. 🤬
CloudWatch
를 통해 AWS 콘솔에서 로그를 확인 할 수 있었으나 매우 매우 매우 불편하다.
CloudWatch
는 'Log Group'
으로 수집된 로그 정보를 AWS 콘솔에 노출 하게 되는데,
이 Log Group
으로 쌓이는 로깅 정보들이 일정시간 딜레이가 있어서 실시간 로깅은 불가능했다.
심지어 한 서비스 내부에 배포된 Task
가 여러 개였기 때문에 불편한 CloudWatch AWS
콘솔 환경에서 운영하고 있는 서비스를 로깅하기란 매우 힘들었다.
ELK
를 도입하고 싶었으나 이것 또한 내가 아직 이해도가 없었고, 현재 서비스에서는 로깅만이 목표였기 때문에 과하다고 생각이 들었다.
이번 포스팅을 통해 ECS 환경에서 로깅을 하기위해 삽질과 공부를 병행한 결과를 공유한다.
현재 우리팀에서는 운영환경 로깅을 아래와 같은 방법으로 진행하고 있다.
- 현재 배포된 Task 들의 실시간 로깅 -> AWS CLI 와 Session Manager 통한 로깅
- 비교적 가까운 과거 (Cloud Watch 로그가 삭제되지 않고 남아있는 기간) 의 로깅 -> 오픈소스 Utern 활용
- 이미 Cloud Watch 로그가 삭제 된 비교적 오래 전 시기의 로깅 -> S3 에 저장된 log 확인
3번 같은 경우를 위해 AWS Lambda 를 통해 CloudWatch 로그정보를 S3 에 저장하는 아키텍쳐를 개발 했다.
해당 내용은 이 포스팅 (클릭) 에서 자세하게 다루고 있다.
서론이 길었다.
그럼, 자세히 알아보자!
ECS 클러스터가 명세된 TaskDefinition 에 "taskRoleArn" 을 추가해야한다.
{ "family": "{ECS Family}-task-definition", "containerDefinitions": [ { ...(중간 생략) ], "taskRoleArn": "ecsTaskRole", << ✅ 이 부분 "executionRoleArn": "ecsTaskExecutionRole", "cpu": "4096", "memory": "8192", "networkMode": "awsvpc", "requiresCompatibilities": [ "FARGATE" ] }
수정 한 후에 수정된 TaskDefinition 으로 명세된 ECS 배포를 진행한다.
터미널을 통해 AWSCLI 를 설치한다.
이미 설치되어 있다면 넘어가도 된다.😋
AWSCLI 설치
$ brew install awscli
설치를 완료한 후에 버전을 확인해 보자
awscli 버전 확인
$ aws --version
ACCESS KEY 와 SECRET KEY 로 AWS 자격증명을 해야한다.
AWS 자격 증명
$ aws configure
direnv
를 사용하고 있다면 direnv
로 폴더를 분리하여 자격증명 하는 것을 권장한다. AWSCLI
설치가 완료되었으니 AWS Session Manager
를 설치해보자.
AWS Session Manager 다운로드
$ curl "https://s3.amazonaws.com/session-manager-downloads/plugin/latest/mac_arm64/sessionmanager-bundle.zip" -o "sessionmanager-bundle.zip"
압축해제
$ unzip sessionmanager-bundle.zip
AWS Session Manager 설치
sudo ./sessionmanager-bundle/install -i /usr/local/sessionmanagerplugin -b /usr/local/bin/session-manager-plugin
installation successful! 이 뜨면 설치 완료! 🎉
AWSCLI
와 Session Manager
를 통해 ECS
에 배포된 컨테이너에 접근하기 위해서는 executeCommand
상태를 enable
로 변경해줘야 한다.
우선 변경하지 않은 상태에서 Task 상태를 조회해보겠다.
ECS Task executeCommand 상태 확인
$ aws ecs describe-tasks --cluster {ECS 클러스터 이름} --tasks {확인하고자 하는 ECS 서비스 내부의 TASK 값} | grep enableExecuteCommand
위에 사진에서 보이듯 해당 Task 는 활성 상태가 false
임을 확인할 수 있다.
이제 해당 클러스터와 서비스의 executeCommand
상태를 true
로 변경해주자.
ECS Task executeCommand 활성화
$ aws ecs update-service --cluster {ECS 클러스터 이름} --service {ECS 클러스터 서비스 이름} --enable-execute-command
위의 명령어를 실행하면 아무 반응이 없다. 지극히 정상이니 당황하지 말자 ! 😋
하지만 다시 상태를 확인해도 false가 뜬다. 당연하다. 상태 변경 적용을 위해 ECS 클러스터를 다시 재배포 해줘야 한다. 🔑
배포 후 다시 ECS Task executeCommand 상태 확인
$ aws ecs describe-tasks --cluster {ECS 클러스터 이름} --tasks {확인하고자 하는 ECS 서비스 내부의 TASK 값} | grep enableExecuteCommand
enable-execute-command
를 진행한 것은 Task 상위 단계인 Service 에 적용한 것이므로 재배포 되어도 앞으로는 Task 들의 상태는 true
로 유지된다. 이제 모든 준비가 끝났다.
서버리스인 ECS 에 마치 EC2 마냥 접근 할 수 있게 되었다. 😋
접근해보자!
Session Manager 를 통해 컨테이너 접근
$ aws ecs execute-command --cluster {ECS 클러스터 이름} --task {접근하고자하는 컨테이너가 있는 Task 값} --container {접근하고자 하는 컨테이너 이름} --command "bin/sh" --interactive
마치 EC2 에 접근한 것과 같이 ECS 에 배포된 컨테이너에 접근 할 수 있다.
{접근하고자 하는 컨테이너 이름} 에는 TaskDefinition 에 명세한 컨테이너 이름을 적어주면 된다.
물론 AWS 콘솔에서도 ECS 화면에서 배포된 컨테이너 목록을 확인할 수 있다. 나는 web
컨테이너에 접근한 것이다.
나는 WEB 컨테이너 내부에 /logs/web 이라는 폴더를 Dockerfile 에 volume 설정으로 명세를 해놓았고, WAS 설정으로 로그 저장을 사전에 해놓았기에, 컨테이너 내부에 저런 폴더 경로에 .log 파일들이 생성 되는 것이다.
해당 .log 파일을 실시간으로 보고싶다면 tail -f {log 파일 명}.log
명령어를 통해 로깅이 가능하다.
Session Manager 를 통한 로깅은 '실시간 로깅' 에 특화 되어있다.
- ECS 배포가 새로 되면 Cluster 내부의 Task 는 새롭게 배포된다.
- 즉, 컨테이너 내부의 로그 파일들은 삭제가 된다.
- 그러므로 과거의 로그를 찾기에는 한계가 있다.
위에서 그렇게 CloudWatch 에 대해 불편하다고 했는데 이게 무슨 말인가... 🫢
일단, ECS 의 모든 로그 정보는 CloudWatch 에 전달 되어 보관된다.
(해당 설정은 TaskDefintion 의 logConfiguration
설정을 통해 가능하다.)
그렇기에, 컨테이너가 재배포된다고 해도 컨테이너 Task 로그가 사라지는 것이지, 과거 ECS 클러스터의 로그들이 사라지는 것은 아니다.
(하지만, CloudWatch 저장 기한을 설정 하는 것을 권한다. 이 내용은 CloudWatch 로그를 S3 로 이관한 내용을 다룬 포스팅 에서 더 자세히 다룬다..)
당.연.히
AWS Console 을 통한 CloudWatch 로깅을 하지 않을 것이다. 🤖
CloudWatch 로그를 조금 더 쉽게 볼 수 있게 해주는 서드파티 툴인 Utern 을 소개한다. 👏
reference : https://github.com/knqyf263/utern
Utern 설치
$ brew tap knqyf263/utern $ brew install knqyf263/utern/utern
설치가 되었으면 끝이다 ! 🍭
물론, 위에서도 언급했지만 direnv
를 통해 AWS 자격 증명을 하는 것을 권장한다.
위 사진과 같이 direnv 가 적용된 폴더에 들어가게 되면 어떤 내용이 exporting 되는지 확인이 가능하다.
Utern 을 통한 Log group 로깅
$ utern --since 2023-07-20T13:00:00+09:00 --timestaps --filter error {log group 이름}
위의 사진은 간단하게 50분 전 모든 로그를 불러오는 명령어의 결과다.
Utern 을 통해 로그 정보를 불러오면 배포된 모든 Task 정보의 로그를 가져온다.
다른 Task 의 로그들은 색깔로 구분되어 노출된다.
겁나 비싸다.
비싸. 비싸. 💸
그렇기에 우리팀은 일주일만 ECS 로그 정보들을 CloudWatch Log Group 에 저장한다.
그렇다면 일주일이 지난 로그는 어떻게 해야할까?
일주일이 지난 CloudWatch 로그들은 S3
에 적재한다.
AWS Lambda
를 통해 적재하도록 자동화 아키텍쳐를 구축했다.
이 내용은 여기를 참고해달라!
iterm
등의 터미널로 split
하여 로깅.CloudWatch Log Group
에 저장된 로그에 접근.--since, --from, --filter
등 명령어로 로그 정보를 추릴수 있음.CloudWatch Log Group
에 모든 로그를 계속 저장하는 것은 비용이 어마어마함.S3
로 이관AWS Lambda
를 통해 자동화 하는 것을 권장혹시나 ECS 로깅에 대해 더 좋은 방법이 있거나 피드백이 있으시면 언제든 댓글로 말씀 부탁드립니다 🥰
고민한 흔적이 느껴지는 포스팅 잘 보았습니다!