저번달에 새벽1시였나 서버가 갑자기 죽었다 깜짝놀라서 기존 서버를 내리고 새로운 서버를 배포 했다 그러니 잘 돌아갔다...
하지만 이유를 알 수 없었다... 기존 서버를 없에버려서... 그때 실제 유저들이 돈을 내고 사용하고 있던 서비스라서 너무 놀라서 일단 서버를 복구해야겠다는 생각으로 한 행동인데 복구가 되자마자 왜 서버가 꺼졌을까 너무 궁금해졌다 나중에 생각해보면 그냥 기존 ec2를 냅두고 새로운 서버를 배포하고 기존 서버에서 이슈 트래킹을 했으면 어땠을까 라는 생각이 들었다 몇가지 예상되는 원인(OOM 등)들이 있었지만 이건 예상이지 확실한건 아니다
그리고 또한 가끔 시스템이 느린 경우도 있었다 이것에 대한 이유를 해결하고 싶었지만 하루에 몇번의 요구사항이 변경되던 시기라서 너무 바빴고, 가끔 느린경우도 어느순간 돌아오기도하고 아주 가끔이라서 백로그에 두고 해결은 안했다
어플리케이션의 성능 문제를 실시간으로 감지하고, 장애의 근본 원인을 빠르게 찾을 수 있도록 도와주는 APM(어플리케이션의 성능을 모니터링하고 관리하는 도구)을 도입하기로 했다
핀포인트, 스카우터, 다이나트레이스, 뉴 레릭, 인스타나, 와탭 등등 여러 도구가 있었지만 돈이 없기 때문에 오픈소스인 핀포인트, 스카우터중 골라야 했고 그중에 스카우터는 문서도 잘 되어있고 사람들이 많이 사용해서 참고 자료도 많았다 그래서 스카우터로 도입하기로 했다
우리는 Elastic beanstalk(이하 빈스톡) + github acions를 활용해서 CICD배포를 진행하고 있다
scouter를 도입하는 방법자체는 ec2에 들어가서 scouter wget하고 설정파일 설정하고 실행하는 간단한 작업이지만 cicd를 하고 있는 서비스에서 배포할때마다 ec2에 접근해서 저 일련과정을 하는것 자체가 비효율적이라고 생각했고 .ebextensions라고 웹 어플리케이션 소스 코드에 빈스톡 구성 파일을 추가해서 사용하기로 했다 (벌써부터 느껴지는 삽질의 기운...)
스카우터의 개념과 작동방식, 용어와 스카우터를 설치하고 설정하고 실행하는 방법은 너무 잘 나와있어서 여기에 굳이 쓰진 않겠다
스카우터의 개념과 작동방식, 용어와 스카우터를 설치하고 설정하고 실행하는 방법은 너무 잘 나와있어서 여기에 굳이 쓰진 않겠다
스카우터 서버(collector), 스카우터 호스트 에이전트, 스카우터 자바 에이전트를 전부 어플리케이션이 돌아가는 서버(이하 상용 서버)에 넣는거 자체가 좀 성능에 누를 끼치지 않을까 고려해서 스카우터 서버는(collector) 새로운 ec2를 파기로 했다 (이것도 돈 아까우니까 새로운 계정 파서 일단 1년 프리티어) 왜 와이? 제대로 도입하기전에 실제로 한번 ec2에 접속해서 서버, 에이전트, 스프링 3개를 돌리니까 cpu 메모리가 고갈되는 현상을 확인했기 때문
스카우터 서버 ec2는 고정 ip를 설정해줬다 참고로 고정 ip 할당하면 프리티어까진 돈이 안든다
그냥 로컬에 설치하고 실행하면 된다
스카우터 클라이언트를 내 로컬 컴퓨터에 설치하는중에 실행이 안되는것을 보았다 권한이 없었다 했나 맥북에서 발생하는 이슈였다
맥용 클라이언트는 자바 11이상인데 나는 17이라서 괜찮고
xattr -cr scouter.client.app 이 명령어를 입력하니까 잘 됬다
scouter.client.app 디렉토리와 그 안의 모든 파일 및 디렉토리의 확장 속성을 제거하는 명령어인데 인터넷에서 다운로드한 애플리케이션이나 파일이 실행되지 않을 때, "확장 속성"을 제거하여 실행할 수 있게 한다고 한다
해결!
설정파일에 6100포트와 db_dir, log_dir 설정해주고 실행했다 물론 스카우터 서버 ec2에 인바운드 규칙에 6100 포트 대상은 상용 서버 ip로 해서 tcp, udp다 열어주었고, 아웃바운드 규칙에 6100포트 대상은 내 로컬 컴퓨터 ip 로 tcp, udp 다 열어주었다 스카우터 서버는 도입할때 딱히 이슈는 없었다
상용 서버의 아웃바운드 규칙에 6100 포트 대상은 스카우터 서버(collector) 고정ip로 tcp, udp다 열어주자
여기서부터 삽질 시작이였다
ebextensions에
03-install-scouter-host-agent.config
files:
"/opt/elasticbeanstalk/hooks/appdeploy/pre/03-install-scouter-host-agent.sh":
mode: "000755"
owner: root
group: root
content: |
#!/bin/bash
SCOUTER_VERSION="2.20.0"
SCOUTER_DIR="/opt/scouter"
SCOUTER_URL="https://github.com/scouter-project/scouter/releases/download/v$SCOUTER_VERSION/scouter-all-$SCOUTER_VERSION.tar.gz"
SCOUTER_HOST_AGENT_DIR="$SCOUTER_DIR/agent.host"
SCOUTER_HOST_AGENT_CONF="$SCOUTER_HOST_AGENT_DIR/conf/scouter.conf"
mkdir -p $SCOUTER_DIR
wget $SCOUTER_URL -O /tmp/scouter-all.tar.gz
tar -xzf /tmp/scouter-all.tar.gz -C $SCOUTER_DIR --strip-components=1
cat <<EOF > $SCOUTER_HOST_AGENT_CONF
net_collector_ip= {스카우터 서버(collector) 의 고정 ip}
net_collector_udp_port=6100
net_collector_tcp_port=6100
EOF
# Ensure the script has execution permissions
chmod +x $SCOUTER_HOST_AGENT_DIR/host.sh
cd $SCOUTER_HOST_AGENT_DIR
./host.sh start
commands:
01_run_scouter_install_script:
command: sudo /opt/elasticbeanstalk/hooks/appdeploy/pre/03-install-scouter-host-agent.sh
이렇게 해줬는데 배포가 안됬다... github actions에 로그는
Error: Deployment failed: Error: Environment still has health Yellow 30 seconds after update finished!
이렇다
1-1 번 방법으로 해보니
cpu 그래프에 파란 선이 보인다 잘 되는 것이다 ec2 상태 모니터링을 확인했는데 스토리지가 갑자기 치솟으더니 cpu도 치솟고 서버가 죽었다 일단 메모리 문제라고 생각이 들었다
1-1) 해도 같은 이슈 발생
2-1) 해도 같은 이슈 발생
3-1 실행 하니 이젠 다른 에러가 터짐
16:29:46 WARN: The following instances have not responded in the allowed command timeout time (they might still finish eventually on their own): [{인스턴스id}].
16:29:46 INFO: Command execution completed on all instances. Summary: [Successful: 0, TimedOut: 1].
16:29:46 ERROR: Unsuccessful command execution on instance id(s) 'i-{인스턴스id}'. Aborting the operation.
16:29:46 ERROR: Failed to deploy application.
16:29:52 ERROR: Deployment failed! Current State: Version: ***-2024-06-03T19-24-02, Health: Green, Health Status: Ok
Error: Deployment failed: Error: Deployment failed! Current State: Version: ***-2024-06-03T19-24-02, Health: Green, Health Status: Ok
그러면 아까랑 똑같이 03-install-scouter-host-agent.config에서 command 삭제하고 배포, 그다음에 ec2 직접 접속해서 수동 실행 해보기를 해보자 -> 이렇게 하니 계속 잘 된다.... 메모리 이슈는 해결된 것 같다 메모리 1기가로는 scouter와 스프링을 같이 돌리기 힘든 것 같다 성능 최적화는 나중에 해보고 일단 timeout이슈를 해결해보자
거의 하루종일 구글링을 해본 결과 https://theholyjava.wordpress.com/2015/07/29/fixing-a-mysterious-ebextensions-command-time-out-aws-elastic-beanstalk/ 해당 블로그 글을 참고할 수 있었다
나랑 같은 이슈가 생겼고 &를 이용하여 백그라운드로 시작하는 명령어의 stdin stderr의 출력을 /dev/null로 redirection하라는 소리였다
1-1) 그래도 계속 timeout이슈 발생
2-1) 이렇게 하니까 해결됬다!
files:
"/opt/elasticbeanstalk/hooks/appdeploy/pre/03-install-scouter-host-agent.sh":
mode: "000755"
owner: root
group: root
content: |
#!/bin/bash
SCOUTER_VERSION="2.20.0"
SCOUTER_DIR="/opt/scouter"
SCOUTER_URL="https://github.com/scouter-project/scouter/releases/download/v$SCOUTER_VERSION/scouter-all-$SCOUTER_VERSION.tar.gz"
SCOUTER_HOST_AGENT_DIR="$SCOUTER_DIR/agent.host"
SCOUTER_HOST_AGENT_CONF="$SCOUTER_HOST_AGENT_DIR/conf/scouter.conf"
mkdir -p $SCOUTER_DIR
wget $SCOUTER_URL -O /tmp/scouter-all.tar.gz
tar -xzf /tmp/scouter-all.tar.gz -C $SCOUTER_DIR --strip-components=1
cat <<EOF > $SCOUTER_HOST_AGENT_CONF
net_collector_ip={스카우터 서버(collector) 의 고정 ip}
net_collector_udp_port=6100
net_collector_tcp_port=6100
hook_profile_fullstack_method_sampling_interval_ms=10000
hook_args_sampling_interval_ms=10000
hook_dbsql_enabled=true
hook_http_enabled=true
hook_thread_enabled=true
hook_profile_fullstack_method_sampling_enabled=true
hook_args_enabled=true
EOF
# Ensure the script has execution permissions
chmod +x $SCOUTER_HOST_AGENT_DIR/host.sh
cd $SCOUTER_HOST_AGENT_DIR
sed -i 's/^JAVA_OPTS=.*$/JAVA_OPTS="-Xmx256m"/' ./host.sh
nohup ./host.sh start > /dev/null 2>&1 &
container_commands:
01_run_scouter_install_script:
command: sudo /opt/elasticbeanstalk/hooks/appdeploy/pre/03-install-scouter-host-agent.sh
최종 코드
잘 된다....... 해결!
04-install-scouter-java-agent.config
files:
"/opt/elasticbeanstalk/hooks/appdeploy/pre/04-install-scouter-java-agent.sh":
mode: "000755"
owner: root
group: root
content: |
#!/bin/bash
# Variables
SCOUTER_VERSION="2.20.0"
SCOUTER_AGENT_DIR="/opt/scouter"
SCOUTER_JAVA_AGENT_URL="https://github.com/scouter-project/scouter/releases/download/v$SCOUTER_VERSION/scouter-agent-java-$SCOUTER_VERSION.tar.gz"
SCOUTER_JAVA_AGENT_CONF="/opt/scouter/agent.java/conf/scouter.conf"
# Download and extract Scouter agent
# Configure Scouter agent
cat <<EOF > $SCOUTER_JAVA_AGENT_CONF
obj_name=java
net_collector_ip=3.36.225.29
net_collector_udp_port=6100
net_collector_tcp_port=6100
EOF
container_commands:
01_run_scouter_install_script:
command: sudo /opt/elasticbeanstalk/hooks/appdeploy/pre/04-install-scouter-java-agent.sh
스카우터 자바 에이전트는 호스트 에이전트와 다르게 독립적인 실행이 아니라 java 어플리케이션이 실행될 때 attach되서 실행된다 한다
실행 방법은
1. 톰캣의 시작 스크립트에 스카우터 정보 넣기
2. 어플리케이션 시작할때 scouter 명령행 옵션을 포함하여 jar 파일을 실행
2번으로 실행해보자
00-makeFiles.config
files:
"/sbin/appstart":
mode: "000755"
owner: webapp
group: webapp
content: |
#!/usr/bin/env bash
JAR_PATH=/var/app/current/application.jar
SCOUTER_AGENT_PATH=/opt/scouter/agent.java/scouter.agent.jar
SCOUTER_CONF_PATH=/opt/scouter/agent.java/conf/scouter.conf
# run app
java -javaagent:$SCOUTER_AGENT_PATH \
-Dscouter.config=$SCOUTER_CONF_PATH \
-jar \
-Dspring.profiles.active=prod -Dfile.encoding=UTF-8 -jar $JAR_PATH
스카우터 자바 에이전트의 obj_name을 넣어줄 수 있지만 안해도 돌아가긴한다 그냥 패스!
굳
참고자료
https://gunsdevlog.blogspot.com/2017/07/scouter-apm-1.html
https://theholyjava.wordpress.com/2015/07/29/fixing-a-mysterious-ebextensions-command-time-out-aws-elastic-beanstalk/
https://github.com/scouter-project/scouter/blob/master/README_kr.md