Connection refused when running mongo DB command in docker - mongodb

I'm new to docker and mongoDB, so I expect I'm missing some steps. Here's what I have in my Dockerfile so far:
FROM python:2.7
RUN apt-get update \
&& apt-get install -y mongodb \
&& rm -rf /var/lib/apt/lists/*
RUN mkdir -p /data/db
RUN service mongodb start
RUN mongod --fork --logpath /var/log/mongodb.log
RUN mongo db --eval 'db.createUser({user:"dbuser",pwd:"dbpass",roles:["readWrite","dbAdmin"]})'
The connection fails on the last command:
Error: couldn't connect to server 127.0.0.1:27017 at src/mongo/shell/mongo.js:145
exception: connect failed`.
How can I connect successfully? Should I change the host/IP, and to what, in which commands?

Several things going wrong here. First are the commands you're running:
RUN service mongodb start
RUN mongod --fork --logpath /var/log/mongodb.log
Each of these will run to create a layer in docker. And once the command being run returns, the temporary container that was started is stopped and any files changed in the container are captured to make a new layer. There are no persistent processes that last between these commands.
These commands are also running the background version of the startup commands. In docker, you'll find this to be problematic since when you use this as your container's command, you'll find the container dies as soon as the command finishes. Pid 1 on the container has the same role of pid 1 on a linux OS, once it dies, so does everything else.
The second issue I'm seeing is mixing data with your container in the form of initializing the database with the last RUN command. This fails since there's no database running (see above). I'd recommend instead to make an entrypoint that configures the database if one does not already exist, and then use a volume in your docker-compose.yml or on your docker run commandline to persist data between containers.
If you absolutely must initialize the data as part of your image, then you can try merging the various commands into a single run:
RUN mongod --fork --logpath /var/log/mongodb.log \
&& mongo db --eval 'db.createUser({user:"dbuser",pwd:"dbpass",roles:["readWrite","dbAdmin"]})'

I think you misunderstood what Dockerfiles are used for.
As Dockerfile reference points out, a
Dockerfile is a text document that contains all the commands a user could call on the command line to assemble an image.
The whole concept of an image is to derive running container from it which are then filled with data and queried (in case of a database) or are beeing called by an external container / host (in case of an web service) or many other possible usages.
To answer your question I'll assume that:
You want to use a mongo database to store data.
You have some pyhton code which needs to have access to mongo.
You want some initial data in your database.
To do so:
Run a mongo database
docker run --name my-mongo -d mongo
Note: There is no need to write a custom image. Use the official mongo image!
Create a python image which contains your script
a) Write your Dockerfile
FROM python:3-alpine
ADD my_script.py /
RUN pip install any-dependency-you-might-need
CMD [ "python", "./my_script.py" ]
b) Write your my_script.py
Insert your application stuff here. It will be executed in the python container. And as mongo will be linked, you can use s.th. like client = MongoClient('mongodb://mongo:27017/') to get started.
Run your python container with a link to mongo
a) Build it:
docker build -t my-pyhthon-magic .
b) Run it:
docker run -d --name python-magic-container --link my-mongo:mongo my-python-magic
Note: The --link here links a running container named my-mongo to be reached internally in my-python-magic-container as mongo. That`s why you can use it in your python script.
I hope this helped you - don't hesitate to ask or modify your question if I misunderstood you.

Related

Docker Postgres data host volume mapping

I'm trying to docker-containerize PostgreSQL server and this container will have many other applications as well. The need is that, PostgreSQL server data should be mapped to the host volume so that when container is stopped, we won't lose the data. Also that, the next time when we start the container, the same directory can be mapped again and postgres can use the old data. Below is the DOCKERFILE. Note that I'm using ubuntu 22.04 on the host.
FROM ubuntu:22.04
ENV DEBIAN_FRONTEND noninteractive
RUN apt install -y postgresql
ENTRYPOINT ["tail", "-f", "/dev/null"]
Docker image is built using the command
docker build -t pg_test .
and the container is run using the command
docker run --name test -v /home/me/data:/var/lib/postgresql/14/main pg_test
'/home/me/data' is the host directory which is empty where I want to map the postgres server data. '/var/lib/postgresql/14/main' is the directory inside the docker container where the postgres is supposed to store the data.
Once the docker container starts, I enter the docker container using the command
docker exec -it test bash
and once I'm inside, I'm trying to start the PostgreSQL service. But PostgreSQL fails to start as there is no data in '/var/lib/postgresql/14/main' directory. I understand that since I have mapped an empty host directory to '/var/lib/postgresql/14/main' directory, postgres doesn't have the files required to start.
I understand that I'm doing it the wrong way, but I couldn't find a way around it. Can anyone please help me to do this the right way, if there is one?
Any help would be appreciable.
You should use the postgres docker image, it will set up the db for you when you start the container, you can find instructions on https://hub.docker.com/_/postgres
If you must use a custom image, you will need to initialize the db yourself, usually by running initdb or whatever your system provides.
But really you should use the appropriate docker image, and if you need more services you start them in their own container and connect them to the postgres one

With a container running MongoDB, how can I run a setup script on start?

I have a docker container that is running a mongo database, and then a service that is checking for data stored on it, but first some basic setup has to be done like adding a user and collection. I have a script that does all of that, but as of now I have to run it manually with docker exec -it logging-service_mongo_1 bash docker-entrypoint-initdb.d/test2.sh
Note that the script is a volume for the container. Is there a way that I can have the script run when the container running mongo has been established? I have tried using entrypoint, but had no luck with that. Apologies if this information is lacking, this is my first attempt using both docker and mongodb
One more thing is that the code I inherited contains this
CMD [ "npm", "run", "start:prod" ]
which I think may have been messing with the entrypoint when I attempted that
If you are using the official MongoDB docker image, take a look at the "Initializing a fresh instance" section of the image documentation:
When a container is started for the first time it will execute files with extensions .sh and .js that are found in /docker-entrypoint-initdb.d. Files will be executed in alphabetical order. .js files will be executed by mongo using the database specified by the MONGO_INITDB_DATABASE variable, if it is present, or test otherwise. You may also switch databases within the .js script.
You can either build a new image based on this one that bakes the script into /docker-entrypoint-initdb.d, or you can mount scripts into that directory using bind mounts (docker run -v $PWD/myscript.sh:/docker-entrypoint-initdb.d/myscript.sh ...)
if you only need to setup the user and password yo can set it while starting the container
docker run -d --name container_name \
-e MONGO_INITDB_ROOT_USERNAME=admin \
-e MONGO_INITDB_ROOT_PASSWORD=password \
mongo
If you use docker-compose
mongodb:
container_name: mongodb
ports:
- 27017:27017
environment:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: password
volumes:
- mongo_data:/data/db
Regarding the collection it will be created once you insert data on it.
If you really need to do this after the mongo container start, i suggest you to create another container that tries to setup the mongo when it detects that mongo turned on

MongoDB: Is it ok to run multiple mongod on the same directory(dbpath)?

I'm currently working with Docker, I use mongo image for my DB container. For persistent storage, I mounted host machine's directory(e.g. /var/docker/data/db) to container(e.g. /data/db).
By now, whenever I wanted to run mongo shell and connect to my db I was doing these things:
Attach to running MongoDB container using docker exec -it <container> bash
Run mongo shell inside the container
Do some job
But I think it'll be much better if I could run mongod separately on the host machine, not in the container, and then connect to it even when the container is not running.
So is it possible to doing so? If I run two mongod process on the same directory(files), will there be an file access conflict?
If someone did similar kind of work, share me your experience please. Thanks.

docker build does not sustain processes

So this might be my Dockerfile:
FROM ubuntu:latest
RUN apt-get -y update && apt-get install -y mysql-server-5.6
RUN service mysql start
RUN service mysql status
It throws an error during the build that MySQL is not running, even though the previous command finished with a success. The deamons seem not to be able to be running between different commands in the Dockerfile.
This is an artificial example, but in my real Dockerfile I have lines which configure the database and they need to have a deamon running in the backgroud. The only solution to go around this that I found is to run:
RUN service mysql start && ./database_configure1.sh
RUN service mysql start && ./do_something_else_with_db.sh
and so on
But this is probably not the way to do it. Is there any better way to go about this?
Each RUN command within your Dockerfile runs within a different container, so here's the actual sequence of events:
service mysql start starts MySQL.
Then the container is stopped (MySQL is stopped).
Then a snapshot is taken.
Then a new container is launched using that snapshot.
service mysql status is run in the new container.
Of course, mysql isn't actually running in the latter container, so that fails.
So, instead, you need to do everything in a single build step. Usually, you'll want to do this by running a shell script within your container.
Here goes.
Your directory tree should look like this:
Dockerfile
do_stuff_with_mysql.sh
Then, in your Dockerfile, do:
ADD do_stuff_with_mysql.sh /
RUN chmod 755 /do_stuff_with_mysql.sh
RUN do_stuff_with_mysql.sh
And, in do_stuff_with_mysql.sh, you should have something that looks like this:
#!/bin/bash
set -o errexit
set -o nounset
service mysql start
./database_configure1.sh
./do_something_else_with_db.sh
service mysql stop
# you should loop on `service mysql status` to confirm MySQL is done shutting down

Docker container mongod error when starting via ssh

I have installed mongodb on a docker container together with openssh on ubuntu 14.04. The container is running with ssh but when I ssh into the container I get the following error when trying to start mongod.
root#430f9502ba2d:~# service mongod start
Rather than invoking init scripts through /etc/init.d, use the service(8)
utility, e.g. service mongod start
Since the script you are attempting to invoke has been converted to an
Upstart job, you may also use the start(8) utility, e.g. start mongod
Also start mongod does not affect anything.
Tried looking at this also Mongo daemon doesn't run by service mongod start without it helping.
mongod --config /your/path/to/mongod.conf doesn't seem to work also, just locks up.
The error below is standard as of course there is no mongod server running.
root#430f9502ba2d:/# mongo
MongoDB shell version: 2.6.9
connecting to: test
2015-05-07T20:49:56.213+0000 warning: Failed to connect to 127.0.0.1:27017, reason: errno:111 Connection refused
2015-05-07T20:49:56.214+0000 Error: couldn't connect to server 127.0.0.1:27017 (127.0.0.1), connection attempt failed at src/mongo/shell/mongo.js:146
exception: connect failed
The problem here is your approach. Docker does not have an init system like you are used to on traditional systems. What docker does is replace PID 1 with the process you specify in the CMD or ENTRYPOINT Dockerfile commands. For now, ignore ENTRYPOINT, because it replaces what your CMD is run with (normally, it's /bin/sh -c). You need to instruct docker to start your mongod service in your Dockerfile with the CMD command, like:
CMD usr/bin/mongod
And when you run your container, mongod will be your PID 1. Now, you're probably wondering at this point "But what about my SSH server?" and the answer is: Don't run an SSH server on your docker containers. There are some use cases where running an SSH server is okay, but almost all of the "normal" reasons (debug, C&C, etc) are nullified with the "best practice" for getting a shell on your container:
docker exec -it myContainer /bin/bash
This will drop you into a shell on your running container. The recommendation here for managing configuration and changes in your docker container is to use something like Ansible. However, remember that docker containers are ephemeral, and you shouldn't be restarting services and changing configuration state on them. If you need a config change, change the Dockerfile or config data, and then start a new container. Good luck! Here is a little more information on Dockerizing MongoDB, but keep in mind that the method described there alters the ENTRYPOINT in the Dockerfile, which is a little more involved and requires a better understanding of what's going on in Dockerfiles.
This is really helpful. I was trying to make old Ansible playbooks work with Docker by creating several blank containers and let Ansible do the rest.
It works through command
mongod --dbpath /var/lib/mongodb --smallfiles