From 73b485023220f4e860acf4016796337504c796b6 Mon Sep 17 00:00:00 2001 From: CrazyMax Date: Sat, 26 Aug 2023 22:16:27 +0200 Subject: [PATCH] docker(install): opt to set daemon config Signed-off-by: CrazyMax --- __tests__/docker/install.test.itg.ts | 3 +- package.json | 2 + src/docker/assets.ts | 29 +++++++++----- src/docker/install.ts | 58 +++++++++++++++++++++++++++- yarn.lock | 9 +++++ 5 files changed, 89 insertions(+), 12 deletions(-) diff --git a/__tests__/docker/install.test.itg.ts b/__tests__/docker/install.test.itg.ts index 01c20eb3..ce4f715f 100644 --- a/__tests__/docker/install.test.itg.ts +++ b/__tests__/docker/install.test.itg.ts @@ -42,7 +42,8 @@ describe('install', () => { const install = new Install({ version: version, runDir: tmpDir, - contextName: 'foo' + contextName: 'foo', + daemonConfig: `{"features":{"containerd-snapshotter":true}}` }); await install.download(); await install.install(); diff --git a/package.json b/package.json index 5f6eec6a..8cfbc389 100644 --- a/package.json +++ b/package.json @@ -56,12 +56,14 @@ "async-retry": "^1.3.3", "csv-parse": "^5.4.0", "handlebars": "^4.7.8", + "js-yaml": "^4.1.0", "jwt-decode": "^3.1.2", "semver": "^7.5.4", "tmp": "^0.2.1" }, "devDependencies": { "@types/csv-parse": "^1.2.2", + "@types/js-yaml": "^4.0.5", "@types/node": "^16.18.21", "@types/semver": "^7.5.0", "@types/tmp": "^0.2.3", diff --git a/src/docker/assets.ts b/src/docker/assets.ts index 40fe1285..17b925bb 100644 --- a/src/docker/assets.ts +++ b/src/docker/assets.ts @@ -48,38 +48,40 @@ const get = (filename: string, data: string, mode?: string): string => { export const setupDockerLinuxShData = ` #!/usr/bin/env bash -set -eu - : "\${TOOLDIR=}" : "\${RUNDIR=}" +: "\${DAEMON_CONFIG_PATH=}" : "\${DOCKER_HOST=}" export PATH="$TOOLDIR::$PATH" if [ -z "$DOCKER_HOST" ]; then echo >&2 'error: DOCKER_HOST required' - false + exit 1 fi if ! command -v dockerd &> /dev/null; then echo >&2 'error: dockerd missing from PATH' - false + exit 1 fi -mkdir -p "$RUNDIR" - ( echo "Starting dockerd" set -x exec dockerd \\ - --debug \\ --host="$DOCKER_HOST" \\ + --config-file="$DAEMON_CONFIG_PATH" \\ --exec-root="$RUNDIR/execroot" \\ --data-root="$RUNDIR/data" \\ --pidfile="$RUNDIR/docker.pid" \\ + --iptables=false \\ + --ip6tables=false \\ + --ip-masq=false \\ --userland-proxy=false \\ 2>&1 | tee "$RUNDIR/dockerd.log" ) & + +sleep 3 `; export const setupDockerWinPs1Data = ` @@ -92,7 +94,10 @@ param( [string]$RunDir, [Parameter(Mandatory = $true)] - [string]$DockerHost) + [string]$DockerHost, + + [Parameter(Mandatory = $false)] + [string]$DaemonConfig) $pwver = (Get-ItemProperty -Path HKLM:\\SOFTWARE\\Microsoft\\PowerShell\\3\\PowerShellEngine -Name 'PowerShellVersion').PowerShellVersion Write-Host "PowerShell version: $pwver" @@ -120,6 +125,12 @@ if (Get-Service docker -ErrorAction SilentlyContinue) { $env:DOCKER_HOST = $DockerHost Write-Host "DOCKER_HOST: $env:DOCKER_HOST" +if ($DaemonConfig) { + Write-Host "Writing Docker daemon config" + New-Item -ItemType Directory -Force -Path "$env:ProgramData\\Docker\\config" + $DaemonConfig | Out-File -FilePath "$env:ProgramData\\Docker\\config\\daemon.json" +} + 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 @@ -246,7 +257,7 @@ forwardAgent: false # # Colima default behaviour: buildkit enabled # Default: {} -docker: {} +{{daemonConfig}} # Virtual Machine type (qemu, vz) # NOTE: this is macOS 13 only. For Linux and macOS <13.0, qemu is always used. diff --git a/src/docker/install.ts b/src/docker/install.ts index bd6c8197..35d35b50 100644 --- a/src/docker/install.ts +++ b/src/docker/install.ts @@ -19,6 +19,7 @@ import fs from 'fs'; import os from 'os'; import path from 'path'; import retry from 'async-retry'; +import yaml from 'js-yaml'; import * as handlebars from 'handlebars'; import * as util from 'util'; import * as core from '@actions/core'; @@ -37,6 +38,7 @@ export interface InstallOpts { channel?: string; runDir: string; contextName?: string; + daemonConfig?: string; } export class Install { @@ -44,6 +46,7 @@ export class Install { private readonly version: string; private readonly channel: string; private readonly contextName: string; + private readonly daemonConfig?: string; private _version: string | undefined; private _toolDir: string | undefined; @@ -52,6 +55,7 @@ export class Install { this.version = opts.version || 'latest'; this.channel = opts.channel || 'stable'; this.contextName = opts.contextName || 'setup-docker-action'; + this.daemonConfig = opts.daemonConfig; } get toolDir(): string { @@ -137,10 +141,15 @@ export class Install { } await core.group('Creating colima config', async () => { + let daemonConfig = yaml.dump({docker: {}}); + if (this.daemonConfig) { + daemonConfig = yaml.dump(yaml.load(JSON.stringify({docker: JSON.parse(this.daemonConfig)}))); + } const colimaCfg = handlebars.compile(colimaYamlData)({ hostArch: Install.platformArch(), dockerVersion: this._version, - dockerChannel: this.channel + dockerChannel: this.channel, + daemonConfig: daemonConfig }); core.info(`Writing colima config to ${path.join(colimaDir, 'colima.yaml')}`); fs.writeFileSync(path.join(colimaDir, 'colima.yaml'), colimaCfg); @@ -192,6 +201,29 @@ export class Install { const dockerHost = `unix://${path.join(this.runDir, 'docker.sock')}`; await io.mkdirP(this.runDir); + const daemonConfigPath = path.join(this.runDir, 'daemon.json'); + await fs.writeFileSync(daemonConfigPath, '{}'); + + let daemonConfig = undefined; + const daemonConfigDefaultPath = '/etc/docker/daemon.json'; + if (fs.existsSync(daemonConfigDefaultPath)) { + await core.group('Default Docker daemon config found', async () => { + core.info(JSON.stringify(fs.readFileSync(daemonConfigDefaultPath, {encoding: 'utf8'}), null, 2)); + }); + daemonConfig = JSON.parse(fs.readFileSync(daemonConfigDefaultPath, {encoding: 'utf8'})); + } + if (this.daemonConfig) { + daemonConfig = Object.assign(daemonConfig || {}, JSON.parse(this.daemonConfig)); + } + + if (daemonConfig) { + const daemonConfigStr = JSON.stringify(daemonConfig, null, 2); + await core.group('Writing Docker daemon config', async () => { + fs.writeFileSync(daemonConfigPath, daemonConfigStr); + core.info(daemonConfigStr); + }); + } + await core.group('Start Docker daemon', async () => { const bashPath: string = await io.which('bash', true); const proc = await child_process.spawn(`sudo -E ${bashPath} ${setupDockerLinuxSh()}`, [], { @@ -201,6 +233,7 @@ export class Install { env: Object.assign({}, process.env, { TOOLDIR: this.toolDir, RUNDIR: this.runDir, + DAEMON_CONFIG_PATH: daemonConfigPath, DOCKER_HOST: dockerHost }) as { [key: string]: string; @@ -251,11 +284,32 @@ export class Install { private async installWindows(): Promise { const dockerHost = 'npipe:////./pipe/setup_docker_action'; + let daemonConfig = undefined; + const daemonConfigPath = path.join(this.runDir, 'daemon.json'); + if (fs.existsSync(daemonConfigPath)) { + await core.group('Default Docker daemon config found', async () => { + core.info(JSON.stringify(fs.readFileSync(daemonConfigPath, {encoding: 'utf8'}), null, 2)); + }); + daemonConfig = JSON.parse(fs.readFileSync(daemonConfigPath, {encoding: 'utf8'})); + } + if (this.daemonConfig) { + daemonConfig = Object.assign(daemonConfig || {}, JSON.parse(this.daemonConfig)); + } + + let daemonConfigStr = '{}'; + if (daemonConfig) { + daemonConfigStr = JSON.stringify(daemonConfig, null, 2); + await core.group('Docker daemon config', async () => { + core.info(daemonConfigStr); + }); + } + await core.group('Install Docker daemon service', async () => { const setupCmd = await Util.powershellCommand(setupDockerWinPs1(), { ToolDir: this.toolDir, RunDir: this.runDir, - DockerHost: dockerHost + DockerHost: dockerHost, + DaemonConfig: daemonConfigStr }); await Exec.exec(setupCmd.command, setupCmd.args); const logCmd = await Util.powershellCommand(dockerServiceLogsPs1()); diff --git a/yarn.lock b/yarn.lock index b5000abb..c5c5cabb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -974,6 +974,7 @@ __metadata: "@actions/tool-cache": ^2.0.1 "@octokit/plugin-rest-endpoint-methods": ^7.2.3 "@types/csv-parse": ^1.2.2 + "@types/js-yaml": ^4.0.5 "@types/node": ^16.18.21 "@types/semver": ^7.5.0 "@types/tmp": ^0.2.3 @@ -990,6 +991,7 @@ __metadata: eslint-plugin-prettier: ^4.2.1 handlebars: ^4.7.8 jest: ^29.5.0 + js-yaml: ^4.1.0 jwt-decode: ^3.1.2 prettier: ^2.8.7 rimraf: ^4.4.1 @@ -1825,6 +1827,13 @@ __metadata: languageName: node linkType: hard +"@types/js-yaml@npm:^4.0.5": + version: 4.0.5 + resolution: "@types/js-yaml@npm:4.0.5" + checksum: 7dcac8c50fec31643cc9d6444b5503239a861414cdfaa7ae9a38bc22597c4d850c4b8cec3d82d73b3fbca408348ce223b0408d598b32e094470dfffc6d486b4d + languageName: node + linkType: hard + "@types/json-schema@npm:^7.0.9": version: 7.0.9 resolution: "@types/json-schema@npm:7.0.9"