From 78ab231c50074762aec9566e095e2c2e2590d3b5 Mon Sep 17 00:00:00 2001 From: CrazyMax <1951866+crazy-max@users.noreply.github.com> Date: Wed, 11 Dec 2024 18:49:32 +0100 Subject: [PATCH] docker(install): opt to expose local tcp address Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com> --- __tests__/docker/install.test.itg.ts | 30 +++++++++++++++++++++ src/docker/assets.ts | 37 ++++++++++++++++++------- src/docker/install.ts | 40 ++++++++++++++++++---------- 3 files changed, 83 insertions(+), 24 deletions(-) diff --git a/__tests__/docker/install.test.itg.ts b/__tests__/docker/install.test.itg.ts index 592ec9e4..6f651a70 100644 --- a/__tests__/docker/install.test.itg.ts +++ b/__tests__/docker/install.test.itg.ts @@ -69,6 +69,36 @@ describe('rootless', () => { ); }); +describe('tcp', () => { + // prettier-ignore + test.each(getSources(false))( + 'install %s', async (source) => { + await ensureNoSystemContainerd(); + const install = new Install({ + source: source, + runDir: tmpDir(), + contextName: 'foo', + daemonConfig: `{"debug":true}`, + localTCPPort: 2378 + }); + await expect( + tryInstall(install, async () => { + const out = await Docker.getExecOutput(['info'], { + env: Object.assign({}, process.env, { + DOCKER_HOST: 'tcp://localhost:2378', + DOCKER_CONTENT_TRUST: 'false' + }) as { + [key: string]: string; + } + }); + expect(out.exitCode).toBe(0); + }) + ).resolves.not.toThrow(); + }, + 30 * 60 * 1000 + ); +}); + async function tryInstall(install: Install, extraCheck?: () => Promise): Promise { try { await install.download(); diff --git a/src/docker/assets.ts b/src/docker/assets.ts index 80b46e17..523effff 100644 --- a/src/docker/assets.ts +++ b/src/docker/assets.ts @@ -51,7 +51,10 @@ param( [string]$RunDir, [Parameter(Mandatory = $true)] - [string]$DockerHost, + [string]$DockerHostSocket, + + [Parameter(Mandatory = $false)] + [string]$DockerHostTCP, [Parameter(Mandatory = $false)] [string]$DaemonConfig) @@ -82,7 +85,7 @@ if (Get-Service docker -ErrorAction SilentlyContinue) { $env:Path = "$ToolDir;" + [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") Write-Host "Path: $env:Path" -$env:DOCKER_HOST = $DockerHost +$env:DOCKER_HOST = $DockerHostSocket Write-Host "DOCKER_HOST: $env:DOCKER_HOST" if ($DaemonConfig) { @@ -91,16 +94,21 @@ if ($DaemonConfig) { $DaemonConfig | Out-File -FilePath "$env:ProgramData\\Docker\\config\\daemon.json" } +$arguments = @( + "--host=$DockerHostSocket", + "--data-root=$RunDir\\\\moby-root", + "--exec-root=$RunDir\\\\moby-exec", + "--pidfile=$RunDir\\\\docker.pid", + "--register-service" +) +if ($DockerHostTCP) { + $arguments += "--host=$DockerHostTCP" +} + Write-Host "Creating service" New-Item -ItemType Directory "$RunDir\\moby-root" -ErrorAction SilentlyContinue | Out-Null New-Item -ItemType Directory "$RunDir\\moby-exec" -ErrorAction SilentlyContinue | Out-Null -Start-Process -Wait -NoNewWindow "$ToolDir\\dockerd" \` - -ArgumentList \` - "--host=$DockerHost", \` - "--data-root=$RunDir\\moby-root", \` - "--exec-root=$RunDir\\moby-exec", \` - "--pidfile=$RunDir\\docker.pid", \` - "--register-service" +Start-Process -Wait -NoNewWindow "$ToolDir\\dockerd" -ArgumentList $arguments Write-Host "Starting service" Start-Service -Name docker Write-Host "Service started successfully!" @@ -231,6 +239,11 @@ provision: export DEBIAN_FRONTEND=noninteractive if [ "{{srcType}}" == "archive" ]; then curl -fsSL https://get.docker.com | sh -s -- --channel {{srcArchiveChannel}} --version {{srcArchiveVersion}} + sed -i 's|^ExecStart=.*|ExecStart=/usr/local/bin/dockerd -H fd:// -H tcp://0.0.0.0:2375|' /etc/systemd/system/docker.service + systemctl daemon-reload + systemctl restart docker + systemctl status docker.socket || true + systemctl status docker.service || true elif [ "{{srcType}}" == "image" ]; then arch=$(uname -m) case $arch in @@ -250,7 +263,7 @@ provision: wget https://raw.githubusercontent.com/moby/moby/{{gitCommit}}/contrib/init/systemd/docker.socket \ -O /etc/systemd/system/docker.socket - sed -i 's|^ExecStart=.*|ExecStart=/usr/local/bin/dockerd -H fd://|' /etc/systemd/system/docker.service + sed -i 's|^ExecStart=.*|ExecStart=/usr/local/bin/dockerd -H fd:// -H tcp://0.0.0.0:2375|' /etc/systemd/system/docker.service sed -i 's|containerd.service||' /etc/systemd/system/docker.service if ! getent group docker; then groupadd --system docker @@ -285,6 +298,10 @@ hostResolver: portForwards: - guestSocket: "/var/run/docker.sock" hostSocket: "{{dockerSock}}" +{{#if localTCPPort}} +- guestPort: 2375 + hostPort: {{localTCPPort}} +{{/if}} audio: # EXPERIMENTAL diff --git a/src/docker/install.ts b/src/docker/install.ts index 984fcf1b..620109a5 100644 --- a/src/docker/install.ts +++ b/src/docker/install.ts @@ -56,6 +56,7 @@ export interface InstallOpts { contextName?: string; daemonConfig?: string; rootless?: boolean; + localTCPPort?: number; } interface LimaImage { @@ -65,13 +66,15 @@ interface LimaImage { } export class Install { - private runDir: string; + private readonly runDir: string; private readonly source: InstallSource; private readonly contextName: string; private readonly daemonConfig?: string; + private readonly rootless: boolean; + private readonly localTCPPort?: number; + private _version: string | undefined; private _toolDir: string | undefined; - private rootless: boolean; private gitCommit: string | undefined; @@ -79,7 +82,6 @@ export class Install { constructor(opts: InstallOpts) { this.runDir = opts.runDir; - this.rootless = opts.rootless || false; this.source = opts.source || { type: 'archive', version: 'latest', @@ -87,6 +89,8 @@ export class Install { }; this.contextName = opts.contextName || 'setup-docker-action'; this.daemonConfig = opts.daemonConfig; + this.rootless = opts.rootless || false; + this.localTCPPort = opts.localTCPPort; } get toolDir(): string { @@ -268,6 +272,7 @@ export class Install { customImages: Install.limaCustomImages(), daemonConfig: limaDaemonConfig, dockerSock: `${limaDir}/docker.sock`, + localTCPPort: this.localTCPPort, gitCommit: this.gitCommit, srcType: src.type, srcArchiveVersion: this._version, // Use the resolved version (e.g. latest -> 27.4.0) @@ -376,8 +381,10 @@ export class Install { await Exec.exec('sudo', ['sh', '-c', 'echo 0 > /proc/sys/kernel/apparmor_restrict_unprivileged_userns']); } } - - const cmd = `${dockerPath} --host="${dockerHost}" --config-file="${daemonConfigPath}" --exec-root="${this.runDir}/execroot" --data-root="${this.runDir}/data" --pidfile="${this.runDir}/docker.pid"`; + let cmd = `${dockerPath} --host="${dockerHost}" --config-file="${daemonConfigPath}" --exec-root="${this.runDir}/execroot" --data-root="${this.runDir}/data" --pidfile="${this.runDir}/docker.pid"`; + if (this.localTCPPort) { + cmd += ` --host="tcp://127.0.0.1:${this.localTCPPort}"`; + } core.info(`[command] ${cmd}`); // https://github.com/actions/toolkit/blob/3d652d3133965f63309e4b2e1c8852cdbdcb3833/packages/exec/src/toolrunner.ts#L47 let sudo = 'sudo'; if (this.rootless) { @@ -438,7 +445,7 @@ EOF`, } private async installWindows(): Promise { - const dockerHost = 'npipe:////./pipe/setup_docker_action'; + const dockerHostSocket = 'npipe:////./pipe/setup_docker_action'; let daemonConfig = undefined; const daemonConfigPath = path.join(this.runDir, 'daemon.json'); @@ -460,24 +467,29 @@ EOF`, }); } + const params = { + ToolDir: this.toolDir, + RunDir: this.runDir, + DockerHostSocket: dockerHostSocket, + DaemonConfig: daemonConfigStr + }; + if (this.localTCPPort) { + params['DockerHostTCP'] = `tcp://127.0.0.1:${this.localTCPPort}`; + } + await core.group('Install Docker daemon service', async () => { - const setupCmd = await Util.powershellCommand(setupDockerWinPs1(), { - ToolDir: this.toolDir, - RunDir: this.runDir, - DockerHost: dockerHost, - DaemonConfig: daemonConfigStr - }); + const setupCmd = await Util.powershellCommand(setupDockerWinPs1(), params); await Exec.exec(setupCmd.command, setupCmd.args); const logCmd = await Util.powershellCommand(dockerServiceLogsPs1()); await Exec.exec(logCmd.command, logCmd.args); }); await core.group('Create Docker context', async () => { - await Docker.exec(['context', 'create', this.contextName, '--docker', `host=${dockerHost}`]); + await Docker.exec(['context', 'create', this.contextName, '--docker', `host=${dockerHostSocket}`]); await Docker.exec(['context', 'use', this.contextName]); }); - return dockerHost; + return dockerHostSocket; } public async tearDown(): Promise {