Commit 3874cbb1 authored by Michał Kępień's avatar Michał Kępień

Merge branch 'michal/add-an-executor-for-docker-on-windows' into 'main'

Add an executor for Docker on Windows

See merge request !6
parents 4e69dde3 9ada3335
Pipeline #55920 passed with stage
in 9 seconds
image: registry.gitlab.isc.org/isc-projects/images/bind9:debian-sid-amd64
shellcheck:
.test_job: &test_job
stage: test
tags:
- amd64
- docker
- linux
flake8:
<<: *test_job
image: registry.gitlab.isc.org/isc-projects/images/bind9:debian-buster-amd64
script:
- find . -name "*.py" -execdir flake8 {} +
pylint:
<<: *test_job
image: registry.gitlab.isc.org/isc-projects/images/bind9:debian-buster-amd64
script:
- find . -name "*.py" -execdir pylint {} +
shellcheck:
<<: *test_job
image: registry.gitlab.isc.org/isc-projects/images/bind9:debian-sid-amd64
script:
- find . -name "*.sh" -execdir shellcheck -x {} +
# GitLab Runner Custom Executor for Docker on Windows
## Overview
This Python script allows GitLab CI jobs to be run inside Docker
containers on Windows Server systems which are [not supported][1] by the
native Docker executor included in GitLab Runner.
## Prerequisites
- [GitLab Runner][2]
- [Docker][3]
- [Python 3.6+][4]
## Installation
- Register a new GitLab CI runner using `gitlab-runner.exe register`,
specifying `custom` as the executor to use.
- Adjust the relevant section of GitLab Runner's `config.toml` so
that the executor gets invoked properly:
```toml
shell = "powershell"
[runners.custom]
config_exec = "C:\\path\\to\\python\\python.exe"
config_args = [ "C:\\path\\to\\windows-docker\\executor.py", "config" ]
prepare_exec = "C:\\path\\to\\python\\python.exe"
prepare_args = [ "C:\\path\\to\\windows-docker\\executor.py", "prepare" ]
run_exec = "C:\\path\\to\\python\\python.exe"
run_args = [ "C:\\path\\to\\windows-docker\\executor.py", "run" ]
cleanup_exec = "C:\\path\\to\\python\\python.exe"
cleanup_args = [ "C:\\path\\to\\windows-docker\\executor.py", "cleanup" ]
```
## Limitations
- Docker images are *not* automatically pulled or updated to the latest
available version during job setup. `docker pull` needs to be either
run manually or from the Windows Task Scheduler.
[1]: https://docs.gitlab.com/runner/executors/docker.html#supported-windows-versions
[2]: https://docs.gitlab.com/runner/install/windows.html
[3]: https://docs.microsoft.com/en-us/virtualization/windowscontainers/quick-start/set-up-environment
[4]: https://www.python.org/downloads/windows/
"""
executor.py - GitLab Runner Custom executor script for Docker on Windows
Written in 2020 by Michał Kępień <michal@isc.org>
To the extent possible under law, the author(s) have dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
You should have received a copy of the CC0 Public Domain Dedication along with
this software. If not, see http://creativecommons.org/publicdomain/zero/1.0/.
"""
import json
import os
import subprocess
import sys
DOCKER_PATH = 'C:\\Program Files\\Docker\\docker.exe'
def fatal_error(message):
"""
Print an error message to stderr and exit.
"""
print(message, file=sys.stderr)
sys.exit(1)
def docker_command(cmd):
"""
Invoke the given Docker command, exiting immediately if it fails.
"""
try:
subprocess.run([DOCKER_PATH] + cmd, check=True)
except subprocess.CalledProcessError:
sys.exit(1)
def do_config(*_):
"""
Perform the Config stage of a GitLab CI job.
"""
config = {
'builds_dir': 'C:\\builds',
'cache_dir': 'C:\\cache',
'builds_dir_is_shared': False,
}
print(json.dumps(config))
def do_prepare(container_name, _):
"""
Perform the Prepare stage of a GitLab CI job.
"""
docker_command(['run',
'--name', container_name,
'--interactive',
'--detach',
'--rm',
os.environ['CUSTOM_ENV_CI_JOB_IMAGE']])
def do_run(container_name, args):
"""
Perform the Run stage of a GitLab CI job.
"""
valid_stages = [
'prepare_script',
'get_sources',
'restore_cache',
'download_artifacts',
'build_script',
'step_script',
'after_script',
'archive_cache',
'upload_artifacts_on_success',
'upload_artifacts_on_failure',
]
script_src = args[0]
stage = args[1]
if stage not in valid_stages:
fatal_error(f'Unsupported run stage "{stage}"')
script_dst_path = f'C:\\{stage}.ps1'
script_dst = f'{container_name}:{script_dst_path}'
docker_command(['cp', script_src, script_dst])
docker_command(['exec', container_name, 'powershell.exe', script_dst_path])
def do_cleanup(container_name, _):
"""
Perform the Cleanup stage of a GitLab CI job.
"""
docker_command(['stop', container_name])
def main():
"""
Parse arguments and perform the requested stage of a GitLab CI job.
"""
actions = {
'config': do_config,
'prepare': do_prepare,
'run': do_run,
'cleanup': do_cleanup,
}
valid_actions = '|'.join(actions.keys())
try:
action = actions[sys.argv[1]]
except (IndexError, KeyError):
fatal_error(f'Usage: {sys.argv[0]} {valid_actions} [args...]')
container_name = 'gitlab-runner-' + os.environ['CUSTOM_ENV_CI_JOB_ID']
action(container_name, sys.argv[2:])
if __name__ == '__main__':
main()
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment