[英]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 等注入到部署中。
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
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:一个例子:
Install helm on your machine so helm
command exists在你的机器上安装 helm 以便helm
命令存在
https://artifacthub.io/packages/helm/pauls-helm-charts/helloworld - Install button https://artifacthub.io/packages/helm/pauls-helm-charts/helloworld - 安装按钮
helm repo add pauls-helm-charts http://tech.paulcz.net/charts
helm pull pauls-helm-charts/helloworld --version 2.0.0
tar -zxvf helloworld-2.0.0.tgz && cd helloworld
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}}
...
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.