繁体   English   中英

如何使用 Kubernetes yaml 文件设置动态值

[英]How to set dynamic values with Kubernetes yaml file

例如,部署 yaml 文件:

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: guestbook
spec:
  replicas: 2
  template:
    metadata:
      labels:
        app: guestbook
      spec:
        container:
          - name: guestbook
            image: {{Here want to read value from config file outside}}

Kubernetes 有一个ConfigMap功能,但这也将键/值写入 yaml 文件。 有没有办法将密钥设置为环境变量?

您不能自动执行此操作,您需要使用外部脚本来“编译”您的模板,或者按照@Jakub 的建议使用 helm。

您可能想要使用自定义 bash 脚本,可能与您的 CI 管道集成。

给定一个名为deploy.yml.template的模板 yml 文件与您提供的非常相似,您可以使用以下内容:

#!/bin/bash

# sample value for your variables
MYVARVALUE="nginx:latest"

# read the yml template from a file and substitute the string 
# {{MYVARNAME}} with the value of the MYVARVALUE variable
template=`cat "deploy.yml.template" | sed "s/{{MYVARNAME}}/$MYVARVALUE/g"`

# apply the yml with the substituted value
echo "$template" | kubectl apply -f -

您还可以在部署时使用envsubst

例如

cat $app/deployment.yaml | envsubst | kubectl apply ...

它将用它们的值替换文件中的所有变量。 在部署到多个环境时,我们在 CI 上成功地使用了这种方法,还将 CI_TAG 等注入到部署中。

我认为在 Kubernetes 中通过变量或 Config Map 设置图像是不可能的。 但是您可以使用例如Helm使您的部署更加灵活和可配置。

一行:

cat app-deployment.yaml | sed "s/{{BITBUCKET_COMMIT}}/$BITBUCKET_COMMIT/g" | kubectl apply -f -

在 yaml 中:

  ...
  containers:
  - name: ulisses
    image: niceuser/niceimage:{{BITBUCKET_COMMIT}}
  ...

这种事情用ytt非常容易:

deployment.yml

#@ load("@ytt:data", "data")
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: guestbook
spec:
  replicas: 2
  template:
    metadata:
      labels:
        app: guestbook
      spec:
        container:
          - name: guestbook
            image: #@ data.values.image

values.yml

#@data/values
image: nginx@sha256:fe2fa7bb1ceb86c6d9c935bc25c3dd8cbd64f2e95ed5b894f93ae7ffbd1e92bb

那么...

$ ytt -f deployment.yml -f values.yml | kubectl apply -f -

甚至更好的是,使用ytt的表亲kapp来获得高控制度的部署体验:

$ ytt -f deployment.yml -f values.yml | kapp deploy -a guestbook -f -

我创建了一个名为kubectl_create的脚本并使用它来运行 create 命令。 它将替换环境变量中引用的模板中的任何值。

#!/bin/bash
set -e
eval "cat <<EOF
$(<$1)
EOF
" | kubectl create -f -

例如,如果模板文件有:

apiVersion: v1
kind: Service

metadata:
  name: nginx-external
  labels:
    app: nginx

spec:
  loadBalancerIP: ${PUBLIC_IP}
  type: LoadBalancer
  ports:
  - name: http
    port: 80
    targetPort: 80
  - name: https
    port: 443
    targetPort: 443

  selector:
    app: nginx

运行kubectl_create nginx-service.yaml ,然后在运行实际的 kubectl create 命令之前,环境变量 PUBLIC_IP 将被替换。

我的做法:

tools/jinja2-cli.py

#!/usr/bin/env python3
import os
import sys
from jinja2 import Environment, FileSystemLoader

sys.stdout.write(Environment(loader=FileSystemLoader('templates/')).from_string(sys.stdin.read()).render(env=os.environ) + "\n")

制定规则:

_GENFILES = $(basename $(TEMPLATES))
GENFILES = $(_GENFILES:templates/%=%)

$(GENFILES): %: templates/%.j2 $(MKFILES) tools/jinja2-cli.py .env
        env $$(cat .env | xargs) tools/jinja2-cli.py < $< > $@ || (rm -f $@; false)

.j2模板文件中,您可以使用任何 jinja 语法结构,例如{{env.GUEST}}将替换为.env定义的GUEST

所以你的templates/deploy.yaml.j2看起来像:

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: guestbook
spec:
  replicas: 2
  template:
    metadata:
      labels:
        app: guestbook
      spec:
        container:
          - name: guestbook
            image: {{env.GUEST}}

另一种方法(仅使用bash内置函数和xargs )可能是

env $(cat .env | xargs) cat <<EOF | kubectl create -f -
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: guestbook
spec:
  replicas: 2
  template:
    metadata:
      labels:
        app: guestbook
      spec:
        container:
          - name: guestbook
            image: ${GUEST}
EOF

我一直在使用kubetpl

它具有三种不同的模板风格,并支持 ConfigMap/Secret 冻结。

yaml 不会从另一个 yaml 文件中读取值。 作为替代方法,您可以试试这个。

kind: Pod
metadata:
  creationTimestamp: null
  annotations:
    namespace: &namespaceId dev
    imageId: &imgageId nginx
    podName: &podName nginx-pod
    containerName: &containerName nginx-container
  name: *podName
  namespace: *namespaceId
spec:
  containers:
  - image: *imgageId
    name: *containerName
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}

我创建了一个名为 kubectl_apply 的脚本。 它从 .env 加载变量,替换 yml 中的 ${CUSTOMVAR} 并将其传递给 kubectl 命令

  #!/bin/bash
  set -a
  source .env
  set +a
  eval "cat <<EOF
  $(<$1)
  EOF
  " | kubectl apply -f -

我已经发布了一个命令行工具ysed ,它可以帮助您解决这个问题,以防您计划编写脚本。

我认为现在应该使用标准 - Helm 而不是自定义脚本来解决这个问题。 无需部署即可在机器上生成 Kubernets yaml。

一个例子:

  1. 在你的机器上安装 helm 以便helm命令存在

  2. https://artifacthub.io/packages/helm/pauls-helm-charts/helloworld - 安装按钮

  3. helm repo add pauls-helm-charts http://tech.paulcz.net/charts

  4. helm pull pauls-helm-charts/helloworld --version 2.0.0

  5. tar -zxvf helloworld-2.0.0.tgz && cd helloworld

  6. helm template -f values.yaml --output-dir helloworld . --namespace my-namespace --name-template=my-name

所以它从values.yaml创建了这些文件:

wrote helloworld/helloworld/templates/serviceaccount.yaml
wrote helloworld/helloworld/templates/service.yaml
wrote helloworld/helloworld/templates/deployment.yaml

values.yaml ,您可以更改预定义的repository (或者可以根据需要在 Kubernetes yaml 中 100% 重复任何值):

image:
  repository: paulczar/spring-helloworld

现在,如果您要部署,请确保kubectl正常工作并使用kubectl apply -f serviceaccount.yaml等应用这些生成的文件。

Helm 正是用于此类用途以及更多用途。 它将复杂的资源部署集作为一个组等处理。

但是,如果我们仍在寻找一些简单的替代方案,那么使用 ant 怎么样?

如果您想在构建过程或测试过程中修改文件,那么您也可以使用 ant 任务。

使用 ant,您可以将所有环境值加载为属性,或者您可以简单地加载属性文件,例如:

<property environment="env" />
<property file="build.properties" />

然后你可以有一个目标,将模板文件转换为你想要的 yaml 文件。

<target name="generate_from_template">

    <!-- Copy task to replaces values and create new file -->
    <copy todir="${dest.dir}" verbose="true" overwrite="true" failonerror="true">

        <!-- List of files to be processed -->
        <fileset file="${source.dir}/xyz.template.yml" />

        <!-- Mapper to transform filename. Removes '.template' from the file
            name when copying the file to output directory -->
        <mapper type="regexp" from="(.*).template(.*)" to="\1\2" />

        <!-- Filter chain that replaces the template values with actual values 
            fetched from properties file -->
        <filterchain>
            <expandproperties />
        </filterchain>
    </copy>
</target>

当然,如果您想为多个文件(嵌套或其他)动态更改值,您可以使用fileset而不是file

您的模板文件xyz.template.yml应如下所示:

apiVersion: v1
kind: Service
metadata:
  name: ${XYZ_RES_NAME}-ser
  labels:
    app: ${XYZ_RES_NAME}
    version: v1
spec:
  type: NodePort
  ports:
    - port: ${env.XYZ_RES_PORT}
      protocol: TCP
  selector:
    app: ${XYZ_RES_NAME}
    version: v1

env. 从环境变量和其他属性文件加载的属性

希望它有所帮助:)

如果您只想在部署运行时更改镜像或标签,您可以在部署中设置特定容器的镜像:

kubectl apply -f k8s
kubectl set image deployments/worker-deployment worker=IMAGE:TAG

在 jitsi 项目中, tpl == frep命令用于替换值,这是envsubst的扩展

https://github.com/jitsi/docker-jitsi-meet/issues/65

我一直在使用旧的 shell 工具,比如 sed 和朋友,但是当这些代码有很多价值需要处理时,它很快就会变得不可读。

创建一个名为kubectl_advance的文件,如下所示,并像 kubectl 命令一样调用它。

例如

EXPORT MY_VAL="my-v1"

kubectl_advance -c -f sample.yaml # -c option is to call create command
kubectl_advance -r -f sample2.yaml # -r option is to call replace command

假设 yaml 文件具有 ${MY_VAL} 之类的值将被环境变量替换。

#!/usr/bin/env bash

helpFunction()
{
   echo "Supported option is [-f] for file"
   exit 1
}

while getopts "f:cr" opt
do
   case "$opt" in
      f ) yamlFile="$OPTARG" ;;
      c ) COMMAND_IS_CREATE="true" ;;
      r ) COMMAND_IS_REPLACE="true" ;;
      ? ) helpFunction ;; # Print helpFunction in case parameter is non-existent
   esac
done

echo 'yaml file is : '$yamlFile

YAML_CONTENT=`eval "cat <<EOF
$(<$yamlFile)
EOF
"`

echo 'Final File Content is :=>'
echo '------------------'

echo "$YAML_CONTENT"


if [[ "$COMMAND_IS_CREATE" == "true" ]]; then
  COMMAND="create"
fi

if [[ "$COMMAND_IS_REPLACE" == "true" ]]; then
  COMMAND="replace"
fi

echo "$YAML_CONTENT" | kubectl $COMMAND -f -

当您要替换的变量是包含像这样的斜杠的 url 时

DASHBOARD_HOST=http://abd1c6f-123246.eu-central-1.elb.amazonaws.com    

使用 sed 的解决方案bad flag in substitute command: '/'产生一个bad flag in substitute command: '/'错误。 但是由于 sed s命令可以使用任何字符作为分隔符,我们可以像这样使用s#而不是s/来优化解决方案:

sed "s#{{DASHBOARD_HOST}}#$DASHBOARD_HOST#g" app-deployment.yaml | kubectl apply -f -

我们也可以ommit的cat ,通过规定gertvdijk因为sed是能够读取文件放在它自己。 我们要在app-deployment.yaml替换的变量可能看起来像这样:

...
params:
  - name: DASHBOARD_HOST
    value: {{DASHBOARD_HOST}}
...

多变量替换

使用 sed 您甚至可以替换yaml 文件中的多个变量 假设您的app-deployment.yaml具有以下内容:

...
params:
  - name: DASHBOARD_HOST
    value: {{DASHBOARD_HOST}}
  - name: DASHBOARD_PORT
    value: {{DASHBOARD_PORT}}
...

现在在你的 shell 中设置这两个变量:

DASHBOARD_HOST=http://abd1c6f-123246.eu-central-1.elb.amazonaws.com
DASHBOARD_PORT=9785

然后使用; 链接 sed s#命令像这样:

sed "s#{{DASHBOARD_HOST}}#$DASHBOARD_HOST#g;s#{{DASHBOARD_PORT}}#$DASHBOARD_PORT#g" app-deployment.yaml | kubectl apply -f -

对于我的部署,我通常使用 Helm 图表。 它需要我定期更新 values.yaml 文件。

为了动态更新 YAML 文件,我使用了“envsubst”,因为它很简单,不需要复杂的配置。 此外,大多数工具仅适用于有效的 Kubernetes 清单,而不适用于简单的 YAML 文件。

我创建了一个简单的脚本来处理 YAML 修改以简化使用

https://github.com/alexusarov/vars_replacer

例子:

./vars_replacer.sh -i [input_file] -o [output_file] -p "[key=value] [key=value]"

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM