Подтвердить что ты не робот

Как имитировать '-volumes-from' в Kubernetes

Я ищу шаблон, который позволяет обмениваться томами между двумя контейнерами, работающими на одном контейнере в Кубернете.

Мой вариант использования: У меня есть приложение Ruby on Rails, запущенное внутри контейнера докеров. Изображение docker содержит статические ресурсы в каталоге /app/<app-name>/public, и мне нужно получить доступ к этим ресурсам из контейнера nginx, работающего рядом с тем же пакетом.

В docker 'vanilla' я бы использовал флаг --volumes-from для совместного использования этого каталога:

docker run --name app -v /app/<app-dir>/public <app-image>
docker run --volumes-from app nginx

После прочтения этого документа: https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/volumes.md Я попробовал это (только соответствующие записи):

spec:
  containers:
    - image: <app-image>
      name: <app-name>
      volumeMounts:
        - mountPath: /app/<app-name>/public
          name: assets
    - image: nginx
      name: nginx
      volumeMounts:
        - mountPath: /var/www/html
          name: assets
          readOnly: true
    volumes:
      - name: assets
        hostPath:
          path: /tmp/assets

Но:

  • Даже если /tmp/assets на node существует, он пуст
  • /app/<app-name>/public внутри контейнера приложения также пуст

В качестве обходного пути я попытаюсь заполнить общий каталог, когда контейнер приложения вставлен (просто cp /app/<app-name>/public/* в общий каталог), но мне действительно не нравится эта идея.

Вопрос: как имитировать --volumes-from в Kubernetes, или если нет прямого аналога, как я могу обмениваться файлами из одного контейнера на другой, работающий в одном и том же контейнере?

apiVersion: v1beta3

Client Version: version.Info{Major:"0", Minor:"17", GitVersion:"v0.17.0", GitCommit:"82f8bdac06ddfacf493a9ed0fedc85f5ea62ebd5", GitTreeState:"clean"}
Server Version: version.Info{Major:"0", Minor:"17", GitVersion:"v0.17.0", GitCommit:"82f8bdac06ddfacf493a9ed0fedc85f5ea62ebd5", GitTreeState:"clean"}
4b9b3361

Ответ 1

[update-2016-8] В последнем выпуске Kubernetes вы можете использовать очень приятную функцию с именем init-container, чтобы заменить часть postStart в моем ответе ниже, что позволит убедиться, что контейнер.

введите описание изображения здесь

ПРИМЕЧАНИЕ: initContainer по-прежнему является бета-функцией, поэтому рабочая версия этого yaml на самом деле похожа: http://kubernetes.io/docs/user-guide/production-pods/#handling-initialization, обратите внимание на часть pod.beta.kubernetes.io/init-containers.

--- исходный ответ начинается ---

Собственно, вы можете. Вам необходимо использовать обработчик жизненного цикла контейнера для управления файлами/каталогами, которые вы хотите разделить с другими контейнерами. Как:

---
apiVersion: v1
kind: Pod
metadata:
    name: server
spec:
    restartPolicy: OnFailure
    containers:
    - image: resouer/sample:v2
      name: war
      lifecycle:
        postStart:
          exec:
            command:
              - "cp"
              - "/sample.war"
              - "/app"
      volumeMounts:
      - mountPath: /app
        name: hostv1 
    - name: peer
      image: busybox
      command: ["tail", "-f", "/dev/null"]
      volumeMounts:
      - name: hostv2
        mountPath: /app/sample.war
    volumes:
    - name: hostv1
      hostPath:
          path: /tmp
    - name: hostv2
      hostPath:
          path: /tmp/sample.war

Пожалуйста, проверьте мои настройки для получения более подробной информации:

https://gist.github.com/resouer/378bcdaef1d9601ed6aa

И, конечно, вы можете использовать emptyDir. Таким образом, военный контейнер может делить его /sample.war на одноранговый контейнер без каталога беспорядочного peer/app.

Если мы допустим перенос /app, это будет намного проще:

---
apiVersion: v1
kind: Pod
metadata:
  name: javaweb-2
spec:
  restartPolicy: OnFailure
  containers:
  - image: resouer/sample:v2
    name: war
    lifecycle:
      postStart:
        exec:
          command:
            - "cp"
            - "/sample.war"
            - "/app"
    volumeMounts:
    - mountPath: /app
      name: app-volume
  - image: resouer/mytomcat:7.0
    name: tomcat
    command: ["sh","-c","/root/apache-tomcat-7.0.42-v2/bin/start.sh"]
    volumeMounts:
    - mountPath: /root/apache-tomcat-7.0.42-v2/webapps
      name: app-volume
    ports:
    - containerPort: 8080
      hostPort: 8001 
  volumes:
  - name: app-volume
    emptyDir: {}

Ответ 2

Ответ - на данный момент - вы не можете. Здесь несколько обсуждений из проблем Кубернеса:

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

  • Если ваши активы заблокированы в точке, в которой собирается контейнер, вы можете использовать что-то вроде gitRepo том, который скопировал бы его в emptyDir в момент перехода в реальном времени, и будет означать, что вам не придется перемещать контент вокруг все, просто загрузите его непосредственно в общий каталог.
  • Если ваши активы заблокированы в точке контейнера будучи построенным, вероятно, лучше всего скопировать их в тот момент, используя команда Docker COPY.
  • Если вы действительно хотите придерживаться того, как вы это делаете, вам придется скопировать содержимое в том тома emptyDir, который предназначен именно для того, что вы ищете (минус отсутствие необходимости скопируйте его).

Объемы NFS [1] также могут решить вашу проблему, но могут быть чрезмерно сложными.

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

[1] https://github.com/GoogleCloudPlatform/kubernetes/blob/master/examples/nfs/nfs-web-pod.yaml

Ответ 3

Дальнейшее обновление из будущего:

Теперь есть плагин FlexVol для томов Docker: https://github.com/dims/docker-flexvol

Во время написания FlexVol все еще является альфа-функцией, поэтому предостерегает emptor.

Ответ 4

Если вы используете Docker v17.0.5 или выше, вы можете использовать многоступенчатую сборку для копирования файлов из одного из ваших контейнеров в другой во время сборки. Это отличный учебник по расширенным функциям по адресу https://medium.com/@tonistiigi/advanced-multi-stage-build-patterns-6f741b852fae.

То, как я использовал его для копирования статических ресурсов из моего внутреннего контейнера в прокси Nginx,

ARG API_BACKEND_CONTAINER="api:backend"
FROM $API_BACKEND_CONTAINER as source

FROM nginx:mainline-alpine

ARG NGINX_ROOT=/usr/share/nginx/html/
COPY --from=source  /var/share/api/static/ ${NGINX_ROOT}

Самое замечательное то, что поскольку API_BACKEND_CONTAINER является аргументом сборки, я могу передать тег последней сборки API.

Ответ 5

Kubernetes имеет свои собственные типы томов, и это наиболее часто используемые типы томов:

  1. emptyDir
  2. секрет
  3. gitRepo
  4. hostPath (аналогично --volumes-from)
  5. Конфиг Карты
  6. постоянное хранилище (диски хранения, предоставляемые облачными платформами)

Вы можете узнать больше о томах kubernets здесь - https://kubernetes.io/docs/concepts/storage/volumes/

Пример тома hostpath:

apiVersion: v1
kind: Pod
metadata:
  name: test-pd
spec:
  containers:
  - image: k8s.gcr.io/test-webserver
    name: test-container
    volumeMounts:
    - mountPath: /test-pd
      name: test-volume
  volumes:
  - name: test-volume
    hostPath:
      # directory location on host
      path: /data
      # this field is optional
      type: Directory

hostpath будет монтировать каталог хост/узел в каталог контейнера. Несколько контейнеров внутри модуля могут использовать разные или одинаковые тома. Вы должны указать это в каждом контейнере. Тома hostPath не зависят от жизненного цикла модуля, но создают тесную связь между узлом и модулем, поэтому следует избегать использования hostPath.