Wie automatisiere ich das Bauen von Docker Container für IoT-Geräte mit unterschiedlicher Prozessorarchitektur?
Das war die Frage, die ich mich kürzlich beschäftigt hat.
Für ein IoT Projekt sollen Microservices für verschiedene Prozessorarchitekturen (x86, ARM) gebaut werden. Die Artefakte sollen Docker Container sein, welche mit derselben SCM (Release -) Version getagged werden.
Der Release soll in GitLab manuell angestossen werden. Dabei wird der Master-Branch verwendet.
Verwendete Technologien
Folgende Technologien wurden für das Projekt definiert:
- CI Umgebung: GitLab
- Buildtool: Gradle
Gradle Integration
Bei der Suche nach geeigneten Gradle-Plugins stiess ich auf eine hohe Anzahl von Plugins, welche mehr oder weniger ähnliche Funktionalität hatten. Schliesslich waren Popularität, Dokumentation, Anzahl Contributors und Aktivität ausschlaggebend für die Wahl folgender Opensource Plugins, welche die funktionalen Kriterien erfüllen.
• Gradle Docker Plugin von bmuschko[1] für das Bauen, Taggen und Pushen der Container.
• Gradle Release Plugin von researchgate[2] für das automatisierte Taggen eines Releases in Git.
Build-Prozess
Der Release Prozess wird manuell in GitLab UI angestossen.
Schematischer Ablauf (sequentiell):
- Start Release in GitLab UI
- Service wird kompiliert, Unit- und Integrationstests durchgeführt und gebaut
- Dockerfile für x86 wird erzeugt (Gradle Task)
- Docker-Image für x86 wird gebaut (Gradle Task)
- Docker-Image für x86 wird getaggt (Gradle Task)
- Docker-Image für x86 wird ins Docker-Repository hochgeladen (Gradle Task)
- Dockerfile für ARM wird erzeugt (Gradle Task)
- Docker-Image für ARM wird gebaut (Gradle Task)
- Docker-Image für ARM wird getaggt (Gradle Task)
- Docker-Image für ARM wird ins Docker-Repository hochgeladen (Gradle Task)
- Release wird getaggt in SCM (Gradle Task)
- Release-Nummer wird erhöht und committed (Gradle Task)
Definition des Builds mit allen Tasks und Abhängigkeiten
Vereinfachtes gradle.build
..... apply plugin: 'com.bmuschko.docker-java-application' apply plugin: "net.researchgate.release" import com.bmuschko.gradle.docker.tasks.image.Dockerfile import com.bmuschko.gradle.docker.tasks.image.DockerBuildImage import com.bmuschko.gradle.docker.tasks.image.DockerPushImage ........ task createDockerfileX86(type: Dockerfile){ destFile = project.file('build/libs/Dockerfile') from 'openjdk:8-jre-alpine' maintainer '......"' copyFile 'gw-bif-aws-gateway-' + version + '.jar', '/' defaultCommand 'java', '-jar', '/gw-bif-aws-gateway-' + version + '.jar' } task buildImageX86(type: DockerBuildImage){ dependsOn createDockerfileX86 inputDir = createDockerfileX86.destFile.parentFile tag = '....../gw-bif/gw-bif-aws-gateway-x86:' + version } task pushImageX86(type: DockerPushImage){ dependsOn buildImageX86 imageName= '....../gw-bif/gw-bif-aws-gateway-x86:' + version } task createDockerfileArm(type: Dockerfile){ destFile = project.file('build/libs/Dockerfile') from 'armhf/openjdk:8-jre-alpine' maintainer '......' copyFile 'gw-bif-aws-gateway-' + version + '.jar', '/' defaultCommand 'java', '-jar', '/gw-bif-aws-gateway-' + version + '.jar' } task buildImageArm(type: DockerBuildImage){ dependsOn createDockerfileArm inputDir = createDockerfileArm.destFile.parentFile tag = '......../gw-bif/gw-bif-aws-gateway-arm:' + version } task pushImageArm(type: DockerPushImage){ dependsOn buildImageArm imageName= '......./gw-bif/gw-bif-aws-gateway-arm:' + version } // tag and push docker image with tagged release version afterReleaseBuild.dependsOn pushImageX86 afterReleaseBuild.dependsOn pushImageArm ........
Die Variable “version” wird direkt aus dem gradle.properties file gelesen.
Fazit
Die verwendeten Technologien arbeiten Hand in Hand zusammen, wobei Gradle den Build Prozess orchestriert, Git sich um die Versionierung kümmert und Docker die Plattform bietet, um verschiedene Prozessorarchitekturen zu unterstützen.
Zu beachten gilt, dass das Pushen von Images und das Tagging des Releases nicht transaktional abläuft. Es könnte sich also ergeben, dass ein Image bereits ins Docker-Repository hochgeladen wurde und der SCM Release anschliessend fehlschlägt. Dies war im Projekt insofern kein Problem, da beim Retry einfach das Image überschrieben wird und sich inhaltlich keine Änderungen ergeben.
Links
https://github.com/bmuschko/gradle-docker-plugin [1]
https://github.com/researchgate/gradle-release [2]
https://gradle.org/
https://about.gitlab.com/
https://www.docker.com/