1 - Приклад: Налаштування мікросервісу на Java

1.1 - Зовнішня конфігурація за допомогою MicroProfile, ConfigMaps та Secrets

У цьому посібнику ви дізнаєтеся, як і чому варто зовнішньо налаштовувати конфігурацію вашого мікросервісу. Зокрема, ви дізнаєтеся, як використовувати Kubernetes ConfigMaps і Secrets для встановлення змінних середовища та їх подальшого використання за допомогою MicroProfile Config.

Перш ніж ви розпочнете

Створення Kubernetes ConfigMaps та Secrets

Існує кілька способів встановлення змінних середовища для Docker-контейнера в Kubernetes, зокрема: Dockerfile, kubernetes.yml, Kubernetes ConfigMap та Kubernetes Secret. У цьому посібнику ви дізнаєтеся, як використовувати останні два для встановлення змінних середовища, значення яких будуть впроваджені у ваші мікросервіси. Однією з переваг використання ConfigMap та Secret є те, що вони можуть повторно використовуватися у кількох контейнерах, включаючи можливість призначення різним змінним середовища для різних контейнерів.

ConfigMap — це обʼєкти API, які зберігають неконфіденційні пари "ключ-значення". У інтерактивному посібнику ви дізнаєтеся, як використовувати ConfigMap для зберігання імені програми. Більше інформації про ConfigMap ви можете знайти у документації.

Хоча Secret також використовуються для зберігання пар "ключ-значення", вони відрізняються від ConfigMap тим, що призначені для конфіденційної/чутливої інформації та зберігаються за допомогою кодування Base64. Це робить Secret відповідним вибором для зберігання таких речей, як облікові дані, ключі та токени, що ви й зробите в інтерактивному завданні. Більше інформації про Secret ви можете знайти у документації.

Зовнішня конфігурація з коду

Зовнішня конфігурація застосунків корисна, оскільки конфігурація зазвичай змінюється залежно від вашого середовища. Для цього ми будемо використовувати Java Contexts and Dependency Injection (CDI) та MicroProfile Config. MicroProfile Config — це функція MicroProfile, набору відкритих Java-технологій для розробки та розгортання хмаро-орієнтованих мікросервісів.

CDI надає стандартну можливість впровадження залежностей, що дозволяє створювати застосунок з працюючих разом, слабо звʼязаних частин. MicroProfile Config надає застосункам та мікросервісам стандартний спосіб отримання конфігураційних властивостей з різних джерел, включаючи застосунок, середовище виконання та оточення. Відповідно до визначеного пріоритету джерела, властивості автоматично комбінуються в єдиний набір властивостей, до якого застосунок може отримати доступ через API. Разом, CDI та MicroProfile будуть використані в інтерактивному посібнику для отримання зовнішньо наданих властивостей з Kubernetes ConfigMap та Secret і їх додавання у ваш код застосунку.

Багато відкритих фреймворків та середовищ виконання реалізують і підтримують MicroProfile Config. Протягом інтерактивного уроку ви будете використовувати Open Liberty, гнучке відкрите середовище виконання Java для створення та запуску хмаро-орієнтованих застосунків та мікросервісів. Однак замість нього можна використовувати будь-яке сумісне з MicroProfile середовище.

Цілі

  • Створити Kubernetes ConfigMap та Secret
  • Встановити конфігурацію мікросервісу за допомогою MicroProfile Config

Приклад: Зовнішня конфігурація за допомогою MicroProfile, ConfigMap та Secret

Почати інтерактивний урок

2 - Оновлення конфігурації за допомогою ConfigMap

Ця сторінка містить покроковий приклад оновлення конфігурації всередині Pod за допомогою ConfigMap і базується на завданні Налаштування Pod для використання ConfigMap. Наприкінці цього посібника ви зрозумієте, як змінити конфігурацію для запущеного застосунку. Цей посібник використовує образи alpine та nginx як приклади.

Перш ніж ви розпочнете

Вам треба мати кластер Kubernetes, а також інструмент командного рядка kubectl має бути налаштований для роботи з вашим кластером. Рекомендується виконувати ці настанови у кластері, що має щонайменше два вузли, які не виконують роль вузлів управління. Якщо у вас немає кластера, ви можете створити його, за допомогою minikube або використовувати одну з цих пісочниць:

Вам потрібно мати інструмент командного рядка curl для виконання HTTP-запитів з термінала або командного рядка. Якщо у вас немає curl, ви можете його встановити. Ознайомтеся з документацією для вашої операційної системи.

Цілі

  • Оновлення конфігурації через ConfigMap, змонтованого як том
  • Оновлення змінних середовища Pod за допомогою ConfigMap
  • Оновлення конфігурації через ConfigMap в багатоконтейнерному Pod
  • Оновлення конфігурації через ConfigMap у Pod, що містить контейнер Sidecar

Оновлення конфігурації через ConfigMap, змонтовану як том

Використовуйте команду kubectl create configmap для створення ConfigMap з літеральних значень:

kubectl create configmap sport --from-literal=sport=football

Нижче наведено приклад маніфесту Deployment з ConfigMap sport, змонтованим як том у єдиний контейнер Pod.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: configmap-volume
  labels:
    app.kubernetes.io/name: configmap-volume
spec:
  replicas: 3
  selector:
    matchLabels:
      app.kubernetes.io/name: configmap-volume
  template:
    metadata:
      labels:
        app.kubernetes.io/name: configmap-volume
    spec:
      containers:
        - name: alpine
          image: alpine:3
          command:
            - /bin/sh
            - -c
            - while true; do echo "$(date) My preferred sport is $(cat /etc/config/sport)";
              sleep 10; done;
          ports:
            - containerPort: 80
          volumeMounts:
            - name: config-volume
              mountPath: /etc/config
      volumes:
        - name: config-volume
          configMap:
            name: sport

Створіть Deployment:

kubectl apply -f https://k8s.io/examples/deployments/deployment-with-configmap-as-volume.yaml

Перевірте Podʼи цього Deployment, щоб переконатися, що вони готові (відповідно до селектору):

kubectl get pods --selector=app.kubernetes.io/name=configmap-volume

Ви повинні побачити подібний вивід:

NAME                                READY   STATUS    RESTARTS   AGE
configmap-volume-6b976dfdcf-qxvbm   1/1     Running   0          72s
configmap-volume-6b976dfdcf-skpvm   1/1     Running   0          72s
configmap-volume-6b976dfdcf-tbc6r   1/1     Running   0          72s

На кожному вузлі, де працює один із цих Pod, kubelet отримує дані для цього ConfigMap і перетворює їх на файли у локальному томі. Потім kubelet монтує цей том у контейнер, як зазначено у шаблоні Pod. Код, що виконується у цьому контейнері, завантажує інформацію з файлу та використовує її для друку звіту на stdout. Ви можете перевірити цей звіт, переглянувши логи одного з Pod у цьому Deployment:

# Виберіть один Pod, що належить до Deployment, і перегляньте його логи
kubectl logs deployments/configmap-volume

Ви повинні побачити подібний вивід:

Found 3 pods, using pod/configmap-volume-76d9c5678f-x5rgj
Thu Jan  4 14:06:46 UTC 2024 My preferred sport is football
Thu Jan  4 14:06:56 UTC 2024 My preferred sport is football
Thu Jan  4 14:07:06 UTC 2024 My preferred sport is football
Thu Jan  4 14:07:16 UTC 2024 My preferred sport is football
Thu Jan  4 14:07:26 UTC 2024 My preferred sport is football

Відредагуйте ConfigMap:

kubectl edit configmap sport

В редакторі, що з’явиться, змініть значення ключа sport з football на cricket. Збережіть зміни. Інструмент kubectl відповідним чином оновлює ConfigMap (якщо виникне помилка, спробуйте ще раз).

Ось приклад того, як може виглядати маніфест після редагування:

apiVersion: v1
data:
  sport: cricket
kind: ConfigMap
# Наявні метадані можна залишити без змін.
# Значення, які ви побачите, не будуть точно відповідати цим.
metadata:
  creationTimestamp: "2024-01-04T14:05:06Z"
  name: sport
  namespace: default
  resourceVersion: "1743935"
  uid: 024ee001-fe72-487e-872e-34d6464a8a23

Ви повинні побачити наступний вивід:

configmap/sport edited

Відстежуйте (слідкуйте за останніми записами в) логах одного з Pod, що належить до цього Deployment:

kubectl logs deployments/configmap-volume --follow

Через кілька секунд ви повинні побачити зміну виводу логів:

Thu Jan  4 14:11:36 UTC 2024 My preferred sport is football
Thu Jan  4 14:11:46 UTC 2024 My preferred sport is football
Thu Jan  4 14:11:56 UTC 2024 My preferred sport is football
Thu Jan  4 14:12:06 UTC 2024 My preferred sport is cricket
Thu Jan  4 14:12:16 UTC 2024 My preferred sport is cricket

Коли у вас є ConfigMap, змонтований у працюючий Pod, використовуючи або том configMap, або projected том, і ви оновлюєте цей ConfigMap, працюючий Pod майже миттєво бачить це оновлення. Однак ваш застосунок бачить зміни лише в тому випадку, якщо він запрограмований опитувати зміни або стежити за оновленнями файлів. Застосунок, що завантажує свою конфігурацію лише під час запуску, не помітить змін.

Оновлення змінних середовища Pod за допомогою ConfigMap

Використовуйте команду kubectl create configmap для створення ConfigMap з літеральних значень:

kubectl create configmap fruits --from-literal=fruits=apples

Нижче наведено приклад маніфесту Deployment з налаштуванням змінної середовища через ConfigMap fruits.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: configmap-env-var
  labels:
    app.kubernetes.io/name: configmap-env-var
spec:
  replicas: 3
  selector:
    matchLabels:
      app.kubernetes.io/name: configmap-env-var
  template:
    metadata:
      labels:
        app.kubernetes.io/name: configmap-env-var
    spec:
      containers:
        - name: alpine
          image: alpine:3
          env:
            - name: FRUITS
              valueFrom:
                configMapKeyRef:
                  key: fruits
                  name: fruits
          command:
            - /bin/sh
            - -c
            - while true; do echo "$(date) The basket is full of $FRUITS";
                sleep 10; done;
          ports:
            - containerPort: 80

Створіть Deployment:

kubectl apply -f https://k8s.io/examples/deployments/deployment-with-configmap-as-envvar.yaml

Перевірте Pod цього Deployment, щоб переконатися, що вони готові (збігаються з селектором):

kubectl get pods --selector=app.kubernetes.io/name=configmap-env-var

Ви повинні побачити подібний вивід:

NAME                                 READY   STATUS    RESTARTS   AGE
configmap-env-var-59cfc64f7d-74d7z   1/1     Running   0          46s
configmap-env-var-59cfc64f7d-c4wmj   1/1     Running   0          46s
configmap-env-var-59cfc64f7d-dpr98   1/1     Running   0          46s

Ключ-значення у ConfigMap налаштовано як змінну середовища в контейнері Pod. Перевірте це, переглянувши логи одного Pod, що належить до Deployment.

kubectl logs deployment/configmap-env-var

Ви повинні побачити подібний вивід:

Found 3 pods, using pod/configmap-env-var-7c994f7769-l74nq
Thu Jan  4 16:07:06 UTC 2024 The basket is full of apples
Thu Jan  4 16:07:16 UTC 2024 The basket is full of apples
Thu Jan  4 16:07:26 UTC 2024 The basket is full of apples

Відредагуйте ConfigMap:

kubectl edit configmap fruits

В редакторі, що зʼявиться, змініть значення ключа fruits з apples на mangoes. Збережіть зміни. Інструмент kubectl відповідним чином оновлює ConfigMap (якщо виникне помилка, спробуйте ще раз).

Ось приклад того, як може виглядати маніфест після редагування:

apiVersion: v1
data:
  fruits: mangoes
kind: ConfigMap
# Наявні метадані можна залишити без змін.
# Значення, які ви побачите, не будуть точно відповідати цим.
metadata:
  creationTimestamp: "2024-01-04T16:04:19Z"
  name: fruits
  namespace: default
  resourceVersion: "1749472"

Ви повинні побачити наступний вивід:

configmap/fruits edited

Відстежуйте логи Deployment та спостерігайте за виводом протягом кількох секунд:

# Як пояснюється у тексті, вивід НЕ змінюється
kubectl logs deployments/configmap-env-var --follow

Зверніть увагу, що вивід залишається незмінним, навіть якщо ви редагували ConfigMap:

Thu Jan  4 16:12:56 UTC 2024 The basket is full of apples
Thu Jan  4 16:13:06 UTC 2024 The basket is full of apples
Thu Jan  4 16:13:16 UTC 2024 The basket is full of apples
Thu Jan  4 16:13:26 UTC 2024 The basket is full of apples

Ви можете ініціювати таку заміну. Виконайте розгортання для Deployment, використовуючи kubectl rollout:

# Запустіть розгортання
kubectl rollout restart deployment configmap-env-var

# Дочекайтеся завершення розгортання
kubectl rollout status deployment configmap-env-var --watch=true

Далі перевірте Deployment:

kubectl get deployment configmap-env-var

Ви повинні побачити подібний вивід:

NAME                READY   UP-TO-DATE   AVAILABLE   AGE
configmap-env-var   3/3     3            3           12m

Перевірте Podʼи:

kubectl get pods --selector=app.kubernetes.io/name=configmap-env-var

Розгортання змушує Kubernetes створити новий ReplicaSet для Deployment; це означає, що наявні Podʼи з часом завершуються, а нові створюються. Через кілька секунд ви повинні побачити подібний вивід:

NAME                                 READY   STATUS        RESTARTS   AGE
configmap-env-var-6d94d89bf5-2ph2l   1/1     Running       0          13s
configmap-env-var-6d94d89bf5-74twx   1/1     Running       0          8s
configmap-env-var-6d94d89bf5-d5vx8   1/1     Running       0          11s

Перегляньте логи для одного з Podʼів у цьому Deployment:

# Виберіть один Pod, що належить до Deployment, і перегляньте його логи
kubectl logs deployment/configmap-env-var

Ви повинні побачити подібний вивід:

Found 3 pods, using pod/configmap-env-var-6d9ff89fb6-bzcf6
Thu Jan  4 16:30:35 UTC 2024 The basket is full of mangoes
Thu Jan  4 16:30:45 UTC 2024 The basket is full of mangoes
Thu Jan  4 16:30:55 UTC 2024 The basket is full of mangoes

Це демонструє сценарій оновлення змінних середовища у Podʼі, що отримані з ConfigMap. Зміни до значень ConfigMap застосовуються до Pod під час наступного розгортання. Якщо Pod створюються з іншої причини, наприклад, при масштабуванні Deployment, тоді нові Pod також використовують останні значення конфігурації; якщо ви не ініціюєте розгортання, то ви можете виявити, що ваш застосунок працює зі змішаними старими та новими значеннями змінних середовища.

Оновлення конфігурації через ConfigMap у багатоконтейнерному Поді

Використовуйте команду kubectl create configmap, щоб створити ConfigMap з літеральних значень:

kubectl create configmap color --from-literal=color=red

Нижче подано приклад маніфесту для Deployment, що керує набором Podʼів, кожен з двома контейнерами. Два контейнери спільно використовують том emptyDir, який вони використовують для звʼязку. Перший контейнер працює як вебсервер (nginx). Шлях монтування для спільного тому в контейнері вебсервера — /usr/share/nginx/html. Другий допоміжний контейнер базується на alpine, і для цього контейнера том emptyDir монтується у /pod-data. Допоміжний контейнер записує файл у HTML, чий вміст залежить від ConfigMap. Контейнер вебсервера обслуговує HTML за допомогою HTTP.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: configmap-two-containers
  labels:
    app.kubernetes.io/name: configmap-two-containers
spec:
  replicas: 3
  selector:
    matchLabels:
      app.kubernetes.io/name: configmap-two-containers
  template:
    metadata:
      labels:
        app.kubernetes.io/name: configmap-two-containers
    spec:
      volumes:
        - name: shared-data
          emptyDir: {}
        - name: config-volume
          configMap:
            name: color
      containers:
        - name: nginx
          image: nginx
          volumeMounts:
            - name: shared-data
              mountPath: /usr/share/nginx/html
        - name: alpine
          image: alpine:3
          volumeMounts:
            - name: shared-data
              mountPath: /pod-data
            - name: config-volume
              mountPath: /etc/config
          command:
            - /bin/sh
            - -c
            - while true; do echo "$(date) My preferred color is $(cat /etc/config/color)" > /pod-data/index.html;
              sleep 10; done;

Створіть Deployment:

kubectl apply -f https://k8s.io/examples/deployments/deployment-with-configmap-two-containers.yaml

Перевірте Podʼи для цього Deployment, щоб переконатися, що вони готові (збігаються з селектором):

kubectl get pods --selector=app.kubernetes.io/name=configmap-two-containers

Ви повинні побачити вивід, схожий на:

NAME                                        READY   STATUS    RESTARTS   AGE
configmap-two-containers-565fb6d4f4-2xhxf   2/2     Running   0          20s
configmap-two-containers-565fb6d4f4-g5v4j   2/2     Running   0          20s
configmap-two-containers-565fb6d4f4-mzsmf   2/2     Running   0          20s

Надайте доступ до Deployment (інструмент kubectl створює Service для вас):

kubectl expose deployment configmap-two-containers --name=configmap-service --port=8080 --target-port=80

Використайте kubectl, щоб перенаправити порт:

kubectl port-forward service/configmap-service 8080:8080 & # це залишається запущеним у фоновому режимі

Отримайте доступ до Service.

curl http://localhost:8080

Ви повинні побачити вивід, схожий на:

Fri Jan  5 08:08:22 UTC 2024 My preferred color is red

Відредагуйте ConfigMap:

kubectl edit configmap color

У відкритому редакторі, змініть значення ключа color з red на blue. Збережіть свої зміни. Інструмент kubectl оновлює ConfigMap відповідно (якщо ви побачите помилку, спробуйте ще раз).

Ось приклад того, як може виглядати цей маніфест після редагування:

apiVersion: v1
data:
  color: blue
kind: ConfigMap
# Ви можете залишити наявні метадані такими, які вони є.
# Значення, які ви побачите, не збігатимуться з цими.
metadata:
  creationTimestamp: "2024-01-05T08:12:05Z"
  name: color
  namespace: configmap
  resourceVersion: "1801272"
  uid: 80d33e4a-cbb4-4bc9-ba8c-544c68e425d6

Затримайтесь на URL сервісу протягом кількох секунд.

# Скасуйте це, коли будете задоволені (Ctrl-C)
while true; do curl --connect-timeout 7.5 http://localhost:8080; sleep 10; done

Ви повинні побачити, що виведення змінюється наступним чином:

Fri Jan  5 08:14:00 UTC 2024 My preferred color is red
Fri Jan  5 08:14:02 UTC 2024 My preferred color is red
Fri Jan  5 08:14:20 UTC 2024 My preferred color is red
Fri Jan  5 08:14:22 UTC 2024 My preferred color is red
Fri Jan  5 08:14:32 UTC 2024 My preferred color is blue
Fri Jan  5 08:14:43 UTC 2024 My preferred color is blue
Fri Jan  5 08:15:00 UTC 2024 My preferred color is blue

Оновлення конфігурації через ConfigMap у Поді з контейнером sidecar

Вищевказаний сценарій можна відтворити за допомогою контейнера sidecar як допоміжного контейнера для запису HTML-файлу. Оскільки контейнер sidecar концептуально є контейнером ініціалізації, гарантується, що він запускається перед головним контейнером вебсервера. Це забезпечує, що файл HTML завжди доступний, коли вебсервер буде готовий його обслуговувати. Будь ласка, дивіться Увімкнення контейнерів sidecar, щоб скористатися цією функцією.

Якщо ви продовжуєте з попереднього сценарію, ви можете використати знову ConfigMap з імʼям color для цього сценарію. Якщо ви виконуєте цей сценарій самостійно, використовуйте команду kubectl create configmap, щоб створити ConfigMap з літеральних значень:

kubectl create configmap color --from-literal=color=blue

Нижче наведено приклад маніфесту для Deployment, що керує набором Podʼів, кожен з головним контейнером і контейнером sidecar. Обидва контейнери використовують спільний том emptyDir для звʼязку. Головний контейнер працює як вебсервер (NGINX). Шлях монтування для спільного тому в контейнері вебсервера — /usr/share/nginx/html. Другий контейнер є контейнером sidecar, який базується на Alpine Linux і діє як допоміжний контейнер. Для цього контейнера том emptyDir монтується у /pod-data. Контейнер sidecar записує файл у HTML, чий вміст залежить від ConfigMap. Контейнер вебсервера обслуговує HTML через HTTP.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: configmap-sidecar-container
  labels:
    app.kubernetes.io/name: configmap-sidecar-container
spec:
  replicas: 3
  selector:
    matchLabels:
      app.kubernetes.io/name: configmap-sidecar-container
  template:
    metadata:
      labels:
        app.kubernetes.io/name: configmap-sidecar-container
    spec:
      volumes:
        - name: shared-data
          emptyDir: {}
        - name: config-volume
          configMap:
            name: color
      containers:
        - name: nginx
          image: nginx
          volumeMounts:
            - name: shared-data
              mountPath: /usr/share/nginx/html
      initContainers:
        - name: alpine
          image: alpine:3
          restartPolicy: Always
          volumeMounts:
            - name: shared-data
              mountPath: /pod-data
            - name: config-volume
              mountPath: /etc/config
          command:
            - /bin/sh
            - -c
            - while true; do echo "$(date) My preferred color is $(cat /etc/config/color)" > /pod-data/index.html;
              sleep 10; done;

Створіть Deployment:

kubectl apply -f https://k8s.io/examples/deployments/deployment-with-configmap-and-sidecar-container.yaml

Перевірте Podʼи для цього Deployment, щоб переконатися, що вони готові (збігаються з селектором):

kubectl get pods --selector=app.kubernetes.io/name=configmap-sidecar-container

Ви повинні побачити вивід, схожий на:

NAME                                           READY   STATUS    RESTARTS   AGE
configmap-sidecar-container-5fb59f558b-87rp7   2/2     Running   0          94s
configmap-sidecar-container-5fb59f558b-ccs7s   2/2     Running   0          94s
configmap-sidecar-container-5fb59f558b-wnmgk   2/2     Running   0          94s

Надайте доступ до Deployment (інструмент kubectl створює Service для вас):

kubectl expose deployment configmap-sidecar-container --name=configmap-sidecar-service --port=8081 --target-port=80

Використайте kubectl, щоб перенаправити порт:

kubectl port-forward service/configmap-sidecar-service 8081:8081 & # це залишається запущеним у фоновому режимі

Отримайте доступ до Service.

curl http://localhost:8081

Ви повинні побачити вивід, схожий на:

Sat Feb 17 13:09:05 UTC 2024 My preferred color is blue

Відредагуйте ConfigMap:

kubectl edit configmap color

У відкритому редакторі змініть значення ключа color з blue на green. Збережіть свої зміни. Інструмент kubectl оновлює ConfigMap відповідно (якщо ви побачите помилку, спробуйте ще раз).

Ось приклад того, як може виглядати цей маніфест після редагування:

apiVersion: v1
data:
  color: green
kind: ConfigMap
# You can leave the existing metadata as they are.
# The values you'll see won't exactly match these.
metadata:
  creationTimestamp: "2024-02-17T12:20:30Z"
  name: color
  namespace: default
  resourceVersion: "1054"
  uid: e40bb34c-58df-4280-8bea-6ed16edccfaa

Затримайтесь на URL сервісу протягом кількох секунд.

# Скасуйте це, коли будете задоволені (Ctrl-C)
while true; do curl --connect-timeout 7.5 http://localhost:8081; sleep 10; done

Ви повинні побачити, що вивід змінюється наступним чином:

Sat Feb 17 13:12:35 UTC 2024 My preferred color is blue
Sat Feb 17 13:12:45 UTC 2024 My preferred color is blue
Sat Feb 17 13:12:55 UTC 2024 My preferred color is blue
Sat Feb 17 13:13:05 UTC 2024 My preferred color is blue
Sat Feb 17 13:13:15 UTC 2024 My preferred color is green
Sat Feb 17 13:13:25 UTC 2024 My preferred color is green
Sat Feb 17 13:13:35 UTC 2024 My preferred color is green

Оновлення конфігурації через незмінний ConfigMap, який монтується як том

Нижче наведено приклад маніфесту для незмінного ConfigMap.

apiVersion: v1
data:
  company_name: "ACME, Inc." # наявна вигадана назва компанії
kind: ConfigMap
immutable: true
metadata:
  name: company-name-20150801

Створіть незмінний ConfigMap:

kubectl apply -f https://k8s.io/examples/configmap/immutable-configmap.yaml

Нижче наведено приклад маніфесту Deployment з незмінним ConfigMap company-name-20150801, який монтується як том в єдиний контейнер Pod.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: immutable-configmap-volume
  labels:
    app.kubernetes.io/name: immutable-configmap-volume
spec:
  replicas: 3
  selector:
    matchLabels:
      app.kubernetes.io/name: immutable-configmap-volume
  template:
    metadata:
      labels:
        app.kubernetes.io/name: immutable-configmap-volume
    spec:
      containers:
        - name: alpine
          image: alpine:3
          command:
            - /bin/sh
            - -c
            - while true; do echo "$(date) The name of the company is $(cat /etc/config/company_name)";
              sleep 10; done;
          ports:
            - containerPort: 80
          volumeMounts:
            - name: config-volume
              mountPath: /etc/config
      volumes:
        - name: config-volume
          configMap:
            name: company-name-20150801

Створіть Deployment:

kubectl apply -f https://k8s.io/examples/deployments/deployment-with-immutable-configmap-as-volume.yaml

Перевірте Podʼи для цього Deployment, щоб переконатися, що вони готові (збігаються з селектором):

kubectl get pods --selector=app.kubernetes.io/name=immutable-configmap-volume

Ви повинні побачити вивід схожий на:

ІNAME                                          READY   STATUS    RESTARTS   AGE
immutable-configmap-volume-78b6fbff95-5gsfh   1/1     Running   0          62s
immutable-configmap-volume-78b6fbff95-7vcj4   1/1     Running   0          62s
immutable-configmap-volume-78b6fbff95-vdslm   1/1     Running   0          62s

Контейнер Podʼа посилається на дані, визначені в ConfigMap, і використовує їх для виводу звіту в stdout. Ви можете перевірити цей звіт, переглянувши логи для одного з Podʼів у цьому Deployment:

# Виберіть один Pod, який належить до Deployment, і перегляньте його логи
kubectl logs deployments/immutable-configmap-volume

Ви повинні побачити вивід, подібний до:

Found 3 pods, using pod/immutable-configmap-volume-78b6fbff95-5gsfh
Wed Mar 20 03:52:34 UTC 2024 The name of the company is ACME, Inc.
Wed Mar 20 03:52:44 UTC 2024 The name of the company is ACME, Inc.
Wed Mar 20 03:52:54 UTC 2024 The name of the company is ACME, Inc.

Створіть новий незмінний ConfigMap, використовуючи наведений нижче маніфест:

apiVersion: v1
data:
  company_name: "Fiktivesunternehmen GmbH" # нова вигадана назва компанії
kind: ConfigMap
immutable: true
metadata:
  name: company-name-20240312
kubectl apply -f https://k8s.io/examples/configmap/new-immutable-configmap.yaml

Ви повинні побачити вивід схожий на:

configmap/company-name-20240312 створено

Перевірте новостворений ConfigMap:

kubectl get configmap

Ви повинні побачити вивід, який відображає обидва? старий та новий ConfigMaps:

NAME                    DATA   AGE
company-name-20150801   1      22m
company-name-20240312   1      24s

Відредагуйте Deployment, щоб вказати новий ConfigMap

Редагування Deployment:

kubectl edit deployment immutable-configmap-volume

В редакторі, що зʼявиться, оновіть наявне визначення тому для використання нового ConfigMap.

volumes:
- configMap:
    defaultMode: 420
    name: company-name-20240312 # Оновіть це поле
  name: config-volume

Ви маєте побачити вивід, подібний до:

deployment.apps/immutable-configmap-volume edited

Це запустить розгортання. Почекайте поки всі раніше створені Podʼи завершаться, а нові Podʼи будуть в стані ready.

Відстежуйте стан Podʼів:

kubectl get pods --selector=app.kubernetes.io/name=immutable-configmap-volume
NAME                                          READY   STATUS        RESTARTS   AGE
immutable-configmap-volume-5fdb88fcc8-29v8n   1/1     Running       0          13s
immutable-configmap-volume-5fdb88fcc8-52ddd   1/1     Running       0          14s
immutable-configmap-volume-5fdb88fcc8-n5jx4   1/1     Running       0          15s
immutable-configmap-volume-78b6fbff95-5gsfh   1/1     Terminating   0          32m
immutable-configmap-volume-78b6fbff95-7vcj4   1/1     Terminating   0          32m
immutable-configmap-volume-78b6fbff95-vdslm   1/1     Terminating   0          32m

Ви нарешті побачите вивід, подібний до:

NAME                                          READY   STATUS    RESTARTS   AGE
immutable-configmap-volume-5fdb88fcc8-29v8n   1/1     Running   0          43s
immutable-configmap-volume-5fdb88fcc8-52ddd   1/1     Running   0          44s
immutable-configmap-volume-5fdb88fcc8-n5jx4   1/1     Running   0          45s

Перевірте логи для одного з Podʼів у цьому Deployment:

# Виберіть один Pod, який належить до Deployment, і перегляньте його логи
kubectl logs deployments/immutable-configmap-volume

Ви повинні побачити вивід, подібний до:

Found 3 pods, using pod/immutable-configmap-volume-5fdb88fcc8-n5jx4
Wed Mar 20 04:24:17 UTC 2024 The name of the company is Fiktivesunternehmen GmbH
Wed Mar 20 04:24:27 UTC 2024 The name of the company is Fiktivesunternehmen GmbH
Wed Mar 20 04:24:37 UTC 2024 The name of the company is Fiktivesunternehmen GmbH

Як тільки всі розгортання мігрують на використання нового незмінного ConfigMap, потрібно видалити старий ConfigMap:

kubectl delete configmap company-name-20150801

Підсумок

Зміни у ConfigMap, змонтованому як том у Pod, стають доступними безперешкодно після наступної синхронізації kubelet.

Зміни у ConfigMap, який налаштовує змінні середовища для Pod, стають доступними після наступного розгортання для цього Pod.

Після того як ConfigMap позначено як незмінний, неможливо скасувати цю зміну (ви не можете зробити незмінний ConfigMap змінним), і ви також не можете внести жодну зміну до вмісту поля data або binaryData. Ви можете видалити та створити ConfigMap заново, або можете створити новий відмінний ConfigMap. Коли ви видаляєте ConfigMap, запущені контейнери та їхні Podʼи зберігають точку монтування до будь-якого тому, який посилається на цей наявнийConfigMap.

Очищення

Завершіть команди kubectl port-forward, якщо вони виконуються.

Видаліть ресурси, створені під час навчання:

kubectl delete deployment configmap-volume configmap-env-var configmap-two-containers configmap-sidecar-container immutable-configmap-volume
kubectl delete service configmap-service configmap-sidecar-service
kubectl delete configmap sport fruits color company-name-20240312

kubectl delete configmap company-name-20150801 # У випадку, якщо він не був оброблений під час виконання завдання

3 - Конфігурування Redis за допомогою ConfigMap

Ця сторінка надає реальний приклад конфігурування Redis за допомогою ConfigMap і базується на завданні Конфігурування Pod для використання ConfigMap.

Цілі

  • Створити ConfigMap з конфігураційними значеннями Redis
  • Створити Pod з Redis, який монтує та використовує створений ConfigMap
  • Перевірити, що конфігурація була правильно застосована.

Перш ніж ви розпочнете

Вам треба мати кластер Kubernetes, а також інструмент командного рядка kubectl має бути налаштований для роботи з вашим кластером. Рекомендується виконувати ці настанови у кластері, що має щонайменше два вузли, які не виконують роль вузлів управління. Якщо у вас немає кластера, ви можете створити його, за допомогою minikube або використовувати одну з цих пісочниць:

Для перевірки версії введіть kubectl version.

Реальний приклад: Конфігурування Redis за допомогою ConfigMap

Виконайте наведені нижче кроки для конфігурування кешу Redis за допомогою даних, збережених у ConfigMap.

Спершу створіть ConfigMap з порожнім блоком конфігурації:

cat <<EOF >./example-redis-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: example-redis-config
data:
  redis-config: ""
EOF

Застосуйте створений вище ConfigMap разом з маніфестом Podʼа Redis:

kubectl apply -f example-redis-config.yaml
kubectl apply -f https://raw.githubusercontent.com/kubernetes/website/main/content/en/examples/pods/config/redis-pod.yaml

Перегляньте вміст маніфесту Podʼа Redis і зверніть увагу на наступне:

  • Том config створено за допомогою spec.volumes[1]
  • Пара key і path у spec.volumes[1].configMap.items[0] експонує ключ redis-config з example-redis-config ConfigMap як файл з назвою redis.conf у томі config.
  • Том config потім монтується в /redis-master за допомогою spec.containers[0].volumeMounts[1].

Це має загальний ефект експозиції даних з data.redis-config з example-redis-config ConfigMap як /redis-master/redis.conf всередині Pod.

apiVersion: v1
kind: Pod
metadata:
  name: redis
spec:
  containers:
  - name: redis
    image: redis:5.0.4
    command:
      - redis-server
      - "/redis-master/redis.conf"
    env:
    - name: MASTER
      value: "true"
    ports:
    - containerPort: 6379
    resources:
      limits:
        cpu: "0.1"
    volumeMounts:
    - mountPath: /redis-master-data
      name: data
    - mountPath: /redis-master
      name: config
  volumes:
    - name: data
      emptyDir: {}
    - name: config
      configMap:
        name: example-redis-config
        items:
        - key: redis-config
          path: redis.conf

Перегляньте створені обʼєкти:

kubectl get pod/redis configmap/example-redis-config 

Ви повинні побачити наступний вивід:

NAME        READY   STATUS    RESTARTS   AGE
pod/redis   1/1     Running   0          8s

NAME                             DATA   AGE
configmap/example-redis-config   1      14s

Нагадаємо, що ми залишили ключ redis-config у example-redis-config ConfigMap порожнім:

kubectl describe configmap/example-redis-config

Ви повинні побачити порожній ключ redis-config:

Name:         example-redis-config
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
redis-config:

Використовуйте kubectl exec, щоб увійти в Pod і запустити інструмент redis-cli, щоб перевірити поточну конфігурацію:

kubectl exec -it redis -- redis-cli

Перевірте maxmemory:

127.0.0.1:6379> CONFIG GET maxmemory

Він має показати типове значення 0:

1) "maxmemory"
2) "0"

Аналогічно, перевірте maxmemory-policy:

127.0.0.1:6379> CONFIG GET maxmemory-policy

Що також повинно показати типове значення noeviction:

1) "maxmemory-policy"
2) "noeviction"

Тепер додамо деякі конфігураційні значення до example-redis-config ConfigMap:

apiVersion: v1
kind: ConfigMap
metadata:
  name: example-redis-config
data:
  redis-config: |
    maxmemory 2mb
    maxmemory-policy allkeys-lru    

Застосуйте оновлений ConfigMap:

kubectl apply -f example-redis-config.yaml

Перевірте, що ConfigMap був оновлений:

kubectl describe configmap/example-redis-config

Ви повинні побачити конфігураційні значення, які ми щойно додали:

Name:         example-redis-config
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
redis-config:
----
maxmemory 2mb
maxmemory-policy allkeys-lru

Ще раз перевірте Pod Redis за допомогою redis-cli через kubectl exec, щоб побачити, чи конфігурація була застосована:

kubectl exec -it redis -- redis-cli

Перевірте maxmemory:

127.0.0.1:6379> CONFIG GET maxmemory

Він залишається з типовим значенням 0:

1) "maxmemory"
2) "0"

Аналогічно, maxmemory-policy залишається з типовими налаштуваннями noeviction:

127.0.0.1:6379> CONFIG GET maxmemory-policy

Повертає:

1) "maxmemory-policy"
2) "noeviction"

Конфігураційні значення не змінилися, оскільки Pod необхідно перезапустити, щоб отримати оновлені значення з асоційованих ConfigMap. Видалимо та заново створимо Pod:

kubectl delete pod redis
kubectl apply -f https://raw.githubusercontent.com/kubernetes/website/main/content/en/examples/pods/config/redis-pod.yaml

Тепер ще раз перевірте конфігураційні значення:

kubectl exec -it redis -- redis-cli

Перевірте maxmemory:

127.0.0.1:6379> CONFIG GET maxmemory

Тепер він має показати оновлене значення 2097152:

1) "maxmemory"
2) "2097152"

Аналогічно, maxmemory-policy також було оновлено:

127.0.0.1:6379> CONFIG GET maxmemory-policy

Він тепер показує бажане значення allkeys-lru:

1) "maxmemory-policy"
2) "allkeys-lru"

Очистіть свою роботу, видаливши створені ресурси:

kubectl delete pod/redis configmap/example-redis-config

Що далі

4 - Використання контейнерів sidecar

Цей розділ актуальний для людей, які впроваджують нову вбудовану функцію sidecar-контейнерів для своїх навантажень.

Sidecar-контейнери — це не нова концепція, про що було згадано в блог-пості ще у 2015 році. Kubernetes дозволяв запускати декілька контейнерів у Pod, щоб реалізувати цю концепцію. Однак запуск sidecar-контейнера як звичайного контейнера має багато обмежень, які вирішуються за допомогою нової підтримки вбудованих sidecar-контейнерів.

СТАН ФУНКЦІОНАЛУ: Kubernetes v1.29 [beta] (стандартно увімкнено: true)

Цілі

  • Зрозуміти необхідність використання sidecar-контейнерів.
  • Вміти розвʼязувати проблеми з sidecar-контейнерами.
  • Зрозуміти варіанти універсального "впровадження" sidecar-контейнерів у будь-яке навантаження.

Перш ніж ви розпочнете

Вам треба мати кластер Kubernetes, а також інструмент командного рядка kubectl має бути налаштований для роботи з вашим кластером. Рекомендується виконувати ці настанови у кластері, що має щонайменше два вузли, які не виконують роль вузлів управління. Якщо у вас немає кластера, ви можете створити його, за допомогою minikube або використовувати одну з цих пісочниць:

Версія вашого Kubernetes сервера має бути не старішою ніж 1.29. Для перевірки версії введіть kubectl version.

Огляд sidecar-контейнерів

Sidecar-контейнери — це додаткові контейнери, які працюють разом з основним контейнером застосунку в межах одного Podʼа. Ці контейнери використовуються для покращення або розширення функціональності основного app-контейнера, надаючи додаткові послуги або функціональність, такі як логування, моніторинг, безпека або синхронізація даних, без прямого втручання в код основного застосунку. Детальніше можна прочитати на сторінці концепції Sidecar-контейнерів.

Концепція sidecar-контейнерів не є новою, і є багато її реалізацій. Як і sidecar-контейнери, які ви, як особа, що визначає Pod, хочете запустити, ви також можете побачити, що деякі надбудови змінюють Podʼи, до того, як Podʼи почнуть працювати, додаючи додаткові sidecar-контейнери. Механізми інʼєкцій цих додаткових sidecar-контейнерів часто використовують мутуючі вебхуки. Наприклад, надбудова service mesh може впроваджувати sidecar-контейнер, який налаштовує взаємний TLS і шифрування під час передачі між різними Podʼами.

Хоча концепція sidecar-контейнерів не є новою, вбудована реалізація цієї функції в Kubernetes, однак, нова. І як і з будь-якою новою функцією, впровадження цієї функції може викликати певні труднощі.

Цей навчальний посібник досліджує труднощі та рішення, з якими можуть зіткнутися кінцеві користувачі, а також автори sidecar-контейнерів.

Переваги вбудованих sidecar-контейнерів

Використання нативної підтримки sidecar-контейнерів у Kubernetes має кілька переваг:

  1. Ви можете налаштувати нативний sidecar-контейнер так, щоб він запускався перед init-контейнерами.
  2. Вбудовані sidecar-контейнери можна налаштувати так, щоб вони гарантовано завершувалися останніми. Sidecar-контейнери завершують роботу за допомогою сигналу SIGTERM, коли всі звичайні контейнери завершили роботу та завершилися. Якщо sidecar-контейнер не завершує роботу коректно, сигнал SIGKILL буде використано для його завершення.
  3. Для Jobs, коли restartPolicy: OnFailure або restartPolicy: Never, нативні sidecar-контейнери не блокують завершення Pod. Для старих sidecar-контейнерів потрібно було приділяти особливу увагу вирішенню цієї ситуації.
  4. Також для Jobs, вбудовані sidecar-контейнери будуть продовжувати перезапускатися після завершення, навіть якщо звичайні контейнери не будуть цього робити при restartPolicy: Never у Pod.

Дивіться відмінності від контейнерів ініціалізації для додаткових відомостей.

Впровадження вбудованих sidecar-контейнерів

Функціональна можливість SidecarContainers перебуває у стані бета-версії, починаючи з версії Kubernetes 1.29, і є стандартно увімкненою. Деякі кластери можуть мати цю функцію вимкненою або мати встановлене програмне забезпечення, яке не сумісне з цією функцією.

Коли це трапляється, Pod може бути відхилено або sidecar-контейнери можуть блокувати запуск Pod, роблячи Pod непридатним для використання. Цей стан легко виявити, оскільки Pod просто застряє на стадії ініціалізації. Однак рідко буває зрозуміло, що спричинило проблему.

Ось міркування та кроки з усунення несправностей, які можна виконати під час впровадження sidecar-контейнерів для свого навантаження.

Переконайтеся, що функціональну можливість увімкнено

Перш за все, переконайтеся, що як API-сервер, так і вузли мають версію Kubernetes v1.29 або пізнішу. Функція не працюватиме на кластерах, де вузли працюють на більш ранніх версіях, де вона не увімкнена.

Ви повинні переконатися, що функціональна можливість увімкнено як для API-сервера (серверів) у межах панелі управління, так і для всіх вузлів.

Одним зі способів перевірити увімкнення функціональної можливості є виконання команди:

  • Для API-сервера

    kubectl get --raw /metrics | grep kubernetes_feature_enabled | grep SidecarContainers

  • Для окремого вузла

    kubectl get --raw /api/v1/nodes/<node-name>/proxy/metrics | grep kubernetes_feature_enabled | grep SidecarContainers

Якщо ви бачите щось на кшталт: kubernetes_feature_enabled{name="SidecarContainers",stage="BETA"} 1, це означає, що функцію увімкнено.

Перевірка сторонніх інструментів і мутуючих вебхуків

Якщо у вас виникли проблеми під час перевірки функції, це може бути ознакою того, що один зі сторонніх інструментів або мутуючих вебхуків не працюють.

Коли функціональну можливість SidecarContainers увімкнено, Podʼи отримують нове поле в їхньому API. Деякі інструменти або мутуючі вебхуки могли бути створені на основі попередньої версії Kubernetes API.

Якщо інструменти передають невідомі поля як є, використовуючи різні стратегії виправлення для змінни об’єкта Pod, це не буде проблемою. Однак є інструменти, які видалять невідомі поля; якщо у вас є такі, їх потрібно буде перекомпілювати з v1.28+ версією клієнтського коду Kubernetes API.

Спосіб перевірки цього полягає у використанні команди kubectl describe pod для вашого Podʼа, який пройшов через мутуючий admission webhook. Якщо будь-які інструменти вилучили нове поле (restartPolicy: Always), ви не побачите його у виводі команди.

Якщо ви зіткнулися з такою проблемою, рекомендується повідомити автора інструментів або вебхуків, щоб вони використовували одну зі стратегій накладання патчів для модифікації обʼєктів замість їх повного оновлення.

Автоматичне встромляння sidecar-контейнерів

Якщо ви використовуєте програмне забезпечення, яке автоматично встромляє sidecar-контейнери, існує кілька можливих стратегій, які ви можете застосувати, щоб забезпечити можливість використання нативних sidecar-контейнерів. Усі ці стратегії загалом є варіантами вибору того, чи буде Pod, до якого встромляється sidecar, розміщений на вузлі, який підтримує цю функцію.

Наприклад, можна ознайомитися з цією дискусією в спільноті Istio, яка досліджує наведені нижче варіанти.

  1. Позначення Podʼів, що розміщуються на вузлах із підтримкою sidecars. Ви можете використовувати мітки вузлів і node affinity, щоб позначити вузли, які підтримують sidecar-контейнери, і забезпечити розміщення Pods на цих вузлах.
  2. Перевірка сумісності вузлів під час додавання контейнера. Під час впровадження sidecar-контейнерів можна використовувати такі стратегії перевірки сумісності вузлів:
    • Запитати версію вузла та припустити, що функціональну можливість увімкнено для версії 1.29+.
    • Запитати метрики Prometheus вузла та перевірити стан увімкнення функції.
    • Припустити, що вузли працюють із підтримуваною версійною розбіжністю від API-сервера.
    • Можуть існувати інші власні способи визначення сумісності вузлів.
  3. Розробка універсального інжектора sidecar-контейнерів. Ідея універсального sidecar-контейнера полягає в тому, щоб додати sidecar-контейнер як звичайний контейнер, а також як нативний sidecar-контейнер, і мати логіку на рівні виконання, яка визначить, який варіант працюватиме. Універсальний інжектор sidecar є ресурсозатратним, оскільки він враховуватиме запити двічі, але його можна розглядати як робоче рішення для особливих випадків.
    • Один зі способів полягає в тому, щоб під час запуску нативного sidecar-контейнера визначити версію вузла та завершити роботу негайно, якщо версія не підтримує функцію sidecar.
    • Розгляньте дизайн із виявленням функції під час виконання:
      • Визначте empty dir, щоб контейнери могли взаємодіяти один з одним.
      • Впровадьте init-контейнер, який назвемо NativeSidecar, з restartPolicy=Always.
      • NativeSidecar має записати файл в empty dir під час першого запуску та завершити роботу з кодом виходу 0.
      • NativeSidecar під час повторного запуску (коли нативні sidecar підтримуються) перевіряє, чи файл уже існує в empty dir, і змінює його, вказуючи, що вбудовані sidecar-контейнери підтримуються і працюють.
      • Впровадьте звичайний контейнер, який назвемо OldWaySidecar.
      • OldWaySidecar під час запуску перевіряє наявність файлу в empty dir.
      • Якщо файл вказує, що NativeSidecar не працює, він припускає, що функція sidecar не підтримується, і працює як sidecar.
      • Якщо файл вказує, що NativeSidecar працює, він або не робить нічого та спить назавжди (у випадку, коли Pod має restartPolicy=Always), або завершить роботу негайно з кодом виходу 0 (у випадку, коли Pod має restartPolicy!=Always).

Що далі