В этой статье будет рассмотрен встроенный в Node.js метод os.cpus() и то, как наша команда использовала его для устранения ошибки.
Сначала немного предыстории о том, как я наткнулся на этот метод. Я работаю над проектом с небольшой командой, в которой мы используем контейнер Docker для выполнения ненадежного кода. При попытке запустить контейнер Docker в среде разработки, в зависимости от ядра процессора разработчика, некоторые из нас получат сообщение об ошибке, подобное этому:
docker: Error response from daemon: image with reference dockerUser/dockerImageName:dockerImageTag was found but does not match the specified platform: wanted linux/arm64/v8, actual: linux/amd64. See 'docker run --help'.
Мы поняли, что получили эту ошибку, потому что половина нашей команды использовала компьютер с чипом Intel, а другая половина — с кремниевым чипом. В приведенной выше ошибке мы узнаем, что загружаем образ с linux/amd64 (Intel), но единственная доступная архитектура процессора — linux/arm64/v8 (Silicon).
Итак, как мы решили эту ошибку? С помощью встроенного в Node.js метода os.cpus().
Во-первых, что делает os.cpus()?
Os.cpus() — это встроенный метод Node.js, предоставляющий информацию о ядре процессора используемого вами компьютера. Он возвращает объект со следующей информацией:
- model: строка, указывающая модель ядра процессора.
- скорость: число, указывающее скорость ядра ЦП (в МГц).
- times: объект, который содержит информацию о времени, которое ЦП провел в различных режимах (пользовательский, приятный, системный, бездействующий, прерывание) в миллисекундах.
Для наших целей нам понадобилась информация, содержащаяся в свойстве модели.
Во-вторых, как мы используем os.cpus()?
// import 'os' module const os = require('os'); // log os.cpus() object console.log(os.cpus());
После выполнения файла, содержащего приведенный выше код, ваш терминал должен напечатать объект, который выглядит так:
Example 1: [ { model: 'Apple M1 Pro', speed: 24, times: { user: 5923420, nice: 0, sys: 6578150, idle: 78493650, irq: 0 } }, { model: 'Apple M1 Pro', speed: 24, times: { user: 5989680, nice: 0, sys: 6034680, idle: 78970000, irq: 0 } }, { model: 'Apple M1 Pro', speed: 24, times: { user: 4231150, nice: 0, sys: 1405030, idle: 85358180, irq: 0 } }, { model: 'Apple M1 Pro', speed: 24, times: { user: 2766490, nice: 0, sys: 960700, idle: 87267170, irq: 0 } }, { model: 'Apple M1 Pro', speed: 24, times: { user: 1364820, nice: 0, sys: 534220, idle: 89095320, irq: 0 } } ] Example 2: [ { model: 'Intel(R) Core(TM) i7 CPU 860 @ 2.80GHz', speed: 2926, times: { user: 252020, nice: 0, sys: 30340, idle: 1070356870, irq: 0 } }, { model: 'Intel(R) Core(TM) i7 CPU 860 @ 2.80GHz', speed: 2926, times: { user: 306960, nice: 0, sys: 26980, idle: 1071569080, irq: 0 } }, { model: 'Intel(R) Core(TM) i7 CPU 860 @ 2.80GHz', speed: 2926, times: { user: 248450, nice: 0, sys: 21750, idle: 1070919370, irq: 0 } }, { model: 'Intel(R) Core(TM) i7 CPU 860 @ 2.80GHz', speed: 2926, times: { user: 256880, nice: 0, sys: 19430, idle: 1070905480, irq: 20 } } ]
Ваш вывод может содержать больше элементов в объекте или меньше, в зависимости от ядра вашего процессора. Половина нашей команды напечатала Intel… вместо Apple…, как в примерах выше. Название модели — это вся информация, необходимая для решения нашей проблемы, но если вы хотите узнать больше о свойствах скорости и времени, ознакомьтесь с этой ссылкой (также источником для Примера 2).
Теперь при выполнении команды docker run для запуска контейнера Docker мы можем добавить следующий флаг:
docker run --platform ${platform} <all other flags/information>
Но откуда взялась переменная платформы? Проверьте код ниже:
let platform = os.cpus()[0].model.includes("Intel") ? "linux/arm64/v8" : "linux/amd64";
Используя тернарный оператор, скобочную нотацию, метод include и метод os.cpus(), мы создали условный оператор, который меняет назначение переменной платформы в зависимости от ядра процессора пользователя. Окончательный код выглядит так:
const os = require('os'); let platform = os.cpus()[0].model.includes("Intel") ? "linux/arm64/v8" : "linux/amd64"; exec(`docker run --platform ${platform} <all other flags/information>`)
Если в вашей команде члены вашей команды используют между собой более двух разных ядер ЦП, то вместо тернарного оператора вы можете использовать что-то вроде оператора switch и добавить все необходимые параметры.
Если, как и я, вы также никогда не слышали об этом конкретном методе Node.js, я надеюсь, что вы нашли эту статью информативной и будете использовать ее, если когда-либо столкнетесь с подобной ошибкой.
Спасибо за прочтение!