Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(deployments): allows for custom sizing for kubernetes distrbuted deployments in halconfig #724

Merged
merged 1 commit into from
Oct 11, 2017

Conversation

omawhite
Copy link
Contributor

@omawhite omawhite commented Oct 9, 2017

see spinnaker issue 683

import com.netflix.spinnaker.clouddriver.kubernetes.deploy.description.servergroup.KubernetesVolumeMount;
import com.netflix.spinnaker.clouddriver.kubernetes.deploy.description.servergroup.KubernetesVolumeSource;
import com.netflix.spinnaker.clouddriver.kubernetes.deploy.description.servergroup.KubernetesVolumeSourceType;
import com.netflix.spinnaker.clouddriver.kubernetes.deploy.description.servergroup.*;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@omawhite I think IntelliJ did this. We probably want to change it back to list all the packages explicitly.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah there's some setting to keep those expanded by default

// This is super-goofy. What can we do differently for this? Anything in the config parsing logic?
default String stringOrNull(Object value) {
return value != null ? String.valueOf(value) : null;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lwander We'd be interested in your thoughts on this little nugget. The issue arises when the size specification is in form with only numeric characters: "1" as opposed to "1000m" or "1Gi".

We used String.valueOf to ensure that those cases were parsed out of the config as strings. That, in turn, caused problems when a value was unset (null), because String.valueOf(null) evaluates to "null" as a string, which is not what we want to be in place when something isn't set.

Our tactical solution was this stringOrNull method, which just feels weird. Is there something more framework-y in the wider halyard code base that we might leverage for this? Or a natural util-ish place we could stick this little method instead of implementing it twice in the deployment code? We also considered putting it in the CustomSizing class and calling that from both places where it's needed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah agreed this is a little funky - but this is also the first time where the type isn't explicit in the config. Would it be possible to make it clear that component sizing is mapping string -> string -> string? Or is the fear that this is too restrictive?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We were concerned about being too restrictive, but at this point it probably makes sense to explicitly make it all maps with strings.

Copy link
Member

@lwander lwander left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One thing that is missing is restricting the java heap size. @greenkiwi pointed me at this great flag to size your heap to that of the docker container's allocated memory:

ENV JAVA_DOCKER_MEMORY_OPTS '-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=1 -XshowSettings:vm'

import com.netflix.spinnaker.clouddriver.kubernetes.deploy.description.servergroup.KubernetesVolumeMount;
import com.netflix.spinnaker.clouddriver.kubernetes.deploy.description.servergroup.KubernetesVolumeSource;
import com.netflix.spinnaker.clouddriver.kubernetes.deploy.description.servergroup.KubernetesVolumeSourceType;
import com.netflix.spinnaker.clouddriver.kubernetes.deploy.description.servergroup.*;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah there's some setting to keep those expanded by default

*/
@Data
@EqualsAndHashCode(callSuper = false)
public class CustomSizing implements Map<String, Map> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the intent here just to provide a type alias?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Heh. Not really.

Initially this class had some structure to it, because it assumed the kubernetes "requests" and "limits" nomenclature. We also extended Node initially, and then removed that after we realized we had nothing to validate because there's no CLI interaction with this data (and we couldn't think of any reasonable validation that wasn't k8s-specific). By the time we removed those things, this had nothing left but the Map implementation; you were the first to realize this. :-)

But now, we've given this class a new reason to exist: it holds our goofy little stringOrNull method, so that it doesn't have to be duplicated in the manual and orca deployment flows.

(We abandoned the idea of explicitly making this a three-layer map with strings at its leaf nodes. No implementation felt clean, and we also realized that when we add replicaSetSize to it later this week, that will be an integer, at the top tier of the map. So we'd be breaking that constraint ourselves.)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm it might still be valuable to validate even if there is no CLI command to generate entries here - but maybe not.

Sounds good

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'd be wide open to it if you can guide us on what to validate in a way that doesn't assume a specific cloud provider, or on a way to detect that we're deploying to k8s and only then do our k8s-specific validations. I would definitely feel better if we validated some basics in the k8s case.

On a later PR, of course. :-)

@@ -373,14 +359,7 @@ default KubernetesContainerDescription buildContainer(String name, ServiceSettin
readinessProbe.setHandler(handler);
container.setReadinessProbe(readinessProbe);

/* TODO(lwander) this needs work
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You guys rock

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:-)

To be completely honest, we only moved your TODO into the applyCustomSize method. Because we didn't implement handling of the SMALL/MEDIUM/LARGE specifiers, we kept your placeholder in its new home, below.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Heh I saw that after

// This is super-goofy. What can we do differently for this? Anything in the config parsing logic?
default String stringOrNull(Object value) {
return value != null ? String.valueOf(value) : null;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah agreed this is a little funky - but this is also the first time where the type isn't explicit in the config. Would it be possible to make it clear that component sizing is mapping string -> string -> string? Or is the fear that this is too restrictive?

@edwinavalos
Copy link
Contributor

@lwander should we be append the JAVA_OPTS in this code, or should we be instructing people that they should introduce that in to their service-settings files for individual services?

@lwander
Copy link
Member

lwander commented Oct 10, 2017

I think it'd be nice to append this in this code for the k8s deployments. They can always be overridden using custom service settings.

@omawhite
Copy link
Contributor Author

Hey @lwander in reference to this environment variable, we noticed that the change wasn't added until java version 8u131, but it appears that the spinnaker components are using 8u111.

ENV JAVA_DOCKER_MEMORY_OPTS '-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=1 -XshowSettings:vm'

@omawhite
Copy link
Contributor Author

omawhite commented Oct 10, 2017

@lwander so we found that java version 8u131 isn't available until alpine version 3.6, the containers currently run 3.4. So until that changes people will just have to manually set the JAVA_OPTS in addition to setting custom sizing.

@omawhite
Copy link
Contributor Author

squashed commits

@lwander
Copy link
Member

lwander commented Oct 11, 2017

Good catch @omawhite on the java version.

@lwander
Copy link
Member

lwander commented Oct 11, 2017

I'm ready to merge when you guys feel ready (or you can go ahead @edwinavalos)

@edwinavalos edwinavalos merged commit 5795c82 into spinnaker:master Oct 11, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
4 participants