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

Add optional OkHttp transport (instead of Netty) #710

Merged
merged 34 commits into from
Jun 13, 2018
Merged

Add optional OkHttp transport (instead of Netty) #710

merged 34 commits into from
Jun 13, 2018

Conversation

bsideup
Copy link
Member

@bsideup bsideup commented May 28, 2018

This PR introduces OkHttp transport as an alternative to Netty. It's fully shaded (including SBT's file sockets) and doesn't add dependencies to the project.
OkHttp is a modern JVM http library, it's super easy to use custom socket factories (like unix socket or npipe), easy to shade (zero dependencies, only okhttp & okio) and work with.

Coverage:
macOS:

  • Docker Machine + TLS certs
  • Docker for Mac + unix socket
  • Docker for Mac + TCP

Linux (based on CI envs):

  • Native Docker + unix socket

Windows:

  • Docker machine + TLS certs
  • Docker for Windows + TCP
  • Docker for Windows + npipe 🎉

28.05.2018: need help to test on Windows, especially npipe

@bsideup bsideup added this to the next milestone May 28, 2018
@bsideup bsideup requested review from rnorth and kiview May 28, 2018 06:06
@@ -18,6 +18,8 @@ shadowJar {

mergeServiceFiles()

exclude 'org/newsclub/**'
Copy link
Member Author

Choose a reason for hiding this comment

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

docker-java shades it without the relocation o_O we're not using it anyways

.withDockerCmdExecFactory(new OkHttpDockerCmdExecFactory());
} else if ("netty".equals(transportType)) {
clientBuilder
.withDockerCmdExecFactory(new TestcontainersDockerCmdExecFactory());
Copy link
Contributor

Choose a reason for hiding this comment

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

maybe the TestcontainersDockerCmdExecFactory should be renamed to NettyDockerCmdExecFactory in one of the next major releases?

Copy link
Member Author

Choose a reason for hiding this comment

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

We plan to switch to okhttp by default and keep Netty as a fallback for a few releases unless we 100% that okhttp works for everyone. Once it happen, we will delete our Netty factory completely. There is also one in docker-java, this is why I named it TestcontainersDockerCmdExecFactory back then

public void test() throws InvalidConfigurationException {
try {
config = tryConfiguration(SOCKET_LOCATION);
log.info("Accessing docker with local Unix socket");
Copy link
Contributor

Choose a reason for hiding this comment

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

s/local Unix socket/Named Pipe/

SSLContext sslContext = sslConfig.getSSLContext();
if (sslContext != null) {
clientBuilder
.sslSocketFactory(sslContext.getSocketFactory(), new TrustAllX509TrustManager());
Copy link
Contributor

Choose a reason for hiding this comment

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

Not relevant for this PR, but I'm curious: why is the TrustAllX509TrustManager necessary?

Copy link
Member Author

Choose a reason for hiding this comment

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

because it is mutual TLS and we have to trust the certs from Docker as well :)

import org.jetbrains.annotations.NotNull;

@Slf4j
public class NpipeSocketClientProviderStrategy extends DockerClientProviderStrategy {
Copy link
Member

Choose a reason for hiding this comment

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

WDYT about splitting the Npipe support into seperate PR?
Would of course also mean removing the switch cases for npipe.

Copy link
Member Author

Choose a reason for hiding this comment

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

We could do that, but why?

Copy link
Member

Choose a reason for hiding this comment

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

To make the whole PR smaller, but I see that it's even more effort to put it into a separate PR now.

.getInstance(config);

String transportType = TestcontainersConfiguration.getInstance().getTransportType();
if ("okhttp".equals(transportType)) {
Copy link
Member

Choose a reason for hiding this comment

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

Nitpicky, but constants for transport types.

Copy link
Member Author

Choose a reason for hiding this comment

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

Does it really makes sense to use constants for single-use things?

Copy link
Member

Choose a reason for hiding this comment

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

IMO yes, but that's a question of personal taste 😉

}

clientBuilder
// Disable pooling
Copy link
Member

Choose a reason for hiding this comment

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

Wouldn't it be fine to use pooling?

Copy link
Member Author

Choose a reason for hiding this comment

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

file-based sockets are not poolable

super.init(dockerClientConfig);

OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder()
.readTimeout(0, TimeUnit.SECONDS)
Copy link
Member

Choose a reason for hiding this comment

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

Is it okay to have no timeout here? Are we blocking forever if the daemon isn't answering?

Copy link
Member Author

Choose a reason for hiding this comment

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

Image pulling / building sometimes takes a lot of time, and we have timeouts on our side

Copy link
Member

Choose a reason for hiding this comment

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

I was not sure if we have the timeouts already, then it makes sense.


HttpUrl.Builder baseUrlBuilder;

switch (dockerHost.getScheme()) {
Copy link
Member

Choose a reason for hiding this comment

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

Since we are having to switch statements with the same argument, WDYT about rearranging the code so we only have one? Or are there good reasons to have 2 switch statements?

Copy link
Member Author

Choose a reason for hiding this comment

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

I wanted to keep them separate to not mix the client & request builders. Also helps to understand that i.e. there is no special case for "http/https/tcp" on client builder but there is one for the request

Copy link
Member

Choose a reason for hiding this comment

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

Okay, makes sense then.

@kiview
Copy link
Member

kiview commented Jun 11, 2018

I'll try to test npipe tonight.

@kiview
Copy link
Member

kiview commented Jun 11, 2018

Quick test on Windows with this testcontainers.properties works like a charm (NpipeSocketClientProviderStrategy was automatically set after manually specifying transport.type=okhttp):

docker.client.strategy=org.testcontainers.dockerclient.NpipeSocketClientProviderStrategy
transport.type=okhttp

Expose daemon on TCP without TLS is disabled in my setup.

@bsideup bsideup merged commit 85321e1 into master Jun 13, 2018
@bsideup bsideup deleted the okhttp branch June 13, 2018 20:45
@gesellix
Copy link
Contributor

🎉 :)

@aulea aulea mentioned this pull request Sep 14, 2018
rnorth pushed a commit that referenced this pull request Sep 20, 2018
#756 tested on Windows. 
Fixed RegistryAuthLocatorTest on Windows and also allowed better fallbacks from running credential provider (to allow lookup alternative AuthConfigs), when:
1) there is no hostName, then there is no point to ask credentials
2) when credential helper response with "credentials not found in native keychain" to try other resources

Main reason for failing for me on Windows machine was #710 changes. When i used Netty or OkHttp together with npipe, then it worked fine. Yesterday evening i found out the reason and today morning i found also fix in master for that :-) - #865, breaking docker response by line breaks.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants