Dockerizing Our API
Understanding Docker
As a former sysadmin, the concept of containers was a bit hard to grasp at first.
“So you want to virtualize an app, in something like a VM? But it’s not the entire VM? Oh but it could be the entire VM?”
The concept wasn’t fully clear to me until I came across Mike Coleman’s post on Docker’s blog.
I don’t want to summarize it and do any injustice to the original post, so check it out!
If you’re already familiar with Docker..
Dockerizing the Database
Mongo has an official Docker image, so we’ll be using that
$ docker run --name jamstack-db -d -p 27017:27017 mongo:latest mongod --bind_ip_all
Now let’s decrypt all of the arguments:
- –name // specify a name
- -d // detach, or run in background
- -p 27017:27017// Host:Container port syntax. Host will listen on 27017, mapped to the container’s exposed port of 27017
- mongo:latest // use the mongo image, latest version
- mongod // command to start the database
- –bind_ip_all // versions >3.5 of mongod listen to localhost by default
Dockerizing the API [with troubleshooting!]
If you just want to get this API started without troubleshooting, follow the Quick Start section in the README.
1) Ensure our MongoDB container is running
Let’s make sure we don’t start an API without the backend :)
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b75379169b08 mongo:latest "docker-entrypoint..." 6 hours ago Exited (0) 6 hours ago jamstack-db
# mine was stopped, so let's start it
$ docker start jamstack-db
2) Create a Dockerfile
3) Also, a .dockerignore file
4) Building our image
After creating those files in the API project directory, we will create a Docker image, then create a container based on that image.
Note: If you haven’t created the JAMstack API yet, read my post, here
# Build image
$ docker build -t nsuave/jamstack-api .
- -t // tag for the image being built
- . // current directory
# Create container
$ docker run --name jamstack-api -d -p 8008:8008 nsuave/jamstack-api
- –name // specify a name
- -d // detach or run in background
- -p 8008:8008 // Host will listen on port 8008. Remember that we defined the container’s exposed port of 8008 in server.js
- running a container based on the “nsuave/jamstack-api” image that we created
It’s running! Kind of.
If you run “docker logs jamstack-api”, you’ll notice an “ECONNREFUSED” error.
$ docker logs jamstack-api
> [email protected] start /usr/src/jamstack-api
> node server.js
{ MongoError: failed to connect to server [localhost:27017] on first connect [MongoError: connect ECONNREFUSED 127.0.0.1:27017]
at Pool.<anonymous> (/usr/src/jamstack-api/node_modules/mongodb-core/lib/topologies/server.js:336:35)
at emitOne (events.js:116:13)
at Pool.emit (events.js:211:7)
at Connection.<anonymous> (/usr/src/jamstack-api/node_modules/mongodb-core/lib/connection/pool.js:280:12)
at Object.onceWrapper (events.js:317:30)
at emitTwo (events.js:126:13)
at Connection.emit (events.js:214:7)
at Socket.<anonymous> (/usr/src/jamstack-api/node_modules/mongodb-core/lib/connection/connection.js:187:49)
at Object.onceWrapper (events.js:315:30)
at emitOne (events.js:116:13)
name: 'MongoError',
message: 'failed to connect to server [localhost:27017] on first connect [MongoError: connect ECONNREFUSED 127.0.0.1:27017]' }
Our database container should be listening on 27017, right?
$ docker run --name jamstack-db -d -p 27017:27017 mongo:latest mongod
And our config/db.js file is trying to connect to that port, right?
url: "mongodb://localhost:27017"
The first problem
This StackOverflow post quickly shows up when you search for that error. Looks like we need to change our config/db.js file!
url: "mongodb://mongo:27017"
When we created the container, it was using the source code that used ‘localhost’ instead of ‘mongo’.
We need to reference the container name of ‘mongo’ instead, and Docker will handle the networking between the containers.
Now that we’ve updated config/db.js to use ‘mongo’ instead of ‘localhost’, let’s update the image with our new file, but hold off on creating a new container:
$ docker stop jamstack-api
$ docker rm jamstack-api
$ docker rmi nsuave/jamstack-api
$ docker build -t nsuave/jamstack-api .
The second problem
Did you notice the reference to –link flag in that StackOverflow post?
According to the official docs, this flag will “Add link to another container”
Sounds like what we want! Syntax is sourceContainerName:containerAliasName
// old
$ docker run --name jamstack-api -d -p 8008:8008 nsuave/jamstack-api
// new
$ docker run --name jamstack-api -d -p 8008:8008 --link jamstack-db:mongo nsuave/jamstack-api
Voila!
We’re back in business! API is now running in a container, and it’s talking to a MongoDB container.
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e61e2362a5b7 nsuave/jamstack-api "npm start" 5 seconds ago Up 4 minutes 0.0.0.0:8008->8008/tcp jamstack-api
b75379169b08 mongo:latest "docker-entrypoint..." 3 days ago Up 9 minutes 0.0.0.0:27017->27017/tcp jamstack-db