Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,17 @@ k6/secrets/*.txt
!k6/secrets/.gitkeep
deploy/ec2/monitoring/.env
deploy/ec2/monitoring/alertmanager/secrets/discord_webhook_url
.terraform/
*.tfstate
*.tfstate.*
terraform.tfvars
*.auto.tfvars
override.tf
override.tf.json
*_override.tf
*_override.tf.json
crash.log
tfplan
tfplan-*
*.tfplan
deploy/ec2/monitoring-lite/alertmanager/secrets/discord_webhook_url
4 changes: 4 additions & 0 deletions deploy/ec2/caddy/Caddyfile.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
__SERVER_NAME__ {
encode zstd gzip
reverse_proxy 127.0.0.1:8088
}
37 changes: 37 additions & 0 deletions deploy/ec2/install_caddy.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#!/usr/bin/env bash
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SERVER_NAME="${SERVER_NAME:?SERVER_NAME is required}"
DEPLOY_USER="${DEPLOY_USER:-${SUDO_USER:-ubuntu}}"
NGINX_INTERNAL_ONLY="${NGINX_INTERNAL_ONLY:-true}"

if ! command -v caddy >/dev/null 2>&1; then
sudo apt-get update
sudo apt-get install -y debian-keyring debian-archive-keyring apt-transport-https curl
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list >/dev/null
sudo apt-get update
sudo apt-get install -y caddy
fi

if [[ "${NGINX_INTERNAL_ONLY}" == "true" ]]; then
sudo APP_CONFIG_SOURCE="/opt/ssd/config/application-dev.yml" \
NGINX_ENABLE_SSL=false \
NGINX_INTERNAL_ONLY=true \
NGINX_SERVER_NAME="_" \
"${SCRIPT_DIR}/install_infra.sh"
fi
Comment thread
coderabbitai[bot] marked this conversation as resolved.

rendered_caddyfile="$(mktemp)"
trap 'rm -f "${rendered_caddyfile}"' EXIT

sed \
-e "s#__SERVER_NAME__#${SERVER_NAME}#g" \
"${SCRIPT_DIR}/caddy/Caddyfile.template" > "${rendered_caddyfile}"

sudo install -d -m 755 /etc/caddy
sudo install -m 644 "${rendered_caddyfile}" /etc/caddy/Caddyfile
sudo systemctl enable --now caddy
sudo systemctl restart caddy
sudo systemctl status caddy --no-pager
11 changes: 10 additions & 1 deletion deploy/ec2/install_infra.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ APP_CONFIG_FILE="${APP_CONFIG_FILE:-${RUNTIME_CONFIG_DIR}/application-dev.yml}"
APP_CONFIG_SOURCE="${APP_CONFIG_SOURCE:-}"
NETWORK_NAME="${NETWORK_NAME:-ssd-net}"
NGINX_SERVER_NAME="${NGINX_SERVER_NAME:-dev-api.simsaimdang.shop}"
NGINX_ENABLE_SSL="${NGINX_ENABLE_SSL:-true}"
NGINX_INTERNAL_ONLY="${NGINX_INTERNAL_ONLY:-false}"
NGINX_TIMEOUT_FILE="${NGINX_TIMEOUT_FILE:-/etc/nginx/conf.d/zzz-ssd-timeout.conf}"
NGINX_UPSTREAM_FILE="${NGINX_UPSTREAM_FILE:-/etc/nginx/conf.d/ssd-upstream.conf}"
NGINX_SITE_AVAILABLE="${NGINX_SITE_AVAILABLE:-/etc/nginx/sites-available/${NGINX_SERVER_NAME}}"
Expand Down Expand Up @@ -101,14 +103,21 @@ fi

if command -v nginx >/dev/null 2>&1; then
install -d -m 755 /etc/nginx/conf.d /etc/nginx/sites-available /etc/nginx/sites-enabled
rm -f /etc/nginx/sites-enabled/default

if copy_if_changed "${SCRIPT_DIR}/nginx/zzz-ssd-timeout.conf" "${NGINX_TIMEOUT_FILE}" 644; then
nginx_changed=1
fi

rendered_site_file="$(mktemp)"
trap 'rm -f "${rendered_site_file}"' EXIT
sed "s#__SERVER_NAME__#${NGINX_SERVER_NAME}#g" "${SCRIPT_DIR}/nginx/site.conf.template" > "${rendered_site_file}"
nginx_template="${SCRIPT_DIR}/nginx/site.https.conf.template"
if [[ "${NGINX_INTERNAL_ONLY}" == "true" ]]; then
nginx_template="${SCRIPT_DIR}/nginx/site.internal.conf.template"
elif [[ "${NGINX_ENABLE_SSL}" != "true" ]]; then
nginx_template="${SCRIPT_DIR}/nginx/site.http.conf.template"
fi
sed "s#__SERVER_NAME__#${NGINX_SERVER_NAME}#g" "${nginx_template}" > "${rendered_site_file}"
if install_rendered_if_changed "${rendered_site_file}" "${NGINX_SITE_AVAILABLE}" 644; then
nginx_changed=1
fi
Expand Down
52 changes: 52 additions & 0 deletions deploy/ec2/install_prod_monitoring_lite.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#!/usr/bin/env bash
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
APP_NAME="${APP_NAME:-ssd}"
DEPLOY_USER="${DEPLOY_USER:-${SUDO_USER:-ubuntu}}"
MONITORING_SOURCE_DIR="${MONITORING_SOURCE_DIR:-${SCRIPT_DIR}/monitoring-lite}"
MONITORING_DIR="${MONITORING_DIR:-/opt/${APP_NAME}/monitoring-prod-lite}"
APP_CONFIG_FILE="${APP_CONFIG_FILE:-/opt/${APP_NAME}/config/application-dev.yml}"
DISCORD_WEBHOOK_FILE="${DISCORD_WEBHOOK_FILE:-${MONITORING_DIR}/alertmanager/secrets/discord_webhook_url}"
ENV_FILE="${ENV_FILE:-${MONITORING_DIR}/.env}"

install -d -m 755 -o "${DEPLOY_USER}" -g "${DEPLOY_USER}" "${MONITORING_DIR}"

tmp_dir="$(mktemp -d)"
trap 'rm -rf "${tmp_dir}"' EXIT
cp -a "${MONITORING_SOURCE_DIR}/." "${tmp_dir}/"
rm -f "${tmp_dir}/.env" "${tmp_dir}/alertmanager/secrets/discord_webhook_url"
cp -a "${tmp_dir}/." "${MONITORING_DIR}/"
chown -R "${DEPLOY_USER}:${DEPLOY_USER}" "${MONITORING_DIR}"
Comment thread
coderabbitai[bot] marked this conversation as resolved.

install -d -m 750 -o "${DEPLOY_USER}" -g 65534 "$(dirname "${DISCORD_WEBHOOK_FILE}")"
if [[ ! -s "${DISCORD_WEBHOOK_FILE}" ]]; then
webhook_url="$(awk '
/^discord:/ {in_discord=1; next}
in_discord && /^[^[:space:]]/ {in_discord=0}
in_discord && /webhook-url:/ {sub(/^[[:space:]]*webhook-url:[[:space:]]*/, ""); print; exit}
' "${APP_CONFIG_FILE}" | tr -d '"' | tr -d "'")"
printf '%s' "${webhook_url}" > "${DISCORD_WEBHOOK_FILE}"
chmod 600 "${DISCORD_WEBHOOK_FILE}"
fi
Comment thread
coderabbitai[bot] marked this conversation as resolved.

chown "${DEPLOY_USER}:65534" "$(dirname "${DISCORD_WEBHOOK_FILE}")"
chmod 750 "$(dirname "${DISCORD_WEBHOOK_FILE}")"
chown 65534:65534 "${DISCORD_WEBHOOK_FILE}"
chmod 600 "${DISCORD_WEBHOOK_FILE}"

if [[ ! -f "${ENV_FILE}" ]]; then
grafana_password="$(openssl rand -base64 24 | tr -d '\n')"
{
echo 'GRAFANA_ADMIN_USER=admin'
echo "GRAFANA_ADMIN_PASSWORD=${grafana_password}"
} > "${ENV_FILE}"
chmod 600 "${ENV_FILE}"
chown "${DEPLOY_USER}:${DEPLOY_USER}" "${ENV_FILE}"
fi

cd "${MONITORING_DIR}"
docker compose -f docker-compose.monitoring-lite.yml config >/dev/null
docker compose -f docker-compose.monitoring-lite.yml up -d

echo "[INFO] SSD lightweight monitoring is running"
19 changes: 19 additions & 0 deletions deploy/ec2/monitoring-lite/alertmanager/alertmanager.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
global:
resolve_timeout: 5m

route:
receiver: discord
group_by: ["alertname", "service"]
group_wait: 30s
group_interval: 5m
repeat_interval: 3h

receivers:
- name: discord
discord_configs:
- webhook_url_file: /etc/alertmanager/secrets/discord_webhook_url
title: '{{ template "ssd.discord.title" . }}'
message: '{{ template "ssd.discord.message" . }}'

templates:
- /etc/alertmanager/templates/*.tmpl
1 change: 1 addition & 0 deletions deploy/ec2/monitoring-lite/alertmanager/secrets/.gitkeep
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

11 changes: 11 additions & 0 deletions deploy/ec2/monitoring-lite/alertmanager/templates/discord.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{{ define "ssd.discord.title" -}}
[{{ .Status | toUpper }}] {{ .CommonLabels.alertname }}
{{- end }}

{{ define "ssd.discord.message" -}}
{{ range .Alerts -}}
- service={{ .Labels.service }} severity={{ .Labels.severity }}
summary={{ .Annotations.summary }}
description={{ .Annotations.description }}
{{ end -}}
{{- end }}
85 changes: 85 additions & 0 deletions deploy/ec2/monitoring-lite/docker-compose.monitoring-lite.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
name: ssd-prod-monitoring-lite

services:
prometheus:
image: prom/prometheus:v2.54.1
container_name: ssd-prod-prometheus
restart: unless-stopped
command:
- --config.file=/etc/prometheus/prometheus.yml
- --storage.tsdb.retention.time=7d
- --storage.tsdb.retention.size=1GB
- --web.enable-lifecycle
ports:
- "127.0.0.1:9091:9090"
volumes:
- ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro
- ./prometheus/rules:/etc/prometheus/rules:ro
- prometheus_data:/prometheus
networks:
- monitoring
- ssd-net

alertmanager:
image: prom/alertmanager:v0.28.1
container_name: ssd-prod-alertmanager
restart: unless-stopped
command:
- --config.file=/etc/alertmanager/alertmanager.yml
- --storage.path=/alertmanager
ports:
- "127.0.0.1:9093:9093"
volumes:
- ./alertmanager/alertmanager.yml:/etc/alertmanager/alertmanager.yml:ro
- ./alertmanager/templates:/etc/alertmanager/templates:ro
- ./alertmanager/secrets:/etc/alertmanager/secrets:ro
- alertmanager_data:/alertmanager
networks:
- monitoring

grafana:
image: grafana/grafana:11.1.4
container_name: ssd-prod-grafana
restart: unless-stopped
depends_on:
- prometheus
env_file:
- .env
environment:
GF_USERS_ALLOW_SIGN_UP: "false"
GF_AUTH_ANONYMOUS_ENABLED: "false"
GF_SERVER_ROOT_URL: "https://dev-api.simsaimdang.shop/grafana/"
GF_SERVER_SERVE_FROM_SUB_PATH: "true"
ports:
- "127.0.0.1:3001:3000"
volumes:
- ../monitoring/grafana/provisioning/datasources/prometheus.yml:/etc/grafana/provisioning/datasources/prometheus.yml:ro
- ../monitoring/grafana/provisioning/dashboards/dashboard.yml:/etc/grafana/provisioning/dashboards/dashboard.yml:ro
- ../monitoring/grafana/dashboards/ssd-production-overview.json:/var/lib/grafana/dashboards/ssd-production-overview.json:ro
- grafana_data:/var/lib/grafana
networks:
- monitoring

node-exporter:
image: prom/node-exporter:v1.8.2
container_name: ssd-prod-node-exporter
restart: unless-stopped
command:
- --path.rootfs=/host
pid: host
volumes:
- /:/host:ro,rslave
networks:
- monitoring

networks:
monitoring:
name: ssd-prod-monitoring
ssd-net:
external: true
name: ssd-net

volumes:
prometheus_data:
alertmanager_data:
grafana_data:
25 changes: 25 additions & 0 deletions deploy/ec2/monitoring-lite/prometheus/prometheus.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
global:
scrape_interval: 15s
evaluation_interval: 15s

alerting:
alertmanagers:
- static_configs:
- targets:
- alertmanager:9093

rule_files:
- /etc/prometheus/rules/*.yml

scrape_configs:
- job_name: ssd-api
metrics_path: /actuator/prometheus
scheme: https
static_configs:
- targets:
- dev-api.simsaimdang.shop

- job_name: node-exporter
static_configs:
- targets:
- node-exporter:9100
51 changes: 51 additions & 0 deletions deploy/ec2/monitoring-lite/prometheus/rules/ssd-alerts.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
groups:
- name: ssd-operational-alerts
rules:
- alert: SsdApiScrapeDown
expr: sum(up{job="ssd-api"}) < 1
for: 1m
labels:
severity: critical
service: ssd-api
annotations:
summary: "SSD API 서버 메트릭 수집 실패"
description: "Prometheus가 1분 이상 SSD API /actuator/prometheus를 수집하지 못했습니다."

- alert: HighHostCpuUsage
expr: 1 - avg(rate(node_cpu_seconds_total{mode="idle"}[5m])) > 0.8
for: 5m
labels:
severity: warning
service: host
annotations:
summary: "EC2 CPU 사용률 높음"
description: "호스트 CPU 사용률이 5분 이상 80%를 초과했습니다."

- alert: HighHostDiskUsage
expr: |
1 - (
node_filesystem_avail_bytes{mountpoint="/",fstype!~"tmpfs|overlay"}
/
node_filesystem_size_bytes{mountpoint="/",fstype!~"tmpfs|overlay"}
) > 0.85
for: 5m
labels:
severity: warning
service: host
annotations:
summary: "EC2 Disk 사용률 높음"
description: "루트 디스크 사용률이 5분 이상 85%를 초과했습니다."

- alert: HighJvmHeapUsage
expr: |
sum(jvm_memory_used_bytes{job="ssd-api", area="heap"})
/
sum(jvm_memory_max_bytes{job="ssd-api", area="heap"})
> 0.8
for: 3m
labels:
severity: warning
service: ssd-api
annotations:
summary: "JVM Heap 사용률 높음"
description: "JVM Heap 사용률이 3분 이상 80%를 초과했습니다."
4 changes: 2 additions & 2 deletions deploy/ec2/monitoring/prometheus/prometheus.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ rule_files:
scrape_configs:
- job_name: ssd-api
metrics_path: /actuator/prometheus
scheme: http
scheme: https
static_configs:
- targets:
- dev-api.simsaimdang.shop
Expand All @@ -35,7 +35,7 @@ scrape_configs:
module: [http_2xx]
static_configs:
- targets:
- http://dev-api.simsaimdang.shop/actuator/health
- https://dev-api.simsaimdang.shop/actuator/health
- http://166.104.223.33:8080/docs
relabel_configs:
- source_labels: [__address__]
Expand Down
Loading
Loading