Как установить мои плагины в файловую систему приложения до запуска контейнера приложения?

У меня есть приложение, упакованное как образ докера. Приложение имеет некоторые плагины по умолчанию, установленные в /opt/myapp/plugins/. Я хочу установить некоторые дополнительные плагины, что в основном означает копирование плагинов по вышеупомянутому пути приложения:

cp /path/to/more-plugins/* /opt/myapp/plugins/

Как я могу это сделать? Помогает ли initContainers в таких случаях? Имеет ли init-контейнер доступ к файловой системе контейнера приложений, чтобы можно было выполнить приведенную выше команду? Я попытался использовать busybox в initContainers и запустил ls -lR /opt/myapp, чтобы посмотреть, существует ли вообще такой путь. Но похоже, что у контейнера инициализации нет доступа к файловой системе приложения.

Итак, каковы различные решения этой проблемы? А какой самый лучший?


person Nawaz    schedule 17.03.2020    source источник
comment
stackoverflow.com/a/60608825/1318694   -  person Matt    schedule 17.03.2020


Ответы (2)


Я не эксперт по контейнерам, но я понимаю, что лучший способ сделать это — создать новый контейнер на основе вашего текущего образа докера, который копирует файлы на место. Ваш образ с вашими плагинами и конфигурациями — это то, что загружает и управляет k8s.

FROM my/oldimage:1.7.1
COPY more-plugins/* /opt/myapp/plugins/
$ docker build -t my/newimage:1.7.1 .
person PaulProgrammer    schedule 17.03.2020
comment
Вы имеете в виду другое производное приложение от моего приложения, например FROM myapp:v1.0, а затем COPY и лайки? Что произойдет с ENTRYPOINT и CMD, определенными в myapp? Будут ли они игнорироваться? - person Nawaz; 17.03.2020
comment
ENTRYPOINT и CMD наследуются, если вы не переопределите их. - person Matt; 17.03.2020
comment
Я понимаю, что определение производного изображения решит эту проблему. Однако что, если я использую command: в контейнере приложения, определенном в deployment.yaml, и там я устанавливаю плагины, а затем вызываю исполняемый файл оттуда, вместо того, чтобы полагаться на ENTRYPOINT? Это хорошая идея? - person Nawaz; 17.03.2020
comment
Возможно, вам понадобится какой-то общий том для копирования. - person Matt; 17.03.2020
comment
Однако я бы сделал копию только в сборке образа контейнера. Это означает, что у вас всегда есть полный, воспроизводимый артефакт того, что работает. - person Matt; 17.03.2020

Итак, каковы различные решения этой проблемы? А какой самый лучший?

Лучшее решение уже предоставлено @PaulProgrammer, и пока нет противопоказаний, вам следует сделать подключаемые модули приложения неотъемлемой частью образа docker. Доводы в пользу таких решений уже хорошо объяснил @Matt:

Однако я бы сделал копию только в сборке образа контейнера. Это означает, что у вас всегда есть полный, воспроизводимый артефакт того, что работает. – Мэтт

Я полностью с этим согласен и также настоятельно рекомендую вам пересобрать образ докера, а не решать эту проблему на уровне kubernetes.

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

Хочу еще раз подчеркнуть, что это не оптимальное решение, но с технической точки зрения это также возможно сделать с помощью init-контейнеров в kubernetes. Кроме того, я даже попытаюсь объяснить, почему это не лучшее решение или, точнее, почему оно неприменимо в вашем конкретном случае использования.

Как я могу это сделать? Полезен ли initContainers в таких случаях? Имеет ли init-контейнер доступ к файловой системе контейнера приложений, чтобы можно было выполнить приведенную выше команду? Я попытался использовать busybox в initContainers и запустил ls -lR /opt/myapp, чтобы посмотреть, существует ли вообще такой путь. Но похоже, что у контейнера инициализации нет доступа к файловой системе приложения.

Имейте в виду, что контейнеры инициализации всегда запускаются до запуска контейнеров приложений, и они не могут изменить исходную файловую систему контейнера приложений, как в случае запустить его еще даже не существует. Однако их можно использовать для предварительного заполнения дополнительного тома, который впоследствии можно смонтировать в контейнере приложения. Посмотрите на пример ниже:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
  labels:
    app: my-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: debian
  template:
    metadata:
      labels:
        app: debian
    spec:
      containers:
      - name: debian
        image: debian
        command: ['sh', '-c', 'sleep 3600']
        volumeMounts:
         - mountPath: "/app/data"
           name: my-volume
           readOnly: true
      volumes:
      - name: my-volume
        persistentVolumeClaim:
          claimName: example-pvc
      initContainers:
      - name: init-myservice
        image: busybox
        command: ['sh', '-c', 'echo "Content of my file" > /mnt/my_file']
        volumeMounts:
         - mountPath: "/mnt"
           name: my-volume

В этом примере мы заполняем каталог /app/data контейнера приложения некоторым содержимым с помощью контейнера инициализации. command здесь не так важно. Это может быть что угодно: от получения некоторого контента с помощью wget до клонирования репозитория git или scp некоторого контента с удаленного сервера. Обратите внимание, что вы не можете добавить таким образом дополнительный контент к уже существующему. Если каталог уже существовал и в нем уже был какой-то контент, он стирается и заполняется новым. На самом деле это не с технической точки зрения. Каталог используется как новая точка подключения для другого тома. Поскольку теперь он указывает на другой диск и его содержимое, исходное содержимое каталога больше недоступно с нашей точки зрения.

Каков типичный сценарий использования? Чем это может быть полезно?

Если вашему приложению нужны данные для обработки, вы обычно не хотите делать их неотъемлемой частью вашего образа Docker. Представьте, что он довольно часто меняется и вам всегда нужно скачивать его самую последнюю версию. Таким образом, вам не придется каждый раз беспокоиться о восстановлении изображений.

Но это не применимо в вашем случае. Во-первых, потому что вам нужно добавить некоторые данные (дополнительные плагины) к чему-то, что уже является неотъемлемой частью образа контейнера вашего приложения. В этой ситуации контейнеры инициализации не очень помогут. Во-вторых, вам скорее нужно иметь последовательное, воспроизводимое изображение, содержащее все необходимые плагины.

Как я уже сказал, технически это осуществимо, так как вы можете загрузить куда-нибудь все необходимые вам плагины (включая оригинальные, которые уже присутствуют в базовом образе) и скопировать весь контент с помощью контейнера инициализации. Преимущество такого подхода в том, что он не требует от вас создания пользовательских изображений при выпуске новой версии вашего базового приложения. Вы только изменяете тег изображения, а контейнер инициализации позаботится о заполнении каталога /opt/myapp/plugins/ всеми необходимыми подключаемыми модулями и гарантирует, что он не содержит ничего, кроме них. .

Я надеюсь, что он привнес что-то новое в эту ветку и немного прояснил, в каких ситуациях стоит использовать контейнер инициализации для заполнения вашего контейнера приложения данными, а в каких — лучше придерживаться своего собственного образа Docker.

person mario    schedule 17.03.2020
comment
Я испытал это только на прошлой неделе; спасибо, что подтвердили это еще раз: Обратите внимание, что вы не можете добавить таким образом дополнительный контент к уже существующему. Если каталог уже существовал и в нем уже было какое-то содержимое, он стирается и заполняется новым. На самом деле это не с технической точки зрения. Каталог используется как новая точка подключения для другого тома. Поскольку теперь он указывает на другой диск и его содержимое, исходное содержимое каталога больше недоступно с нашей точки зрения. - person Nawaz; 18.03.2020