---
title: "Kubernetes DaemonSet을 활용한 클러스터 모니터링 및 메트릭 수집 완벽 가이드"
description: "Kubernetes DaemonSet은 클러스터의 모든 노드에 파드 하나씩 배포하는 컨트롤러로, 모니터링 에이전트·로그 수집·네트워크·스토리지 등 노드별 작업에 적합하다. 예시로 Node Exporter DaemonSet을 monitoring 네임스페이스에 배포하고, Prometheus와 Grafana를 연동해 시스템 메트릭을 수집·시각화하는 전체 흐름을 단계별 YAML 파일과 명령어로 제공한다. 또한 DaemonSet과 ReplicaSet의 차이점과 배포 순서를 정리한다."
date: "2025-10-22"
last_modified: "2026-05-15T08:36:00.000Z"
type: "Post"
tags:
  - "kubernetes"
  - "Monitoring"
  - "Service Discovery"
categories:
  - "🤖 Computer Science"
series:
  - "k8s"
canonical_url: "https://blog.pieroot.xyz/k8s-daemonset"
markdown_url: "https://blog.pieroot.xyz/k8s-daemonset.md"
---

# Kubernetes DaemonSet을 활용한 클러스터 모니터링 및 메트릭 수집 완벽 가이드

Kubernetes DaemonSet은 클러스터의 모든 노드에 파드 하나씩 배포하는 컨트롤러로, 모니터링 에이전트·로그 수집·네트워크·스토리지 등 노드별 작업에 적합하다. 예시로 Node Exporter DaemonSet을 monitoring 네임스페이스에 배포하고, Prometheus와 Grafana를 연동해 시스템 메트릭을 수집·시각화하는 전체 흐름을 단계별 YAML 파일과 명령어로 제공한다. 또한 DaemonSet과 ReplicaSet의 차이점과 배포 순서를 정리한다.

## DaemonSet이란?

DaemonSet은 Kubernetes에서 클러스터의 모든 노드(또는 특정 노드들)에 파드를 하나씩 배포하는 컨트롤러입니다. 레플리카셋이 지정된 수의 파드 복제본을 유지하는 것과 달리, DaemonSet은 각 노드마다 정확히 하나의 파드를 실행합니다.

주로 다음과 같은 용도로 사용됩니다:

- 모니터링 에이전트: 각 노드의 시스템 메트릭 수집

- 로그 수집기: 노드별 로그 수집 및 중앙 집중화

- 네트워크 플러그인: CNI(Container Network Interface) 데몬

- 스토리지 데몬: Ceph, GlusterFS 등의 분산 스토리지 클라이언트

![image](https://blog.pieroot.xyz/api/image-proxy?id=f5eb6382-106b-4c93-a322-77f38ee1a11b&kind=s3&pageId=2e4067c0-15d0-8046-af6e-d621b20ec11e&source=block&blockId=2e4067c0-15d0-80cc-9b53-e998a603a4e1)

### 구성 요소

이번 실습에서는 Node Exporter DaemonSet을 배포하고, Prometheus와 Grafana를 통해 모니터링 환경을 구축합니다.

1. **Namespace**: `monitoring` 네임스페이스 생성하여 모니터링 관련 리소스를 격리합니다.

1. **ServiceAccount**: `node-exporter`와 `prometheus` 서비스 어카운트를 생성하여 파드에 적절한 권한을 부여합니다.

1. **RBAC**: Prometheus가 Kubernetes 리소스를 탐색할 수 있도록 ClusterRole과 ClusterRoleBinding을 통해 권한을 부여합니다.

1. **Node Exporter DaemonSet**: 각 노드에 시스템 메트릭 수집기를 배포합니다.

1. **Services**:
  - Node Exporter 서비스 (ClusterIP, NodePort)
  - Prometheus 서비스 (ClusterIP, LoadBalancer)
  - Grafana 서비스 (ClusterIP, LoadBalancer)

1. **Prometheus**: 메트릭을 수집하고 저장하는 시계열 데이터베이스입니다.

1. **Grafana**: Prometheus에서 수집한 메트릭 데이터를 시각화하는 대시보드 도구입니다.

---

### 1️⃣ Namespace 생성

모니터링 관련 리소스를 격리하기 위한 네임스페이스를 먼저 생성합니다.

```yaml
# namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: monitoring
```

---

### 2️⃣ ServiceAccount & RBAC 설정

Node Exporter와 Prometheus가 적절한 권한으로 동작할 수 있도록 ServiceAccount와 RBAC를 설정합니다.

```yaml
# 서비스 어카운트 생성 - node-exporter
apiVersion: v1
kind: ServiceAccount
metadata:
  name: node-exporter
  namespace: monitoring
---
# 서비스 어카운트 생성 - prometheus
apiVersion: v1
kind: ServiceAccount
metadata:
  name: prometheus
  namespace: monitoring
---
# 클러스터롤 생성 - prometheus-discovery for Service Discovery
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: prometheus-discovery
rules:
  - apiGroups: [""]
    resources: ["nodes", "pods", "endpoints", "services", "namespaces"]
    verbs: ["get", "list", "watch"]
  - apiGroups: ["apps", "extensions"]
    resources: ["replicasets"]
    verbs: ["get", "list", "watch"]
---
# 클러스터롤바인딩 - prometheus-discovery
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: prometheus-discovery
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: prometheus-discovery
subjects:
  - kind: ServiceAccount
    name: prometheus
    namespace: monitoring
```

> **RBAC 설명**
> 
> - **ClusterRole**: Prometheus가 Kubernetes API를 통해 서비스 디스커버리를 수행하기 위한 권한 정의
> 
> - **ClusterRoleBinding**: prometheus 서비스 어카운트에 ClusterRole 권한을 바인딩
> 
> - 이를 통해 Prometheus는 `monitoring` 네임스페이스의 Pod들을 자동으로 탐색 가능

---

### 3️⃣ Node Exporter DaemonSet

Node Exporter는 시스템 메트릭(CPU, 메모리, 디스크, 네트워크 등)을 수집하여 Prometheus가 스크래핑할 수 있도록 HTTP 엔드포인트로 노출하는 도구입니다. DaemonSet으로 배포되어 클러스터의 각 노드에서 실행됩니다.

#### 주요 특징

- `prom/node-exporter:v1.8.1` 이미지 사용

- **hostNetwork 모드**: 노드의 네트워크 네임스페이스를 직접 사용하여 실제 네트워크 메트릭 수집

- **tolerations 설정**: control-plane/master 노드의 taint를 무시하고 배포 가능

- **rootfs 마운트**: 호스트의 루트 파일시스템을 읽기 전용으로 마운트하여 시스템 정보 수집

- **securityContext**: nobody 사용자로 실행, 권한 상승 방지, 읽기 전용 루트 파일시스템

#### DaemonSet 매니페스트

```yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: node-exporter
  namespace: monitoring
  labels:
    app: node-exporter
spec:
  selector:
    matchLabels:
      app: node-exporter
  updateStrategy:
    type: RollingUpdate
  template:
    metadata:
      labels:
        app: node-exporter
    spec:
      # 서비스 어카운트 지정
      serviceAccountName: node-exporter
      # control-plane 노드에도 배포하려면 taint 허용
      tolerations:
        - key: "node-role.kubernetes.io/control-plane"
          operator: "Exists"
          effect: "NoSchedule"
        - key: "node-role.kubernetes.io/master"
          operator: "Exists"
          effect: "NoSchedule"
      # 모든 워커 노드에 배포. 특정 라벨만 대상으로 하려면 아래에 nodeSelector 추가
      # nodeSelector:
      #   node-role: worker
      hostNetwork: true
      dnsPolicy: ClusterFirstWithHostNet
      containers:
        - name: node-exporter
          image: prom/node-exporter:v1.8.1
          imagePullPolicy: IfNotPresent
          args:
            # 보안상 기본값 유지, 필요한 경우 커스텀 플래그 추가
            - --path.rootfs=/host
          ports:
            - name: metrics
              containerPort: 9100
              hostPort: 9100
              protocol: TCP
          resources:
            requests:
              cpu: "50m"
              memory: "64Mi"
            limits:
              cpu: "200m"
              memory: "256Mi"
          securityContext:
            runAsUser: 65534 # nobody
            runAsGroup: 65534 # nogroup
            allowPrivilegeEscalation: false
            readOnlyRootFilesystem: true
            seccompProfile:
              type: RuntimeDefault
          volumeMounts:
            - name: rootfs
              mountPath: /host
              readOnly: true
      volumes:
        - name: rootfs
          hostPath:
            path: /
            type: Directory

```

> **DaemonSet 주요 설정 설명**
> 
> - **tolerations**: Master/Control-plane 노드의 taint를 허용하여 모든 노드에 배포
> 
> - **hostNetwork: true**: 호스트 네트워크 사용으로 실제 노드 네트워크 메트릭 수집
> 
> - **hostPort: 9100**: 각 노드의 9100 포트로 직접 접근 가능
> 
> - **readOnlyRootFilesystem**: 보안 강화를 위한 읽기 전용 루트 파일시스템

#### 배포 명령어

```bash
# 네임스페이스 생성
kubectl apply -f namespace.yaml

# 서비스 어카운트 및 RBAC 생성
kubectl apply -f serviceaccount-rbac.yaml

# Node Exporter DaemonSet 배포
kubectl apply -f node-exporter-daemonset.yaml

# 서비스 생성
kubectl apply -f node-exporter-service.yaml
```

#### 확인 방법

배포 후 다음 명령어로 상태를 확인할 수 있습니다:

```bash
# DaemonSet 상태 확인
kubectl get daemonset -n monitoring

# Pod 상태 확인 (각 노드마다 하나씩 실행됨)
kubectl get pods -n monitoring -l app=node-exporter

# 서비스 확인
kubectl get svc -n monitoring

# 특정 파드의 로그 확인
kubectl logs -n monitoring -l app=node-exporter --tail=50
```

정상적으로 배포되면, 클러스터의 노드 수만큼 Node Exporter 파드가 실행됩니다. 예를 들어 3개의 노드가 있다면 3개의 파드가 생성됩니다.

#### Node Exporter Service

Node Exporter에 접근하기 위한 서비스를 생성합니다. ClusterIP와 NodePort 두 가지 타입을 제공합니다.

```yaml
# 서비스 생성
apiVersion: v1
kind: Service
metadata:
  name: node-exporter
  namespace: monitoring
  labels:
    app: node-exporter
spec:
  type: ClusterIP
  ports:
    - name: metrics
      port: 9100
      targetPort: 9100
      protocol: TCP
  selector:
    app: node-exporter
---
# node-exporter 서비스 (Prometheus가 접근)
apiVersion: v1
kind: Service
metadata:
  name: node-exporter-nodeport
  namespace: monitoring
  labels:
    app: node-exporter
spec:
  type: NodePort
  ports:
    - name: metrics
      port: 9100
      targetPort: 9100
      protocol: TCP
      nodePort: 30100
  selector:
    app: node-exporter
```

---

### 4️⃣ Prometheus 설정 및 배포

#### Prometheus ConfigMap

Prometheus의 설정 파일을 ConfigMap으로 관리합니다. Kubernetes Service Discovery를 통해 Node Exporter Pod를 자동으로 탐색합니다.

```yaml
# prometheus-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: prometheus-config
  namespace: monitoring
data:
  prometheus.yml: |
    global:
      scrape_interval: 15s
      evaluation_interval: 15s

    scrape_configs:
      - job_name: 'node-exporter-pods'
        kubernetes_sd_configs:
          - role: pod
            kubeconfig_file: ""
        relabel_configs:
          - source_labels: [__meta_kubernetes_namespace]
            action: keep
            regex: monitoring
          - source_labels: [__meta_kubernetes_pod_label_app]
            action: keep
            regex: node-exporter
          - source_labels: [__meta_kubernetes_pod_container_port_number]
            action: keep
            regex: 9100
          - source_labels: [__meta_kubernetes_pod_ip, __meta_kubernetes_pod_container_port_number]
            separator: ':'
            target_label: __address__
            action: replace
```

> **Kubernetes Service Discovery 설명**
> 
> - **kubernetes\_sd\_configs**: Kubernetes API를 통해 타겟을 자동 탐색
> 
> - **role: pod**: Pod 단위로 스크래핑 타겟 탐색
> 
> - **relabel\_configs**: 메타데이터 기반 필터링
> 
> - `monitoring` 네임스페이스의 Pod만 선택
> 
> - `app=node-exporter` 라벨을 가진 Pod만 선택
> 
> - 9100 포트를 사용하는 컨테이너만 선택

#### Prometheus Deployment

```yaml
# prometheus-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: prometheus
  namespace: monitoring
  labels:
    app: prometheus
spec:
  replicas: 1
  selector:
    matchLabels:
      app: prometheus
  template:
    metadata:
      labels:
        app: prometheus
    spec:
      serviceAccountName: prometheus
      containers:
        - name: prometheus
          image: prom/prometheus:v2.55.0
          args:
            - --config.file=/etc/prometheus/prometheus.yml
            - --storage.tsdb.path=/prometheus
            - --web.enable-admin-api
          ports:
            - name: web
              containerPort: 9090
          volumeMounts:
            - name: config
              mountPath: /etc/prometheus
            - name: data
              mountPath: /prometheus
          resources:
            requests:
              cpu: "200m"
              memory: "256Mi"
            limits:
              cpu: "1"
              memory: "1Gi"
      volumes:
        - name: config
          configMap:
            name: prometheus-config
        - name: data
          emptyDir: {}
```

#### Prometheus Service

```yaml
# prometheus-service.yaml

# Prometheus 서비스 (ClusterIP - Grafana가 접근)
apiVersion: v1
kind: Service
metadata:
  name: prometheus
  namespace: monitoring
  labels:
    app: prometheus
spec:
  type: ClusterIP
  ports:
    - name: web
      port: 9090
      targetPort: 9090
      protocol: TCP
  selector:
    app: prometheus
---
# Prometheus LoadBalancer 서비스 (외부 접근용)
apiVersion: v1
kind: Service
metadata:
  name: prometheus-lb
  namespace: monitoring
  labels:
    app: prometheus-lb
spec:
  type: LoadBalancer
  ports:
    - name: web
      port: 9090
      targetPort: 9090
      protocol: TCP
  selector:
    app: prometheus
```

---

### 5️⃣ Grafana 설정 및 배포

#### Grafana ConfigMap

Grafana의 데이터소스와 대시보드 프로비저닝 설정을 ConfigMap으로 관리합니다.

```yaml
# grafana-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: grafana-config
  namespace: monitoring
data:
  datasources.yml: |
    apiVersion: 1
    datasources:
      - name: Prometheus
        type: prometheus
        access: proxy
        url: 
```

#### Grafana Deployment

```yaml
# grafana-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: grafana
  namespace: monitoring
  labels:
    app: grafana
spec:
  replicas: 1
  selector:
    matchLabels:
      app: grafana
  template:
    metadata:
      labels:
        app: grafana
    spec:
      containers:
        - name: grafana
          image: grafana/grafana:12.4.0-19274378403
          ports:
            - name: web
              containerPort: 3000
          env:
            - name: GF_SECURITY_ADMIN_USER
              value: admin
            - name: GF_SECURITY_ADMIN_PASSWORD
              value: admin
            - name: GF_PATHS_PROVISIONING
              value: /etc/grafana/provisioning
          volumeMounts:
            - name: grafana-config
              mountPath: /etc/grafana/provisioning/datasources/datasources.yml
              subPath: datasources.yml
            - name: grafana-config-dash
              mountPath: /etc/grafana/provisioning/dashboards/dashboards.yml
              subPath: dashboards.yml
            - name: grafana-dash-jsons
              mountPath: /var/lib/grafana/dashboards/node_exporter_full.json
              subPath: node_exporter_full.json
            - name: grafana-storage
              mountPath: /var/lib/grafana
          resources:
            requests:
              cpu: "100m"
              memory: "128Mi"
            limits:
              cpu: "500m"
              memory: "512Mi"
      volumes:
        - name: grafana-config
          configMap:
            name: grafana-config
        - name: grafana-config-dash
          configMap:
            name: grafana-config
        - name: grafana-dash-jsons
          configMap:
            name: grafana-config
        - name: grafana-storage
          emptyDir: {}
```

#### Grafana Service

```yaml
# grafana-service.yaml

# Grafana 서비스 (ClusterIP - 클러스터 내부 접근용)
apiVersion: v1
kind: Service
metadata:
  name: grafana
  namespace: monitoring
  labels:
    app: grafana
spec:
  type: ClusterIP
  ports:
    - name: web
      port: 3000
      targetPort: 3000
      protocol: TCP
  selector:
    app: grafana
---
# Grafana LoadBalancer 서비스 (외부 접근용)
apiVersion: v1
kind: Service
metadata:
  name: grafana-lb
  namespace: monitoring
  labels:
    app: grafana-lb
spec:
  type: LoadBalancer
  ports:
    - name: web
      port: 3000
      targetPort: 3000
      protocol: TCP
  selector:
    app: grafana
```

---

### 6️⃣ 전체 배포 순서

모든 리소스를 순서대로 배포하는 방법입니다.

```bash
# 1. 네임스페이스 생성
kubectl apply -f namespace.yaml

# 2. ServiceAccount 및 RBAC 설정
kubectl apply -f serviceaccount-rbac.yaml

# 3. Node Exporter DaemonSet 및 서비스 배포
kubectl apply -f node-exporter-daemonset.yaml
kubectl apply -f node-exporter-service.yaml

# 4. Prometheus 설정 및 배포
kubectl apply -f prometheus-config.yaml
kubectl apply -f prometheus-deployment.yaml
kubectl apply -f prometheus-service.yaml

# 5. Grafana 설정 및 배포
kubectl apply -f grafana-config.yaml
kubectl apply -f grafana-deployment.yaml
kubectl apply -f grafana-service.yaml
```

> **One-liner 배포**
> 
> 모든 YAML 파일을 하나의 디렉토리에 저장했다면, 다음 명령어로 한 번에 배포할 수 있습니다:
> 
> `kubectl apply -f ./monitoring/`

---

### Prometheus & Grafana 상세 설명

Prometheus는 메트릭을 수집하고 저장하는 오픈소스 모니터링 시스템입니다. 시계열 데이터베이스를 내장하고 있어 메트릭을 효율적으로 저장하고 쿼리할 수 있습니다.

Grafana는 Prometheus에서 수집한 데이터를 시각화하는 대시보드 도구로, 다양한 그래프와 차트를 통해 시스템 상태를 직관적으로 파악할 수 있습니다.

#### 배포 방법

다음 명령어로 Prometheus와 Grafana를 배포합니다:

```bash
# Prometheus 설정 및 배포
kubectl apply -f prometheus.yaml

# Prometheus 서비스 생성
kubectl apply -f prometheus-service.yaml

# Grafana 배포 및 서비스 생성
kubectl apply -f grafana.yaml
kubectl apply -f grafana-service.yaml
```

#### 확인 방법

배포 후 다음 명령어로 상태를 확인합니다:

```bash
# Prometheus 상태 확인
kubectl get pods -n monitoring -l app=prometheus

# Grafana 상태 확인
kubectl get pods -n monitoring -l app=grafana

# 서비스 확인
kubectl get svc -n monitoring

# Prometheus가 타겟을 수집하고 있는지 확인
kubectl logs -n monitoring -l app=prometheus --tail=50
```

#### 접근 정보

서비스가 정상적으로 실행되면 다음 주소로 접근할 수 있습니다:

- **Prometheus**: `http://&lt;MASTER_NODE_IP&gt;:9090`Prometheus UI에서 수집된 메트릭을 확인하고 PromQL 쿼리를 실행할 수 있습니다.

- **Grafana**: `http://&lt;MASTER_NODE_IP&gt;:3000`기본 계정 정보: `admin` / `admin` (최초 로그인 시 비밀번호 변경 권장)

#### Grafana 대시보드 설정

Grafana에 접속한 후 다음 단계를 통해 대시보드를 구성할 수 있습니다:

1. Data Source 추가: Configuration → Data Sources → Add data source → Prometheus 선택

1. Prometheus URL 입력: `http://prometheus:9090`

1. 대시보드 가져오기: Dashboards → Import → 대시보드 ID 입력 (예: 1860 - Node Exporter Full)

### DaemonSet vs ReplicaSet

DaemonSet과 ReplicaSet의 주요 차이점을 정리하면 다음과 같습니다:

### 핵심 정리

이 문서에서는 Kubernetes의 DaemonSet 개념과 실습 방법에 대해 알아보았습니다. DaemonSet은 각 노드마다 하나의 파드를 실행하는 컨트롤러로, 모니터링이나 로그 수집 같은 노드별 작업에 최적화되어 있습니다.

✅ **DaemonSet**: 클러스터의 모든 노드(또는 특정 노드)에 파드를 하나씩 배포하는 Kubernetes 컨트롤러

✅ **주요 용도**: 모니터링 에이전트, 로그 수집기, 네트워크 플러그인, 스토리지 데몬

✅ **Node Exporter**: 각 노드의 시스템 메트릭(CPU, 메모리, 디스크 등)을 수집하는 DaemonSet

✅ **Prometheus**: 메트릭 수집 및 저장을 담당하는 시계열 데이터베이스

✅ **Grafana**: Prometheus 데이터를 시각화하는 대시보드 도구

✅ **주요 특징**: hostNetwork 모드, tolerations로 master 노드 배포 가능, 노드 추가 시 자동 배포

✅ **ReplicaSet과의 차이**: ReplicaSet은 지정된 수의 복제본 유지, DaemonSet은 노드당 1개 파드 실행
