Initiate your MongoDB Container with ENV (Environment Variables)

You want to add a MongoDB Container to your Docker environment? Do you want to use Environment Variables instead of hardcoding credentials in your scripts? Great! But how to initiate users with this credentials from your docker-entrypoint scripts?

Before we can continue to build our development environment for PHP and MongoDB with Docker, we have to solve a general – not PHP related problem. You find a lot of information on the internet how to set up a MongoDB container in Docker. And you also find a lot of information how to use environment variable to pass the MongoDB credentials to your app (in our case our PHP app). But there is one downside with most of the solutions: the all hard code the credentials in the docker-entrypoint script for the MongoDB container. Out of security concerns, this is a really bad solutions. Especially, because we are using git. You don’t want to commit credential in your repository! Never!

Add MongoDB to your docker-compose.yml

Before we dive into using the ENVs, we have to create a docker-compose.yml file with MongoDB as a service. The official documentation from Docker for MongoDB leaves you with that:

# docker-compose.yml
version: '3.7'

services:

  mongo:
    image: mongo
    restart: always
    environment:
      MONGO_INITDB_ROOT_USERNAME: root
      MONGO_INITDB_ROOT_PASSWORD: example

This will create a container with the latest version of MongoDB. But right now, we did not create any database and we also don’t want to use our root user in our app.

The official documentation will tell you to execute some bash scripts to create databases and additional users. Of course, we could do that manually or integrate the steps in a pipeline. But right now, we don’t have a pipeline. And manual configuration steps are ugly.

So, don’t execute the following steps from the documentation. We try to find a more elegant solution!

$ docker run -d --network some-network --name some-mongo \
	-e MONGO_INITDB_ROOT_USERNAME=mongoadmin \
	-e MONGO_INITDB_ROOT_PASSWORD=secret \
	mongo

$ docker run -it --rm --network some-network mongo \
	mongosh --host some-mongo \
		-u mongoadmin \
		-p secret \
		--authenticationDatabase admin \
		some-db

What we can do with Docker is to create a entrypoint-script which is executed when the container is created. Some blog articles about MongoDB and Docker suggest here a JavaScript-File where you could easily create a database and users. But there is a downside! Not enviroment variables in JavaScript. So again, we need to find a different solution.

Shell Script as Container Entrypoint

Our solution is really easy and convenient: we are going to use a simpel Shell script from where we execute the commands from the Docker documentation. And the best part is: we can use environment variables in our script!

So let’s create a new file init.sh:

# init.sh
set -e

mongosh <<EOF
use admin
db.createUser({
  user: '$MONGODB_USER',
  pwd:  '$MONGODB_PASSWORD',
  roles: [{
    role: 'readWrite',
    db: '$MONGODB_DB'
  }]
})
EOF

Now we just have to do some little changes to our docker-compose.yml file and we will be ready to boot up MongoDB container.

# docker-compose.yml
version: '3.7'

services:
  mongo:
    image: mongo:latest
    restart: always
    environment:
      MONGO_INITDB_DATABASE: ${MONGO_INITDB_DATABASE}
      MONGO_INITDB_ROOT_USERNAME: ${MONGO_INITDB_ROOT_USERNAME}
      MONGO_INITDB_ROOT_PASSWORD: ${MONGO_INITDB_ROOT_PASSWORD}
      MONGODB_DB: ${MONGODB_DB}
      MONGODB_USER: ${MONGODB_USER}
      MONGODB_PASSWORD: ${MONGODB_PASSWORD}
    volumes:
      - ./init.sh:/docker-entrypoint-initdb.d/init.sh:ro

Our MongoDB container expects now 6 environment variables as you can see in the docker-compose.yml file. MONGO_INITDB_DATABASE, MONGO_INITDB_ROOT_USERNAME and MONGO_INITDB_ROOT_PASSWORD are defined in the official MongoDB image and are the root data to manage the database and create users.

The other three variables MONGODB_DB, MONGODB_USER and MONGODB_PASSWORD are our projects credentials for accessing our MongoDB database. They are used in the before created init.sh script.

Bonus: External access to your MongoDB database

With the docker-compose.yml file we created in the blog post, we are able to access MongoDB from another container which must be in the same Docker network. You could spin up another service in the docker-compose.yml file and access the database with the credentials we just created by using the service name mongo as hostname.

If you want to access the Mongo database from anywhere else you have to expose the port 27017 outside your Docker network. This could be needed because you have your application locally running and use Docker just for serving MongoDB or you want to use a Client Software for MongoDB like Studio 3T.

To allow access to your MongoDB from outside your Docker, you have to adjust the docker-compose.yml (see lines 8 and 9).

# docker-compose.yml
version: '3.7'

services:
  mongo:
    image: mongo:latest
    restart: always
    ports:
      - 27017:27017
    environment:
      MONGO_INITDB_DATABASE: ${MONGO_INITDB_DATABASE}
      MONGO_INITDB_ROOT_USERNAME: ${MONGO_INITDB_ROOT_USERNAME}
      MONGO_INITDB_ROOT_PASSWORD: ${MONGO_INITDB_ROOT_PASSWORD}
      MONGODB_DB: ${MONGODB_DB}
      MONGODB_USER: ${MONGODB_USER}
      MONGODB_PASSWORD: ${MONGODB_PASSWORD}
    volumes:
      - ./init.sh:/docker-entrypoint-initdb.d/init.sh:ro

Now you can connect to your Database from outside Docker. Just use localhost as hostname.

Summary

In this blog post I showed you how to set up a MongoDB container with Docker Compose. We are using a Shell Script to create a database and credentials to use in our project.

Also we are able to access the MongoDB database with a tool like Studio 3T from our host system.

Please read also my series of blog posts about how to create a development and production environment for PHP and Symfony with Docker if that is of interest for you. In part 3 we are going to add a MongoDB container to our project based on the findings from this blog post.

Schreiben Sie einen Kommentar