我正在尝试使用docker将我们的java web应用程序部署到aws弹性beanstalk,我们的想法是能够在本地运行容器以进行开发和测试,并最终使用git将其推送到生产环境。
我已经创建了一个安装了tomcat8和java8的基本映像,执行gradle构建的映像继承了这个基本映像,从而加快了构建过程。
一切正常,除了使用docker构建的继承应用程序容器似乎不缓存gradle依赖项这一事实,它每次都会下载它,包括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"]
答案 0 :(得分:11)
我遇到了这个问题。您可能会同意,最佳做法是在构建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
选项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
中答案 1 :(得分:8)
在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
贝娄是我现在所做的:
的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
答案 2 :(得分:7)
您可能需要考虑将应用程序映像拆分为两个映像:一个用于构建myapp.war,另一个用于运行应用程序。这样,您可以在实际构建期间使用docker卷,并将主机的~/.gradle
文件夹绑定到执行构建的容器中。不过,只有一步来运行您的应用程序,您可以采取更多步骤。例如:
构建器图片
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 / cache的数据卷甚至可以改进该示例,有关详细信息,请参阅Docker user guide。
答案 3 :(得分:-1)
尝试更改gradle用户主目录
RUN mkdir -p /opt/gradle/.gradle
ENV GRADLE_USER_HOME = / opt / gradle / .gradle