在上次文章中,我们简要介绍了Score工具的背景,以及展示了如何编写一个 busybox 的简单应用,并最终通过Docker Compose部署起来。现在让我们深入查看下Score配置文件的规范定义。
对于同一份 Score 配置文件,通过不同的转化工具输出不同格式的目标配置: 架构图中左边的Score配置文件内容如下:
apiVersion: score.dev/v1b1
metadata:
name: hello-world
service:
ports:
www:
port: 80
targetPort: 8080
containers:
container-id:
image: busybox
variables:
CONNECTION_STRING:
其中第一行 apiVersion 是定义 Score 的版本,metadata 的 name 制定 workload 的名字,然后 service 和 containers 分别定义服务和容器配置。但是该配置文件的详细规范是怎么样定义的呢?
Score用来描述一个workload的配置是yaml格式的文件,主要由以下几个部分组成:
apiVersion
Score 配置规范的版本,目前是 score.dev/v1b1
,这是必填项
metadata
定义 workload 的元信息,目前主要是name,也是必填项
containers
定义 workload 的的容器是如何执行的,必填项
resources
可选项,定义工作负载所需的依赖项。
service
可选项,定义应用程序在执行时如何公开其资源。
下面是一个常见的 workload 顶层的配置项:
apiVersion: score.dev/v1b1
metadata:
name: hello-world
service:
ports:
# . . .
containers:
my-container:
# . . .
resources:
env:
# . . .
大家可以自行对比应前面的 hello-world
配置文件。
resources
规范资源的定义如下:
resources:
[resource-name]:
type: [resource-type]
properties: # optional
[property-name]:
type: string # optional
default: interface{} # optional
required: [true | false] # default false
secret: [true | false] # default false
资源通过 resource-name
指定名字,然后是属性的类型和对应的属性。其中 resource-type
有一些预定义的类型(以及在不同目标的对应关系):
资源类型 | score-compose | score-humanitec |
---|---|---|
environment | ${PROPERTY-NAME} |
${values.property-name} |
volume | 对外部 volume 的引用 | 对外部 volume 的引用 |
workload | 不适用 | ${modules.workload-name.property-name} |
比如 ${resources.resource-name.property-name}
会映射到以下资源:
resources:
resource-name:
property-name: my-property-name
下面是资源引用的完整例子:
apiVersion: score.dev/v1b1
metadata:
name: backend
containers:
container-id:
image: busybox
command: ["/bin/sh"]
args: ["-c", "while true; do echo Hello $${FRIEND}!; sleep 5; done"]
variables:
CONNECTION_STRING: postgresql://${resources.db.username}:${resources.db.password}@${resources.db.host}:${resources.db.port}/${resources.db.name}
resources:
db:
type: postgres
properties:
host:
port:
default: 5432
name:
username:
secret: true
password:
secret: true
service
规范服务部分可定义多个对外服务的网络端口,其结构如下:
service:
ports:
port-name: string # (required)
port: integer # (required)
protocol: string # (optional)
hostIP: integer # (optional)
targetPort: integer # (optional)
在 service 下的 ports 部分为每个服务定义一个端口名字,然后通过 port 指定端口。默认是 TCP 服务,也可以手工指定 SCTP、TCP、UDP 等服务。hostIP 指定 host 机器绑定的 IP 地址,targetPort 用于指定要暴露的端口(默认是port值)。下面是一个常见发服务配置例子:
apiVersion: score.dev/v1b1
metadata:
name: web-app
service:
ports:
www:
port: 80
targetPort: 8080
admin:
port: 8080
protocol: UDP
这里定义了www和admin网络端口,www默认将8080映射到80端口,admin是UDP协议的8080端口。
containers
规范workload 的容器配置参数最为繁杂,其结构如下:
image: string
command: []string
args: []string
variables: map[string]string
files:
target: string
mode: string
content: []string
volumes:
source: string
path: string
target: string
read_only: [true | false]
resources:
limits: map[string]interface{}
requests: map[string]interface{}
livenessProbe: ContainerProbeSpec
scheme: string
host: string
httpGet: map[string]interface{}
port: int
path: string
httpHeaders:
name: string
value: string
readinessProbe: ContainerProbeSpec
scheme: string
host: string
httpGet: map[string]interface{}
port: int
path: string
httpHeaders:
name: string
value: string
具体的含义:
container-id: 指定容器镜像的名称。
image: 指定容器镜像
command: 容器的入口命令
args: 入口命令行参数
variables: 指定环境变量
files: 指定要挂载的额外文件
target: 指定路径和名称
mode: 访问模式
content: 指定内联内容并支持模板
volumes:指定要挂载的卷
source:指定外部体积参考。
path:指定卷中的子路径。
target: 目标路径
read_only:是否只读模式
limits: 最大允许内存。
memory:表示最大允许内存的字符串值。
cpu:表示最大允许 CPU 的字符串值。
requests: 所需的最小内存。
memory:表示最小所需内存的字符串值。
cpu:一个字符串值,表示所需的最低 CPU。
livenessProbe:表示容器是否正在运行。
path: 指定 HTTPGet方法的路径。
port: 指定 HTTPGet方法的端口。
httpGetGet:在指定的路径和端口上 执行 HTTP 。
readinessProbe: 指示容器是否准备好响应请求。
path: 指定 HTTPGet方法的路径
port: 指定 HTTPGet方法的端口
httpHeaders:要在请求中设置的标头
name: 在请求中设置的自定义标头
value: 值
httpGetGet:在指定的路径和端口上 执行 HTTP 。
下面是这些参数常见用法的例子:
containers:
container-id:
image: busybox # Docker image name and tag
command: # (Optional) Overrides image entry point
- "/bin/echo"
args: # (Optional) Overrides entry point point
- "Hello $(FRIEND)"
variables: # (Optional) Specifies environment variable
FRIEND: World!
files: # (Optional) Specifies extra files to mount
- target: /etc/hello-world/config.yaml # - Target file path and name
mode: "666" # - Access mode
content: # - Inline content (supports templates)
- "---"
- ${resources.env.APP_CONFIG}
volumes: # (Optional) Specifies volumes to mount
- source: ${resources.data} # - External volume reference
path: sub/path # - (Optional) Sub path in the volume
target: /mnt/data # - Target mount path on the container
read_only: true # - (Optional) Mount as read-only
resources: # (Optional) CPU and memory resources needed
limits: # - (Optional) Maximum allowed
memory: "128Mi"
cpu: "500m"
requests: # - (Optional) Minimal required
memory: "64Mi"
cpu: "250m"
livenessProbe: # (Optional) Liveness probe
httpGet: # - Only HTTP GET is supported
path: /alive
port: 8080
readinessProbe: # (Optional) Liveness probe
httpGet: # - Only HTTP GET is supported
path: /ready
port: 8080
httpHeaders: # - (Optional) HTTP Headers to include
- name: Custom-Header
value: Awesome
可以简单理解为一个结构体,其中可以通过路径引用其他配置参数。
大家是否觉得这些参数配置有些复杂?其实网上也有人对此提出了质疑,具体并贴出了以下一个讽刺漫画应景:
用中国话说就是:为了精简政府机构,结果最后就又多了一个精简机构的机构。而Score 这里是不是又多了一个配置的标准呢?