Skip to content

Commit

Permalink
chore(deployment): support unified deployment config (#2378)
Browse files Browse the repository at this point in the history
  • Loading branch information
alon-dotan-starkware authored Dec 4, 2024
1 parent ed273b2 commit 174e3f2
Show file tree
Hide file tree
Showing 9 changed files with 126 additions and 107 deletions.
149 changes: 78 additions & 71 deletions deployments/sequencer/app/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,19 @@

class ServiceApp(Construct):
def __init__(
self, scope: Construct, id: str, *, namespace: str, topology: topology.ServiceTopology
self,
scope: Construct,
id: str,
*,
namespace: str,
topology: topology.ServiceTopology,
):
super().__init__(scope, id)

self.namespace = namespace
self.label = {"app": Names.to_label_value(self, include_hash=False)}
self.topology = topology
self.node_config = topology.config.get_config()

self.set_k8s_namespace()

Expand All @@ -44,7 +50,7 @@ def set_k8s_configmap(self):
self,
"configmap",
metadata=k8s.ObjectMeta(name=f"{self.node.id}-config"),
data=dict(config=json.dumps(self.topology.config.get())),
data=dict(config=json.dumps(self.topology.config.get_config())),
)

def set_k8s_service(self):
Expand All @@ -65,7 +71,14 @@ def set_k8s_service(self):
),
)

def _get_container_ports(self):
ports = []
for c in ["http_server_config.port", "monitoring_endpoint_config.port"]:
ports.append(self.node_config[c].get("value"))
return ports

def set_k8s_deployment(self):
node_http_port = self.node_config["http_server_config.port"].get("value")
return k8s.KubeDeployment(
self,
"deployment",
Expand All @@ -83,60 +96,50 @@ def set_k8s_deployment(self):
# command=["sleep", "infinity"],
args=container.args,
ports=[
k8s.ContainerPort(container_port=port.container_port)
for port in container.ports
k8s.ContainerPort(
container_port=port,
)
for port in self._get_container_ports()
],
startup_probe=k8s.Probe(
http_get=k8s.HttpGetAction(
path=container.startup_probe.path,
port=k8s.IntOrString.from_string(
container.startup_probe.port
)
if isinstance(container.startup_probe.port, str)
else k8s.IntOrString.from_number(
container.startup_probe.port
startup_probe=(
k8s.Probe(
http_get=k8s.HttpGetAction(
path=container.startup_probe.path,
port=k8s.IntOrString.from_number(node_http_port),
),
),
period_seconds=container.startup_probe.period_seconds,
failure_threshold=container.startup_probe.failure_threshold,
timeout_seconds=container.startup_probe.timeout_seconds,
)
if container.startup_probe is not None
else None,
readiness_probe=k8s.Probe(
http_get=k8s.HttpGetAction(
path=container.readiness_probe.path,
port=k8s.IntOrString.from_string(
container.readiness_probe.port
)
if isinstance(container.readiness_probe.port, str)
else k8s.IntOrString.from_number(
container.readiness_probe.port
period_seconds=container.startup_probe.period_seconds,
failure_threshold=container.startup_probe.failure_threshold,
timeout_seconds=container.startup_probe.timeout_seconds,
)
if container.startup_probe is not None
else None
),
readiness_probe=(
k8s.Probe(
http_get=k8s.HttpGetAction(
path=container.readiness_probe.path,
port=k8s.IntOrString.from_number(node_http_port),
),
),
period_seconds=container.readiness_probe.period_seconds,
failure_threshold=container.readiness_probe.failure_threshold,
timeout_seconds=container.readiness_probe.timeout_seconds,
)
if container.readiness_probe is not None
else None,
liveness_probe=k8s.Probe(
http_get=k8s.HttpGetAction(
path=container.liveness_probe.path,
port=k8s.IntOrString.from_string(
container.liveness_probe.port
)
if isinstance(container.liveness_probe.port, str)
else k8s.IntOrString.from_number(
container.liveness_probe.port
period_seconds=container.readiness_probe.period_seconds,
failure_threshold=container.readiness_probe.failure_threshold,
timeout_seconds=container.readiness_probe.timeout_seconds,
)
if container.readiness_probe is not None
else None
),
liveness_probe=(
k8s.Probe(
http_get=k8s.HttpGetAction(
path=container.liveness_probe.path,
port=k8s.IntOrString.from_number(node_http_port),
),
),
period_seconds=container.liveness_probe.period_seconds,
failure_threshold=container.liveness_probe.failure_threshold,
timeout_seconds=container.liveness_probe.timeout_seconds,
)
if container.liveness_probe is not None
else None,
period_seconds=container.liveness_probe.period_seconds,
failure_threshold=container.liveness_probe.failure_threshold,
timeout_seconds=container.liveness_probe.timeout_seconds,
)
if container.liveness_probe is not None
else None
),
volume_mounts=[
k8s.VolumeMount(
name=mount.name,
Expand All @@ -151,28 +154,32 @@ def set_k8s_deployment(self):
volumes=list(
chain(
(
k8s.Volume(
name=f"{self.node.id}-{volume.name}",
config_map=k8s.ConfigMapVolumeSource(
name=f"{self.node.id}-{volume.name}"
),
(
k8s.Volume(
name=f"{self.node.id}-{volume.name}",
config_map=k8s.ConfigMapVolumeSource(
name=f"{self.node.id}-{volume.name}"
),
)
for volume in self.topology.deployment.configmap_volumes
)
for volume in self.topology.deployment.configmap_volumes
)
if self.topology.deployment.configmap_volumes is not None
else None,
if self.topology.deployment.configmap_volumes is not None
else None
),
(
k8s.Volume(
name=f"{self.node.id}-{volume.name}",
persistent_volume_claim=k8s.PersistentVolumeClaimVolumeSource(
claim_name=f"{self.node.id}-{volume.name}",
read_only=volume.read_only,
),
(
k8s.Volume(
name=f"{self.node.id}-{volume.name}",
persistent_volume_claim=k8s.PersistentVolumeClaimVolumeSource(
claim_name=f"{self.node.id}-{volume.name}",
read_only=volume.read_only,
),
)
for volume in self.topology.deployment.pvc_volumes
)
for volume in self.topology.deployment.pvc_volumes
)
if self.topology.deployment is not None
else None,
if self.topology.deployment is not None
else None
),
)
),
),
Expand Down
14 changes: 9 additions & 5 deletions deployments/sequencer/config/sequencer.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,16 @@
class SequencerDevConfig(Config):
def __init__(self, mount_path: str, config_file_path: str = ""):
super().__init__(
schema=json.loads(open(os.path.join(CONFIG_DIR, "default_config.json"), "r").read()),
config=json.loads(open(os.path.join(CONFIG_DIR, "presets", "config.json"), "r").read())
if not config_file_path
else json.loads(open(os.path.abspath(config_file_path)).read()),
global_config=json.loads(
open(os.path.join(CONFIG_DIR, "default_config.json"), "r").read()
),
config=(
json.loads(open(os.path.join(CONFIG_DIR, "presets", "config.json"), "r").read())
if not config_file_path
else json.loads(open(os.path.abspath(config_file_path)).read())
),
mount_path=mount_path,
)

def validate(self):
jsonschema.validate(self.config, schema=self.schema)
jsonschema.validate(self.config, schema=self.global_config)
16 changes: 11 additions & 5 deletions deployments/sequencer/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

from config.sequencer import Config
from app.service import ServiceApp
from services.topology_helpers import get_dev_config
from services import topology, helpers


Expand All @@ -31,15 +32,20 @@ def __init__(


def main():
if helpers.args.env == "dev":
system_preset = topology.SequencerDev()
elif helpers.args.env == "prod":
system_preset = topology.SequencerProd()
args = helpers.argument_parser()
if args.env == "dev":
system_preset = topology.SequencerDev(config=get_dev_config(args.config_file))
elif args.env == "prod":
raise NotImplementedError("Production environment not supported.")
# system_preset = topology.SequencerProd()

app = App(yaml_output_type=YamlOutputType.FOLDER_PER_CHART_FILE_PER_RESOURCE)

SequencerNode(
scope=app, name="sequencer-node", namespace=helpers.args.namespace, topology=system_preset
scope=app,
name="sequencer-node",
namespace=args.namespace,
topology=system_preset,
)

app.synth()
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -22,26 +22,25 @@ spec:
failureThreshold: 5
httpGet:
path: /monitoring/alive
port: 8082
port: 8080
periodSeconds: 10
timeoutSeconds: 5
name: sequencer-node-server
ports:
- containerPort: 8080
- containerPort: 8081
- containerPort: 8082
readinessProbe:
failureThreshold: 5
httpGet:
path: /monitoring/ready
port: 8082
port: 8080
periodSeconds: 10
timeoutSeconds: 5
startupProbe:
failureThreshold: 10
httpGet:
path: /monitoring/nodeVersion
port: 8082
port: 8080
periodSeconds: 10
timeoutSeconds: 5
volumeMounts:
Expand Down
3 changes: 0 additions & 3 deletions deployments/sequencer/services/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,3 @@ def argument_parser():
)

return parser.parse_args()


args = argument_parser()
11 changes: 8 additions & 3 deletions deployments/sequencer/services/objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,17 @@ class PersistentVolumeClaim:

@dataclasses.dataclass
class Config:
schema: Dict[Any, Any]
global_config: Dict[Any, Any]
config: Dict[Any, Any]
mount_path: str

def get(self):
return self.config
def _merged_config(self) -> Dict[Any, Any]:
_config = self.global_config.copy()
_config.update(self.config)
return _config

def get_config(self):
return self._merged_config()

def validate(self):
pass
Expand Down
2 changes: 1 addition & 1 deletion deployments/sequencer/services/topology.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class ServiceTopology:
default_factory=topology_helpers.get_deployment
)
config: typing.Optional[objects.Config] = dataclasses.field(
default_factory=topology_helpers.get_config
default_factory=topology_helpers.get_dev_config
)
service: typing.Optional[objects.Service] = dataclasses.field(
default_factory=topology_helpers.get_service
Expand Down
29 changes: 15 additions & 14 deletions deployments/sequencer/services/topology_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,25 @@ def get_pvc() -> objects.PersistentVolumeClaim:
)


def get_config() -> objects.Config:
def get_dev_config(config_file_path: str) -> objects.Config:
return SequencerDevConfig(
mount_path="/config/sequencer/presets/", config_file_path=helpers.args.config_file
mount_path="/config/sequencer/presets/", config_file_path=config_file_path
)


def get_ingress() -> objects.Ingress:
def get_ingress(url: str = "test.gcp-integration.sw-dev.io") -> objects.Ingress:
return objects.Ingress(
annotations={
"kubernetes.io/tls-acme": "true",
"cert-manager.io/common-name": f"{helpers.args.namespace}.gcp-integration.sw-dev.io",
"cert-manager.io/common-name": f"{url}",
"cert-manager.io/issue-temporary-certificate": "true",
"cert-manager.io/issuer": "letsencrypt-prod",
"acme.cert-manager.io/http01-edit-in-place": "true",
},
class_name=None,
rules=[
objects.IngressRule(
host=f"{helpers.args.namespace}.gcp-integration.sw-dev.io",
host=url,
paths=[
objects.IngressRuleHttpPath(
path="/monitoring/",
Expand All @@ -42,12 +42,7 @@ def get_ingress() -> objects.Ingress:
],
)
],
tls=[
objects.IngressTls(
hosts=[f"{helpers.args.namespace}.gcp-integration.sw-dev.io"],
secret_name="sequencer-tls",
)
],
tls=[objects.IngressTls(hosts=[url], secret_name="sequencer-tls")],
)


Expand All @@ -57,10 +52,14 @@ def get_service() -> objects.Service:
selector={},
ports=[
objects.PortMapping(
name="http", port=const.HTTP_SERVICE_PORT, container_port=const.HTTP_CONTAINER_PORT
name="http",
port=const.HTTP_SERVICE_PORT,
container_port=const.HTTP_CONTAINER_PORT,
),
objects.PortMapping(
name="rpc", port=const.RPC_SERVICE_PORT, container_port=const.RPC_CONTAINER_PORT
name="rpc",
port=const.RPC_SERVICE_PORT,
container_port=const.RPC_CONTAINER_PORT,
),
objects.PortMapping(
name="monitoring",
Expand Down Expand Up @@ -108,7 +107,9 @@ def get_deployment() -> objects.Deployment:
),
volume_mounts=[
objects.VolumeMount(
name="config", mount_path="/config/sequencer/presets/", read_only=True
name="config",
mount_path="/config/sequencer/presets/",
read_only=True,
),
objects.VolumeMount(name="data", mount_path="/data", read_only=False),
],
Expand Down

0 comments on commit 174e3f2

Please sign in to comment.