spring-cloud-dataflow.md 594.7 KB
Newer Older
D
dallascao 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
# Spring 云数据流参考 GUID

# 前言

## 1. 关于文档

此版本的文档可在[HTML](https://docs.spring.io/spring-cloud-dataflow/docs/2.9.2/reference/htmlsingle)中找到。

可以找到 Spring 云数据流参考指南的最新副本[here](https://docs.spring.io/spring-cloud-dataflow/docs/current-SNAPSHOT/reference/html/)

本文件的副本可供你自己使用并分发给他人,但前提是你不对此类副本收取任何费用,并且还需每一份副本均包含本版权声明,无论是以印刷形式还是以电子方式分发。

## 2. 获得帮助

云数据流有问题吗?我们愿意提供帮助!

* 问一个问题。我们监控[stackoverflow.com](https://stackoverflow.com)中带有[`spring-cloud-dataflow`]标记的问题(https://stackoverflow.com/tags/ Spring-cloud-dataflow)。

*[github.com/spring-cloud/spring-cloud-dataflow/issues](https://github.com/spring-cloud/spring-cloud-dataflow/issues)处使用 Spring 云数据流报告错误。

*[Gitter](https://gitter.im/spring-cloud/spring-cloud-dataflow)上与社区和开发人员聊天。

|   |所有的云数据流都是开源的,包括文档!如果你在 DOCS 中发现问题<br/>,或者你只是想改进它们,请[参与进来](https://github.com/spring-cloud/spring-cloud-dataflow)。|
|---|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

# 开始

## 3. 开始-本地

有关设置 Docker Compose 和手动安装的更多信息,请参见 microSite 的[本地机器](https://dataflow.spring.io/docs/installation/local/)部分。

在本地安装了数据流服务器之后,你可能想要开始将现成的预构建应用程序部署到相干流或批处理数据管道中。我们有一些指南可以帮助你同时开始[Stream](https://dataflow.spring.io/docs/stream-developer-guides/)[Batch](https://dataflow.spring.io/docs/batch-developer-guides/)处理。

dallascao's avatar
dallascao 已提交
34
## 4. 入门-Cloud Foundry
D
dallascao 已提交
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510

本节介绍如何在 Cloud Foundry 上开始使用 Spring 云数据流。有关在 Cloud Foundry 上安装 Spring 云数据流的更多信息,请参见 microSite 的[Cloud Foundry](https://dataflow.spring.io/docs/installation/cloudfoundry/)部分。

一旦在 Cloud Foundry 上安装了数据流服务器,你可能想开始着手将现成的预构建应用程序部署到连贯的流或批处理数据管道中。我们有一些指南可以帮助你同时开始[Stream](https://dataflow.spring.io/docs/stream-developer-guides/)[Batch](https://dataflow.spring.io/docs/batch-developer-guides/)处理。

## 5. 开始-Kubernetes

[Spring Cloud Data Flow](https://cloud.spring.io/spring-cloud-dataflow/)是一个用于构建数据集成和实时数据处理管道的工具包。

管道由 Spring 引导应用程序组成,这些应用程序是用 Spring Cloud Stream 或 Spring Cloud Task 微服务框架构建的。这使得 Spring 云数据流适合一系列数据处理用例,从导入-导出到事件流和预测分析。

该项目提供了使用 Spring 云数据流的支持,Kubernetes 是这些管道的运行时,应用程序打包为 Docker 映像。

有关在 Kubernetes 上安装 Spring 云数据流的更多信息,请参见 microSite 的[Kubernetes](https://dataflow.spring.io/docs/installation/kubernetes/)部分。

在 Kubernetes 上安装了数据流服务器之后,你可能想要着手将现成的预构建应用程序部署到一个连贯的流或批处理数据管道中。我们有一些指南可以帮助你同时开始[Stream](https://dataflow.spring.io/docs/stream-developer-guides/)[Batch](https://dataflow.spring.io/docs/batch-developer-guides/)处理。

### 5.1.应用程序和服务器属性

本节介绍如何定制应用程序的部署。你可以使用许多属性来影响部署的应用程序的设置。属性可以在每个应用程序的基础上应用,也可以在所有已部署应用程序的适当服务器配置中应用。

|   |在每个应用程序的基础上设置的属性总是优先于作为服务器配置设置的属性。这种安排使你可以在每个应用程序的基础上重写全局服务器级别的属性。|
|---|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

要为所有部署的任务应用的属性在`src/kubernetes/server/server-config-[binder].yaml`文件中定义,在`src/kubernetes/skipper/skipper-config-[binder].yaml`中为流定义。将`[binder]`替换为你正在使用的消息传递中间件——例如,`rabbit``kafka`

#### 5.1.1.内存和 CPU 设置

应用程序使用默认的内存和 CPU 设置进行部署。如果需要,可以调整这些值。下面的示例显示了如何将`Limits`设置为`1000m`,对于内存为`CPU`,将`1024Mi`设置为`Requests`,对于 CPU 为`800m`,对于内存为`640Mi`:

```
deployer.<application>.kubernetes.limits.cpu=1000m
deployer.<application>.kubernetes.limits.memory=1024Mi
deployer.<application>.kubernetes.requests.cpu=800m
deployer.<application>.kubernetes.requests.memory=640Mi
```

这些值将导致使用以下容器设置:

```
Limits:
  cpu:	1
  memory:	1Gi
Requests:
  cpu:	800m
  memory:	640Mi
```

你还可以控制全局设置`cpu``memory`的默认值。

下面的示例展示了如何为流设置 CPU 和内存:

```
data:
  application.yaml: |-
    spring:
      cloud:
        skipper:
          server:
            platform:
              kubernetes:
                accounts:
                  default:
                    limits:
                      memory: 640mi
                      cpu: 500m
```

下面的示例展示了如何为任务设置 CPU 和内存:

```
data:
  application.yaml: |-
    spring:
      cloud:
        dataflow:
          task:
            platform:
              kubernetes:
                accounts:
                  default:
                    limits:
                      memory: 640mi
                      cpu: 500m
```

到目前为止,我们使用的设置仅影响容器的设置。它们不会影响容器中 JVM 进程的内存设置。如果你想要设置 JVM 内存设置,那么你可以设置一个环境变量来这样做。有关详细信息,请参见下一节。

#### 5.1.2.环境变量

要影响给定应用程序的环境设置,可以使用`spring.cloud.deployer.kubernetes.environmentVariables`Deployer 属性。例如,生产设置中的一个常见要求是影响 JVM 内存参数。你可以通过使用`JAVA_TOOL_OPTIONS`环境变量来实现这一点,如下例所示:

```
deployer.<application>.kubernetes.environmentVariables=JAVA_TOOL_OPTIONS=-Xmx1024m
```

|   |`environmentVariables`属性接受以逗号分隔的字符串。如果一个环境变量包含的值<br/>也是逗号分隔的字符串,那么它必须用单引号括起来——例如,`spring.cloud.deployer.kubernetes.environmentVariables=spring.cloud.stream.kafka.binder.brokers='somehost:9092,<br/>anotherhost:9093'`|
|---|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

这将覆盖所需`<application>`的 JVM 内存设置(用应用程序的名称替换`<application>`)。

#### 5.1.3.活性和准备状态探查

`liveness``readiness`探针分别使用称为`/health``/info`的路径。它们分别使用`delay``10``period``60``10`。在部署流时,可以使用 Deployer 属性更改这些默认值。活性和准备状态探测仅应用于流。

下面的示例通过设置部署程序属性来更改`liveness`探测(将`<application>`替换为应用程序的名称):

```
deployer.<application>.kubernetes.livenessProbePath=/health
deployer.<application>.kubernetes.livenessProbeDelay=120
deployer.<application>.kubernetes.livenessProbePeriod=20
```

可以将其声明为流的服务器全局配置的一部分,如下例所示:

```
data:
  application.yaml: |-
    spring:
      cloud:
        skipper:
          server:
            platform:
              kubernetes:
                accounts:
                  default:
                    livenessProbePath: /health
                    livenessProbeDelay: 120
                    livenessProbePeriod: 20
```

类似地,你可以将`liveness`交换为`readiness`,以覆盖默认的`readiness`设置。

默认情况下,端口 8080 被用作探测端口。可以使用 Deployer 属性更改`liveness``readiness`探测端口的默认值,如下例所示:

```
deployer.<application>.kubernetes.readinessProbePort=7000
deployer.<application>.kubernetes.livenessProbePort=7000
```

可以将其声明为流的全局配置的一部分,如下例所示:

```
data:
  application.yaml: |-
    spring:
      cloud:
        skipper:
          server:
            platform:
              kubernetes:
                accounts:
                  default:
                    readinessProbePort: 7000
                    livenessProbePort: 7000
```

|   |默认情况下,`liveness``readiness`探测路径使用 Spring Boot2.x+actuator 端点。要使用 Spring Boot1.x 执行器端点路径,必须调整`liveness``readiness`值,如下面的示例所示(将`<application>`替换为应用程序的名称):<br/><br/>```<br/>deployer.<application>.kubernetes.livenessProbePath=/health<br/>deployer.<application>.kubernetes.readinessProbePath=/info<br/>```<br/>在每个应用程序的基础上自动将`liveness``readiness`端点都设置为默认的 Spring 引导 1.x 路径,你可以设置以下属性:<br/>r=“gt=”“606”/><593"/>|
|---|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

你可以使用存储在[Kubernetes 的秘密](https://kubernetes.io/docs/concepts/configuration/secret/)中的凭据访问安全的探测端点。如果凭据包含在秘密的`credentials`块的`data`键名下,则可以使用现有的秘密。你可以在每个应用程序的基础上配置探测身份验证。启用后,将使用相同的凭据和身份验证类型将其应用于`liveness``readiness`探测端点。目前,只支持`Basic`身份验证。

创造一个新的秘密:

1. 使用用于访问安全探测端点的凭据生成 base64 字符串。

   基本身份验证将用户名和密码编码为`username:password`格式的 base64 字符串。

   下面的示例(其中包括输出,你应该用你的值替换`user``pass`)展示了如何生成 base64 字符串:

   ```
   $ echo -n "user:pass" | base64
   dXNlcjpwYXNz
   ```

2. 使用编码的凭据,创建一个包含以下内容的文件(例如,`myprobesecret.yml`):

   ```
   apiVersion: v1
   kind: Secret
   metadata:
     name: myprobesecret
   type: Opaque
   data:
     credentials: GENERATED_BASE64_STRING
   ```

3.`GENERATED_BASE64_STRING`替换为前面生成的 base64 编码的值。

4. 使用`kubectl`创建秘密,如下例所示:

   ```
   $ kubectl create -f ./myprobesecret.yml
   secret "myprobesecret" created
   ```

5. 将以下部署人员属性设置为在访问探测端点时使用身份验证,如下例所示:

   ```
   deployer.<application>.kubernetes.probeCredentialsSecret=myprobesecret
   ```

`<application>`替换为要对其应用身份验证的应用程序的名称。

#### 5.1.4.使用`SPRING_APPLICATION_JSON`

你可以使用`SPRING_APPLICATION_JSON`环境变量来设置数据流服务器属性(包括 Maven 存储库设置的配置),这些属性在所有数据流服务器实现中都是通用的。这些设置位于部署 YAML 的容器`env`部分的服务器级别。下面的示例展示了如何做到这一点:

```
env:
- name: SPRING_APPLICATION_JSON
  value: "{ \"maven\": { \"local-repository\": null, \"remote-repositories\": { \"repo1\": { \"url\": \"https://repo.spring.io/libs-snapshot\"} } } }"
```

#### 5.1.5.专用 Docker 注册表

你可以在每个应用程序的基础上从私有注册表中提取 Docker 映像。首先,你必须在集群中创建一个秘密。按照[从私有注册表中提取图像](https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/)指南创建秘密。

创建了秘密之后,就可以使用`imagePullSecret`属性来设置要使用的秘密,如下例所示:

```
deployer.<application>.kubernetes.imagePullSecret=mysecret
```

`<application>`替换为应用程序的名称,并将`mysecret`替换为前面创建的秘密的名称。

你还可以在全局服务器级别上配置图像提取秘密。

下面的示例展示了如何对流进行此操作:

```
data:
  application.yaml: |-
    spring:
      cloud:
        skipper:
          server:
            platform:
              kubernetes:
                accounts:
                  default:
                    imagePullSecret: mysecret
```

下面的示例展示了如何对任务执行此操作:

```
data:
  application.yaml: |-
    spring:
      cloud:
        dataflow:
          task:
            platform:
              kubernetes:
                accounts:
                  default:
                    imagePullSecret: mysecret
```

用前面创建的秘密的名称替换`mysecret`

#### 5.1.6.注解

你可以在每个应用程序的基础上向 Kubernetes 对象添加注释。支持的对象类型是 pod`Deployment``Service``Job`。注释以`key:value`格式定义,允许用逗号分隔多个注释。有关注释的更多信息和用例,请参见[注解](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/)

下面的示例展示了如何配置应用程序来使用注释:

```
deployer.<application>.kubernetes.podAnnotations=annotationName:annotationValue
deployer.<application>.kubernetes.serviceAnnotations=annotationName:annotationValue,annotationName2:annotationValue2
deployer.<application>.kubernetes.jobAnnotations=annotationName:annotationValue
```

用应用程序的名称和注释值替换`<application>`

#### 5.1.7.入口点样式

入口点样式会影响将应用程序属性传递给要部署的容器的方式。目前,支持三种样式:

* `exec`(默认):将部署请求中的所有应用程序属性和命令行参数作为容器参数传递。应用程序属性被转换为`--key=value`的格式。

* `shell`:将所有应用程序属性和命令行参数作为环境变量传递。每个应用程序或命令行参数属性都被转换为大写字符串,并且`.`字符被替换为`_`

* `boot`:创建一个名为`SPRING_APPLICATION_JSON`的环境变量,该变量包含所有应用程序属性的 JSON 表示。来自部署请求的命令行参数被设置为容器参数。

|   |在所有情况下,在服务器级配置和每个应用程序的基础上定义的环境变量都会按原样发送到容器。|
|---|------------------------------------------------------------------------------------------------------------------------------------------------|

你可以按以下方式配置应用程序:

```
deployer.<application>.kubernetes.entryPointStyle=<Entry Point Style>
```

`<application>`替换为应用程序的名称,并将`<Entry Point Style>`替换为所需的入口点样式。

你还可以在全局服务器级别配置入口点样式。

下面的示例展示了如何对流进行此操作:

```
data:
  application.yaml: |-
    spring:
      cloud:
        skipper:
          server:
            platform:
              kubernetes:
                accounts:
                  default:
                    entryPointStyle: entryPointStyle
```

下面的示例展示了如何对任务执行此操作:

```
data:
  application.yaml: |-
    spring:
      cloud:
        dataflow:
          task:
            platform:
              kubernetes:
                accounts:
                  default:
                    entryPointStyle: entryPointStyle
```

用所需的入口点样式替换`entryPointStyle`

你应该选择`exec``shell`的入口点样式,以对应于在容器的`ENTRYPOINT`中定义`ENTRYPOINT`语法的方式。有关`exec``shell`的更多信息和用例,请参见 Docker 文档的[ENTRYPOINT](https://docs.docker.com/engine/reference/builder/#entrypoint)部分。

使用`boot`入口点样式对应于使用`exec`样式`ENTRYPOINT`。来自部署请求的命令行参数将传递给容器,添加的应用程序属性将映射到`SPRING_APPLICATION_JSON`环境变量中,而不是命令行参数。

|   |当使用`boot`入口点样式时,`deployer.<application>.kubernetes.environmentVariables`属性不能包含`SPRING_APPLICATION_JSON`。|
|---|------------------------------------------------------------------------------------------------------------------------------------------------------------|

#### 5.1.8.部署服务帐户

你可以通过属性为应用程序部署配置自定义服务帐户。你可以使用现有的服务帐户或创建新的服务帐户。创建服务帐户的一种方法是使用`kubectl`,如下例所示:

```
$ kubectl create serviceaccount myserviceaccountname
serviceaccount "myserviceaccountname" created
```

然后,你可以按以下方式配置各个应用程序:

```
deployer.<application>.kubernetes.deploymentServiceAccountName=myserviceaccountname
```

`<application>`替换为应用程序的名称,并将`myserviceaccountname`替换为服务帐户的名称。

你还可以在全局服务器级别配置服务帐户名。

下面的示例展示了如何对流进行此操作:

```
data:
  application.yaml: |-
    spring:
      cloud:
        skipper:
          server:
            platform:
              kubernetes:
                accounts:
                  default:
                    deploymentServiceAccountName: myserviceaccountname
```

下面的示例展示了如何对任务执行此操作:

```
data:
  application.yaml: |-
    spring:
      cloud:
        dataflow:
          task:
            platform:
              kubernetes:
                accounts:
                  default:
                    deploymentServiceAccountName: myserviceaccountname
```

`myserviceaccountname`替换为要应用于所有部署的服务帐户名称。

#### 5.1.9.图像拉取策略

图像拉取策略定义了何时应该将 Docker 图像拉到本地注册中心。目前,有三项政策得到支持:

* `IfNotPresent`(默认值):如果图像已经存在,请不要拉它。

* `Always`:无论图像是否已经存在,都要拉它。

* `Never`:永远不要拉图像。只使用已经存在的图像。

下面的示例展示了如何单独配置应用程序:

```
deployer.<application>.kubernetes.imagePullPolicy=Always
```

`<application>`替换为应用程序的名称,并将`Always`替换为所需的图像拉出策略。

你可以在全局服务器级别配置一个映像拉出策略。

下面的示例展示了如何对流进行此操作:

```
data:
  application.yaml: |-
    spring:
      cloud:
        skipper:
          server:
            platform:
              kubernetes:
                accounts:
                  default:
                    imagePullPolicy: Always
```

下面的示例展示了如何对任务执行此操作:

```
data:
  application.yaml: |-
    spring:
      cloud:
        dataflow:
          task:
            platform:
              kubernetes:
                accounts:
                  default:
                    imagePullPolicy: Always
```

`Always`替换为所需的图像拉出策略。

#### 5.1.10.部署标签

你可以在与[Deployment](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/)相关的对象上设置自定义标签。有关标签的更多信息,请参见[Labels](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/)。标签以`key:value`格式指定。

下面的示例展示了如何单独配置应用程序:

```
deployer.<application>.kubernetes.deploymentLabels=myLabelName:myLabelValue
```

用应用程序的名称替换`<application>`,用标签名称替换`myLabelName`,用标签的值替换`myLabelValue`

此外,你还可以应用多个标签,如下例所示:

```
deployer.<application>.kubernetes.deploymentLabels=myLabelName:myLabelValue,myLabelName2:myLabelValue2
```

#### 5.1.11.公差

公差与污点一起工作,以确保 POD 不被调度到特定节点上。公差被设置到 POD 配置中,而污点被设置到节点上。有关更多信息,请参见 Kubernetes 引用的[污点和公差](https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/)部分。

下面的示例展示了如何单独配置应用程序:

```
deployer.<application>.kubernetes.tolerations=[{key: 'mykey', operator: 'Equal', value: 'myvalue', effect: 'NoSchedule'}]
```

根据所需的容忍配置,将`<application>`替换为应用程序的名称和键值对。

你也可以在全局服务器级别配置容差。

下面的示例展示了如何对流进行此操作:

```
data:
  application.yaml: |-
    spring:
      cloud:
        skipper:
          server:
            platform:
              kubernetes:
                accounts:
                  default:
                    tolerations:
                      - key: mykey
                        operator: Equal
                        value: myvalue
                        effect: NoSchedule
```

下面的示例展示了如何对任务执行此操作:

```
data:
  application.yaml: |-
    spring:
      cloud:
        dataflow:
          task:
            platform:
              kubernetes:
                accounts:
                  default:
                    tolerations:
                      - key: mykey
                        operator: Equal
                        value: myvalue
                        effect: NoSchedule
```

根据所需的容忍配置替换`tolerations`键值对。

#### 5.1.12.秘密参考文献

秘密可以被引用,它们的全部数据内容可以被解码,并作为单个变量插入到 POD 环境中。有关更多信息,请参见 Kubernetes 引用的[将秘密中的所有键值对配置为容器环境变量](https://kubernetes.io/docs/tasks/inject-data-application/distribute-credentials-secure/#configure-all-key-value-pairs-in-a-secret-as-container-environment-variables)部分。

下面的示例展示了如何单独配置应用程序:

```
deployer.<application>.kubernetes.secretRefs=testsecret
```

你还可以指定多个秘密,如下所示:

```
deployer.<application>.kubernetes.secretRefs=[testsecret,anothersecret]
```

`<application>`替换为应用程序的名称,并将`secretRefs`属性替换为应用程序环境和秘密的适当值。

你也可以在全局服务器级别配置秘密引用。

下面的示例展示了如何对流进行此操作:

```
data:
  application.yaml: |-
    spring:
      cloud:
        skipper:
          server:
            platform:
              kubernetes:
                accounts:
                  default:
                    secretRefs:
                      - testsecret
                      - anothersecret
```

下面的示例展示了如何对任务执行此操作:

```
data:
  application.yaml: |-
    spring:
      cloud:
        dataflow:
          task:
            platform:
              kubernetes:
                accounts:
                  default:
                    secretRefs:
                      - testsecret
                      - anothersecret
```

`secretRefs`中的项替换为一个或多个秘密名称。

#### 5.1.13.秘密密钥引用

秘密可以被引用,它们的解码值可以被插入到 POD 环境中。有关更多信息,请参见 Kubernetes 引用的[使用秘密作为环境变量](https://kubernetes.io/docs/concepts/configuration/secret/#using-secrets-as-environment-variables)部分。

下面的示例展示了如何单独配置应用程序:

```
deployer.<application>.kubernetes.secretKeyRefs=[{envVarName: 'MY_SECRET', secretName: 'testsecret', dataKey: 'password'}]
```

`<application>`替换为应用程序的名称,并将`envVarName``secretName``dataKey`属性替换为应用程序环境和秘密的适当值。

你也可以在全局服务器级别配置密钥引用。

下面的示例展示了如何对流进行此操作:

```
data:
  application.yaml: |-
    spring:
      cloud:
        skipper:
          server:
            platform:
              kubernetes:
                accounts:
                  default:
                    secretKeyRefs:
                      - envVarName: MY_SECRET
                        secretName: testsecret
                        dataKey: password
```

下面的示例展示了如何对任务执行此操作:

```
data:
  application.yaml: |-
    spring:
      cloud:
        dataflow:
          task:
            platform:
              kubernetes:
                accounts:
                  default:
                    secretKeyRefs:
                      - envVarName: MY_SECRET
                        secretName: testsecret
                        dataKey: password
```

`envVarName``secretName``dataKey`属性替换为适合你的秘密的值。

#### 5.1.14.配置图引用

配置图可以被引用,其全部数据内容可以被解码,并作为单个变量插入到 POD 环境中。有关更多信息,请参见 Kubernetes 引用的[将配置映射中的所有键值对配置为容器环境变量](https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/#configure-all-key-value-pairs-in-a-configmap-as-container-environment-variables)部分。

下面的示例展示了如何单独配置应用程序:

```
deployer.<application>.kubernetes.configMapRefs=testcm
```

你还可以指定多个 ConfigMap 实例,如下所示:

```
deployer.<application>.kubernetes.configMapRefs=[testcm,anothercm]
```

`<application>`替换为应用程序的名称,并将`configMapRefs`属性替换为应用程序环境和配置图的适当值。

你还可以在全局服务器级别配置配置配置映射引用。

下面的示例展示了如何对流进行此操作。编辑适当的`skipper-config-(binder).yaml`,使用相应的活页夹替换`(binder)`:

```
data:
  application.yaml: |-
    spring:
      cloud:
        skipper:
          server:
            platform:
              kubernetes:
                accounts:
                  default:
                    configMapRefs:
                      - testcm
                      - anothercm
```

下面的示例展示了如何通过编辑`server-config.yaml`文件来完成任务:

```
data:
  application.yaml: |-
    spring:
      cloud:
        dataflow:
          task:
            platform:
              kubernetes:
                accounts:
                  default:
                    configMapRefs:
                      - testcm
                      - anothercm
```

`configMapRefs`中的项替换为一个或多个秘密名称。

#### 5.1.15.配置映射密钥引用

可以引用配置图并将其相关的键值插入到 POD 环境中。有关更多信息,请参见 Kubernetes 引用的[使用配置图数据定义容器环境变量](https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/#define-container-environment-variables-using-configmap-data)部分。

下面的示例展示了如何单独配置应用程序:

```
deployer.<application>.kubernetes.configMapKeyRefs=[{envVarName: 'MY_CM', configMapName: 'testcm', dataKey: 'platform'}]
```

`<application>`替换为应用程序的名称,并将`envVarName``configMapName``dataKey`属性替换为应用程序环境和配置图的适当值。

你还可以在全局服务器级别配置配置配置映射引用。

下面的示例展示了如何对流进行此操作。编辑适当的`skipper-config-(binder).yaml`,使用相应的活页夹替换`(binder)`:

```
data:
  application.yaml: |-
    spring:
      cloud:
        skipper:
          server:
            platform:
              kubernetes:
                accounts:
                  default:
                    configMapKeyRefs:
                      - envVarName: MY_CM
                        configMapName: testcm
                        dataKey: platform
```

下面的示例展示了如何通过编辑`server-config.yaml`文件来完成任务:

```
data:
  application.yaml: |-
    spring:
      cloud:
        dataflow:
          task:
            platform:
              kubernetes:
                accounts:
                  default:
                    configMapKeyRefs:
                      - envVarName: MY_CM
                        configMapName: testcm
                        dataKey: platform
```

用配置映射的适当值替换`envVarName``configMapName``dataKey`属性。

#### 5.1.16.POD 安全上下文

你可以配置 POD 安全上下文,以便在指定的 UID(用户 ID)或 GID(组 ID)下运行进程。当你不希望在缺省`root`UID 和 GID 下运行进程时,这是很有用的。你可以定义`runAsUser``fsGroup`,并且可以将它们配置为一起工作。有关更多信息,请参见 Kubernetes 引用的[安全环境](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/)部分。

下面的示例展示了如何单独配置应用程序吊舱:

```
deployer.<application>.kubernetes.podSecurityContext={runAsUser: 65534, fsGroup: 65534}
```

`<application>`替换为应用程序的名称,并将`runAsUser`和/或`fsGroup`属性替换为容器环境的适当值。

你也可以在全局服务器级别配置 POD 安全上下文。

下面的示例展示了如何对流进行此操作。编辑适当的`skipper-config-(binder).yaml`,使用相应的活页夹替换`(binder)`:

```
data:
  application.yaml: |-
    spring:
      cloud:
        skipper:
          server:
            platform:
              kubernetes:
                accounts:
                  default:
                    podSecurityContext:
                      runAsUser: 65534
                      fsGroup: 65534
```

下面的示例展示了如何通过编辑`server-config.yaml`文件来完成任务:

```
data:
  application.yaml: |-
    spring:
      cloud:
        dataflow:
          task:
            platform:
              kubernetes:
                accounts:
                  default:
                    podSecurityContext:
                      runAsUser: 65534
                      fsGroup: 65534
```

用容器环境的适当值替换`runAsUser`和/或`fsGroup`属性。

#### 5.1.17.服务端口

部署应用程序时,将使用`8080`的默认端口创建一个 Kubernetes 服务对象。如果设置了`server.port`属性,它将重写默认端口值。你可以在每个应用程序的基础上向服务对象添加额外的端口。你可以使用逗号分隔符添加多个端口。

下面的示例展示了如何为应用程序配置服务对象上的附加端口:

```
deployer.<application>.kubernetes.servicePorts=5000
deployer.<application>.kubernetes.servicePorts=5000,9000
```

`<application>`替换为应用程序的名称和端口的值。

#### 5.1.18.statefulset init 容器

当通过使用 statefulset 部署应用程序时,将使用 init 容器在 POD 中设置实例索引。默认情况下,使用的图像是`busybox`,你可以对其进行自定义。

下面的示例展示了如何单独配置应用程序吊舱:

```
deployer.<application>.kubernetes.statefulSetInitContainerImageName=myimage:mylabel
```

`<application>`替换为应用程序的名称,并将`statefulSetInitContainerImageName`属性替换为适合你的环境的值。

你也可以在全局服务器级别配置 statefulset init 容器。

下面的示例展示了如何对流进行此操作。编辑适当的`skipper-config-(binder).yaml`,使用相应的活页夹替换`(binder)`:

```
data:
  application.yaml: |-
    spring:
      cloud:
        skipper:
          server:
            platform:
              kubernetes:
                accounts:
                  default:
                    statefulSetInitContainerImageName: myimage:mylabel
```

下面的示例展示了如何通过编辑`server-config.yaml`文件来完成任务:

```
data:
  application.yaml: |-
    spring:
      cloud:
        dataflow:
          task:
            platform:
              kubernetes:
                accounts:
                  default:
                    statefulSetInitContainerImageName: myimage:mylabel
```

`statefulSetInitContainerImageName`属性替换为适合你的环境的值。

#### 5.1.19.init 容器

部署应用程序时,可以根据每个应用程序设置自定义的 init 容器。有关更多信息,请参阅 Kubernetes 引用的[init 容器](https://kubernetes.io/docs/concepts/workloads/pods/init-containers/)部分。

下面的示例展示了如何为应用程序配置 init 容器:

```
deployer.<application>.kubernetes.initContainer={containerName: 'test', imageName: 'busybox:latest', commands: ['sh', '-c', 'echo hello']}
```

用应用程序的名称替换`<application>`,并设置适合 init 容器的`initContainer`属性的值。

#### 5.1.20.生命周期支持

部署应用程序时,可以附加`postStart``preStop`[生命周期处理程序](https://kubernetes.io/docs/tasks/configure-pod-container/attach-handler-lifecycle-event/)来执行命令。除了`exec`之外,Kubernetes API 还支持其他类型的处理程序。此功能可以扩展为在将来的版本中支持其他操作。要配置上面链接页中所示的生命周期处理程序,请使用以下属性键将每个命令指定为逗号分隔的列表:

```
deployer.<application>.kubernetes.lifecycle.postStart.exec.command=/bin/sh,-c,'echo Hello from the postStart handler > /usr/share/message'
deployer.<application>.kubernetes.lifecycle.preStop.exec.command=/bin/sh,-c,'nginx -s quit; while killall -0 nginx; do sleep 1; done'
```

#### 5.1.21.额外的集装箱

在部署应用程序时,可能需要将一个或多个容器与主容器一起部署。这将允许你适应一些部署模式,例如 Sidecar 和 Adapter,以备多容器 POD 设置的情况。

下面的示例展示了如何为应用程序配置其他容器:

```
deployer.<application>.kubernetes.additionalContainers=[{name: 'c1', image: 'busybox:latest', command: ['sh', '-c', 'echo hello1'], volumeMounts: [{name: 'test-volume', mountPath: '/tmp', readOnly: true}]},{name: 'c2', image: 'busybox:1.26.1', command: ['sh', '-c', 'echo hello2']}]
```

# 应用程序

选择预构建的[stream](https://cloud.spring.io/spring-cloud-stream-app-starters/)[任务或批处理](https://cloud.spring.io/spring-cloud-task-app-starters/)启动器应用程序,用于各种数据集成和处理场景,以促进学习和实验。下一节中的表格包括预先构建的应用程序,以供浏览。有关更多详细信息,请查看如何[注册支持的应用程序](#supported-apps-and-tasks)

## 6. 可用的应用程序

|                                                                             Source                                                                              |处理器|                                                                                    Sink                                                                                    |                                                                 Task                                                                 |
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------|
|           [sftp](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-sftp-source)            |[tcp-client](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-tcp-client-processor)|                  [mqtt](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-mqtt-sink)                  |        [timestamp](https://docs.spring.io/spring-cloud-task-app-starters/docs/current/reference/htmlsingle/#_timestamp_task)         |
|            [jms](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-jms-source)             |[可脚本转换](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-scriptable-transform)|                   [log](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-log-sink)                   |[composed-task-runner](https://docs.spring.io/spring-cloud-task-app-starters/docs/current/reference/htmlsingle/#_composed_task_runner)|
|            [ftp](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-ftp-source)             |[transform](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-clound-stream-modules-transform-processor)|            [throughput](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-throughput-sink)            |  [timestamp-batch](https://docs.spring.io/spring-cloud-task-app-starters/docs/current/reference/htmlsingle/#_timestamp_batch_task)   |
|           [time](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-time-source)            |[header-enricher](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-header-enricher-processor)|               [mongodb](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-mongodb-sink)               |                                                                                                                                      |
| [load-generator](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-load-generator-source)  |[Python-HTTP](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-python-http-processor)|                   [ftp](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-ftp-sink)                   |                                                                                                                                      |
|         [syslog](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-syslog-source)          |[推特-情绪](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-twitter-sentiment-processor)|                  [jdbc](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-jdbc-sink)                  |                                                                                                                                      |
|           [s3](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-aws-s3-source)            |[splitter](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-splitter)|             [cassandra](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-cassandra-sink)             |                                                                                                                                      |
|    [loggregator](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-loggregator-source)     |[图像识别](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-image-recognition-processor)|                [router](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-router-sink)                |                                                                                                                                      |
|[triggertask (deprecated)](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-trigger-source)|[bridge](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-bridge-processor)|             [redis-pubsub](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-redis-sink)              |                                                                                                                                      |
|  [twitterstream](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-twitterstream-source)   |[pmml](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-pmml-processor)|                  [file](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-file-sink)                  |                                                                                                                                      |
|        [mongodb](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-mongodb-source)         |[Python-Jython](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-python-jython-processor)|             [websocket](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-websocket-sink)             |                                                                                                                                      |
|     [gemfire-cq](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-gemfire-cq-source)      |[Groovy-transform](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-groovy-transform-processor)|                  [s3](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-aws-s3-sink)                  |                                                                                                                                      |
|           [http](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-http-source)            |[httpclient](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-httpclient-processor)|                [rabbit](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-rabbit-sink)                |                                                                                                                                      |
|         [rabbit](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-rabbit-source)          |[filter](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-filter-processor)|               [counter](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-counter-sink)               |                                                                                                                                      |
|            [tcp](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-tcp-source)             |[姿态估计](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-pose-estimation-processor)|                [pgcopy](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-pgcopy-sink)                |                                                                                                                                      |
|        [trigger](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-trigger-source)         |[grpc](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-grpc-processor)|                                                   [gpfdist](https://github.com/spring-cloud-stream-app-starters/gpfdist)                                                   |                                                                                                                                      |
|           [mqtt](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-mqtt-source)            |[groovy-filter](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-groovy-filter-processor)|                  [sftp](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-sftp-sink)                  |                                                                                                                                      |
|     [tcp-client](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-tcp-client-source)      |[aggregator](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-aggregator-processor)|[task-launcher-dataflow](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-task-launcher-dataflow-sink)|                                                                                                                                      |
|           [mail](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-mail-source)            |[counter](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-counter-processor)|                  [hdfs](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-hdfs-sink)                  |                                                                                                                                      |
|           [jdbc](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-jdbc-source)            |[tensorflow](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-tensorflow-processor)|                   [tcp](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-tcp-sink)                   |                                                                                                                                      |
|        [gemfire](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-gemfire-source)         |[tasklaunchrequest-transform(不推荐)](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-tasklaunchrequest-transform)|               [gemfire](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-gemfire-sink)               |                                                                                                                                      |
|           [file](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-file-source)            |[物体检测](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-object-detection-processor)|                                                                                                                                                                            |                                                                                                                                      |
|  [sftp-dataflow](https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/htmlsingle/#spring-cloud-stream-modules-sftp-dataflow-source)   |                                                                                                                                                                                              |                                                                                                                                                                            |                                                                                                                                      |

# 建筑

## 7. 导言

Spring 云数据流简化了专注于数据处理用例的应用程序的开发和部署。

微网站的[建筑](https://dataflow.spring.io/docs/concepts/architecture/)部分描述了数据流的体系结构。

# 配置

## 8. Maven

如果希望覆盖特定的 Maven 配置属性(远程存储库、代理和其他属性)或在代理后面运行数据流服务器,则需要在启动数据流服务器时将这些属性指定为命令行参数,如以下示例所示:

```
$ java -jar spring-cloud-dataflow-server-2.9.2.jar --spring.config.additional-location=/home/joe/maven.yml
```

前面的命令假定为与下面类似的`maven.yaml`:

```
maven:
  localRepository: mylocal
  remote-repositories:
    repo1:
      url: https://repo1
      auth:
        username: user1
        password: pass1
      snapshot-policy:
        update-policy: daily
        checksum-policy: warn
      release-policy:
        update-policy: never
        checksum-policy: fail
    repo2:
      url: https://repo2
      policy:
        update-policy: always
        checksum-policy: fail
  proxy:
    host: proxy1
    port: "9010"
    auth:
      username: proxyuser1
      password: proxypass1
```

默认情况下,该协议被设置为`http`。如果代理不需要用户名和密码,则可以省略 auth 属性。另外,默认情况下, Maven `localRepository`被设置为`${user.home}/.m2/repository/`。如前面的示例所示,你可以指定远程存储库以及它们的身份验证(如果需要)。如果远程存储库位于代理之后,则可以指定代理属性,如前面的示例所示。

你可以为每个远程存储库配置指定存储库策略,如前面的示例所示。键`policy`既适用于`snapshot`,也适用于`release`存储库策略。

有关受支持的存储库策略列表,请参见[存储库策略](https://github.com/apache/maven-resolver/blob/master/maven-resolver-api/src/main/java/org/eclipse/aether/repository/RepositoryPolicy.java)主题。

因为这是 Spring boot`@ConfigurationProperties`,所以你需要通过将它们添加到`SPRING_APPLICATION_JSON`环境变量中来进行指定。下面的示例展示了 JSON 的结构:

```
$ SPRING_APPLICATION_JSON='
{
  "maven": {
    "local-repository": null,
    "remote-repositories": {
      "repo1": {
        "url": "https://repo1",
        "auth": {
          "username": "repo1user",
          "password": "repo1pass"
        }
      },
      "repo2": {
        "url": "https://repo2"
      }
    },
    "proxy": {
      "host": "proxyhost",
      "port": 9018,
      "auth": {
        "username": "proxyuser",
        "password": "proxypass"
      }
    }
  }
}
'
```

### 8.1.马车

对于使用`Wagon`运输和 Maven 有一个有限的支持。目前,这是为了支持*先发制人*基于`http`的存储库的身份验证而存在的,并且需要手动启用。

通过将`maven.use-wagon`属性设置为`true`,可以启用基于 wagon 的`http`传输。然后,你可以为每个远程存储库启用*先发制人*身份验证。配置大致遵循[HttpClient HTTP Wagon](https://maven.apache.org/guides/mini/guide-http-settings.html)中的类似模式。在撰写本文时, Maven 自己网站中的文档有点误导性,并且缺少大多数可能的配置选项。

`maven.remote-repositories.<repo>.wagon.http`名称空间包含所有与 Wagon`http`相关的设置,它下面的键直接映射到受支持的`http`方法—即`all``put``get``head`,就像 Maven 自己的配置一样。在这些方法配置下,然后可以设置各种选项,例如`use-preemptive`。将带有所有请求的 auth 头发送到指定的远程存储库的 Simpl*先发制人*配置看起来像以下示例:

```
maven:
  use-wagon: true
  remote-repositories:
    springRepo:
      url: https://repo.example.org
      wagon:
        http:
          all:
            use-preemptive: true
      auth:
        username: user
        password: password
```

与配置`all`方法不同,你可以只调整`get``head`请求的设置,如下所示:

```
maven:
  use-wagon: true
  remote-repositories:
    springRepo:
      url: https://repo.example.org
      wagon:
        http:
          get:
            use-preemptive: true
          head:
            use-preemptive: true
            use-default-headers: true
            connection-timeout: 1000
            read-timeout: 1000
            headers:
              sample1: sample2
            params:
              http.socket.timeout: 1000
              http.connection.stalecheck: true
      auth:
        username: user
        password: password
```

这里有`use-default-headers``connection-timeout``read-timeout`、request`headers`和 httpclient`params`的设置。有关参数的更多信息,请参见[货车配置](https://github.com/apache/maven-wagon/blob/master/wagon-providers/wagon-http-shared/src/main/java/org/apache/maven/wagon/shared/http/ConfigurationUtils.java)

## 9. 安全

默认情况下,数据流服务器是不安全的,并在未加密的 HTTP 连接上运行。你可以通过启用 HTTPS 并要求客户机使用[OAuth 2.0](https://oauth.net/2/)进行身份验证来保护 REST 端点以及数据流仪表板。

|   |附录[Azure](#appendix-identity-provider-azure)包含如何<br/>设置*Azure 活动目录*集成的更多信息。|
|---|------------------------------------------------------------------------------------------------------------------------------------|

|   |默认情况下,REST 端点(管理、管理和健康状态)以及仪表板 UI 不需要经过身份验证的访问。|
|---|----------------------------------------------------------------------------------------------------------------------------------------|

虽然理论上可以结合 Spring 云数据流选择任何 OAuth 提供商,但我们建议使用[CloudFoundry 用户帐户和认证(UAA)服务器](https://github.com/cloudfoundry/uaa)

UAAOpenID 不仅得到了认证,并由 Cloud Foundry 使用,而且你还可以在本地独立部署场景中使用它。此外,UAA 不仅提供了自己的用户存储,而且还提供了全面的 LDAP 集成。

#### 9.1.启用 HTTPS

默认情况下,仪表板、管理和健康端点使用 HTTP 作为传输。你可以通过在`application.yml`中的配置中添加一个证书来切换到 HTTPS,如下例所示:

```
server:
  port: 8443                                         (1)
  ssl:
    key-alias: yourKeyAlias                          (2)
    key-store: path/to/keystore                      (3)
    key-store-password: yourKeyStorePassword         (4)
    key-password: yourKeyPassword                    (5)
    trust-store: path/to/trust-store                 (6)
    trust-store-password: yourTrustStorePassword     (7)
```

|**1**|由于默认端口是`9393`,你可以选择将该端口更改为更常见的 HTTPS 典型端口。|
|-----|-------------------------------------------------------------------------------------------------------------------------------------------------------|
|**2**|密钥存储在密钥存储库中的别名(或名称)。|
|**3**|密钥存储文件的路径。你还可以通过使用 Classpath 前缀来指定 Classpath 资源-例如:`classpath:path/to/keystore`。|
|**4**|密钥存储库的密码。|
|**5**|密钥的密码。|
|**6**|信任存储文件的路径。你还可以通过使用 Classpath 前缀来指定 Classpath 资源-例如:`classpath:path/to/trust-store`|
|**7**|信任存储的密码。|

|   |如果启用了 HTTPS,它将完全取代 HTTP 作为<br/>上的协议,REST 端点和数据流仪表板将在该协议上进行交互。普通 HTTP 请求<br/>失败。因此,请确保相应地配置你的 shell。|
|---|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

##### 使用自签名证书

出于测试目的或在开发过程中,创建自签名证书可能比较方便。要开始,请执行以下命令来创建证书:

```
$ keytool -genkey -alias dataflow -keyalg RSA -keystore dataflow.keystore \
          -validity 3650 -storetype JKS \
          -dname "CN=localhost, OU=Spring, O=Pivotal, L=Kailua-Kona, ST=HI, C=US"  (1)
          -keypass dataflow -storepass dataflow
```

|**1**|`CN`是这里的重要参数。它应该匹配你试图访问的域-例如,`localhost`。|
|-----|---------------------------------------------------------------------------------------------------------------------|

然后将以下行添加到你的`application.yml`文件中:

```
server:
  port: 8443
  ssl:
    enabled: true
    key-alias: dataflow
    key-store: "/your/path/to/dataflow.keystore"
    key-store-type: jks
    key-store-password: dataflow
    key-password: dataflow
```

这就是数据流服务器所需做的全部工作。一旦启动服务器,你应该能够在`[localhost:8443/](https://localhost:8443/)`上访问它。由于这是一个自签名的证书,你应该在浏览器中点击一个警告,你需要忽略它。

|   |*从来没有*在生产中使用自签名证书。|
|---|---------------------------------------------------|

##### 自签名证书和 shell

默认情况下,自签名证书是 shell 的一个问题,需要额外的步骤才能使 shell 与自签名证书一起工作。有两种选择:

* 将自签名证书添加到 JVM 信任存储库中。

* 跳过证书验证。

###### 将自签名证书添加到 JVM 信任存储库

为了使用 JVM 信任存储库选项,你需要从密钥存储库导出先前创建的证书,如下所示:

```
$ keytool -export -alias dataflow -keystore dataflow.keystore -file dataflow_cert -storepass dataflow
```

接下来,你需要创建一个 shell 可以使用的信任库,如下所示:

```
$ keytool -importcert -keystore dataflow.truststore -alias dataflow -storepass dataflow -file dataflow_cert -noprompt
```

现在,你已经准备好使用以下 JVM 参数启动数据流壳层了:

```
$ java -Djavax.net.ssl.trustStorePassword=dataflow \
       -Djavax.net.ssl.trustStore=/path/to/dataflow.truststore \
       -Djavax.net.ssl.trustStoreType=jks \
       -jar spring-cloud-dataflow-shell-2.9.2.jar
```

|   |如果在通过 SSL 建立连接时遇到麻烦,可以使用<br/>日志,并将`javax.net.debug`JVM 参数设置为`ssl`。|
|---|-------------------------------------------------------------------------------------------------------------------------------------------------------------------|

不要忘记使用以下命令锁定数据流服务器:

```
dataflow:> dataflow config server https://localhost:8443/
```

###### 跳过证书验证

或者,你也可以通过提供可选的`--dataflow.skip-ssl-validation=true`命令行参数来绕过认证验证。

如果你设置了这个命令行参数,shell 将接受任何(自签名的)SSL 证书。

|   |如果可能的话,你应该避免使用这个选项。禁用信任管理器<br/>会破坏 SSL 的目的,并使你的应用程序容易受到中间人攻击。|
|---|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

#### 9.2.使用 OAuth2.0 进行身份验证

为了支持身份验证和授权, Spring 云数据流使用[OAuth 2.0](https://oauth.net/2/)。它允许你将 Spring 云数据流集成到单点登录(SSO)环境中。

|   |Spring 在云数据流 2.0 中,OAuth2 是用于提供身份验证和授权的唯一机制<br/>。|
|---|------------------------------------------------------------------------------------------------------------------|

使用了以下 OAuth2 授予类型:

* **授权代码**:用于 GUI(浏览器)集成。访问者将被重定向到你的 OAuth 服务进行身份验证。

* **密码**:由 shell(和 REST 集成)使用,因此访问者可以使用用户名和密码登录

* **客户凭据**:直接从 OAuth 提供程序检索访问令牌,并使用授权 HTTP 头将其传递给数据流服务器

|   |当前, Spring 云数据流使用不透明的令牌和不透明的<br/>令牌。|
|---|------------------------------------------------------------------------------------------|

你可以通过两种方式访问 REST 端点:

* **基本身份验证**,它使用*密码授予类型*对你的 OAuth2 服务进行身份验证

* **访问令牌**,它使用客户端*凭据授予类型*

|   |当你设置身份验证时,你确实应该启用 HTTPS,尤其是在生产环境中。|
|---|------------------------------------------------------------------------------------------------------------------|

你可以通过向`application.yml`添加以下内容或通过设置环境变量来打开 OAuth2 身份验证。下面的示例显示了[CloudFoundry 用户帐户和认证(UAA)服务器](https://github.com/cloudfoundry/uaa)所需的最小设置:

```
spring:
  security:
    oauth2:                                                           (1)
      client:
        registration:
          uaa:                                                        (2)
            client-id: myclient
            client-secret: mysecret
            redirect-uri: '{baseUrl}/login/oauth2/code/{registrationId}'
            authorization-grant-type: authorization_code
            scope:
            - openid                                                  (3)
        provider:
          uaa:
            jwk-set-uri: http://uaa.local:8080/uaa/token_keys
            token-uri: http://uaa.local:8080/uaa/oauth/token
            user-info-uri: http://uaa.local:8080/uaa/userinfo    (4)
            user-name-attribute: user_name                            (5)
            authorization-uri: http://uaa.local:8080/uaa/oauth/authorize
      resourceserver:
        opaquetoken:
          introspection-uri: http://uaa.local:8080/uaa/introspect (6)
          client-id: dataflow
          client-secret: dataflow
```

|**1**|提供此属性将激活 OAuth2 安全性。|
|-----|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|**2**|提供者 ID。你可以指定多个提供者。|
|**3**|由于 UAA 是 OpenID 提供程序,因此你必须至少指定`openid`范围。<br/>如果你的提供程序还提供了其他范围来控制角色分配,<br/>你还必须在此指定这些范围。|
|**4**|OpenID 端点。用于检索用户信息,如用户名。强制性的。|
|**5**|包含用户名的响应的 JSON 属性。|
|**6**|用于内省和验证一个直接传入的令牌。强制性的。|

你可以使用 curl 验证基本身份验证是否正常工作,如下所示:

```
curl -u myusername:mypassword http://localhost:9393/ -H 'Accept: application/json'
```

因此,你应该看到一个可用的 REST 端点列表。

|   |当你使用 Web 浏览器访问根 URL 并启用<br/>安全性时,你将被重定向到仪表板 UI。要查看休息端点的<br/>列表,请指定`application/json``Accept`标头。也要确保<br/>通过使用[Postman](https://chrome.google.com/webstore/detail/postman/fhbjgbiflinjbdggehcddcbncdddomop?hl=en)(Chrome)<br/>[RESTClient](https://addons.mozilla.org/en-GB/firefox/addon/restclient/)(Firefox)等工具添加`Accept`头。|
|---|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

除了基本的身份验证,你还可以提供一个访问令牌,以访问 REST API。为此,从你的 OAuth2 提供程序检索一个 OAuth2 访问令牌,并使用**授权**HTTP 报头将该访问令牌传递给 REST API,如下所示:

```
$ curl -H "Authorization: Bearer <ACCESS_TOKEN>" http://localhost:9393/ -H 'Accept: application/json'
```

#### 9.3.自定义授权

前面的内容主要涉及身份验证——即如何评估用户的身份。在本节中,我们将讨论可用的 ** 授权 ** 选项—即谁可以做什么。

该授权规则在`dataflow-server-defaults.yml`( Spring 云数据流核心模块的一部分)中定义。

由于安全角色的确定是特定于环境的, Spring 云数据流在默认情况下将所有角色分配给经过身份验证的 OAuth2 用户。`DefaultDataflowAuthoritiesExtractor`类用于此目的。

或者,通过将你的提供者的布尔属性`map-oauth-scopes`设置为`true`(默认值为`false`),可以将 Spring 云数据流映射到数据流角色。例如,如果你的提供者的 ID 是`uaa`,则属性将是`spring.cloud.dataflow.security.authorization.provider-role-mappings.uaa.map-oauth-scopes`

有关更多详细信息,请参见[角色映射](#configuration-security-role-mapping)一章。

你还可以通过提供你自己的 Spring  Bean 定义来定制角色映射行为,该定义扩展了 Spring 云数据流的`AuthorityMapper`接口。在这种情况下,自定义 Bean 的定义优先于 Spring 云数据流提供的默认定义。

默认方案使用七个角色来保护 Spring 云数据流公开的[REST 端点](#api-guide):

* **角色 \_ 创建**:用于任何涉及创建的内容,例如创建流或任务

* **角色 \_ 部署**:用于部署流或启动任务

* **角色 \_destroy**:用于任何涉及删除流、任务等的内容。

* **角色 \_ 管理**:用于引导管理端点

* **角色 \_ 修改**:对于任何涉及系统状态突变的内容

* **角色 \_ 日程安排**:用于调度相关操作(例如调度任务)

* **角色 \_ 视图**:对于任何与检索状态有关的内容

正如本节前面提到的,所有与授权相关的默认设置都在`dataflow-server-defaults.yml`中指定,这是 Spring 云数据流核心模块的一部分。尽管如此,如果需要,你可以重写这些设置——例如,在`application.yml`中。该配置采用 YAML 列表的形式(因为某些规则可能优先于其他规则)。因此,你需要复制和粘贴整个列表,并根据你的需要对其进行定制(因为无法合并列表)。

|   |始终引用`application.yml`文件的版本,因为下面的代码片段可能已经过时了。|
|---|-----------------------------------------------------------------------------------------------------|

默认规则如下:

```
spring:
  cloud:
    dataflow:
      security:
        authorization:
          enabled: true
          loginUrl: "/"
          permit-all-paths: "/authenticate,/security/info,/assets/**,/dashboard/logout-success-oauth.html,/favicon.ico"
          rules:
            # About

            - GET    /about                          => hasRole('ROLE_VIEW')

            # Audit

            - GET /audit-records                     => hasRole('ROLE_VIEW')
            - GET /audit-records/**                  => hasRole('ROLE_VIEW')

            # Boot Endpoints

            - GET /management/**                  => hasRole('ROLE_MANAGE')

            # Apps

            - GET    /apps                           => hasRole('ROLE_VIEW')
            - GET    /apps/**                        => hasRole('ROLE_VIEW')
            - DELETE /apps/**                        => hasRole('ROLE_DESTROY')
            - POST   /apps                           => hasRole('ROLE_CREATE')
            - POST   /apps/**                        => hasRole('ROLE_CREATE')
            - PUT    /apps/**                        => hasRole('ROLE_MODIFY')

            # Completions

            - GET /completions/**                    => hasRole('ROLE_VIEW')

            # Job Executions & Batch Job Execution Steps && Job Step Execution Progress

            - GET    /jobs/executions                => hasRole('ROLE_VIEW')
            - PUT    /jobs/executions/**             => hasRole('ROLE_MODIFY')
            - GET    /jobs/executions/**             => hasRole('ROLE_VIEW')
            - GET    /jobs/thinexecutions            => hasRole('ROLE_VIEW')

            # Batch Job Instances

            - GET    /jobs/instances                 => hasRole('ROLE_VIEW')
            - GET    /jobs/instances/*               => hasRole('ROLE_VIEW')

            # Running Applications

            - GET    /runtime/streams                => hasRole('ROLE_VIEW')
            - GET    /runtime/streams/**             => hasRole('ROLE_VIEW')
            - GET    /runtime/apps                   => hasRole('ROLE_VIEW')
            - GET    /runtime/apps/**                => hasRole('ROLE_VIEW')

            # Stream Definitions

            - GET    /streams/definitions            => hasRole('ROLE_VIEW')
            - GET    /streams/definitions/*          => hasRole('ROLE_VIEW')
            - GET    /streams/definitions/*/related  => hasRole('ROLE_VIEW')
            - POST   /streams/definitions            => hasRole('ROLE_CREATE')
            - DELETE /streams/definitions/*          => hasRole('ROLE_DESTROY')
            - DELETE /streams/definitions            => hasRole('ROLE_DESTROY')

            # Stream Deployments

            - DELETE /streams/deployments/*          => hasRole('ROLE_DEPLOY')
            - DELETE /streams/deployments            => hasRole('ROLE_DEPLOY')
            - POST   /streams/deployments/**         => hasRole('ROLE_MODIFY')
            - GET    /streams/deployments/**         => hasRole('ROLE_VIEW')

            # Stream Validations

            - GET /streams/validation/               => hasRole('ROLE_VIEW')
            - GET /streams/validation/*              => hasRole('ROLE_VIEW')

            # Stream Logs
            - GET /streams/logs/*                    => hasRole('ROLE_VIEW')

            # Task Definitions

            - POST   /tasks/definitions              => hasRole('ROLE_CREATE')
            - DELETE /tasks/definitions/*            => hasRole('ROLE_DESTROY')
            - GET    /tasks/definitions              => hasRole('ROLE_VIEW')
            - GET    /tasks/definitions/*            => hasRole('ROLE_VIEW')

            # Task Executions

            - GET    /tasks/executions               => hasRole('ROLE_VIEW')
            - GET    /tasks/executions/*             => hasRole('ROLE_VIEW')
            - POST   /tasks/executions               => hasRole('ROLE_DEPLOY')
            - POST   /tasks/executions/*             => hasRole('ROLE_DEPLOY')
            - DELETE /tasks/executions/*             => hasRole('ROLE_DESTROY')

            # Task Schedules

            - GET    /tasks/schedules                => hasRole('ROLE_VIEW')
            - GET    /tasks/schedules/*              => hasRole('ROLE_VIEW')
            - GET    /tasks/schedules/instances      => hasRole('ROLE_VIEW')
            - GET    /tasks/schedules/instances/*    => hasRole('ROLE_VIEW')
            - POST   /tasks/schedules                => hasRole('ROLE_SCHEDULE')
            - DELETE /tasks/schedules/*              => hasRole('ROLE_SCHEDULE')

            # Task Platform Account List */

            - GET    /tasks/platforms                => hasRole('ROLE_VIEW')

            # Task Validations

            - GET    /tasks/validation/               => hasRole('ROLE_VIEW')
            - GET    /tasks/validation/*              => hasRole('ROLE_VIEW')

            # Task Logs
            - GET /tasks/logs/*                       => hasRole('ROLE_VIEW')

            # Tools

            - POST   /tools/**                       => hasRole('ROLE_VIEW')
```

每一行的格式如下:

```
HTTP_METHOD URL_PATTERN '=>' SECURITY_ATTRIBUTE
```

地点:

* HTTP\_Method 是一种 HTTP 方法(如 PUT 或 GET),大写的情况。

* URL\_Pattern 是一种 Ant 风格的 URL 模式。

* Security\_Attribute 是一个 SPEL 表达式。见[基于表达式的访问控制](https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#el-access)

* 每个字符都用一个或空白字符(空格、制表符等)隔开。

请注意,上面是一个 YAML 列表,而不是一个位于`spring.cloud.dataflow.security.authorization.rules`键下的映射(因此在每一行的开始处使用’-’破折号)。

##### 授权——shell 和 dashboard 行为

当启用安全性时,仪表板和外壳是角色感知的,这意味着,根据分配的角色,并非所有功能都是可见的。

例如,用户没有必要角色的 shell 命令被标记为不可用。

|   |目前,shell 的`help`命令列出了不可用的命令。<br/>请跟踪以下问题:[github.com/spring-projects/spring-shell/issues/115](https://github.com/spring-projects/spring-shell/issues/115)|
|---|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

相反,对于仪表板,UI 不会显示用户未获得授权的页面或页面元素。

##### 保护 Spring 引导管理端点

启用安全性时,[Spring Boot HTTP Management Endpoints](https://docs.spring.io/spring-boot/docs/2.1.1.RELEASE/reference/html/production-ready-monitoring.html)将以与其他 REST 端点相同的方式进行安全性保护。管理 REST 端点在`/management`下可用,并且需要`MANAGEMENT`角色。

`dataflow-server-defaults.yml`中的默认配置如下:

```
management:
  endpoints:
    web:
      base-path: /management
  security:
    roles: MANAGE
```

|   |目前,你不应该自定义默认的管理路径。|
|---|----------------------------------------------------------------|

#### 9.4.建立 UAA 身份验证

对于本地部署场景,我们建议使用[CloudFoundry 用户帐户和认证(UAA)服务器](https://github.com/cloudfoundry/uaa),即[OpenID 认证](https://openid.net/certification/)。虽然 UAA 由[Cloud Foundry](https://www.cloudfoundry.org/)使用,但它也是一个功能齐全的独立 OAuth2 服务器,具有 Enterprise 功能,例如[LDAP 集成](https://github.com/cloudfoundry/uaa/blob/develop/docs/UAA-LDAP.md)

##### 所需经费

你需要签出、构建和运行 UAA。要做到这一点,请确保:

1511
* 使用 Java8.
D
dallascao 已提交
1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201

* 已安装[Git](https://git-scm.com/)

* 安装[CloudFoundry UAA 命令行客户端](https://github.com/cloudfoundry/cf-uaac)

* 在同一台计算机上运行时,对 UAA 使用不同的主机名——例如,`[uaa/](http://uaa/)`

如果在安装*UAAC*时遇到问题,则可能需要设置`GEM_HOME`环境变量:

```
export GEM_HOME="$HOME/.gem"
```

你还应该确保`~/.gem/gems/cf-uaac-4.2.0/bin`已被添加到你的路径中。

##### 为 JWT 编写 UAA

由于 UAA 是一个 OpenID 提供者,并且使用 JSON Web 令牌,因此它需要一个私钥来对这些 JWTS 进行签名:

```
openssl genrsa -out signingkey.pem 2048
openssl rsa -in signingkey.pem -pubout -out verificationkey.pem
export JWT_TOKEN_SIGNING_KEY=$(cat signingkey.pem)
export JWT_TOKEN_VERIFICATION_KEY=$(cat verificationkey.pem)
```

稍后,一旦 UAA 被启动,你就可以在访问`[uaa:8080/uaa/token_keys](http://uaa:8080/uaa/token_keys)`时看到这些键。

|   |在这里,URL`[uaa:8080/uaa/token_keys](http://uaa:8080/uaa/token_keys)`中的`uaa`是主机名。|
|---|-------------------------------------------------------------------------------------------------------|

##### 下载并启动 UAA

要下载和安装 UAA,请运行以下命令:

```
git clone https://github.com/pivotal/uaa-bundled.git
cd uaa-bundled
./mvnw clean install
java -jar target/uaa-bundled-1.0.0.BUILD-SNAPSHOT.jar
```

UAA 的配置由 YAML 文件`uaa.yml`驱动,或者你可以使用 UAA 命令行客户端编写配置脚本:

```
uaac target http://uaa:8080/uaa
uaac token client get admin -s adminsecret
uaac client add dataflow \
  --name dataflow \
  --secret dataflow \
  --scope cloud_controller.read,cloud_controller.write,openid,password.write,scim.userids,sample.create,sample.view,dataflow.create,dataflow.deploy,dataflow.destroy,dataflow.manage,dataflow.modify,dataflow.schedule,dataflow.view \
  --authorized_grant_types password,authorization_code,client_credentials,refresh_token \
  --authorities uaa.resource,dataflow.create,dataflow.deploy,dataflow.destroy,dataflow.manage,dataflow.modify,dataflow.schedule,dataflow.view,sample.view,sample.create\
  --redirect_uri http://localhost:9393/login \
  --autoapprove openid

uaac group add "sample.view"
uaac group add "sample.create"
uaac group add "dataflow.view"
uaac group add "dataflow.create"

uaac user add springrocks -p mysecret --emails [email protected]
uaac user add vieweronly -p mysecret --emails [email protected]

uaac member add "sample.view" springrocks
uaac member add "sample.create" springrocks
uaac member add "dataflow.view" springrocks
uaac member add "dataflow.create" springrocks
uaac member add "sample.view" vieweronly
```

前面的脚本设置了 DataFlow 客户机和两个用户:

* 用户*洒水车*同时具有两个作用域:`sample.view``sample.create`

* 用户*仅限 Vieweronly*只有一个作用域:`sample.view`

添加后,你可以快速重复检查 UAA 是否已创建用户:

```
curl -v -d"username=springrocks&password=mysecret&client_id=dataflow&grant_type=password" -u "dataflow:dataflow" http://uaa:8080/uaa/oauth/token -d 'token_format=opaque'
```

前面的命令应该产生类似于下面的输出:

```
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to uaa (127.0.0.1) port 8080 (#0)
* Server auth using Basic with user 'dataflow'
> POST /uaa/oauth/token HTTP/1.1
> Host: uaa:8080
> Authorization: Basic ZGF0YWZsb3c6ZGF0YWZsb3c=
> User-Agent: curl/7.54.0
> Accept: */*
> Content-Length: 97
> Content-Type: application/x-www-form-urlencoded
>
* upload completely sent off: 97 out of 97 bytes
< HTTP/1.1 200
< Cache-Control: no-store
< Pragma: no-cache
< X-XSS-Protection: 1; mode=block
< X-Frame-Options: DENY
< X-Content-Type-Options: nosniff
< Content-Type: application/json;charset=UTF-8
< Transfer-Encoding: chunked
< Date: Thu, 31 Oct 2019 21:22:59 GMT
<
* Connection #0 to host uaa left intact
{"access_token":"0329c8ecdf594ee78c271e022138be9d","token_type":"bearer","id_token":"eyJhbGciOiJSUzI1NiIsImprdSI6Imh0dHBzOi8vbG9jYWxob3N0OjgwODAvdWFhL3Rva2VuX2tleXMiLCJraWQiOiJsZWdhY3ktdG9rZW4ta2V5IiwidHlwIjoiSldUIn0.eyJzdWIiOiJlZTg4MDg4Ny00MWM2LTRkMWQtYjcyZC1hOTQ4MmFmNGViYTQiLCJhdWQiOlsiZGF0YWZsb3ciXSwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDkwL3VhYS9vYXV0aC90b2tlbiIsImV4cCI6MTU3MjYwMDE3OSwiaWF0IjoxNTcyNTU2OTc5LCJhbXIiOlsicHdkIl0sImF6cCI6ImRhdGFmbG93Iiwic2NvcGUiOlsib3BlbmlkIl0sImVtYWlsIjoic3ByaW5ncm9ja3NAc29tZXBsYWNlLmNvbSIsInppZCI6InVhYSIsIm9yaWdpbiI6InVhYSIsImp0aSI6IjAzMjljOGVjZGY1OTRlZTc4YzI3MWUwMjIxMzhiZTlkIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImNsaWVudF9pZCI6ImRhdGFmbG93IiwiY2lkIjoiZGF0YWZsb3ciLCJncmFudF90eXBlIjoicGFzc3dvcmQiLCJ1c2VyX25hbWUiOiJzcHJpbmdyb2NrcyIsInJldl9zaWciOiJlOTkyMDQxNSIsInVzZXJfaWQiOiJlZTg4MDg4Ny00MWM2LTRkMWQtYjcyZC1hOTQ4MmFmNGViYTQiLCJhdXRoX3RpbWUiOjE1NzI1NTY5Nzl9.bqYvicyCPB5cIIu_2HEe5_c7nSGXKw7B8-reTvyYjOQ2qXSMq7gzS4LCCQ-CMcb4IirlDaFlQtZJSDE-_UsM33-ThmtFdx--TujvTR1u2nzot4Pq5A_ThmhhcCB21x6-RNNAJl9X9uUcT3gKfKVs3gjE0tm2K1vZfOkiGhjseIbwht2vBx0MnHteJpVW6U0pyCWG_tpBjrNBSj9yLoQZcqrtxYrWvPHaa9ljxfvaIsOnCZBGT7I552O1VRHWMj1lwNmRNZy5koJFPF7SbhiTM8eLkZVNdR3GEiofpzLCfoQXrr52YbiqjkYT94t3wz5C6u1JtBtgc2vq60HmR45bvg","refresh_token":"6ee95d017ada408697f2d19b04f7aa6c-r","expires_in":43199,"scope":"scim.userids openid sample.create cloud_controller.read password.write cloud_controller.write sample.view","jti":"0329c8ecdf594ee78c271e022138be9d"}
```

通过使用`token_format`参数,你可以请求令牌为:

* 不透明

* JWT

## 10. 配置-本地

### 10.1.功能切换

Spring 云数据流服务器提供了一组特定的特性,这些特性可以在启动时启用/禁用。这些特性包括用于以下方面的所有生命周期操作和 REST 端点(服务器和客户端实现,包括 shell 和 UI):

* Streams(需要 Skipper)

* 任务

* 任务调度程序

在启动数据流服务器时,可以通过设置以下布尔属性来启用和禁用这些功能:

* `spring.cloud.dataflow.features.streams-enabled`

* `spring.cloud.dataflow.features.tasks-enabled`

* `spring.cloud.dataflow.features.schedules-enabled`

默认情况下,Stream(需要 Skipper)和 Tasks 是启用的,而 Task Scheduler 是默认情况下禁用的。

REST`/about`端点提供关于已启用和禁用的特性的信息。

### 10.2.数据库

关系数据库用于存储流和任务定义以及执行任务的状态。 Spring 云数据流为**H2****MySQL****甲骨文****PostgreSQL****DB2****SQL 服务器**提供模式。当服务器启动时,架构会自动创建。

默认情况下, Spring 云数据流提供了**H2**数据库的嵌入式实例。**H2**数据库适合用于开发目的,但不建议用于生产用途。

|   |**H2**数据库不支持作为外部模式。|
|---|-----------------------------------------------------|

**MySQL**(通过 MariaDB 驱动程序)、**PostgreSQL****SQL 服务器**和嵌入式**H2**的 JDBC 驱动程序是可用的,无需额外配置。如果你正在使用任何其他数据库,那么你需要在服务器的 Classpath 上放置相应的 JDBC 驱动程序 JAR。

数据库属性可以作为环境变量或命令行参数传递给数据流服务器。

#### 10.2.1.MySQL

下面的示例展示了如何使用 MariaDB 驱动程序定义 MySQL 数据库连接。

```
java -jar spring-cloud-dataflow-server/target/spring-cloud-dataflow-server-2.9.2.jar \
    --spring.datasource.url=jdbc:mysql://localhost:3306/mydb \
    --spring.datasource.username= \
    --spring.datasource.password= \
    --spring.datasource.driver-class-name=org.mariadb.jdbc.Driver
```

最高*5.7*的 MySQL 版本可以与 MariaDB 驱动程序一起使用。从版本*8.0*开始,必须使用 MySQL 自己的驱动程序。

```
java -jar spring-cloud-dataflow-server/target/spring-cloud-dataflow-server-2.9.2.jar \
    --spring.datasource.url=jdbc:mysql://localhost:3306/mydb \
    --spring.datasource.username= \
    --spring.datasource.password= \
    --spring.datasource.driver-class-name=com.mysql.jdbc.Driver
```

|   |由于许可证限制,我们无法捆绑 MySQL 驱动程序。你需要自己将其添加到<br/>服务器的 Classpath 中。|
|---|-------------------------------------------------------------------------------------------------------------------------|

#### 10.2.2.马里亚布

下面的示例展示了如何使用命令行参数定义 MariaDB 数据库连接。

```
java -jar spring-cloud-dataflow-server/target/spring-cloud-dataflow-server-2.9.2.jar \
    --spring.datasource.url=jdbc:mariadb://localhost:3306/mydb?useMysqlMetadata=true \
    --spring.datasource.username= \
    --spring.datasource.password= \
    --spring.datasource.driver-class-name=org.mariadb.jdbc.Driver
```

从 MariaDB V2.4.1Connector 发行版开始,还需要向 JDBC URL 添加`useMysqlMetadata=true`。在 MySQL 和 MariaDB 完全转换为两个不同的数据库之前,这是一个必需的解决方案。

MariaDB 版本*10.3*引入了对真实数据库序列的支持,这是又一个突破性的变化,而这些数据库周围的工具完全支持 MySQL 和 MariaDB 作为单独的数据库类型。解决办法是使用较老的方言,而不是尝试使用序列。

```
java -jar spring-cloud-dataflow-server/target/spring-cloud-dataflow-server-2.9.2.jar \
    --spring.datasource.url=jdbc:mariadb://localhost:3306/mydb?useMysqlMetadata=true \
    --spring.datasource.username= \
    --spring.datasource.password= \
    --spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MariaDB102Dialect \
    --spring.datasource.driver-class-name=org.mariadb.jdbc.Driver
```

#### 10.2.3.PostgreSQL

下面的示例展示了如何使用命令行参数定义 PostgreSQL 数据库连接:

```
java -jar spring-cloud-dataflow-server/target/spring-cloud-dataflow-server-2.9.2.jar \
    --spring.datasource.url=jdbc:postgresql://localhost:5432/mydb \
    --spring.datasource.username= \
    --spring.datasource.password= \
    --spring.datasource.driver-class-name=org.postgresql.Driver
```

#### 10.2.4.SQL 服务器

下面的示例展示了如何使用命令行参数定义 SQL Server 数据库连接:

```
java -jar spring-cloud-dataflow-server/target/spring-cloud-dataflow-server-2.9.2.jar \
    --spring.datasource.url='jdbc:sqlserver://localhost:1433;databaseName=mydb' \
    --spring.datasource.username= \
    --spring.datasource.password= \
    --spring.datasource.driver-class-name=com.microsoft.sqlserver.jdbc.SQLServerDriver
```

#### 10.2.5.DB2

下面的示例展示了如何使用命令行参数定义 DB2 数据库连接:

```
java -jar spring-cloud-dataflow-server/target/spring-cloud-dataflow-server-2.9.2.jar \
    --spring.datasource.url=jdbc:db2://localhost:50000/mydb \
    --spring.datasource.username= \
    --spring.datasource.password= \
    --spring.datasource.driver-class-name=com.ibm.db2.jcc.DB2Driver
```

|   |由于许可限制,我们无法捆绑 DB2Driver。你需要自己将其添加到<br/>服务器的 Classpath 中。|
|---|-----------------------------------------------------------------------------------------------------------------------|

#### 10.2.6.甲骨文

下面的示例展示了如何使用命令行参数定义 Oracle 数据库连接:

```
java -jar spring-cloud-dataflow-server/target/spring-cloud-dataflow-server-2.9.2.jar \
    --spring.datasource.url=jdbc:oracle:thin:@localhost:1521/MYDB \
    --spring.datasource.username= \
    --spring.datasource.password= \
    --spring.datasource.driver-class-name=oracle.jdbc.OracleDriver
```

|   |由于许可证限制,我们无法捆绑 Oracle Driver。你需要自己将其添加到<br/>服务器的 Classpath 中。|
|---|--------------------------------------------------------------------------------------------------------------------------|

#### 10.2.7.添加自定义 JDBC 驱动程序

要为数据库添加自定义驱动程序(例如,Oracle),你应该重建数据流服务器,并将依赖项添加到 Maven `pom.xml`文件中。你需要修改`spring-cloud-dataflow-server`模块的 Maven `pom.xml`。GitHub 存储库中有 GA 发布标记,因此你可以切换到所需的 GA 标记,以便在生产就绪代码库中添加驱动程序。

要为 Spring 云数据流服务器添加自定义的 JDBC 驱动程序依赖项:

1. 选择与要重建和克隆 GitHub 存储库的服务器版本对应的标记。

2. 编辑 Spring-cloud-dataflow-server/ POM.xml,并在`dependencies`部分中添加所需的数据库驱动程序的依赖项。在下面的示例中,选择了一个 Oracle 驱动程序:

```
<dependencies>
...
  <dependency>
    <groupId>com.oracle.jdbc</groupId>
    <artifactId>ojdbc8</artifactId>
    <version>12.2.0.1</version>
  </dependency>
...
</dependencies>
```

1. 按照[Building Spring Cloud Data Flow](#building)中所述构建应用程序

还可以通过向 dataFlow-server.yml 文件添加必要的属性,在重建服务器时提供默认值,如下面的 PostgreSQL 示例所示:

```
spring:
  datasource:
    url: jdbc:postgresql://localhost:5432/mydb
    username: myuser
    password: mypass
    driver-class-name:org.postgresql.Driver
```

1. 或者,你可以使用你的构建文件构建自定义的云数据流服务器 Spring。如果需要添加驱动程序 JAR,则在[回购样本](https://github.com/spring-cloud/spring-cloud-dataflow-samples/tree/master/custom-dataflow-builds)中有自定义服务器构建的示例。

#### 10.2.8.模式处理

在默认情况下,数据库模式是用*飞道*管理的,如果可以给数据库用户足够的权限,这是很方便的。

下面是对*船长*服务器启动时发生的情况的描述:

* Flyway 检查`flyway_schema_history`表是否存在。

* 如果架构不是空的,那么基线(到版本 1)是否存在,因为如果使用共享 DB,*数据流*表可能就在适当的位置。

* 如果模式为空,Flyway 假定从头开始。

* 完成所有需要的模式迁移。

下面是对*数据流*服务器启动时发生的情况的描述:

* Flyway 检查`flyway_schema_history_dataflow`表是否存在。

* 如果架构不是空的,那么基线(到版本 1)是否存在,因为如果使用共享 DB,*船长*表可能就在适当的位置。

* 如果模式为空,Flyway 假定从头开始。

* 完成所有需要的模式迁移。

* 由于历史原因,如果我们检测到模式来自*1.7.x*行,我们将这些转换为*2.0.x*起所需的结构,并完全继续使用 Flyway。

|   |我们的源代码[schemas](https://github.com/spring-cloud/spring-cloud-dataflow/tree/master/spring-cloud-dataflow-server-core/src/main/resources/schemas)中有模式 DDL,如果*飞道*通过使用配置`spring.flyway.enabled=false`禁用,则可以手动使用它。如果公司的数据库<br/>受到限制,即应用程序本身无法创建模式,那么这是一个很好的选择。|
|---|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

### 10.3.部署人员属性

你可以使用[本地部署人员](https://github.com/spring-cloud/spring-cloud-deployer-local)的以下配置属性来自定义如何部署流和任务。当使用数据流 shell 进行部署时,可以使用语法`deployer.<appName>.local.<deployerPropertyName>`。参见下面的 shell 用法示例。这些属性还用于在数据流服务器和 Skipper 中的本地平台中配置[本地任务平台](#configuration-local-tasks)以部署流时使用。

|Deployer Property Name|                                              Description                                               |默认值|
|----------------------|--------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------|
|workingDirectoriesRoot|                Directory in which all created processes will run and create log files.                 |java.io.tmpdir|
|   envVarsToInherit   |Array of regular expression patterns for environment variables that are passed to launched applications.|Windows 上的 \<"TMP", "LANG", "LANGUAGE", "LC\_.\*", "PATH", "SPRING\_APPLICATION\_JSON"\>和 UNIX 上的 \<"TMP", "LANG", "LANGUAGE", "LC\_.\*", "PATH"\>|
|  deleteFilesOnExit   |                      Whether to delete created files and directories on JVM exit.                      |                                                                        true                                                                         |
|       javaCmd        |                                          Command to run java                                           |爪哇|
|   shutdownTimeout    |                            Max number of seconds to wait for app shutdown.                             |                                                                         30                                                                          |
|       javaOpts       |                          The Java Options to pass to the JVM, e.g -Dtest=foo                           |                                                                      \<none\>                                                                       |
|    inheritLogging    |    allow logging to be redirected to the output stream of the process that triggered child process.    |                                                                        false                                                                        |
|      debugPort       |                                       Port for remote debugging                                        |                                                                      \<none\>                                                                       |

例如,要在`ticktock`流中为 Time 应用程序设置 Java 选项,请使用以下流部署属性。

```
dataflow:> stream create --name ticktock --definition "time --server.port=9000 | log"
dataflow:> stream deploy --name ticktock --properties "deployer.time.local.javaOpts=-Xmx2048m -Dtest=foo"
```

为了方便起见,你可以设置`deployer.memory`属性来设置 Java 选项`-Xmx`,如下例所示:

```
dataflow:> stream deploy --name ticktock --properties "deployer.time.memory=2048m"
```

在部署时,如果在`deployer.<app>.local.javaOpts`属性中指定一个`-Xmx`选项以及`deployer.<app>.local.memory`选项的值,则`javaOpts`属性中的值具有优先权。此外,部署应用程序时的`javaOpts`属性集具有优于数据流服务器的`spring.cloud.deployer.local.javaOpts`属性的优先权。

### 10.4.伐木

Spring 云数据流`local`服务器被自动配置为使用`RollingFileAppender`进行日志记录。日志配置位于名为`logback-spring.xml`的文件中包含的 Classpath 上。

默认情况下,日志文件被配置为使用:

```
<property name="LOG_FILE" value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}}/spring-cloud-dataflow-server}"/>
```

使用`RollingPolicy`的注销配置:

```
<appender name="FILE"
			  class="ch.qos.logback.core.rolling.RollingFileAppender">
		<file>${LOG_FILE}.log</file>
		<rollingPolicy
				class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
			<!-- daily rolling -->
			<fileNamePattern>${LOG_FILE}.${LOG_FILE_ROLLING_FILE_NAME_PATTERN:-%d{yyyy-MM-dd}}.%i.gz</fileNamePattern>
			<maxFileSize>${LOG_FILE_MAX_SIZE:-100MB}</maxFileSize>
			<maxHistory>${LOG_FILE_MAX_HISTORY:-30}</maxHistory>
			<totalSizeCap>${LOG_FILE_TOTAL_SIZE_CAP:-500MB}</totalSizeCap>
		</rollingPolicy>
		<encoder>
			<pattern>${FILE_LOG_PATTERN}</pattern>
		</encoder>
	</appender>
```

要检查当前 Spring 云数据流服务器`java.io.tmpdir`服务器的`local`服务器,

```
jinfo <pid> | grep "java.io.tmpdir"
```

如果要更改或重写任何属性`LOG_FILE``LOG_TEMP``LOG_TEMP``LOG_FILE_MAX_SIZE``LOG_FILE_MAX_HISTORY``LOG_FILE_TOTAL_SIZE_CAP`,请将它们设置为系统属性。

### 10.5.溪流

数据流服务器将流的生命周期的管理委托给 Skipper 服务器。将配置属性`spring.cloud.skipper.client.serverUri`设置为 Skipper 的位置,例如

```
$ java -jar spring-cloud-dataflow-server-2.9.2.jar --spring.cloud.skipper.client.serverUri=https://192.51.100.1:7577/api
```

Show Streams 的配置是通过在 Skipper 服务器上配置`platform accounts`来部署的,以及部署到哪些平台。有关更多信息,请参见[platforms](https://docs.spring.io/spring-cloud-skipper/docs/current/reference/htmlsingle/#platforms)上的文档。

### 10.6.任务

数据流服务器负责部署任务。数据流启动的任务将其状态写入数据流服务器使用的同一数据库。对于 Spring 批处理作业的任务,作业和步骤执行数据也存储在该数据库中。与 Skipper 推出的流一样,任务可以在多个平台上启动。如果没有定义平台,则使用类[LocalDeployerProperties](https://github.com/spring-cloud/spring-cloud-deployer-local/blob/master/spring-cloud-deployer-local/src/main/java/org/springframework/cloud/deployer/spi/local/LocalDeployerProperties.java)的默认值创建一个名为`default`的平台,该值在表[本地部署人员属性](#configuration-local-deployer)中进行了总结

要为本地平台配置新的平台帐户,请在你的`application.yaml`文件中的`spring.cloud.dataflow.task.platform.local`节下通过另一种 Spring 启动支持的机制提供一个条目。在下面的示例中,创建了两个名为`localDev``localDevDebug`的本地平台帐户。诸如`shutdownTimeout``javaOpts`之类的键是本地部署程序属性。

```
spring:
  cloud:
    dataflow:
      task:
        platform:
          local:
            accounts:
              localDev:
                shutdownTimeout: 60
                javaOpts: "-Dtest=foo -Xmx1024m"
              localDevDebug:
                javaOpts: "-Xdebug -Xmx2048m"
```

|   |通过将一个平台定义为`default`,你可以跳过使用`platformName`,否则将需要使用该平台。|
|---|------------------------------------------------------------------------------------------------------------------------|

启动任务时,使用 Task Launch 选项`--platformName`传递平台帐户名的值`platformName`如果不传递`platformName`的值,则将使用该值`default`

|   |当将任务部署到多个平台时,任务的配置需要连接到与数据流服务器相同的数据库。|
|---|-----------------------------------------------------------------------------------------------------------------------------------------|

你可以配置本地运行的数据流服务器,以便将任务部署到 Cloud Foundry 或 Kubernetes。有关更多信息,请参见[Cloud Foundry 任务平台配置](#configuration-cloudfoundry-tasks)[Kubernetes 任务平台配置](#configuration-kubernetes-tasks)部分。

[dataflow.spring.io](http://dataflow.spring.io)上的[对任务的多平台支持](https://dataflow.spring.io/docs/recipes/multi-platform-deployment/)一节中提供了跨多个平台启动和调度任务的详细示例。

##### 开始船长

```
git clone https://github.com/spring-cloud/spring-cloud-skipper.git
cd spring-cloud/spring-cloud-skipper
./mvnw clean package -DskipTests=true
java -jar spring-cloud-skipper-server/target/spring-cloud-skipper-server-2.2.0.BUILD-SNAPSHOT.jar
```

##### 启动 Spring 云数据流

```
git clone https://github.com/spring-cloud/spring-cloud-dataflow.git
cd spring-cloud-dataflow
./mvnw clean package -DskipTests=true
cd ..
```

创建一个包含以下内容的 YAML 文件 scdf.yml:

```
spring:
  cloud:
    dataflow:
      security:
        authorization:
          provider-role-mappings:
            uaa:
              map-oauth-scopes: true
              role-mappings:
                ROLE_CREATE: foo.create
                ROLE_DEPLOY: foo.create
                ROLE_DESTROY: foo.create
                ROLE_MANAGE: foo.create
                ROLE_MODIFY: foo.create
                ROLE_SCHEDULE: foo.create
                ROLE_VIEW: foo.view
  security:
    oauth2:
      client:
        registration:
          uaa:
            redirect-uri: '{baseUrl}/login/oauth2/code/{registrationId}'
            authorization-grant-type: authorization_code
            client-id: dataflow
            client-secret: dataflow
            scope:                                                       (1)
            - openid
            - foo.create
            - foo.view
        provider:
          uaa:
            jwk-set-uri: http://uaa:8080/uaa/token_keys
            token-uri: http://uaa:8080/uaa/oauth/token
            user-info-uri: http://uaa:8080/uaa/userinfo                  (2)
            user-name-attribute: user_name
            authorization-uri: http://uaa:8080/uaa/oauth/authorize
      resourceserver:
        opaquetoken:                                                     (3)
          introspection-uri: http://uaa:8080/uaa/introspect
          client-id: dataflow
          client-secret: dataflow
```

|**1**|如果你使用作用域来标识角色,请确保还请求<br/>相关的作用域,例如`dataflow.view``dataflow.create`,并且不要忘记请求`openid`作用域|
|-----|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|**2**|用于检索配置文件信息,例如用于显示目的的用户名(强制使用)|
|**3**|用于令牌内省和验证(强制)|

当向 Spring 云数据流传递外部检索的(不透明的)OAuth 访问令牌时,`introspection-uri`属性尤其重要。 Spring 在这种情况下,云数据流将获取 OAuth 访问,并使用 UAA 的[自检令牌端点](https://docs.cloudfoundry.org/api/uaa/version/74.4.0/index.html#introspect-token)不仅检查令牌的有效性,而且还从 UAA 检索相关联的 OAuth 范围

最后启动 Spring 云数据流:

```
java -jar spring-cloud-dataflow/spring-cloud-dataflow-server/target/spring-cloud-dataflow-server-2.4.0.BUILD-SNAPSHOT.jar --spring.config.additional-location=scdf.yml
```

##### 角色映射

默认情况下,所有角色都分配给登录到 Spring 云数据流的用户。但是,你可以设置属性:

`spring.cloud.dataflow.security.authorization.provider-role-mappings.uaa.map-oauth-scopes: true`

这将指示底层`DefaultAuthoritiesExtractor`将 OAuth 范围映射到相应的权限。支持以下范围:

* 范围`dataflow.create`映射到`CREATE`角色

* 范围`dataflow.deploy`映射到`DEPLOY`角色

* 范围`dataflow.destroy`映射到`DESTROY`角色

* 范围`dataflow.manage`映射到`MANAGE`角色

* 范围`dataflow.modify`映射到`MODIFY`角色

* 范围`dataflow.schedule`映射到`SCHEDULE`角色

* 范围`dataflow.view`映射到`VIEW`角色

此外,你还可以将任意范围映射到每个数据流角色:

```
spring:
  cloud:
    dataflow:
      security:
        authorization:
          provider-role-mappings:
            uaa:
              map-oauth-scopes: true                                    (1)
              role-mappings:
                ROLE_CREATE: dataflow.create                            (2)
                ROLE_DEPLOY: dataflow.deploy
                ROLE_DESTROY: dataflow.destoy
                ROLE_MANAGE: dataflow.manage
                ROLE_MODIFY: dataflow.modify
                ROLE_SCHEDULE: dataflow.schedule
                ROLE_VIEW: dataflow.view
```

|**1**|启用从 OAuth 范围到数据流角色的显式映射支持|
|-----|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|**2**|当启用角色映射支持时,你必须为<br/>所有 7 个 Spring 云数据流角色[Cloud Foundry Deployer 属性](#configuration-cloudfoundry-deployer)**角色 \_ 部署****角色 \_destroy****角色 \_ 管理****角色 \_ 修改****角色 \_ 日程安排**提供映射。|

|   |你可以将 OAuth 范围分配给多个 Spring 云数据流角色,从而使你在授权配置的粒度方面具有灵活性。|
|---|----------------------------------------------------------------------------------------------------------------------------------------------------------|

#### 10.6.4.LDAP 身份验证

LDAP 身份验证(轻量级目录访问协议)是由 Spring 云数据流使用的 UAA 间接提供的。UAA 本身提供[全面的 LDAP 支持](https://github.com/cloudfoundry/uaa/blob/develop/docs/UAA-LDAP.md)

|   |虽然你可以使用自己的 OAuth2 身份验证服务器,但是这里记录的 LDAP 支持<br/>需要使用 UAA 作为身份验证服务器。对于任何<br/>其他提供者,请参阅该特定提供者的文档。|
|---|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

UAA 支持使用以下模式对 LDAP(轻量级目录访问协议)服务器进行身份验证:

* [直接绑定](https://github.com/cloudfoundry/uaa/blob/develop/docs/UAA-LDAP.md#ldap-search-and-bind)

* [搜索和绑定](https://github.com/cloudfoundry/uaa/blob/develop/docs/UAA-LDAP.md#ldap-bind)

* [搜索和比较](https://github.com/cloudfoundry/uaa/blob/develop/docs/UAA-LDAP.md#ldap-search-and-compare)

|   |当与外部身份提供程序(例如 LDAP)集成时,UAA 内的身份验证<br/>变为**锁链**。UAA 首先尝试使用<br/>用户的凭据,在外部提供者<br/>ldap 之前对 UAA 用户存储区进行身份验证。有关更多信息,请参见*用户帐户和身份验证 LDAP 集成*Github 文档中的[链式认证](https://github.com/cloudfoundry/uaa/blob/develop/docs/UAA-LDAP.md#chained-authentication)。|
|---|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

##### LDAP 角色映射

OAuth2 身份验证服务器(UAA)为[将 LDAP 组映射到 OAuth 范围](https://github.com/cloudfoundry/uaa/blob/develop/docs/UAA-LDAP.md#scopes)提供了全面的支持。

存在以下备选方案:

* `ldap/ldap-groups-null.xml`不会映射任何组

* `ldap/ldap-groups-as-scopes.xml`将从一个 LDAP 属性检索组名称。例如`CN`

* `ldap/ldap-groups-map-to-scopes.xml`组将使用外部 \_group\_ 映射表映射到 UAA 组。

这些值是通过配置属性`ldap.groups.file controls`指定的。在封面下,这些值引用一个 Spring XML 配置文件。

|   |在测试和开发过程中,可能需要对 LDAP 组和用户进行<br/>的频繁更改,并查看反映在 UAA 中的更改。但是,用户[secrets](https://kubernetes.io/docs/concepts/configuration/secret/)信息在登录期间被缓存。下面的脚本<br/>有助于快速检索更新的信息:<br/><br/>```<br/>#!/bin/bash<br/>uaac token delete --all<br/>uaac target http://localhost:8080/uaa<br/>uaac token owner get cf <username> -s "" -p  <password><br/>uaac token client get admin -s adminsecret<br/>uaac user get <username><br/>```|
|---|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

##### LDAP 安全和 UAA 示例应用程序

为了快速启动和运行并帮助你了解安全架构,我们在 Github 上提供了[LDAP 安全性和 UAA 示例](https://github.com/spring-cloud/spring-cloud-dataflow-samples/tree/master/security-ldap-uaa-example)

|   |这只是一个演示/示例应用程序,不应在生产中使用。|
|---|------------------------------------------------------------------------------|

该设置包括:

* Spring 云数据流服务器

* Skipper 服务器

* CloudFoundry 用户帐户和认证(UAA)服务器

* 轻量级目录访问协议服务器(由[Apache 目录服务器](https://directory.apache.org/)提供)

最后,作为本示例的一部分,你将学习如何使用此安全设置配置和启动一个组合任务。

#### 10.6.5. Spring 安全 OAuth2 资源/授权服务器示例

对于本地测试和开发,你还可以使用[Spring Security OAuth](https://projects.spring.io/spring-security-oauth/)提供的资源和授权服务器支持。它允许你使用以下简单的注释轻松地创建自己的(非常基本的)OAuth2 服务器:

* `@EnableResourceServer`

* `@EnableAuthorizationServer`

|   |实际上,UAA 使用了 Spring 安全 OAuth2 下的覆盖,因此基本端点<br/>是相同的。|
|---|--------------------------------------------------------------------------------------------------------|

可以在以下位置找到一个工作示例应用程序:[https://github.com/ghillert/oauth-test-server/](https://github.com/ghillert/oauth-test-server/)

复制该项目并配置 Spring 云数据流,其中包含相应的客户机 ID 和客户机秘密:

```
security:
  oauth2:
    client:
      client-id: myclient
      client-secret: mysecret
      access-token-uri: http://127.0.0.1:9999/oauth/token
      user-authorization-uri: http://127.0.0.1:9999/oauth/authorize
    resource:
      user-info-uri: http://127.0.0.1:9999/me
      token-info-uri: http://127.0.0.1:9999/oauth/check_token
```

|   |此示例应用程序不用于生产。|
|---|----------------------------------------------------------|

#### 10.6.6.数据流壳身份验证

使用 shell 时,可以通过用户名和密码提供凭据,也可以通过指定*凭据-提供者*命令提供凭据。如果你的 OAuth2 提供程序支持*密码*grant 类型,那么你可以通过以下方式启动*数据流壳*:

```
$ java -jar spring-cloud-dataflow-shell-2.9.2.jar         \
  --dataflow.uri=http://localhost:9393                                \   (1)
  --dataflow.username=my_username                                     \   (2)
  --dataflow.password=my_password                                     \   (3)
  --skip-ssl-validation  true                                         \   (4)
```

|**1**|可选的,默认为[本地主机:9393](http://localhost:9393)。|
|-----|----------------------------------------------------------------------------------------------------------------|
|**2**|强制性的。|
|**3**|如果未提供密码,则会提示用户输入密码。|
|**4**|可选的,默认为`false`,忽略证书错误(当使用自签名证书时)。谨慎使用!|

|   |请记住,当启用 Spring 云数据流的身份验证时,如果你想通过用户名/密码身份验证使用 shell,则底层的 OAuth2 提供者支持OAuth2grant 类型。|
|---|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

在 Data Flow 壳牌 中,你还可以使用以下命令提供凭据:

```
server-unknown:>dataflow config server                                \
  --uri  http://localhost:9393                                        \   (1)
  --username myuser                                                   \   (2)
  --password mysecret                                                 \   (3)
  --skip-ssl-validation  true                                         \   (4)
```

|**1**|可选的,默认为[本地主机:9393](http://localhost:9393)。|
|-----|-------------------------------------------------------------------------------------------|
|**2**|强制..|
|**3**|如果启用了安全性,但未提供密码,则会提示用户使用该密码。|
|**4**|可选的,忽略证书错误(当使用自签名证书时)。谨慎使用!|

下图显示了连接到数据流服务器并对其进行身份验证的典型 shell 命令:

![在 shell 中使用数据流服务器进行目标和身份验证](https://raw.githubusercontent.com/spring-cloud/spring-cloud-dataflow/master/spring-cloud-dataflow-docs/src/main/asciidoc/images/dataflow-security-shell-target.png)

2202
图 1.在 shell 中使用数据流服务器进行目标和身份验证
D
dallascao 已提交
2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673

一旦成功锁定目标,你应该会看到以下输出:

```
dataflow:>dataflow config info
dataflow config info

╔═══════════╤═══════════════════════════════════════╗
║Credentials│[username='my_username, password=****']║
╠═══════════╪═══════════════════════════════════════╣
║Result     │                                       ║
║Target     │http://localhost:9393                  ║
╚═══════════╧═══════════════════════════════════════╝
```

或者,你可以指定*凭据-提供者*命令,以便直接传入一个承载令牌,而不是提供用户名和密码。这可以在 shell 中进行,或者在启动 shell 时提供`--dataflow.credentials-provider-command`命令行参数。

|   |当使用*凭据-提供者*命令时,请注意你的<br/>指定命令**必须**返回一个*不记名令牌*(访问令牌前缀为*承担者*)。*不记名令牌*例如,在 UNIX 环境中,可以使用以下简单化命令:<br/>```<br/>$ java -jar spring-cloud-dataflow-shell-2.9.2.jar \<br/>  --dataflow.uri=http://localhost:9393 \<br/>  --dataflow.credentials-provider-command="echo Bearer 123456789"<br/>```|
|---|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

### 10.7.关于配置

Spring 关于 RESTful API 结果的云数据流包含显示名称、版本,以及(如果指定的话)用于构成 Spring 云数据流的每个主要依赖项的 URL。结果(如果启用)还包含 Shell 依赖项的 SHA1 和或 SHA256 校验和。通过设置以下属性,可以配置为每个依赖项返回的信息:

* Spring.cloud.dataflow.version-info. Spring-cloud-dataflow-core.name:用于核心的名称。

* Spring.cloud.dataflow.version-info. Spring-cloud-dataflow-core.version:用于内核的版本。

* Spring.cloud.dataflow.version-info. Spring-cloud-dataflow-dashboard.name:用于仪表板的名称。

* Spring.cloud.dataflow.version-info. Spring-cloud-dataflow-dashboard.version:用于仪表板的版本。

* Spring.cloud.dataflow.version-info. Spring-cloud-dataflow-implementation.name:用于实现的名称。

* Spring.cloud.dataflow.version-info. Spring-cloud-dataflow-implementation.version:用于实现的版本。

* Spring.cloud.dataflow.version-info. Spring-cloud-dataflow-shell.name:用于 shell 的名称。

* Spring.cloud.dataflow.version-info. Spring-cloud-dataflow-shell.version:用于 shell 的版本。

* Spring.cloud.dataflow.version-info. Spring-cloud-dataflow-shell.url:用于下载 shell 依赖项的 URL。

* Spring.cloud.dataflow.version-info. Spring-cloud-dataflow-shell.checksum-sha1:与 shell 依赖项信息一起返回的 sha1 校验和值。

* Spring.cloud.dataflow.version-info. Spring-cloud-dataflow-shell.checksum-sha256:与 shell 依赖项信息一起返回的 sha256 校验和值。

* Spring.cloud.dataflow.version-info. Spring-cloud-dataflow-shell.checksum-sha1-url:如果没有指定`spring.cloud.dataflow.version-info.spring-cloud-dataflow-shell.checksum-sha1`,SCDF 使用在此 URL 处指定的文件的内容进行校验和。

* Spring.cloud.dataflow.version-info. Spring-cloud-dataflow-shell.checksum-sha256-url:如果没有指定`port`,SCDF 使用在此 URL 处指定的文件的内容进行校验和。

#### 10.7.1.启用 shell 校验和值

默认情况下,不会为 shell 依赖项显示校验和值.如果需要启用此功能,请将`spring.cloud.dataflow.version-info.dependency-fetch.enabled`属性设置为 true。

#### 10.7.2.为 URL 保留的值

你可以将保留的值(由花括号包围)插入到 URL 中,以确保链接是最新的:

* 存储库:如果使用构建快照、里程碑或数据流的候选版本,则存储库引用 repo- Spring-io 存储库。否则,它指的是 Maven central。

* 版本:插入 JAR/ POM 的版本。

例如,如果你使用 Spring 云数据流 shell 的 1.2.3.3.Release 版本,则`[myrepository/org/springframework/cloud/spring-cloud-dataflow-shell/{version}/spring-cloud-dataflow-shell-{version}.jar](https://myrepository/org/springframework/cloud/spring-cloud-dataflow-shell/{version}/spring-cloud-dataflow-shell-{version}.jar)`生成`[myrepository/org/springframework/cloud/spring-cloud-dataflow-shell/1.2.3.RELEASE/spring-cloud-dataflow-shell-1.2.3.RELEASE.jar](https://myrepository/org/springframework/cloud/spring-cloud-dataflow-shell/1.2.3.RELEASE/spring-cloud-dataflow-shell-1.2.3.RELEASE.jar)`

## 11. 配置-Cloud Foundry

本节描述了如何配置 Spring 云数据流服务器的特性,例如安全性和使用哪个关系数据库。它还描述了如何配置 Spring Cloud Data Flow Shell 的功能。

### 11.1.功能切换

Data Flow Server 提供了一组特定的特性,你可以在启动时启用或禁用这些特性。这些特性包括用于以下方面的所有生命周期操作和 REST 端点(服务器、客户端实现,包括 Shell 和 UI):

* 溪流

* 任务

在启动数据流服务器时,可以通过设置以下布尔属性来启用或禁用这些功能:

* `spring.cloud.dataflow.features.streams-enabled`

* `spring.cloud.dataflow.features.tasks-enabled`

默认情况下,所有功能都已启用。

REST 端点(`/features`)提供有关已启用和已禁用功能的信息。

### 11.2.部署人员属性

你可以使用数据流服务器的[Cloud Foundry 部署人员](https://github.com/spring-cloud/spring-cloud-deployer-cloudfoundry)的以下配置属性来定制应用程序的部署方式。在使用数据流壳层进行部署时,可以使用语法`deployer.<appName>.cloudfoundry.<deployerPropertyName>`。参见下面的 shell 用法示例。在配置数据流服务器中的[Cloud Foundry 任务平台](#configuration-cloudfoundry-tasks)和 Skipper 中的 Kubernetes 平台以部署流时,也会使用这些属性。

| Deployer Property Name  |说明|                                                                                                                   Default Value                                                                                                                   |
|-------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|        services         |要绑定到已部署应用程序的服务的名称。|                                                                                                                     \<none\>                                                                                                                      |
|          host           |作为路由的一部分使用的主机名。|                                                                                                         hostname derived by Cloud Foundry                                                                                                         |
|         domain          |当映射应用程序的路由时要使用的域。|                                                                                                                     \<none\>                                                                                                                      |
|         routes          |应用程序应该绑定到的路由列表。与主机和域互斥。|                                                                                                                     \<none\>                                                                                                                      |
|        buildpack        |用于部署应用程序的 buildpack。不赞成使用构建包。|                                                                 [github.com/cloudfoundry/java-buildpack.git#v4.29.1](https://github.com/cloudfoundry/java-buildpack.git#v4.29.1)                                                                  |
|       buildpacks        |用于部署应用程序的构建包列表。|                                                                 [github.com/cloudfoundry/java-buildpack.git#v4.29.1](https://github.com/cloudfoundry/java-buildpack.git#v4.29.1)                                                                  |
|         memory          |要分配的内存量。默认单元是 mebibytes,支持“m”和“g”后缀|                                                                                                                       1024m                                                                                                                       |
|          disk           |要分配的磁盘空间量。默认的单元是支持的 mebibytes、“m”和“g”后缀。|                                                                                                                       1024m                                                                                                                       |
|       healthCheck       |在已部署的应用程序上执行的健康检查的类型。值可以是 HTTP、None、Process 和 Port|                                                                                                                       PORT                                                                                                                        |
| healthCheckHttpEndpoint |HTTP 健康检查将使用的路径,|                                                                                                                      /health                                                                                                                      |
|   healthCheckTimeout    |健康检查的超时值(以秒为单位)。|                                                                                                                        120                                                                                                                        |
|        instances        |要运行的实例的数量。|                                                                                                                         1                                                                                                                         |
|enableRandomAppNamePrefix|标记,以启用在应用程序名称前加上一个随机前缀。|                                                                                                                       true                                                                                                                        |
|       apiTimeout        |用于阻止 API 调用的超时(以秒为单位)。|                                                                                                                        360                                                                                                                        |
|      statusTimeout      |状态 API 操作的超时(以毫秒为单位)|                                                                                                                       5000                                                                                                                        |
|useSpringApplicationJson |标志,指示应用程序属性是被输入`SPRING_APPLICATION_JSON`还是作为单独的环境变量。|                                                                                                                       true                                                                                                                        |
|     stagingTimeout      |为安装应用程序分配的超时时间。|                                                                                                                    15 minutes                                                                                                                     |
|     startupTimeout      |为启动应用程序分配的超时时间。|                                                                                                                     5 minutes                                                                                                                     |
|      appNamePrefix      |用作已部署应用程序名称前缀的字符串|                                                                     The Spring Boot property `spring.application.name` of the application that is using the deployer library.                                                                     |
|      deleteRoutes       |在取消部署应用程序时是否也要删除路由。|                                                                                                                       true                                                                                                                        |
|        javaOpts         |要传递给 JVM 的 Java 选项,例如-dtest=foo|                                                                                                                     \<none\>                                                                                                                      |
|    push任务Enabled     |是推送任务应用程序,还是假设应用程序在启动时已经存在。|                                                                                                                       true                                                                                                                        |
|autoDeleteMavenArtifacts |是否在部署时从本地存储库中自动删除 Maven 工件。|                                                                                                                       true                                                                                                                        |
|       env.\<key\>       |定义顶层环境变量。这对于自定义[Java 构建包配置](https://github.com/cloudfoundry/java-buildpack#configuration-and-extension)非常有用,因为 Java 构建包不识别`SPRING_APPLICATION_JSON`,这些变量必须作为顶级环境变量包含在应用程序清单中。|The deployer determines if the app has [Java CfEnv](https://github.com/pivotal-cf/java-cfenv) in its classpath. If so, it applies the required [configuration](https://github.com/pivotal-cf/java-cfenv#pushing-your-application-to-cloud-foundry).|

以下是使用 Cloud Foundry 部署属性的一些示例:

* 你可以设置用于部署每个应用程序的构建包。例如,要使用 Java 脱机 buildback,请设置以下环境变量:

```
cf set-env dataflow-server SPRING_CLOUD_DATAFLOW_TASK_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_DEPLOYMENT_BUILDPACKS java_buildpack_offline
```

* 现在不赞成设置`buildpack`,而赞成`buildpacks`,它允许你在需要时传递多个参数。有关这方面的更多信息,请访问[构建包如何工作](https://docs.cloudfoundry.org/buildpacks/understand-buildpacks.html)

* 你可以使用[本地主机:9393](http://localhost:9393)环境变量自定义 Cloud Foundry 使用的健康检查机制,以判断应用程序是否正在运行。当前支持的选项是`http`(默认)、`port``none`

你还可以分别设置指定基于 HTTP 的健康检查端点和超时的环境变量:`SPRING_CLOUD_DATAFLOW_TASK_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_DEPLOYMENT_HEALTH_CHECK_TIMEOUT``SPRING_CLOUD_DATAFLOW_TASK_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_DEPLOYMENT_HEALTH_CHECK_TIMEOUT`。这些默认值为`/health`( Spring 引导默认位置)和`120`秒。

* 你还可以通过使用 DSL 指定部署属性。例如,如果要将`http`应用程序分配的内存设置为 512M,并将 MySQL 服务绑定到`120`应用程序,则可以运行以下命令:

```
dataflow:> stream create --name mysqlstream --definition "http | jdbc --tableName=names --columns=name"
dataflow:> stream deploy --name mysqlstream --properties "deployer.http.memory=512, deployer.jdbc.cloudfoundry.services=mysql"
```

|   |你可以为流应用程序和任务应用程序分别配置这些设置。要更改任务的设置,请在属性名称中将<br/>替换为`STREAM`,如下例所示:<br/><br/>```<br/>cf set-env dataflow-server SPRING_CLOUD_DATAFLOW_TASK_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_DEPLOYMENT_MEMORY 512<br/>```|
|---|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

### 11.3.任务

数据流服务器负责部署任务。数据流启动的任务将其状态写入数据流服务器使用的同一数据库。对于 Spring 批处理作业的任务,作业和步骤执行数据也存储在该数据库中。与 Skipper 一样,任务可以在多个平台上启动。当数据流在 Cloud Foundry 上运行时,必须定义一个任务平台。要配置以 Cloud Foundry 为目标的新平台帐户,请在你的`application.yaml`文件中的`spring.cloud.dataflow.task.platform.cloudfoundry`节下通过另一种 Spring 启动支持的机制提供一个条目。在下面的示例中,创建了两个名为`dev``qa`的 Cloud Foundry 平台帐户。如`memory``disk`的键是[Cloud Foundry Deployer 属性](#configuration-cloudfoundry-deployer)

```
spring:
  cloud:
    dataflow:
      task:
        platform:
          cloudfoundry:
            accounts:
              dev:
                connection:
                  url: https://api.run.pivotal.io
                  org: myOrg
                  space: mySpace
                  domain: cfapps.io
                  username: [email protected]
                  password: drowssap
                  skipSslValidation: false
                deployment:
                  memory: 512m
                  disk: 2048m
                  instances: 4
                  services: rabbit,mysql
                  appNamePrefix: dev1
              qa:
                connection:
                  url: https://api.run.pivotal.io
                  org: myOrgQA
                  space: mySpaceQA
                  domain: cfapps.io
                  username: [email protected]
                  password: drowssap
                  skipSslValidation: true
                deployment:
                  memory: 756m
                  disk: 724m
                  instances: 2
                  services: rabbitQA,mysqlQA
                  appNamePrefix: qa1
```

|   |通过将一个平台定义为`platformName`,你可以跳过使用`platformName`,否则将需要使用该平台。|
|---|------------------------------------------------------------------------------------------------------------------------|

启动任务时,使用 Task Launch 选项`--platformName`传递平台帐户名的值`platformName`如果不传递`platformName`的值,将使用该值`default`

|   |当将任务部署到多个平台时,任务的配置需要连接到与数据流服务器相同的数据库。|
|---|-----------------------------------------------------------------------------------------------------------------------------------------|

你可以将 Cloud Foundry 上的数据流服务器配置为将任务部署到 Cloud Foundry 或 Kubernetes。有关更多信息,请参见[Kubernetes 任务平台配置](#configuration-kubernetes-tasks)一节。

[dataflow.spring.io](http://dataflow.spring.io)上的[对任务的多平台支持](https://dataflow.spring.io/docs/recipes/multi-platform-deployment/)一节中提供了跨多个平台启动和调度任务的详细示例。

### 11.4.应用程序名称和前缀

为了帮助避免在 Cloud Foundry 中与跨空间的路由发生冲突,可以使用一种命名策略,该策略为部署的应用程序提供一个随机的前缀,并且在默认情况下启用。你可以使用`cf set-env`命令重写`cf set-env`并设置相应的属性。

例如,如果你想禁用随机化,可以使用以下命令重写它:

```
cf set-env dataflow-server SPRING_CLOUD_DATAFLOW_TASK_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_DEPLOYMENT_ENABLE_RANDOM_APP_NAME_PREFIX false
```

### 11.5.自定义路线

作为随机名称的替代方法,或者为了更好地控制已部署应用程序所使用的主机名,你可以使用自定义部署属性,如下例所示:

```
dataflow:>stream create foo --definition "http | log"

sdataflow:>stream deploy foo --properties "deployer.http.cloudfoundry.domain=mydomain.com,
                                          deployer.http.cloudfoundry.host=myhost,
                                          deployer.http.cloudfoundry.route-path=my-path"
```

前面的示例将`http`应用程序绑定到`[myhost.mydomain.com/my-path](https://myhost.mydomain.com/my-path)`URL。注意,这个示例显示了**全部**的可用定制选项。在实践中,你只能使用三个中的一个或两个。

### 11.6.Docker 应用程序

从版本 1.2 开始,通过使用用于 Cloud Foundry 的数据流,可以注册和部署基于 Docker 的应用程序作为流和任务的一部分。

如果使用 Spring boot 和基于 RabbitMQ 的 Docker 映像,则可以提供一个公共部署属性,以方便将应用程序绑定到 RabbitMQ 服务。假设你的 RabbitMQ 服务名为`rabbit`,那么你可以提供以下内容:

```
cf set-env dataflow-server SPRING_APPLICATION_JSON '{"spring.cloud.dataflow.applicationProperties.stream.spring.rabbitmq.addresses": "${vcap.services.rabbit.credentials.protocols.amqp.uris}"}'
```

对于 Spring 云任务应用程序,如果使用名为`mysql`的数据库服务实例,则可以使用类似于以下内容的方法:

```
cf set-env SPRING_DATASOURCE_URL '${vcap.services.mysql.credentials.jdbcUrl}'
cf set-env SPRING_DATASOURCE_USERNAME '${vcap.services.mysql.credentials.username}'
cf set-env SPRING_DATASOURCE_PASSWORD '${vcap.services.mysql.credentials.password}'
cf set-env SPRING_DATASOURCE_DRIVER_CLASS_NAME 'org.mariadb.jdbc.Driver'
```

对于非 Java 或非引导应用程序,Docker 应用程序必须解析`VCAP_SERVICES`变量,才能绑定到任何可用的服务。

|   |传递应用程序属性<br/><br/>当使用非引导应用程序时,你可能希望通过使用传统的<br/>环境变量来传递应用程序属性,而不是使用特殊的`SPRING_APPLICATION_JSON`变量。要做到这一点,请分别为流和任务设置以下变量<br/>:<br/><br/>`TRUST_CERTS`|
|---|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

### 11.7.应用程序级服务绑定

在 Cloud Foundry 中部署流时,你可以利用特定于应用程序的服务绑定,因此并不是所有服务都为 Spring 云数据流精心编制的所有应用程序进行了全局配置。

例如,如果你希望在以下流定义中仅为`mysql`应用程序提供`jdbc`服务绑定,则可以将服务绑定作为部署属性传递:

```
dataflow:>stream create --name httptojdbc --definition "http | jdbc"
dataflow:>stream deploy --name httptojdbc --properties "deployer.jdbc.cloudfoundry.services=mysqlService"
```

其中`mysqlService`是专门绑定到`jdbc`应用程序的服务的名称,而`http`应用程序不通过这种方法获得绑定。

如果有多个服务要绑定,则可以将它们作为逗号分隔的项传递(例如:`deployer.jdbc.cloudfoundry.services=mysqlService,someService`)。

### 11.8.配置服务绑定参数

CloudFoundry API 支持在绑定服务实例时提供配置参数。一些服务代理要求或推荐绑定配置。例如,使用 CF CLI 绑定[谷歌云平台服务](https://docs.pivotal.io/partners/gcp-sb/using.html)看起来像是:

```
cf bind-service my-app my-google-bigquery-example -c '{"role":"bigquery.user"}'
```

同样,[NFS 卷服务](https://docs.cloudfoundry.org/devguide/services/using-vol-services.html)支持绑定配置,例如:

```
cf bind-service my-app nfs_service_instance -c '{"uid":"1000","gid":"1000","mount":"/var/volume1","readonly":true}'
```

从版本 2.0 开始,Cloud Foundry 的数据流允许你提供绑定配置参数,可以在应用程序级别或服务器级别`cloudfoundry.services`部署属性中提供。例如,要绑定到 NFS 服务,如上所示:

```
dataflow:> stream deploy --name mystream --properties "deployer.<app>.cloudfoundry.services='nfs_service_instance uid:1000,gid:1000,mount:/var/volume1,readonly:true'"
```

该格式旨在与数据流 DSL 解析器兼容。通常,`cloudfoundry.services`部署属性接受以逗号分隔的值。由于逗号也用于分离配置参数,并避免空格问题,因此包括配置参数在内的任何项目都必须用单引号括起来。有效的价值包括:

```
rabbitmq,'nfs_service_instance uid:1000,gid:1000,mount:/var/volume1,readonly:true',mysql,'my-google-bigquery-example role:bigquery.user'
```

|   |单引号中允许空格,并且可以使用`=`代替`:`来分隔键值对。|
|---|--------------------------------------------------------------------------------------------------------|

### 11.9.用户提供的服务

除了市场服务,Cloud Foundry 还支持[用户提供的服务](https://docs.cloudfoundry.org/devguide/services/user-provided.html)。在整个参考手册中,都提到了常规服务,但也没有排除使用用户提供的服务,无论是作为消息传递中间件使用(例如,如果你想要使用外部的 Apache Kafka 安装)或某些流应用程序(例如,Oracle 数据库)使用。

现在,我们回顾一个从 UPS 提取和提供连接凭据的示例。

下面的示例显示了 Apache Kafka 的 UPS 设置示例:

```
cf create-user-provided-service kafkacups -p '{”brokers":"HOST:PORT","zkNodes":"HOST:PORT"}'
```

UPS 凭据被包装在`VCAP_SERVICES`中,并且可以直接在流定义中提供它们,如下例所示。

```
stream create fooz --definition "time | log"
stream deploy fooz --properties "app.time.spring.cloud.stream.kafka.binder.brokers=${vcap.services.kafkacups.credentials.brokers},app.time.spring.cloud.stream.kafka.binder.zkNodes=${vcap.services.kafkacups.credentials.zkNodes},app.log.spring.cloud.stream.kafka.binder.brokers=${vcap.services.kafkacups.credentials.brokers},app.log.spring.cloud.stream.kafka.binder.zkNodes=${vcap.services.kafkacups.credentials.zkNodes}"
```

### 11.10.数据库连接池

在 DataFlow2.0 中, Spring Cloud Connector 库不再用于创建数据源。现在使用的库[java-cfenv](https://github.com/pivotal-cf/java-cfenv)允许你设置[Spring Boot properties](https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-connect-to-production-database)来配置连接池。

### 11.11.最大磁盘配额

默认情况下,Cloud Foundry 中的每个应用程序都从 1G 磁盘配额开始,并且可以将其调整为默认的最大 2G。通过使用 Pivotal Cloud Foundry 的 Ops Manager GUI,默认的最大值也可以覆盖到 10G。

这种配置与 Spring 云数据流相关,因为每个任务部署都由应用程序(通常是 Spring 引导 UBER-JAR 的)组成,并且这些应用程序是从远程 Maven 存储库解析的。在解析之后,应用程序工件被下载到本地 Maven 存储库以进行缓存和重用。当这种情况发生在后台时,默认磁盘配额(1G)可以迅速填充,特别是当我们实验由独特的应用程序组成的流时。为了克服这种磁盘限制,并根据你的缩放要求,你可能希望将默认的最大值从 2G 更改为 10G。让我们回顾一下更改默认的最大磁盘配额分配的步骤。

#### 11.11.1.PCF 的运营经理

从 PCF 的 Ops Manager 中,选择“Pivotal Elastic Runtime”贴片并导航到“Application Developer Control”选项卡。将“每个应用程序的最大磁盘配额”设置从 2048(2G)更改为 10240(10G)。保存磁盘配额更新,并单击“应用更改”以完成配置覆盖。

### 11.12.规模应用

一旦成功应用了磁盘配额更改,并假设你有[正在运行的应用程序](#running-on-cloudfoundry),就可以通过 CF CLI 使用新的`disk_limit`扩展应用程序,如下例所示:

```
→ cf scale dataflow-server -k 10GB

Scaling app dataflow-server in org ORG / space SPACE as user...
OK

....
....
....
....

     state     since                    cpu      memory           disk           details
#0   running   2016-10-31 03:07:23 PM   1.8%     497.9M of 1.1G   193.9M of 10G
```

然后,你可以列出应用程序并查看新的最大磁盘空间,如下例所示:

```
→ cf apps
Getting apps in org ORG / space SPACE as user...
OK

name              requested state   instances   memory   disk   urls
dataflow-server   started           1/1         1.1G     10G    dataflow-server.apps.io
```

### 11.13.管理磁盘使用

即使在配置数据流服务器使用 10G 空间时,也有可能耗尽本地磁盘上的可用空间。为了防止这种情况,从外部来源下载的`jar`工件,即注册为`http``maven`资源的应用程序,在部署应用程序时会自动删除,无论部署请求是否成功。对于容器运行时稳定性比部署期间产生的 I/O 延迟更关键的生产环境,这种行为是最优的。在开发环境中,部署发生得更频繁。此外,`jar`工件(或打火机`metadata`JAR)包含描述应用程序配置属性的元数据,这些元数据用于与应用程序配置相关的各种操作,这些操作在生产前活动期间更频繁地执行(有关详细信息,请参见[应用程序元数据](https://dataflow.spring.io/docs/applications/application-metadata))。为了提供响应更快的交互式开发人员体验,而不是在预生产环境中使用更多的磁盘,你可以将 CloudFoundry 部署程序属性`autoDeleteMavenArtifacts`设置为`false`

如果使用默认的`port`健康检查类型部署数据流服务器,则必须显式地监视服务器上的磁盘空间,以避免耗尽空间。如果你使用`http`健康检查类型来部署服务器(请参见下一个示例),那么如果磁盘空间较低,则将重新启动数据流服务器。这是由于 Spring boot 的[磁盘空间健康指示器](https://github.com/spring-projects/spring-boot/blob/v1.5.14.RELEASE/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/DiskSpaceHealthIndicator.java)。通过使用带有`management.health.diskspace`前缀的属性,可以[configure](https://docs.spring.io/spring-boot/docs/1.5.14.RELEASE/reference/htmlsingle/#common-application-properties)磁盘空间健康指示器的设置。

对于版本 1.7,我们正在研究使用[批量服务](https://docs.cloudfoundry.org/devguide/services/using-vol-services.html)来使数据流服务器存储`.jar`工件,然后将它们推送到 Cloud Foundry。

下面的示例展示了如何将`http`健康检查类型部署到一个名为`/management/health`的端点:

```
---
  ...
  health-check-type: http
  health-check-http-endpoint: /management/health
```

### 11.14.应用解决方案

尽管我们建议对应用程序[注册一个流应用程序](#spring-cloud-dataflow-register-stream-apps)使用 Maven artifactory,但在某些情况下,以下一种替代方法可能是有意义的。

* 我们定制并维护了一个[SCDF 应用程序工具](https://github.com/spring-cloud-stream-app-starters/scdf-app-tool),它可以在 Cloud Foundry 中作为常规 Spring 启动应用程序运行,但它将在运行时为 SCDF 托管和服务应用程序 JAR。

* 在 Spring Boot 的帮助下,我们可以在 Cloud Foundry 中服务[静态内容](https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-developing-web-applications.html#boot-features-spring-mvc-static-content)。 Spring 一个简单的引导应用程序可以捆绑所有所需的流和任务应用程序。通过让它在 Cloud Foundry 上运行,静态应用程序就可以为 über-Jar 服务了。例如,可以通过使用`--uri=http://<Route-To-StaticApp>/http-source.jar`在 shell 中注册名称为`http-source.jar`的应用程序。

* über-Jar 可以托管在任何可以通过 HTTP 访问的外部服务器上。它们也可以从原始的 GitHub URI 中解决。从 shell 中,你可以使用`--uri=http://<Raw_GitHub_URI>/http-source.jar`注册名称为`http-source.jar`的应用程序。

* [静态构建包](https://docs.cloudfoundry.org/buildpacks/staticfile/index.html)支持 Cloud Foundry 是另一种选择。类似的 HTTP 解析也适用于此模型。

* [批量服务](https://docs.cloudfoundry.org/devguide/services/using-vol-services.html)是另一个不错的选择。所需的 über-jars 可以托管在外部文件系统中。例如,在卷服务的帮助下,你可以使用`--uri=file://<Path-To-FileSystem>/http-source.jar`以`http-source.jar`的名称注册应用程序。

### 11.15.安全

默认情况下,数据流服务器是不安全的,并在未加密的 HTTP 连接上运行。你可以通过启用 HTTPS 并要求客户机进行身份验证来保护 REST 端点(以及数据流仪表板)。有关保护 REST 端点和配置以针对 OAuth 后端(运行在 Cloud Foundry 上的 UAA 和 SSO)进行身份验证的更多详细信息,请参见核心[[configuration-local-security]](#configuration-local-security)中的安全部分。你可以在`dataflow-server.yml`中配置安全细节,或者通过`cf set-env`命令将它们作为环境变量传递。

#### 11.15.1.认证

Spring 云数据流既可以与 Pivotal 单点登录服务(例如,在 PWS 上)集成,也可以与 Cloud Foundry 用户帐户和认证(UAA)服务器集成。

##### 关键的单点登录服务

Spring 将云数据流部署到 Cloud Foundry 时,可以将应用程序绑定到关键的单点登录服务。通过这样做, Spring 云数据流利用了[Java CFEnv](https://github.com/pivotal-cf/java-cfenv),后者为 OAuth2.0 提供了特定于云 Foundry 的自动配置支持。

为此,将 Pivotal 单点登录服务绑定到数据流服务器应用程序,并提供以下属性:

```
SPRING_CLOUD_DATAFLOW_SECURITY_CFUSEUAA: false                                                 (1)
SECURITY_OAUTH2_CLIENT_CLIENTID: "${security.oauth2.client.clientId}"
SECURITY_OAUTH2_CLIENT_CLIENTSECRET: "${security.oauth2.client.clientSecret}"
SECURITY_OAUTH2_CLIENT_ACCESSTOKENURI: "${security.oauth2.client.accessTokenUri}"
SECURITY_OAUTH2_CLIENT_USERAUTHORIZATIONURI: "${security.oauth2.client.userAuthorizationUri}"
SECURITY_OAUTH2_RESOURCE_USERINFOURI: "${security.oauth2.resource.userInfoUri}"
```

|**1**|重要的是,将属性`spring.cloud.dataflow.security.cf-use-uaa`设置为`false`|
|-----|-----------------------------------------------------------------------------------------------|

对于非云计算代工安全场景,也同样支持授权。请参阅核心数据流[[configuration-local-security]]中的安全部分。

由于角色的配置在不同的环境中可能会有很大的差异,因此默认情况下,我们将所有 Spring 云数据流角色分配给用户。

你可以通过提供自己的[`AuthoritiesExtractor`](https://DOCS. Spring.io/ Spring-boot/DOCS/current/api/org/springframework/boot/autofigure/security/oAututh2/resource/authoritiesextractor.html)来定制这种行为。

下面的示例显示了一种可能的方法,用于在`UserInfoTokenServices`上设置自定义`AuthoritiesExtractor`:

```
public class MyUserInfoTokenServicesPostProcessor
	implements BeanPostProcessor {

	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) {
		if (bean instanceof UserInfoTokenServices) {
			final UserInfoTokenServices userInfoTokenServices == (UserInfoTokenServices) bean;
			userInfoTokenServices.setAuthoritiesExtractor(ctx.getBean(AuthoritiesExtractor.class));
		}
		return bean;
	}

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) {
		return bean;
	}
}
```

然后,你可以在你的配置类中声明它,如下所示:

```
@Bean
public BeanPostProcessor myUserInfoTokenServicesPostProcessor() {
	BeanPostProcessor postProcessor == new MyUserInfoTokenServicesPostProcessor();
	return postProcessor;
}
```

##### Cloud Foundry UAA

Cloud Foundry 用户帐户和身份验证(UAA)的可用性取决于 Cloud Foundry 环境。为了提供 UAA 集成,你必须提供必要的 OAuth2 配置属性(例如,通过设置`SPRING_APPLICATION_JSON`属性)。

下面的 JSON 示例展示了如何创建安全配置:

```
{
  "security.oauth2.client.client-id": "scdf",
  "security.oauth2.client.client-secret": "scdf-secret",
  "security.oauth2.client.access-token-uri": "https://login.cf.myhost.com/oauth/token",
  "security.oauth2.client.user-authorization-uri": "https://login.cf.myhost.com/oauth/authorize",
  "security.oauth2.resource.user-info-uri": "https://login.cf.myhost.com/userinfo"
}
```

默认情况下,`spring.cloud.dataflow.security.cf-use-uaa`属性设置为`true`。此属性激活一个特殊的[`AuthoritiesExtractor`](https://DOCS. Spring.io/ Spring-boot/DOCS/current/api/org/springframework/boot/autofigure/security/oauth2/resource/authoritiesextractor.html),该函数称为`CloudFoundryDataflowAuthoritiesExtractor`。

如果不使用 CloudFoundry UAA,则应将`spring.cloud.dataflow.security.cf-use-uaa`设置为`false`。

在这种情况下,`spring.cloud.dataflow.security.cf-use-uaa`会调用[Cloud Foundry Apps API](https://apidocs.cloudfoundry.org/253/apps/retrieving_permissions_on_a_app.html),并确保用户实际上是空间开发人员。

如果已验证的用户被验证为空间开发人员,则将分配所有角色。

### 11.16.配置参考

你必须提供几个配置部分。这些是 Spring boot`@ConfigurationProperties`,因此你可以将它们设置为环境变量,或者通过 Spring boot 支持的任何其他方式。下面的列表是环境变量格式,因为这是在 Cloud Foundry 中开始配置引导应用程序的一种简单方法。请注意,在将来,你将能够将任务部署到多个平台,但是对于 2.0.0.m1,你只能部署到一个平台,并且名称必须是`spring.cloud.dataflow.security.cf-use-uaa`。

```
# Default values appear after the equal signs.
# Example values, typical for Pivotal Web Services, are included as comments.

# URL of the CF API (used when using cf login -a for example) - for example, https://api.run.pivotal.io
SPRING_CLOUD_DATAFLOW_TASK_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_CONNECTION_URL=

# The name of the organization that owns the space above - for example, youruser-org
SPRING_CLOUD_DATAFLOW_TASK_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_CONNECTION_ORG=

# The name of the space into which modules will be deployed - for example, development
SPRING_CLOUD_DATAFLOW_TASK_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_CONNECTION_SPACE=

# The root domain to use when mapping routes - for example, cfapps.io
SPRING_CLOUD_DATAFLOW_TASK_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_CONNECTION_DOMAIN=

# The user name and password of the user to use to create applications
SPRING_CLOUD_DATAFLOW_TASK_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_CONNECTION_USERNAME=
SPRING_CLOUD_DATAFLOW_TASK_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_CONNECTION_PASSWORD

# The identity provider to be used when accessing the Cloud Foundry API (optional).
# The passed string has to be a URL-Encoded JSON Object, containing the field origin with value as origin_key of an identity provider - for example, {"origin":"uaa"}
SPRING_CLOUD_DATAFLOW_TASK_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_CONNECTION_LOGIN_HINT=

# Whether to allow self-signed certificates during SSL validation (you should NOT do so in production)
SPRING_CLOUD_DATAFLOW_TASK_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_CONNECTION_SKIP_SSL_VALIDATION

# A comma-separated set of service instance names to bind to every deployed task application.
# Among other things, this should include an RDBMS service that is used
# for Spring Cloud Task execution reporting, such as my_postgres
SPRING_CLOUD_DATAFLOW_TASK_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_DEPLOYMENT_SERVICES
spring.cloud.deployer.cloudfoundry.task.services=

# Timeout, in seconds, to use when doing blocking API calls to Cloud Foundry
SPRING_CLOUD_DATAFLOW_TASK_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_DEPLOYMENT_API_TIMEOUT=

# Timeout, in milliseconds, to use when querying the Cloud Foundry API to compute app status
SPRING_CLOUD_DATAFLOW_TASK_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_DEPLOYMENT_STATUS_TIMEOUT
```

请注意,你可以通过使用`spring.cloud.deployer.cloudfoundry.services`、`spring.cloud.deployer.cloudfoundry.buildpacks`或 Spring Cloud Deployer-Standard`spring.cloud.dataflow.security.cf-use-uaa`和`spring.cloud.deployer.disk`作为单个部署请求的一部分来使用`deployer.<app-name>`快捷方式,如下例所示:

```
stream create --name ticktock --definition "time | log"
stream deploy --name ticktock --properties "deployer.time.memory=2g"
```

前面示例中的命令部署的时间源内存为 2048MB,而日志接收器使用的是缺省的 1024MB。

部署流时,还可以将`JAVA_OPTS`作为部署属性传递,如下例所示:

```
stream deploy --name ticktock --properties "deployer.time.cloudfoundry.javaOpts=-Duser.timezone=America/New_York"
```

### 11.17.调试

如果你想更好地了解部署流和任务时发生了什么,你可能需要启用以下功能:

* 反应堆“堆栈轨迹”,显示在发生错误之前涉及哪些操作人员。这个特性是有帮助的,因为部署人员依赖于 Project Reactor,而常规的堆栈跟踪可能并不总是允许在错误发生之前理解流程。请注意,这会带来性能损失,因此默认情况下会禁用它。

```
spring.cloud.dataflow.server.cloudfoundry.debugReactor == true
```

* 部署人员和 Cloud Foundry 客户端库请求和响应日志。此功能允许查看数据流服务器和 Cloud Foundry 云控制器之间的详细对话。

```
logging.level.cloudfoundry-client == DEBUG
```

### 11.18. Spring 云配置服务器

你可以使用 Spring Cloud Config Server 来集中 Spring 引导应用程序的配置属性。同样, Spring 云数据流和 Spring 云数据流所编排的应用程序都可以与配置服务器集成以使用相同的能力。

#### 11.18.1.流、任务和 Spring 云配置服务器

Spring 与云数据流服务器类似,可以同时配置流和任务应用程序,以解决来自配置服务器的集中属性。为部署的应用程序设置`spring.cloud.config.uri`属性是绑定到配置服务器的一种常见方式。有关更多信息,请参见[Spring Cloud Config Client](https://cloud.spring.io/spring-cloud-config/spring-cloud-config.html#_spring_cloud_config_client)参考指南。由于此属性很可能在数据流服务器部署的所有应用程序中使用,数据流服务器用于流应用程序的`spring.cloud.dataflow.applicationProperties.stream`属性和用于任务应用程序的`spring.cloud.dataflow.applicationProperties.task`属性可用于将配置服务器的`uri`传递给每个部署的流或任务应用程序。有关更多信息,请参见[通用应用程序属性](#spring-cloud-dataflow-global-properties)一节。

请注意,如果你使用来自[应用程序启动程序项目](https://cloud.spring.io/spring-cloud-stream-app-starters/)的应用程序,这些应用程序已经嵌入了[通用应用程序属性](#spring-cloud-dataflow-global-properties)依赖项。如果你从头开始构建应用程序,并且希望添加对 Config Server 的客户端支持,那么可以向 Config Server 客户机库添加依赖项引用。下面的片段展示了一个 Maven 示例:

```
...
<dependency>
  <groupId>io.pivotal.spring.cloud</groupId>
  <artifactId>spring-cloud-services-starter-config-client</artifactId>
  <version>CONFIG_CLIENT_VERSION</version>
</dependency>
...
```

其中`CONFIG_CLIENT_VERSION`可以是用于 Pivotal Cloud Foundry 的[Spring Cloud Config Server](https://github.com/pivotal-cf/spring-cloud-services-connector/releases)客户端的最新版本。

|   |如果使用该库的应用程序在应用程序启动时以及每当访问`/health`端点时无法连接到配置<br/>服务器,你可能会看到`WARN`日志消息,<br/>如果你知道你没有使用 Config 服务器功能,可以通过将`SPRING_CLOUD_CONFIG_ENABLED`环境变量设置为`false`来禁用客户端库。|
|---|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

#### 11.18.2.样本清单模板

以下 SCDF 和 Skipper`manifest.yml`模板包括 Skipper 和 Spring Cloud Data Flow 服务器所需的环境变量以及部署的应用程序和任务,以在 Cloud Foundry 上成功运行,并在运行时从`my-config-server`自动解析集中的属性:

```
---
applications:
- name: data-flow-server
  host: data-flow-server
  memory: 2G
  disk_quota: 2G
  instances: 1
  path: {PATH TO SERVER UBER-JAR}
  env:
    SPRING_APPLICATION_NAME: data-flow-server
    MAVEN_REMOTE_REPOSITORIES_REPO1_URL: https://repo.spring.io/libs-snapshot
    SPRING_CLOUD_DATAFLOW_TASK_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_CONNECTION_URL: https://api.sys.huron.cf-app.com
    SPRING_CLOUD_DATAFLOW_TASK_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_CONNECTION_ORG: sabby20
    SPRING_CLOUD_DATAFLOW_TASK_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_CONNECTION_SPACE: sabby20
    SPRING_CLOUD_DATAFLOW_TASK_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_CONNECTION_DOMAIN: apps.huron.cf-app.com
    SPRING_CLOUD_DATAFLOW_TASK_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_CONNECTION_USERNAME: admin
    SPRING_CLOUD_DATAFLOW_TASK_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_CONNECTION_PASSWORD: ***
    SPRING_CLOUD_DATAFLOW_TASK_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_CONNECTION_SKIP_SSL_VALIDATION: true
    SPRING_CLOUD_DATAFLOW_TASK_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_DEPLOYMENT_SERVICES: mysql
    SPRING_CLOUD_SKIPPER_CLIENT_SERVER_URI: https://<skipper-host-name>/api
services:
- mysql
- my-config-server

---
applications:
- name: skipper-server
  host: skipper-server
  memory: 1G
  disk_quota: 1G
  instances: 1
  timeout: 180
  buildpack: java_buildpack
  path: <PATH TO THE DOWNLOADED SKIPPER SERVER UBER-JAR>
  env:
    SPRING_APPLICATION_NAME: skipper-server
    SPRING_CLOUD_SKIPPER_SERVER_ENABLE_LOCAL_PLATFORM: false
    SPRING_CLOUD_SKIPPER_SERVER_STRATEGIES_HEALTHCHECK_TIMEOUTINMILLIS: 300000
    SPRING_CLOUD_SKIPPER_SERVER_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_CONNECTION_URL: https://api.local.pcfdev.io
    SPRING_CLOUD_SKIPPER_SERVER_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_CONNECTION_ORG: pcfdev-org
    SPRING_CLOUD_SKIPPER_SERVER_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_CONNECTION_SPACE: pcfdev-space
    SPRING_CLOUD_SKIPPER_SERVER_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_DEPLOYMENT_DOMAIN: cfapps.io
    SPRING_CLOUD_SKIPPER_SERVER_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_CONNECTION_USERNAME: admin
    SPRING_CLOUD_SKIPPER_SERVER_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_CONNECTION_PASSWORD: admin
    SPRING_CLOUD_SKIPPER_SERVER_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_CONNECTION_SKIP_SSL_VALIDATION: false
    SPRING_CLOUD_SKIPPER_SERVER_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_DEPLOYMENT_DELETE_ROUTES: false
    SPRING_CLOUD_SKIPPER_SERVER_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_DEPLOYMENT_SERVICES: rabbit, my-config-server
services:
- mysql
  my-config-server
```

其中`my-config-server`是运行在 Cloud Foundry 上的 Spring Cloud Config 服务实例的名称。

通过将服务分别绑定到 Spring 云数据流服务器、 Spring 云任务和通过 Skipper 绑定到所有 Spring 云流应用程序,我们现在可以解析由该服务支持的集中式属性。

#### 11.18.3.自签名 SSL 证书和 Spring 云配置服务器

通常,在开发环境中,我们可能没有有效的证书来支持客户端和后端服务之间的 SSL 通信。但是,Pivotal Cloud Foundry 的配置服务器使用 HTTPS 进行所有客户端到服务的通信,因此在没有有效证书的环境中,我们需要添加自签名的 SSL 证书。

通过使用上一节中为服务器列出的相同的`WARN`模板,我们可以通过设置`TRUST_CERTS: <API_ENDPOINT>`来提供自签名的 SSL 证书。

然而,已部署的应用程序还需要`TRUST_CERTS`作为一个平坦的环境变量(而不是包装在`SPRING_APPLICATION_JSON`中),因此我们必须用另一组令牌(`SPRING_CLOUD_DATAFLOW_TASK_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_DEPLOYMENT_USE_SPRING_APPLICATION_JSON: false`)来指示服务器执行任务。通过这种设置,应用程序将其应用程序属性作为常规的环境变量接收。

下面的清单显示了更新后的`manifest.yml`所需的更改。数据流服务器和已部署的应用程序都从`my-config-server`云配置服务器(部署为 Cloud Foundry 服务)获得它们的配置。

```
---
applications:
- name: test-server
  host: test-server
  memory: 1G
  disk_quota: 1G
  instances: 1
  path: spring-cloud-dataflow-server-VERSION.jar
  env:
    SPRING_APPLICATION_NAME: test-server
    MAVEN_REMOTE_REPOSITORIES_REPO1_URL: https://repo.spring.io/libs-snapshot
    SPRING_CLOUD_DATAFLOW_TASK_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_CONNECTION_URL: https://api.sys.huron.cf-app.com
    SPRING_CLOUD_DATAFLOW_TASK_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_CONNECTION_ORG: sabby20
    SPRING_CLOUD_DATAFLOW_TASK_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_CONNECTION_SPACE: sabby20
    SPRING_CLOUD_DATAFLOW_TASK_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_CONNECTION_DOMAIN: apps.huron.cf-app.com
    SPRING_CLOUD_DATAFLOW_TASK_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_CONNECTION_USERNAME: admin
    SPRING_CLOUD_DATAFLOW_TASK_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_CONNECTION_PASSWORD: ***
    SPRING_CLOUD_DATAFLOW_TASK_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_CONNECTION_SKIP_SSL_VALIDATION: true
    SPRING_CLOUD_DATAFLOW_TASK_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_DEPLOYMENT_SERVICES: mysql, config-server
    SPRING_CLOUD_SKIPPER_CLIENT_SERVER_URI: https://<skipper-host-name>/api
    TRUST_CERTS: <API_ENDPOINT> #this is for the server
    SPRING_CLOUD_DATAFLOW_APPLICATION_PROPERTIES_TASK_TRUST_CERTS: <API_ENDPOINT>   #this propagates to all tasks
services:
- mysql
- my-config-server #this is for the server
```

还可以将`my-config-server`服务添加到 Skipper 的清单环境中

```
---
applications:
- name: skipper-server
  host: skipper-server
  memory: 1G
  disk_quota: 1G
  instances: 1
  timeout: 180
  buildpack: java_buildpack
  path: <PATH TO THE DOWNLOADED SKIPPER SERVER UBER-JAR>
  env:
    SPRING_APPLICATION_NAME: skipper-server
    SPRING_CLOUD_SKIPPER_SERVER_ENABLE_LOCAL_PLATFORM: false
    SPRING_CLOUD_SKIPPER_SERVER_STRATEGIES_HEALTHCHECK_TIMEOUTINMILLIS: 300000
    SPRING_CLOUD_SKIPPER_SERVER_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_CONNECTION_URL: <URL>
    SPRING_CLOUD_SKIPPER_SERVER_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_CONNECTION_ORG: <ORG>
    SPRING_CLOUD_SKIPPER_SERVER_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_CONNECTION_SPACE: <SPACE>
    SPRING_CLOUD_SKIPPER_SERVER_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_DEPLOYMENT_DOMAIN: <DOMAIN>
    SPRING_CLOUD_SKIPPER_SERVER_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_CONNECTION_USERNAME: <USER>
    SPRING_CLOUD_SKIPPER_SERVER_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_CONNECTION_PASSWORD: <PASSWORD>
    SPRING_CLOUD_SKIPPER_SERVER_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_DEPLOYMENT_SERVICES: rabbit, my-config-server #this is so all stream applications bind to my-config-server
services:
- mysql
  my-config-server
```

### 11.19.配置调度

本节讨论如何配置 Spring 云数据流以连接到[PCF 调度器](https://www.cloudfoundry.org/the-foundry/scheduler/)作为其代理来执行任务。

|   |在遵循这些指令之前,确保在你的 Cloud Foundry 空间中有一个运行 PCF-Scheduler 服务的实例。`TRUST_CERTS`要在你的空间中创建一个 PCF-Scheduler(假设它在你的市场中),请从 CF CLI 执行以下操作:`cf create-service scheduler-for-pcf standard <name of service>`。<br/>服务的名称稍后将用于绑定正在运行的应用程序在*PCF*中。|
|---|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

为了进行调度,你必须在你的环境中添加(或更新)以下环境变量:

* 通过将`spring.cloud.dataflow.features.schedules-enabled`设置为`true`,启用对 Spring 云数据流的调度。

* 通过将 PCF-Scheduler 服务名添加到`SPRING_CLOUD_DATAFLOW_TASK_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_DEPLOYMENT_SERVICES`环境变量,将任务部署程序绑定到你的 PCF-Scheduler 实例。

* 通过设置`SPRING_CLOUD_DATAFLOW_TASK_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_SCHEDULER_SCHEDULER_URL`环境变量,建立到 PCF-Scheduler 的 URL。

|   |在创建了前面的配置之后,你必须创建任何需要调度的任务定义。|
|---|------------------------------------------------------------------------------------------------------------|

下面的示例清单显示了配置的两个环境属性(假设你有一个名为`myscheduler`的 PCF-Scheduler 服务可用):

```
---
applications:
- name: data-flow-server
  host: data-flow-server
  memory: 2G
  disk_quota: 2G
  instances: 1
  path: {PATH TO SERVER UBER-JAR}
  env:
    SPRING_APPLICATION_NAME: data-flow-server
    SPRING_CLOUD_SKIPPER_SERVER_ENABLE_LOCAL_PLATFORM: false
    SPRING_CLOUD_SKIPPER_SERVER_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_CONNECTION_URL: <URL>
    SPRING_CLOUD_SKIPPER_SERVER_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_CONNECTION_ORG: <ORG>
    SPRING_CLOUD_SKIPPER_SERVER_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_CONNECTION_SPACE: <SPACE>
    SPRING_CLOUD_SKIPPER_SERVER_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_DEPLOYMENT_DOMAIN: <DOMAIN>
    SPRING_CLOUD_SKIPPER_SERVER_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_CONNECTION_USERNAME: <USER>
    SPRING_CLOUD_SKIPPER_SERVER_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_CONNECTION_PASSWORD: <PASSWORD>
    SPRING_CLOUD_SKIPPER_SERVER_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_DEPLOYMENT_SERVICES: rabbit, myscheduler
    SPRING_CLOUD_DATAFLOW_FEATURES_SCHEDULES_ENABLED: true
    SPRING_CLOUD_SKIPPER_CLIENT_SERVER_URI: https://<skipper-host-name>/api
    SPRING_CLOUD_DATAFLOW_TASK_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]_SCHEDULER_SCHEDULER_URL: https://scheduler.local.pcfdev.io
services:
- mysql
```

其中`SPRING_CLOUD_DATAFLOW_TASK_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[default]*SCHEDULER_SCHEDULER_URL*`* 具有以下格式:`scheduler.<Domain-Name>`(例如,`[scheduler.local.pcfdev.io](https://scheduler.local.pcfdev.io)`)。检查你的 \_PCF* 环境中的实际地址。

|   |在[dataflow.spring.io](http://dataflow.spring.io)上的[对任务的多平台支持](https://dataflow.spring.io/docs/recipes/multi-platform-deployment/)一节中提供了跨多个平台启动和调度任务的详细示例。|
|---|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

## 12. 配置-Kubernetes

节描述了如何配置 Spring 云数据流特性,例如部署人员属性、任务以及使用哪个关系数据库。

### 12.1.功能切换

Data Flow Server 提供了一组特定的特性,可以在启动时启用或禁用这些特性。这些特性包括用于以下方面的所有生命周期操作、REST 端点(服务器和客户端实现,包括 shell 和 UI):

* 溪流

* Tasks

* 时间表

启动数据流服务器时,可以通过设置以下布尔环境变量来启用或禁用这些特性:

* `SPRING_CLOUD_DATAFLOW_FEATURES_STREAMS_ENABLED`

* `SPRING_CLOUD_DATAFLOW_FEATURES_TASKS_ENABLED`

* `SPRING_CLOUD_DATAFLOW_FEATURES_SCHEDULES_ENABLED`

认情况下,所有的功能都是启用的。

`/features`REST 端点提供有关已启用和禁用的特性的信息。

### 12.2.部署人员属性

可以使用以下配置属性`jar`来自定义如何部署流和任务。在部署数据流壳时,可以使用语法`deployer.<appName>.kubernetes.<deployerPropertyName>`。这些属性还用于在数据流服务器中配置[Kubernetes 任务平台](#configuration-kubernetes-tasks),以及在 Skipper 中配置用于部署流的 Kubernetes 平台。

|             Deployer Property Name             |说明|                         Default Value                          |
|------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------|
|                   namespace                    |要使用的名称空间|environment variable `KUBERNETES_NAMESPACE`, otherwise `default`|
|            deployment.nodeSelector             |以`key:value`格式应用于部署的节点选择器。多个节点选择器是用逗号分隔的。|                            \<none\>                            |
|                imagePullSecret                 |秘密为一个访问一个私人注册中心的图片拉.|                            \<none\>                            |
|                imagePullPolicy                 |当拖动图像时要应用的图像拖动策略。有效的选项是`Always`、`IfNotPresent`和`Never`。|                          IfNotPresent                          |
|               livenessProbeDelay               |当应用程序容器的 Kubernetes 活性检查应开始检查其健康状态时,以秒为单位的延迟。|                               10                               |
|              livenessProbePeriod               |执行应用程序容器的 Kubernetes 活性检查的周期(以秒为单位)。|                               60                               |
|              livenessProbeTimeout              |应用程序容器的 Kubernetes 活性检查的超时(以秒为单位)。如果健康检查返回的时间超过这个值,则假定它为“不可用”。|                               2                                |
|               livenessProbePath                |应用程序容器必须响应的路径,以进行活性检查。|                            \<none\>                            |
|               livenessProbePort                |应用程序容器必须响应的端口,以进行活性检查。|                            \<none\>                            |
|              readinessProbeDelay               |当应用程序容器的准备状态检查应该开始检查模块是否完全启动并运行时,以秒为单位的延迟。|                               10                               |
|              readinessProbePeriod              |以秒为单位执行应用程序容器的准备状态检查。|                               10                               |
|             readinessProbeTimeout              |在准备就绪检查期间,应用程序容器必须响应其健康状态的超时(以秒为单位)。|                               2                                |
|               readinessProbePath               |应用程序容器必须响应的路径,以进行准备检查。|                            \<none\>                            |
|               readinessProbePort               |应用程序容器必须响应的端口,以进行准备检查。|                            \<none\>                            |
|             probeCredentialsSecret             |包含访问安全探测端点时要使用的凭据的秘密名称。|                            \<none\>                            |
|                 limits.memory                  |内存限制,分配 POD 所需的最大值,默认单元为 mebibytes,支持“M”和“G”后缀|                            \<none\>                            |
|                   limits.cpu                   |CPU 限制,分配 POD 所需的最大值|                            \<none\>                            |
|                requests.memory                 |内存请求,保证分配 POD 所需的值.|                            \<none\>                            |
|                  requests.cpu                  |的 CPU 请求,保证分配 POD 所需的值.|                            \<none\>                            |
|statefulSet.volumeClaimTemplate.storageClassName|有状态集的存储类的名称|                            \<none\>                            |
|    statefulSet.volumeClaimTemplate.storage     |存储数量。默认单元是 mebibytes,支持“m”和“g”后缀|                            \<none\>                            |
|              environmentVariables              |为任何已部署的应用程序容器设置的环境变量列表|                            \<none\>                            |
|                entryPointStyle                 |用于 Docker 映像的入口点样式。用于确定如何传入属性。可以是`exec`,`shell`,和`boot`|                             `exec`                             |
|               createLoadBalancer               |为每个应用程序创建的服务创建一个“loadbalancer”。这便于将外部 IP 分配给应用程序。|                             false                              |
|               serviceAnnotations               |为每个应用程序创建的服务设置的服务注释。格式`annotation1:value1,annotation2:value2`的字符串|                            \<none\>                            |
|                 podAnnotations                 |为每个部署创建的 POD 设置的 POD 注释。格式`annotation1:value1,annotation2:value2`的字符串|                            \<none\>                            |
|                 jobAnnotations                 |为 POD 或为作业创建的作业设置的作业注释。格式`annotation1:value1,annotation2:value2`的字符串|                            \<none\>                            |
|          minutesToWaitForLoadBalancer          |在尝试删除服务之前,等待负载均衡器可用的时间(以分钟为单位)。|                               5                                |
|           maxTerminatedErrorRestarts           |对于由于错误或过度使用资源而失败的应用程序,最大允许重启。|                               2                                |
|          maxCrashLoopBackOffRestarts           |在崩溃循环中的应用程序的最大允许重启。值为`Always`,`IfNotPresent`,`Never`|                         `IfNotPresent`                         |
|                  volumeMounts                  |以 YAML 格式表示的卷挂载。例如``[{name: 'testhostpath', mountPath: '/test/hostPath'}, {name: 'testpvc', mountPath: '/test/pvc'}, {name: 'testnfs', mountPath: '/test/nfs'}]``|                            \<none\>                            |
|                    volumes                     |Kubernetes 实例支持的卷以 YAML 格式提供。例如``[{name: testhostpath, hostPath: { path: '/test/override/hostPath' }},{name: 'testpvc', persistentVolumeClaim: { claimName: 'testClaim', readOnly: 'true' }}, {name: 'testnfs', nfs: { server: '10.0.0.1:111', path: '/test/nfs' }}]``|                            \<none\>                            |
|                  hostNetwork                   |部署的 hostnetwork 设置,请参见[Kubernetes.io/DOCS/api-reference/v1/definitions/#\_v1\_podspec](https://kubernetes.io/docs/api-reference/v1/definitions/#_v1_podspec)|                             false                              |
|                createDeployment                |用“复制集”而不是“复制控制器”创建“部署”。|                              true                              |
|                   createJob                    |在启动任务时,创建一个“工作”,而不只是一个“pod”。|                             false                              |
|                containerCommand                |使用提供的命令和参数重写缺省的 Entry Point 命令。|                            \<none\>                            |
|                 containerPorts                 |添加要在容器上公开的其他端口。|                            \<none\>                            |
|                 createNodePort                 |当`NodePort`时要使用的显式端口是`Service`类型。|                            \<none\>                            |
|          deploymentServiceAccountName          |应用程序部署中使用的服务帐户名称。注意:用于应用程序部署的服务帐户名称来自数据流服务器部署。|                            \<none\>                            |
|                deploymentLabels                |以`key:value`格式添加到部署中的附加标签。多个标签是用逗号分隔的。|                            \<none\>                            |
|                bootMajorVersion                |Spring 主要使用的引导版本。当前仅用于自动配置 Spring 启动版本特定的探测路径。有效的选项是`1`或`2`。|                               2                                |
|                tolerations.key                 |要用到的关键是容忍度。|                            \<none\>                            |
|               tolerations.effect               |宽容的效果。有关有效选项,请参见[Kubernetes.io/DOCS/概念/配置/污点容忍](https://kubernetes.io/docs/concepts/configuration/taint-and-toleration)。|                            \<none\>                            |
|              tolerations.operator              |宽容的操作者。有关有效选项,请参见[Kubernetes.io/DOCS/概念/配置/污点容忍/](https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/)。|                            \<none\>                            |
|         tolerations.tolerationSeconds          |定义 POD 在添加污点后将与节点绑定多长时间的秒数。|                            \<none\>                            |
|               tolerations.value                |适用的容忍值,与`operator`结合使用,以选择适当的`effect`。|                            \<none\>                            |
|                   secretRefs                   |将整个数据内容加载到各个环境变量中的秘密的名称。多个秘密可以用逗号分隔。|                            \<none\>                            |
|            secretKeyRefs.envVarName            |保存秘密数据的环境变量名|                            \<none\>                            |
|            secretKeyRefs.secretName            |要访问的秘密名称|                            \<none\>                            |
|             secretKeyRefs.dataKey              |从其中获取秘密数据的键名|                            \<none\>                            |
|                 configMapRefs                  |用于将整个数据内容加载到各个环境变量中的配置图的名称。多个配置映射以逗号分隔。|                            \<none\>                            |
|          configMapKeyRefs.envVarName           |保存配置图数据的环境变量名|                            \<none\>                            |
|         configMapKeyRefs.configMapName         |要访问的配置图名称|                            \<none\>                            |
|            configMapKeyRefs.dataKey            |从其中获取配置图数据的键名|                            \<none\>                            |
|             maximumConcurrentTasks             |此平台实例允许的最大并发任务。|                               20                               |
|          podSecurityContext.runAsUser          |用于运行 POD 容器进程的数字用户 ID|                            \<none\>                            |
|           podSecurityContext.fsGroup           |用于运行 POD 容器进程的数字组 ID|                            \<none\>                            |
|             affinity.nodeAffinity              |以 YAML 格式表示的节点亲和力。例如``{ requiredDuringSchedulingIgnoredDuringExecution: { nodeSelectorTerms: [ { matchExpressions: [ { key: 'kubernetes.io/e2e-az-name', operator: 'In', values: [ 'e2e-az1', 'e2e-az2']}]}]}, preferredDuringSchedulingIgnoredDuringExecution: [ { weight: 1, preference: { matchExpressions: [ { key: 'another-node-label-key', operator: 'In', values: [ 'another-node-label-value' ]}]}}]}``|                            \<none\>                            |
|              affinity.podAffinity              |以 YAML 格式表示的 POD 亲和力。例如``{ requiredDuringSchedulingIgnoredDuringExecution: { labelSelector: [ { matchExpressions: [ { key: 'app', operator: 'In', values: [ 'store']}]}], topologyKey: 'kubernetes.io/hostnam'}, preferredDuringSchedulingIgnoredDuringExecution: [ { weight: 1, podAffinityTerm: { labelSelector: { matchExpressions: [ { key: 'security', operator: 'In', values: [ 'S2' ]}]}, topologyKey: 'failure-domain.beta.kubernetes.io/zone'}}]}``|                            \<none\>                            |
|            affinity.podAntiAffinity            |以 YAML 格式表示的 POD 反亲和力。例如``{ requiredDuringSchedulingIgnoredDuringExecution: { labelSelector: { matchExpressions: [ { key: 'app', operator: 'In', values: [ 'store']}]}], topologyKey: 'kubernetes.io/hostname'}, preferredDuringSchedulingIgnoredDuringExecution: [ { weight: 1, podAffinityTerm: { labelSelector: { matchExpressions: [ { key: 'security', operator: 'In', values: [ 'S2' ]}]}, topologyKey: 'failure-domain.beta.kubernetes.io/zone'}}]}``|                            \<none\>                            |
|       statefulSetInitContainerImageName        |用于 statefulset init 容器的自定义映像名|                            \<none\>                            |
|                 initContainer                  |以 YAML 格式表示的 init 容器,应用于 POD。例如``{containerName: 'test', imageName: 'busybox:latest', commands: ['sh', '-c', 'echo hello']}``|                            \<none\>                            |
|              additionalContainers              |以 YAML 格式表示的附加容器将应用于 POD。例如``[{name: 'c1', image: 'busybox:latest', command: ['sh', '-c', 'echo hello1'], volumeMounts: [{name: 'test-volume', mountPath: '/tmp', readOnly: true}]}, {name: 'c2', image: 'busybox:1.26.1', command: ['sh', '-c', 'echo hello2']}]``|                            \<none\>                            |

### 12.3.任务

据流服务器负责部署任务。数据流启动的任务将其状态写入数据流服务器使用的同一数据库。对于 Spring 批处理作业的任务,作业和步骤执行数据也存储在该数据库中。与 Skipper 一样,任务可以在多个平台上启动。当数据流在 Kubernetes 上运行时,必须定义一个任务平台。要配置以 Kubernetes 为目标的新平台帐户,请在你的`application.yaml`文件中的`spring.cloud.dataflow.task.platform.kubernetes`节下通过另一种 Spring 启动支持的机制提供一个条目。在下面的示例中,创建了两个名为`dev`和`qa`的 Kubernetes 平台帐户。如`memory`和`disk`的键是[Cloud Foundry Deployer 属性](#configuration-cloudfoundry-deployer)。

```
spring:
  cloud:
    dataflow:
      task:
        platform:
          kubernetes:
            accounts:
              dev:
                namespace: devNamespace
                imagePullPolicy: Always
                entryPointStyle: exec
                limits:
                  cpu: 4
              qa:
                namespace: qaNamespace
                imagePullPolicy: IfNotPresent
                entryPointStyle: boot
                limits:
                  memory: 2048m
```

|   |通过将一个平台定义为`default`,你可以跳过使用`default`,否则将需要使用该平台。|
|---|------------------------------------------------------------------------------------------------------------------------|

动任务时,使用 Task Launch 选项`--platformName`传递平台帐户名的值`platformName`如果不传递`platformName`的值,则将使用该值`default`。

|   |当将任务部署到多个平台时,任务的配置需要连接到与数据流服务器相同的数据库。|
|---|-----------------------------------------------------------------------------------------------------------------------------------------|

可以将 Kubernetes 上的数据流服务器配置为将任务部署到 Cloud Foundry 和 Kubernetes。有关更多信息,请参见[Cloud Foundry 任务平台配置](#configuration-cloudfoundry-tasks)一节。

于跨多个平台启动和调度任务的详细示例,可在[对任务的多平台支持](https://dataflow.spring.io/docs/recipes/multi-platform-deployment/)上的[dataflow.spring.io](http://dataflow.spring.io)一节中获得。

### 12.4.一般配置

Spring 用于 Kubernetes 的云数据流服务器使用[`spring-cloud-kubernetes`](https://github.com/fabric8io/ Spring-cloud-kubernetes)模块来处理安装在`/etc/secrets`下的秘密。配置映射必须在由 Spring 引导处理的`/config`目录中挂载为`application.yaml`。为了避免访问 Kubernetes API 服务器,将`SPRING_CLOUD_KUBERNETES_CONFIG_ENABLE_API`和`/etc/secrets`设置为`false`。

#### 12.4.1.使用配置图和秘密

以通过使用 Kubernetes[ConfigMap](https://kubernetes.io/docs/tasks/configure-pod-container/configmap/)和[secrets](https://kubernetes.io/docs/concepts/configuration/secret/)将配置属性传递给数据流服务器。

面的示例展示了一种可能的配置,该配置启用了 MySQL 并设置了内存限制:

```
apiVersion: v1
kind: ConfigMap
metadata:
  name: scdf-server
  labels:
    app: scdf-server
data:
  application.yaml: |-
    spring:
      cloud:
        dataflow:
          task:
            platform:
              kubernetes:
                accounts:
                  default:
                    limits:
                      memory: 1024Mi
      datasource:
        url: jdbc:mysql://${MYSQL_SERVICE_HOST}:${MYSQL_SERVICE_PORT}/mysql
        username: root
        password: ${mysql-root-password}
        driverClassName: org.mariadb.jdbc.Driver
        testOnBorrow: true
        validationQuery: "SELECT 1"
```

面的示例假定 MySQL 是以`mysql`作为服务名称部署的。Kubernetes 将这些服务的主机值和端口值作为环境变量发布,我们可以在配置部署的应用程序时使用这些环境变量。

们更喜欢在机密文件中提供 MySQL 连接密码,如下例所示:

```
apiVersion: v1
kind: Secret
metadata:
  name: mysql
  labels:
    app: mysql
data:
  mysql-root-password: eW91cnBhc3N3b3Jk
```

码是以 64 为基础编码的值。

### 12.5.数据库配置

Spring 云数据流为 H2、HSQLDB、MySQL、Oracle、PostgreSQL、DB2 和 SQL Server 提供了模式。如果 Classpath 中有正确的数据库驱动程序和适当的凭据,则在服务器启动时会自动创建适当的模式。

MySQL 的 JDBC 驱动程序(通过 MariaDB 驱动程序)、HSQLDB、PostgreSQL 和嵌入式 H2 都是开箱即用的。如果使用任何其他数据库,则需要在服务器的 Classpath 上放置相应的 JDBC 驱动程序 JAR。

如,如果除了在机密文件中使用密码外,还使用 MySQL,则可以在配置图中提供以下属性:

```
data:
  application.yaml: |-
    spring:
      datasource:
        url: jdbc:mysql://${MYSQL_SERVICE_HOST}:${MYSQL_SERVICE_PORT}/mysql
        username: root
        password: ${mysql-root-password}
        driverClassName: org.mariadb.jdbc.Driver
        url: jdbc:mysql://${MYSQL_SERVICE_HOST}:${MYSQL_SERVICE_PORT}/test
        driverClassName: org.mariadb.jdbc.Driver
```

于 PostgreSQL,你可以使用以下配置:

```
data:
  application.yaml: |-
    spring:
      datasource:
        url: jdbc:postgresql://${PGSQL_SERVICE_HOST}:${PGSQL_SERVICE_PORT}/database
        username: root
        password: ${postgres-password}
        driverClassName: org.postgresql.Driver
```

于 HSQLDB,你可以使用以下配置:

```
data:
  application.yaml: |-
    spring:
      datasource:
        url: jdbc:hsqldb:hsql://${HSQLDB_SERVICE_HOST}:${HSQLDB_SERVICE_PORT}/database
        username: sa
        driverClassName: org.hsqldb.jdbc.JDBCDriver
```

署中的以下 YAML 片段是挂载配置图的示例作为`application.yaml``/config`下的`/config`,其中 Spring boot 将处理它加上一个安装在`/etc/secrets`下的秘密,由于环境变量`SPRING_CLOUD_KUBERNETES_SECRETS_PATHS`被设置为`/etc/secrets`,它将被 Spring-cloud-kubernetes 库选中。

```
...
      containers:
      - name: scdf-server
        image: springcloud/spring-cloud-dataflow-server:2.5.0.BUILD-SNAPSHOT
        imagePullPolicy: Always
        volumeMounts:
          - name: config
            mountPath: /config
            readOnly: true
          - name: database
            mountPath: /etc/secrets/database
            readOnly: true
        ports:
...
      volumes:
        - name: config
          configMap:
            name: scdf-server
            items:
            - key: application.yaml
              path: application.yaml
        - name: database
          secret:
            secretName: mysql
```

可以在[spring-cloud-task](https://github.com/spring-cloud/spring-cloud-task/tree/master/spring-cloud-task-core/src/main/resources/org/springframework/cloud/task/migration)repo 中找到特定数据库类型的迁移脚本。

### 12.6.监测和管理

们建议使用`kubectl`命令对流和任务进行故障排除。

可以使用以下命令列出所使用的所有工件和资源:

```
kubectl get all,cm,secrets,pvc
```

过使用标签来选择资源,你可以列出特定应用程序或服务使用的所有资源。下面的命令列出了`mysql`服务使用的所有资源:

```
kubectl get all -l app=mysql
```

可以通过发出以下命令来获取特定 pod 的日志:

```
kubectl logs pod <pod-name>
```

果持续重启 POD,可以添加`-p`作为查看上一个日志的选项,如下所示:

```
kubectl logs -p <pod-name>
```

还可以通过添加`-f`选项跟踪或跟踪日志,如下所示:

```
kubectl logs -f <pod-name>
```

个有用的命令是使用`describe`命令,以帮助解决问题(例如,一个容器在启动时出现致命错误),如下例所示:

```
kubectl describe pod ticktock-log-0-qnk72
```

#### 12.6.1.检查服务器日志

可以使用以下命令访问服务器日志:

```
kubectl get pod -l app=scdf=server
kubectl logs <scdf-server-pod-name>
```

#### 12.6.2.溪流

署流应用程序时,流名后面跟着应用程序的名称。对于处理器和接收器,还附加了一个实例索引。

查看 Spring 云数据流服务器部署的所有 pod,你可以指定`role=spring-app`标签,如下所示:

```
kubectl get pod -l role=spring-app
```

查看特定应用程序部署的详细信息,你可以使用以下命令:

```
kubectl describe pod <app-pod-name>
```

查看应用程序日志,你可以使用以下命令:

```
kubectl logs <app-pod-name>
```

果你想跟踪日志,可以使用以下命令:

```
kubectl logs -f <app-pod-name>
```

#### 12.6.3.任务

务以裸荚形式启动,无需复制控制器。任务完成后,这些吊舱仍将保留,这为你提供了查看日志的机会。

查看特定任务的所有吊舱,请使用以下命令:

```
kubectl get pod -l task-name=<task-name>
```

查看任务日志,请使用以下命令:

```
kubectl logs <task-pod-name>
```

有两个选项来删除已完成的 pod。一旦不再需要它们,你可以手动删除它们,或者可以使用数据流 shell`task execution cleanup`命令删除已完成的 pod 以执行任务。

手动删除 Task Pod,请使用以下命令:

```
kubectl delete pod <task-pod-name>
```

使用`task execution cleanup`命令,你必须首先确定用于执行任务的`ID`。要做到这一点,请使用`task execution list`命令,如下例(带输出)所示:

```
dataflow:>task execution list
═════════╤══╤════════════════════════════╤════════════════════════════╤═════════╗
Task Name│ID│         Start Time         │          End Time          │Exit Code║
═════════╪══╪════════════════════════════╪════════════════════════════╪═════════╣
task1    │1 │Fri May 05 18:12:05 EDT 2017│Fri May 05 18:12:05 EDT 2017│0        ║
═════════╧══╧════════════════════════════╧════════════════════════════╧═════════╝
```

了 ID 之后,就可以发出命令来清理执行工件(已完成的 POD),如下例所示:

```
dataflow:>task execution cleanup --id 1
Request to clean up resources for task execution 1 has been submitted
```

##### 任务的数据库凭据

Spring 默认情况下,云数据流在任务启动时将数据库凭据作为属性传递给 POD。如果使用`exec`或`shell`入口点样式,如果用户在任务的 POD 上执行`kubectl describe`,则可以查看 DB 凭据。要配置 Spring 云数据流以使用 Kubernetes Secrets:将`spring.cloud.dataflow.task.use.kubernetes.secrets.for.db.credentials`属性设置为`true`。如果使用 Spring 云数据流提供的 YAML 文件更新 `SRC/Kubernetes/服务器/服务器-deployment.yaml’,以添加以下环境变量:

```
- name: SPRING_CLOUD_DATAFLOW_TASK_USE_KUBERNETES_SECRETS_FOR_DB_CREDENTIALS
  value: 'true'
```

果从以前的 SCDF 版本升级,请务必验证`spring.datasource.username`和`myscheduler`环境变量是否存在于服务器-config.yaml 中的`secretKeyRefs`中。如果没有,请按下面的示例添加:

```
...
  task:
    platform:
      kubernetes:
        accounts:
          default:
            secretKeyRefs:
              - envVarName: "spring.datasource.password"
                secretName: mysql
                dataKey: mysql-root-password
              - envVarName: "spring.datasource.username"
                  secretName: mysql
                  dataKey: mysql-root-username
...
```

要验证相关的秘密(数据密钥)在秘密中也是可用的。SCDF 在这里为 MySQL 提供了这样的示例:`src/kubernetes/mysql/mysql-svc.yaml`。

|   |默认情况下,通过属性传递 DB 凭据是为了保持向后兼容性。这一功能将会在未来的发布中被移除。|
|---|------------------------------------------------------------------------------------------------------------------------------------------------------|

### 12.7.调度

节介绍如何配置计划任务的定制。 Spring 云数据流 Kubernetes 服务器中的任务调度在默认情况下是启用的。属性用于影响计划任务的设置,并且可以在全局或每个计划的基础上进行配置。

|   |除非注意,否则按计划设置的属性总是优先于作为服务器配置设置的属性。这种安排允许为特定的计划覆盖全局服务器级别的属性。|
|---|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

见[`KubernetesSchedulerProperties`](https://github.com/ Spring-cloud/ Spring-cloud-scheduler-kubernetes/blob/master/SRC/main/java/org/springframework/cloud/scheduler/spi/kubernetes/kuberneteslerproperties.java)以获得更多支持的选项。

#### 12.7.1.入口点样式

口点样式会影响如何将应用程序属性传递给要部署的任务容器。目前,支持三种样式:

* `exec`:(默认)将所有应用程序属性作为命令行参数传递。

* `shell`:将所有应用程序属性作为环境变量传递。

* `boot`:创建一个名为`SPRING_APPLICATION_JSON`的环境变量,该变量包含所有应用程序属性的 JSON 表示。

可以按以下方式配置入口点样式:

```
deployer.kubernetes.entryPointStyle=<Entry Point Style>
```

所需的入口点样式替换`<Entry Point Style>`。

可以在部署 YAML 的容器`env`部分中在服务器级别配置入口点样式,如下例所示:

```
env:
- name: SPRING_CLOUD_SCHEDULER_KUBERNETES_ENTRY_POINT_STYLE
  value: entryPointStyle
```

所需的入口点样式替换`entryPointStyle`。

应该选择`exec`或`shell`的入口点样式,以对应于在容器的`ENTRYPOINT`中定义`Dockerfile`语法的方式。有关`exec`vs`shell`的更多信息和用例,请参见 Docker 文档的[ENTRYPOINT](https://docs.docker.com/engine/reference/builder/#entrypoint)部分。

使用`boot`入口点样式对应于使用`exec`样式`ENTRYPOINT`。来自部署请求的命令行参数将传递给容器,并添加映射到`SPRING_APPLICATION_JSON`环境变量中的应用程序属性,而不是命令行参数。

#### 12.7.2.环境变量

影响给定应用程序的环境设置,可以利用`spring.cloud.deployer.kubernetes.environmentVariables`属性。例如,生产设置中的一个常见要求是影响 JVM 内存参数。你可以通过使用`JAVA_TOOL_OPTIONS`环境变量来实现这一点,如下例所示:

```
deployer.kubernetes.environmentVariables=JAVA_TOOL_OPTIONS=-Xmx1024m
```

|   |当部署流应用程序或启动某些属性可能包含敏感信息的任务应用程序时,请使用`shell`或`boot`作为`entryPointStyle`。这是因为`exec`(默认)将所有属性转换为命令行参数,因此在某些环境中可能不安全。|
|---|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

外,你还可以在部署 YAML 的容器`env`部分中在服务器级别上配置环境变量,如下例所示:

|   |当在服务器配置中指定环境变量时,并在每个计划的基础上,环境变量将被合并。这允许在服务器配置中设置公共环境变量,并在特定的计划级别上设置更具体的环境变量。|
|---|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

```
env:
- name: SPRING_CLOUD_SCHEDULER_KUBERNETES_ENVIRONMENT_VARIABLES
  value: myVar=myVal
```

所需的环境变量替换`myVar=myVal`。

#### 12.7.3.图像拉取策略

像拉取策略定义了何时应该将 Docker 图像拉到本地注册中心。目前,有三项政策得到支持:

* `IfNotPresent`:(默认)如果图像已经存在,请不要拉它。

* `Always`:无论图像是否已经存在,都要拉它。

* `Never`:永远不要拉图像。只使用已经存在的图像。

面的示例展示了如何单独配置容器:

```
deployer.kubernetes.imagePullPolicy=Always
```

所需的图像拉出策略替换`Always`。

可以在部署 YAML 的容器`env`部分中,在服务器级别上配置图像拉取策略,如下例所示:

```
env:
- name: SPRING_CLOUD_SCHEDULER_KUBERNETES_IMAGE_PULL_POLICY
  value: Always
```

所需的图像拉出策略替换`Always`。

#### 12.7.4.专用 Docker 注册表

密且需要身份验证的 Docker 映像可以通过配置秘密来提取。首先,你必须在集群中创建一个秘密。按照[从私有注册表中提取图像](https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/)指南创建秘密。

建了秘密之后,使用`imagePullSecret`属性设置要使用的秘密,如下例所示:

```
deployer.kubernetes.imagePullSecret=mysecret
```

前面创建的秘密的名称替换`mysecret`。

还可以在部署 YAML 的容器`env`部分中,在服务器级别上配置图像提取秘密,如下例所示:

```
env:
- name: SPRING_CLOUD_SCHEDULER_KUBERNETES_IMAGE_PULL_SECRET
  value: mysecret
```

前面创建的秘密的名称替换`mysecret`。

#### 12.7.5.名称空间

认情况下,用于调度任务的命名空间是`default`。可以在部署 YAML 的容器`env`部分的服务器级配置中设置该值,如下例所示:

```
env:
- name: SPRING_CLOUD_SCHEDULER_KUBERNETES_NAMESPACE
  value: mynamespace
```

#### 12.7.6.服务帐户

可以通过属性为计划的任务配置自定义服务帐户。可以使用现有的服务帐户,也可以创建新的服务帐户。创建服务帐户的一种方法是使用`kubectl`,如下例所示:

```
$ kubectl create serviceaccount myserviceaccountname
serviceaccount "myserviceaccountname" created
```

后,你可以将服务帐户配置为按计划使用,如下所示:

```
deployer.kubernetes.taskServiceAccountName=myserviceaccountname
```

`myserviceaccountname`替换为你的服务帐户名称。

可以在部署 YAML 的容器`env`部分中在服务器级别配置服务帐户名称,如下例所示:

```
env:
- name: SPRING_CLOUD_SCHEDULER_KUBERNETES_TASK_SERVICE_ACCOUNT_NAME
  value: myserviceaccountname
```

`myserviceaccountname`替换为要应用于所有部署的服务帐户名称。

关调度任务的详细信息,请参见[调度任务](#spring-cloud-dataflow-schedule-launch-tasks)。

### 12.8.调试支持

Spring 通过[Java 调试连接协议(JDWP)](https://docs.oracle.com/javase/8/docs/technotes/guides/jpda/jdwp-spec.html)支持调试 Kubernetes 服务器的云数据流和包含的组件(例如[Spring Cloud Kubernetes Deployer](https://github.com/spring-cloud/spring-cloud-deployer-kubernetes))。本节概述了一种手动启用调试的方法,以及另一种使用 Spring Cloud Data Flow Server Kubernetes 提供的配置文件来“修补”正在运行的部署的方法。

|   |JDWP 本身不使用任何身份验证。本节假定调试是在本地开发环境(如 MiniKube)上完成的,因此没有提供关于确保调试端口安全的指导。|
|---|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

#### 12.8.1.手动启用调试

手动启用 JDWP,首先编辑`src/kubernetes/server/server-deployment.yaml`,并在`spec.template.spec.containers.ports`下添加一个额外的`containerPort`条目,其值为`5005`。另外,在`JAVA_TOOL_OPTIONS`下添加[`JAVA_TOOL_OPTIONS`](https://DOCS.oracle.com/javase/8/DOCS/platform/jvmti/jvmti.html#tooloptions)环境变量,如以下示例所示:

```
spec:
  ...
  template:
    ...
    spec:
      containers:
      - name: scdf-server
        ...
        ports:
        ...
		- containerPort: 5005
        env:
        - name: JAVA_TOOL_OPTIONS
          value: '-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005'
```

|   |前面的示例使用端口 5005,但它可以是与另一个端口不冲突的任何数字。对于添加的`containerPort`值和`address`标志的参数`JAVA_TOOL_OPTIONS``-agentlib`,所选择的端口号也必须相同,如前面的示例所示。|
|---|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

在可以启动 Spring 云数据流 Kubernetes 服务器。一旦服务器启动,你就可以验证`scdf-server`部署上的配置更改,如下例(带输出)所示:

```
kubectl describe deployment/scdf-server
...
...
Pod Template:
  ...
  Containers:
   scdf-server:
    ...
    Ports:       80/TCP, 5005/TCP
    ...
    Environment:
      JAVA_TOOL_OPTIONS:  -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005
	  ...
```

启动服务器并启用 JDWP 之后,你需要配置对端口的访问。在这个示例中,我们使用`port-forward`](https://kubernetes.io/DOCS/tasks/access-application-cluster/port-forward-access-application-cluster/)子命令`kubectl`。下面的示例(带输出)展示了如何使用`port-forward`将本地端口公开到调试目标:

```
$ kubectl get pod -l app=scdf-server
NAME                           READY     STATUS    RESTARTS   AGE
scdf-server-5b7cfd86f7-d8mj4   1/1       Running   0          10m
$ kubectl port-forward scdf-server-5b7cfd86f7-d8mj4 5005:5005
Forwarding from 127.0.0.1:5005 -> 5005
Forwarding from [::1]:5005 -> 5005
```

在可以通过将调试器指向`127.0.0.1`作为主机,将`5005`作为端口来附加调试器。`port-forward`子命令运行到停止为止(例如,按`CTRL+c`)。

可以通过将更改恢复到`src/kubernetes/server/server-deployment.yaml`来删除调试支持。在下一次部署 Spring 云数据流 Kubernetes 服务器时,将拾取恢复的更改。当每次部署服务器时默认应该启用调试时,手动将调试支持添加到配置中是有用的。

#### 12.8.2.启用带修补程序的调试

手动更改`server-deployment.yaml`不同,Kubernetes 对象可以在适当的位置进行“修补”。为了方便起见,包含了提供与手动方法相同配置的修补程序文件。要通过修补程序启用调试,请使用以下命令:

```
kubectl patch deployment scdf-server -p "$(cat src/kubernetes/server/server-deployment-debug.yaml)"
```

行前面的命令会自动添加`containerPort`属性和`JAVA_TOOL_OPTIONS`环境变量。下面的示例(带输出)展示了如何验证对`scdf-server`部署的更改:

```
$ kubectl describe deployment/scdf-server
...
...
Pod Template:
  ...
  Containers:
   scdf-server:
    ...
    Ports:       5005/TCP, 80/TCP
    ...
    Environment:
      JAVA_TOOL_OPTIONS:  -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005
	  ...
```

启用对调试端口的访问,而不是使用`kubectl`的`port-forward`子命令,你可以修补`scdf-server`Kubernetes 服务对象。你必须首先确保`scdf-server`Kubernetes 服务对象具有正确的配置。下面的示例(带输出)展示了如何这样做:

```
kubectl describe service/scdf-server
Port:                     <unset>  80/TCP
TargetPort:               80/TCP
NodePort:                 <unset>  30784/TCP
```

果输出包含`<unset>`,则必须对服务进行修补以添加此端口的名称。下面的示例展示了如何做到这一点:

```
$ kubectl patch service scdf-server -p "$(cat src/kubernetes/server/server-svc.yaml)"
```

|   |只有在添加调试功能之前创建了目标群集时,才应该缺少端口号。由于向`scdf-server`Kubernetes 服务对象添加了多个端口,因此每个端口都需要有自己的名称。|
|---|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

在你可以添加调试端口了,如下例所示:

```
kubectl patch service scdf-server -p "$(cat src/kubernetes/server/server-svc-debug.yaml)"
```

面的示例(带输出)展示了如何验证映射:

```
$ kubectl describe service scdf-server
Name:                     scdf-server
...
...
Port:                     scdf-server-jdwp  5005/TCP
TargetPort:               5005/TCP
NodePort:                 scdf-server-jdwp  31339/TCP
...
...
Port:                     scdf-server  80/TCP
TargetPort:               80/TCP
NodePort:                 scdf-server  30883/TCP
...
...
```

出结果表明,5005 集装箱港口已被映射到 31339 的节点。下面的示例(带输出)展示了如何获得 MiniKube 节点的 IP 地址:

```
$ minikube ip
192.168.99.100
```

了这些信息,你可以使用 192.168.99.100 的主机和 31339 的端口来创建调试连接。

面的示例展示了如何禁用 JDWP:

```
$ kubectl rollout undo deployment/scdf-server
$ kubectl patch service scdf-server --type json -p='[{"op": "remove", "path": "/spec/ports/0"}]'
```

3674
Kubernetes 部署对象在进行修补之前会回滚到其状态。然后用`remove`操作修补 Kubernetes 服务对象,以从`containerPorts`列表中删除端口 5005.
D
dallascao 已提交
3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659 4660 4661 4662 4663 4664 4665 4666 4667 4668 4669 4670 4671 4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734 4735 4736 4737 4738 4739 4740 4741 4742 4743 4744 4745 4746 4747 4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764 4765 4766 4767 4768 4769 4770 4771 4772 4773 4774 4775 4776 4777 4778 4779 4780 4781 4782 4783 4784 4785 4786 4787 4788 4789 4790 4791 4792 4793 4794 4795 4796 4797 4798 4799 4800 4801 4802 4803 4804 4805 4806 4807 4808 4809 4810 4811 4812 4813 4814 4815 4816 4817 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 4988 4989 4990 4991 4992 4993 4994 4995 4996 4997 4998 4999 5000 5001 5002 5003 5004 5005 5006 5007 5008 5009 5010 5011 5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044 5045 5046 5047 5048 5049 5050 5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064 5065 5066 5067 5068 5069 5070 5071 5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119 5120 5121 5122 5123 5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140 5141 5142 5143 5144 5145 5146 5147 5148 5149 5150 5151 5152 5153 5154 5155 5156 5157 5158 5159 5160 5161 5162 5163 5164 5165 5166 5167 5168 5169 5170 5171 5172 5173 5174 5175 5176 5177 5178 5179 5180 5181 5182 5183 5184 5185 5186 5187 5188 5189 5190 5191 5192 5193 5194 5195 5196 5197 5198 5199 5200 5201 5202 5203 5204 5205 5206 5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 5220 5221 5222 5223 5224 5225 5226 5227 5228 5229 5230 5231 5232 5233 5234 5235 5236 5237 5238 5239 5240 5241 5242 5243 5244 5245 5246 5247 5248 5249 5250 5251 5252 5253 5254 5255 5256 5257 5258 5259 5260 5261 5262 5263 5264 5265 5266 5267 5268 5269 5270 5271 5272 5273 5274 5275 5276 5277 5278 5279 5280 5281 5282 5283 5284 5285 5286 5287 5288 5289 5290 5291 5292 5293 5294 5295 5296 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 5314 5315 5316 5317 5318 5319 5320 5321 5322 5323 5324 5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363 5364 5365 5366 5367 5368 5369 5370 5371 5372 5373 5374 5375 5376 5377 5378 5379 5380 5381 5382 5383 5384 5385 5386 5387 5388 5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402 5403 5404 5405 5406 5407 5408 5409 5410 5411 5412 5413 5414 5415 5416 5417 5418 5419 5420 5421 5422 5423 5424 5425 5426 5427 5428 5429 5430 5431 5432 5433 5434 5435 5436 5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448 5449 5450 5451 5452 5453 5454 5455 5456 5457 5458 5459 5460 5461 5462 5463 5464 5465 5466 5467 5468 5469 5470 5471 5472 5473 5474 5475 5476 5477 5478 5479 5480 5481 5482 5483 5484 5485 5486 5487 5488 5489 5490 5491 5492 5493 5494 5495 5496 5497 5498 5499 5500 5501 5502 5503 5504 5505 5506 5507 5508 5509 5510 5511 5512 5513 5514 5515 5516 5517 5518 5519 5520 5521 5522 5523 5524 5525 5526 5527 5528 5529 5530 5531 5532 5533 5534 5535 5536 5537 5538 5539 5540 5541 5542 5543 5544 5545 5546 5547 5548 5549 5550 5551 5552 5553 5554 5555 5556 5557 5558 5559 5560 5561 5562 5563 5564 5565 5566 5567 5568 5569 5570 5571 5572 5573 5574 5575 5576 5577 5578 5579 5580 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592

|   |`kubectl rollout undo`强制 pod 重新启动。修补 Kubernetes 服务对象不会重新创建服务,并且到`scdf-server`部署的端口映射保持不变。|
|---|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

关部署回滚(包括管理历史记录)和[使用 Kubectl 补丁更新 API 对象](https://kubernetes.io/docs/tasks/run-application/update-api-object-kubectl-patch/)的更多信息,请参见[撤回部署](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#rolling-back-a-deployment)。

# Shell

节介绍了启动 shell 的选项,以及与 shell 如何处理空格、引号和 SPEL 表达式的解释有关的更高级功能。对于最常用的 shell 命令,[Stream DSL](#spring-cloud-dataflow-stream-intro)和[组合任务 DSL](#spring-cloud-dataflow-composed-tasks)的介绍性章节是很好的起点。

## 13. 外壳选项

shell 是在[Spring Shell](https://projects.spring.io/spring-shell/)项目的基础上构建的。有些命令行选项来自 Spring shell,有些则是特定于数据流的。shell 接受以下命令行选项:

```
unix:>java -jar spring-cloud-dataflow-shell-2.9.2.jar --help
Data Flow Options:
  --dataflow.uri=                              Address of the Data Flow Server [default: http://localhost:9393].
  --dataflow.username=                        Username of the Data Flow Server [no default].
  --dataflow.password=                    Password of the Data Flow Server [no default].
  --dataflow.credentials-provider-command= Executes an external command which must return an
                                                    OAuth Bearer Token (Access Token prefixed with 'Bearer '),
                                                    e.g. 'Bearer 12345'), [no default].
  --dataflow.skip-ssl-validation=       Accept any SSL certificate (even self-signed) [default: no].
  --dataflow.proxy.uri=                  Address of an optional proxy server to use [no default].
  --dataflow.proxy.username=        Username of the proxy server (if required by proxy server) [no default].
  --dataflow.proxy.password=        Password of the proxy server (if required by proxy server) [no default].
  --spring.shell.historySize=                 Default size of the shell log file [default: 3000].
  --spring.shell.commandFile=                 Data Flow Shell executes commands read from the file(s) and then exits.
  --help                                            This message.
```

可以使用`spring.shell.commandFile`选项指向一个现有的文件,该文件包含用于部署一个或多个相关流和任务的所有 shell 命令。还支持运行多个文件。它们应该以逗号分隔的字符串传递:

`--spring.shell.commandFile=file1.txt,file2.txt`

创建一些脚本以帮助自动化部署时,此选项非常有用。

外,下面的 shell 命令有助于将复杂的脚本模块化为多个独立的文件:

`dataflow:>script --file <YOUR_AWESOME_SCRIPT>`

## 14. 列出可用的命令

命令提示符下输入`help`,将显示所有可用命令的列表。大多数命令用于数据流功能,但也有一些是通用的。下面的清单显示了`help`命令的输出:

```
! - Allows execution of operating system (OS) commands
clear - Clears the console
cls - Clears the console
date - Displays the local date and time
exit - Exits the shell
http get - Make GET request to http endpoint
http post - POST data to http endpoint
quit - Exits the shell
system properties - Shows the shells properties {JB - restore the apostrophe}
version - Displays shell version
```

命令名添加到`help`将显示有关如何调用该命令的其他信息:

```
dataflow:>help stream create
Keyword:                   stream create
Description:               Create a new stream definition
 Keyword:                  ** default **
 Keyword:                  name
   Help:                   the name to give to the stream
   Mandatory:              true
   Default if specified:   '__NULL__'
   Default if unspecified: '__NULL__'

 Keyword:                  definition
   Help:                   a stream definition, using the DSL (e.g. "http --port=9000 | hdfs")
   Mandatory:              true
   Default if specified:   '__NULL__'
   Default if unspecified: '__NULL__'

 Keyword:                  deploy
   Help:                   whether to deploy the stream immediately
   Mandatory:              false
   Default if specified:   'true'
   Default if unspecified: 'false'
```

## 15. 制表符补全

可以在 shell 中完成 shell 命令选项,方法是在前导`--`之后按`TAB`键。例如,在`stream create --`之后按`TAB`会产生以下一对建议:

```
dataflow:>stream create --
stream create --definition    stream create --name
```

果键入`--de`,然后按 Tab,`--definition`展开。

表符补全也可以在流或用于应用程序或任务属性的组合任务 DSL 表达式中使用。你还可以使用`TAB`在流 DSL 表达式中获得你可以使用的可用源、处理器或接收器的提示。

## 16. 空白和引用规则

有当参数值包含空格或`|`字符时,才需要引用参数值。下面的示例将一个 SPEL 表达式(应用于它遇到的任何数据)传递给转换处理器:

```
transform --expression='new StringBuilder(payload).reverse()'
```

果参数值需要嵌入单个引号,请使用两个单引号,如下所示:

```
// Query is: Select * from /Customers where name='Smith'
scan --query='Select * from /Customers where name=''Smith'''
```

### 16.1.引号和逃逸

Spring 有一个基于外壳的客户机,它与数据流服务器进行对话,并负责**解析**DSL。反过来,应用程序可能具有依赖于嵌入式语言的应用程序属性,例如**Spring Expression Language**。

shell、数据流 DSL 解析器和 SPEL 都有关于它们如何处理引号以及语法转义如何工作的规则。当结合在一起时,可能会出现混乱。本节解释了应用的规则,并提供了当涉及所有三个组件时可能遇到的最复杂情况的示例。

|   |并不总是那么复杂<br/><br/>如果不使用数据流 shell(例如,如果直接使用 RESTAPI)或如果应用程序属性不是 SPEL 表达式,则转义规则更简单。|
|---|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

#### 16.1.1.外壳规则

以说,就报价而言,最复杂的组件是 shell。不过,规则可以很简单地列出:

* shell 命令由键(`--something`)和相应的值组成。不过,还有一种特殊的无键映射,将在后面进行描述。

* 值通常不能包含空格,因为空格是命令的默认分隔符。

* 但是,可以通过用引号(单引号(`'`)或双引号(`"`)包围该值来添加空格。

* 传递到部署属性内部的值(例如,`deployment <stream-name> --properties " …​"`)不应再次引用。

* 如果周围有引号,则值可以通过用反斜杠(`\`)作为前缀来嵌入相同类型的文字引号。

* 其他的转义也可以使用,例如`\t`,`\n`,`\r`,`\f`以及`\uxxxx`形式的 Unicode 转义。

* 无键映射是以一种特殊的方式处理的,因此它不需要引用来包含空格。

如,shell 支持`!`命令来执行本机 shell 命令。`!`接受单个无键参数。这就是为什么下面的示例有效的原因:

```
dataflow:>! rm something
```

里的参数是整个`rm something`字符串,该字符串按原样传递给底层 shell。

举一个例子,下面的命令是严格等价的,参数值是`something`(不带引号):

```
dataflow:>stream destroy something
dataflow:>stream destroy --name something
dataflow:>stream destroy "something"
dataflow:>stream destroy --name "something"
```

#### 16.1.2.属性文件规则

从文件中加载属性时,规则会放松。

* 属性文件(包括 Java 和 YAML)中使用的特殊字符需要转义。例如`\`应由`\\`代替,`\t`应由`\\t`代替,等等。

* 对于 Java 属性文件(`--propertiesFile <FILE_PATH>.properties`),属性值不应被引号包围。即使它们有空位,也不需要。

  ```
  filter.expression=payload > 5
  ```

* 但是,对于 YAML 属性文件(`--propertiesFile <FILE_PATH>.yaml`),值需要用双引号包围。

  ```
  app:
      filter:
          filter:
              expression: "payload > 5"
  ```

#### 16.1.3.DSL 解析规则

解析器级别(即在流或任务定义的主体内部),规则如下:

* 选项值通常被解析到第一个空格字符。

* 不过,它们也可以由文字字符串组成,用单引号或双引号环绕。

* 要嵌入这样的引号,请使用所需类型的两个连续引号。

此,在以下示例中,过滤器应用程序的`--expression`选项的值在语义上是等效的:

```
filter --expression=payload>5
filter --expression="payload>5"
filter --expression='payload>5'
filter --expression='payload > 5'
```

以说,最后一条更具可读性。多亏了周围的引语,这才成为可能。实际表达式是`payload > 5`。

在,假设我们要针对字符串消息进行测试。如果我们想将有效负载与 spel 文字字符串`"something"`进行比较,我们可以使用以下方法:

```
filter --expression=payload=='something'           (1)
filter --expression='payload == ''something'''     (2)
filter --expression='payload == "something"'       (3)
```

|**1**|这是可行的,因为没有空间。不过,它不是很清晰。|
|-----|-----------------------------------------------------------------------------------------------------------------------|
|**2**|这使用单引号来保护整个论证。因此,实际的单个报价需要加倍。|
|**3**|SPEL 识别带有单引号或双引号的字符串文字,因此最后一个方法可以说是可读性最强的。|

注意,前面的示例是在 shell 之外考虑的(例如,当直接调用 RESTAPI 时)。当在 shell 中输入时,很可能整个流定义本身就在双引号中,这将需要转义。整个例子如下:

```
dataflow:>stream create something --definition "http | filter --expression=payload='something' | log"

dataflow:>stream create something --definition "http | filter --expression='payload == ''something''' | log"

dataflow:>stream create something --definition "http | filter --expression='payload == \"something\"' | log"
```

#### 16.1.4.SPEL 语法和 SPEL 文字

后一块拼图是关于 spel 表达式的。许多应用程序接受将被解释为 SPEL 表达式的选项,并且,正如前面所看到的,字符串文字也以一种特殊的方式处理。规则如下:

* 文字可以用单引号或双引号括起来。

* 引号需要加倍才能嵌入文字引号。双引号内的单引号不需要特殊处理,反之亦然。

为最后一个示例,假设你希望使用[转换处理器]($https://docs.spring.io/spring-cloud-stream-app-starters/docs/current/reference/html/spring-cloud-stream-modules-processors.html#spring-clound-stream-modules-transform-processor)。此处理器接受`expression`选项,这是一个 SPEL 表达式。它将根据传入的消息进行评估,缺省值为`payload`(未更改消息有效负载的转发)。

要的是要理解以下陈述是等效的:

```
transform --expression=payload
transform --expression='payload'
```

而,它们不同于以下(以及它们的变体):

```
transform --expression="'payload'"
transform --expression='''payload'''
```

一个系列计算的是消息有效负载,而后面的示例计算的是文字字符串`payload`。

#### 16.1.5.把这一切放在一起

为最后一个完整的示例,请考虑如何通过在数据流壳层的上下文中创建一个流来强制将所有消息转换为字符串文字`hello world`:

```
dataflow:>stream create something --definition "http | transform --expression='''hello world''' | log" (1)

dataflow:>stream create something --definition "http | transform --expression='\"hello world\"' | log" (2)

dataflow:>stream create something --definition "http | transform --expression=\"'hello world'\" | log" (2)
```

|**1**|在第一行中,字符串周围是单引号(在数据流解析器级别),但它们需要加倍,因为它们位于字符串文本中(由等号之后的第一个引号开始)。|
|-----|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|**2**|第二行和第三行分别使用单引号和双引号,以在数据流解析器级别上包含整个字符串。因此,另一种报价可以在字符串中使用。不过,整个过程都在 shell 的`--definition`参数中,该参数使用了双引号。因此,双引号被转义(在 shell 级别)。|

# 溪流

节将更详细地介绍如何创建流,这些流是[Spring Cloud Stream](https://cloud.spring.io/spring-cloud-stream/)应用程序的集合。它涵盖了创建和部署流等主题。

果你刚开始使用 Spring 云数据流,那么在深入了解本节之前,你可能应该阅读[开始](#getting-started)指南。

## 17. 导言

是长期存在的[Spring Cloud Stream](https://cloud.spring.io/spring-cloud-stream/)应用程序的集合,它们通过消息传递中间件彼此通信。基于文本的 DSL 定义了应用程序之间的配置和数据流。虽然为你提供了许多应用程序来实现通用用例,但你通常会创建一个自定义 Spring 云流应用程序来实现自定义业务逻辑。

的一般生命周期是:

1. 登记申请。

2. 创建一个流定义。

3. 部署流。

4. 取消部署或破坏该流。

5. 升级或回滚流中的应用程序。

于部署流,数据流服务器必须被配置为将部署委托给 Spring 云生态系统中名为[Skipper](https://cloud.spring.io/spring-cloud-skipper/)的新服务器。

外,你可以将 Skipper 配置为将应用程序部署到一个或多个 Cloud Foundry ORGS 和空间、Kubernetes 集群上的一个或多个名称空间,或者本地机器。在数据流中部署流时,可以指定在部署时使用哪个平台。Skipper 还为数据流提供了对部署的流执行更新的功能。可以通过多种方式更新流中的应用程序,但最常见的示例之一是使用新的自定义业务逻辑升级处理器应用程序,同时不使用现有的源和接收器应用程序。

### 17.1.流管道 DSL

是通过使用受 Unix 启发的[管道语法](https://en.wikipedia.org/wiki/Pipeline_(Unix))来定义的。该语法使用垂直条形(称为“管道”)来连接多个命令。UNIX 中的命令`ls -l | grep key | less`获取`ls -l`进程的输出,并将其输送到`grep key`进程的输入。然后,将`grep`的输出发送到`less`进程的输入。每个`|`符号将左侧命令的标准输出与右侧命令的标准输入连接起来。数据从左到右在管道中流动。

 Data Flow 中,UNIX 命令被[Spring Cloud Stream](https://cloud.spring.io/spring-cloud-stream/)应用程序代替,每个管道符号表示通过消息传递中间件(例如 RabbitMQ 或 Apache Kafka)连接应用程序的输入和输出。

个 Spring Cloud Stream 应用程序都以一个简单的名称注册。注册过程指定可以在哪里获得应用程序(例如,在 Maven 存储库或 Docker 注册表中)。你可以在[section](#spring-cloud-dataflow-register-stream-apps)中找到有关如何注册 Spring 云流应用程序的更多信息。在数据流中,我们将 Spring 云应用程序分为源、处理器或接收器。

为一个简单的示例,考虑从 HTTP 源收集数据并将其写入文件接收器。使用 DSL,流描述为:

`http | file`

及某些处理的流将表示为:

`http | filter | transform | file`

以使用 shell 的`stream create`命令创建流定义,如下例所示:

`dataflow:> stream create --name httpIngest --definition "http | file"`

 DSL 被传递到`--definition`命令选项。

定义的部署是通过 shell 的`stream deploy`命令完成的,如下所示:

`dataflow:> stream deploy --name ticktock`

[开始](#getting-started)部分向你展示了如何启动服务器以及如何启动和使用 Spring 云数据流壳层。

注意,shell 调用了数据流服务器的 REST API。有关直接向服务器发出 HTTP 请求的详细信息,请参见[REST API 指南](#api-guide)。

|   |在命名流定义时,请记住,流中的每个应用程序都将在平台上创建,其名称的格式为`<stream name>-<app name>`。因此,生成的应用程序名称的总长度不能超过 58 个字符。|
|---|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

### 17.2.流应用程序 DSL

以使用流应用程序 DSL 为 Spring 云流应用程序中的每个定义自定义绑定属性。有关更多信息,请参见 microSite 的[流应用程序 DSL](https://dataflow.spring.io/docs/feature-guides/streams/stream-application-dsl/)部分。

虑下面的 Java 接口,它定义了一个输入方法和两个输出方法:

```
public interface Barista {

    @Input
    SubscribableChannel orders();

    @Output
    MessageChannel hotDrinks();

    @Output
    MessageChannel coldDrinks();
}
```

一步考虑以下 Java 接口,这是创建 Kafka Streams 应用程序的典型方法:

```
interface KStreamKTableBinding {

    @Input
    KStream<?, ?> inputStream();

    @Input
    KTable<?, ?> inputTable();
}
```

这些具有多个输入和输出绑定的情况下,数据流不能对从一个应用程序到另一个应用程序的数据流进行任何假设。因此,你需要将绑定属性设置为“连接”应用程序。**流应用程序 DSL**使用“双管道”,而不是“管道符号”,以表示数据流不应配置应用程序的绑定属性。想一想`||`的意思是“平行”。下面的示例展示了这样一个“并行”定义:

```
dataflow:> stream create --definition "orderGeneratorApp || baristaApp || hotDrinkDeliveryApp || coldDrinkDeliveryApp" --name myCafeStream
```

|   |打破零钱!SCDF Local、Cloud Foundry1.7.0 至 1.7.2 和 SCDF Kubernetes1.7.0 至 1.7.1 的版本使用`comma`字符作为应用程序之间的分隔符。这引起了传统的流 DSL 的突破性变化。虽然并不理想,但更改分隔符字符被认为是对现有用户影响最小的最佳解决方案。|
|---|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

个流有四个应用程序。`baristaApp`有两个输出目的地,`hotDrinks`和`coldDrinks`,分别被`hotDrinkDeliveryApp`和`coldDrinkDeliveryApp`使用。部署此流时,需要设置绑定属性,以便`baristaApp`将热饮消息发送到`hotDrinkDeliveryApp`目的地,并将冷饮消息发送到`coldDrinkDeliveryApp`目的地。下面的清单就是这样做的:

```
app.baristaApp.spring.cloud.stream.bindings.hotDrinks.destination=hotDrinksDest
app.baristaApp.spring.cloud.stream.bindings.coldDrinks.destination=coldDrinksDest
app.hotDrinkDeliveryApp.spring.cloud.stream.bindings.input.destination=hotDrinksDest
app.coldDrinkDeliveryApp.spring.cloud.stream.bindings.input.destination=coldDrinksDest
```

果希望使用消费者组,则需要分别在生产者应用程序和消费者应用程序上设置 Spring 云流应用程序属性`spring.cloud.stream.bindings.<channelName>.producer.requiredGroups`和`spring.cloud.stream.bindings.<channelName>.group`。

应用程序 DSL 的另一个常见用例是部署一个 HTTP 网关应用程序,该应用程序向 Kafka 或 RabbitMQ 应用程序发送同步请求或回复消息。在这种情况下,HTTP 网关应用程序和 Kafka 或 RabbitMQ 应用程序都可以是 Spring 不利用 Spring 云流库的集成应用程序。

可以使用流应用程序 DSL 仅部署单个应用程序。

### 17.3.应用程序属性

个应用程序都获取属性来定制其行为。例如,`http`源模块公开了一个`port`设置,该设置允许从默认值更改数据摄入端口:

```
dataflow:> stream create --definition "http --port=8090 | log" --name myhttpstream
```

个`port`属性实际上与标准的 Spring boot`server.port`属性相同。数据流增加了使用简写形式`port`而不是`server.port`的能力。你还可以指定 longhand 版本:

```
dataflow:> stream create --definition "http --server.port=8000 | log" --name myhttpstream
```

[流应用程序属性](#spring-cloud-dataflow-application-properties)一节中将更多地讨论这种简写行为。如果你有[已注册的应用程序属性元数据](https://dataflow.spring.io/docs/applications/application-metadata/#using-application-metadata),则可以在输入`--`后在 shell 中使用 tab 补全来获得候选属性名列表。

shell 为应用程序属性提供了制表符补全功能。`app info --name <appName> --type <appType>`shell 命令为所有受支持的属性提供了额外的文档。

|   |支持的流`<appType>`的可能性有:`source`,`processor`,和`sink`。|
|---|----------------------------------------------------------------------------------|

## 18. 流生命周期

的生命周期经历了以下几个阶段:

1. [注册一个流应用程序](#spring-cloud-dataflow-register-stream-apps)

2. [创建一个流](#spring-cloud-dataflow-create-stream)

3. [部署流](#spring-cloud-dataflow-deploy-stream)

4. [破坏一条小溪](#spring-cloud-dataflow-destroy-stream)或[取消部署流](#spring-cloud-dataflow-undeploy-stream)

5. [Upgrade](#spring-cloud-dataflow-streams-upgrading)或[roll back](#spring-cloud-dataflow-streams-rollback)流中的应用程序。

[Skipper](https://cloud.spring.io/spring-cloud-skipper/)是一种服务器,它允许你在多个云平台上发现 Spring 引导应用程序并管理它们的生命周期。

Skipper 中的应用程序作为包捆绑在一起,包中包含应用程序的资源位置、应用程序属性和部署属性。你可以认为 Skipper 包类似于工具中的包,如`apt-get`或`brew`。

数据流部署流时,它会生成一个包并上载到 Skipper,该包表示流中的应用程序。在流中升级或回滚应用程序的后续命令将传递给 Skipper。此外,流定义是从包中反向工程的,流的状态也被委托给 Skipper。

### 18.1.注册一个流应用程序

可以使用`app register`命令注册版本流应用程序。你必须提供唯一的名称、应用程序类型和可以解析为应用程序工件的 URI。对于类型,请指定`source`、`processor`或`sink`。该版本是从 URI 解析的。以下是几个例子:

```
dataflow:>app register --name mysource --type source --uri maven://com.example:mysource:0.0.1
dataflow:>app register --name mysource --type source --uri maven://com.example:mysource:0.0.2
dataflow:>app register --name mysource --type source --uri maven://com.example:mysource:0.0.3

dataflow:>app list --id source:mysource
═══╤══════════════════╤═════════╤════╤════╗
app│      source      │processor│sink│task║
═══╪══════════════════╪═════════╪════╪════╣
   │> mysource-0.0.1 <│         │    │    ║
   │mysource-0.0.2    │         │    │    ║
   │mysource-0.0.3    │         │    │    ║
═══╧══════════════════╧═════════╧════╧════╝

dataflow:>app register --name myprocessor --type processor --uri file:///Users/example/myprocessor-1.2.3.jar

dataflow:>app register --name mysink --type sink --uri https://example.com/mysink-2.0.1.jar
```

用程序 URI 应该符合以下模式格式:

* Maven 模式:

  ```
  maven://<groupId>:<artifactId>[:<extension>[:<classifier>]]:<version>
  ```

* HTTP 架构:

  ```
  http://<web-path>/<artifactName>-<version>.jar
  ```

* 文件架构:

  ```
  file:///<local-path>/<artifactName>-<version>.jar
  ```

* Docker 模式:

  ```
  docker:<docker-image-path>/<imageName>:<version>
  ```

|   |对于版本控制的流应用程序,URI`<version>`部分是必需的。<br/>Skipper 使用多版本控制的流应用程序允许通过使用部署属性在运行时升级或回滚这些应用程序。|
|---|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

果你想注册使用 RabbitMQ 活页夹构建的`http`和`log`应用程序的快照版本,可以执行以下操作:

```
dataflow:>app register --name http --type source --uri maven://org.springframework.cloud.stream.app:http-source-rabbit:1.2.1.BUILD-SNAPSHOT
dataflow:>app register --name log --type sink --uri maven://org.springframework.cloud.stream.app:log-sink-rabbit:1.2.1.BUILD-SNAPSHOT
```

果希望一次注册多个应用程序,可以将它们存储在一个属性文件中,其中键的格式为`<type>.<name>`,值是 URI。

如,要注册使用 RabbitMQ 绑定程序构建的`http`和`log`应用程序的快照版本,可以在属性文件中包含以下内容(例如,`stream-apps.properties`):

```
source.http=maven://org.springframework.cloud.stream.app:http-source-rabbit:1.2.1.BUILD-SNAPSHOT
sink.log=maven://org.springframework.cloud.stream.app:log-sink-rabbit:1.2.1.BUILD-SNAPSHOT
```

后,要大量导入应用程序,请使用`app import`命令,并通过`--uri`开关提供属性文件的位置,如下所示:

```
dataflow:>app import --uri file:///<YOUR_FILE_LOCATION>/stream-apps.properties
```

使用`--type app`注册应用程序与注册`source`、`processor`或`sink`相同。类型`app`的应用程序只能在流应用程序 DSL 中使用(它在 DSL 中使用双管道`||`而不是单管道`|`),并指示数据流不要配置应用程序的 Spring 云流绑定属性。使用`--type app`注册的应用程序不必是 Spring 云流应用程序。它可以是任何 Spring 启动应用程序。有关使用此应用程序类型的更多信息,请参见[流应用 DSL 介绍](#spring-cloud-dataflow-stream-app-dsl)。

可以注册相同应用程序的多个版本(例如,相同的名称和类型),但只能将其中一个设置为默认值。默认版本用于部署流。

一次注册应用程序时,它被标记为默认值。可以使用`app default`命令更改默认的应用程序版本:

```
dataflow:>app default --id source:mysource --version 0.0.2
dataflow:>app list --id source:mysource
═══╤══════════════════╤═════════╤════╤════╗
app│      source      │processor│sink│task║
═══╪══════════════════╪═════════╪════╪════╣
   │mysource-0.0.1    │         │    │    ║
   │> mysource-0.0.2 <│         │    │    ║
   │mysource-0.0.3    │         │    │    ║
═══╧══════════════════╧═════════╧════╧════╝
```

`app list --id <type:name>`命令列出了给定流应用程序的所有版本。

`app unregister`命令有一个可选的`--version`参数,用于指定要取消注册的应用程序版本:

```
dataflow:>app unregister --name mysource --type source --version 0.0.1
dataflow:>app list --id source:mysource
═══╤══════════════════╤═════════╤════╤════╗
app│      source      │processor│sink│task║
═══╪══════════════════╪═════════╪════╪════╣
   │> mysource-0.0.2 <│         │    │    ║
   │mysource-0.0.3    │         │    │    ║
═══╧══════════════════╧═════════╧════╧════╝
```

果`--version`未指定,则默认版本未注册。

|   |流中的所有应用程序都应该为要部署的流设置一个默认版本。<br/>否则,在部署过程中它们将被视为未注册的应用程序。<br/>使用`app default`命令设置默认值。|
|---|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

```
app default --id source:mysource --version 0.0.3
dataflow:>app list --id source:mysource
═══╤══════════════════╤═════════╤════╤════╗
app│      source      │processor│sink│task║
═══╪══════════════════╪═════════╪════╪════╣
   │mysource-0.0.2    │         │    │    ║
   │> mysource-0.0.3 <│         │    │    ║
═══╧══════════════════╧═════════╧════╧════╝
```

`stream deploy`需要设置默认的应用程序版本。不过,`stream update`和`stream rollback`命令可以使用所有(默认和非默认)注册的应用程序版本。

面的命令创建了一个使用默认 MySource 版本(0.0.3)的流:

```
dataflow:>stream create foo --definition "mysource | log"
```

后我们可以将版本更新到 0.0.2:

```
dataflow:>stream update foo --properties version.mysource=0.0.2
```

|   |只有预先注册的应用程序才能用于`deploy`、`update`或`rollback`a 流。|
|---|-------------------------------------------------------------------------------------------|

`mysource`更新为`0.0.1`(未注册)的尝试失败。

#### 18.1.1.注册支持的应用程序和任务

了方便起见,我们为所有开箱即用流和任务或批处理应用程序启动器提供了带有应用程序 URI(用于 Maven 和 Docker)的静态文件。你可以指向这个文件并大量导入所有的应用程序 URI。否则,正如前面所解释的,你可以单独注册它们,或者拥有自己的自定义属性文件,其中只包含所需的应用程序 URI。但是,我们建议在自定义属性文件中设置一个所需的应用程序 URI 的“集中”列表。

##### Spring Cloud Stream 应用程序初学者

表包括指向基于 Spring Cloud Stream2.1.x 和 Spring Boot2.1.x 的可用流应用程序启动器的`dataflow.spring.io`链接:

|    Artifact Type    |                                        Stable Release                                        |快照发布|
|---------------------|----------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|  RabbitMQ + Maven   | [dataflow.spring.io/rabbitmq-maven-latest](https://dataflow.spring.io/rabbitmq-maven-latest) |[dataflow.spring.io/Einstein-BUILD-SNAPSHOT-stream-applications-rabbit-maven](https://dataflow.spring.io/Einstein-BUILD-SNAPSHOT-stream-applications-rabbit-maven)|
|  RabbitMQ + Docker  |[dataflow.spring.io/rabbitmq-docker-latest](https://dataflow.spring.io/rabbitmq-docker-latest)|[dataflow.spring.io/Einstein-BUILD-SNAPSHOT-stream-applications-rabbit-docker](https://dataflow.spring.io/Einstein-BUILD-SNAPSHOT-stream-applications-rabbit-docker)|
|Apache Kafka + Maven |    [dataflow.spring.io/kafka-maven-latest](https://dataflow.spring.io/kafka-maven-latest)    |[dataflow.spring.io/Einstein-BUILD-SNAPSHOT-stream-applications-kafka-maven](https://dataflow.spring.io/Einstein-BUILD-SNAPSHOT-stream-applications-kafka-maven)|
|Apache Kafka + Docker|   [dataflow.spring.io/kafka-docker-latest](https://dataflow.spring.io/kafka-docker-latest)   |[dataflow.spring.io/Einstein-BUILD-SNAPSHOT-stream-applications-kafka-docker](https://dataflow.spring.io/Einstein-BUILD-SNAPSHOT-stream-applications-kafka-docker)|

|   |默认情况下,应用程序启动执行器端点是安全的。你可以通过使用`app.*.spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration`属性部署流来禁用安全性。<br/>在 Kubernetes 上,请参阅[活性和准备状态探查](#getting-started-kubernetes-probes)部分,以了解如何为执行器端点配置<br/>安全性。|
|---|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

|   |从 Spring Cloud Stream2.1GA 版本开始,我们现在与 Spring Cloud 函数<br/>编程模型具有强大的互操作性。在此基础上,使用 Einstein Release-Train,现在可以选择几个流应用<br/>启动器,并使用函数式编程模型将它们组合成一个应用程序。查看["Composed Function Support in<br/>Spring Cloud Data Flow"](https://spring.io/blog/2019/01/09/composed-function-support-in-spring-cloud-data-flow)博客,以了解有关开发人员和业务流程的更多信息,并提供示例。|
|---|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

##### Spring 云任务应用程序初学者

表包括基于 Spring Cloud Task2.1.x 和 Spring Boot2.1.x 的可用任务应用程序启动器:

|Artifact Type|                                    Stable Release                                    |快照发布|
|-------------|--------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------|
|    Maven    | [dataflow.spring.io/task-maven-latest](https://dataflow.spring.io/task-maven-latest) |[dataflow.spring.io/Elston-BUILD-SNAPSHOT-task-applications-maven](https://dataflow.spring.io/Elston-BUILD-SNAPSHOT-task-applications-maven)|
|   Docker    |[dataflow.spring.io/task-docker-latest](https://dataflow.spring.io/task-docker-latest)|[dataflow.spring.io/Elston-BUILD-SNAPSHOT-task-applications-docker](https://dataflow.spring.io/Elston-BUILD-SNAPSHOT-task-applications-docker)|

可以在[任务应用程序启动项目页面](https://cloud.spring.io/spring-cloud-task-app-starters/)和相关参考文档中找到有关可用任务启动器的更多信息。有关可用的流启动器的更多信息,请查看[流应用程序启动项目页面](https://cloud.spring.io/spring-cloud-stream-app-starters/)和相关的参考文档。

如,如果你想注册所有使用 Kafka Binder 构建的批量开箱即用流应用程序,可以使用以下命令:

```
$ dataflow:>app import --uri https://dataflow.spring.io/kafka-maven-latest
```

者,你可以使用 Rabbit Binder 注册所有的流应用程序,如下所示:

```
$ dataflow:>app import --uri https://dataflow.spring.io/rabbitmq-maven-latest
```

还可以传递`--local`选项(默认情况下是`true`),以指示是否应该在 shell 进程本身中解析属性文件位置。如果应该从数据流服务器进程解析位置,请指定`--local false`。

|   |当使用`app register`或`app import`时,如果应用程序已经用<br/>提供的名称、类型和版本注册,则默认情况下不会覆盖该应用程序。如果你想重写<br/>预先存在的应用程序`uri`或`metadata-uri`坐标,请包括`--force`选项。<br/>但是,注意,一旦下载,应用程序可能会基于资源<br/>位置在数据流服务器上本地缓存。如果资源位置没有改变(即使实际资源*字节*可能是不同的),它<br/>也不会被重新下载。另一方面,当使用`maven://`资源时,使用一个固定的位置仍然可以绕过<br/>缓存(如果使用`-SNAPSHOT`版本)。此外,如果流已经部署并使用了某个注册应用程序的某个版本,然后(强制)重新注册一个<br/>不同的应用程序没有任何效果,直到流再次部署。|
|---|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

|   |在某些情况下,资源是在服务器端解析的。在其他情况下,<br/>URI 被传递给一个运行时容器实例,并在其中进行解析。有关更多详细信息,请参见<br/>每个数据流服务器的具体文档。|
|---|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

#### 18.1.2.创建自定义应用程序

然数据流包括源程序、处理器程序和接收程序,但你可以扩展这些程序或编写自定义[Spring Cloud Stream](https://github.com/spring-cloud/spring-cloud-stream)应用程序。

Spring 使用[Spring Initializr](https://start.spring.io/)创建 Spring 云流应用程序的过程在 Spring 云流[文件](https://docs.spring.io/spring-cloud-stream/docs/current/reference/htmlsingle/index.html#_getting_started)中进行了详细说明。你可以将多个绑定程序包含到一个应用程序。如果你这样做了,请参阅[[passing\_producer\_consumer\_properties]]中的说明,以了解如何配置它们。

了支持允许的属性,在 Spring 云数据流中运行的 Spring 云流应用程序可以将 Spring boot`configuration-processor`作为可选依赖项,如以下示例所示:

```
<dependencies>
  <!-- other dependencies -->
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
  </dependency>
</dependencies>
```

意:确保`spring-boot-maven-plugin`包含在 POM 中。该插件对于创建注册在 Spring 云数据流中的可执行 JAR 是必需的。 Spring InitialZR 包括在所生成的插件中的 POM。

旦创建了自定义应用程序,就可以注册它,如[注册一个流应用程序](#spring-cloud-dataflow-register-stream-apps)中所述。

### 18.2.创建一个流

Spring 云数据流服务器公开了用于管理流定义的生命周期的完整 RESTful API,但最简单的使用方法是通过 Spring 云数据流壳层。[开始](#getting-started)部分描述了如何启动 shell。

的流是在流定义的帮助下创建的。这些定义是从一个简单的 DSL 构建的。例如,考虑一下如果我们运行以下 shell 命令会发生什么:

```
dataflow:> stream create --definition "time | log" --name ticktock
```

定义了一个名为`ticktock`的流,该流基于 DSL 表达式`time | log`。DSL 使用“pipe”符号(`|`)将源连接到接收器。

`stream info`命令显示了有关流的有用信息,如下例所示(与其输出一起):

```
dataflow:>stream info ticktock
═══════════╤═════════════════╤══════════╗
Stream Name│Stream Definition│  Status  ║
═══════════╪═════════════════╪══════════╣
ticktock   │time | log       │undeployed║
═══════════╧═════════════════╧══════════╝
```

#### 18.2.1.流应用程序属性

用程序属性是与流中的每个应用程序相关联的属性。在部署应用程序时,应用程序属性将通过命令行参数或环境变量应用于应用程序,这取决于底层的部署实现。

下流可以具有在创建流时定义的应用程序属性:

```
dataflow:> stream create --definition "time | log" --name ticktock
```

`app info --name <appName> --type <appType>`shell 命令显示应用程序的公开应用程序属性。有关暴露的属性的更多信息,请参见[应用程序元数据](https://dataflow.spring.io/docs/applications/application-metadata)。

面的清单显示了`time`应用程序的公开属性:

```
dataflow:> app info --name time --type source
══════════════════════════════╤══════════════════════════════╤══════════════════════════════╤══════════════════════════════╗
         Option Name          │         Description          │           Default            │             Type             ║
══════════════════════════════╪══════════════════════════════╪══════════════════════════════╪══════════════════════════════╣
trigger.time-unit             │The TimeUnit to apply to delay│<none>                        │java.util.concurrent.TimeUnit ║
                              │values.                       │                              │                              ║
trigger.fixed-delay           │Fixed delay for periodic      │1                             │java.lang.Integer             ║
                              │triggers.                     │                              │                              ║
trigger.cron                  │Cron expression value for the │<none>                        │java.lang.String              ║
                              │Cron Trigger.                 │                              │                              ║
trigger.initial-delay         │Initial delay for periodic    │0                             │java.lang.Integer             ║
                              │triggers.                     │                              │                              ║
trigger.max-messages          │Maximum messages per poll, -1 │1                             │java.lang.Long                ║
                              │means infinity.               │                              │                              ║
trigger.date-format           │Format for the date value.    │<none>                        │java.lang.String              ║
══════════════════════════════╧══════════════════════════════╧══════════════════════════════╧══════════════════════════════╝
```

面的清单显示了`log`应用程序的公开属性:

```
dataflow:> app info --name log --type sink
══════════════════════════════╤══════════════════════════════╤══════════════════════════════╤══════════════════════════════╗
         Option Name          │         Description          │           Default            │             Type             ║
══════════════════════════════╪══════════════════════════════╪══════════════════════════════╪══════════════════════════════╣
log.name                      │The name of the logger to use.│<none>                        │java.lang.String              ║
log.level                     │The level at which to log     │<none>                        │org.springframework.integratio║
                              │messages.                     │                              │n.handler.LoggingHandler$Level║
log.expression                │A SpEL expression (against the│payload                       │java.lang.String              ║
                              │incoming message) to evaluate │                              │                              ║
                              │as the logged message.        │                              │                              ║
══════════════════════════════╧══════════════════════════════╧══════════════════════════════╧══════════════════════════════╝
```

可以在创建`stream`时为`time`和`log`应用程序指定应用程序属性,如下所示:

```
dataflow:> stream create --definition "time --fixed-delay=5 | log --level=WARN" --name ticktock
```

意,在前面的示例中,为`fixed-delay`和`level`应用程序定义的`time`属性是 shell 补全提供的“简式”属性名称。这些“简式”属性名称仅适用于公开的属性。在所有其他情况下,你应该只使用完全限定的属性名。

#### 18.2.2.通用应用程序属性

Spring 除了通过 DSL 进行配置外,云数据流还提供了一种机制,用于设置由其启动的所有流应用程序的公共属性。这可以通过在启动服务器时添加带`spring.cloud.dataflow.applicationProperties.stream`前缀的属性来完成。这样做时,服务器将所有属性(不带前缀)传递给它启动的实例。

如,通过使用以下选项启动数据流服务器,可以将所有启动的应用程序配置为使用特定的 Kafka 代理:

```
--spring.cloud.dataflow.applicationProperties.stream.spring.cloud.stream.kafka.binder.brokers=192.168.1.100:9092
--spring.cloud.dataflow.applicationProperties.stream.spring.cloud.stream.kafka.binder.zkNodes=192.168.1.100:2181
```

样做会将`spring.cloud.stream.kafka.binder.brokers`和`spring.cloud.stream.kafka.binder.zkNodes`属性传递给所有启动的应用程序。

|   |使用此机制配置的属性的优先级低于流部署属性。<br/>如果在流部署时指定了具有相同键的属性(例如,`app.http.spring.cloud.stream.kafka.binder.brokers`重写公共属性),则会重写这些属性。|
|---|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

### 18.3.部署流

节描述了当 Spring 云数据流服务器负责部署流时如何部署流。它涵盖了通过使用 Skipper 服务部署和升级流。关于如何设置部署属性的描述适用于两种流部署方法。

虑`ticktock`流定义:

```
dataflow:> stream create --definition "time | log" --name ticktock
```

部署流,请使用以下 shell 命令:

```
dataflow:> stream deploy --name ticktock
```

据流服务器委托跳过`time`和`log`应用程序的解析和部署。

`stream info`命令显示了有关流的有用信息,包括部署属性:

```
dataflow:>stream info --name ticktock
═══════════╤═════════════════╤═════════╗
Stream Name│Stream Definition│  Status ║
═══════════╪═════════════════╪═════════╣
ticktock   │time | log       │deploying║
═══════════╧═════════════════╧═════════╝

Stream Deployment properties: {
  "log" : {
    "resource" : "maven://org.springframework.cloud.stream.app:log-sink-rabbit",
    "spring.cloud.deployer.group" : "ticktock",
    "version" : "2.0.1.RELEASE"
  },
  "time" : {
    "resource" : "maven://org.springframework.cloud.stream.app:time-source-rabbit",
    "spring.cloud.deployer.group" : "ticktock",
    "version" : "2.0.1.RELEASE"
  }
}
```

于`stream deploy`命令,有一个重要的可选命令参数(称为`--platformName`)。可以将 Skipper 配置为部署到多个平台。Skipper 预先配置了一个名为`default`的平台,该平台将应用程序部署到运行 Skipper 的本地机器上。`--platformName`命令行参数的默认值是`default`。如果通常部署到一个平台,则在安装 Skipper 时,可以重写`default`平台的配置。否则,将`platformName`指定为`stream platform-list`命令返回的值之一。

前面的示例中,时间源每秒发送当前时间作为消息,而日志接收器通过使用日志框架输出它。你可以跟踪`stdout`日志(它有一个`<instance>`后缀)。日志文件位于数据流服务器的日志输出中显示的目录中,如以下清单所示:

```
$ tail -f /var/folders/wn/8jxm_tbd1vj28c8vj37n900m0000gn/T/spring-cloud-dataflow-912434582726479179/ticktock-1464788481708/ticktock.log/stdout_0.log
2016-06-01 09:45:11.250  INFO 79194 --- [  kafka-binder-] log.sink    : 06/01/16 09:45:11
2016-06-01 09:45:12.250  INFO 79194 --- [  kafka-binder-] log.sink    : 06/01/16 09:45:12
2016-06-01 09:45:13.251  INFO 79194 --- [  kafka-binder-] log.sink    : 06/01/16 09:45:13
```

还可以在创建流时通过传递`--deploy`标志一步创建和部署流,如下所示:

```
dataflow:> stream create --definition "time | log" --name ticktock --deploy
```

而,在现实世界的用例中,在一步中创建和部署流并不常见。原因是,当你使用`stream deploy`命令时,你可以传入定义如何将应用程序映射到平台上的属性(例如,要使用的容器的内存大小是多少,要运行的每个应用程序的数量是多少,以及是否启用数据分区功能)。属性还可以覆盖在创建流时设置的应用程序属性。下一节将详细介绍此功能。

#### 18.3.1.部署属性

署流时,可以指定可以控制应用程序部署和配置方式的属性。有关更多信息,请参见微型网站的[部署属性](https://dataflow.spring.io/docs/feature-guides/streams/deployment-properties/)部分。

### 18.4.破坏一条小溪

可以通过从 shell 中发出`stream destroy`命令来删除流,如下所示:

```
dataflow:> stream destroy --name ticktock
```

果流已部署,则在删除流定义之前未部署流。

### 18.5.取消部署流

常,你希望停止流,但保留名称和定义以备将来使用。在这种情况下,你可以`undeploy`流的名称:

```
dataflow:> stream undeploy --name ticktock
dataflow:> stream deploy --name ticktock
```

可以稍后发出`deploy`命令重新启动它:

```
dataflow:> stream deploy --name ticktock
```

### 18.6.验证流

时,流定义中包含的应用程序在其注册中包含无效的 URI。这可能是由于在应用程序注册时输入了无效的 URI,或者应用程序从要从中提取它的存储库中删除而导致的。要验证流中包含的所有应用程序都是可解析的,用户可以使用`validate`命令:

```
dataflow:>stream validate ticktock
═══════════╤═════════════════╗
Stream Name│Stream Definition║
═══════════╪═════════════════╣
ticktock   │time | log       ║
═══════════╧═════════════════╝

ticktock is a valid stream.
═══════════╤═════════════════╗
 App Name  │Validation Status║
═══════════╪═════════════════╣
source:time│valid            ║
sink:log   │valid            ║
═══════════╧═════════════════╝
```

前面的示例中,用户验证了他们的 ticktock 流。`source:time`和`sink:log`都是有效的。现在,我们可以看到,如果我们有一个流定义,其中注册的应用程序具有无效的 URI,会发生什么情况:

```
dataflow:>stream validate bad-ticktock
════════════╤═════════════════╗
Stream Name │Stream Definition║
════════════╪═════════════════╣
bad-ticktock│bad-time | log   ║
════════════╧═════════════════╝

bad-ticktock is an invalid stream.
═══════════════╤═════════════════╗
   App Name    │Validation Status║
═══════════════╪═════════════════╣
source:bad-time│invalid          ║
sink:log       │valid            ║
═══════════════╧═════════════════╝
```

这种情况下, Spring 云数据流声明该流是无效的,因为`source:bad-time`具有无效的 URI。

### 18.7.更新数据流

更新流,请使用`stream update`命令,该命令将`--properties`或`--propertiesFile`作为命令参数。Skipper 有一个重要的新顶级前缀:`version`。以下命令部署`http | log`流(以及在部署时注册的`log`的版本`1.1.0.RELEASE`):

```
dataflow:> stream create --name httptest --definition "http --server.port=9000 | log"
dataflow:> stream deploy --name httptest
dataflow:>stream info httptest
══════════════════════════════╤══════════════════════════════╤════════════════════════════╗
             Name             │             DSL              │          Status            ║
══════════════════════════════╪══════════════════════════════╪════════════════════════════╣
httptest                      │http --server.port=9000 | log │deploying                   ║
══════════════════════════════╧══════════════════════════════╧════════════════════════════╝

Stream Deployment properties: {
  "log" : {
    "spring.cloud.deployer.indexed" : "true",
    "spring.cloud.deployer.group" : "httptest",
    "maven://org.springframework.cloud.stream.app:log-sink-rabbit" : "1.1.0.RELEASE"
  },
  "http" : {
    "spring.cloud.deployer.group" : "httptest",
    "maven://org.springframework.cloud.stream.app:http-source-rabbit" : "1.1.0.RELEASE"
  }
}
```

后,下面的命令更新流以使用日志应用程序的`1.2.0.RELEASE`版本。在使用应用程序的特定版本更新流之前,我们需要确保应用程序已注册到该版本:

```
dataflow:>app register --name log --type sink --uri maven://org.springframework.cloud.stream.app:log-sink-rabbit:1.2.0.RELEASE
Successfully registered application 'sink:log'
```

后我们可以更新应用程序:

```
dataflow:>stream update --name httptest --properties version.log=1.2.0.RELEASE
```

|   |你只能使用预先注册的应用程序版本`deploy`、`update`或`rollback`a 流。|
|---|---------------------------------------------------------------------------------------------------|

了验证部署属性和更新的版本,我们可以使用`stream info`,如下例所示(其输出):

```
dataflow:>stream info httptest
══════════════════════════════╤══════════════════════════════╤════════════════════════════╗
             Name             │             DSL              │          Status            ║
══════════════════════════════╪══════════════════════════════╪════════════════════════════╣
httptest                      │http --server.port=9000 | log │deploying                   ║
══════════════════════════════╧══════════════════════════════╧════════════════════════════╝

Stream Deployment properties: {
  "log" : {
    "spring.cloud.deployer.indexed" : "true",
    "spring.cloud.deployer.count" : "1",
    "spring.cloud.deployer.group" : "httptest",
    "maven://org.springframework.cloud.stream.app:log-sink-rabbit" : "1.2.0.RELEASE"
  },
  "http" : {
    "spring.cloud.deployer.group" : "httptest",
    "maven://org.springframework.cloud.stream.app:http-source-rabbit" : "1.1.0.RELEASE"
  }
}
```

### 18.8.强制更新流

升级流时,你可以使用`--force`选项来部署当前部署的应用程序的新实例,即使没有应用程序或部署属性发生变化。当应用程序本身在启动时(例如,从 Spring Cloud Config Server)获得配置信息时,需要这种行为。你可以使用`--app-names`选项指定强制升级的应用程序。如果没有指定任何应用程序名称,则所有应用程序都将被迫升级。你可以指定`--force`和`--app-names`选项以及`--properties`或`--propertiesFile`选项。

### 18.9.流版本

Skipper 保留部署的流的历史记录。在更新一个流之后,会有第二个流的版本。你可以使用`stream history --name <name-of-stream>`命令查询版本的历史记录:

```
dataflow:>stream history --name httptest
═══════╤════════════════════════════╤════════╤════════════╤═══════════════╤════════════════╗
Version│        Last updated        │ Status │Package Name│Package Version│  Description   ║
═══════╪════════════════════════════╪════════╪════════════╪═══════════════╪════════════════╣
2      │Mon Nov 27 22:41:16 EST 2017│DEPLOYED│httptest    │1.0.0          │Upgrade complete║
1      │Mon Nov 27 22:40:41 EST 2017│DELETED │httptest    │1.0.0          │Delete complete ║
═══════╧════════════════════════════╧════════╧════════════╧═══════════════╧════════════════╝
```

### 18.10.流清单

Skipper 保留所有应用程序、它们的应用程序属性以及它们的部署属性的“清单”,在所有值都被替换之后。这代表了部署到平台上的内容的最终状态。你可以使用以下命令查看流的任何版本的清单:

```
stream manifest --name <name-of-stream> --releaseVersion <optional-version>
```

果没有指定`--releaseVersion`,则返回最后一个版本的清单。

面的示例展示了清单的使用:

```
dataflow:>stream manifest --name httptest
```

使用该命令会产生以下输出:

```
# Source: log.yml
apiVersion: skipper.spring.io/v1
kind: SpringCloudDeployerApplication
metadata:
  name: log
spec:
  resource: maven://org.springframework.cloud.stream.app:log-sink-rabbit
  version: 1.2.0.RELEASE
  applicationProperties:
    spring.cloud.dataflow.stream.app.label: log
    spring.cloud.stream.bindings.input.group: httptest
    spring.cloud.dataflow.stream.name: httptest
    spring.cloud.dataflow.stream.app.type: sink
    spring.cloud.stream.bindings.input.destination: httptest.http
  deploymentProperties:
    spring.cloud.deployer.indexed: true
    spring.cloud.deployer.group: httptest
    spring.cloud.deployer.count: 1

---
# Source: http.yml
apiVersion: skipper.spring.io/v1
kind: SpringCloudDeployerApplication
metadata:
  name: http
spec:
  resource: maven://org.springframework.cloud.stream.app:http-source-rabbit
  version: 1.2.0.RELEASE
  applicationProperties:
    spring.cloud.dataflow.stream.app.label: http
    spring.cloud.stream.bindings.output.producer.requiredGroups: httptest
    server.port: 9000
    spring.cloud.stream.bindings.output.destination: httptest.http
    spring.cloud.dataflow.stream.name: httptest
    spring.cloud.dataflow.stream.app.type: source
  deploymentProperties:
    spring.cloud.deployer.group: httptest
```

大多数部署和应用程序属性都是由数据流设置的,以使应用程序能够相互对话,并发送带有标识标签的应用程序指标。

### 18.11.回滚一条流

你可以使用`stream rollback`命令回滚到流的上一个版本:

```
dataflow:>stream rollback --name httptest
```

可选的`--releaseVersion`命令参数添加了流的版本。如果未指定,则回滚操作将转到上一个流版本。

### 18.12.应用程序数量

应用程序计数是用于指定应用程序实例数量的系统的动态属性。有关更多信息,请参见微型网站的[应用程序数量](https://dataflow.spring.io/docs/feature-guides/streams/application-count/)部分。

### 18.13.Skipper 的升级策略

Skipper 有一个简单的“红/黑”升级策略。它使用与当前运行的版本一样多的实例来部署应用程序的新版本,并检查应用程序的`/health`端点。如果新应用程序的健康状况良好,则取消部署上一个应用程序。如果新应用程序的健康状况不佳,则所有新应用程序都未被部署,并且升级被认为是不成功的。

升级策略不是滚动升级,因此,如果应用程序的五个实例正在运行,那么,在阳光明媚的情况下,在未部署旧版本之前,也有五个新应用程序正在运行。

## 19. 流 DSL

本节将介绍[流 DSL 介绍](#spring-cloud-dataflow-stream-intro-dsl)中未涉及的流 DSL 的其他特性。

### 19.1.点击一条小溪

可以在流中的各个生产者端点创建分接头。有关更多信息,请参见微型网站的[敲击溪流](https://dataflow.spring.io/docs/feature-guides/streams/taps/)部分。

### 19.2.在流中使用标签

当一个流是由具有相同名称的多个应用程序组成时,它们必须用标签进行限定。有关更多信息,请参见微型网站的[标记应用程序](https://dataflow.spring.io/docs/feature-guides/streams/labels/)部分。

### 19.3.已命名的目的地

你可以使用指定的目的地,而不是引用源程序或接收器应用程序。有关更多信息,请参见微型网站的[已命名的目的地](https://dataflow.spring.io/docs/feature-guides/streams/named-destinations/)部分。

### 19.4.扇入扇出

通过使用指定的目的地,你可以支持扇入和扇出用例。有关更多信息,请参见微型网站的[扇入扇出](https://dataflow.spring.io/docs/feature-guides/streams/fanin-fanout/)部分。

## 20. 流 Java DSL

你可以使用`spring-cloud-dataflow-rest-client`模块提供的基于 Java 的 DSL,而不是使用 shell 来创建和部署流。有关更多信息,请参见微型网站的[Java DSL](https://dataflow.spring.io/docs/feature-guides/streams/java-dsl/)部分。

## 21. 具有多个绑定配置的流应用程序

在某些情况下,当需要连接到不同的消息传递中间件配置时,流可以将其应用程序绑定到多个 Spring 云流绑定程序。在这些情况下,你应该确保应用程序的绑定配置是适当的。例如,支持 Kafka 和 Rabbit Binder 的多绑定转换器是以下流中的处理器:

```
http | multibindertransform --expression=payload.toUpperCase() | log
```

|   |在前面的示例中,你将编写自己的`multibindertransform`应用程序。|
|---|--------------------------------------------------------------------------------------|

在这个流中,每个应用程序都以以下方式连接到消息传递中间件:

1. HTTP 源将事件发送到 RabbitMQ(`rabbit1`)。

2. 多绑定转换处理器接收来自 RabbitMQ(`rabbit1`)的事件,并将处理后的事件发送到 Kafka(`kafka1`)。

3. 日志接收器接收来自 Kafka(`kafka1`)的事件。

在这里,`rabbit1`和`kafka1`是 Spring Cloud Stream 应用程序属性中给出的绑定程序名称。基于这种设置,应用程序在其类空间中具有以下具有适当配置的绑定器:

* http:rabbit binder

* 转换:Kafka 和 Rabbit Binder

* 日志:Kafka Binder

`spring-cloud-stream``binder`配置属性可以在应用程序本身中设置。如果不是,则可以在部署流时通过`deployment`属性传递它们:

```
dataflow:>stream create --definition "http | multibindertransform --expression=payload.toUpperCase() | log" --name mystream

dataflow:>stream deploy mystream --properties "app.http.spring.cloud.stream.bindings.output.binder=rabbit1,app.multibindertransform.spring.cloud.stream.bindings.input.binder=rabbit1,
app.multibindertransform.spring.cloud.stream.bindings.output.binder=kafka1,app.log.spring.cloud.stream.bindings.input.binder=kafka1"
```

你可以通过部署属性指定任何绑定程序配置属性来覆盖它们。

## 22. 函数组成

函数组合允许你动态地将功能逻辑附加到现有的事件流应用程序。有关更多详细信息,请参见 microSite 的[函数组成](https://dataflow.spring.io/docs/feature-guides/streams/function-composition/)部分。

## 23. 功能应用程序

通过 Spring Cloud Stream3.x 添加[功能支持](https://cloud.spring.io/spring-cloud-static/spring-cloud-stream/current/reference/html/spring-cloud-stream.html#spring-cloud-stream-overview-producing-consuming-messages),你可以分别通过实现 Java util 的`Source`、`Sink`和`Processor`接口来构建`Supplier`应用程序。有关此功能的更多信息,请参见 SCDF 站点的[功能应用程序配方](https://dataflow.spring.io/docs/recipes/functional-apps/)。

## 24. 例子

本章包括以下几个例子:

* [简单的流处理](#spring-cloud-dataflow-simple-stream)

* [有状态流处理](#spring-cloud-dataflow-stream-partitions)

* [其他源和汇应用程序类型](#spring-cloud-dataflow-stream-app-types)

你可以在“[Samples](#dataflow-samples)”一章中找到更多示例的链接。

### 24.1.简单的流处理

作为一个简单处理步骤的示例,我们可以使用以下流定义将 HTTP 发布的数据的有效负载转换为大写:

```
http | transform --expression=payload.toUpperCase() | log
```

要创建这个流,请在 shell 中输入以下命令:

```
dataflow:> stream create --definition "http --server.port=9000 | transform --expression=payload.toUpperCase() | log" --name mystream --deploy
```

下面的示例使用 shell 命令来发布一些数据:

```
dataflow:> http post --target http://localhost:9000 --data "hello"
```

前面的示例在日志中生成大写`HELLO`,如下所示:

```
2016-06-01 09:54:37.749  INFO 80083 --- [  kafka-binder-] log.sink    : HELLO
```

### 24.2.有状态流处理

为了演示数据分区功能,下面的清单部署了一个以 Kafka 为绑定器的流:

```
dataflow:>stream create --name words --definition "http --server.port=9900 | splitter --expression=payload.split(' ') | log"
Created new stream 'words'

dataflow:>stream deploy words --properties "app.splitter.producer.partitionKeyExpression=payload,deployer.log.count=2"
Deployed stream 'words'

dataflow:>http post --target http://localhost:9900 --data "How much wood would a woodchuck chuck if a woodchuck could chuck wood"
> POST (text/plain;Charset=UTF-8) http://localhost:9900 How much wood would a woodchuck chuck if a woodchuck could chuck wood
> 202 ACCEPTED

dataflow:>runtime apps
╔════════════════════╤═══════════╤═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╗
║App Id / Instance Id│Unit Status│                                                               No. of Instances / Attributes                                                               ║
╠════════════════════╪═══════════╪═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╣
║words.log-v1        │ deployed  │                                                                             2                                                                             ║
╟┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┼┈┈┈┈┈┈┈┈┈┈┈┼┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈╢
║                    │           │       guid = 24166                                                                                                                                        ║
║                    │           │        pid = 33097                                                                                                                                        ║
║                    │           │       port = 24166                                                                                                                                        ║
║words.log-v1-0      │ deployed  │     stderr = /var/folders/js/7b_pn0t575l790x7j61slyxc0000gn/T/spring-cloud-deployer-6467595568759190742/words-1542803461063/words.log-v1/stderr_0.log     ║
║                    │           │     stdout = /var/folders/js/7b_pn0t575l790x7j61slyxc0000gn/T/spring-cloud-deployer-6467595568759190742/words-1542803461063/words.log-v1/stdout_0.log     ║
║                    │           │        url = https://192.168.0.102:24166                                                                                                                   ║
║                    │           │working.dir = /var/folders/js/7b_pn0t575l790x7j61slyxc0000gn/T/spring-cloud-deployer-6467595568759190742/words-1542803461063/words.log-v1                  ║
╟┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┼┈┈┈┈┈┈┈┈┈┈┈┼┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈╢
║                    │           │       guid = 41269                                                                                                                                        ║
║                    │           │        pid = 33098                                                                                                                                        ║
║                    │           │       port = 41269                                                                                                                                        ║
║words.log-v1-1      │ deployed  │     stderr = /var/folders/js/7b_pn0t575l790x7j61slyxc0000gn/T/spring-cloud-deployer-6467595568759190742/words-1542803461063/words.log-v1/stderr_1.log     ║
║                    │           │     stdout = /var/folders/js/7b_pn0t575l790x7j61slyxc0000gn/T/spring-cloud-deployer-6467595568759190742/words-1542803461063/words.log-v1/stdout_1.log     ║
║                    │           │        url = https://192.168.0.102:41269                                                                                                                   ║
║                    │           │working.dir = /var/folders/js/7b_pn0t575l790x7j61slyxc0000gn/T/spring-cloud-deployer-6467595568759190742/words-1542803461063/words.log-v1                  ║
╟────────────────────┼───────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╢
║words.http-v1       │ deployed  │                                                                             1                                                                             ║
╟┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┼┈┈┈┈┈┈┈┈┈┈┈┼┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈╢
║                    │           │       guid = 9900                                                                                                                                         ║
║                    │           │        pid = 33094                                                                                                                                        ║
║                    │           │       port = 9900                                                                                                                                         ║
║words.http-v1-0     │ deployed  │     stderr = /var/folders/js/7b_pn0t575l790x7j61slyxc0000gn/T/spring-cloud-deployer-6467595568759190742/words-1542803461054/words.http-v1/stderr_0.log    ║
║                    │           │     stdout = /var/folders/js/7b_pn0t575l790x7j61slyxc0000gn/T/spring-cloud-deployer-6467595568759190742/words-1542803461054/words.http-v1/stdout_0.log    ║
║                    │           │        url = https://192.168.0.102:9900                                                                                                                    ║
║                    │           │working.dir = /var/folders/js/7b_pn0t575l790x7j61slyxc0000gn/T/spring-cloud-deployer-6467595568759190742/words-1542803461054/words.http-v1                 ║
╟────────────────────┼───────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╢
║words.splitter-v1   │ deployed  │                                                                             1                                                                             ║
╟┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┼┈┈┈┈┈┈┈┈┈┈┈┼┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈╢
║                    │           │       guid = 33963                                                                                                                                        ║
║                    │           │        pid = 33093                                                                                                                                        ║
║                    │           │       port = 33963                                                                                                                                        ║
║words.splitter-v1-0 │ deployed  │     stderr = /var/folders/js/7b_pn0t575l790x7j61slyxc0000gn/T/spring-cloud-deployer-6467595568759190742/words-1542803437542/words.splitter-v1/stderr_0.log║
║                    │           │     stdout = /var/folders/js/7b_pn0t575l790x7j61slyxc0000gn/T/spring-cloud-deployer-6467595568759190742/words-1542803437542/words.splitter-v1/stdout_0.log║
║                    │           │        url = https://192.168.0.102:33963                                                                                                                   ║
║                    │           │working.dir = /var/folders/js/7b_pn0t575l790x7j61slyxc0000gn/T/spring-cloud-deployer-6467595568759190742/words-1542803437542/words.splitter-v1             ║
╚════════════════════╧═══════════╧═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╝
```

当你查看`words.log-v1-0`日志时,你应该会看到以下内容:

```
2016-06-05 18:35:47.047  INFO 58638 --- [  kafka-binder-] log.sink                                 : How
2016-06-05 18:35:47.066  INFO 58638 --- [  kafka-binder-] log.sink                                 : chuck
2016-06-05 18:35:47.066  INFO 58638 --- [  kafka-binder-] log.sink                                 : chuck
```

当你查看`words.log-v1-1`日志时,你应该会看到以下内容:

```
2016-06-05 18:35:47.047  INFO 58639 --- [  kafka-binder-] log.sink                                 : much
2016-06-05 18:35:47.066  INFO 58639 --- [  kafka-binder-] log.sink                                 : wood
2016-06-05 18:35:47.066  INFO 58639 --- [  kafka-binder-] log.sink                                 : would
2016-06-05 18:35:47.066  INFO 58639 --- [  kafka-binder-] log.sink                                 : a
2016-06-05 18:35:47.066  INFO 58639 --- [  kafka-binder-] log.sink                                 : woodchuck
2016-06-05 18:35:47.067  INFO 58639 --- [  kafka-binder-] log.sink                                 : if
2016-06-05 18:35:47.067  INFO 58639 --- [  kafka-binder-] log.sink                                 : a
2016-06-05 18:35:47.067  INFO 58639 --- [  kafka-binder-] log.sink                                 : woodchuck
2016-06-05 18:35:47.067  INFO 58639 --- [  kafka-binder-] log.sink                                 : could
2016-06-05 18:35:47.067  INFO 58639 --- [  kafka-binder-] log.sink                                 : wood
```

这个示例表明,包含相同单词的有效负载分割被路由到相同的应用程序实例。

### 24.3.其他源和汇应用程序类型

这个例子展示了一些更复杂的东西:将`time`源转换成其他的东西。另一种受支持的源类型是`http`,它接受通过 HTTP POST 请求来摄取数据。请注意,`http`源接受来自数据流服务器(缺省 8080)的不同端口上的数据。默认情况下,端口是随机分配的。

要创建一个使用`http`源但仍使用相同`log`接收器的流,我们将[简单的流处理](#spring-cloud-dataflow-simple-stream)示例中的原始命令更改为以下内容:

```
dataflow:> stream create --definition "http | log" --name myhttpstream --deploy
```

请注意,这一次,在实际发布一些数据(通过使用 shell 命令)之前,我们不会看到任何其他输出。要查看`http`源正在监听的随机分配的端口,请运行以下命令:

```
dataflow:>runtime apps

╔══════════════════════╤═══════════╤═════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╗
║ App Id / Instance Id │Unit Status│                                                                    No. of Instances / Attributes                                                                    ║
╠══════════════════════╪═══════════╪═════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╣
║myhttpstream.log-v1   │ deploying │                                                                                  1                                                                                  ║
╟┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┼┈┈┈┈┈┈┈┈┈┈┈┼┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈╢
║                      │           │       guid = 39628                                                                                                                                                  ║
║                      │           │        pid = 34403                                                                                                                                                  ║
║                      │           │       port = 39628                                                                                                                                                  ║
║myhttpstream.log-v1-0 │ deploying │     stderr = /var/folders/js/7b_pn0t575l790x7j61slyxc0000gn/T/spring-cloud-deployer-6467595568759190742/myhttpstream-1542803867070/myhttpstream.log-v1/stderr_0.log ║
║                      │           │     stdout = /var/folders/js/7b_pn0t575l790x7j61slyxc0000gn/T/spring-cloud-deployer-6467595568759190742/myhttpstream-1542803867070/myhttpstream.log-v1/stdout_0.log ║
║                      │           │        url = https://192.168.0.102:39628                                                                                                                             ║
║                      │           │working.dir = /var/folders/js/7b_pn0t575l790x7j61slyxc0000gn/T/spring-cloud-deployer-6467595568759190742/myhttpstream-1542803867070/myhttpstream.log-v1              ║
╟──────────────────────┼───────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╢
║myhttpstream.http-v1  │ deploying │                                                                                  1                                                                                  ║
╟┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┼┈┈┈┈┈┈┈┈┈┈┈┼┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈╢
║                      │           │       guid = 52143                                                                                                                                                  ║
║                      │           │        pid = 34401                                                                                                                                                  ║
║                      │           │       port = 52143                                                                                                                                                  ║
║myhttpstream.http-v1-0│ deploying │     stderr = /var/folders/js/7b_pn0t575l790x7j61slyxc0000gn/T/spring-cloud-deployer-6467595568759190742/myhttpstream-1542803866800/myhttpstream.http-v1/stderr_0.log║
║                      │           │     stdout = /var/folders/js/7b_pn0t575l790x7j61slyxc0000gn/T/spring-cloud-deployer-6467595568759190742/myhttpstream-1542803866800/myhttpstream.http-v1/stdout_0.log║
║                      │           │        url = https://192.168.0.102:52143                                                                                                                             ║
║                      │           │working.dir = /var/folders/js/7b_pn0t575l790x7j61slyxc0000gn/T/spring-cloud-deployer-6467595568759190742/myhttpstream-1542803866800/myhttpstream.http-v1             ║
╚══════════════════════╧═══════════╧═════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╝
```

你应该看到对应的`http`源具有`url`属性,该属性包含它正在监听的主机和端口信息。现在你已经准备好发布到该 URL,如下面的示例所示:

```
dataflow:> http post --target http://localhost:1234 --data "hello"
dataflow:> http post --target http://localhost:1234 --data "goodbye"
```

然后,流将来自`http`源的数据漏斗到由`log`汇实现的输出日志,产生类似于以下内容的输出:

```
2016-06-01 09:50:22.121  INFO 79654 --- [  kafka-binder-] log.sink    : hello
2016-06-01 09:50:26.810  INFO 79654 --- [  kafka-binder-] log.sink    : goodbye
```

我们还可以更改 sink 实现。你可以通过管道将输出发送到文件(`file`)、Hadoop(`hdfs`)或任何其他可用的接收器应用程序。你还可以定义自己的应用程序。

# 流开发人员指南

有关如何在本地计算机上创建、测试和运行 Spring 云流应用程序的更多信息,请参见 microSite 上的[流开发人员指南](https://dataflow.spring.io/docs/stream-developer-guides/)。

# 流监控

有关如何监视作为流的一部分部署的应用程序的更多信息,请参见 microSite 上的[溪流监测指南](https://dataflow.spring.io/docs/feature-guides/streams/monitoring/)。

# 任务

本节将详细介绍如何在 Spring 云数据流上编排[Spring Cloud Task](https://cloud.spring.io/spring-cloud-task/)应用程序。

如果你刚开始使用 Spring 云数据流,那么在深入了解本节之前,你可能应该阅读“[Local](#getting-started-local)”、“[Cloud Foundry](#getting-started-cloudfoundry)”或“[Kubernetes](#getting-started-kubernetes)”的入门指南。

## 25. 导言

任务应用程序是短命的,这意味着它会故意停止运行,并且可以按需运行或在以后进行计划。一种用例可能是抓取网页并写入数据库。

[Spring Cloud Task](https://cloud.spring.io/spring-cloud-task/)框架基于 Spring 引导,并增加了引导应用程序记录短期应用程序的生命周期事件的能力,例如启动时间、结束时间和退出状态。[`TaskExecution`](https://DOCS. Spring.io/ Spring-cloud-task/DOCS/2.0.0.release/reference/htmlsingle/#features-task-execution-details)文档显示了哪些信息存储在数据库中。在 Spring 云任务应用程序中执行代码的入口点通常是 Boot 的`CommandLineRunner`接口的实现,如下面的[example](https://docs.spring.io/spring-cloud-task/docs/2.0.0.RELEASE/reference/htmlsingle/#getting-started-writing-the-code)所示。

Spring 批处理项目可能是 Spring 编写短期应用程序的开发人员想到的。 Spring 批处理提供了一组比 Spring 云任务丰富得多的功能,并且在处理大量数据时是推荐的。一种用例可能是读取许多 CSV 文件,转换每一行数据,并将每个转换后的行写入数据库。 Spring Batch 提供了它自己的数据库模式,该模式具有关于 Spring 批处理作业的执行的更丰富的[一组信息](https://docs.spring.io/spring-batch/4.1.x/reference/html/schema-appendix.html#metaDataSchema)。 Spring 云任务是与 Spring 批处理集成的,这样,如果 Spring 云任务应用程序定义了 Spring 批处理,则在 Spring 云任务和 Spring 云批处理执行表之间创建链接。

在本地计算机上运行数据流时,任务将在单独的 JVM 中启动。在 Cloud Foundry 上运行时,将使用[Cloud Foundry 的任务](https://docs.cloudfoundry.org/devguide/using-tasks.html)功能启动任务。在 Kubernetes 上运行时,可以使用`Pod`或`Job`资源启动任务。

## 26. 任务的生命周期

在深入研究创建任务的细节之前,你应该了解 Spring 云数据流上下文中任务的典型生命周期:

1. [创建任务应用程序](#spring-cloud-dataflow-create-task-apps)

2. [注册任务应用程序](#spring-cloud-dataflow-register-task-apps)

3. [创建任务定义](#spring-cloud-dataflow-create-task-definition)

4. [启动一项任务](#spring-cloud-dataflow-task-launch)

5. [审查任务执行情况](#spring-cloud-dataflow-task-review-executions)

6. [销毁任务定义](#spring-cloud-dataflow-task-definition-destroying)

7. [持续部署](#spring-cloud-dataflow-task-cd)

### 26.1.创建任务应用程序

Spring 尽管云任务确实提供了许多开箱即用的应用程序(at[spring-cloud-task-app-starters](https://github.com/spring-cloud-task-app-starters)),但大多数任务应用程序都需要定制开发。要创建自定义任务应用程序:

1. 使用[Spring Initializer](https://start.spring.io)创建一个新项目,确保选择以下启动器:

   1. `Cloud Task`:这个依赖关系是`spring-cloud-starter-task`。

   2. `JDBC`:此依赖项是`spring-jdbc`启动器。

   3. 选择你的数据库依赖项:输入数据流当前使用的数据库依赖项。例如:`H2`。

2. 在你的新项目中,创建一个新类作为你的主类,如下所示:

   ```
   @EnableTask
   @SpringBootApplication
   public class MyTask {

       public static void main(String[] args) {
   		SpringApplication.run(MyTask.class, args);
   	}
   }
   ```

3. 在这个类中,你需要在应用程序中实现一个或多个`CommandLineRunner`或`ApplicationRunner`。你既可以实现自己的,也可以使用 Spring Boot 提供的功能(例如,有一个用于运行批处理作业的功能)。

4. 用 Spring boot 将应用程序打包到一个 über JAR 中,是通过标准[Spring Boot conventions](https://docs.spring.io/spring-boot/docs/2.1.1.RELEASE/reference/html/getting-started-first-application.html#getting-started-first-application-executable-jar)完成的。打包的应用程序可以注册和部署,如下所示。

#### 26.1.1.任务数据库配置

|   |在启动任务应用程序时,请确保 Spring 云数据流所使用的数据库驱动程序也是对任务应用程序的依赖关系,例如,如果你的 Spring 云数据流被设置为使用 PostgreSQL,确保任务应用程序也有 PostgreSQL 作为依赖项。|
|---|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

|   |当你在外部运行任务(即从命令行),并且希望 Spring 云数据流在其 UI 中显示任务执行情况时,请确保两者共享公共数据源设置,<br/>默认情况下, Spring 云任务使用本地 H2 实例,并将执行记录到数据库中所使用的 Spring 云数据流。|
|---|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

### 26.2.注册任务应用程序

你可以使用 Spring cloud data flow shell`app register`命令在 app 注册表中注册一个任务应用程序。你必须提供一个唯一的名称和一个可以解析为应用程序工件的 URI。对于类型,请指定`task`。下面的清单展示了三个例子:

```
dataflow:>app register --name task1 --type task --uri maven://com.example:mytask:1.0.2

dataflow:>app register --name task2 --type task --uri file:///Users/example/mytask-1.0.2.jar

dataflow:>app register --name task3 --type task --uri https://example.com/mytask-1.0.2.jar
```

当提供带有`maven`方案的 URI 时,格式应符合以下要求:

```
maven://<groupId>:<artifactId>[:<extension>[:<classifier>]]:<version>
```

如果希望一次注册多个应用程序,可以将它们存储在一个属性文件中,其中键的格式为`<type>.<name>`,值是 URI。例如,下面的列表将是一个有效的属性文件:

```
task.cat=file:///tmp/cat-1.2.1.BUILD-SNAPSHOT.jar
task.hat=file:///tmp/hat-1.2.1.BUILD-SNAPSHOT.jar
```

然后,你可以使用`app import`命令,并通过使用`--uri`选项提供属性文件的位置,如下所示:

```
app import --uri file:///tmp/task-apps.properties
```

例如,如果你希望在一次操作中注册所有附带数据流的任务应用程序,那么你可以使用以下命令进行注册:

```
dataflow:>app import --uri https://dataflow.spring.io/task-maven-latest
```

你还可以通过`--local`选项(默认情况下是`TRUE`)来指示是否应该在 shell 进程本身中解析属性文件位置。如果应该从数据流服务器进程解析位置,请指定`--local false`。

当使用`app register`或`app import`时,如果任务应用程序已经使用提供的名称和版本注册,则默认情况下不会覆盖该应用程序。如果你想用不同的`uri`或`uri-metadata`位置覆盖预先存在的任务应用程序,请包含`--force`选项。

|   |在某些情况下,资源是在服务器端解析的。<br/>在其他情况下,URI 被传递到一个运行时容器实例,在那里它被解析。<br/>有关更多详细信息,请参阅每个数据流服务器的特定文档。|
|---|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

### 26.3.创建任务定义

你可以通过提供定义名称以及应用于任务执行的属性,从任务应用程序创建任务定义。你可以通过 RESTful API 或 shell 创建任务定义。要通过使用 shell 创建任务定义,请使用`task create`命令创建任务定义,如下例所示:

```
dataflow:>task create mytask --definition "timestamp --format=\"yyyy\""
Created new task 'mytask'
```

你可以通过 RESTful API 或 shell 获得当前任务定义的列表。要通过使用 shell 获得任务定义列表,请使用`task list`命令。

#### 26.3.1.最大任务定义名称长度

任务定义名称的最大字符长度取决于平台。

|   |有关资源命名的详细信息,请参阅平台文档。<br/>本地平台将任务定义名称存储在最大为 255 的数据库列中。|
|---|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

|Kubernetes 裸荚|Kubernetes Jobs|Cloud Foundry|Local|
|--------------------|---------------|-------------|-----|
|         63         |      52       |     63      | 255 |

#### 26.3.2.自动创建任务定义

从版本 2.3.0 开始,你可以通过将`spring.cloud.dataflow.task.autocreate-task-definitions`设置为`true`来配置数据流服务器以自动创建任务定义。这不是默认的行为,而是作为一种方便而提供的。启用此属性后,任务启动请求可以将已注册的任务应用程序名称指定为任务名称。如果注册了任务应用程序,服务器将创建一个基本的任务定义,该定义仅根据需要指定应用程序名。这消除了类似于以下操作的手动步骤:

```
dataflow:>task create mytask --definition "mytask"
```

你仍然可以为每个任务启动请求指定命令行参数和部署属性。

### 26.4.启动一项任务

可以通过 RESTful API 或 shell 启动一个临时任务。要通过 shell 启动一个特别任务,请使用`task launch`命令,如下面的示例所示:

```
dataflow:>task launch mytask
Launched task 'mytask'
```

当任务启动时,你可以将启动任务时需要作为命令行参数传递给任务应用程序的任何属性设置如下:

```
dataflow:>task launch mytask --arguments "--server.port=8080 --custom=value"
```

|   |参数需要以空格分隔的值传递。|
|---|----------------------------------------------------------|

你可以通过使用`--properties`选项来传递用于`TaskLauncher`本身的附加属性。这个选项的格式是一个逗号分隔的属性字符串,前缀是`app.<task definition name>.<property>`。属性作为应用程序属性传递到`TaskLauncher`。由实现来选择如何将这些信息传递到实际的任务应用程序中。如果该属性的前缀是`deployer`,而不是`app`,则将其作为部署属性传递给`TaskLauncher`,其含义可能是`TaskLauncher`实现特定的。

```
dataflow:>task launch mytask --properties "deployer.timestamp.custom1=value1,app.timestamp.custom2=value2"
```

#### 26.4.1.应用程序属性

每个应用程序都获取属性来定制其行为。例如,`timestamp`Task`format`设置建立了与默认值不同的输出格式。

```
dataflow:> task create --definition "timestamp --format=\"yyyy\"" --name printTimeStamp
```

这个`timestamp`属性实际上与时间戳应用程序指定的`timestamp.format`属性相同。数据流增加了使用简写形式`format`而不是`timestamp.format`的能力。你还可以指定 Longhand 版本,如下面的示例所示:

```
dataflow:> task create --definition "timestamp --timestamp.format=\"yyyy\"" --name printTimeStamp
```

在[流应用程序属性](#spring-cloud-dataflow-application-properties)一节中对这种简写行为进行了更多的讨论。如果有[已注册的应用程序属性元数据](https://dataflow.spring.io/docs/applications/application-metadata/#using-application-metadata),则可以在输入`--`后在 shell 中使用 tab 补全来获得候选属性名列表。

shell 为应用程序属性提供了制表符补全功能。`app info --name <appName> --type <appType>`shell 命令为所有受支持的属性提供了额外的文档。支持的任务`<appType>`是`task`。

|   |在 Kubernetes 上重新启动 Spring 批处理作业时,必须使用`shell`或`boot`的入口点。|
|---|---------------------------------------------------------------------------------------------------|

##### Kubernetes 上具有敏感信息的应用程序属性

当启动某些属性可能包含敏感信息的任务应用程序时,使用`shell`或`boot`作为`entryPointStyle`。这是因为`exec`(默认)将所有属性转换为命令行参数,因此在某些环境中可能不安全。

#### 26.4.2.通用应用程序属性

Spring 除了通过 DSL 进行配置外,云数据流还提供了一种机制,用于设置由其启动的所有任务应用程序所共有的属性。可以通过在启动服务器时添加带`spring.cloud.dataflow.applicationProperties.task`前缀的属性来实现此目的。然后,服务器将不带前缀的所有属性传递给它启动的实例。

例如,通过使用以下选项启动数据流服务器,可以配置所有启动的应用程序使用`prop1`和`prop2`属性:

```
--spring.cloud.dataflow.applicationProperties.task.prop1=value1
--spring.cloud.dataflow.applicationProperties.task.prop2=value2
```

这会将`prop1=value1`和`prop2=value2`属性传递给所有启动的应用程序。

|   |使用此机制配置的属性的优先级低于任务部署属性。<br/>如果在任务启动时指定了具有相同键的属性(例如,`app.trigger.prop2`重写公共属性),则会重写这些属性。|
|---|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

### 26.5.限制并发任务启动的数量

Spring 云数据流允许用户限制每个配置平台的并发运行任务的最大数量,以防止 IaaS 或硬件资源的饱和。默认情况下,对于所有受支持的平台,限制设置为`20`。如果平台实例上并发运行的任务数量大于或等于限制,则下一个任务启动请求失败,并通过 RESTful API、shell 或 UI 返回错误消息。可以通过设置相应的部署人员属性`spring.cloud.dataflow.task.platform.<platform-type>.accounts[<account-name>].maximumConcurrentTasks`为平台实例配置此限制,其中`<account-name>`是已配置平台帐户的名称(如果没有显式配置帐户,`default`)。`<platform-type>`是指当前支持的部署程序之一:`local`或`kubernetes`。对于`cloudfoundry`,该属性是`spring.cloud.dataflow.task.platform.<platform-type>.accounts[<account-name>].deployment.maximumConcurrentTasks`。(区别在于`deployment`已被添加到路径中)。

如果可能的话,每个受支持平台的`TaskLauncher`实现通过查询底层平台的运行时状态来确定当前正在运行的任务的数量。用于识别`task`的方法因平台的不同而不同。例如,在本地主机上启动任务使用`LocalTaskLauncher`。`LocalTaskLauncher`为每个启动请求运行一个进程,并在内存中跟踪这些进程。在这种情况下,我们不查询底层 OS,因为以这种方式识别任务是不切实际的。对于 Cloud Foundry,任务是其部署模型支持的核心概念。(所有任务的状态)可直接通过 API 获得。这意味着帐户的组织和空间中的每个正在运行的任务容器都包含在正在运行的执行计数中,无论它是否通过使用 Spring 云数据流或直接调用`CloudFoundryTaskLauncher`来启动。对于 Kubernetes 来说,通过`KubernetesTaskLauncher`启动一个任务,如果成功,将导致一个正在运行的 pod,我们希望它最终完成或失败。在这种环境下,通常没有简单的方法来识别与任务相对应的 pod。因此,我们只计算`KubernetesTaskLauncher`发射的吊舱。由于 Task Launcher 在 POD 的元数据中提供了`task-name`标签,因此我们通过该标签的存在来过滤所有运行中的 POD。

### 26.6.审查任务执行情况

一旦任务启动,任务的状态就存储在关系数据库中。国家包括:

* 任务名称

* 开始时间

* 结束时间

* 退出代码

* 退出消息

* 上次更新时间

* 参数

你可以通过 RESTful API 或 shell 检查任务执行的状态。要通过 shell 显示最新的任务执行情况,请使用`task execution list`命令。

要获得只针对一个任务定义的任务执行列表,请添加`--name`和任务定义名称——例如,`task execution list --name foo`。要获取任务执行的全部详细信息,请使用带有任务执行 ID 的`task execution status`命令,例如`task execution status --id 549`。

### 26.7.销毁任务定义

销毁任务定义会从定义库中删除该定义。这可以通过 RESTful API 或 shell 来完成。要通过 shell 销毁任务,请使用`task destroy`命令,如以下示例所示:

```
dataflow:>task destroy mytask
Destroyed task 'mytask'
```

`task destroy`命令还具有`cleanup`被销毁任务的任务执行的选项,如以下示例所示:

```
dataflow:>task destroy mytask --cleanup
Destroyed task 'mytask'
```

默认情况下,`cleanup`选项被设置为`false`(也就是说,默认情况下,任务执行不会在任务被销毁时被清理)。

要通过 shell 销毁所有任务,请使用`task all destroy`命令,如下例所示:

```
dataflow:>task all destroy
Really destroy all tasks? [y, n]: y
All tasks destroyed
```

如果需要,你可以使用力开关:

```
dataflow:>task all destroy --force
All tasks destroyed
```

定义中先前启动的任务的任务执行信息保留在任务存储库中。

|   |这不会停止此定义的任何当前正在运行的任务。相反,它将从数据库中删除任务定义。|
|---|------------------------------------------------------------------------------------------------------------------------------|

|   |`task destroy <task-name>`只删除定义,而不删除部署在 Cloud Foundry 上的任务。<br/>完成删除任务的唯一方法是通过 CLI 分两步:<br/><br/>\+<br/>。使用`cf apps`命令获取应用程序列表。<br/>。确定要删除的任务应用程序并运行`cf delete <task-name>`命令。|
|---|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

### 26.8.验证任务

有时,包含在任务定义中的应用程序在其注册中具有无效的 URI。这可能是由于在应用程序注册时输入了无效的 URI,或者应用程序从要从中提取它的存储库中删除而导致的。要验证任务中包含的所有应用程序都是可解析的,请使用`validate`命令,如下所示:

```
dataflow:>task validate time-stamp
╔══════════╤═══════════════╗
║Task Name │Task Definition║
╠══════════╪═══════════════╣
║time-stamp│timestamp      ║
╚══════════╧═══════════════╝

time-stamp is a valid task.
╔═══════════════╤═════════════════╗
║   App Name    │Validation Status║
╠═══════════════╪═════════════════╣
║task:timestamp │valid            ║
╚═══════════════╧═════════════════╝
```

在前面的示例中,用户验证了他们的时间戳任务。`task:timestamp`应用程序是有效的。现在我们可以看到,如果我们有一个流定义,而注册的应用程序具有无效的 URI,会发生什么情况:

```
dataflow:>task validate bad-timestamp
╔═════════════╤═══════════════╗
║  Task Name  │Task Definition║
╠═════════════╪═══════════════╣
║bad-timestamp│badtimestamp   ║
╚═════════════╧═══════════════╝

bad-timestamp is an invalid task.
╔══════════════════╤═════════════════╗
║     App Name     │Validation Status║
╠══════════════════╪═════════════════╣
║task:badtimestamp │invalid          ║
╚══════════════════╧═════════════════╝
```

在这种情况下, Spring 云数据流声明该任务是无效的,因为`task:badtimestamp`具有无效的 URI。

### 26.9.停止任务执行

在某些情况下,在平台上运行的任务可能不会因为平台或应用程序业务逻辑本身的问题而停止。 Spring 对于这样的情况,云数据流提供了向平台发送请求以结束任务的能力。要做到这一点,请为给定的一组任务执行提交`task execution stop`,如下所示:

```
task execution stop --ids 5

Request to stop the task execution with id(s): 5 has been submitted
```

使用前面的命令,将停止执行`id=5`的触发器提交给底层部署程序实现。结果,操作将停止该任务。当我们查看任务执行的结果时,我们看到任务执行是用 0 退出代码完成的:

```
dataflow:>task execution list
╔══════════╤══╤════════════════════════════╤════════════════════════════╤═════════╗
║Task Name │ID│         Start Time         │          End Time          │Exit Code║
╠══════════╪══╪════════════════════════════╪════════════════════════════╪═════════╣
║batch-demo│5 │Mon Jul 15 13:58:41 EDT 2019│Mon Jul 15 13:58:55 EDT 2019│0        ║
║timestamp │1 │Mon Jul 15 09:26:41 EDT 2019│Mon Jul 15 09:26:41 EDT 2019│0        ║
╚══════════╧══╧════════════════════════════╧════════════════════════════╧═════════╝
```

如果你为一个任务执行提交了一个停止,而该任务执行中有与之相关联的子任务执行,例如一个组合任务,那么将为每个子任务执行发送一个停止请求。

|   |当停止具有正在运行的 Spring 批处理作业的任务执行时,该作业的批处理状态为`STARTED`。<br/>当请求停止时,每个受支持的平台都向任务应用程序发送一个 SIG-INT。这使得 Spring Cloud Task 能够捕获应用程序的状态。然而, Spring 批处理不处理 SIG-INT,因此,作业停止,但仍处于开始状态。|
|---|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

|   |在启动远程分区 Spring 批处理任务应用程序时, Spring 云数据流支持为 Cloud Foundry 和 Kubernetes 平台直接停止工作分区任务。本地平台不支持停止工作分区任务。|
|---|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

#### 26.9.1.停止在 Spring 云数据流之外启动的任务执行

你可能希望停止已在 Spring 云数据流之外启动的任务。这方面的一个例子是由远程批处理分区应用程序启动的工作应用程序。在这种情况下,远程批处理分区应用程序为每个工作者应用程序存储`external-execution-id`。但是,没有存储平台信息。因此,当 Spring 云数据流必须停止远程批处理分区的应用程序及其工作应用程序时,需要指定平台名称,如下所示:

```
dataflow:>task execution stop --ids 1 --platform myplatform
Request to stop the task execution with id(s): 1 for platform myplatform has been submitted
```

## 27. 订阅任务和批处理事件

你还可以在任务启动时利用各种任务和批处理事件。如果任务被启用来生成任务或批处理事件(带有`spring-cloud-task-stream`的附加依赖关系,并且在以 Kafka 为绑定器的情况下,`spring-cloud-stream-binder-kafka`),则这些事件将在任务生命周期期间发布。默认情况下,代理上发布的事件(Rabbit、Kafka 和其他事件)的目标名称是事件名称本身(例如:`task-events`,`job-execution-events`,等等)。

```
dataflow:>task create myTask --definition "myBatchJob"
dataflow:>stream create task-event-subscriber1 --definition ":task-events > log" --deploy
dataflow:>task launch myTask
```

通过在启动任务时指定显式名称,你可以控制这些事件的目标名称,如下所示:

```
dataflow:>stream create task-event-subscriber2 --definition ":myTaskEvents > log" --deploy
dataflow:>task launch myTask --properties "app.myBatchJob.spring.cloud.stream.bindings.task-events.destination=myTaskEvents"
```

下表列出了代理上的默认任务、批处理事件和目标名称:

|      **Event**      |**目的地**|
|---------------------|-----------------------|
|     Task events     |`task-events`|
|Job Execution events |`job-execution-events`|
|Step Execution events|`step-execution-events`|
|  Item Read events   |`item-read-events`|
| Item Process events |`item-process-events`|
|  Item Write events  |`item-write-events`|
|     Skip events     |`skip-events`|

## 28. 组合任务

Spring 云数据流允许你创建有向图,其中图的每个节点都是任务应用程序。这是通过对组合任务使用 DSL 来完成的。你可以通过 RESTful API、 Spring Cloud Data Flow Shell 或 Spring Cloud Data Flow UI 创建一个组合任务。

### 28.1.组成的任务运行器

复合任务通过一个名为复合任务运行器的任务应用程序运行。 Spring 云数据流服务器在启动合成任务时自动部署合成任务运行器。

#### 28.1.1.配置组合任务运行器

Composed Task Runner 应用程序有一个`dataflow-server-uri`属性,用于验证和启动子任务。这默认为`[localhost:9393](http://localhost:9393)`。如果运行分布式 Spring 云数据流服务器,就像在 Cloud Foundry 或 Kubernetes 上部署该服务器一样,你需要提供可用于访问该服务器的 URI。你可以通过在启动组合任务时为组合任务运行器应用程序设置`dataflow-server-uri`属性,或者在启动 Spring 云数据流服务器时为其设置`spring.cloud.dataflow.server.uri`属性来提供此功能。对于后一种情况,`dataflow-server-uri`Composed Task Runner 应用程序属性将在启动 Composed 任务时自动设置。

##### 配置选项

`ComposedTaskRunner`任务有以下选项:

* `composed-task-arguments`用于每个任务的命令行参数。(字符串,缺省:\<none\>)。

* `increment-instance-enabled`允许一个`ComposedTaskRunner`实例在不更改参数的情况下再次运行,方法是根据前一次执行中的`run.id`添加一个递增的数 job 参数。(布尔值,默认值:`true`)。ComposedTaskRunner 是使用[Spring Batch](https://github.com/spring-projects/spring-batch)构建的。因此,一旦成功执行,该批处理作业就被视为已完成。要多次启动相同的`ComposedTaskRunner`定义,你必须将`increment-instance-enabled`或`uuid-instance-enabled`属性设置为`true`,或者更改每次启动定义的参数。当使用此选项时,必须将其应用于所需应用程序的所有任务启动,包括第一次启动。

* `uuid-instance-enabled`通过向`ctr.id`作业参数添加 UUID,允许在不更改参数的情况下再次运行单个`ComposedTaskRunner`实例。(布尔值,默认值:`false`)。ComposedTaskRunner 是使用[Spring Batch](https://github.com/spring-projects/spring-batch)构建的。因此,一旦成功执行,该批处理作业就被视为已完成。要多次启动相同的`ComposedTaskRunner`定义,必须将`increment-instance-enabled`或`uuid-instance-enabled`属性设置为`true`,或者更改每次启动定义的参数。当使用此选项时,必须将其应用于所需应用程序的所有任务启动,包括第一次启动。当设置为 true 时,此选项将覆盖`increment-instance-id`的值。当同时运行同一组合任务定义的多个实例时,将此选项设置为`true`。

* `interval-time-between-checks``ComposedTaskRunner`在检查数据库以查看任务是否完成之间等待的时间,以毫秒为单位。(整数,缺省:`10000`)。`ComposedTaskRunner`使用数据存储来确定每个子任务的状态。这个间隔指示`ComposedTaskRunner`它应该检查其子任务状态的频率。

* `transaction-isolation-level`为组合任务运行器建立事务隔离级别。可以找到[here](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/transaction/TransactionDefinition.html)的可用事务隔离级别列表。默认值为`ISOLATION_REPEATABLE_READ`。

* `max-wait-time`在组合任务执行失败之前,单个步骤可以运行的最大时间(以毫秒为单位)(整数,缺省:0)。确定在 CTR 以失败结束之前允许每个子任务运行的最长时间。`0`的默认值表示没有超时。

* `split-thread-allow-core-thread-timeout`指定是否允许拆分核心线程超时。(Boolean,默认值:`false`)设置了管理核心线程是否超时的策略,如果在 Keep-Alive 时间内没有任务到达就会终止,如果新任务到达时需要替换核心线程。

* `split-thread-core-pool-size`Split 的核心池大小。(整数,缺省:`1`)拆分中包含的每个子任务都需要一个线程才能执行。因此,例如,像`<AAA || BBB || CCC> && <DDD || EEE>`这样的定义将需要`split-thread-core-pool-size`的`3`。这是因为最大的分割包含三个子任务。如果计算`2`,则意味着`AAA`和`BBB`将并行运行,但 CCC 将等待`AAA`或`BBB`完成才能运行。然后`DDD`和`EEE`将并行运行。

* `split-thread-keep-alive-seconds`Split 的线程保持活秒。(整数,缺省:`60`)如果池当前有超过`corePoolSize`的线程,如果多余的线程空闲时间超过`keepAliveTime`,则停止这些线程。

* `split-thread-max-pool-size`Split 的最大池大小。(整数,缺省:`Integer.MAX_VALUE`)。建立线程池允许的最大线程数.

* **分割线程队列容量**Split 的容量`BlockingQueue`。(整数,缺省:`Integer.MAX_VALUE`)

  * 如果运行的线程少于`corePoolSize`,则`Executor`总是更喜欢添加新线程,而不是排队。

  * 如果`corePoolSize`或更多线程正在运行,则`Executor`总是更喜欢对请求进行排队,而不是添加新线程。

  * 如果一个请求不能排队,则创建一个新线程,除非它超过`maximumPoolSize`。在这种情况下,任务将被拒绝。

* `split-thread-wait-for-tasks-to-complete-on-shutdown`是否在关机时等待计划任务完成,不中断运行任务并运行队列中的所有任务。(布尔值,默认值:`false`)

* `dataflow-server-uri`接收任务启动请求的数据流服务器的 URI。(字符串,默认值:`[localhost:9393](http://localhost:9393)`)

* `dataflow-server-username`接收任务启动请求的数据流服务器的可选用户名。用于通过使用基本身份验证访问数据流服务器。如果设置`dataflow-server-access-token`,则不使用。

* `dataflow-server-password`接收任务启动请求的数据流服务器的可选密码。用于通过使用基本身份验证访问数据流服务器。如果设置`dataflow-server-access-token`,则不使用。

* `dataflow-server-access-token`此属性设置一个可选的 OAuth2 访问令牌。通常,如果可用,则通过使用来自当前登录用户的令牌自动设置该值。但是,对于特殊的用例,也可以显式地设置该值。

当你想要使用当前登录用户的访问令牌并将其传播给组合的任务运行器时,存在一个特殊的布尔属性`dataflow-server-use-user-access-token`。 Spring 云数据流使用此属性,如果设置为`true`,则自动填充`dataflow-server-access-token`属性。当使用`dataflow-server-use-user-access-token`时,必须为每个任务执行传递它。在某些情况下,在默认情况下,用户的`dataflow-server-access-token`必须为每个组合任务启动传递。在这种情况下,将 Spring 云数据流`spring.cloud.dataflow.task.useUserAccessToken`属性设置为`true`。

要为组合任务运行器设置属性,你需要在该属性前加上`app.composed-task-runner.`。例如,要设置`dataflow-server-uri`属性,该属性将看起来像`app.composed-task-runner.dataflow-server-uri`。

### 28.2.组合任务的生命周期

组合任务的生命周期由三部分组成:

* [创建一个完整的任务](#spring-cloud-data-flow-composed-task-creating)

* [停止一项复杂的任务](#spring-cloud-data-flow-composed-task-stopping)

* [重新启动一个组合任务](#spring-cloud-data-flow-composed-task-restarting)

#### 28.2.1.创建一个完整的任务

在通过 Task Create 命令创建任务定义时,将使用组合任务的 DSL,如以下示例所示:

```
dataflow:> app register --name timestamp --type task --uri maven://org.springframework.cloud.task.app:timestamp-task:
dataflow:> app register --name mytaskapp --type task --uri file:///home/tasks/mytask.jar
dataflow:> task create my-composed-task --definition "mytaskapp && timestamp"
dataflow:> task launch my-composed-task
```

在前面的示例中,我们假设组合任务使用的应用程序尚未注册。因此,在前两个步骤中,我们注册了两个任务应用程序。然后,我们使用`task create`命令创建组合任务定义。前面示例中的组合任务 DSL 在启动时运行`mytaskapp`,然后运行时间戳应用程序。

但是在我们推出`my-composed-task`定义之前,我们可以查看 Spring 云数据流为我们生成了什么。这可以通过使用 Task List 命令来完成,如下例所示(包括其输出):

```
dataflow:>task list
╔══════════════════════════╤══════════════════════╤═══════════╗
║        Task Name         │   Task Definition    │Task Status║
╠══════════════════════════╪══════════════════════╪═══════════╣
║my-composed-task          │mytaskapp && timestamp│unknown    ║
║my-composed-task-mytaskapp│mytaskapp             │unknown    ║
║my-composed-task-timestamp│timestamp             │unknown    ║
╚══════════════════════════╧══════════════════════╧═══════════╝
```

Spring 在该示例中,云数据流创建了三个任务定义,其中一个是针对组成我们的组合任务的应用程序(`my-composed-task-mytaskapp`和`my-composed-task-timestamp`)以及组成任务的定义(`my-composed-task`)。我们还看到,为子任务生成的每个名称都由组合任务的名称和应用程序的名称组成,用连字符`-`分隔(如*我的-沉着的-任务*`-`*MyTaskApp*)。

##### 任务应用程序参数

组成组合任务定义的任务应用程序也可以包含参数,如以下示例所示:

```
dataflow:> task create my-composed-task --definition "mytaskapp --displayMessage=hello && timestamp --format=YYYY"
```

#### 28.2.2.展开一项沉着的任务

发起一项组合任务的方式与发起一项独立任务的方式相同,如下所示:

```
task launch my-composed-task
```

一旦任务启动,并且假设所有任务都成功完成,当你运行`task execution list`时,你可以看到三个任务执行,如以下示例所示:

```
dataflow:>task execution list
╔══════════════════════════╤═══╤════════════════════════════╤════════════════════════════╤═════════╗
║        Task Name         │ID │         Start Time         │          End Time          │Exit Code║
╠══════════════════════════╪═══╪════════════════════════════╪════════════════════════════╪═════════╣
║my-composed-task-timestamp│713│Wed Apr 12 16:43:07 EDT 2017│Wed Apr 12 16:43:07 EDT 2017│0        ║
║my-composed-task-mytaskapp│712│Wed Apr 12 16:42:57 EDT 2017│Wed Apr 12 16:42:57 EDT 2017│0        ║
║my-composed-task          │711│Wed Apr 12 16:42:55 EDT 2017│Wed Apr 12 16:43:15 EDT 2017│0        ║
╚══════════════════════════╧═══╧════════════════════════════╧════════════════════════════╧═════════╝
```

在前面的示例中,我们看到`my-compose-task`启动了,并且其他任务也是按顺序启动的。它们都以`Exit Code`为`0`成功运行。

##### 将属性传递给子任务

要在任务启动时在组合任务图中设置子任务的属性,请使用以下格式:`app.<composed task definition name>.<child task app name>.<property>`。下面的清单显示了一个组合任务定义作为示例:

```
dataflow:> task create my-composed-task --definition "mytaskapp  && mytimestamp"
```

要使`mytaskapp`显示“hello”并将`mytimestamp`时间戳格式设置为`YYYY`用于组合任务定义,请使用以下任务启动格式:

```
task launch my-composed-task --properties "app.my-composed-task.mytaskapp.displayMessage=HELLO,app.my-composed-task.mytimestamp.timestamp.format=YYYY"
```

与应用程序属性类似,你也可以使用以下格式为子任务设置`deployer`属性:

```
task launch my-composed-task --properties "deployer.my-composed-task.mytaskapp.memory=2048m,app.my-composed-task.mytimestamp.timestamp.format=HH:mm:ss"
Launched task 'a1'
```

##### 将参数传递给组成的任务运行器

你可以使用`--arguments`选项为组合任务运行器传递命令行参数:

```
dataflow:>task create my-composed-task --definition "<aaa: timestamp || bbb: timestamp>"
Created new task 'my-composed-task'

dataflow:>task launch my-composed-task --arguments "--increment-instance-enabled=true --max-wait-time=50000 --split-thread-core-pool-size=4" --properties "app.my-composed-task.bbb.timestamp.format=dd/MM/yyyy HH:mm:ss"
Launched task 'my-composed-task'
```

##### 退出状态

下面的列表显示了在每个步骤执行之后,如何为组合任务中包含的每个步骤(任务)设置退出状态:

* 如果`TaskExecution`具有`ExitMessage`,则将其用作`ExitStatus`。

* 如果不存在`ExitMessage`,并且`ExitCode`设置为零,则该步骤的`ExitStatus`为`COMPLETED`。

* 如果不存在`ExitMessage`,并且`ExitCode`被设置为任何非零数,则该步骤的`ExitStatus`是`FAILED`。

#### 28.2.3.摧毁一项沉着的任务

用于销毁独立任务的命令与用于销毁组合任务的命令相同。唯一的区别是,破坏一个组合任务也会破坏与之相关的子任务。下面的示例显示了使用`destroy`命令之前和之后的任务列表:

```
dataflow:>task list
╔══════════════════════════╤══════════════════════╤═══════════╗
║        Task Name         │   Task Definition    │Task Status║
╠══════════════════════════╪══════════════════════╪═══════════╣
║my-composed-task          │mytaskapp && timestamp│COMPLETED  ║
║my-composed-task-mytaskapp│mytaskapp             │COMPLETED  ║
║my-composed-task-timestamp│timestamp             │COMPLETED  ║
╚══════════════════════════╧══════════════════════╧═══════════╝
...
dataflow:>task destroy my-composed-task
dataflow:>task list
╔═════════╤═══════════════╤═══════════╗
║Task Name│Task Definition│Task Status║
╚═════════╧═══════════════╧═══════════╝
```

#### 28.2.4.停止一项复杂的任务

在需要停止组合任务执行的情况下,你可以通过以下方式完成此操作:

* RESTful API

* Spring 云数据流仪表板

要通过仪表板停止组合任务,请选择**工作**选项卡,并单击要停止的作业执行旁边的 \*stop()按钮。

当当前运行的子任务完成时,将停止组合任务运行。与停止组合任务时正在运行的子任务相关联的步骤标记为`STOPPED`,以及组合任务作业执行。

#### 28.2.5.重新启动一个组合任务

如果组合任务在执行过程中失败,并且组合任务的状态`FAILED`,则可以重新启动该任务。你可以通过以下方式实现此目的:

* RESTful API

* 贝壳

* Spring 云数据流仪表板

要通过 shell 重新启动组合任务,请使用相同的参数启动该任务。要通过仪表板重新启动组合任务,请选择**工作**选项卡,并单击要重新启动的作业执行旁边的**重新启动**按钮。

|   |重新启动已停止(通过 Spring Cloud Data Flow 仪表板或 RESTful API)的组合任务作业,重新启动`STOPPED`子任务,然后按照指定的顺序启动剩余的(未启动的)子任务。|
|---|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

## 29. 组合任务 DSL

组合任务可以通过三种方式运行:

* [有条件执行](#spring-cloud-data-flow-conditional-execution)

* [过渡性执行](#spring-cloud-data-flow-transitional-execution)

* [分割执行](#spring-cloud-data-flow-split-execution)

### 29.1.有条件执行

条件执行是通过使用双符号表示的(`&&`)。这使得序列中的每个任务只有在前一个任务成功完成时才能启动,如以下示例所示:

```
task create my-composed-task --definition "task1 && task2"
```

当发起名为`my-composed-task`的组合任务时,它启动名为`task1`的任务,如果`task1`成功完成,则启动名为`task2`的任务。如果`task1`失败,则`task2`不启动。

你还可以使用 Spring 云数据流仪表板来创建你的条件执行,方法是使用设计器拖放所需的应用程序,并将它们连接在一起以创建你的有向图,如下图所示:

![组合任务条件执行](https://raw.githubusercontent.com/spring-cloud/spring-cloud-dataflow/master/spring-cloud-dataflow-docs/src/main/asciidoc/images/dataflow-ctr-conditional-execution.png)

5593
图 2.有条件执行
D
dallascao 已提交
5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607 5608 5609 5610 5611 5612 5613 5614 5615 5616 5617 5618 5619 5620 5621 5622 5623 5624 5625 5626 5627 5628 5629 5630 5631 5632 5633

前面的图是使用 Spring 云数据流仪表板创建的有向图的屏幕截图。你可以看到图中的四个组件组成了一个条件执行:

* **开始**图标:所有有向图都从这个符号开始。只有一个。

* **任务**图标:表示有向图中的每个任务。

* **结束**图标:表示有向图的结束。

* 实线箭头:表示以下之间的流条件执行流:

  * 两个应用程序。

  * 启动控制节点和应用程序.

  * 一个应用程序和终端控制节点.

* **结束**图标:所有有向图都以这个符号结尾。

|   |通过单击“定义”选项卡上的“组合任务定义”旁边的**细节**按钮,可以查看有向图的图表。|
|---|--------------------------------------------------------------------------------------------------------------------------------------------|

### 29.2.过渡性执行

DSL 支持对有向图执行过程中的转换进行细粒度控制。转换是通过提供一个基于前一个任务的退出状态的相等条件来指定的。任务转换由以下符号`->`表示。

#### 29.2.1.基本过渡

一个基本的过渡将如下所示:

```
task create my-transition-composed-task --definition "foo 'FAILED' -> bar 'COMPLETED' -> baz"
```

在前面的示例中,`foo`将启动,并且,如果退出状态为`FAILED`,则`bar`任务将启动。如果`foo`的退出状态是`COMPLETED`,则`baz`将启动。由`cat`返回的所有其他状态都没有影响,任务将正常结束。

使用 Spring 云数据流仪表板创建相同的“基本转换”将类似于以下图像:

![组合任务基本转换](https://raw.githubusercontent.com/spring-cloud/spring-cloud-dataflow/master/spring-cloud-dataflow-docs/src/main/asciidoc/images/dataflow-ctr-transition-basic.png)

5634
图 3.基本过渡
D
dallascao 已提交
5635 5636 5637 5638 5639 5640 5641 5642 5643 5644 5645 5646 5647 5648 5649 5650 5651 5652 5653 5654 5655 5656 5657 5658 5659 5660 5661 5662 5663 5664 5665 5666 5667 5668 5669

前面的图表是在 Spring 云数据流仪表板中创建的有向图的屏幕截图。请注意,有两种不同类型的连接器:

* 虚线:表示从应用程序到可能的目标应用程序之一的转换。

* 实线:在条件执行中连接应用程序,或在应用程序和控制节点(开始或结束)之间连接应用程序。

要创建过渡连接器:

1. 在创建转换时,使用连接器将应用程序链接到每个可能的目标。

2. 完成后,转到每个连接,并通过单击它来选择它。

3. 一个螺栓图标出现。

4. 点击那个图标。

5. 输入该连接器所需的退出状态。

6. 该连接器的实线变为虚线。

#### 29.2.2.使用通配符的转换

对于 DSL 的转换,通配符是支持的,如下例所示:

```
task create my-transition-composed-task --definition "foo 'FAILED' -> bar '*' -> baz"
```

在前面的示例中,`foo`将启动,并且,如果退出状态为`FAILED`,则`bar`任务将启动。对于除`FAILED`以外的`cat`的任何退出状态,`baz`都将发射。

使用 Spring 云数据流仪表板创建相同的“通配符转换”将类似于以下图像:

![带有通配符的组合任务基本转换](https://raw.githubusercontent.com/spring-cloud/spring-cloud-dataflow/master/spring-cloud-dataflow-docs/src/main/asciidoc/images/dataflow-ctr-transition-basic-wildcard.png)

5670
图 4.带有通配符的基本转换
D
dallascao 已提交
5671 5672 5673 5674 5675 5676 5677 5678 5679 5680 5681 5682 5683 5684 5685

#### 29.2.3.使用以下条件执行的转换

只要不使用通配符,就可以在转换之后执行条件执行,如下例所示:

```
task create my-transition-conditional-execution-task --definition "foo 'FAILED' -> bar 'UNKNOWN' -> baz && qux && quux"
```

在前面的示例中,`foo`将启动,并且,如果它的退出状态为`FAILED`,则`bar`任务将启动。如果`foo`的退出状态为`UNKNOWN`,则将启动`baz`。对于除`foo`或`UNKNOWN`以外的`foo`的任何退出状态,将启动`qux`,成功完成后,将启动`quux`。

使用 Spring 云数据流仪表板创建相同的“带条件执行的转换”将类似于以下图像:

![有条件执行的组合任务转换](https://raw.githubusercontent.com/spring-cloud/spring-cloud-dataflow/master/spring-cloud-dataflow-docs/src/main/asciidoc/images/dataflow-ctr-transition-conditional-execution.png)

5686
图 5.带条件执行的转换
D
dallascao 已提交
5687 5688 5689 5690 5691 5692 5693 5694 5695 5696 5697 5698 5699 5700 5701 5702 5703 5704

|   |在这个图中,虚线将`foo`应用程序与目标应用程序连接起来,但是一条实线将`foo`、`qux`和`quux`之间的条件执行连接起来。|
|---|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

### 29.3.分割执行

拆分让一个组合任务中的多个任务并行运行。它是通过使用角括号(`<>`)对要并行运行的任务和流进行分组来表示的。这些任务和流由双管道`||`符号分隔,如以下示例所示:

```
task create my-split-task --definition "<foo || bar || baz>"
```

前面的示例并行地启动任务`foo`、`bar`和`baz`。

使用 Spring 云数据流仪表板创建相同的“分割执行”将类似于以下图像:

![组合任务拆分](https://raw.githubusercontent.com/spring-cloud/spring-cloud-dataflow/master/spring-cloud-dataflow-docs/src/main/asciidoc/images/dataflow-ctr-split.png)

5705
图 6.分裂
D
dallascao 已提交
5706 5707 5708 5709 5710 5711 5712 5713 5714 5715 5716 5717 5718

使用 Task DSL,你还可以连续运行多个分割组,如以下示例所示:

```
task create my-split-task --definition "<foo || bar || baz> && <qux || quux>"
```

在前面的示例中,`foo`、`bar`和`baz`任务是并行启动的。一旦它们全部完成,`qux`和`quux`任务将并行启动。一旦他们完成了,这项稳定的任务就结束了。但是,如果`foo`、`bar`或`baz`失败,则包含`qux`和`quux`的拆分不会启动。

使用 Spring 云数据流仪表板创建相同的“多组分割”将类似于以下图像:

![组合任务拆分](https://raw.githubusercontent.com/spring-cloud/spring-cloud-dataflow/master/spring-cloud-dataflow-docs/src/main/asciidoc/images/dataflow-ctr-multiple-splits.png)

5719
图 7.作为有条件执行的一部分拆分
D
dallascao 已提交
5720 5721 5722 5723 5724 5725 5726 5727 5728 5729 5730 5731 5732 5733 5734 5735 5736 5737 5738 5739

请注意,在连接两个连续的拆分时,设计器会插入一个`SYNC`控制节点。

|   |拆分中使用的任务不应设置其`ExitMessage`。将`ExitMessage`设置为<br/>仅用于[过渡](#spring-cloud-data-flow-transitional-execution)。|
|---|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

#### 29.3.1.包含条件执行的拆分

拆分也可以在斜括号内有条件执行,如以下示例所示:

```
task create my-split-task --definition "<foo && bar || baz>"
```

在前面的示例中,我们看到`foo`和`baz`是并行发射的。但是,`bar`在`foo`成功完成之前不会启动。

使用 Spring 云数据流仪表板创建相同的“`split containing conditional execution`”类似于以下图像:

![有条件执行的组合任务分割](https://raw.githubusercontent.com/spring-cloud/spring-cloud-dataflow/master/spring-cloud-dataflow-docs/src/main/asciidoc/images/dataflow-ctr-split-contains-conditional.png)

5740
图 8.用条件执行拆分
D
dallascao 已提交
5741 5742 5743 5744 5745 5746 5747 5748 5749 5750 5751 5752 5753 5754 5755 5756 5757 5758 5759 5760 5761 5762 5763 5764 5765 5766 5767 5768 5769 5770 5771 5772 5773 5774 5775 5776 5777 5778 5779 5780 5781 5782 5783 5784 5785 5786 5787 5788 5789 5790 5791 5792 5793 5794 5795 5796 5797 5798 5799 5800 5801 5802 5803 5804 5805 5806 5807 5808 5809 5810 5811 5812 5813 5814 5815 5816 5817 5818 5819 5820 5821 5822 5823 5824 5825 5826 5827 5828 5829 5830 5831 5832 5833 5834 5835 5836 5837 5838 5839 5840 5841 5842 5843 5844 5845 5846 5847 5848 5849 5850 5851 5852 5853 5854 5855 5856 5857 5858 5859 5860 5861 5862 5863 5864 5865 5866 5867 5868 5869 5870

#### 29.3.2.为拆分建立适当的线程计数

拆分中包含的每个子任务都需要一个线程才能运行。要正确地设置这一点,你需要查看你的图表,并找到子任务数量最多的分割。在此拆分中,子任务的数量是你需要的线程数量。要设置线程计数,请使用`split-thread-core-pool-size property`(默认为`1`)。因此,例如,像`<AAA || BBB || CCC> && <DDD || EEE>`这样的定义需要`split-thread-core-pool-size`的`3`。这是因为最大的分割包含三个子任务。计数为 2 意味着`AAA`和`BBB`将并行运行,但 CCC 将等待`AAA`或`BBB`中的任何一个完成才能运行。然后`DDD`和`EEE`将并行运行。

## 30. 从流启动任务

你可以通过使用[`task-launcher-dataflow`](https://github.com/ Spring-cloud-stream-app-starters/tasklauncher-dataflow/blob/master/ Spring-cloud-starter-stream-sink-task-launcher-dataflow/readme.ADOC)接收器从流启动任务。接收器连接到数据流服务器,并使用其 REST API 来启动任何已定义的任务。接收器接受表示[JSON 有效载荷](https://github.com/spring-cloud-stream-app-starters/tasklauncher-dataflow/blob/master/spring-cloud-starter-stream-sink-task-launcher-dataflow/README.adoc#payload)的`task launch request`,它提供要启动的任务的名称,并可能包括命令行参数和部署属性。

[`app-starters-task-launch-request-common`](https://github.com/ Spring-cloud-stream-app-starters/core/blob/master/common/app-starters-task-launch-request-common/readme.ADOC)组件,结合 Spring cloud stream[功能组合](https://docs.spring.io/spring-cloud-stream/docs/current-snapshot/reference/htmlsingle/#_functional_composition),可以将任何源或处理器的输出转换为任务启动请求。

向`app-starters-task-launch-request-common`添加依赖项可自动配置`java.util.function.Function`实现,该实现通过[Spring Cloud Function](https://cloud.spring.io/spring-cloud-function/)注册为`task发射Request`。

例如,你可以从[time](https://github.com/spring-cloud-stream-app-starters/time/tree/master/spring-cloud-starter-stream-source-time)源开始,添加以下依赖项,构建它,并将其注册为自定义源。在这个示例中,我们将其称为`time-tlr`:

```
<dependency>
    <groupId>org.springframework.cloud.stream.app</groupId>
    <artifactId>app-starters-task-launch-request-common</artifactId>
</dependency>
```

|   |[Spring Cloud Stream Initializr](https://start-scs.cfapps.io/)为创建流应用程序提供了一个很好的起点。|
|---|--------------------------------------------------------------------------------------------------------------------------------|

接下来,[register](#applications)接收`task-launcher-dataflow`并创建一个任务(我们使用提供的时间戳任务):

```
stream create --name task-every-minute --definition "time-tlr --trigger.fixed-delay=60 --spring.cloud.stream.function.definition=taskLaunchRequest --task.launch.request.task-name=timestamp-task | task-launcher-dataflow" --deploy
```

前面的流每分钟产生一个任务启动请求。请求提供要启动的任务的名称:`{"name":"timestamp-task"}`。

下面的流定义演示了命令行参数的使用。它生成诸如`{"args":["foo=bar","time=12/03/18 17:44:12"],"deploymentProps":{},"name":"timestamp-task"}`之类的消息,以便为任务提供命令行参数:

```
stream create --name task-every-second --definition "time-tlr --spring.cloud.stream.function.definition=taskLaunchRequest --task.launch.request.task-name=timestamp-task --task.launch.request.args=foo=bar --task.launch.request.arg-expressions=time=payload | task-launcher-dataflow" --deploy
```

请注意使用 SPEL 表达式将每个消息有效负载映射到`time`命令行参数,以及一个静态参数(`foo=bar`)。

然后,你可以使用 shell 命令`task execution list`查看任务执行列表,如下例所示(及其输出):

```
dataflow:>task execution list
╔════════════════════╤══╤════════════════════════════╤════════════════════════════╤═════════╗
║     Task Name      │ID│         Start Time         │          End Time          │Exit Code║
╠════════════════════╪══╪════════════════════════════╪════════════════════════════╪═════════╣
║timestamp-task_26176│4 │Tue May 02 12:13:49 EDT 2017│Tue May 02 12:13:49 EDT 2017│0        ║
║timestamp-task_32996│3 │Tue May 02 12:12:49 EDT 2017│Tue May 02 12:12:49 EDT 2017│0        ║
║timestamp-task_58971│2 │Tue May 02 12:11:50 EDT 2017│Tue May 02 12:11:50 EDT 2017│0        ║
║timestamp-task_13467│1 │Tue May 02 12:10:50 EDT 2017│Tue May 02 12:10:50 EDT 2017│0        ║
╚════════════════════╧══╧════════════════════════════╧════════════════════════════╧═════════╝
```

在这个示例中,我们展示了如何使用`time`源以固定的速率启动任务。此模式可应用于任何源,以启动响应任何事件的任务。

### 30.1.从流中发起一项复杂的任务

可以使用`task-launcher-dataflow`接收器启动组合任务,如讨论的[here](#spring-cloud-dataflow-launch-tasks-from-stream)。由于我们直接使用`ComposedTaskRunner`,因此在创建组合任务启动流之前,我们需要为组合任务运行器本身以及组合任务设置任务定义。假设我们想要创建以下复合任务定义:`AAA && BBB`。第一步是创建任务定义,如下例所示:

```
task create composed-task-runner --definition "composed-task-runner"
task create AAA --definition "timestamp"
task create BBB --definition "timestamp"
```

|   |可以找到`ComposedTaskRunner`的版本[here](https://github.com/spring-cloud-task-app-starters/composed-task-runner/releases)。|
|---|-------------------------------------------------------------------------------------------------------------------------------------|

现在,我们为组合任务定义所需的任务定义已经准备好了,我们需要创建一个启动`ComposedTaskRunner`的流。因此,在这种情况下,我们创建一个流,使用:

* `time`源自定义以发出任务启动请求,如图[earlier](#spring-cloud-dataflow-launch-tasks-from-stream)所示。

* 启动`task-launcher-dataflow`的`ComposedTaskRunner`接收器

该流应类似于以下内容:

```
stream create ctr-stream --definition "time --fixed-delay=30 --task.launch.request.task-name=composed-task-launcher --task.launch.request.args=--graph=AAA&&BBB,--increment-instance-enabled=true | task-launcher-dataflow"
```

目前,我们主要关注启动`ComposedTaskRunner`所需的配置:

* `graph`:这是将由`ComposedTaskRunner`执行的图形。在这种情况下,它是`AAA&&BBB`。

* `increment-instance-enabled`:这使得`ComposedTaskRunner`的每个执行都是唯一的。`ComposedTaskRunner`是通过使用[Spring Batch](https://projects.spring.io/spring-batch/)构建的。因此,我们希望为`ComposedTaskRunner`的每次启动都有一个新的作业实例。为此,我们将`increment-instance-enabled`设置为`true`。

## 31. 与任务共享云数据流的数据存储

正如[任务](#spring-cloud-dataflow-task)文档中所讨论的, Spring 云数据流允许你查看 Spring 云任务应用程序的执行情况。因此,在这一节中,我们将讨论任务应用程序和 Spring 云数据流共享任务执行信息所需的内容。

### 31.1.一个通用的数据存储依赖项

Spring 云数据流支持许多开箱即用的数据库,因此通常需要做的就是声明`spring_datasource_*`环境变量,以建立云数据流所需的数据存储。无论你决定将哪个数据库用于 Spring 云数据流,都要确保你的任务在其`pom.xml`或`gradle.build`文件中也包含该数据库依赖项。如果 Spring 云数据流使用的数据库依赖项在任务应用程序中不存在,则任务失败且任务执行不被记录。

### 31.2.公共数据存储

Spring 云数据流和你的任务应用程序必须访问相同的数据存储实例。这样, Spring 云数据流就可以读取由任务应用程序记录的任务执行情况,以便在 shell 和 dashboard 视图中列出它们。此外,任务应用程序必须具有对 Spring 云数据流使用的任务数据表的读写权限。

有了对任务应用程序和 Spring 云数据流之间的数据源依赖关系的这种理解,你现在就可以了解如何在各种任务编排场景中应用它们了。

#### 31.2.1.简单的任务启动

当从 Spring 云数据流启动任务时,数据流将其数据源属性(`spring.datasource.url`,`spring.datasource.driverClassName`,`spring.datasource.username`,`spring.datasource.密码`)添加到所启动任务的应用程序属性中。因此,任务应用程序将其任务执行信息记录到 Spring 云数据流库中。

#### 31.2.2.组合任务运行器

Spring 云数据流允许你创建一个有向图,其中该图的每个节点都是一个任务应用程序。这是通过[组合任务运行器](https://github.com/spring-cloud-task-app-starters/composed-task-runner/blob/master/spring-cloud-starter-task-composedtaskrunner/README.adoc)完成的。在这种情况下,适用于[简单的任务启动](#datasource-simple-task-launch)或任务启动器接收器的规则也适用于组合的任务运行器。所有子应用程序还必须具有对组合任务运行器正在使用的数据存储的访问权限。此外,所有的子应用程序必须具有与其`pom.xml`或`gradle.build`文件中枚举的组合任务运行器相同的数据库依赖关系。

#### 31.2.3.从 Spring 云数据流在外部启动任务

你可以通过使用另一种方法(例如调度器)来启动 Spring 云任务应用程序,但仍然可以跟踪 Spring 云数据流中的任务执行。如果任务应用程序遵守指定的规则[here](#a-common-datastore-dependency)和[here](#a-common-datastore),就可以这样做。

|   |如果你想使用 Spring 云数据流来查看你的[Spring Batch](https://projects.spring.io/spring-batch/)作业,请确保<br/>你的批处理应用程序使用`@EnableTask`注释,并遵循枚举的规则[here](#a-common-datastore-dependency)和<br/>。<br/>可获得更多信息[here](https://github.com/spring-projects/spring-batch-admin/blob/master/MIGRATION.md)。|
|---|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

## 32. 调度任务

Spring 云数据流允许你使用`cron`表达式来调度任务的执行。你可以通过 RESTful API 或 Spring Cloud Data Flow UI 创建日程安排。

### 32.1.调度器

Spring 云数据流通过在云平台上可用的调度代理来调度其任务的执行。当使用 Cloud Foundry 平台时, Spring 云数据流使用[PCF 调度器](https://www.cloudfoundry.org/the-foundry/scheduler/)。当使用 Kubernetes 时,将使用[CronJob](https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/)。

|   |调度任务不实现持续部署功能。 Spring 云数据流中对任务定义的应用程序版本或属性的任何更改都不会影响计划的任务。|
|---|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

![调度器架构概述](https://raw.githubusercontent.com/spring-cloud/spring-cloud-dataflow/master/spring-cloud-dataflow-docs/src/main/asciidoc/images/dataflow-scheduling-architecture.png)

5871
图 9.建筑概述
D
dallascao 已提交
5872 5873 5874 5875 5876 5877 5878 5879 5880 5881 5882 5883 5884 5885 5886 5887 5888 5889 5890 5891 5892 5893 5894 5895 5896 5897 5898 5899 5900 5901 5902 5903 5904 5905 5906 5907 5908 5909 5910 5911 5912 5913 5914 5915 5916 5917 5918 5919 5920 5921 5922 5923 5924 5925 5926 5927 5928 5929 5930 5931 5932 5933 5934 5935 5936 5937 5938 5939 5940 5941 5942 5943 5944 5945 5946 5947 5948 5949 5950 5951 5952 5953 5954 5955 5956 5957 5958 5959 5960 5961 5962 5963 5964 5965 5966 5967 5968 5969 5970 5971 5972 5973 5974 5975 5976 5977 5978 5979 5980 5981 5982 5983 5984 5985 5986 5987 5988 5989 5990 5991 5992 5993 5994 5995 5996 5997 5998 5999 6000 6001 6002 6003 6004 6005 6006 6007 6008 6009 6010 6011 6012 6013 6014 6015 6016 6017 6018 6019 6020 6021 6022 6023 6024 6025 6026 6027 6028 6029 6030 6031 6032 6033 6034 6035 6036 6037 6038 6039 6040 6041 6042 6043 6044 6045 6046 6047 6048 6049 6050 6051 6052 6053 6054 6055 6056 6057 6058 6059 6060 6061 6062 6063 6064 6065 6066 6067 6068 6069 6070 6071 6072 6073 6074 6075 6076 6077 6078 6079 6080 6081 6082 6083 6084 6085

### 32.2.启用调度

默认情况下, Spring 云数据流使调度功能失效。要启用调度特性,请将以下特性属性设置为`true`:

* `spring.cloud.dataflow.features.schedules-enabled`

* `spring.cloud.dataflow.features.tasks-enabled`

### 32.3.计划的生命周期

时间表的生命周期包括三个部分:

* [调度任务执行](#spring-cloud-data-flow-schedule-scheduling)

* [删除日程安排](#spring-cloud-data-flow-schedule-unscheduling)

* [上市时间表](#spring-cloud-data-flow-schedule-list)

#### 32.3.1.调度任务执行

你可以通过以下方式安排任务执行:

* Spring 云数据流 shell

* Spring 云数据流仪表板

* Spring 云数据流 RESTful API

#### 32.3.2.安排任务

要使用 shell 调度任务,请使用`task schedule create`命令创建调度,如以下示例所示:

```
dataflow:>task schedule create --definitionName mytask --name mytaskschedule --expression '*/1 * * * *'
Created schedule 'mytaskschedule'
```

在前面的示例中,我们为名为`mytaskschedule`的任务定义创建了一个名为`mytask`的调度。这个时刻表每分钟启动一次`mytask`。

|   |如果使用 Cloud Foundry,上面的`cron`表达式将是:`*/1 * ? * *`。这是因为 Cloud Foundry 使用 Quartz`cron`表达式格式。|
|---|----------------------------------------------------------------------------------------------------------------------------------------------------|

##### 计划名称的最大长度

调度名称的最大字符长度取决于平台。

|Kubernetes|Cloud Foundry|Local|
|----------|-------------|-----|
|    52    |     63      | N/A |

#### 32.3.3.删除日程安排

你可以使用以下选项删除日程安排:

* Spring 云数据流 shell

* Spring 云数据流仪表板

* Spring 云数据流 RESTful API

要使用 shell 删除任务调度,请使用`task schedule destroy`命令,如以下示例所示:

```
dataflow:>task schedule destroy --name mytaskschedule
Deleted task schedule 'mytaskschedule'
```

#### 32.3.4.上市时间表

你可以使用以下选项查看可用的时间表:

* Spring 云数据流 shell

* Spring 云数据流仪表板

* Spring 云数据流 RESTful API

要从 shell 查看计划,请使用`task schedule list`命令,如以下示例所示:

```
dataflow:>task schedule list
╔══════════════════════════╤════════════════════╤════════════════════════════════════════════════════╗
║      Schedule Name       │Task Definition Name│                     Properties                     ║
╠══════════════════════════╪════════════════════╪════════════════════════════════════════════════════╣
║mytaskschedule            │mytask              │spring.cloud.scheduler.cron.expression = */1 * * * *
╚══════════════════════════╧════════════════════╧════════════════════════════════════════════════════╝
```

|   |通过使用 Spring 云数据流 UI 创建、删除和列出计划的指令可以找到[here](https://dataflow.spring.io/docs/feature-guides/batch/scheduling/)。|
|---|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

## 33. 持续部署

随着任务应用程序的发展,你希望将更新带到生产环境中。 Spring 云数据流围绕能够更新任务应用程序提供的功能,本节将介绍这些功能。

当一个任务应用程序被注册(参见[注册任务应用程序](#spring-cloud-dataflow-register-task-apps))时,一个版本将与它关联。一个任务应用程序可以有多个与其关联的版本,其中一个被选为默认值。下面的图像演示了一个应用程序,该应用程序具有与其相关的多个版本(请参见时间戳条目)。

![任务应用程序版本](https://raw.githubusercontent.com/spring-cloud/spring-cloud-dataflow/master/spring-cloud-dataflow-docs/src/main/asciidoc/images/dataflow-task-application-versions.png)

应用程序的版本是通过注册具有相同名称和坐标的多个应用程序来管理的,*除了*版本。例如,如果你使用以下值注册一个应用程序,那么你将获得一个应用程序,它注册了两个版本(2.1.0.Release 和 2.1.1.Release):

* 应用程序 1

  * 名称:`timestamp`

  * 类型:`task`

  * URI:`maven://org.springframework.cloud.task.app:timestamp-task:2.1.0.RELEASE`

* 应用程序 2

  * 名称:`timestamp`

  * 类型:`task`

  * URI:`maven://org.springframework.cloud.task.app:timestamp-task:2.1.1.RELEASE`

Spring 除了具有多个版本外,云数据流还需要知道在下一个启动时运行哪个版本。这是通过将版本设置为默认版本来表示的。将任务应用程序配置为默认版本的任何版本,都是在下一个启动请求中运行的版本。你可以看到 UI 中的默认版本,如下图所示:

![任务应用程序默认版本](https://raw.githubusercontent.com/spring-cloud/spring-cloud-dataflow/master/spring-cloud-dataflow-docs/src/main/asciidoc/images/dataflow-task-default-version.png)

### 33.1.任务启动生命周期

在 Spring 云数据流的先前版本中,当接收到启动任务的请求时, Spring 云数据流将部署应用程序(如果需要)并运行它。如果应用程序运行在不需要每次都部署应用程序的平台上(例如,CloudFoundry),则使用先前部署的应用程序。这一流程在 2.3 中发生了变化。下图显示了现在出现任务启动请求时会发生什么:

![启动任务的流程](https://raw.githubusercontent.com/spring-cloud/spring-cloud-dataflow/master/spring-cloud-dataflow-docs/src/main/asciidoc/images/dataflow-task-launch-flow.png)

在前面的图表中有三个主要的流程需要考虑。第一次发射或不作任何改变就发射是一种。另外两个是在有更改时启动,但应用程序不是当前的,以及在有更改且应用程序正在运行时启动。我们先看流程,不做任何改变。

#### 33.1.1.在不做任何更改的情况下启动任务

1. 数据流中包含一个启动请求。数据流确定不需要升级,因为没有任何更改(自上次执行以来没有更改任何属性、部署属性或版本)。

1. 在缓存已部署工件的平台上(本文写作时为 CloudFoundry),数据流检查应用程序是否已预先部署。

2. 如果需要部署应用程序,那么数据流将部署任务应用程序。

3. 数据流启动应用程序。

这个流是默认的行为,如果没有任何变化,那么每次请求出现时都会发生。请注意,这是数据流一直用于启动任务的相同的流。

#### 33.1.2.使用当前未运行的更改启动任务

启动任务时要考虑的第二个流是,当任务没有运行,但任务应用程序版本、应用程序属性或部署属性中的任何一个发生了更改时。在这种情况下,将执行以下流程:

1. 数据流中包含一个启动请求。由于任务应用程序版本、应用程序属性或部署属性发生了更改,因此数据流确定需要进行升级。

2. 数据流检查任务定义的另一个实例是否正在运行。

1. 如果当前没有其他正在运行的任务定义实例,则删除旧的部署。

2. 在缓存已部署工件的平台上(本文所述为 CloudFoundry),数据流检查应用程序是否以前部署过(由于删除了旧的部署,此检查在该流中计算为`false`)。

3. 数据流使用更新的值(新的应用程序版本、新的合并属性和新的合并部署属性)进行任务应用程序的部署。

4. 数据流启动应用程序。

Spring 云数据流从根本上支持连续部署。

#### 33.1.3.在另一个实例运行时启动具有更改的任务

最后一个主流程是当启动请求来到 Spring 云数据流以执行升级但任务定义当前正在运行时。在这种情况下,由于需要删除当前应用程序,启动将被阻止。在某些平台上(本文所述为 CloudFoundry),删除应用程序会导致当前正在运行的所有应用程序被关闭。这个特性防止了这种情况的发生。下面的过程描述了当一个任务在另一个实例运行时发生更改时会发生的情况:

1. 数据流中包含一个启动请求。由于任务应用程序版本、应用程序属性或部署属性发生了更改,因此数据流确定需要进行升级。

2. 数据流检查任务定义的另一个实例是否正在运行。

3. 数据流阻止了启动的发生,因为任务定义的其他实例正在运行。

|   |由于需要删除当前正在运行的任务,任何需要升级在请求时正在运行的任务定义的启动都将被阻止运行。|
|---|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

# 任务开发人员指南

有关如何在本地计算机上创建、测试和运行 Spring 云任务应用程序的更多信息,请参见 microSite 的[批处理开发者](https://dataflow.spring.io/docs/batch-developer-guides/)部分。

# 任务监控

有关如何监视作为任务一部分部署的应用程序的更多信息,请参见 MicroSite 的[任务监控](https://dataflow.spring.io/docs/feature-guides/batch/monitoring/)指南。

# 仪表板

本节描述了如何使用 Spring 云数据流的仪表板。

## 34. 导言

Spring 云数据流提供了一种称为仪表板的基于浏览器的 GUI 来管理以下信息:

* **应用程序**:**应用程序**选项卡列出了所有可用的应用程序,并提供了用于注册和取消注册它们的控件。

* **运行时**:**运行时**选项卡提供了所有正在运行的应用程序的列表。

* **溪流**:**溪流**选项卡允许你列出、设计、创建、部署和销毁流定义。

* **任务**:**任务**选项卡允许你列出、创建、启动、调度和销毁任务定义。

* **工作**:**工作**选项卡允许你执行批处理作业相关的功能。

启动 Spring 云数据流后,仪表板可在以下位置使用:

`[<host>:<port>/dashboard](http://<host>:<port>/dashboard)`

例如,如果 Spring 云数据流在本地运行,则仪表板在`[localhost:9393/dashboard](http://localhost:9393/dashboard)`处可用。

如果你启用了 HTTPS,则仪表板的位置为`[localhost:9393/dashboard](https://localhost:9393/dashboard)`。如果你启用了安全性,则登录表单的网址为`[localhost:9393/dashboard/#/login](http://localhost:9393/dashboard/#/login)`。

|   |默认的仪表板服务器端口是`9393`。|
|---|--------------------------------------------|

下图显示了 Spring 云数据流仪表板的打开页面:

![The Spring Cloud Data Flow Dashboard](https://raw.githubusercontent.com/spring-cloud/spring-cloud-dataflow/master/spring-cloud-dataflow-docs/src/main/asciidoc/images/dataflow-dashboard-about.png)

6086
图 10. Spring 云数据流仪表板
D
dallascao 已提交
6087 6088 6089 6090 6091 6092 6093 6094 6095

## 35. 应用程序

仪表板的**应用程序**选项卡列出了所有可用的应用程序,并提供了用于注册和取消注册它们的控件(如果适用)。通过使用“批量导入应用程序”操作,你可以一次导入多个应用程序。

下图显示了仪表板中可用应用程序的典型列表:

![可用的应用程序列表](https://raw.githubusercontent.com/spring-cloud/spring-cloud-dataflow/master/spring-cloud-dataflow-docs/src/main/asciidoc/images/dataflow-available-apps-list.png)

6096
图 11.可用的应用程序列表
D
dallascao 已提交
6097 6098 6099 6100 6101 6102 6103 6104 6105 6106 6107 6108 6109 6110 6111 6112 6113 6114 6115 6116 6117 6118

### 35.1.应用程序的批量导入

应用程序可以通过“应用程序”页面上可用的多种方式导入。对于大容量导入,应用程序定义预计将以属性样式表示,如下所示:

```
<type>.<name> = <coordinates>
```

以下示例展示了典型的应用程序定义:

```
task.timestamp=maven://org.springframework.cloud.task.app:timestamp-task:1.2.0.RELEASE
processor.transform=maven://org.springframework.cloud.stream.app:transform-processor-rabbit:1.2.0.RELEASE
```

在“从 HTTP URI 位置导入应用程序坐标”部分中,你可以指定指向存储在其他地方的属性文件的 URI,它应该包含前面示例中所示的格式化的属性。或者,通过在“从属性文件导入应用程序坐标”部分中使用**作为属性的应用程序**文本框,你可以直接列出每个属性字符串。最后,如果属性存储在一个本地文件中,**导入一个文件**选项打开一个本地文件浏览器来选择该文件。在通过其中一个路由设置定义之后,单击**进口申请**。

下图显示了批量导入应用程序的一种方法的示例页面:

![批量导入应用程序](https://raw.githubusercontent.com/spring-cloud/spring-cloud-dataflow/master/spring-cloud-dataflow-docs/src/main/asciidoc/images/dataflow-bulk-import-applications.png)

6119
图 12.批量导入应用程序
D
dallascao 已提交
6120 6121 6122 6123 6124 6125 6126 6127 6128

## 36. 运行时

仪表板应用程序的**运行时**选项卡显示了所有正在运行的应用程序的列表。对于每个运行时应用程序,将显示部署的状态和部署的实例的数量。通过单击应用程序 ID,可以获得已用部署属性的列表。

下图显示了**运行时**选项卡的使用示例:

![正在运行的应用程序列表](https://raw.githubusercontent.com/spring-cloud/spring-cloud-dataflow/master/spring-cloud-dataflow-docs/src/main/asciidoc/images/dataflow-runtime.png)

6129
图 13.正在运行的应用程序列表
D
dallascao 已提交
6130 6131 6132 6133 6134 6135 6136 6137 6138 6139 6140 6141 6142 6143 6144 6145 6146 6147 6148 6149 6150

## 37. 溪流

**溪流**选项卡有两个子选项卡:**定义**和**创建流**。以下主题描述了如何与每一个项目合作:

* [处理流定义](#dashboard-stream-definitions)

* [创建一个流](#dashboard-flo-streams-designer)

* [部署流](#dashboard-stream-deploy)

* [访问流日志](#dashboard-stream-logs)

### 37.1.处理流定义

仪表板的**溪流**部分包括**定义**选项卡,该选项卡提供了流定义的列表。在这里,你可以选择部署或取消部署这些流定义。此外,你可以通过单击**毁灭**来删除该定义。每一行在左侧包括一个箭头,你可以单击该箭头查看定义的可视化表示。将鼠标悬停在可视化表示中的框中,将显示有关应用程序的更多详细信息,包括传递给它们的任何选项。

在下面的截图中,`timer`流已被扩展以显示可视化表示:

![流定义列表](https://raw.githubusercontent.com/spring-cloud/spring-cloud-dataflow/master/spring-cloud-dataflow-docs/src/main/asciidoc/images/dataflow-streams-list-definitions.png)

6151
图 14.流定义列表
D
dallascao 已提交
6152 6153 6154 6155 6156

如果单击 Details 按钮,视图会发生变化,以显示该流和任何相关流的可视化表示。在前面的示例中,如果单击`timer`流的详细信息,则该视图将更改为以下视图,该视图清楚地显示了三个流之间的关系(其中两个流正在访问`timer`流):

![流详细信息页面](https://raw.githubusercontent.com/spring-cloud/spring-cloud-dataflow/master/spring-cloud-dataflow-docs/src/main/asciidoc/images/dataflow-stream-details.png)

6157
图 15.流详细信息页面
D
dallascao 已提交
6158 6159 6160 6161 6162 6163 6164 6165 6166 6167 6168 6169 6170 6171 6172 6173 6174 6175 6176

### 37.2.创建一个流

仪表板的**溪流**部分包括**创建流**选项卡,这使得[Spring Flo](https://github.com/spring-projects/spring-flo)设计器可用。设计器是一个画布应用程序,它提供了用于创建数据管道的交互式图形界面。

在此选项卡中,你可以:

* 通过使用 DSL、图形化画布或两者结合来创建、管理和可视化流管道

* 使用具有内容辅助和自动完成功能的 DSL 编写管道

* 在 GUI 中使用自动调整和网格布局功能,以实现更简单和交互式的管道组织

你应该注意这个[screencast](https://www.youtube.com/watch?v=78CgV46OstI),它突出显示了一些“用于 Spring 云数据流的 FLO”功能。 Spring FLO[wiki](https://github.com/spring-projects/spring-flo/wiki)包括关于核心 FLO 能力的更详细的内容。

下图显示了正在使用的 FLO 设计器:

![Flo for Spring Cloud Data Flo](https://raw.githubusercontent.com/spring-cloud/spring-cloud-dataflow/master/spring-cloud-dataflow-docs/src/main/asciidoc/images/dataflow-flo-create-stream.png)

6177
图 16. Spring 云数据流的 FLO
D
dallascao 已提交
6178 6179 6180 6181 6182 6183 6184 6185 6186 6187 6188 6189 6190 6191 6192 6193 6194 6195

### 37.3.部署流

Stream 部署 页面包括制表符,这些制表符提供了设置部署属性和部署流的不同方式。下面的屏幕截图显示了`foobar`(`time | log`)的流部署页面。

你可以使用以下方法定义部署属性:

* Form Builder 选项卡:帮助你定义部署属性(部署程序、应用程序属性等)的构建器

* Free Text 选项卡:一个自由的文本区(用于键-值对)

你可以在两个视图之间切换。

|   |表单生成器提供了对输入的更强的验证。|
|---|----------------------------------------------------------|

![表单构建器](https://raw.githubusercontent.com/spring-cloud/spring-cloud-dataflow/master/spring-cloud-dataflow-docs/src/main/asciidoc/images/dataflow-stream-deploy-builder.png)

6196
图 17.下图显示了表单生成器
D
dallascao 已提交
6197 6198 6199

![Free text](https://raw.githubusercontent.com/spring-cloud/spring-cloud-dataflow/master/spring-cloud-dataflow-docs/src/main/asciidoc/images/dataflow-stream-deploy-freetext.png)

6200
图 18.下图显示了自由文本中的相同属性。
D
dallascao 已提交
6201 6202 6203 6204 6205 6206 6207 6208 6209 6210 6211 6212 6213

### 37.4.访问流日志

一旦部署了流应用程序,就可以从流`summary`页面访问它们的日志,如下图所示:

![流日志](https://raw.githubusercontent.com/spring-cloud/spring-cloud-dataflow/master/spring-cloud-dataflow-docs/src/main/asciidoc/images/dataflow-stream-logs.png)

### 37.5.创建扇入和扇出的流

在[扇入扇出](#spring-cloud-dataflow-stream-dsl-fanin-fanout)章节中,你可以通过使用[已命名的目的地](#spring-cloud-dataflow-stream-dsl-named-destinations)了解如何支持扇入扇出用例。UI 还为指定的目的地提供了专门的支持:

![扇入扇出示例](https://raw.githubusercontent.com/spring-cloud/spring-cloud-dataflow/master/spring-cloud-dataflow-docs/src/main/asciidoc/images/dataflow-flo-create-stream-fanin-fanout.png)

6214
图 19. Spring 云数据流的 FLO
D
dallascao 已提交
6215 6216 6217 6218 6219 6220 6221 6222 6223

在这个示例中,我们有来自*HTTP 源*和*JDBC 源代码*的数据,这些数据被发送到 *shareddata* 通道,这表示一个 Fan-in 用例。在另一端,我们有一个*Cassandra 水槽*和一个*文件接收器*订阅的*SharedData*通道,它代表一个扇出用例。

### 37.6.创建分接流

使用仪表板创建水龙头非常简单。假设你有一个由*HTTP 源*和*文件接收器*组成的流,并且你想要访问这个流来将数据发送到*JDBC 接收器*。要创建分接流,请将*HTTP 源*的输出连接器连接到*JDBC 接收器*。连接显示为虚线,表示你创建了一个分接流。

![Tap Stream 示例](https://raw.githubusercontent.com/spring-cloud/spring-cloud-dataflow/master/spring-cloud-dataflow-docs/src/main/asciidoc/images/dataflow-flo-create-tap-stream.png)

6224
图 20.创建分接流
D
dallascao 已提交
6225 6226 6227 6228 6229 6230 6231

主流(*HTTP 源 * 到*文件接收器*)将被自动命名,如果你还没有为该流提供名称的话。在创建分接流时,主流必须始终显式地命名。在前面的图像中,主流被命名为*http\_ingest*。

通过使用仪表板,你还可以切换主流,使其成为辅助分接流。

![将分接流切换到主流](https://raw.githubusercontent.com/spring-cloud/spring-cloud-dataflow/master/spring-cloud-dataflow-docs/src/main/asciidoc/images/dataflow-flo-tap-stream-switch-to-primary-stream.png)

6232
图 21.将一次流转换为二次抽头流
D
dallascao 已提交
6233 6234 6235 6236 6237

将鼠标悬停在现有的主流上,即*HTTP 源*和*文件接收器*之间的直线。出现了几个控制图标,通过单击标记为*切换到/从水龙头切换*的图标,你可以将主流更改为分接流。对分接流执行相同的操作,并将其切换到主流。

![将分接流转换为主流的最终结果](https://raw.githubusercontent.com/spring-cloud/spring-cloud-dataflow/master/spring-cloud-dataflow-docs/src/main/asciidoc/images/dataflow-flo-tap-stream-switch-to-primary-stream-result.png)

6238
图 22.切换主流的最终结果
D
dallascao 已提交
6239 6240 6241 6242 6243 6244 6245 6246 6247 6248 6249 6250

|   |当与[已命名的目的地](#spring-cloud-dataflow-stream-dsl-named-destinations)直接交互时,<br/>可以有“n”个组合(输入/输出)。这允许你创建涉及<br/>各种数据源和目的地的复杂拓扑。|
|---|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

### 37.7.导入和导出流程

仪表板的**进口/出口**选项卡包括一个页面,该页面提供了导入和导出流的选项。

下图显示了 溪流 导出页面:

![流 utils 导出](https://raw.githubusercontent.com/spring-cloud/spring-cloud-dataflow/master/spring-cloud-dataflow-docs/src/main/asciidoc/images/dataflow-streams-utils-export.png)

6251
图 23.流 utils 导出页面
D
dallascao 已提交
6252 6253 6254 6255 6256

在导入流时,必须从有效的 JSON 文件导入。你可以手动起草该文件,也可以从 Streams 导出页面导出该文件。

![流 utils 导入](https://raw.githubusercontent.com/spring-cloud/spring-cloud-dataflow/master/spring-cloud-dataflow-docs/src/main/asciidoc/images/dataflow-streams-utils-import.png)

6257
图 24.流 utils 导入页面
D
dallascao 已提交
6258 6259 6260 6261 6262

导入文件后,你将获得操作是否成功完成的确认。

![流 utils 导入结果](https://raw.githubusercontent.com/spring-cloud/spring-cloud-dataflow/master/spring-cloud-dataflow-docs/src/main/asciidoc/images/dataflow-streams-utils-import-result.png)

6263
图 25.流 utils 导入结果页
D
dallascao 已提交
6264 6265 6266 6267 6268 6269 6270 6271 6272 6273 6274 6275 6276 6277 6278 6279 6280 6281 6282 6283 6284 6285 6286 6287

## 38. 任务

仪表板的**任务**选项卡当前有三个选项卡:

* [Apps](#dashboard-tasks-apps)

* [定义](#dashboard-task-definition)

* [Executions](#dashboard-tasks-executions)

* [调度](#dashboard-task-scheduling)

### 38.1.应用程序

每个应用程序都将一个工作单元封装到一个可重用的组件中。在数据流运行时环境中,应用程序允许你为流和任务创建定义。因此,**应用程序**选项卡中的**任务**选项卡允许你创建任务定义。

|   |你还可以使用此选项卡创建批处理作业。|
|---|-----------------------------------------------|

下图显示了一个典型的任务应用程序列表:

![任务应用程序列表](https://raw.githubusercontent.com/spring-cloud/spring-cloud-dataflow/master/spring-cloud-dataflow-docs/src/main/asciidoc/images/dataflow-task-apps-list.png)

6288
图 26.任务应用程序列表
D
dallascao 已提交
6289 6290 6291 6292 6293 6294 6295 6296 6297 6298 6299 6300 6301 6302 6303 6304 6305 6306 6307

在这个屏幕上,你可以执行以下操作:

* 查看详细信息,例如任务应用程序选项。

* 从相应的应用程序中创建任务定义。

#### 38.1.1.查看任务应用程序的详细信息

在此页面上,你可以查看所选任务应用程序的详细信息,包括该应用程序的可用选项(属性)列表。

### 38.2.定义

本页列出了数据流任务定义,并提供了启动或销毁这些任务的操作。

下图显示了定义页面:

![任务定义列表](https://raw.githubusercontent.com/spring-cloud/spring-cloud-dataflow/master/spring-cloud-dataflow-docs/src/main/asciidoc/images/dataflow-task-definitions-list.png)

6308
图 27.任务定义列表
D
dallascao 已提交
6309 6310 6311 6312 6313 6314 6315 6316 6317 6318 6319 6320 6321 6322 6323 6324 6325 6326 6327 6328 6329 6330 6331 6332 6333 6334 6335 6336

#### 38.2.1.创建任务定义

下图显示了由时间戳应用程序以及可用于创建 TaskDefiniton 的任务应用程序列表组成的任务定义:

![任务应用程序列表](https://raw.githubusercontent.com/spring-cloud/spring-cloud-dataflow/master/spring-cloud-dataflow-docs/src/main/asciidoc/images/dataflow-task-definition-create.png)

在这个页面上,你还可以指定应用程序部署期间使用的各种属性。一旦你对任务定义满意,就可以单击**CREATE TASK**按钮。然后,一个对话框要求提供任务定义名称和描述。至少,你必须为新定义提供一个名称。

#### 38.2.2.创建组合任务定义

仪表板包括**创建组合任务**选项卡,它提供了用于创建组合任务的交互式图形界面。

在此选项卡中,你可以:

* 通过使用 DSL、图形化画布或两者结合来创建和可视化组合任务。

* 在 GUI 中使用自动调整和网格布局功能,以实现对组合任务的更简单和交互式的组织。

在**创建组合任务**屏幕上,你可以通过输入参数键和参数值来定义一个或多个任务参数。

|   |未键入任务参数。|
|---|------------------------------|

下图显示了组成任务设计器:

![组合任务设计器](https://raw.githubusercontent.com/spring-cloud/spring-cloud-dataflow/master/spring-cloud-dataflow-docs/src/main/asciidoc/images/dataflow-ctr-flo-tab.png)

6337
图 28.组合任务设计器
D
dallascao 已提交
6338 6339 6340 6341 6342 6343 6344

#### 38.2.3.启动任务

一旦创建了任务定义,就可以通过仪表板启动任务。要这样做,请单击**任务**选项卡,然后按`Launch`选择要启动的任务。下图显示了任务启动页面:

![任务启动](https://raw.githubusercontent.com/spring-cloud/spring-cloud-dataflow/master/spring-cloud-dataflow-docs/src/main/asciidoc/images/dataflow-task-launch.png)

6345
图 29.任务启动页面
D
dallascao 已提交
6346 6347 6348 6349 6350 6351 6352 6353 6354

#### 38.2.4.导入/导出任务

**进口/出口**页面提供了导入和导出任务的选项。这可以通过单击页面左侧的**进口/出口**选项来完成。从这里,单击**导出任务:使用选定的任务创建一个 JSON 文件**选项。出现`Export Tasks(s)`页面。

下图显示了任务导出页面:

![任务 utils 导出](https://raw.githubusercontent.com/spring-cloud/spring-cloud-dataflow/master/spring-cloud-dataflow-docs/src/main/asciidoc/images/dataflow-tasks-utils-export.png)

6355
图 30.任务 utils 导出页面
D
dallascao 已提交
6356 6357 6358 6359 6360

类似地,你可以导入任务定义。要这样做,请单击页面左侧的**进口/出口**选项。从这里,单击**导入任务:从 JSON 文件导入任务**选项以显示**导入任务**页面。在**导入任务**页面上,你必须从有效的 JSON 文件导入。你可以手动起草该文件,也可以从**任务导出**页面导出该文件。

![任务 utils 导入](https://raw.githubusercontent.com/spring-cloud/spring-cloud-dataflow/master/spring-cloud-dataflow-docs/src/main/asciidoc/images/dataflow-tasks-utils-import.png)

6361
图 31.任务 utils 导入页面
D
dallascao 已提交
6362 6363 6364 6365 6366

在导入文件后,你将获得有关操作是否成功完成的确认。

![任务 utils 导入结果](https://raw.githubusercontent.com/spring-cloud/spring-cloud-dataflow/master/spring-cloud-dataflow-docs/src/main/asciidoc/images/dataflow-tasks-utils-import-result.png)

6367
图 32.任务 utils 导入结果页
D
dallascao 已提交
6368 6369 6370 6371 6372 6373 6374 6375 6376 6377 6378

### 38.3.处决

**任务执行**选项卡显示当前正在运行和已完成的任务执行情况。从这个页面,你可以向下钻取**任务执行**详细信息页面。此外,你可以重新启动**任务执行**或停止正在运行的执行。

最后,你可以清理一个或多个任务执行。此操作将从基础持久性存储中删除任何相关的任务或批处理作业。此操作只能为*家长*任务执行触发,并级联到子任务执行(如果有的话)。

下图显示了**处决**选项卡:

![任务执行列表](https://raw.githubusercontent.com/spring-cloud/spring-cloud-dataflow/master/spring-cloud-dataflow-docs/src/main/asciidoc/images/dataflow-task-executions-list.png)

6379
图 33.任务执行列表
D
dallascao 已提交
6380 6381 6382 6383 6384 6385 6386 6387 6388 6389 6390 6391 6392 6393 6394 6395 6396 6397 6398 6399 6400 6401 6402 6403 6404 6405 6406 6407 6408 6409 6410 6411 6412 6413 6414 6415 6416 6417 6418 6419 6420 6421 6422 6423 6424 6425 6426 6427 6428 6429 6430 6431 6432 6433 6434 6435 6436 6437 6438 6439 6440

### 38.4.执行细节

对于**任务执行**选项卡上的每个任务执行,你可以通过单击任务执行的**执行 ID**来检索有关特定执行的详细信息。

![任务执行列表](https://raw.githubusercontent.com/spring-cloud/spring-cloud-dataflow/master/spring-cloud-dataflow-docs/src/main/asciidoc/images/dataflow-task-execution-detail.png)

在这个屏幕上,你不仅可以查看来自任务执行页面的信息,还可以查看:

* 任务参数

* 外部执行 ID

* 批处理作业指示器(指示任务执行是否包含 Spring 批处理作业)。

* 作业执行 ID 链接(单击作业执行 ID 将带你到该作业执行 ID 的[作业执行细节](#dashboard-job-executions-details))。

* 任务执行持续时间

* 任务执行退出消息

* 记录任务执行的输出

此外,你还可以触发以下操作:

* 重新启动一项任务

* 停止正在运行的任务

* 任务执行清理(仅针对父任务执行)

#### 38.4.1.停止执行任务

要向平台提交停止任务执行请求,请单击需要停止的任务执行旁边的下拉按钮。现在点击**停止任务**选项。仪表板会显示一个对话框,询问你是否确定要停止任务执行。如果是,请单击`Stop Task Execution(s)`。

![停止执行任务](https://raw.githubusercontent.com/spring-cloud/spring-cloud-dataflow/master/spring-cloud-dataflow-docs/src/main/asciidoc/images/dataflow-task-execution-stop.png)

|   |Spring 通过 Spring 批处理应用程序启动的使用远程分区的子云任务应用程序不被停止。|
|---|-------------------------------------------------------------------------------------------------------------------------|

## 39. 工作

仪表板的**工作执行**选项卡允许你检查批处理作业。屏幕的主要部分提供了一个作业执行列表。批处理作业是每个任务执行一个或多个批处理作业的任务。每个作业执行都有对任务执行 ID 的引用(在 Task ID 列中)。

作业执行列表还显示了底层作业定义的状态。因此,如果删除了底层定义,则在**状态**列中出现“未找到定义”。

对于每项工作,你可以采取以下操作:

* 重新启动(对于失败的作业)。

* 停止(运行作业)。

* 查看执行细节。

|   |单击“停止”按钮实际上会向正在运行的作业发送“停止”请求,该请求可能不会立即停止。|
|---|----------------------------------------------------------------------------------------------------------|

下图显示了**工作**选项卡:

![工作执行列表](https://raw.githubusercontent.com/spring-cloud/spring-cloud-dataflow/master/spring-cloud-dataflow-docs/src/main/asciidoc/images/dataflow-job-executions-list.png)

6441
图 34.工作执行列表
D
dallascao 已提交
6442 6443 6444 6445 6446 6447 6448 6449 6450

### 39.1.作业执行细节

在你启动了一个批处理作业之后,作业执行详细信息页面将显示有关该作业的信息。

下图显示了作业执行详细信息页面:

![作业执行细节](https://raw.githubusercontent.com/spring-cloud/spring-cloud-dataflow/master/spring-cloud-dataflow-docs/src/main/asciidoc/images/dataflow-jobs-job-execution-details.png)

6451
图 35.作业执行细节
D
dallascao 已提交
6452 6453 6454 6455 6456 6457 6458 6459 6460 6461 6462

作业执行详细信息页包含已执行步骤的列表。你可以点击放大镜图标,进一步深入了解每一步的执行细节。

### 39.2.步骤执行细节

Step Execution Details 页面提供了关于作业中单个步骤的信息。

下图显示了 Step Execution Details 页面:

![步骤执行历史](https://raw.githubusercontent.com/spring-cloud/spring-cloud-dataflow/master/spring-cloud-dataflow-docs/src/main/asciidoc/images/dataflow-step-execution-history.png)

6463
图 36.步骤执行细节
D
dallascao 已提交
6464 6465 6466 6467 6468 6469 6470 6471 6472 6473 6474 6475 6476 6477 6478 6479 6480 6481 6482 6483 6484 6485 6486 6487 6488 6489 6490 6491 6492 6493 6494 6495 6496 6497 6498 6499 6500 6501 6502 6503 6504 6505 6506 6507 6508 6509

Step Execution Details 屏幕提供了所有 Step Execution Context 键-值对的完整列表。

|   |对于异常,**退出描述**字段包含额外的错误信息。<br/>但是,此字段最多可以有 2500 个字符。<br/>因此,在异常堆栈跟踪较长的情况下,可能会发生错误消息的微调。<br/>当发生这种情况时,请检查服务器日志文件以获取更多详细信息。|
|---|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

### 39.3.步骤执行历史

在**步骤执行历史**下,还可以查看与所选步骤相关的各种指标,例如持续时间、读计数、写计数等。

## 40. Scheduling

你可以从 SCDF 仪表板为任务定义创建计划。有关更多信息,请参见微型网站的[调度批处理作业](https://dataflow.spring.io/docs/feature-guides/batch/scheduling/)部分。

## 41. 审计

仪表板的审核页允许你访问记录的审核事件。审计事件记录如下:

* Streams

  * 创建

  * 删除

  * Deploy

  * 取消部署

* Tasks

  * 创建

  * 删除

  * Launch

* 任务的时间安排

  * 创建时间表

  * 删除时间表

下图显示了审计记录页面:

![可用的审计记录清单](https://raw.githubusercontent.com/spring-cloud/spring-cloud-dataflow/master/spring-cloud-dataflow-docs/src/main/asciidoc/images/dataflow-audit-records-list.png)

6510
图 37.列出审计记录概览
D
dallascao 已提交
6511 6512 6513 6514 6515

通过单击*显示详细信息*图标(右侧圆圈中的“i”),你可以获得有关审核详细信息的更多详细信息:

![单一审计记录的详细信息](https://raw.githubusercontent.com/spring-cloud/spring-cloud-dataflow/master/spring-cloud-dataflow-docs/src/main/asciidoc/images/dataflow-audit-records-details.png)

6516
图 38.列出审计记录的细节
D
dallascao 已提交
6517 6518 6519 6520 6521 6522 6523 6524 6525 6526 6527 6528 6529 6530 6531 6532 6533 6534 6535 6536 6537 6538 6539 6540 6541 6542 6543 6544 6545 6546 6547 6548 6549 6550 6551 6552 6553 6554 6555 6556 6557 6558 6559 6560 6561 6562 6563 6564 6565 6566 6567 6568 6569 6570 6571 6572 6573 6574 6575 6576 6577 6578 6579 6580 6581 6582 6583 6584 6585 6586 6587 6588 6589 6590 6591 6592 6593 6594 6595 6596 6597 6598 6599 6600 6601 6602 6603 6604 6605 6606 6607 6608 6609 6610 6611 6612 6613 6614 6615 6616 6617 6618 6619 6620 6621 6622 6623 6624 6625 6626 6627 6628 6629 6630 6631 6632 6633 6634 6635 6636 6637 6638 6639 6640 6641 6642 6643 6644 6645 6646 6647 6648 6649 6650 6651 6652 6653 6654 6655 6656 6657 6658 6659 6660 6661 6662 6663 6664 6665 6666 6667 6668 6669 6670 6671 6672 6673 6674 6675 6676 6677 6678 6679 6680 6681 6682 6683 6684 6685 6686 6687 6688 6689 6690 6691 6692 6693 6694 6695 6696 6697 6698 6699 6700 6701 6702 6703 6704 6705 6706 6707 6708 6709 6710 6711 6712 6713 6714 6715 6716 6717 6718 6719 6720 6721 6722 6723 6724 6725 6726 6727 6728 6729 6730 6731 6732 6733 6734 6735 6736 6737 6738 6739 6740 6741 6742 6743 6744 6745 6746 6747 6748 6749 6750 6751 6752 6753 6754 6755 6756 6757 6758 6759 6760 6761 6762 6763 6764 6765 6766 6767 6768 6769 6770 6771 6772 6773 6774 6775 6776 6777 6778 6779 6780 6781 6782 6783 6784 6785 6786 6787 6788 6789 6790 6791 6792 6793 6794 6795 6796 6797 6798 6799 6800 6801 6802 6803 6804 6805 6806 6807 6808 6809 6810 6811 6812 6813 6814 6815 6816 6817 6818 6819 6820 6821 6822 6823 6824 6825 6826 6827 6828 6829 6830 6831 6832 6833 6834 6835 6836 6837 6838 6839 6840 6841 6842 6843 6844 6845 6846 6847 6848 6849 6850 6851 6852 6853 6854 6855 6856 6857 6858 6859 6860 6861 6862 6863 6864 6865 6866 6867 6868 6869 6870 6871 6872 6873 6874 6875 6876 6877 6878 6879 6880 6881 6882 6883 6884 6885 6886 6887 6888 6889 6890 6891 6892 6893 6894 6895 6896 6897 6898 6899 6900 6901 6902 6903 6904 6905 6906 6907 6908 6909 6910 6911 6912 6913 6914 6915 6916 6917 6918 6919 6920 6921 6922 6923 6924 6925 6926 6927 6928 6929 6930 6931 6932 6933 6934 6935 6936 6937 6938 6939 6940 6941 6942 6943 6944 6945 6946 6947 6948 6949 6950 6951 6952 6953 6954 6955 6956 6957 6958 6959 6960 6961 6962 6963 6964 6965 6966 6967 6968 6969 6970 6971 6972 6973 6974 6975 6976 6977 6978 6979 6980 6981 6982 6983 6984 6985 6986 6987 6988 6989 6990 6991 6992 6993 6994 6995 6996 6997 6998 6999 7000 7001 7002 7003 7004 7005 7006 7007 7008 7009 7010 7011 7012 7013 7014 7015 7016 7017 7018 7019 7020 7021 7022 7023 7024 7025 7026 7027 7028 7029 7030 7031 7032 7033 7034 7035 7036 7037 7038 7039 7040 7041 7042 7043 7044 7045 7046 7047 7048 7049 7050 7051 7052 7053 7054 7055 7056 7057 7058 7059 7060 7061 7062 7063 7064 7065 7066 7067 7068 7069 7070 7071 7072 7073 7074 7075 7076 7077 7078 7079 7080 7081 7082 7083 7084 7085 7086 7087 7088 7089 7090 7091 7092 7093 7094 7095 7096 7097 7098 7099 7100 7101 7102 7103 7104 7105 7106 7107 7108 7109 7110 7111 7112 7113 7114 7115 7116 7117 7118 7119 7120 7121 7122 7123 7124 7125 7126 7127 7128 7129 7130 7131 7132 7133 7134 7135 7136 7137 7138 7139 7140 7141 7142 7143 7144 7145 7146 7147 7148 7149 7150 7151 7152 7153 7154 7155 7156 7157 7158 7159 7160 7161 7162 7163 7164 7165 7166 7167 7168 7169 7170 7171 7172 7173 7174 7175 7176 7177 7178 7179 7180 7181 7182 7183 7184 7185 7186 7187 7188 7189 7190 7191 7192 7193 7194 7195 7196 7197 7198 7199 7200 7201 7202 7203 7204 7205 7206 7207 7208 7209 7210 7211 7212 7213 7214 7215 7216 7217 7218 7219 7220 7221 7222 7223 7224 7225 7226 7227 7228 7229 7230 7231 7232 7233 7234 7235 7236 7237 7238 7239 7240 7241 7242 7243 7244 7245 7246 7247 7248 7249 7250 7251 7252 7253 7254 7255 7256 7257 7258 7259 7260 7261 7262 7263 7264 7265 7266 7267 7268 7269 7270 7271 7272 7273 7274 7275 7276 7277 7278 7279 7280 7281 7282 7283 7284 7285 7286 7287 7288 7289 7290 7291 7292 7293 7294 7295 7296 7297 7298 7299 7300 7301 7302 7303 7304 7305 7306 7307 7308 7309 7310 7311 7312 7313 7314 7315 7316 7317 7318 7319 7320 7321 7322 7323 7324 7325 7326 7327 7328 7329 7330 7331 7332 7333 7334 7335 7336 7337 7338 7339 7340 7341 7342 7343 7344 7345 7346 7347 7348 7349 7350 7351 7352 7353 7354 7355 7356 7357 7358 7359 7360 7361 7362 7363 7364 7365 7366 7367 7368 7369 7370 7371 7372 7373 7374 7375 7376 7377 7378 7379 7380 7381 7382 7383 7384 7385 7386 7387 7388 7389 7390 7391 7392 7393 7394 7395 7396 7397 7398 7399 7400 7401 7402 7403 7404 7405 7406 7407 7408 7409 7410 7411 7412 7413 7414 7415 7416 7417 7418 7419 7420 7421 7422 7423 7424 7425 7426 7427 7428 7429 7430 7431 7432 7433 7434 7435 7436 7437 7438 7439 7440 7441 7442 7443 7444 7445 7446 7447 7448 7449 7450 7451 7452 7453 7454 7455 7456 7457 7458 7459 7460 7461 7462 7463 7464 7465 7466 7467 7468 7469 7470 7471 7472 7473 7474 7475 7476 7477 7478 7479 7480 7481 7482 7483 7484 7485 7486 7487 7488 7489 7490 7491 7492 7493 7494 7495 7496 7497 7498 7499 7500 7501 7502 7503 7504 7505 7506 7507 7508 7509 7510 7511 7512 7513 7514 7515 7516 7517 7518 7519 7520 7521 7522 7523 7524 7525 7526 7527 7528 7529 7530 7531 7532 7533 7534 7535 7536 7537 7538 7539 7540 7541 7542 7543 7544 7545 7546 7547 7548 7549 7550 7551 7552 7553 7554 7555 7556 7557 7558 7559 7560 7561 7562 7563 7564 7565 7566 7567 7568 7569 7570 7571 7572 7573 7574 7575 7576 7577 7578 7579 7580 7581 7582 7583 7584 7585 7586 7587 7588 7589 7590 7591 7592 7593 7594 7595 7596 7597 7598 7599 7600 7601 7602 7603 7604 7605 7606 7607 7608 7609 7610 7611 7612 7613 7614 7615 7616 7617 7618 7619 7620 7621 7622 7623 7624 7625 7626 7627 7628 7629 7630 7631 7632 7633 7634 7635 7636 7637 7638 7639 7640 7641 7642 7643 7644 7645 7646 7647 7648 7649 7650 7651 7652 7653 7654 7655 7656 7657 7658 7659 7660 7661 7662 7663 7664 7665 7666 7667 7668 7669 7670 7671 7672 7673 7674 7675 7676 7677 7678 7679 7680 7681 7682 7683 7684 7685 7686 7687 7688 7689 7690 7691 7692 7693 7694 7695 7696 7697 7698 7699 7700 7701 7702 7703 7704 7705 7706 7707 7708 7709 7710 7711 7712 7713 7714 7715 7716 7717 7718 7719 7720 7721 7722 7723 7724 7725 7726 7727 7728 7729 7730 7731 7732 7733 7734 7735 7736 7737 7738 7739 7740 7741 7742 7743 7744 7745 7746 7747 7748 7749 7750 7751 7752 7753 7754 7755 7756 7757 7758 7759 7760 7761 7762 7763 7764 7765 7766 7767 7768 7769 7770 7771 7772 7773 7774 7775 7776 7777 7778 7779 7780 7781 7782 7783 7784 7785 7786 7787 7788 7789 7790 7791 7792 7793 7794 7795 7796 7797 7798 7799 7800 7801 7802 7803 7804 7805 7806 7807 7808 7809 7810 7811 7812 7813 7814 7815 7816 7817 7818 7819 7820 7821 7822 7823 7824 7825 7826 7827 7828 7829 7830 7831 7832 7833 7834 7835 7836 7837 7838 7839 7840 7841 7842 7843 7844 7845 7846 7847 7848 7849 7850 7851 7852 7853 7854 7855 7856 7857 7858 7859 7860 7861 7862 7863 7864 7865 7866 7867 7868 7869 7870 7871 7872 7873 7874 7875 7876 7877 7878 7879 7880 7881 7882 7883 7884 7885 7886 7887 7888 7889 7890 7891 7892 7893 7894 7895 7896 7897 7898 7899 7900 7901 7902 7903 7904 7905 7906 7907 7908 7909 7910 7911 7912 7913 7914 7915 7916 7917 7918 7919 7920 7921 7922 7923 7924 7925 7926 7927 7928 7929 7930 7931 7932 7933 7934 7935 7936 7937 7938 7939 7940 7941 7942 7943 7944 7945 7946 7947 7948 7949 7950 7951 7952 7953 7954 7955 7956 7957 7958 7959 7960 7961 7962 7963 7964 7965 7966 7967 7968 7969 7970 7971 7972 7973 7974 7975 7976 7977 7978 7979 7980 7981 7982 7983 7984 7985 7986 7987 7988 7989 7990 7991 7992 7993 7994 7995 7996 7997 7998 7999 8000 8001 8002 8003 8004 8005 8006 8007 8008 8009 8010 8011 8012 8013 8014 8015 8016 8017 8018 8019 8020 8021 8022 8023 8024 8025 8026 8027 8028 8029 8030 8031 8032 8033 8034 8035 8036 8037 8038 8039 8040 8041 8042 8043 8044 8045 8046 8047 8048 8049 8050 8051 8052 8053 8054 8055 8056 8057 8058 8059 8060 8061 8062 8063 8064 8065 8066 8067 8068 8069 8070 8071 8072 8073 8074 8075 8076 8077 8078 8079 8080 8081 8082 8083 8084 8085 8086 8087 8088 8089 8090 8091 8092 8093 8094 8095 8096 8097 8098 8099 8100 8101 8102 8103 8104 8105 8106 8107 8108 8109 8110 8111 8112 8113 8114 8115 8116 8117 8118 8119 8120 8121 8122 8123 8124 8125 8126 8127 8128 8129 8130 8131 8132 8133 8134 8135 8136 8137 8138 8139 8140 8141 8142 8143 8144 8145 8146 8147 8148 8149 8150 8151 8152 8153 8154 8155 8156 8157 8158 8159 8160 8161 8162 8163 8164 8165 8166 8167 8168 8169 8170 8171 8172 8173 8174 8175 8176 8177 8178 8179 8180 8181 8182 8183 8184 8185 8186 8187 8188 8189 8190 8191 8192 8193 8194 8195 8196 8197 8198 8199 8200 8201 8202 8203 8204 8205 8206 8207 8208 8209 8210 8211 8212 8213 8214 8215 8216 8217 8218 8219 8220 8221 8222 8223 8224 8225 8226 8227 8228 8229 8230 8231 8232 8233 8234 8235 8236 8237 8238 8239 8240 8241 8242 8243 8244 8245 8246 8247 8248 8249 8250 8251 8252 8253 8254 8255 8256 8257 8258 8259 8260 8261 8262 8263 8264 8265 8266 8267 8268 8269 8270 8271 8272 8273 8274 8275 8276 8277 8278 8279 8280 8281 8282 8283 8284 8285 8286 8287 8288 8289 8290 8291 8292 8293 8294 8295 8296 8297 8298 8299 8300 8301 8302 8303 8304 8305 8306 8307 8308 8309 8310 8311 8312 8313 8314 8315 8316 8317 8318 8319 8320 8321 8322 8323 8324 8325 8326 8327 8328 8329 8330 8331 8332 8333 8334 8335 8336 8337 8338 8339 8340 8341 8342 8343 8344 8345 8346 8347 8348 8349 8350 8351 8352 8353 8354 8355 8356 8357 8358 8359 8360 8361 8362 8363 8364 8365 8366 8367 8368 8369 8370 8371 8372 8373 8374 8375 8376 8377 8378 8379 8380 8381 8382 8383 8384 8385 8386 8387 8388 8389 8390 8391 8392 8393 8394 8395 8396 8397 8398 8399 8400 8401 8402 8403 8404 8405 8406 8407 8408 8409 8410 8411 8412 8413 8414 8415 8416 8417 8418 8419 8420 8421 8422 8423 8424 8425 8426 8427 8428 8429 8430 8431 8432 8433 8434 8435 8436 8437 8438 8439 8440 8441 8442 8443 8444 8445 8446 8447 8448 8449 8450 8451 8452 8453 8454 8455 8456 8457 8458 8459 8460 8461 8462 8463 8464 8465 8466 8467 8468 8469 8470 8471 8472 8473 8474 8475 8476 8477 8478 8479 8480 8481 8482 8483 8484 8485 8486 8487 8488 8489 8490 8491 8492 8493 8494 8495 8496 8497 8498 8499 8500 8501 8502 8503 8504 8505 8506 8507 8508 8509 8510 8511 8512 8513 8514 8515 8516 8517 8518 8519 8520 8521 8522 8523 8524 8525 8526 8527 8528 8529 8530 8531 8532 8533 8534 8535 8536 8537 8538 8539 8540 8541 8542 8543 8544 8545 8546 8547 8548 8549 8550 8551 8552 8553 8554 8555 8556 8557 8558 8559 8560 8561 8562 8563 8564 8565 8566 8567 8568 8569 8570 8571 8572 8573 8574 8575 8576 8577 8578 8579 8580 8581 8582 8583 8584 8585 8586 8587 8588 8589 8590 8591 8592 8593 8594 8595 8596 8597 8598 8599 8600 8601 8602 8603 8604 8605 8606 8607 8608 8609 8610 8611 8612 8613 8614 8615 8616 8617 8618 8619 8620 8621 8622 8623 8624 8625 8626 8627 8628 8629 8630 8631 8632 8633 8634 8635 8636 8637 8638 8639 8640 8641 8642 8643 8644 8645 8646 8647 8648 8649 8650 8651 8652 8653 8654 8655 8656 8657 8658 8659 8660 8661 8662 8663 8664 8665 8666 8667 8668 8669 8670 8671 8672 8673 8674 8675 8676 8677 8678 8679 8680 8681 8682 8683 8684 8685 8686 8687 8688 8689 8690 8691 8692 8693 8694 8695 8696 8697 8698 8699 8700 8701 8702 8703 8704 8705 8706 8707 8708 8709 8710 8711 8712 8713 8714 8715 8716 8717 8718 8719 8720 8721 8722 8723 8724 8725 8726 8727 8728 8729 8730 8731 8732 8733 8734 8735 8736 8737 8738 8739 8740 8741 8742 8743 8744 8745 8746 8747 8748 8749 8750 8751 8752 8753 8754 8755 8756 8757 8758 8759 8760 8761 8762 8763 8764 8765 8766 8767 8768 8769 8770 8771 8772 8773 8774 8775 8776 8777 8778 8779 8780 8781 8782 8783 8784 8785 8786 8787 8788 8789 8790 8791 8792 8793 8794 8795 8796 8797 8798 8799 8800 8801 8802 8803 8804 8805 8806 8807 8808 8809 8810 8811 8812 8813 8814 8815 8816 8817 8818 8819 8820 8821 8822 8823 8824 8825 8826 8827 8828 8829 8830 8831 8832 8833 8834 8835 8836 8837 8838 8839 8840 8841 8842 8843 8844 8845 8846 8847 8848 8849 8850 8851 8852 8853 8854 8855 8856 8857 8858 8859 8860 8861 8862 8863 8864 8865 8866 8867 8868 8869 8870 8871 8872 8873 8874 8875 8876 8877 8878 8879 8880 8881 8882 8883 8884 8885 8886 8887 8888 8889 8890 8891 8892 8893 8894 8895 8896 8897 8898 8899 8900 8901 8902 8903 8904 8905 8906 8907 8908 8909 8910 8911 8912 8913 8914 8915 8916 8917 8918 8919 8920 8921 8922 8923 8924 8925 8926 8927 8928 8929 8930 8931 8932 8933 8934 8935 8936 8937 8938 8939 8940 8941 8942 8943 8944 8945 8946 8947 8948 8949 8950 8951 8952 8953 8954 8955 8956 8957 8958 8959 8960 8961 8962 8963 8964 8965 8966 8967 8968 8969 8970 8971 8972 8973 8974 8975 8976 8977 8978 8979 8980 8981 8982 8983 8984 8985 8986 8987 8988 8989 8990 8991 8992 8993 8994 8995 8996 8997 8998 8999 9000 9001 9002 9003 9004 9005 9006 9007 9008 9009 9010 9011 9012 9013 9014 9015 9016 9017 9018 9019 9020 9021 9022 9023 9024 9025 9026 9027 9028 9029 9030 9031 9032 9033 9034 9035 9036 9037 9038 9039 9040 9041 9042 9043 9044 9045 9046 9047 9048 9049 9050 9051 9052 9053 9054 9055 9056 9057 9058 9059 9060 9061 9062 9063 9064 9065 9066 9067 9068 9069 9070 9071 9072 9073 9074 9075 9076 9077 9078 9079 9080 9081 9082 9083 9084 9085 9086 9087 9088 9089 9090 9091 9092 9093 9094 9095 9096 9097 9098 9099 9100 9101 9102 9103 9104 9105 9106 9107 9108 9109 9110 9111 9112 9113 9114 9115 9116 9117 9118 9119 9120 9121 9122 9123 9124 9125 9126 9127 9128 9129 9130 9131 9132 9133 9134 9135 9136 9137 9138 9139 9140 9141 9142 9143 9144 9145 9146 9147 9148 9149 9150 9151 9152 9153 9154 9155 9156 9157 9158 9159 9160 9161 9162 9163 9164 9165 9166 9167 9168 9169 9170 9171 9172 9173 9174 9175 9176 9177 9178 9179 9180 9181 9182 9183 9184 9185 9186 9187 9188 9189 9190 9191 9192 9193 9194 9195 9196 9197 9198 9199 9200 9201 9202 9203 9204 9205 9206 9207 9208 9209 9210 9211 9212 9213 9214 9215 9216 9217 9218 9219 9220 9221 9222 9223 9224 9225 9226 9227 9228 9229 9230 9231 9232 9233 9234 9235 9236 9237 9238 9239 9240 9241 9242 9243 9244 9245 9246 9247 9248 9249 9250 9251 9252 9253 9254 9255 9256 9257 9258 9259 9260 9261 9262 9263 9264 9265 9266 9267 9268 9269 9270 9271 9272 9273 9274 9275 9276 9277 9278 9279 9280 9281 9282 9283 9284 9285 9286 9287 9288 9289 9290 9291 9292 9293 9294 9295 9296 9297 9298 9299 9300 9301 9302 9303 9304 9305 9306 9307 9308 9309 9310 9311 9312 9313 9314 9315 9316 9317 9318 9319 9320 9321 9322 9323 9324 9325 9326 9327 9328 9329 9330 9331 9332 9333 9334 9335 9336 9337 9338 9339 9340 9341 9342 9343 9344 9345 9346 9347 9348 9349 9350 9351 9352 9353 9354 9355 9356 9357 9358 9359 9360 9361 9362 9363 9364 9365 9366 9367 9368 9369 9370 9371 9372 9373 9374 9375 9376 9377 9378 9379 9380 9381 9382 9383 9384 9385 9386 9387 9388 9389 9390 9391 9392 9393 9394 9395 9396 9397 9398 9399 9400 9401 9402 9403 9404 9405 9406 9407 9408 9409 9410 9411 9412 9413 9414 9415 9416 9417 9418 9419 9420 9421 9422 9423 9424 9425 9426 9427 9428 9429 9430 9431 9432 9433 9434 9435 9436 9437 9438 9439 9440 9441 9442 9443 9444 9445 9446 9447 9448 9449 9450 9451 9452 9453 9454 9455 9456 9457 9458 9459 9460 9461 9462 9463 9464 9465 9466 9467 9468 9469 9470 9471 9472 9473 9474 9475 9476 9477 9478 9479 9480 9481 9482 9483 9484 9485 9486 9487 9488 9489 9490 9491 9492 9493 9494 9495 9496 9497 9498 9499 9500 9501 9502 9503 9504 9505 9506 9507 9508 9509 9510 9511 9512 9513 9514 9515 9516 9517 9518 9519 9520 9521 9522 9523 9524 9525 9526 9527 9528 9529 9530 9531 9532 9533 9534 9535 9536 9537 9538 9539 9540 9541 9542 9543 9544 9545 9546 9547 9548 9549 9550 9551 9552 9553 9554 9555 9556 9557 9558 9559 9560 9561 9562 9563 9564 9565 9566 9567 9568 9569 9570 9571 9572 9573 9574 9575 9576 9577 9578 9579 9580 9581 9582 9583 9584 9585 9586 9587 9588 9589 9590 9591 9592 9593 9594 9595 9596 9597 9598 9599 9600 9601 9602 9603 9604 9605 9606 9607 9608 9609 9610 9611 9612 9613 9614 9615 9616 9617 9618 9619 9620 9621 9622 9623 9624 9625 9626 9627 9628 9629 9630 9631 9632 9633 9634 9635 9636 9637 9638 9639 9640 9641 9642 9643 9644 9645 9646 9647 9648 9649 9650 9651 9652 9653 9654 9655 9656 9657 9658 9659 9660 9661 9662 9663 9664 9665 9666 9667 9668 9669 9670 9671 9672 9673 9674 9675 9676 9677 9678 9679 9680 9681 9682 9683 9684 9685 9686 9687 9688 9689 9690 9691 9692 9693 9694 9695 9696 9697 9698 9699 9700 9701 9702 9703 9704 9705 9706 9707 9708 9709 9710 9711 9712 9713 9714 9715 9716 9717 9718 9719 9720 9721 9722 9723 9724 9725 9726 9727 9728 9729 9730 9731 9732 9733 9734 9735 9736 9737 9738 9739 9740 9741 9742 9743 9744 9745 9746 9747 9748 9749 9750 9751 9752 9753 9754 9755 9756 9757 9758 9759 9760 9761 9762 9763 9764 9765 9766 9767 9768 9769 9770 9771 9772 9773 9774 9775 9776 9777 9778 9779 9780 9781 9782 9783 9784 9785 9786 9787 9788 9789 9790 9791 9792 9793 9794 9795 9796 9797 9798 9799 9800 9801 9802 9803 9804 9805 9806 9807 9808 9809 9810 9811 9812 9813 9814 9815 9816 9817 9818 9819 9820 9821 9822 9823 9824 9825 9826 9827 9828 9829 9830 9831 9832 9833 9834 9835 9836 9837 9838 9839 9840 9841 9842 9843 9844 9845 9846 9847 9848 9849 9850 9851 9852 9853 9854 9855 9856 9857 9858 9859 9860 9861 9862 9863 9864 9865 9866 9867 9868 9869 9870 9871 9872 9873 9874 9875 9876 9877 9878 9879 9880 9881 9882 9883 9884 9885 9886 9887 9888 9889 9890 9891 9892 9893 9894 9895 9896 9897 9898 9899 9900 9901 9902 9903 9904 9905 9906 9907 9908 9909 9910 9911 9912 9913 9914 9915 9916 9917 9918 9919 9920 9921 9922 9923 9924 9925 9926 9927 9928 9929 9930 9931 9932 9933 9934 9935 9936 9937 9938 9939 9940 9941 9942 9943 9944 9945 9946 9947 9948 9949 9950 9951 9952 9953 9954 9955 9956 9957 9958 9959 9960 9961 9962 9963 9964 9965 9966 9967 9968 9969 9970 9971 9972 9973 9974 9975 9976 9977 9978 9979 9980 9981 9982 9983 9984 9985 9986 9987 9988 9989 9990 9991 9992 9993 9994 9995 9996 9997 9998 9999 10000 10001 10002 10003 10004 10005 10006 10007 10008 10009 10010 10011 10012 10013 10014 10015 10016 10017 10018 10019 10020 10021 10022 10023 10024 10025 10026 10027 10028 10029 10030 10031 10032 10033 10034 10035 10036 10037 10038 10039 10040 10041 10042 10043 10044 10045 10046 10047 10048 10049 10050 10051 10052 10053 10054 10055 10056 10057 10058 10059 10060 10061 10062 10063 10064 10065 10066 10067 10068 10069 10070 10071 10072 10073 10074 10075 10076 10077 10078 10079 10080 10081 10082 10083 10084 10085 10086 10087 10088 10089 10090 10091 10092 10093 10094 10095 10096 10097 10098 10099 10100 10101 10102 10103 10104 10105 10106 10107 10108 10109 10110 10111 10112 10113 10114 10115 10116 10117 10118 10119 10120 10121 10122 10123 10124 10125 10126 10127 10128 10129 10130 10131 10132 10133 10134 10135 10136 10137 10138 10139 10140 10141 10142 10143 10144 10145 10146 10147 10148 10149 10150 10151 10152 10153 10154 10155 10156 10157 10158 10159 10160 10161 10162 10163 10164 10165 10166 10167 10168 10169 10170 10171 10172 10173 10174 10175 10176 10177 10178 10179 10180 10181 10182 10183 10184 10185 10186 10187 10188 10189 10190 10191 10192 10193 10194 10195 10196 10197 10198 10199 10200 10201 10202 10203 10204 10205 10206 10207 10208 10209 10210 10211 10212 10213 10214 10215 10216 10217 10218 10219 10220 10221 10222 10223 10224 10225 10226 10227 10228 10229 10230 10231 10232 10233 10234 10235 10236 10237 10238 10239 10240 10241 10242 10243 10244 10245 10246 10247 10248 10249 10250 10251 10252 10253 10254 10255 10256 10257 10258 10259 10260 10261 10262 10263 10264 10265 10266 10267 10268 10269 10270 10271 10272 10273 10274 10275 10276 10277 10278 10279 10280 10281 10282 10283 10284 10285 10286 10287 10288 10289 10290 10291 10292 10293 10294 10295 10296 10297 10298 10299 10300 10301 10302 10303 10304 10305 10306 10307 10308 10309 10310 10311 10312 10313 10314 10315 10316 10317 10318 10319 10320 10321 10322 10323 10324 10325 10326 10327 10328 10329 10330 10331 10332 10333 10334 10335 10336 10337 10338 10339 10340 10341 10342 10343 10344 10345 10346 10347 10348 10349 10350 10351 10352 10353 10354 10355 10356 10357 10358 10359 10360 10361 10362 10363 10364 10365 10366 10367 10368 10369 10370 10371 10372 10373 10374 10375 10376 10377 10378 10379 10380 10381 10382 10383 10384 10385 10386 10387 10388 10389 10390 10391 10392 10393 10394 10395 10396 10397 10398 10399 10400 10401 10402 10403 10404 10405 10406 10407 10408 10409 10410 10411 10412 10413 10414 10415 10416 10417 10418 10419 10420 10421 10422 10423 10424 10425 10426 10427 10428 10429 10430 10431 10432 10433 10434 10435 10436 10437 10438 10439 10440 10441 10442 10443 10444 10445 10446 10447 10448 10449 10450 10451 10452 10453 10454 10455 10456 10457 10458 10459 10460 10461 10462 10463 10464 10465 10466 10467 10468 10469 10470 10471 10472 10473 10474 10475 10476 10477 10478 10479 10480 10481 10482 10483 10484 10485 10486 10487 10488 10489 10490 10491 10492 10493 10494 10495 10496 10497 10498 10499 10500 10501 10502 10503 10504 10505 10506 10507 10508 10509 10510 10511 10512 10513 10514 10515 10516 10517 10518 10519 10520 10521 10522 10523 10524 10525 10526 10527 10528 10529 10530 10531 10532 10533 10534 10535 10536 10537 10538 10539 10540 10541 10542 10543 10544 10545 10546 10547 10548 10549 10550 10551 10552 10553 10554 10555 10556 10557 10558 10559 10560 10561 10562 10563 10564 10565 10566 10567 10568 10569 10570 10571 10572 10573 10574 10575 10576 10577 10578 10579 10580 10581 10582 10583 10584 10585 10586 10587 10588 10589 10590 10591 10592 10593 10594 10595 10596 10597 10598 10599 10600 10601 10602 10603 10604 10605 10606 10607 10608 10609 10610 10611 10612 10613 10614 10615 10616 10617 10618 10619 10620 10621 10622 10623 10624 10625 10626 10627 10628 10629 10630 10631 10632 10633 10634 10635 10636 10637 10638 10639 10640 10641 10642 10643 10644 10645 10646 10647 10648 10649 10650 10651 10652 10653 10654 10655 10656 10657 10658 10659 10660 10661 10662 10663 10664 10665 10666 10667 10668 10669 10670 10671 10672 10673 10674 10675 10676 10677 10678 10679 10680 10681 10682 10683 10684 10685 10686 10687 10688 10689 10690 10691 10692 10693 10694 10695 10696 10697 10698 10699 10700 10701 10702 10703 10704 10705 10706 10707 10708 10709 10710 10711 10712 10713 10714 10715 10716 10717 10718 10719 10720 10721 10722 10723 10724 10725 10726 10727 10728 10729 10730 10731 10732 10733 10734 10735 10736 10737 10738 10739 10740 10741 10742 10743 10744 10745 10746 10747 10748 10749 10750 10751 10752 10753 10754 10755 10756 10757 10758 10759 10760 10761 10762 10763 10764 10765 10766 10767 10768 10769 10770 10771 10772 10773 10774 10775 10776 10777 10778 10779 10780 10781 10782 10783 10784 10785 10786 10787 10788 10789 10790 10791 10792 10793 10794 10795 10796 10797 10798 10799 10800 10801 10802 10803 10804 10805 10806 10807 10808 10809 10810 10811 10812 10813 10814 10815 10816 10817 10818 10819 10820 10821 10822 10823 10824 10825 10826 10827 10828 10829 10830 10831 10832 10833 10834 10835 10836 10837 10838 10839 10840 10841 10842 10843 10844 10845 10846 10847 10848 10849 10850 10851 10852 10853 10854 10855 10856 10857 10858 10859 10860 10861 10862 10863 10864 10865 10866 10867 10868 10869 10870 10871 10872 10873 10874 10875 10876 10877 10878 10879 10880 10881 10882 10883 10884 10885 10886 10887 10888 10889 10890 10891 10892 10893 10894 10895 10896 10897 10898 10899 10900 10901 10902 10903 10904 10905 10906 10907 10908 10909 10910 10911 10912 10913 10914 10915 10916 10917 10918 10919 10920 10921 10922 10923 10924 10925 10926 10927 10928 10929 10930 10931 10932 10933 10934 10935 10936 10937 10938 10939 10940 10941 10942 10943 10944 10945 10946 10947 10948 10949 10950 10951 10952 10953 10954 10955 10956 10957 10958 10959 10960 10961 10962 10963 10964 10965 10966 10967 10968 10969 10970 10971 10972 10973 10974 10975 10976 10977 10978 10979 10980 10981 10982 10983 10984 10985 10986 10987 10988 10989 10990 10991 10992 10993 10994 10995 10996 10997 10998 10999 11000 11001 11002 11003 11004 11005 11006 11007 11008 11009 11010 11011 11012 11013 11014 11015 11016 11017 11018 11019 11020 11021 11022 11023 11024 11025 11026 11027 11028 11029 11030 11031 11032 11033 11034 11035 11036 11037 11038 11039 11040 11041 11042 11043 11044 11045 11046 11047 11048 11049 11050 11051 11052 11053 11054 11055 11056 11057 11058 11059 11060 11061 11062 11063 11064 11065 11066 11067 11068 11069 11070 11071 11072 11073 11074 11075 11076 11077 11078 11079 11080 11081 11082 11083 11084 11085 11086 11087 11088 11089 11090 11091 11092 11093 11094 11095 11096 11097 11098 11099 11100 11101 11102 11103 11104 11105 11106 11107 11108 11109 11110 11111 11112 11113 11114 11115 11116 11117 11118 11119 11120 11121 11122 11123 11124 11125 11126 11127 11128 11129 11130 11131 11132 11133 11134 11135 11136 11137 11138 11139 11140 11141 11142 11143 11144 11145 11146 11147 11148 11149 11150 11151 11152 11153 11154 11155 11156 11157 11158 11159 11160 11161 11162 11163 11164 11165 11166 11167 11168 11169 11170 11171 11172 11173 11174 11175 11176 11177 11178 11179 11180 11181 11182 11183 11184 11185 11186 11187 11188 11189 11190 11191 11192 11193 11194 11195 11196 11197 11198 11199 11200 11201 11202 11203 11204 11205 11206 11207 11208 11209 11210 11211 11212 11213 11214 11215 11216 11217 11218 11219 11220 11221 11222 11223 11224 11225 11226 11227 11228 11229 11230 11231 11232 11233 11234 11235 11236 11237 11238 11239 11240 11241 11242 11243 11244 11245 11246 11247 11248 11249 11250 11251 11252 11253 11254 11255 11256 11257 11258 11259 11260 11261 11262 11263 11264 11265 11266 11267 11268 11269 11270 11271 11272 11273 11274 11275 11276 11277 11278 11279 11280 11281 11282 11283 11284 11285 11286 11287 11288 11289 11290 11291 11292 11293 11294 11295 11296 11297 11298 11299 11300 11301 11302 11303 11304 11305 11306 11307 11308 11309 11310 11311 11312 11313 11314 11315 11316 11317 11318 11319 11320 11321 11322 11323 11324 11325 11326 11327 11328 11329 11330 11331 11332 11333 11334 11335 11336 11337 11338 11339 11340 11341 11342 11343 11344 11345 11346 11347 11348 11349 11350 11351 11352 11353 11354 11355 11356 11357 11358 11359 11360 11361 11362 11363 11364 11365 11366 11367 11368 11369 11370 11371 11372 11373 11374 11375 11376 11377 11378 11379 11380 11381 11382 11383 11384 11385 11386 11387 11388 11389 11390 11391 11392 11393 11394 11395 11396 11397 11398 11399 11400 11401 11402 11403 11404 11405 11406 11407 11408 11409 11410 11411 11412 11413 11414 11415 11416 11417 11418 11419 11420 11421 11422 11423 11424 11425 11426 11427 11428 11429 11430 11431 11432 11433 11434 11435 11436 11437 11438 11439 11440 11441 11442 11443 11444 11445 11446 11447 11448 11449 11450 11451 11452 11453 11454 11455 11456 11457 11458 11459 11460 11461 11462 11463 11464 11465 11466 11467 11468 11469 11470 11471 11472 11473 11474 11475 11476 11477 11478 11479 11480 11481 11482 11483 11484 11485 11486 11487 11488 11489 11490 11491 11492 11493 11494 11495 11496 11497 11498 11499 11500 11501 11502 11503 11504 11505 11506 11507 11508 11509 11510 11511 11512 11513 11514 11515 11516 11517 11518 11519 11520 11521 11522 11523 11524 11525 11526 11527 11528 11529 11530 11531 11532 11533 11534 11535 11536 11537 11538 11539 11540 11541 11542 11543 11544 11545 11546 11547 11548 11549 11550 11551 11552 11553 11554 11555 11556 11557 11558 11559 11560 11561 11562 11563 11564 11565 11566 11567 11568 11569 11570 11571 11572 11573 11574 11575 11576 11577 11578 11579 11580 11581 11582 11583 11584 11585 11586 11587 11588 11589 11590 11591 11592 11593 11594 11595 11596 11597 11598 11599 11600 11601 11602 11603 11604 11605 11606 11607 11608 11609 11610 11611 11612 11613 11614 11615 11616 11617 11618 11619 11620 11621 11622 11623 11624 11625 11626 11627 11628 11629 11630 11631 11632 11633 11634 11635 11636 11637 11638 11639 11640 11641 11642 11643 11644 11645 11646 11647 11648 11649 11650 11651 11652 11653 11654 11655 11656 11657 11658 11659 11660 11661 11662 11663 11664 11665 11666 11667 11668 11669 11670 11671 11672 11673 11674 11675 11676 11677 11678 11679 11680 11681 11682 11683 11684 11685 11686 11687 11688 11689 11690 11691 11692 11693 11694 11695 11696 11697 11698 11699 11700 11701 11702 11703 11704 11705 11706 11707 11708 11709 11710 11711 11712 11713 11714 11715 11716 11717 11718 11719 11720 11721 11722 11723 11724 11725 11726 11727 11728 11729 11730 11731 11732 11733 11734 11735 11736 11737 11738 11739 11740 11741 11742 11743 11744 11745 11746 11747 11748 11749 11750 11751 11752 11753 11754 11755 11756 11757 11758 11759 11760 11761 11762 11763 11764 11765 11766 11767 11768 11769 11770 11771 11772

审计通常提供以下信息:

* 这一纪录是什么时候创造的?

* 触发审计事件的用户的名称(如果启用了安全性)

* 审计操作(计划、流程或任务)

* 执行的操作(创建、删除、部署、回滚、取消部署或更新)

* 相关 ID,例如流或任务名

* 审计数据

*审计数据*属性的写入值取决于执行的*审计业务*和*动作类型*。例如,在创建调度时,任务定义、任务定义属性、部署属性和命令行参数的名称将写入持久性存储。

在保存审核记录之前,会以尽力而为的方式对敏感信息进行消毒。检测到以下任何一个键,并屏蔽了它们的敏感值:

* password

* 秘密

* 钥匙

* 令牌

* 。\* 凭证。\*

* VCAP\_ 服务

# 样本

这一节展示了可用的样本。

## 42. 链接

已经创建了几个示例,以帮助你开始实现比参考指南中所示的基本流和任务更高级别的用例。这些样本是单独的[repository](https://github.com/spring-cloud/spring-cloud-dataflow-samples)的一部分,并且有自己的[参考文献](https://docs.spring.io/spring-cloud-dataflow-samples/docs/current/reference/htmlsingle/)。

以下样品可供选择:

一般情况

* [Java DSL](https://docs.spring.io/spring-cloud-dataflow-samples/docs/current/reference/htmlsingle/#_java_dsl)

* [HTTP 到 Cassandra](https://docs.spring.io/spring-cloud-dataflow-samples/docs/current/reference/htmlsingle/#spring-cloud-data-flow-samples-http-cassandra-overview)

* [从 HTTP 到 MySQL](https://docs.spring.io/spring-cloud-dataflow-samples/docs/current/reference/htmlsingle/#_http_to_mysql_demo)

* [HTTP 到 Gemfire](https://docs.spring.io/spring-cloud-dataflow-samples/docs/current/reference/htmlsingle/#_http_to_gemfire_demo)

* [Gemfire CQ 到日志演示](https://docs.spring.io/spring-cloud-dataflow-samples/docs/current/reference/htmlsingle/#_gemfire_cq_to_log_demo)

* [Gemfire to Log 演示](https://docs.spring.io/spring-cloud-dataflow-samples/docs/current/reference/htmlsingle/#_gemfire_to_log_demo)

* [定制处理器](https://docs.spring.io/spring-cloud-dataflow-samples/docs/current/reference/htmlsingle/#_custom_spring_cloud_stream_processor)

任务和批处理

* [云铸造中的批处理作业](https://docs.spring.io/spring-cloud-dataflow-samples/docs/current/reference/htmlsingle/#_batch_job_on_cloud_foundry)

* [批处理文件摄取](https://docs.spring.io/spring-cloud-dataflow-samples/docs/current/reference/htmlsingle/#_batch_file_ingest)

数据科学

* [物种预测](https://docs.spring.io/spring-cloud-dataflow-samples/docs/current/reference/htmlsingle/#_species_prediction)

职能

* [Using Spring Cloud Function](https://docs.spring.io/spring-cloud-dataflow-samples/docs/current/reference/htmlsingle/#_functions_in_spring_cloud_data_flow)

# REST API 指南

本部分描述 Spring 云数据流 REST API。

## 43. 概述

Spring 云数据流提供了一个 REST API,该 API 允许你访问服务器的所有方面。实际上, Spring Cloud Data Flow shell 是该 API 的一流使用者。

|   |如果你计划在 Java 中使用 REST API,那么你应该考虑使用内部使用 REST API 的<br/>提供的 Java 客户机(`DataflowTemplate`)。|
|---|---------------------------------------------------------------------------------------------------------------------------------------------------------|

### 43.1.HTTP 动词

Spring 云数据流试图在其使用 HTTP 动词时尽可能紧密地坚持标准 HTTP 和 REST 约定,如下表所述:

|  Verb  |用法|
|--------|------------------------------------------------------------------------------------------------------------------------------------------------|
| `GET`  |用于检索资源。|
| `POST` |用于创建新资源。|
| `PUT`  |用于更新现有资源,包括部分更新。也用于<br/>暗示`restarts`概念的资源,如任务。|
|`DELETE`|用于删除现有资源。|

### 43.2.HTTP 状态代码

Spring 云数据流试图在其使用 HTTP 状态代码时尽可能紧密地坚持标准 HTTP 和 REST 约定,如下表所示:

|       Status code        |用法|
|--------------------------|--------------------------------------------------------------------------------------------------------------------|
|         `200 OK`         |请求已成功完成。|
|      `201 Created`       |成功地创建了一个新的资源。资源的 URI 可以从响应的`Location`头中获得。|
|     `204 No Content`     |已成功地应用了对现有资源的更新。|
|    `400 Bad Request`     |这一要求是错误的。响应体包括提供进一步信息的错误描述。|
|     `404 Not Found`      |所要求的资源不存在。|
|      `409 Conflict`      |请求的资源已经存在。例如,任务已经存在,或者流已经被部署了。|
|`422 Unprocessable Entity`|在无法停止或重新启动作业执行的情况下返回。|

### 43.3.标头

每个响应都有以下标题:

|     Name     |说明|
|--------------|------------------------------------------------------------|
|`Content-Type`|有效负载的内容类型,例如`application/hal+json`|

### 43.4.错误

|   Path    |  Type  |说明|
|-----------|--------|------------------------------------------------------|
|  `error`  |`String`|发生的 HTTP 错误,例如`Bad Request`|
| `message` |`String`|对错误原因的描述|
|  `path`   |`String`|提出请求的路径|
| `status`  |`Number`|HTTP 状态代码,例如`400`|
|`timestamp`|`String`|发生错误的时间(以毫秒为单位)|

### 43.5.超媒体

Spring 云数据流使用超媒体,并且资源在其响应中包括到其他资源的链接。回复为[从资源到资源语言的超文本应用程序(HAL)](http://stateless.co/hal_specification.html)格式。链接可以在`_links`键下找到。API 的用户不应该自己创建 URI。相反,他们应该使用上述链接来导航。

## 44. 资源

该 API 包括以下资源:

* [Index](#api-guide-resources-index)

* [服务器元信息](#resources-about)

* [审计记录](#api-guide-resources-audit-records)

* [已登记的申请](#resources-registered-applications)

* [流定义](#api-guide-resources-stream-definitions)

* [流部署](#api-guide-resources-stream-deployment)

* [流验证](#api-guide-resources-stream-validate)

* [任务定义](#api-guide-resources-task-definitions)

* [任务执行](#api-guide-resources-task-executions)

* [任务调度程序](#api-guide-resources-task-scheduler)

* [任务验证](#api-guide-resources-task-validate)

* [工作执行](#api-guide-resources-job-executions)

* [作业实例](#api-guide-resources-job-instances)

* [作业步执行](#api-guide-resources-job-step-executions)

* [有关应用程序的运行时信息](#api-guide-resources-runtime-information-applications)

* [流日志](#api-guide-resources-stream-logs)

* [Task Logs](#api-guide-resources-task-logs)

### 44.1.索引

该索引提供了进入 Spring 云数据流的 REST API 的入口点。以下主题提供了更多细节:

* [访问索引](#api-guide-resources-index-access)

* [请求结构](#api-guide-resources-index-request-structure)

* [示例请求](#api-guide-resources-index-example-request)

* [反应结构](#api-guide-resources-index-response-structure)

* [示例响应](#api-guide-resources-index-example-response)

* [链接](#api-guide-resources-index-links)

#### 44.1.1.访问索引

使用`GET`请求访问索引。

##### 请求结构

```
GET / HTTP/1.1
Host: localhost:9393
```

##### 示例请求

```
$ curl 'http://localhost:9393/' -i -X GET
```

##### 反应结构

|路径|  Type   |     说明     |
|-------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------|
|`_links`|`Object` |                              Links to other resources                              |
|`['api.revision']`|`Number` |           Incremented each time a change is implemented in this REST API           |
|`_links.audit-records.href`|`String` |                             Link to the audit records                              |
|`_links.dashboard.href`|`String` |                               Link to the dashboard                                |
|`_links.streams/definitions.href`|`String` |                          Link to the streams/definitions                           |
|`_links.streams/definitions/definition.href`|`String` |                     Link to the streams/definitions/definition                     |
|`_links.streams/definitions/definition.templated`|`Boolean`|                  Link streams/definitions/definition is templated                  |
|`_links.runtime/apps.href`|`String` |                              Link to the runtime/apps                              |
|`_links.runtime/apps/{appId}.href`|`String` |                          Link to the runtime/apps/{appId}                          |
|`_links.runtime/apps/{appId}.templated`|`Boolean`|                           Link runtime/apps is templated                           |
|`_links.runtime/apps/{appId}/instances.href`|`String` |                     Link to the runtime/apps/{appId}/instances                     |
|`_links.runtime/apps/{appId}/instances.templated`|`Boolean`|                  Link runtime/apps/{appId}/instances is templated                  |
|`_links.runtime/apps/{appId}/instances/{instanceId}.href`|`String` |              Link to the runtime/apps/{appId}/instances/{instanceId}               |
|`_links.runtime/apps/{appId}/instances/{instanceId}.templated`|`Boolean`|           Link runtime/apps/{appId}/instances/{instanceId} is templated            |
|`_links.runtime/streams.href`|`String` |                            Link to the runtime/streams                             |
|`_links.runtime/streams.templated`|`Boolean`|                         Link runtime/streams is templated                          |
|`_links.runtime/streams/{streamNames}.href`|`String` |                     Link to the runtime/streams/{streamNames}                      |
|`_links.runtime/streams/{streamNames}.templated`|`Boolean`|                  Link runtime/streams/{streamNames} is templated                   |
|`_links.streams/logs.href`|`String` |                              Link to the streams/logs                              |
|`_links.streams/logs/{streamName}.href`|`String` |                       Link to the streams/logs/{streamName}                        |
|`_links.streams/logs/{streamName}/{appName}.href`|`String` |                  Link to the streams/logs/{streamName}/{appName}                   |
|`_links.streams/logs/{streamName}.templated`|`Boolean`|                    Link streams/logs/{streamName} is templated                     |
|`_links.streams/logs/{streamName}/{appName}.templated`|`Boolean`|               Link streams/logs/{streamName}/{appName} is templated                |
|`_links.streams/deployments`|`Object` |                            Link to streams/deployments                             |
|`_links.streams/deployments.href`|`String` |                            Link to streams/deployments                             |
|`_links.streams/deployments/{name}`|`Object` |                    Link streams/deployments/{name} is templated                    |
|`_links.streams/deployments/{name}.href`|`String` |                    Link streams/deployments/{name} is templated                    |
|`_links.streams/deployments/{name}.templated`|`Boolean`|                    Link streams/deployments/{name} is templated                    |
|`_links.streams/deployments/{name}{?reuse-deployment-properties}.href`|`String` |                    Link streams/deployments/{name} is templated                    |
|`_links.streams/deployments/{name}{?reuse-deployment-properties}.templated`|`Boolean`|                    Link streams/deployments/{name} is templated                    |
|`_links.streams/deployments/deployment.href`|`String` |                     Link to the streams/deployments/deployment                     |
|`_links.streams/deployments/deployment.templated`|`Boolean`|                  Link streams/deployments/deployment is templated                  |
|`_links.streams/deployments/manifest/{name}/{version}.href`|`String` |             Link to the streams/deployments/manifest/{name}/{version}              |
|`_links.streams/deployments/manifest/{name}/{version}.templated`|`Boolean`|          Link streams/deployments/manifest/{name}/{version} is templated           |
|`_links.streams/deployments/history/{name}.href`|`String` |                   Link to the streams/deployments/history/{name}                   |
|`_links.streams/deployments/history/{name}.templated`|`Boolean`|                   Link streams/deployments/history is templated                    |
|`_links.streams/deployments/rollback/{name}/{version}.href`|`String` |             Link to the streams/deployments/rollback/{name}/{version}              |
|`_links.streams/deployments/rollback/{name}/{version}.templated`|`Boolean`|          Link streams/deployments/rollback/{name}/{version} is templated           |
|`_links.streams/deployments/update/{name}.href`|`String` |                   Link to the streams/deployments/update/{name}                    |
|`_links.streams/deployments/update/{name}.templated`|`Boolean`|                Link streams/deployments/update/{name} is templated                 |
|`_links.streams/deployments/platform/list.href`|`String` |                   Link to the streams/deployments/platform/list                    |
|`_links.streams/deployments/scale/{streamName}/{appName}/instances/{count}.href`|`String` |   Link to the streams/deployments/scale/{streamName}/{appName}/instances/{count}   |
|`_links.streams/deployments/scale/{streamName}/{appName}/instances/{count}.templated`|`Boolean`|Link streams/deployments/scale/{streamName}/{appName}/instances/{count} is templated|
|`_links.streams/validation.href`|`String` |                           Link to the streams/validation                           |
|`_links.streams/validation.templated`|`Boolean`|                        Link streams/validation is templated                        |
|`_links.tasks/platforms.href`|`String` |                            Link to the tasks/platforms                             |
|`_links.tasks/definitions.href`|`String` |                           Link to the tasks/definitions                            |
|`_links.tasks/definitions/definition.href`|`String` |                      Link to the tasks/definitions/definition                      |
|`_links.tasks/definitions/definition.templated`|`Boolean`|                   Link tasks/definitions/definition is templated                   |
|`_links.tasks/executions.href`|`String` |                            Link to the tasks/executions                            |
|`_links.tasks/executions/name.href`|`String` |                         Link to the tasks/executions/name                          |
|`_links.tasks/executions/name.templated`|`Boolean`|                      Link tasks/executions/name is templated                       |
|`_links.tasks/executions/current.href`|`String` |                        Link to the tasks/executions/current                        |
|`_links.tasks/executions/execution.href`|`String` |                       Link to the tasks/executions/execution                       |
|`_links.tasks/executions/execution.templated`|`Boolean`|                    Link tasks/executions/execution is templated                    |
|`_links.tasks/info/executions.href`|`String` |                         Link to the tasks/info/executions                          |
|`_links.tasks/info/executions.templated`|`Boolean`|                            Link tasks/info is templated                            |
|`_links.tasks/logs.href`|`String` |                               Link to the tasks/logs                               |
|`_links.tasks/logs.templated`|`Boolean`|                            Link tasks/logs is templated                            |
|`_links.tasks/schedules.href`|`String` |                       Link to the tasks/executions/schedules                       |
|`_links.tasks/schedules/instances.href`|`String` |                       Link to the tasks/schedules/instances                        |
|`_links.tasks/schedules/instances.templated`|`Boolean`|                    Link tasks/schedules/instances is templated                     |
|`_links.tasks/validation.href`|`String` |                            Link to the tasks/validation                            |
|`_links.tasks/validation.templated`|`Boolean`|                         Link tasks/validation is templated                         |
|`_links.jobs/executions.href`|`String` |                            Link to the jobs/executions                             |
|`_links.jobs/thinexecutions.href`|`String` |                          Link to the jobs/thinexecutions                           |
|`_links.jobs/executions/name.href`|`String` |                          Link to the jobs/executions/name                          |
|`_links.jobs/executions/name.templated`|`Boolean`|                       Link jobs/executions/name is templated                       |
|`_links.jobs/executions/status.href`|`String` |                         Link to the jobs/executions/status                         |
|`_links.jobs/executions/status.templated`|`Boolean`|                      Link jobs/executions/status is templated                      |
|`_links.jobs/thinexecutions/name.href`|`String` |                        Link to the jobs/thinexecutions/name                        |
|`_links.jobs/thinexecutions/name.templated`|`Boolean`|                       Link jobs/executions/name is templated                       |
|`_links.jobs/thinexecutions/jobInstanceId.href`|`String` |                   Link to the jobs/thinexecutions/jobInstanceId                    |
|`_links.jobs/thinexecutions/jobInstanceId.templated`|`Boolean`|                  Link jobs/executions/jobInstanceId is templated                   |
|`_links.jobs/thinexecutions/taskExecutionId.href`|`String` |                  Link to the jobs/thinexecutions/taskExecutionId                   |
|`_links.jobs/thinexecutions/taskExecutionId.templated`|`Boolean`|                 Link jobs/executions/taskExecutionId is templated                  |
|`_links.jobs/executions/execution.href`|`String` |                       Link to the jobs/executions/execution                        |
|`_links.jobs/executions/execution.templated`|`Boolean`|                    Link jobs/executions/execution is templated                     |
|`_links.jobs/executions/execution/steps.href`|`String` |                    Link to the jobs/executions/execution/steps                     |
|`_links.jobs/executions/execution/steps.templated`|`Boolean`|                 Link jobs/executions/execution/steps is templated                  |
|`_links.jobs/executions/execution/steps/step.href`|`String` |                  Link to the jobs/executions/execution/steps/step                  |
|`_links.jobs/executions/execution/steps/step.templated`|`Boolean`|               Link jobs/executions/execution/steps/step is templated               |
|`_links.jobs/executions/execution/steps/step/progress.href`|`String` |             Link to the jobs/executions/execution/steps/step/progress              |
|`_links.jobs/executions/execution/steps/step/progress.templated`|`Boolean`|          Link jobs/executions/execution/steps/step/progress is templated           |
|`_links.jobs/instances/name.href`|`String` |                          Link to the jobs/instances/name                           |
|`_links.jobs/instances/name.templated`|`Boolean`|                       Link jobs/instances/name is templated                        |
|`_links.jobs/instances/instance.href`|`String` |                        Link to the jobs/instances/instance                         |
|`_links.jobs/instances/instance.templated`|`Boolean`|                     Link jobs/instances/instance is templated                      |
|`_links.tools/parseTaskTextToGraph.href`|`String` |                       Link to the tools/parseTaskTextToGraph                       |
|`_links.tools/convertTaskGraphToText.href`|`String` |                      Link to the tools/convertTaskGraphToText                      |
|`_links.apps.href`|`String` |                                  Link to the apps                                  |
|`_links.about.href`|`String` |                                 Link to the about                                  |
|`_links.completions/stream.href`|`String` |                           Link to the completions/stream                           |
|`_links.completions/stream.templated`|`Boolean`|                        Link completions/stream is templated                        |
|`_links.completions/task.href`|`String` |                            Link to the completions/task                            |
|`_links.completions/task.templated`|`Boolean`|                         Link completions/task is templated                         |

##### 示例响应

```
HTTP/1.1 200 OK
Content-Type: application/hal+json
Content-Length: 7064

{
  "_links" : {
    "dashboard" : {
      "href" : "http://localhost:9393/dashboard"
    },
    "audit-records" : {
      "href" : "http://localhost:9393/audit-records"
    },
    "streams/definitions" : {
      "href" : "http://localhost:9393/streams/definitions"
    },
    "streams/definitions/definition" : {
      "href" : "http://localhost:9393/streams/definitions/{name}",
      "templated" : true
    },
    "streams/validation" : {
      "href" : "http://localhost:9393/streams/validation/{name}",
      "templated" : true
    },
    "runtime/streams" : {
      "href" : "http://localhost:9393/runtime/streams{?names}",
      "templated" : true
    },
    "runtime/streams/{streamNames}" : {
      "href" : "http://localhost:9393/runtime/streams/{streamNames}",
      "templated" : true
    },
    "runtime/apps" : {
      "href" : "http://localhost:9393/runtime/apps"
    },
    "runtime/apps/{appId}" : {
      "href" : "http://localhost:9393/runtime/apps/{appId}",
      "templated" : true
    },
    "runtime/apps/{appId}/instances" : {
      "href" : "http://localhost:9393/runtime/apps/{appId}/instances",
      "templated" : true
    },
    "runtime/apps/{appId}/instances/{instanceId}" : {
      "href" : "http://localhost:9393/runtime/apps/{appId}/instances/{instanceId}",
      "templated" : true
    },
    "streams/deployments" : {
      "href" : "http://localhost:9393/streams/deployments"
    },
    "streams/deployments/{name}{?reuse-deployment-properties}" : {
      "href" : "http://localhost:9393/streams/deployments/{name}?reuse-deployment-properties=false",
      "templated" : true
    },
    "streams/deployments/{name}" : {
      "href" : "http://localhost:9393/streams/deployments/{name}",
      "templated" : true
    },
    "streams/deployments/history/{name}" : {
      "href" : "http://localhost:9393/streams/deployments/history/{name}",
      "templated" : true
    },
    "streams/deployments/manifest/{name}/{version}" : {
      "href" : "http://localhost:9393/streams/deployments/manifest/{name}/{version}",
      "templated" : true
    },
    "streams/deployments/platform/list" : {
      "href" : "http://localhost:9393/streams/deployments/platform/list"
    },
    "streams/deployments/rollback/{name}/{version}" : {
      "href" : "http://localhost:9393/streams/deployments/rollback/{name}/{version}",
      "templated" : true
    },
    "streams/deployments/update/{name}" : {
      "href" : "http://localhost:9393/streams/deployments/update/{name}",
      "templated" : true
    },
    "streams/deployments/deployment" : {
      "href" : "http://localhost:9393/streams/deployments/{name}",
      "templated" : true
    },
    "streams/deployments/scale/{streamName}/{appName}/instances/{count}" : {
      "href" : "http://localhost:9393/streams/deployments/scale/{streamName}/{appName}/instances/{count}",
      "templated" : true
    },
    "streams/logs" : {
      "href" : "http://localhost:9393/streams/logs"
    },
    "streams/logs/{streamName}" : {
      "href" : "http://localhost:9393/streams/logs/{streamName}",
      "templated" : true
    },
    "streams/logs/{streamName}/{appName}" : {
      "href" : "http://localhost:9393/streams/logs/{streamName}/{appName}",
      "templated" : true
    },
    "tasks/platforms" : {
      "href" : "http://localhost:9393/tasks/platforms"
    },
    "tasks/definitions" : {
      "href" : "http://localhost:9393/tasks/definitions"
    },
    "tasks/definitions/definition" : {
      "href" : "http://localhost:9393/tasks/definitions/{name}",
      "templated" : true
    },
    "tasks/executions" : {
      "href" : "http://localhost:9393/tasks/executions"
    },
    "tasks/executions/name" : {
      "href" : "http://localhost:9393/tasks/executions{?name}",
      "templated" : true
    },
    "tasks/executions/current" : {
      "href" : "http://localhost:9393/tasks/executions/current"
    },
    "tasks/executions/execution" : {
      "href" : "http://localhost:9393/tasks/executions/{id}",
      "templated" : true
    },
    "tasks/validation" : {
      "href" : "http://localhost:9393/tasks/validation/{name}",
      "templated" : true
    },
    "tasks/info/executions" : {
      "href" : "http://localhost:9393/tasks/info/executions{?completed,name}",
      "templated" : true
    },
    "tasks/logs" : {
      "href" : "http://localhost:9393/tasks/logs/{taskExternalExecutionId}{?platformName}",
      "templated" : true
    },
    "tasks/schedules" : {
      "href" : "http://localhost:9393/tasks/schedules"
    },
    "tasks/schedules/instances" : {
      "href" : "http://localhost:9393/tasks/schedules/instances/{taskDefinitionName}",
      "templated" : true
    },
    "jobs/executions" : {
      "href" : "http://localhost:9393/jobs/executions"
    },
    "jobs/executions/name" : {
      "href" : "http://localhost:9393/jobs/executions{?name}",
      "templated" : true
    },
    "jobs/executions/status" : {
      "href" : "http://localhost:9393/jobs/executions{?status}",
      "templated" : true
    },
    "jobs/executions/execution" : {
      "href" : "http://localhost:9393/jobs/executions/{id}",
      "templated" : true
    },
    "jobs/executions/execution/steps" : {
      "href" : "http://localhost:9393/jobs/executions/{jobExecutionId}/steps",
      "templated" : true
    },
    "jobs/executions/execution/steps/step" : {
      "href" : "http://localhost:9393/jobs/executions/{jobExecutionId}/steps/{stepId}",
      "templated" : true
    },
    "jobs/executions/execution/steps/step/progress" : {
      "href" : "http://localhost:9393/jobs/executions/{jobExecutionId}/steps/{stepId}/progress",
      "templated" : true
    },
    "jobs/instances/name" : {
      "href" : "http://localhost:9393/jobs/instances{?name}",
      "templated" : true
    },
    "jobs/instances/instance" : {
      "href" : "http://localhost:9393/jobs/instances/{id}",
      "templated" : true
    },
    "tools/parseTaskTextToGraph" : {
      "href" : "http://localhost:9393/tools"
    },
    "tools/convertTaskGraphToText" : {
      "href" : "http://localhost:9393/tools"
    },
    "jobs/thinexecutions" : {
      "href" : "http://localhost:9393/jobs/thinexecutions"
    },
    "jobs/thinexecutions/name" : {
      "href" : "http://localhost:9393/jobs/thinexecutions{?name}",
      "templated" : true
    },
    "jobs/thinexecutions/jobInstanceId" : {
      "href" : "http://localhost:9393/jobs/thinexecutions{?jobInstanceId}",
      "templated" : true
    },
    "jobs/thinexecutions/taskExecutionId" : {
      "href" : "http://localhost:9393/jobs/thinexecutions{?taskExecutionId}",
      "templated" : true
    },
    "apps" : {
      "href" : "http://localhost:9393/apps"
    },
    "about" : {
      "href" : "http://localhost:9393/about"
    },
    "completions/stream" : {
      "href" : "http://localhost:9393/completions/stream{?start,detailLevel}",
      "templated" : true
    },
    "completions/task" : {
      "href" : "http://localhost:9393/completions/task{?start,detailLevel}",
      "templated" : true
    }
  },
  "api.revision" : 14
}
```

##### Links

索引的主要元素是链接,因为它们允许你遍历 API 并执行所需的功能:

|                              Relation                              |说明|
|--------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|                              `about`                               |访问元信息,包括已启用的功能、安全信息、版本信息|
|                            `dashboard`                             |访问仪表板 UI|
|                          `audit-records`                           |提供审计跟踪信息|
|                               `apps`                               |处理已登记的申请|
|                        `completions/stream`                        |公开 Stream 的 DSL 完成功能|
|                         `completions/task`                         |公开任务的 DSL 完成功能|
|                         `jobs/executions`                          |提供 JobExecution 资源|
|                       `jobs/thinexecutions`                        |提供不包含步骤执行的 JobExecution 瘦资源|
|                    `jobs/executions/execution`                     |提供特定作业执行的详细信息|
|                 `jobs/executions/execution/steps`                  |提供作业执行的步骤|
|               `jobs/executions/execution/steps/step`               |返回特定步骤的详细信息|
|          `jobs/executions/execution/steps/step/progress`           |提供特定步骤的进度信息|
|                       `jobs/executions/name`                       |按作业名称检索作业执行|
|                      `jobs/executions/status`                      |按作业状态检索作业执行|
|                     `jobs/thinexecutions/name`                     |按作业名检索作业执行,不包括步骤执行|
|                `jobs/thinexecutions/jobInstanceId`                 |通过不包含步骤执行的作业实例 ID 检索作业执行|
|               `jobs/thinexecutions/taskExecutionId`                |通过不包含步骤执行的任务执行 ID 检索作业执行|
|                     `jobs/instances/instance`                      |为特定的作业实例提供作业实例资源|
|                       `jobs/instances/name`                        |为特定的作业名称提供作业实例资源|
|                         `runtime/streams`                          |公开流运行时状态|
|                  `runtime/streams/{streamNames}`                   |公开给定流名称的流运行时状态|
|                           `runtime/apps`                           |提供运行时应用程序资源|
|                       `runtime/apps/{appId}`                       |公开特定应用程序的运行时状态|
|                  `runtime/apps/{appId}/instances`                  |提供应用程序实例的状态|
|           `runtime/apps/{appId}/instances/{instanceId}`            |提供特定应用程序实例的状态|
|                        `tasks/definitions`                         |提供任务定义资源|
|                   `tasks/definitions/definition`                   |提供特定任务定义的详细信息|
|                         `tasks/validation`                         |提供任务定义的验证|
|                         `tasks/executions`                         |返回任务执行并允许启动任务|
|                     `tasks/executions/current`                     |提供正在运行的任务的当前计数|
|                      `tasks/info/executions`                       |提供任务执行信息|
|                         `tasks/schedules`                          |提供任务的进度信息|
|                    `tasks/schedules/instances`                     |提供特定任务的进度信息|
|                      `tasks/executions/name`                       |返回给定任务名的所有任务执行|
|                    `tasks/executions/execution`                    |提供特定任务执行的详细信息|
|                         `tasks/platforms`                          |提供用于启动任务的平台帐户。通过添加一个请求参数“SchedulesEnabled=True”,可以对结果进行筛选,以显示支持调度的平台。|
|                            `tasks/logs`                            |检索任务应用程序日志|
|                       `streams/definitions`                        |公开 Streams 资源|
|                  `streams/definitions/definition`                  |处理特定的流定义|
|                        `streams/validation`                        |提供流定义的验证|
|                       `streams/deployments`                        |提供流部署操作|
|                    `streams/deployments/{name}`                    |请求流定义的部署信息|
|     `streams/deployments/{name}{?reuse-deployment-properties}`     |请求流定义的部署信息|
|                  `streams/deployments/deployment`                  |请求(非)部署现有的流定义|
|          `streams/deployments/manifest/{name}/{version}`           |返回发布版本的清单信息|
|                `streams/deployments/history/{name}`                |将 Stream 的部署历史记录作为此版本的一个或多个版本的列表获取|
|          `streams/deployments/rollback/{name}/{version}`           |将流回滚到流的上一个或特定版本|
|                `streams/deployments/update/{name}`                 |更新数据流。|
|                `streams/deployments/platform/list`                 |支持的部署平台列表|
|`streams/deployments/scale/{streamName}/{appName}/instances/{count}`|为选定的流按比例增加或减少应用程序实例的数量|
|                           `streams/logs`                           |检索流的应用程序日志|
|                    `streams/logs/{streamName}`                     |检索流的应用程序日志|
|               `streams/logs/{streamName}/{appName}`                |检索流的特定应用程序日志|
|                    `tools/parseTaskTextToGraph`                    |将任务定义解析为图结构|
|                   `tools/convertTaskGraphToText`                   |将图形格式转换为 DSL 文本格式|

### 44.2.服务器元信息

服务器元信息端点提供了有关服务器本身的更多信息。以下主题提供了更多细节:

* [检索有关服务器的信息](#api-guide-resources-server-meta-retrieving)

* [请求结构](#api-guide-resources-server-meta-request-structure)

* [示例请求](#api-guide-resources-server-meta-example-request)

* [反应结构](#api-guide-resources-server-meta-response-structure)

#### 44.2.1.检索有关服务器的信息

一个`GET`请求返回 Spring 云数据流的元信息,包括:

* 运行时环境信息

* 关于启用了哪些功能的信息

* Spring 云数据流服务器的依赖信息

* 安全信息

##### 请求结构

```
GET /about HTTP/1.1
Accept: application/json
Host: localhost:9393
```

##### 示例请求

```
$ curl 'http://localhost:9393/about' -i -X GET \
    -H 'Accept: application/json'
```

##### 反应结构

```
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 2598

{
  "featureInfo" : {
    "analyticsEnabled" : true,
    "streamsEnabled" : true,
    "tasksEnabled" : true,
    "schedulesEnabled" : true,
    "monitoringDashboardType" : "NONE"
  },
  "versionInfo" : {
    "implementation" : {
      "name" : "${info.app.name}",
      "version" : "${info.app.version}"
    },
    "core" : {
      "name" : "Spring Cloud Data Flow Core",
      "version" : "2.9.2"
    },
    "dashboard" : {
      "name" : "Spring Cloud Dataflow UI",
      "version" : "3.2.2"
    },
    "shell" : {
      "name" : "Spring Cloud Data Flow Shell",
      "version" : "2.9.2",
      "url" : "https://repo1.maven.org/maven2/org/springframework/cloud/spring-cloud-dataflow-shell/2.9.2/spring-cloud-dataflow-shell-2.9.2.jar"
    }
  },
  "securityInfo" : {
    "authenticationEnabled" : false,
    "authenticated" : false,
    "username" : null,
    "roles" : [ ]
  },
  "runtimeEnvironment" : {
    "appDeployer" : {
      "deployerImplementationVersion" : "Test Version",
      "deployerName" : "Test Server",
      "deployerSpiVersion" : "2.8.2",
      "javaVersion" : "1.8.0_322",
      "platformApiVersion" : "",
      "platformClientVersion" : "",
      "platformHostVersion" : "",
      "platformSpecificInfo" : {
        "default" : "local"
      },
      "platformType" : "Skipper Managed",
      "springBootVersion" : "2.5.8",
      "springVersion" : "5.3.14"
    },
    "taskLaunchers" : [ {
      "deployerImplementationVersion" : "2.7.2",
      "deployerName" : "LocalTaskLauncher",
      "deployerSpiVersion" : "2.7.2",
      "javaVersion" : "1.8.0_322",
      "platformApiVersion" : "Linux 5.11.0-1025-azure",
      "platformClientVersion" : "5.11.0-1025-azure",
      "platformHostVersion" : "5.11.0-1025-azure",
      "platformSpecificInfo" : { },
      "platformType" : "Local",
      "springBootVersion" : "2.5.8",
      "springVersion" : "5.3.14"
    }, {
      "deployerImplementationVersion" : "2.7.2",
      "deployerName" : "LocalTaskLauncher",
      "deployerSpiVersion" : "2.7.2",
      "javaVersion" : "1.8.0_322",
      "platformApiVersion" : "Linux 5.11.0-1025-azure",
      "platformClientVersion" : "5.11.0-1025-azure",
      "platformHostVersion" : "5.11.0-1025-azure",
      "platformSpecificInfo" : { },
      "platformType" : "Local",
      "springBootVersion" : "2.5.8",
      "springVersion" : "5.3.14"
    } ]
  },
  "monitoringDashboardInfo" : {
    "url" : "",
    "refreshInterval" : 15,
    "dashboardType" : "NONE",
    "source" : "default-scdf-source"
  },
  "_links" : {
    "self" : {
      "href" : "http://localhost:9393/about"
    }
  }
}
```

### 44.3.已登记的申请

注册的应用程序端点提供了关于已注册到 Spring 云数据流服务器的应用程序的信息。以下主题提供了更多细节:

* [列出应用程序](#resources-app-registry-list)

* [获取特定应用程序的信息](#resources-app-registry-get)

* [注册新的应用程序](#resources-app-registry-post)

* [用 Version 注册新应用程序](#resources-app-registry-post-versioned)

* [批量注册应用程序](#resources-app-registry-bulk)

* [设置默认的应用程序版本](#resources-app-registry-default)

* [取消注册应用程序](#resources-app-registry-delete)

* [取消注册所有应用程序](#resources-app-registry-delete-all)

#### 44.3.1.列出应用程序

一个`GET`请求列出了 Spring 云数据流中已知的所有应用程序。以下主题提供了更多细节:

* [请求结构](#api-guide-resources-app-registry-request-structure)

* [请求参数](#api-guide-resources-app-registry-request-parameters)

* [示例请求](#api-guide-resources-app-registry-example-request)

* [反应结构](#api-guide-resources-app-registry-response-structure)

##### 请求结构

```
GET /apps?search=&type=source&defaultVersion=true&page=0&size=10&sort=name%2CASC HTTP/1.1
Accept: application/json
Host: localhost:9393
```

##### 请求参数

|   Parameter    |说明|
|----------------|----------------------------------------------------------------------------------------------|
|    `search`    |对名称执行的搜索字符串(可选)|
|     `type`     |将返回的应用程序限制为应用程序的类型。[应用程序、源程序、处理器、接收器、任务]之一|
|`defaultVersion`|设置为仅检索缺省版本的应用程序的布尔标志(可选)|
|     `page`     |基于零的页码(可选)|
|     `sort`     |列表中的排序(可选)|
|     `size`     |请求的页面大小(可选)|

##### 示例请求

```
$ curl 'http://localhost:9393/apps?search=&type=source&defaultVersion=true&page=0&size=10&sort=name%2CASC' -i -X GET \
    -H 'Accept: application/json'
```

##### 反应结构

```
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 1097

{
  "_embedded" : {
    "appRegistrationResourceList" : [ {
      "name" : "http",
      "type" : "source",
      "uri" : "maven://org.springframework.cloud.stream.app:http-source-rabbit:1.2.0.RELEASE",
      "version" : "1.2.0.RELEASE",
      "defaultVersion" : true,
      "versions" : [ "1.2.0.RELEASE" ],
      "label" : null,
      "_links" : {
        "self" : {
          "href" : "http://localhost:9393/apps/source/http/1.2.0.RELEASE"
        }
      }
    }, {
      "name" : "time",
      "type" : "source",
      "uri" : "maven://org.springframework.cloud.stream.app:time-source-rabbit:1.2.0.RELEASE",
      "version" : "1.2.0.RELEASE",
      "defaultVersion" : true,
      "versions" : [ "1.2.0.RELEASE" ],
      "label" : null,
      "_links" : {
        "self" : {
          "href" : "http://localhost:9393/apps/source/time/1.2.0.RELEASE"
        }
      }
    } ]
  },
  "_links" : {
    "self" : {
      "href" : "http://localhost:9393/apps?page=0&size=10&sort=name,asc"
    }
  },
  "page" : {
    "size" : 10,
    "totalElements" : 2,
    "totalPages" : 1,
    "number" : 0
  }
}
```

#### 44.3.2.获取特定应用程序的信息

在`/apps/<type>/<name>`上的`GET`请求获取特定应用程序的信息。以下主题提供了更多细节:

* [请求结构](#api-guide-resources-app-registry-get-request-structure)

* [路径参数](#api-guide-resources-app-registry-get-path-parameters)

* [示例请求](#api-guide-resources-app-registry-get-example-request)

* [反应结构](#api-guide-resources-app-registry-get-response-structure)

##### 请求结构

```
GET /apps/source/http?exhaustive=false HTTP/1.1
Accept: application/json
Host: localhost:9393
```

##### 请求参数

| Parameter  |   说明   |
|------------|--------------------------------------------------------------------------|
|`exhaustive`|返回所有应用程序属性,包括常见的 Spring 引导属性|

##### 路径参数

/apps/{type}/{name}

|Parameter|说明|
|---------|-----------------------------------------------------------------------------|
| `type`  |要查询的应用程序类型。[应用程序、源程序、处理器、接收器、任务]之一|
| `name`  |要查询的应用程序的名称|

##### 示例请求

```
$ curl 'http://localhost:9393/apps/source/http?exhaustive=false' -i -X GET \
    -H 'Accept: application/json'
```

##### 反应结构

```
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 2100

{
  "name" : "http",
  "type" : "source",
  "uri" : "maven://org.springframework.cloud.stream.app:http-source-rabbit:1.2.0.RELEASE",
  "version" : "1.2.0.RELEASE",
  "defaultVersion" : true,
  "versions" : null,
  "label" : null,
  "options" : [ {
    "id" : "http.path-pattern",
    "name" : "path-pattern",
    "type" : "java.lang.String",
    "description" : "An Ant-Style pattern to determine which http requests will be captured.",
    "shortDescription" : "An Ant-Style pattern to determine which http requests will be captured.",
    "defaultValue" : "/",
    "hints" : {
      "keyHints" : [ ],
      "keyProviders" : [ ],
      "valueHints" : [ ],
      "valueProviders" : [ ]
    },
    "deprecation" : null,
    "deprecated" : false
  }, {
    "id" : "http.mapped-request-headers",
    "name" : "mapped-request-headers",
    "type" : "java.lang.String[]",
    "description" : "Headers that will be mapped.",
    "shortDescription" : "Headers that will be mapped.",
    "defaultValue" : null,
    "hints" : {
      "keyHints" : [ ],
      "keyProviders" : [ ],
      "valueHints" : [ ],
      "valueProviders" : [ ]
    },
    "deprecation" : null,
    "deprecated" : false
  }, {
    "id" : "http.secured",
    "name" : "secured",
    "type" : "java.lang.Boolean",
    "description" : "Secure or not HTTP source path.",
    "shortDescription" : "Secure or not HTTP source path.",
    "defaultValue" : false,
    "hints" : {
      "keyHints" : [ ],
      "keyProviders" : [ ],
      "valueHints" : [ ],
      "valueProviders" : [ ]
    },
    "deprecation" : null,
    "deprecated" : false
  }, {
    "id" : "server.port",
    "name" : "port",
    "type" : "java.lang.Integer",
    "description" : "Server HTTP port.",
    "shortDescription" : "Server HTTP port.",
    "defaultValue" : null,
    "hints" : {
      "keyHints" : [ ],
      "keyProviders" : [ ],
      "valueHints" : [ ],
      "valueProviders" : [ ]
    },
    "deprecation" : null,
    "deprecated" : false
  } ],
  "shortDescription" : null,
  "inboundPortNames" : [ ],
  "outboundPortNames" : [ ],
  "optionGroups" : { }
}
```

#### 44.3.3.注册新的应用程序

在`/apps/<type>/<name>`上的`POST`请求允许注册新的申请。以下主题提供了更多细节:

* [请求结构](#api-guide-resources-app-registry-post-request-structure)

* [请求参数](#api-guide-resources-app-registry-post-request-parameters)

* [路径参数](#api-guide-resources-app-registry-post-path-parameters)

* [示例请求](#api-guide-resources-app-registry-post-example-request)

* [反应结构](#api-guide-resources-app-registry-post-response-structure)

##### 请求结构

```
POST /apps/source/http HTTP/1.1
Host: localhost:9393
Content-Type: application/x-www-form-urlencoded

uri=maven%3A%2F%2Forg.springframework.cloud.stream.app%3Ahttp-source-rabbit%3A1.1.0.RELEASE
```

##### 请求参数

|  Parameter   |说明|
|--------------|--------------------------------------------------------------------------------------------------------|
|    `uri`     |应用程序位所在的 URI|
|`metadata-uri`|可以找到应用程序元数据 JAR 的 URI|
|   `force`    |如果已经存在具有相同名称和类型的注册,则必须为 true,否则将发生错误|

##### 路径参数

/apps/{type}/{name}

|Parameter|说明|
|---------|--------------------------------------------------------------------------------|
| `type`  |申请注册的类别。[应用程序、源程序、处理器、接收器、任务]之一|
| `name`  |登记申请书的名称|

##### 示例请求

```
$ curl 'http://localhost:9393/apps/source/http' -i -X POST \
    -d 'uri=maven%3A%2F%2Forg.springframework.cloud.stream.app%3Ahttp-source-rabbit%3A1.1.0.RELEASE'
```

##### 反应结构

```
HTTP/1.1 201 Created
```

#### 44.3.4.用 Version 注册新应用程序

在`/apps/<type>/<name>/<version>`上的`POST`请求允许注册新的申请。以下主题提供了更多细节:

* [请求结构](#api-guide-resources-app-registry-post-versioned-request-structure)

* [请求参数](#api-guide-resources-app-registry-post-versioned-request-parameters)

* [路径参数](#api-guide-resources-app-registry-post-versioned-path-parameters)

* [示例请求](#api-guide-resources-app-registry-post-versioned-example-request)

* [反应结构](#api-guide-resources-app-registry-post-versioned-response-structure)

##### 请求结构

```
POST /apps/source/http/1.1.0.RELEASE HTTP/1.1
Host: localhost:9393
Content-Type: application/x-www-form-urlencoded

uri=maven%3A%2F%2Forg.springframework.cloud.stream.app%3Ahttp-source-rabbit%3A1.1.0.RELEASE
```

##### 请求参数

|  Parameter   |说明|
|--------------|--------------------------------------------------------------------------------------------------------|
|    `uri`     |应用程序位所在的 URI|
|`metadata-uri`|可以找到应用程序元数据 JAR 的 URI|
|   `force`    |如果已经存在具有相同名称和类型的注册,则必须为 true,否则将发生错误|

##### 路径参数

/apps/{type}/{name}/{version:.+}

|Parameter|说明|
|---------|-------------------------------------------------------------------------------------------|
| `type`  |申请注册的类别。[应用程序、源程序、处理器、接收器、任务]之一(可选)|
| `name`  |登记申请书的名称|
|`version`|要注册的应用程序的版本|

##### 示例请求

```
$ curl 'http://localhost:9393/apps/source/http/1.1.0.RELEASE' -i -X POST \
    -d 'uri=maven%3A%2F%2Forg.springframework.cloud.stream.app%3Ahttp-source-rabbit%3A1.1.0.RELEASE'
```

##### 反应结构

```
HTTP/1.1 201 Created
```

#### 44.3.5.批量注册应用程序

在`/apps`上的`POST`请求允许一次注册多个应用程序。以下主题提供了更多细节:

* [请求结构](#api-guide-resources-app-registry-bulk-request-structure)

* [请求参数](#api-guide-resources-app-registry-bulk-request-parameters)

* [示例请求](#api-guide-resources-app-registry-bulk-example-request)

* [反应结构](#api-guide-resources-app-registry-bulk-response-structure)

##### 请求结构

```
POST /apps HTTP/1.1
Host: localhost:9393
Content-Type: application/x-www-form-urlencoded

apps=source.http%3Dmaven%3A%2F%2Forg.springframework.cloud.stream.app%3Ahttp-source-rabbit%3A1.1.0.RELEASE&force=false
```

##### 请求参数

|Parameter|说明|
|---------|--------------------------------------------------------------------------------------------------------|
|  `uri`  |可以获取包含注册的属性文件的 URI。独家使用`apps`。|
| `apps`  |内联注册集。独家使用`uri`。|
| `force` |如果已经存在具有相同名称和类型的注册,则必须为 true,否则将发生错误|

##### 示例请求

```
$ curl 'http://localhost:9393/apps' -i -X POST \
    -d 'apps=source.http%3Dmaven%3A%2F%2Forg.springframework.cloud.stream.app%3Ahttp-source-rabbit%3A1.1.0.RELEASE&force=false'
```

##### 反应结构

```
HTTP/1.1 201 Created
Content-Type: application/hal+json
Content-Length: 658

{
  "_embedded" : {
    "appRegistrationResourceList" : [ {
      "name" : "http",
      "type" : "source",
      "uri" : "maven://org.springframework.cloud.stream.app:http-source-rabbit:1.1.0.RELEASE",
      "version" : "1.1.0.RELEASE",
      "defaultVersion" : true,
      "versions" : null,
      "label" : null,
      "_links" : {
        "self" : {
          "href" : "http://localhost:9393/apps/source/http/1.1.0.RELEASE"
        }
      }
    } ]
  },
  "_links" : {
    "self" : {
      "href" : "http://localhost:9393/apps?page=0&size=20"
    }
  },
  "page" : {
    "size" : 20,
    "totalElements" : 1,
    "totalPages" : 1,
    "number" : 0
  }
}
```

#### 44.3.6.设置默认的应用程序版本

对于具有相同`name`和`type`的应用程序,可以注册多个版本。在这种情况下,你可以选择其中一个版本作为默认应用程序。

以下主题提供了更多细节:

* [请求结构](#api-guide-resources-app-registry-default-request-structure)

* [路径参数](#api-guide-resources-app-registry-default-path-parameters)

* [示例请求](#api-guide-resources-app-registry-default-example-request)

* [反应结构](#api-guide-resources-app-registry-default-response-structure)

##### 请求结构

```
PUT /apps/source/http/1.2.0.RELEASE HTTP/1.1
Accept: application/json
Host: localhost:9393
```

##### 路径参数

/apps/{type}/{name}/{version:.+}

|Parameter|       说明       |
|---------|--------------------------------------------------------------------|
| `type`  |应用程序的类型。[应用程序、源程序、处理器、接收器、任务]之一|
| `name`  |申请的名称|
|`version`|应用程序的版本|

##### 示例请求

```
$ curl 'http://localhost:9393/apps/source/http/1.2.0.RELEASE' -i -X PUT \
    -H 'Accept: application/json'
```

##### 反应结构

```
HTTP/1.1 202 Accepted
```

#### 44.3.7.取消注册应用程序

在`/apps/<type>/<name>`上的`DELETE`请求取消注册先前已注册的应用程序。以下主题提供了更多细节:

* [请求结构](#api-guide-resources-app-registry-delete-request-structure)

* [路径参数](#api-guide-resources-app-registry-delete-path-parameters)

* [示例请求](#api-guide-resources-app-registry-delete-example-request)

* [反应结构](#api-guide-resources-app-registry-delete-response-structure)

##### 请求结构

```
DELETE /apps/source/http/1.2.0.RELEASE HTTP/1.1
Host: localhost:9393
```

##### 路径参数

/apps/{type}/{name}/{version}

|Parameter|说明|
|---------|----------------------------------------------------------------------------------|
| `type`  |要取消注册的应用程序的类型。[应用程序、源程序、处理器、接收器、任务]之一|
| `name`  |要注销的应用程序的名称|
|`version`|要取消注册的应用程序的版本(可选)|

##### 示例请求

```
$ curl 'http://localhost:9393/apps/source/http/1.2.0.RELEASE' -i -X DELETE
```

##### 反应结构

```
HTTP/1.1 200 OK
```

#### 44.3.8.取消注册所有应用程序

在`/apps`上的`DELETE`请求取消注册所有的应用程序。以下主题提供了更多细节:

* [请求结构](#api-guide-resources-app-registry-delete-all-request-structure)

* [示例请求](#api-guide-resources-app-registry-delete-all-example-request)

* [反应结构](#api-guide-resources-app-registry-delete-all-response-structure)

##### 请求结构

```
DELETE /apps HTTP/1.1
Host: localhost:9393
```

##### 示例请求

```
$ curl 'http://localhost:9393/apps' -i -X DELETE
```

##### 反应结构

```
HTTP/1.1 200 OK
```

### 44.4.审计记录

审计记录端点提供有关审计记录的信息。以下主题提供了更多细节:

* [列出所有审计记录](#api-guide-resources-audit-records-list)

* [检索审计记录详细信息](#api-guide-resources-audit-record-get)

* [列出所有审计操作类型](#api-guide-resources-audit-action-types)

* [列出所有审计操作类型](#api-guide-resources-audit-operation-types)

#### 44.4.1.列出所有审计记录

审计记录端点允许你检索审计跟踪信息。

以下主题提供了更多细节:

* [请求结构](#api-guide-resources-audit-records-list-request-structure)

* [请求参数](#api-guide-resources-audit-records-list-request-parameters)

* [示例请求](#api-guide-resources-audit-records-list-example-request)

* [反应结构](#api-guide-resources-audit-records-list-response-structure)

##### 请求结构

```
GET /audit-records?page=0&size=10&operations=STREAM&actions=CREATE&fromDate=2000-01-01T00%3A00%3A00&toDate=2099-01-01T00%3A00%3A00 HTTP/1.1
Host: localhost:9393
```

##### 请求参数

| Parameter  |    说明    |
|------------|------------------------------------------------------|
|   `page`   |基于零的页码(可选)|
|   `size`   |请求的页面大小(可选)|
|`operations`|用逗号分隔的审计操作列表(可选)|
| `actions`  |用逗号分隔的审计操作列表(可选)|
| `fromDate` |自日期过滤器(例如:2019-02-03T00:00:30)(可选)|
|  `toDate`  |截止日期过滤器(例如:2019-02-03T00:00:30)(可选)|

##### 示例请求

```
$ curl 'http://localhost:9393/audit-records?page=0&size=10&operations=STREAM&actions=CREATE&fromDate=2000-01-01T00%3A00%3A00&toDate=2099-01-01T00%3A00%3A00' -i -X GET
```

##### 反应结构

```
HTTP/1.1 200 OK
Content-Type: application/hal+json
Content-Length: 680

{
  "_embedded" : {
    "auditRecordResourceList" : [ {
      "auditRecordId" : 5,
      "createdBy" : null,
      "correlationId" : "timelog",
      "auditData" : "time --format='YYYY MM DD' | log",
      "createdOn" : "2022-01-18T18:52:24.663Z",
      "auditAction" : "CREATE",
      "auditOperation" : "STREAM",
      "platformName" : null,
      "_links" : {
        "self" : {
          "href" : "http://localhost:9393/audit-records/5"
        }
      }
    } ]
  },
  "_links" : {
    "self" : {
      "href" : "http://localhost:9393/audit-records?page=0&size=10"
    }
  },
  "page" : {
    "size" : 10,
    "totalElements" : 1,
    "totalPages" : 1,
    "number" : 0
  }
}
```

#### 44.4.2.检索审计记录详细信息

审计记录端点允许你获得单个审计记录。以下主题提供了更多细节:

* [请求结构](#api-guide-resources-audit-record-get-request-structure)

* [路径参数](#api-guide-resources-audit-record-get-path-parameters)

* [示例请求](#api-guide-resources-audit-record-get-example-request)

* [反应结构](#api-guide-resources-audit-record-get-response-structure)

##### 请求结构

```
GET /audit-records/5 HTTP/1.1
Host: localhost:9393
```

##### 路径参数

/audit-records/{id}

|Parameter|                 Description                  |
|---------|----------------------------------------------|
|  `id`   |要查询的审计记录的 ID(必需的)|

##### 示例请求

```
$ curl 'http://localhost:9393/audit-records/5' -i -X GET
```

##### 反应结构

```
HTTP/1.1 200 OK
Content-Type: application/hal+json
Content-Length: 354

{
  "auditRecordId" : 5,
  "createdBy" : null,
  "correlationId" : "timelog",
  "auditData" : "time --format='YYYY MM DD' | log",
  "createdOn" : "2022-01-18T18:52:24.663Z",
  "auditAction" : "CREATE",
  "auditOperation" : "STREAM",
  "platformName" : null,
  "_links" : {
    "self" : {
      "href" : "http://localhost:9393/audit-records/5"
    }
  }
}
```

#### 44.4.3.列出所有审计操作类型

审计记录端点允许你获取操作类型。以下主题提供了更多细节:

* [请求结构](#api-guide-resources-audit-action-types-request-structure)

* [示例请求](#api-guide-resources-audit-action-types-example-request)

* [反应结构](#api-guide-resources-audit-action-types-response-structure)

##### 请求结构

```
GET /audit-records/audit-action-types HTTP/1.1
Host: localhost:9393
```

##### 示例请求

```
$ curl 'http://localhost:9393/audit-records/audit-action-types' -i -X GET
```

##### 反应结构

```
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 1111

[ {
  "id" : 100,
  "name" : "Create",
  "description" : "Create an Entity",
  "nameWithDescription" : "Create (Create an Entity)",
  "key" : "CREATE"
}, {
  "id" : 200,
  "name" : "Delete",
  "description" : "Delete an Entity",
  "nameWithDescription" : "Delete (Delete an Entity)",
  "key" : "DELETE"
}, {
  "id" : 300,
  "name" : "Deploy",
  "description" : "Deploy an Entity",
  "nameWithDescription" : "Deploy (Deploy an Entity)",
  "key" : "DEPLOY"
}, {
  "id" : 400,
  "name" : "Rollback",
  "description" : "Rollback an Entity",
  "nameWithDescription" : "Rollback (Rollback an Entity)",
  "key" : "ROLLBACK"
}, {
  "id" : 500,
  "name" : "Undeploy",
  "description" : "Undeploy an Entity",
  "nameWithDescription" : "Undeploy (Undeploy an Entity)",
  "key" : "UNDEPLOY"
}, {
  "id" : 600,
  "name" : "Update",
  "description" : "Update an Entity",
  "nameWithDescription" : "Update (Update an Entity)",
  "key" : "UPDATE"
}, {
  "id" : 700,
  "name" : "SuccessfulLogin",
  "description" : "Successful login",
  "nameWithDescription" : "SuccessfulLogin (Successful login)",
  "key" : "LOGIN_SUCCESS"
} ]
```

#### 44.4.4.列出所有审计操作类型

审计记录端点允许你获得操作类型。以下主题提供了更多细节:

* [请求结构](#api-guide-resources-audit-operation-types-request-structure)

* [示例请求](#api-guide-resources-audit-operation-types-example-request)

* [反应结构](#api-guide-resources-audit-operation-types-response-structure)

##### 请求结构

```
GET /audit-records/audit-operation-types HTTP/1.1
Host: localhost:9393
```

##### 示例请求

```
$ curl 'http://localhost:9393/audit-records/audit-operation-types' -i -X GET
```

##### 反应结构

```
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 315

[ {
  "id" : 100,
  "name" : "App Registration",
  "key" : "APP_REGISTRATION"
}, {
  "id" : 200,
  "name" : "Schedule",
  "key" : "SCHEDULE"
}, {
  "id" : 300,
  "name" : "Stream",
  "key" : "STREAM"
}, {
  "id" : 400,
  "name" : "Task",
  "key" : "TASK"
}, {
  "id" : 500,
  "name" : "Login",
  "key" : "LOGIN"
} ]
```

### 44.5.流定义

注册的应用程序端点提供了关于已注册到 Spring 云数据流服务器的流定义的信息。以下主题提供了更多细节:

* [创建新的流定义](#api-guide-resources-stream-definitions-create)

* [列出所有流定义](#api-guide-resources-stream-definitions-list)

* [列出相关的流定义](#api-guide-resources-stream-definitions-list-related)

* [检索流定义详细信息](#api-guide-resources-stream-definition-get)

* [删除单个流定义](#api-guide-resources-stream-definitions-delete-one)

* [删除所有流定义](#api-guide-resources-stream-definitions-delete-all)

* [部署流定义](#api-guide-resources-stream-deployment-deploy)

* [取消部署流定义](#api-guide-resources-stream-deployment-undeploy)

* [取消部署所有流定义](#api-guide-resources-stream-deployment-undeploy-all)

#### 44.5.1.创建新的流定义

创建流定义是通过创建对流定义端点的 POST 请求来实现的。对`ticktock`流的 curl 请求可能类似于以下内容:

```
curl -X POST -d "name=ticktock&definition=time | log" localhost:9393/streams/definitions?deploy=false
```

流定义还可以包含其他参数。例如,在“[请求结构](#api-guide-resources-stream-definitions-create-request-structure)”下显示的示例中,我们还提供了日期时间格式。

以下主题提供了更多细节:

* [请求结构](#api-guide-resources-stream-definitions-create-request-structure)

* [请求参数](#api-guide-resources-stream-definitions-create-request-parameters)

* [示例请求](#api-guide-resources-stream-definitions-create-example-request)

* [反应结构](#api-guide-resources-stream-definitions-create-response-structure)

##### 请求结构

```
POST /streams/definitions HTTP/1.1
Host: localhost:9393
Content-Type: application/x-www-form-urlencoded

name=timelog&definition=time+--format%3D%27YYYY+MM+DD%27+%7C+log&description=Demo+stream+for+testing&deploy=false
```

##### 请求参数

|  Parameter  |说明|
|-------------|----------------------------------------------------------------|
|   `name`    |创建的任务定义的名称|
|`definition` |流的定义,使用数据流 DSL|
|`description`|流定义的描述|
|  `deploy`   |如果为真,则在创建时部署流(默认值为 false)|

##### 示例请求

```
$ curl 'http://localhost:9393/streams/definitions' -i -X POST \
    -d 'name=timelog&definition=time+--format%3D%27YYYY+MM+DD%27+%7C+log&description=Demo+stream+for+testing&deploy=false'
```

##### 反应结构

```
HTTP/1.1 201 Created
Content-Type: application/hal+json
Content-Length: 410

{
  "name" : "timelog",
  "dslText" : "time --format='YYYY MM DD' | log",
  "originalDslText" : "time --format='YYYY MM DD' | log",
  "status" : "undeployed",
  "description" : "Demo stream for testing",
  "statusDescription" : "The app or group is known to the system, but is not currently deployed",
  "_links" : {
    "self" : {
      "href" : "http://localhost:9393/streams/definitions/timelog"
    }
  }
}
```

#### 44.5.2.列出所有流定义

Streams Endpoint 允许你列出所有的流定义。以下主题提供了更多细节:

* [请求结构](#api-guide-resources-stream-definitions-list-request-structure)

* [请求参数](#api-guide-resources-stream-definitions-list-request-parameters)

* [示例请求](#api-guide-resources-stream-definitions-list-example-request)

* [反应结构](#api-guide-resources-stream-definitions-list-response-structure)

##### 请求结构

```
GET /streams/definitions?page=0&sort=name%2CASC&search=&size=10 HTTP/1.1
Host: localhost:9393
```

##### 请求参数

|Parameter|说明|
|---------|--------------------------------------------------|
| `page`  |基于零的页码(可选)|
|`search` |对名称执行的搜索字符串(可选)|
| `sort`  |列表中的排序(可选)|
| `size`  |请求的页面大小(可选)|

##### 示例请求

```
$ curl 'http://localhost:9393/streams/definitions?page=0&sort=name%2CASC&search=&size=10' -i -X GET
```

##### 反应结构

```
HTTP/1.1 200 OK
Content-Type: application/hal+json
Content-Length: 1160

{
  "_embedded" : {
    "streamDefinitionResourceList" : [ {
      "name" : "mysamplestream",
      "dslText" : "time | log",
      "originalDslText" : "time | log",
      "status" : "undeployed",
      "description" : "",
      "statusDescription" : "The app or group is known to the system, but is not currently deployed",
      "_links" : {
        "self" : {
          "href" : "http://localhost:9393/streams/definitions/mysamplestream"
        }
      }
    }, {
      "name" : "timelog",
      "dslText" : "time --format='YYYY MM DD' | log",
      "originalDslText" : "time --format='YYYY MM DD' | log",
      "status" : "undeployed",
      "description" : "Demo stream for testing",
      "statusDescription" : "The app or group is known to the system, but is not currently deployed",
      "_links" : {
        "self" : {
          "href" : "http://localhost:9393/streams/definitions/timelog"
        }
      }
    } ]
  },
  "_links" : {
    "self" : {
      "href" : "http://localhost:9393/streams/definitions?page=0&size=10&sort=name,asc"
    }
  },
  "page" : {
    "size" : 10,
    "totalElements" : 2,
    "totalPages" : 1,
    "number" : 0
  }
}
```

#### 44.5.3.列出相关的流定义

Streams Endpoint 允许你列出相关的流定义。以下主题提供了更多细节:

* [请求结构](#api-guide-resources-stream-definitions-list-related-request-structure)

* [请求参数](#api-guide-resources-stream-definitions-list-related-request-parameters)

* [示例请求](#api-guide-resources-stream-definitions-list-related-example-request)

* [反应结构](#api-guide-resources-stream-definitions-list-related-response-structure)

##### 请求结构

```
GET /streams/definitions/timelog/related?page=0&sort=name%2CASC&search=&size=10&nested=true HTTP/1.1
Host: localhost:9393
```

##### 请求参数

|Parameter|说明|
|---------|--------------------------------------------------------------------------------------|
|`nested` |我们是否应该通过 tasknameContains 递归地找到相关的流定义(可选)|
| `page`  |基于零的页码(可选)|
|`search` |对名称执行的搜索字符串(可选)|
| `sort`  |列表中的排序(可选)|
| `size`  |请求的页面大小(可选)|

##### 示例请求

```
$ curl 'http://localhost:9393/streams/definitions/timelog/related?page=0&sort=name%2CASC&search=&size=10&nested=true' -i -X GET
```

##### 反应结构

```
HTTP/1.1 200 OK
Content-Type: application/hal+json
Content-Length: 769

{
  "_embedded" : {
    "streamDefinitionResourceList" : [ {
      "name" : "timelog",
      "dslText" : "time --format='YYYY MM DD' | log",
      "originalDslText" : "time --format='YYYY MM DD' | log",
      "status" : "undeployed",
      "description" : "Demo stream for testing",
      "statusDescription" : "The app or group is known to the system, but is not currently deployed",
      "_links" : {
        "self" : {
          "href" : "http://localhost:9393/streams/definitions/timelog"
        }
      }
    } ]
  },
  "_links" : {
    "self" : {
      "href" : "http://localhost:9393/streams/definitions/timelog/related?page=0&size=10&sort=name,asc"
    }
  },
  "page" : {
    "size" : 10,
    "totalElements" : 1,
    "totalPages" : 1,
    "number" : 0
  }
}
```

#### 44.5.4.检索流定义详细信息

流定义端点允许你获得单个流定义。以下主题提供了更多细节:

* [请求结构](#api-guide-resources-stream-definition-get-request-structure)

* [路径参数](#api-guide-resources-stream-definition-get-path-parameters)

* [示例请求](#api-guide-resources-stream-definition-get-example-request)

* [反应结构](#api-guide-resources-stream-definition-get-response-structure)

##### 请求结构

```
GET /streams/definitions/timelog HTTP/1.1
Host: localhost:9393
```

##### 路径参数

/streams/definitions/{name}

|Parameter|说明|
|---------|-----------------------------------------------------|
| `name`  |要查询的流定义的名称(必需的)|

##### 示例请求

```
$ curl 'http://localhost:9393/streams/definitions/timelog' -i -X GET
```

##### 反应结构

```
HTTP/1.1 200 OK
Content-Type: application/hal+json
Content-Length: 410

{
  "name" : "timelog",
  "dslText" : "time --format='YYYY MM DD' | log",
  "originalDslText" : "time --format='YYYY MM DD' | log",
  "status" : "undeployed",
  "description" : "Demo stream for testing",
  "statusDescription" : "The app or group is known to the system, but is not currently deployed",
  "_links" : {
    "self" : {
      "href" : "http://localhost:9393/streams/definitions/timelog"
    }
  }
}
```

#### 44.5.5.删除单个流定义

Streams Endpoint 允许你删除单个流定义。(另请参见:[删除所有流定义](#api-guide-resources-stream-definitions-delete-all)。)以下主题提供了更多详细信息:

* [请求结构](#api-guide-resources-stream-definitions-delete-one-request-structure)

* [请求参数](#api-guide-resources-stream-definitions-delete-one-request-parameters)

* [示例请求](#api-guide-resources-stream-definitions-delete-one-example-request)

* [反应结构](#api-guide-resources-stream-definitions-delete-one-response-structure)

##### 请求结构

```
DELETE /streams/definitions/timelog HTTP/1.1
Host: localhost:9393
```

##### 请求参数

这个端点没有请求参数。

##### 示例请求

```
$ curl 'http://localhost:9393/streams/definitions/timelog' -i -X DELETE
```

##### 反应结构

```
HTTP/1.1 200 OK
```

#### 44.5.6.删除所有流定义

Streams Endpoint 允许你删除所有单个流定义。(另请参见:[删除单个流定义](#api-guide-resources-stream-definitions-delete-one)。)以下主题提供了更多详细信息:

* [请求结构](#api-guide-resources-stream-definitions-delete-all-request-structure)

* [请求参数](#api-guide-resources-stream-definitions-delete-all-request-parameters)

* [示例请求](#api-guide-resources-stream-definitions-delete-all-example-request)

* [反应结构](#api-guide-resources-stream-definitions-delete-all-response-structure)

##### 请求结构

```
DELETE /streams/definitions HTTP/1.1
Host: localhost:9393
```

##### 请求参数

这个端点没有请求参数。

##### 示例请求

```
$ curl 'http://localhost:9393/streams/definitions' -i -X DELETE
```

##### 反应结构

```
HTTP/1.1 200 OK
```

### 44.6.流验证

流验证端点允许你在流定义中验证应用程序。以下主题提供了更多细节:

* [请求结构](#api-guide-resources-stream-validation-request-structure)

* [路径参数](#api-guide-resources-stream-validation-path-parameters)

* [示例请求](#api-guide-resources-stream-validation-example-request)

* [反应结构](#api-guide-resources-stream-validation-response-structure)

#### 44.6.1.请求结构

```
GET /streams/validation/timelog HTTP/1.1
Host: localhost:9393
```

#### 44.6.2.路径参数

/streams/validation/{name}

|Parameter|说明|
|---------|----------------------------------------------------------|
| `name`  |要验证的流定义的名称(必需的)|

#### 44.6.3.示例请求

```
$ curl 'http://localhost:9393/streams/validation/timelog' -i -X GET
```

#### 44.6.4.反应结构

```
HTTP/1.1 200 OK
Content-Type: application/hal+json
Content-Length: 197

{
  "appName" : "timelog",
  "dsl" : "time --format='YYYY MM DD' | log",
  "description" : "Demo stream for testing",
  "appStatuses" : {
    "source:time" : "valid",
    "sink:log" : "valid"
  }
}
```

### 44.7.流部署

部署定义端点提供有关在 Spring 云数据流服务器中注册的部署的信息。以下主题提供了更多细节:

* [部署流定义](#api-guide-resources-stream-deployment-deploy)

* [取消部署流定义](#api-guide-resources-stream-deployment-undeploy)

* [取消部署所有流定义](#api-guide-resources-stream-deployment-undeploy-all)

* [更新部署的流](#api-guide-resources-stream-deployment-update)

* [回滚流定义](#api-guide-resources-stream-deployment-rollback)

* [获取舱单](#api-guide-resources-stream-deployment-manifest)

* [获取部署历史](#api-guide-resources-stream-deployment-history)

* [获取部署平台](#api-guide-resources-stream-deployment-platform-list)

* [缩放流定义](#api-guide-resources-stream-deployment-scale)

#### 44.7.1.部署流定义

流定义端点允许你部署单个流定义。你可以选择在请求主体中将应用程序参数作为属性传递。以下主题提供了更多细节:

* [请求结构](#api-guide-resources-stream-definitions-deployment-deploy-request-structure)

* [请求参数](#api-guide-resources-stream-definitions-deployment-deploy-request-parameters)

* [示例请求](#api-guide-resources-stream-definitions-deployment-deploy-example-request)

* [反应结构](#api-guide-resources-stream-definitions-deployment-deploy-response-structure)

##### 请求结构

```
POST /streams/deployments/timelog HTTP/1.1
Content-Type: application/json
Content-Length: 36
Host: localhost:9393

{"app.time.timestamp.format":"YYYY"}
```

/流/部署/{timelog}

|Parameter|说明|
|---------|----------------------------------------------------|
|`timelog`|现有流定义的名称(必需的)|

##### 请求参数

这个端点没有请求参数。

##### 示例请求

```
$ curl 'http://localhost:9393/streams/deployments/timelog' -i -X POST \
    -H 'Content-Type: application/json' \
    -d '{"app.time.timestamp.format":"YYYY"}'
```

##### 反应结构

```
HTTP/1.1 201 Created
```

#### 44.7.2.取消部署流定义

流定义端点允许你取消部署单个流定义。以下主题提供了更多细节:

* [请求结构](#api-guide-resources-stream-definitions-deployment-undeploy-request-structure)

* [请求参数](#api-guide-resources-stream-definitions-deployment-undeploy-request-parameters)

* [示例请求](#api-guide-resources-stream-definitions-deployment-undeploy-example-request)

* [反应结构](#api-guide-resources-stream-definitions-deployment-undeploy-response-structure)

##### 请求结构

```
DELETE /streams/deployments/timelog HTTP/1.1
Host: localhost:9393
```

/流/部署/{timelog}

|Parameter|说明|
|---------|----------------------------------------------------|
|`timelog`|现有流定义的名称(必需的)|

##### 请求参数

这个端点没有请求参数。

##### 示例请求

```
$ curl 'http://localhost:9393/streams/deployments/timelog' -i -X DELETE
```

##### 反应结构

```
HTTP/1.1 200 OK
```

#### 44.7.3.取消部署所有流定义

流定义端点允许你取消部署所有单个流定义。以下主题提供了更多细节:

* [请求结构](#api-guide-resources-stream-definitions-deployment-undeploy-all-request-structure)

* [请求参数](#api-guide-resources-stream-definitions-deployment-undeploy-all-request-parameters)

* [示例请求](#api-guide-resources-stream-definitions-deployment-undeploy-all-example-request)

* [反应结构](#api-guide-resources-stream-definitions-deployment-undeploy-all-response-structure)

##### 请求结构

```
DELETE /streams/deployments HTTP/1.1
Host: localhost:9393
```

##### 请求参数

这个端点没有请求参数。

##### 示例请求

```
$ curl 'http://localhost:9393/streams/deployments' -i -X DELETE
```

##### 反应结构

```
HTTP/1.1 200 OK
```

#### 44.7.4.更新部署的流

多亏了 Skipper,你可以更新部署的流,并提供额外的部署属性。

* [请求结构](#api-guide-resources-stream-definitions-deployment-update-request-structure)

* [请求参数](#api-guide-resources-stream-definitions-deployment-update-request-parameters)

* [示例请求](#api-guide-resources-stream-definitions-deployment-update-example-request)

* [反应结构](#api-guide-resources-stream-definitions-deployment-update-response-structure)

##### 请求结构

```
POST /streams/deployments/update/timelog1 HTTP/1.1
Content-Type: application/json
Content-Length: 196
Host: localhost:9393

{"releaseName":"timelog1","packageIdentifier":{"repositoryName":"test","packageName":"timelog1","packageVersion":"1.0.0"},"updateProperties":{"app.time.timestamp.format":"YYYYMMDD"},"force":false}
```

/流/部署/更新/{timelog1}

|Parameter |说明|
|----------|----------------------------------------------------|
|`timelog1`|现有流定义的名称(必需的)|

##### 请求参数

这个端点没有请求参数。

##### 示例请求

```
$ curl 'http://localhost:9393/streams/deployments/update/timelog1' -i -X POST \
    -H 'Content-Type: application/json' \
    -d '{"releaseName":"timelog1","packageIdentifier":{"repositoryName":"test","packageName":"timelog1","packageVersion":"1.0.0"},"updateProperties":{"app.time.timestamp.format":"YYYYMMDD"},"force":false}'
```

##### 反应结构

```
HTTP/1.1 201 Created
```

#### 44.7.5.回滚流定义

将流回滚到流的上一个或特定版本。

* [请求结构](#api-guide-resources-stream-definitions-deployment-rollback-request-structure)

* [请求参数](#api-guide-resources-stream-definitions-deployment-rollback-request-parameters)

* [示例请求](#api-guide-resources-stream-definitions-deployment-rollback-example-request)

* [反应结构](#api-guide-resources-stream-definitions-deployment-rollback-response-structure)

##### 请求结构

```
POST /streams/deployments/rollback/timelog1/1 HTTP/1.1
Content-Type: application/json
Host: localhost:9393
```

/流/部署/回滚/{name}/{version}

|Parameter|说明|
|---------|----------------------------------------------------|
| `name`  |现有流定义的名称(必需的)|
|`version`|要回滚到的版本|

##### 请求参数

这个端点没有请求参数。

##### 示例请求

```
$ curl 'http://localhost:9393/streams/deployments/rollback/timelog1/1' -i -X POST \
    -H 'Content-Type: application/json'
```

##### 反应结构

```
HTTP/1.1 201 Created
```

#### 44.7.6.获取舱单

返回已发布版本的清单。对于具有依赖关系的包,清单包括这些依赖关系的内容。

* [请求结构](#api-guide-resources-stream-definitions-deployment-manifest-request-structure)

* [请求参数](#api-guide-resources-stream-definitions-deployment-manifest-request-parameters)

* [示例请求](#api-guide-resources-stream-definitions-deployment-manifest-example-request)

* [反应结构](#api-guide-resources-stream-definitions-deployment-manifest-response-structure)

##### 请求结构

```
GET /streams/deployments/manifest/timelog1/1 HTTP/1.1
Content-Type: application/json
Host: localhost:9393
```

/流/部署/清单/{name}/{version}

|Parameter|说明|
|---------|----------------------------------------------------|
| `name`  |现有流定义的名称(必需的)|
|`version`|流的版本|

##### 请求参数

这个端点没有请求参数。

##### 示例请求

```
$ curl 'http://localhost:9393/streams/deployments/manifest/timelog1/1' -i -X GET \
    -H 'Content-Type: application/json'
```

##### 反应结构

```
HTTP/1.1 200 OK
```

#### 44.7.7.获取部署历史

获取数据流的部署历史。

* [请求结构](#api-guide-resources-stream-definitions-deployment-history-request-structure)

* [示例请求](#api-guide-resources-stream-definitions-deployment-history-example-request)

* [反应结构](#api-guide-resources-stream-definitions-deployment-history-response-structure)

##### 请求结构

```
GET /streams/deployments/history/timelog1 HTTP/1.1
Content-Type: application/json
Host: localhost:9393
```

##### 示例请求

```
$ curl 'http://localhost:9393/streams/deployments/history/timelog1' -i -X GET \
    -H 'Content-Type: application/json'
```

##### 反应结构

```
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 162

[ {
  "name" : null,
  "version" : 0,
  "info" : null,
  "pkg" : null,
  "configValues" : {
    "raw" : null
  },
  "manifest" : null,
  "platformName" : null
} ]
```

#### 44.7.8.获取部署平台

检索受支持的部署平台的列表。

* [请求结构](#api-guide-resources-stream-definitions-deployment-platform-list-request-structure)

* [示例请求](#api-guide-resources-stream-definitions-deployment-history-example-request)

* [反应结构](#api-guide-resources-stream-definitions-deployment-history-response-structure)

##### 请求结构

```
GET /streams/deployments/platform/list HTTP/1.1
Content-Type: application/json
Host: localhost:9393
```

##### 示例请求

```
$ curl 'http://localhost:9393/streams/deployments/platform/list' -i -X GET \
    -H 'Content-Type: application/json'
```

##### 反应结构

```
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 106

[ {
  "id" : null,
  "name" : "default",
  "type" : "local",
  "description" : null,
  "options" : [ ]
} ]
```

#### 44.7.9.缩放流定义

流定义端点允许你在流定义中扩展单个应用程序。你可以选择在请求主体中将应用程序参数作为属性传递。以下主题提供了更多细节:

* [请求结构](#api-guide-resources-stream-definitions-deployment-scale-request-structure)

* [请求参数](#api-guide-resources-stream-definitions-deployment-scale-request-parameters)

* [示例请求](#api-guide-resources-stream-definitions-deployment-scale-example-request)

* [反应结构](#api-guide-resources-stream-definitions-deployment-scale-response-structure)

##### 请求结构

```
POST /streams/deployments/scale/timelog/log/instances/1 HTTP/1.1
Content-Type: application/json
Content-Length: 36
Host: localhost:9393

{"app.time.timestamp.format":"YYYY"}
```

/streams/deployments/scale/{streamname}/{appname}/instance/{count}

| Parameter  |说明|
|------------|------------------------------------------------------------------|
|`streamName`|现有流定义的名称(必需的)|
| `appName`  |在流应用程序中按比例命名|
|  `count`   |选定的流应用程序的实例数(必需的)|

##### 请求参数

这个端点没有请求参数。

##### 示例请求

```
$ curl 'http://localhost:9393/streams/deployments/scale/timelog/log/instances/1' -i -X POST \
    -H 'Content-Type: application/json' \
    -d '{"app.time.timestamp.format":"YYYY"}'
```

##### 反应结构

```
HTTP/1.1 201 Created
```

### 44.8.任务定义

任务定义端点提供了有关在 Spring 云数据流服务器中注册的任务定义的信息。以下主题提供了更多细节:

* [创建新的任务定义](#api-guide-resources-task-definitions-creating)

* [列出所有任务定义](#api-guide-resources-task-definitions-list)

* [检索任务定义详细信息](#api-guide-resources-task-definition-detail)

* [删除任务定义](#api-guide-resources-delete-task-definition)

#### 44.8.1.创建新的任务定义

任务定义端点允许你创建一个新的任务定义。以下主题提供了更多细节:

* [请求结构](#api-guide-resources-stream-task-definitions-creating-request-structure)

* [请求参数](#api-guide-resources-stream-task-definitions-creating-request-parameters)

* [示例请求](#api-guide-resources-stream-task-definitions-creating-example-request)

* [反应结构](#api-guide-resources-stream-task-definitions-creating-response-structure)

##### 请求结构

```
POST /tasks/definitions HTTP/1.1
Host: localhost:9393
Content-Type: application/x-www-form-urlencoded

name=my-task&definition=timestamp+--format%3D%27YYYY+MM+DD%27&description=Demo+task+definition+for+testing
```

##### 请求参数

|  Parameter  |说明|
|-------------|------------------------------------------------|
|   `name`    |创建的任务定义的名称|
|`definition` |任务的定义,使用数据流 DSL|
|`description`|任务定义的描述|

##### 示例请求

```
$ curl 'http://localhost:9393/tasks/definitions' -i -X POST \
    -d 'name=my-task&definition=timestamp+--format%3D%27YYYY+MM+DD%27&description=Demo+task+definition+for+testing'
```

##### 反应结构

```
HTTP/1.1 200 OK
Content-Type: application/hal+json
Content-Length: 342

{
  "name" : "my-task",
  "dslText" : "timestamp --format='YYYY MM DD'",
  "description" : "Demo task definition for testing",
  "composed" : false,
  "composedTaskElement" : false,
  "lastTaskExecution" : null,
  "status" : "UNKNOWN",
  "_links" : {
    "self" : {
      "href" : "http://localhost:9393/tasks/definitions/my-task"
    }
  }
}
```

#### 44.8.2.列出所有任务定义

任务定义端点允许你获得所有任务定义。以下主题提供了更多细节:

* [请求结构](#api-guide-resources-stream-task-definitions-list-request-structure)

* [请求参数](#api-guide-resources-stream-task-definitions-list-request-parameters)

* [示例请求](#api-guide-resources-stream-task-definitions-list-example-request)

* [反应结构](#api-guide-resources-stream-task-definitions-list-response-structure)

##### 请求结构

```
GET /tasks/definitions?page=0&size=10&sort=taskName%2CASC&search=&manifest=true HTTP/1.1
Host: localhost:9393
```

##### 请求参数

|Parameter |说明|
|----------|-------------------------------------------------------------------------------|
|  `page`  |基于零的页码(可选)|
|  `size`  |请求的页面大小(可选)|
| `search` |对名称执行的搜索字符串(可选)|
|  `sort`  |列表中的排序(可选)|
|`manifest`|将任务清单包含到最新任务执行中的标志(可选)|

##### 示例请求

```
$ curl 'http://localhost:9393/tasks/definitions?page=0&size=10&sort=taskName%2CASC&search=&manifest=true' -i -X GET
```

##### 反应结构

```
HTTP/1.1 200 OK
Content-Type: application/hal+json
Content-Length: 689

{
  "_embedded" : {
    "taskDefinitionResourceList" : [ {
      "name" : "my-task",
      "dslText" : "timestamp --format='YYYY MM DD'",
      "description" : "Demo task definition for testing",
      "composed" : false,
      "composedTaskElement" : false,
      "lastTaskExecution" : null,
      "status" : "UNKNOWN",
      "_links" : {
        "self" : {
          "href" : "http://localhost:9393/tasks/definitions/my-task"
        }
      }
    } ]
  },
  "_links" : {
    "self" : {
      "href" : "http://localhost:9393/tasks/definitions?page=0&size=10&sort=taskName,asc"
    }
  },
  "page" : {
    "size" : 10,
    "totalElements" : 1,
    "totalPages" : 1,
    "number" : 0
  }
}
```

#### 44.8.3.检索任务定义详细信息

任务定义端点允许你获得单个任务定义。以下主题提供了更多细节:

* [请求结构](#api-guide-resources-stream-task-definitions-detail-request-structure)

* [请求参数](#api-guide-resources-stream-task-definitions-detail-request-parameters)

* [示例请求](#api-guide-resources-stream-task-definitions-detail-example-request)

* [反应结构](#api-guide-resources-stream-task-definitions-detail-response-structure)

##### 请求结构

```
GET /tasks/definitions/my-task?manifest=true HTTP/1.1
Host: localhost:9393
```

/tasks/definitions/{my-task}

|Parameter|说明|
|---------|--------------------------------------------------|
|`my-task`|现有任务定义的名称(必需的)|

##### 请求参数

这个端点没有请求参数。

##### 示例请求

```
$ curl 'http://localhost:9393/tasks/definitions/my-task?manifest=true' -i -X GET
```

##### 反应结构

```
HTTP/1.1 200 OK
Content-Type: application/hal+json
Content-Length: 342

{
  "name" : "my-task",
  "dslText" : "timestamp --format='YYYY MM DD'",
  "description" : "Demo task definition for testing",
  "composed" : false,
  "composedTaskElement" : false,
  "lastTaskExecution" : null,
  "status" : "UNKNOWN",
  "_links" : {
    "self" : {
      "href" : "http://localhost:9393/tasks/definitions/my-task"
    }
  }
}
```

#### 44.8.4.删除任务定义

任务定义端点允许你删除单个任务定义。以下主题提供了更多细节:

* [请求结构](#api-guide-resources-delete-task-definition-request-structure)

* [请求参数](#api-guide-resources-delete-task-definition-request-parameters)

* [示例请求](#api-guide-resources-delete-task-definition-example-request)

* [反应结构](#api-guide-resources-delete-task-definition-response-structure)

##### 请求结构

```
DELETE /tasks/definitions/my-task?cleanup=true HTTP/1.1
Host: localhost:9393
```

/tasks/definitions/{my-task}

|Parameter|说明|
|---------|--------------------------------------------------|
|`my-task`|现有任务定义的名称(必需的)|

##### 请求参数

这个端点没有请求参数。

##### 示例请求

```
$ curl 'http://localhost:9393/tasks/definitions/my-task?cleanup=true' -i -X DELETE
```

##### 反应结构

```
HTTP/1.1 200 OK
```

### 44.9.任务调度程序

任务调度程序端点提供了有关已注册到调度程序实现中的任务调度的信息。以下主题提供了更多细节:

* [创建新的任务时间表](#api-guide-resources-task-schedule-creating)

* [列出所有时间表](#api-guide-resources-task-schedule-list)

* [列出过滤的时间表](#api-guide-resources-task-schedule-filtered-list)

* [删除任务时间表](#api-guide-resources-task-delete-schedule)

#### 44.9.1.创建新的任务时间表

任务调度端点允许你创建一个新的任务调度。以下主题提供了更多细节:

* [请求结构](#api-guide-resources-stream-task-schedule-creating-request-structure)

* [请求参数](#api-guide-resources-stream-task-schedule-creating-request-parameters)

* [示例请求](#api-guide-resources-stream-task-schedule-creating-example-request)

* [反应结构](#api-guide-resources-stream-task-schedule-creating-response-structure)

##### 请求结构

```
POST /tasks/schedules HTTP/1.1
Host: localhost:9393
Content-Type: application/x-www-form-urlencoded

scheduleName=myschedule&taskDefinitionName=mytaskname&properties=scheduler.cron.expression%3D00+22+17+%3F+*&arguments=--foo%3Dbar
```

##### 请求参数

|     Parameter      |说明|
|--------------------|----------------------------------------------------------------|
|   `scheduleName`   |创建的计划的名称|
|`taskDefinitionName`|要调度的任务定义的名称|
|    `properties`    |调度和启动任务所需的属性|
|    `arguments`     |用于启动任务的命令行参数|

##### 示例请求

```
$ curl 'http://localhost:9393/tasks/schedules' -i -X POST \
    -d 'scheduleName=myschedule&taskDefinitionName=mytaskname&properties=scheduler.cron.expression%3D00+22+17+%3F+*&arguments=--foo%3Dbar'
```

##### 反应结构

```
HTTP/1.1 201 Created
```

#### 44.9.2.列出所有时间表

任务调度端点允许你获取所有任务调度。以下主题提供了更多细节:

* [请求结构](#api-guide-resources-stream-task-schedule-list-request-structure)

* [请求参数](#api-guide-resources-stream-task-schedule-list-request-parameters)

* [示例请求](#api-guide-resources-stream-task-schedule-list-example-request)

* [反应结构](#api-guide-resources-stream-task-schedule-list-response-structure)

##### 请求结构

```
GET /tasks/schedules?page=0&size=10 HTTP/1.1
Host: localhost:9393
```

##### 请求参数

|Parameter|说明|
|---------|-------------------------------------|
| `page`  |基于零的页码(可选)|
| `size`  |请求的页面大小(可选)|

##### 示例请求

```
$ curl 'http://localhost:9393/tasks/schedules?page=0&size=10' -i -X GET
```

##### 反应结构

```
HTTP/1.1 200 OK
Content-Type: application/hal+json
Content-Length: 587

{
  "_embedded" : {
    "scheduleInfoResourceList" : [ {
      "scheduleName" : "FOO",
      "taskDefinitionName" : "BAR",
      "scheduleProperties" : {
        "scheduler.AAA.spring.cloud.scheduler.cron.expression" : "00 41 17 ? * *"
      },
      "_links" : {
        "self" : {
          "href" : "http://localhost:9393/tasks/schedules/FOO"
        }
      }
    } ]
  },
  "_links" : {
    "self" : {
      "href" : "http://localhost:9393/tasks/schedules?page=0&size=10"
    }
  },
  "page" : {
    "size" : 10,
    "totalElements" : 1,
    "totalPages" : 1,
    "number" : 0
  }
}
```

#### 44.9.3.列出过滤的时间表

任务调度端点允许你获得具有指定任务定义名称的所有任务调度。以下主题提供了更多细节:

* [请求结构](#api-guide-resources-stream-task-schedule-list-filtered-request-structure)

* [请求参数](#api-guide-resources-stream-task-schedule-list-filtered-request-parameters)

* [示例请求](#api-guide-resources-stream-task-schedule-list-filtered-example-request)

* [反应结构](#api-guide-resources-stream-task-schedule-list-filtered-response-structure)

##### 请求结构

```
GET /tasks/schedules/instances/FOO?page=0&size=10 HTTP/1.1
Host: localhost:9393
```

/tasks/schedues/instance/{task-definition-name}

|      Parameter       |说明|
|----------------------|------------------------------------------------------------------|
|`task-definition-name`|根据指定的任务定义(必需的)筛选计划|

##### 请求参数

|Parameter|说明|
|---------|-------------------------------------|
| `page`  |基于零的页码(可选)|
| `size`  |请求的页面大小(可选)|

##### 示例请求

```
$ curl 'http://localhost:9393/tasks/schedules/instances/FOO?page=0&size=10' -i -X GET
```

##### 反应结构

```
HTTP/1.1 200 OK
Content-Type: application/hal+json
Content-Length: 599

{
  "_embedded" : {
    "scheduleInfoResourceList" : [ {
      "scheduleName" : "FOO",
      "taskDefinitionName" : "BAR",
      "scheduleProperties" : {
        "scheduler.AAA.spring.cloud.scheduler.cron.expression" : "00 41 17 ? * *"
      },
      "_links" : {
        "self" : {
          "href" : "http://localhost:9393/tasks/schedules/FOO"
        }
      }
    } ]
  },
  "_links" : {
    "self" : {
      "href" : "http://localhost:9393/tasks/schedules/instances/FOO?page=0&size=1"
    }
  },
  "page" : {
    "size" : 1,
    "totalElements" : 1,
    "totalPages" : 1,
    "number" : 0
  }
}
```

#### 44.9.4.删除任务时间表

任务调度端点允许你删除单个任务调度。以下主题提供了更多细节:

* [请求结构](#api-guide-resources-delete-task-schedule-request-structure)

* [请求参数](#api-guide-resources-delete-task-schedule-request-parameters)

* [示例请求](#api-guide-resources-delete-task-schedule-example-request)

* [反应结构](#api-guide-resources-delete-task-schedule-response-structure)

##### 请求结构

```
DELETE /tasks/schedules/mytestschedule HTTP/1.1
Host: localhost:9393
```

/tasks/schedues/{schedulename}

|  Parameter   |说明|
|--------------|-------------------------------------------|
|`scheduleName`|现有时间表的名称(必需的)|

##### 请求参数

这个端点没有请求参数。

##### 示例请求

```
$ curl 'http://localhost:9393/tasks/schedules/mytestschedule' -i -X DELETE
```

##### 反应结构

```
HTTP/1.1 200 OK
```

### 44.10.任务验证

任务验证端点允许你在任务定义中验证应用程序。以下主题提供了更多细节:

* [请求结构](#api-guide-resources-task-validation-request-structure)

* [路径参数](#api-guide-resources-task-validation-path-parameters)

* [示例请求](#api-guide-resources-task-validation-example-request)

* [反应结构](#api-guide-resources-task-validation-response-structure)

#### 44.10.1.请求结构

```
GET /tasks/validation/taskC HTTP/1.1
Host: localhost:9393
```

#### 44.10.2.路径参数

/tasks/validation/{name}

|Parameter|说明|
|---------|--------------------------------------------------------|
| `name`  |要验证的任务定义的名称(必需的)|

#### 44.10.3.示例请求

```
$ curl 'http://localhost:9393/tasks/validation/taskC' -i -X GET
```

#### 44.10.4.反应结构

```
HTTP/1.1 200 OK
Content-Type: application/hal+json
Content-Length: 144

{
  "appName" : "taskC",
  "dsl" : "timestamp --format='yyyy MM dd'",
  "description" : "",
  "appStatuses" : {
    "task:taskC" : "valid"
  }
}
```

### 44.11.任务执行

任务执行端点提供了有关在 Spring 云数据流服务器上注册的任务执行的信息。以下主题提供了更多细节:

* [启动一项任务](#api-guide-resources-task-executions-launching)

* [停止任务](#api-guide-resources-task-executions-stopping)

* [列出所有的任务执行](#api-guide-resources-task-executions-list)

* [用指定的任务名列出所有的任务执行](#api-guide-resources-task-executions-list-by-name)

* [任务执行细节](#api-guide-resources-task-executions-detail)

* [删除任务执行](#api-guide-resources-task-executions-delete)

* [任务执行当前计数](#api-guide-resources-task-executions-current-count)

#### 44.11.1.启动一项任务

通过请求创建新的任务执行来启动任务。以下主题提供了更多细节:

* [请求结构](#api-guide-resources-task-executions-launching-request-structure)

* [请求参数](#api-guide-resources-task-executions-launching-request-parameters)

* [示例请求](#api-guide-resources-task-executions-launching-example-request)

* [反应结构](#api-guide-resources-task-executions-launching-response-structure)

##### 请求结构

```
POST /tasks/executions HTTP/1.1
Host: localhost:9393
Content-Type: application/x-www-form-urlencoded

name=taskA&properties=app.my-task.foo%3Dbar%2Cdeployer.my-task.something-else%3D3&arguments=--server.port%3D8080+--foo%3Dbar
```

##### 请求参数

| Parameter  |说明|
|------------|----------------------------------------------------------|
|   `name`   |要启动的任务定义的名称|
|`properties`|启动时要使用的应用程序和部署程序属性|
|`arguments` |要传递给任务的命令行参数|

##### 示例请求

```
$ curl 'http://localhost:9393/tasks/executions' -i -X POST \
    -d 'name=taskA&properties=app.my-task.foo%3Dbar%2Cdeployer.my-task.something-else%3D3&arguments=--server.port%3D8080+--foo%3Dbar'
```

##### 反应结构

```
HTTP/1.1 201 Created
Content-Type: application/json
Content-Length: 1

1
```

#### 44.11.2.停止任务

停止任务是通过发布现有任务执行的 ID 来完成的。以下主题提供了更多细节:

* [请求结构](#api-guide-resources-task-executions-stopping-request-structure)

* [路径参数](#api-guide-resources-task-executions-stopping-path-parameters)

* [请求参数](#api-guide-resources-task-executions-stopping-request-parameters)

* [示例请求](#api-guide-resources-task-executions-stopping-example-request)

* [反应结构](#api-guide-resources-task-executions-stopping-response-structure)

##### 请求结构

```
POST /tasks/executions/1 HTTP/1.1
Host: localhost:9393
Content-Type: application/x-www-form-urlencoded

platform=default
```

##### 路径参数

/任务/执行/{id}

|Parameter|说明|
|---------|------------------------------------------------|
|  `id`   |现有任务执行的 ID(必需的)|

##### 请求参数

|Parameter |说明|
|----------|---------------------------------------------------------|
|`platform`|与任务执行相关联的平台(可选)|

##### 示例请求

```
$ curl 'http://localhost:9393/tasks/executions/1' -i -X POST \
    -d 'platform=default'
```

##### 反应结构

```
HTTP/1.1 200 OK
```

#### 44.11.3.列出所有的任务执行

Task Executions Endpoint 允许你列出所有的任务执行。以下主题提供了更多细节:

* [请求结构](#api-guide-resources-task-executions-list-request-structure)

* [请求参数](#api-guide-resources-task-executions-list-request-parameters)

* [示例请求](#api-guide-resources-task-executions-list-example-request)

* [反应结构](#api-guide-resources-task-executions-list-response-structure)

##### 请求结构

```
GET /tasks/executions?page=0&size=10 HTTP/1.1
Host: localhost:9393
```

##### 请求参数

|Parameter|说明|
|---------|-------------------------------------|
| `page`  |基于零的页码(可选)|
| `size`  |请求的页面大小(可选)|

##### 示例请求

```
$ curl 'http://localhost:9393/tasks/executions?page=0&size=10' -i -X GET
```

##### 反应结构

```
HTTP/1.1 200 OK
Content-Type: application/hal+json
Content-Length: 2711

{
  "_embedded" : {
    "taskExecutionResourceList" : [ {
      "executionId" : 2,
      "exitCode" : null,
      "taskName" : "taskB",
      "startTime" : null,
      "endTime" : null,
      "exitMessage" : null,
      "arguments" : [ ],
      "jobExecutionIds" : [ ],
      "errorMessage" : null,
      "externalExecutionId" : "taskB-7939f7fe-40a8-438c-a00c-4b2e041a42a7",
      "parentExecutionId" : null,
      "resourceUrl" : "org.springframework.cloud.task.app:timestamp-task:jar:1.2.0.RELEASE",
      "appProperties" : {
        "management.metrics.tags.service" : "task-application",
        "timestamp.format" : "yyyy MM dd",
        "spring.datasource.username" : null,
        "spring.datasource.url" : null,
        "spring.datasource.driverClassName" : null,
        "management.metrics.tags.application" : "${spring.cloud.task.name:unknown}-${spring.cloud.task.executionid:unknown}",
        "spring.cloud.task.name" : "taskB"
      },
      "deploymentProperties" : {
        "app.my-task.foo" : "bar",
        "deployer.my-task.something-else" : "3"
      },
      "platformName" : "default",
      "taskExecutionStatus" : "UNKNOWN",
      "_links" : {
        "self" : {
          "href" : "http://localhost:9393/tasks/executions/2"
        }
      }
    }, {
      "executionId" : 1,
      "exitCode" : null,
      "taskName" : "taskA",
      "startTime" : null,
      "endTime" : null,
      "exitMessage" : null,
      "arguments" : [ ],
      "jobExecutionIds" : [ ],
      "errorMessage" : null,
      "externalExecutionId" : "taskA-37a1d8dd-9c33-4080-859f-899ed0e91b84",
      "parentExecutionId" : null,
      "resourceUrl" : "org.springframework.cloud.task.app:timestamp-task:jar:1.2.0.RELEASE",
      "appProperties" : {
        "management.metrics.tags.service" : "task-application",
        "timestamp.format" : "yyyy MM dd",
        "spring.datasource.username" : null,
        "spring.datasource.url" : null,
        "spring.datasource.driverClassName" : null,
        "management.metrics.tags.application" : "${spring.cloud.task.name:unknown}-${spring.cloud.task.executionid:unknown}",
        "spring.cloud.task.name" : "taskA"
      },
      "deploymentProperties" : {
        "app.my-task.foo" : "bar",
        "deployer.my-task.something-else" : "3"
      },
      "platformName" : "default",
      "taskExecutionStatus" : "UNKNOWN",
      "_links" : {
        "self" : {
          "href" : "http://localhost:9393/tasks/executions/1"
        }
      }
    } ]
  },
  "_links" : {
    "self" : {
      "href" : "http://localhost:9393/tasks/executions?page=0&size=10"
    }
  },
  "page" : {
    "size" : 10,
    "totalElements" : 2,
    "totalPages" : 1,
    "number" : 0
  }
}
```

#### 44.11.4.用指定的任务名列出所有的任务执行

Task Executions Endpoint 允许你使用指定的任务名称列出任务执行。以下主题提供了更多细节:

* [请求结构](#api-guide-resources-task-executions-list-by-name-request-structure)

* [请求参数](#api-guide-resources-task-executions-list-by-name-request-parameters)

* [示例请求](#api-guide-resources-task-executions-list-by-name-example-request)

* [反应结构](#api-guide-resources-task-executions-list-by-name-response-structure)

##### 请求结构

```
GET /tasks/executions?name=taskB&page=0&size=10 HTTP/1.1
Host: localhost:9393
```

##### 请求参数

|Parameter|说明|
|---------|-------------------------------------------|
| `page`  |基于零的页码(可选)|
| `size`  |请求的页面大小(可选)|
| `name`  |与任务执行相关联的名称|

##### 示例请求

```
$ curl 'http://localhost:9393/tasks/executions?name=taskB&page=0&size=10' -i -X GET
```

##### 反应结构

```
HTTP/1.1 200 OK
Content-Type: application/hal+json
Content-Length: 1492

{
  "_embedded" : {
    "taskExecutionResourceList" : [ {
      "executionId" : 2,
      "exitCode" : null,
      "taskName" : "taskB",
      "startTime" : null,
      "endTime" : null,
      "exitMessage" : null,
      "arguments" : [ ],
      "jobExecutionIds" : [ ],
      "errorMessage" : null,
      "externalExecutionId" : "taskB-7939f7fe-40a8-438c-a00c-4b2e041a42a7",
      "parentExecutionId" : null,
      "resourceUrl" : "org.springframework.cloud.task.app:timestamp-task:jar:1.2.0.RELEASE",
      "appProperties" : {
        "management.metrics.tags.service" : "task-application",
        "timestamp.format" : "yyyy MM dd",
        "spring.datasource.username" : null,
        "spring.datasource.url" : null,
        "spring.datasource.driverClassName" : null,
        "management.metrics.tags.application" : "${spring.cloud.task.name:unknown}-${spring.cloud.task.executionid:unknown}",
        "spring.cloud.task.name" : "taskB"
      },
      "deploymentProperties" : {
        "app.my-task.foo" : "bar",
        "deployer.my-task.something-else" : "3"
      },
      "platformName" : "default",
      "taskExecutionStatus" : "UNKNOWN",
      "_links" : {
        "self" : {
          "href" : "http://localhost:9393/tasks/executions/2"
        }
      }
    } ]
  },
  "_links" : {
    "self" : {
      "href" : "http://localhost:9393/tasks/executions?page=0&size=10"
    }
  },
  "page" : {
    "size" : 10,
    "totalElements" : 1,
    "totalPages" : 1,
    "number" : 0
  }
}
```

#### 44.11.5.任务执行细节

Task Executions Endpoint 允许你获得有关任务执行的详细信息。以下主题提供了更多细节:

* [请求结构](#api-guide-resources-task-executions-detail-request-structure)

* [请求参数](#api-guide-resources-task-executions-detail-request-parameters)

* [示例请求](#api-guide-resources-task-executions-detail-example-request)

* [反应结构](#api-guide-resources-task-executions-detail-response-structure)

##### 请求结构

```
GET /tasks/executions/1 HTTP/1.1
Host: localhost:9393
```

/任务/执行/{id}

|Parameter|说明|
|---------|-----------------------------------------------|
|  `id`   |现有任务执行的 ID(必需的)|

##### 请求参数

这个端点没有请求参数。

##### 示例请求

```
$ curl 'http://localhost:9393/tasks/executions/1' -i -X GET
```

##### 反应结构

```
HTTP/1.1 200 OK
Content-Type: application/hal+json
Content-Length: 1085

{
  "executionId" : 1,
  "exitCode" : null,
  "taskName" : "taskA",
  "startTime" : null,
  "endTime" : null,
  "exitMessage" : null,
  "arguments" : [ ],
  "jobExecutionIds" : [ ],
  "errorMessage" : null,
  "externalExecutionId" : "taskA-37a1d8dd-9c33-4080-859f-899ed0e91b84",
  "parentExecutionId" : null,
  "resourceUrl" : "org.springframework.cloud.task.app:timestamp-task:jar:1.2.0.RELEASE",
  "appProperties" : {
    "management.metrics.tags.service" : "task-application",
    "timestamp.format" : "yyyy MM dd",
    "spring.datasource.username" : null,
    "spring.datasource.url" : null,
    "spring.datasource.driverClassName" : null,
    "management.metrics.tags.application" : "${spring.cloud.task.name:unknown}-${spring.cloud.task.executionid:unknown}",
    "spring.cloud.task.name" : "taskA"
  },
  "deploymentProperties" : {
    "app.my-task.foo" : "bar",
    "deployer.my-task.something-else" : "3"
  },
  "platformName" : "default",
  "taskExecutionStatus" : "UNKNOWN",
  "_links" : {
    "self" : {
      "href" : "http://localhost:9393/tasks/executions/1"
    }
  }
}
```

#### 44.11.6.删除任务执行

任务执行端点允许你:

* 清理用于部署任务的资源

* 从持久性存储中删除相关的任务数据以及可能相关的 Spring 批处理作业数据

|   |清理实现(第一个选项)是特定于平台的。这两个操作都可以一次或单独触发<br/>。|
|---|---------------------------------------------------------------------------------------------------------------------------|

以下主题提供了更多细节:

* [请求结构](#api-guide-resources-task-executions-delete-request-structure)

* [请求参数](#api-guide-resources-task-executions-delete-request-parameters)

* [示例请求](#api-guide-resources-task-executions-delete-example-request)

* [反应结构](#api-guide-resources-task-executions-delete-response-structure)

请参阅以下有关[删除任务执行数据](#api-guide-resources-task-executions-delete-multiple-and-task-data)的部分。

##### 请求结构

```
DELETE /tasks/executions/1,2?action=CLEANUP,REMOVE_DATA HTTP/1.1
Host: localhost:9393
```

/任务/执行/{ids}

|Parameter|说明|
|---------|-----------------------------------------------------|
|  `ids`  |提供 2 个逗号分隔的任务执行 ID 值。|

|   |你必须提供实际存在的任务执行 ID。否则,将返回`404`(未找到)HTTP 状态。<br/>在提交多个任务执行 ID 的情况下,单个任务执行 ID 的无效将导致整个请求失败,<br/>不执行任何操作。|
|---|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

##### 请求参数

这个端点支持一个名为**行动**的可选请求参数。它是一个枚举,支持以下值:

* CLEANUP

* 删除 \_ 数据

|Parameter|说明|
|---------|-----------------------------------------------------------|
|`action` |同时使用两个动作清理和删除 \_data。|

##### 示例请求

```
$ curl 'http://localhost:9393/tasks/executions/1,2?action=CLEANUP,REMOVE_DATA' -i -X DELETE
```

##### 反应结构

```
HTTP/1.1 200 OK
```

#### 44.11.7.删除任务执行数据

你不仅可以清理用于部署任务的资源,还可以从底层持久性存储中删除与任务执行相关的数据。此外,如果一个任务执行与一个或多个批处理作业执行相关联,那么这些执行也会被删除。

下面的示例说明了如何使用多个任务执行 ID 和多个动作来发出请求:

```
$ curl 'http://localhost:9393/tasks/executions/1,2?action=CLEANUP,REMOVE_DATA' -i -X DELETE
```

/任务/执行/{ids}

|Parameter|说明|
|---------|-----------------------------------------------------|
|  `ids`  |提供 2 个逗号分隔的任务执行 ID 值。|

|Parameter|说明|
|---------|-----------------------------------------------------------|
|`action` |同时使用两个动作清理和删除 \_data。|

|   |当使用`REMOVE_DATA`动作参数从持久性存储中删除数据时,你必须提供表示父任务执行的<br/>任务执行 ID。当你提供子任务执行(作为组合任务的一部分执行)时,将返回<br/>a`400`(错误请求)HTTP 状态。|
|---|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

|   |当删除大量的任务执行时,一些数据库类型限制`IN`子句中的条目数量(云数据流用来删除任务执行关系的方法)。<br/> Spring 云数据流支持 SQL Server 的分块删除(最多 2100 个条目)和 Oracle DBS(最多 1000 个条目)。<br/>然而, Spring 云数据流允许用户设置自己的分块因子。要做到这一点,将`spring.cloud.dataflow.task.executionDeleteChunkSize`属性设置为适当的块大小。<br/>默认值为`0`,这意味着 Spring 云数据流不会将块任务执行删除(Oracle 和 SQL Server 数据库除外)。|
|---|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

#### 44.11.8.任务执行当前计数

Task Executions Current Endpoint 允许你检索当前运行的执行次数。以下主题提供了更多细节:

* [请求结构](#api-guide-resources-task-executions-current-count-request-structure)

* [请求参数](#api-guide-resources-task-executions-current-count-request-parameters)

* [示例请求](#api-guide-resources-task-executions-current-count-example-request)

* [反应结构](#api-guide-resources-task-executions-current-count-response-structure)

##### 请求结构

ADOC-包括:/home/runner/work/ Spring-cloud-dataflow/ Spring-cloud-dataflow/ Spring-cloud-dataflow-DOCS/../ Spring-cloud-dataflow-classic-DOCS/target/genered-snippets/task-executions-documentation/launch-task-current-count/http-request.ADOC[]

##### 请求参数

这个端点没有请求参数。

##### 示例请求

ADOC-包括:/home/runner/work/ Spring-cloud-dataflow/ Spring-cloud-dataflow/ Spring-cloud-dataflow-DOCS/../ Spring-cloud-dataflow-classic-DOCS/target/generated-snippets/task-executions-documentation/launch-task-current/current-count/curl-request.ADOC[]

##### 反应结构

ADOC-包括:/home/runner/work/ Spring-cloud-dataflow/ Spring-cloud-dataflow/ Spring-cloud-dataflow-DOCS/../ Spring-cloud-dataflow-classic-DOCS/target/generated-snippets/task-executions-documentation/launch-task-current-current-count/http-response.ADOC[]

### 44.12.工作执行

作业执行端点提供了关于在 Spring 云数据流服务器上注册的作业执行的信息。以下主题提供了更多细节:

* [列出所有的工作执行](#api-guide-resources-job-executions-list)

* [列出所有未包含步骤执行的作业执行](#api-guide-resources-job-executions-thin-job-execution-list)

* [用指定的作业名称列出所有作业执行](#api-guide-resources-job-executions-job-execution-info-only-list-by-name)

* [列出所有具有指定作业名的作业执行,但不包括步骤执行](#api-guide-resources-job-executions-thin-job-execution-info-only-list-by-name)

* [列出指定日期范围内不包括步骤执行的所有作业执行](#api-guide-resources-job-executions-thin-job-execution-info-only-list-by-date)

* [列出指定作业实例 ID 的所有作业执行,其中不包括步骤执行](#api-guide-resources-job-executions-thin-job-execution-info-only-list-by-job-instance-id)

* [列出指定任务执行 ID 的所有作业执行,但不包括步骤执行](#api-guide-resources-job-executions-thin-job-execution-info-only-list-by-task-execution-id)

* [作业执行细节](#api-guide-resources-job-executions-detail)

* [停止作业执行](#api-guide-resources-job-executions-stop)

* [重新启动作业执行](#api-guide-resources-job-executions-restart)

#### 44.12.1.列出所有的工作执行

作业执行端点允许你列出所有作业执行。以下主题提供了更多细节:

* [请求结构](#api-guide-resources-job-executions-list-request-structure)

* [请求参数](#api-guide-resources-job-executions-list-request-parameters)

* [示例请求](#api-guide-resources-job-executions-list-example-request)

* [反应结构](#api-guide-resources-job-executions-list-response-structure)

##### 请求结构

```
GET /jobs/executions?page=0&size=10 HTTP/1.1
Host: localhost:9393
```

##### 请求参数

|Parameter|说明|
|---------|-------------------------------------|
| `page`  |基于零的页码(可选)|
| `size`  |请求的页面大小(可选)|

##### 示例请求

```
$ curl 'http://localhost:9393/jobs/executions?page=0&size=10' -i -X GET
```

##### 反应结构

```
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 3066

{
  "_embedded" : {
    "jobExecutionResourceList" : [ {
      "executionId" : 2,
      "stepExecutionCount" : 0,
      "jobId" : 2,
      "taskExecutionId" : 2,
      "name" : "DOCJOB1",
      "startDate" : "2022-01-18",
      "startTime" : "18:54:42",
      "duration" : "00:00:00",
      "jobExecution" : {
        "id" : 2,
        "version" : 1,
        "jobParameters" : {
          "parameters" : { }
        },
        "jobInstance" : {
          "id" : 2,
          "jobName" : "DOCJOB1",
          "version" : null
        },
        "stepExecutions" : [ ],
        "status" : "STOPPED",
        "startTime" : "2022-01-18T18:54:42.193+0000",
        "createTime" : "2022-01-18T18:54:42.192+0000",
        "endTime" : null,
        "lastUpdated" : "2022-01-18T18:54:42.193+0000",
        "exitStatus" : {
          "exitCode" : "UNKNOWN",
          "exitDescription" : ""
        },
        "executionContext" : {
          "dirty" : false,
          "empty" : true,
          "values" : [ ]
        },
        "failureExceptions" : [ ],
        "jobConfigurationName" : null,
        "allFailureExceptions" : [ ]
      },
      "jobParameters" : { },
      "jobParametersString" : "",
      "restartable" : true,
      "abandonable" : true,
      "stoppable" : false,
      "defined" : true,
      "timeZone" : "UTC",
      "_links" : {
        "self" : {
          "href" : "http://localhost:9393/jobs/executions/2"
        }
      }
    }, {
      "executionId" : 1,
      "stepExecutionCount" : 0,
      "jobId" : 1,
      "taskExecutionId" : 1,
      "name" : "DOCJOB",
      "startDate" : "2022-01-18",
      "startTime" : "18:54:42",
      "duration" : "00:00:00",
      "jobExecution" : {
        "id" : 1,
        "version" : 2,
        "jobParameters" : {
          "parameters" : { }
        },
        "jobInstance" : {
          "id" : 1,
          "jobName" : "DOCJOB",
          "version" : null
        },
        "stepExecutions" : [ ],
        "status" : "STOPPING",
        "startTime" : "2022-01-18T18:54:42.189+0000",
        "createTime" : "2022-01-18T18:54:42.188+0000",
        "endTime" : null,
        "lastUpdated" : "2022-01-18T18:54:42.260+0000",
        "exitStatus" : {
          "exitCode" : "UNKNOWN",
          "exitDescription" : ""
        },
        "executionContext" : {
          "dirty" : false,
          "empty" : true,
          "values" : [ ]
        },
        "failureExceptions" : [ ],
        "jobConfigurationName" : null,
        "allFailureExceptions" : [ ]
      },
      "jobParameters" : { },
      "jobParametersString" : "",
      "restartable" : false,
      "abandonable" : true,
      "stoppable" : false,
      "defined" : false,
      "timeZone" : "UTC",
      "_links" : {
        "self" : {
          "href" : "http://localhost:9393/jobs/executions/1"
        }
      }
    } ]
  },
  "_links" : {
    "self" : {
      "href" : "http://localhost:9393/jobs/executions?page=0&size=10"
    }
  },
  "page" : {
    "size" : 10,
    "totalElements" : 2,
    "totalPages" : 1,
    "number" : 0
  }
}
```

#### 44.12.2.列出所有未包含步骤执行的作业执行

作业执行端点允许你列出不包括步骤执行的所有作业执行。以下主题提供了更多细节:

* [请求结构](#api-guide-resources-job-executions-thin-job-execution-list-request-structure)

* [请求参数](#api-guide-resources-job-executions-thin-job-execution-list-request-parameters)

* [示例请求](#api-guide-resources-job-executions-thin-job-execution-list-example-request)

* [反应结构](#api-guide-resources-job-executions-thin-job-execution-list-response-structure)

##### 请求结构

```
GET /jobs/thinexecutions?page=0&size=10 HTTP/1.1
Host: localhost:9393
```

##### 请求参数

|Parameter|说明|
|---------|-------------------------------------|
| `page`  |基于零的页码(可选)|
| `size`  |请求的页面大小(可选)|

##### 示例请求

```
$ curl 'http://localhost:9393/jobs/thinexecutions?page=0&size=10' -i -X GET
```

##### 反应结构

```
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 1604

{
  "_embedded" : {
    "jobExecutionThinResourceList" : [ {
      "executionId" : 2,
      "stepExecutionCount" : 0,
      "jobId" : 2,
      "taskExecutionId" : 2,
      "instanceId" : 2,
      "name" : "DOCJOB1",
      "startDate" : "2022-01-18",
      "startTime" : "18:54:42",
      "startDateTime" : "2022-01-18T18:54:42.193+0000",
      "duration" : "00:00:00",
      "jobParameters" : { },
      "jobParametersString" : "",
      "restartable" : true,
      "abandonable" : true,
      "stoppable" : false,
      "defined" : true,
      "timeZone" : "UTC",
      "status" : "STOPPED",
      "_links" : {
        "self" : {
          "href" : "http://localhost:9393/jobs/thinexecutions/2"
        }
      }
    }, {
      "executionId" : 1,
      "stepExecutionCount" : 0,
      "jobId" : 1,
      "taskExecutionId" : 1,
      "instanceId" : 1,
      "name" : "DOCJOB",
      "startDate" : "2022-01-18",
      "startTime" : "18:54:42",
      "startDateTime" : "2022-01-18T18:54:42.189+0000",
      "duration" : "00:00:00",
      "jobParameters" : { },
      "jobParametersString" : "",
      "restartable" : false,
      "abandonable" : false,
      "stoppable" : true,
      "defined" : false,
      "timeZone" : "UTC",
      "status" : "STARTED",
      "_links" : {
        "self" : {
          "href" : "http://localhost:9393/jobs/thinexecutions/1"
        }
      }
    } ]
  },
  "_links" : {
    "self" : {
      "href" : "http://localhost:9393/jobs/thinexecutions?page=0&size=10"
    }
  },
  "page" : {
    "size" : 10,
    "totalElements" : 2,
    "totalPages" : 1,
    "number" : 0
  }
}
```

#### 44.12.3.用指定的作业名称列出所有作业执行

作业执行端点允许你列出所有作业执行。以下主题提供了更多细节:

* [请求结构](#api-guide-resources-job-executions-list-by-name-request-structure)

* [请求参数](#api-guide-resources-job-executions-list-by-name-request-parameters)

* [示例请求](#api-guide-resources-job-executions-list-by-name-example-request)

* [反应结构](#api-guide-resources-job-executions-list-by-name-response-structure)

##### 请求结构

```
GET /jobs/executions?name=DOCJOB&page=0&size=10 HTTP/1.1
Host: localhost:9393
```

##### 请求参数

|Parameter|说明|
|---------|------------------------------------------|
| `page`  |基于零的页码(可选)|
| `size`  |请求的页面大小(可选)|
| `name`  |与作业执行相关联的名称|

##### 示例请求

```
$ curl 'http://localhost:9393/jobs/executions?name=DOCJOB&page=0&size=10' -i -X GET
```

##### 反应结构

```
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 1669

{
  "_embedded" : {
    "jobExecutionResourceList" : [ {
      "executionId" : 1,
      "stepExecutionCount" : 0,
      "jobId" : 1,
      "taskExecutionId" : 1,
      "name" : "DOCJOB",
      "startDate" : "2022-01-18",
      "startTime" : "18:54:42",
      "duration" : "00:00:00",
      "jobExecution" : {
        "id" : 1,
        "version" : 2,
        "jobParameters" : {
          "parameters" : { }
        },
        "jobInstance" : {
          "id" : 1,
          "jobName" : "DOCJOB",
          "version" : null
        },
        "stepExecutions" : [ ],
        "status" : "STOPPING",
        "startTime" : "2022-01-18T18:54:42.189+0000",
        "createTime" : "2022-01-18T18:54:42.188+0000",
        "endTime" : null,
        "lastUpdated" : "2022-01-18T18:54:42.260+0000",
        "exitStatus" : {
          "exitCode" : "UNKNOWN",
          "exitDescription" : ""
        },
        "executionContext" : {
          "dirty" : false,
          "empty" : true,
          "values" : [ ]
        },
        "failureExceptions" : [ ],
        "jobConfigurationName" : null,
        "allFailureExceptions" : [ ]
      },
      "jobParameters" : { },
      "jobParametersString" : "",
      "restartable" : false,
      "abandonable" : true,
      "stoppable" : false,
      "defined" : false,
      "timeZone" : "UTC",
      "_links" : {
        "self" : {
          "href" : "http://localhost:9393/jobs/executions/1"
        }
      }
    } ]
  },
  "_links" : {
    "self" : {
      "href" : "http://localhost:9393/jobs/executions?page=0&size=10"
    }
  },
  "page" : {
    "size" : 10,
    "totalElements" : 1,
    "totalPages" : 1,
    "number" : 0
  }
}
```

#### 44.12.4.列出所有具有指定作业名的作业执行,但不包括步骤执行

作业执行端点允许你列出所有作业执行。以下主题提供了更多细节:

* [请求结构](#api-guide-resources-job-executions-thin-list-by-name-request-structure)

* [请求参数](#api-guide-resources-job-executions-thin-list-by-name-request-parameters)

* [示例请求](#api-guide-resources-job-executions-thin-list-by-name-example-request)

* [反应结构](#api-guide-resources-job-executions-thin-list-by-name-response-structure)

##### 请求结构

```
GET /jobs/thinexecutions?name=DOCJOB&page=0&size=10 HTTP/1.1
Host: localhost:9393
```

##### 请求参数

|Parameter|说明|
|---------|------------------------------------------|
| `page`  |基于零的页码(可选)|
| `size`  |请求的页面大小(可选)|
| `name`  |与作业执行相关联的名称|

##### 示例请求

```
$ curl 'http://localhost:9393/jobs/thinexecutions?name=DOCJOB&page=0&size=10' -i -X GET
```

##### 反应结构

```
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 943

{
  "_embedded" : {
    "jobExecutionThinResourceList" : [ {
      "executionId" : 1,
      "stepExecutionCount" : 0,
      "jobId" : 1,
      "taskExecutionId" : 1,
      "instanceId" : 1,
      "name" : "DOCJOB",
      "startDate" : "2022-01-18",
      "startTime" : "18:54:42",
      "startDateTime" : "2022-01-18T18:54:42.189+0000",
      "duration" : "00:00:00",
      "jobParameters" : { },
      "jobParametersString" : "",
      "restartable" : false,
      "abandonable" : true,
      "stoppable" : false,
      "defined" : false,
      "timeZone" : "UTC",
      "status" : "STOPPING",
      "_links" : {
        "self" : {
          "href" : "http://localhost:9393/jobs/thinexecutions/1"
        }
      }
    } ]
  },
  "_links" : {
    "self" : {
      "href" : "http://localhost:9393/jobs/thinexecutions?page=0&size=10"
    }
  },
  "page" : {
    "size" : 10,
    "totalElements" : 1,
    "totalPages" : 1,
    "number" : 0
  }
}
```

#### 44.12.5.列出指定日期范围内不包括步骤执行的所有作业执行

作业执行端点允许你列出所有作业执行。以下主题提供了更多细节:

* [请求结构](#api-guide-resources-job-executions-thin-list-by-date-request-structure)

* [请求参数](#api-guide-resources-job-executions-thin-list-by-date-request-parameters)

* [示例请求](#api-guide-resources-job-executions-thin-list-by-date-example-request)

* [反应结构](#api-guide-resources-job-executions-thin-list-by-date-response-structure)

##### 请求结构

```
GET /jobs/thinexecutions?page=0&size=10&fromDate=2000-09-24T17%3A00%3A45%2C000&toDate=2050-09-24T18%3A00%3A45%2C000 HTTP/1.1
Host: localhost:9393
```

##### 请求参数

|Parameter |说明|
|----------|----------------------------------------------------------------------------|
|  `page`  |基于零的页码(可选)|
|  `size`  |请求的页面大小(可选)|
|`fromDate`|以“yyyy-mm-dd’t”格式筛选来自起始日期的结果,格式为:mm:ss,sss|
| `toDate` |过滤结果到`to`日期,格式为“yyyy-mm-dd’t”hh:mm:ss,sss"|

##### 示例请求

```
$ curl 'http://localhost:9393/jobs/thinexecutions?page=0&size=10&fromDate=2000-09-24T17%3A00%3A45%2C000&toDate=2050-09-24T18%3A00%3A45%2C000' -i -X GET
```

##### 反应结构

```
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 1605

{
  "_embedded" : {
    "jobExecutionThinResourceList" : [ {
      "executionId" : 2,
      "stepExecutionCount" : 0,
      "jobId" : 2,
      "taskExecutionId" : 2,
      "instanceId" : 2,
      "name" : "DOCJOB1",
      "startDate" : "2022-01-18",
      "startTime" : "18:54:42",
      "startDateTime" : "2022-01-18T18:54:42.193+0000",
      "duration" : "00:00:00",
      "jobParameters" : { },
      "jobParametersString" : "",
      "restartable" : true,
      "abandonable" : true,
      "stoppable" : false,
      "defined" : true,
      "timeZone" : "UTC",
      "status" : "STOPPED",
      "_links" : {
        "self" : {
          "href" : "http://localhost:9393/jobs/thinexecutions/2"
        }
      }
    }, {
      "executionId" : 1,
      "stepExecutionCount" : 0,
      "jobId" : 1,
      "taskExecutionId" : 1,
      "instanceId" : 1,
      "name" : "DOCJOB",
      "startDate" : "2022-01-18",
      "startTime" : "18:54:42",
      "startDateTime" : "2022-01-18T18:54:42.189+0000",
      "duration" : "00:00:00",
      "jobParameters" : { },
      "jobParametersString" : "",
      "restartable" : false,
      "abandonable" : true,
      "stoppable" : false,
      "defined" : false,
      "timeZone" : "UTC",
      "status" : "STOPPING",
      "_links" : {
        "self" : {
          "href" : "http://localhost:9393/jobs/thinexecutions/1"
        }
      }
    } ]
  },
  "_links" : {
    "self" : {
      "href" : "http://localhost:9393/jobs/thinexecutions?page=0&size=10"
    }
  },
  "page" : {
    "size" : 10,
    "totalElements" : 2,
    "totalPages" : 1,
    "number" : 0
  }
}
```

#### 44.12.6.列出指定作业实例 ID 的所有作业执行,其中不包括步骤执行

作业执行端点允许你列出所有作业执行。以下主题提供了更多细节:

* [请求结构](#api-guide-resources-job-executions-thin-list-by-job-instance-id-request-structure)

* [请求参数](#api-guide-resources-job-executions-thin-list-by-job-instance-id-request-parameters)

* [示例请求](#api-guide-resources-job-executions-thin-list-by-job-instance-id-example-request)

* [反应结构](#api-guide-resources-job-executions-thin-list-by-job-instance-id-response-structure)

##### 请求结构

```
GET /jobs/thinexecutions?page=0&size=10&jobInstanceId=1 HTTP/1.1
Host: localhost:9393
```

##### 请求参数

|   Parameter   |说明|
|---------------|-------------------------------------|
|    `page`     |基于零的页码(可选)|
|    `size`     |请求的页面大小(可选)|
|`jobInstanceId`|根据作业实例 ID 筛选结果|

##### 示例请求

```
$ curl 'http://localhost:9393/jobs/thinexecutions?page=0&size=10&jobInstanceId=1' -i -X GET
```

##### 反应结构

```
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 943

{
  "_embedded" : {
    "jobExecutionThinResourceList" : [ {
      "executionId" : 1,
      "stepExecutionCount" : 0,
      "jobId" : 1,
      "taskExecutionId" : 1,
      "instanceId" : 1,
      "name" : "DOCJOB",
      "startDate" : "2022-01-18",
      "startTime" : "18:54:42",
      "startDateTime" : "2022-01-18T18:54:42.189+0000",
      "duration" : "00:00:00",
      "jobParameters" : { },
      "jobParametersString" : "",
      "restartable" : false,
      "abandonable" : true,
      "stoppable" : false,
      "defined" : false,
      "timeZone" : "UTC",
      "status" : "STOPPING",
      "_links" : {
        "self" : {
          "href" : "http://localhost:9393/jobs/thinexecutions/1"
        }
      }
    } ]
  },
  "_links" : {
    "self" : {
      "href" : "http://localhost:9393/jobs/thinexecutions?page=0&size=10"
    }
  },
  "page" : {
    "size" : 10,
    "totalElements" : 1,
    "totalPages" : 1,
    "number" : 0
  }
}
```

#### 44.12.7.列出指定任务执行 ID 的所有作业执行,但不包括步骤执行

作业执行端点允许你列出所有作业执行。以下主题提供了更多细节:

* [请求结构](#api-guide-resources-job-executions-thin-list-by-task-execution-id-request-structure)

* [请求参数](#api-guide-resources-job-executions-thin-list-by-task-execution-id-request-parameters)

* [示例请求](#api-guide-resources-job-executions-thin-list-by-task-execution-id-example-request)

* [反应结构](#api-guide-resources-job-executions-thin-list-by-task-execution-id-response-structure)

##### 请求结构

```
GET /jobs/thinexecutions?page=0&size=10&taskExecutionId=1 HTTP/1.1
Host: localhost:9393
```

##### 请求参数

|    Parameter    |说明|
|-----------------|--------------------------------------|
|     `page`      |基于零的页码(可选)|
|     `size`      |请求的页面大小(可选)|
|`taskExecutionId`|通过任务执行 ID 过滤结果|

##### 示例请求

```
$ curl 'http://localhost:9393/jobs/thinexecutions?page=0&size=10&taskExecutionId=1' -i -X GET
```

##### 反应结构

```
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 943

{
  "_embedded" : {
    "jobExecutionThinResourceList" : [ {
      "executionId" : 1,
      "stepExecutionCount" : 0,
      "jobId" : 1,
      "taskExecutionId" : 1,
      "instanceId" : 1,
      "name" : "DOCJOB",
      "startDate" : "2022-01-18",
      "startTime" : "18:54:42",
      "startDateTime" : "2022-01-18T18:54:42.189+0000",
      "duration" : "00:00:00",
      "jobParameters" : { },
      "jobParametersString" : "",
      "restartable" : false,
      "abandonable" : true,
      "stoppable" : false,
      "defined" : false,
      "timeZone" : "UTC",
      "status" : "STOPPING",
      "_links" : {
        "self" : {
          "href" : "http://localhost:9393/jobs/thinexecutions/1"
        }
      }
    } ]
  },
  "_links" : {
    "self" : {
      "href" : "http://localhost:9393/jobs/thinexecutions?page=0&size=10"
    }
  },
  "page" : {
    "size" : 10,
    "totalElements" : 1,
    "totalPages" : 1,
    "number" : 0
  }
}
```

#### 44.12.8.作业执行细节

作业执行端点允许你获得有关作业执行的详细信息。以下主题提供了更多细节:

* [请求结构](#api-guide-resources-job-executions-detail-request-structure)

* [请求参数](#api-guide-resources-job-executions-detail-request-parameters)

* [示例请求](#api-guide-resources-job-executions-detail-example-request)

* [反应结构](#api-guide-resources-job-executions-detail-response-structure)

##### 请求结构

```
GET /jobs/executions/2 HTTP/1.1
Host: localhost:9393
```

/jobs/executions/{id}

|Parameter|说明|
|---------|----------------------------------------------|
|  `id`   |现有作业执行的 ID(必需的)|

##### 请求参数

这个端点没有请求参数。

##### 示例请求

```
$ curl 'http://localhost:9393/jobs/executions/2' -i -X GET
```

##### 反应结构

```
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 1188

{
  "executionId" : 2,
  "stepExecutionCount" : 0,
  "jobId" : 2,
  "taskExecutionId" : 2,
  "name" : "DOCJOB1",
  "startDate" : "2022-01-18",
  "startTime" : "18:54:42",
  "duration" : "00:00:00",
  "jobExecution" : {
    "id" : 2,
    "version" : 1,
    "jobParameters" : {
      "parameters" : { }
    },
    "jobInstance" : {
      "id" : 2,
      "jobName" : "DOCJOB1",
      "version" : 0
    },
    "stepExecutions" : [ ],
    "status" : "STOPPED",
    "startTime" : "2022-01-18T18:54:42.193+0000",
    "createTime" : "2022-01-18T18:54:42.192+0000",
    "endTime" : null,
    "lastUpdated" : "2022-01-18T18:54:42.193+0000",
    "exitStatus" : {
      "exitCode" : "UNKNOWN",
      "exitDescription" : ""
    },
    "executionContext" : {
      "dirty" : false,
      "empty" : true,
      "values" : [ ]
    },
    "failureExceptions" : [ ],
    "jobConfigurationName" : null,
    "allFailureExceptions" : [ ]
  },
  "jobParameters" : { },
  "jobParametersString" : "",
  "restartable" : true,
  "abandonable" : true,
  "stoppable" : false,
  "defined" : true,
  "timeZone" : "UTC",
  "_links" : {
    "self" : {
      "href" : "http://localhost:9393/jobs/executions/2"
    }
  }
}
```

#### 44.12.9.停止作业执行

作业执行端点允许你停止作业执行。以下主题提供了更多细节:

* [请求结构](#api-guide-resources-job-executions-stop-request-structure)

* [请求参数](#api-guide-resources-job-executions-stop-request-parameters)

* [示例请求](#api-guide-resources-job-executions-stop-example-request)

* [反应结构](#api-guide-resources-job-executions-stop-response-structure)

##### 请求结构

```
PUT /jobs/executions/1 HTTP/1.1
Accept: application/json
Host: localhost:9393
Content-Type: application/x-www-form-urlencoded

stop=true
```

/jobs/executions/{id}

|Parameter|说明|
|---------|----------------------------------------------|
|  `id`   |现有作业执行的 ID(必需的)|

##### 请求参数

|Parameter|说明|
|---------|-------------------------------------------|
| `stop`  |如果设置为 true,则发送停止作业的信号|

##### 示例请求

```
$ curl 'http://localhost:9393/jobs/executions/1' -i -X PUT \
    -H 'Accept: application/json' \
    -d 'stop=true'
```

##### 反应结构

```
HTTP/1.1 200 OK
```

#### 44.12.10.重新启动作业执行

作业执行端点允许你重新启动作业执行。以下主题提供了更多细节:

* [请求结构](#api-guide-resources-job-executions-restart-request-structure)

* [请求参数](#api-guide-resources-job-executions-restart-request-parameters)

* [示例请求](#api-guide-resources-job-executions-restart-example-request)

* [反应结构](#api-guide-resources-job-executions-restart-response-structure)

##### 请求结构

```
PUT /jobs/executions/2 HTTP/1.1
Accept: application/json
Host: localhost:9393
Content-Type: application/x-www-form-urlencoded

restart=true
```

/jobs/executions/{id}

|Parameter|说明|
|---------|----------------------------------------------|
|  `id`   |现有作业执行的 ID(必需的)|

##### 请求参数

|Parameter|说明|
|---------|----------------------------------------------|
|`restart`|如果设置为 true,则发送重启作业的信号|

##### 示例请求

```
$ curl 'http://localhost:9393/jobs/executions/2' -i -X PUT \
    -H 'Accept: application/json' \
    -d 'restart=true'
```

##### 反应结构

```
HTTP/1.1 200 OK
```

### 44.13.作业实例

作业实例端点提供了关于在 Spring 云数据流服务器上注册的作业实例的信息。以下主题提供了更多细节:

* [列出所有作业实例](#api-guide-resources-job-instances-list)

* [作业实例详细信息](#api-guide-resources-job-instances-detail)

#### 44.13.1.列出所有作业实例

作业实例端点允许你列出所有作业实例。以下主题提供了更多细节:

* [请求结构](#api-guide-resources-job-instances-list-request-structure)

* [请求参数](#api-guide-resources-job-instances-list-request-parameters)

* [示例请求](#api-guide-resources-job-instances-list-example-request)

* [反应结构](#api-guide-resources-job-instances-list-response-structure)

##### 请求结构

```
GET /jobs/instances?name=DOCJOB&page=0&size=10 HTTP/1.1
Host: localhost:9393
```

##### 请求参数

|Parameter|说明|
|---------|-----------------------------------------|
| `page`  |基于零的页码(可选)|
| `size`  |请求的页面大小(可选)|
| `name`  |与作业实例关联的名称|

##### 示例请求

```
$ curl 'http://localhost:9393/jobs/instances?name=DOCJOB&page=0&size=10' -i -X GET
```

##### 反应结构

```
HTTP/1.1 200 OK
Content-Type: application/hal+json
Content-Length: 1845

{
  "_embedded" : {
    "jobInstanceResourceList" : [ {
      "jobName" : "DOCJOB",
      "jobInstanceId" : 1,
      "jobExecutions" : [ {
        "executionId" : 1,
        "stepExecutionCount" : 0,
        "jobId" : 1,
        "taskExecutionId" : 1,
        "name" : "DOCJOB",
        "startDate" : "2022-01-18",
        "startTime" : "18:54:40",
        "duration" : "00:00:00",
        "jobExecution" : {
          "id" : 1,
          "version" : 1,
          "jobParameters" : {
            "parameters" : { }
          },
          "jobInstance" : {
            "id" : 1,
            "jobName" : "DOCJOB",
            "version" : 0
          },
          "stepExecutions" : [ ],
          "status" : "STARTED",
          "startTime" : "2022-01-18T18:54:40.048+0000",
          "createTime" : "2022-01-18T18:54:40.045+0000",
          "endTime" : null,
          "lastUpdated" : "2022-01-18T18:54:40.048+0000",
          "exitStatus" : {
            "exitCode" : "UNKNOWN",
            "exitDescription" : ""
          },
          "executionContext" : {
            "dirty" : false,
            "empty" : true,
            "values" : [ ]
          },
          "failureExceptions" : [ ],
          "jobConfigurationName" : null,
          "allFailureExceptions" : [ ]
        },
        "jobParameters" : { },
        "jobParametersString" : "",
        "restartable" : false,
        "abandonable" : false,
        "stoppable" : true,
        "defined" : false,
        "timeZone" : "UTC"
      } ],
      "_links" : {
        "self" : {
          "href" : "http://localhost:9393/jobs/instances/1"
        }
      }
    } ]
  },
  "_links" : {
    "self" : {
      "href" : "http://localhost:9393/jobs/instances?page=0&size=10"
    }
  },
  "page" : {
    "size" : 10,
    "totalElements" : 1,
    "totalPages" : 1,
    "number" : 0
  }
}
```

#### 44.13.2.作业实例详细信息

作业实例端点允许你列出所有作业实例。以下主题提供了更多细节:

* [请求结构](#api-guide-resources-job-instances-detail-request-structure)

* [请求参数](#api-guide-resources-job-instances-detail-request-parameters)

* [示例请求](#api-guide-resources-job-instances-detail-example-request)

* [反应结构](#api-guide-resources-job-instances-detail-response-structure)

##### 请求结构

```
GET /jobs/instances/1 HTTP/1.1
Host: localhost:9393
```

/jobs/instances/{id}

|Parameter|说明|
|---------|---------------------------------------------|
|  `id`   |现有作业实例的 ID(必需的)|

##### 请求参数

这个端点没有请求参数。

##### 示例请求

```
$ curl 'http://localhost:9393/jobs/instances/1' -i -X GET
```

##### 反应结构

```
HTTP/1.1 200 OK
Content-Type: application/hal+json
Content-Length: 1354

{
  "jobName" : "DOCJOB",
  "jobInstanceId" : 1,
  "jobExecutions" : [ {
    "executionId" : 1,
    "stepExecutionCount" : 0,
    "jobId" : 1,
    "taskExecutionId" : 1,
    "name" : "DOCJOB",
    "startDate" : "2022-01-18",
    "startTime" : "18:54:40",
    "duration" : "00:00:00",
    "jobExecution" : {
      "id" : 1,
      "version" : 1,
      "jobParameters" : {
        "parameters" : { }
      },
      "jobInstance" : {
        "id" : 1,
        "jobName" : "DOCJOB",
        "version" : 0
      },
      "stepExecutions" : [ ],
      "status" : "STARTED",
      "startTime" : "2022-01-18T18:54:40.048+0000",
      "createTime" : "2022-01-18T18:54:40.045+0000",
      "endTime" : null,
      "lastUpdated" : "2022-01-18T18:54:40.048+0000",
      "exitStatus" : {
        "exitCode" : "UNKNOWN",
        "exitDescription" : ""
      },
      "executionContext" : {
        "dirty" : false,
        "empty" : true,
        "values" : [ ]
      },
      "failureExceptions" : [ ],
      "jobConfigurationName" : null,
      "allFailureExceptions" : [ ]
    },
    "jobParameters" : { },
    "jobParametersString" : "",
    "restartable" : false,
    "abandonable" : false,
    "stoppable" : true,
    "defined" : false,
    "timeZone" : "UTC"
  } ],
  "_links" : {
    "self" : {
      "href" : "http://localhost:9393/jobs/instances/1"
    }
  }
}
```

### 44.14.作业步执行

Job Step Executions Endpoint 提供了关于在 Spring 云数据流服务器上注册的 Job Step Executions 的信息。以下主题提供了更多细节:

* [列出作业执行的所有步骤执行](#api-guide-resources-job-step-executions-list)

* [作业步骤执行细节](#api-guide-resources-job-step-execution-detail)

* [作业步骤执行进度](#api-guide-resources-job-step-execution-progress)

#### 44.14.1.列出作业执行的所有步骤执行

Job Step Executions Endpoint 允许你列出所有 Job Step Executions。以下主题提供了更多细节:

* [请求结构](#api-guide-resources-job-step-executions-list-request-structure)

* [请求参数](#api-guide-resources-job-step-executions-list-request-parameters)

* [示例请求](#api-guide-resources-job-step-executions-list-example-request)

* [反应结构](#api-guide-resources-job-step-executions-list-response-structure)

##### 请求结构

```
GET /jobs/executions/1/steps?page=0&size=10 HTTP/1.1
Host: localhost:9393
```

##### 请求参数

|Parameter|说明|
|---------|-------------------------------------|
| `page`  |基于零的页码(可选)|
| `size`  |请求的页面大小(可选)|

##### 示例请求

```
$ curl 'http://localhost:9393/jobs/executions/1/steps?page=0&size=10' -i -X GET
```

##### 反应结构

```
HTTP/1.1 200 OK
Content-Type: application/hal+json
Content-Length: 1623

{
  "_embedded" : {
    "stepExecutionResourceList" : [ {
      "jobExecutionId" : 1,
      "stepExecution" : {
        "stepName" : "DOCJOB_STEP",
        "id" : 1,
        "version" : 0,
        "status" : "STARTING",
        "readCount" : 0,
        "writeCount" : 0,
        "commitCount" : 0,
        "rollbackCount" : 0,
        "readSkipCount" : 0,
        "processSkipCount" : 0,
        "writeSkipCount" : 0,
        "startTime" : "2022-01-18T18:52:35.974+0000",
        "endTime" : null,
        "lastUpdated" : "2022-01-18T18:52:35.974+0000",
        "executionContext" : {
          "dirty" : false,
          "empty" : true,
          "values" : [ ]
        },
        "exitStatus" : {
          "exitCode" : "EXECUTING",
          "exitDescription" : ""
        },
        "terminateOnly" : false,
        "filterCount" : 0,
        "failureExceptions" : [ ],
        "jobParameters" : {
          "parameters" : { }
        },
        "jobExecutionId" : 1,
        "skipCount" : 0,
        "summary" : "StepExecution: id=1, version=0, name=DOCJOB_STEP, status=STARTING, exitStatus=EXECUTING, readCount=0, filterCount=0, writeCount=0 readSkipCount=0, writeSkipCount=0, processSkipCount=0, commitCount=0, rollbackCount=0"
      },
      "stepType" : "",
      "_links" : {
        "self" : {
          "href" : "http://localhost:9393/jobs/executions/1/steps/1"
        }
      }
    } ]
  },
  "_links" : {
    "self" : {
      "href" : "http://localhost:9393/jobs/executions/1/steps?page=0&size=10"
    }
  },
  "page" : {
    "size" : 10,
    "totalElements" : 1,
    "totalPages" : 1,
    "number" : 0
  }
}
```

#### 44.14.2.作业步骤执行细节

Job Step Executions Endpoint 允许你获得有关 Job Step 执行的详细信息。以下主题提供了更多细节:

* [请求结构](#api-guide-resources-job-step-execution-detail-request-structure)

* [请求参数](#api-guide-resources-job-step-execution-detail-request-parameters)

* [示例请求](#api-guide-resources-job-step-execution-detail-example-request)

* [反应结构](#api-guide-resources-job-step-execution-detail-response-structure)

##### 请求结构

```
GET /jobs/executions/1/steps/1 HTTP/1.1
Host: localhost:9393
```

/jobs/executions/{id}/stepid/{stepid}

|Parameter|说明|
|---------|----------------------------------------------------------------------------|
|  `id`   |现有作业执行的 ID(必需的)|
|`stepid` |特定作业执行的已有步骤执行的 ID(必需的)|

##### 请求参数

这个端点没有请求参数。

##### 示例请求

```
$ curl 'http://localhost:9393/jobs/executions/1/steps/1' -i -X GET
```

##### 反应结构

```
HTTP/1.1 200 OK
Content-Type: application/hal+json
Content-Length: 1173

{
  "jobExecutionId" : 1,
  "stepExecution" : {
    "stepName" : "DOCJOB_STEP",
    "id" : 1,
    "version" : 0,
    "status" : "STARTING",
    "readCount" : 0,
    "writeCount" : 0,
    "commitCount" : 0,
    "rollbackCount" : 0,
    "readSkipCount" : 0,
    "processSkipCount" : 0,
    "writeSkipCount" : 0,
    "startTime" : "2022-01-18T18:52:35.974+0000",
    "endTime" : null,
    "lastUpdated" : "2022-01-18T18:52:35.974+0000",
    "executionContext" : {
      "dirty" : false,
      "empty" : true,
      "values" : [ ]
    },
    "exitStatus" : {
      "exitCode" : "EXECUTING",
      "exitDescription" : ""
    },
    "terminateOnly" : false,
    "filterCount" : 0,
    "failureExceptions" : [ ],
    "jobParameters" : {
      "parameters" : { }
    },
    "jobExecutionId" : 1,
    "skipCount" : 0,
    "summary" : "StepExecution: id=1, version=0, name=DOCJOB_STEP, status=STARTING, exitStatus=EXECUTING, readCount=0, filterCount=0, writeCount=0 readSkipCount=0, writeSkipCount=0, processSkipCount=0, commitCount=0, rollbackCount=0"
  },
  "stepType" : "",
  "_links" : {
    "self" : {
      "href" : "http://localhost:9393/jobs/executions/1/steps/1"
    }
  }
}
```

#### 44.14.3.作业步骤执行进度

Job Step Executions Endpoint 允许你获得有关 Job Step 执行进度的详细信息。以下主题提供了更多细节:

* [请求结构](#api-guide-resources-job-step-execution-progress-request-structure)

* [请求参数](#api-guide-resources-job-step-execution-progress-request-parameters)

* [示例请求](#api-guide-resources-job-step-execution-progress-example-request)

* [反应结构](#api-guide-resources-job-step-execution-progress-response-structure)

##### 请求结构

```
GET /jobs/executions/1/steps/1/progress HTTP/1.1
Host: localhost:9393
```

/jobs/executions/{id}/steps/{stepid}/progress

|Parameter|说明|
|---------|----------------------------------------------------------------------------|
|  `id`   |现有作业执行的 ID(必需的)|
|`stepid` |特定作业执行的已有步骤执行的 ID(必需的)|

##### 请求参数

这个端点没有请求参数。

##### 示例请求

```
$ curl 'http://localhost:9393/jobs/executions/1/steps/1/progress' -i -X GET
```

##### 反应结构

```
HTTP/1.1 200 OK
Content-Type: application/hal+json
Content-Length: 2676

{
  "stepExecution" : {
    "stepName" : "DOCJOB_STEP",
    "id" : 1,
    "version" : 0,
    "status" : "STARTING",
    "readCount" : 0,
    "writeCount" : 0,
    "commitCount" : 0,
    "rollbackCount" : 0,
    "readSkipCount" : 0,
    "processSkipCount" : 0,
    "writeSkipCount" : 0,
    "startTime" : "2022-01-18T18:52:35.974+0000",
    "endTime" : null,
    "lastUpdated" : "2022-01-18T18:52:35.974+0000",
    "executionContext" : {
      "dirty" : false,
      "empty" : true,
      "values" : [ ]
    },
    "exitStatus" : {
      "exitCode" : "EXECUTING",
      "exitDescription" : ""
    },
    "terminateOnly" : false,
    "filterCount" : 0,
    "failureExceptions" : [ ],
    "jobParameters" : {
      "parameters" : { }
    },
    "jobExecutionId" : 1,
    "skipCount" : 0,
    "summary" : "StepExecution: id=1, version=0, name=DOCJOB_STEP, status=STARTING, exitStatus=EXECUTING, readCount=0, filterCount=0, writeCount=0 readSkipCount=0, writeSkipCount=0, processSkipCount=0, commitCount=0, rollbackCount=0"
  },
  "stepExecutionHistory" : {
    "stepName" : "DOCJOB_STEP",
    "count" : 0,
    "commitCount" : {
      "count" : 0,
      "min" : 0.0,
      "max" : 0.0,
      "standardDeviation" : 0.0,
      "mean" : 0.0
    },
    "rollbackCount" : {
      "count" : 0,
      "min" : 0.0,
      "max" : 0.0,
      "standardDeviation" : 0.0,
      "mean" : 0.0
    },
    "readCount" : {
      "count" : 0,
      "min" : 0.0,
      "max" : 0.0,
      "standardDeviation" : 0.0,
      "mean" : 0.0
    },
    "writeCount" : {
      "count" : 0,
      "min" : 0.0,
      "max" : 0.0,
      "standardDeviation" : 0.0,
      "mean" : 0.0
    },
    "filterCount" : {
      "count" : 0,
      "min" : 0.0,
      "max" : 0.0,
      "standardDeviation" : 0.0,
      "mean" : 0.0
    },
    "readSkipCount" : {
      "count" : 0,
      "min" : 0.0,
      "max" : 0.0,
      "standardDeviation" : 0.0,
      "mean" : 0.0
    },
    "writeSkipCount" : {
      "count" : 0,
      "min" : 0.0,
      "max" : 0.0,
      "standardDeviation" : 0.0,
      "mean" : 0.0
    },
    "processSkipCount" : {
      "count" : 0,
      "min" : 0.0,
      "max" : 0.0,
      "standardDeviation" : 0.0,
      "mean" : 0.0
    },
    "duration" : {
      "count" : 0,
      "min" : 0.0,
      "max" : 0.0,
      "standardDeviation" : 0.0,
      "mean" : 0.0
    },
    "durationPerRead" : {
      "count" : 0,
      "min" : 0.0,
      "max" : 0.0,
      "standardDeviation" : 0.0,
      "mean" : 0.0
    }
  },
  "percentageComplete" : 0.5,
  "finished" : false,
  "duration" : 151.0,
  "_links" : {
    "self" : {
      "href" : "http://localhost:9393/jobs/executions/1/steps/1"
    }
  }
}
```

### 44.15.有关应用程序的运行时信息

你可以获得系统已知的运行应用程序的信息,无论是全局的还是单独的。以下主题提供了更多细节:

* [列出运行时的所有应用程序](#api-guide-resources-runtime-information-applications-listing-all)

* [查询单个应用程序的所有实例](#api-guide-resources-runtime-information-applications-querying-all-instances-single-app)

* [查询单个应用程序的单个实例](#api-guide-resources-runtime-information-applications-querying-single-instance-single-app)

#### 44.15.1.列出运行时的所有应用程序

要检索所有应用程序的所有实例的信息,请使用`GET`查询`/runtime/apps`端点。以下主题提供了更多细节:

* [请求结构](#api-guide-resources-runtime-information-applications-listing-all-request-structure)

* [示例请求](#api-guide-resources-runtime-information-applications-listing-all-example-request)

* [反应结构](#api-guide-resources-runtime-information-applications-listing-all-response-structure)

##### 请求结构

```
GET /runtime/apps HTTP/1.1
Accept: application/json
Host: localhost:9393
```

##### 示例请求

```
$ curl 'http://localhost:9393/runtime/apps' -i -X GET \
    -H 'Accept: application/json'
```

##### 反应结构

```
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 209

{
  "_links" : {
    "self" : {
      "href" : "http://localhost:9393/runtime/apps?page=0&size=20"
    }
  },
  "page" : {
    "size" : 20,
    "totalElements" : 0,
    "totalPages" : 0,
    "number" : 0
  }
}
```

#### 44.15.2.查询单个应用程序的所有实例

要检索有关特定应用程序的所有实例的信息,请使用`GET`查询`/runtime/apps/<appId>/instances`端点。以下主题提供了更多细节:

* [请求结构](#api-guide-resources-runtime-information-applications-querying-all-instances-single-app-request-structure)

* [示例请求](#api-guide-resources-runtime-information-applications-querying-all-instances-single-app-example-request)

* [反应结构](#api-guide-resources-runtime-information-applications-querying-all-instances-single-app-response-structure)

##### 请求结构

```
GET /runtime/apps HTTP/1.1
Accept: application/json
Host: localhost:9393
```

##### 示例请求

```
$ curl 'http://localhost:9393/runtime/apps' -i -X GET \
    -H 'Accept: application/json'
```

##### 反应结构

```
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 209

{
  "_links" : {
    "self" : {
      "href" : "http://localhost:9393/runtime/apps?page=0&size=20"
    }
  },
  "page" : {
    "size" : 20,
    "totalElements" : 0,
    "totalPages" : 0,
    "number" : 0
  }
}
```

#### 44.15.3.查询单个应用程序的单个实例

要检索有关特定应用程序的特定实例的信息,请使用`GET`查询`/runtime/apps/<appId>/instances/<instanceId>`端点。以下主题提供了更多细节:

* [请求结构](#api-guide-resources-runtime-information-applications-querying-single-instance-single-app-request-structure)

* [示例请求](#api-guide-resources-runtime-information-applications-querying-single-instance-single-app-example-request)

* [反应结构](#api-guide-resources-runtime-information-applications-querying-single-instance-single-app-response-structure)

##### 请求结构

```
GET /runtime/apps HTTP/1.1
Accept: application/json
Host: localhost:9393
```

##### 示例请求

```
$ curl 'http://localhost:9393/runtime/apps' -i -X GET \
    -H 'Accept: application/json'
```

##### 反应结构

```
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 209

{
  "_links" : {
    "self" : {
      "href" : "http://localhost:9393/runtime/apps?page=0&size=20"
    }
  },
  "page" : {
    "size" : 20,
    "totalElements" : 0,
    "totalPages" : 0,
    "number" : 0
  }
}
```

### 44.16.流日志

你可以获得该流的应用程序日志,用于整个流或流中的特定应用程序。以下主题提供了更多细节:

* [根据流名获取应用程序的日志](#api-guide-resources-stream-logs-by-stream-name)

* [从流中获取特定应用程序的日志](#api-guide-resources-stream-logs-by-app-name)

#### 44.16.1.根据流名获取应用程序的日志

使用带有`/streams/logs/<streamName>`REST 端点的 http`GET`方法来检索给定流名称的所有应用程序日志。以下主题提供了更多细节:

* [请求结构](#api-guide-resources-stream-logs-by-stream-name-request-structure)

* [示例请求](#api-guide-resources-stream-logs-by-stream-name-example-request)

* [反应结构](#api-guide-resources-stream-logs-by-stream-name-response-structure)

##### 请求结构

```
GET /streams/logs/ticktock HTTP/1.1
Host: localhost:9393
```

##### 示例请求

```
$ curl 'http://localhost:9393/streams/logs/ticktock' -i -X GET
```

##### 反应结构

```
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 93

{
  "logs" : {
    "ticktock-time-v1" : "Logs-time",
    "ticktock-log-v1" : "Logs-log"
  }
}
```

#### 44.16.2.从流中获取特定应用程序的日志

要从流中检索特定应用程序的日志,请使用`GET`HTTP 方法查询`/streams/logs/<streamName>/<appName>`端点。以下主题提供了更多细节:

* [请求结构](#api-guide-resources-stream-logs-by-app-name-request-structure)

* [示例请求](#api-guide-resources-stream-logs-by-app-name-example-request)

* [反应结构](#api-guide-resources-stream-logs-by-app-name-response-structure)

##### 请求结构

```
GET /streams/logs/ticktock/ticktock-log-v1 HTTP/1.1
Host: localhost:9393
```

##### 示例请求

```
$ curl 'http://localhost:9393/streams/logs/ticktock/ticktock-log-v1' -i -X GET
```

##### 反应结构

```
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 55

{
  "logs" : {
    "ticktock-log-v1" : "Logs-log"
  }
}
```

### 44.17.任务日志

你可以获得特定任务执行的任务执行日志。

以下主题提供了更多细节:

* [获取任务执行日志](#api-guide-resources-stream-logs-by-task-id)

#### 44.17.1.获取任务执行日志

要检索任务执行的日志,请使用 http`GET`方法查询`/tasks/logs/<ExternalTaskExecutionId>`端点。以下主题提供了更多细节:

* [请求结构](#api-guide-resources-task-logs-by-task-id-request-structure)

* [请求参数](#api-guide-resources-task-logs-by-task-id-request-parameters)

* [示例请求](#api-guide-resources-task-logs-by-task-id-example-request)

* [反应结构](#api-guide-resources-task-logs-by-task-id-response-structure)

##### 请求结构

```
GET /tasks/logs/taskA-a5f123da-9a3b-42e8-b839-2eb441c561de?platformName=default HTTP/1.1
Host: localhost:9393
```

##### 请求参数

|  Parameter   |说明|
|--------------|----------------------------------------------|
|`platformName`|该任务启动的平台的名称。|

##### 示例请求

```
$ curl 'http://localhost:9393/tasks/logs/taskA-a5f123da-9a3b-42e8-b839-2eb441c561de?platformName=default' -i -X GET
```

##### 反应结构

```
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 10043

"stdout:\n2022-01-18 18:54:53.319  INFO 3680 --- [           main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.spring[email protected]4e515669: startup date [Tue Jan 18 18:54:53 UTC 2022]; root of context hierarchy\n2022-01-18 18:54:53.728  INFO 3680 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'configurationPropertiesRebinderAutoConfiguration' of type [org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration$$EnhancerBySpringCGLIB$$b056ca48] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)\n\n  .   ____          _            __ _ _\n /\\\\ / ___'_ __ _ _(_)_ __  __ _ \\ \\ \\ \\\n( ( )\\___ | '_ | '_| | '_ \\/ _` | \\ \\ \\ \\\n \\\\/  ___)| |_)| | | | | || (_| |  ) ) ) )\n  '  |____| .__|_| |_|_| |_\\__, | / / / /\n =========|_|==============|___/=/_/_/_/\n :: Spring Boot ::        (v1.5.2.RELEASE)\n\n2022-01-18 18:54:53.937  INFO 3680 --- [           main] c.c.c.ConfigServicePropertySourceLocator : Fetching config from server at: http://localhost:8888\n2022-01-18 18:54:54.009  WARN 3680 --- [           main] c.c.c.ConfigServicePropertySourceLocator : Could not locate PropertySource: I/O error on GET request for \"http://localhost:8888/timestamp-task/default\": Connection refused (Connection refused); nested exception is java.net.ConnectException: Connection refused (Connection refused)\n2022-01-18 18:54:54.019  INFO 3680 --- [           main] o.s.c.t.a.t.TimestampTaskApplication     : No active profile set, falling back to default profiles: default\n2022-01-18 18:54:54.042  INFO 3680 --- [           main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.spring[email protected]445b84c0: startup date [Tue Jan 18 18:54:54 UTC 2022]; parent: org.spring[email protected]4e515669\n2022-01-18 18:54:54.607  INFO 3680 --- [           main] o.s.cloud.context.scope.GenericScope     : BeanFactory id=1e36064f-ccbe-3d2f-9196-128427cc78a0\n2022-01-18 18:54:54.696  INFO 3680 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration' of type [org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration$$EnhancerBySpringCGLIB$$b056ca48] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)\n2022-01-18 18:54:54.705  INFO 3680 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration' of type [org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration$$EnhancerBySpringCGLIB$$943cc74b] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)\n2022-01-18 18:54:55.229  INFO 3680 --- [           main] o.s.jdbc.datasource.init.ScriptUtils     : Executing SQL script from class path resource [org/springframework/cloud/task/schema-h2.sql]\n2022-01-18 18:54:55.258  INFO 3680 --- [           main] o.s.jdbc.datasource.init.ScriptUtils     : Executed SQL script from class path resource [org/springframework/cloud/task/schema-h2.sql] in 29 ms.\n2022-01-18 18:54:55.582  INFO 3680 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup\n2022-01-18 18:54:55.589  INFO 3680 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Bean with name 'configurationPropertiesRebinder' has been autodetected for JMX exposure\n2022-01-18 18:54:55.589  INFO 3680 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Bean with name 'environmentManager' has been autodetected for JMX exposure\n2022-01-18 18:54:55.591  INFO 3680 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Bean with name 'refreshScope' has been autodetected for JMX exposure\n2022-01-18 18:54:55.592  INFO 3680 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Located managed bean 'environmentManager': registering with JMX server as MBean [taskA-a5f123da-9a3b-42e8-b839-2eb441c561de:name=environmentManager,type=EnvironmentManager]\n2022-01-18 18:54:55.603  INFO 3680 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Located managed bean 'refreshScope': registering with JMX server as MBean [taskA-a5f123da-9a3b-42e8-b839-2eb441c561de:name=refreshScope,type=RefreshScope]\n2022-01-18 18:54:55.613  INFO 3680 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Located managed bean 'configurationPropertiesRebinder': registering with JMX server as MBean [taskA-a5f123da-9a3b-42e8-b839-2eb441c561de:name=configurationPropertiesRebinder,context=445b84c0,type=ConfigurationPropertiesRebinder]\n2022-01-18 18:54:55.690  INFO 3680 --- [           main] o.s.c.support.DefaultLifecycleProcessor  : Starting beans in phase 0\n2022-01-18 18:54:55.702  WARN 3680 --- [           main] s.c.a.AnnotationConfigApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.context.ApplicationContextException: Failed to start bean 'taskLifecycleListener'; nested exception is java.lang.IllegalArgumentException: Invalid TaskExecution, ID 1 not found\n2022-01-18 18:54:55.703  INFO 3680 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Unregistering JMX-exposed beans on shutdown\n2022-01-18 18:54:55.703  INFO 3680 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Unregistering JMX-exposed beans\n2022-01-18 18:54:55.703 ERROR 3680 --- [           main] o.s.c.t.listener.TaskLifecycleListener   : An event to end a task has been received for a task that has not yet started.\n2022-01-18 18:54:55.709  INFO 3680 --- [           main] utoConfigurationReportLoggingInitializer : \n\nError starting ApplicationContext. To display the auto-configuration report re-run your application with 'debug' enabled.\n2022-01-18 18:54:55.715 ERROR 3680 --- [           main] o.s.boot.SpringApplication               : Application startup failed\n\norg.springframework.context.ApplicationContextException: Failed to start bean 'taskLifecycleListener'; nested exception is java.lang.IllegalArgumentException: Invalid TaskExecution, ID 1 not found\n\tat org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:178) ~[spring-context-4.3.7.RELEASE.jar!/:4.3.7.RELEASE]\n\tat org.springframework.context.support.DefaultLifecycleProcessor.access$200(DefaultLifecycleProcessor.java:50) ~[spring-context-4.3.7.RELEASE.jar!/:4.3.7.RELEASE]\n\tat org.springframework.context.support.DefaultLifecycleProcessor$LifecycleGroup.start(DefaultLifecycleProcessor.java:348) ~[spring-context-4.3.7.RELEASE.jar!/:4.3.7.RELEASE]\n\tat org.springframework.context.support.DefaultLifecycleProcessor.startBeans(DefaultLifecycleProcessor.java:151) ~[spring-context-4.3.7.RELEASE.jar!/:4.3.7.RELEASE]\n\tat org.springframework.context.support.DefaultLifecycleProcessor.onRefresh(DefaultLifecycleProcessor.java:114) ~[spring-context-4.3.7.RELEASE.jar!/:4.3.7.RELEASE]\n\tat org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:879) ~[spring-context-4.3.7.RELEASE.jar!/:4.3.7.RELEASE]\n\tat org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:545) ~[spring-context-4.3.7.RELEASE.jar!/:4.3.7.RELEASE]\n\tat org.springframework.boot.SpringApplication.refresh(SpringApplication.java:737) [spring-boot-1.5.2.RELEASE.jar!/:1.5.2.RELEASE]\n\tat org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:370) [spring-boot-1.5.2.RELEASE.jar!/:1.5.2.RELEASE]\n\tat org.springframework.boot.SpringApplication.run(SpringApplication.java:314) [spring-boot-1.5.2.RELEASE.jar!/:1.5.2.RELEASE]\n\tat org.springframework.boot.SpringApplication.run(SpringApplication.java:1162) [spring-boot-1.5.2.RELEASE.jar!/:1.5.2.RELEASE]\n\tat org.springframework.boot.SpringApplication.run(SpringApplication.java:1151) [spring-boot-1.5.2.RELEASE.jar!/:1.5.2.RELEASE]\n\tat org.springframework.cloud.task.app.timestamp.TimestampTaskApplication.main(TimestampTaskApplication.java:29) [classes!/:1.2.0.RELEASE]\n\tat sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_322]\n\tat sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_322]\n\tat sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_322]\n\tat java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_322]\n\tat org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:48) [timestamp-task-1.2.0.RELEASE.jar:1.2.0.RELEASE]\n\tat org.springframework.boot.loader.Launcher.launch(Launcher.java:87) [timestamp-task-1.2.0.RELEASE.jar:1.2.0.RELEASE]\n\tat org.springframework.boot.loader.Launcher.launch(Launcher.java:50) [timestamp-task-1.2.0.RELEASE.jar:1.2.0.RELEASE]\n\tat org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:51) [timestamp-task-1.2.0.RELEASE.jar:1.2.0.RELEASE]\nCaused by: java.lang.IllegalArgumentException: Invalid TaskExecution, ID 1 not found\n\tat org.springframework.util.Assert.notNull(Assert.java:134) ~[spring-core-4.3.7.RELEASE.jar!/:4.3.7.RELEASE]\n\tat org.springframework.cloud.task.listener.TaskLifecycleListener.doTaskStart(TaskLifecycleListener.java:200) ~[spring-cloud-task-core-1.2.0.RELEASE.jar!/:1.2.0.RELEASE]\n\tat org.springframework.cloud.task.listener.TaskLifecycleListener.start(TaskLifecycleListener.java:282) ~[spring-cloud-task-core-1.2.0.RELEASE.jar!/:1.2.0.RELEASE]\n\tat org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:175) ~[spring-context-4.3.7.RELEASE.jar!/:4.3.7.RELEASE]\n\t... 20 common frames omitted\n\n"
```

# 附录

在云数据流方面遇到了麻烦,我们很乐意提供帮助!

* 问一个问题。我们监控[stackoverflow.com](https://stackoverflow.com)中带有[`spring-cloud-dataflow`]标记的问题(https://stackoverflow.com/tags/ Spring-cloud-dataflow)。

* 在[github.com/spring-cloud/spring-cloud-dataflow/issues](https://github.com/spring-cloud/spring-cloud-dataflow/issues)处使用 Spring 云数据流报告错误。

## 附录 A:数据流模板

正如 API 指南一章中所描述的, Spring 云数据流的功能通过 REST 端点完全公开。虽然你可以直接使用这些端点, Spring 云数据流还提供了基于 Java 的 API,这使得使用这些 REST 端点更加容易。

中心入口点是`org.springframework.cloud.dataflow.rest.client`包中的`DataFlowTemplate`类。

该类实现`DataFlowOperations`接口,并委托给以下子模板,这些子模板为每个功能集提供特定的功能:

|          Interface          |说明|
|-----------------------------|----------------------------------------------|
|     `StreamOperations`      |用于流操作的 REST 客户机|
|     `CounterOperations`     |用于柜台操作的 REST 客户机|
|`FieldValueCounterOperations`|用于字段值计数器操作的 REST 客户机|
|`AggregateCounterOperations` |用于聚合计数器操作的 REST 客户机|
|      `TaskOperations`       |用于任务操作的 REST 客户机|
|       `JobOperations`       |REST 客户机用于作业操作|
|   `AppRegistryOperations`   |应用程序注册操作的 REST 客户端|
|   `CompletionOperations`    |用于完成操作的 REST 客户机|
|     `RuntimeOperations`     |用于运行时操作的 REST 客户机|

在初始化`DataFlowTemplate`时,可以通过 Hateoas(作为应用状态引擎的超媒体)提供的 REST 关系发现子模板。

|   |如果无法解析某个资源,则相应的子模板将以 null 表示<br/>。一个常见的原因是 Spring 云数据流允许在启动时启用或禁用特定的<br/>特征集。有关更多信息,请参见[local](#configuration-local-enable-disable-specific-features)、[Cloud Foundry](#configuration-cloudfoundry-enable-disable-specific-features)或[Kubernetes](#configuration-kubernetes-enable-disable-specific-features)配置章节中的一章,这取决于你在哪里部署应用程序。|
|---|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

11773
### A.1.使用数据流模板
D
dallascao 已提交
11774 11775 11776 11777 11778 11779 11780 11781 11782 11783 11784 11785 11786 11787 11788 11789 11790 11791 11792 11793 11794 11795 11796 11797 11798 11799 11800 11801 11802 11803 11804 11805 11806 11807 11808 11809 11810 11811 11812 11813 11814 11815 11816 11817 11818 11819 11820 11821 11822 11823 11824 11825 11826 11827 11828 11829 11830 11831 11832 11833 11834 11835 11836 11837 11838 11839 11840 11841 11842

当你使用数据流模板时,唯一需要的数据流依赖项是 Spring Cloud Data Flow REST 客户机,如以下 Maven 片段所示:

```
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-dataflow-rest-client</artifactId>
  <version>2.9.2</version>
</dependency>
```

有了这个依赖关系,你就得到了`DataFlowTemplate`类,以及调用 Spring 云数据流服务器所需的所有依赖关系。

在实例化`DataFlowTemplate`时,还传递一个`RestTemplate`。请注意,所需的`RestTemplate`需要一些额外的配置才能在`DataFlowTemplate`的上下文中有效。当将`RestTemplate`声明为 Bean 时,以下配置就足够了:

```
  @Bean
  public static RestTemplate restTemplate() {
    RestTemplate restTemplate = new RestTemplate();
    restTemplate.setErrorHandler(new VndErrorResponseErrorHandler(restTemplate.getMessageConverters()));
    for(HttpMessageConverter<?> converter : restTemplate.getMessageConverters()) {
      if (converter instanceof MappingJackson2HttpMessageConverter) {
        final MappingJackson2HttpMessageConverter jacksonConverter =
            (MappingJackson2HttpMessageConverter) converter;
        jacksonConverter.getObjectMapper()
            .registerModule(new Jackson2HalModule())
            .addMixIn(JobExecution.class, JobExecutionJacksonMixIn.class)
            .addMixIn(JobParameters.class, JobParametersJacksonMixIn.class)
            .addMixIn(JobParameter.class, JobParameterJacksonMixIn.class)
            .addMixIn(JobInstance.class, JobInstanceJacksonMixIn.class)
            .addMixIn(ExitStatus.class, ExitStatusJacksonMixIn.class)
            .addMixIn(StepExecution.class, StepExecutionJacksonMixIn.class)
            .addMixIn(ExecutionContext.class, ExecutionContextJacksonMixIn.class)
            .addMixIn(StepExecutionHistory.class, StepExecutionHistoryJacksonMixIn.class);
      }
    }
    return restTemplate;
  }
```

|   |你还可以通过使用`DataFlowTemplate.getDefaultDataflowRestTemplate();`获得预先配置的`RestTemplate`|
|---|-------------------------------------------------------------------------------------------------------------|

现在,你可以使用以下代码实例化`DataFlowTemplate`:

```
DataFlowTemplate dataFlowTemplate = new DataFlowTemplate(
    new URI("http://localhost:9393/"), restTemplate);         (1)
```

|**1**|`URI`指向你的 Spring 云数据流服务器的根。|
|-----|-------------------------------------------------------------------|

根据你的需求,你现在可以调用服务器。例如,如果你想获得当前可用应用程序的列表,可以运行以下代码:

```
PagedResources<AppRegistrationResource> apps = dataFlowTemplate.appRegistryOperations().list();

System.out.println(String.format("Retrieved %s application(s)",
    apps.getContent().size()));

for (AppRegistrationResource app : apps.getContent()) {
  System.out.println(String.format("App Name: %s, App Type: %s, App URI: %s",
    app.getName(),
    app.getType(),
    app.getUri()));
}
```

11843
### A.2.数据流模板和安全性
D
dallascao 已提交
11844 11845 11846 11847 11848 11849 11850 11851 11852 11853 11854 11855 11856 11857 11858 11859 11860 11861 11862 11863 11864 11865 11866 11867 11868 11869 11870 11871 11872 11873 11874 11875 11876 11877 11878 11879 11880 11881 11882 11883 11884 11885 11886 11887 11888 11889 11890

当使用`DataFlowTemplate`时,还可以提供所有与安全相关的选项,就像使用*数据流壳*一样。实际上,*数据流壳*对其所有操作都使用`DataFlowTemplate`。

为了让你开始使用,我们提供了一个`HttpClientConfigurer`,它使用 Builder 模式来设置各种与安全相关的选项:

```
	HttpClientConfigurer
		.create(targetUri)                                             (1)
		.basicAuthCredentials(username, password)                      (2)
		.skipTlsCertificateVerification()                              (3)
		.withProxyCredentials(proxyUri, proxyUsername, proxyPassword)  (4)
		.addInterceptor(interceptor)                                   (5)
		.buildClientHttpRequestFactory()                               (6)
```

|**1**|使用提供的目标 URI 创建 HttpClientConfigurer。|
|-----|------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|**2**|设置基本身份验证的凭据(使用 OAuth2Password Grant)|
|**3**|跳过 SSL 证书验证(** 仅用于开发!**)|
|**4**|配置任何代理设置|
|**5**|添加一个自定义拦截器,例如设置 OAuth2 授权头。这允许<br/>你传递一个 OAuth2 访问令牌,而不是用户名/密码凭据。|
|**6**|构建可以在`RestTemplate`上设置的`ClientHttpRequestFactory`。|

一旦配置了`HttpClientConfigurer`,就可以使用其`buildClientHttpRequestFactory`构建`ClientHttpRequestFactory`,然后在`RestTemplate`上设置相应的属性。然后可以使用`RestTemplate`实例化实际的`DataFlowTemplate`。

要配置*基本身份验证*,需要进行以下设置:

```
	RestTemplate restTemplate = DataFlowTemplate.getDefaultDataflowRestTemplate();
	HttpClientConfigurer httpClientConfigurer = HttpClientConfigurer.create("http://localhost:9393");

	httpClientConfigurer.basicAuthCredentials("my_username", "my_password");
	restTemplate.setRequestFactory(httpClientConfigurer.buildClientHttpRequestFactory());

	DataFlowTemplate dataFlowTemplate = new DataFlowTemplate("http://localhost:9393", restTemplate);
```

你可以在 GitHub 上的[spring-cloud-dataflow-samples](https://github.com/spring-cloud/spring-cloud-dataflow-samples/tree/master/dataflow-template-example)存储库中找到一个示例应用程序。

## 附录 B:“操作指南”

这一部分提供了一些常见的“我该如何做到这一点……”问题的答案,这些问题在人们使用 Spring 云数据流时经常会出现。

如果你有一个我们在此未讨论的特定问题,你可能想查看[stackoverflow.com](https://stackoverflow.com/tags/spring-cloud-dataflow),以查看是否有人已经提供了答案。这也是一个提出新问题的好地方(使用`spring-cloud-dataflow`标签)。

我们也非常乐意扩展这一部分。如果你想添加一个“how-to”,你可以给我们发送[拉请求](https://github.com/spring-cloud/spring-cloud-dataflow)。

11891
### B.1.配置 Maven 属性
D
dallascao 已提交
11892 11893 11894 11895 11896 11897 11898 11899 11900 11901 11902 11903 11904 11905 11906 11907 11908 11909 11910 11911 11912 11913 11914 11915 11916 11917 11918 11919 11920 11921 11922 11923 11924 11925 11926 11927 11928 11929 11930 11931 11932 11933 11934 11935 11936 11937 11938 11939 11940 11941 11942 11943 11944 11945 11946 11947 11948

你可以在启动数据流服务器时,通过命令行属性设置 Maven 属性,例如本地 Maven 存储库位置、远程 Maven 存储库、身份验证凭据和代理服务器属性。或者,你可以通过为数据流服务器设置`SPRING_APPLICATION_JSON`环境属性来设置这些属性。

如果应用程序是通过使用 Maven 存储库解析的,则需要显式地配置远程 Maven 存储库,但`local`数据流服务器除外。其他数据流服务器实现(它们使用 Maven 资源来解析应用程序工件)对于远程存储库没有默认值。`local`服务器将`[repo.spring.io/libs-snapshot](https://repo.spring.io/libs-snapshot)`作为默认的远程存储库。

要将属性作为命令行选项传递,请使用类似于以下命令的命令运行服务器:

```
$ java -jar <dataflow-server>.jar --maven.localRepository=mylocal
--maven.remote-repositories.repo1.url=https://repo1
--maven.remote-repositories.repo1.auth.username=repo1user
--maven.remote-repositories.repo1.auth.password=repo1pass
--maven.remote-repositories.repo2.url=https://repo2 --maven.proxy.host=proxyhost
--maven.proxy.port=9018 --maven.proxy.auth.username=proxyuser
--maven.proxy.auth.password=proxypass
```

你也可以使用`SPRING_APPLICATION_JSON`环境属性:

```
export SPRING_APPLICATION_JSON='{ "maven": { "local-repository": "local","remote-repositories": { "repo1": { "url": "https://repo1", "auth": { "username": "repo1user", "password": "repo1pass" } },
"repo2": { "url": "https://repo2" } }, "proxy": { "host": "proxyhost", "port": 9018, "auth": { "username": "proxyuser", "password": "proxypass" } } } }'
```

以下是格式良好的 JSON 中的相同内容:

```
SPRING_APPLICATION_JSON='{
  "maven": {
    "local-repository": "local",
    "remote-repositories": {
      "repo1": {
        "url": "https://repo1",
        "auth": {
          "username": "repo1user",
          "password": "repo1pass"
        }
      },
      "repo2": {
        "url": "https://repo2"
      }
    },
    "proxy": {
      "host": "proxyhost",
      "port": 9018,
      "auth": {
        "username": "proxyuser",
        "password": "proxypass"
      }
    }
  }
}'
```

|   |Spring 根据云数据流服务器的实现方式,你可能必须通过使用平台特定的环境设置能力来传递环境属性。例如,在 Cloud Foundry 中,将它们传递为`cf set-env SPRING_APPLICATION_JSON`。|
|---|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

11949
### B.2.故障排除
D
dallascao 已提交
11950 11951 11952

本节介绍如何在你选择的平台上对 Spring 云数据流进行故障诊断。关于[Stream](https://dataflow.spring.io/docs/stream-developer-guides/troubleshooting/)和[Batch](https://dataflow.spring.io/docs/batch-developer-guides/troubleshooting/)处理,请参见微站点的故障排除部分。

11953
### B.3.常见问题
D
dallascao 已提交
11954 11955 11956 11957 11958 11959 11960

在这一部分中,我们回顾了 Spring 云数据流的常见问题。有关更多信息,请参见微型网站的[常见问题](https://dataflow.spring.io/docs/resources/faq/)部分。

## 附录 C:建筑物

本附录描述了如何构建 Spring 云数据流。

11961
要构建源代码,你需要安装 JDK1.8.
D
dallascao 已提交
11962 11963 11964 11965 11966 11967 11968 11969 11970 11971 11972 11973 11974 11975 11976 11977 11978

构建使用 Maven 包装器,因此你不必安装 Maven 的特定版本。

主要的构建命令如下:

```
$ ./mvnw clean install
```

为了加快构建速度,你可以添加`-DskipTests`以避免运行测试。

|   |你也可以自己安装 Maven(\>=3.3.3),并在下面的示例中运行`mvn`命令来代替`./mvnw`。<br/>如果你这样做了,如果你的本地 Maven 设置不包含 Spring 预发布工件的存储库声明,那么你可能还需要添加`-P spring`。|
|---|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

|   |你可能需要通过设置一个`MAVEN_OPTS`的值类似于`-Xmx512m -XX:MaxPermSize=128m`的环境变量来增加 Maven 可用的内存量。<br/>我们试图在`.mvn`配置中覆盖这一点,所以,如果你发现你必须这样做才能使构建成功,请提出一张票,让设置添加到源代码控制。|
|---|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

11979
### C.1.文件
D
dallascao 已提交
11980 11981 11982 11983 11984 11985 11986

有一个生成文档的`full`配置文件。你可以使用以下命令只构建文档:

```
$ ./mvnw clean package -DskipTests -P full -pl {project-artifactId} -am
```

11987
### C.2.使用代码
D
dallascao 已提交
11988 11989 11990

如果你没有最喜欢的 IDE,我们建议你在使用代码时使用[Spring Tools Suite](https://spring.io/tools)或[Eclipse](https://www.eclipse.org)。我们使用[m2eclipse](https://www.eclipse.org/m2e/)Eclipse 插件来提供 Maven 支持。其他 IDE 和工具通常也可以正常工作。

11991
#### C.2.1.用 M2Eclipse 导入到 Eclipse 中
D
dallascao 已提交
11992 11993 11994

在使用 Eclipse 时,我们推荐[m2eclipe](https://www.eclipse.org/m2e/)Eclipse 插件。如果你还没有安装 M2Eclipse,那么可以从 Eclipse 市场获得它。

11995
遗憾的是,M2E 还不支持 Maven 3.3.因此,一旦项目被导入到 Eclipse 中,你还需要告诉 M2Eclipse 为项目使用`.settings.xml`文件。如果不这样做,你可能会在项目中看到与 POM 相关的许多不同的错误。这样做:
D
dallascao 已提交
11996 11997 11998 11999 12000 12001 12002 12003 12004 12005 12006 12007 12008 12009 12010 12011 12012 12013

1. 打开你的 Eclipse 首选项。

2. 展开**Maven preferences**。

3. 选择**用户设置**。

4. 在**用户设置**字段中,单击**浏览**并导航到你导入的 Spring 云项目。

5. 在该项目中选择`.settings.xml`文件。

6. 点击**申请**。

7. 点击**OK**。

|   |或者,你可以将 Spring Cloud 的[`.settings.xml`](https://github.com/ Spring-cloud/ Spring-cloud-build/blob/master/.settings.xml)文件中的存储库设置复制到你自己的`~/.m2/settings.xml`文件中。|
|---|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

12014
#### C.2.2.在没有 M2Eclipse 的情况下导入 Eclipse
D
dallascao 已提交
12015 12016 12017 12018 12019 12020 12021 12022 12023 12024 12025 12026 12027

如果不喜欢使用 M2Eclipse,可以使用以下命令生成 Eclipse 项目元数据:

```
$ ./mvnw eclipse:eclipse
```

通过从**档案**菜单中选择**导入现有项目**,可以导入生成的 Eclipse 项目。

## 附录 D:贡献

Spring 云是在非限制性的 Apache2.0 许可下发布的,遵循非常标准的 GitHub 开发流程,使用 GitHub Tracker 处理问题,并将拉请求合并到主分支中。如果你想贡献一些微不足道的东西,请不要犹豫,但请遵循本附录中的指导方针。

12028
### D.1.签署贡献者许可协议
D
dallascao 已提交
12029 12030 12031

在我们接受一个非平凡的(除了纠正打印错误以外的任何事情)补丁或拉请求之前,我们需要你签署[供款人协议](https://cla.pivotal.io)。签署贡献者的协议并不会授予任何人对主库的提交权限,但这确实意味着我们可以接受你的贡献,并且如果我们接受了,你将获得作者信用。活跃的贡献者可能会被要求加入核心团队,并被赋予合并拉请求的能力。

12032
### D.2.守则惯例和内部管理
D
dallascao 已提交
12033 12034 12035 12036 12037 12038 12039 12040 12041 12042 12043 12044 12045 12046 12047 12048 12049 12050 12051 12052 12053 12054 12055 12056 12057

对于一个拉请求,下面的指导原则都不是必不可少的,但是它们都可以帮助你的开发人员同事理解并处理你的代码。它们也可以在原始的拉请求之后但在合并之前添加。

* 使用 Spring 框架代码格式约定。如果使用 Eclipse,可以使用`eclipse-code-formatter.xml`项目中的[Spring Cloud Build](https://github.com/spring-cloud/spring-cloud-build/blob/master/spring-cloud-dependencies-parent/eclipse-code-formatter.xml)文件导入格式化设置。如果使用 IntelliJ,则可以使用[Eclipse 代码格式化插件](https://plugins.jetbrains.com/plugin/6546)导入相同的文件。

* 确保所有新的`.java`文件都有一个简单的 Javadoc 类注释,其中至少有一个`@author`标记来标识你,并且最好至少有一个段落来描述类的目的。

* 将 ASF 许可标头注释添加到所有新的`.java`文件中(要这样做,请从项目中的现有文件中复制它)。

* 将自己作为`@author`添加到要进行实质性修改的.java 文件中(不仅仅是外观上的更改)。

* 添加一些 Javadocs,如果你更改了名称空间,还可以添加一些 XSDDOC 元素。

* 一些单元测试也会有很大帮助。必须有人来做这件事,而你的开发人员也会对此表示赞赏。

* 如果没有其他人使用你的分支,则将它与当前的主分支(或主项目中的其他目标分支)重新绑定。

* 写提交消息时,请遵循[这些约定](https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html)。如果修复了现有的问题,请在提交消息的末尾添加`Fixes gh-XXXX`(其中 xxxx 是问题编号)。

  \== 身份提供者

本附录包含如何设置特定的提供者来处理数据流安全性的信息。

在撰写本文时,Azure 是唯一的身份提供程序。

12058
### D.3.天蓝色
D
dallascao 已提交
12059 12060 12061 12062 12063 12064 12065 12066

Azure AD 是一个成熟的身份提供程序,提供了一系列有关身份验证和授权的功能。与任何其他提供商一样,它也有自己的细微差别,这意味着必须小心地设置它。

在这一节中,我们将介绍如何为 AD 和 Spring 云数据流完成 OAuth2 设置。

|   |你需要完整的组织访问权限来正确设置所有内容。|
|---|------------------------------------------------------------------------|

12067
#### D.3.1.创造一个新的广告环境
D
dallascao 已提交
12068 12069 12070

要开始,请创建一个新的 ActiveDirectory 环境。选择类型为 Azure Active Directory(而不是 B2C 类型),然后选择你的组织名称和初始域。下图显示了设置:

12071
<img alt="Create AD Environment" src="https://docs.spring.io/spring-cloud-dataflow/docs/2.9.2/reference/htmlsingle/images/azure-create-ad-env.png" width="60%" />
D
dallascao 已提交
12072

12073
#### D.3.2.创建一个新的应用程序注册
D
dallascao 已提交
12074 12075 12076 12077 12078 12079 12080

应用程序注册是创建 OAuth 客户端以被 OAuth 应用程序使用的地方。至少,你需要创建两个客户机,一个用于数据流和 Skipper 服务器,另一个用于数据流壳层,因为这两个客户机的配置略有不同。服务器应用程序可以被认为是受信任的应用程序,而 shell 则不受信任(因为用户可以看到它的完整配置)。

注意:我们建议对数据流和 Skipper 服务器都使用相同的 OAuth 客户机。虽然你可以使用不同的客户机,但它目前不会提供任何价值,因为配置需要相同。

下图显示了创建一个新应用程序注册的设置:

12081
<img alt="Create App Registration" src="https://docs.spring.io/spring-cloud-dataflow/docs/2.9.2/reference/htmlsingle/images/azure-create-app-registration.png" width="60%" />
D
dallascao 已提交
12082 12083 12084 12085

|   |当需要时,在 AD 中的`Certificates & secrets`下创建一个客户端秘密。|
|---|------------------------------------------------------------------------------|

12086
#### D.3.3.公开 DataFlow API
D
dallascao 已提交
12087 12088 12089 12090 12091 12092 12093 12094 12095 12096 12097 12098 12099 12100 12101 12102 12103 12104 12105

要准备 OAuth 范围,请为每个数据流安全角色创建一个。在这个例子中,这些将是

* `api://dataflow-server/dataflow.create`

* `api://dataflow-server/dataflow.deploy`

* `api://dataflow-server/dataflow.destroy`

* `api://dataflow-server/dataflow.manage`

* `api://dataflow-server/dataflow.schedule`

* `api://dataflow-server/dataflow.modify`

* `api://dataflow-server/dataflow.view`

下图显示了要公开的 API:

12106
<img alt="Expose APIs" src="https://docs.spring.io/spring-cloud-dataflow/docs/2.9.2/reference/htmlsingle/images/azure-expose-apis.png" width="60%" />
D
dallascao 已提交
12107 12108 12109

需要将先前创建的作用域添加为 API 权限,如下图所示:

12110
<img alt="Api Permissions" src="https://docs.spring.io/spring-cloud-dataflow/docs/2.9.2/reference/htmlsingle/images/azure-api-permissions.png" width="60%" />
D
dallascao 已提交
12111

12112
#### D.3.4.创建特权客户端
D
dallascao 已提交
12113 12114 12115 12116 12117 12118 12119 12120

对于即将使用密码授权的 OAuth 客户机,需要为 OAuth 客户机创建与服务器使用的 API 权限相同(在上一节中进行了描述)。

|   |所有这些权限都需要以管理权限授予。|
|---|---------------------------------------------------------------|

下图显示了特权设置:

12121
<img alt="Privileged Client" src="https://docs.spring.io/spring-cloud-dataflow/docs/2.9.2/reference/htmlsingle/images/azure-privileged-client.png" width="60%" />
D
dallascao 已提交
12122 12123 12124 12125

|   |特权客户机需要一个客户机秘密,当在 shell 中使用时,该秘密需要公开给客户机<br/>配置。如果不想公开该秘密,请使用[创建公共客户端](#appendix-identity-provider-azure-pubclient)公共客户端。|
|---|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

12126
#### D.3.5.创建公共客户端
D
dallascao 已提交
12127 12128 12129 12130 12131

公共客户机基本上是一个没有客户机秘密且其类型设置为公共的客户机。

下图显示了一个公共客户端的配置:

12132
<img alt="Public Client" src="https://docs.spring.io/spring-cloud-dataflow/docs/2.9.2/reference/htmlsingle/images/azure-public-client.png" width="60%" />
D
dallascao 已提交
12133

12134
#### D.3.6.配置示例
D
dallascao 已提交
12135 12136 12137 12138 12139 12140 12141 12142 12143 12144 12145 12146 12147 12148 12149 12150 12151 12152 12153 12154 12155 12156 12157 12158 12159 12160 12161 12162 12163 12164 12165 12166 12167 12168 12169 12170 12171 12172 12173 12174 12175 12176 12177 12178 12179 12180 12181 12182 12183 12184 12185 12186 12187 12188 12189 12190 12191 12192 12193 12194 12195 12196 12197 12198 12199 12200 12201 12202 12203 12204 12205 12206 12207 12208 12209 12210 12211 12212 12213 12214 12215 12216 12217 12218 12219 12220 12221 12222 12223 12224 12225 12226 12227 12228 12229 12230 12231 12232 12233 12234 12235 12236 12237 12238 12239 12240 12241 12242 12243 12244 12245 12246 12247 12248 12249 12250 12251 12252 12253 12254 12255 12256 12257 12258 12259 12260 12261 12262 12263 12264 12265 12266 12267 12268 12269 12270 12271 12272 12273 12274 12275 12276 12277 12278 12279 12280 12281 12282 12283 12284 12285 12286 12287 12288 12289 12290 12291 12292 12293 12294 12295 12296 12297 12298 12299 12300 12301 12302 12303 12304 12305 12306 12307 12308 12309 12310 12311 12312 12313 12314 12315 12316 12317 12318

本节包含数据流和 Skipper 服务器以及 shell 的配置示例。

启动数据流服务器:

```
$ java -jar spring-cloud-dataflow-server.jar \
  --spring.config.additional-location=dataflow-azure.yml
```

dataFlow-azure.yml

```
spring:
  cloud:
    dataflow:
      security:
        authorization:
          provider-role-mappings:
            dataflow-server:
              map-oauth-scopes: true
              role-mappings:
                ROLE_VIEW: dataflow.view
                ROLE_CREATE: dataflow.create
                ROLE_MANAGE: dataflow.manage
                ROLE_DEPLOY: dataflow.deploy
                ROLE_DESTROY: dataflow.destroy
                ROLE_MODIFY: dataflow.modify
                ROLE_SCHEDULE: dataflow.schedule
  security:
    oauth2:
      client:
        registration:
          dataflow-server:
            provider: azure
            redirect-uri: '{baseUrl}/login/oauth2/code/{registrationId}'
            client-id: <client id>
            client-secret: <client secret>
            scope:
            - openid
            - profile
            - email
            - offline_access
            - api://dataflow-server/dataflow.view
            - api://dataflow-server/dataflow.deploy
            - api://dataflow-server/dataflow.destroy
            - api://dataflow-server/dataflow.manage
            - api://dataflow-server/dataflow.modify
            - api://dataflow-server/dataflow.schedule
            - api://dataflow-server/dataflow.create
        provider:
          azure:
            issuer-uri: https://login.microsoftonline.com/799dcfde-b9e3-4dfc-ac25-659b326e0bcd/v2.0
            user-name-attribute: name
      resourceserver:
        jwt:
          jwk-set-uri: https://login.microsoftonline.com/799dcfde-b9e3-4dfc-ac25-659b326e0bcd/discovery/v2.0/keys
```

要启动 Skipper 服务器:

```
$ java -jar spring-cloud-skipper-server.jar \
  --spring.config.additional-location=skipper-azure.yml
```

Skipper-Azure.yml

```
spring:
  cloud:
    skipper:
      security:
        authorization:
          provider-role-mappings:
            skipper-server:
              map-oauth-scopes: true
              role-mappings:
                ROLE_VIEW: dataflow.view
                ROLE_CREATE: dataflow.create
                ROLE_MANAGE: dataflow.manage
                ROLE_DEPLOY: dataflow.deploy
                ROLE_DESTROY: dataflow.destroy
                ROLE_MODIFY: dataflow.modify
                ROLE_SCHEDULE: dataflow.schedule
  security:
    oauth2:
      client:
        registration:
          skipper-server:
            provider: azure
            redirect-uri: '{baseUrl}/login/oauth2/code/{registrationId}'
            client-id: <client id>
            client-secret: <client secret>
            scope:
            - openid
            - profile
            - email
            - offline_access
            - api://dataflow-server/dataflow.view
            - api://dataflow-server/dataflow.deploy
            - api://dataflow-server/dataflow.destroy
            - api://dataflow-server/dataflow.manage
            - api://dataflow-server/dataflow.modify
            - api://dataflow-server/dataflow.schedule
            - api://dataflow-server/dataflow.create
        provider:
          azure:
            issuer-uri: https://login.microsoftonline.com/799dcfde-b9e3-4dfc-ac25-659b326e0bcd/v2.0
            user-name-attribute: name
      resourceserver:
        jwt:
          jwk-set-uri: https://login.microsoftonline.com/799dcfde-b9e3-4dfc-ac25-659b326e0bcd/discovery/v2.0/keys
```

要启动 shell 并(可选地)将凭据作为选项传递:

```
$ java -jar spring-cloud-dataflow-shell.jar \
  --spring.config.additional-location=dataflow-azure-shell.yml \
  --dataflow.username=<USERNAME> \
  --dataflow.password=<PASSWORD>
```

dataflow-azure-shell.yml

```
  security:
    oauth2:
      client:
        registration:
          dataflow-shell:
            provider: azure
            client-id: <client id>
            client-secret: <client secret>
            authorization-grant-type: password
            scope:
            - offline_access
            - api://dataflow-server/dataflow.create
            - api://dataflow-server/dataflow.deploy
            - api://dataflow-server/dataflow.destroy
            - api://dataflow-server/dataflow.manage
            - api://dataflow-server/dataflow.modify
            - api://dataflow-server/dataflow.schedule
            - api://dataflow-server/dataflow.view
        provider:
          azure:
            issuer-uri: https://login.microsoftonline.com/799dcfde-b9e3-4dfc-ac25-659b326e0bcd/v2.0
```

启动一个公共 shell 并(可选地)将凭据作为选项传递:

```
$ java -jar spring-cloud-dataflow-shell.jar \
  --spring.config.additional-location=dataflow-azure-shell-public.yml \
  --dataflow.username=<USERNAME> \
  --dataflow.password=<PASSWORD>
```

dataFlow-Azure-shell-public.yml

```
spring:
  security:
    oauth2:
      client:
        registration:
          dataflow-shell:
            provider: azure
            client-id: <client id>
            authorization-grant-type: password
            client-authentication-method: post
            scope:
            - offline_access
            - api://dataflow-server/dataflow.create
            - api://dataflow-server/dataflow.deploy
            - api://dataflow-server/dataflow.destroy
            - api://dataflow-server/dataflow.manage
            - api://dataflow-server/dataflow.modify
            - api://dataflow-server/dataflow.schedule
            - api://dataflow-server/dataflow.view
        provider:
          azure:
            issuer-uri: https://login.microsoftonline.com/799dcfde-b9e3-4dfc-ac25-659b326e0bcd/v2.0
茶陵後's avatar
茶陵後 已提交
12319
```