Kubernetes: ConfigMaps и Secrets на примере Gorush сервера

Автор: | 02/14/2020
 

Имеется Gorush сервер, запущенный в посте Kubernetes: запуск push-сервера Gorush в EKS за AWS LoadBalancer, к которому теперь хочется добавить возможность добавления своего файла настроек — для Staging с одними данными, и для Production — с другими.

Используем Kubernetes ConfigMap для хранения содержимого файлов настроек Gorush, которые потом покдлючим внутрь запускаемых подов и их контейнеров, и Secrets — для конфиденциальных данных.

Сейчас в файле gorush-configmap.yaml описывается дефолтный configMap для Gorush, в котором передаются настройки подключения к Redis-сервису:

apiVersion: v1
kind: ConfigMap
metadata:
  name: gorush-config
  namespace: gorush
data:
  # stat
  stat.engine: redis
  stat.redis.host: redis:6379

Кроме этого, надо добавить:

  • SSL-сертификат, используемый при отравке пушей
  • пароль этого сертификата

Добавим два объекта типа Kubernetes Secret — один для пароля, второй — для файла ключа аутентификации в Apple при отправке пушей.

Kubernetes Secrets

Создаём новый файл — gorush-secrets.yaml, добавляем в него пока только тело p12-сертификата:

Т.к. у нас бинарный p12-ключ — используем тип data, получаем base64 из сертификата:

cat apns_wl.p12 | base64
MIIM9QIBAzCCDLwGCSqGSIb3DQEHAaCCDK0EggypMIIMpTCCBycGCSqGSIb3DQEHBqCCBxgwggcU
AgEAMIIHDQYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQYwDgQI+BcNML0eE1oCAggAgIIG4KVvRBPp
qRiubF1QeqOE1n6x1+k92pjpxvpJph+ZhS+1ztMSFOOIlwAPNMBYDd1Opg8x3lXCxN88OzuyFSHu
nLSzqyx1b8sPEEhUejeKlzqDQczOhJTuvO9lDNZQS/4Cbn1LRlr6DbrqSexE1GRgpal5Hcc5i9rr
...

Добавляем data map:

---
apiVersion: v1
kind: Secret
metadata:
  name: ios-push-secret
  namespace: gorush
type: Opaque
data:
  ios-push-rsa-key: |
    MIIM9QIBAzCCDLwGCSqGSIb3DQEHAaCCDK0EggypMIIMpTCCBycGCSqGSIb3DQEHBqCCBxgwggcU
    AgEAMIIHDQYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQYwDgQI+BcNML0eE1oCAggAgIIG4KVvRBPp
    ...

Либо, если это PEM-ключ, то можно передать как stringData — без base64, просто текст:

---
apiVersion: v1
kind: Secret
metadata:
  name: ios-push-secret
  namespace: gorush
type: Opaque
stringData:
  ios-push-rsa-key: |
    -----BEGIN CERTIFICATE-----
    MIIGJDCCBQygAwIBAgIIAtw7YRUahfYwDQYJKoZIhvcNAQELBQAwgZYxCzAJBgNV
    BAYTAlVTMRMwEQYDVQQKDApBcHBsZSBJbmMuMSwwKgYDVQQLDCNBcHBsZSBXb3Js
    ZHdpZGUgRGV2ZWxvcGVyIFJlbGF0aW9uczFEMEIGA1UEAww7QXBwbGUgV29ybGR3
...

Создаём секрет:

kubectl apply -f gorush-secrets.yaml
secret/ios-push-secret created

Проверяем:

kubectl -n gorush describe secret ios-push-secret
Name:         ios-push-secret
Namespace:    gorush
Labels:       <none>
Annotations:
Type:         Opaque
Data
====
ios-push-rsa-key:  4586 bytes

Далее — этот сертификат надо смонтировать в виде файла в создаваемые поды и их контейнеры.

Kubernetes Secrets и volumeMounts — секреты, как файлы

Обновляем gorush-deployment.yaml — добавляем создание volumes из секрета:

...
      volumes:
      - name: ios-push-secret-vol
        secret:
          secretName: ios-push-secret
          items:
          - key: ios-push-p12-key
            path: apns-crt.p12

Затем — его монтирование в под:

...
    spec:
      containers:
      - image: appleboy/gorush
        name: gorush
        imagePullPolicy: Always
        ports:
        - containerPort: 8088
...
        volumeMounts:
        - name: ios-push-secret-vol
          mountPath: /data/ssl/apns-crt.p12
          subPath: apns-crt.p12
          readOnly: true

Что бы представить себе связи при маппинге конфигов или секретов и разделов/файлов:

  • kind: Secret: // сам секрет
    • name: ios-push-secret // имя секрета — используем это имя в spec > volumes > secret > secretName
    • data:
      • ios-push-rsa-key // тело сертификата
  • volumes: // описывается в spec, создаёт сами разделы
    • name: ios-push-secret-vol // имя создаваемого раздела, используем в spec > containers >volumeMounts > name
    • secret: // в разделе будут данные типа secret
      • secretName: ios-push-secret // ищем секрет с name: ios-push-secret
      • items: // внутри секрета
        • - key: ios-push-rsa-key // ищем Secrets > data > ios-push-rsa-key
        • path: apns-rsa.pem // и как будем его монтировать
  • volumeMounts: // описывается в spec > containers
    • name: ios-push-secret-vol // имя раздела, который будем монтировать — spec > volumes > name: ios-push-secret-vol
    • mountPath: /data/ssl/apns-rsa.pem // полный путь монтирования
    • subPath: apns-rsa.pem // имя файла в каталоге, если подключаем как отдельный файл

Деплоим — проверяем:

kubectl -n gorush exec -ti gorush-7ff8fd9f4c-gds8r -c bastion cat /data/ssl/apns-rsa.pem
Bag Attributes
friendlyName: Apple Push Services: ***
localKeyID: C0 3A 96 69 CB C4 9E E6 14 EB 43 1F 31 30 97 4D 85 89 A0 8D
subject=/UID=***/CN=Apple Push Services: ***/OU=7MF8BB6LXN/O=***/C=VG
issuer=/C=US/O=Apple Inc./OU=Apple Worldwide Developer Relations/CN=Apple Worldwide Developer Relations Certification Authorit
-----BEGIN CERTIFICATE-----
MIIGJDCCBQygAwIBAgIIAtw7YRUahfYwDQYJKoZIhvcNAQELBQAwgZYxCzAJBgNV
BAYTAlVTMRMwEQYDVQQKDApBcHBsZSBJbmMuMSwwKgYDVQQLDCNBcHBsZSBXb3Js
...

Kubernetes Secrets и env — секреты, как переменные

Следующим шагом — надо добавить пароль от этого сертификата.

Варианта два — конфиг Gorush, или переменная окружения.

В конфиге Gorush есть параметр ios.password:

...
    ios:
      enabled: true
      key_path: "/data/ssl/apns-crt.p12"
      password: "p@ssw0rd"
      production: true
...

А при использовании переменных Gorush добавляет префикс GORUSH:

...
  viper.SetEnvPrefix("gorush") // will be uppercased automatically
...

Значит переменная будет GORUSH_IOS_PASSWORD.

Добавляем значение в файл секретов, в тот же ios-push-secret.

Добавляем ещё один мап, тип stringData:

---
apiVersion: v1
kind: Secret
metadata:
  name: ios-push-secret
  namespace: gorush-stage
type: Opaque
data:
  ios-push-p12-key: |
    MIIM9QIBAzCCDLwGCSqGSIb3DQEHAaCCDK0EggypMIIMpTCCBycGCSqGSIb3DQEHBqCCBxgwggcU
    AgEAMIIHDQYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQYwDgQI+BcNML0eE1oCAggAgIIG4KVvRBPp
...
stringData:
  ios-push-p12-pass: p@ssw0rd

Применяем:

kubectl apply -f gorush-secrets.yaml
secret/ios-push-secret configured

Проверяем — теперь у нас в секрете два объекта данных, повторяем describe secret:

kubectl -n gorush describe secret ios-push-secret
Name:         ios-push-secret
Namespace:    gorush
Labels:       <none>
Annotations:
Type:         Opaque
Data
====
ios-push-p12-key:   3321 bytes
ios-push-p12-pass:  13 bytes

Добавляем её в описание шаблона подов в файле деплоймента, используя secretKeyRef:

...
    spec:
      containers:
      - image: appleboy/gorush
        name: gorush
        imagePullPolicy: Always
        ports:
        - containerPort: 8088
...
        env:
        - name: GORUSH_IOS_PASSWORD
          valueFrom:
            secretKeyRef:
              name: ios-push-secret
              key: ios-push-p12-pass
        volumeMounts:
        - name: ios-push-secret-vol
          mountPath: /data/ssl/apns-crt.p12
          subPath: apns-crt.p12
          readOnly: true
...

Деплоим, проверяем:

kubectl -n gorush exec -ti gorush-58bcd746c4-67b9n -c gorush env | grep GORUSH_IOS
GORUSH_IOS_PASSWORD=p@ssw0rd

Пароль на месте.

ConfigMap

Kubernetes ConfigMap — конфиги, как файлы

Последним шагом нам надо создать файл настроек, и подменить файл настроек самого Gorush.

Файл будет общий для Production и Staging, а ключи будем передавать через разные секреты для разных окружений.

Аналогично можно через переменные и ConfigMap передать разные параметры для разных окружений.

Тут используем ConfigMap для создания файла config.yml, который потом смонтируем в запускаемые контейнеры.

У Gorush уже есть файл gorush-configmap.yaml — используем его, добавляем новый конфиг с именем gorush-config-file:

---
apiVersion: v1
kind: ConfigMap
metadata:
  name: gorush-config
  namespace: gorush
data:
  # stat
  stat.engine: redis
  stat.redis.host: redis:6379
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: gorush-config-file
  namespace: gorush
data:
  gorush-config-file: |
    core:
      enabled: true
      mode: "release"
      port: "8088"
      max_notification: 1000
      sync: false
...

Добавляем его в volumes файла деплоймента:

...
      volumes:
      - name: ios-push-secret-vol
        secret:
          secretName: ios-push-secret
          items:
          - key: ios-push-p12-key
            path: apns-crt.p12
      - name: gorush-config-file-vol
        configMap:
          name: gorush-config-file
          items:
            - key: gorush-config-file
              path: config.yml

А затем в volumeMounts в шаблоне пода:

...
    spec:
      containers:
      - image: appleboy/gorush
        name: gorush
        imagePullPolicy: Always
        ports:
        - containerPort: 8088
        ...
        env:
        - name: GORUSH_IOS_PASSWORD
          valueFrom:
            secretKeyRef:
              name: ios-push-secret
              key: ios-push-p12-pass
        volumeMounts:
        - name: ios-push-secret-vol
          mountPath: /data/ssl/apns-crt.p12
          subPath: apns-crt.p12
          readOnly: true
        - name: gorush-config-file-vol
          mountPath: /config.yml
          readOnly: true
          subPath: config.yml
...

Обновляем конфигмапы:

kubectl apply -f gorush-configmap.yaml
configmap/gorush-config unchanged
configmap/gorush-config-file created

Проверяем:

kubectl -n gorush get configmap
NAME                 DATA   AGE
gorush-config        2      28h
gorush-config-file   1      76s

Применяем деплоймент, и проверяем конфиг в контейнере:

kubectl -n gorush-stage exec -ti gorush-6bc78df55d-9w9m8 -c gorush cat /config.yml
core:
enabled: true
mode: "release"
port: "8088"
max_notification: 1000
sync: false
...
ios:
enabled: true
key_path: "/data/ssl/apns-crt.p12"
password: ""
production: true

Для автообновления подов при внесении изменений в ConfigMap и Secrets — можно использовать Reloader, см. Kubernetes: ConfigMap и Secrets — auto-reload данных в подах.

Готово.