如何运行自定义 docker 镜像 testContainer

Posted

技术标签:

【中文标题】如何运行自定义 docker 镜像 testContainer【英文标题】:How to run a custom docker image testContainer 【发布时间】:2020-11-12 20:38:22 【问题描述】:

我浏览了多个博客和官方文档,但无法解决我的问题。我正在使用 testContainers-scala 版本 0.38.1scala 版本 2.11

我正在尝试使用 testContainer-scala 创建一个简单的测试,如下所示:

class MyServiceITSpec extends AnyFlatSpec with ForAllTestContainer 
  override val container = GenericContainer(dockerImage="my-service",
    exposedPorts = Seq(8080),
    env=(HashMap[String, String]("PARAM1" -> "value1", "PARAM2" -> "value2", "PARAM3" -> "value3")),
    waitStrategy = Wait.forHttp("/")
  )

  "GenericContainer" should "start my service and say Hello! Wassupp" in 
    assert(Source.fromInputStream(
      new URL(s"http://$container.containerIpAddress:$container.mappedPort(8080)/").openConnection().getInputStream
    ).mkString.contains("Hello! Wassupp"))
  

在上面sn-p的基础上,我的理解是这样的(错的请指正):

    端口 8155 由 docker 容器公开,并且将分配一个随机主机端口针对该端口。 我们可以将分配的端口作为 container.mappedPort 获取

在这里,我试图断言 http://localhost:mappedPort/ 返回 Hello! Wassupp

但是,我收到以下错误:

Caused by: org.testcontainers.containers.ContainerLaunchException: Could not create/start container
  at org.testcontainers.containers.GenericContainer.tryStart(GenericContainer.java:498)
  at org.testcontainers.containers.GenericContainer.lambda$doStart$0(GenericContainer.java:325)
  at org.rnorth.ducttape.unreliables.Unreliables.retryUntilSuccess(Unreliables.java:81)
  ... 18 more
Caused by: org.testcontainers.containers.ContainerLaunchException: Timed out waiting for URL to be accessible (http://localhost:32869/ should return HTTP 200)
  at org.testcontainers.containers.wait.strategy.HttpWaitStrategy.waitUntilReady(HttpWaitStrategy.java:214)
  at org.testcontainers.containers.wait.strategy.AbstractWaitStrategy.waitUntilReady(AbstractWaitStrategy.java:35)
  at org.testcontainers.containers.GenericContainer.waitUntilContainerStarted(GenericContainer.java:890)
  at org.testcontainers.containers.GenericContainer.tryStart(GenericContainer.java:441)
  ... 20 more

相同的图像运行得很好:

docker run -p 8081:8080 -e PARAM1=value1 -e PARAM2=value2 -e PARAM3=VALUE3 my-service

【问题讨论】:

您确定您的应用程序返回 http 代码 200? waitStrategy = Wait.forHttp("/") 意味着应该返回一个http响应。 是的,确实如此。但是,我发现这个问题的根源是缺少标题。添加下面的答案以供可能遇到类似问题的任何人参考。 【参考方案1】:

所以在处理了这些错误之后,我发现了我的问题。这与请求中缺少所需的请求标头有关。我正在为遇到类似问题的任何人添加参考代码。

import com.dimafeng.testcontainers.ForAllTestContainer, GenericContainer
import org.scalatest.flatspec.AnyFlatSpec
import org.testcontainers.containers.wait.strategy.Wait

import scala.collection.immutable.HashMap
import scalaj.http.Http



    class MyServiceITSpec extends AnyFlatSpec with ForAllTestContainer 
      override val container = GenericContainer(dockerImage="my-service-img:tag12345",
        exposedPorts = Seq(8080),
        env=(HashMap[String, String]("PARAM1" -> "value1", "PARAM2" -> "value2")),
        waitStrategy = Wait.forHttp("/") // or "/health" based on ur implementation 
      )
    
      "My Service" should "successfully fetch the msg" in 
        assert(Http(s"http://$container.containerIpAddress:$container.mappedPort(8080)/products/product1")
          .header("HEADER1", "value1")
          .header("HEADER2", "value2")
          .asString.code==200)
      
    
    

读了很多资料后发现的一些解释:

    您将 docker 应用程序公开的端口号指定为 exposedPorts。 TestContainers 然后将此端口映射到随机端口(这是为了避免端口号冲突而设计的)。如果你要直接在你的机器上运行这个 docker 镜像,你会这样写:

docker run -p 8081:8080 -e PARAM1=value1 -e PARAM2=value2 my-service-img:tag12345

这里,您的暴露端口是 8080映射端口是 8081

    TestContainers 通过暴露 8080 端口然后将其映射到随机端口来运行 docker 映像。映射的端口可以是 container.mappedPort()

    另一个需要注意的重要事情是等待策略。这告诉代码等待,除非 / 端点启动。这是您的应用程序公开的一种健康检查。你可以有一个更好的端点——比如 /health。默认情况下,它会等待 60 秒 让该端点激活。发布它无论如何都会运行测试,如果应用程序到那时还没有启动,它会导致错误。我不确定如何覆盖默认超时,但我认为应该有办法做到这一点。

    最后,我正在使用 scalaj.http.Http 发出 HTTP 请求(它非常容易使用 - 你可以)。

【讨论】:

以上是关于如何运行自定义 docker 镜像 testContainer的主要内容,如果未能解决你的问题,请参考以下文章

自定义镜像-docker

Docker之创建自定义镜像

利用Dockerfile自定义镜像-图解轻松学Docker&K8S

如何将本地 docker 镜像作为 k3s 节点运行

基于docker镜像centos:7 镜像制作自定义的centos及tomcat/php/nginx镜像

基于docker镜像centos:7 镜像制作自定义的centos及tomcat/php/nginx镜像