Недавно я попытался заменить докер-образ alpine
на Distroless
, чтобы получить больше преимуществ. Но я столкнулся с ошибкой: «Нет доступной оболочки».
CMD из dockerfile
выглядит следующим образом:
CMD node dosomething.js & node server.js
В этой форме (она же shell-форма) вызывается командная оболочка для выполнения команд (node dosomething.js & node server.js).
Если вы используете shell-форму CMD, то команда будет выполняться в /bin/sh -c
Поскольку Distroless
не содержит shell внутри, произойдет ошибка.
Образы «Distroless» содержат только ваше приложение и его зависимости во время выполнения. Они не содержат менеджеров пакетов, оболочек или любых других программ, которые вы ожидаете найти в стандартном дистрибутиве Linux.
Я начал с идеи перенести код dosomething.js
в server.js
и в итоге обнаружил, что это слишком сложно, поскольку server.js был сгенерирован из исходного кода, и трудно вставить что-то и пожелать, чтобы это все еще работало.
Тогда пришла вторая идея — позволить бегунку запускать dosomething.js
и server.js
как дочерние процессы. Его код выглядел следующим образом:
runner.js
const { fork } = require('child_process')
const path = require('path')
fork(
path.resolve('dosomething.js'),
null,
{
detached: true
}
)
fork(
path.resolve('server.js'),
null,
{
detached: true,
}
)
Fork запустит дочерний процесс из модуля (первый аргумент, например, path.resolve('server.js')
), определенного в качестве первого аргумента.
Второй аргумент — это список аргументов для server.js. Когда server.js
принимает аргументы для управления своим поведением, мы можем добавить что-то сюда. Я сделал его равным null, так как для данного примера дополнительные аргументы не нужны.
Последний аргумент — это опции, и detached:true
означает, что дочерний процесс, запущенный из модуля (например, server.js), работает независимо от своего родительского процесса. Это имеет различное поведение на разных платформах, но вкратце можно сказать, что это заставляет дочерний процесс продолжать работать независимо от того, умирает главный процесс или нет. Это подходит под мои требования.
Итак, наконец, CMD в файле docker выглядит следующим образом:
CMD ["runner"]
Таким образом, вышеуказанное приложение решило проблему. Но только когда нам нужно, чтобы были запущены оба dosomthing.js
и server.js
, это работает. Что если я хочу, чтобы server.js
запускался только тогда, когда dosomthing.js
завершается без ошибки или с любой ошибкой. Это можно легко реализовать с помощью командной оболочки с оператором &&
и ||
. Я расскажу об этом в следующем посте.
Спасибо за прочтение.