deploy: add launchctl templates for active apps
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
# macOS launchctl 本机部署模板
|
||||
|
||||
本目录用于把本机 32960/JT808/history 三个服务的启动方式仓库化。模板面向当前生产验证链路:
|
||||
本目录用于把本机生产验证服务的启动方式仓库化。模板面向当前生产验证链路:
|
||||
|
||||
- `gb32960-ingest-app`: TCP `32960`,HTTP `20100`
|
||||
- `jt808-ingest-app`: TCP `808`,HTTP `20400`
|
||||
- `yutong-mqtt-app`: HTTP `20500`
|
||||
- `vehicle-history-app`: HTTP `20200`
|
||||
- `vehicle-analytics-app`: HTTP `20300`
|
||||
|
||||
`vehicle-history-app` 的热历史查询只依赖 Kafka 与 TDengine:RAW 帧的 `parsedJson`、`metadataJson`、`rawUri` 已进入 TDengine `raw_frames`。GB32960/JT808 接入服务可以继续保留 `SINK_ARCHIVE_PATH` 作为原始 `.bin` 冷备,history 本机模板不再要求共享 archive root。
|
||||
|
||||
@@ -30,11 +32,19 @@ export VEHICLE_IDENTITY_MYSQL_JDBC_URL='jdbc:mysql://<mysql-host>:3306/vehicle_i
|
||||
export VEHICLE_IDENTITY_MYSQL_USERNAME='<mysql-user>'
|
||||
export VEHICLE_IDENTITY_MYSQL_PASSWORD='<mysql-password>'
|
||||
export VEHICLE_IDENTITY_MYSQL_REFRESH_INTERVAL='60s'
|
||||
export MYSQL_JDBC_URL="$VEHICLE_IDENTITY_MYSQL_JDBC_URL"
|
||||
export MYSQL_USERNAME="$VEHICLE_IDENTITY_MYSQL_USERNAME"
|
||||
export MYSQL_PASSWORD="$VEHICLE_IDENTITY_MYSQL_PASSWORD"
|
||||
export YUTONG_MQTT_ENABLED='false'
|
||||
export YUTONG_MQTT_URI=''
|
||||
export YUTONG_MQTT_TOPIC='#'
|
||||
export YUTONG_MQTT_USERNAME=''
|
||||
export YUTONG_MQTT_PASSWORD=''
|
||||
|
||||
mkdir -p "$HOME/Library/LaunchAgents" "$PROJECT_ROOT/data"
|
||||
mkdir -p /tmp/lingniu-gb32960-live /tmp/lingniu-jt808-live /tmp/lingniu-history-live
|
||||
mkdir -p /tmp/lingniu-gb32960-live /tmp/lingniu-jt808-live /tmp/lingniu-yutong-mqtt-live /tmp/lingniu-vehicle-history-live /tmp/lingniu-vehicle-analytics-live
|
||||
|
||||
for service in gb32960 jt808 vehicle-history; do
|
||||
for service in gb32960 jt808 yutong-mqtt vehicle-history vehicle-analytics; do
|
||||
sed \
|
||||
-e "s#__PROJECT_ROOT__#$PROJECT_ROOT#g" \
|
||||
-e "s#__JAVA_BIN__#$JAVA_BIN#g" \
|
||||
@@ -46,6 +56,14 @@ for service in gb32960 jt808 vehicle-history; do
|
||||
-e "s#__VEHICLE_IDENTITY_MYSQL_USERNAME__#$VEHICLE_IDENTITY_MYSQL_USERNAME#g" \
|
||||
-e "s#__VEHICLE_IDENTITY_MYSQL_PASSWORD__#$VEHICLE_IDENTITY_MYSQL_PASSWORD#g" \
|
||||
-e "s#__VEHICLE_IDENTITY_MYSQL_REFRESH_INTERVAL__#$VEHICLE_IDENTITY_MYSQL_REFRESH_INTERVAL#g" \
|
||||
-e "s#__MYSQL_JDBC_URL__#$MYSQL_JDBC_URL#g" \
|
||||
-e "s#__MYSQL_USERNAME__#$MYSQL_USERNAME#g" \
|
||||
-e "s#__MYSQL_PASSWORD__#$MYSQL_PASSWORD#g" \
|
||||
-e "s#__YUTONG_MQTT_ENABLED__#$YUTONG_MQTT_ENABLED#g" \
|
||||
-e "s#__YUTONG_MQTT_URI__#$YUTONG_MQTT_URI#g" \
|
||||
-e "s#__YUTONG_MQTT_TOPIC__#$YUTONG_MQTT_TOPIC#g" \
|
||||
-e "s#__YUTONG_MQTT_USERNAME__#$YUTONG_MQTT_USERNAME#g" \
|
||||
-e "s#__YUTONG_MQTT_PASSWORD__#$YUTONG_MQTT_PASSWORD#g" \
|
||||
"deploy/local/launchctl/com.lingniu.${service}.plist.template" \
|
||||
> "$HOME/Library/LaunchAgents/com.lingniu.${service}.plist"
|
||||
done
|
||||
@@ -59,6 +77,8 @@ history 消费者会按协议和 raw/event 自动拆分 consumer group。设置
|
||||
- `vehicle-history-live-gb32960-raw`
|
||||
- `vehicle-history-live-jt808-event`
|
||||
- `vehicle-history-live-jt808-raw`
|
||||
- `vehicle-history-live-yutong-mqtt-event`
|
||||
- `vehicle-history-live-yutong-mqtt-raw`
|
||||
|
||||
本地模板与 ECS 生产口径一致,身份绑定只使用 MySQL。启动前必须提供 `VEHICLE_IDENTITY_MYSQL_*` 连接参数;服务会自动创建 `vehicle_identity_binding` 和 `vehicle_identity_binding_registration` 两张表:前者只保存 `plate`、`vin`,后者保存注册字段;服务按刷新周期用注册表里的车牌关联 VIN,后续 raw/event 会带真实 VIN。
|
||||
|
||||
@@ -67,9 +87,11 @@ history 消费者会按协议和 raw/event 自动拆分 consumer group。设置
|
||||
```bash
|
||||
launchctl bootstrap "gui/$(id -u)" "$HOME/Library/LaunchAgents/com.lingniu.gb32960.plist"
|
||||
launchctl bootstrap "gui/$(id -u)" "$HOME/Library/LaunchAgents/com.lingniu.jt808.plist"
|
||||
launchctl bootstrap "gui/$(id -u)" "$HOME/Library/LaunchAgents/com.lingniu.yutong-mqtt.plist"
|
||||
launchctl bootstrap "gui/$(id -u)" "$HOME/Library/LaunchAgents/com.lingniu.vehicle-history.plist"
|
||||
launchctl bootstrap "gui/$(id -u)" "$HOME/Library/LaunchAgents/com.lingniu.vehicle-analytics.plist"
|
||||
|
||||
launchctl list | rg 'com.lingniu.(gb32960|jt808|vehicle-history)'
|
||||
launchctl list | rg 'com.lingniu.(gb32960|jt808|yutong-mqtt|vehicle-history|vehicle-analytics)'
|
||||
```
|
||||
|
||||
替换 jar 前先停止服务,避免 KeepAlive 在 jar 拷贝中途拉起半包:
|
||||
@@ -77,7 +99,9 @@ launchctl list | rg 'com.lingniu.(gb32960|jt808|vehicle-history)'
|
||||
```bash
|
||||
launchctl bootout "gui/$(id -u)" "$HOME/Library/LaunchAgents/com.lingniu.gb32960.plist" || true
|
||||
launchctl bootout "gui/$(id -u)" "$HOME/Library/LaunchAgents/com.lingniu.jt808.plist" || true
|
||||
launchctl bootout "gui/$(id -u)" "$HOME/Library/LaunchAgents/com.lingniu.yutong-mqtt.plist" || true
|
||||
launchctl bootout "gui/$(id -u)" "$HOME/Library/LaunchAgents/com.lingniu.vehicle-history.plist" || true
|
||||
launchctl bootout "gui/$(id -u)" "$HOME/Library/LaunchAgents/com.lingniu.vehicle-analytics.plist" || true
|
||||
```
|
||||
|
||||
## 验证地址
|
||||
@@ -89,13 +113,21 @@ curl -sS http://127.0.0.1:20100/actuator/health/readiness
|
||||
curl -sS http://127.0.0.1:20400/actuator/health
|
||||
curl -sS http://127.0.0.1:20400/actuator/health/liveness
|
||||
curl -sS http://127.0.0.1:20400/actuator/health/readiness
|
||||
curl -sS http://127.0.0.1:20500/actuator/health
|
||||
curl -sS http://127.0.0.1:20500/actuator/health/liveness
|
||||
curl -sS http://127.0.0.1:20500/actuator/health/readiness
|
||||
curl -sS http://127.0.0.1:20200/actuator/health
|
||||
curl -sS http://127.0.0.1:20200/actuator/health/liveness
|
||||
curl -sS http://127.0.0.1:20200/actuator/health/readiness
|
||||
curl -sS http://127.0.0.1:20300/actuator/health
|
||||
curl -sS http://127.0.0.1:20300/actuator/health/liveness
|
||||
curl -sS http://127.0.0.1:20300/actuator/health/readiness
|
||||
```
|
||||
|
||||
Swagger:
|
||||
|
||||
- GB32960 ingest: `http://127.0.0.1:20100/swagger-ui/index.html`
|
||||
- JT808 ingest: `http://127.0.0.1:20400/swagger-ui/index.html`
|
||||
- Yutong MQTT ingest: `http://127.0.0.1:20500/swagger-ui/index.html`
|
||||
- History query: `http://127.0.0.1:20200/swagger-ui/index.html`
|
||||
- Analytics metrics: `http://127.0.0.1:20300/swagger-ui/index.html`
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>com.lingniu.vehicle-analytics</string>
|
||||
<key>WorkingDirectory</key>
|
||||
<string>__PROJECT_ROOT__</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>__JAVA_BIN__</string>
|
||||
<string>-jar</string>
|
||||
<string>__PROJECT_ROOT__/modules/apps/vehicle-analytics-app/target/vehicle-analytics-app.jar</string>
|
||||
</array>
|
||||
<key>EnvironmentVariables</key>
|
||||
<dict>
|
||||
<key>HTTP_PORT</key>
|
||||
<string>20300</string>
|
||||
<key>KAFKA_ENABLED</key>
|
||||
<string>true</string>
|
||||
<key>KAFKA_CONSUMER_ENABLED</key>
|
||||
<string>true</string>
|
||||
<key>KAFKA_CONSUMER_AUTO_OFFSET_RESET</key>
|
||||
<string>latest</string>
|
||||
<key>KAFKA_CONSUMER_CLIENT_ID_PREFIX</key>
|
||||
<string>vehicle-analytics-live</string>
|
||||
<key>KAFKA_BROKERS</key>
|
||||
<string>114.55.58.251:9092</string>
|
||||
<key>KAFKA_GROUP_STAT</key>
|
||||
<string>vehicle-stat-live</string>
|
||||
<key>VEHICLE_STAT_ENABLED</key>
|
||||
<string>true</string>
|
||||
<key>VEHICLE_STAT_ZONE_ID</key>
|
||||
<string>Asia/Shanghai</string>
|
||||
<key>VEHICLE_STAT_JT808_MILEAGE_ENABLED</key>
|
||||
<string>true</string>
|
||||
<key>MYSQL_JDBC_URL</key>
|
||||
<string>__MYSQL_JDBC_URL__</string>
|
||||
<key>MYSQL_USERNAME</key>
|
||||
<string>__MYSQL_USERNAME__</string>
|
||||
<key>MYSQL_PASSWORD</key>
|
||||
<string>__MYSQL_PASSWORD__</string>
|
||||
<key>NACOS_CONFIG_ENABLED</key>
|
||||
<string>false</string>
|
||||
<key>MANAGEMENT_HEALTH_REDIS_ENABLED</key>
|
||||
<string>false</string>
|
||||
</dict>
|
||||
<key>StandardOutPath</key>
|
||||
<string>/tmp/lingniu-vehicle-analytics-live/vehicle-analytics.log</string>
|
||||
<key>StandardErrorPath</key>
|
||||
<string>/tmp/lingniu-vehicle-analytics-live/vehicle-analytics.err.log</string>
|
||||
<key>RunAtLoad</key>
|
||||
<true/>
|
||||
<key>KeepAlive</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -38,6 +38,10 @@
|
||||
<string>vehicle.event.jt808.v1</string>
|
||||
<key>KAFKA_TOPIC_JT808_RAW</key>
|
||||
<string>vehicle.raw.jt808.v1</string>
|
||||
<key>KAFKA_TOPIC_YUTONG_MQTT_EVENT</key>
|
||||
<string>vehicle.event.mqtt-yutong.v1</string>
|
||||
<key>KAFKA_TOPIC_YUTONG_MQTT_RAW</key>
|
||||
<string>vehicle.raw.mqtt-yutong.v1</string>
|
||||
<key>TDENGINE_HISTORY_ENABLED</key>
|
||||
<string>true</string>
|
||||
<key>TDENGINE_HISTORY_DATABASE</key>
|
||||
@@ -64,9 +68,9 @@
|
||||
<string>false</string>
|
||||
</dict>
|
||||
<key>StandardOutPath</key>
|
||||
<string>/tmp/lingniu-history-live/vehicle-history.log</string>
|
||||
<string>/tmp/lingniu-vehicle-history-live/vehicle-history.log</string>
|
||||
<key>StandardErrorPath</key>
|
||||
<string>/tmp/lingniu-history-live/vehicle-history.err.log</string>
|
||||
<string>/tmp/lingniu-vehicle-history-live/vehicle-history.err.log</string>
|
||||
<key>RunAtLoad</key>
|
||||
<true/>
|
||||
<key>KeepAlive</key>
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>com.lingniu.yutong-mqtt</string>
|
||||
<key>WorkingDirectory</key>
|
||||
<string>__PROJECT_ROOT__</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>__JAVA_BIN__</string>
|
||||
<string>-jar</string>
|
||||
<string>__PROJECT_ROOT__/modules/apps/yutong-mqtt-app/target/yutong-mqtt-app.jar</string>
|
||||
</array>
|
||||
<key>EnvironmentVariables</key>
|
||||
<dict>
|
||||
<key>HTTP_PORT</key>
|
||||
<string>20500</string>
|
||||
<key>YUTONG_MQTT_ENABLED</key>
|
||||
<string>__YUTONG_MQTT_ENABLED__</string>
|
||||
<key>YUTONG_MQTT_AUTO_STARTUP</key>
|
||||
<string>true</string>
|
||||
<key>YUTONG_MQTT_ENDPOINT_NAME</key>
|
||||
<string>yutong</string>
|
||||
<key>YUTONG_MQTT_URI</key>
|
||||
<string>__YUTONG_MQTT_URI__</string>
|
||||
<key>YUTONG_MQTT_TOPIC</key>
|
||||
<string>__YUTONG_MQTT_TOPIC__</string>
|
||||
<key>YUTONG_MQTT_QOS</key>
|
||||
<string>1</string>
|
||||
<key>YUTONG_MQTT_CLIENT_ID</key>
|
||||
<string>lingniu-yutong-mqtt-live</string>
|
||||
<key>YUTONG_MQTT_USERNAME</key>
|
||||
<string>__YUTONG_MQTT_USERNAME__</string>
|
||||
<key>YUTONG_MQTT_PASSWORD</key>
|
||||
<string>__YUTONG_MQTT_PASSWORD__</string>
|
||||
<key>YUTONG_MQTT_CLEAN_SESSION</key>
|
||||
<string>false</string>
|
||||
<key>KAFKA_ENABLED</key>
|
||||
<string>true</string>
|
||||
<key>KAFKA_BROKERS</key>
|
||||
<string>114.55.58.251:9092</string>
|
||||
<key>KAFKA_NODE_ID</key>
|
||||
<string>yutong-mqtt-live</string>
|
||||
<key>KAFKA_TOPIC_YUTONG_MQTT_EVENT</key>
|
||||
<string>vehicle.event.mqtt-yutong.v1</string>
|
||||
<key>KAFKA_TOPIC_YUTONG_MQTT_RAW</key>
|
||||
<string>vehicle.raw.mqtt-yutong.v1</string>
|
||||
<key>KAFKA_TOPIC_YUTONG_MQTT_DLQ</key>
|
||||
<string>vehicle.dlq.mqtt-yutong.v1</string>
|
||||
<key>SINK_ARCHIVE_PATH</key>
|
||||
<string>__SHARED_ARCHIVE_PATH__</string>
|
||||
<key>VEHICLE_IDENTITY_STORE</key>
|
||||
<string>mysql</string>
|
||||
<key>VEHICLE_IDENTITY_MYSQL_TABLE</key>
|
||||
<string>vehicle_identity_binding</string>
|
||||
<key>VEHICLE_IDENTITY_MYSQL_JDBC_URL</key>
|
||||
<string>__VEHICLE_IDENTITY_MYSQL_JDBC_URL__</string>
|
||||
<key>VEHICLE_IDENTITY_MYSQL_USERNAME</key>
|
||||
<string>__VEHICLE_IDENTITY_MYSQL_USERNAME__</string>
|
||||
<key>VEHICLE_IDENTITY_MYSQL_PASSWORD</key>
|
||||
<string>__VEHICLE_IDENTITY_MYSQL_PASSWORD__</string>
|
||||
<key>VEHICLE_IDENTITY_MYSQL_REFRESH_INTERVAL</key>
|
||||
<string>__VEHICLE_IDENTITY_MYSQL_REFRESH_INTERVAL__</string>
|
||||
<key>NACOS_CONFIG_ENABLED</key>
|
||||
<string>false</string>
|
||||
<key>MANAGEMENT_HEALTH_REDIS_ENABLED</key>
|
||||
<string>false</string>
|
||||
</dict>
|
||||
<key>StandardOutPath</key>
|
||||
<string>/tmp/lingniu-yutong-mqtt-live/launchctl-yutong-mqtt.log</string>
|
||||
<key>StandardErrorPath</key>
|
||||
<string>/tmp/lingniu-yutong-mqtt-live/launchctl-yutong-mqtt.err.log</string>
|
||||
<key>RunAtLoad</key>
|
||||
<true/>
|
||||
<key>KeepAlive</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -125,13 +125,37 @@ class PortainerComposeResourceLimitsTest {
|
||||
String readme = Files.readString(repositoryRoot()
|
||||
.resolve("deploy/local/launchctl/README.md"));
|
||||
|
||||
for (String httpPort : List.of("20100", "20400", "20200")) {
|
||||
for (String httpPort : List.of("20100", "20400", "20500", "20200", "20300")) {
|
||||
assertThat(readme)
|
||||
.contains("curl -sS http://127.0.0.1:" + httpPort + "/actuator/health/liveness")
|
||||
.contains("curl -sS http://127.0.0.1:" + httpPort + "/actuator/health/readiness");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void localLaunchctlTemplatesCoverActiveProductionApps() throws IOException {
|
||||
Path launchctl = repositoryRoot().resolve("deploy/local/launchctl");
|
||||
String readme = Files.readString(launchctl.resolve("README.md"));
|
||||
|
||||
assertThat(readme)
|
||||
.contains("gb32960 jt808 yutong-mqtt vehicle-history vehicle-analytics")
|
||||
.contains("mkdir -p /tmp/lingniu-gb32960-live /tmp/lingniu-jt808-live /tmp/lingniu-yutong-mqtt-live /tmp/lingniu-vehicle-history-live /tmp/lingniu-vehicle-analytics-live")
|
||||
.contains("launchctl bootstrap \"gui/$(id -u)\" \"$HOME/Library/LaunchAgents/com.lingniu.yutong-mqtt.plist\"")
|
||||
.contains("launchctl bootstrap \"gui/$(id -u)\" \"$HOME/Library/LaunchAgents/com.lingniu.vehicle-analytics.plist\"")
|
||||
.contains("launchctl bootout \"gui/$(id -u)\" \"$HOME/Library/LaunchAgents/com.lingniu.yutong-mqtt.plist\" || true")
|
||||
.contains("launchctl bootout \"gui/$(id -u)\" \"$HOME/Library/LaunchAgents/com.lingniu.vehicle-analytics.plist\" || true")
|
||||
.contains("launchctl list | rg 'com.lingniu.(gb32960|jt808|yutong-mqtt|vehicle-history|vehicle-analytics)'")
|
||||
.contains("Yutong MQTT ingest: `http://127.0.0.1:20500/swagger-ui/index.html`")
|
||||
.contains("Analytics metrics: `http://127.0.0.1:20300/swagger-ui/index.html`")
|
||||
.doesNotContain("三个服务");
|
||||
|
||||
assertLaunchctlTemplate(launchctl, "gb32960", "gb32960-ingest-app", "20100");
|
||||
assertLaunchctlTemplate(launchctl, "jt808", "jt808-ingest-app", "20400");
|
||||
assertLaunchctlTemplate(launchctl, "yutong-mqtt", "yutong-mqtt-app", "20500");
|
||||
assertLaunchctlTemplate(launchctl, "vehicle-history", "vehicle-history-app", "20200");
|
||||
assertLaunchctlTemplate(launchctl, "vehicle-analytics", "vehicle-analytics-app", "20300");
|
||||
}
|
||||
|
||||
@Test
|
||||
void tdengineVerificationRunbookChecksLivenessAndReadinessForManagedApps() throws IOException {
|
||||
String runbook = Files.readString(repositoryRoot()
|
||||
@@ -495,6 +519,21 @@ class PortainerComposeResourceLimitsTest {
|
||||
.doesNotContain(" start_period: 60s\n");
|
||||
}
|
||||
|
||||
private static void assertLaunchctlTemplate(Path launchctl,
|
||||
String serviceName,
|
||||
String appName,
|
||||
String httpPort) throws IOException {
|
||||
Path template = launchctl.resolve("com.lingniu." + serviceName + ".plist.template");
|
||||
assertThat(template).exists();
|
||||
assertThat(Files.readString(template))
|
||||
.contains("<string>com.lingniu." + serviceName + "</string>")
|
||||
.contains("__PROJECT_ROOT__/modules/apps/" + appName + "/target/" + appName + ".jar")
|
||||
.contains("<key>HTTP_PORT</key>\n <string>" + httpPort + "</string>")
|
||||
.contains("<key>NACOS_CONFIG_ENABLED</key>\n <string>false</string>")
|
||||
.contains("<key>MANAGEMENT_HEALTH_REDIS_ENABLED</key>\n <string>false</string>")
|
||||
.contains("/tmp/lingniu-" + serviceName + "-live/");
|
||||
}
|
||||
|
||||
private static String serviceBlock(String compose, String serviceName) {
|
||||
String marker = "\n " + serviceName + ":\n";
|
||||
int start = compose.indexOf(marker);
|
||||
|
||||
Reference in New Issue
Block a user