docker: custom colima cfg on install

Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
This commit is contained in:
CrazyMax 2023-02-27 09:59:45 +01:00
parent 4d66b2fa08
commit 3ec6f00f46
No known key found for this signature in database
GPG Key ID: 3248E46B6BB8C7F7
6 changed files with 282 additions and 30 deletions

View File

@ -26,7 +26,7 @@ describe('install', () => {
await expect((async () => { await expect((async () => {
const install = new Install(); const install = new Install();
const toolPath = await install.download(version); const toolPath = await install.download(version);
await install.install(toolPath); await install.install(toolPath, version);
await Docker.printVersion(); await Docker.printVersion();
await Docker.printInfo(); await Docker.printInfo();
})()).resolves.not.toThrow(); })()).resolves.not.toThrow();

View File

@ -51,6 +51,7 @@
"@actions/io": "^1.1.2", "@actions/io": "^1.1.2",
"@actions/tool-cache": "^2.0.1", "@actions/tool-cache": "^2.0.1",
"csv-parse": "^5.3.5", "csv-parse": "^5.3.5",
"handlebars": "^4.7.7",
"jwt-decode": "^3.1.2", "jwt-decode": "^3.1.2",
"semver": "^7.3.8", "semver": "^7.3.8",
"tmp": "^0.2.1" "tmp": "^0.2.1"

175
scripts/colima.yaml Normal file
View File

@ -0,0 +1,175 @@
# Number of CPUs to be allocated to the virtual machine.
# Default: 2
cpu: 2
# Size of the disk in GiB to be allocated to the virtual machine.
# NOTE: changing this has no effect after the virtual machine has been created.
# Default: 60
disk: 60
# Size of the memory in GiB to be allocated to the virtual machine.
# Default: 2
memory: 2
# Architecture of the virtual machine (x86_64, aarch64, host).
# Default: host
arch: host
# Container runtime to be used (docker, containerd).
# Default: docker
runtime: docker
# Kubernetes configuration for the virtual machine.
kubernetes:
enabled: false
# Auto-activate on the Host for client access.
# Setting to true does the following on startup
# - sets as active Docker context (for Docker runtime).
# - sets as active Kubernetes context (if Kubernetes is enabled).
# Default: true
autoActivate: false
# Network configurations for the virtual machine.
network:
# Assign reachable IP address to the virtual machine.
# NOTE: this is currently macOS only and ignored on Linux.
# Default: false
address: false
# Custom DNS resolvers for the virtual machine.
#
# EXAMPLE
# dns: [8.8.8.8, 1.1.1.1]
#
# Default: []
dns: []
# DNS hostnames to resolve to custom targets using the internal resolver.
# This setting has no effect if a custom DNS resolver list is supplied above.
# It does not configure the /etc/hosts files of any machine or container.
# The value can be an IP address or another host.
#
# EXAMPLE
# dnsHosts:
# example.com: 1.2.3.4
dnsHosts:
host.docker.internal: host.lima.internal
# Network driver to use (slirp, gvproxy), (requires vmType `qemu`)
# - slirp is the default user mode networking provided by Qemu
# - gvproxy is an alternative to VPNKit based on gVisor https://github.com/containers/gvisor-tap-vsock
# Default: gvproxy
driver: gvproxy
# Forward the host's SSH agent to the virtual machine.
# Default: false
forwardAgent: false
# Docker daemon configuration that maps directly to daemon.json.
# https://docs.docker.com/engine/reference/commandline/dockerd/#daemon-configuration-file.
# NOTE: some settings may affect Colima's ability to start docker. e.g. `hosts`.
#
# EXAMPLE - disable buildkit
# docker:
# features:
# buildkit: false
#
# EXAMPLE - add insecure registries
# docker:
# insecure-registries:
# - myregistry.com:5000
# - host.docker.internal:5000
#
# Colima default behaviour: buildkit enabled
# Default: {}
docker: {}
# Virtual Machine type (qemu, vz)
# NOTE: this is macOS 13 only. For Linux and macOS <13.0, qemu is always used.
#
# vz is macOS virtualization framework and requires macOS 13
#
# Default: qemu
vmType: qemu
# Volume mount driver for the virtual machine (virtiofs, 9p, sshfs).
#
# virtiofs is limited to macOS and vmType `vz`. It is the fastest of the options.
#
# 9p is the recommended and the most stable option for vmType `qemu`.
#
# sshfs is faster than 9p but the least reliable of the options (when there are lots
# of concurrent reads or writes).
#
# Default: virtiofs (for vz), sshfs (for qemu)
mountType: 9p
# The CPU type for the virtual machine (requires vmType `qemu`).
# Options available for host emulation can be checked with: `qemu-system-$(arch) -cpu help`.
# Instructions are also supported by appending to the cpu type e.g. "qemu64,+ssse3".
# Default: host
cpuType: host
# For a more general purpose virtual machine, Ubuntu container is optionally provided
# as a layer on the virtual machine.
# The underlying virtual machine is still accessible via `colima ssh --layer=false` or running `colima` in
# the Ubuntu session.
#
# Default: false
layer: false
# Custom provision scripts for the virtual machine.
# Provisioning scripts are executed on startup and therefore needs to be idempotent.
#
# EXAMPLE - script exected as root
# provision:
# - mode: system
# script: apk add htop vim
#
# EXAMPLE - script exected as user
# provision:
# - mode: user
# script: |
# [ -f ~/.provision ] && exit 0;
# echo provisioning as $USER...
# touch ~/.provision
#
# Default: []
provision:
- mode: system
script: |
mkdir -p /tmp/docker-bins
cd /tmp/docker-bins
wget -qO- "https://download.docker.com/linux/static/{{dockerChannel}}/{{hostArch}}/docker-{{dockerVersion}}.tgz" | tar xvz --strip 1
mv -f /tmp/docker-bins/* /usr/bin/
# Modify ~/.ssh/config automatically to include a SSH config for the virtual machine.
# SSH config will still be generated in ~/.colima/ssh_config regardless.
# Default: true
sshConfig: false
# Configure volume mounts for the virtual machine.
# Colima mounts user's home directory by default to provide a familiar
# user experience.
#
# EXAMPLE
# mounts:
# - location: ~/secrets
# writable: false
# - location: ~/projects
# writable: true
#
# Colima default behaviour: $HOME and /tmp/colima are mounted as writable.
# Default: []
mounts: []
# Environment variables for the virtual machine.
#
# EXAMPLE
# env:
# KEY: value
# ANOTHER_KEY: another value
#
# Default: {}
env: {}

View File

@ -17,10 +17,11 @@
import fs from 'fs'; import fs from 'fs';
import os from 'os'; import os from 'os';
import path from 'path'; import path from 'path';
import * as handlebars from 'handlebars';
import * as util from 'util';
import * as core from '@actions/core'; import * as core from '@actions/core';
import * as io from '@actions/io'; import * as io from '@actions/io';
import * as tc from '@actions/tool-cache'; import * as tc from '@actions/tool-cache';
import * as util from 'util';
import * as scripts from '../scripts'; import * as scripts from '../scripts';
import {Context} from '../context'; import {Context} from '../context';
@ -64,10 +65,11 @@ export class Install {
return tooldir; return tooldir;
} }
public async install(toolDir: string): Promise<void> { public async install(toolDir: string, version: string, channel?: string): Promise<void> {
channel = channel || 'stable';
switch (os.platform()) { switch (os.platform()) {
case 'darwin': { case 'darwin': {
await this.installDarwin(toolDir); await this.installDarwin(toolDir, version, channel);
break; break;
} }
case 'linux': { case 'linux': {
@ -84,12 +86,33 @@ export class Install {
} }
} }
private async installDarwin(toolDir: string): Promise<void> { private async installDarwin(toolDir: string, version: string, channel?: string): Promise<void> {
const colimaDir = path.join(os.homedir(), '.colima', 'default');
await io.mkdirP(colimaDir);
const dockerHost = `unix://${colimaDir}/docker.sock`;
if (!(await Install.colimaInstalled())) { if (!(await Install.colimaInstalled())) {
await core.group('Installing colima', async () => { await core.group('Installing colima', async () => {
await Exec.exec('brew', ['install', 'colima']); await Exec.exec('brew', ['install', 'colima']);
}); });
} }
await core.group('Creating colima config', async () => {
const colimaCfg = handlebars.compile(
fs.readFileSync(scripts.colimaConfig, {
encoding: 'utf8',
flag: 'r'
})
)({
hostArch: Install.platformArch(),
dockerVersion: version,
dockerChannel: channel
});
core.info(`Writing colima config to ${path.join(colimaDir, 'colima.yaml')}`);
fs.writeFileSync(path.join(colimaDir, 'colima.yaml'), colimaCfg);
core.info(colimaCfg);
});
// colima is already started on the runner so env var added in download // colima is already started on the runner so env var added in download
// method is not expanded to the running process. // method is not expanded to the running process.
const envs = Object.assign({}, process.env, { const envs = Object.assign({}, process.env, {
@ -98,7 +121,12 @@ export class Install {
[key: string]: string; [key: string]: string;
}; };
await core.group('Starting colima', async () => { await core.group('Starting colima', async () => {
await Exec.exec('colima', ['start', '--runtime', 'docker', '--mount-type', '9p'], {env: envs}); await Exec.exec('colima', ['start', '--very-verbose'], {env: envs});
});
await core.group('Create Docker context', async () => {
await Exec.exec('docker', ['context', 'create', 'setup-docker-action', '--docker', `host=${dockerHost}`]);
await Exec.exec('docker', ['context', 'use', 'setup-docker-action']);
}); });
} }
@ -109,6 +137,7 @@ export class Install {
private async installWindows(toolDir: string): Promise<void> { private async installWindows(toolDir: string): Promise<void> {
const dockerHost = 'npipe:////./pipe/setup_docker_action'; const dockerHost = 'npipe:////./pipe/setup_docker_action';
const setupCmd = await Util.powershellCommand(scripts.setupDockerPowershell, { const setupCmd = await Util.powershellCommand(scripts.setupDockerPowershell, {
ToolDir: toolDir, ToolDir: toolDir,
TmpDir: Context.tmpDir(), TmpDir: Context.tmpDir(),
@ -117,6 +146,7 @@ export class Install {
await core.group('Install Docker daemon service', async () => { await core.group('Install Docker daemon service', async () => {
await Exec.exec(setupCmd.command, setupCmd.args); await Exec.exec(setupCmd.command, setupCmd.args);
}); });
await core.group('Create Docker context', async () => { await core.group('Create Docker context', async () => {
await Exec.exec('docker', ['context', 'create', 'setup-docker-action', '--docker', `host=${dockerHost}`]); await Exec.exec('docker', ['context', 'create', 'setup-docker-action', '--docker', `host=${dockerHost}`]);
await Exec.exec('docker', ['context', 'use', 'setup-docker-action']); await Exec.exec('docker', ['context', 'use', 'setup-docker-action']);
@ -124,60 +154,56 @@ export class Install {
} }
private downloadURL(version: string, channel: string): string { private downloadURL(version: string, channel: string): string {
let platformOS, platformArch: string; const platformOS = Install.platformOS();
const platformArch = Install.platformArch();
const ext = platformOS === 'win' ? '.zip' : '.tgz';
return util.format('https://download.docker.com/%s/static/%s/%s/docker-%s%s', platformOS, channel, platformArch, version, ext);
}
private static platformOS(): string {
switch (os.platform()) { switch (os.platform()) {
case 'darwin': { case 'darwin': {
platformOS = 'mac'; return 'mac';
break;
} }
case 'linux': { case 'linux': {
platformOS = 'linux'; return 'linux';
break;
} }
case 'win32': { case 'win32': {
platformOS = 'win'; return 'win';
break;
} }
default: { default: {
platformOS = os.platform(); return os.platform();
break;
} }
} }
}
private static platformArch(): string {
switch (os.arch()) { switch (os.arch()) {
case 'x64': { case 'x64': {
platformArch = 'x86_64'; return 'x86_64';
break;
} }
case 'ppc64': { case 'ppc64': {
platformArch = 'ppc64le'; return 'ppc64le';
break;
} }
case 'arm': { case 'arm': {
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
const arm_version = (process.config.variables as any).arm_version; const arm_version = (process.config.variables as any).arm_version;
switch (arm_version) { switch (arm_version) {
case 6: { case 6: {
platformArch = 'armel'; return 'armel';
break;
} }
case 7: { case 7: {
platformArch = 'armhf'; return 'armhf';
break;
} }
default: { default: {
platformArch = `v${arm_version}`; return `v${arm_version}`;
break;
} }
} }
break;
} }
default: { default: {
platformArch = os.arch(); return os.arch();
break;
} }
} }
const ext = platformOS === 'win' ? '.zip' : '.tgz';
return util.format('https://download.docker.com/%s/static/%s/%s/docker-%s%s', platformOS, channel, platformArch, version, ext);
} }
private static async colimaInstalled(): Promise<boolean> { private static async colimaInstalled(): Promise<boolean> {

View File

@ -19,3 +19,4 @@ import path from 'path';
const scriptsPath = path.join(__dirname, '..', 'scripts'); const scriptsPath = path.join(__dirname, '..', 'scripts');
export const setupDockerPowershell = path.join(scriptsPath, 'setup-docker.ps1'); export const setupDockerPowershell = path.join(scriptsPath, 'setup-docker.ps1');
export const colimaConfig = path.join(scriptsPath, 'colima.yaml');

View File

@ -782,6 +782,7 @@ __metadata:
eslint-plugin-import: ^2.27.5 eslint-plugin-import: ^2.27.5
eslint-plugin-jest: ^26.9.0 eslint-plugin-jest: ^26.9.0
eslint-plugin-prettier: ^4.2.1 eslint-plugin-prettier: ^4.2.1
handlebars: ^4.7.7
jest: ^27.5.1 jest: ^27.5.1
jwt-decode: ^3.1.2 jwt-decode: ^3.1.2
prettier: ^2.8.3 prettier: ^2.8.3
@ -3667,6 +3668,24 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"handlebars@npm:^4.7.7":
version: 4.7.7
resolution: "handlebars@npm:4.7.7"
dependencies:
minimist: ^1.2.5
neo-async: ^2.6.0
source-map: ^0.6.1
uglify-js: ^3.1.4
wordwrap: ^1.0.0
dependenciesMeta:
uglify-js:
optional: true
bin:
handlebars: bin/handlebars
checksum: 1e79a43f5e18d15742977cb987923eab3e2a8f44f2d9d340982bcb69e1735ed049226e534d7c1074eaddaf37e4fb4f471a8adb71cddd5bc8cf3f894241df5cee
languageName: node
linkType: hard
"hard-rejection@npm:^2.1.0": "hard-rejection@npm:^2.1.0":
version: 2.1.0 version: 2.1.0
resolution: "hard-rejection@npm:2.1.0" resolution: "hard-rejection@npm:2.1.0"
@ -5144,6 +5163,13 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"minimist@npm:^1.2.5":
version: 1.2.8
resolution: "minimist@npm:1.2.8"
checksum: 75a6d645fb122dad29c06a7597bddea977258957ed88d7a6df59b5cd3fe4a527e253e9bbf2e783e4b73657f9098b96a5fe96ab8a113655d4109108577ecf85b0
languageName: node
linkType: hard
"minipass-collect@npm:^1.0.2": "minipass-collect@npm:^1.0.2":
version: 1.0.2 version: 1.0.2
resolution: "minipass-collect@npm:1.0.2" resolution: "minipass-collect@npm:1.0.2"
@ -5267,6 +5293,13 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"neo-async@npm:^2.6.0":
version: 2.6.2
resolution: "neo-async@npm:2.6.2"
checksum: deac9f8d00eda7b2e5cd1b2549e26e10a0faa70adaa6fdadca701cc55f49ee9018e427f424bac0c790b7c7e2d3068db97f3093f1093975f2acb8f8818b936ed9
languageName: node
linkType: hard
"nested-error-stacks@npm:^2.0.0, nested-error-stacks@npm:^2.1.0": "nested-error-stacks@npm:^2.0.0, nested-error-stacks@npm:^2.1.0":
version: 2.1.1 version: 2.1.1
resolution: "nested-error-stacks@npm:2.1.1" resolution: "nested-error-stacks@npm:2.1.1"
@ -6694,6 +6727,15 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"uglify-js@npm:^3.1.4":
version: 3.17.4
resolution: "uglify-js@npm:3.17.4"
bin:
uglifyjs: bin/uglifyjs
checksum: 7b3897df38b6fc7d7d9f4dcd658599d81aa2b1fb0d074829dd4e5290f7318dbca1f4af2f45acb833b95b1fe0ed4698662ab61b87e94328eb4c0a0d3435baf924
languageName: node
linkType: hard
"unbox-primitive@npm:^1.0.2": "unbox-primitive@npm:^1.0.2":
version: 1.0.2 version: 1.0.2
resolution: "unbox-primitive@npm:1.0.2" resolution: "unbox-primitive@npm:1.0.2"
@ -6939,6 +6981,13 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"wordwrap@npm:^1.0.0":
version: 1.0.0
resolution: "wordwrap@npm:1.0.0"
checksum: 2a44b2788165d0a3de71fd517d4880a8e20ea3a82c080ce46e294f0b68b69a2e49cff5f99c600e275c698a90d12c5ea32aff06c311f0db2eb3f1201f3e7b2a04
languageName: node
linkType: hard
"wrap-ansi@npm:^7.0.0": "wrap-ansi@npm:^7.0.0":
version: 7.0.0 version: 7.0.0
resolution: "wrap-ansi@npm:7.0.0" resolution: "wrap-ansi@npm:7.0.0"