简体   繁体   English

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

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

For example, a deployment 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}}

There is a ConfigMap feature with Kubernetes, but that's also write the key/value to the yaml file. Kubernetes 有一个ConfigMap功能,但这也将键/值写入 yaml 文件。 Is there a way to set the key to environment variables?有没有办法将密钥设置为环境变量?

You can't do it automatically, you need to use an external script to "compile" your template, or use helm as suggested by @Jakub.您不能自动执行此操作,您需要使用外部脚本来“编译”您的模板,或者按照@Jakub 的建议使用 helm。

You may want to use a custom bash script, maybe integrated with your CI pipeline.您可能想要使用自定义 bash 脚本,可能与您的 CI 管道集成。

Given a template yml file called deploy.yml.template very similar to the one you provided, you can use something like this:给定一个名为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 -

You can also use envsubst when deploying.您还可以在部署时使用envsubst

eg例如

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

It will replace all variables in the file with their values.它将用它们的值替换文件中的所有变量。 We are successfully using this approach on our CI when deploying to multiple environments, also to inject the CI_TAG etc into the deployments.在部署到多个环境时,我们在 CI 上成功地使用了这种方法,还将 CI_TAG 等注入到部署中。

I don't think it is possible to set image through variable or Config Map in Kubernetes.我认为在 Kubernetes 中通过变量或 Config Map 设置图像是不可能的。 But you can use for example Helm to make your deployments much more flexible and configurable.但是您可以使用例如Helm使您的部署更加灵活和可配置。

One line:一行:

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

In yaml:在 yaml 中:

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

This kind of thing is painfully easy with ytt :这种事情用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

Then...那么...

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

or even better, use ytt 's cousin, kapp for a high-control deployment experience:甚至更好的是,使用ytt的表亲kapp来获得高控制度的部署体验:

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

I create a script called kubectl_create and use it to run the create command.我创建了一个名为kubectl_create的脚本并使用它来运行 create 命令。 It will substitute any value in the template that is referenced in an environment variable.它将替换环境变量中引用的模板中的任何值。

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

For example, if the template file has:例如,如果模板文件有:

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

Run kubectl_create nginx-service.yaml and then the environment variable PUBLIC_IP will be substituted before running the actual kubectl create command.运行kubectl_create nginx-service.yaml ,然后在运行实际的 kubectl create 命令之前,环境变量 PUBLIC_IP 将被替换。

My approach:我的做法:

tools/jinja2-cli.py : 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")

Make rule:制定规则:

_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)

Inside the .j2 template file you can use any jinja syntax construct, eg {{env.GUEST}} will be replaced by the value of GUEST defined in .env.j2模板文件中,您可以使用任何 jinja 语法结构,例如{{env.GUEST}}将替换为.env定义的GUEST

So your templates/deploy.yaml.j2 would look like:所以你的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}}

Another approach (using just bash builtins and xargs ) might be另一种方法(仅使用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

I have been using kubetpl我一直在使用kubetpl

It has three different template flavors and supports ConfigMap/Secret freezing.它具有三种不同的模板风格,并支持 ConfigMap/Secret 冻结。

yaml does not read values from another yaml file. yaml 不会从另一个 yaml 文件中读取值。 As an alternative approach you could try this.作为替代方法,您可以试试这个。

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: {}

I create a script called kubectl_apply.我创建了一个名为 kubectl_apply 的脚本。 It loads variables from .env, replace ${CUSTOMVAR} in yml and pass it to kubectl command它从 .env 加载变量,替换 yml 中的 ${CUSTOMVAR} 并将其传递给 kubectl 命令

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

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

I think the standard - Helm should be used instead of custom scripts to solve this problem nowadays.我认为现在应该使用标准 - Helm 而不是自定义脚本来解决这个问题。 You don't need to deploy to generate Kubernets yamls on the machine.无需部署即可在机器上生成 Kubernets yaml。

An example:一个例子:

  1. Install helm on your machine so helm command exists在你的机器上安装 helm 以便helm命令存在

  2. https://artifacthub.io/packages/helm/pauls-helm-charts/helloworld - Install button 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

So it created these files from values.yaml :所以它从values.yaml创建了这些文件:

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

Inside values.yaml , you can change predefined repository (or 100% any value can be repeated in Kubernetes yamls as you wish):values.yaml ,您可以更改预定义的repository (或者可以根据需要在 Kubernetes yaml 中 100% 重复任何值):

image:
  repository: paulczar/spring-helloworld

Now if you want to deploy, make sure kubectl works and just apply these generated files using kubectl apply -f serviceaccount.yaml , etc.现在,如果您要部署,请确保kubectl正常工作并使用kubectl apply -f serviceaccount.yaml等应用这些生成的文件。

Helm is exactly meant for such things and a lot more. Helm 正是用于此类用途以及更多用途。 It handle complex set of resource deployment as a group etc.它将复杂的资源部署集作为一个组等处理。

But if we are still looking for some simple alternative then how about using ant?但是,如果我们仍在寻找一些简单的替代方案,那么使用 ant 怎么样?

If you want to modify the file as part of build process or test process then you can go with ant task as well.如果您想在构建过程或测试过程中修改文件,那么您也可以使用 ant 任务。

Using ant you can load all environment values as property or you can simply load properties file like:使用 ant,您可以将所有环境值加载为属性,或者您可以简单地加载属性文件,例如:

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

Then you can have a target which converts template files into your desired yaml file.然后你可以有一个目标,将模板文件转换为你想要的 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>

Of course you can use a fileset instead of file in case you want to change values dynamically for multiple files (nested or whatever)当然,如果您想为多个文件(嵌套或其他)动态更改值,您可以使用fileset而不是file

Your template file xyz.template.yml should look like:您的模板文件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. property being loaded from environment variables and other from property file从环境变量和其他属性文件加载的属性

Hope it helped :)希望它有所帮助:)

If you just want to change the image or a tag while your deployment is running, you could set the image of a specific container in your deployment:如果您只想在部署运行时更改镜像或标签,您可以在部署中设置特定容器的镜像:

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

In the jitsi project the tpl == frep command is used to substitute values, an extension to envsubst在 jitsi 项目中, tpl == frep命令用于替换值,这是envsubst的扩展

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

I keep on using the old shell tools like sed and friends but such code is quickly unreadable when its more than a handful of value to deal with.我一直在使用旧的 shell 工具,比如 sed 和朋友,但是当这些代码有很多价值需要处理时,它很快就会变得不可读。

create a file called kubectl_advance as below and enjoy calling it just like kubectl commands.创建一个名为kubectl_advance的文件,如下所示,并像 kubectl 命令一样调用它。

eg例如

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

Assuming the yaml file has the value like ${MY_VAL} to be replaced by the environment variable.假设 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 -

When the variable you want to replace is a url containing slashes like this当您要替换的变量是包含像这样的斜杠的 url 时

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

the solution using sed produces a bad flag in substitute command: '/' error.使用 sed 的解决方案bad flag in substitute command: '/'产生一个bad flag in substitute command: '/'错误。 But as sed s command can use any character as a delimiter , we could optimize the solution using s# instead of s/ like this:但是由于 sed s命令可以使用任何字符作为分隔符,我们可以像这样使用s#而不是s/来优化解决方案:

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

We can also ommit the cat as stated by gertvdijk since sed is able to read files on it's own.我们也可以ommit的cat ,通过规定gertvdijk因为sed是能够读取文件放在它自己。 The variable we want to replace inside the app-deployment.yaml could look somehow like this:我们要在app-deployment.yaml替换的变量可能看起来像这样:

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

Multiple variable substitution多变量替换

Using sed you can even replace multiple variables in your yaml file.使用 sed 您甚至可以替换yaml 文件中的多个变量 Let's assume your app-deployment.yaml has the following contents:假设您的app-deployment.yaml具有以下内容:

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

Now set both variables inside your shell:现在在你的 shell 中设置这两个变量:

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

And then chain the sed s# commands using ;然后使用; 链接 sed s#命令like this:像这样:

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

For my deployments, I typically use Helm charts.对于我的部署,我通常使用 Helm 图表。 It requires me to update values.yaml files periodically.它需要我定期更新 values.yaml 文件。

For dynamically updating YAML files, I used 'envsubst' since it is simple and does not require sophisticated configuration.为了动态更新 YAML 文件,我使用了“envsubst”,因为它很简单,不需要复杂的配置。 In addition, most of the tools only work with valid Kubernetes manifests, not simple YAML files.此外,大多数工具仅适用于有效的 Kubernetes 清单,而不适用于简单的 YAML 文件。

I created a simple script to handle the YAML modification to simplify the usage我创建了一个简单的脚本来处理 YAML 修改以简化使用

https://github.com/alexusarov/vars_replacer https://github.com/alexusarov/vars_replacer

Example:例子:

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

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

相关问题 如何在 Kubernetes yaml 文件中动态设置包含 URL(带斜杠)的值并防止:替换命令中的错误标志 - How to dynamically set values containing URLs (with slashes) in Kubernetes yaml files & prevent: bad flag in substitute command Openshift / Kubernetes:使用Yaml文件中的服务帐户中的令牌 - Openshift/Kubernetes: Use token from Service account in yaml file 从 YAML 管道到模板文件的 Azure Pipeline 动态参数 - Azure Pipeline dynamic parameters to template file from YAML pipeline 用于值的 Configmap 中的 Helm 模板。yaml - Helm Templating in Configmap for values.yaml 如何使用 jinja 评估 yaml 密钥,然后使用 ansible 使用 jinja in.j2 文件评估其值? - How to evaluate a yaml key using jinja and then evaluate its value using jinja in .j2 file using ansible? 如何将传递的值设置为模板的字段? - How to set passed values into template's fields? 如何使用 Python 检索动态 html 内容的值 - How to retrieve the values of dynamic html content using Python 是否可以将模板化的 blob 文本包含到 values.yaml 中? - Is it possible to include a templated blob text into values.yaml? 如何为包含的.html文件动态设置宽度 - How to set width dynamically for included .html file 如何以编程方式将值添加到Wordpress模板文件? - How to add values to a Wordpress template file programmatically?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM