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

docs: networking basics #612

Merged
merged 3 commits into from Nov 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
15 changes: 14 additions & 1 deletion docker_test.go
Expand Up @@ -5,8 +5,8 @@ import (
"database/sql"
"errors"
"fmt"

// Import mysql into the scope of this package (required)
_ "github.com/go-sql-driver/mysql"
"io"
"io/ioutil"
"math/rand"
Expand All @@ -18,6 +18,8 @@ import (
"testing"
"time"

_ "github.com/go-sql-driver/mysql"

"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/strslice"
"github.com/docker/go-units"
Expand Down Expand Up @@ -54,6 +56,7 @@ func init() {
}
}

// testNetworkAliases {
func TestContainerAttachedToNewNetwork(t *testing.T) {
aliases := []string{"alias1", "alias2", "alias3"}
networkName := "new-network"
Expand Down Expand Up @@ -131,6 +134,8 @@ func TestContainerAttachedToNewNetwork(t *testing.T) {
}
}

// }

func TestContainerWithHostNetworkOptions(t *testing.T) {
absPath, err := filepath.Abs("./testresources/nginx-highport.conf")
if err != nil {
Expand Down Expand Up @@ -981,6 +986,7 @@ func TestContainerCreationWaitsForLogContextTimeout(t *testing.T) {
}

func TestContainerCreationWaitsForLog(t *testing.T) {
// exposePorts {
ctx := context.Background()
req := ContainerRequest{
Image: "docker.io/mysql:latest",
Expand All @@ -996,13 +1002,18 @@ func TestContainerCreationWaitsForLog(t *testing.T) {
ContainerRequest: req,
Started: true,
})
// }

require.NoError(t, err)
terminateContainerOnEnd(t, ctx, mysqlC)

// containerHost {
host, _ := mysqlC.Host(ctx)
// }
// mappedPort {
p, _ := mysqlC.MappedPort(ctx, "3306/tcp")
port := p.Int()
// }
connectionString := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?tls=skip-verify",
"root", "password", host, port, "database")

Expand Down Expand Up @@ -1368,6 +1379,7 @@ func TestContainerCreationWaitsForLogAndPort(t *testing.T) {
require.NoError(t, err)
terminateContainerOnEnd(t, ctx, mysqlC)

// buildingAddresses {
host, _ := mysqlC.Host(ctx)
p, _ := mysqlC.MappedPort(ctx, "3306/tcp")
port := p.Int()
Expand All @@ -1378,6 +1390,7 @@ func TestContainerCreationWaitsForLogAndPort(t *testing.T) {
if err != nil {
t.Fatal(err)
}
// }

defer db.Close()

Expand Down
56 changes: 56 additions & 0 deletions docs/features/networking.md
@@ -0,0 +1,56 @@
# Networking and communicating with containers

## Exposing container ports to the host

It is common to want to connect to a container from your test process, running on the test 'host' machine.
For example, you may be testing some code that needs to connect to a backend or data store container.

Generally, each required port needs to be explicitly exposed. For example, we can specify one or more ports as follows:

<!--codeinclude-->
[Exposing ports](../../docker_test.go) inside_block:exposePorts
<!--/codeinclude-->

Note that this exposed port number is from the *perspective of the container*.

*From the host's perspective* Testcontainers actually exposes this on a random free port.
This is by design, to avoid port collisions that may arise with locally running software or in between parallel test runs.

Because there is this layer of indirection, it is necessary to ask Testcontainers for the actual mapped port at runtime.
This can be done using the `MappedPort` function, which takes the original (container) port as an argument:

<!--codeinclude-->
[Retrieving actual ports at runtime](../../docker_test.go) inside_block:mappedPort
<!--/codeinclude-->

!!! warning
Because the randomised port mapping happens during container startup, the container must be running at the time `MappedPort` is called.
You may need to ensure that the startup order of components in your tests caters for this.

## Getting the container host

When running with a local Docker daemon, exposed ports will usually be reachable on `localhost`.
However, in some CI environments they may instead be reachable on a different host.

As such, Testcontainers provides a convenience function to obtain an address on which the container should be reachable from the host machine.

<!--codeinclude-->
[Getting the container host](../../docker_test.go) inside_block:containerHost
<!--/codeinclude-->

It is normally advisable to use `Host` and `MappedPort` together when constructing addresses - for example:

<!--codeinclude-->
[Getting the container host and mapped port](../../docker_test.go) inside_block:buildingAddresses
<!--/codeinclude-->

## Advanced networking

Docker provides the ability for you to create custom networks and place containers on one or more networks. Then, communication can occur between networked containers without the need of exposing ports through the host. With Testcontainers, you can do this as well.

!!! tip
Note that _Testcontainers for Go_ allows a container to be on multiple networks including network aliases.

<!--codeinclude-->
[Creating custom networks](../../docker_test.go) inside_block:testNetworkAliases
<!--/codeinclude-->
1 change: 1 addition & 0 deletions mkdocs.yml
Expand Up @@ -30,6 +30,7 @@ nav:
- quickstart/gotest.md
- Features:
- features/creating_container.md
- features/networking.md
- features/garbage_collector.md
- features/build_from_dockerfile.md
- features/docker_compose.md
Expand Down