开始
3. 入门 - 本地
有关设置 docker compose 和手动安装的更多信息,请参阅微型网站的 Local Machine 部分。
4. 入门 - Cloud Foundry
本节介绍如何在 Cloud Foundry 上开始使用 Spring Cloud Data Flow。有关在 Cloud Foundry 上安装 Spring Cloud Data Flow 的更多信息,请参阅微型网站的 Cloud Foundry 部分。
5. 入门 - Kubernetes
Spring Cloud Data Flow 是一个用于构建数据集成和实时数据处理管道的工具包。
管道由使用 Spring Cloud Stream 或 Spring Cloud Task 微服务框架构建的 Spring Boot 应用程序组成。 这使得 Spring Cloud Data Flow 适用于一系列数据处理用例,从导入导出到事件流和预测分析。
该项目支持将 Spring Cloud Data Flow 与 Kubernetes 结合使用作为这些管道的运行时,并将应用程序打包为 Docker 映像。
有关在 Kubernetes 上安装 Spring Cloud Data Flow 的更多信息,请参阅微型网站的 Kubernetes 部分。
5.1. 应用程序和服务器属性
本节介绍如何自定义应用程序的部署。您可以使用许多属性来影响已部署应用程序的设置。属性可以基于每个应用程序应用,也可以应用于所有已部署应用程序的相应服务器配置中。
基于每个应用程序设置的属性始终优先于设置为服务器配置的属性。这种安排允许您基于每个应用程序覆盖全局服务器级别属性。 |
要应用于所有已部署任务的属性在文件中定义,而 Streams 的属性在 中定义。替换为您正在使用的消息传递中间件 — 例如,或 .src/kubernetes/server/server-config-[binder].yaml
src/kubernetes/skipper/skipper-config-[binder].yaml
[binder]
rabbit
kafka
5.1.1. 内存和 CPU 设置
应用程序使用默认内存和 CPU 设置进行部署。如果需要,您可以调整这些值。以下示例演示如何设置为 for 和 for memory,以及 to for CPU 和 for memory:Limits
1000m
CPU
1024Mi
Requests
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. 环境变量
要影响给定应用程序的环境设置,您可以使用 deployer 属性。
例如,生产环境中的常见要求是影响 JVM 内存参数。
您可以使用环境变量来执行此操作,如下例所示:spring.cloud.deployer.kubernetes.environmentVariables
JAVA_TOOL_OPTIONS
deployer.<application>.kubernetes.environmentVariables=JAVA_TOOL_OPTIONS=-Xmx1024m
该属性接受逗号分隔的字符串。如果环境变量包含值
这也是一个逗号分隔的字符串,它必须用单引号引起来——例如,environmentVariables spring.cloud.deployer.kubernetes.environmentVariables=spring.cloud.stream.kafka.binder.brokers='somehost:9092,
anotherhost:9093'
|
这将覆盖所需 JVM 内存设置(替换为应用程序的名称)。<application>
<application>
5.1.3. 存活和就绪探针
和 探测器分别使用称为 和 的路径。它们分别对 和 a of 和 and 使用 a of 。您可以在部署流时使用 Deployer 属性更改这些默认值。liveness 和 readiness 探测仅适用于流。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
您可以声明 Same as the part of the server global configuration for streams,如下例所示:
data:
application.yaml: |-
spring:
cloud:
skipper:
server:
platform:
kubernetes:
accounts:
default:
livenessProbePath: /health
livenessProbeDelay: 120
livenessProbePeriod: 20
同样,您可以 swap for 覆盖默认设置。liveness
readiness
readiness
默认情况下,端口 8080 用作探测端口。您可以使用 deployer 属性更改 和 probe ports 的默认值,如下例所示:liveness
readiness
deployer.<application>.kubernetes.readinessProbePort=7000
deployer.<application>.kubernetes.livenessProbePort=7000
您可以将 SAME 声明为 AS the PART of the global configuration for streams,如下例所示:
data:
application.yaml: |-
spring:
cloud:
skipper:
server:
platform:
kubernetes:
accounts:
default:
readinessProbePort: 7000
livenessProbePort: 7000
默认情况下,和 probe 路径使用 Spring Boot 2.x+ 执行器端点。要使用 Spring Boot 1.x 执行器端点路径,必须调整and值,如下例所示(替换为应用程序的名称):
要基于每个应用程序自动将 both 和 endpoints 设置为默认的 Spring Boot 1.x 路径,可以设置以下属性:
|
您可以使用存储在 Kubernetes 密钥中的凭证访问安全的探测终端节点。您可以使用现有密钥,前提是凭证包含在密钥块的密钥名称下。您可以按应用程序配置探测身份验证。启用后,它将使用相同的凭证和身份验证类型应用于探测终端节点。目前仅支持身份验证。credentials
data
liveness
readiness
Basic
要创建新密钥,请执行以下操作:
-
使用用于访问安全探测端点的凭证生成 base64 字符串。
基本身份验证将用户名和密码编码为 base64 字符串,格式为 .
username:password
以下示例(包括输出,您应该在其中替换 and 替换为您的值)显示了如何生成 base64 字符串:
user
pass
$ echo -n "user:pass" | base64 dXNlcjpwYXNz
-
使用编码的凭据,创建包含以下内容的文件(例如 ):
myprobesecret.yml
apiVersion: v1 kind: Secret metadata: name: myprobesecret type: Opaque data: credentials: GENERATED_BASE64_STRING
-
替换为之前生成的 base64 编码值。
GENERATED_BASE64_STRING
-
使用 创建 密钥,如下例所示:
kubectl
$ kubectl create -f ./myprobesecret.yml secret "myprobesecret" created
-
将以下 Deployer 属性设置为在访问探测端点时使用身份验证,如下例所示:
deployer.<application>.kubernetes.probeCredentialsSecret=myprobesecret
替换为要应用身份验证的应用程序的名称。
<application>
5.1.4. 使用SPRING_APPLICATION_JSON
可以使用环境变量来设置数据流服务器属性(包括 Maven 存储库设置的配置),这些属性在所有数据流服务器实现中都是通用的。这些设置位于部署 YAML 的 container 部分的服务器级别。以下示例显示了如何执行此操作:SPRING_APPLICATION_JSON
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 镜像。首先,您必须在集群中创建一个密钥。按照 从私有注册表拉取映像 指南创建密钥。
创建密钥后,您可以使用该属性设置要使用的密钥,如下例所示: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
以下示例显示如何配置应用程序以使用注释:
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
:将所有应用程序属性和命令行参数作为环境变量传递。每个 applicationor 命令行参数属性都转换为大写字符串,并且字符将替换为 。.
_
-
boot
:创建一个环境变量,该变量包含所有应用程序属性的 JSON 表示形式。部署请求中的命令行参数设置为 container args。SPRING_APPLICATION_JSON
在所有情况下,在服务器级配置和基于每个应用程序定义的环境变量都会按原样发送到容器。 |
您可以按如下方式配置应用程序:
deployer.<application>.kubernetes.entryPointStyle=<Entry Point Style>
替换为您的应用程序名称和所需的入口点样式。<application>
<Entry Point Style>
您还可以在 Global Server 级别配置入口点样式。
以下示例显示如何对流执行此操作:
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
您应该选择 或 的入口点样式,以对应于在容器的 .有关更多信息和用例 versus ,请参阅 Docker 文档的 ENTRYPOINT 部分。exec
shell
ENTRYPOINT
Dockerfile
exec
shell
使用入口点样式对应于使用样式 .来自部署请求的命令行参数将传递到容器,并添加应用程序属性映射到环境变量中,而不是命令行参数。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 相关的对象设置自定义标签。有关标签的更多信息,请参阅标签。标签以 format 指定。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 参考的污点和容忍度部分。
以下示例显示了如何单独配置应用程序:
deployer.<application>.kubernetes.tolerations=[{key: 'mykey' operator: 'Equal', value: 'myvalue', effect: 'NoSchedule'}]
根据所需的容忍度配置,替换为您的应用程序名称和键值对。<application>
您也可以在 Global Server 级别配置容忍度。
以下示例显示如何对流执行此操作:
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. 秘密引用
可以引用 Secret,并且可以解码其整个数据内容,并将其作为单个变量插入 Pod 环境中。 有关更多信息,请参阅 Kubernetes 参考的将密钥中的所有键值对配置为容器环境变量部分。
以下示例显示了如何单独配置应用程序:
deployer.<application>.kubernetes.secretRefs=testsecret
您还可以指定多个密钥,如下所示:
deployer.<application>.kubernetes.secretRefs=[testsecret,anothersecret]
替换为您的应用程序的名称,并将属性替换为适用于您的应用程序环境和密钥的值。<application>
secretRefs
您也可以在全局服务器级别配置 secret 引用。
以下示例显示如何对流执行此操作:
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. Secret Key 引用
可以引用 Secret,并且可以将其解码值插入到 Pod 环境中。 有关更多信息,请参阅 Kubernetes 参考的 Using Secrets as Environment Variables 部分。
以下示例显示了如何单独配置应用程序:
deployer.<application>.kubernetes.secretKeyRefs=[{envVarName: 'MY_SECRET', secretName: 'testsecret', dataKey: 'password'}]
替换为您的应用程序的名称,并将 、 和 属性替换为适用于您的应用程序环境和密钥的值。<application>
envVarName
secretName
dataKey
您还可以在 Global Server 级别配置密钥引用。
以下示例显示如何对流执行此操作:
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. ConfigMap 参考
可以引用 ConfigMap,并且可以解码其整个数据内容,并将其作为单个变量插入到 Pod 环境中。 有关更多信息,请参阅 Kubernetes 参考的将 ConfigMap 中的所有键值对配置为容器环境变量部分。
以下示例显示了如何单独配置应用程序:
deployer.<application>.kubernetes.configMapRefs=testcm
您还可以指定多个 ConfigMap 实例,如下所示:
deployer.<application>.kubernetes.configMapRefs=[testcm,anothercm]
替换为您的应用程序名称,并将属性替换为适用于您的应用程序环境和 ConfigMap 的值。<application>
configMapRefs
您也可以在全局服务器级别配置 ConfigMap 引用。
以下示例演示如何对流执行此操作。编辑相应的 ,替换为正在使用的相应活页夹: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. ConfigMap 键引用
可以引用 ConfigMap,并将其关联的键值插入到 Pod 环境中。 有关更多信息,请参阅 Kubernetes 参考的使用 ConfigMap 数据定义容器环境变量部分。
以下示例显示了如何单独配置应用程序:
deployer.<application>.kubernetes.configMapKeyRefs=[{envVarName: 'MY_CM', configMapName: 'testcm', dataKey: 'platform'}]
替换为应用程序的名称,将 、 和 属性替换为适用于您的应用程序环境和 ConfigMap 的值。<application>
envVarName
configMapName
dataKey
您也可以在全局服务器级别配置 ConfigMap 引用。
以下示例演示如何对流执行此操作。编辑相应的 ,替换为正在使用的相应活页夹: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
将 、 和 属性替换为 ConfigMap 的相应值。envVarName
configMapName
dataKey
5.1.16. Pod 安全上下文
你可以配置 Pod 安全上下文,以在指定的 UID(用户 ID)或 GID(组 ID)下运行进程。
当您不想在默认 UID 和 GID 下运行进程时,这非常有用。
您可以定义 (UID) 或 (GID),并且可以将它们配置为协同工作。
有关更多信息,请参阅 Kubernetes 参考的 Security Context 部分。root
runAsUser
fsGroup
以下示例显示了如何单独配置应用程序 Pod:
deployer.<application>.kubernetes.podSecurityContext={runAsUser: 65534, fsGroup: 65534}
替换为您的应用程序名称,并将 and/or 属性替换为适用于您的容器环境的值。<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
将 and/or 属性替换为适用于您的容器环境的值。runAsUser
fsGroup
5.1.17. 服务端口
部署应用程序时,将创建一个默认端口为 .如果设置了该属性,它将覆盖默认端口值。您可以基于每个应用程序向 Service 对象添加其他端口。您可以使用逗号分隔符添加多个端口。8080
server.port
以下示例显示了如何在应用程序的 Service 对象上配置其他端口:
deployer.<application>.kubernetes.servicePorts=5000
deployer.<application>.kubernetes.servicePorts=5000,9000
替换为您的应用程序名称和端口的值。<application>
5.1.18. StatefulSet 初始化容器
使用 StatefulSet 部署应用程序时,使用 Init Container 在 Pod 中设置实例索引。
默认情况下,使用的图像是 ,您可以对其进行自定义。busybox
以下示例显示了如何单独配置应用程序 Pod:
deployer.<application>.kubernetes.statefulSetInitContainerImageName=myimage:mylabel
替换为您的应用程序的名称,并将 attribute 替换为适合您的环境的值。<application>
statefulSetInitContainerImageName
您也可以在全局服务器级别配置 StatefulSet Init Container。
以下示例演示如何对流执行此操作。编辑相应的 ,替换为正在使用的相应活页夹: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 Container。 有关更多信息,请参阅 Kubernetes 参考的 Init Containers 部分。
以下示例说明如何为应用程序配置 Init 容器:
deployer.<application>.kubernetes.initContainer={containerName: 'test', imageName: 'busybox:latest', commands: ['sh', '-c', 'echo hello']}
替换为应用程序的名称,并设置适用于您的 Init Container 的属性值。<application>
initContainer
5.1.20. 生命周期支持
在部署应用程序时,您可以附加 和 Lifecycle 处理程序来执行命令。
Kubernetes API 支持除 之外的其他类型的处理程序。此功能可能会扩展以支持未来版本中的其他操作。
要配置生命周期处理程序,如上面的链接页面所示,请使用以下属性键将每个命令指定为逗号分隔的列表:postStart
preStop
exec
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、适配器(在多容器 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']}]