Skip to content
This repository has been archived by the owner on Mar 28, 2020. It is now read-only.

Docker support #6 #17

Merged
merged 8 commits into from Oct 5, 2017
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions .dockerignore
@@ -0,0 +1,5 @@
.idea
*.iml
.git
build
cloud
37 changes: 37 additions & 0 deletions Dockerfile
@@ -0,0 +1,37 @@
# 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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

docker engine runs containers as root by default, is this required?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'gradle' image creates own 'gradle' user and sets it as current user. Therefore switch back to 'root' to do all pre-cooking is required.
Added comment to Dockerfile.dev


RUN mkdir -p /opt/app
WORKDIR /opt/app

COPY settings.gradle .
COPY api ./api

# Assemble artifact
RUN gradle clean build


# Run the application in a small 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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please align arguments vertically for better readability

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


USER app

EXPOSE 8080

# Run as plain jar file
CMD ["java", "-jar", "api.jar"]
17 changes: 17 additions & 0 deletions Dockerfile.dev
@@ -0,0 +1,17 @@
FROM gradle:4.1-jdk8-alpine
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's think how we could sync build image specification with production Dockerfile

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any ideas on this?

Copy link
Contributor

@trioletas trioletas Sep 28, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No idea yet, a head scratcher for me as well!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideal case would be to have some kind of includes (see moby/moby#735), however it is not supported by Docker (and not clear if it will be supported).
Other solutions were using e.g. C pre-processors or similar tools to manipulate text files that also seems to be more a workaround.

For sure another alternative is KISS - the less moving parts we have in Dockerfile the less things to keep in sync.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, it’s not that big of a deal, code reviews should help keeping things in sync between the two Dockerfiles


# 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

WORKDIR /opt/app

COPY .env .
COPY settings.gradle .

# Release gradle caches if any
RUN find /opt/.gradle -type f -name "*.lock" | while read f; do rm $f; done
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is that generally necessary ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Depends... Our docker-compose.yml mounts volumes from local file system, including gradle caches to speed-up startup of the contenerized application. In case another gradle daemon is already running then application inside container will fail to start

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest that we keep Dockerfile as simple as humanly possible and add this one in to the documentation instead. In a troubleshooting section or something.

Copy link
Contributor

@trioletas trioletas Oct 4, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sergeytrasko please follow up on this and we can merge this one to trunk I believe

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will do today evening

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not required any more (as we are not mounting local FS gradle caches any more)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok thx


ENTRYPOINT ["gradle", "-g", "/opt/.gradle"]
30 changes: 26 additions & 4 deletions README.md
Expand Up @@ -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

Expand All @@ -31,23 +34,40 @@ 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.:
```
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

`$ 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
Expand All @@ -56,6 +76,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

Expand Down
5 changes: 3 additions & 2 deletions api/build.gradle
Expand Up @@ -2,7 +2,7 @@ buildscript {
ext {
springBootVersion = '1.5.4.RELEASE'
}

repositories {
mavenCentral()
}
Expand All @@ -15,7 +15,7 @@ buildscript {
repositories {
mavenCentral()
}

apply plugin: 'java'
sourceCompatibility = 1.8
targetCompatibility = 1.8
Expand All @@ -26,6 +26,7 @@ apply from: 'dotenv.gradle'

bootRun() {
environment << dotenv
jvmArgs = ['-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005']
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we extract this to Dockerfile or docker-compose ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed, there is a option to run the application using gradle from CLI and attach remote debugger from IDE.
Agree, that it is not very realistic case, but let's keep door open unless we have better solution

}

dependencies {
Expand Down
10 changes: 10 additions & 0 deletions docker-compose.test.yml
@@ -0,0 +1,10 @@
version: "3"
services:
spring-boot-graphql-template-test:
command: clean test
build:
context: .
dockerfile: Dockerfile.dev
volumes:
- $HOME/.gradle/caches:/opt/.gradle/caches
- ${PWD}/api:/opt/app/api
13 changes: 13 additions & 0 deletions docker-compose.yml
@@ -0,0 +1,13 @@
version: "3"
services:
spring-boot-graphql-template:
command: bootRun
build:
context: .
dockerfile: Dockerfile.dev
volumes:
- $HOME/.gradle/caches:/opt/.gradle/caches
- ${PWD}/api:/opt/app/api
ports:
- "8080:8080"
- "5005:5005"
Empty file modified gradlew 100644 → 100755
Empty file.