SlideShare a Scribd company logo
1 of 42
Download to read offline
© OPITZ CONSULTING 2019
Best Practices 

Java und JVM in Containern
BEDCon 2019
Dr. Halil-Cem Gürsoy
OPITZ CONSULTING



@hgutwit
© OPITZ CONSULTING 2019
$ whoami | xargs finger
■Senior Solution Architect @ OPITZ CONSULTING
■Seit 20 Jahren in der Java-Welt
■ davor im wissenschaftlichen Umfeld Pascal, C, Lisp, Prolog…
■Verteilte Enterprise Systeme
■ Build, Deployment & Persistenz
■„DevOps“, Infrastructure as Code, Automatisierung…
© OPITZ CONSULTING 2019
Eine lange Docker-Reise
■Seit Docker 0.8 (2014) produktiv mit Docker unterwegs
■Build & Testumgebungen für große agile Teams
■ Java/JEE, Testcluster, Datenbanken (NoSQL, RDBMS)
■Continuous Delivery mit Docker
■ Jenkins, Atlassian Bamboo, Docker Swarm, Kubernetes …
■ …aber bekennend "Kubephob" (Konfrontations-Therapie)
© OPITZ CONSULTING 2019
Agenda
■Basics, die nichts mit Java/JVM zu tun haben aber wichtig sind
■Java und der Speicher
■Java und die CPU
■Java und Images
■Noch sparsamer, noch schneller
© OPITZ CONSULTING 2019
Warum gerade Java?
https://www.tiobe.com/tiobe-index/
© OPITZ CONSULTING 2019
Warum gerade Java?
https://redmonk.com/rstephens/2019/07/18/top20-june-2019/
© OPITZ CONSULTING 2019
–Wladimir Iljitsch Lenin
„Доверяй, но проверяй“
© OPITZ CONSULTING 2019
Base Images
■Ideal-Welt: wir bauen unsere Base-Images FROM scratch
■ kann sehr aufwendig sein, aber Kontrolle über den Inhalt
■Möglichst mit offiziellen Images starten
■Sicherheitsupdates beachten, regelmäßig bauen
© OPITZ CONSULTING 2019
Base Images
■möglichst nur eine oder wenige Linux-Distributionen auswählen
■minimales System nutzen: 

nur die Pakete, die notwendig sind, nachvollziehbar installieren
■--entrypoint sollte die eigentliche Applikation aufrufen
■… aber auch ein docker run myimage:1 bash erlauben
■Weitere Hinweise im Github-Repo docker-library/official-images
© OPITZ CONSULTING 2019https://www.flickr.com/photos/clement127/15914534662
latest is Evil!
© OPITZ CONSULTING 2019
Deployment?
■Container sollten nicht wie VM’s „provisioniert“ werden
■Anti-Pattern:
■ Container mit Application Server wird gestartet…
■ …und Applikation wird in den laufenden App-Server deployed
■Reproduzierbar?
© OPITZ CONSULTING 2019https://www.flickr.com/photos/vanmelis/14920357394
© OPITZ CONSULTING 2019
https://www.flickr.com/photos/mac_users_guide/3665683020
© OPITZ CONSULTING 2019
Java & glibc
■glibc’s malloc() reserviert 64Mb-Blöcke („Arenas“)
■ Virtual Adress space, u.a. Java Metaspace, Threads usw.
■(Fast) kein Problem bis zur Verwendung von mlockall()
■ „Arenas“ werden dann tatsächlich gemappt
■ElasticSearch, Apache Cassandra (via JNA)
■ Optionale Konfiguration zur Swap-Vermeidung
■Diverse Bug-Einträge, u.a. JDK-8193521
© OPITZ CONSULTING 2019
Java & glibc
■MALLOC_ARENA_MAX auf niedrigen Wert setzen
■ Vorsicht wenn SELinux im Einsatz ist!
■ Default: 8 * CPU-Kerne
■Ausprobieren und messen!
■Swap disablen statt JNA/mlockall
© OPITZ CONSULTING 2019https://www.flickr.com/photos/venndiagram/5331296718
© OPITZ CONSULTING 2019
Java Heap
docker run -m 256m --rm openjdk:8u111-jdk java -XX:+PrintFlagsFinal -version
|grep -i heapsize | egrep 'Initial|Max'
openjdk version "1.8.0_111"
OpenJDK Runtime Environment (build 1.8.0_111-8u111-b14-2~bpo8+1-b14)
OpenJDK 64-Bit Server VM (build 25.111-b14, mixed mode)
    uintx InitialHeapSize                          := 65011712
    uintx MaxHeapSize                              := 1035993088
© OPITZ CONSULTING 2019
Java Heap
docker run -m 256m --rm openjdk:8-jdk java -XX:+PrintFlagsFinal -version |
grep -i heapsize | egrep 'Initial|Max'
openjdk version "1.8.0_222"
OpenJDK Runtime Environment (build 1.8.0_222-b10)
OpenJDK 64-Bit Server VM (build 25.222-b10, mixed mode)
    uintx InitialHeapSize                          := 8388608
    uintx MaxHeapSize                              := 132120576
© OPITZ CONSULTING 2019
Neue Optionen ab 8u191*
■JDK-8196595: 

--XX:[+|-]UseContainerSupport (default: +)
■JDK-8186248:
■ -XX:InitialRAMPercentage, -XX:MaxRAMPercentage

-XX:MinRAMPercentage
■ ersetzen:

-XX:InitialRAMFraction, -XX:MaxRAMFraction

-XX:MinRAMFraction
■ Genaue Berechnungsformeln im Code
© OPITZ CONSULTING 2019
Min / Max Heap
docker run -m 1024m --rm openjdk:12.0.2-jdk java -XX:+PrintFlagsFinal -
version | grep -E "UseContainerSupport | MaxRAMPercentage | MinRAMPercentage"
   double MaxRAMPercentage                       = 25.000000
   double MinRAMPercentage                       = 50.000000
     bool UseContainerSupport                    = true
docker run -m 1024m --rm openjdk:12.0.2-jdk java -XshowSettings:vm -version
VM settings:
    Max. Heap Size (Estimated): 247.50M
    Using VM: OpenJDK 64-Bit Server VM
docker run -m 1024m --rm openjdk:12.0.2-jdk java -XX:MaxRAMPercentage=75.0

-XshowSettings:vm -version
VM settings:
Max. Heap Size (Estimated): 742.44M
Using VM: OpenJDK 64-Bit Server VM
© OPITZ CONSULTING 2019https://www.flickr.com/photos/lemsipmatt/2894816411/
© OPITZ CONSULTING 2019
CPU-Limits
■Ab Java 9 / 10 werden Docker CPU-Limits berücksichtigt
■ --cpuset-cpus, --cpus / --cpu-quota, --cpu-period,

--cpu-shares
■–XX:PreferContainerQuotaForCPUCount (default true)
■Alternativ/Manuell: –XX:ActiveProcessorCount
© OPITZ CONSULTING 2019
CPU-Limits
echo 'Runtime.getRuntime().availableProcessors()' | 

docker run -i --rm openjdk:12.0.2-jdk jshell
jshell> Runtime.getRuntime().availableProcessors()
$1 ==> 4
echo 'Runtime.getRuntime().availableProcessors()' | 

docker run --cpus 1 -i --rm openjdk:12.0.2-jdk jshell
jshell> Runtime.getRuntime().availableProcessors()

$1 ==> 1
© OPITZ CONSULTING 2019https://www.flickr.com/photos/digimeister/16138848190
© OPITZ CONSULTING 2019
Ein hochkomplexes Beispiel
© OPITZ CONSULTING 2019
Java Images
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hellojava 3 7733be0c7852 About a minute ago 390MB
debian stretch-slim 220611111e8c 2 weeks ago 55.3MB
openjdk 12.0.2-jdk e1e07dfba89c 2 weeks ago 470MB
© OPITZ CONSULTING 2019
Auf Diät…
■Ab Java 9 haben wir JDK-Module zur Verfügung
■Es sollten nur die benötigten Module der JRE in das Image
■Mit Hilfe von jlink kann eine angepasste JRE erzeugt werden
■ Mit jdeps kann Liste der benötigten Module erzeugt werden
© OPITZ CONSULTING 2019
Auf Diät…
© OPITZ CONSULTING 2019
Slim…
docker images | grep hello
hellojava slim-1 0f67adf4b101 5 minutes ago 92.1MB
hellojava 3 7733be0c7852 51 minutes ago 390MB
© OPITZ CONSULTING 2019
Da geht noch was!
■Projekt Portola migriert die OpenJDK von glibc auf musl
■musl ist eine schlanke Implementierung der libc für Alpine Linux
■Early Access von OpenJDK für Alpine/musl: 

http://jdk.java.net/14/
■Alpine/musl mit java.base ca. 51 Mb!
© OPITZ CONSULTING 2019https://www.flickr.com/photos/grepsy/6993325519/
© OPITZ CONSULTING 2019
AppCDS
■In 8u40 als kommerzielles Feature eingeführt
■Option -XX:+UseAppCDS in JDK 11 obsolet erklärt und in 12 entfernt, da
nun „default“
■Interne Repräsentation der Applikations-Klassen in memmory-mapped files
■Schnelleres Laden bei großen Servern/Applikationen und kleineres memory
Footprint
■ Beispiele mit WebLogic usw. ca. 10% - 20% schneller
■ Bei „einfachen“ / kleinen Applikationen kein besonderer Effekt
© OPITZ CONSULTING 2019
AppCDS
© OPITZ CONSULTING 2019
AOT statt JIT-Compiler
■Ähnlich der AppCDS wird im Vorfeld eine Shared Library erzeugt
■Es erfolgt zur Laufzeit keine Optimierung durch HotSpot
■Macht Sinn bei kurz laufenden Java-Prozessen
■ … z.B. bei Functions mit Java (Fn, OpenFaaS, …)
■Stolperfalle: Shared Library kann sehr groß werden
■ Selektiv die verwendeten Klassen compilieren
© OPITZ CONSULTING 2019https://www.flickr.com/photos/jdlasica/698202275/
© OPITZ CONSULTING 2019
GraalVM
■„…is a universal virtual machine for running applications written in
JavaScript, Python, Ruby, R, JVM-based languages like Java, Scala,
Groovy, Kotlin, Clojure, and LLVM-based languages such as C and
C++.“ https://www.graalvm.org
© OPITZ CONSULTING 2019
GraalVM
© OPITZ CONSULTING 2019
GraalVM
© OPITZ CONSULTING 2019
GraalVM
Step 5/8 : RUN native-image HelloJava
---> Running in ca6f04a96def
Build on Server(pid: 32, port: 38449)*
[hellojava:32]    classlist:   1,477.66 ms
[hellojava:32]        (cap):     890.19 ms
[hellojava:32]        setup:   1,932.33 ms
…
[hellojava:32]      compile:   6,405.54 ms
[hellojava:32]        image:     502.27 ms
[hellojava:32]        write:     109.88 ms
[hellojava:32]      [total]:  20,302.07 ms
root@b914b8045203:/# ls -lh
total 5.5M
drwxr-xr-x   2 root root 4.0K Aug 12 00:00 bin
drwxr-xr-x   2 root root 4.0K Mar 28 09:12 boot
drwxr-xr-x   5 root root  360 Sep  4 20:30 dev
drwxr-xr-x   1 root root 4.0K Sep  4 20:30 etc
-rwxr-xr-x   1 root root 5.4M Sep  4 20:24 hellojava
© OPITZ CONSULTING 2019
GraalVM
■Aktuell noch „Probleme“ mit Reflection und Proxies
■"Spring Framework provides initial support for GraalVM native
images as of 5.1.“
■Andere Frameworks wie Micronaut sind da besser vorbereitet
© OPITZ CONSULTING 2019http://www.flickr.com/photos/an_untrained_eye/6630719431
© OPITZ CONSULTING 2019
https://www.flickr.com/photos/tcmorgan/7372944070
@OC_WIRE
OPITZCONSULTING
opitzconsulting
opitz-consulting-bcb8-1009116
WWW.OPITZ-CONSULTING.COM

More Related Content

What's hot

OC|Webcast: Oracle Lizenzierung - Virtualisierung und Cloud
OC|Webcast: Oracle Lizenzierung - Virtualisierung und CloudOC|Webcast: Oracle Lizenzierung - Virtualisierung und Cloud
OC|Webcast: Oracle Lizenzierung - Virtualisierung und CloudOPITZ CONSULTING Deutschland
 
OC|Webcast: Schnell und clever in die AWS Cloud – Migrationsszenarien und Han...
OC|Webcast: Schnell und clever in die AWS Cloud – Migrationsszenarien und Han...OC|Webcast: Schnell und clever in die AWS Cloud – Migrationsszenarien und Han...
OC|Webcast: Schnell und clever in die AWS Cloud – Migrationsszenarien und Han...OPITZ CONSULTING Deutschland
 
Oracle-Lizenzierung bei Virtualisierung und in der Cloud
Oracle-Lizenzierung bei Virtualisierung und in der CloudOracle-Lizenzierung bei Virtualisierung und in der Cloud
Oracle-Lizenzierung bei Virtualisierung und in der CloudOPITZ CONSULTING Deutschland
 
Die SOA Suite in der Amazon Cloud sicher betreiben
Die SOA Suite in der Amazon Cloud sicher betreiben Die SOA Suite in der Amazon Cloud sicher betreiben
Die SOA Suite in der Amazon Cloud sicher betreiben OPITZ CONSULTING Deutschland
 
Tipps & Tricks zum Aufbau einer Unternehmenscloud mit CC13
Tipps & Tricks zum Aufbau einer Unternehmenscloud mit CC13Tipps & Tricks zum Aufbau einer Unternehmenscloud mit CC13
Tipps & Tricks zum Aufbau einer Unternehmenscloud mit CC13OPITZ CONSULTING Deutschland
 
Wie baue ich eine KI, die besser als jeder Mensch ein Problem und dessen Ursa...
Wie baue ich eine KI, die besser als jeder Mensch ein Problem und dessen Ursa...Wie baue ich eine KI, die besser als jeder Mensch ein Problem und dessen Ursa...
Wie baue ich eine KI, die besser als jeder Mensch ein Problem und dessen Ursa...OPITZ CONSULTING Deutschland
 
WebLogic Server auf ODA: Erfahrungen aus einem Kundenprojekt
WebLogic Server auf ODA: Erfahrungen aus einem KundenprojektWebLogic Server auf ODA: Erfahrungen aus einem Kundenprojekt
WebLogic Server auf ODA: Erfahrungen aus einem KundenprojektOPITZ CONSULTING Deutschland
 
OSMC 2010 | Java Monitoring und Troubleshooting by Rainer Jung
OSMC 2010 | Java Monitoring und Troubleshooting by Rainer JungOSMC 2010 | Java Monitoring und Troubleshooting by Rainer Jung
OSMC 2010 | Java Monitoring und Troubleshooting by Rainer JungNETWAYS
 
2012 borys neselovskyi_automatisierte_middleware_installation_praesentation
2012 borys neselovskyi_automatisierte_middleware_installation_praesentation2012 borys neselovskyi_automatisierte_middleware_installation_praesentation
2012 borys neselovskyi_automatisierte_middleware_installation_praesentationbneselov
 
2014 borys neselovskyi_web_logic_server_auf_oda_praesentation
2014 borys neselovskyi_web_logic_server_auf_oda_praesentation2014 borys neselovskyi_web_logic_server_auf_oda_praesentation
2014 borys neselovskyi_web_logic_server_auf_oda_praesentationbneselov
 
Oracle AVDF in der Praxis
Oracle AVDF in der PraxisOracle AVDF in der Praxis
Oracle AVDF in der PraxisTrivadis
 
Einführung in Puppet und Vagrant
Einführung in Puppet und VagrantEinführung in Puppet und Vagrant
Einführung in Puppet und Vagrants0enke
 
Java magazin9 2012_wls 12c_das_dutzend_ist_voll
Java magazin9 2012_wls 12c_das_dutzend_ist_vollJava magazin9 2012_wls 12c_das_dutzend_ist_voll
Java magazin9 2012_wls 12c_das_dutzend_ist_vollWolfgang Weigend
 

What's hot (20)

OC|Webcast: Oracle Lizenzierung - Virtualisierung und Cloud
OC|Webcast: Oracle Lizenzierung - Virtualisierung und CloudOC|Webcast: Oracle Lizenzierung - Virtualisierung und Cloud
OC|Webcast: Oracle Lizenzierung - Virtualisierung und Cloud
 
OC|Webcast: Grundlagen der Oracle-Lizenzierung
OC|Webcast: Grundlagen der Oracle-LizenzierungOC|Webcast: Grundlagen der Oracle-Lizenzierung
OC|Webcast: Grundlagen der Oracle-Lizenzierung
 
OC|Webcast: Schnell und clever in die AWS Cloud – Migrationsszenarien und Han...
OC|Webcast: Schnell und clever in die AWS Cloud – Migrationsszenarien und Han...OC|Webcast: Schnell und clever in die AWS Cloud – Migrationsszenarien und Han...
OC|Webcast: Schnell und clever in die AWS Cloud – Migrationsszenarien und Han...
 
2020 oracle lizenznews
2020 oracle lizenznews2020 oracle lizenznews
2020 oracle lizenznews
 
Oracle-Lizenzierung bei Virtualisierung und in der Cloud
Oracle-Lizenzierung bei Virtualisierung und in der CloudOracle-Lizenzierung bei Virtualisierung und in der Cloud
Oracle-Lizenzierung bei Virtualisierung und in der Cloud
 
"OC|Webcast: Grundlagen der Oracle Lizenzierung"
"OC|Webcast: Grundlagen der Oracle Lizenzierung""OC|Webcast: Grundlagen der Oracle Lizenzierung"
"OC|Webcast: Grundlagen der Oracle Lizenzierung"
 
Die SOA Suite in der Amazon Cloud sicher betreiben
Die SOA Suite in der Amazon Cloud sicher betreiben Die SOA Suite in der Amazon Cloud sicher betreiben
Die SOA Suite in der Amazon Cloud sicher betreiben
 
Tipps & Tricks zum Aufbau einer Unternehmenscloud mit CC13
Tipps & Tricks zum Aufbau einer Unternehmenscloud mit CC13Tipps & Tricks zum Aufbau einer Unternehmenscloud mit CC13
Tipps & Tricks zum Aufbau einer Unternehmenscloud mit CC13
 
Der Mythos der Trunk-basierten Entwicklung
Der Mythos der Trunk-basierten EntwicklungDer Mythos der Trunk-basierten Entwicklung
Der Mythos der Trunk-basierten Entwicklung
 
Wie baue ich eine KI, die besser als jeder Mensch ein Problem und dessen Ursa...
Wie baue ich eine KI, die besser als jeder Mensch ein Problem und dessen Ursa...Wie baue ich eine KI, die besser als jeder Mensch ein Problem und dessen Ursa...
Wie baue ich eine KI, die besser als jeder Mensch ein Problem und dessen Ursa...
 
WebLogic Server auf ODA: Erfahrungen aus einem Kundenprojekt
WebLogic Server auf ODA: Erfahrungen aus einem KundenprojektWebLogic Server auf ODA: Erfahrungen aus einem Kundenprojekt
WebLogic Server auf ODA: Erfahrungen aus einem Kundenprojekt
 
OSMC 2010 | Java Monitoring und Troubleshooting by Rainer Jung
OSMC 2010 | Java Monitoring und Troubleshooting by Rainer JungOSMC 2010 | Java Monitoring und Troubleshooting by Rainer Jung
OSMC 2010 | Java Monitoring und Troubleshooting by Rainer Jung
 
2012 borys neselovskyi_automatisierte_middleware_installation_praesentation
2012 borys neselovskyi_automatisierte_middleware_installation_praesentation2012 borys neselovskyi_automatisierte_middleware_installation_praesentation
2012 borys neselovskyi_automatisierte_middleware_installation_praesentation
 
2014 borys neselovskyi_web_logic_server_auf_oda_praesentation
2014 borys neselovskyi_web_logic_server_auf_oda_praesentation2014 borys neselovskyi_web_logic_server_auf_oda_praesentation
2014 borys neselovskyi_web_logic_server_auf_oda_praesentation
 
Oracle AVDF in der Praxis
Oracle AVDF in der PraxisOracle AVDF in der Praxis
Oracle AVDF in der Praxis
 
Einführung in Puppet und Vagrant
Einführung in Puppet und VagrantEinführung in Puppet und Vagrant
Einführung in Puppet und Vagrant
 
Java magazin9 2012_wls 12c_das_dutzend_ist_voll
Java magazin9 2012_wls 12c_das_dutzend_ist_vollJava magazin9 2012_wls 12c_das_dutzend_ist_voll
Java magazin9 2012_wls 12c_das_dutzend_ist_voll
 
Performance-Analyse mit Bordmitteln
Performance-Analyse mit BordmittelnPerformance-Analyse mit Bordmitteln
Performance-Analyse mit Bordmitteln
 
CDI
CDICDI
CDI
 
CI und OTPC in ADF Projekten
CI und OTPC in ADF ProjektenCI und OTPC in ADF Projekten
CI und OTPC in ADF Projekten
 

Similar to Best Practices 
Java und JVM in Containern

Leveraging the Power of Solr with Spark
Leveraging the Power of Solr with SparkLeveraging the Power of Solr with Spark
Leveraging the Power of Solr with SparkQAware GmbH
 
Icsug conf 14_tipps-und-skripts-fuer-ibm-connections-administratoren
Icsug conf 14_tipps-und-skripts-fuer-ibm-connections-administratorenIcsug conf 14_tipps-und-skripts-fuer-ibm-connections-administratoren
Icsug conf 14_tipps-und-skripts-fuer-ibm-connections-administratorenICS User Group
 
Big Data Community Webinar vom 16. Mai 2019: Oracle NoSQL DB im Überblick
Big Data Community Webinar vom 16. Mai 2019: Oracle NoSQL DB im ÜberblickBig Data Community Webinar vom 16. Mai 2019: Oracle NoSQL DB im Überblick
Big Data Community Webinar vom 16. Mai 2019: Oracle NoSQL DB im ÜberblickKarin Patenge
 
Boost your APEX Deployment and Provisioning with Docker
Boost your APEX Deployment and Provisioning with DockerBoost your APEX Deployment and Provisioning with Docker
Boost your APEX Deployment and Provisioning with DockerSteven Grzbielok
 
Oracle WebLogic for DevOps
Oracle WebLogic for DevOpsOracle WebLogic for DevOps
Oracle WebLogic for DevOpsAndreas Koop
 
Let's talk about Java EE
Let's talk about Java EELet's talk about Java EE
Let's talk about Java EEAndreas König
 
Cloud-native and Enterprise Java? Hold my beer!
Cloud-native and Enterprise Java? Hold my beer!Cloud-native and Enterprise Java? Hold my beer!
Cloud-native and Enterprise Java? Hold my beer!OPEN KNOWLEDGE GmbH
 
Docker Workshop Experten Forum Stuttgart 2015, Agile Methoden GmbH
Docker Workshop Experten Forum Stuttgart 2015, Agile Methoden GmbHDocker Workshop Experten Forum Stuttgart 2015, Agile Methoden GmbH
Docker Workshop Experten Forum Stuttgart 2015, Agile Methoden GmbHagilemethoden
 
MySQL für Oracle DBA's
MySQL für Oracle DBA'sMySQL für Oracle DBA's
MySQL für Oracle DBA'sFromDual GmbH
 
Supersonic Java für die Cloud: Quarkus
Supersonic Java für die Cloud: QuarkusSupersonic Java für die Cloud: Quarkus
Supersonic Java für die Cloud: QuarkusOPEN KNOWLEDGE GmbH
 
20190604_DOAGDatabase2019_OracleNoSQLDB_for_DBAs
20190604_DOAGDatabase2019_OracleNoSQLDB_for_DBAs20190604_DOAGDatabase2019_OracleNoSQLDB_for_DBAs
20190604_DOAGDatabase2019_OracleNoSQLDB_for_DBAsKarin Patenge
 
DOAG SIG: MySQL Replikation, Scale-Out, Master- Master Replikation, Backup
DOAG SIG: MySQL Replikation, Scale-Out, Master- Master Replikation, BackupDOAG SIG: MySQL Replikation, Scale-Out, Master- Master Replikation, Backup
DOAG SIG: MySQL Replikation, Scale-Out, Master- Master Replikation, BackupFromDual GmbH
 
Microservices and Container Management with Mesosphere DC/OS
Microservices and Container Management with Mesosphere DC/OSMicroservices and Container Management with Mesosphere DC/OS
Microservices and Container Management with Mesosphere DC/OSRalf Ernst
 
Ready for the Future: Jakarta EE in Zeiten von Cloud Native & Co
Ready for the Future: Jakarta EE in Zeiten von Cloud Native & CoReady for the Future: Jakarta EE in Zeiten von Cloud Native & Co
Ready for the Future: Jakarta EE in Zeiten von Cloud Native & CoOPEN KNOWLEDGE GmbH
 
A Hitchhiker's Guide to the Cloud Native Stack
A Hitchhiker's Guide to the Cloud Native StackA Hitchhiker's Guide to the Cloud Native Stack
A Hitchhiker's Guide to the Cloud Native StackQAware GmbH
 
A Hitchhiker’s Guide to the Cloud Native Stack. #ContainerConf
A Hitchhiker’s Guide to the Cloud Native Stack. #ContainerConfA Hitchhiker’s Guide to the Cloud Native Stack. #ContainerConf
A Hitchhiker’s Guide to the Cloud Native Stack. #ContainerConfMario-Leander Reimer
 

Similar to Best Practices 
Java und JVM in Containern (20)

Herbstcampus2019_Kubernetes Docker Swarm
Herbstcampus2019_Kubernetes Docker SwarmHerbstcampus2019_Kubernetes Docker Swarm
Herbstcampus2019_Kubernetes Docker Swarm
 
Leveraging the Power of Solr with Spark
Leveraging the Power of Solr with SparkLeveraging the Power of Solr with Spark
Leveraging the Power of Solr with Spark
 
Icsug conf 14_tipps-und-skripts-fuer-ibm-connections-administratoren
Icsug conf 14_tipps-und-skripts-fuer-ibm-connections-administratorenIcsug conf 14_tipps-und-skripts-fuer-ibm-connections-administratoren
Icsug conf 14_tipps-und-skripts-fuer-ibm-connections-administratoren
 
Big Data Community Webinar vom 16. Mai 2019: Oracle NoSQL DB im Überblick
Big Data Community Webinar vom 16. Mai 2019: Oracle NoSQL DB im ÜberblickBig Data Community Webinar vom 16. Mai 2019: Oracle NoSQL DB im Überblick
Big Data Community Webinar vom 16. Mai 2019: Oracle NoSQL DB im Überblick
 
Boost your APEX Deployment and Provisioning with Docker
Boost your APEX Deployment and Provisioning with DockerBoost your APEX Deployment and Provisioning with Docker
Boost your APEX Deployment and Provisioning with Docker
 
Oracle WebLogic for DevOps
Oracle WebLogic for DevOpsOracle WebLogic for DevOps
Oracle WebLogic for DevOps
 
Oracle WebLogic for DevOps
Oracle WebLogic for DevOpsOracle WebLogic for DevOps
Oracle WebLogic for DevOps
 
NoSQL with MySQL
NoSQL with MySQLNoSQL with MySQL
NoSQL with MySQL
 
Let's talk about Java EE
Let's talk about Java EELet's talk about Java EE
Let's talk about Java EE
 
Cloud-native and Enterprise Java? Hold my beer!
Cloud-native and Enterprise Java? Hold my beer!Cloud-native and Enterprise Java? Hold my beer!
Cloud-native and Enterprise Java? Hold my beer!
 
Docker Workshop Experten Forum Stuttgart 2015, Agile Methoden GmbH
Docker Workshop Experten Forum Stuttgart 2015, Agile Methoden GmbHDocker Workshop Experten Forum Stuttgart 2015, Agile Methoden GmbH
Docker Workshop Experten Forum Stuttgart 2015, Agile Methoden GmbH
 
MySQL für Oracle DBA's
MySQL für Oracle DBA'sMySQL für Oracle DBA's
MySQL für Oracle DBA's
 
Supersonic Java für die Cloud: Quarkus
Supersonic Java für die Cloud: QuarkusSupersonic Java für die Cloud: Quarkus
Supersonic Java für die Cloud: Quarkus
 
20190604_DOAGDatabase2019_OracleNoSQLDB_for_DBAs
20190604_DOAGDatabase2019_OracleNoSQLDB_for_DBAs20190604_DOAGDatabase2019_OracleNoSQLDB_for_DBAs
20190604_DOAGDatabase2019_OracleNoSQLDB_for_DBAs
 
DOAG SIG: MySQL Replikation, Scale-Out, Master- Master Replikation, Backup
DOAG SIG: MySQL Replikation, Scale-Out, Master- Master Replikation, BackupDOAG SIG: MySQL Replikation, Scale-Out, Master- Master Replikation, Backup
DOAG SIG: MySQL Replikation, Scale-Out, Master- Master Replikation, Backup
 
Microservices and Container Management with Mesosphere DC/OS
Microservices and Container Management with Mesosphere DC/OSMicroservices and Container Management with Mesosphere DC/OS
Microservices and Container Management with Mesosphere DC/OS
 
Ready for the Future: Jakarta EE in Zeiten von Cloud Native & Co
Ready for the Future: Jakarta EE in Zeiten von Cloud Native & CoReady for the Future: Jakarta EE in Zeiten von Cloud Native & Co
Ready for the Future: Jakarta EE in Zeiten von Cloud Native & Co
 
Dockerize It - Mit apex in die amazon cloud
Dockerize It - Mit apex in die amazon cloudDockerize It - Mit apex in die amazon cloud
Dockerize It - Mit apex in die amazon cloud
 
A Hitchhiker's Guide to the Cloud Native Stack
A Hitchhiker's Guide to the Cloud Native StackA Hitchhiker's Guide to the Cloud Native Stack
A Hitchhiker's Guide to the Cloud Native Stack
 
A Hitchhiker’s Guide to the Cloud Native Stack. #ContainerConf
A Hitchhiker’s Guide to the Cloud Native Stack. #ContainerConfA Hitchhiker’s Guide to the Cloud Native Stack. #ContainerConf
A Hitchhiker’s Guide to the Cloud Native Stack. #ContainerConf
 

More from OPITZ CONSULTING Deutschland

Architecture Room Stuttgart - "Cloud-native ist nur ein Teil des Spiels!"
Architecture Room Stuttgart - "Cloud-native ist nur ein Teil des Spiels!"Architecture Room Stuttgart - "Cloud-native ist nur ein Teil des Spiels!"
Architecture Room Stuttgart - "Cloud-native ist nur ein Teil des Spiels!"OPITZ CONSULTING Deutschland
 
OC|Weekly Talk: Inspect’n’Adapt – Make Change come true!
OC|Weekly Talk: Inspect’n’Adapt – Make Change come true!OC|Weekly Talk: Inspect’n’Adapt – Make Change come true!
OC|Weekly Talk: Inspect’n’Adapt – Make Change come true!OPITZ CONSULTING Deutschland
 
OC|Weekly Talk: "Das müsste man mal digitalisieren" - Mit Low-Code schnell zu...
OC|Weekly Talk: "Das müsste man mal digitalisieren" - Mit Low-Code schnell zu...OC|Weekly Talk: "Das müsste man mal digitalisieren" - Mit Low-Code schnell zu...
OC|Weekly Talk: "Das müsste man mal digitalisieren" - Mit Low-Code schnell zu...OPITZ CONSULTING Deutschland
 
OC|Weekly Talk: Service Management – Was hat sich durch Corona geändert?
OC|Weekly Talk: Service Management – Was hat sich durch Corona geändert?OC|Weekly Talk: Service Management – Was hat sich durch Corona geändert?
OC|Weekly Talk: Service Management – Was hat sich durch Corona geändert?OPITZ CONSULTING Deutschland
 
OC|Weekly Talk - Digitales Coaching & Smart Sparring
OC|Weekly Talk - Digitales Coaching & Smart Sparring OC|Weekly Talk - Digitales Coaching & Smart Sparring
OC|Weekly Talk - Digitales Coaching & Smart Sparring OPITZ CONSULTING Deutschland
 
Effiziente Betriebsoptimierung durch Cloud Nutzung
Effiziente Betriebsoptimierung durch Cloud NutzungEffiziente Betriebsoptimierung durch Cloud Nutzung
Effiziente Betriebsoptimierung durch Cloud NutzungOPITZ CONSULTING Deutschland
 
OC|Weekly Talk - Mitarbeiterführung in Zeiten von Social Distance
OC|Weekly Talk - Mitarbeiterführung in Zeiten von Social DistanceOC|Weekly Talk - Mitarbeiterführung in Zeiten von Social Distance
OC|Weekly Talk - Mitarbeiterführung in Zeiten von Social DistanceOPITZ CONSULTING Deutschland
 
Handlungsoptionen bei der Modernisierung von Legacy-Systemen
Handlungsoptionen bei der Modernisierung von Legacy-SystemenHandlungsoptionen bei der Modernisierung von Legacy-Systemen
Handlungsoptionen bei der Modernisierung von Legacy-SystemenOPITZ CONSULTING Deutschland
 

More from OPITZ CONSULTING Deutschland (17)

OC|Webcast "Daten wirklich nutzen"
OC|Webcast "Daten wirklich nutzen"OC|Webcast "Daten wirklich nutzen"
OC|Webcast "Daten wirklich nutzen"
 
Architecture Room Stuttgart - "Cloud-native ist nur ein Teil des Spiels!"
Architecture Room Stuttgart - "Cloud-native ist nur ein Teil des Spiels!"Architecture Room Stuttgart - "Cloud-native ist nur ein Teil des Spiels!"
Architecture Room Stuttgart - "Cloud-native ist nur ein Teil des Spiels!"
 
OC|Webcast "Die neue Welt der Virtualisierung"
OC|Webcast "Die neue Welt der Virtualisierung"OC|Webcast "Die neue Welt der Virtualisierung"
OC|Webcast "Die neue Welt der Virtualisierung"
 
10 Thesen zur professionellen Softwareentwicklung
10 Thesen zur professionellen Softwareentwicklung10 Thesen zur professionellen Softwareentwicklung
10 Thesen zur professionellen Softwareentwicklung
 
OC|Weekly Talk: Inspect’n’Adapt – Make Change come true!
OC|Weekly Talk: Inspect’n’Adapt – Make Change come true!OC|Weekly Talk: Inspect’n’Adapt – Make Change come true!
OC|Weekly Talk: Inspect’n’Adapt – Make Change come true!
 
OC|Weekly Talk The Power of DevOps…
OC|Weekly Talk  The Power of DevOps…OC|Weekly Talk  The Power of DevOps…
OC|Weekly Talk The Power of DevOps…
 
OC|Weekly Talk: "Das müsste man mal digitalisieren" - Mit Low-Code schnell zu...
OC|Weekly Talk: "Das müsste man mal digitalisieren" - Mit Low-Code schnell zu...OC|Weekly Talk: "Das müsste man mal digitalisieren" - Mit Low-Code schnell zu...
OC|Weekly Talk: "Das müsste man mal digitalisieren" - Mit Low-Code schnell zu...
 
OC|Weekly Talk: Service Management – Was hat sich durch Corona geändert?
OC|Weekly Talk: Service Management – Was hat sich durch Corona geändert?OC|Weekly Talk: Service Management – Was hat sich durch Corona geändert?
OC|Weekly Talk: Service Management – Was hat sich durch Corona geändert?
 
OC|Weekly Talk - Digitales Coaching & Smart Sparring
OC|Weekly Talk - Digitales Coaching & Smart Sparring OC|Weekly Talk - Digitales Coaching & Smart Sparring
OC|Weekly Talk - Digitales Coaching & Smart Sparring
 
OC|Weekly Talk - Beratung remote
OC|Weekly Talk - Beratung remoteOC|Weekly Talk - Beratung remote
OC|Weekly Talk - Beratung remote
 
Effiziente Betriebsoptimierung durch Cloud Nutzung
Effiziente Betriebsoptimierung durch Cloud NutzungEffiziente Betriebsoptimierung durch Cloud Nutzung
Effiziente Betriebsoptimierung durch Cloud Nutzung
 
OC|Weekly Talk - Mitarbeiterführung in Zeiten von Social Distance
OC|Weekly Talk - Mitarbeiterführung in Zeiten von Social DistanceOC|Weekly Talk - Mitarbeiterführung in Zeiten von Social Distance
OC|Weekly Talk - Mitarbeiterführung in Zeiten von Social Distance
 
OC|Weekly Talk Remote Design Thinking
OC|Weekly Talk Remote Design ThinkingOC|Weekly Talk Remote Design Thinking
OC|Weekly Talk Remote Design Thinking
 
OC|Webcast Smart Innovation am 7. April 2020
OC|Webcast Smart Innovation am 7. April 2020OC|Webcast Smart Innovation am 7. April 2020
OC|Webcast Smart Innovation am 7. April 2020
 
Handlungsoptionen bei der Modernisierung von Legacy-Systemen
Handlungsoptionen bei der Modernisierung von Legacy-SystemenHandlungsoptionen bei der Modernisierung von Legacy-Systemen
Handlungsoptionen bei der Modernisierung von Legacy-Systemen
 
InspireIT - Online-Event
InspireIT - Online-Event InspireIT - Online-Event
InspireIT - Online-Event
 
Analytics as a Service - Microsoft Azure
Analytics as a Service  - Microsoft Azure Analytics as a Service  - Microsoft Azure
Analytics as a Service - Microsoft Azure
 

Best Practices 
Java und JVM in Containern

  • 1. © OPITZ CONSULTING 2019 Best Practices 
 Java und JVM in Containern BEDCon 2019 Dr. Halil-Cem Gürsoy OPITZ CONSULTING
 
 @hgutwit
  • 2. © OPITZ CONSULTING 2019 $ whoami | xargs finger ■Senior Solution Architect @ OPITZ CONSULTING ■Seit 20 Jahren in der Java-Welt ■ davor im wissenschaftlichen Umfeld Pascal, C, Lisp, Prolog… ■Verteilte Enterprise Systeme ■ Build, Deployment & Persistenz ■„DevOps“, Infrastructure as Code, Automatisierung…
  • 3. © OPITZ CONSULTING 2019 Eine lange Docker-Reise ■Seit Docker 0.8 (2014) produktiv mit Docker unterwegs ■Build & Testumgebungen für große agile Teams ■ Java/JEE, Testcluster, Datenbanken (NoSQL, RDBMS) ■Continuous Delivery mit Docker ■ Jenkins, Atlassian Bamboo, Docker Swarm, Kubernetes … ■ …aber bekennend "Kubephob" (Konfrontations-Therapie)
  • 4. © OPITZ CONSULTING 2019 Agenda ■Basics, die nichts mit Java/JVM zu tun haben aber wichtig sind ■Java und der Speicher ■Java und die CPU ■Java und Images ■Noch sparsamer, noch schneller
  • 5. © OPITZ CONSULTING 2019 Warum gerade Java? https://www.tiobe.com/tiobe-index/
  • 6. © OPITZ CONSULTING 2019 Warum gerade Java? https://redmonk.com/rstephens/2019/07/18/top20-june-2019/
  • 7. © OPITZ CONSULTING 2019 –Wladimir Iljitsch Lenin „Доверяй, но проверяй“
  • 8. © OPITZ CONSULTING 2019 Base Images ■Ideal-Welt: wir bauen unsere Base-Images FROM scratch ■ kann sehr aufwendig sein, aber Kontrolle über den Inhalt ■Möglichst mit offiziellen Images starten ■Sicherheitsupdates beachten, regelmäßig bauen
  • 9. © OPITZ CONSULTING 2019 Base Images ■möglichst nur eine oder wenige Linux-Distributionen auswählen ■minimales System nutzen: 
 nur die Pakete, die notwendig sind, nachvollziehbar installieren ■--entrypoint sollte die eigentliche Applikation aufrufen ■… aber auch ein docker run myimage:1 bash erlauben ■Weitere Hinweise im Github-Repo docker-library/official-images
  • 10. © OPITZ CONSULTING 2019https://www.flickr.com/photos/clement127/15914534662 latest is Evil!
  • 11. © OPITZ CONSULTING 2019 Deployment? ■Container sollten nicht wie VM’s „provisioniert“ werden ■Anti-Pattern: ■ Container mit Application Server wird gestartet… ■ …und Applikation wird in den laufenden App-Server deployed ■Reproduzierbar?
  • 12. © OPITZ CONSULTING 2019https://www.flickr.com/photos/vanmelis/14920357394
  • 13. © OPITZ CONSULTING 2019 https://www.flickr.com/photos/mac_users_guide/3665683020
  • 14. © OPITZ CONSULTING 2019 Java & glibc ■glibc’s malloc() reserviert 64Mb-Blöcke („Arenas“) ■ Virtual Adress space, u.a. Java Metaspace, Threads usw. ■(Fast) kein Problem bis zur Verwendung von mlockall() ■ „Arenas“ werden dann tatsächlich gemappt ■ElasticSearch, Apache Cassandra (via JNA) ■ Optionale Konfiguration zur Swap-Vermeidung ■Diverse Bug-Einträge, u.a. JDK-8193521
  • 15. © OPITZ CONSULTING 2019 Java & glibc ■MALLOC_ARENA_MAX auf niedrigen Wert setzen ■ Vorsicht wenn SELinux im Einsatz ist! ■ Default: 8 * CPU-Kerne ■Ausprobieren und messen! ■Swap disablen statt JNA/mlockall
  • 16. © OPITZ CONSULTING 2019https://www.flickr.com/photos/venndiagram/5331296718
  • 17. © OPITZ CONSULTING 2019 Java Heap docker run -m 256m --rm openjdk:8u111-jdk java -XX:+PrintFlagsFinal -version |grep -i heapsize | egrep 'Initial|Max' openjdk version "1.8.0_111" OpenJDK Runtime Environment (build 1.8.0_111-8u111-b14-2~bpo8+1-b14) OpenJDK 64-Bit Server VM (build 25.111-b14, mixed mode)     uintx InitialHeapSize                          := 65011712     uintx MaxHeapSize                              := 1035993088
  • 18. © OPITZ CONSULTING 2019 Java Heap docker run -m 256m --rm openjdk:8-jdk java -XX:+PrintFlagsFinal -version | grep -i heapsize | egrep 'Initial|Max' openjdk version "1.8.0_222" OpenJDK Runtime Environment (build 1.8.0_222-b10) OpenJDK 64-Bit Server VM (build 25.222-b10, mixed mode)     uintx InitialHeapSize                          := 8388608     uintx MaxHeapSize                              := 132120576
  • 19. © OPITZ CONSULTING 2019 Neue Optionen ab 8u191* ■JDK-8196595: 
 --XX:[+|-]UseContainerSupport (default: +) ■JDK-8186248: ■ -XX:InitialRAMPercentage, -XX:MaxRAMPercentage
 -XX:MinRAMPercentage ■ ersetzen:
 -XX:InitialRAMFraction, -XX:MaxRAMFraction
 -XX:MinRAMFraction ■ Genaue Berechnungsformeln im Code
  • 20. © OPITZ CONSULTING 2019 Min / Max Heap docker run -m 1024m --rm openjdk:12.0.2-jdk java -XX:+PrintFlagsFinal - version | grep -E "UseContainerSupport | MaxRAMPercentage | MinRAMPercentage"    double MaxRAMPercentage                       = 25.000000    double MinRAMPercentage                       = 50.000000      bool UseContainerSupport                    = true docker run -m 1024m --rm openjdk:12.0.2-jdk java -XshowSettings:vm -version VM settings:     Max. Heap Size (Estimated): 247.50M     Using VM: OpenJDK 64-Bit Server VM docker run -m 1024m --rm openjdk:12.0.2-jdk java -XX:MaxRAMPercentage=75.0
 -XshowSettings:vm -version VM settings: Max. Heap Size (Estimated): 742.44M Using VM: OpenJDK 64-Bit Server VM
  • 21. © OPITZ CONSULTING 2019https://www.flickr.com/photos/lemsipmatt/2894816411/
  • 22. © OPITZ CONSULTING 2019 CPU-Limits ■Ab Java 9 / 10 werden Docker CPU-Limits berücksichtigt ■ --cpuset-cpus, --cpus / --cpu-quota, --cpu-period,
 --cpu-shares ■–XX:PreferContainerQuotaForCPUCount (default true) ■Alternativ/Manuell: –XX:ActiveProcessorCount
  • 23. © OPITZ CONSULTING 2019 CPU-Limits echo 'Runtime.getRuntime().availableProcessors()' | 
 docker run -i --rm openjdk:12.0.2-jdk jshell jshell> Runtime.getRuntime().availableProcessors() $1 ==> 4 echo 'Runtime.getRuntime().availableProcessors()' | 
 docker run --cpus 1 -i --rm openjdk:12.0.2-jdk jshell jshell> Runtime.getRuntime().availableProcessors()
 $1 ==> 1
  • 24. © OPITZ CONSULTING 2019https://www.flickr.com/photos/digimeister/16138848190
  • 25. © OPITZ CONSULTING 2019 Ein hochkomplexes Beispiel
  • 26. © OPITZ CONSULTING 2019 Java Images $ docker images REPOSITORY TAG IMAGE ID CREATED SIZE hellojava 3 7733be0c7852 About a minute ago 390MB debian stretch-slim 220611111e8c 2 weeks ago 55.3MB openjdk 12.0.2-jdk e1e07dfba89c 2 weeks ago 470MB
  • 27. © OPITZ CONSULTING 2019 Auf Diät… ■Ab Java 9 haben wir JDK-Module zur Verfügung ■Es sollten nur die benötigten Module der JRE in das Image ■Mit Hilfe von jlink kann eine angepasste JRE erzeugt werden ■ Mit jdeps kann Liste der benötigten Module erzeugt werden
  • 28. © OPITZ CONSULTING 2019 Auf Diät…
  • 29. © OPITZ CONSULTING 2019 Slim… docker images | grep hello hellojava slim-1 0f67adf4b101 5 minutes ago 92.1MB hellojava 3 7733be0c7852 51 minutes ago 390MB
  • 30. © OPITZ CONSULTING 2019 Da geht noch was! ■Projekt Portola migriert die OpenJDK von glibc auf musl ■musl ist eine schlanke Implementierung der libc für Alpine Linux ■Early Access von OpenJDK für Alpine/musl: 
 http://jdk.java.net/14/ ■Alpine/musl mit java.base ca. 51 Mb!
  • 31. © OPITZ CONSULTING 2019https://www.flickr.com/photos/grepsy/6993325519/
  • 32. © OPITZ CONSULTING 2019 AppCDS ■In 8u40 als kommerzielles Feature eingeführt ■Option -XX:+UseAppCDS in JDK 11 obsolet erklärt und in 12 entfernt, da nun „default“ ■Interne Repräsentation der Applikations-Klassen in memmory-mapped files ■Schnelleres Laden bei großen Servern/Applikationen und kleineres memory Footprint ■ Beispiele mit WebLogic usw. ca. 10% - 20% schneller ■ Bei „einfachen“ / kleinen Applikationen kein besonderer Effekt
  • 33. © OPITZ CONSULTING 2019 AppCDS
  • 34. © OPITZ CONSULTING 2019 AOT statt JIT-Compiler ■Ähnlich der AppCDS wird im Vorfeld eine Shared Library erzeugt ■Es erfolgt zur Laufzeit keine Optimierung durch HotSpot ■Macht Sinn bei kurz laufenden Java-Prozessen ■ … z.B. bei Functions mit Java (Fn, OpenFaaS, …) ■Stolperfalle: Shared Library kann sehr groß werden ■ Selektiv die verwendeten Klassen compilieren
  • 35. © OPITZ CONSULTING 2019https://www.flickr.com/photos/jdlasica/698202275/
  • 36. © OPITZ CONSULTING 2019 GraalVM ■„…is a universal virtual machine for running applications written in JavaScript, Python, Ruby, R, JVM-based languages like Java, Scala, Groovy, Kotlin, Clojure, and LLVM-based languages such as C and C++.“ https://www.graalvm.org
  • 37. © OPITZ CONSULTING 2019 GraalVM
  • 38. © OPITZ CONSULTING 2019 GraalVM
  • 39. © OPITZ CONSULTING 2019 GraalVM Step 5/8 : RUN native-image HelloJava ---> Running in ca6f04a96def Build on Server(pid: 32, port: 38449)* [hellojava:32]    classlist:   1,477.66 ms [hellojava:32]        (cap):     890.19 ms [hellojava:32]        setup:   1,932.33 ms … [hellojava:32]      compile:   6,405.54 ms [hellojava:32]        image:     502.27 ms [hellojava:32]        write:     109.88 ms [hellojava:32]      [total]:  20,302.07 ms root@b914b8045203:/# ls -lh total 5.5M drwxr-xr-x   2 root root 4.0K Aug 12 00:00 bin drwxr-xr-x   2 root root 4.0K Mar 28 09:12 boot drwxr-xr-x   5 root root  360 Sep  4 20:30 dev drwxr-xr-x   1 root root 4.0K Sep  4 20:30 etc -rwxr-xr-x   1 root root 5.4M Sep  4 20:24 hellojava
  • 40. © OPITZ CONSULTING 2019 GraalVM ■Aktuell noch „Probleme“ mit Reflection und Proxies ■"Spring Framework provides initial support for GraalVM native images as of 5.1.“ ■Andere Frameworks wie Micronaut sind da besser vorbereitet
  • 41. © OPITZ CONSULTING 2019http://www.flickr.com/photos/an_untrained_eye/6630719431
  • 42. © OPITZ CONSULTING 2019 https://www.flickr.com/photos/tcmorgan/7372944070 @OC_WIRE OPITZCONSULTING opitzconsulting opitz-consulting-bcb8-1009116 WWW.OPITZ-CONSULTING.COM