Maison  >  Article  >  développement back-end  >  Conteneurs de test Golang, impossible de faire fonctionner le réseau

Conteneurs de test Golang, impossible de faire fonctionner le réseau

WBOY
WBOYavant
2024-02-14 13:30:091060parcourir

Golang testcontainers,无法使网络工作

l'éditeur php Strawberry a rencontré un problème lors de l'utilisation des conteneurs de test Golang, c'est-à-dire qu'il n'a pas pu faire fonctionner le réseau correctement. Golang testcontainers est un outil permettant d'exécuter des conteneurs dans des tests, qui aide les développeurs à démarrer et à détruire rapidement des conteneurs dans un environnement de test. Cependant, en utilisation réelle, l'éditeur PHP Strawberry a constaté que la fonction réseau ne pouvait pas être utilisée normalement dans le conteneur, ce qui a provoqué certains problèmes lors du test. Ensuite, nous explorerons ensemble la solution à ce problème.

Contenu de la question

J'essaie de créer des tests dans mon microservice et je souhaite créer un réseau auquel j'attacherai mon conteneur de test de base de données (postgres) et mon conteneur de test de microservice. Peu importe ce que j'essaie, je n'arrive pas à connecter mon microservice à la base de données. Mon microservice est Golang utilisant Fiber et Gorm. J'essaie de me connecter à la base de données dans le fichier de configuration db.go comme ceci :

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
}

Voici à quoi ressemble mon conteneur de test :

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,
    })

C'est peut-être parce que je ne comprends tout simplement pas ce qui se passe pendant le processus de connexion réseau dans Docker, mais je suis vraiment perdu et lorsque j'ai configuré l'environnement pour HOST et DB_PORT (j'ai essayé toutes les combinaisons sous le soleil), il refuse les microservices connectés à la base de données

Dans le conteneur de test du microservice j'ai essayé :

"HOST":              prescriptionDBHost,
"DB_PORT":           prescriptionDBPort.Port(),
La méthode d'extraction de

prescriptionDBHost est :

prescriptionDBHost, err := prescriptionDBContainer.Name(context.Background())

entraîne le message d'erreur : 

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

Ensuite, j'ai essayé de supprimer le "/" du nom d'hôte, par exemple :

"HOST":              strings.Trim(prescriptionDBHost,"/"),
"DB_PORT":           prescriptionDBPort.Port(),

J'ai aussi essayé :

"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(),

Les 4 derniers exemples ici entraînent tous une sorte d'erreur TCP de connexion, par exemple :

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)

J'ai également débogué et arrêté le testcontainer après avoir créé le conteneur de base de données, puis je suis allé sur mon microservice et j'ai codé en dur une connexion au conteneur avec DB_HOST=localhost et port= et cela a fonctionné, donc je suis vraiment perdu sur ce qui se passe. Quelque chose ne va pas . La seule chose à laquelle je peux penser est que le conteneur de microservices n'est pas connecté au réseau avant d'essayer de se connecter à la base de données ? J'ai effectué une vérification du réseau Docker et je peux voir que le conteneur de base de données est attaché, mais le microservice ne s'attache jamais (mais peut-être est-ce juste pour d'autres raisons ?).

Solution

Vous pouvez faire ceci :

prescriptionDBContainer, err := testcontainers.GenericContainer(context.Background(), testcontainers.GenericContainerRequest{
    ContainerRequest: testcontainers.ContainerRequest{
        Image:        "postgres",
        ExposedPorts: []string{"5432/tcp"},
        Env: map[string]string{
            "POSTGRES_USER":     "postgres",
            "POSTGRES_PASSWORD": "password",
            "POSTGRES_DB":       "prescription",
        },
        Networks:       []string{networkName},
        NetworkAliases: map[string][]string{networkName: []string{"postgres"}},
        WaitingFor: wait.ForAll(
            wait.ForLog("database system is ready to accept connections"),
            wait.ForListeningPort("5432/tcp"),
        ),
    },
    Started: true,
})
if err != nil {
    t.Fatal(err)
}

prescriptionContainer, err := testcontainers.GenericContainer(context.Background(), testcontainers.GenericContainerRequest{
    ContainerRequest: testcontainers.ContainerRequest{
        FromDockerfile: testcontainers.FromDockerfile{Context: "./testapp"},
        ExposedPorts:   []string{"8080/tcp"},
        Networks:       []string{networkName},
        NetworkAliases: map[string][]string{networkName: []string{"blah"}},
        Env: map[string]string{
            "DATABASE_URL": "postgres://postgres:password@postgres:5432/prescription",
        },
        WaitingFor: wait.ForListeningPort("8080/tcp"),
    },
    Started: true,
})

AttentionNetworkAliases的配置方式;在您的代码中,您将两者都设置为 db-network 但是,我想,这是由于误解。该设置配置了一个可以引用容器的别名(在本例中,我使用 postgres 作为 postgres 容器;这意味着当连接 HOST 时,根据上面示例中使用的 URL,postgres 将是 postgres).

Comme alternative, vous pouvez utiliser le port, err :=处方DBContainer.MappedPort(context.Background(), "5432/tcp") 获取主机上公开的端口,然后连接到端口上的 host.docker.internal port.Port().当被测试的应用程序在主机上而不是在容器中运行时,经常使用此方法(但在这种情况下,您将连接到 localhost 并使用从 MappedPort()rapport renvoyé).

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer