Skip to content

Commit 1d49775

Browse files
authored
Merge pull request #531 from crazy-max/docker-install-local-tcp
docker(install): opt to expose local tcp address
2 parents ba72b5a + 51e6621 commit 1d49775

File tree

4 files changed

+105
-32
lines changed

4 files changed

+105
-32
lines changed

.github/workflows/test.yml

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -103,12 +103,18 @@ jobs:
103103
let includes = [];
104104
for (const os of ['ubuntu-latest', 'macos-13', 'windows-latest']) {
105105
for (const test of tests) {
106-
if (os === 'macos-13' && test === 'docker/install.test.itg.ts') {
107-
includes.push({ os: os, test: test, docker_install_type: 'image', docker_install_version: '27.3.1' });
108-
includes.push({ os: os, test: test, docker_install_type: 'image', docker_install_version: 'master' });
109-
includes.push({ os: os, test: test, docker_install_type: 'image', docker_install_version: 'latest' });
110-
includes.push({ os: os, test: test, docker_install_type: 'archive', docker_install_version: 'v26.1.4' });
111-
includes.push({ os: os, test: test, docker_install_type: 'archive', docker_install_version: 'latest' });
106+
if (test === 'docker/install.test.itg.ts') {
107+
includes.push({ os: os, test: test, test_name: 'root', docker_install_type: 'image', docker_install_version: '27.3.1' });
108+
includes.push({ os: os, test: test, test_name: 'root', docker_install_type: 'image', docker_install_version: 'master' });
109+
includes.push({ os: os, test: test, test_name: 'root', docker_install_type: 'image', docker_install_version: 'latest' });
110+
includes.push({ os: os, test: test, test_name: 'root', docker_install_type: 'archive', docker_install_version: 'v26.1.4' });
111+
includes.push({ os: os, test: test, test_name: 'root', docker_install_type: 'archive', docker_install_version: 'latest' });
112+
if (os === 'ubuntu-latest') {
113+
includes.push({ os: os, test: test, test_name: 'rootless', docker_install_type: 'image', docker_install_version: 'latest' });
114+
includes.push({ os: os, test: test, test_name: 'rootless', docker_install_type: 'archive', docker_install_version: 'latest' });
115+
}
116+
includes.push({ os: os, test: test, test_name: 'tcp', docker_install_type: 'image', docker_install_version: 'latest' });
117+
includes.push({ os: os, test: test, test_name: 'tcp', docker_install_type: 'archive', docker_install_version: 'latest' });
112118
} else {
113119
includes.push({ os: os, test: test });
114120
}
@@ -176,8 +182,16 @@ jobs:
176182
run: yarn install
177183
-
178184
name: Test
179-
run: |
180-
yarn test:itg-coverage --runTestsByPath __tests__/${{ matrix.test }} --coverageDirectory=./coverage
185+
uses: actions/github-script@v7
186+
with:
187+
script: |
188+
const testName = `${{ matrix.test_name }}`;
189+
let args = ['test:itg-coverage'];
190+
if (testName) {
191+
args.push(`--testNamePattern=^${testName} `);
192+
}
193+
args.push(`--runTestsByPath`, `__tests__/${{ matrix.test }}`, `--coverageDirectory=./coverage`);
194+
await exec.exec('yarn', args);
181195
env:
182196
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
183197
CTN_BUILDER_NAME: ${{ steps.builder.outputs.name }}

__tests__/docker/install.test.itg.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,36 @@ describe('rootless', () => {
6969
);
7070
});
7171

72+
describe('tcp', () => {
73+
// prettier-ignore
74+
test.each(getSources(false))(
75+
'install %s', async (source) => {
76+
await ensureNoSystemContainerd();
77+
const install = new Install({
78+
source: source,
79+
runDir: tmpDir(),
80+
contextName: 'foo',
81+
daemonConfig: `{"debug":true}`,
82+
localTCPPort: 2378
83+
});
84+
await expect(
85+
tryInstall(install, async () => {
86+
const out = await Docker.getExecOutput(['info'], {
87+
env: Object.assign({}, process.env, {
88+
DOCKER_HOST: 'tcp://localhost:2378',
89+
DOCKER_CONTENT_TRUST: 'false'
90+
}) as {
91+
[key: string]: string;
92+
}
93+
});
94+
expect(out.exitCode).toBe(0);
95+
})
96+
).resolves.not.toThrow();
97+
},
98+
30 * 60 * 1000
99+
);
100+
});
101+
72102
async function tryInstall(install: Install, extraCheck?: () => Promise<void>): Promise<void> {
73103
try {
74104
await install.download();

src/docker/assets.ts

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,10 @@ param(
5151
[string]$RunDir,
5252
5353
[Parameter(Mandatory = $true)]
54-
[string]$DockerHost,
54+
[string]$DockerHostSocket,
55+
56+
[Parameter(Mandatory = $false)]
57+
[string]$DockerHostTCP,
5558
5659
[Parameter(Mandatory = $false)]
5760
[string]$DaemonConfig)
@@ -82,7 +85,7 @@ if (Get-Service docker -ErrorAction SilentlyContinue) {
8285
$env:Path = "$ToolDir;" + [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")
8386
Write-Host "Path: $env:Path"
8487
85-
$env:DOCKER_HOST = $DockerHost
88+
$env:DOCKER_HOST = $DockerHostSocket
8689
Write-Host "DOCKER_HOST: $env:DOCKER_HOST"
8790
8891
if ($DaemonConfig) {
@@ -91,16 +94,21 @@ if ($DaemonConfig) {
9194
$DaemonConfig | Out-File -FilePath "$env:ProgramData\\Docker\\config\\daemon.json"
9295
}
9396
97+
$arguments = @(
98+
"--host=$DockerHostSocket",
99+
"--data-root=$RunDir\\\\moby-root",
100+
"--exec-root=$RunDir\\\\moby-exec",
101+
"--pidfile=$RunDir\\\\docker.pid",
102+
"--register-service"
103+
)
104+
if ($DockerHostTCP) {
105+
$arguments += "--host=$DockerHostTCP"
106+
}
107+
94108
Write-Host "Creating service"
95109
New-Item -ItemType Directory "$RunDir\\moby-root" -ErrorAction SilentlyContinue | Out-Null
96110
New-Item -ItemType Directory "$RunDir\\moby-exec" -ErrorAction SilentlyContinue | Out-Null
97-
Start-Process -Wait -NoNewWindow "$ToolDir\\dockerd" \`
98-
-ArgumentList \`
99-
"--host=$DockerHost", \`
100-
"--data-root=$RunDir\\moby-root", \`
101-
"--exec-root=$RunDir\\moby-exec", \`
102-
"--pidfile=$RunDir\\docker.pid", \`
103-
"--register-service"
111+
Start-Process -Wait -NoNewWindow "$ToolDir\\dockerd" -ArgumentList $arguments
104112
Write-Host "Starting service"
105113
Start-Service -Name docker
106114
Write-Host "Service started successfully!"
@@ -231,6 +239,11 @@ provision:
231239
export DEBIAN_FRONTEND=noninteractive
232240
if [ "{{srcType}}" == "archive" ]; then
233241
curl -fsSL https://get.docker.com | sh -s -- --channel {{srcArchiveChannel}} --version {{srcArchiveVersion}}
242+
sed -i 's|^ExecStart=.*|ExecStart=/usr/bin/dockerd -H fd://{{#if localTCPPort}} -H tcp://0.0.0.0:2375{{/if}} --containerd=/run/containerd/containerd.sock|' /usr/lib/systemd/system/docker.service
243+
systemctl daemon-reload
244+
systemctl restart docker
245+
systemctl status docker.socket || true
246+
systemctl status docker.service || true
234247
elif [ "{{srcType}}" == "image" ]; then
235248
arch=$(uname -m)
236249
case $arch in
@@ -250,7 +263,7 @@ provision:
250263
wget https://raw.githubusercontent.com/moby/moby/{{gitCommit}}/contrib/init/systemd/docker.socket \
251264
-O /etc/systemd/system/docker.socket
252265
253-
sed -i 's|^ExecStart=.*|ExecStart=/usr/local/bin/dockerd -H fd://|' /etc/systemd/system/docker.service
266+
sed -i 's|^ExecStart=.*|ExecStart=/usr/local/bin/dockerd -H fd://{{#if localTCPPort}} -H tcp://0.0.0.0:2375{{/if}}|' /etc/systemd/system/docker.service
254267
sed -i 's|containerd.service||' /etc/systemd/system/docker.service
255268
if ! getent group docker; then
256269
groupadd --system docker
@@ -285,6 +298,10 @@ hostResolver:
285298
portForwards:
286299
- guestSocket: "/var/run/docker.sock"
287300
hostSocket: "{{dockerSock}}"
301+
{{#if localTCPPort}}
302+
- guestPort: 2375
303+
hostPort: {{localTCPPort}}
304+
{{/if}}
288305
289306
audio:
290307
# EXPERIMENTAL

src/docker/install.ts

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ export interface InstallOpts {
5656
contextName?: string;
5757
daemonConfig?: string;
5858
rootless?: boolean;
59+
localTCPPort?: number;
5960
}
6061

6162
interface LimaImage {
@@ -65,28 +66,31 @@ interface LimaImage {
6566
}
6667

6768
export class Install {
68-
private runDir: string;
69+
private readonly runDir: string;
6970
private readonly source: InstallSource;
7071
private readonly contextName: string;
7172
private readonly daemonConfig?: string;
73+
private readonly rootless: boolean;
74+
private readonly localTCPPort?: number;
75+
7276
private _version: string | undefined;
7377
private _toolDir: string | undefined;
74-
private rootless: boolean;
7578

7679
private gitCommit: string | undefined;
7780

7881
private readonly limaInstanceName = 'docker-actions-toolkit';
7982

8083
constructor(opts: InstallOpts) {
8184
this.runDir = opts.runDir;
82-
this.rootless = opts.rootless || false;
8385
this.source = opts.source || {
8486
type: 'archive',
8587
version: 'latest',
8688
channel: 'stable'
8789
};
8890
this.contextName = opts.contextName || 'setup-docker-action';
8991
this.daemonConfig = opts.daemonConfig;
92+
this.rootless = opts.rootless || false;
93+
this.localTCPPort = opts.localTCPPort;
9094
}
9195

9296
get toolDir(): string {
@@ -268,6 +272,7 @@ export class Install {
268272
customImages: Install.limaCustomImages(),
269273
daemonConfig: limaDaemonConfig,
270274
dockerSock: `${limaDir}/docker.sock`,
275+
localTCPPort: this.localTCPPort,
271276
gitCommit: this.gitCommit,
272277
srcType: src.type,
273278
srcArchiveVersion: this._version, // Use the resolved version (e.g. latest -> 27.4.0)
@@ -376,8 +381,10 @@ export class Install {
376381
await Exec.exec('sudo', ['sh', '-c', 'echo 0 > /proc/sys/kernel/apparmor_restrict_unprivileged_userns']);
377382
}
378383
}
379-
380-
const cmd = `${dockerPath} --host="${dockerHost}" --config-file="${daemonConfigPath}" --exec-root="${this.runDir}/execroot" --data-root="${this.runDir}/data" --pidfile="${this.runDir}/docker.pid"`;
384+
let cmd = `${dockerPath} --host="${dockerHost}" --config-file="${daemonConfigPath}" --exec-root="${this.runDir}/execroot" --data-root="${this.runDir}/data" --pidfile="${this.runDir}/docker.pid"`;
385+
if (this.localTCPPort) {
386+
cmd += ` --host="tcp://127.0.0.1:${this.localTCPPort}"`;
387+
}
381388
core.info(`[command] ${cmd}`); // https://github.com/actions/toolkit/blob/3d652d3133965f63309e4b2e1c8852cdbdcb3833/packages/exec/src/toolrunner.ts#L47
382389
let sudo = 'sudo';
383390
if (this.rootless) {
@@ -438,7 +445,7 @@ EOF`,
438445
}
439446

440447
private async installWindows(): Promise<string> {
441-
const dockerHost = 'npipe:////./pipe/setup_docker_action';
448+
const dockerHostSocket = 'npipe:////./pipe/setup_docker_action';
442449

443450
let daemonConfig = undefined;
444451
const daemonConfigPath = path.join(this.runDir, 'daemon.json');
@@ -460,24 +467,29 @@ EOF`,
460467
});
461468
}
462469

470+
const params = {
471+
ToolDir: this.toolDir,
472+
RunDir: this.runDir,
473+
DockerHostSocket: dockerHostSocket,
474+
DaemonConfig: daemonConfigStr
475+
};
476+
if (this.localTCPPort) {
477+
params['DockerHostTCP'] = `tcp://127.0.0.1:${this.localTCPPort}`;
478+
}
479+
463480
await core.group('Install Docker daemon service', async () => {
464-
const setupCmd = await Util.powershellCommand(setupDockerWinPs1(), {
465-
ToolDir: this.toolDir,
466-
RunDir: this.runDir,
467-
DockerHost: dockerHost,
468-
DaemonConfig: daemonConfigStr
469-
});
481+
const setupCmd = await Util.powershellCommand(setupDockerWinPs1(), params);
470482
await Exec.exec(setupCmd.command, setupCmd.args);
471483
const logCmd = await Util.powershellCommand(dockerServiceLogsPs1());
472484
await Exec.exec(logCmd.command, logCmd.args);
473485
});
474486

475487
await core.group('Create Docker context', async () => {
476-
await Docker.exec(['context', 'create', this.contextName, '--docker', `host=${dockerHost}`]);
488+
await Docker.exec(['context', 'create', this.contextName, '--docker', `host=${dockerHostSocket}`]);
477489
await Docker.exec(['context', 'use', this.contextName]);
478490
});
479491

480-
return dockerHost;
492+
return dockerHostSocket;
481493
}
482494

483495
public async tearDown(): Promise<void> {

0 commit comments

Comments
 (0)