i'm a newbie to Kubernetes. This is my situation:
I found a open-source project on Github, it is a online bookstore: https://github.com/devdcores/BookStoreApp-Distributed-Application (anyway, thankss to author of this repo). This project is written in microservice-architecture, it had a docker-compose to build and run container instantly. I've try and it worked.
But when i try to build and run this project in Kubernetes and Helm, problem raise:
Some service cannot connect to mysqldb: Access denied for user 'bookstoreDBA'#'172.17.0.1' (using password: YES). So i look into source code and found this:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://bookstore-mysql-db:3306/bookstore_db?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
username: bookstoreDBA
password: PaSSworD
My question is: Is the url set up properly? Is it the reason cause problem? If it is (not), then how to fix this problem?
P/S: These are environment variables and service.yaml for mysql container:
env:
MYSQL_DATABASE: bookstore_db
MYSQL_PASSWORD: PaSSworD
MYSQL_ROOT_PASSWORD: r00tPaSSworD
MYSQL_USER: bookstoreDBA
# service.yaml
apiVersion: v1
kind: Service
metadata:
annotations:
kompose.cmd: kompose convert
kompose.version: 1.22.0 (955b78124)
creationTimestamp: null
labels:
io.kompose.service: bookstore-mysql-db
name: bookstore-mysql-db
spec:
ports:
- name: "3306"
port: 3306
targetPort: 3306
selector:
io.kompose.service: bookstore-mysql-db
status:
loadBalancer: {}
I use mysql client to create bookstoreDBA user and grant needed privileges. Then restart the cluster. Now every things work properly.
Related
I am trying to connect the container of my springboot application with the container of a mysql image using docker-compose, however when I run docker-compose up my terminal starts a loop where it starts the spring application, try to connect with the MySQL container, fails and keep trying. The error that I get is com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failures
docker-compose file:
version: '3.8'
services:
mysqldb:
image: mysql
platform: linux/x86_64
env_file: ./.env
restart: always
environment:
- MYSQL_ROOT_PASSWORD=$MYSQLDB_ROOT_PASSWORD
- MYSQL_DATABASE=$MYSQLDB_DATABASE
ports:
- $MYSQLDB_LOCAL_PORT:$MYSQLDB_DOCKER_PORT
volumes:
- db:/var/lib/mysql
app:
depends_on:
- mysqldb
build: .
restart: always
env_file: ./.env
ports:
- $APP_LOCAL_PORT:$APP_DOCKER_PORT
environment:
- DB_HOST=mysqldb
- DB_USER=$MYSQLDB_USER
- DB_PASSWORD=$MYSQLDB_ROOT_PASSWORD
- DB_NAME=$MYSQLDB_DATABASE
- DB_PORT=$MYSQLDB_DOCKER_PORT
stdin_open: true
tty: true
volumes:
db:
.env:
MYSQLDB_USER=root
MYSQLDB_ROOT_PASSWORD=12345678
MYSQLDB_DATABASE=dronefeederdb
MYSQLDB_LOCAL_PORT=3306
MYSQLDB_DOCKER_PORT=3306
APP_LOCAL_PORT=8080
APP_DOCKER_PORT=8080
Application.yaml:
server:
port: 8080
spring:
datasource:
username: ${DB_USER}
password: ${DB_PASSWORD}
url: jdbc:mysql://${DB_HOST}:${DB_PORT}/${DB_NAME}
jpa:
hibernate:
ddl-auto: update
show-sql: true
open-in-view: false
#https://ia-tec-development.medium.com/lombok-e-spring-data-jpa-142398897733
security.user:
name: dronefeeder
password: dronefeeder
#https://www.baeldung.com/spring-boot-security-autoconfiguration
resilience4j.circuitbreaker:
configs:
default:
waitDurationInOpenState: 10s
failureRateThreshold: 10
#instances:
#estudantes:
#baseConfig: default
Dockerfile:
FROM openjdk:11.0-jdk as build-image
WORKDIR /app
COPY . .
RUN ./mvnw clean package -DskipTests
FROM openjdk:11.0-jre
COPY --from=build-image /app/target/*.jar /app/app.jar
EXPOSE 8080
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom", "-jar", "/app/app.jar"]
Repository link:
https://github.com/julia-baptista/dronefeeder/tree/docker-configuration
I believe the issue is your application's use of localhost for the SQL URL in the Application.yaml property file. Since your app runs on a container by itself it tries to look at localhost of the container, while your SQL server is in another container, with its own localhost. Localhost in docker container do not refer to the host, they refer to the localhost within the container itself. If you want to access the host machine, this is an excellent answer From inside of a Docker container, how do I connect to the localhost of the machine?
url: jdbc:mysql://localhost:3306/dronefeederdb
localhost should not be used, you need to use the sql continainer url.
The fastest option is to use host.docker.internal instead of localhost. But it's not the best.
Another quick option is to run the two containers on the same docker network. Define that in your compose file the same way as the volumes. Then set each container to that network. See Networking in Compose. Then you can set your SQL url to use the SQL container name instead of localhost. So this..
url: jdbc:mysql://localhost:3306/dronefeederdb becomes url: jdbc:mysql://mysql/dronefeederdb
Neither option is robust, since you're hardcoding the container name in the application property file. A better solution is to have an environment variable in your webApp image that can accept the URL to the SQL server. Then you can provide the SQL location when running the container, or in your compose file (Environment variables in Compose). This way the SQL server can be anywhere.
Update:
There were a couple of issues in the compose and env files that caused mySQL container to fail startup. Thus the webApp was not able to connect.
Credentials
MYSQL_USER was set to root. mySql already creates the user root. You cannot create it again. I changed that to foo. See the Environment Variables section in the official docker image readme for more.
MYSQL_PASSWORD was not set. This is the password for the user your app will use. I set this to pass!123
The apps DB_PASSWORD was set to user root. That would have been ok if sql had started and it was using the root user I guess. But I changed that to the non-root user since were setting DB_USER=foo
Network was not defined
The two containers need to be on the same "docker network" if they are to run together in docker in the same machine. There's more to this which is beyond my experience. But in this case it needs to be on the same network for app to access mysqldb by its container name. I created dronefeederNet and added each container to it.
Files:
.env
MYSQLDB_USER=foo
MYSQLDB_PASSWORD=pass!123
MYSQLDB_ROOT_PASSWORD=12345678
MYSQLDB_DATABASE=dronefeederdb
MYSQLDB_LOCAL_PORT=3307
MYSQLDB_DOCKER_PORT=3306
APP_LOCAL_PORT=8081
APP_DOCKER_PORT=8080
docker-compose.yml
version: '3.8'
services:
mysqldb:
image: mysql
platform: linux/x86_64
env_file: ./.env
restart: always
environment:
- MYSQL_USER=$MYSQLDB_USER
- MYSQL_PASSWORD=$MYSQLDB_PASSWORD
- MYSQL_ROOT_PASSWORD=$MYSQLDB_ROOT_PASSWORD
- MYSQL_DATABASE=$MYSQLDB_DATABASE
ports:
- $MYSQLDB_LOCAL_PORT:$MYSQLDB_DOCKER_PORT
volumes:
- db:/var/lib/mysql
networks:
- dronefeederNet
app:
depends_on:
- mysqldb
build: .
restart: always
env_file: ./.env
ports:
- $APP_LOCAL_PORT:$APP_DOCKER_PORT
environment:
- DB_HOST=mysqldb
- DB_USER=$MYSQLDB_USER
- DB_PASSWORD=$MYSQLDB_PASSWORD
- DB_NAME=$MYSQLDB_DATABASE
- DB_PORT=$MYSQLDB_DOCKER_PORT
stdin_open: true
tty: true
networks:
- dronefeederNet
volumes:
db:
networks:
dronefeederNet:
Give this a try and I hope it runs. I was able to start it up ok.
You need to add in the app definition block a depends on: sentence, to make docker compose to not boot the application until the database is up.
Check this documentation: Docker Compose Startup Order
This is a Java Spring boot REST API application, using an index.html to present the UI web page to user.
When the index.html is displayed, it would trigger the logic from the Javascript/jQuery to make a REST api call(coded as below) to the backend service in the Java controller class to get 2 random generated numbers:
$.ajax({
url: "http://localhost:8080/multiplications/random"
The program is working fine when run it as a Spring Boot app in Eclipse!
However, it's not working after I used the .jar file to build a Docker image file then deployed it using Kubernetes/minikube(I'm new to Docker/Kubernetes).
here's the dockfile to build the image file using the .jar:
FROM openjdk:latest
ADD target/social-multiplication-v3-0.3.0-SNAPSHOT.jar app.jar
ENTRYPOINT ["java","-jar","app.jar"]
EXPOSE 8080
Here's the deployment.yaml file:
---
kind: Service
apiVersion: v1
metadata:
name: multiplicationservice
spec:
selector:
app: multiplication
ports:
- protocol: "TCP"
port: 80
targetPort: 8080
nodePort: 30001
type: LoadBalancer
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: mdeploy
spec:
replicas: 1
selector:
matchLabels:
app: multiplication
template:
metadata:
labels:
app: multiplication
spec:
containers:
- name: multiplication
image: huxianjun/multiplication
ports:
- containerPort: 80
and the IP address of the host where the application being deployed in Kubernetes:
$ minikube ip
192.168.99.101
At the end, I can get to the index.html page from browser by folllowing URL:
http://192.168.99.101:30001/
The page is being displayed as expected - What NOT working is, the following REST api call didn't occur thus the 2 numbers not returned from the call and displayed on the page:
$.ajax({
url: "http://localhost:8080/multiplications/random"
My guess is, is it caused by the 'localhost' & the port'8080' not aligned with those port# defined in the deployment.yaml file? or even something conflict to the 'EXPOSE 8080' in the docfile?
In your case, you are calling the $.ajax command from your browser which is in your host machine, hence, those API calls will be sent from your local machine but not within your docker container.
To solve the problem, you can update the URL to be using http://192.168.99.101:30001/ like this
$.ajax({
url: "http://192.168.99.101:30001/multiplications/random"
Try run sudo lsof -i :8080, if you use linux. It'll show all your available ports. If you don't see 8080 port, your application's port aren't available and visible for your localhost. That's because Docker containers are "closed/isolated" for all external processes and files. Moreover, EXPOSE 8080 instruction in Dockerfile is not enough.
Try docker run -p 8080:8080 YOUR_CREATED_IMAGE_NAME. It will build redirection from docker container localhost:8080 to Your localhost:8080
I'm developping an application using spring-boot and Docker. For security reasons I want to not use any more application.properties and use only environnement variable.
If you have best practices I will be grateful.
This is a snipet of my docker-compose.yml
version: "2.1"
services:
app_users:
image: images/app_users
container_name: app_user_ctn
build:
context: ../..
dockerfile: docker/dev/Dockerfile
ports:
- "30333:8080"
external_links:
- mysql
environment:
SPRING_DATASOURCE_URL: jdbc:mysql://mysql/myDB?autoReconnect=true
SPRING_DATASOURCE_USERNAME: mysqluser1
SPRING_DATASOURCE_PASSWORD: mysqlpwsword
SPRING_DATASOURCE_DRIVER_CLASS_NAME: com.mysql.jdbc.Driver
LDAP_PASSWORD: ldapPswd
LDAP_URLS: ldap://myServer:389
LDAP_USERNAME: cn=admin,dc=com,dc=expl
When I make a request to ldap I get NulPointerException because ldap environnement variables are not initialize.
When I use application.yml it works.
...
spring:
ldap:
password: ldapPswd
urls: ldap://myServer:389
username: cn=admin,dc=com,dc=expl
....
Would you have any ideas ?
Best regards
I'm traying to deploy a microserivice and a flyway service with Docker Compose in Ubuntu. The docker-compose.yml looks like this:
version: '2'
services:
mysqldb:
image: mysql:5.6.26
environment:
MYSQL_USER: user
MYSQL_PASSWORD: password
MYSQL_ROOT_PASSWORD: password
MYSQL_DATABASE: base
ports:
- "3306:3306"
flyway-service-i:
image: mialk/flyway-service
volumes:
- "../resources/db/migration:/migrations/ro"
depends_on:
- mysqldb
links:
- mysqldb
command: migrate -url=jdbc:mysql://mysqldb:3306/base -user=user -password=password -baselineOnMigrate=true - locations='filesystem:/migrations'
service1:
image: my/service
ports:
- "8080:8080"
links:
- mysqldb
environment:
- SPRING_DATASOURCE_URL=jdbc:mysql://mysqldb:3306/base
- SPRING_DATASOURCE_USERNAME=user
- SPRING_DATASOURCE_PASSWORD=password
But when I run the command: sudo docker-compose up, I have this message:
flyway-service-i_1 | ERROR: Unable to obtain Jdbc connection from DataSource (jdbc:mysql://mysqldb:3306/base) for user 'user': Host '172.18.0.4' is not allowed to connect to this MySQL server
Each time that I run the command, I get a different host, e.g:
ERROR: Unable to obtain Jdbc connection from DataSource (jdbc:mysql://mysqldb:3306/base) for user 'user': Host '172.18.0.6' is not allowed to connect to this MySQL server
The data base was created in that way:
CREATE DATABASE base CHARACTER SET utf8 COLLATE utf8_bin;
GRANT ALL PRIVILEGES ON base.* To 'user'#'localhost';
The ifconfig command shows that Docker has the IP 172.17.0.1.
I don't know why flyway can't connect to the data base, and why the host changes en each call,can you help me please?
Thanks! :)
Issue
In this line
GRANT ALL PRIVILEGES ON base.* To 'user'#'localhost';
you grant priviledges to user on localhost but your service1 and flyaway-service-1 services are running in their own separate containers and therefore are not running on localhost (with respect to the mysqldb container). If these services were running inside the mysqldb container then maybe they could be running on localhost.
Possible Resolution?
You may want to try using the hostname of the services/containers you're granting access to instead of localhost?
ie :
GRANT ALL PRIVILEGES ON base.* To 'user'#'service1';
Docker Networks instead of Container Links
Also, I would suggest using Docker's new networking feature instead of the legacy container linking method. See rationale behind docker compose "links" order
I have 3 projects: A hystrix dashboard, a turbine server (using AMQP) and an API
When I start in development env, I set up 2 instances of the API (using port 8080 and 8081). To test the turbine aggregation, I make calls and in the dashboard, I can see Hosts: 2.
Although when I use Docker, even when the load balancer hits the 2 server, I only see one Host on the hystrix dashboard.
My assumptions:
1- as both containers start on the same port (8080), Turbine sees them as one
2- as I also dockerize RabbitMQ, this may be causing problems
here is my docker-compose.yml file
version: '2'
services:
postgres:
image: postgres:9.5
ports:
- "5432"
environment:
POSTGRES_PASSWORD: postgres
POSTGRES_USER: postgres
POSTGRES_DB: fq
volumes:
- /var/lib/postgresql
rabbitmq:
image: rabbitmq:3-management
ports:
- "5672"
- "15672"
environment:
RABBITMQ_DEFAULT_USER: turbine
RABBITMQ_DEFAULT_PASS: turbine
volumes:
- /var/lib/rabbitmq/
hystrix:
build: hystrixdashboard/.
links:
- turbine_server
ports:
- "8989:8989"
turbine_server:
build: turbine/.
links:
- rabbitmq
ports:
- "8090:8090"
persona_api:
build: persona/.
ports:
- "8080"
links:
- postgres
- rabbitmq
lb:
image: 'dockercloud/haproxy:1.5.1'
links:
- persona_api
volumes:
- /var/run/docker.sock:/var/run/docker.sock
ports:
- 80:80
my persona_api config file
spring:
application:
name: persona_api
profiles:
active: dev
rabbitmq:
addresses: 127.0.0.1:5672
username: turbine
password: turbine
useSSL: false
server:
compression.enabled: true
port: ${PORT:8080}
params:
datasource:
driverClassName: org.postgresql.Driver
username: postgres
password: postgres
maximumPoolSize: 10
poolName: fq_connection_pool
spring.jpa:
show-sql: true
hibernate:
ddl-auto: update
turbine:
aggregator:
clusterConfig: persona_api
appConfig: persona_api
---
spring:
profiles: dev
params:
datasource:
jdbcUrl: jdbc:postgresql://127.0.0.1:5432/fq
---
spring:
profiles: docker
rabbitmq:
addresses: rabbitmq:5672
params:
datasource:
jdbcUrl: jdbc:postgresql://postgres:5432/fq
I'm afraid that if I deploy it to production (on Rancher or Docker cloud), I'll see the same problem.
here is a GIF of what is happening when I set up two APIs load balanced
try:
hystrix.stream.queue.send-id=false
in your API
I do assume your problem is the RabbitMQ connection you are using. Cause the connection string you are using is localhost but actually except the RabbitMQ container on none the connection will be available on localhost. I do suggest that you inject the Rabbit host into your Spring connection using environment variables. If I read your files correct it should be ${RABBITMQ_PORT_5672_TCP_ADDR} instead of localhost. But be aware that I couldn't try. Its just an educated guess. Better you double check by doing an env inside your persona_api container when everything is running.
It's should be fixed your issue.
eureka:
instance:
prefer-ip-address: true
instance-id: ${spring.cloud.client.ipAddress}:${server.port} #make the application unique on the rancher service layer
spring:
application:
index: ${random.uuid} #make the application unique on the rancher containe layer,same service but with multi-instances.
https://github.com/spring-cloud/spring-cloud-netflix/issues/740
Need instance-id:${spring.cloud.client.ipAddress}:${server.port} and index: ${random.uuid} both