본문으로 건너뛰기

프로덕션 배포

Caffeine 애플리케이션을 프로덕션 환경에 배포합니다.

🎯 학습 목표

  • 프로덕션 환경 구성
  • Kubernetes 배포
  • 모니터링 및 로깅
  • 보안 설정

예상 소요 시간: 90분


📋 사전 요구사항


Step 1: 프로덕션 설정

appsettings.Production.json:

{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"Caffeine": {
"ServerUrl": "https://caffeine-server.production.svc.cluster.local:5001",
"ApiKey": "${CAFFEINE_API_KEY}",
"Timeout": "00:01:00",
"RetryCount": 5
},
"Redis": {
"ConnectionString": "redis-master.production.svc.cluster.local:6379,password=${REDIS_PASSWORD}"
},
"InfluxDB": {
"Url": "http://influxdb.production.svc.cluster.local:8086",
"Token": "${INFLUXDB_TOKEN}",
"Org": "nexcode",
"Bucket": "caffeine-prod"
},
"Kafka": {
"BootstrapServers": "kafka-0.kafka-headless.production.svc.cluster.local:9092"
}
}

Step 2: Kubernetes 매니페스트

Deployment

k8s/deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
name: edge-app
namespace: production
spec:
replicas: 3
selector:
matchLabels:
app: edge-app
template:
metadata:
labels:
app: edge-app
spec:
containers:
- name: edge-app
image: nexcode/edge-app:2.0.1
ports:
- containerPort: 80
env:
- name: ASPNETCORE_ENVIRONMENT
value: "Production"
- name: CAFFEINE_API_KEY
valueFrom:
secretKeyRef:
name: caffeine-secrets
key: api-key
- name: REDIS_PASSWORD
valueFrom:
secretKeyRef:
name: redis-secrets
key: password
- name: INFLUXDB_TOKEN
valueFrom:
secretKeyRef:
name: influxdb-secrets
key: token
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /health
port: 80
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 80
initialDelaySeconds: 5
periodSeconds: 5

Service

k8s/service.yaml:

apiVersion: v1
kind: Service
metadata:
name: edge-app
namespace: production
spec:
type: LoadBalancer
selector:
app: edge-app
ports:
- protocol: TCP
port: 80
targetPort: 80

Ingress

k8s/ingress.yaml:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: edge-app
namespace: production
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- edge.nexcode.co.kr
secretName: edge-app-tls
rules:
- host: edge.nexcode.co.kr
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: edge-app
port:
number: 80

Step 3: Secrets 관리

k8s/secrets.yaml:

apiVersion: v1
kind: Secret
metadata:
name: caffeine-secrets
namespace: production
type: Opaque
stringData:
api-key: "sk_prod_abc123xyz"

---
apiVersion: v1
kind: Secret
metadata:
name: redis-secrets
namespace: production
type: Opaque
stringData:
password: "your-redis-password"

---
apiVersion: v1
kind: Secret
metadata:
name: influxdb-secrets
namespace: production
type: Opaque
stringData:
token: "your-influxdb-token"

보안 주의: 실제 환경에서는 Sealed Secrets, External Secrets Operator, 또는 HashiCorp Vault 사용 권장


Step 4: Helm Chart 배포

helm/values.yaml:

replicaCount: 3

image:
repository: nexcode/edge-app
tag: "2.0.1"
pullPolicy: IfNotPresent

service:
type: LoadBalancer
port: 80

ingress:
enabled: true
className: nginx
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
hosts:
- host: edge.nexcode.co.kr
paths:
- path: /
pathType: Prefix
tls:
- secretName: edge-app-tls
hosts:
- edge.nexcode.co.kr

resources:
requests:
memory: 256Mi
cpu: 250m
limits:
memory: 512Mi
cpu: 500m

autoscaling:
enabled: true
minReplicas: 3
maxReplicas: 10
targetCPUUtilizationPercentage: 80

monitoring:
enabled: true
serviceMonitor:
enabled: true
# Helm 배포
helm install edge-app ./helm \
--namespace production \
--create-namespace \
--values helm/values.yaml

# 배포 확인
kubectl get pods -n production
kubectl get svc -n production
kubectl get ingress -n production

Step 5: 모니터링 설정

Prometheus ServiceMonitor

k8s/servicemonitor.yaml:

apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: edge-app
namespace: production
spec:
selector:
matchLabels:
app: edge-app
endpoints:
- port: http
path: /metrics
interval: 30s

Grafana 대시보드

{
"dashboard": {
"title": "Edge App Monitoring",
"panels": [
{
"title": "CPU Usage",
"targets": [
{
"expr": "rate(container_cpu_usage_seconds_total{pod=~\"edge-app.*\"}[5m])"
}
]
},
{
"title": "Memory Usage",
"targets": [
{
"expr": "container_memory_usage_bytes{pod=~\"edge-app.*\"}"
}
]
},
{
"title": "Request Rate",
"targets": [
{
"expr": "rate(http_requests_total{app=\"edge-app\"}[5m])"
}
]
}
]
}
}

Step 6: 로깅 설정

Serilog 구성

Program.cs:

using Serilog;
using Serilog.Sinks.Elasticsearch;

Log.Logger = new LoggerConfiguration()
.MinimumLevel.Information()
.Enrich.FromLogContext()
.Enrich.WithProperty("Application", "EdgeApp")
.Enrich.WithProperty("Environment", builder.Environment.EnvironmentName)
.WriteTo.Console(
outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}")
.WriteTo.Elasticsearch(new ElasticsearchSinkOptions(new Uri("http://elasticsearch:9200"))
{
AutoRegisterTemplate = true,
IndexFormat = $"edge-app-{DateTime.UtcNow:yyyy.MM}"
})
.CreateLogger();

builder.Host.UseSerilog();

Step 7: CI/CD 파이프라인

.github/workflows/deploy.yml:

name: Deploy to Production

on:
push:
tags:
- 'v*'

jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: '10.0.x'

- name: Build
run: dotnet build -c Release

- name: Test
run: dotnet test --no-build -c Release

- name: Docker Build
run: |
docker build -t nexcode/edge-app:${{ github.ref_name }} .
docker push nexcode/edge-app:${{ github.ref_name }}

- name: Deploy to Kubernetes
run: |
helm upgrade edge-app ./helm \
--namespace production \
--set image.tag=${{ github.ref_name }} \
--wait

Step 8: 헬스 체크 구현

HealthChecks/CaffeineHealthCheck.cs:

using Microsoft.Extensions.Diagnostics.HealthChecks;
using Caffeine.Client;

public class CaffeineHealthCheck : IHealthCheck
{
private readonly CaffeineClient _client;

public CaffeineHealthCheck(CaffeineClient client)
{
_client = client;
}

public async Task<HealthCheckResult> CheckHealthAsync(
HealthCheckContext context,
CancellationToken cancellationToken = default)
{
try
{
// 서버 연결 확인
var connected = await _client.ConnectAsync(cancellationToken);

if (connected)
{
return HealthCheckResult.Healthy("Caffeine 서버 연결 정상");
}

return HealthCheckResult.Unhealthy("Caffeine 서버 연결 실패");
}
catch (Exception ex)
{
return HealthCheckResult.Unhealthy("Caffeine 서버 오류", ex);
}
}
}

Program.cs:

builder.Services.AddHealthChecks()
.AddCheck<CaffeineHealthCheck>("caffeine")
.AddRedis(builder.Configuration["Redis:ConnectionString"]!)
.AddInfluxDB(builder.Configuration["InfluxDB:Url"]!);

app.MapHealthChecks("/health");
app.MapHealthChecks("/ready");

🎓 배운 내용

1. Kubernetes 배포

  • Deployment, Service, Ingress
  • Secrets 관리
  • Resource limits
  • Health checks

2. 모니터링

  • Prometheus metrics
  • Grafana 대시보드
  • Elasticsearch 로깅

3. CI/CD

  • GitHub Actions
  • Docker 빌드
  • Helm 배포

🔍 운영 체크리스트

배포 전

  • 모든 테스트 통과
  • Secrets 설정 완료
  • Resource limits 설정
  • Health checks 구현
  • 모니터링 대시보드 준비

배포 후

  • Pod 상태 확인
  • 로그 확인
  • 메트릭 확인
  • 알람 설정
  • 백업 설정

🚀 다음 단계

축하합니다! 프로덕션 배포를 완료했습니다.

추가 학습:


완료 시간: 약 90분
난이도: ⭐⭐⭐⭐ 전문가
이전: ← 엣지 애플리케이션