Skip to content

By default the Docker run will make use of in-memory mount destinations #30

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

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Changelog
All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## Unreleased

## [0.7.1] - 2018-01-25
### Fixed
- Issue [#29](https://github.com/42BV/spring-boot-docker-postgres/issues/29), **By default use in-memory destination mounts for Docker run**; by default the Docker run will make use of in-memory mounts for the application and data path in the standard Postgres Docker image. If in-memory must be disabled, it can be done in the properties. Custom paths can be passed as a list under the inMemoryMountDestinations list.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-boot-docker-postgres</artifactId>
<version>0.7.1-SNAPSHOT</version>
<version>0.7.1</version>
<packaging>jar</packaging>
<groupId>nl.42</groupId>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@

public class DockerPostgresBootSequence {

private static final Integer DEFAULT_PORT = 5432;
private static final Logger LOGGER = LoggerFactory.getLogger(DockerPostgresBootSequence.class);

private final DockerPostgresProperties properties;
Expand All @@ -25,31 +24,30 @@ public DockerPostgresBootSequence(DockerPostgresProperties properties, DataSourc

public DockerStartContainerCommand execute() throws IOException, InterruptedException {

properties.init(dataSourceProperties.getUrl());
LOGGER.info("| Docker Postgres Properties");
LOGGER.info("| * Image name: " + properties.getImageName());
LOGGER.info("| * Image version: " + properties.getImageVersion());
LOGGER.info("| * Force clean: " + properties.isForceClean());
LOGGER.info("| * Stop port occupying container: " + properties.isStopPortOccupyingContainer());
LOGGER.info("| * Timeout: " + properties.getTimeout());
LOGGER.info("| * Container name: " + properties.getContainerName());
if (properties.getPort() == null) {
if (dataSourceProperties.getUrl() != null) {
properties.setPort(determinePort(dataSourceProperties.getUrl()));
// Scrap the port from the JDBC URL
} else {
properties.setPort(DEFAULT_PORT);
}
}
LOGGER.info("| * Port: " + properties.getPort());
LOGGER.info("| * Password: " + properties.getPassword());
LOGGER.info("| * Startup Verification Text: [" + properties.getStartupVerificationText() + "]");
LOGGER.info("| * Times expected verification text: " + properties.getTimesExpectedVerificationText() + "x");
LOGGER.info("| * After verification wait: " + properties.getAfterVerificationWait() + "ms");
LOGGER.info("| * Docker command: [" + properties.getDockerCommand() + "]");
LOGGER.info("| * Use Docker command: [" + properties.getUseDockerCommand() + "]");
LOGGER.info("| * Custom variables (" + properties.getCustomVariables().size() + ")");
for (String key : properties.getCustomVariables().keySet()) {
LOGGER.info("| - " + key + ": " + properties.getCustomVariables().get(key));
}
LOGGER.info("| * In memory: " + properties.isInMemory());
LOGGER.info("| * In memory mount destinations");
for (String inMemoryMountDestination : properties.getInMemoryMountDestinations()) {
LOGGER.info("| - " + inMemoryMountDestination);
}
LOGGER.info("| * Std out: " + properties.getStdOutFilename());
LOGGER.info("| * Std err: " + properties.getStdErrFilename());

Expand Down Expand Up @@ -106,18 +104,6 @@ public DockerStartContainerCommand execute() throws IOException, InterruptedExce
return postgresContainer;
}

private Integer determinePort(String url) {
if (url == null || url.length() == 0) {
throw new ExceptionInInitializerError("spring.datasource.url is empty. No port could be derived.");
}
int lastColonPos = url.lastIndexOf(':');
int slashAfterPortPos = url.indexOf('/', lastColonPos);
if (lastColonPos == -1 || slashAfterPortPos == -1 || slashAfterPortPos < lastColonPos + 2) {
throw new ExceptionInInitializerError("spring.datasource.url does not have port information: [" + url + "]. No port could be derived.");
}
return Integer.parseInt(url.substring(lastColonPos + 1, slashAfterPortPos));
}

private void applyAfterVerificationWait(Integer afterVerificationWait) throws InterruptedException {
if (afterVerificationWait > 0) {
LOGGER.info("| Applying after verification wait of " + afterVerificationWait + "ms");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
package nl._42.boot.docker.postgres;

import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.context.properties.ConfigurationProperties;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@ConfigurationProperties(prefix = "docker.postgres", ignoreUnknownFields = false)
public class DockerPostgresProperties {

private static final String DEFAULT_PORT = "5432";
private static final String POSTGRES_BASE_FOLDER_APPLICATION = "/app";
private static final String POSTGRES_BASE_FOLDER_DATA = "/var/lib/postgresql/data";
private static final String IN_MEMORY_TEMPLATE = "[IN_MEMORY_TEMPLATE]";
private static final String VAR_IN_MEMORY_MOUNT_DESTINATION = "inMemoryMountDestination";

private boolean enabled = true;

private String stdOutFilename = "docker-std-out.log";
Expand All @@ -28,7 +37,9 @@ public class DockerPostgresProperties {

private Integer timesExpectedVerificationText = 2;

private String dockerCommand = "docker run --rm --tty -e POSTGRES_PASSWORD=${password} -p ${port}:5432 --name ${containerName} ${imageName}:${imageVersion}";
private String dockerCommand = "docker run --rm --tty -e POSTGRES_PASSWORD=${password} -p ${port}:5432 --name ${containerName} " + IN_MEMORY_TEMPLATE + " ${imageName}:${imageVersion}";

private String useDockerCommand;

private Integer timeout = 300000; // 5 minutes because of time required for downloading?

Expand All @@ -42,8 +53,22 @@ public class DockerPostgresProperties {

private String containerOccupyingPort = null;

private boolean inMemory = true;

private String inMemoryMountDestinationCommand =
"--mount type=tmpfs,destination=${" + VAR_IN_MEMORY_MOUNT_DESTINATION + "_@N}";

private List<String> inMemoryMountDestinations = new ArrayList<>();

private Map<String, String> customVariables = new HashMap<>();

Map<String,String> properties = null;

public DockerPostgresProperties() {
inMemoryMountDestinations.add(POSTGRES_BASE_FOLDER_APPLICATION);
inMemoryMountDestinations.add(POSTGRES_BASE_FOLDER_DATA);
}

public boolean isEnabled() {
return enabled;
}
Expand Down Expand Up @@ -188,8 +213,57 @@ public void setForceCleanAfterwards(boolean forceCleanAfterwards) {
this.forceCleanAfterwards = forceCleanAfterwards;
}

public boolean isInMemory() {
return inMemory;
}

public void setInMemory(boolean inMemory) {
this.inMemory = inMemory;
}

public List<String> getInMemoryMountDestinations() {
return inMemoryMountDestinations;
}

public void setInMemoryMountDestinations(List<String> inMemoryMountDestinations) {
this.inMemoryMountDestinations = inMemoryMountDestinations;
}

public String getInMemoryMountDestinationCommand() {
return inMemoryMountDestinationCommand;
}

public void setInMemoryMountDestinationCommand(String inMemoryMountDestinationCommand) {
this.inMemoryMountDestinationCommand = inMemoryMountDestinationCommand;
}

public String getUseDockerCommand() {
if (useDockerCommand == null) {
getProperties();
}
return useDockerCommand;
}

public Map<String, String> getProperties() {
Map<String,String> properties = new HashMap<>();
return properties;
}

public void init(String datasourceUrl) {
initPort(datasourceUrl);
properties = new HashMap<>();
this.useDockerCommand = replaceInMemoryTemplate(properties, getDockerCommand());
initProperties();
}

private void initPort(String datasourceUrl) {
if (getPort() != null) {
return;
}
// Scrape the port from the JDBC URL
setPort(determinePort(datasourceUrl != null ? datasourceUrl : DEFAULT_PORT));
}

private void initProperties() {
properties.put("stdOutFilename", getStdOutFilename());
properties.put("stdErrFilename", getStdErrFilename());
properties.put("timeout", getTimeout().toString());
Expand All @@ -202,13 +276,50 @@ public Map<String, String> getProperties() {
properties.put("timesExpectedVerificationText", getTimesExpectedVerificationText().toString());
properties.put("afterVerificationWait", getAfterVerificationWait().toString());
properties.put("dockerCommand", getDockerCommand());
properties.put("useDockerCommand", getUseDockerCommand());
properties.put("forceClean", Boolean.toString(isForceClean()));
properties.put("forceCleanAfterwards", Boolean.toString(isForceCleanAfterwards()));
properties.put("stopPortOccupyingContainer", Boolean.toString(isStopPortOccupyingContainer()));
properties.put("afterVerificationWait", Boolean.toString(isForceClean()));
properties.put("containerOccupyingPort", getContainerOccupyingPort());
properties.put("inMemory", Boolean.toString(isInMemory()));
properties.putAll(getCustomVariables());
return properties;
}

private String replaceInMemoryTemplate(Map<String, String> properties, String dockerCommand) {
int templatePosition = dockerCommand.indexOf(IN_MEMORY_TEMPLATE);
if (templatePosition == -1) {
return dockerCommand;
}
List<String> inMemoryCommands = new ArrayList<>();
if (inMemory) {
Integer destinationNumber = 1;
for (String inMemoryMountDestination : getInMemoryMountDestinations()) {
inMemoryCommands.add(inMemoryMountDestinationCommand.replace(
"@N",
destinationNumber.toString()));
properties.put(
VAR_IN_MEMORY_MOUNT_DESTINATION + "_" + destinationNumber,
inMemoryMountDestination);
destinationNumber++;
}
}
return
dockerCommand.substring(0, templatePosition) +
StringUtils.join(inMemoryCommands, ' ') +
dockerCommand.substring(templatePosition + IN_MEMORY_TEMPLATE.length());
}

private Integer determinePort(String url) {
if (url == null || url.length() == 0) {
throw new ExceptionInInitializerError("spring.datasource.url is empty. No port could be derived.");
}
int lastColonPos = url.lastIndexOf(':');
int slashAfterPortPos = url.indexOf('/', lastColonPos);
if (lastColonPos == -1 || slashAfterPortPos == -1 || slashAfterPortPos < lastColonPos + 2) {
throw new ExceptionInInitializerError("spring.datasource.url does not have port information: [" + url + "]. No port could be derived.");
}
return Integer.parseInt(url.substring(lastColonPos + 1, slashAfterPortPos));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public class DockerStartContainerCommand extends DockerInfiniteProcessRunner {
private static final Logger LOGGER = LoggerFactory.getLogger(DockerStartContainerCommand.class);

public DockerStartContainerCommand(DockerPostgresProperties properties, boolean imageDownloaded) {
super(properties.getDockerCommand(), properties, imageDownloaded);
super(properties.getUseDockerCommand(), properties, imageDownloaded);

if (!imageDownloaded) {
LOGGER.info("| Process will download (no visual feedback, please be patient)...");
Expand Down