@@ -19,6 +19,7 @@ package org.apache.spark.deploy.k8s.integrationtest.docker
19
19
import java .io .{File , PrintWriter }
20
20
import java .net .URI
21
21
import java .nio .file .Paths
22
+ import java .util .UUID
22
23
23
24
import com .google .common .base .Charsets
24
25
import com .google .common .io .Files
@@ -33,10 +34,10 @@ import scala.collection.JavaConverters._
33
34
import org .apache .spark .deploy .k8s .integrationtest .constants ._
34
35
import org .apache .spark .deploy .k8s .integrationtest .KubernetesSuite
35
36
import org .apache .spark .deploy .k8s .integrationtest .Logging
36
- import org .apache .spark .deploy .k8s .integrationtest .Utils .{ RedirectThread , tryWithResource }
37
+ import org .apache .spark .deploy .k8s .integrationtest .Utils .tryWithResource
37
38
38
39
private [spark] class KubernetesSuiteDockerManager (
39
- dockerEnv : Map [String , String ], dockerTag : String ) extends Logging {
40
+ dockerEnv : Map [String , String ], userProvidedDockerImageTag : Option [ String ] ) extends Logging {
40
41
41
42
private val DOCKER_BUILD_PATH = SPARK_DISTRO_PATH
42
43
// Dockerfile paths must be relative to the build path.
@@ -47,9 +48,11 @@ private[spark] class KubernetesSuiteDockerManager(
47
48
private val INIT_CONTAINER_DOCKER_FILE = DOCKERFILES_DIR + " init-container/Dockerfile"
48
49
private val TIMEOUT = PatienceConfiguration .Timeout (Span (2 , Minutes ))
49
50
private val INTERVAL = PatienceConfiguration .Interval (Span (2 , Seconds ))
51
+
52
+ private val resolvedDockerImageTag =
53
+ userProvidedDockerImageTag.getOrElse(UUID .randomUUID().toString.replaceAll(" -" , " " ))
50
54
private val dockerHost = dockerEnv.getOrElse(" DOCKER_HOST" ,
51
55
throw new IllegalStateException (" DOCKER_HOST env not found." ))
52
-
53
56
private val originalDockerUri = URI .create(dockerHost)
54
57
private val httpsDockerUri = new URIBuilder ()
55
58
.setHost(originalDockerUri.getHost)
@@ -69,31 +72,39 @@ private[spark] class KubernetesSuiteDockerManager(
69
72
.build()
70
73
71
74
def buildSparkDockerImages (): Unit = {
72
- Eventually .eventually(TIMEOUT , INTERVAL ) { dockerClient.ping() }
73
- buildImage(" spark-base" , BASE_DOCKER_FILE )
74
- buildImage(" spark-driver" , DRIVER_DOCKER_FILE )
75
- buildImage(" spark-executor" , EXECUTOR_DOCKER_FILE )
76
- buildImage(" spark-init" , INIT_CONTAINER_DOCKER_FILE )
75
+ if (userProvidedDockerImageTag.isEmpty) {
76
+ Eventually .eventually(TIMEOUT , INTERVAL ) {
77
+ dockerClient.ping()
78
+ }
79
+ buildImage(" spark-base" , BASE_DOCKER_FILE )
80
+ buildImage(" spark-driver" , DRIVER_DOCKER_FILE )
81
+ buildImage(" spark-executor" , EXECUTOR_DOCKER_FILE )
82
+ buildImage(" spark-init" , INIT_CONTAINER_DOCKER_FILE )
83
+ }
77
84
}
78
85
79
86
def deleteImages (): Unit = {
80
- removeRunningContainers()
81
- deleteImage(" spark-base" )
82
- deleteImage(" spark-driver" )
83
- deleteImage(" spark-executor" )
84
- deleteImage(" spark-init" )
87
+ if (userProvidedDockerImageTag.isEmpty) {
88
+ removeRunningContainers()
89
+ deleteImage(" spark-base" )
90
+ deleteImage(" spark-driver" )
91
+ deleteImage(" spark-executor" )
92
+ deleteImage(" spark-init" )
93
+ }
85
94
}
86
95
96
+ def dockerImageTag (): String = resolvedDockerImageTag
97
+
87
98
private def buildImage (name : String , dockerFile : String ): Unit = {
88
- logInfo(s " Building Docker image - $name: $dockerTag " )
99
+ logInfo(s " Building Docker image - $name: $resolvedDockerImageTag " )
89
100
val dockerFileWithBaseTag = new File (DOCKER_BUILD_PATH .resolve(
90
- s " $dockerFile- $dockerTag " ).toAbsolutePath.toString)
101
+ s " $dockerFile- $resolvedDockerImageTag " ).toAbsolutePath.toString)
91
102
dockerFileWithBaseTag.deleteOnExit()
92
103
try {
93
104
val originalDockerFileText = Files .readLines(
94
105
DOCKER_BUILD_PATH .resolve(dockerFile).toFile, Charsets .UTF_8 ).asScala
95
106
val dockerFileTextWithProperBaseImage = originalDockerFileText.map(
96
- _.replace(" FROM spark-base" , s " FROM spark-base: $dockerTag " ))
107
+ _.replace(" FROM spark-base" , s " FROM spark-base: $resolvedDockerImageTag " ))
97
108
tryWithResource(Files .newWriter(dockerFileWithBaseTag, Charsets .UTF_8 )) { fileWriter =>
98
109
tryWithResource(new PrintWriter (fileWriter)) { printWriter =>
99
110
for (line <- dockerFileTextWithProperBaseImage) {
@@ -105,8 +116,8 @@ private[spark] class KubernetesSuiteDockerManager(
105
116
}
106
117
dockerClient.build(
107
118
DOCKER_BUILD_PATH ,
108
- s " $name: $dockerTag " ,
109
- s " $dockerFile- $dockerTag " ,
119
+ s " $name: $resolvedDockerImageTag " ,
120
+ s " $dockerFile- $resolvedDockerImageTag " ,
110
121
new LoggingBuildHandler ())
111
122
} finally {
112
123
dockerFileWithBaseTag.delete()
@@ -119,15 +130,15 @@ private[spark] class KubernetesSuiteDockerManager(
119
130
private def removeRunningContainers (): Unit = {
120
131
val imageIds = dockerClient.listImages(ListImagesParam .allImages())
121
132
.asScala
122
- .filter(image => image.repoTags().asScala.exists(_.endsWith(s " : $dockerTag " )))
133
+ .filter(image => image.repoTags().asScala.exists(_.endsWith(s " : $resolvedDockerImageTag " )))
123
134
.map(_.id())
124
135
.toSet
125
136
Eventually .eventually(KubernetesSuite .TIMEOUT , KubernetesSuite .INTERVAL ) {
126
137
val runningContainersWithImageTag = stopRunningContainers(imageIds)
127
138
require(
128
139
runningContainersWithImageTag.isEmpty,
129
140
s " ${runningContainersWithImageTag.size} containers found still running " +
130
- s " with the image tag $dockerTag " )
141
+ s " with the image tag $resolvedDockerImageTag " )
131
142
}
132
143
dockerClient.listContainers(ListContainersParam .allContainers())
133
144
.asScala
@@ -139,7 +150,7 @@ private[spark] class KubernetesSuiteDockerManager(
139
150
.asScala
140
151
.filter(container => imageIds.contains(container.imageId()))
141
152
require(containersWithImageTag.isEmpty, s " ${containersWithImageTag.size} containers still " +
142
- s " found with image tag $dockerTag . " )
153
+ s " found with image tag $resolvedDockerImageTag . " )
143
154
}
144
155
145
156
}
@@ -148,7 +159,7 @@ private[spark] class KubernetesSuiteDockerManager(
148
159
val runningContainersWithImageTag = getRunningContainersWithImageIds(imageIds)
149
160
if (runningContainersWithImageTag.nonEmpty) {
150
161
logInfo(s " Found ${runningContainersWithImageTag.size} containers running with " +
151
- s " an image with the tag $dockerTag . Attempting to remove these containers, " +
162
+ s " an image with the tag $resolvedDockerImageTag . Attempting to remove these containers, " +
152
163
s " and then will stall for 2 seconds. " )
153
164
runningContainersWithImageTag.foreach { container =>
154
165
dockerClient.stopContainer(container.id(), 5 )
@@ -168,10 +179,10 @@ private[spark] class KubernetesSuiteDockerManager(
168
179
169
180
private def deleteImage (name : String ): Unit = {
170
181
try {
171
- dockerClient.removeImage(s " $name: $dockerTag " )
182
+ dockerClient.removeImage(s " $name: $resolvedDockerImageTag " )
172
183
} catch {
173
184
case e : RuntimeException =>
174
- logWarning(s " Failed to delete image $name: $dockerTag . There may be images leaking in the " +
185
+ logWarning(s " Failed to delete image $name: $resolvedDockerImageTag . There may be images leaking in the " +
175
186
s " docker environment which are now stale and unused. " , e)
176
187
}
177
188
}
0 commit comments