forked from cerc-io/stack-orchestrator
Switch to Docker-style limits
This commit is contained in:
parent
2a9955055c
commit
4b3b3478e7
@ -10,3 +10,4 @@ pydantic==1.10.9
|
|||||||
tomli==2.0.1
|
tomli==2.0.1
|
||||||
validators==0.22.0
|
validators==0.22.0
|
||||||
kubernetes>=28.1.0
|
kubernetes>=28.1.0
|
||||||
|
humanfriendly>=10.0
|
||||||
|
@ -25,17 +25,37 @@ from stack_orchestrator.deploy.k8s.helpers import get_node_pv_mount_path
|
|||||||
from stack_orchestrator.deploy.k8s.helpers import envs_from_environment_variables_map
|
from stack_orchestrator.deploy.k8s.helpers import envs_from_environment_variables_map
|
||||||
from stack_orchestrator.deploy.deploy_util import parsed_pod_files_map_from_file_names, images_for_deployment
|
from stack_orchestrator.deploy.deploy_util import parsed_pod_files_map_from_file_names, images_for_deployment
|
||||||
from stack_orchestrator.deploy.deploy_types import DeployEnvVars
|
from stack_orchestrator.deploy.deploy_types import DeployEnvVars
|
||||||
from stack_orchestrator.deploy.spec import Spec
|
from stack_orchestrator.deploy.spec import Spec, Resources, ResourceLimits
|
||||||
from stack_orchestrator.deploy.images import remote_tag_for_image
|
from stack_orchestrator.deploy.images import remote_tag_for_image
|
||||||
|
|
||||||
DEFAULT_VOLUME_RESOURCES = {
|
DEFAULT_VOLUME_RESOURCES = Resources({
|
||||||
"requests": {"storage": "2Gi"}
|
"reservations": {"storage": "2Gi"}
|
||||||
}
|
})
|
||||||
|
|
||||||
DEFAULT_CONTAINER_RESOURCES = {
|
DEFAULT_CONTAINER_RESOURCES = Resources({
|
||||||
"requests": {"cpu": "100m", "memory": "200Mi"},
|
"reservations": {"cpus": "0.1", "memory": "200M"},
|
||||||
"limits": {"cpu": "1000m", "memory": "2000Mi"},
|
"limits": {"cpus": "1.0", "memory": "2000M"},
|
||||||
}
|
})
|
||||||
|
|
||||||
|
|
||||||
|
def get_k8s_resource_requirements(resources: Resources) -> client.V1ResourceRequirements:
|
||||||
|
def to_dict(limits: ResourceLimits):
|
||||||
|
if not limits:
|
||||||
|
return None
|
||||||
|
|
||||||
|
ret = {}
|
||||||
|
if limits.cpus:
|
||||||
|
ret["cpu"] = str(limits.cpus)
|
||||||
|
if limits.memory:
|
||||||
|
ret["memory"] = f"{int(limits.memory / (1000 * 1000))}M"
|
||||||
|
if limits.storage:
|
||||||
|
ret["storage"] = f"{int(limits.storage / (1000 * 1000))}M"
|
||||||
|
return ret
|
||||||
|
|
||||||
|
return client.V1ResourceRequirements(
|
||||||
|
requests=to_dict(resources.reservations),
|
||||||
|
limits=to_dict(resources.limits)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ClusterInfo:
|
class ClusterInfo:
|
||||||
@ -159,10 +179,7 @@ class ClusterInfo:
|
|||||||
spec = client.V1PersistentVolumeClaimSpec(
|
spec = client.V1PersistentVolumeClaimSpec(
|
||||||
access_modes=["ReadWriteOnce"],
|
access_modes=["ReadWriteOnce"],
|
||||||
storage_class_name="manual",
|
storage_class_name="manual",
|
||||||
resources=client.V1ResourceRequirements(
|
resources=get_k8s_resource_requirements(resources),
|
||||||
requests=resources.get("requests"),
|
|
||||||
limits=resources.get("limits")
|
|
||||||
),
|
|
||||||
volume_name=f"{self.app_name}-{volume_name}"
|
volume_name=f"{self.app_name}-{volume_name}"
|
||||||
)
|
)
|
||||||
pvc = client.V1PersistentVolumeClaim(
|
pvc = client.V1PersistentVolumeClaim(
|
||||||
@ -217,7 +234,7 @@ class ClusterInfo:
|
|||||||
spec = client.V1PersistentVolumeSpec(
|
spec = client.V1PersistentVolumeSpec(
|
||||||
storage_class_name="manual",
|
storage_class_name="manual",
|
||||||
access_modes=["ReadWriteOnce"],
|
access_modes=["ReadWriteOnce"],
|
||||||
capacity=resources.get("requests", DEFAULT_VOLUME_RESOURCES["requests"]),
|
capacity=get_k8s_resource_requirements(resources).requests,
|
||||||
host_path=client.V1HostPathVolumeSource(path=get_node_pv_mount_path(volume_name))
|
host_path=client.V1HostPathVolumeSource(path=get_node_pv_mount_path(volume_name))
|
||||||
)
|
)
|
||||||
pv = client.V1PersistentVolume(
|
pv = client.V1PersistentVolume(
|
||||||
@ -257,10 +274,7 @@ class ClusterInfo:
|
|||||||
env=envs_from_environment_variables_map(self.environment_variables.map),
|
env=envs_from_environment_variables_map(self.environment_variables.map),
|
||||||
ports=[client.V1ContainerPort(container_port=port)],
|
ports=[client.V1ContainerPort(container_port=port)],
|
||||||
volume_mounts=volume_mounts,
|
volume_mounts=volume_mounts,
|
||||||
resources=client.V1ResourceRequirements(
|
resources=get_k8s_resource_requirements(resources),
|
||||||
requests=resources.get("requests"),
|
|
||||||
limits=resources.get("limits")
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
containers.append(container)
|
containers.append(container)
|
||||||
volumes = volumes_for_pod_files(self.parsed_pod_yaml_map, self.spec, self.app_name)
|
volumes = volumes_for_pod_files(self.parsed_pod_yaml_map, self.spec, self.app_name)
|
||||||
|
@ -13,12 +13,60 @@
|
|||||||
# You should have received a copy of the GNU Affero General Public License
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
# along with this program. If not, see <http:#www.gnu.org/licenses/>.
|
# along with this program. If not, see <http:#www.gnu.org/licenses/>.
|
||||||
|
|
||||||
from pathlib import Path
|
|
||||||
import typing
|
import typing
|
||||||
|
import humanfriendly
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from stack_orchestrator.util import get_yaml
|
from stack_orchestrator.util import get_yaml
|
||||||
from stack_orchestrator import constants
|
from stack_orchestrator import constants
|
||||||
|
|
||||||
|
|
||||||
|
class ResourceLimits:
|
||||||
|
cpus: float = None
|
||||||
|
memory: int = None
|
||||||
|
storage: int = None
|
||||||
|
|
||||||
|
def __init__(self, obj={}):
|
||||||
|
if "cpus" in obj:
|
||||||
|
self.cpus = float(obj["cpus"])
|
||||||
|
if "memory" in obj:
|
||||||
|
self.memory = humanfriendly.parse_size(obj["memory"])
|
||||||
|
if "storage" in obj:
|
||||||
|
self.storage = humanfriendly.parse_size(obj["storage"])
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return len(self.__dict__)
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
for k in self.__dict__:
|
||||||
|
yield k, self.__dict__[k]
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return str(self.__dict__)
|
||||||
|
|
||||||
|
|
||||||
|
class Resources:
|
||||||
|
limits: ResourceLimits = None
|
||||||
|
reservations: ResourceLimits = None
|
||||||
|
|
||||||
|
def __init__(self, obj={}):
|
||||||
|
if "reservations" in obj:
|
||||||
|
self.reservations = ResourceLimits(obj["reservations"])
|
||||||
|
if "limits" in obj:
|
||||||
|
self.limits = ResourceLimits(obj["limits"])
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return len(self.__dict__)
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
for k in self.__dict__:
|
||||||
|
yield k, self.__dict__[k]
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return str(self.__dict__)
|
||||||
|
|
||||||
|
|
||||||
class Spec:
|
class Spec:
|
||||||
|
|
||||||
obj: typing.Any
|
obj: typing.Any
|
||||||
@ -48,10 +96,10 @@ class Spec:
|
|||||||
else {})
|
else {})
|
||||||
|
|
||||||
def get_container_resources(self):
|
def get_container_resources(self):
|
||||||
return self.obj.get("resources", {}).get("containers")
|
return Resources(self.obj.get("resources", {}).get("containers", {}))
|
||||||
|
|
||||||
def get_volume_resources(self):
|
def get_volume_resources(self):
|
||||||
return self.obj.get("resources", {}).get("volumes")
|
return Resources(self.obj.get("resources", {}).get("volumes", {}))
|
||||||
|
|
||||||
def get_http_proxy(self):
|
def get_http_proxy(self):
|
||||||
return (self.obj[constants.network_key][constants.http_proxy_key]
|
return (self.obj[constants.network_key][constants.http_proxy_key]
|
||||||
|
Loading…
Reference in New Issue
Block a user