I am trying to create some tests in my microservice, I want to create a network, attach my db testcontainer (postgres) and my microservice testcontainer to that. Whatever I try i just cant get my microservice to connect to the database. My microservice is golang using fiber and gorm. I try to connect to the database in a db.go config file that looks like :
func SetupDB(port string, host string) *gorm.DB {
dsn := "host=" + host + " user=postgres password=password dbname=prescription port=" + port + " sslmode=disable"
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
if err != nil {
panic("error connecting to database")
}
db.AutoMigrate(&model.Prescription{})
return db
}
This is what my testcontainers look like:
prescriptionDBContainer, err := testcontainers.GenericContainer(context.Background(), testcontainers.GenericContainerRequest{
ContainerRequest: testcontainers.ContainerRequest{
Image: "postgres",
ExposedPorts: []string{postgresPort.Port()},
Env: map[string]string{
"POSTGRES_USER": "postgres",
"POSTGRES_PASSWORD": "password",
"POSTGRES_DB": "prescription",
},
Networks: []string{network.Name},
NetworkAliases: map[string][]string{
network.Name: {"db-network"},
},
WaitingFor: wait.ForAll(
wait.ForLog("database system is ready to accept connections"),
wait.ForListeningPort(postgresPort),
),
},
Started: true,
})
prescriptionContainer, err := testcontainers.GenericContainer(context.Background(), testcontainers.GenericContainerRequest{
ContainerRequest: testcontainers.ContainerRequest{
FromDockerfile: testcontainers.FromDockerfile{Context: "../../../../prescription"},
Networks: []string{network.Name},
NetworkAliases: map[string][]string{
network.Name: {"db-network"},
},
Env: map[string]string{
"POSTGRES_USER": "postgres",
"POSTGRES_PASSWORD": "password",
"POSTGRES_DB": "prescription",
"HOST": prescriptionDBHost,
"DB_PORT": prescriptionDBPort.Port(),
},
ExposedPorts: []string{pMicroPort.Port()},
WaitingFor: wait.ForListeningPort("8080"),
},
Started: true,
})
Maybe its because i dont fundamentally understand something that goes on during networking in docker, but I am really lost, when i set the env for HOST and DB_PORT (i’ve tried every combination under the sun), it refuses to connect the microservice to the database
in the testcontainer for my microservice I’ve tried :
"HOST": prescriptionDBHost,
"DB_PORT": prescriptionDBPort.Port(),
prescriptionDBHost is extracted by :
prescriptionDBHost, err := prescriptionDBContainer.Name(context.Background())
that resulted in the error message :
failed to initialize database, got error failed to connect to `host=/stoic_heyrovsky user=postgres database=prescription`: dial error (dial unix /stoic_heyrovsky/.s.PGSQL.53802: connect: no such file or directory)
panic: error connecting to database
I then tried to trim the "/" from the hostname such as:
"HOST": strings.Trim(prescriptionDBHost,"/"),
"DB_PORT": prescriptionDBPort.Port(),
I’ve also tried :
"HOST": "localhost",
"DB_PORT": prescriptionDBPort.Port(),
"HOST": "127.0.0.1",
"DB_PORT": prescriptionDBPort.Port(),
prescriptionDBHost, err := prescriptionDBContainer.ContainerIP(context.Background())
"HOST": prescriptionDBHost,
"DB_PORT": prescriptionDBPort.Port(),
The last 4 examples here have all result in some sort of dial tcp error for example like:
failed to initialize database, got error failed to connect to `host=localhost user=postgres database=prescription`: dial error (dial tcp [::1]:53921: connect: cannot assign requested address)
I’ve also debugged and stopped after the testcontainer created the database container, then went to my microservice and hardcoded connecting to that container using DB_HOST=localhost and port= and that was successful so I’m really lost in what is going wrong. The only thing I can think of is that the microservice container is not being attached to the network before it tries to connect to the database? I did a docker network inspect and i can see that the database container is attached but the microservice never gets attached (but maybe that’s just because of something else?).
2
Answers
You can do something like this:
Note the way
NetworkAliases
is configured; in your code you are setting both todb-network
but, I guess, this is due to a misunderstanding. The setting configures an alias that the container can be referenced as (in this case I’m usingpostgres
for the postgres container; that means that when connectingHOST
would bepostgres
as per the URL used in the above example).As an alternative you could use
port, err := prescriptionDBContainer.MappedPort(context.Background(), "5432/tcp")
to get the port exposed on the host and then connect tohost.docker.internal
on portport.Port()
. This method is frequently used when the app being tested is running on the host rather than in a container (but in that case you would connect tolocalhost
and use the report returned fromMappedPort()
).You could leverage the existing postgres module and the functional option to create a network including aliases: https://golang.testcontainers.org/modules/postgres/#withnetwork
Because containers would live in the same network, they can see each other by host and known ports.