
# 在容器中部署数据建模引擎运行SDK
容器是操作系统内核自带能力，是基于Linux内核实现的轻量级高性能资源隔离机制，可以帮助应用程序快速、可靠、一致地部署，不受部署环境的影响。
本文指导您将工业数字模型驱动引擎（Industrial Digital Model Engine，简称iDME）的数据建模引擎运行SDK部署到容器中。您不需要改动任何代码和架构，仅需将整体数据建模引擎运行SDK构建为镜像，即可部署到容器中。
 #### 准备事项
- 创建一个配置文件，添加对应资源的配置信息。例如"application.properties"。如果配置项的值包含中文，请先使用工具将其转换为**Unicode** 编码。
  如下内容以[数据建模引擎运行SDK通用配置](https://support.huaweicloud.com/sdkreference-idme/idme_sdkreference_0012.html)和部分[数据建模引擎运行SDK自定义配置](https://support.huaweicloud.com/sdkreference-idme/idme_sdkreference_0013.html)为例。
  以**Postgresql** 数据库为基础的**本地服务单点登录** 为例，以下为对应的环境变量配置示例：
  ```
  ## 数据库配置
  # 数据库IP地址
  RDS_IP=127.0.0.1
  # 数据库使用端口
  RDS_PORT=5432
  # 数据库账号
  RDS_NAME=root
  # 数据库密码
  RDS_PASSWORD=123456
  # 数据库名
  RDS_DATABASE=sdk17
  # 使用的数据库类型
  RDS_TYPE=postgresql
  # 数据库连接url
  spring.datasource.url=jdbc:postgresql://${RDS_IP}:${RDS_PORT}/${RDS_DATABASE}?stringtype=unspecified
  # 数据库使用的连接驱动
  spring.datasource.driverClassName=org.postgresql.Driver
  # 数据建模引擎初始化环境使用的数据库类型
  xdm.runtime.db-type=postgresql
  # 数据建模引擎初始化模型使用的数据库方言
  xdm.runtime.hibernate.dialect=com.huawei.it.rdm.configuration.XdmPostgresqlDialect
  ## SSF单点登录
  # 单点登录使用的数据库类型
  SSF_RDS_TYPE=postgresql
  # 单点登录使用的数据库连接驱动
  SSF_DRIVER=org.postgresql.Driver
  # 单点登录的数据库连接信息
  spring.datasource.ssf.url=jdbc:postgresql://${RDS_IP}:${RDS_PORT}/${RDS_DATABASE}_ssf
  ## Redis配置
  # Redis数据库单点模式下的IP地址
  REDIS_HOST=127.0.0.1
  # Redis数据库集群模式下的IP地址
  # REDIS_CLUSTER_NODES=127.0.0.1:6379,127.0.0.1:6380
  # Redis数据库使用的端口
  REDIS_PORT=6379
  # Redis数据库密码
  REDIS_PASSWORD=root
  # Redis数据库的服务类型；SINGLE：单点模型，CLUSTER：集群模式
  REDIS_TYPE=SINGLE
  ## 公共信息配置
  # 数据建模引擎模型初始化配置，开启后会根据jar包中的模型信息更新数据
  xdm.runtime.init=true
  # 部署版本，建议和应用发布版本保持一致；同一个版本重复部署不会更新模型信息
  DEPLOY_VERSION=2.25.070.01
  # 当前部署应用ID
  TENANT_ID=da1f9c962b264627840dd50ae9b2e1fe
  # 当前部署应用名称
  APP_NAME=XDMLocal
  # 当前部署应用的唯一标识，一般为应用ID
  APP_IDENTIFIER=da1f9c962b264627840dd50ae9b2e1fe
  # 当前部署应用英文名称小写
  PAAS_APP_NAME=xdmlocal
  # 是否注册delegator代理器相关的bean
  xdm.delegate.bean.inject=false
  # 服务访问的上下文路径，格式需按照：/rdm_xxx_app/services/ 进行设置，xxx建议使用应用ID
  server.servlet.context-path=/rdm_da1f9c962b264627840dd50ae9b2e1fe_app/services/
  # 服务设置的端口
  server.port=8003
  # 全量数据服务API地址（访问详情接口必选配置），格式：http://{部署服务器的IP地址}{服务端口}
  APIG_DEFAULT_GROUP_HOST=http://127.0.0.1:8003
  # IAM Token 校验开关（true：开启，false：关闭，默认为false）
  OPEN_IAM_TOKEN_VALIDATION=false
  # 应用信息，当前配置使用环境变量进行填充；按需可以在设计态获取进行手动填充
  xdm.runtime.tenant.info={"id":"${TENANT_ID}","creator":"test1 3c03e719256a427eb9277b64fc83fb40","createTime":"2022-07-19T12:02:45.000+0000","modifier":"test1 3c03e719256a427eb9277b64fc83fb40","lastModifiedTime":"2022-07-19T12:02:45.000+0000","markForDelete":false,"name":"${APP_NAME}","nameEn":"${APP_NAME}","description":"${APP_NAME}","descriptionEn":"","owner":"lundefined","shortName":"${APP_NAME}","codeRepository":"","dbConn":null,"dbReadOnlyConn":null,"hisDeployUnit":null,"databaseType":"postgresql","aliasName":"${APP_NAME}","hisAppId":"","tps":1000,"qps":1000,"operationTime":null,"appNameEn":"${APP_NAME}","certifiedDataSourceName":null,"certifiedDataSourceNumber":null,"integrationMode":"API","domain":null,"appEnvInfo":"dev","metadataSynchronization":false,"codeDownloadPath":"","jarDownloadPath":"","appStatus":1,"domainId":"ac15e3fa2b1d499788d2538044961bd0","domainName":null,"identifier":"${APP_NAME}","deployedStatus":true,"damintegrated":false,"xdmhosted":false,"classname":"com.huawei.it.rdm.tenantmgmt.bean.Application"}
  # 应用运行态标识，格式为：rdm_{应用英文名称小写}_app
  xdm.application.sub-app-id=rdm_xdmlocal_app
  # 事务协调器开关，此项配置依赖xdm-tx-distributor.jar包的独立部署
  xdm.tx-distributor.enable=true
  # scc组件路径，需要置空
  devspore.security.provider.scc.tools-dir=
  ## SDK许可证配置
  # 是否为SDK部署标识，用于开放SDK的特有接口
  XDM_SDK_DEPLOY_ENABLE=true
  # license管理开关，开启后可以在web页面中管理license
  xdm.runtime.license-control.enable=true
  # SDK包部署方式，目前只支持主机(MACHINE)和容器(CONTAINER)部署
  xdm.license.deploy-type=MACHINE
  # license的校验方式
  xdm.license.runtime.valid-type=LICENSE
  # 许可证的初始化方式
  xdm.license.init-type=SYSTEM_PATH
  # license文件所在的位置
  xdm.license.licenseFile=/opt/cloud/license.dat
  # license解析所需密钥，申请license时获取
  xdm.license.public-key=iDME SDK:1:5:A9D150C6F***
  ## 服务编排配置
  # 服务编排全局开关
  #CUSTOM_SERVICE_GLOBAL_SWITCH=true
  ## 服务编排管理开关
  #CUSTOM_SERVICE_MANAGEABLE=true
  ## 服务编排是否可编辑开关
  #CUSTOM_SERVICE_MODIFIABLE=true
  ## 服务编排是否可执行开关
  #CUSTOM_SERVICE_EXECUTABLE=true
  ## 是否开启java服务编排
  #OPEN_JAVA_CUSTOM_SERVICE=true
  ## java服务编排的编译路径
  #xdm.runtime.java-compile.lib-path=/opt/cloud/java-compile
  ## MongoDB配置
  # 是否开启MongoDB
  # xdm.mongodb.init=true
  ## MongoDB的链接地址
  #MONGODB_URI=mongodb://rwuser:root@127.0.0.1:8635/test?authSource=admin
  ## 使用的MongoDB数据库名
  #MONGODB_DATABASE=test
  ## Elasticsearch配置
  ## Elasticsearch的IP端口信息
  #ES_URL=192.168.0.54:9200
  ## Elasticsearch的用户名
  #ES_USERNAME=admin
  ## Elasticsearch的密码
  #ES_PASSWORD=admin
  ## Elasticsearch的类型
  #ES_SCHEMA=http
  ## Kafka配置
  ## 是否开启Kafka
  #xdm.kafka.init=true
  ## Kafka的连接地址
  #KAFKA_BOOTSTRAP_SERVERS=127.0.0.1:9094
  ## 文件服务配置，在OBS配置和S3配置中进行选择
  ## #
  ## OBS服务配置
  ## OBS服务所在的地址
  #OBS_END_POINT=https://obs.cn-north-4.myhuaweicloud.com
  ## OBS服务使用的桶名
  #BUCKET_NAME=test
  ## 访问OBS使用的AK密钥
  #RES_AK=res_ak1
  ## 访问OBS服务使用的SK密钥
  #RES_SK=res_ak1
  ## #
  ## S3配置
  ## 对象存储服务的类型
  #xdm.objectstorage.type=S3
  ## S3服务所在地址
  #xdm.objectstorage.s3.host=127.0.0.1:9000
  ## S3服务使用的桶名
  #BUCKET_NAME=test
  ## S3服务的账号
  #xdm.objectstorage.s3.ak=admin
  ## S3服务的密码
  #xdm.objectstorage.s3.sk=123456
  ###
  ## 部分特性配置
  ## 二级缓存功能开关
  #OPEN_SECOND_LEVEL_CACHE=false
  ## 三级缓存开关
  #THIRD_LEVEL_REDIS_CLOSED=false
  ## 设置是否开启多数据源功能
  #DYNAMIC_DATASOURCE_ENABLED=false
  ## WSF组件配置
  ## 数据建模引擎全局配置开关开关
  #dme.wsf.enable=true
  ## WSF组件开关
  #devspore.security.wsf.enable=true
  ## WSF参数校验器开关
  #dme.wsf.param.check.enable=true
  ## WSF自定义参数校验配置文件，指向目录，目录下需要有validate文件夹
  #dme.wsf.param.config.path=/opt/cloud
  ## WSF文件上传校验开关
  #dme.wsf.multipart.check.enable=true
  ## WSF自定义文件上传配置
  #dme.wsf.upload.config.path=/opt/cloud/CustomUploadFileConfig.properties
  ## WSF csrf校验开关
  #dme.wsf.csrf.check.enable=true
  ## 日志配置
  ## WSF框架日志等级
  #WSF_LOG_LEVEL=INFO
  ## SSF框架日志等级
  #SSF_LOG_LEVEL=INFO
  ```
  如果当前使用的是**MySQL**数据库，则需要在PostgreSQL环境变量的基础上进行以下配置调整：
  ```
  # # 数据库配置
  # 数据库IP地址
  RDS_IP=127.0.0.1
  # 数据库使用端口
  RDS_PORT=3306
  # 数据库账号
  RDS_NAME=root
  # 数据库密码
  RDS_PASSWORD=123456
  # 数据库名
  RDS_DATABASE=sdk17
  # 使用的数据库类型
  RDS_TYPE=mysql
  # 数据库连接url
  spring.datasource.url=jdbc:mariadb://${RDS_IP}:${RDS_PORT}/${RDS_DATABASE}
  # 数据库使用的连接驱动
  spring.datasource.driverClassName=org.mariadb.jdbc.Driver
  # 数据建模引擎初始化环境使用的数据库类型
  xdm.runtime.db-type=mysql
  # 数据建模引擎初始化模型使用的数据库方言
  xdm.runtime.hibernate.dialect=com.huawei.it.rdm.configuration.XdmMySqlDialect
  # # SSF单点登录
  # 单点登录使用的数据库类型
  SSF_RDS_TYPE=mysql
  # 单点登录使用的数据库连接驱动
  SSF_DRIVER=org.mariadb.jdbc.Driver
  # 单点登录的数据库连接信息
  # ${RDS_DATABASE}_ssf数据库，需要手动执行"set global log_bin_trust_function_creators=true;"，避免登录服务初始化失败
  spring.datasource.ssf.url=jdbc:mariadb://${RDS_IP}:${RDS_PORT}/${RDS_DATABASE}_ssf
  ```
  如果当前使用的是GaussDB数据库，则需要在PostgreSQL环境变量的基础上进行以下配置调整：
  ```
  ## 数据库配置
  # 数据库IP地址
  RDS_IP=127.0.0.1
  # 数据库使用端口
  RDS_PORT=8000
  # 数据库账号
  RDS_NAME=root
  # 数据库密码
  RDS_PASSWORD=123456
  # 数据库名
  RDS_DATABASE=sdk17
  # 使用的数据库类型
  RDS_TYPE=gaussdb
  # 数据库连接url
  spring.datasource.url=jdbc:opengauss://${RDS_IP}:${RDS_PORT}/${RDS_DATABASE}?stringtype=unspecified&sslmode=require&batchMode=off&reWriteBatchedInserts=true
  # 数据库使用的连接驱动
  spring.datasource.driverClassName=com.huawei.opengauss.jdbc.Driver
  # 数据建模引擎初始化环境使用的数据库类型
  xdm.runtime.db-type=gaussdb
  # 数据建模引擎初始化模型使用的数据库方言
  xdm.runtime.hibernate.dialect=com.huawei.it.rdm.configuration.XdmGaussDbDialect
  ## SSF单点登录
  # 单点登录使用的数据库类型
  SSF_RDS_TYPE=opengauss
  # 单点登录使用的数据库连接驱动
  SSF_DRIVER=com.huawei.opengauss.jdbc.Driver
  # 单点登录的数据库连接信息
  spring.datasource.ssf.url=jdbc:opengauss://${RDS_IP}:${RDS_PORT}/${RDS_DATABASE}_ssf
  spring.datasource.ssf.mapperLocations=classpath*:ssf/mapper_gauss/**/*.xml
  ```
  
- 创建一个脚本文件，用于启动应用运行态SDK。例如"startxdm.bash"。
  ```
  # 指定启动类
  START_CLASS=com.huawei.microservice.rdm.RdmApplication
  # 指定启动类所在路径，为lib目录下
  LOAD_CLASSPATH=./lib/*:./
  BIND_ADDRESS=`hostname -I`
  # 从部署包中解压出olc配置文件，加粗的字段需要根据实际包名填写，请确保替换为正确的包名(jar包位于lib目录下)
  jar xvf ./lib/microserviceTemplate.app-1.0.0-SNAPSHOT-shaded-small.jar olc
  # 使用以下命令基于JDK 17启动Java服务。如需以后台方式运行，并将日志输出到xdm.log日志中，可在命令末尾添加>xdm.log 2>&1 &参数
  # 容器环境JVM参数配置建议：
  # 1. JVM内存分配为容器内存的80%，避免资源抢占
  # 2. 明确限定元空间和堆内存的最大大小，以避免资源过度消耗
  java -Xms8g -Xmx8g -XX:MaxMetaspaceSize=768m\
      --add-opens java.base/java.lang=ALL-UNNAMED \
      --add-opens java.base/java.util=ALL-UNNAMED \
      --add-opens java.base/javax.crypto=ALL-UNNAMED \
      --add-opens java.base/sun.security.util=ALL-UNNAMED \
      --add-opens java.base/sun.security.x509=ALL-UNNAMED \
      --add-opens java.base/sun.security.pkcs=ALL-UNNAMED \
      --add-opens=java.base/java.io=ALL-UNNAMED \
      -Dolc.config.path=./olc \
      -Dconfig.file=./application.properties \
      -classpath $LOAD_CLASSPATH $START_CLASS \
      --server.address=${BIND_ADDRESS}
  ```
  
- 获取数据建模引擎运行SDK包，具体操作请参见[获取数据建模引擎SDK](https://support.huaweicloud.com/sdkreference-idme/idme_sdkreference_0009.html)。
- 已获取基础容器镜像，且该镜像已安装JDK 17。
 
#### 部署数据建模引擎运行SDK
1. 使用SSH方式登录机器。
2. 执行如下命令，检查是否安装docker。 
   ```
   docker -v
   ```
   - 如果已安装docker，请执行下一步。
   
   - 如果未安装docker，请安装。详细操作请参见[Docker-CE](https://mirrors.huaweicloud.com/mirrorDetail/5ea14d84b58d16ef329c5c13?mirrorName=docker-ce&catalog=docker)。
   
   
   
   
3. 基于[准备事项]中已获取的基础容器镜像，并根据实际部署环境和业务场景，编写一个Dockerfile文件。
   
   Dockerfile文件的填写示例如下：
   ```
   # 使用基础镜像
   FROM {基础镜像}
   # 资源复制：SDK包、配置文件、启动脚本
   COPY ./{SDK包名} /opt/cloud/app.tar
   COPY ./application.properties /opt/cloud/application.properties
   COPY ./startxdm.sh /opt/cloud/startxdm.sh
   # 解压数据建模引擎运行SDK包
   RUN tar -xvf /opt/cloud/app.tar -C /opt/cloud/
    
   # 设置工作目录
   WORKDIR /opt/cloud
   # 挂载 /opt/cloud 目录
   VOLUME /opt/cloud
   # 启动建模引擎SDK服务
   CMD ["sh","startxdm.sh"]
   ```
   其中：
   - FROM语句：指定基础镜像，用于后续的指令构建。
   
   - COPY语句：将文件或目录复制到镜像中。
   
   - WORKDIR语句：设置后续指令的工作目录。
   
   - VOLUME语句：为容器创建挂载点或声明卷。
   
   - RUN语句：构建镜像时执行的命令。
   
   - CMD语句：容器启动时执行的命令。
   
   
   
   
4. 执行如下命令，构建镜像。 
   ```
   docker build -t <镜像名称>:<版本名称> .
   ```
   
   
5. 执行如下命令，启动容器，挂载容器工作目录和映射服务启动端口号。 
   ```
   docker run -d -v /root/idme/:/opt/cloud/ -p 8003:8003 <镜像名称>:<版本名称>
   ```
   
   
6. 根据实际情况，选择如下方式，验证是否启动成功。 
   - **方式一：查看容器日志**
     执行如下命令，查看容器日志。
     ```
     docker logs <容器ID> |grep "Started RdmApplication"
     ```
     显示结果为类似如下信息，则说明启动成功。
     ```
     Started RdmApplication in xxx.xxx seconds (JVM running for xxx.xxx)
     ```
     
   
   - **方式二：调用指定接口**
     约等待2分钟，调用如下健康检查接口，查询服务是否正常启动。
     ```
     http://{容器的IP地址}:{SDK服务的端口号}/rdm_{应用的唯一标识}_app/services/v1/health
     ```
     例如：
     ```
     http://127.0.0.1:8003/rdm_123456_app/services/v1/health
     ```
     显示结果为如下信息，则说明启动成功。
     ```
     {"result":"SUCCESS","data":["success"],"errors":[]}
     ```
     
   
   
   
   
 
#### 异常处理
**问题描述**
服务正常启动，但调用任何接口都返回如下错误信息：
```
{
    "result": "FAIL",
    "timestamp": "2024-12-04 10:33:04",
    "error_code": "LIC.60007023",
    "error_msg": "No access rights. Please check license config or file.",
    "trance_id": null
}
```
**可能原因**
此错误信息表示当前SDK未正常运行，无法提供服务。可能存在如下原因：
- 当前SDK服务的宽限使用时间已到期。
- 当前SDK服务未配置License。
- 当前SDK服务配置的License已过期。
- 当前SDK服务配置License的信息填写不正确。
**处理步骤**
1. 在容器环境中，调用如下接口，获取容器的ESN。
   ```
   http://{容器的IP地址}:{SDK服务的端口号}/rdm_{应用的唯一标识}_app/services/v1/license/collect-esn
   ```
   记录显示结果中的"data"信息。
   ```
   {
       "result": "SUCCESS",
       "data": [
           "ESN"
       ],
       "errors": []
   }
   ```
   
2. 将[1]记录的"data"信息提供给运维工程师，获取License文件。
3. 在配置文件（例如"application.properties"）中添加[License配置](https://support.huaweicloud.com/sdkreference-idme/idme_sdkreference_0013.html#ZH-CN_TOPIC_0000002137019365__zh-cn_topic_0000001968767369_section1272355992312)信息。
 
