Perl on Docker - Multi-stage Builds zur Verkürzung von Build-Laufzeiten
Veröffentlicht von Thomas Fahle am (Permalink)
Einführung
Beim Bau eines Docker-Images werden oft (mehrere) Artifakte erzeugt, deren Erstellung recht zeit- und ressourceaufwendig sein kann. Ein typisches Bespiel dafür ist das Kompilieren von umfangreichen C-Programmen.
Ohne multi-stage builds muss das Image auch bei noch so kleinen Änderungen am Dockerfile komplett neu erstellt werden.
Mit Docker Multi-Stage Builds kann man hingegen innerhalb eines Dockerfiles mehrere unabhängige Zwischencontainer/Images erstellen, die jeweils ein Ergebnis (Artefakt) produzieren. Dieses intermediäre Ergebnis wird von Docker zwischengespeichert (Cache) und kann von anderen Containern/Images gezogen werden. Es wird also nur der geänderte Teil des Images neu erzeugt, alle anderen Teile werden wiederverwendet.
In diesem Beitrag wird ein C-Programm (hier ta-lib) aus den Sourcen in ein intermediäres Image installiert. Dieses Artefakt wird in einem weiterem Build Stage zur Installation eines CPAN-Moduls (hier Finance::TA) wiederverwendet. Wiederholte Docker Builds laufen Dank dieser Vorgehensweise erheblich schneller.
Beispiel: ta-lib in Zwischencontainer kompilieren (Stage 1) und Finance::TA installieren (Stage 2)
Das nachfolgende Beispiel nutzt Official Docker Perl Images, die bereits in Perl on Docker - Offizielle Perl Docker Images als Grundlage eigener Images beschrieben wurden, als Basis.
Im ersten Schritt wird ta-lib wie breits in TA-LIB und Finance::TA auf Ubuntu installieren beschrieben aus den C-Sourcen in einen Zwischencontainer installiert.
Im zweiten Schritt wird das CPAN Modul Finance::TA mittels cpanm installiert. Die fertigen Binaries, Bibliotheken und Header aus dem ersten Schritt/Zwischencontainer werden in den zweiten Container (Layer) kopiert.
Zu Demonstrationszwecken werden noch einige weitere CPAN-Module und ein kleines Testprogramm (finance-ta-sma.pl) installiert. Das Programm wurde bereits in Finance::TA - Perl Bibliothek zur Nutzung der Technical Analysis Library (http://ta-lib.org) beschrieben.
Randnotiz: Hier wird alles – auch alte Beiträge – wiederverwendet.
Dockerfile
Datei Dockerfile.
# Stage 1: Build TA-LIB FROM perl:5.34.0 as ta-lib # https://github.com/perl/docker-perl/blob/311f05366d91427d289740dd15fb9401dc4347ef/5.034.000-main-buster/Dockerfile RUN set -ex; \ wget http://prdownloads.sourceforge.net/ta-lib/ta-lib-0.4.0-src.tar.gz && \ tar -xvzf ta-lib-0.4.0-src.tar.gz && \ cd ta-lib/ && \ ./configure --prefix=/usr/local && \ make && \ make install; \ cd .. ; \ rm -rf ta-lib ta-lib-0.4.0-src.tar.gz ; # Stage 2: Install Finance::TA FROM perl:5.34.0 LABEL maintainer="Thomas Fahle <perlhowto.github.io@gmail.com>" LABEL version="0.10" LABEL description="Perl on Docker - Finance::TA/ta-lib Container - based on perl:5.34.0 buildpacks-deps" # Copy compiled (docker cached) ta-lib from stage 1 into stage 2 COPY --from=ta-lib /usr/local/lib/libta_lib.* /usr/local/lib/ COPY --from=ta-lib /usr/local/bin/ta-lib-config /usr/local/bin/ta-lib-config COPY --from=ta-lib /usr/local/include/ta-lib/ /usr/local/include/ta-lib/ # Upgrade already installed packages in noninteractive mode # Install SQLite3 # Install tree # Install vim # Autoremove unused packages # Clean local repos # # cpanm # Install DBD::SQLite # Install Finance::TA # Install Text::CSV Text::CSV_XS Text::CSV_PP Text::CSV::Slurp # # Free disk space to decrease image size ARG DEBIAN_FRONTEND=noninteractive # Set TALIB_CFLAGS because # ta-lib-config --cflags returns incorrect data ARG TALIB_CFLAGS='-I/usr/local/include/ta-lib -DHAVE_CONFIG_H' RUN set -ex; \ apt-get update && \ apt-get dist-upgrade -y && \ apt-get -y -qq --no-install-recommends install sqlite3 tree vim && \ apt-get -y autoremove && \ apt-get clean \ ; \ /usr/local/bin/cpanm \ DBD::SQLite \ Finance::TA \ Text::CSV Text::CSV_XS Text::CSV_PP Text::CSV::Slurp \ ; \ rm -rf /var/lib/apt/lists/* ; \ rm -rf /tmp/* ; \ rm -rf /root/.cpanm/ WORKDIR /app # Copy simple demo program into container to check Finance::TA COPY ./finance-ta-sma.pl /app/finance-ta-sma.pl CMD ["/bin/bash"]
Das Image kann jetzt gebaut,
sudo DOCKER_BUILDKIT=1 docker build -t ta-lib-image .
gestartet
sudo docker run -it --rm --name ta-lib ta-lib-image
und getestet werden.
root@c97043f36ab8:/app# /app/finance-ta-sma.pl i | value | slow_sma | fast_sma | 0 | 91.500000 | N/A | N/A | 1 | 94.815000 | N/A | N/A | 2 | 94.375000 | N/A | 93.5633333333333 | 3 | 95.095000 | 93.94625 | 94.7616666666667 | 4 | 93.780000 | 94.51625 | 94.4166666666667 | 5 | 94.625000 | 94.46875 | 94.5 | 6 | 92.530000 | 94.0075 | 93.645 | 7 | 92.750000 | 93.42125 | 93.3016666666667 | 8 | 90.315000 | 92.555 | 91.865 | 9 | 92.470000 | 92.01625 | 91.845 |
Keine erneute Kompilation von ta-lib (Stage 1) bei Änderungen in Stage 2
Falls das Image nach einer Anpassung, z.B. Installation weiterer CPAN-Module, im Abschnitt 2 des Dockerfiles neu gebaut werden muss, so wird nur der zweite Zwischencontainer neu erstellt. Der Zwischencontainer aus Schritt 1 wird nicht neu erzeugt, sondern aus dem Docker-Image-Cache gezogen. Dies beschleunigt den erneuten Build-Vorgang erheblich.
Bei Änderungen in Schritt 1 muss natürlich das Zwischenimage neu gebaut werden, da hilft leider nichts.
Beispielprogramm finance-ta-sma.pl
Hier noch das Beispielprogramm finance-ta-sma.pl aus Finance::TA - Perl Bibliothek zur Nutzung der Technical Analysis Library (http://ta-lib.org):
#!/usr/bin/env perl use strict; use warnings; use Finance::TA; # Data straight from https://metacpan.org/dist/Finance-TA/view/TA.pod my @series = ( '91.500000', '94.815000', '94.375000', '95.095000', '93.780000', '94.625000', '92.530000', '92.750000', '90.315000', '92.470000' ); # https://metacpan.org/dist/Finance-TA/view/TA.pod#TA_SMA-(Simple-Moving-Average) # TA_SMA (Simple Moving Average) # ($retCode, $begIdx, $outReal) = TA_SMA($startIdx, $endIdx, \@inReal, $optInTimePeriod); # my $startIdx = 0; my $endIdx = $#series; # Fast SMA my $optInTimePeriod_fast_sma = 3; my ( $retCode_fast_sma, $begIdx_fast_sma, $result_fast_sma ) = TA_SMA( $startIdx, $endIdx, \@series, $optInTimePeriod_fast_sma ); # Die on TA errors die "Error fast TA_SMA $retCode_fast_sma" unless $retCode_fast_sma == $TA_SUCCESS; # Slow SMA my $optInTimePeriod_slow_sma = 4; my ( $retCode_slow_sma, $begIdx_slow_sma, $result_slow_sma ) = TA_SMA( $startIdx, $endIdx, \@series, $optInTimePeriod_slow_sma ); # Die on TA errors die "Error slow TA_SMA $retCode_slow_sma" unless $retCode_slow_sma == $TA_SUCCESS; my $format = "%s | %10s | %10s | %20s |\n"; printf( $format, 'i', 'value', 'slow_sma', 'fast_sma' ); for ( my $i = 0 ; $i <= $#series ; $i++ ) { my $value = $series[$i]; my $fast_sma = 'N/A'; my $slow_sma = 'N/A'; if ( $i >= $begIdx_fast_sma ) { $fast_sma = $result_fast_sma->[ $i - $begIdx_fast_sma ]; } if ( $i >= $begIdx_slow_sma ) { $slow_sma = $result_slow_sma->[ $i - $begIdx_slow_sma ]; } printf( $format, $i, $value, $slow_sma, $fast_sma ); }
That's it.
Siehe auch
- Docker - Use multi-stage builds
- Docker
- Docker Docs
- Official Docker Perl
- Github docker-perl
- Debugging a Perl Docker container
- Perl on Docker - Dancer2 Hello World Beispiel
- Perl on Docker - Offizielle Perl Docker Images als Grundlage eigener Images
- Perl on Docker - Dancer2 und Redis docker-compose Beispiel
- Perl on Docker - Perl commandline Programm als Docker Container erstellen und nutzen
- TA-Lib: Technical Analysis Library
- TA-LIB und Finance::TA auf Ubuntu installieren
- Finance::TA - Perl Bibliothek zur Nutzung der Technical Analysis Library (http://ta-lib.org)
Source-Code der Beispiele im Github Repo perl-howto-code.
Bildnachweis
Photo by mostafa meraji on Unsplash