Skip to content

Commit

Permalink
Add Healthcheck to ContainerConfigurationTemplate (#1217)
Browse files Browse the repository at this point in the history
  • Loading branch information
TadCordle authored Nov 30, 2018
1 parent 29480e0 commit f59326e
Show file tree
Hide file tree
Showing 15 changed files with 263 additions and 96 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ private Image<Layer> afterCachedLayerSteps()
try (TimerEventDispatcher ignored =
new TimerEventDispatcher(buildConfiguration.getEventDispatcher(), DESCRIPTION)) {
// Constructs the image.
Image.Builder<Layer> imageBuilder = Image.builder();
Image.Builder<Layer> imageBuilder = Image.builder(buildConfiguration.getTargetFormat());
Image<Layer> baseImage = NonBlockingSteps.get(pullBaseImageStep).getBaseImage();
ContainerConfiguration containerConfiguration =
buildConfiguration.getContainerConfiguration();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package com.google.cloud.tools.jib.configuration;

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import java.time.Duration;
import java.util.Arrays;
Expand All @@ -29,13 +30,14 @@ public class DockerHealthCheck {
/** Builds the immutable {@link DockerHealthCheck}. */
public static class Builder {

@Nullable private final ImmutableList<String> command;
private final ImmutableList<String> command;
@Nullable private Duration interval;
@Nullable private Duration timeout;
@Nullable private Duration startPeriod;
@Nullable private Integer retries;

private Builder(@Nullable ImmutableList<String> command) {
private Builder(ImmutableList<String> command) {
Preconditions.checkArgument(command.size() > 1, "command must not be empty");
this.command = command;
}

Expand Down Expand Up @@ -99,13 +101,13 @@ public static DockerHealthCheck disabled() {
}

/**
* Creates a new {@link DockerHealthCheck.Builder} with the command set to be inherited from the
* base image (corresponds to empty list in container config).
* Creates a new {@link DockerHealthCheck} with the command set to be inherited from the base
* image.
*
* @return the new {@link DockerHealthCheck.Builder}
* @return the new {@link DockerHealthCheck}
*/
public static Builder builderWithInheritedCommand() {
return new Builder(null);
public static DockerHealthCheck inherited() {
return new DockerHealthCheck(ImmutableList.of(), null, null, null, null);
}

/**
Expand Down Expand Up @@ -140,17 +142,18 @@ public static Builder builderWithExecCommand(String... command) {
* @return the new {@link DockerHealthCheck.Builder}
*/
public static Builder builderWithShellCommand(String command) {
Preconditions.checkArgument(!command.trim().isEmpty(), "command must not be empty/whitespace");
return new Builder(ImmutableList.of("CMD-SHELL", command));
}

@Nullable private final ImmutableList<String> command;
private final ImmutableList<String> command;
@Nullable private final Duration interval;
@Nullable private final Duration timeout;
@Nullable private final Duration startPeriod;
@Nullable private final Integer retries;

private DockerHealthCheck(
@Nullable ImmutableList<String> command,
ImmutableList<String> command,
@Nullable Duration interval,
@Nullable Duration timeout,
@Nullable Duration startPeriod,
Expand All @@ -168,8 +171,8 @@ private DockerHealthCheck(
*
* @return the healthcheck command
*/
public Optional<List<String>> getCommand() {
return Optional.ofNullable(command);
public List<String> getCommand() {
return command;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public class ImageToTarballTranslator {
/**
* Instantiate with an {@link Image}.
*
* @param image the image to convert into a tarball.
* @param image the image to convert into a tarball
*/
public ImageToTarballTranslator(Image<Layer> image) {
this.image = image;
Expand Down
44 changes: 42 additions & 2 deletions jib-core/src/main/java/com/google/cloud/tools/jib/image/Image.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@

package com.google.cloud.tools.jib.image;

import com.google.cloud.tools.jib.configuration.DockerHealthCheck;
import com.google.cloud.tools.jib.configuration.Port;
import com.google.cloud.tools.jib.filesystem.AbsoluteUnixPath;
import com.google.cloud.tools.jib.image.json.HistoryEntry;
import com.google.cloud.tools.jib.image.json.ManifestTemplate;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
Expand All @@ -36,6 +38,7 @@ public class Image<T extends Layer> {
/** Builds the immutable {@link Image}. */
public static class Builder<T extends Layer> {

private final Class<? extends ManifestTemplate> imageFormat;
private final ImageLayers.Builder<T> imageLayersBuilder = ImageLayers.builder();
private final ImmutableList.Builder<HistoryEntry> historyBuilder = ImmutableList.builder();

Expand All @@ -49,9 +52,14 @@ public static class Builder<T extends Layer> {
@Nullable private Instant created;
@Nullable private ImmutableList<String> entrypoint;
@Nullable private ImmutableList<String> programArguments;
private DockerHealthCheck healthCheck = DockerHealthCheck.inherited();
@Nullable private String workingDirectory;
@Nullable private String user;

private Builder(Class<? extends ManifestTemplate> imageFormat) {
this.imageFormat = imageFormat;
}

/**
* Sets the image creation time.
*
Expand Down Expand Up @@ -122,6 +130,17 @@ public Builder<T> setProgramArguments(@Nullable List<String> programArguments) {
return this;
}

/**
* Sets the container's healthcheck configuration.
*
* @param healthCheck the healthcheck configuration
* @return this
*/
public Builder<T> setHealthCheck(DockerHealthCheck healthCheck) {
this.healthCheck = healthCheck;
return this;
}

/**
* Adds items to the "ExposedPorts" field in the container configuration.
*
Expand Down Expand Up @@ -209,12 +228,14 @@ public Builder<T> addHistory(HistoryEntry history) {

public Image<T> build() {
return new Image<>(
imageFormat,
created,
imageLayersBuilder.build(),
historyBuilder.build(),
ImmutableMap.copyOf(environmentBuilder),
entrypoint,
programArguments,
healthCheck,
ImmutableSet.copyOf(exposedPortsBuilder),
ImmutableSet.copyOf(volumesBuilder),
ImmutableMap.copyOf(labelsBuilder),
Expand All @@ -223,10 +244,14 @@ public Image<T> build() {
}
}

public static <T extends Layer> Builder<T> builder() {
return new Builder<>();
public static <T extends Layer> Builder<T> builder(
Class<? extends ManifestTemplate> imageFormat) {
return new Builder<>(imageFormat);
}

/** The image format. */
private final Class<? extends ManifestTemplate> imageFormat;

/** The image creation time. */
@Nullable private final Instant created;

Expand All @@ -245,6 +270,9 @@ public static <T extends Layer> Builder<T> builder() {
/** Arguments to append to the image entrypoint when running the image. */
@Nullable private final ImmutableList<String> programArguments;

/** Healthcheck configuration. */
private final DockerHealthCheck healthCheck;

/** Ports that the container listens on. */
@Nullable private final ImmutableSet<Port> exposedPorts;

Expand All @@ -261,30 +289,38 @@ public static <T extends Layer> Builder<T> builder() {
@Nullable private final String user;

private Image(
Class<? extends ManifestTemplate> imageFormat,
@Nullable Instant created,
ImageLayers<T> layers,
ImmutableList<HistoryEntry> history,
@Nullable ImmutableMap<String, String> environment,
@Nullable ImmutableList<String> entrypoint,
@Nullable ImmutableList<String> programArguments,
DockerHealthCheck healthCheck,
@Nullable ImmutableSet<Port> exposedPorts,
@Nullable ImmutableSet<AbsoluteUnixPath> volumes,
@Nullable ImmutableMap<String, String> labels,
@Nullable String workingDirectory,
@Nullable String user) {
this.imageFormat = imageFormat;
this.created = created;
this.layers = layers;
this.history = history;
this.environment = environment;
this.entrypoint = entrypoint;
this.programArguments = programArguments;
this.healthCheck = healthCheck;
this.exposedPorts = exposedPorts;
this.volumes = volumes;
this.labels = labels;
this.workingDirectory = workingDirectory;
this.user = user;
}

public Class<? extends ManifestTemplate> getImageFormat() {
return this.imageFormat;
}

@Nullable
public Instant getCreated() {
return created;
Expand All @@ -305,6 +341,10 @@ public ImmutableList<String> getProgramArguments() {
return programArguments;
}

public DockerHealthCheck getHealthCheck() {
return healthCheck;
}

@Nullable
public ImmutableSet<Port> getExposedPorts() {
return exposedPorts;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import com.google.cloud.tools.jib.image.DescriptorDigest;
import com.google.cloud.tools.jib.json.JsonTemplate;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
Expand All @@ -39,6 +40,13 @@
* "Env": ["/usr/bin/java"],
* "Entrypoint": ["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],
* "Cmd": ["arg1", "arg2"],
* "Healthcheck": {
* "Test": ["CMD-SHELL", "/usr/bin/check-health localhost"],
* "Interval": 30000000000,
* "Timeout": 10000000000,
* "StartPeriod": 0,
* "Retries": 3
* }
* "ExposedPorts": { "6000/tcp":{}, "8000/tcp":{}, "9000/tcp":{} },
* "Volumes":{"/var/job-result-data":{},"/var/log/my-app-logs":{}}},
* "Labels": { "com.example.label": "value" },
Expand Down Expand Up @@ -104,6 +112,9 @@ private static class ConfigurationObjectTemplate implements JsonTemplate {
/** Arguments to pass into main. */
@Nullable private List<String> Cmd;

/** Healthcheck. */
@Nullable private HealthCheckObjectTemplate Healthcheck;

/** Network ports the container exposes. */
@Nullable private Map<String, Map<?, ?>> ExposedPorts;

Expand All @@ -120,6 +131,27 @@ private static class ConfigurationObjectTemplate implements JsonTemplate {
@Nullable private Map<String, Map<?, ?>> Volumes;
}

/** Template for inner JSON object representing the healthcheck configuration. */
private static class HealthCheckObjectTemplate implements JsonTemplate {

/** The test to perform to check that the container is healthy. */
@Nullable private List<String> Test;

/** Number of nanoseconds to wait between probe attempts. */
@Nullable private Long Interval;

/** Number of nanoseconds to wait before considering the check to have hung. */
@Nullable private Long Timeout;

/**
* Number of nanoseconds to wait for the container to initialize before starting health-retries.
*/
@Nullable private Long StartPeriod;

/** The number of consecutive failures needed to consider the container as unhealthy. */
@Nullable private Integer Retries;
}

/**
* Template for inner JSON object representing the filesystem changesets used to build the
* container filesystem.
Expand Down Expand Up @@ -152,6 +184,41 @@ public void setContainerCmd(@Nullable List<String> cmd) {
config.Cmd = cmd;
}

public void setContainerHealthCheckTest(List<String> test) {
if (config.Healthcheck == null) {
config.Healthcheck = new HealthCheckObjectTemplate();
}
Preconditions.checkNotNull(config.Healthcheck).Test = test;
}

public void setContainerHealthCheckInterval(@Nullable Long interval) {
if (config.Healthcheck == null) {
config.Healthcheck = new HealthCheckObjectTemplate();
}
Preconditions.checkNotNull(config.Healthcheck).Interval = interval;
}

public void setContainerHealthCheckTimeout(@Nullable Long timeout) {
if (config.Healthcheck == null) {
config.Healthcheck = new HealthCheckObjectTemplate();
}
Preconditions.checkNotNull(config.Healthcheck).Timeout = timeout;
}

public void setContainerHealthCheckStartPeriod(@Nullable Long startPeriod) {
if (config.Healthcheck == null) {
config.Healthcheck = new HealthCheckObjectTemplate();
}
Preconditions.checkNotNull(config.Healthcheck).StartPeriod = startPeriod;
}

public void setContainerHealthCheckRetries(@Nullable Integer retries) {
if (config.Healthcheck == null) {
config.Healthcheck = new HealthCheckObjectTemplate();
}
Preconditions.checkNotNull(config.Healthcheck).Retries = retries;
}

public void setContainerExposedPorts(@Nullable Map<String, Map<?, ?>> exposedPorts) {
config.ExposedPorts = exposedPorts;
}
Expand Down Expand Up @@ -208,6 +275,31 @@ List<String> getContainerCmd() {
return config.Cmd;
}

@Nullable
List<String> getContainerHealthTest() {
return config.Healthcheck == null ? null : config.Healthcheck.Test;
}

@Nullable
Long getContainerHealthInterval() {
return config.Healthcheck == null ? null : config.Healthcheck.Interval;
}

@Nullable
Long getContainerHealthTimeout() {
return config.Healthcheck == null ? null : config.Healthcheck.Timeout;
}

@Nullable
Long getContainerHealthStartPeriod() {
return config.Healthcheck == null ? null : config.Healthcheck.StartPeriod;
}

@Nullable
Integer getContainerHealthRetries() {
return config.Healthcheck == null ? null : config.Healthcheck.Retries;
}

@Nullable
Map<String, Map<?, ?>> getContainerExposedPorts() {
return config.ExposedPorts;
Expand Down
Loading

0 comments on commit f59326e

Please sign in to comment.