Docker multi-arch builds (#2021)

Replaces the current docker build with a multi arch build powered by buildx.
The new build creates two scm-manager docker image variants.
One based on alpine which uses the openjdk distribution and the other based on debian and eclipse temurin:

scmmanager/scm-manager:<version>-alpine
- linux/amd64
- linux/arm64
scmmanager/scm-manager:<version>-debian
- linux/amd64
- linux/arm64
- linux/arm/v7
scmmanager/scm-manager:<version>
- linux/amd64 alpine based
- linux/arm64 alpine based
- linux/arm/v7 debian based
scmmanager/scm-manager:latest
- linux/amd64 alpine based
- linux/arm64 alpine based
- linux/arm/v7 debian based

The development build produces only a single amd64 image at cloudogu/scm-manager with a snapshot version.

Co-authored-by: Eduard Heimbuch <eduard.heimbuch@cloudogu.com>
This commit is contained in:
Sebastian Sdorra
2022-05-04 14:38:31 +02:00
committed by GitHub
parent 3853084106
commit af2cdfb739
7 changed files with 280 additions and 37 deletions

7
Jenkinsfile vendored
View File

@@ -8,7 +8,7 @@ pipeline {
agent {
docker {
image 'scmmanager/java-build:11.0.9.1_1-2'
image 'scmmanager/java-build:11.0.15_10-2'
args '-v /var/run/docker.sock:/var/run/docker.sock --group-add 998'
label 'docker'
}
@@ -285,14 +285,15 @@ void withChromaticEnvironment(Closure<Void> closure) {
void withPublishEnivronment(Closure<Void> closure) {
withCredentials([
usernamePassword(credentialsId: 'maven.scm-manager.org', usernameVariable: 'ORG_GRADLE_PROJECT_packagesScmManagerUsername', passwordVariable: 'ORG_GRADLE_PROJECT_packagesScmManagerPassword'),
usernamePassword(credentialsId: 'hub.docker.com-cesmarvin', usernameVariable: 'ORG_GRADLE_PROJECT_dockerUsername', passwordVariable: 'ORG_GRADLE_PROJECT_dockerPassword'),
usernamePassword(credentialsId: 'cesmarvin-github', usernameVariable: 'ORG_GRADLE_PROJECT_gitHubUsername', passwordVariable: 'ORG_GRADLE_PROJECT_gitHubApiToken'),
string(credentialsId: 'cesmarvin_npm_token', variable: 'ORG_GRADLE_PROJECT_npmToken'),
file(credentialsId: 'oss-gpg-secring', variable: 'GPG_KEY_RING'),
usernamePassword(credentialsId: 'oss-keyid-and-passphrase', usernameVariable: 'GPG_KEY_ID', passwordVariable: 'GPG_KEY_PASSWORD')
]) {
withEnv(["ORG_GRADLE_PROJECT_npmEmail=cesmarvin@cloudogu.com"]) {
closure.call()
docker.withRegistry('', 'hub.docker.com-cesmarvin') {
closure.call()
}
}
}
}

View File

@@ -18,7 +18,6 @@ for example:
docker run --name scm -p 8080:8080 -v scm-home:/var/lib/scm scmmanager/scm-manager:2.0.0
```
## Persistence
It is recommended to create a persistent volume for the scm-manager home directory.
@@ -60,7 +59,6 @@ docker run -e JAVA_OPTS="-Dsome.property=value" scmmanager/scm-manager:<version>
```
## Docker Compose
If you want to use the image with docker-compose have a look at the example below.
@@ -79,3 +77,33 @@ services:
volumes:
scmhome: {}
```
## Variants
We are offer two variants of the SCM-Manager docker image one with OpenJDK on Alpine and the other with Eclipse Temurin on Debian.
### scmmanager/scm-manager:<version>-alpine
This image uses the Alpine operating system and the OpenJDK distribution from the official apk repository.
The image is available for the following os/architectures:
* linux/amd64
* linux/arm64
### scmmanager/scm-manager:<version>-debian
This image uses the Debian operating system and the Eclipse Temurin JDK.
The image is available for the following os/architectures:
* linux/amd64
* linux/arm64
* linux/arm/v7
### scmmanager/scm-manager:<version>
The default image is mainly an alias for the alpine variant, but there is no alpine variant for arm/v7.
For arm/v7 the debian variant is used.
* linux/amd64 uses the alpine variant
* linux/arm64 uses the alpine variant
* linux/arm/v7 uses the debian variant

View File

@@ -0,0 +1,2 @@
- type: added
description: Docker images for linux/arm/v7 and linux/arm64 ([#2021](https://github.com/scm-manager/scm-manager/pull/2021))

View File

@@ -22,11 +22,33 @@
# SOFTWARE.
#
FROM adoptopenjdk/openjdk11:jdk-11.0.14_9-alpine-slim
ENV SCM_HOME=/var/lib/scm
ENV CACHE_DIR=/var/cache/scm/work
# Create minimal java version
FROM alpine:3.15.4 as jre-build
COPY . /
RUN set -x \
&& apk add --no-cache openjdk11-jdk openjdk11-jmods \
&& jlink \
--add-modules ALL-MODULE-PATH \
--strip-debug \
--no-man-pages \
--no-header-files \
--compress=2 \
--output /javaruntime
# ---
# SCM-Manager runtime
FROM alpine:3.15.4 as runtime
ENV SCM_HOME /var/lib/scm
ENV CACHE_DIR /var/cache/scm/work
ENV JAVA_HOME /opt/java/openjdk
ENV PATH "${JAVA_HOME}/bin:${PATH}"
COPY --from=jre-build /javaruntime "${JAVA_HOME}"
COPY build/docker/etc /etc
COPY build/docker/opt /opt
RUN set -x \
# ttf-dejavu graphviz are required for the plantuml plugin
@@ -38,10 +60,11 @@ RUN set -x \
&& chown 1000:0 ${SCM_HOME} ${CACHE_DIR} \
&& chmod -R g=u ${SCM_HOME} ${CACHE_DIR}
USER 1000
WORKDIR "/opt/scm-server"
VOLUME ["${SCM_HOME}", "${CACHE_DIR}"]
EXPOSE 8080
USER 1000
# we us a high relative high start period,
# because the start time depends on the number of installed plugins

View File

@@ -0,0 +1,73 @@
#
# MIT License
#
# Copyright (c) 2020-present Cloudogu GmbH and Contributors
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
# Create minimal java version
FROM eclipse-temurin:11.0.14.1_1-jdk-focal as jre-build
RUN jlink \
--add-modules ALL-MODULE-PATH \
--strip-debug \
--no-man-pages \
--no-header-files \
--compress=2 \
--output /javaruntime
# ---
# SCM-Manager runtime
FROM debian:11.3-slim as runtime
ENV SCM_HOME /var/lib/scm
ENV CACHE_DIR /var/cache/scm/work
ENV JAVA_HOME /opt/java/openjdk
ENV PATH "${JAVA_HOME}/bin:${PATH}"
COPY --from=jre-build /javaruntime "${JAVA_HOME}"
COPY build/docker/etc /etc
COPY build/docker/opt /opt
RUN set -x \
&& apt-get update \
# libfreetype6 libfontconfig1 graphviz
&& apt-get install -y --no-install-recommends libfreetype6 libfontconfig1 graphviz mercurial bash ca-certificates \
# use gid 0 for openshift compatibility
&& useradd -d "${SCM_HOME}" -u 1000 -g 0 -m -s /bin/bash scm \
&& mkdir -p ${SCM_HOME} ${CACHE_DIR} \
&& chmod +x /opt/scm-server/bin/scm-server \
# set permissions to group 0 for openshift compatibility
&& chown 1000:0 ${SCM_HOME} ${CACHE_DIR} \
&& chmod -R g=u ${SCM_HOME} ${CACHE_DIR}
USER 1000
WORKDIR "/opt/scm-server"
VOLUME ["${SCM_HOME}", "${CACHE_DIR}"]
EXPOSE 8080
# we us a high relative high start period,
# because the start time depends on the number of installed plugins
HEALTHCHECK --interval=30s --timeout=3s --start-period=30s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:8080/scm/api/v2 || exit 1
ENTRYPOINT [ "/opt/scm-server/bin/scm-server" ]

View File

@@ -23,13 +23,12 @@
*/
plugins {
id 'com.bmuschko.docker-remote-api' version '6.6.1'
id 'org.scm-manager.packaging'
id 'org.scm-manager.license'
}
import org.gradle.util.VersionNumber
import com.bmuschko.gradle.docker.tasks.image.*
import groovy.json.JsonSlurper
configurations {
server
@@ -70,45 +69,76 @@ task context(type: Copy) {
}
}
task dockerImage(type: DockerBuildImage) {
inputDir = file('build/docker')
images = images()
task setupBuilder() {
doLast {
def inspect = exec {
commandLine = ["docker", "buildx", "inspect", "scm-builder"]
ignoreExitValue = true
}
if (inspect.exitValue != 0) {
exec {
commandLine = ["docker", "run", "--privileged", "--rm", "tonistiigi/binfmt", "--install", "arm,arm64"]
}
exec {
commandLine = ["docker", "buildx", "create", "--name", "scm-builder", "--driver", "docker-container", "--platform", "linux/arm/v7,linux/arm64/v8,linux/amd64"]
}
exec {
commandLine = ["docker", "buildx", "inspect", "scm-builder"]
}
}
}
}
task build(type: Exec) {
commandLine = ["docker", "buildx", "bake", "--builder", "scm-builder", isSnapshot ? "dev": "prod"]
environment "VERSION", dockerTag
environment "COMMIT_SHA", revision
environment "IMAGE", dockerRepository
doLast {
File file = new File(project.buildDir, 'docker.tag')
file.text = dockerTag
}
dependsOn 'context'
dependsOn 'context', 'setupBuilder'
}
def images() {
if (isSnapshot) {
return [
"${dockerRepository}:${dockerTag}"
]
} else {
// What about patch releases?
// It is a good idea to push always latest
return [
"${dockerRepository}:${dockerTag}",
"${dockerRepository}:latest"
]
}
task pushImages(type: Exec) {
commandLine = ["docker", "buildx", "bake", "--builder", "scm-builder", isSnapshot ? "dev": "prod", "--push"]
environment "VERSION", dockerTag
environment "COMMIT_SHA", revision
environment "IMAGE", dockerRepository
dependsOn 'build'
}
task publish(type: DockerPushImage) {
images = images()
if (project.hasProperty("dockerUsername") && project.hasProperty("dockerPassword")) {
registryCredentials {
username = project.property("dockerUsername")
password = project.property("dockerPassword")
task publish() {
doLast {
if (!isSnapshot) {
// get digest of debian arm v7 image
def stdout = new ByteArrayOutputStream()
exec {
commandLine = ["docker", "buildx", "imagetools", "inspect", "--raw", "${dockerRepository}:${dockerTag}-debian"]
standardOutput = stdout
}
def inspect = new JsonSlurper().parseText(stdout.toString())
def manifest = inspect.manifests.find { m -> m.platform.architecture == "arm" }
// append arm image to manifest with version and without os suffix
exec {
commandLine = ["docker", "buildx", "imagetools", "create", "--append", "-t", "${dockerRepository}:${dockerTag}", "${dockerRepository}:${dockerTag}-debian@${manifest.digest}"]
}
// append arm image to latest manifest
exec {
commandLine = ["docker", "buildx", "imagetools", "create", "--append", "-t", "${dockerRepository}:latest", "${dockerRepository}:${dockerTag}-debian@${manifest.digest}"]
}
}
}
dependsOn dockerImage
dependsOn 'pushImages'
}
task distribution(type: PackageYaml) {
type = 'docker'
dependsOn dockerImage
dependsOn build
}
artifacts {

View File

@@ -0,0 +1,86 @@
#
# MIT License
#
# Copyright (c) 2020-present Cloudogu GmbH and Contributors
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
group "prod" {
targets = [
"alpine",
"debian"
]
}
variable "VERSION" {
default = "unknown"
}
variable "COMMIT_SHA" {
default = "unknown"
}
variable "IMAGE" {
default = "docker.io/cloudogu/scm-manager"
}
target "base" {
context = "."
args = {
VERSION = VERSION
COMMIT_SHA = COMMIT_SHA
}
labels = {
"org.opencontainers.image.vendor" = "Cloudogu GmbH"
"org.opencontainers.image.title" = "Official SCM-Manager image"
"org.opencontainers.image.description" = "The easiest way to share and manage your Git, Mercurial and Subversion repositories"
"org.opencontainers.image.url" = "https://scm-manager.org/"
"org.opencontainers.image.source" = "https://github.com/scm-manager/docker"
"org.opencontainers.image.licenses" = "MIT"
"org.opencontainers.image.version" = VERSION
"org.opencontainers.image.revision" = COMMIT_SHA
}
}
target "dev" {
inherits = ["base"]
dockerfile = "Dockerfile.alpine"
tags = ["${IMAGE}:${VERSION}"]
}
target "alpine" {
inherits = ["base"]
dockerfile = "Dockerfile.alpine"
tags = [
"${IMAGE}:latest",
"${IMAGE}:${VERSION}",
"${IMAGE}:${VERSION}-alpine"
]
platforms = ["linux/amd64", "linux/arm64/v8"]
}
target "debian" {
inherits = ["base"]
dockerfile = "Dockerfile.debian"
tags = [
"${IMAGE}:${VERSION}-debian"
]
platforms = ["linux/amd64", "linux/arm64/v8", "linux/arm/v7"]
}