Skip to content

Commit

Permalink
Add support for resource limits when running on Openshift
Browse files Browse the repository at this point in the history
Add resource limits to workspace Pods when running on OpenShift.
The memory limit is normally obtained from the API request to
create the workspace, however it can be overridden via the property
`che.openshift.workspace.memory.override`. The cpu limit used is
determined by the property `che.openshift.workspace.cpu.limit`.

In both cases, the value of the property is passed directly to
OpenShift, so any valid quantity is acceptable (e.g. 150Mi,
1Gi, 1024, etc).

Signed-off-by: Angel Misevski <amisevsk@redhat.com>
  • Loading branch information
amisevsk committed Mar 29, 2017
1 parent f538239 commit 4d601c7
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,9 @@ che.openshift.liveness.probe.delay=300
che.openshift.liveness.probe.timeout=1
che.openshift.workspaces.pvc.name=claim-che-workspace
che.openshift.workspaces.pvc.quantity=10Gi
che.openshift.workspace.cpu.limit=1
# Override memory limit used for openshift workspaces. String, e.g. 1300Mi
che.openshift.workspace.memory.override=NULL

# Which implementation of DockerConnector to use in managing containers. In general,
# the base implementation of DockerConnector is appropriate, but OpenShiftConnector
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,8 @@ public class OpenShiftConnector extends DockerConnector {
private final String cheWorkspaceStorage;
private final String cheWorkspaceProjectsStorage;
private final String cheServerExternalAddress;
private final String cheWorkspaceCpuLimit;
private final String cheWorkspaceMemory;

@Inject
public OpenShiftConnector(DockerConnectorConfiguration connectorConfiguration,
Expand All @@ -183,7 +185,10 @@ public OpenShiftConnector(DockerConnectorConfiguration connectorConfiguration,
@Named("che.openshift.workspaces.pvc.name") String workspacesPersistentVolumeClaim,
@Named("che.openshift.workspaces.pvc.quantity") String workspacesPvcQuantity,
@Named("che.workspace.storage") String cheWorkspaceStorage,
@Named("che.workspace.projects.storage") String cheWorkspaceProjectsStorage) {
@Named("che.workspace.projects.storage") String cheWorkspaceProjectsStorage,
@Named("che.openshift.workspace.cpu.limit") String cheWorkspaceCpuLimit,
@Nullable @Named("che.openshift.workspace.memory.override") String cheWorkspaceMemory) {


super(connectorConfiguration, connectionFactory, authResolver, dockerApiVersionPathPrefixProvider);
this.cheServerExternalAddress = cheServerExternalAddress;
Expand All @@ -194,6 +199,8 @@ public OpenShiftConnector(DockerConnectorConfiguration connectorConfiguration,
this.workspacesPvcQuantity = workspacesPvcQuantity;
this.cheWorkspaceStorage = cheWorkspaceStorage;
this.cheWorkspaceProjectsStorage = cheWorkspaceProjectsStorage;
this.cheWorkspaceCpuLimit = cheWorkspaceCpuLimit;
this.cheWorkspaceMemory = cheWorkspaceMemory;

this.openShiftClient = new DefaultOpenShiftClient();
}
Expand Down Expand Up @@ -252,6 +259,21 @@ public ContainerCreated createContainer(CreateContainerParams createContainerPar
String[] volumes = createContainerParams.getContainerConfig().getHostConfig().getBinds();

Map<String, String> additionalLabels = createContainerParams.getContainerConfig().getLabels();

String memoryLimit;
if (!isNullOrEmpty(cheWorkspaceMemory)) {
LOG.info("Che property 'che.openshift.workspace.memory.override' "
+ "used to override workspace memory limit to {}.", cheWorkspaceMemory);
memoryLimit = cheWorkspaceMemory;
} else {
long memoryLimitBytes = createContainerParams.getContainerConfig().getHostConfig().getMemory();
memoryLimit = Long.toString(memoryLimitBytes / 1048576) + "Mi";
LOG.info("Creating workspace pod with memory limit of {}.", memoryLimit);
}
Map<String, Quantity> resourceLimits = new HashMap<>();
resourceLimits.put("memory", new Quantity(memoryLimit));
resourceLimits.put("cpu", new Quantity(cheWorkspaceCpuLimit));

String containerID;
try {
createOpenShiftService(workspaceID, exposedPorts, additionalLabels);
Expand All @@ -260,16 +282,18 @@ public ContainerCreated createContainer(CreateContainerParams createContainerPar
containerName,
exposedPorts,
envVariables,
volumes);
volumes,
resourceLimits);

containerID = waitAndRetrieveContainerID(deploymentName);
if (containerID == null) {
throw new OpenShiftException("Failed to get the ID of the container running in the OpenShift pod");
}
} catch (IOException e) {
} catch (IOException | KubernetesClientException e) {
// Make sure we clean up deployment and service in case of an error -- otherwise Che can end up
// in an inconsistent state.
LOG.info("Error while creating Pod, removing deployment");
LOG.info(e.getMessage());
String deploymentName = CHE_OPENSHIFT_RESOURCES_PREFIX + workspaceID;
cleanUpWorkspaceResources(deploymentName);
openShiftClient.resource(imageStreamTag).delete();
Expand Down Expand Up @@ -990,7 +1014,8 @@ private String createOpenShiftDeployment(String workspaceID,
String sanitizedContainerName,
Set<String> exposedPorts,
String[] envVariables,
String[] volumes) {
String[] volumes,
Map<String, Quantity> resourceLimits) {

String deploymentName = CHE_OPENSHIFT_RESOURCES_PREFIX + workspaceID;
LOG.info("Creating OpenShift deployment {}", deploymentName);
Expand Down Expand Up @@ -1018,7 +1043,8 @@ private String createOpenShiftDeployment(String workspaceID,
deploymentName,
selector,
command,
false);
false,
resourceLimits);

try {
waitAndRetrieveContainerID(deploymentName);
Expand All @@ -1043,7 +1069,8 @@ private String createOpenShiftDeployment(String workspaceID,
deploymentName,
selector,
null,
true);
true,
resourceLimits);
LOG.info("OpenShift deployment {} created", deploymentName);
return deployment.getMetadata().getName();
}
Expand Down Expand Up @@ -1079,7 +1106,8 @@ private Deployment createOpenShiftDeploymentInternal(String workspaceID,
Map<String,
String> selector,
String[] command,
boolean withSubpath) {
boolean withSubpath,
Map<String, Quantity> resourceLimits) {

Container container = new ContainerBuilder()
.withName(sanitizedContainerName)
Expand All @@ -1093,6 +1121,9 @@ private Deployment createOpenShiftDeploymentInternal(String workspaceID,
.withLivenessProbe(getLivenessProbeFrom(exposedPorts))
.withCommand(command)
.withVolumeMounts(getVolumeMountsFrom(volumes, workspaceID, withSubpath))
.withNewResources()
.withLimits(resourceLimits)
.endResources()
.build();

PodSpec podSpec = new PodSpecBuilder()
Expand Down Expand Up @@ -1196,7 +1227,6 @@ private ContainerInfo createContainerInfo(Service svc,
// HostConfig
HostConfig hostConfig = new HostConfig();
hostConfig.setBinds(new String[0]);
hostConfig.setMemory(imageInfo.getConfig().getMemory());

// Env vars
List<String> imageEnv = Arrays.asList(imageContainerConfig.getEnv());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,9 @@ public class OpenShiftConnectorTest {
private static final String OPENSHIFT_DEFAULT_WORKSPACE_QUANTITY = "10Gi";
private static final String OPENSHIFT_DEFAULT_WORKSPACE_STORAGE = "/data/workspaces";
private static final String OPENSHIFT_DEFAULT_WORKSPACE_PROJECTS_STORAGE = "/projects";
private static final String CHE_DEFAULT_SERVER_EXTERNAL_ADDRESS = "che.openshift.mini";

private static final String CHE_DEFAULT_SERVER_EXTERNAL_ADDRESS = "che.openshift.mini";
private static final String CHE_WORKSPACE_CPU_LIMIT = "1";

@Mock
private DockerConnectorConfiguration dockerConnectorConfiguration;
@Mock
Expand Down Expand Up @@ -73,7 +74,9 @@ public void shouldGetWorkspaceIDWhenAValidOneIsProvidedInCreateContainerParams()
OPENSHIFT_DEFAULT_WORKSPACE_PERSISTENT_VOLUME_CLAIM,
OPENSHIFT_DEFAULT_WORKSPACE_QUANTITY,
OPENSHIFT_DEFAULT_WORKSPACE_STORAGE,
OPENSHIFT_DEFAULT_WORKSPACE_PROJECTS_STORAGE);
OPENSHIFT_DEFAULT_WORKSPACE_PROJECTS_STORAGE,
CHE_WORKSPACE_CPU_LIMIT,
null);
String workspaceID = openShiftConnector.getCheWorkspaceId(createContainerParams);

//Then
Expand Down

0 comments on commit 4d601c7

Please sign in to comment.