In this brief post, I’ll share how to use MongoDB in a Golang application executed within a Docker container, using docker-compose. The challenge is ensuring that the Golang application waits for the MongoDB instance to be fully operational before starting, to avoid connection retries.
To achieve this, create a docker-compose.yml
file.
version: '3.9' services: api: build: . ports: - 8080:8080 links: - mongodb depends_on: - mongodb environment: WAIT_HOSTS: mongodb:27017 mongodb: image: mongo:7.0 ports: - 27017:27017 volumes: - ~/apps/mongo:/data/db
From the Docker Compose file, we see that we have a service in the build directory that listens on port 8080. The ‘links’ property set to MongoDB means that the application can refer to the MongoDB service using the hostname ‘mongodb’. It also ‘depends on’ MongoDB, indicating that it must wait for MongoDB to start listening on port 27017 before initiating. In short, our service can only start once the MongoDB port is open.
Docker
FROM golang:1.21.3-alpine as builder WORKDIR /root/ RUN apk add --update --no-cache make RUN mkdir -p /root/mongo-docker-compose WORKDIR /root/mongo-docker-compose COPY . . RUN make build FROM alpine:3.18 WORKDIR /root/ COPY --from=builder /root/mongo-docker-compose/bin/ . ADD https://github.com/ufoscout/docker-compose-wait/releases/download/2.8.0/wait wait RUN chmod +x wait ENV TESTDB_MONGO=mongodb EXPOSE 8080 CMD ./wait && ./mongo-docker-compose
In the first part of the Dockerfile, the Golang application is built. In the second part, we prepare for its execution. More specifically, we download the ‘wait’ command and assign execution permissions to it. It’s small command-line utility to wait for other docker images to be started while using docker-compose. It permits waiting for a fixed amount of seconds, until a TCP port is open on a target image (our case) or until a file or directory is present on the local filesystem.
Continuing our examination of the Dockerfile, we observe that the ‘TESTDB_MONGO’ variable is also defined. This variable, utilized in the Go code, holds the ‘name’ of the MongoDB service as specified in the docker-compose file. If the definition of this variable is omitted, or if it contains an incorrect value, the application will be unable to connect to MongoDB, thereby rendering the application non-functional.
Code
Let’s now turn our attention to the Go code above. Here, we will explore how it interacts with the setup we’ve discussed, particularly in relation to the Docker and MongoDB configuration.
const ( hostKey = key("hostKey") UserCollection = "users" DBName = "test" mongoKey = "TESTDB_MONGO" ) // Initialize the database func init() { mongoServer := os.Getenv(mongoKey) if mongoServer == "" { mongoServer = "localhost" } ctx = context.Background() ctx, cancel := context.WithCancel(ctx) defer cancel() ctx = context.WithValue(ctx, hostKey, mongoServer) var err error testDb, err = configDB(ctx) if err != nil { fmt.Printf("db configuration %s\n", err) } fmt.Printf("db connected ") }
It’s important to focus primarily on the ‘mongoKey’, which contains the value ‘TESTDB_MONGO’. This is the name of the environment variable that holds the MongoDB server’s name. That’s all. Enjoy with Go and Mongodb
It’s possible found the simple project here:
https://github.com/niqt/mongo-docker-compose
“Note: English is not my native language, so please excuse any errors. I would appreciate your assistance in correcting them.”