How to: Docker container running java jar connecting to host mysql server? - java

I wrote a simple java program that should connect to the host machine running a MYSQL server and insert a record. The java progam is running inside a docker container with an ubuntu base image. At this point I have the jar working but can't connect to the host machine MYSQL server yet.
I've tried different mysql server installs and coppied from other dockerfiles in the hope to copy/past something together that works but it's getting messy and I don't know what parts are necessary anymore.
Java code:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
class ConnectionTest {
private Connection conn;
ConnectionTest() throws IOException, ClassNotFoundException {
try {
test();
} catch (SQLException e) {
logError(e);
}
}
private void logError(SQLException e) throws IOException {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
String sStackTrace = sw.toString();
File fout = new File("logs.txt");
FileOutputStream fos = new FileOutputStream(fout);
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(fos));
bw.write(sStackTrace);
bw.close();
}
private void test() throws SQLException, ClassNotFoundException { ;
String hostname = "localhost";
String dbName = "test";
String userName = "root";
String password = "";
Class.forName("com.mysql.cj.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://" + hostname + ":3306/" + dbName + "?useLegacyDatetimeCode=false&serverTimezone=Europe/Paris", userName, password);
PreparedStatement prep = conn.prepareStatement("INSERT INTO test(Login, Password) values('test', 'test')");
prep.execute();
}
}
Dockerfile:
RUN mkdir -p /root/java
COPY jdk-8u221-linux-x64.tar.gz /
RUN tar -zxf jdk-8u221-linux-x64.tar.gz -C /root/java
RUN apt-get update
RUN update-alternatives --install /usr/bin/java java /root/java/jdk1.8.0_221/bin/java 100
ENV JAVA_HOME /root/java/jdk1.8.0_221/bin
RUN export JAVA_HOME
RUN apt-get update \
&& DEBIAN_FRONTEND=noninteractive apt-get install -y mysql-server \
&& sed -i "s/127.0.0.1/0.0.0.0/g" /etc/mysql/mysql.conf.d/mysqld.cnf \
&& mkdir /var/run/mysqld \
&& chown -R mysql:mysql /var/run/mysqld
VOLUME ["/var/lib/mysql"]
CMD ["mysqld_safe"]
EXPOSE 3306
COPY lib /root/test/lib
COPY entrypoint.sh /
ENTRYPOINT ["/entrypoint.sh"]
Entrypoint.sh:
chmod -R 777 /root/test
cd /root/test
java -cp "lib/*" -jar lib/DockerTest.jar
tail -f /dev/null
/root/test/lib contains both the mysql-connector-java.jar and the DockerTest.jar. If I run mysqld before the jar the server starts but the jar won't launch.
MYSQL status when the server is running:
$ winpty docker exec -it mysql_container service mysql status
* /usr/bin/mysqladmin Ver 8.42 Distrib 5.7.27, for Linux on x86_64
Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Server version 5.7.27-0ubuntu0.16.04.1
Protocol version 10
Connection Localhost via UNIX socket
UNIX socket /var/run/mysqld/mysqld.sock
Uptime: 3 sec
Threads: 1 Questions: 4 Slow queries: 0 Opens: 105 Flush tables: 1 Open tables: 98 Queries per second avg: 1.333
Error when running just the jar:
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:174)
at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:64)
at com.mysql.cj.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:832)
at com.mysql.cj.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:456)
at com.mysql.cj.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:240)
at com.mysql.cj.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:207)
at java.sql.DriverManager.getConnection(DriverManager.java:664)
at java.sql.DriverManager.getConnection(DriverManager.java:247)
at ConnectionTest.test(ConnectionTest.java:42)
at ConnectionTest.<init>(ConnectionTest.java:13)
at Main.main(Main.java:5)
Caused by: com.mysql.cj.exceptions.CJCommunicationsException: Communications link failure

If you are using Spring Framework you can set the spring.datasource.url in application.properties to use host.docker.internal:3306 if the MySQL is running on your local / host machine.
spring.datasource.url=jdbc:mysql://host.docker.internal:3306/<yourdatabase>

Related

Unable to connect to mysql using jdbc in docker

I have the following docker-compose:
version: '3.1'
services:
db:
container_name: db
image: mysql
environment:
- MYSQL_ROOT_PASSWORD=password
- MYSQL_DATABASE=world
volumes:
- ./mysql-db/:/docker-entrypoint-initdb.d
networks:
- my-network
app:
depends_on:
- db
container_name: app
build: App/
networks:
- my-network
networks:
my-network:
driver: bridge
This builds the mysql image and uses a local file to create the database. I am able to connect to the database through a database client on my host machine. I know the db is running and working with those credentials on port 3306.
App/Dockerfile:
# Build stage
FROM maven:latest AS build
COPY src /app/src
COPY pom.xml /app
# need to assemble to package in plugins
RUN mvn -f /app/pom.xml clean compile assembly:single
# Package stage
FROM openjdk:latest
COPY --from=build /app/target/seMethods-1.0-jar-with-dependencies.jar /usr/local/lib/build.jar
ENTRYPOINT ["java", "-jar", "/usr/local/lib/build.jar"]
This builds the jar file using maven.
App/src/App.java
// sql imports
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
public class App
{
public static void main( String[] args )
{
try {
String dbUrl = "jdbc:mysql://db:3306/world";
Connection con = DriverManager.getConnection(dbUrl,"root","password");
String testStatement = "SELECT * FROM city;";
PreparedStatement preparedTest = con.prepareStatement(testStatement);
ResultSet rs = preparedTest.executeQuery();
while(rs.next()){
System.out.println(rs.getRow());
}
} catch (Exception e) {
// handle any errors
System.out.println(String.format("Error: %s", e));
}
}
}
When my docker-compose runs, the containers are created although my app stops with the following:
Error: 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.
How can I connect my db container to app?
You are trying to access a ressource outside your app docker container without having set ports on it. By default as you likely know docker container are insulated from the system, thus you can not access port 3306 from inside the container while you can from your host machine. Add the ports to the docker compose file.
Solved.
When creating the db image, the init file used to generate the inital database took a few seconds to complete. Adding a Thread.sleep() hotfix to the start of my java app allowed the database tables to be created and then I am able to connect.

Error while connecting to windows drive from linux machine [via java program]

I am trying to connect to windows network drive using Jcifs = 1.3.17 in java
code
String baseAddress = "smb://file-123/XYZ_Others/"
String DOMAIN = "XYZ"
smbFile = new SmbFile(baseAddress, new NtlmPasswordAuthentication(DOMAIN, userName, password))
//How i am using smbFile
final boolean isDirectory = smbFile.isDirectory(); //getting error here
If i run the code from mac it is working fine [it can able to connect] however if i try to run from linux [amazon cloud] i am getting following error
cifs.smb.SmbException: Failed to connect to server
at jcifs.smb.SmbFile.connect0(SmbFile.java:882) ~[jcifs-1.3.17.jar:?]
at jcifs.smb.SmbFile.queryPath(SmbFile.java:1335) ~[jcifs-1.3.17.jar:?]
at jcifs.smb.SmbFile.exists(SmbFile.java:1417) ~[jcifs-1.3.17.jar:?]
at jcifs.smb.SmbFile.isDirectory(SmbFile.java:1490) ~[jcifs-1.3.17.jar:?]
When i try to use smb client from command prompt
smbclient -L smb://test/ -U username -W ANT -R host -D DIR
Getting error as
Connection to smb: failed (Error NT_STATUS_BAD_NETWORK_NAME)

Migrate from MySQL to Postgresql

I Installed Postgresql-9.5 and PgAdmin III in my CentOS 6.6, i use these commands,
1) service postgresql-9.5 status
2) service postgresql-9.5 start
3) su postgres
4) psql
5) password
6) mysqldump --compatible=postgresql --default-character-set=utf8 -r databasename.mysql -u root -p databasename
7) mysqldump -u root -p --compatible=postgres databasename < /home/databasename.mysql
UNLOCK TABLES;
/*!40103 SET TIME_ZONE=#OLD_TIME_ZONE */;
/*!40101 SET SQL_MODE=#OLD_SQL_MODE /;
/!40014 SET FOREIGN_KEY_CHECKS=#OLD_FOREIGN_KEY_CHECKS /;
/!40014 SET UNIQUE_CHECKS=#OLD_UNIQUE_CHECKS /;
/!40111 SET SQL_NOTES=#OLD_SQL_NOTES */;
-- Dump completed on 2017-08-28 11:42:14
Once it completed i open my PgAdmin III and check there is nothing... No data present inside my Database. What mistake I done.
mysqldump can't be used for executing SQL commands from file - you need to use something like psql: psql -h hostname -d databasename -U username -f file.sql.
You need to create database before using this command (so remove create database from file).
UNLOCK TABLES; That will throw error in PostgreSQL, you need to remove that line.
An insanely easy approach will be to use NMIG an amazing script with near 0 config needed.
Clone the repo
npm i, npm run build
Set your MySQL and Postgres servers connections in the ./config/config.json
npm start
Enjoy your migrated db

Cannot connect from MySQL Workbench to dockerized MySQL server

I'm trying to connect from the MySQL Workbench to my dockerized mysql server. I'm using Windows 10. Here is my Dockerfile:
FROM ubuntu:latest
# package updates & install mysql
RUN apt-get update && apt-get install -y mysql-server
RUN apt-get -y install supervisor
ADD supervisord.conf /etc/supervisor/conf.d/supervisord.conf
# bind sql script
ADD musicdb.sql /tmp/musicdb.sql
RUN sed -i -e"s/^bind-address\s*=\s*127.0.0.1/bind-address = 0.0.0.0/" /etc/mysql/my.cnf
EXPOSE 3306
RUN /bin/bash -c "/usr/bin/mysqld_safe &" && \
sleep 5 && \
mysql -u root -e "CREATE DATABASE musicdb" && \
mysql -u root musicdb < /tmp/musicdb.sql
CMD ["/usr/bin/supervisord", "-n"]
I'm using this library to create, run, etc. the container from Java:
https://github.com/spotify/docker-client
My actual method to do this in Java is:
public static void createContainerWithPorts(){
DockerClient docker;
try {
docker = DefaultDockerClient.fromEnv().build();
//PortBindings
Map<String, List<PortBinding>> portBindings = new HashMap<>();
List<PortBinding> hostPorts = new ArrayList<>();
hostPorts.add(PortBinding.of("0.0.0.0", "3306"));
portBindings.put("3306", hostPorts);
HostConfig hostConfig = HostConfig.builder().portBindings(portBindings).build();
ContainerConfig containerConfig = ContainerConfig.builder().hostConfig(hostConfig).image("mysql-container").exposedPorts("3306").build();
//create container
ContainerCreation contaierCreation = docker.createContainer(containerConfig);
String id = contaierCreation.id();
//start container
docker.startContainer(id);
ContainerInfo containerInfo = docker.inspectContainer(id);
System.out.println(containerInfo.toString());
Scanner scanner = new Scanner(System.in);
scanner.next();
docker.killContainer(id);
docker.removeContainer(id);
docker.close();
} catch (DockerCertificateException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (DockerException e) {
e.printStackTrace();
}
}
Java builds the Container fine from the before created Docker Image. When I'm looking on actual running Docker Container it looks that the port binding works. When I access my container with docker exec -it SQLContainer bash it works fine and I can access my SQL server.
When i try to connect with MySQL Workbench, I got the error message shown in the picture below:
MySQL Workbench Error Message
Does someone know what I'm doing wrong?
Thanks,
I think you need to create a new user for your mysql server and specify from where the user can be used. This is because root access is only available through localhost I believe.
So to create a new user, you need to add a little something to the RUN command where you start your server:
RUN /bin/bash -c "/usr/bin/mysqld_safe &" && \
sleep 5 && \
mysql -u root -e "CREATE DATABASE musicdb" && \
mysql -u root musicdb < /tmp/musicdb.sql && \
mysql -u root -e "CREATE USER 'newUser'#'%' IDENTIFIED BY 'somePassword'" && \
mysql -u root -e "GRANT ALL PRIVILEGES ON *.* TO 'newUser'#'%' WITH GRANT OPTION"
That way you create a new user with the name newUser that can access from anywhere.

Fail to connect to mysql database using Java

I got an exception connecting to MySQL through Java. I downloaded the MySQL Java connector and added it to the classpath. I'm trying to connect to a MySQL table without success.
I have also tried to telnet localhost 3306 but got the following error: "nodename nor servname provided, or not known"
The code is as follows:
//import java.sql.Connection;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
public class ConnectToDatabase {
public static void main(String[] args) throws Exception{
//Accessing driver from the JAR file
Class.forName ("com.mysql.jdbc.Driver").newInstance ();
Connection con = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/cldatabase", "root", "root");
//Here we create our query
PreparedStatement statement = con.prepareStatement(
"SELECT * FROM profiles");
ResultSet result = statement.executeQuery();
while(result.next()){
System.out.println(result.getString("firstName") + " " +
result.getString("lastName"));
}
}
And this exception was thrown:
Exception in thread "main" com.mysql.jdbc.exceptions.jdbc4.
CommunicationsException: Communications link failure
The last packet sent successfully to the server was 0 milliseconds ago.
I have xampp installed on my mac.
this is what comes up when I run "ps -ef | grep mysql"
0 1694 1 0 0:00.02 ?? 0:00.03 /bin/sh /Applications/XAMPP/xamppfiles/bin/mysqld_safe --datadir=/Applications/XAMPP/xamppfiles/var/mysql --pid-file=/Applications/XAMPP/xamppfiles/var/mysql/T-s-sMacBook-Air.local.pid
-2 1792 1694 0 0:00.07 ?? 0:00.28 /Applications/XAMPP/xamppfiles/sbin/mysqld --basedir=/Applications/XAMPP/xamppfiles --datadir=/Applications/XAMPP/xamppfiles/var/mysql --user=nobody --log-error=/Applications/XAMPP/xamppfiles/var/mysql/k-Air.local.err --pid-file=/Applications/XAMPP/xamppfiles/var/mysql/-MacBook-Air.local.pid --socket=/Applications/XAMPP/xamppfiles/var/mysql/mysql.sock --port=3306
501 1814 1484 0 0:00.00 ttys000 0:00.00 grep mysql
Do any of the answers to this similar question on ServerFault help?
1) Verify the address mysql is bound
to, it's probably 127.0.0.1 (only)
which I believe is the default (at
least on standard Ubuntu server).
You'll have to comment out the
bind-address parameter in my.cnf to
bind to all available addresses (you
can't choose multiple, it's one or
all).
2) If it is bound to 127.0.0.1 and you
can't connect using "localhost", make
sure it's not resolving to the IPv6
localhost address instead of IPv4. (or
just use the IP address)
3) Double and triple-check the port
that mysql is listening on.
4) Make sure you're using the right
JDBC connector for your JDK.
5) Make sure you're not doing
something really silly like starting
mysql with --skip-networking.
What do you get when you run "lsof -i :3306" ?
if you are facing problem on Class.forName("com.mysql.jdbc.Driver"); then copy mysql connector on following location..definately it will work..C:\Program Files\Apache Software Foundation\Tomcat 7.0\webapps\lib\WEB-INF..note that in webapps folder there is no directory called lib then manually create lib and WEB-INF directory and paste mysql connector in that.no need any classpath settings.....
if still you face problem then send your query...

Categories

Resources