MacOS + Docker (Version 17.12.0-ce-mac49 (21995)) here. I am trying to Dockerize an existing Spring Boot app. Here's my Dockerfile:
FROM openjdk:8
RUN mkdir /opt/myapp
ADD build/libs/myapp.jar /opt/myapp
ADD application.yml /opt/myapp
ADD logback.groovy /opt/myapp
WORKDIR /opt/myapp
EXPOSE 9200
ENTRYPOINT ["java", "-Dspring.config=.", "-jar", "myapp.jar"]
Here's my Spring Boot application.yml config file. As you can see it expects Docker to inject environment variables from an env file:
logging:
config: 'logback.groovy'
server:
port: 9200
error:
whitelabel:
enabled: true
spring:
cache:
type: none
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://${DB_HOST}:3306/myapp_db?useSSL=false&nullNamePatternMatchesAll=true
username: ${DB_USERNAME}
password: ${DB_PASSWORD}
testWhileIdle: true
validationQuery: SELECT 1
jpa:
show-sql: false
hibernate:
ddl-auto: none
naming:
physical-strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy
implicit-strategy: org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy
properties:
hibernate.dialect: org.hibernate.dialect.MySQL5InnoDBDialect
hibernate.cache.use_second_level_cache: false
hibernate.cache.use_query_cache: false
hibernate.generate_statistics: false
hibernate.hbm2ddl.auto: validate
myapp:
detailsMode: ${DETAILS_MODE}
tokenExpiryDays:
alert: 5
jwtInfo:
secret: ${JWT_SECRET}
expiry: ${JWT_EXPIRY}
topics:
adminAlerts: admin-alerts
Here's my myapp-local.env file:
DB_HOST=localhost
DB_USERNAME=root
DB_PASSWORD=
DETAILS_MODE=Terse
JWT_SECRET=12345==
JWT_EXPIRY=86400000
It's worth noting that above in the env file, I have tried localhost, 127.0.0.1 and 172.17.0.1 and all of them produce identical errors below.
Then I build the container:
docker build -t myapp .
Success! Then I run the container:
docker run -it -p 9200:9200 --net="host" --env-file myapp-local.env --name myapp myapp
...and I watch as the container quickly dies with MySQL connection-related exceptions (can't connect to the MySQL machine running locally). I can confirm that the Spring Boot app has no problem connecting to MySQL when it runs as an executable ("fat") jar outside of Docker, and I can confirm that the local MySQL instance is up and running and is perfectly healthy.
Unable to connect to database. }com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure
The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
at com.mysql.cj.jdbc.exceptions.SQLError.createCommunicationsException(SQLError.java:590)
at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:57)
at com.mysql.cj.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:1606)
at com.mysql.cj.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:633)
at com.mysql.cj.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:347)
When I turn TRACE-level logging on, I see it is trying to connect to:
url=jdbc:mysql://localhost:3306/myapp?useSSL=false&nullNamePatternMatchesAll=true
So it does look like Docker is properly injecting the env file's vars into the Spring YAML-based config. So this doesn't feel like a config issue, moreover an isse with the container speaking to the MySQL port running on the Docker host.
Can anybody see where I'm going awry?
Accessing the host machine from within a container is not recommended. Usually it can be solved by wrapping service you need into a container and accessing it via container name.
There is no solution, there are only workarounds, you can use one of them:
On Mac you can access the host services using docker.for.mac.host.internal DNS name.
You need to set environment variable like this:
DB_HOST=docker.for.mac.host.internal
And refer to the DB_HOST from your connection string.
For more details see the documentation:
From 17.12 onwards our recommendation is to connect to the special
Mac-only DNS name docker.for.mac.host.internal, which resolves to the
internal IP address used by the host.
Note: Having --net="host" doesn't let you reach the host machine via localhost. localhost always points to local machine, but in case if it is invoked from within a container it points to the container itself.
So basically Docker app is not in the same network as the host you're running it from and that's why you can't access MySQL by pointing to localhost (because this is another network from Docker's point of view).
What you could try is to run docker with --net="host" option and then it will share the network with its host.
You can find better explanation on this issue in this topic From inside of a Docker container, how do I connect to the localhost of the machine?
Related
I'm attempting to run a Spring Boot app that connects a Postgres DB using:
docker-compose.yml (for Postgres) :
version: '3'
services:
postgres-db:
container_name: postgres-db
image: postgres:latest
restart: always
ports:
- "5432:5432"
environment:
POSTGRES_USER: my_user
POSTGRES_PASSWORD: my_password
POSTGRES_DB: shorten-db
To run the Postgres DB:
docker-compose up
.Dockerfile (for the Spring Boot app) :
FROM openjdk:12-jdk-alpine
RUN addgroup -S spring && adduser -S spring -G spring
USER spring:spring
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
In order to run the Spring app using Docker I use:
mvn package
docker build -t url-shorten/url-shorten-docker .
docker run -p 8080:8080 url-shorten/url-shorten-docker
But I receive the error when starting when running above docker command:
Caused by: org.postgresql.util.PSQLException: Connection to localhost:5432 refused. Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections.
In Spring application.properties I connect to the DB using:
spring.datasource.url=jdbc:postgresql://localhost:5432/shorten-db
I think this error is due to the Spring Boot app is running in a different container to DB so it cannot find the DB on localhost. Is there an idiomatic way of connecting the Spring Book docker container to the DB container. Or do I have do access the IP address of my machine and use this address to connect to the Postgres DB running on Docker?
Yes, you can't use localhost in this situation
spring.datasource.url=jdbc:postgresql://postgres-db:5432/shorten-db
In Spring application.properties, try to change DB config to:
spring.datasource.url=jdbc:postgresql://postgres-db:5432/shorten-db
In container networks, You need to use the container name as a host.
You can add both DB and app containers to one Docker network and change PostgreSQL host in datasource URL to postgres-db. Then Spring app will work with your DB.
I have Eureka from Spring Cloud started inside docker container. This is my Dockerfile for building and exposing Eureka:
FROM maven:3.5-jdk-8 AS build
COPY src /home/eureka/src
COPY pom.xml /home/eureka
RUN mvn -f /home/eureka/pom.xml clean package
FROM openjdk:8-jdk-alpine
COPY --from=build /home/eureka/target/service-registry-1.0-SNAPSHOT.jar /usr/app/service-registry-1.0-SNAPSHOT.jar
ENTRYPOINT ["java","-jar","/usr/app/service-registry-1.0-SNAPSHOT.jar"]
EXPOSE 8761
This is my docker compose file:
version: '2.1'
services:
eureka-service-registry-app:
build: eureka-service-registry-app
ports:
- "8761-8761"
There are more app will be in infrastructure, but right now they are commented.
I start docker-compose up, process looks ok, but when I want to check Eureka web dashboard by localhost:8761 this host is unavailable. Hm, ok. In list of my containers I see the follow:
0.0.0.0:32772->8761/tcp
and localhost:32772 is available and Eureka is alive. Moreover if I start docker-compose up again this port will be incremented and new port where Eureka will be available will be 32773. Thus I see there some schema but I don't understand how to make this port stable and regular as Eureka has been started with no Docker on 8761
You define a port range with
ports:
- "8761-8761"
Please change it to
ports:
- "8761:8761"
As others already pointed out: The port exposing in the docker-compose.yml should be changed to
-"8761:8761".
However I see more points to that.
The default port of Eureka is (as far as I know) 1111.
Are you exposing the correct port?
Furthermore be careful when using eureka in combination with docker.
They might register themselves with localhost or their internal IP-Address from the
Docker container, which might not be available from the other docker containers.
Consider having a look at the following application proporties (or environment variables):
eureka.instance.prefer-ip-address=false
eureka.instance.ip-address=$HOST_IP_ADDRESS
eureka.instance.hostname=localhost
I am using a docker-compose command to create and start my containers.
My Docker Version
docker --version
Docker version 17.09.0-ce, build afdb6d4
My Docker-Compose version
docker-compose --version
docker-compose version 1.16.1, build 6d1ac21
The .yml file that I'm using looks something like this:
(Note that I've just shortened it to take sensitive things out)
---
services:
zookeeper:
image: "zookeeper"
server-1:
cap_add:
- "NET_ADMIN"
server-0:
cap_add:
- "NET_ADMIN"
dns:
- 8.8.8.8
- 9.9.9.9
environment:
SERVER_ID: 0
NETEM_HOSTS: ""
LOSS_VALUES: ""
MAX_RATE_VALUES: ""
DELAY_VALUES: ""
image: "cloud.mycompany.com:5000/server-0:latest"
fakedns:
image: "cloud.mycompany.com:5000/fakedns:latest"
version: "3.3"
Then I start using:
docker-compose --file compose.yml up -d
My Question is this:
1) After containers come up... when I go into a container, for e.g. in this case server-0, I don't see the /etc/resolv.conf file updated to use these nameservers. Instead it uses the embedded dns of docker which is 127.0.0.11
2) How do I make sure that it uses what I specify in file that is used by docker-compose
3) I tried to do this with the command and it seems to work, but I need to do from compose-file
docker run -p 4000:53 --dns=8.8.8.8 cloud.mycompany.com:5000/server-0:latest
4) Ideally, I want it to have the IP address of the container 'fakedns' so that it uses this one instead of the embedded one #127.0.0.11
You won't see custom DNS servers in /etc/resolv.conf but Docker's resolver will forward DNS requests to them.
User Defined Networks and DNS
Docker compose definitions that are v2+ create a user defined network by default.
Docker with a user defined network uses an embedded DNS server so that Docker can respond for local container requests (service discovery).
For any DNS hosts Docker can not resolve, the request will be forwarded onto a DNS server. This is either the system default server, the server configured in dockerd or the DNS server configured for the container at run time.
Docker DNS
Be careful when using internal DNS servers. Things in the Docker daemon will break if you point the systems DNS at a container as you create a chicken or the egg problem, Docker needs DNS to start but can't start the container to provide DNS.
As your example config is only setting the DNS for one app container it should be ok, but make sure the DNS container is up and healthy before your application.
I have my spring boot application and mysql database running in separate docker containers. I am able to access server database from my host.
My application.properties for Spring boot application looks like below:
spring.datasource.url=jdbc:mysql://benefitsmysql:3308/benefitsmysql
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect
# ====================================================================================
# = SSL Configuration
# ====================================================================================
#security.basic.enabled=false
server.port=8443
server.ssl.key-store=keystore.jks
server.ssl.key-store-password=*******
server.ssl.keyStoreType=jks
server.ssl.keyAlias=tomcatselfsigned
I am building a docker container image by using maven plugin for docker. My Dockerfile looks like below:
FROM java:8
VOLUME /tmp
ADD Benefits.jar Benefits.jar
EXPOSE 8443
RUN bash -c 'touch /Benefits.jar'
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/Benefits.jar"]
I am starting docker container for spring boot application like below:
docker run -p 8443:8443 --name benefits --link benefitsmysql:mysql -d c794a4d0c634
and if I do docker ps -a, I get following output
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8070c575b6dd c794a4d0c634 "java -Djava.secur..." 2 minutes ago Up 2 minutes 0.0.0.0:8443->8443/tcp benefits
aa417df08b94 mysql:5.6 "docker-entrypoint..." 2 days ago Up 2 days 0.0.0.0:3308->3306/tcp benefitsmysql
f55a2a7ac487 hello-world "/hello" 2 days ago Exited (0) 2 days ago gifted_lalande
Now when I access my spring boot application running inside docker container from my windows machine like https://192.168.99.103:8443/home, I get connection refused error ERR_CONNECTION_REFUSED.
What am I missing in this configuration?
yogsma
I read your blog, and apply your solve, but docker-machine ip didn't solve my problem.
Then I realize docker containers can't communicate with 127.0.0.1 and I use their container ip
docker inspect <container_id>
then find IpAddress.
This ip address is solves my problem.I dont need to use docker-machine ip
I'm a little lost as to why my java application can't connect to my postgres database. I'm aiming to connect to a postgres database through jdbc. The application is to run inside a docker container.
this.connection = `DriverManager.getConnection("jdbc:postgresql://<myip>:5432/databasename", "usr", "password");`
I'm getting the exception:
Connection refused. Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections.
When I run the application from my desktop, it connects as expected. When I run it from within the docker container, it fails.
I've just installed docker this afternoon and ran through the getting started for windows, so my setup state is just after running that. Here's the contents of my Dockerfile:
FROM java:8
ADD VaultServer /
EXPOSE 3971
EXPOSE 3972
ENTRYPOINT ["java", "-jar", "VaultServer.jar"]
Inside the data folder there is a file called pg_hba.conf you have to configure it to accept the connections. So your pg_hba.conf file should have a line like this
host all all YourDockerip/24 md5.
After that configure the postgresql.conf file. You have to update the listen_addresses to all and make sure to uncomment that line by removing the # mark. So your listen_addresses should look like this listen_addresses = '*'.