如何运行自定义 docker 镜像 testContainer
Posted
技术标签:
【中文标题】如何运行自定义 docker 镜像 testContainer【英文标题】:How to run a custom docker image testContainer 【发布时间】:2020-11-12 20:38:22 【问题描述】:我浏览了多个博客和官方文档,但无法解决我的问题。我正在使用 testContainers-scala 版本 0.38.1 和 scala 版本 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的主要内容,如果未能解决你的问题,请参考以下文章
利用Dockerfile自定义镜像-图解轻松学Docker&K8S