![](/img/trans.png)
[英]How to dynamically set values containing URLs (with slashes) in Kubernetes yaml files & prevent: bad flag in substitute command
[英]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。
一個例子:
在你的機器上安裝 helm 以便helm
命令存在
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
所以它從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.