Как это лучше всего сделать в K8S?
Есть несколько способов снять кожу с кошки, но я бы предложил сделать следующее:
- Сохраните конфигурацию в
configMap
и смонтируйте ее как отдельный том. Такая карта хранится как манифест k8s, поэтому все изменения в ней отделены от образа сборки докера - нет необходимости перестраивать или хранить конфиденциальные данные в изображении. Вы также можете использовать вместо (или вместе с) secret
таким же образом, как configMap
.
- Используйте
initContainers
, чтобы выполнить инициализацию до того, как основной контейнер должен быть подключен к сети, автоматически покрывая ваш «один раз при развертывании». В качестве альтернативы (если операция инициализации не повторяется) вы можете использовать Jobs
и запускать ее при необходимости.
Вот отрывок из примера, который мы используем в gitlab runner:
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
name: ss-my-project
spec:
...
template:
....
spec:
...
volumes:
- name: volume-from-config-map-config-files
configMap:
name: cm-my-config-files
- name: volume-from-config-map-script
projected:
sources:
- configMap:
name: cm-my-scripts
items:
- key: run.sh
path: run.sh
mode: 0755
# if you need to run as non-root here is how it is done:
securityContext:
runAsNonRoot: true
runAsUser: 999
supplementalGroups: [999]
containers:
- image: ...
name: ...
command:
- /scripts/run.sh
...
volumeMounts:
- name: volume-from-config-map-script
mountPath: "/scripts"
readOnly: true
- mountPath: /usr/share/my-app-config/config.file
name: volume-from-config-map-config-files
subPath: config.file
...
Вы можете, конечно, смонтировать несколько томов из карт конфигурации или объединить их в один, в зависимости от частоты ваших изменений и затронутых частей. Это пример с двумя отдельно смонтированными configMap
, чтобы проиллюстрировать принцип (и отметить исполняемый файл скрипта), но вы можете использовать только один для всех необходимых файлов, поместить несколько файлов в один или поместить один файл в каждый - в соответствии с вашими потребностями .
Пример такого configMap выглядит так:
apiVersion: v1
kind: ConfigMap
metadata:
name: cm-my-scripts
data:
run.sh: |
#!/bin/bash
echo "Doing some work here..."
И пример файла конфигурации configMap выглядит так:
kind: ConfigMap
apiVersion: v1
metadata:
name: cm-my-config-files
data:
config.file: |
---
# Some config.file (example name) required in project
# in whatever format config file actually is (just example)
... (here is actual content like server.host: "0" or EFG=True or whatever)
Игра с одним или несколькими файлами в configMaps
может привести к желаемому результату, и в зависимости от ваших потребностей вы можете иметь столько, сколько вам нужно.
В docker-compose я могу создать ponting для тома в каталоге, где находятся файлы конфигурации, а затем в командной части выполнить чтение bash -c cmds из файлов конфигурации на томе.
В k8s это эквивалентно hostPath
, но тогда вы серьезно ограничите способность k8s планировать модули для разных узлов. Это может быть хорошо, если у вас есть кластер с одним узлом (или во время разработки), чтобы упростить изменение файлов конфигурации, но для фактического развертывания рекомендуется подход, описанный выше.