From e8012f409f64b4c22887f0509a8428e1211ad31c Mon Sep 17 00:00:00 2001 From: Sergey Trasko Date: Tue, 26 Sep 2017 08:58:39 +0300 Subject: [PATCH 1/8] Docker support #6 --- .dockerignore | 5 +++++ Dockerfile.dev | 12 ++++++++++++ Dockerfile.test | 12 ++++++++++++ README.md | 21 ++++++++++++++++++--- api/build.gradle | 5 +++-- docker-compose.test.yml | 9 +++++++++ docker-compose.yml | 12 ++++++++++++ 7 files changed, 71 insertions(+), 5 deletions(-) create mode 100644 .dockerignore create mode 100644 Dockerfile.dev create mode 100644 Dockerfile.test create mode 100644 docker-compose.test.yml create mode 100644 docker-compose.yml diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..f8266c3 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,5 @@ +.idea +*.iml +.git +build +cloud \ No newline at end of file diff --git a/Dockerfile.dev b/Dockerfile.dev new file mode 100644 index 0000000..8d80f9e --- /dev/null +++ b/Dockerfile.dev @@ -0,0 +1,12 @@ +FROM gradle:4.1-jdk8 + +ENV HOME /home/gradle + +RUN mkdir -p $HOME/app \ + && cd $HOME/app +WORKDIR $HOME/app + +COPY .env . +COPY settings.gradle . + +CMD ["gradle", "bootRun"] diff --git a/Dockerfile.test b/Dockerfile.test new file mode 100644 index 0000000..cd8524e --- /dev/null +++ b/Dockerfile.test @@ -0,0 +1,12 @@ +FROM gradle:4.1-jdk8 + +ENV HOME /home/gradle + +RUN mkdir -p $HOME/app \ + && cd $HOME/app +WORKDIR $HOME/app + +COPY .env . +COPY settings.gradle . + +CMD ["gradle", "clean", "test"] diff --git a/README.md b/README.md index ca283a9..56a721d 100644 --- a/README.md +++ b/README.md @@ -10,9 +10,12 @@ Spring Boot, GraphQL template project with batteries included.  - Logging level, e.g. `LOGGING_LEVEL_feign=DEBUG` - App properties, e.g. `APP_DEPENDENCY_API_HOST=example.com` - See [Spring Boot documentation on relaxed property binding](https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-relaxed-binding) +- Docker :whale: configuration for production deployment, development and test + - Remote debugging for development mode ## Required Software - JDK 1.8 +- Or docker + docker-compose ### Lombok @@ -31,7 +34,9 @@ Spring Boot, GraphQL template project with batteries included. ## Develop -1. Create top level `.env` file and add required [key-values](https://docs.oracle.com/cd/E23095_01/Platform.93/ATGProgGuide/html/s0204propertiesfileformat01.html) +1. Create `.env` file + +Create top level `.env` file and add required [key-values](https://docs.oracle.com/cd/E23095_01/Platform.93/ATGProgGuide/html/s0204propertiesfileformat01.html) e.g.: ``` @@ -39,11 +44,19 @@ APP_ICNDB_URL=https://api.icndb.com LOGGING_LEVEL_feign=DEBUG ``` -2. `$ gradlew bootRun` +2.1. Run + +- Gradle: `$ gradlew bootRun` +- Docker: `$ docker-compose up` (or `$ docker-compose up --build` if image should be rebuilt) + +2.2. Debug + +Run remote debugger from IDE. Debug port is 5005 ## Test -`$ gradlew test` +- Gradle: `$ gradlew test` +- Docker: `$ docker-compose -f docker-compose.test.yml up --build` ## Build @@ -56,6 +69,8 @@ LOGGING_LEVEL_feign=DEBUG - [GraphQL](http://graphql.org/learn/) : API query runtime - [GraphQL and GraphiQL Spring Framework Boot Starters](https://github.com/graphql-java/graphql-spring-boot) - [GraphQL Java Tools](https://github.com/graphql-java/graphql-java-tools) +- Docker + - [Home Page](https://www.docker.com) ## Cloud Deployment diff --git a/api/build.gradle b/api/build.gradle index f3d8788..651a264 100644 --- a/api/build.gradle +++ b/api/build.gradle @@ -2,7 +2,7 @@ buildscript { ext { springBootVersion = '1.5.4.RELEASE' } - + repositories { mavenCentral() } @@ -15,7 +15,7 @@ buildscript { repositories { mavenCentral() } - + apply plugin: 'java' sourceCompatibility = 1.8 targetCompatibility = 1.8 @@ -26,6 +26,7 @@ apply from: 'dotenv.gradle' bootRun() { environment << dotenv + jvmArgs = ['-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005'] } dependencies { diff --git a/docker-compose.test.yml b/docker-compose.test.yml new file mode 100644 index 0000000..8dc523b --- /dev/null +++ b/docker-compose.test.yml @@ -0,0 +1,9 @@ +version: "3" +services: + spring-boot-graphql-template-test: + build: + context: . + dockerfile: Dockerfile.test + volumes: + - $HOME/.gradle/caches:/home/gradle/.gradle/caches + - ${PWD}/api:/home/gradle/app/api diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..567a540 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,12 @@ +version: "3" +services: + spring-boot-graphql-template: + build: + context: . + dockerfile: Dockerfile.dev + volumes: + - $HOME/.gradle/caches:/home/gradle/.gradle/caches + - ${PWD}/api:/home/gradle/app/api + ports: + - "8080:8080" + - "5005:5005" \ No newline at end of file From e1cc251108912a07b5ff0cc3fa0deb2ac94628ab Mon Sep 17 00:00:00 2001 From: Sergey Trasko Date: Tue, 26 Sep 2017 15:13:59 +0300 Subject: [PATCH 2/8] Docker support #6 Production image --- Dockerfile | 21 +++++++++++++++++++++ README.md | 9 ++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..db6e394 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,21 @@ +FROM gradle:4.1-jdk8 + +ENV HOME /home/gradle + +RUN mkdir -p $HOME/app \ + && cd $HOME/app + +WORKDIR $HOME/app + +USER root + +COPY settings.gradle . +COPY api ./api + +RUN chown -R gradle $HOME/app + +USER gradle + +EXPOSE 8080 + +CMD ["gradle", "bootRun"] diff --git a/README.md b/README.md index 56a721d..9598f96 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,14 @@ Run remote debugger from IDE. Debug port is 5005 ## Build -`$ gradlew buld` +- Gradle: `$ gradlew buld` +- Docker: `$ docker build -t spring-boot-graphql-template .` + +## Run productive + +Assuming that the Docker image is already built on the previous step + +- Docker (add `-d` to run in daemon mode): `$ docker run -e 'APP_ICNDB_URL=https://api.icndb.com' -p 8080:8080 spring-boot-graphql-template` ## Tech Stack - [Spring Boot](https://projects.spring.io/spring-boot/) : Application framework From b32878706c5d88886446b87a715ef5edc50137b0 Mon Sep 17 00:00:00 2001 From: Sergey Trasko Date: Tue, 26 Sep 2017 21:16:58 +0300 Subject: [PATCH 3/8] Docker support #6 Part of PR feedback addressed --- Dockerfile.dev | 25 +++++++++++++++++++------ Dockerfile.test | 12 ------------ docker-compose.test.yml | 7 ++++--- docker-compose.yml | 5 +++-- gradlew | 0 5 files changed, 26 insertions(+), 23 deletions(-) delete mode 100644 Dockerfile.test mode change 100644 => 100755 gradlew diff --git a/Dockerfile.dev b/Dockerfile.dev index 8d80f9e..a866f80 100644 --- a/Dockerfile.dev +++ b/Dockerfile.dev @@ -1,12 +1,25 @@ -FROM gradle:4.1-jdk8 +FROM gradle:4.1-jdk8-alpine -ENV HOME /home/gradle +# Gradle image creates a 'gradle' user, so fallback to 'root' to do initial setup +USER root -RUN mkdir -p $HOME/app \ - && cd $HOME/app -WORKDIR $HOME/app +RUN mkdir -p /opt/app \ + && mkdir -p /opt/.gradle \ + && addgroup -S -g 1001 boot \ + && adduser -D -S -G boot -u 1001 -s /bin/ash boot \ + && chown -R boot:boot /opt/app \ + && chown -R boot:boot /opt/.gradle + +WORKDIR /opt/app COPY .env . COPY settings.gradle . -CMD ["gradle", "bootRun"] +# Run the build on behalf of non-root 'boot' user +USER boot + +# Release gradle caches if any +RUN find /opt/.gradle -type f -name "*.lock" | while read f; do rm $f; done + +# Using gradle home where 'boot' user has full access to +ENTRYPOINT ["gradle", "-g", "/opt/.gradle"] diff --git a/Dockerfile.test b/Dockerfile.test deleted file mode 100644 index cd8524e..0000000 --- a/Dockerfile.test +++ /dev/null @@ -1,12 +0,0 @@ -FROM gradle:4.1-jdk8 - -ENV HOME /home/gradle - -RUN mkdir -p $HOME/app \ - && cd $HOME/app -WORKDIR $HOME/app - -COPY .env . -COPY settings.gradle . - -CMD ["gradle", "clean", "test"] diff --git a/docker-compose.test.yml b/docker-compose.test.yml index 8dc523b..d0fa707 100644 --- a/docker-compose.test.yml +++ b/docker-compose.test.yml @@ -1,9 +1,10 @@ version: "3" services: spring-boot-graphql-template-test: + command: clean test build: context: . - dockerfile: Dockerfile.test + dockerfile: Dockerfile.dev volumes: - - $HOME/.gradle/caches:/home/gradle/.gradle/caches - - ${PWD}/api:/home/gradle/app/api + - $HOME/.gradle/caches:/opt/.gradle/caches + - ${PWD}/api:/opt/app/api diff --git a/docker-compose.yml b/docker-compose.yml index 567a540..18baf9e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,12 +1,13 @@ version: "3" services: spring-boot-graphql-template: + command: bootRun build: context: . dockerfile: Dockerfile.dev volumes: - - $HOME/.gradle/caches:/home/gradle/.gradle/caches - - ${PWD}/api:/home/gradle/app/api + - $HOME/.gradle/caches:/opt/.gradle/caches + - ${PWD}/api:/opt/app/api ports: - "8080:8080" - "5005:5005" \ No newline at end of file diff --git a/gradlew b/gradlew old mode 100644 new mode 100755 From ac2898818027676dbdfededbbae8e7097dc06ac0 Mon Sep 17 00:00:00 2001 From: Sergey Trasko Date: Tue, 26 Sep 2017 21:49:05 +0300 Subject: [PATCH 4/8] Docker support #6 Part of PR feedback addressed - production build --- Dockerfile | 39 ++++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/Dockerfile b/Dockerfile index db6e394..ae620bd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,21 +1,38 @@ -FROM gradle:4.1-jdk8 - -ENV HOME /home/gradle - -RUN mkdir -p $HOME/app \ - && cd $HOME/app - -WORKDIR $HOME/app +# Building the image +FROM gradle:4.1-jdk8-alpine as build +# Gradle image creates a 'gradle' user, so fallback to 'root' to do initial setup USER root +RUN mkdir -p /opt/app +WORKDIR /opt/app + +COPY .env . COPY settings.gradle . COPY api ./api -RUN chown -R gradle $HOME/app +# Assemble artifact +RUN gradle clean build + + +# Run the application in a smil container +FROM openjdk:8-jre-alpine as runtime + +RUN mkdir -p /opt/app + +WORKDIR /opt/app + +# Take artifact from previous step +COPY --from=build /opt/app/api/build/libs/api.jar . + +# Create new user to run application on behalf of +RUN addgroup -S -g 1001 app \ + && adduser -D -S -G app -u 1001 -s /bin/ash app \ + && chown -R app:app /opt/app -USER gradle +USER app EXPOSE 8080 -CMD ["gradle", "bootRun"] +# Run as plain jar file +CMD ["java", "-jar", "api.jar"] From 54397a7aa4b89fed1002158d3cdb8fb526d24ed0 Mon Sep 17 00:00:00 2001 From: Sergey Trasko Date: Wed, 27 Sep 2017 09:49:49 +0300 Subject: [PATCH 5/8] Docker support #6 Formatting --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index ae620bd..ea7fa5e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -27,7 +27,7 @@ COPY --from=build /opt/app/api/build/libs/api.jar . # Create new user to run application on behalf of RUN addgroup -S -g 1001 app \ - && adduser -D -S -G app -u 1001 -s /bin/ash app \ + && adduser -D -S -G app -u 1001 -s /bin/ash app \ && chown -R app:app /opt/app USER app From 595cab23f876d44c1aa99dd3a6cf94e8e624e2bb Mon Sep 17 00:00:00 2001 From: Sergey Trasko Date: Wed, 27 Sep 2017 09:52:31 +0300 Subject: [PATCH 6/8] Docker support #6 Formatting --- Dockerfile.dev | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile.dev b/Dockerfile.dev index a866f80..d62613a 100644 --- a/Dockerfile.dev +++ b/Dockerfile.dev @@ -6,7 +6,7 @@ USER root RUN mkdir -p /opt/app \ && mkdir -p /opt/.gradle \ && addgroup -S -g 1001 boot \ - && adduser -D -S -G boot -u 1001 -s /bin/ash boot \ + && adduser -D -S -G boot -u 1001 -s /bin/ash boot \ && chown -R boot:boot /opt/app \ && chown -R boot:boot /opt/.gradle From 3565fd59abc29bf8f006927f3b700d03ee296124 Mon Sep 17 00:00:00 2001 From: Sergey Trasko Date: Wed, 27 Sep 2017 17:41:50 +0300 Subject: [PATCH 7/8] Docker support #6 PR feedback - don't use .env from prod - don't create a separet user for dev --- Dockerfile | 3 +-- Dockerfile.dev | 10 +--------- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/Dockerfile b/Dockerfile index ea7fa5e..fb187c3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,7 +7,6 @@ USER root RUN mkdir -p /opt/app WORKDIR /opt/app -COPY .env . COPY settings.gradle . COPY api ./api @@ -15,7 +14,7 @@ COPY api ./api RUN gradle clean build -# Run the application in a smil container +# Run the application in a small container FROM openjdk:8-jre-alpine as runtime RUN mkdir -p /opt/app diff --git a/Dockerfile.dev b/Dockerfile.dev index d62613a..03a44cd 100644 --- a/Dockerfile.dev +++ b/Dockerfile.dev @@ -4,22 +4,14 @@ FROM gradle:4.1-jdk8-alpine USER root RUN mkdir -p /opt/app \ - && mkdir -p /opt/.gradle \ - && addgroup -S -g 1001 boot \ - && adduser -D -S -G boot -u 1001 -s /bin/ash boot \ - && chown -R boot:boot /opt/app \ - && chown -R boot:boot /opt/.gradle + && mkdir -p /opt/.gradle WORKDIR /opt/app COPY .env . COPY settings.gradle . -# Run the build on behalf of non-root 'boot' user -USER boot - # Release gradle caches if any RUN find /opt/.gradle -type f -name "*.lock" | while read f; do rm $f; done -# Using gradle home where 'boot' user has full access to ENTRYPOINT ["gradle", "-g", "/opt/.gradle"] From 1c70d74d183e8a1625c813ae282898d6d9a6ee40 Mon Sep 17 00:00:00 2001 From: Sergey Trasko Date: Thu, 5 Oct 2017 18:26:43 +0300 Subject: [PATCH 8/8] Docker support #6 - Don't mount gradle caches from local FS - Pre-fetch gradle dependencies before copying sources to cache them --- Dockerfile.dev | 17 ++++++++++------- docker-compose.test.yml | 1 - docker-compose.yml | 1 - 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/Dockerfile.dev b/Dockerfile.dev index 03a44cd..b7d0b20 100644 --- a/Dockerfile.dev +++ b/Dockerfile.dev @@ -3,15 +3,18 @@ FROM gradle:4.1-jdk8-alpine # Gradle image creates a 'gradle' user, so fallback to 'root' to do initial setup USER root -RUN mkdir -p /opt/app \ - && mkdir -p /opt/.gradle +ENV GRADLE_USER_HOME /opt +RUN mkdir -p /opt/app WORKDIR /opt/app -COPY .env . -COPY settings.gradle . +# Copy gradle build scripts +COPY .env settings.gradle ./ +COPY api/build.gradle api/dotenv.gradle ./api/ -# Release gradle caches if any -RUN find /opt/.gradle -type f -name "*.lock" | while read f; do rm $f; done +# Fetch dependencies - do it before copying the source code to cache the layer +RUN ["gradle", "--no-daemon"] -ENTRYPOINT ["gradle", "-g", "/opt/.gradle"] +COPY api api + +ENTRYPOINT ["gradle", "--no-daemon"] diff --git a/docker-compose.test.yml b/docker-compose.test.yml index d0fa707..14d726a 100644 --- a/docker-compose.test.yml +++ b/docker-compose.test.yml @@ -6,5 +6,4 @@ services: context: . dockerfile: Dockerfile.dev volumes: - - $HOME/.gradle/caches:/opt/.gradle/caches - ${PWD}/api:/opt/app/api diff --git a/docker-compose.yml b/docker-compose.yml index 18baf9e..10b128a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,7 +6,6 @@ services: context: . dockerfile: Dockerfile.dev volumes: - - $HOME/.gradle/caches:/opt/.gradle/caches - ${PWD}/api:/opt/app/api ports: - "8080:8080"