configMap

Подключение в виде volume

Достаточно часто стоит задача – подключить к подам не пустые файлы с конфигурацией или простыми данными. В принципе можно воспользоваться volume типа emptyDir и при помощи инит контейнера создать все необходимые файлы и директории. Но этот способ очень громоздкий и неудобный.

Наилучшим вариантом решения такой задачи является использование volumes типа configMap.

configMap применяется для:

  • Создание конфигурационных файлов или любых других не пустых файлов.
  • Определения большого количества переменных среды окружения контейнера.

Содержимое configMap хранится в базе etcd. Поэтому не имеет смысл использовать его для больших бинарных файлов.

Текстовые данные должны быть в кодировке UTF-8. Если файл должен быть в другой кодировке, используйте binаryData.

Необходимо сначала создать объект configMap, прежде чем вы начнёте его использовать. Иначе при инициализации пода будет выводиться сообщение об ошибке, а сам под не будет запущен.

Например, в поде с web сервером openresty необходимо заменить файл index.html, выдаваемый по умолчанию при обращении в корень.

Файл index.html (meta charset закомментировано специально, мы будем использовать эту строку в дальнейшем).

<html>
<head>
  <title>Тестовая страница</title>
  <!--<meta charset="UTF-8">-->
</head>
<body>
  <h1>Тестовая страница</h1>
  <p>Простая тестовая страница, для видео на <a href="https://www.youtube.com/channel/UCU55LZT7oRxhX4GTvb5H4HA">
  моём канале</a>.
  </p>
</body>
</html>

Для того, чтобы получить configMap из этого файла, необходимо выполнить следующую команду:

kubectl create configmap index-html --from-file=index.html \
--dry-run=client -o yaml | sed '/creationTimestamp/d' > 00-index-html.yaml

Параметр —dry-run заставляет программу kubectl получившийся yaml файл выводить на стандартный вывод, а не применять его в кластер Kubernetes. Также при помощи sed мы удалим параметр creationTimestamp, что бы в дальнейшем кластер мог нормально работать с этим configMap. По умолчанию параметру присваивается значение 0 и кубернетес перестает отслеживать изменения данного объекта API.

В результате будет создан файл (00-index-html.yaml), следующего содержания:

apiVersion: v1
data:
index.html: |-
  <html>
  <head>
    <title>Тестовая страница</title>
    <!--<meta charset="UTF-8">-->
  </head>
  <body>
    <h1>Тестовая страница</h1>
    <p>Простая тестовая страница, для видео на <a href="https://www.youtube.com/channel/UCU55LZT7oRxhX4GTvb5H4HA">
    моём канале</a>.
    </p>
  </body>
  </html>
kind: ConfigMap
metadata:
  name: index-html

В один configMap можно поместить сразу несколько файлов. Например, если необходимо включить все файлы в текущей директории, команда будет выглядеть следующим образом:

kubectl create configmap index-html --from-file=./ --dry-run=client \
-o yaml | sed '/creationTimestamp/d' > 00-index-html.yaml

Пример подключения configMap в качестве volume:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: openresty
  namespace: volumes-sample
  labels:
    app: openresty
spec:
  replicas: 1
  selector:
    matchLabels:
      app: openresty
  template:
    metadata:
      labels:
        app: openresty
    spec:
      containers:
        - name: openresty
          image: openresty/openresty:centos-rpm
          env:
            - name: NGINX_HOST
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
          volumeMounts:
            - name: index-html
              mountPath: /usr/local/openresty/nginx/html/index.html
              subPath: index.html
      volumes:
        - name: index-html
          configMap:
            name: index-html

В разделе volumes указываются все подключаемые тома. В случае configMap достаточно указать name.

Подключение к поду описывается стандартно в разделе volumeMounts.

  • Name – указываем имя volume из раздела volumes.
  • mountPath – точка монтирования. В конкретном примере в configMap описан один файл и монтирование происходит как файл, а не как директории.
  • subPath — путь внутри тома, из которого должен быть смонтирован том контейнера. По умолчанию «» (корень тома).

Явно описав параметр subPath мы указали, что index.html в mountPath не директория куда подключать том. Т.е. мы в директории заменили/добавили конкретный файл.

Но при использовании subPath возникает проблема: при изменении configMap не будет изменяться содержимое подмонтированного ресурса. Поэтому, если вы предполагаете вносить изменения в файлы в configMap используйте другой способ подключения volume.

volumeMounts:
  - name: index-html
    mountPath: /usr/local/openresty/nginx/html/

В данном случае volume будет подмонтирован как обычный том. Т.е. если в это директории раньше были какие либо файлы, они не будут видны.

Если вы настроили доступ к Deployment через внешний сервис или ingress, посмотрите содержимое страницы, русские буквы будут отображаться не корректно.

Если вы этого не делали, подключитесь к поду и посмотрите содержимое файла. Для начала посмотрите название подов:

kubectl -n volumes-sample get pods

Затем запустите bash внутри пода, указав его правильное имя:

kubectl -n volumes-sample exec openresty-7cd79cfd94-5zjgl -i -t -- bash

Внутри пода в bash выполните команду:

cat /usr/local/openresty/nginx/html/index.html

Попробуйте отредактировать configMap прямо в кубернетес (при условии, что вы применили файлы деплоя configMap и Deploy), при помощи следующей команды:

kubectl -n volumes-sample edit cm index-html

В html файле уберите комментарии (<!— и —>) и сохраните изменения.

Через некоторое время посмотрите содержимое страницы, русские буквы будут отображаться корректно. Следовательно, изменения в configMap приводят к изменению содержимого файлов в поде, куда они подключены.

Подключение в виде переменных среды окружения

Достаточно часто, при запуске приложения приходится определять большое количество переменных среды окружения. Это можно делать явно, при описании под. Но можно вынести в отдельный configMap.

Пример определения configMap.

apiVersion: v1
kind: ConfigMap
metadata:
  name: env-config
data:
  ENV_HOSTS: "1"
  ENV_SOME_VALUE: new
  ENV_URL_KRYUKOV_BIZ: http://www.kryukov.biz

Как видно из примера, переменные среды окружения определяются в разделе data.

Пример подключения configMap:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: openresty
  namespace: volumes-sample
  labels:
    app: openresty
spec:
  replicas: 1
  selector:
    matchLabels:
      app: openresty
  template:
    metadata:
      labels:
        app: openresty
    spec:
      containers:
        - name: openresty
          image: openresty/openresty:centos-rpm
          env:
            - name: NGINX_HOST
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
          envFrom:
            - configMapRef:
                name: env-config
          ports:
            - containerPort: 80
              name: http
              protocol: TCP
          volumeMounts:
            - name: index-html
              mountPath: /usr/local/openresty/nginx/html/
      volumes:
        - name: index-html
          configMap:
            name: index-html

Подключение configMap происходит в определении контейнера при помощи envFrom.

Что бы увидеть эти переменные, можно подключиться к поду как в предыдущем примере. И в командной строке набрать:

env | grep ENV

При изменении configMap во время работы пода, не произойдет изменение переменных среды окружения. Т.е. сначала изменяем configMap, затем перезапускаем под.