forked from cerc-io/stack-orchestrator
Host port mapping recipes (#521)
* Implement --map-ports-to-host feature
This commit is contained in:
parent
e89f7c9526
commit
f48f4978aa
@ -15,7 +15,7 @@ services:
|
|||||||
- "6060"
|
- "6060"
|
||||||
- "26657"
|
- "26657"
|
||||||
- "26656"
|
- "26656"
|
||||||
- "9473:9473"
|
- "9473"
|
||||||
- "8545"
|
- "8545"
|
||||||
- "8546"
|
- "8546"
|
||||||
- "9090"
|
- "9090"
|
||||||
|
@ -17,7 +17,7 @@ services:
|
|||||||
- "6060"
|
- "6060"
|
||||||
- "26657"
|
- "26657"
|
||||||
- "26656"
|
- "26656"
|
||||||
- "9473:9473"
|
- "9473"
|
||||||
- "8545"
|
- "8545"
|
||||||
- "8546"
|
- "8546"
|
||||||
- "9090"
|
- "9090"
|
||||||
|
@ -73,7 +73,7 @@ After deleting the volumes, any subsequent re-start will begin chain sync from c
|
|||||||
|
|
||||||
## Ports
|
## Ports
|
||||||
It is usually necessary to expose certain container ports on one or more the host's addresses to allow incoming connections.
|
It is usually necessary to expose certain container ports on one or more the host's addresses to allow incoming connections.
|
||||||
Any ports defined in the Docker compose file are exposed by default with random port assignments, but the values can be
|
Any ports defined in the Docker compose file are exposed by default with random port assignments, bound to "any" interface (IP address 0.0.0.0), but the port mappings can be
|
||||||
customized by editing the "spec" file generated by `laconic-so deploy init`.
|
customized by editing the "spec" file generated by `laconic-so deploy init`.
|
||||||
|
|
||||||
In this example, ports `8545` and `5052` have been assigned to a specific addresses/port combination on the host, while
|
In this example, ports `8545` and `5052` have been assigned to a specific addresses/port combination on the host, while
|
||||||
@ -92,7 +92,15 @@ volumes:
|
|||||||
mainnet_eth_geth_1_data: ./data/mainnet_eth_geth_1_data
|
mainnet_eth_geth_1_data: ./data/mainnet_eth_geth_1_data
|
||||||
mainnet_eth_lighthouse_1_data: ./data/mainnet_eth_lighthouse_1_data
|
mainnet_eth_lighthouse_1_data: ./data/mainnet_eth_lighthouse_1_data
|
||||||
```
|
```
|
||||||
|
In addition, a stack-wide port mapping "recipe" can be applied at the time the
|
||||||
|
`laconic-so deploy init` command is run, by supplying the desired recipe with the `--map-ports-to-host` option. The following recipes are supported:
|
||||||
|
| Recipe | Host Port Mapping |
|
||||||
|
|--------|-------------------|
|
||||||
|
| any-variable-random | Bind to 0.0.0.0 using a random port assigned at start time (default) |
|
||||||
|
| localhost-same | Bind to 127.0.0.1 using the same port number as exposed by the containers |
|
||||||
|
| any-same | Bind to 0.0.0.0 using the same port number as exposed by the containers |
|
||||||
|
| localhost-fixed-random | Bind to 127.0.0.1 using a random port number selected at the time the command is run (not checked for already in use)|
|
||||||
|
| any-fixed-random | Bind to 0.0.0.0 using a random port number selected at the time the command is run (not checked for already in use) |
|
||||||
## Data volumes
|
## Data volumes
|
||||||
Container data volumes are bind-mounted to specified paths in the host filesystem.
|
Container data volumes are bind-mounted to specified paths in the host filesystem.
|
||||||
The default setup (generated by `laconic-so deploy init`) places the volumes in the `./data` subdirectory of the deployment directory:
|
The default setup (generated by `laconic-so deploy init`) places the volumes in the `./data` subdirectory of the deployment directory:
|
||||||
|
@ -32,9 +32,6 @@ default_spec_file_content = """config:
|
|||||||
chain_id: my-chain-id
|
chain_id: my-chain-id
|
||||||
"""
|
"""
|
||||||
|
|
||||||
init_help_text = """Add helpful text here on setting config variables.
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
class SetupPhase(Enum):
|
class SetupPhase(Enum):
|
||||||
INITIALIZE = 1
|
INITIALIZE = 1
|
||||||
@ -275,7 +272,6 @@ def create(command_context: DeployCommandContext, extra_args):
|
|||||||
|
|
||||||
|
|
||||||
def init(command_context: DeployCommandContext):
|
def init(command_context: DeployCommandContext):
|
||||||
print(init_help_text)
|
|
||||||
yaml = get_yaml()
|
yaml = get_yaml()
|
||||||
return yaml.load(default_spec_file_content)
|
return yaml.load(default_spec_file_content)
|
||||||
|
|
||||||
|
@ -23,9 +23,6 @@ default_spec_file_content = """config:
|
|||||||
config_variable: test-value
|
config_variable: test-value
|
||||||
"""
|
"""
|
||||||
|
|
||||||
init_help_text = """Add helpful text here on setting config variables.
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
# Output a known string to a know file in the bind mounted directory ./container-output-dir
|
# Output a known string to a know file in the bind mounted directory ./container-output-dir
|
||||||
# for test purposes -- test checks that the file was written.
|
# for test purposes -- test checks that the file was written.
|
||||||
@ -40,7 +37,6 @@ def setup(command_context: DeployCommandContext, parameters, extra_args):
|
|||||||
|
|
||||||
|
|
||||||
def init(command_context: DeployCommandContext):
|
def init(command_context: DeployCommandContext):
|
||||||
print(init_help_text)
|
|
||||||
yaml = get_yaml()
|
yaml = get_yaml()
|
||||||
return yaml.load(default_spec_file_content)
|
return yaml.load(default_spec_file_content)
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@ import click
|
|||||||
from importlib import util
|
from importlib import util
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
import random
|
||||||
from shutil import copyfile, copytree
|
from shutil import copyfile, copytree
|
||||||
import sys
|
import sys
|
||||||
from app.util import get_stack_file_path, get_parsed_deployment_spec, get_parsed_stack_config, global_options, get_yaml
|
from app.util import get_stack_file_path, get_parsed_deployment_spec, get_parsed_stack_config, global_options, get_yaml
|
||||||
@ -166,10 +167,48 @@ def _find_extra_config_dirs(parsed_pod_file, pod):
|
|||||||
return config_dirs
|
return config_dirs
|
||||||
|
|
||||||
|
|
||||||
|
def _get_mapped_ports(stack: str, map_recipe: str):
|
||||||
|
port_map_recipes = ["any-variable-random", "localhost-same", "any-same", "localhost-fixed-random", "any-fixed-random"]
|
||||||
|
ports = _get_ports(stack)
|
||||||
|
if ports:
|
||||||
|
# Implement any requested mapping recipe
|
||||||
|
if map_recipe:
|
||||||
|
if map_recipe in port_map_recipes:
|
||||||
|
for service in ports.keys():
|
||||||
|
ports_array = ports[service]
|
||||||
|
for x in range(0, len(ports_array)):
|
||||||
|
orig_port = ports_array[x]
|
||||||
|
random_port = random.randint(20000,50000) # Beware: we're relying on luck to not collide
|
||||||
|
if map_recipe == "any-variable-random":
|
||||||
|
# This is the default so take no action
|
||||||
|
pass
|
||||||
|
elif map_recipe == "localhost-same":
|
||||||
|
# Replace instances of "- XX" with "- 127.0.0.1:XX"
|
||||||
|
ports_array[x] = f"127.0.0.1:{orig_port}:{orig_port}"
|
||||||
|
elif map_recipe == "any-same":
|
||||||
|
# Replace instances of "- XX" with "- 0.0.0.0:XX"
|
||||||
|
ports_array[x] = f"0.0.0.0:{orig_port}:{orig_port}"
|
||||||
|
elif map_recipe == "localhost-fixed-random":
|
||||||
|
# Replace instances of "- XX" with "- 127.0.0.1:<rnd>:XX"
|
||||||
|
ports_array[x] = f"127.0.0.1:{random_port}:{orig_port}"
|
||||||
|
elif map_recipe == "any-fixed-random":
|
||||||
|
# Replace instances of "- XX" with "- 0.0.0.0:<rnd>:XX"
|
||||||
|
ports_array[x] = f"0.0.0.0:{random_port}:{orig_port}"
|
||||||
|
else:
|
||||||
|
print("Error: bad map_recipe")
|
||||||
|
else:
|
||||||
|
print(f"Error: --map-ports-to-host must specify one of: {port_map_recipes}")
|
||||||
|
sys.exit(1)
|
||||||
|
return ports
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@click.command()
|
@click.command()
|
||||||
@click.option("--output", required=True, help="Write yaml spec file here")
|
@click.option("--output", required=True, help="Write yaml spec file here")
|
||||||
|
@click.option("--map-ports-to-host", required=False,
|
||||||
|
help="Map ports to the host as one of: any-variable-random (default), localhost-same, any-same, localhost-fixed-random, any-fixed-random")
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
def init(ctx, output):
|
def init(ctx, output, map_ports_to_host):
|
||||||
yaml = get_yaml()
|
yaml = get_yaml()
|
||||||
stack = global_options(ctx).stack
|
stack = global_options(ctx).stack
|
||||||
verbose = global_options(ctx).verbose
|
verbose = global_options(ctx).verbose
|
||||||
@ -180,8 +219,7 @@ def init(ctx, output):
|
|||||||
if verbose:
|
if verbose:
|
||||||
print(f"Creating spec file for stack: {stack}")
|
print(f"Creating spec file for stack: {stack}")
|
||||||
|
|
||||||
ports = _get_ports(stack)
|
ports = _get_mapped_ports(stack, map_ports_to_host)
|
||||||
if ports:
|
|
||||||
spec_file_content["ports"] = ports
|
spec_file_content["ports"] = ports
|
||||||
|
|
||||||
named_volumes = _get_named_volumes(stack)
|
named_volumes = _get_named_volumes(stack)
|
||||||
|
Loading…
Reference in New Issue
Block a user