Merge pull request #2069 from balena-os/local-journalctl

Stop using host journalctl
This commit is contained in:
Felipe Lalanne 2022-12-07 16:28:02 -03:00 committed by GitHub
commit 5c9b896c82
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 45 additions and 15 deletions

View File

@ -37,7 +37,6 @@ RUN strip /usr/local/bin/node
# Install fatrw
RUN curl -SLO "${FATRW_LOCATION}" && \
echo curl -SLO "${FATRW_LOCATION}" && \
ls -la "${FATRW_ARCHIVE}" && \
tar -xzf "${FATRW_ARCHIVE}" -C /usr/local/bin && \
rm -f "${FATRW_ARCHIVE}"
@ -45,6 +44,21 @@ RUN curl -SLO "${FATRW_LOCATION}" && \
# Just install dev dependencies first
RUN npm ci --build-from-source --sqlite=/usr/lib
###################################################################
# Journal access.
# The supervisor is built on an alpine image but still needs
# to use journalctl (from systemd) which cannot be built for
# musl. We hack around this by copying the binary and its library
# dependencies to the final image
###################################################################
FROM balenalib/${ARCH}-debian:bullseye-run as journal
RUN apt-get update && apt-get install -y --no-install-recommends systemd
COPY ./build-utils/setup-journal.sh /
RUN /setup-journal.sh
###################################################
# Extra dependencies. This uses alpine 3.11 as the
# procmail package was removed on 3.12
@ -70,6 +84,9 @@ COPY --from=build-base /usr/local/bin/fatrw /usr/local/bin/fatrw
# Similarly, from the procmail package we just need the lockfile binary
COPY --from=extra /usr/bin/lockfile /usr/bin/lockfile
# Copy journalctl and library dependecies to the final image
COPY --from=journal /sysroot /
# Runtime dependencies
RUN apk add --no-cache \
ca-certificates \

12
build-utils/setup-journal.sh Executable file
View File

@ -0,0 +1,12 @@
#!/bin/sh
set -e
mkdir -p /sysroot/bin
cp /bin/journalctl /sysroot/bin/
# Get all library dependencies from the binary
for lib in $(ldd /bin/journalctl | grep -oE '(\/.+?) '); do
mkdir -p "/sysroot/$(dirname "$lib")"
# Copy the dependency dereferencing any symlinks
cp -L "$lib" "/sysroot/$lib"
done

View File

@ -26,6 +26,16 @@ if [ -n "${BALENA_ROOT_CA}" ]; then
fi
fi
# Setup necessary directories for journalctl
# NOTE: this won't be necessary once the supervisor can update
# itself, as using the label io.balena.features.journal-logs will
# achieve the same objective
if [ -d /mnt/root/run/log/journal ]; then
mkdir -p /run/log
ln -sf /mnt/root/run/log/journal /run/log/journal
ln -sf /mnt/root/etc/machine-id /etc/machine-id
fi
# Mount the host kernel module path onto the expected location
# We need to do this as busybox doesn't support using a custom location
if [ ! -d /lib/modules ]; then

View File

@ -1,6 +1,5 @@
import { ChildProcess, spawn } from 'child_process';
import constants = require('./constants');
import log from './supervisor-console';
export function spawnJournalctl(opts: {
@ -13,11 +12,7 @@ export function spawnJournalctl(opts: {
filterString?: string;
since?: number;
}): ChildProcess {
const args = [
// The directory we want to run the chroot from
constants.rootMountPoint,
'journalctl',
];
const args: string[] = [];
if (opts.all) {
args.push('-a');
}
@ -52,9 +47,9 @@ export function spawnJournalctl(opts: {
args.push(opts.filterString);
}
log.debug('Spawning journald with: chroot ', args.join(' '));
log.debug('Spawning journalctl', args.join(' '));
const journald = spawn('chroot', args, {
const journald = spawn('journalctl', args, {
stdio: 'pipe',
});

View File

@ -1,7 +1,6 @@
import { SinonStub, stub } from 'sinon';
import { expect } from 'chai';
import constants = require('~/lib/constants');
import { spawnJournalctl } from '~/lib/journald';
describe('lib/journald', () => {
@ -29,8 +28,7 @@ describe('lib/journald', () => {
format: 'json-pretty',
});
const expectedCommand = `chroot`;
const expectedCoreArgs = [`${constants.rootMountPoint}`, 'journalctl'];
const expectedCommand = `journalctl`;
const expectedOptionalArgs = [
'-a',
'--follow',
@ -45,13 +43,11 @@ describe('lib/journald', () => {
];
const actualCommand = spawn.firstCall.args[0];
const actualCoreArgs = spawn.firstCall.args[1].slice(0, 2);
const actualOptionalArgs = spawn.firstCall.args[1].slice(2);
const actualOptionalArgs = spawn.firstCall.args[1];
expect(spawn.calledOnce).to.be.true;
expect(actualCommand).deep.equal(expectedCommand);
expect(actualCoreArgs).deep.equal(expectedCoreArgs);
expectedOptionalArgs.forEach((arg) => {
expect(actualOptionalArgs).to.include(arg);