Skip to content

Commit ecc3ff1

Browse files
authored
refactor(docker): better image (#49)
1 parent e2034e9 commit ecc3ff1

File tree

3 files changed

+88
-49
lines changed

3 files changed

+88
-49
lines changed

.github/workflows/docker-ci.yaml

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,66 @@ on:
55
- .github/workflows/docker-ci.yaml
66
- .github/scripts/**
77
- build.sbt
8+
- src/**
89

910
env:
1011
GITHUB_TOKEN: ${{ secrets.READ_PACKAGES }}
1112

1213
jobs:
13-
build:
14+
build-and-test:
15+
name: Build & Test
1416
runs-on: self-hosted
1517
steps:
1618
- uses: actions/checkout@v4
17-
- run: .github/scripts/dnd-sbt docker/Docker/publishLocal
19+
20+
- name: Build Docker image
21+
run: |
22+
.github/scripts/dnd-sbt Docker/publishLocal
23+
IMAGE_NAME=$(.github/scripts/dnd-sbt printDockerImageName | grep DOCKER_IMAGE | cut -d= -f2)
24+
echo "IMAGE=${IMAGE_NAME}" >> $GITHUB_ENV
25+
26+
- name: Test image - run container
27+
run: |
28+
CONTAINER_ID=$(docker run -d -p 50051 ${IMAGE})
29+
echo "CONTAINER_ID=${CONTAINER_ID}" >> $GITHUB_ENV
30+
HOST_PORT=$(docker port ${CONTAINER_ID} 50051 | cut -d':' -f2)
31+
echo "HOST_PORT=${HOST_PORT}" >> $GITHUB_ENV
32+
sleep 15
33+
34+
- name: Test image - verify service is running
35+
run: |
36+
nc -z localhost ${HOST_PORT}
37+
if [ $? -ne 0 ]; then
38+
echo "Service check failed!"
39+
exit 1
40+
fi
41+
42+
- name: Cleanup container
43+
if: always()
44+
run: |
45+
if [ ! -z "${CONTAINER_ID}" ]; then
46+
docker stop ${CONTAINER_ID}
47+
docker rm ${CONTAINER_ID}
48+
fi
49+
50+
security-scan:
51+
name: Security Scan
52+
runs-on: self-hosted
53+
steps:
54+
- uses: actions/checkout@v4
55+
56+
- name: Build Docker image
57+
run: |
58+
.github/scripts/dnd-sbt Docker/publishLocal
59+
IMAGE_NAME=$(.github/scripts/dnd-sbt printDockerImageName | grep DOCKER_IMAGE | cut -d= -f2)
60+
echo "IMAGE=${IMAGE_NAME}" >> $GITHUB_ENV
61+
62+
- name: Run Trivy vulnerability scanner
63+
uses: aquasecurity/trivy-action@master
64+
with:
65+
image-ref: ${{ env.IMAGE }}
66+
format: 'table'
67+
exit-code: '1'
68+
ignore-unfixed: true
69+
vuln-type: 'os,library'
70+
severity: 'CRITICAL,HIGH'

.github/workflows/publish.yaml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ jobs:
3636
password: ${{ secrets.WRITE_PACKAGES }}
3737
logout: false
3838
- name: publish docker images
39-
run: .github/scripts/dnd-sbt docker/Docker/publish
39+
run: .github/scripts/dnd-sbt Docker/publish
4040
- name: set should_trigger_deploy
4141
id: should_trigger_deploy
4242
shell: bash
@@ -47,6 +47,9 @@ jobs:
4747
needs: [publish-jars, publish-docker-image]
4848
runs-on: self-hosted
4949
steps:
50+
- uses: actions/checkout@v4
51+
with:
52+
fetch-depth: 0
5053
- uses: softprops/action-gh-release@v2
5154
with:
5255
token: ${{ secrets.RAW_CI_PAT }}

build.sbt

Lines changed: 29 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import java.nio.file.Paths
22

3-
import sbt.*
4-
import sbt.Keys.*
3+
import sbt.Keys._
4+
import sbt._
55

66
import com.typesafe.sbt.packager.docker.{Cmd, LayeredMapping}
77

@@ -19,6 +19,7 @@ lazy val commonSettings = Seq(
1919
// Use cached resolution of dependencies
2020
// http://www.scala-sbt.org/0.13/docs/Cached-Resolution.html
2121
updateOptions := updateOptions.in(Global).value.withCachedResolution(true),
22+
resolvers ++= Seq(Resolver.mavenLocal),
2223
resolvers += "RAW Labs GitHub Packages" at "https://maven.pkg.github.com/raw-labs/_")
2324

2425
lazy val buildSettings = Seq(
@@ -42,7 +43,9 @@ lazy val compileSettings = Seq(
4243
Compile / packageBin / packageOptions += Package.ManifestAttributes(
4344
"Automatic-Module-Name" -> name.value.replace('-', '.')),
4445
// Ensure Java annotations get compiled first, so that they are accessible from Scala.
45-
compileOrder := CompileOrder.JavaThenScala)
46+
compileOrder := CompileOrder.JavaThenScala,
47+
Compile / mainClass := Some("com.rawlabs.das.server.DASServer")
48+
)
4649

4750
lazy val testSettings = Seq(
4851
// Ensuring tests are run in a forked JVM for isolation.
@@ -51,7 +54,7 @@ lazy val testSettings = Seq(
5154
// Test / parallelExecution := false,
5255
// Pass system properties starting with "raw." to the forked JVMs.
5356
Test / javaOptions ++= {
54-
import scala.collection.JavaConverters.*
57+
import scala.collection.JavaConverters._
5558
val props = System.getProperties
5659
props
5760
.stringPropertyNames()
@@ -79,6 +82,7 @@ lazy val strictBuildSettings =
7982
commonSettings ++ compileSettings ++ buildSettings ++ testSettings ++ Seq(scalacOptions ++= Seq("-Xfatal-warnings"))
8083

8184
lazy val root = (project in file("."))
85+
.enablePlugins(JavaAppPackaging, DockerPlugin)
8286
.settings(
8387
name := "das-salesforce",
8488
strictBuildSettings,
@@ -94,56 +98,36 @@ lazy val root = (project in file("."))
9498
"com.fasterxml.jackson.datatype" % "jackson-datatype-jsr310" % "2.18.2",
9599
"com.fasterxml.jackson.datatype" % "jackson-datatype-jdk8" % "2.18.2",
96100
"com.fasterxml.jackson.datatype" % "jackson-datatype-joda" % "2.18.2",
97-
"com.fasterxml.jackson.module" %% "jackson-module-scala" % "2.18.2"))
98-
99-
val amzn_jdk_version = "21.0.4.7-1"
100-
val amzn_corretto_bin = s"java-21-amazon-corretto-jdk_${amzn_jdk_version}_amd64.deb"
101-
val amzn_corretto_bin_dl_url = s"https://corretto.aws/downloads/resources/${amzn_jdk_version.replace('-', '.')}"
101+
"com.fasterxml.jackson.module" %% "jackson-module-scala" % "2.18.2"
102+
)
103+
,
104+
dockerSettings
105+
)
102106

103-
lazy val dockerSettings = strictBuildSettings ++ Seq(
104-
name := "das-salesforce-server",
105-
dockerBaseImage := s"--platform=amd64 debian:bookworm-slim",
107+
lazy val dockerSettings = Seq(
108+
Docker/ packageName := "das-salesforce-server",
109+
dockerBaseImage := "eclipse-temurin:21-jre",
106110
dockerLabels ++= Map(
107111
"vendor" -> "RAW Labs SA",
108112
"product" -> "das-salesforce-server",
109113
"image-type" -> "final",
110114
"org.opencontainers.image.source" -> "https://github.com/raw-labs/das-salesforce"),
111115
Docker / daemonUser := "raw",
116+
Docker / daemonUserUid := Some("1001"),
117+
Docker / daemonGroup := "raw",
118+
Docker / daemonGroupGid := Some("1001"),
112119
dockerExposedVolumes := Seq("/var/log/raw"),
113120
dockerExposedPorts := Seq(50051),
114121
dockerEnvVars := Map("PATH" -> s"${(Docker / defaultLinuxInstallLocation).value}/bin:$$PATH"),
115-
// We remove the automatic switch to USER 1001:0.
116-
// We we want to run as root to install the JDK, also later we will switch to a non-root user.
117-
dockerCommands := dockerCommands.value.filterNot {
118-
case Cmd("USER", args @ _*) => args.contains("1001:0")
119-
case cmd => false
120-
},
121-
dockerCommands ++= Seq(
122-
Cmd(
123-
"RUN",
124-
s"""set -eux \\
125-
&& apt-get update \\
126-
&& apt-get install -y --no-install-recommends \\
127-
curl wget ca-certificates gnupg software-properties-common fontconfig java-common \\
128-
&& wget $amzn_corretto_bin_dl_url/$amzn_corretto_bin \\
129-
&& dpkg --install $amzn_corretto_bin \\
130-
&& rm -f $amzn_corretto_bin \\
131-
&& apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false \\
132-
wget gnupg software-properties-common"""),
133-
Cmd("USER", "raw")),
134122
dockerEnvVars += "LANG" -> "C.UTF-8",
135-
dockerEnvVars += "JAVA_HOME" -> "/usr/lib/jvm/java-21-amazon-corretto",
136-
Compile / doc / sources := Seq.empty, // Do not generate scaladocs
137-
// Skip docs to speed up build
138-
Compile / packageDoc / mappings := Seq(),
139123
updateOptions := updateOptions.value.withLatestSnapshots(true),
140124
Linux / linuxPackageMappings += packageTemplateMapping(s"/var/lib/${packageName.value}")(),
141125
bashScriptDefines := {
142126
val ClasspathPattern = "declare -r app_classpath=\"(.*)\"\n".r
143127
bashScriptDefines.value.map {
144128
case ClasspathPattern(classpath) => s"""
145-
|declare -r app_classpath="$${app_home}/../conf:$classpath"
146-
|""".stripMargin
129+
|declare -r app_classpath="$${app_home}/../conf:$classpath"
130+
|""".stripMargin
147131
case _ @entry => entry
148132
}
149133
},
@@ -163,8 +147,6 @@ lazy val dockerSettings = strictBuildSettings ++ Seq(
163147
}
164148
case lm @ _ => lm
165149
},
166-
Compile / mainClass := Some("com.rawlabs.das.server.DASServer"),
167-
Docker / dockerAutoremoveMultiStageIntermediateImages := false,
168150
dockerAlias := dockerAlias.value.withTag(Option(version.value.replace("+", "-"))),
169151
dockerAliases := {
170152
val devRegistry = sys.env.getOrElse("DEV_REGISTRY", "ghcr.io/raw-labs/das-salesforce")
@@ -177,10 +159,11 @@ lazy val dockerSettings = strictBuildSettings ++ Seq(
177159
}
178160
})
179161

180-
lazy val docker = (project in file("docker"))
181-
.dependsOn(root % "compile->compile;test->test")
182-
.enablePlugins(JavaAppPackaging, DockerPlugin)
183-
.settings(
184-
strictBuildSettings,
185-
dockerSettings,
186-
libraryDependencies += "com.raw-labs" %% "das-server-scala" % "0.4.1" % "compile->compile;test->test")
162+
lazy val printDockerImageName = taskKey[Unit]("Prints the full Docker image name that will be produced")
163+
164+
printDockerImageName := {
165+
// Get the main Docker alias (the first one in the sequence)
166+
val alias = (Docker / dockerAliases).value.head
167+
// The toString method already returns the full image name with registry and tag
168+
println(s"DOCKER_IMAGE=${alias}")
169+
}

0 commit comments

Comments
 (0)