# 在 Openshift 中設定 Cluster Observability Operator 監控一個服務
## 0. 本篇文章 Openshift 環境資訊
- Openshift version: `4.18.22`
- Cluster Observability Operator version : `1.2.2`
    - [安裝 Cluster Observability Operator 文件](https://hackmd.io/8tQR4UDWTB-cG20AnmWGAg?view#32-%E9%96%8B%E5%A7%8B%E5%AE%89%E8%A3%9D-Cluster-Observability-Operator)
## 1. Preface
可以透過設定由Cluster Observability Operator 所管理的監控堆疊 (monitoring stacks),來監控服務的指標 (metrics)。
若要測試監控服務,請遵循以下步驟:
* 部署一個定義了 service endpoint 的範例服務。
* 建立一個 `ServiceMonitor` 物件,用以指定 COO 應如何監控該服務。
* 建立一個 `MonitoringStack` 物件來探索 (discover) 前述的 `ServiceMonitor` 物件。
## 2. 為 Cluster Observability Operator 部署範例服務
此設定檔會在使用者自訂的 `ns1-coo` 專案中,部署一個名為 `prometheus-coo-example-app` 的範例服務。該服務會公開 (expose) 自訂的 `version` 指標。
### 2.1. **先決條件**
您能以具備 `cluster-admin` 叢集角色的使用者身分,或是以具 `namespace` 管理權限的使用者身分存取叢集。
### 2.2. 開始部署與設定
1. 建立並切換專案目錄
    ```
    mkdir sample; cd sample
    ```
2. 建立一個名為 `prometheus-coo-example-app.yaml` 的 YAML 檔案,其中包含以下用於 `namespace`、`deployment` 和 `service` 的設定細節:
    ```
    cat <<EOF > prometheus-coo-example-app.yaml
    apiVersion: v1
    kind: Namespace
    metadata:
      name: ns1-coo
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      labels:
        app: prometheus-coo-example-app
      name: prometheus-coo-example-app
      namespace: ns1-coo
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: prometheus-coo-example-app
      template:
        metadata:
          labels:
            app: prometheus-coo-example-app
        spec:
          containers:
          - image: ghcr.io/rhobs/prometheus-example-app:0.4.2
            imagePullPolicy: IfNotPresent
            name: prometheus-coo-example-app
    ---
    apiVersion: v1
    kind: Service
    metadata:
      labels:
        app: prometheus-coo-example-app
      name: prometheus-coo-example-app
      namespace: ns1-coo
    spec:
      ports:
      - port: 8080
        protocol: TCP
        targetPort: 8080
        name: web
      selector:
        app: prometheus-coo-example-app
      type: ClusterIP
    EOF
    ```
3. 建立範例應用
    ```
    oc apply -f prometheus-coo-example-app.yaml
    ```
4. 確認 pod 狀態是 `running`
    ```
    oc -n ns1-coo get pods
    ```
    正確執行結果:
    ```
    NAME                                          READY   STATUS    RESTARTS   AGE
    prometheus-coo-example-app-57b7fcf6c6-w7b2b   1/1     Running   0          8s
    ```
好的,這段技術文件的繁體中文翻譯如下:
## 3. 指定服務如何由 Cluster Observability Operator 監控
要使用您在「為 Cluster Observability Operator 部署範例服務」一節中所建立的範例服務公開的**指標 (metrics)**,您必須設定監控元件以從 `/metrics` **端點 (endpoint)** 抓取指標。
您可以透過建立一個 `ServiceMonitor` 物件來指定如何監控服務,或建立一個 `PodMonitor` 物件來指定如何監控 Pod,以完成此設定。`ServiceMonitor` 物件需要一個 `Service` 物件,而 `PodMonitor` 物件則不需要,這讓 `MonitoringStack` 物件能夠直接從 Pod 公開的指標端點抓取指標。
此程序展示如何為 `ns1-coo` namespace 中一個名為 `prometheus-coo-example-app` 的範例服務建立 `ServiceMonitor` 物件。
### 3.1. 先決條件
* 您需以具有 `cluster-admin` **叢集角色 (cluster role)** 的使用者身分,或具有該命名空間管理權限的使用者身分存取叢集。
* 您已安裝 Cluster Observability Operator。
* 您已在 `ns1-coo` 命名空間中部署 `prometheus-coo-example-app` 範例服務。
### 3.2. 開始部署與設定
建立一個名為 `example-coo-app-service-monitor.yaml` 的 YAML 檔案,其中包含以下 `ServiceMonitor` 物件的設定詳細資訊:
1. 定義一個 `ServiceMonitor` 物件
    > `MonitoringStack` 物件將會引用它,以抓取 (scrape) 由 `prometheus-coo-example-app` 範例服務所暴露 (exposed) 的指標資料
    ```
    cat <<EOF > example-coo-app-service-monitor.yaml
    apiVersion: monitoring.rhobs/v1
    kind: ServiceMonitor
    metadata:
      labels:
        k8s-app: prometheus-coo-example-monitor
      name: prometheus-coo-example-monitor
      namespace: ns1-coo
    spec:
      endpoints:
      - interval: 30s
        port: web
        scheme: http
      selector:
        matchLabels:
          app: prometheus-coo-example-app
    EOF
    ```
2. 透過執行以下指令,將此設定應用至叢集:
    ```
    oc apply -f example-coo-app-service-monitor.yaml
    ```
3. 透過執行以下指令並觀察輸出結果,來驗證 `ServiceMonitor` 資源是否已成功建立:
    ```
    oc -n ns1-coo get servicemonitors.monitoring.rhobs
    ```
    執行結果:
    ```
    NAME                             AGE
    prometheus-coo-example-monitor   77s
    ```
## 4. 為 Cluster Observability Operator 建立一個 `MonitoringStack` 物件
若要抓取由目標 `prometheus-coo-example-app` 服務所暴露的指標資料,您需要建立一個 `MonitoringStack` 物件,該物件需引用您在「為 Cluster Observability Operator 指定服務的監控方式」一節中所建立的 `ServiceMonitor` 物件。接著,這個 `MonitoringStack` 物件便能發現該服務,並從中抓取其暴露的指標資料。
### 4.1. 先決條件
* 您需以具有 `cluster-admin` 叢集角色的使用者身分,或是在該命名空間中具有管理權限的使用者身分存取叢集。
* 您已安裝叢集可觀察性 Operator (Cluster Observability Operator)。
* 您已在 `ns1-coo` 命名空間中部署了 `prometheus-coo-example-app` 範例服務。
* 您已在 `ns1-coo` 命名空間中建立了一個名為 `prometheus-coo-example-monitor` 的 `ServiceMonitor` 物件。
### 4.2. 開始部署與設定
1.  為 `MonitoringStack` 物件的設定建立一個 YAML 檔案。在此範例中,將檔案命名為 `example-coo-monitoring-stack.yaml`。
    ```
    cat <<EOF > example-coo-monitoring-stack.yaml
    apiVersion: monitoring.rhobs/v1alpha1
    kind: MonitoringStack
    metadata:
      name: example-coo-monitoring-stack
      namespace: ns1-coo
    spec:
      logLevel: debug
      retention: 1d
      resourceSelector:
        matchLabels:
          k8s-app: prometheus-coo-example-monitor
    EOF
    ```
2.  加入以下 `MonitoringStack` 物件的設定詳細資訊:
    ```
    oc apply -f example-coo-monitoring-stack.yaml
    ```
3. 執行以下指令並檢視輸出,以驗證 **MonitoringStack** 物件是否可用:
    ```
    oc -n ns1-coo get monitoringstack
    ```
    執行結果:
    ```
    NAME                           AGE
    example-coo-monitoring-stack   9s
    ```
4. 執行以下指令,從 Prometheus 擷取作用中目標 (active targets) 的資訊,並篩選輸出,僅列出標籤為 `app=prometheus-coo-example-app` 的目標。此舉可以驗證帶有此特定標籤的目標,確實已被 Prometheus **發現**並正在**主動監控**。
    ```
    oc -n ns1-coo exec -c prometheus prometheus-example-coo-monitoring-stack-0 -- curl -s 'http://localhost:9090/api/v1/targets' | jq '.data.activeTargets[].discoveredLabels | select(.__meta_kubernetes_endpoints_label_app=="prometheus-coo-example-app")'
    ```
    正確執行結果:
    ```
    {
      "__address__": "10.247.0.35:8080",
      "__meta_kubernetes_endpoint_address_target_kind": "Pod",
      "__meta_kubernetes_endpoint_address_target_name": "prometheus-coo-example-app-57b7fcf6c6-w7b2b",
      "__meta_kubernetes_endpoint_node_name": "worker-3",
      "__meta_kubernetes_endpoint_port_name": "web",
      "__meta_kubernetes_endpoint_port_protocol": "TCP",
      "__meta_kubernetes_endpoint_ready": "true",
      "__meta_kubernetes_endpoints_annotation_endpoints_kubernetes_io_last_change_trigger_time": "2025-09-18T06:21:52Z",
      "__meta_kubernetes_endpoints_annotationpresent_endpoints_kubernetes_io_last_change_trigger_time": "true",
      "__meta_kubernetes_endpoints_label_app": "prometheus-coo-example-app",
      "__meta_kubernetes_endpoints_labelpresent_app": "true",
      "__meta_kubernetes_endpoints_name": "prometheus-coo-example-app",
      "__meta_kubernetes_namespace": "ns1-coo",
      "__meta_kubernetes_pod_annotation_k8s_ovn_org_pod_networks": "{\"default\":{\"ip_addresses\":[\"10.247.0.35/23\"],\"mac_address\":\"0a:58:0a:f7:00:23\",\"gateway_ips\":[\"10.247.0.1\"],\"routes\":[{\"dest\":\"10.244.0.0/14\",\"nextHop\":\"10.247.0.1\"},{\"dest\":\"10.98.0.0/16\",\"nextHop\":\"10.247.0.1\"},{\"dest\":\"169.254.0.5/32\",\"nextHop\":\"10.247.0.1\"},{\"dest\":\"100.64.0.0/16\",\"nextHop\":\"10.247.0.1\"}],\"ip_address\":\"10.247.0.35/23\",\"gateway_ip\":\"10.247.0.1\",\"role\":\"primary\"}}",
      "__meta_kubernetes_pod_annotation_k8s_v1_cni_cncf_io_network_status": "[{\n    \"name\": \"ovn-kubernetes\",\n    \"interface\": \"eth0\",\n    \"ips\": [\n        \"10.247.0.35\"\n    ],\n    \"mac\": \"0a:58:0a:f7:00:23\",\n    \"default\": true,\n    \"dns\": {}\n}]",
      "__meta_kubernetes_pod_annotation_openshift_io_scc": "restricted-v2",
      "__meta_kubernetes_pod_annotation_seccomp_security_alpha_kubernetes_io_pod": "runtime/default",
      "__meta_kubernetes_pod_annotationpresent_k8s_ovn_org_pod_networks": "true",
      "__meta_kubernetes_pod_annotationpresent_k8s_v1_cni_cncf_io_network_status": "true",
      "__meta_kubernetes_pod_annotationpresent_openshift_io_scc": "true",
      "__meta_kubernetes_pod_annotationpresent_seccomp_security_alpha_kubernetes_io_pod": "true",
      "__meta_kubernetes_pod_controller_kind": "ReplicaSet",
      "__meta_kubernetes_pod_controller_name": "prometheus-coo-example-app-57b7fcf6c6",
      "__meta_kubernetes_pod_host_ip": "10.10.7.18",
      "__meta_kubernetes_pod_ip": "10.247.0.35",
      "__meta_kubernetes_pod_label_app": "prometheus-coo-example-app",
      "__meta_kubernetes_pod_label_pod_template_hash": "57b7fcf6c6",
      "__meta_kubernetes_pod_labelpresent_app": "true",
      "__meta_kubernetes_pod_labelpresent_pod_template_hash": "true",
      "__meta_kubernetes_pod_name": "prometheus-coo-example-app-57b7fcf6c6-w7b2b",
      "__meta_kubernetes_pod_node_name": "worker-3",
      "__meta_kubernetes_pod_phase": "Running",
      "__meta_kubernetes_pod_ready": "true",
      "__meta_kubernetes_pod_uid": "275239d6-4353-4f0d-8887-4b0046efd0df",
      "__meta_kubernetes_service_label_app": "prometheus-coo-example-app",
      "__meta_kubernetes_service_labelpresent_app": "true",
      "__meta_kubernetes_service_name": "prometheus-coo-example-app",
      "__metrics_path__": "/metrics",
      "__scheme__": "http",
      "__scrape_interval__": "30s",
      "__scrape_timeout__": "10s",
      "job": "serviceMonitor/ns1-coo/prometheus-coo-example-monitor/0"
    }
    ```
## 5. Validating the monitoring stack
若要驗證 monitoring stack 是否正常運作,請存取範例服務,然後檢視收集到的指標資料。
### 5.1. 先決條件
* 您需以具有 `cluster-admin` 叢集角色的使用者身分,或是在該命名空間中具有管理權限的使用者身分存取叢集。
* 您已安裝叢集可觀察性 Operator (Cluster Observability Operator)。
* 您已在 `ns1-coo` 命名空間中部署了 `prometheus-coo-example-app` 範例服務。
* 您已在 `ns1-coo` 命名空間中建立了一個名為 `prometheus-coo-example-monitor` 的 `ServiceMonitor` 物件。
* 您已在 `ns1-coo` 命名空間中建立了一個名為 `example-coo-monitoring-stack` 的 `MonitoringStack` 物件。
### 5.2. 開始驗證
1.  建立一個路由 (Route) 以暴露 (expose) `prometheus-coo-example-app` 範例服務。請在您的終端機中執行以下指令:
    ```
    oc expose svc prometheus-coo-example-app -n ns1-coo
    ```
    
2. 檢視 route 物件
    ```
    oc -n ns1-coo get route
    ```
    執行結果:
    ```
    NAME                         HOST/PORT                                                    PATH   SERVICES                     PORT   TERMINATION   WILDCARD
    prometheus-coo-example-app   prometheus-coo-example-app-ns1-coo.apps.topgun.example.com          prometheus-coo-example-app   web                  None
    ```
2.  透過您的瀏覽器或命令列存取此路由,以產生指標資料
    ```
    curl http://prometheus-coo-example-app-ns1-coo.apps.topgun.example.com; echo
    ```
    執行結果:
    ```
    Hello from example application.
    ```
3.  在 Prometheus Pod 上執行查詢,以回傳 HTTP 請求總數 (total HTTP requests) 的指標:
    ```
    oc -n ns1-coo exec -c prometheus prometheus-example-coo-monitoring-stack-0 -- curl -s 'http://localhost:9090/api/v1/query?query=http_requests_total' | jq
    ```
    執行結果:
    ```
    {
      "status": "success",
      "data": {
        "resultType": "vector",
        "result": [
          {
            "metric": {
              "__name__": "http_requests_total",
              "code": "200",
              "endpoint": "web",
              "instance": "10.247.0.35:8080",
              "job": "prometheus-coo-example-app",
              "method": "get",
              "namespace": "ns1-coo",
              "pod": "prometheus-coo-example-app-57b7fcf6c6-w7b2b",
              "service": "prometheus-coo-example-app"
            },
            "value": [
              1758178540.022,
              "5"
            ]
          },
          {
            "metric": {
              "__name__": "http_requests_total",
              "code": "404",
              "endpoint": "web",
              "instance": "10.247.0.35:8080",
              "job": "prometheus-coo-example-app",
              "method": "get",
              "namespace": "ns1-coo",
              "pod": "prometheus-coo-example-app-57b7fcf6c6-w7b2b",
              "service": "prometheus-coo-example-app"
            },
            "value": [
              1758178540.022,
              "0"
            ]
          }
        ]
      }
    }
    ```
## 6. 抓取多個 namespace 中的目標
若要抓取多個命名空間中的目標,請在 `MonitoringStack` 物件中設定 namespace 與 resource selector 。
### 6.1. 先決條件
* 您需要以具有 **`cluster-admin`** 叢集角色的使用者,或具有該 namespace **管理權限**的使用者身分存取叢集。
* 您已安裝 Cluster Observability Operator。
### 6.2. 開始部署與設定
1.  部署以下的 namespace 與 `MonitoringStack` YAML 檔案:
    ```
    cat <<EOF > example-coo-monitoring-stack-v2.yaml
    apiVersion: v1
    kind: Namespace
    metadata:
      name: ns1-coo
      labels:
        monitoring.rhobs/stack: multi-ns
    ---
    apiVersion: monitoring.rhobs/v1alpha1
    kind: MonitoringStack
    metadata:
      name: example-coo-monitoring-stack
      namespace: ns1-coo
    spec:
      logLevel: debug
      retention: 1d
      resourceSelector:
          matchLabels:
            k8s-app: prometheus-coo-example-monitor
      namespaceSelector:
          matchLabels:
            monitoring.rhobs/stack: multi-ns
    EOF
    ```
2. 建立 `MonitoringStack`
    ```
    oc apply -f example-coo-monitoring-stack-v2.yaml
    ```
3.  在 `ns1-coo` 命名空間中部署一個範例應用程式,該應用程式帶有一個**持續觸發的警報**:
    ```
    cat <<EOF > prometheus-coo-example-app-v2.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      labels:
        app: prometheus-coo-example-app
      name: prometheus-coo-example-app
      namespace: ns1-coo
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: prometheus-coo-example-app
      template:
        metadata:
          labels:
            app: prometheus-coo-example-app
        spec:
          containers:
          - image: ghcr.io/rhobs/prometheus-example-app:0.4.2
            imagePullPolicy: IfNotPresent
            name: prometheus-coo-example-app
    ---
    apiVersion: v1
    kind: Service
    metadata:
      labels:
        app: prometheus-coo-example-app
      name: prometheus-coo-example-app
      namespace: ns1-coo
    spec:
      ports:
      - port: 8080
        protocol: TCP
        targetPort: 8080
        name: web
      selector:
        app: prometheus-coo-example-app
      type: ClusterIP
    ---
    apiVersion: monitoring.rhobs/v1
    kind: ServiceMonitor
    metadata:
      labels:
        k8s-app: prometheus-coo-example-monitor
      name: prometheus-coo-example-monitor
      namespace: ns1-coo
    spec:
      endpoints:
      - interval: 30s
        port: web
        scheme: http
      selector:
        matchLabels:
          app: prometheus-coo-example-app
    ---
    apiVersion: monitoring.rhobs/v1
    kind: PrometheusRule
    metadata:
      name: example-alert
      namespace: ns1-coo
      labels:
        k8s-app: prometheus-coo-example-monitor
    spec:
      groups:
      - name: example
        rules:
        - alert: VersionAlert
          for: 1m
          expr: version{job="prometheus-coo-example-app"} > 0
          labels:
            severity: warning
    EOF
    ```
4. 重新部署範例應用
    ```
    oc apply -f prometheus-coo-example-app-v2.yaml
    ```
5.  在另一個標記為 `monitoring.rhobs/stack: multi-ns` 的 namespace 中部署相同的範例應用程式:
    ```
    cat <<EOF > prometheus-coo-example-app-ns2.yaml
    apiVersion: v1
    kind: Namespace
    metadata:
      name: ns2-coo
      labels:
        monitoring.rhobs/stack: multi-ns
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      labels:
        app: prometheus-coo-example-app
      name: prometheus-coo-example-app
      namespace: ns2-coo
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: prometheus-coo-example-app
      template:
        metadata:
          labels:
            app: prometheus-coo-example-app
        spec:
          containers:
          - image: ghcr.io/rhobs/prometheus-example-app:0.4.2
            imagePullPolicy: IfNotPresent
            name: prometheus-coo-example-app
    ---
    apiVersion: v1
    kind: Service
    metadata:
      labels:
        app: prometheus-coo-example-app
      name: prometheus-coo-example-app
      namespace: ns2-coo
    spec:
      ports:
      - port: 8080
        protocol: TCP
        targetPort: 8080
        name: web
      selector:
        app: prometheus-coo-example-app
      type: ClusterIP
    ---
    apiVersion: monitoring.rhobs/v1
    kind: ServiceMonitor
    metadata:
      labels:
        k8s-app: prometheus-coo-example-monitor
      name: prometheus-coo-example-monitor
      namespace: ns2-coo
    spec:
      endpoints:
      - interval: 30s
        port: web
        scheme: http
      selector:
        matchLabels:
          app: prometheus-coo-example-app
    EOF
    ```
6. 部署新的範例應用
    ```
    oc apply -f prometheus-coo-example-app-ns2.yaml
    ```
#### 4.5.3. 驗證
請驗證 **`Prometheus`** 實例已新增目標,且警報正在觸發。您可以使用**連接埠轉發 (port-forward)** 指令,來公開由 `MonitoringStack` 實例所部署的 `Prometheus` 或 `Alertmanager` 使用者介面。
1. Prometheus
    ```
    oc port-forward -n ns1-coo pod/prometheus-example-coo-monitoring-stack-0 9090
    ```
2. 打開瀏覽器連接至 `http://localhost:9090/targets` 驗證目標是否**正在被抓取**
    
3. Alertmanager
    ```
    oc port-forward -n ns1-coo pod/alertmanager-example-coo-monitoring-stack-0 9093
    ```
4. `http://localhost:9093/#/alerts`,來驗證目標警報是否正在觸發
    
## 7. 參考資料
- [Configuring the Cluster Observability Operator to monitor a service - Red Hat Docs](https://docs.redhat.com/en/documentation/openshift_container_platform/4.18/html-single/cluster_observability_operator/index#configuring-the-cluster-observability-operator-to-monitor-a-service)