banner
WilsonJ

WilsonJ

github
follow

Using docker-compose to start mongo in 'single replica mode' to support transactions.

The primary condition for MongoDB to support transactions is that the MongoDB version must be 4.x or above, and it must be in replica set mode. Since many times using MongoDB does not require deploying multiple replicas, but transactions are desired, the 'single replica mode' can be used, which ensures that there is only one MongoDB instance while still being in replica set mode. This article uses MongoDB 5.0.8 as an example.

This article is just a brief note on issues encountered in daily use; if there are any errors, please feel free to point them out.

First, here is the docker-compose.yml#

version: '3.0'
services:
  mongo:
    image: mongo:5.0.8
    restart: unless-stopped
    container_name: mongodb
    command: --replSet rs0 --bind_ip_all --keyFile /data/mongodb/keyFile
    environment:
      TZ: 'Asia/Shanghai'
      # Username and password
      MONGO_INITDB_ROOT_USERNAME: 'admin'
      MONGO_INITDB_ROOT_PASSWORD: 'password'
    ports:
      - 27017:27017
    volumes:
      - ./mongodb/data:/data/db
      - ./mongodb/keyFile:/data/mongodb/keyFile

Prepare the keyFile#

I roughly tested that the keyFile is not needed in version 4.x, but it is required in version 5.x; otherwise, it will report “BadValue: security.keyFile is required when authorization is enabled with replica sets.”
image

Generate the keyFile#
openssl rand -base64 128 > ./mongodb/keyFile

Here, ./mongodb/keyFile specifies the name of the generated file and the folder in which it is located.

Set permissions and ownership#

The permissions of the keyFile must be 600; if the permissions are too broad, it will report “error opening file: /data/mongodb/keyFile: bad file” on startup.

image

After changing the permissions to 600, the ownership of the keyFile must also be changed to mongodb; otherwise, it will report "permissions on /data/mongodb/keyFile are too open" on startup.

image

Since the container is started, the ownership of the keyFile must be changed to 999, so that the container will automatically change the ownership of the keyFile to mongodb.

sudo chmod 600 keyFile
sudo chown 999:999 keyFile

Outside the container

image

Inside the container

image

Once the keyFile is prepared, you can start the container according to the above docker-compose.yml.

Initialization#

After the container starts, MongoDB is still not usable; you need to enter the container to initialize the replica set.
Enter the container

docker exec -it mongodb /bin/bash

Log into MongoDB with the username and password you just set

mongo -u admin --authenticationDatabase admin

image

Execute the initialization

rs.initiate()

If it displays, it means it was successful.

image

At this point, MongoDB is considered to be fully started.

Spring Boot project configuration#

To implement transactions, configuration is also needed in the project.

Spring Boot version: 2.1.6.RELEASE

@Configuration
@Slf4j
public class MongoTransactionConfig {
    @Bean
    MongoTransactionManager transactionManager(MongoDbFactory factory){
        log.warn("Enabling MongoDB transactions");
        return new MongoTransactionManager(factory);
    }
}

In higher versions of Spring Boot, MongoDbFactory has been deprecated and should be replaced with MongoDatabaseFactory.

Spring Boot version: 2.6.1

@Configuration
@Slf4j
public class MongoTransactionConfig {
    @Bean
    MongoTransactionManager transactionManager(MongoDatabaseFactory factory){
        log.warn("Enabling MongoDB transactions");
        return new MongoTransactionManager(factory);
    }
}

After adding the configuration class, you only need to add the @Transactional annotation to the method to implement MongoDB transactions.


!!! New !!!
Many times we want to retain the mounted data and rebuild the container. Since Docker randomly assigns a hostname to the container every time a new container is built, but we still use the data mounted from the previous container, this causes the hostname in the MongoDB replica set configuration to still be that of the previous container, which leads to the newly started MongoDB being unusable. Therefore, we only need to change the hostname in the MongoDB replica set configuration to solve this problem.

When we start MongoDB and connect directly, this error will be reported.

image

First, we enter the container and check the current hostname of the container.

image

Using the method mentioned above, log into MongoDB with the admin account and check the config.

rs.config()

image
As mentioned above, the hostname in the config is different from the current container's hostname.

Method 1: Change the hostname#

  1. Get the replica set configuration
config=rs.conf()
  1. Based on the JSON format of the above configuration, you can identify the position of the hostname and reassign it (change host to the current container's host).
config.members[0].host="c3e9261f8a04:27017"
  1. Finally, update the config
rs.reconfig(config, {force : true})

image

After changing, MongoDB can start normally.

Method 2: Specify the hostname in the YAML#

version: '3.0'
services:
  mongo:
  	hostname: mongo501
    image: mongo:5.0.8
    restart: unless-stopped
    container_name: mongodb
    command: --replSet rs0 --bind_ip_all --keyFile /data/mongodb/keyFile
    environment:
      TZ: 'Asia/Shanghai'
      # Username and password
      MONGO_INITDB_ROOT_USERNAME: 'admin'
      MONGO_INITDB_ROOT_PASSWORD: 'password'
    ports:
      - 27017:27017
    volumes:
      - ./mongodb/data:/data/db
      - ./mongodb/keyFile:/data/mongodb/keyFile

In this way, the hostname of each newly created container will be the same.

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.