From 0ab806d9665b6ae1c6ac4246a5d385872e7d59f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Gronowski?= Date: Wed, 16 Oct 2024 10:42:54 +0200 Subject: [PATCH] Support image source on darwin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Paweł Gronowski --- __tests__/docker/install.test.itg.ts | 3 ++- src/docker/assets.ts | 29 ++++++++++++++++++++----- src/docker/install.ts | 32 +++++++++++++++++++--------- src/hubRepository.ts | 8 +++---- 4 files changed, 52 insertions(+), 20 deletions(-) diff --git a/__tests__/docker/install.test.itg.ts b/__tests__/docker/install.test.itg.ts index c061afb4..db73638d 100644 --- a/__tests__/docker/install.test.itg.ts +++ b/__tests__/docker/install.test.itg.ts @@ -41,8 +41,9 @@ aarch64:https://cloud.debian.org/images/cloud/bookworm/20231013-1532/debian-12-g }); // prettier-ignore test.each([ - {type: 'archive', version: 'v26.1.4', channel: 'stable'} as InstallSourceArchive, {type: 'image', tag: '27.3.1'} as InstallSourceImage, + {type: 'image', tag: 'master'} as InstallSourceImage, + {type: 'archive', version: 'v26.1.4', channel: 'stable'} as InstallSourceArchive, ])( 'install docker %s', async (source) => { if (process.env.ImageOS && process.env.ImageOS.startsWith('ubuntu')) { diff --git a/src/docker/assets.ts b/src/docker/assets.ts index 15e39c22..5d9c4999 100644 --- a/src/docker/assets.ts +++ b/src/docker/assets.ts @@ -221,16 +221,35 @@ provision: EOF fi export DEBIAN_FRONTEND=noninteractive - curl -fsSL https://get.docker.com | sh -s -- --channel {{dockerBinChannel}} --version {{dockerBinVersion}} + if [ {{srcType}} == "archive" ]; then + curl -fsSL https://get.docker.com | sh -s -- --channel {{srcArchiveChannel}} --version {{srcArchiveVersion}} + elif [ {{srcType}} == "image" ]; then + wget https://raw.githubusercontent.com/moby/moby/{{srcImageTag}}/contrib/init/systemd/docker.service \ + https://raw.githubusercontent.com/moby/moby/v{{srcImageTag}}/contrib/init/systemd/docker.service \ + -O /etc/systemd/system/docker.service || true + wget https://raw.githubusercontent.com/moby/moby/{{srcImageTag}}/contrib/init/systemd/docker.socket \ + https://raw.githubusercontent.com/moby/moby/v{{srcImageTag}}/contrib/init/systemd/docker.socket \ + -O /etc/systemd/system/docker.socket || true + + mkdir -p /usr/local/bin + cp /tool/* /usr/local/bin/ + sed -i 's|^ExecStart=.*|ExecStart=/usr/local/bin/dockerd -H fd://|' /etc/systemd/system/docker.service + sed -i 's|containerd.service||' /etc/systemd/system/docker.service + if ! getent group docker; then + groupadd --system docker + fi + systemctl daemon-reload + if ! systemctl enable --now docker; then + systemctl status docker.socket + systemctl status docker.service + fi + fi probes: - script: | #!/bin/bash set -eux -o pipefail - if ! timeout 30s bash -c "until command -v docker >/dev/null 2>&1; do sleep 3; done"; then - echo >&2 "docker is not installed yet" - exit 1 - fi + # Don't check for docker CLI as it's not installed in the VM (only on the host) if ! timeout 30s bash -c "until pgrep dockerd; do sleep 3; done"; then echo >&2 "dockerd is not running" exit 1 diff --git a/src/docker/install.ts b/src/docker/install.ts index e6f219f3..c86e32c8 100644 --- a/src/docker/install.ts +++ b/src/docker/install.ts @@ -127,13 +127,16 @@ export class Install { const cli = await HubRepository.build('dockereng/cli-bin'); extractFolder = await cli.extractImage(tag); - // Daemon is only available for Windows and Linux - if (['win32', 'linux'].includes(platform)) { + if (['win32', 'linux', 'darwin'].includes(platform)) { core.info(`Downloading dockerd from moby/moby-bin:${tag}`); const moby = await HubRepository.build('moby/moby-bin'); - await moby.extractImage(tag, extractFolder); + + // On macOS, we extract the Linux version of dockerd which will be run in a lima VM. + const extractPlatform = platform == 'darwin' ? 'linux' : undefined; + + await moby.extractImage(tag, extractFolder, extractPlatform); } else { - core.info(`dockerd not supported on ${platform}`); + core.warning(`dockerd not supported on ${platform}, only the Docker cli will be available`); } break; } @@ -192,14 +195,19 @@ export class Install { } private async installDarwin(): Promise { - if (this.source.type !== 'archive') { - throw new Error('Only archive source is supported on macOS'); - } - const src = this.source as InstallSourceArchive; + const src = this.source; const limaDir = path.join(os.homedir(), '.lima', this.limaInstanceName); await io.mkdirP(limaDir); const dockerHost = `unix://${limaDir}/docker.sock`; + // this.toolDir is a very long path which causes trouble when mounting it in lima. + // Copy it to a shorter path. + const limaToolsDir = '/tmp/lima'; + + await core.group('Copy tools', async () => { + await Exec.exec('cp', ['-rv', this.toolDir, limaToolsDir]); + }); + // avoid brew to auto update and upgrade unrelated packages. let envs = Object.assign({}, process.env, { HOMEBREW_NO_AUTO_UPDATE: '1', @@ -226,12 +234,16 @@ export class Install { handlebars.registerHelper('stringify', function (obj) { return new handlebars.SafeString(JSON.stringify(obj)); }); + const srcArchive = src as InstallSourceArchive; const limaCfg = handlebars.compile(limaYamlData)({ customImages: Install.limaCustomImages(), daemonConfig: limaDaemonConfig, dockerSock: `${limaDir}/docker.sock`, - dockerBinVersion: src.version.replace(/^v/, ''), - dockerBinChannel: src.channel + srcType: src.type, + srcArchiveVersion: srcArchive.version?.replace(/^v/, ''), + srcArchiveChannel: srcArchive.channel, + srcImageTag: (src as InstallSourceImage).tag, + toolDir: limaToolsDir }); core.info(`Writing lima config to ${path.join(limaDir, 'lima.yaml')}`); fs.writeFileSync(path.join(limaDir, 'lima.yaml'), limaCfg); diff --git a/src/hubRepository.ts b/src/hubRepository.ts index e2a88845..77adaccc 100644 --- a/src/hubRepository.ts +++ b/src/hubRepository.ts @@ -42,12 +42,12 @@ export class HubRepository { // Unpacks the image layers and returns the path to the extracted image. // Only OCI indexes/manifest list are supported for now. - public async extractImage(tag: string, destDir?: string): Promise { + public async extractImage(tag: string, destDir?: string, osPlatform?: string): Promise { const index = await this.getManifest(tag); if (index.mediaType != MEDIATYPE_IMAGE_INDEX_V1 && index.mediaType != MEDIATYPE_IMAGE_MANIFEST_LIST_V2) { throw new Error(`Unsupported image media type: ${index.mediaType}`); } - const digest = HubRepository.getPlatformManifestDigest(index); + const digest = HubRepository.getPlatformManifestDigest(index, osPlatform); const manifest = await this.getManifest(digest); const paths = manifest.layers.map(async layer => { @@ -115,9 +115,9 @@ export class HubRepository { return JSON.parse(body); } - private static getPlatformManifestDigest(index: Index): string { + private static getPlatformManifestDigest(index: Index, osPlatform?: string): string { // This doesn't handle all possible platforms normalizations, but it's good enough for now. - let pos: string = os.platform(); + let pos: string = osPlatform || os.platform(); if (pos == 'win32') { pos = 'windows'; }