diff --git a/Dockerfile b/Dockerfile
index 015fa950..79786696 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -10,6 +10,6 @@ ENV JAVA_OPTS=""
WORKDIR /app
COPY modules/apps/${APP_NAME}/target/${APP_NAME}.jar /app/app.jar
-EXPOSE 20100 20200 20300 32960
+EXPOSE 20100 20200 20300 20400 32960 10808
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar /app/app.jar"]
diff --git a/README.md b/README.md
index d4ba0b9e..9f5b84cd 100644
--- a/README.md
+++ b/README.md
@@ -58,6 +58,7 @@ lingniu-vehicle-ingest/
│ └── apps/
│ ├── command-gateway/ HTTP → 设备下行命令(808 位置/参数/属性/控制/区域删除/报警确认 + 1078 音视频控制)
│ ├── gb32960-ingest-app/ GB32960 TCP 接入 + Kafka 投递
+│ ├── jt808-ingest-app/ JT808 TCP 接入 + Kafka 投递
│ ├── vehicle-history-app/ 历史查询 + 原始归档索引消费
│ └── vehicle-analytics-app/ 车辆状态/日统计消费
├── docs/ 架构文档、模块图、实施计划
@@ -71,6 +72,7 @@ lingniu-vehicle-ingest/
mvn -v
mvn clean install -DskipTests
mvn -pl :gb32960-ingest-app -am spring-boot:run
+mvn -pl :jt808-ingest-app -am spring-boot:run
```
## 迁移说明
diff --git a/deploy/portainer/docker-compose.yml b/deploy/portainer/docker-compose.yml
index ae6fd4b1..3e71b29a 100644
--- a/deploy/portainer/docker-compose.yml
+++ b/deploy/portainer/docker-compose.yml
@@ -19,6 +19,9 @@ x-common-env: &common-env
KAFKA_TOPIC_GB32960_EVENT: ${KAFKA_TOPIC_GB32960_EVENT:-vehicle.event.gb32960.v1}
KAFKA_TOPIC_GB32960_RAW: ${KAFKA_TOPIC_GB32960_RAW:-vehicle.raw.gb32960.v1}
KAFKA_TOPIC_GB32960_DLQ: ${KAFKA_TOPIC_GB32960_DLQ:-vehicle.dlq.gb32960.v1}
+ KAFKA_TOPIC_JT808_EVENT: ${KAFKA_TOPIC_JT808_EVENT:-vehicle.event.jt808.v1}
+ KAFKA_TOPIC_JT808_RAW: ${KAFKA_TOPIC_JT808_RAW:-vehicle.raw.jt808.v1}
+ KAFKA_TOPIC_JT808_DLQ: ${KAFKA_TOPIC_JT808_DLQ:-vehicle.dlq.jt808.v1}
services:
gb32960-ingest-app:
@@ -45,12 +48,32 @@ services:
networks:
- vehicle-ingest
+ jt808-ingest-app:
+ image: crpi-85r4m0ackrm3qpje-vpc.cn-shanghai.personal.cr.aliyuncs.com/oneos/jt808-ingest-app:${LINGNIU_IMAGE_VERSION:?set LINGNIU_IMAGE_VERSION}
+ container_name: jt808-ingest-app
+ restart: unless-stopped
+ environment:
+ <<: *common-env
+ HTTP_PORT: 20400
+ JT808_PORT: 10808
+ KAFKA_CONSUMER_ENABLED: "false"
+ KAFKA_NODE_ID: ${KAFKA_NODE_ID_JT808:-jt808-ingest-portainer}
+ VEHICLE_IDENTITY_FILE: /data/vehicle-identity.jsonl
+ ports:
+ - "${JT808_HTTP_PORT:-20400}:20400"
+ - "${JT808_TCP_PORT:-10808}:10808"
+ volumes:
+ - jt808-ingest-data:/data
+ networks:
+ - vehicle-ingest
+
vehicle-history-app:
image: crpi-85r4m0ackrm3qpje-vpc.cn-shanghai.personal.cr.aliyuncs.com/oneos/vehicle-history-app:${LINGNIU_IMAGE_VERSION:?set LINGNIU_IMAGE_VERSION}
container_name: vehicle-history-app
restart: unless-stopped
depends_on:
- gb32960-ingest-app
+ - jt808-ingest-app
environment:
<<: *common-env
HTTP_PORT: 20200
@@ -75,6 +98,7 @@ services:
restart: unless-stopped
depends_on:
- gb32960-ingest-app
+ - jt808-ingest-app
environment:
<<: *common-env
HTTP_PORT: 20300
@@ -98,6 +122,7 @@ networks:
volumes:
gb32960-ingest-data:
+ jt808-ingest-data:
vehicle-history-archive:
vehicle-history-event-store:
vehicle-analytics-stat:
diff --git a/modules/apps/gb32960-ingest-app/pom.xml b/modules/apps/gb32960-ingest-app/pom.xml
index 2409f6fd..49bf5972 100644
--- a/modules/apps/gb32960-ingest-app/pom.xml
+++ b/modules/apps/gb32960-ingest-app/pom.xml
@@ -41,6 +41,10 @@
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-config
+
+ org.springdoc
+ springdoc-openapi-starter-webmvc-ui
+
org.springframework.boot
spring-boot-starter-test
diff --git a/modules/apps/gb32960-ingest-app/src/main/resources/application.yml b/modules/apps/gb32960-ingest-app/src/main/resources/application.yml
index a30fc25c..92f1591e 100644
--- a/modules/apps/gb32960-ingest-app/src/main/resources/application.yml
+++ b/modules/apps/gb32960-ingest-app/src/main/resources/application.yml
@@ -21,6 +21,12 @@ spring:
server:
port: ${HTTP_PORT:20100}
+springdoc:
+ swagger-ui:
+ path: /swagger-ui.html
+ api-docs:
+ path: /v3/api-docs
+
lingniu:
ingest:
gb32960:
diff --git a/modules/apps/jt808-ingest-app/pom.xml b/modules/apps/jt808-ingest-app/pom.xml
new file mode 100644
index 00000000..c15e4b92
--- /dev/null
+++ b/modules/apps/jt808-ingest-app/pom.xml
@@ -0,0 +1,79 @@
+
+
+ 4.0.0
+
+ com.lingniu.ingest
+ lingniu-vehicle-ingest
+ 0.1.0-SNAPSHOT
+ ../../../pom.xml
+
+
+ jt808-ingest-app
+ jt808-ingest-app
+ JT808 protocol ingress runtime: TCP decode, identity mapping, Kafka production, and downlink session routing.
+
+
+
+ com.lingniu.ingest
+ ingest-core
+
+
+ com.lingniu.ingest
+ session-core
+
+
+ com.lingniu.ingest
+ observability
+
+
+ com.lingniu.ingest
+ vehicle-identity
+
+
+ com.lingniu.ingest
+ protocol-jt808
+
+
+ com.lingniu.ingest
+ sink-mq
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ com.alibaba.cloud
+ spring-cloud-starter-alibaba-nacos-config
+
+
+ org.springdoc
+ springdoc-openapi-starter-webmvc-ui
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+
+ jt808-ingest-app
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+ --sun-misc-unsafe-memory-access=allow
+
+
+
+
+ repackage
+ build-info
+
+
+
+
+
+
+
diff --git a/modules/apps/jt808-ingest-app/src/main/java/com/lingniu/ingest/jt808app/Jt808IngestApplication.java b/modules/apps/jt808-ingest-app/src/main/java/com/lingniu/ingest/jt808app/Jt808IngestApplication.java
new file mode 100644
index 00000000..989826ee
--- /dev/null
+++ b/modules/apps/jt808-ingest-app/src/main/java/com/lingniu/ingest/jt808app/Jt808IngestApplication.java
@@ -0,0 +1,21 @@
+package com.lingniu.ingest.jt808app;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication(scanBasePackages = "com.lingniu.ingest")
+public class Jt808IngestApplication {
+
+ private static final Logger log = LoggerFactory.getLogger(Jt808IngestApplication.class);
+
+ public static void main(String[] args) {
+ try {
+ SpringApplication.run(Jt808IngestApplication.class, args);
+ } catch (Throwable t) {
+ log.error("JT808 ingest application failed to start, forcing JVM exit", t);
+ System.exit(1);
+ }
+ }
+}
diff --git a/modules/apps/jt808-ingest-app/src/main/resources/application.yml b/modules/apps/jt808-ingest-app/src/main/resources/application.yml
new file mode 100644
index 00000000..63660f81
--- /dev/null
+++ b/modules/apps/jt808-ingest-app/src/main/resources/application.yml
@@ -0,0 +1,99 @@
+spring:
+ application:
+ name: jt808-ingest-app
+ config:
+ import:
+ - optional:nacos:${spring.application.name}.${NACOS_CONFIG_FILE_EXTENSION:yml}?group=${NACOS_GROUP:DEFAULT_GROUP}&refreshEnabled=${NACOS_REFRESH_ENABLED:true}
+ cloud:
+ nacos:
+ config:
+ enabled: ${NACOS_CONFIG_ENABLED:true}
+ server-addr: ${NACOS_SERVER_ADDR:127.0.0.1:8848}
+ namespace: ${NACOS_NAMESPACE:}
+ group: ${NACOS_GROUP:DEFAULT_GROUP}
+ file-extension: ${NACOS_CONFIG_FILE_EXTENSION:yml}
+ username: ${NACOS_USERNAME:}
+ password: ${NACOS_PASSWORD:}
+ threads:
+ virtual:
+ enabled: true
+
+server:
+ port: ${HTTP_PORT:20400}
+
+springdoc:
+ swagger-ui:
+ path: /swagger-ui.html
+ api-docs:
+ path: /v3/api-docs
+
+lingniu:
+ ingest:
+ jt808:
+ enabled: true
+ port: ${JT808_PORT:10808}
+ worker-threads: ${JT808_WORKER_THREADS:0}
+ pipeline:
+ disruptor:
+ ring-buffer-size: ${PIPELINE_RING_BUFFER_SIZE:131072}
+ wait-strategy: ${PIPELINE_WAIT_STRATEGY:yielding}
+ producer-type: multi
+ dedup:
+ enabled: true
+ cache-size: 200000
+ ttl-seconds: 600
+ rate-limit:
+ per-vin-qps: 50
+ session:
+ store: ${SESSION_STORE:memory}
+ ttl: ${SESSION_TTL:30m}
+ identity:
+ store: ${VEHICLE_IDENTITY_STORE:file}
+ file:
+ path: ${VEHICLE_IDENTITY_FILE:./data/vehicle-identity.jsonl}
+ sink:
+ mq:
+ enabled: ${KAFKA_ENABLED:true}
+ type: kafka
+ bootstrap-servers: ${KAFKA_BROKERS:114.55.58.251:9092}
+ compression-type: zstd
+ linger-ms: 20
+ batch-size: 65536
+ acks: all
+ enable-idempotence: true
+ node-id: ${KAFKA_NODE_ID:jt808-ingest-local}
+ topics:
+ realtime: ${KAFKA_TOPIC_JT808_EVENT:vehicle.event.jt808.v1}
+ location: ${KAFKA_TOPIC_JT808_EVENT:vehicle.event.jt808.v1}
+ alarm: ${KAFKA_TOPIC_JT808_EVENT:vehicle.event.jt808.v1}
+ session: ${KAFKA_TOPIC_JT808_EVENT:vehicle.event.jt808.v1}
+ media-meta: ${KAFKA_TOPIC_MEDIA_META:vehicle.media.meta.v1}
+ raw-archive: ${KAFKA_TOPIC_JT808_RAW:vehicle.raw.jt808.v1}
+ dlq: ${KAFKA_TOPIC_JT808_DLQ:vehicle.dlq.jt808.v1}
+ consumer:
+ enabled: false
+ event-file-store:
+ enabled: false
+ event-history:
+ enabled: false
+ vehicle-state:
+ enabled: false
+ vehicle-stat:
+ enabled: false
+
+management:
+ endpoints:
+ web:
+ exposure:
+ include: health,info,metrics,prometheus,env
+ health:
+ redis:
+ enabled: ${MANAGEMENT_HEALTH_REDIS_ENABLED:false}
+ metrics:
+ tags:
+ application: jt808-ingest-app
+
+logging:
+ level:
+ root: INFO
+ com.lingniu.ingest: INFO
diff --git a/modules/apps/jt808-ingest-app/src/test/java/com/lingniu/ingest/jt808app/Jt808IngestAppCompositionTest.java b/modules/apps/jt808-ingest-app/src/test/java/com/lingniu/ingest/jt808app/Jt808IngestAppCompositionTest.java
new file mode 100644
index 00000000..8e384b50
--- /dev/null
+++ b/modules/apps/jt808-ingest-app/src/test/java/com/lingniu/ingest/jt808app/Jt808IngestAppCompositionTest.java
@@ -0,0 +1,69 @@
+package com.lingniu.ingest.jt808app;
+
+import com.lingniu.ingest.core.config.IngestCoreAutoConfiguration;
+import com.lingniu.ingest.identity.config.VehicleIdentityAutoConfiguration;
+import com.lingniu.ingest.protocol.jt808.codec.Jt808MessageDecoder;
+import com.lingniu.ingest.protocol.jt808.config.Jt808AutoConfiguration;
+import com.lingniu.ingest.protocol.jt808.inbound.Jt808NettyServer;
+import com.lingniu.ingest.session.config.SessionCoreAutoConfiguration;
+import com.lingniu.ingest.sink.mq.KafkaEnvelopeDeadLetterSink;
+import com.lingniu.ingest.sink.mq.KafkaEventSink;
+import com.lingniu.ingest.sink.mq.SinkMqAutoConfiguration;
+import org.apache.kafka.clients.producer.KafkaProducer;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.autoconfigure.AutoConfigurations;
+import org.springframework.boot.test.context.runner.ApplicationContextRunner;
+import org.springframework.context.ApplicationContext;
+import org.springframework.util.ClassUtils;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+
+class Jt808IngestAppCompositionTest {
+
+ private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
+ .withConfiguration(AutoConfigurations.of(
+ IngestCoreAutoConfiguration.class,
+ SessionCoreAutoConfiguration.class,
+ VehicleIdentityAutoConfiguration.class,
+ SinkMqAutoConfiguration.class,
+ Jt808AutoConfiguration.class))
+ .withAllowBeanDefinitionOverriding(true)
+ .withBean("kafkaProducer", KafkaProducer.class, Jt808IngestAppCompositionTest::kafkaProducer)
+ .withPropertyValues(
+ "lingniu.ingest.jt808.enabled=true",
+ "lingniu.ingest.jt808.port=0",
+ "lingniu.ingest.session.store=memory",
+ "lingniu.ingest.sink.mq.enabled=true",
+ "lingniu.ingest.sink.mq.type=kafka",
+ "lingniu.ingest.sink.mq.bootstrap-servers=localhost:9092",
+ "lingniu.ingest.sink.mq.consumer.enabled=false",
+ "lingniu.ingest.event-file-store.enabled=false",
+ "lingniu.ingest.event-history.enabled=false",
+ "lingniu.ingest.vehicle-state.enabled=false",
+ "lingniu.ingest.vehicle-stat.enabled=false");
+
+ @Test
+ void createsJt808ListenerWithoutHistoryStorageBoundaries() {
+ contextRunner.run(context -> {
+ assertThat(context).hasSingleBean(Jt808MessageDecoder.class);
+ assertThat(context).hasSingleBean(Jt808NettyServer.class);
+ assertThat(context).hasSingleBean(KafkaEventSink.class);
+ assertThat(context).hasSingleBean(KafkaEnvelopeDeadLetterSink.class);
+
+ assertTypeNotPresent(context, "com.lingniu.ingest.sink.archive.ArchiveStore");
+ assertTypeNotPresent(context, "com.lingniu.ingest.eventfilestore.EventFileStore");
+ });
+ }
+
+ @SuppressWarnings("unchecked")
+ private static KafkaProducer kafkaProducer() {
+ return mock(KafkaProducer.class);
+ }
+
+ private static void assertTypeNotPresent(ApplicationContext context, String className) {
+ assertThat(ClassUtils.isPresent(className, context.getClassLoader()))
+ .as("%s must stay outside the JT808 ingest runtime", className)
+ .isFalse();
+ }
+}
diff --git a/modules/apps/jt808-ingest-app/src/test/java/com/lingniu/ingest/jt808app/Jt808IngestAppDefaultsTest.java b/modules/apps/jt808-ingest-app/src/test/java/com/lingniu/ingest/jt808app/Jt808IngestAppDefaultsTest.java
new file mode 100644
index 00000000..5679a261
--- /dev/null
+++ b/modules/apps/jt808-ingest-app/src/test/java/com/lingniu/ingest/jt808app/Jt808IngestAppDefaultsTest.java
@@ -0,0 +1,46 @@
+package com.lingniu.ingest.jt808app;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
+import org.springframework.core.io.ClassPathResource;
+
+import java.util.Properties;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class Jt808IngestAppDefaultsTest {
+
+ @Test
+ void applicationDefaultsKeepJt808IngestAsTcpKafkaProducerOnly() {
+ Properties properties = applicationProperties();
+
+ assertThat(properties)
+ .containsEntry("spring.application.name", "jt808-ingest-app")
+ .containsEntry(
+ "spring.config.import[0]",
+ "optional:nacos:${spring.application.name}.${NACOS_CONFIG_FILE_EXTENSION:yml}?group=${NACOS_GROUP:DEFAULT_GROUP}&refreshEnabled=${NACOS_REFRESH_ENABLED:true}")
+ .containsEntry("spring.cloud.nacos.config.server-addr", "${NACOS_SERVER_ADDR:127.0.0.1:8848}")
+ .containsEntry("server.port", "${HTTP_PORT:20400}")
+ .containsEntry("lingniu.ingest.jt808.enabled", true)
+ .containsEntry("lingniu.ingest.jt808.port", "${JT808_PORT:10808}")
+ .containsEntry("lingniu.ingest.sink.mq.enabled", "${KAFKA_ENABLED:true}")
+ .containsEntry("lingniu.ingest.sink.mq.consumer.enabled", false)
+ .containsEntry("lingniu.ingest.sink.mq.topics.realtime", "${KAFKA_TOPIC_JT808_EVENT:vehicle.event.jt808.v1}")
+ .containsEntry("lingniu.ingest.sink.mq.topics.raw-archive", "${KAFKA_TOPIC_JT808_RAW:vehicle.raw.jt808.v1}")
+ .containsEntry("lingniu.ingest.sink.mq.topics.dlq", "${KAFKA_TOPIC_JT808_DLQ:vehicle.dlq.jt808.v1}")
+ .containsEntry("lingniu.ingest.event-file-store.enabled", false)
+ .containsEntry("lingniu.ingest.event-history.enabled", false)
+ .containsEntry("lingniu.ingest.vehicle-state.enabled", false)
+ .containsEntry("lingniu.ingest.vehicle-stat.enabled", false);
+ }
+
+ private static Properties applicationProperties() {
+ YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
+ factory.setResources(new ClassPathResource("application.yml"));
+
+ Properties properties = factory.getObject();
+
+ assertThat(properties).isNotNull();
+ return properties;
+ }
+}
diff --git a/modules/apps/vehicle-analytics-app/pom.xml b/modules/apps/vehicle-analytics-app/pom.xml
index d904e775..c5414f46 100644
--- a/modules/apps/vehicle-analytics-app/pom.xml
+++ b/modules/apps/vehicle-analytics-app/pom.xml
@@ -41,6 +41,10 @@
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-config
+
+ org.springdoc
+ springdoc-openapi-starter-webmvc-ui
+
org.springframework.boot
spring-boot-starter-test
diff --git a/modules/apps/vehicle-analytics-app/src/main/resources/application.yml b/modules/apps/vehicle-analytics-app/src/main/resources/application.yml
index 9435221f..e1ad81e4 100644
--- a/modules/apps/vehicle-analytics-app/src/main/resources/application.yml
+++ b/modules/apps/vehicle-analytics-app/src/main/resources/application.yml
@@ -21,6 +21,12 @@ spring:
server:
port: ${HTTP_PORT:20300}
+springdoc:
+ swagger-ui:
+ path: /swagger-ui.html
+ api-docs:
+ path: /v3/api-docs
+
lingniu:
ingest:
gb32960:
diff --git a/modules/apps/vehicle-history-app/pom.xml b/modules/apps/vehicle-history-app/pom.xml
index c31f0509..2316864c 100644
--- a/modules/apps/vehicle-history-app/pom.xml
+++ b/modules/apps/vehicle-history-app/pom.xml
@@ -49,6 +49,10 @@
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-config
+
+ org.springdoc
+ springdoc-openapi-starter-webmvc-ui
+
org.springframework.boot
spring-boot-starter-test
diff --git a/modules/apps/vehicle-history-app/src/main/resources/application.yml b/modules/apps/vehicle-history-app/src/main/resources/application.yml
index 2f8d38e5..41312393 100644
--- a/modules/apps/vehicle-history-app/src/main/resources/application.yml
+++ b/modules/apps/vehicle-history-app/src/main/resources/application.yml
@@ -21,6 +21,12 @@ spring:
server:
port: ${HTTP_PORT:20200}
+springdoc:
+ swagger-ui:
+ path: /swagger-ui.html
+ api-docs:
+ path: /v3/api-docs
+
lingniu:
ingest:
gb32960:
diff --git a/pom.xml b/pom.xml
index 6985812f..d6f6d776 100644
--- a/pom.xml
+++ b/pom.xml
@@ -37,6 +37,7 @@
modules/inbound/inbound-xinda-push
modules/apps/command-gateway
modules/apps/gb32960-ingest-app
+ modules/apps/jt808-ingest-app
modules/apps/vehicle-history-app
modules/apps/vehicle-analytics-app
@@ -237,6 +238,11 @@
gb32960-ingest-app
${project.version}
+
+ com.lingniu.ingest
+ jt808-ingest-app
+ ${project.version}
+
com.lingniu.ingest
vehicle-history-app
diff --git a/woodpecker.yml b/woodpecker.yml
index 812ab27c..05d87d68 100644
--- a/woodpecker.yml
+++ b/woodpecker.yml
@@ -13,7 +13,7 @@ steps:
commands: |
cd $CI_WORKSPACE
- mvn -B -ntp -am -pl :gb32960-ingest-app,:vehicle-history-app,:vehicle-analytics-app package -DskipTests
+ mvn -B -ntp -am -pl :gb32960-ingest-app,:jt808-ingest-app,:vehicle-history-app,:vehicle-analytics-app package -DskipTests
BRANCH_NAME=$(echo ${CI_COMMIT_BRANCH:-local} | tr / -)
PROJECT_VERSION=$(mvn -q -DforceStdout help:evaluate -Dexpression=project.version)
@@ -60,6 +60,42 @@ steps:
docker push $IMAGE
+ - name: docker-build-jt808-ingest-app
+ image: docker:24.0.5-cli
+ when:
+ event:
+ - push
+ - pull_request
+ - manual
+ branch:
+ - master
+ - develop
+ - main
+ volumes:
+ - /var/run/docker.sock:/var/run/docker.sock
+ environment:
+ ALIYUN_ACR_USERNAME:
+ from_secret: aliyun_acr_username
+ ALIYUN_ACR_PASSWORD:
+ from_secret: aliyun_acr_password
+ commands: |
+ cd $CI_WORKSPACE
+ APP_NAME=jt808-ingest-app
+ APP_VERSION=$(cat $CI_WORKSPACE/project_version.txt)
+ IMAGE=crpi-85r4m0ackrm3qpje.cn-shanghai.personal.cr.aliyuncs.com/oneos/$APP_NAME:$APP_VERSION
+
+ docker build \
+ --build-arg APP_NAME=$APP_NAME \
+ --build-arg APP_VERSION=$APP_VERSION \
+ -t $IMAGE .
+
+ printf '%s' "$ALIYUN_ACR_PASSWORD" | docker login \
+ --username "$ALIYUN_ACR_USERNAME" \
+ --password-stdin \
+ crpi-85r4m0ackrm3qpje.cn-shanghai.personal.cr.aliyuncs.com
+
+ docker push $IMAGE
+
- name: docker-build-vehicle-history-app
image: docker:24.0.5-cli
when: