Как установить динамические значения с помощью файла Kubernetes yaml?
Например, файл развертывания 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}}
E сть ConfigMap
особенность с Kubernetes, но это также записывает ключ / значение в файл yaml. Есть ли способ установить ключ для переменных среды?
19 ответов
Я не думаю, что можно установить изображение через переменную или Config Map в Kubernetes. Но вы можете использовать, например, Helm, чтобы сделать развертывание более гибким и настраиваемым.
Вы также можете использовать envsubst
при развертывании.
например
cat $app/deployment.yaml | envsubst | kubectl apply ...
Он заменит все переменные в файле их значениями. Мы успешно используем этот подход в нашем CI при развертывании в нескольких средах, а также для внедрения CI_TAG и т. Д. В развертывания.
Вы не можете сделать это автоматически, вам нужно использовать внешний скрипт для "компиляции" вашего шаблона или использовать helm, как предложено @Jakub.
Возможно, вы захотите использовать собственный скрипт bash, возможно, интегрированный с вашим конвейером CI.
Учитывая шаблон YML-файл называется deploy.yml.template
очень похоже на тот, который вы предоставили, вы можете использовать что-то вроде этого:
#!/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 -
Одна линия:
cat app-deployment.yaml | sed "s/{{BITBUCKET_COMMIT}}/$BITBUCKET_COMMIT/g" | kubectl apply -f -
В ямле:
...
containers:
- name: ulisses
image: niceuser/niceimage:{{BITBUCKET_COMMIT}}
...
Когда переменная, которую вы хотите заменить, представляет собой URL-адрес, содержащий косую черту, подобную этой
DASHBOARD_HOST=http://abd1c6f-123246.eu-central-1.elb.amazonaws.com
решение с использованием sed создает
bad flag in substitute command: '/'
ошибка. Но как сед
s
команда может использовать любой символ в качестве разделителя , мы могли бы оптимизировать решение, используя вместо
s/
как это:
sed "s#{{DASHBOARD_HOST}}#$DASHBOARD_HOST#g" app-deployment.yaml | kubectl apply -f -
Мы также можем опустить
cat
как заявил gertvdijk , поскольку
sed
умеет читать файлы самостоятельно. Переменная, которую мы хотим заменить внутри, может выглядеть примерно так:
...
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}}
...
Теперь установите обе переменные внутри вашей оболочки:
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 -
Это очень легко с 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
и используйте его для запуска команды создания. Он заменит любое значение в шаблоне, на которое ссылается переменная среды.
#!/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
и тогда переменная окружения PUBLIC_IP будет подставлена перед выполнением фактической команды kubectl create.
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: {}
Я использую kubetpl
Он имеет три различных шаблона и поддерживает заморозку ConfigMap/Secret.
Мой подход:
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/%.in $(MKFILES) tools/jinja2-cli.py .env
env $$(cat .env | xargs) tools/jinja2-cli.py < $< > $@ || (rm -f $@; false)
Внутри файла вы можете использовать любую синтаксическую конструкцию jinja, например {{env.IMAGE}}
будет заменено значением IMAGE
определяется в .env
Другой подход может быть
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: ${IMAGE}
EOF
Я думаю, что в настоящее время для решения этой проблемы следует использовать стандарт - Helm вместо пользовательских скриптов. Вам не нужно выполнять развертывание для генерации yamls Kubernets на машине.
Пример:
Установите руль на свою машину, чтобы
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
Итак, он создал эти файлы из:
wrote helloworld/helloworld/templates/serviceaccount.yaml
wrote helloworld/helloworld/templates/service.yaml
wrote helloworld/helloworld/templates/deployment.yaml
Внутри
values.yaml
, вы можете изменить предустановленные
repository
(или 100% любое значение можно повторять в ямлах Kubernetes, как хотите):
image:
repository: paulczar/spring-helloworld
Теперь, если вы хотите развернуть, убедитесь, что
kubectl
работает и просто примените эти сгенерированные файлы, используя
kubectl apply -f serviceaccount.yaml
, так далее.
Если вы просто хотите изменить образ или тег во время развертывания, вы можете установить образ определенного контейнера в своем развертывании:
kubectl apply -f k8s
kubectl set image deployments/worker-deployment worker=IMAGE:TAG
Согласно спецификации YAML , сделать это невозможно. но...
Это возможно с помощью оператора разнесения yq.
Пространство имен, развертывание, ClusterIP, вход ... Чисто и СУХО :
cat <<EOF | yq 'explode(.)' | kubectl apply -f -
kind: Namespace
apiVersion: v1
metadata:
name: &namespace example-namespace
---
kind: Deployment
apiVersion: apps/v1
metadata:
name: example-deployment
namespace: *namespace
spec:
replicas: 1
template:
metadata:
labels:
app: &app-label example-app
spec:
containers:
- name: httpecho
image: hashicorp/http-echo:0.2.3
args:
- "-listen=:5678"
- "-text=hello world 1"
ports:
- containerPort: &app-port 5678
selector:
matchLabels:
app: *app-label
---
kind: Service
apiVersion: v1
metadata:
name: &app-cluster-ip example-service
namespace: *namespace
spec:
type: ClusterIP
selector:
app: *app-label
ports:
- name: http
protocol: TCP
port: *app-port
targetPort: *app-port
---
kind: Ingress
apiVersion: networking.k8s.io/v1
metadata:
name: example-ingress
namespace: *namespace
spec:
ingressClassName: caddy
rules:
- host: example.kubernetes.localhost
http:
paths:
- path: /hello
pathType: Prefix
backend:
service:
name: *app-cluster-ip
port:
number: *app-port
EOF
Я создаю скрипт под названием kubectl_apply. Он загружает переменные из.env, заменяет ${CUSTOMVAR} в yml и передает его команде kubectl
#!/bin/bash
set -a
source .env
set +a
eval "cat <<EOF
$(<$1)
EOF
" | kubectl apply -f -
создать файл с именем
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 -
В проекте jitsi
tpl
==
frep
команда используется для подстановки значений, расширение для
envsubst
https://github.com/jitsi/docker-jitsi-meet/issues/65
Я продолжаю использовать старые инструменты оболочки, такие как sed и друзья, но такой код быстро становится нечитаемым, когда с ним нужно иметь дело более чем горстки ценности.
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.
свойство загружается из переменных среды и другого из файла свойств
Надеюсь, это помогло:)
Для своих развертываний я обычно использую диаграммы 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]"