diff options
author | Harald Musum <musum@yahoo-inc.com> | 2016-10-21 14:36:20 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-10-21 14:36:20 +0200 |
commit | c202f27ac730619ca99ac5d75fd04f4942563ca0 (patch) | |
tree | 09eb830e50b8cf6616251bded3cf1fafcbb932b7 | |
parent | 7b584dfeac872aef86b8a2c2c62870cd8e06d26d (diff) | |
parent | 0cddc3c658182f6ed6916d3433ed47ce798e5f1a (diff) |
Merge pull request #928 from yahoo/freva/local-zone-config-server
Freva/local zone config server
10 files changed, 121 insertions, 36 deletions
diff --git a/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/CreateContainerCommandImpl.java b/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/CreateContainerCommandImpl.java index 6f9edc1e106..59d7b987093 100644 --- a/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/CreateContainerCommandImpl.java +++ b/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/CreateContainerCommandImpl.java @@ -32,6 +32,7 @@ class CreateContainerCommandImpl implements Docker.CreateContainerCommand { private Optional<String> networkMode = Optional.empty(); private Optional<String> ipv4Address = Optional.empty(); private Optional<String> ipv6Address = Optional.empty(); + private Optional<String[]> entrypoint = Optional.empty(); CreateContainerCommandImpl(DockerClient docker, DockerImage dockerImage, @@ -56,6 +57,12 @@ class CreateContainerCommandImpl implements Docker.CreateContainerCommand { return this; } + @Override + public Docker.CreateContainerCommand withEntrypoint(String... entrypoint) { + this.entrypoint = Optional.of(entrypoint); + return this; + } + @Override public Docker.CreateContainerCommand withEnvironment(String name, String value) { @@ -119,6 +126,7 @@ class CreateContainerCommandImpl implements Docker.CreateContainerCommand { if (networkMode.isPresent()) containerCmd = containerCmd.withNetworkMode(networkMode.get()); if (ipv4Address.isPresent()) containerCmd = containerCmd.withIpv4Address(ipv4Address.get()); if (ipv6Address.isPresent()) containerCmd = containerCmd.withIpv6Address(ipv6Address.get()); + if (entrypoint.isPresent()) containerCmd = containerCmd.withEntrypoint(entrypoint.get()); return containerCmd; } @@ -126,7 +134,7 @@ class CreateContainerCommandImpl implements Docker.CreateContainerCommand { /** Maps ("--env", {"A", "B", "C"}) to "--env A --env B --env C ". */ private String toRepeatedOption(String option, List<String> optionValues) { StringBuilder builder = new StringBuilder(); - optionValues.stream().forEach(optionValue -> builder.append(option).append(" ").append(optionValue).append(" ")); + optionValues.forEach(optionValue -> builder.append(option).append(" ").append(optionValue).append(" ")); return builder.toString(); } @@ -153,6 +161,7 @@ class CreateContainerCommandImpl implements Docker.CreateContainerCommand { + toOptionalOption("--net", networkMode) + toOptionalOption("--ip", ipv4Address) + toOptionalOption("--ip6", ipv6Address) + + toOptionalOption("--entrypoint", entrypoint) + dockerImage.asString(); } diff --git a/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/Docker.java b/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/Docker.java index 5720b18ac57..c7ef19ccb2a 100644 --- a/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/Docker.java +++ b/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/Docker.java @@ -1,6 +1,7 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.hosted.dockerapi; +import java.io.File; import java.net.InetAddress; import java.util.List; import java.util.Map; @@ -21,6 +22,7 @@ public interface Docker { CreateContainerCommand withNetworkMode(String mode); CreateContainerCommand withIpAddress(InetAddress address); CreateContainerCommand withUlimit(String name, int softLimit, int hardLimit); + CreateContainerCommand withEntrypoint(String... entrypoint); void create(); } @@ -68,6 +70,8 @@ public interface Docker { void deleteImage(DockerImage dockerImage); + void buildImage(File dockerfile, DockerImage dockerImage); + /** * Deletes the local images that are currently not in use by any container and not in the except set. */ diff --git a/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/DockerImpl.java b/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/DockerImpl.java index 464c79be874..80bcbeb6537 100644 --- a/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/DockerImpl.java +++ b/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/DockerImpl.java @@ -15,6 +15,7 @@ import com.github.dockerjava.core.DefaultDockerClientConfig; import com.github.dockerjava.core.DockerClientImpl; import com.github.dockerjava.core.RemoteApiVersion; import com.github.dockerjava.core.async.ResultCallbackTemplate; +import com.github.dockerjava.core.command.BuildImageResultCallback; import com.github.dockerjava.core.command.ExecStartResultCallback; import com.github.dockerjava.core.command.PullImageResultCallback; import com.github.dockerjava.jaxrs.JerseyDockerCmdExecFactory; @@ -28,6 +29,7 @@ import com.yahoo.vespa.hosted.dockerapi.metrics.MetricReceiverWrapper; import javax.annotation.concurrent.GuardedBy; import java.io.ByteArrayOutputStream; +import java.io.File; import java.io.IOException; import java.net.Inet6Address; import java.net.InetAddress; @@ -254,11 +256,9 @@ public class DockerImpl implements Docker { return new ContainerStatsImpl(statsCallback.stats.getNetworks(), statsCallback.stats.getCpuStats(), statsCallback.stats.getMemoryStats(), statsCallback.stats.getBlkioStats()); - } catch (DockerException e) { + } catch (DockerException | InterruptedException e) { numberOfDockerDaemonFails.add(); throw new RuntimeException("Failed to get container stats", e); - } catch (InterruptedException e) { - throw new RuntimeException("Failed to get container stats in time", e); } } @@ -379,6 +379,17 @@ public class DockerImpl implements Docker { } } + @Override + public void buildImage(File dockerfile, DockerImage image) { + try { + dockerClient.buildImageCmd(dockerfile).withTag(image.asString()) + .exec(new BuildImageResultCallback()).awaitCompletion(); + } catch (DockerException | InterruptedException e) { + numberOfDockerDaemonFails.add(); + throw new RuntimeException("Failed to build image " + image.asString(), e); + } + } + private Map<String, Image> filterOutImagesUsedByContainers( Map<String, Image> dockerImagesByImageId, List<com.github.dockerjava.api.model.Container> containerList) { Map<String, Image> filteredDockerImagesByImageId = new HashMap<>(dockerImagesByImageId); @@ -458,7 +469,7 @@ public class DockerImpl implements Docker { @Override public void deleteUnusedDockerImages(Set<DockerImage> except) { - getUnusedDockerImages(except).stream().forEach(this::deleteImage); + getUnusedDockerImages(except).forEach(this::deleteImage); } private class ImagePullCallback extends PullImageResultCallback { diff --git a/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/DockerTestUtils.java b/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/DockerTestUtils.java index fadfbc2d9bd..9af564ef23a 100644 --- a/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/DockerTestUtils.java +++ b/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/DockerTestUtils.java @@ -2,7 +2,6 @@ package com.yahoo.vespa.hosted.dockerapi; import com.github.dockerjava.api.model.Network; -import com.github.dockerjava.core.command.BuildImageResultCallback; import com.yahoo.metrics.simple.MetricReceiver; import com.yahoo.vespa.hosted.dockerapi.metrics.MetricReceiverWrapper; @@ -62,9 +61,9 @@ public class DockerTestUtils { .withName(DockerImpl.DOCKER_CUSTOM_MACVLAN_NETWORK_NAME).withDriver("bridge").withIpam(ipam).exec(); } - public static void createDockerImage(DockerImpl docker, DockerImage dockerImage) throws IOException, ExecutionException, InterruptedException { + public static void buildSimpleHttpServerDockerImage(DockerImpl docker, DockerImage dockerImage) throws IOException, ExecutionException, InterruptedException { try { - docker.deleteImage(new DockerImage(dockerImage.asString())); + docker.deleteImage(dockerImage); } catch (Exception e) { if (! e.getMessage().equals("Failed to delete docker image " + dockerImage.asString())) { throw e; @@ -72,10 +71,8 @@ public class DockerTestUtils { } // Build the image locally - File dockerFilePath = new File("src/test/resources/simple-ipv6-server"); - docker.dockerClient - .buildImageCmd(dockerFilePath) - .withTag(dockerImage.asString()).exec(new BuildImageResultCallback()).awaitCompletion(); + File dockerFileStream = new File("src/test/resources/simple-ipv6-server"); + docker.buildImage(dockerFileStream, dockerImage); } private enum OS { Linux, Mac_OS_X, Unsupported } diff --git a/docker-api/src/test/java/com/yahoo/vespa/hosted/dockerapi/DockerTest.java b/docker-api/src/test/java/com/yahoo/vespa/hosted/dockerapi/DockerTest.java index 0ad369fb84c..a4e1b775919 100644 --- a/docker-api/src/test/java/com/yahoo/vespa/hosted/dockerapi/DockerTest.java +++ b/docker-api/src/test/java/com/yahoo/vespa/hosted/dockerapi/DockerTest.java @@ -159,8 +159,7 @@ public class DockerTest { assumeTrue(DockerTestUtils.dockerDaemonIsPresent()); docker = DockerTestUtils.getDocker(); - DockerTestUtils.createDockerTestNetworkIfNeeded(docker); - DockerTestUtils.createDockerImage(docker, dockerImage); + DockerTestUtils.buildSimpleHttpServerDockerImage(docker, dockerImage); } // Clean up any non deleted containers from previous tests diff --git a/node-admin/Dockerfile.template b/node-admin/Dockerfile.template index 485518cb86a..4494ac700cf 100644 --- a/node-admin/Dockerfile.template +++ b/node-admin/Dockerfile.template @@ -17,8 +17,8 @@ RUN yum install -y tcpdump ADD include/root-bashrc /root/.bashrc # Override what's in the base image with local versions: -ADD target/node-admin-jar-with-dependencies.jar $VESPA_HOME/lib/jars/node-admin-jar-with-dependencies.jar ADD src/main/application/services.xml $VESPA_HOME/conf/node-admin-app/services.xml +ADD target/node-admin-jar-with-dependencies.jar $VESPA_HOME/lib/jars/node-admin-jar-with-dependencies.jar ADD scripts/configure-container-networking.py $VESPA_HOME/libexec/vespa/node-admin/configure-container-networking.py # For deploying sample application. @@ -34,3 +34,6 @@ ADD include/start-services.sh /usr/local/bin/start-services.sh # Make config-server aware of node flavor 'docker'. ADD include/node-flavors.xml $VESPA_HOME/conf/configserver-app/node-flavors.xml + +# Make config-server also listen to 4080 +ADD include/http-server.xml $VESPA_HOME/conf/configserver-app/hosted-vespa/http-server.xml
\ No newline at end of file diff --git a/node-admin/include/http-server.xml b/node-admin/include/http-server.xml new file mode 100644 index 00000000000..f77d392de97 --- /dev/null +++ b/node-admin/include/http-server.xml @@ -0,0 +1 @@ +<server port="4080" id="configserver-real" />
\ No newline at end of file diff --git a/node-admin/include/start-config-server.sh b/node-admin/include/start-config-server.sh index a84b0454db3..19d1d44cc1c 100755 --- a/node-admin/include/start-config-server.sh +++ b/node-admin/include/start-config-server.sh @@ -62,19 +62,6 @@ findroot export LC_ALL=C -function WaitUntilHostIsReachable { - # Address may be IP or hostname. - local address="$1" - - echo -n "Will wait until $address is reachable... " - while ! ping -q -c 1 -W 3 "$address" &>/dev/null - do - echo "not done (will retry)" - sleep 1 - done - echo "Done" -} - function VerifyRequiredEnvironmentVariablesAreSet { if [ -z "$HOSTED_VESPA_REGION" ] then @@ -84,10 +71,6 @@ function VerifyRequiredEnvironmentVariablesAreSet { then Fail "Environment variable CONFIG_SERVER_HOSTNAME is not set" fi - if [ -z "$HOST_BRIDGE_IP" ] - then - Fail "Environment variable HOST_BRIDGE_IP is not set" - fi case "$HOSTED_VESPA_ENVIRONMENT" in prod|test|dev|staging|perf) : ;; @@ -116,10 +99,6 @@ function InternalMain { # Can also set jvmargs if necessary: # set cloudconfig_server.jvmargs=-Dvespa.freezedetector.disable=true -XX:NewRatio=1 -verbose:gc -XX:+PrintGCDateStamps -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -Xms6g -Xmx6g - # The network is set up asynchronously and from outside of this - # container. Wait until it's done. - WaitUntilHostIsReachable "$HOST_BRIDGE_IP" - yinst start cloudconfig_server touch $VESPA_HOME/logs/jdisc_core/jdisc_core.log diff --git a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/docker/LocalZoneUtils.java b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/docker/LocalZoneUtils.java new file mode 100644 index 00000000000..69681a3f72a --- /dev/null +++ b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/docker/LocalZoneUtils.java @@ -0,0 +1,71 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.hosted.node.admin.docker; + +import com.yahoo.vespa.hosted.dockerapi.ContainerName; +import com.yahoo.vespa.hosted.dockerapi.Docker; +import com.yahoo.vespa.hosted.dockerapi.DockerImage; +import com.yahoo.vespa.hosted.dockerapi.DockerImpl; +import com.yahoo.vespa.hosted.node.admin.util.Environment; + +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.UnknownHostException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +/** + * @author freva + */ +public class LocalZoneUtils { + public static final String CONFIG_SERVER_HOSTNAME = "config-server"; + public static final DockerImage VESPA_LOCAL_IMAGE = new DockerImage("vespa-local:latest"); + + private static final String VESPA_HOME = "/home/y"; + private static final String APP_HOSTNAME_PREFIX = "cnode-"; + + public static boolean startConfigServer(Docker docker, Environment environment) throws UnknownHostException { + ContainerName confingServerContainerName = new ContainerName(CONFIG_SERVER_HOSTNAME); + docker.createContainerCommand(VESPA_LOCAL_IMAGE, confingServerContainerName, CONFIG_SERVER_HOSTNAME) + .withNetworkMode(DockerImpl.DOCKER_CUSTOM_MACVLAN_NETWORK_NAME) + .withIpAddress(environment.getInetAddressForHost(CONFIG_SERVER_HOSTNAME)) + .withVolume("/etc/hosts", "/etc/hosts") + .withEnvironment("HOSTED_VESPA_ENVIRONMENT", environment.getEnvironment()) + .withEnvironment("HOSTED_VESPA_REGION", environment.getRegion()) + .withEnvironment("CONFIG_SERVER_HOSTNAME", CONFIG_SERVER_HOSTNAME) + .withEnvironment("VESPA_HOME", VESPA_HOME) + .withEntrypoint("/usr/local/bin/start-config-server.sh") + .withUlimit("nofile", 16384, 16384) + .withUlimit("nproc", 409600, 409600) + .withUlimit("core", -1, -1) + .create(); + + docker.startContainer(confingServerContainerName); + + try { + URL url = new URL("http://" + CONFIG_SERVER_HOSTNAME + ":4080/state/v1/health"); + for (int i = 0; i < 10; i++) { + Thread.sleep(50); + HttpURLConnection http = (HttpURLConnection) url.openConnection(); + if (http.getResponseCode() == 200) return true; + } + } catch (IOException | InterruptedException ignored) { } + + return false; + } + + public static void buildVespaLocalDockerImage(Docker docker, DockerImage vespaBaseImage) throws IOException { + Path dockerfileTemplatePath = Paths.get("Dockerfile.template"); + Path dockerfilePath = Paths.get("Dockerfile"); + + String dockerfileTemplate = new String(Files.readAllBytes(dockerfileTemplatePath)) + .replaceAll("\\$NODE_ADMIN_FROM_IMAGE", vespaBaseImage.asString()) + .replaceAll("\\$VESPA_HOME", VESPA_HOME); + + Files.write(dockerfilePath, dockerfileTemplate.getBytes()); + + docker.buildImage(dockerfilePath.toAbsolutePath().getParent().toFile(), VESPA_LOCAL_IMAGE); + } +} + diff --git a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/integrationTests/DockerMock.java b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/integrationTests/DockerMock.java index 656b3e50a3a..8be3ec0fea0 100644 --- a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/integrationTests/DockerMock.java +++ b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/integrationTests/DockerMock.java @@ -7,6 +7,7 @@ import com.yahoo.vespa.hosted.dockerapi.Docker; import com.yahoo.vespa.hosted.dockerapi.DockerImage; import com.yahoo.vespa.hosted.dockerapi.ProcessResult; +import java.io.File; import java.net.InetAddress; import java.util.ArrayList; import java.util.Arrays; @@ -139,6 +140,11 @@ public class DockerMock implements Docker { } @Override + public void buildImage(File dockerfile, DockerImage dockerImage) { + + } + + @Override public void deleteUnusedDockerImages(Set<DockerImage> except) { } @@ -190,6 +196,11 @@ public class DockerMock implements Docker { } @Override + public CreateContainerCommand withEntrypoint(String... entrypoint) { + return this; + } + + @Override public void create() { } |