×

在开发使用裸机集群节点上的精确时间协议 (PTP) 事件的消费者应用程序时,您需要将消费者应用程序部署在单独的应用程序 Pod 中。消费者应用程序使用 PTP 事件 REST API v2 订阅 PTP 事件。

以下信息提供了开发使用 PTP 事件的消费者应用程序的一般指导。完整的事件消费者应用程序示例不在本信息的范围内。

关于 PTP 快速事件通知框架

使用精确时间协议 (PTP) 快速事件 REST API v2 将集群应用程序订阅到裸机集群节点生成的 PTP 事件。

快速事件通知框架使用 REST API 进行通信。PTP 事件 REST API v1 和 v2 基于可从O-RAN ALLIANCE Specifications获取的O-RAN O-Cloud 事件消费者通知 API 规范 3.0

只有 PTP 事件 REST API v2 符合 O-RAN v3。

使用 PTP 事件 REST API v2 获取 PTP 事件

应用程序使用生产端云事件代理 sidecar 中与 O-RAN v3 兼容的 REST API 订阅 PTP 事件。cloud-event-proxy sidecar 容器可以访问与主应用程序容器相同的资源,而无需使用主应用程序的任何资源,并且不会产生明显的延迟。

Overview of consuming PTP fast events from the PTP event producer REST API
图 1. 从 PTP 事件生产者 REST API v2 使用 PTP 快速事件的概述
20 集群主机上生成事件

PTP 运算符管理的 Pod 中的 linuxptp-daemon 进程作为 Kubernetes DaemonSet 运行,并管理各种 linuxptp 进程(ptp4lphc2sys,以及可选的 grandmaster 时钟 ts2phc)。linuxptp-daemon 将事件传递到 UNIX 域套接字。

20 事件传递到 cloud-event-proxy sidecar

PTP 插件从 UNIX 域套接字读取事件,并将其传递到 PTP 运算符管理的 Pod 中的 cloud-event-proxy sidecar。cloud-event-proxy 将事件从 Kubernetes 基础设施低延迟地传递到云原生网络功能 (CNF)。

20 事件已发布

PTP 运营商管理的 Pod 中的cloud-event-proxy 侧车处理事件,并使用 PTP 事件 REST API v2 发布事件。

20 消费者应用程序请求订阅并接收已订阅的事件

消费者应用程序向生产者cloud-event-proxy 侧车发送 API 请求以创建 PTP 事件订阅。订阅后,消费者应用程序侦听资源限定符中指定的地址,并接收和处理 PTP 事件。

配置 PTP 快速事件通知发布者

要在集群中的网络接口开始使用 PTP 快速事件通知,必须在 PTP Operator PtpOperatorConfig 自定义资源 (CR) 中启用快速事件发布者,并在您创建的 PtpConfig CR 中配置ptpClockThreshold 值。

先决条件
  • 您已安装 OpenShift Container Platform 命令行界面 (oc)。

  • 您已以具有cluster-admin 权限的用户身份登录。

  • 您已安装 PTP Operator。

步骤
  1. 修改默认 PTP Operator 配置以启用 PTP 快速事件。

    1. 将以下 YAML 保存到ptp-operatorconfig.yaml 文件中

      apiVersion: ptp.openshift.io/v1
      kind: PtpOperatorConfig
      metadata:
        name: default
        namespace: openshift-ptp
      spec:
        daemonNodeSelector:
          node-role.kubernetes.io/worker: ""
        ptpEventConfig:
          apiVersion: 2.0 (1)
          enableEventPublisher: true (2)
      1 通过将ptpEventConfig.apiVersion 设置为 2.0 来启用 PTP 事件生产者的 PTP 事件 REST API v2。默认值为 1.0。
      2 通过将enableEventPublisher 设置为true 来启用 PTP 快速事件通知。

      在 OpenShift Container Platform 4.13 或更高版本中,当您使用 HTTP 传输 PTP 事件时,无需在PtpOperatorConfig 资源中设置spec.ptpEventConfig.transportHost 字段。

    2. 更新PtpOperatorConfig CR

      $ oc apply -f ptp-operatorconfig.yaml
  2. 为启用了 PTP 的接口创建一个PtpConfig 自定义资源 (CR),并设置ptpClockThresholdptp4lOpts 的所需值。以下 YAML 演示了您必须在PtpConfig CR 中设置的所需值

    spec:
      profile:
      - name: "profile1"
        interface: "enp5s0f0"
        ptp4lOpts: "-2 -s --summary_interval -4" (1)
        phc2sysOpts: "-a -r -m -n 24 -N 8 -R 16" (2)
        ptp4lConf: "" (3)
        ptpClockThreshold: (4)
          holdOverTimeout: 5
          maxOffsetThreshold: 100
          minOffsetThreshold: -100
    1 附加--summary_interval -4 以使用 PTP 快速事件。
    2 所需的phc2sysOpts 值。-m 将消息打印到stdoutlinuxptp-daemon DaemonSet 解析日志并生成 Prometheus 指标。
    3 指定包含配置的字符串以替换默认的/etc/ptp4l.conf 文件。要使用默认配置,请将该字段留空。
    4 可选。如果不存在ptpClockThreshold 节,则使用默认值填充ptpClockThreshold 字段。该节显示了默认的ptpClockThreshold 值。ptpClockThreshold 值配置在 PTP 主时钟断开连接后触发 PTP 事件之前的时间长度。holdOverTimeout 是在 PTP 主时钟断开连接后 PTP 时钟事件状态更改为FREERUN 之前的时间值(以秒为单位)。maxOffsetThresholdminOffsetThreshold 设置配置以纳秒为单位的偏移值,这些值与CLOCK_REALTIME (phc2sys) 或主偏移值 (ptp4l) 的值进行比较。当ptp4lphc2sys 偏移值超出此范围时,PTP 时钟状态将设置为FREERUN。当偏移值在此范围内时,PTP 时钟状态将设置为LOCKED
其他资源

PTP 事件 REST API v2 消费者应用程序参考

PTP 事件消费者应用程序需要以下功能

  1. 运行具有POST 处理程序的 Web 服务以接收云原生 PTP 事件 JSON 有效负载

  2. 一个createSubscription 函数,用于订阅 PTP 事件生产者

  3. 一个getCurrentState 函数,用于轮询 PTP 事件生产者的当前状态

以下 Go 代码片段说明了这些要求

Go 中的示例 PTP 事件消费者服务器函数
func server() {
  http.HandleFunc("/event", getEvent)
  http.ListenAndServe(":9043", nil)
}

func getEvent(w http.ResponseWriter, req *http.Request) {
  defer req.Body.Close()
  bodyBytes, err := io.ReadAll(req.Body)
  if err != nil {
    log.Errorf("error reading event %v", err)
  }
  e := string(bodyBytes)
  if e != "" {
    processEvent(bodyBytes)
    log.Infof("received event %s", string(bodyBytes))
  } else {
    w.WriteHeader(http.StatusNoContent)
  }
}
Go 中的示例 PTP 事件 createSubscription 函数
import (
"github.com/redhat-cne/sdk-go/pkg/pubsub"
"github.com/redhat-cne/sdk-go/pkg/types"
v1pubsub "github.com/redhat-cne/sdk-go/v1/pubsub"
)

// Subscribe to PTP events using v2 REST API
s1,_:=createsubscription("/cluster/node/<node_name>/sync/sync-status/sync-state")
s2,_:=createsubscription("/cluster/node/<node_name>/sync/ptp-status/lock-state")
s3,_:=createsubscription("/cluster/node/<node_name>/sync/gnss-status/gnss-sync-status")
s4,_:=createsubscription("/cluster/node/<node_name>/sync/sync-status/os-clock-sync-state")
s5,_:=createsubscription("/cluster/node/<node_name>/sync/ptp-status/clock-class")

// Create PTP event subscriptions POST
func createSubscription(resourceAddress string) (sub pubsub.PubSub, err error) {
  var status int
  apiPath := "/api/ocloudNotifications/v2/"
  localAPIAddr := "localhost:8989" // vDU service API address
  apiAddr := "ptp-event-publisher-service-<node_name>.openshift-ptp.svc.cluster.local:9043" (1)
  apiVersion := "2.0"

  subURL := &types.URI{URL: url.URL{Scheme: "http",
    Host: apiAddr
    Path: fmt.Sprintf("%s%s", apiPath, "subscriptions")}}
  endpointURL := &types.URI{URL: url.URL{Scheme: "http",
    Host: localAPIAddr,
    Path: "event"}}

  sub = v1pubsub.NewPubSub(endpointURL, resourceAddress, apiVersion)
  var subB []byte

  if subB, err = json.Marshal(&sub); err == nil {
    rc := restclient.New()
    if status, subB = rc.PostWithReturn(subURL, subB); status != http.StatusCreated {
      err = fmt.Errorf("error in subscription creation api at %s, returned status %d", subURL, status)
    } else {
      err = json.Unmarshal(subB, &sub)
    }
  } else {
    err = fmt.Errorf("failed to marshal subscription for %s", resourceAddress)
  }
  return
}
1 <node_name> 替换为生成 PTP 事件的节点的 FQDN。例如,compute-1.example.com
Go 中的示例 PTP 事件消费者 getCurrentState 函数
//Get PTP event state for the resource
func getCurrentState(resource string) {
  //Create publisher
  url := &types.URI{URL: url.URL{Scheme: "http",
    Host: "ptp-event-publisher-service-<node_name>.openshift-ptp.svc.cluster.local:9043", (1)
    Path: fmt.SPrintf("/api/ocloudNotifications/v2/%s/CurrentState",resource}}
  rc := restclient.New()
  status, event := rc.Get(url)
  if status != http.StatusOK {
    log.Errorf("CurrentState:error %d from url %s, %s", status, url.String(), event)
  } else {
    log.Debugf("Got CurrentState: %s ", event)
  }
}
1 <node_name> 替换为生成 PTP 事件的节点的 FQDN。例如,compute-1.example.com

使用 PTP 事件 REST API v2 的参考事件消费者部署和服务 CR

在部署用于与 PTP 事件 REST API v2 一起使用的 PTP 事件消费者应用程序时,请参考以下示例 PTP 事件消费者自定义资源 (CR)。

参考云事件消费者命名空间
apiVersion: v1
kind: Namespace
metadata:
  name: cloud-events
  labels:
    security.openshift.io/scc.podSecurityLabelSync: "false"
    pod-security.kubernetes.io/audit: "privileged"
    pod-security.kubernetes.io/enforce: "privileged"
    pod-security.kubernetes.io/warn: "privileged"
    name: cloud-events
    openshift.io/cluster-monitoring: "true"
  annotations:
    workload.openshift.io/allowed: management
参考云事件消费者部署
apiVersion: apps/v1
kind: Deployment
metadata:
  name: cloud-consumer-deployment
  namespace: cloud-events
  labels:
    app: consumer
spec:
  replicas: 1
  selector:
    matchLabels:
      app: consumer
  template:
    metadata:
      annotations:
        target.workload.openshift.io/management: '{"effect": "PreferredDuringScheduling"}'
      labels:
        app: consumer
    spec:
      nodeSelector:
        node-role.kubernetes.io/worker: ""
      serviceAccountName: consumer-sa
      containers:
        - name: cloud-event-consumer
          image: cloud-event-consumer
          imagePullPolicy: Always
          args:
            - "--local-api-addr=consumer-events-subscription-service.cloud-events.svc.cluster.local:9043"
            - "--api-path=/api/ocloudNotifications/v2/"
            - "--api-addr=127.0.0.1:8089"
            - "--api-version=2.0"
            - "--http-event-publishers=ptp-event-publisher-service-NODE_NAME.openshift-ptp.svc.cluster.local:9043"
          env:
            - name: NODE_NAME
              valueFrom:
                fieldRef:
                  fieldPath: spec.nodeName
            - name: CONSUMER_TYPE
              value: "PTP"
            - name: ENABLE_STATUS_CHECK
              value: "true"
      volumes:
        - name: pubsubstore
          emptyDir: {}
参考云事件消费者服务帐户
apiVersion: v1
kind: ServiceAccount
metadata:
  name: consumer-sa
  namespace: cloud-events
参考云事件消费者服务
apiVersion: v1
kind: Service
metadata:
  annotations:
    prometheus.io/scrape: "true"
  name: consumer-events-subscription-service
  namespace: cloud-events
  labels:
    app: consumer-service
spec:
  ports:
    - name: sub-port
      port: 9043
  selector:
    app: consumer
  sessionAffinity: None
  type: ClusterIP

使用 REST API v2 订阅 PTP 事件

部署您的cloud-event-consumer 应用程序容器,并将cloud-event-consumer 应用程序订阅到由 PTP Operator 管理的 Pod 中的cloud-event-proxy 容器发布的 PTP 事件。

通过向http://ptp-event-publisher-service-NODE_NAME.openshift-ptp.svc.cluster.local:9043/api/ocloudNotifications/v2/subscriptions发送POST请求并传递相应的订阅请求有效负载来将消费者应用程序订阅到PTP事件。

cloud-event-proxy容器部署在PTP事件生产者Pod中,默认端口为9043。根据需要,您可以为您的应用程序配置不同的端口。

验证PTP事件REST API v2消费者应用程序是否正在接收事件

验证应用程序Pod中的cloud-event-consumer容器是否正在接收精密时间协议 (PTP) 事件。

先决条件
  • 您已安装OpenShift CLI (oc)。

  • 您已以具有cluster-admin 权限的用户身份登录。

  • 您已安装并配置了PTP Operator。

  • 您已部署了一个云事件应用程序Pod和PTP事件消费者应用程序。

步骤
  1. 检查已部署的事件消费者应用程序的日志。例如,运行以下命令:

    $ oc -n cloud-events logs -f deployment/cloud-consumer-deployment
    示例输出
    time = "2024-09-02T13:49:01Z"
    level = info msg = "transport host path is set to  ptp-event-publisher-service-compute-1.openshift-ptp.svc.cluster.local:9043"
    time = "2024-09-02T13:49:01Z"
    level = info msg = "apiVersion=2.0, updated apiAddr=ptp-event-publisher-service-compute-1.openshift-ptp.svc.cluster.local:9043, apiPath=/api/ocloudNotifications/v2/"
    time = "2024-09-02T13:49:01Z"
    level = info msg = "Starting local API listening to :9043"
    time = "2024-09-02T13:49:06Z"
    level = info msg = "transport host path is set to  ptp-event-publisher-service-compute-1.openshift-ptp.svc.cluster.local:9043"
    time = "2024-09-02T13:49:06Z"
    level = info msg = "checking for rest service health"
    time = "2024-09-02T13:49:06Z"
    level = info msg = "health check http://ptp-event-publisher-service-compute-1.openshift-ptp.svc.cluster.local:9043/api/ocloudNotifications/v2/health"
    time = "2024-09-02T13:49:07Z"
    level = info msg = "rest service returned healthy status"
    time = "2024-09-02T13:49:07Z"
    level = info msg = "healthy publisher; subscribing to events"
    time = "2024-09-02T13:49:07Z"
    level = info msg = "received event {\"specversion\":\"1.0\",\"id\":\"ab423275-f65d-4760-97af-5b0b846605e4\",\"source\":\"/sync/ptp-status/clock-class\",\"type\":\"event.sync.ptp-status.ptp-clock-class-change\",\"time\":\"2024-09-02T13:49:07.226494483Z\",\"data\":{\"version\":\"1.0\",\"values\":[{\"ResourceAddress\":\"/cluster/node/compute-1.example.com/ptp-not-set\",\"data_type\":\"metric\",\"value_type\":\"decimal64.3\",\"value\":\"0\"}]}}"
  2. 可选。使用oc和端口转发将linuxptp-daemon部署中的9043端口转发到本地,测试REST API。例如,运行以下命令:

    $ oc port-forward -n openshift-ptp ds/linuxptp-daemon 9043:9043
    示例输出
    Forwarding from 127.0.0.1:9043 -> 9043
    Forwarding from [::1]:9043 -> 9043
    Handling connection for 9043

    打开一个新的shell提示符并测试REST API v2端点

    $ curl -X GET https://127.0.0.1:9043/api/ocloudNotifications/v2/health
    示例输出
    OK

监控PTP快速事件指标

您可以监控运行linuxptp-daemon的集群节点上的PTP快速事件指标。您也可以使用预配置和自更新的Prometheus监控堆栈,在OpenShift Container Platform Web控制台中监控PTP快速事件指标。

先决条件
  • 安装OpenShift Container Platform CLI oc

  • 以具有cluster-admin权限的用户身份登录。

  • 在具有PTP功能的硬件的节点上安装并配置PTP Operator。

步骤
  1. 通过运行以下命令启动节点的调试Pod:

    $ oc debug node/<node_name>
  2. 检查linuxptp-daemon容器公开的PTP指标。例如,运行以下命令:

    sh-4.4# curl https://127.0.0.1:9091/metrics
    示例输出
    # HELP cne_api_events_published Metric to get number of events published by the rest api
    # TYPE cne_api_events_published gauge
    cne_api_events_published{address="/cluster/node/compute-1.example.com/sync/gnss-status/gnss-sync-status",status="success"} 1
    cne_api_events_published{address="/cluster/node/compute-1.example.com/sync/ptp-status/lock-state",status="success"} 94
    cne_api_events_published{address="/cluster/node/compute-1.example.com/sync/ptp-status/class-change",status="success"} 18
    cne_api_events_published{address="/cluster/node/compute-1.example.com/sync/sync-status/os-clock-sync-state",status="success"} 27
  3. 可选。您也可以在cloud-event-proxy容器的日志中找到PTP事件。例如,运行以下命令:

    $ oc logs -f linuxptp-daemon-cvgr6 -n openshift-ptp -c cloud-event-proxy
  4. 要在OpenShift Container Platform Web控制台中查看PTP事件,请复制要查询的PTP指标的名称,例如openshift_ptp_offset_ns

  5. 在OpenShift Container Platform Web控制台中,单击观察指标

  6. 将PTP指标名称粘贴到表达式字段中,然后单击运行查询

其他资源

PTP快速事件指标参考

下表描述了可在运行linuxptp-daemon服务的集群节点上获取的PTP快速事件指标。

表1. PTP快速事件指标
指标 描述 示例

openshift_ptp_clock_class

返回接口的PTP时钟等级。PTP时钟等级的可能值为6 (LOCKED)、7 (PRC UNLOCKED IN-SPEC)、52 (PRC UNLOCKED OUT-OF-SPEC)、187 (PRC UNLOCKED OUT-OF-SPEC)、135 (T-BC HOLDOVER IN-SPEC)、165 (T-BC HOLDOVER OUT-OF-SPEC)、248 (DEFAULT)或255 (SLAVE ONLY CLOCK)。

{node="compute-1.example.com",process="ptp4l"} 6

openshift_ptp_clock_state

返回接口当前的PTP时钟状态。PTP时钟状态的可能值为FREERUNLOCKEDHOLDOVER

{iface="CLOCK_REALTIME", node="compute-1.example.com", process="phc2sys"} 1

openshift_ptp_delay_ns

返回主时钟发送定时分组与从时钟接收定时分组之间的延迟(纳秒)。

{from="master", iface="ens2fx", node="compute-1.example.com", process="ts2phc"} 0

openshift_ptp_ha_profile_status

当不同网卡上存在多个时间源时,返回高可用系统时钟的当前状态。可能的值为0 (INACTIVE)和1 (ACTIVE)。

{node="node1",process="phc2sys",profile="profile1"} 1 {node="node1",process="phc2sys",profile="profile2"} 0

openshift_ptp_frequency_adjustment_ns

返回两个PTP时钟之间的频率调整(纳秒)。例如,上游时钟和网卡之间、系统时钟和网卡之间,或PTP硬件时钟 (phc) 和网卡之间。

{from="phc", iface="CLOCK_REALTIME", node="compute-1.example.com", process="phc2sys"} -6768

openshift_ptp_interface_role

返回接口配置的PTP时钟角色。可能的值为0 (PASSIVE)、1 (SLAVE)、2 (MASTER)、3 (FAULTY)、4 (UNKNOWN)或5 (LISTENING)。

{iface="ens2f0", node="compute-1.example.com", process="ptp4l"} 2

openshift_ptp_max_offset_ns

返回两个时钟或接口之间的最大偏移量(纳秒)。例如,上游GNSS时钟和网卡 (ts2phc) 之间,或PTP硬件时钟 (phc) 和系统时钟 (phc2sys) 之间。

{from="master", iface="ens2fx", node="compute-1.example.com", process="ts2phc"} 1.038099569e+09

openshift_ptp_offset_ns

返回DPLL时钟或GNSS时钟源与网卡硬件时钟之间的偏移量(纳秒)。

{from="phc", iface="CLOCK_REALTIME", node="compute-1.example.com", process="phc2sys"} -9

openshift_ptp_process_restart_count

返回ptp4lts2phc进程重启的次数。

{config="ptp4l.0.config", node="compute-1.example.com",process="phc2sys"} 1

openshift_ptp_process_status

返回一个状态码,指示PTP进程是否正在运行。

{config="ptp4l.0.config", node="compute-1.example.com",process="phc2sys"} 1

openshift_ptp_threshold

返回HoldOverTimeoutMaxOffsetThresholdMinOffsetThreshold的值。

  • holdOverTimeout是PTP主时钟断开连接后PTP时钟事件状态变为FREERUN之前的时间值(秒)。

  • maxOffsetThresholdminOffsetThreshold是以纳秒为单位的偏移值,与您在NIC的PtpConfig CR中配置的CLOCK_REALTIME (phc2sys) 或主偏移量 (ptp4l) 值进行比较。

{node="compute-1.example.com", profile="grandmaster", threshold="HoldOverTimeout"} 5

仅当启用T-GM时才显示PTP快速事件指标

下表描述了仅在启用PTP主时钟 (T-GM) 时才可用的PTP快速事件指标。

表2. 启用T-GM时的PTP快速事件指标
指标 描述 示例

openshift_ptp_frequency_status

返回网卡数字锁相环 (DPLL) 频率的当前状态。可能的值为-1 (UNKNOWN)、0 (INVALID)、1 (FREERUN)、2 (LOCKED)、3 (LOCKED_HO_ACQ)或4 (HOLDOVER)。

{from="dpll",iface="ens2fx",node="compute-1.example.com",process="dpll"} 3

openshift_ptp_nmea_status

返回NMEA连接的当前状态。NMEA是用于1PPS网卡连接的协议。可能的值为0 (UNAVAILABLE)和1 (AVAILABLE)。

{iface="ens2fx",node="compute-1.example.com",process="ts2phc"} 1

openshift_ptp_phase_status

返回网卡DPLL相位的状态。可能的值为-1 (UNKNOWN)、0 (INVALID)、1 (FREERUN)、2 (LOCKED)、3 (LOCKED_HO_ACQ)或4 (HOLDOVER)。

{from="dpll",iface="ens2fx",node="compute-1.example.com",process="dpll"} 3

openshift_ptp_pps_status

返回网卡1PPS连接的当前状态。您使用1PPS连接来同步连接的网卡之间的计时。可能的值为0 (UNAVAILABLE)和1 (AVAILABLE)。

{from="dpll",iface="ens2fx",node="compute-1.example.com",process="dpll"} 1

openshift_ptp_gnss_status

返回全球导航卫星系统 (GNSS) 连接的当前状态。GNSS在全球范围内提供基于卫星的定位、导航和计时服务。可能的值为0 (NOFIX)、1 (DEAD RECKONING ONLY)、2 (2D-FIX)、3 (3D-FIX)、4 (GPS+DEAD RECKONING FIX)、5 (TIME ONLY FIX)。

{from="gnss",iface="ens2fx",node="compute-1.example.com",process="gnss"} 3