web-dev-qa-db-ja.com

Dockerキャッシュグラドルの依存関係

私はJava WebアプリケーションをDockerを使用してAWS Elastic Beanstalkにデプロイしようとしています。アイデアとは、開発とテストのためにコンテナをローカルで実行し、最終的にgitを使用して本番環境にプッシュすることです。 。

Tomcat8とJava8がインストールされたベースイメージを作成しました。gradleビルドを実行するイメージは、このベースイメージから継承され、ビルドプロセスを高速化します。

Dockerを使用して構築された継承アプリケーションコンテナーがgradlewの依存関係をキャッシュしていないようで、gradlewを含めて毎回それをダウンロードするという点を除いて、すべてがうまく機能します。次のコマンドを使用してWebアプリケーションを構築します。

./gradlew war

~/.gradleにファイルをキャッシュできる方法はありますか?これにより、ビルドが劇的にスピードアップします。

これはBeanstalkではそれほど問題ではありませんが、ローカルでビルドして実行しようとする開発者にとっては大きな問題です。想像できるように、これには時間がかかります。

ベースイメージのdockerfile:

FROM phusion/baseimage
EXPOSE 8080
RUN apt-get update
RUN add-apt-repository ppa:webupd8team/Java
RUN apt-get update
RUN echo Oracle-Java8-installer shared/accepted-Oracle-license-v1-1 select true | Sudo /usr/bin/debconf-set-selections
RUN apt-get -y install Oracle-Java8-installer
RUN Java -version
ENV Tomcat_VERSION 8.0.9
RUN wget --quiet --no-cookies http://archive.Apache.org/dist/Tomcat/tomcat-8/v${Tomcat_VERSION}/bin/Apache-Tomcat-${Tomcat_VERSION}.tar.gz -O /tmp/catalina.tar.gz
# Unpack
RUN tar xzf /tmp/catalina.tar.gz -C /opt
RUN mv /opt/Apache-Tomcat-${Tomcat_VERSION} /opt/Tomcat
RUN ln -s /opt/Tomcat/logs /var/log/Tomcat
RUN rm /tmp/catalina.tar.gz
# Remove unneeded apps
RUN rm -rf /opt/Tomcat/webapps/examples
RUN rm -rf /opt/Tomcat/webapps/docs
RUN rm -rf /opt/Tomcat/webapps/ROOT
ENV CATALINA_HOME /opt/Tomcat
ENV PATH $PATH:$CATALINA_HOME/bin
ENV CATALINA_OPTS $PARAM1
# Start Tomcat
CMD ["/opt/Tomcat/bin/catalina.sh", "run"]

アプリケーションのdockerfile:

FROM <tag name here for base image>
RUN mkdir ~/.gradle
# run some extra stuff here to add things to gradle.properties file
# Add project Source
ADD . /var/app/myapp
# Compile and Deploy Application, this is what is downloading gradlew and all the maven dependencies every time, if only there was a way to take the changes it makes to ~/.gradle and persist it as a cache layer
RUN cd /var/app/myapp/ && ./gradlew war
RUN mv /var/app/myapp/build/libs/myapp.war /opt/Tomcat/webapps/ROOT.war
# Start Tomcat
CMD ["/opt/Tomcat/bin/catalina.sh", "run"]
32

私はこの問題に直面しました。ご存知かもしれませんが、Dockerイメージをビルドするときに、独立したステップとして依存関係のみをダウンロードすることをお勧めします。依存関係だけをダウンロードするための直接のサポートがないため、gradleでは少しトリッキーになります。

オプション1:docker-gradle Dockerイメージを使用する


ビルド済みのGradle Dockerイメージを使用してアプリケーションをビルドできます。これにより、ローカルシステムビルドではなく、クリーンなDockerイメージで行われたビルドになります。

docker volume create --name gradle-cache
docker run --rm -v gradle-cache:/home/gradle/.gradle -v "$PWD":/home/gradle/project -w /home/gradle/project gradle:4.7.0-jdk8-Alpine gradle build
ls -ltrh ./build/libs
  • gradleキャッシュはボリュームとしてここにロードされます。したがって、以降のビルドでは、ダウンロードされた依存関係を再利用します。
  • この後、Dockerfileでこのアーティファクトを取得し、アプリケーション固有のイメージを生成してアプリケーションを実行できます。
  • この方法では、ビルダーイメージは必要ありません。アプリケーション構築フローとアプリケーション実行フローは分離されています。
  • Gradleキャッシュボリュームがマウントされているため、ダウンロードした依存関係をさまざまなGradleプロジェクトで再利用できます。

オプション2:マルチステージビルド


----- Dockerfile -----

FROM openjdk:8 AS TEMP_BUILD_IMAGE
ENV APP_HOME=/usr/app/
WORKDIR $APP_HOME
COPY build.gradle settings.gradle gradlew $APP_HOME
COPY gradle $APP_HOME/gradle
RUN ./gradlew build || return 0 
COPY . .
RUN ./gradlew build

FROM openjdk:8
ENV ARTIFACT_NAME=your-application.jar
ENV APP_HOME=/usr/app/
WORKDIR $APP_HOME
COPY --from=TEMP_BUILD_IMAGE $APP_HOME/build/libs/$ARTIFACT_NAME .
EXPOSE 8080
CMD ["Java","-jar",$ARTIFACT_NAME]

上記のDockerfile

  • 最初に、build.gradle、gradlewなどのように、プロジェクトのgradleファイルのみをコピーしようとします。
  • 次にgradleディレクトリ自体をコピーします
  • そして、ビルドを実行しようとします。この時点では、ディレクトリに他のソースコードファイルはありません。したがって、ビルドは失敗します。しかし、その前に、依存関係をダウンロードします。
  • ビルドが失敗することが予想されるため、0を返し、Dockerが実行を継続できるようにする簡単なテクニックを試しました
  • すべての依存関係がダウンロードされ、Dockerがこのレイヤーをキャッシュするため、これにより後続のビルドフローが高速化されます。比較的、gradleキャッシュディレクトリをボリュームマウントすることは、依然として最善のアプローチです。
  • 上記の例は、複数のDockerビルドファイルを回避する マルチステージDockerイメージ ビルドも示しています。
13
Sairam Krish

Build.gradleにresolveDependenciesタスクを追加します。

task resolveDependencies {
    doLast {
        project.rootProject.allprojects.each { subProject ->
            subProject.buildscript.configurations.each { configuration ->
                configuration.resolve()
            }
            subProject.configurations.each { configuration ->
                configuration.resolve()
            }
        }
    }
}

dockerfileを更新します。

ADD build.gradle /opt/app/
WORKDIR /opt/app
RUN gradle resolveDependencies

ADD . .

RUN gradle build -x test --parallel && \
    touch build/libs/api.jar

II

怒鳴るは私が今やっていることです:

build.gradle

ext {
    speed = project.hasProperty('speed') ? project.getProperty('speed') : false
    offlineCompile = new File("$buildDir/output/lib")
}

dependencies {
    if (speed) {
        compile fileTree(dir: offlineCompile, include: '*.jar')
    } else {
        // ...dependencies
    }
}

task downloadRepos(type: Copy) {
    from configurations.all
    into offlineCompile
}

Dockerfile

ADD build.gradle /opt/app/
WORKDIR /opt/app

RUN gradle downloadRepos

ADD . /opt/app
RUN gradle build -Pspeed=true
11
Daniel Wei

アプリケーションイメージを2つのイメージに分割することを検討してください。1つはmyapp.warをビルドするためのもので、もう1つはアプリケーションを実行するためのものです。そうすることで、実際のビルド中にdockerボリュームを使用し、ホストの~/.gradleフォルダーをビルドを実行するコンテナーにバインドできます。ただし、アプリケーションを実行するための1つのステップではなく、より多くのステップがあります。例:

ビルダー画像

FROM <tag name here for base image including all build time dependencies>

# Add project Source
# -> you can use a project specific gradle.properties in your project root
# in order to override global/user gradle.properties
ADD . /var/app/myapp

RUN mkdir -p /root/.gradle
ENV HOME /root
# declare shared volume path
VOLUME /root/.gradle
WORKDIR /var/app/myapp/ 

# Compile only
CMD ["./gradlew", "war"]

アプリケーション画像

FROM <tag name here for application base image>

ADD ./ROOT.war /opt/Tomcat/webapps/ROOT.war

# Start Tomcat
CMD ["/opt/Tomcat/bin/catalina.sh", "run"]

プロジェクトルートでの使用方法。ビルダーDockerfileがそこにあり、アプリケーションDockerfileがwebappサブフォルダー(または他の任意のパス)にあると仮定します。

$ docker build -t builder .
$ docker run --name=build-result -v ~/.gradle/:/root/.gradle/ builder
$ docker cp build-result:/var/app/myapp/myapp.war webapp/ROOT.war
$ cd webapp
$ docker build -t application .
$ docker run -d -P application

表示されたコードはまだテストしていませんが、理解していただければ幸いです。例は、.gradle /キャッシュにデータボリュームを使用することで改善される場合があります。詳細については、Docker ユーザーガイド を参照してください。

7
gesellix