Skip to content

Commit

Permalink
NO-ISSUE support publish ports and set default net to bridge in docke…
Browse files Browse the repository at this point in the history
…r desktop
  • Loading branch information
Michael Levy authored and eranco74 committed Feb 25, 2021
1 parent bb3f746 commit 71da9f7
Show file tree
Hide file tree
Showing 7 changed files with 395 additions and 152 deletions.
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,17 @@ Using the above configuration file, we now can run a simplified version of the m
skipper make tests
```

### Published ports
For `shell`, `run` & `make` commands:
By default, when you run skipper on a linux machine it will use the host network and no mapping required.
For macos and windows machines where the host network is unsupported or for a custom network, you can publish a port and make it available to services outside of the container using the --publish or -p flag.

````
skipper make -p 123:123 tests
skipper make -p 123-130:123-130 tests
````


### Environment variables:
For `shell`, `run` & `make` commands:
You can use `-e` in order to pass environment variables to the container.
Expand Down
50 changes: 46 additions & 4 deletions skipper/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import os.path
import sys

from re import compile as compile_expression
import click
import six
import tabulate
Expand All @@ -18,12 +19,47 @@
DOCKER_TAG_FOR_CACHE = "cache"


def _validate_publish(ctx, param, value):
# pylint: disable=unused-argument
if value:
matcher = compile_expression(r'^((\d+)(-(\d+))?):((\d+)(-(\d+))?)$')

for port_mapping in value:
_validate_port(matcher, port_mapping)

return value


def _validate_port(matcher, port_forwarding):
match = matcher.match(port_forwarding)
if not match:
raise click.BadParameter("Publish need to be in format port:port or port-port:port-port")

host_port_start_range, host_port_end_range, container_port_start_range, container_port_end_range = match.group(2, 4, 6, 8)
_validate_port_out_of_range(host_port_start_range)
_validate_port_out_of_range(host_port_end_range)
_validate_port_out_of_range(container_port_start_range)
_validate_port_out_of_range(container_port_end_range)
_validate_port_range(host_port_start_range, host_port_end_range)
_validate_port_range(container_port_start_range, container_port_end_range)


def _validate_port_range(start, end):
if start and end and end < start:
raise click.BadParameter("Invalid port range: {0} should be bigger than {1}".format(start, end))


def _validate_port_out_of_range(port):
if port and not 1 <= int(port) <= 65535:
raise click.BadParameter("Invalid port number: port {0} is out of range".format(port))


@click.group()
@click.option('-v', '--verbose', help='Increase verbosity', is_flag=True, default=False)
@click.option('--registry', help='URL of the docker registry')
@click.option('--build-container-image', help='Image to use as build container')
@click.option('--build-container-tag', help='Tag of the build container')
@click.option('--build-container-net', help='Network to connect the build container', default='host')
@click.option('--build-container-net', help='Network to connect the build container')
@click.option('--env-file', help='Environment variable file to load')
@click.pass_context
def cli(ctx, registry, build_container_image, build_container_tag, build_container_net, verbose, env_file):
Expand Down Expand Up @@ -209,9 +245,10 @@ def rmi(ctx, remote, image, tag):
@click.option('-n', '--name', help='Container name', default=None)
@click.option('-e', '--env', multiple=True, help='Environment variables to pass the container')
@click.option('-c', '--cache', help='Use cache image', is_flag=True, default=False, envvar='SKIPPER_USE_CACHE_IMAGE')
@click.option('-p', '--publish', multiple=True, help="Publish a port", callback=_validate_publish)
@click.argument('command', nargs=-1, type=click.UNPROCESSED, required=True)
@click.pass_context
def run(ctx, interactive, name, env, cache, command):
def run(ctx, interactive, name, env, publish, cache, command):
"""
Run arbitrary commands
"""
Expand All @@ -231,6 +268,7 @@ def run(ctx, interactive, name, env, cache, command):
interactive=interactive,
name=name,
net=ctx.obj['build_container_net'],
publish=publish,
volumes=ctx.obj.get('volumes'),
workdir=ctx.obj.get('workdir'),
use_cache=cache,
Expand All @@ -244,9 +282,10 @@ def run(ctx, interactive, name, env, cache, command):
@click.option('-e', '--env', multiple=True, help='Environment variables to pass the container')
@click.option('-f', 'makefile', help='Makefile to use', default='Makefile')
@click.option('-c', '--cache', help='Use cache image', is_flag=True, default=False, envvar='SKIPPER_USE_CACHE_IMAGE')
@click.option('-p', '--publish', multiple=True, help="Publish a port", callback=_validate_publish)
@click.argument('make_params', nargs=-1, type=click.UNPROCESSED, required=False)
@click.pass_context
def make(ctx, interactive, name, env, makefile, cache, make_params):
def make(ctx, interactive, name, env, makefile, cache, publish, make_params):
"""
Execute makefile target(s)
"""
Expand All @@ -267,6 +306,7 @@ def make(ctx, interactive, name, env, makefile, cache, make_params):
interactive=interactive,
name=name,
net=ctx.obj['build_container_net'],
publish=publish,
volumes=ctx.obj.get('volumes'),
workdir=ctx.obj.get('workdir'),
use_cache=cache,
Expand All @@ -278,8 +318,9 @@ def make(ctx, interactive, name, env, makefile, cache, make_params):
@click.option('-e', '--env', multiple=True, help='Environment variables to pass the container')
@click.option('-n', '--name', help='Container name', default=None)
@click.option('-c', '--cache', help='Use cache image', is_flag=True, default=False, envvar='SKIPPER_USE_CACHE_IMAGE')
@click.option('-p', '--publish', multiple=True, help="Publish a port", callback=_validate_publish)
@click.pass_context
def shell(ctx, env, name, cache):
def shell(ctx, env, name, cache, publish):
"""
Start a shell
"""
Expand All @@ -299,6 +340,7 @@ def shell(ctx, env, name, cache):
interactive=True,
name=name,
net=ctx.obj['build_container_net'],
publish=publish,
volumes=ctx.obj.get('volumes'),
workdir=ctx.obj.get('workdir'),
use_cache=cache,
Expand Down
43 changes: 34 additions & 9 deletions skipper/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,21 @@
from skipper import utils


def get_default_net():
# The host networking driver only works on Linux hosts, and is not supported on Docker Desktop for Mac,
# Docker Desktop for Windows, or Docker EE for Windows Server.
return 'host' if sys.platform != 'darwin' and sys.platform != 'win32' else 'bridge'


# pylint: disable=too-many-arguments
def run(command, fqdn_image=None, environment=None, interactive=False, name=None, net='host', volumes=None,
def run(command, fqdn_image=None, environment=None, interactive=False, name=None, net=None, publish=(), volumes=None,
workdir=None, use_cache=False, workspace=None, env_file=None):

if not net:
net = get_default_net()

if fqdn_image is not None:
return _run_nested(fqdn_image, environment, command, interactive, name, net, volumes,
return _run_nested(fqdn_image, environment, command, interactive, name, net, publish, volumes,
workdir, use_cache, workspace, env_file)

return _run(command)
Expand All @@ -31,8 +41,7 @@ def _run(cmd_args):

# pylint: disable=too-many-locals
# pylint: disable=too-many-arguments
def _run_nested(fqdn_image, environment, command, interactive, name, net,
volumes, workdir, use_cache, workspace, env_file):
def _run_nested(fqdn_image, environment, command, interactive, name, net, publish, volumes, workdir, use_cache, workspace, env_file):
cwd = os.getcwd()
if workspace is None:
workspace = os.path.dirname(cwd)
Expand All @@ -53,7 +62,7 @@ def _run_nested(fqdn_image, environment, command, interactive, name, net,

cmd += ['--privileged']

cmd += ['--net', net]
cmd = handle_networking(cmd, publish, net)

if env_file:
cmd += ['--env-file', env_file]
Expand All @@ -80,10 +89,7 @@ def _run_nested(fqdn_image, environment, command, interactive, name, net,

cmd = handle_volumes_bind_mount(cmd, homedir, volumes, workspace)

if workdir:
cmd += ['-w', workdir]
else:
cmd += ['-w', '%(workdir)s' % dict(workdir=cwd)]
cmd = handle_workdir(cmd, cwd, workdir)

cmd += ['--entrypoint', '/opt/skipper/skipper-entrypoint.sh']
cmd += [fqdn_image]
Expand All @@ -95,6 +101,25 @@ def _run_nested(fqdn_image, environment, command, interactive, name, net,
return ret


def handle_workdir(cmd, cwd, workdir):
if workdir:
cmd += ['-w', workdir]
else:
cmd += ['-w', '%(workdir)s' % dict(workdir=cwd)]
return cmd


def handle_networking(cmd, publish, net):
if publish:
for port_mapping in publish:
cmd += ['-p', port_mapping]

if net is not None:
cmd += ['--net', net]

return cmd


def handle_volumes_bind_mount(docker_cmd, homedir, volumes, workspace):
volumes = volumes or []
volumes.extend(['%(homedir)s/.netrc:%(homedir)s/.netrc:ro' % dict(homedir=homedir),
Expand Down
Loading

0 comments on commit 71da9f7

Please sign in to comment.