温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Eclipse Che 7工作区的用法

发布时间:2021-06-24 14:21:47 来源:亿速云 阅读:645 作者:chen 栏目:大数据

本篇内容主要讲解“Eclipse Che 7工作区的用法”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Eclipse Che 7工作区的用法”吧!

Eclipse Che工作区由devfile定义。 devfile是开发人员工作区中使用的所有内容的定义。

Che使用devfiles定义:

  • 克隆项目

  • 使用的浏览器IDE

  • 预配置命令

  • 您需要的工具

  • 应用程序运行时定义

创建工作空间时,Che使用该定义为您初始化所有内容,并为您的工具和应用程序运行时运行所有容器。 Che还安装文件系统卷,以使您的源代码可用于工作空间。

可以使用项目源代码对Devfiles进行版本控制。当您需要一个工作空间来修复旧的维护分支时,项目devfile为您提供了一个工作空间的定义,其中包含工具和确切的依赖关系以开始在旧分支上工作。使用它可以轻松地按需实例化工作区。

Che使用您在工作空间中使用的工具来维护devfile的最新信息:

  • 工作区的项目(路径,Git位置,分支)

  • 执行日常任务(构建,运行,测试,调试)的命令

  • 运行时环境(用于运行应用程序的容器映像)

  • Che-Theia插件,具有开发人员将在工作区中使用的工具,IDE功能和帮助程序(Git,Java支持,Sonarlint,Pull Request)

使用devfile启动工作区

本节介绍如何使用您自己的现有devfile启动Che工作区。

先决条件

  • Eclipse Che的运行实例。要安装Eclipse Che的实例,请参见Che'quick-starts'。

  • 在此Eclipse Che实例上定义的现有工作区从用户仪表板创建工作区。

有几种方法可以基于准备好的dev文件启动Che工作区:

来自Git的Devfile

将devfile添加到Git源存储库,然后从该存储库创建工厂。

  • 将devfile.yaml文件放在Git存储库的根目录中。

  • 通过打开以下URL执行工厂:

https:// <您的che-host> /f?url=https://github.com/ <mygroup> / <myrepo>

URL中的Devfile

通过使用指向devfile原始内容的URL构造工厂来执行devfile,例如:

https:// <您的che-host> /f?url=https://pastebin.com/raw/ux6iCGaW

使用chectl工具的Devfile

使用带有chectl工具的workspace:start参数从devfile执行工作空间,如下所示:

$ chectl workspace:start --devfile=devfile.yaml

为项目编写devfile

本节介绍如何为您的项目创建最小的devfile,以及如何在devfile中包含多个项目。

没有项目的最小devfile的示例

准备最小的devfile 足以运行工作空间的最小devfile由以下部分组成:

  • 规格版本

  • 名称

apiVersion: 1.0.0
metadata:
  name: minimal-workspace

带有项目的最小devfile的示例

无需任何进一步配置,带有默认编辑器的工作空间将随其默认插件一起启动,这些插件在Che Server上配置。 Che-Theia与Che Machine Exec插件一起配置为默认编辑器。

添加以下部分以实现更实用的工作空间:

  • 组件列表:开发组件和用户运行时

  • 项目列表:源代码存储库

  • 命令列表:用于管理工作空间组件的操作,例如运行开发工具,启动运行时环境等

apiVersion: 1.0.0
metadata:
  name: petclinic-dev-environment
projects:
  - name: petclinic
    source:
      type: git
      location: 'https://github.com/spring-projects/spring-petclinic.git'
components:
  - type: chePlugin
    id: redhat/java/latest

具有两个项目的devfile示例

在devfile中指定多个项目 一个devfile可以指定多个项目。对于每个项目,请指定源存储库的类型,其位置以及(可选)还指定要将项目克隆到的目录。

apiVersion: 1.0.0
metadata:
  name: example-devfile
projects:
- name: frontend
  source:
    type: git
    location: https://github.com/acmecorp/frontend.git
- name: backend
  clonePath: src/github.com/acmecorp/backend
  source:
    type: git
    location: https://github.com/acmecorp/backend.git

在前面的示例中,定义了两个项目,前端和后端。每个项目都位于其自己的存储库中。后端项目有一个特殊要求,即必须克隆到源根目录下的src/github.com/acmecorp/ backend/目录(由Che运行时隐式定义),而前端项目将被克隆到源目录下的frontend /目录中根。

额外资源

有关所有devfile组件分配和可能值的详细说明,请参见:

  • 规格库

  • 详细的json模式文档

这些示例devfile是很好的灵感来源:

  • 用户界面中默认使用的Eclipse Che工作区的示例devfile。

  • 来自Red Hat Developer程序的Eclipse Che工作区的示例devfile。

Devfile参考

本节包含devfile参考和有关如何使用devfile组成的各种元素的说明。

将组件添加到devfile

单个devfile中的每个组件都必须具有唯一的名称。

组件类型:cheEditor

通过定义其ID描述工作空间中使用的编辑器。一个devfile只能包含cheEditor类型的一个组件。

components:
  - alias: theia-editor
    type: cheEditor
    id: eclipse/che-theia/next

如果缺少cheEditor,则会提供默认编辑器及其默认插件。还为显式定义的编辑器提供了默认插件,这些编辑器具有与默认ID相同的ID(即使它是不同的版本)。 Che-Theia与Che Machine Exec插件一起配置为默认编辑器。

要指定工作区不需要编辑器,请在devfile属性中使用editorFree:true属性。

组件类型:chePlugin

通过定义插件ID来描述工作空间中的插件。允许具有多个chePlugin组件。

 components:
   - alias: exec-plugin
     type: chePlugin
     id: eclipse/che-machine-exec-plugin/0.0.1

上面两种类型都使用id(即用斜杠分隔的发布者),Che Plugin注册表中插件的名称和版本。 可用的Che插件列表以及有关注册表的更多信息可以在https://github.com/eclipse/che-plugin-registry上找到。

指定备用组件注册表

要为cheEditor和chePlugin组件类型指定替代注册表,请使用RegistryUrl参数:

 components:
   - alias: exec-plugin
     type: chePlugin
     registryUrl: https://my-customregistry.com
     id: eclipse/che-machine-exec-plugin/0.0.1

通过链接到其描述符来指定组件

指定cheEditor或chePlugin的一种替代方法,而不是使用编辑器或插件ID(以及可选的替代注册表),是通过使用引用字段提供到组件描述符(通常名为meta.yaml)的直接链接:

 components:
   - alias: exec-plugin
     type: chePlugin
     reference: https://raw.githubusercontent.com.../plugin/1.0.1/meta.yaml

不能在单个组件定义中混合使用id和reference字段。它们是互斥的。

指定组件的容器内存限制

要为cheEditor或chePlugin指定容器的内存限制,请使用memoryLimit参数:

 components:
   - alias: exec-plugin
     type: chePlugin
     id: eclipse/che-machine-exec-plugin/0.0.1
     memoryLimit: 256M

此限制将应用于给定组件的每个容器。

调整组件配置

可能需要精确调整组件,在这种情况下,可以使用组件首选项。该示例显示了如何使用插件首选项配置JVM。

 id: redhat/java/0.38.0
  type: chePlugin
  preferences:
     java.jdt.ls.vmargs: '-noverify -Xmx1G -XX:+UseG1GC -XX:+UseStringDeduplication'

组件类型:kubernetes

一种复杂的组件类型,允许从Kubernetes或OpenShift列表中应用配置。可以通过引用属性来提供组件的内容,该引用属性指向具有组件内容的文件。

components:
    - alias: mysql
      type: kubernetes
      reference: petclinic.yaml
      selector:
        app.kubernetes.io/name: mysql
        app.kubernetes.io/component: database
        app.kubernetes.io/part-of: petclinic

另外,要将具有此类组件的devfile发布到REST API,可以使用referenceContent字段将Kubernetes或OpenShift列表的内容嵌入到devfile中:

 components:
    - alias: mysql
      type: kubernetes
      reference: petclinic.yaml
      referenceContent: |
           kind: List
           items:
            -
             apiVersion: v1
             kind: Pod
             metadata:
              name: ws
             spec:
              containers:
              ... etc

与dockerimage组件一样,可以使用command和args属性覆盖Kubernetes或OpenShift列表中包含的容器的入口点(Kubernetes可以理解)。

列表中可以有更多容器(包含在部署的Pod或Pod模板中)。选择要应用入口点的容器会更改。

入口点可以定义如下:

components:
    - alias: appDeployment
      type: kubernetes
      reference: app-deployment.yaml
      entrypoints:
      - parentName: mysqlServer
        command: ['sleep']
        args: ['infinity']
      - parentSelector:
          app: prometheus
        args: ['-f', '/opt/app/prometheus-config.yaml']

入口点列表包含用于选择容器的约束以及要应用于它们的命令和args参数。在上面的示例中,约束是parentName:mysqlServer,这将导致命令应用到在任何名为mysqlServer的父对象中定义的所有容器。假定父对象是引用文件中定义的列表中的顶级对象,在上例中为app-deployment.yaml。

其他类型的约束(及其组合)也是可能的:

  • containerName:容器的名称

  • parentName:(间接)包含要覆盖的容器的父对象的名称

  • parentSelector:父对象需要具有的标签集

这些约束的组合可用于精确定位引用的Kubernetes列表内的容器。

指定安装源选项

要指定项目源目录装入容器,请使用mountSources参数:

components:
      - alias: appDeployment
        type: kubernetes
        reference: app-deployment.yaml
        mountSources: true

如果启用,则项目源安装将应用于给定组件的每个容器。此参数也适用于chePlugin类型的组件。

组件类型:dockerimage

允许在工作空间中定义容器的基于容器映像的配置的组件类型。一个devfile只能包含dockerimage类型的一个组件。组件的dockerimage类型将自定义工具引入工作空间。该组件由其图像标识。

components:
   - alias: maven
     type: dockerimage
     image: eclipe/maven-jdk8:latest
     volumes:
       - name: mavenrepo
         containerPath: /root/.m2
     env:
       - name: ENV_VAR
         value: value
     endpoints:
       - name: maven-server
         port: 3101
         attributes:
           protocol: http
           secure: 'true'
           public: 'true'
           discoverable: 'false'
     memoryLimit: 1536M
     command: ['tail']
     args: ['-f', '/dev/null']

最小dockerimage组件的示例

apiVersion: 1.0.0
metadata:
    name: MyDevfile
components:
type: dockerimage
image: golang
memoryLimit: 512Mi
command: ['sleep', 'infinity']

它指定组件的类型,dockerimage,并且image属性使用通常的docker命名约定命名要用于组件的映像,即,上述type属性等于 docker.io/library/golang:latest。

dockerimage组件具有许多功能,可通过使用图像资源与Eclipse Che进行有意义的集成所需的其他资源和信息来扩展图像。

挂载项目源

为了使dockerimage组件有权访问项目源,必须将mountSources属性设置为true。

apiVersion: 1.0.0
metadata:
    name: MyDevfile
components:
type: dockerimage
image: golang
memoryLimit: 512Mi
mountSources: true
command: ['sleep', 'infinity']

源安装在CHE_PROJECTS_ROOT环境变量中存储的位置,该位置在映像的运行容器中可用。此位置默认为/ projects。

容器入口点

dockerimage的command属性以及其他参数用于修改从映像创建的容器的入口点命令。在Eclipse Che中,该容器需要无限期运行,以便您可以随时连接到该容器并执行任意命令。因为sleep命令的可用性及其对infinity参数的支持是不同的,并且取决于特定图像中使用的基本图像,所以Che无法自行自动插入此行为。但是,您可以利用此功能来例如以修改后的配置启动必要的服务器等。

永久储存

Docker映像工具可以指定要安装在映像中特定位置的自定义卷。请注意,卷名在所有组件之间共享,因此该机制也可用于在组件之间共享文件系统。

apiVersion: 1.0.0
metadata:
    name: MyDevfile
components:
type: dockerimage
image: golang
memoryLimit: 512Mi
mountSources: true
command: ['sleep', 'infinity']
volumes:
    - name: cache
      containerPath: /.cache
环境

Eclipse Che允许您通过修改映像容器中可用的环境变量来配置Docker容器。

apiVersion: 1.0.0
metadata:
    name: MyDevfile
projects:
name: my-go-project
source:
    type: git
    location: https://github.com/acme/my-go-project.git
    clonePath: go/src/github.com/acme/my-go-project
components:
type: dockerimage
image: golang
memoryLimit: 512Mi
mountSources: true
command: ['sleep', 'infinity']
env:
    - name: GOPATH
      value: $(CHE_PROJECTS_ROOT)/go
    - name: GOCACHE
      value: /tmp/go-cache

变量扩展在环境变量之间起作用,并且它使用Kubernetes约定来引用变量。 您可以在自己的定义中使用预定义的变量。Che服务器预先设置了以下环境变量:

  • CHE_PROJECTS_ROOT:项目目录的位置(请注意,如果组件未装入源,则将无法访问项目)。

  • CHE_WORKSPACE_LOGS_ROOT__DIR:所有组件共有的日志的位置。如果组件选择将日志放入此目录,则可以从所有其他组件访问日志文件。

  • CHE_API_INTERNAL:用于与Che服务器通信的Che服务器API端点的URL。

  • CHE_WORKSPACE_ID:当前工作空间的ID。

  • CHE_WORKSPACE_NAME:当前工作空间的名称。

  • CHE_WORKSPACE_NAMESPACE:当前工作空间的名称空间。

  • CHE_MACHINE_TOKEN:用于根据Che服务器验证请求的令牌。

  • CHE_MACHINE_AUTH_SIGNATUREPUBLICKEY:用于保护与Che服务器的通信安全的公用密钥。

  • CHE_MACHINE_AUTH_SIGNATURE__ALGORITHM:在与Che服务器的安全通信中使用的加密算法。

一个开发文件可能只需要CHE_PROJECTS_ROOT环境变量即可在组件的容器中找到克隆的项目。更高级的devfile可以使用CHE_WORKSPACE_LOGS_ROOT__DIR环境变量来读取日志(例如,作为devfile命令的一部分)。用于安全访问Che服务器的环境变量大多不在devfile的范围内,并且仅在通常由Che插件处理的高级用例中才存在。

Endpoints

您可以指定Docker映像公开的端点。如果Che集群正在使用Kubernetes入口或OpenShift路由运行,则可以使用户访问这些端点,并且可以访问工作空间内的其他组件。如果您的应用程序或数据库服务器正在侦听端口,并且您希望自己能够直接与其交互或希望其他组件与之交互,则可以为应用程序或数据库创建端点。

端点具有许多属性,如以下示例所示:

apiVersion: 1.0.0
metadata:
    name: MyDevfile
projects:
name: my-go-project
source:
    type: git
    location: https://github.com/acme/my-go-project.git
    clonePath: go/src/github.com/acme/my-go-project
components:
type: dockerimage
image: golang
memoryLimit: 512Mi
mountSources: true
command: ['sleep', 'infinity']
env:
    - name: GOPATH
      value: $(CHE_PROJECTS_ROOT)/go
    - name: GOCACHE
      value: /tmp/go-cache
endpoints:
name: web
    port: 8080
    attributes:
        discoverable: false
        public: true
        protocol: http
type: dockerimage
image: postgres
memoryLimit: 512Mi
env:
name: POSTGRES_USER
value: user
name: POSTGRES_PASSWORD
value: password
name: POSTGRES_DB
    value: database
endpoints:
name: postgres
    port: 5432
    attributes:
        discoverable: true
        public: false

在这里,有两个dockerimage,每个dockerimage定义一个端点。端点是一个可访问的端口,可以使它在工作区内部或公开(例如,从UI)访问。每个端点都有一个名称和端口,这是容器中运行的某些服务器正在侦听的端口。以下是您可以在端点上设置的一些属性:

  • discoverable:如果可发现端点,则意味着可以使用其名称作为工作空间容器内的主机名来访问它(在Kubernetes看来,将使用提供的名称为其创建服务)。

  • public:端点也可以在工作空间之外访问(可以从Che用户界面访问该端点)。此类端点总是在端口80或443上发布(取决于是否在Che中启用了tls)。

  • protocol:对于公共端点,该协议向UI提示如何构建用于端点访问的URL。典型值为http,https,ws,wss。

  • secure:布尔值(默认为false),指定是否将端点放置在需要JWT工作区令牌授予访问权限的JWT代理之后。

  • path:端点的URL

  • unsecuredPaths:端点中以逗号分隔的路径列表,即使将secure属性设置为true也不应该对其进行保护

  • CookiesAuthEnabled:设置为true(默认值为false)时,将自动获取JWT工作区令牌并将其包含在特定于工作区的cookie中,以允许请求通过JWT代理传递。

与使用POST请求的服务器结合使用时,此设置可能会导致CSRF攻击。

当在组件内启动新服务器时,Che会自动检测到此情况,并且UI会自动将此端口公开为公用端口。例如,这对于调试Web应用程序很有用。对于使用容器自动启动的服务器(例如,数据库服务器)无法执行此操作。对于此类组件,请明确指定端点。

Kubernetes和OpenShift资源

可以使用可以在devfile中引用的Kubernetes或OpenShift资源列表来描述复杂的部署。这将使它们成为工作空间的一部分。

  • 由于Che工作区在内部被表示为单个部署,因此Kubernetes或OpenShift列表中的所有资源都合并到该单个部署中。

  • 设计此类列表时必须小心,因为这可能导致名称冲突和其他问题。

  • 仅支持Kubernetes对象的以下子集:部署,pod,服务,持久卷声明,机密和配置映射。 Kubernetes入口将被忽略,但支持OpenShift路由。使用其他任何对象类型从devfile创建的工作空间将无法启动。

  • 如果在Kubernetes集群上运行Che,则仅支持Kubernetes列表。但是,如果在OpenShift集群上运行Che,则同时支持Kubernetes和OpenShift列表(因为OpenShift是Kubernetes的超集)。

apiVersion: 1.0.0
metadata:
    name: MyDevfile
projects:
name: my-go-project
source:
    type: git
    location: https://github.com/acme/my-go-project.git
    clonePath: go/src/github.com/acme/my-go-project
components:
type: kubernetes
reference: ../relative/path/postgres.yaml

前面的组件引用了一个相对于devfile本身位置的文件。 这意味着,该devfile仅可由Che工厂加载,您可以向其提供devfile的位置,因此,它可以找出所引用的Kubernetes资源列表的位置。

以下是postgres.yaml文件的示例。

apiVersion: v1
kind: List
items:
-
    apiVersion: v1
    kind: Deployment
    metadata:
        name: postgres
        labels:
            app: postgres
    spec:
        template:
        metadata:
            name: postgres
            app:
                name: postgres
        spec:
            containers:
            - image: postgres
              name: postgres
              ports:
              - name: postgres
                containerPort: 5432
                volumeMounts:
                - name: pg-storage
                  mountPath: /var/lib/postgresql/data
            volumes:
            - name: pg-storage
              persistentVolumeClaim:
                  claimName: pg-storage
-
    apiVersion: v1
    kind: Service
    metadata:
        name: postgres
        labels:
            app: postgres
            name: postgres
    spec:
        ports:
            - port: 5432
              targetPort: 5432
        selector:
            app: postgres
-
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
        name: pg-storage
      labels:
        app: postgres
    spec:
        accessModes:
         - ReadWriteOnce
        resources:
            requests:
                storage: 1Gi

有关带有关联Kubernetes或OpenShift列表的devfile的基本示例,请参见https://github.com/redhat-developer/devfile/tree/master/samples/web-nodejs-with-db-sample。

如果使用仅需要资源的子集的常规或大型资源列表,则可以使用选择器从列表中选择特定资源(与通常的Kubernetes选择器一样,该选择器可用于列表中资源的标签) 。

apiVersion: 1.0.0
metadata:
    name: MyDevfile
projects:
name: my-go-project
source:
    type: git
    location: https://github.com/acme/my-go-project.git
    clonePath: go/src/github.com/acme/my-go-project
components:
type: kubernetes
reference: ../relative/path/postgres.yaml
selector:
    app: postgres

此外,还可以修改资源列表中存在的容器的入口点(命令和自变量)。有关高级用例的详细信息,请参见参考资料(TODO:链接)。

将命令添加到devfile

devfile允许指定可在工作空间中执行的命令。每个命令都可以包含动作的子集,这些动作与将在其容器中执行的特定组件相关。

commands:
   - name: build
     actions:
       - type: exec
         component: mysql
         command: mvn clean
         workdir: /projects/spring-petclinic

您可以使用命令来自动化工作空间。您可以定义用于构建和测试代码或清除数据库的命令。

以下是两种命令:

  • Che特定命令:您完全可以控制哪个组件执行该命令。

  • 特定于编辑器的命令:可以使用特定于编辑器的命令定义(例如:Theia中的task.json和launch.json,等效于这些文件在VS Code中的工作方式)。

Che专用命令

每个特定于che的命令都有一个动作属性(一个要执行的命令)和一个组件属性(指定一个应在其中执行命令的容器)。这些命令使用容器中的默认外壳程序运行。

apiVersion: 1.0.0
metadata:
    name: MyDevfile
projects:
name: my-go-project
source:
    type: git
    location: https://github.com/acme/my-go-project.git
    clonePath: go/src/github.com/acme/my-go-project
components:
type: dockerimage
image: golang
alias: go-cli
memoryLimit: 512Mi
mountSources: true
command: ['sleep', 'infinity']
env:
    - name: GOPATH
      value: $(CHE_PROJECTS_ROOT)/go
    - name: GOCACHE
      value: /tmp/go-cache
commands:
- name: compile and run
  actions:
  - type: exec
    component: go-cli
    command: “go get -d && go run main.go”
    workdir: “${CHE_PROJECTS_ROOT}/src/github.com/acme/my-go-project”

如果要在命令中使用的组件必须具有别名。 此别名用于引用命令定义中的组件。 示例:别名:组件定义中的go-cli和组件:命令定义中的go-cli。 这样可以确保Eclipse Che可以找到正确的容器来运行命令。 一个命令只能有一个动作。

特定于编辑器的命令

如果工作空间中的编辑器支持它,则devfile可以以编辑器特定的格式指定其他配置。 这取决于工作空间编辑器本身中提供的集成代码,因此不是通用机制。 但是,Eclipse Che中的默认Theia编辑器可以理解devfile中提供的task.json和launch.json文件。

apiVersion: 1.0.0
metadata:
    name: MyDevfile
projects:
name: my-go-project
source:
    type: git
    location: https://github.com/acme/my-go-project.git
    clonePath: go/src/github.com/acme/my-go-project
commands:
        - name: tasks
          actions:
          - type: vscode-task
            referenceContent: >
                {
                    "version": "2.0.0",
                    "tasks": [
                        {
                            "label": "create test file",
                            "type": "shell",
                            "command": "touch ${workspaceFolder}/test.file"
                        }
                    ]
                }

此示例显示task.json文件与devfile的关联。注意,vscode-task类型指示Che-Theia编辑器将此命令解释为任务定义和referenceContent属性,其中包含文件本身的内容。您还可以将该文件与devfile分开保存,并使用reference属性指定相对或绝对URL。

除了vscode-task命令之外,Che-Theia编辑器还了解vscode-launch类型,您可以使用该类型指定启动配置。

Devfile属性

Devfile属性可用于配置各种功能。

属性:editorFree

如果未在devfile中指定编辑器,则会提供默认值。当不需要编辑器时,应使用editorFree属性。默认值为false,这意味着devfile需要配置默认编辑器。

没有编辑器的devfile示例

apiVersion: 1.0.0
metadata:
  name: petclinic-dev-environment
components:
  - alias: myApp
    type: kubernetes
    local: my-app.yaml
attributes:
  editorFree: true
Attribute: persistVol

属性:persistVolumes(临时模式)

默认情况下,即使容器重启后,在devfile中指定的卷和PVC也绑定到主机文件夹以持久保存数据。有时,可能有必要禁用数据持久性,例如在卷后端速度较慢时,并且需要使工作空间更快时。为此,应使用persistVolumes devfile属性。默认值为true,如果为false,则将emptyDir卷用于配置的卷和PVC。

启用短暂模式的devfile的示例

apiVersion: 1.0.0
metadata:
  name: petclinic-dev-environment
projects:
  - name: petclinic
    source:
      type: git
      location: 'https://github.com/che-samples/web-java-spring-petclinic.git'
attributes:
  persistVolumes: false

到此,相信大家对“Eclipse Che 7工作区的用法”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI