Доступ к файлу в докере с помощью JavaScript/Node

Есть ли способ программно получить доступ к файлу в контейнере (докере) во время выполнения. Я пытался использовать node-docker-api только для настройки в первую очередь и установления соединения:

const docker = new Docker({
    "host": "tcp://docker:port"
});

// List
docker.container.list()
// Inspect
    .then(containers => containers[0].status())
    .then(container => container.top())
    .then(processes => console.info(processes))
    .catch(error => console.info(error));

где «порт» — 4-значный номер порта. Но я получаю это сообщение об ошибке:

{ Error: connect ECONNREFUSED 127.0.0.1:80
    at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1081:14)
  errno: 'ECONNREFUSED',
  code: 'ECONNREFUSED',
  syscall: 'connect',
  address: '127.0.0.1',
  port: 80 }

ОБНОВИТЬ: Я сделал что-то подобное на Java с dockerjava, используя https://github.com/docker-java/docker-java/issues/253 и httphijack — https://gist.github.com/missedone/76517e618486db746056

ExecCreateCmdResponse execCreateResp = dck.execCreateCmd(cid).withCmd("bash")
        .withAttachStderr().withAttachStdout().withAttachStdin().withTty(false).exec();

HashMap<String, String> headers = new HashMap<>();
headers.put("Content-Type", "application/json");

HttpHijack ws = new HttpHijack(new URI("http://127.0.0.1:2376/v1.19/exec/" + execCreateResp.getId() + "/start"));
String payload = "{\"Detach\": false,\"Tty\": false}";
ws.post(headers, payload);

а затем скопировать файл из контейнера, используя:

try (TarArchiveInputStream tarStream = new TarArchiveInputStream(
    docker.copyArchiveFromContainerCmd(containerId, "/home/seluser/Downloads/" + fileName).exec())) {
    unTar(tarStream, new File(filePath));
    return;
}catch(NotFoundException e){
    e.printStackTrace();
}

Но я не могу найти подход для достижения вышеуказанного с помощью javascript/node

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
1 472
2

Ответы 2

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

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

Если объемы докеров не ваш случай, то единственная идея, на мой взгляд, — поиграть с Докер REST API и особенно с методом Исполнитель.

Используя этот метод, вы можете выполнять команды Linux в контейнере.


ОБНОВЛЕНИЕ 1: Если ваша программа работает на хост-компьютере и вам нужен доступ к данным, сгенерированным томом докера, вы также можете привязать каталог хост-компьютера к каталогу внутри контейнера докера.

Пример: docker run -v /host/folder:/container/folder <your_image>

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

Читать далее


ОБНОВЛЕНИЕ 2: Вы можете использовать Docker REST API для выполнения команд внутри контейнера Docker следующим образом:

  1. Включите TCP-доступ к REST API: Отредактируйте /lib/systemd/system/docker.service и измените следующую строку: ExecStart=/usr/bin/dockerd -g /data/docker -H fd:// - ExecStart=/usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:2375 и сохраните файл. Затем systemctl daemon-reload и service docker restart. Теперь вы должны получить доступ к API на http://127.0.0.1:2375 — вы должны получить { "message": "page not found" } в качестве ответа.

  2. Создайте объект Exec с помощью REST API, например:

curl --header "Content-Type: application/json" \
  --request POST \
  --data '{"AttachStdout": true,"AttachStderr": true,"Cmd": ["date"]}' \
http://127.0.0.1:2375/v{dockerVersion}/containers/{containerId}/exec 

Здесь:

  • dockerVersion — версия вашего движка докера, которую можно получить с помощью команды docker version (см. версию для сервера, в моем случае это 1.38 — поэтому в URL это будет как v1.38 не забудьте v)
  • containerId — идентификатор вашего контейнера в докере, который можно получить с помощью следующей команды: curl http://127.0.0.1:2375/v{dockerVersion}/containers/json

В ответ на /containers/{containerId}/exec вы должны получить что-то вроде: {"Id": "{objectId}"}

  1. Выполнить ранее созданную команду:
curl --header "Content-Type: application/json" \
  --request POST \
  --data '{"Detach": false,"Tty": false}' \
http://127.0.0.1:2375/v{dockerVersion}/exec/{objectId}/start

Здесь:

  • objectId — идентификатор, возвращенный из Docker API на предыдущем шаге (ШАГ 2)

В ответ вы должны получить обычный текст — вывод вашей команды.

ЗАМЕТКА:Cmd в теле JSON представляет собой массив, поэтому вы можете указать несколько команд.

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

Larry 06.02.2019 13:15

Разве вы не можете хранить сгенерированные файлы в томе докера?

Vüsal 06.02.2019 13:17

в основном я запускаю некоторые тесты пользовательского интерфейса селена, используя докер селена. Во время этих тестов файлы загружаются, и я пытаюсь получить к ним доступ после загрузки. Тесты будут выполняться как часть процесса CI на Jenkins.

Larry 06.02.2019 13:19

Пожалуйста, смотрите мой обновленный ответ. Вы можете привязать папку селена в докере к вашему хост-каталогу и получить доступ к файлам в нем. Но, наверное, должно быть какое-то элегантное решение. Я не знаком с селеном.

Vüsal 06.02.2019 13:25

это было бы хорошим решением, если бы я был единственным, кто использовал контейнер, но это не так. Вместо того, чтобы запускать docker с хост-папкой, к которой может получить доступ каждый, было бы неплохо иметь возможность доступа к контейнеру во время выполнения и копирования файлов в рабочий каталог. Я добился этого с помощью Java, используя dockerjava, но не могу найти никакого решения, используя javascript/node

Larry 06.02.2019 13:33

имел в виду «вместо того, чтобы пытаться найти общую папку хоста», к которой каждый может получить доступ

Larry 06.02.2019 13:43

пожалуйста, посмотрите мое обновление, просто чтобы предоставить больше информации о том, как оно было реализовано в java

Larry 06.02.2019 14:42

@ Ларри, проверь раздел UPDATE 2 моего ответа. Я провел небольшое исследование и добавил инструкции о том, как выполнять команды Linux внутри контейнера докеров с использованием REST API.

Vüsal 06.02.2019 22:10

Привет @Larry, если этот или любой другой ответ решил ваш вопрос, рассмотрите возможность его принятия, нажав на галочку. Это показывает более широкому сообществу, что вы нашли решение, и повышает репутацию как отвечающего, так и вас самих. Нет никаких обязательств делать это.

Vüsal 11.02.2019 11:54

Вы можете использовать метод Docker API /getAchive для извлечения файлов из контейнера, а затем распаковать их. Существует реализация Docker API на NodeJS для использования на стороне сервера докероде.

 npm i dockerode

Затем импортируйте его и запустите контейнер, в котором находится файл.

var Docker = require('dockerode');
var docker = new Docker({socketPath: '/var/run/docker.sock'}); //or whatever path to your socket
let file = "abs/path/in/container/somefile.file"
let tag = "docekerImageTag"  //"repo/image" //"johndoe/docker_image"

runContainer(tag,"foo").then(container=>{
  getFile(container,file,ws)
})


function runContainer(containerName,param){
 return docker.run(
    containerName,
    ['Rscript', 'random.rscript','--test',`${param}`,],
    [process.stdout, process.stderr], {Tty:false}, //send only stdout if you don't want the split no tty needed
  ).then(function(data){
      var output=data[0]
      var container=data[1]
      return container
    },rej=>{
      console.info({rej})
      return rej
    }
  )
}
function getFile(container,file,ws){
  container.getArchive({path:file}).then(file=>{
    if (ws) ws.sendMsg(file) //send it somewhere I'm using a websocket. This will give you a stream with the tar file. 
//With the websocket you might have to parse the BufferList and iteratively send the buffers and assemble it on the other end
//fs.write(file,path,"UTF8") is another option. Though I think you still have to iterate the bufferList for "fs" 
  })
}

Не забудьте распаковать файл, если хотите сразу его использовать.

Существует также пакет JavaScript на стороне клиента для распаковки вызова потока js-разархивировать, который хорошо работает, когда вы получаете его на стороне клиента через websocket/other.

Другие вопросы по теме