在开发使用裸机集群节点上的精确时间协议 (PTP) 事件的消费者应用程序时,您需要将消费者应用程序部署在单独的应用程序 Pod 中。消费者应用程序使用 PTP 事件 REST API v2 订阅 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。 |
应用程序使用生产端云事件代理 sidecar 中与 O-RAN v3 兼容的 REST API 订阅 PTP 事件。cloud-event-proxy
sidecar 容器可以访问与主应用程序容器相同的资源,而无需使用主应用程序的任何资源,并且不会产生明显的延迟。
PTP 运算符管理的 Pod 中的 linuxptp-daemon
进程作为 Kubernetes DaemonSet
运行,并管理各种 linuxptp
进程(ptp4l
、phc2sys
,以及可选的 grandmaster 时钟 ts2phc
)。linuxptp-daemon
将事件传递到 UNIX 域套接字。
PTP 插件从 UNIX 域套接字读取事件,并将其传递到 PTP 运算符管理的 Pod 中的 cloud-event-proxy
sidecar。cloud-event-proxy
将事件从 Kubernetes 基础设施低延迟地传递到云原生网络功能 (CNF)。
PTP 运营商管理的 Pod 中的cloud-event-proxy
侧车处理事件,并使用 PTP 事件 REST API v2 发布事件。
消费者应用程序向生产者cloud-event-proxy
侧车发送 API 请求以创建 PTP 事件订阅。订阅后,消费者应用程序侦听资源限定符中指定的地址,并接收和处理 PTP 事件。
要在集群中的网络接口开始使用 PTP 快速事件通知,必须在 PTP Operator PtpOperatorConfig
自定义资源 (CR) 中启用快速事件发布者,并在您创建的 PtpConfig
CR 中配置ptpClockThreshold
值。
您已安装 OpenShift Container Platform 命令行界面 (oc
)。
您已以具有cluster-admin
权限的用户身份登录。
您已安装 PTP Operator。
修改默认 PTP Operator 配置以启用 PTP 快速事件。
将以下 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
CR
$ oc apply -f ptp-operatorconfig.yaml
为启用了 PTP 的接口创建一个PtpConfig
自定义资源 (CR),并设置ptpClockThreshold
和ptp4lOpts
的所需值。以下 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 将消息打印到stdout 。linuxptp-daemon DaemonSet 解析日志并生成 Prometheus 指标。 |
3 | 指定包含配置的字符串以替换默认的/etc/ptp4l.conf 文件。要使用默认配置,请将该字段留空。 |
4 | 可选。如果不存在ptpClockThreshold 节,则使用默认值填充ptpClockThreshold 字段。该节显示了默认的ptpClockThreshold 值。ptpClockThreshold 值配置在 PTP 主时钟断开连接后触发 PTP 事件之前的时间长度。holdOverTimeout 是在 PTP 主时钟断开连接后 PTP 时钟事件状态更改为FREERUN 之前的时间值(以秒为单位)。maxOffsetThreshold 和minOffsetThreshold 设置配置以纳秒为单位的偏移值,这些值与CLOCK_REALTIME (phc2sys ) 或主偏移值 (ptp4l ) 的值进行比较。当ptp4l 或phc2sys 偏移值超出此范围时,PTP 时钟状态将设置为FREERUN 。当偏移值在此范围内时,PTP 时钟状态将设置为LOCKED 。 |
有关配置linuxptp
服务作为具有 PTP 快速事件的普通时钟的完整示例 CR,请参阅将 linuxptp 服务配置为普通时钟。
PTP 事件消费者应用程序需要以下功能
运行具有POST
处理程序的 Web 服务以接收云原生 PTP 事件 JSON 有效负载
一个createSubscription
函数,用于订阅 PTP 事件生产者
一个getCurrentState
函数,用于轮询 PTP 事件生产者的当前状态
以下 Go 代码片段说明了这些要求
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)
}
}
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 。 |
//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 一起使用的 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
部署您的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事件。
|
验证应用程序Pod中的cloud-event-consumer
容器是否正在接收精密时间协议 (PTP) 事件。
您已安装OpenShift CLI (oc
)。
您已以具有cluster-admin
权限的用户身份登录。
您已安装并配置了PTP Operator。
您已部署了一个云事件应用程序Pod和PTP事件消费者应用程序。
检查已部署的事件消费者应用程序的日志。例如,运行以下命令:
$ 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\"}]}}"
可选。使用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
您可以监控运行linuxptp-daemon
的集群节点上的PTP快速事件指标。您也可以使用预配置和自更新的Prometheus监控堆栈,在OpenShift Container Platform Web控制台中监控PTP快速事件指标。
安装OpenShift Container Platform CLI oc
。
以具有cluster-admin
权限的用户身份登录。
在具有PTP功能的硬件的节点上安装并配置PTP Operator。
通过运行以下命令启动节点的调试Pod:
$ oc debug node/<node_name>
检查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
可选。您也可以在cloud-event-proxy
容器的日志中找到PTP事件。例如,运行以下命令:
$ oc logs -f linuxptp-daemon-cvgr6 -n openshift-ptp -c cloud-event-proxy
要在OpenShift Container Platform Web控制台中查看PTP事件,请复制要查询的PTP指标的名称,例如openshift_ptp_offset_ns
。
在OpenShift Container Platform Web控制台中,单击观察 → 指标。
将PTP指标名称粘贴到表达式字段中,然后单击运行查询。
下表描述了可在运行linuxptp-daemon
服务的集群节点上获取的PTP快速事件指标。
指标 | 描述 | 示例 |
---|---|---|
|
返回接口的PTP时钟等级。PTP时钟等级的可能值为6 ( |
|
|
返回接口当前的PTP时钟状态。PTP时钟状态的可能值为 |
|
|
返回主时钟发送定时分组与从时钟接收定时分组之间的延迟(纳秒)。 |
|
|
当不同网卡上存在多个时间源时,返回高可用系统时钟的当前状态。可能的值为0 ( |
|
|
返回两个PTP时钟之间的频率调整(纳秒)。例如,上游时钟和网卡之间、系统时钟和网卡之间,或PTP硬件时钟 ( |
|
|
返回接口配置的PTP时钟角色。可能的值为0 ( |
|
|
返回两个时钟或接口之间的最大偏移量(纳秒)。例如,上游GNSS时钟和网卡 ( |
|
|
返回DPLL时钟或GNSS时钟源与网卡硬件时钟之间的偏移量(纳秒)。 |
|
|
返回 |
|
|
返回一个状态码,指示PTP进程是否正在运行。 |
|
|
返回
|
|
下表描述了仅在启用PTP主时钟 (T-GM) 时才可用的PTP快速事件指标。
指标 | 描述 | 示例 |
---|---|---|
|
返回网卡数字锁相环 (DPLL) 频率的当前状态。可能的值为-1 ( |
|
|
返回NMEA连接的当前状态。NMEA是用于1PPS网卡连接的协议。可能的值为0 ( |
|
|
返回网卡DPLL相位的状态。可能的值为-1 ( |
|
|
返回网卡1PPS连接的当前状态。您使用1PPS连接来同步连接的网卡之间的计时。可能的值为0 ( |
|
|
返回全球导航卫星系统 (GNSS) 连接的当前状态。GNSS在全球范围内提供基于卫星的定位、导航和计时服务。可能的值为0 ( |
|