I have to create an app that runs in python (streamlit), communicate with a neo4j database and allows the user to change and backup the neo4j database interactively. Then I have to deploy this app with docker. My idea was to use docker compose and have one container with the neo4j database and one with the streamlit app and dockerize the whole thing.
Now the problem is that neo4j community edition forces you to shut down the neo4j instance to perform any backup/database loading. The backup is usually done like this:
docker stop dockerid
docker run --interactive --tty --rm --volume=local_path_to/data:/data --volume=/local_path_to/backup_databases:/backups neo4j/neo4j-admin:latest neo4j-admin dump --database=neo4j --to=/backups/backup_test.dump
docker start dockerid
Furthermore the docker container from the official neo4j app dies if you try to shut down the neo4j process running in the container. This is a problem because I need a way of keeping the neo4j docker container alive but to kill the neo4j so that from INSIDE the container i can then launch in some way:
neo4j stop
neo4j-admin dump --database=neo4j --to=/backups/backup_test.dump
neo4j start
To this end I tried to build a custom neo4j image with a different entrypoint, so that it doesn't die when i kill the neo4j process. I did it with this Dockerfile:
FROM neo4j:latest
#Ports that will be exposed
EXPOSE 7473 7474 7687
#environment variables
ENV NEO4J_dbms_security_procedures_unrestricted=algo.*,apoc.*,gds.*
ENV NEO4J_AUTH=neo4j/password
COPY ./docker_entrypoint.sh /usr/local/bin/
RUN chown root:root /usr/local/bin/docker_entrypoint.sh && \
chmod 777 /usr/local/bin/docker_entrypoint.sh
ENTRYPOINT [ "/usr/local/bin/docker_entrypoint.sh" ]
CMD ["neo4j"]
and where docker_entrypoint.sh is:
#!/bin/sh
/var/lib/neo4j/bin/neo4j console &
echo "still working"
tail -f /dev/null
Now, the image builds correctly, and if you docker exec in neo4j is running properly and can be stopped and rerun, but now for whatever reason I cannot seem to connect to the container as I do normally either via browser at http://localhost:7474/browser/ or via neo4j python driver. If i try to connect the python driver outputs:
Couldn't connect to localhost:7687 (resolved to ('127.0.0.1:7687',)):
Connection to 127.0.0.1:7687 closed without handshake response
What am I doing wrong?
EDIT: I create the docker container with the following command:
docker run \
-p7474:7474 -p7687:7687 \
-d \
-v $HOME/neo4j/data/local_data:/data \
-v $HOME/neo4j/logs:/logs \
-v $HOME/neo4j/import:/var/lib/neo4j/import \
-v $HOME/neo4j/plugins:/plugins \
--env NEO4J_dbms_connector_https_advertised__address="localhost:7473" \
--env NEO4J_dbms_connector_http_advertised__address="localhost:7474" \
--env NEO4J_dbms_connector_bolt_advertised__address="localhost:7687" \
--env NEO4J_dbms_security_procedures_unrestricted=algo.*,apoc.*,gds.* \
--env NEO4J_AUTH=neo4j/$PASSWORD \
my_neo4j_docker_image_id
This same command works fine if I use neo4j:latest instead of my_neo4j_docker_image_id.
I finally got it to work. This is not a beautiful workaround by any mean.. but it runs :P . You gotta build a docker image from neo4j official image, in which you wrap the entry point script in another script. The original docker_entrypoint.sh is available here https://github.com/neo4j/docker-neo4j/blob/master/docker-image-src/3.5/docker-entrypoint.sh . Save that as docker_entrypoint_original.sh.
Then write a wrapper script as the new entry point called wrapper.sh :
#!/bin/sh
/usr/local/bin/docker_entrypoint_original.sh neo4j &
echo "I won't be killed along with neo4j process mwahahaha"
tail -f /dev/null #This is the bit that keeps it alive if you kill neo4j
Then you compose your image using the following Dockerfile:
FROM neo4j:latest
#Ports that will be exposed
EXPOSE 7473 7474 7687
#environment variables if you need them
ENV NEO4J_dbms_security_procedures_unrestricted=algo.*,apoc.*,gds.*
ENV NEO4J_AUTH=neo4j/your_password
COPY ./wrapper.sh /usr/local/bin/
COPY ./docker_entrypoint_original.sh /usr/local/bin/
RUN chown root:root /usr/local/bin/wrapper.sh && \
chmod 777 /usr/local/bin/wrapper.sh
RUN chown root:root /usr/local/bin/docker_entrypoint_original.sh && \
chmod 777 /usr/local/bin/docker_entrypoint_original.sh
ENTRYPOINT [ "/usr/local/bin/wrapper.sh"]
And finally you docker run it with:
docker run \
-p7474:7474 -p7687:7687 \
-d \
-v $HOME/neo4j/data/local_data:/data \
-v $HOME/neo4j/logs:/logs \
-v $HOME/neo4j/import:/var/lib/neo4j/import \
-v $HOME/neo4j/plugins:/plugins \
--env NEO4J_dbms_connector_https_advertised__address="localhost:7473" \
--env NEO4J_dbms_connector_http_advertised__address="localhost:7474" \
--env NEO4J_dbms_connector_bolt_advertised__address="localhost:7687" \
--env NEO4J_dbms_security_procedures_unrestricted=algo.*,apoc.*,gds.* \
--env NEO4J_AUTH=neo4j/your_password \
my_neo4j_docker_image_id