Keep 완벽 가이드 - 오픈소스 AIOps 및 알림 관리 플랫폼으로 모니터링 자동화하기
⏱️ 예상 읽기 시간: 15분
서론
현대 IT 환경에서 모니터링 도구들은 끊임없이 알림을 생성하지만, 이들을 효과적으로 관리하고 자동화하는 것은 여전히 큰 과제입니다. Keep은 이러한 문제를 해결하기 위한 오픈소스 AIOps 및 알림 관리 플랫폼으로, “모니터링 도구를 위한 GitHub Actions”라는 컨셉으로 개발되었습니다.
Keep은 10.4k stars를 받은 활발한 오픈소스 프로젝트로, 다양한 모니터링 도구와 통합하여 알림 관리를 자동화하고 인시던트 대응을 효율화할 수 있습니다. 이 가이드에서는 Keep의 핵심 개념부터 실제 구현까지 상세히 알아보겠습니다.
Keep 핵심 개념
AIOps 플랫폼으로서의 Keep
Keep은 AIOps(Artificial Intelligence for IT Operations)와 알림 관리를 결합한 플랫폼입니다:
- 워크플로우 기반 자동화: YAML로 정의된 워크플로우를 통한 지능적 알림 처리
- 다양한 도구 통합: 100개 이상의 provider를 통한 모니터링 생태계 연결
- Enterprise-ready: 대규모 환경에서의 안정적인 운영 지원
주요 특징
- Developer First: 현대적인 REST API, 네이티브 SDK, 포괄적인 문서
- Enterprise Security: SSO, SAML, OIDC, RBAC 등 완전한 보안 지원
- Flexible Deployment: 온프레미스, 클라우드, 에어갭 환경 지원
- Production Scale: 고가용성, 수평적 확장 지원
아키텍처 분석
워크플로우 구조
Keep 워크플로우는 세 가지 주요 구성요소로 이루어집니다:
1. Triggers (트리거)
워크플로우를 시작하는 조건들:
- 알림 기반: 특정 알림 조건에 따른 자동 실행
- 인시던트 기반: 인시던트 발생 시 자동 실행
- 스케줄 기반: 정기적인 실행 (cron 표현식)
- 수동 실행: 사용자 요청에 따른 실행
2. Steps (단계)
데이터 읽기 및 가져오기:
- 데이터 enrichment: 추가 컨텍스트 정보 수집
- 외부 시스템 조회: API 호출을 통한 데이터 획득
- 조건부 로직: 복잡한 비즈니스 로직 실행
3. Actions (액션)
실제 작업 수행:
- 알림 전송: Slack, 이메일, SMS 등으로 알림
- 티켓 생성: Jira, ServiceNow 등에 티켓 생성
- 자동 복구: 서버 재시작, 스케일링 등 자동 작업
아키텍처 다이어그램
graph TD
A[모니터링 도구들] --> B[Keep Platform]
B --> C[워크플로우 엔진]
C --> D[Triggers]
C --> E[Steps]
C --> F[Actions]
D --> G[알림 필터링]
E --> H[데이터 enrichment]
F --> I[자동 대응]
I --> J[Slack 알림]
I --> K[Jira 티켓]
I --> L[자동 복구]
style B fill:#e1f5fe
style C fill:#f3e5f5
style I fill:#e8f5e8
Provider 생태계
Keep은 100개 이상의 provider를 지원하여 다양한 도구와 통합할 수 있습니다:
모니터링 도구
- Prometheus: 메트릭 기반 모니터링
- Grafana: 시각화 및 대시보드
- Datadog: 종합 모니터링 플랫폼
- New Relic: APM 및 인프라 모니터링
- PagerDuty: 인시던트 관리
커뮤니케이션 도구
- Slack: 팀 커뮤니케이션
- Microsoft Teams: 기업 협업
- Discord: 커뮤니티 소통
- Telegram: 모바일 알림
티켓팅 도구
- Jira: 프로젝트 관리
- GitHub Issues: 코드 관련 이슈
- ServiceNow: 기업 서비스 관리
- Linear: 현대적 이슈 트래킹
클라우드 플랫폼
- AWS: 클라우드 서비스 모니터링
- Azure: Microsoft 클라우드 통합
- GCP: Google Cloud 연동
- Kubernetes: 컨테이너 오케스트레이션
기본 워크플로우 예시
Sentry 알림을 Jira 티켓으로 변환
workflow:
id: sentry-to-jira
description: Sentry 크리티컬 알림을 Jira 티켓으로 생성
triggers:
- type: alert
filters:
- key: source
value: sentry
- key: severity
value: critical
- key: service
value: r"(payments|api)"
actions:
- name: create-jira-ticket
if: "not '{{ alert.ticket_id }}'"
provider:
type: jira
config: "{{ providers.jira }}"
with:
board_name: "Oncall Board"
issuetype: "Bug"
summary: "{{ alert.name }} - {{ alert.description }}"
description: |
크리티컬 알림이 발생했습니다.
**알림 세부사항:**
- 서비스: {{ alert.service }}
- 심각도: {{ alert.severity }}
- 시간: {{ alert.timestamp }}
```json
{{ alert | tojson }}
```
enrich_alert:
- key: ticket_id
value: results.issue.key
- key: ticket_url
value: results.ticket_url
복합 워크플로우: 알림 → Slack + 자동 복구
workflow:
id: disk-space-automation
description: 디스크 공간 부족 시 자동 대응
triggers:
- type: alert
filters:
- key: source
value: prometheus
- key: alert_name
value: DiskSpaceHigh
steps:
- name: check-disk-usage
provider:
type: bash
with:
command: "df -h | grep '{{ alert.device }}'"
actions:
- name: notify-ops-team
provider:
type: slack
config: "{{ providers.slack-ops }}"
with:
channel: "#ops-alerts"
message: |
🚨 **디스크 공간 부족 알림**
**서버**: {{ alert.hostname }}
**디스크**: {{ alert.device }}
**사용률**: {{ alert.usage }}%
**현재 상태**:
```
```
자동 정리 작업을 시작합니다...
- name: auto-cleanup
if: " > 90"
provider:
type: bash
with:
command: |
# 로그 파일 정리
find /var/log -name "*.log" -mtime +7 -delete
# 임시 파일 정리
find /tmp -type f -mtime +3 -delete
# Docker 이미지 정리
docker system prune -f
- name: notify-cleanup-result
provider:
type: slack
config: ""
with:
channel: "#ops-alerts"
message: |
✅ **자동 정리 완료**
**정리 결과**:
```
```
설치 및 환경 구성
Docker Compose를 사용한 로컬 설치
# Keep 저장소 클론
git clone https://github.com/keephq/keep.git
cd keep
# Docker Compose로 실행
docker-compose up -d
# 웹 인터페이스 접속
open http://localhost:8080
Kubernetes 배포
# keep-namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: keep-system
---
# keep-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: keep-server
namespace: keep-system
spec:
replicas: 2
selector:
matchLabels:
app: keep-server
template:
metadata:
labels:
app: keep-server
spec:
containers:
- name: keep-server
image: keephq/keep:latest
ports:
- containerPort: 8080
env:
- name: DATABASE_URL
value: "postgresql://user:password@postgres:5432/keep"
- name: REDIS_URL
value: "redis://redis:6379"
---
# keep-service.yaml
apiVersion: v1
kind: Service
metadata:
name: keep-server
namespace: keep-system
spec:
selector:
app: keep-server
ports:
- protocol: TCP
port: 80
targetPort: 8080
type: LoadBalancer
환경 변수 설정
# .env 파일 생성
cat > .env << EOF
# 데이터베이스 설정
DATABASE_URL=postgresql://username:password@localhost:5432/keep
REDIS_URL=redis://localhost:6379
# 보안 설정
SECRET_KEY=your-secret-key-here
JWT_SECRET=your-jwt-secret-here
# 외부 서비스 연동
SLACK_BOT_TOKEN=xoxb-your-slack-bot-token
JIRA_URL=https://your-company.atlassian.net
JIRA_USERNAME=your-jira-username
JIRA_PASSWORD=your-jira-password
# 프로메테우스 연동
PROMETHEUS_URL=http://localhost:9090
GRAFANA_URL=http://localhost:3000
EOF
Provider 설정
Slack Provider 설정
# providers.yaml
providers:
slack-ops:
type: slack
config:
webhook_url: "{{ env.SLACK_WEBHOOK_URL }}"
bot_token: "{{ env.SLACK_BOT_TOKEN }}"
signing_secret: "{{ env.SLACK_SIGNING_SECRET }}"
Jira Provider 설정
providers:
jira:
type: jira
config:
url: "{{ env.JIRA_URL }}"
username: "{{ env.JIRA_USERNAME }}"
password: "{{ env.JIRA_PASSWORD }}"
# 또는 API 토큰 사용
api_token: "{{ env.JIRA_API_TOKEN }}"
Prometheus Provider 설정
providers:
prometheus:
type: prometheus
config:
url: "{{ env.PROMETHEUS_URL }}"
username: "{{ env.PROMETHEUS_USERNAME }}"
password: "{{ env.PROMETHEUS_PASSWORD }}"
실무 활용 사례
1. 인시던트 대응 자동화
workflow:
id: incident-response
description: 인시던트 발생 시 자동 대응 워크플로우
triggers:
- type: alert
filters:
- key: severity
value: critical
- key: service
value: production
steps:
- name: gather-context
provider:
type: prometheus
with:
query: "up{service='{{ alert.service }}'}"
- name: check-recent-deployments
provider:
type: github
with:
repo: "{{ alert.repository }}"
query: "recent deployments"
actions:
- name: create-incident
provider:
type: pagerduty
with:
service_key: "{{ alert.service_key }}"
incident_key: "{{ alert.fingerprint }}"
description: "{{ alert.description }}"
- name: notify-on-call
provider:
type: slack
with:
channel: "#incidents"
message: |
🚨 **인시던트 발생**
**서비스**: {{ alert.service }}
**상태**: {{ steps.gather-context.results.up }}
**최근 배포**: {{ steps.check-recent-deployments.results.latest }}
PagerDuty 인시던트: {{ actions.create-incident.results.incident_url }}
- name: auto-rollback
if: "{{ steps.check-recent-deployments.results.within_1_hour }}"
provider:
type: kubernetes
with:
namespace: "{{ alert.namespace }}"
deployment: "{{ alert.service }}"
action: "rollback"
2. 성능 모니터링 및 자동 스케일링
workflow:
id: auto-scaling
description: CPU 사용률 기반 자동 스케일링
triggers:
- type: alert
filters:
- key: alert_name
value: HighCPUUsage
- key: usage
value: "> 80"
steps:
- name: get-current-replicas
provider:
type: kubernetes
with:
namespace: "{{ alert.namespace }}"
deployment: "{{ alert.deployment }}"
action: "get_replicas"
- name: calculate-new-replicas
provider:
type: python
with:
code: |
current = {{ steps.get-current-replicas.results.replicas }}
usage = {{ alert.usage }}
if usage > 90:
new_replicas = min(current * 2, 20)
elif usage > 80:
new_replicas = min(current + 2, 20)
else:
new_replicas = current
return {"new_replicas": new_replicas}
actions:
- name: scale-deployment
if: "{{ steps.calculate-new-replicas.results.new_replicas > steps.get-current-replicas.results.replicas }}"
provider:
type: kubernetes
with:
namespace: "{{ alert.namespace }}"
deployment: "{{ alert.deployment }}"
action: "scale"
replicas: "{{ steps.calculate-new-replicas.results.new_replicas }}"
- name: notify-scaling
provider:
type: slack
with:
channel: "#ops"
message: |
📈 **자동 스케일링 실행**
**서비스**: {{ alert.deployment }}
**네임스페이스**: {{ alert.namespace }}
**이전 replica**: {{ steps.get-current-replicas.results.replicas }}
**새 replica**: {{ steps.calculate-new-replicas.results.new_replicas }}
**CPU 사용률**: {{ alert.usage }}%
3. 로그 분석 및 이상 탐지
workflow:
id: log-anomaly-detection
description: 로그 패턴 분석을 통한 이상 탐지
triggers:
- type: schedule
cron: "*/5 * * * *" # 5분마다 실행
steps:
- name: fetch-error-logs
provider:
type: elasticsearch
with:
index: "app-logs-*"
query: |
{
"query": {
"bool": {
"must": [
{"term": {"level": "ERROR"}},
{"range": {"@timestamp": {"gte": "now-5m"}}}
]
}
}
}
- name: analyze-patterns
provider:
type: python
with:
code: |
import json
from collections import Counter
logs = {{ steps.fetch-error-logs.results.hits }}
# 에러 패턴 분석
error_patterns = Counter()
for log in logs:
error_patterns[log['_source']['message'][:100]] += 1
# 임계값 초과 패턴 찾기
anomalies = []
for pattern, count in error_patterns.items():
if count > 10: # 5분 내 10회 이상 발생
anomalies.append({
"pattern": pattern,
"count": count
})
return {"anomalies": anomalies}
actions:
- name: alert-anomalies
if: "{{ steps.analyze-patterns.results.anomalies | length > 0 }}"
provider:
type: slack
with:
channel: "#alerts"
message: |
🔍 **로그 이상 패턴 탐지**
지난 5분간 다음과 같은 이상 패턴이 감지되었습니다:
{% for anomaly in steps.analyze-patterns.results.anomalies %}
**패턴**: {{ anomaly.pattern }}
**발생 횟수**: {{ anomaly.count }}
---
{% endfor %}
- name: create-investigation-ticket
if: "{{ steps.analyze-patterns.results.anomalies | length > 3 }}"
provider:
type: jira
with:
project: "OPS"
issuetype: "Investigation"
summary: "로그 이상 패턴 조사 필요"
description: |
자동 로그 분석 결과 다음과 같은 이상 패턴들이 감지되었습니다:
{{ steps.analyze-patterns.results | tojson }}
Enterprise 기능 및 보안 설정
인증 및 권한 관리
SSO (Single Sign-On) 설정
# config/auth.yaml
auth:
providers:
- type: saml
config:
entity_id: "keep-production"
sso_url: "https://your-idp.com/sso"
x509_cert: "{{ env.SAML_CERT }}"
attributes:
email: "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"
name: "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"
- type: oidc
config:
client_id: "{{ env.OIDC_CLIENT_ID }}"
client_secret: "{{ env.OIDC_CLIENT_SECRET }}"
discovery_url: "https://your-provider.com/.well-known/openid-configuration"
scopes: ["openid", "profile", "email"]
RBAC (Role-Based Access Control)
# config/rbac.yaml
roles:
admin:
permissions:
- "workflows:create"
- "workflows:edit"
- "workflows:delete"
- "providers:manage"
- "users:manage"
operator:
permissions:
- "workflows:view"
- "workflows:execute"
- "alerts:manage"
- "incidents:manage"
viewer:
permissions:
- "workflows:view"
- "alerts:view"
- "incidents:view"
# 사용자 역할 할당
users:
- email: "admin@company.com"
roles: ["admin"]
- email: "ops-team@company.com"
roles: ["operator"]
- email: "dev-team@company.com"
roles: ["viewer"]
고가용성 및 스케일링
클러스터 구성
# docker-compose.ha.yaml
version: '3.8'
services:
keep-server-1:
image: keephq/keep:latest
environment:
- INSTANCE_ID=keep-1
- REDIS_URL=redis://redis-cluster:6379
- DATABASE_URL=postgresql://user:pass@postgres-primary:5432/keep
deploy:
replicas: 2
keep-server-2:
image: keephq/keep:latest
environment:
- INSTANCE_ID=keep-2
- REDIS_URL=redis://redis-cluster:6379
- DATABASE_URL=postgresql://user:pass@postgres-replica:5432/keep
deploy:
replicas: 2
redis-cluster:
image: redis:7-alpine
command: redis-server --cluster-enabled yes
deploy:
replicas: 3
postgres-primary:
image: postgres:15
environment:
- POSTGRES_DB=keep
- POSTGRES_USER=keep_user
- POSTGRES_PASSWORD=secure_password
volumes:
- postgres_data:/var/lib/postgresql/data
nginx-lb:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
성능 모니터링
# monitoring/prometheus.yml
global:
scrape_interval: 15s
scrape_configs:
- job_name: 'keep-metrics'
static_configs:
- targets: ['keep-server-1:8080', 'keep-server-2:8080']
metrics_path: '/metrics'
scrape_interval: 10s
- job_name: 'keep-database'
static_configs:
- targets: ['postgres-exporter:9187']
보안 모범 사례
시크릿 관리
# secrets/vault-config.yaml
vault:
address: "https://vault.company.com"
auth_method: "kubernetes"
role: "keep-production"
secrets:
slack_webhook: "vault:secret/keep/slack#webhook_url"
jira_token: "vault:secret/keep/jira#api_token"
database_password: "vault:secret/keep/database#password"
네트워크 보안
# security/network-policy.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: keep-network-policy
namespace: keep-system
spec:
podSelector:
matchLabels:
app: keep-server
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: ingress-nginx
ports:
- protocol: TCP
port: 8080
egress:
- to:
- namespaceSelector:
matchLabels:
name: postgres
ports:
- protocol: TCP
port: 5432
고급 워크플로우 패턴
조건부 분기 처리
workflow:
id: conditional-escalation
description: 알림 심각도에 따른 조건부 에스컬레이션
triggers:
- type: alert
actions:
- name: level-1-notification
if: "{{ alert.severity == 'warning' }}"
provider:
type: slack
with:
channel: "#monitoring"
message: "⚠️ Warning: {{ alert.message }}"
- name: level-2-notification
if: "{{ alert.severity == 'critical' }}"
provider:
type: slack
with:
channel: "#incidents"
message: "🚨 Critical: {{ alert.message }}"
- name: page-oncall
if: "{{ alert.severity == 'critical' and alert.service in ['payment', 'auth'] }}"
provider:
type: pagerduty
with:
service_key: "{{ alert.service }}_oncall"
incident_key: "{{ alert.fingerprint }}"
- name: executive-notification
if: "{{ alert.severity == 'critical' and alert.duration > 300 }}"
provider:
type: email
with:
to: ["cto@company.com", "vp-engineering@company.com"]
subject: "Critical System Alert - {{ alert.service }}"
body: |
A critical alert has been ongoing for over 5 minutes.
Details:
- Service: {{ alert.service }}
- Duration: {{ alert.duration }}s
- Message: {{ alert.message }}
루프 처리 및 배치 작업
workflow:
id: batch-server-health-check
description: 여러 서버의 상태를 배치로 확인
triggers:
- type: schedule
cron: "0 */6 * * *" # 6시간마다 실행
steps:
- name: get-server-list
provider:
type: kubernetes
with:
namespace: "production"
resource: "nodes"
action: "list"
- name: check-server-health
foreach: "{{ steps.get-server-list.results.nodes }}"
provider:
type: ssh
with:
host: "{{ item.ip }}"
username: "monitoring"
key: "{{ secrets.ssh_key }}"
command: |
echo "=== System Health Check ==="
echo "CPU Usage: $(top -bn1 | grep 'Cpu(s)' | awk '{print $2}' | cut -d'%' -f1)"
echo "Memory Usage: $(free | grep Mem | awk '{printf \"%.2f%%\", $3/$2 * 100.0}')"
echo "Disk Usage: $(df -h | grep '/$' | awk '{print $5}')"
echo "Load Average: $(uptime | awk -F'load average:' '{print $2}')"
actions:
- name: generate-health-report
provider:
type: python
with:
code: |
import json
from datetime import datetime
servers = {{ steps.check-server-health.results }}
report = {
"timestamp": datetime.now().isoformat(),
"total_servers": len(servers),
"healthy_servers": 0,
"unhealthy_servers": [],
"summary": {}
}
for server in servers:
# 서버 상태 분석 로직
if server.get("success", False):
report["healthy_servers"] += 1
else:
report["unhealthy_servers"].append({
"host": server["host"],
"error": server.get("error", "Unknown error")
})
return report
- name: send-health-report
provider:
type: slack
with:
channel: "#infrastructure"
message: |
📊 **서버 상태 점검 보고서**
**점검 시간**: {{ steps.generate-health-report.results.timestamp }}
**전체 서버**: {{ steps.generate-health-report.results.total_servers }}
**정상 서버**: {{ steps.generate-health-report.results.healthy_servers }}
**문제 서버**: {{ steps.generate-health-report.results.unhealthy_servers | length }}
{% if steps.generate-health-report.results.unhealthy_servers | length > 0 %}
**문제 서버 목록**:
{% for server in steps.generate-health-report.results.unhealthy_servers %}
- {{ server.host }}: {{ server.error }}
{% endfor %}
{% endif %}
다중 환경 관리
# workflows/multi-env-deployment.yaml
workflow:
id: multi-env-deployment
description: 다중 환경 배포 자동화
triggers:
- type: webhook
config:
path: "/deploy"
method: "POST"
steps:
- name: validate-deployment
provider:
type: python
with:
code: |
import json
payload = {{ trigger.body }}
# 필수 필드 검증
required_fields = ["service", "version", "environments"]
for field in required_fields:
if field not in payload:
raise ValueError(f"Missing required field: {field}")
# 환경 순서 검증
valid_order = ["development", "staging", "production"]
environments = payload["environments"]
if not all(env in valid_order for env in environments):
raise ValueError("Invalid environment specified")
return {
"service": payload["service"],
"version": payload["version"],
"environments": environments
}
- name: deploy-to-environment
foreach: "{{ steps.validate-deployment.results.environments }}"
provider:
type: kubernetes
with:
namespace: "{{ item }}"
resource: "deployment"
name: "{{ steps.validate-deployment.results.service }}"
action: "update"
spec:
containers:
- name: "{{ steps.validate-deployment.results.service }}"
image: "registry.company.com/{{ steps.validate-deployment.results.service }}:{{ steps.validate-deployment.results.version }}"
- name: run-health-check
foreach: "{{ steps.validate-deployment.results.environments }}"
provider:
type: http
with:
url: "https://{{ steps.validate-deployment.results.service }}.{{ item }}.company.com/health"
method: "GET"
timeout: 30
retries: 3
actions:
- name: notify-success
if: "{{ steps.deploy-to-environment.success and steps.run-health-check.success }}"
provider:
type: slack
with:
channel: "#deployments"
message: |
✅ **배포 성공**
**서비스**: {{ steps.validate-deployment.results.service }}
**버전**: {{ steps.validate-deployment.results.version }}
**환경**: {{ steps.validate-deployment.results.environments | join(', ') }}
모든 환경에서 상태 확인이 완료되었습니다.
- name: notify-failure
if: "{{ not (steps.deploy-to-environment.success and steps.run-health-check.success) }}"
provider:
type: slack
with:
channel: "#deployments"
message: |
❌ **배포 실패**
**서비스**: {{ steps.validate-deployment.results.service }}
**버전**: {{ steps.validate-deployment.results.version }}
**실패한 단계**:
{% if not steps.deploy-to-environment.success %}
- 배포 단계
{% endif %}
{% if not steps.run-health-check.success %}
- 상태 확인 단계
{% endif %}
자세한 로그를 확인하고 수동으로 롤백을 진행하세요.
모범 사례 및 최적화
성능 최적화
워크플로우 최적화
# Best practices for workflow optimization
workflow:
id: optimized-workflow
description: 성능 최적화된 워크플로우 예시
# 1. 적절한 타임아웃 설정
timeout: 300 # 5분
# 2. 재시도 정책 설정
retry:
max_attempts: 3
backoff_factor: 2
steps:
# 3. 병렬 처리 활용
- name: parallel-checks
parallel:
- name: check-database
provider:
type: postgres
with:
query: "SELECT 1"
- name: check-cache
provider:
type: redis
with:
command: "ping"
- name: check-external-api
provider:
type: http
with:
url: "https://api.external.com/health"
# 4. 조건부 실행으로 불필요한 작업 방지
- name: detailed-analysis
if: "{{ steps.parallel-checks.results.check-database.success == false }}"
provider:
type: bash
with:
command: "pg_stat_activity analysis script"
리소스 관리
# docker-compose.optimized.yaml
version: '3.8'
services:
keep-server:
image: keephq/keep:latest
environment:
# 워커 프로세스 수 조정
- WORKERS=4
# 메모리 제한 설정
- MAX_MEMORY=2G
# 연결 풀 크기 조정
- DB_POOL_SIZE=20
- REDIS_POOL_SIZE=10
deploy:
resources:
limits:
memory: 2G
cpus: '2'
reservations:
memory: 1G
cpus: '1'
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 30s
timeout: 10s
retries: 3
보안 모범 사례
시크릿 로테이션
workflow:
id: secret-rotation
description: 주기적 시크릿 로테이션
triggers:
- type: schedule
cron: "0 2 1 * *" # 매월 1일 오전 2시
steps:
- name: rotate-api-keys
provider:
type: vault
with:
action: "rotate"
secrets:
- "secret/keep/slack"
- "secret/keep/jira"
- "secret/keep/pagerduty"
- name: update-provider-configs
provider:
type: python
with:
code: |
# 새로운 시크릿으로 provider 설정 업데이트
import requests
new_secrets = {{ steps.rotate-api-keys.results }}
# Keep API를 통해 provider 설정 업데이트
for secret_name, secret_value in new_secrets.items():
requests.put(
f"http://keep-api:8080/providers/{secret_name}",
json={"config": {"token": secret_value}},
headers={"Authorization": f"Bearer {api_token}"}
)
actions:
- name: notify-rotation-complete
provider:
type: slack
with:
channel: "#security"
message: |
🔐 **시크릿 로테이션 완료**
다음 시크릿들이 성공적으로 로테이션되었습니다:
{% for secret in steps.rotate-api-keys.results.keys() %}
- {{ secret }}
{% endfor %}
트러블슈팅 가이드
일반적인 문제들
1. 워크플로우 실행 실패
# 로그 확인
docker-compose logs keep-server
# 워크플로우 상태 확인
curl -H "Authorization: Bearer $API_TOKEN" \
http://localhost:8080/workflows/sentry-alerts/executions
# 디버그 모드로 실행
docker-compose -f docker-compose.debug.yaml up
2. Provider 연결 문제
# provider 테스트 스크립트
import requests
import json
def test_provider(provider_name, config):
response = requests.post(
f"http://localhost:8080/providers/{provider_name}/test",
json={"config": config},
headers={"Authorization": f"Bearer {api_token}"}
)
if response.status_code == 200:
print(f"✅ {provider_name} 연결 성공")
else:
print(f"❌ {provider_name} 연결 실패: {response.text}")
# 주요 provider 테스트
test_provider("slack", {"webhook_url": "https://hooks.slack.com/..."})
test_provider("jira", {"url": "https://company.atlassian.net", "username": "...", "password": "..."})
3. 성능 문제 진단
# 성능 모니터링 워크플로우
workflow:
id: performance-monitoring
description: Keep 성능 모니터링
triggers:
- type: schedule
cron: "*/15 * * * *" # 15분마다
steps:
- name: check-metrics
provider:
type: prometheus
with:
queries:
- "keep_workflow_execution_duration_seconds"
- "keep_workflow_execution_total"
- "keep_active_workflows"
- "keep_memory_usage_bytes"
actions:
- name: alert-performance-issues
if: "{{ steps.check-metrics.results.keep_workflow_execution_duration_seconds.value > 60 }}"
provider:
type: slack
with:
channel: "#ops"
message: |
⚠️ **Keep 성능 이슈 감지**
**평균 실행 시간**: {{ steps.check-metrics.results.keep_workflow_execution_duration_seconds.value }}초
**메모리 사용량**: {{ steps.check-metrics.results.keep_memory_usage_bytes.value | filesizeformat }}
**활성 워크플로우**: {{ steps.check-metrics.results.keep_active_workflows.value }}
결론
Keep은 현대적인 IT 환경에서 필수적인 AIOps 및 알림 관리 자동화를 위한 강력한 오픈소스 플랫폼입니다. 이 가이드를 통해 다음과 같은 핵심 사항들을 학습했습니다:
🚀 핵심 장점
- 워크플로우 기반 자동화: YAML로 정의된 직관적인 워크플로우
- 광범위한 통합: 100+ provider를 통한 모니터링 생태계 연결
- Enterprise-ready: 대규모 환경에서의 안정적인 운영
- 개발자 친화적: 현대적인 API와 포괄적인 문서화
🛠️ 실무 적용 전략
- 단계적 도입: 간단한 알림 워크플로우부터 시작
- 점진적 확장: 성공적인 패턴을 다른 서비스로 확장
- 모니터링 중심: 워크플로우 자체의 성능과 안정성 모니터링
- 팀 협업: 개발, 운영, 보안 팀 간의 협력적 접근
🔮 향후 방향
Keep을 도입함으로써 다음과 같은 이점을 기대할 수 있습니다:
- MTTR 단축: 자동화된 인시던트 대응으로 복구 시간 단축
- 운영 효율성: 반복적인 작업의 자동화로 인력 절약
- 일관성 향상: 표준화된 프로세스를 통한 품질 개선
- 가시성 증대: 통합된 모니터링과 알림으로 시스템 투명성 향상
Keep과 같은 AIOps 플랫폼의 도입은 단순한 도구 사용을 넘어서, 조직의 운영 문화를 자동화와 데이터 기반 의사결정으로 변화시키는 중요한 전환점이 될 것입니다.
지금 바로 Keep GitHub Repository에서 프로젝트를 시작하고, 여러분의 모니터링 환경을 혁신해보세요!
관련 글: