summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathan Fischer <nfischer921@gmail.com>2019-04-17 17:58:05 -0700
committerNathan Fischer <nfischer921@gmail.com>2019-04-22 11:05:18 -0700
commit64f477e36c33afe8dfd87a839ba263e9973b0669 (patch)
tree70b3fe94524c6ebd4413af3c241103c348aeadb0
parentddd54c7bb4b79277684ed47bd35ec33d139aaf5a (diff)
downloadmill-64f477e36c33afe8dfd87a839ba263e9973b0669.tar.gz
mill-64f477e36c33afe8dfd87a839ba263e9973b0669.tar.bz2
mill-64f477e36c33afe8dfd87a839ba263e9973b0669.zip
Contrib module for building docker images
-rwxr-xr-xbuild.sc4
-rw-r--r--contrib/docker/src/DockerModule.scala73
-rw-r--r--docs/pages/9 - Contrib Modules.md44
3 files changed, 121 insertions, 0 deletions
diff --git a/build.sc b/build.sc
index bc693f1c..4d9133d0 100755
--- a/build.sc
+++ b/build.sc
@@ -306,6 +306,10 @@ object contrib extends MillModule {
def moduleDeps = Seq(scalalib)
def ivyDeps = Agg(ivy"org.flywaydb:flyway-core:5.2.4")
}
+
+ object docker extends MillModule {
+ def moduleDeps = Seq(scalalib)
+ }
}
diff --git a/contrib/docker/src/DockerModule.scala b/contrib/docker/src/DockerModule.scala
new file mode 100644
index 00000000..bbf4d926
--- /dev/null
+++ b/contrib/docker/src/DockerModule.scala
@@ -0,0 +1,73 @@
+import mill.T
+import mill.scalalib.JavaModule
+import os.Shellable.IterableShellable
+
+import scala.collection.immutable._
+
+trait DockerModule { outer: JavaModule =>
+
+ trait DockerConfig extends mill.Module {
+ /**
+ * Tags that should be applied to the built image
+ * In the standard registry/repository:tag format
+ */
+ def tags: T[Seq[String]] = T(List(outer.artifactName()))
+ def labels: T[Map[String, String]] = Map.empty[String, String]
+ def baseImage: T[String] = "gcr.io/distroless/java:latest"
+ def pullBaseImage: T[Boolean] = T(baseImage().endsWith(":latest"))
+ private def baseImageCacheBuster: T[(Boolean, Double)] = T.input {
+ val pull = pullBaseImage()
+ if(pull) (pull, Math.random()) else (pull, 0d)
+ }
+
+ def dockerfile: T[String] = T {
+ val jarName = assembly().path.last
+ val labelRhs = labels()
+ .map { case (k, v) =>
+ val lineBrokenValue = v
+ .replace("\r\n", "\\\r\n")
+ .replace("\n", "\\\n")
+ .replace("\r", "\\\r")
+ s""""$k"="$lineBrokenValue""""
+ }
+ .mkString(" ")
+
+ val labelLine = if(labels().isEmpty) "" else s"LABEL $labelRhs"
+
+ s"""
+ |FROM ${baseImage()}
+ |$labelLine
+ |COPY $jarName /$jarName
+ |ENTRYPOINT ["java", "-jar", "/$jarName"]
+ """.stripMargin
+ }
+
+ final def build = T {
+ val dest = T.ctx().dest
+
+ val asmPath = outer.assembly().path
+ os.copy(asmPath, dest / asmPath.last)
+
+ os.write(dest / "Dockerfile", dockerfile())
+
+ val log = T.ctx().log
+
+ val tagArgs = tags().flatMap(t => List("-t", t))
+
+ val (pull, _) = baseImageCacheBuster()
+ val pullLatestBase = IterableShellable(if(pull) Some("--pull") else None)
+
+ val result = os
+ .proc("docker", "build", tagArgs, pullLatestBase, dest)
+ .call(stdout = os.Inherit, stderr = os.Inherit)
+
+ log.info(s"Docker build completed ${if(result.exitCode == 0) "successfully" else "unsuccessfully"} with ${result.exitCode}")
+ tags()
+ }
+
+ final def push() = T.command {
+ val tags = build()
+ tags.foreach(t => os.proc("docker", "push", t).call(stdout = os.Inherit, stderr = os.Inherit))
+ }
+ }
+} \ No newline at end of file
diff --git a/docs/pages/9 - Contrib Modules.md b/docs/pages/9 - Contrib Modules.md
index 1b9b55fa..9adddcc5 100644
--- a/docs/pages/9 - Contrib Modules.md
+++ b/docs/pages/9 - Contrib Modules.md
@@ -38,6 +38,50 @@ object project extends BuildInfo {
* `def buildInfoPackageName: Option[String]`, default: `None`
The package name of the object.
+### Docker
+
+Automatically build docker images from your mill project.
+
+Requires the docker CLI to be installed.
+
+In the simplest configuration just extend `DockerModule` and declare a `DockerConfig` object.
+
+```scala
+import mill._, scalalib._
+
+import ivy`com.lihaoyi::mill-contrib-docker:VERSION`
+import contrib.docker.DockerModule
+
+object foo extends JavaModule with DockerModule {
+ object docker extends DockerConfig
+}
+```
+
+Then
+
+```
+$ mill foo.docker.build
+$ docker run foo
+```
+
+#### Configuration
+
+Configure the image by overriding tasks in the `DockerConfig` object
+
+```scala
+object docker extends DockerConfig {
+ // Override tags to set the output image name
+ def tags = List("aws_account_id.dkr.ecr.region.amazonaws.com/hello-repository")
+
+ def baseImage = "openjdk:11"
+
+ // Configure whether the docker build should check the remote registry for a new version of the base image before building.
+ // By default this is true if the base image is using a latest tag
+ def pullBaseImage = true
+}
+```
+
+Run mill in interactive mode to see the docker client output, like `mill -i foo.docker.build`.
### Flyway