
Wondering what Docker Compose is?
Docker is the most popular containerization tool in the DevOps world. But, What is Docker Compose?
Docker Compose is used to run applications which have multiple containers using a YAML file.
There can be several cases where the docker application must run multiple containers for different technology stack. Now building, running, connecting separate dockerfiles for each container can be a difficult task; this is where docker-compose helps you out.
Using a single and straightforward docker-compose.yml file, you can build, connect, and launch all the containers by running a single command. This is very useful for enterprise applications in production, where several applications run inside containers. It saves a lot of time by running 100s of application inside docker containers with ease.
Installing Docker Compose
Docker should already be installed on your system before installing compose.
Run the command below to install docker-compose.
[email protected]:/home/geekflare$ sudo curl -L "https://github.com/docker/compose/releases/download/1.23.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
[sudo] password for geekflare:
% Total   % Received % Xferd Average Speed  Time   Time    Time Current
Dload Upload  Total  Spent   Left Speed
100Â Â 617Â Â Â 0Â Â 617Â Â Â 0Â Â Â Â 0Â Â 1209Â Â Â Â Â 0 --:--:-- --:--:-- --:--:--Â 1209
100 11.1M 100 11.1M   0    0  348k     0 0:00:32 0:00:32 --:--:-- 476k
Run the command below to set file permissions.
[email protected]:/home/geekflare$ sudo chmod +x /usr/local/bin/docker-compose
Check if it got installed correctly, it should return the docker-compose version.
[email protected]:/home/geekflare$ docker-compose --version
docker-compose version 1.23.1, build b02f1306
Below is the list of commands you can use with docker-compose.
[email protected]:/home/geekflare$ docker-compose
Define and run multi-container applications with Docker.
Usage:
docker-compose [-f <arg>…] [options] [COMMAND] [ARGS…]
docker-compose -h|--help
Options:
-f, --file FILEÂ Â Â Â Â Â Â Â Â Â Â Â Specify an alternate compose file
(default: docker-compose.yml)
-p, --project-name NAMEÂ Â Â Â Specify an alternate project name
(default: directory name)
--verbose                  Show more output
--log-level LEVELÂ Â Â Â Â Â Â Â Â Â Set log level (DEBUG, INFO, WARNING, ERROR, CRITICAL)
--no-ansi                  Do not print ANSI control characters
-v, --version              Print version and exit
-H, --host HOSTÂ Â Â Â Â Â Â Â Â Â Â Â Daemon socket to connect to
--tls                      Use TLS; implied by –tlsverify
--tlscacert CA_PATHÂ Â Â Â Â Â Â Â Trust certs signed only by this CA
--tlscert CLIENT_CERT_PATHÂ Path to TLS certificate file
--tlskey TLS_KEY_PATHÂ Â Â Â Â Â Path to TLS key file
--tlsverify                Use TLS and verify the remote
--skip-hostname-check      Don’t check the daemon’s hostname against the
name specified in the client certificate
--project-directory PATHÂ Â Â Specify an alternate working directory
(default: the path of the Compose file)
--compatibility            If set, Compose will attempt to convert deploy
keys in v3 files to their non-Swarm equivalent
Commands:
build             Build or rebuild services
bundle            Generate a Docker bundle from the Compose file
config            Validate and view the Compose file
create            Create services
down              Stop and remove containers, networks, images, and volumes
events            Receive real time events from containers
exec              Execute a command in a running container
help              Get help on a command
images            List images
kill              Kill containers
logs              View output from containers
pause             Pause services
port              Print the public port for a port binding
ps                List containers
pull              Pull service images
push              Push service images
restart           Restart services
rm                Remove stopped containers
run               Run a one-off command
scale             Set number of containers for a service
start             Start services
stop              Stop services
top               Display the running processes
unpause           Unpause services
up                Create and start containers
version           Show the Docker-Compose version information
Docker Compose File
Here is a sample docker-compose file which does all the magic.
version: '3'
services:
web:
build: .
ports:
- "5000:5000"
redis:
image: "redis:alpine"
The first line in this file specifies the version being used. This number depends on the Docker engine installed on your system. I have Docker 18.09.6 installed which belongs to version 3 of docker-compose. Check out more details on versions here –Â https://docs.docker.com/compose/compose-file/compose-versioning/
This docker file is running two services/applications, web and Redis. The web service is built through a dockerfile and runs at default flask webserver port – 5000. The Redis service runs by pulling the Redis image from docker hub registry.
To execute the docker-compose.yml file, you need to run a very simple command: docker-compose up
Docker Compose Workflow
Below are the three steps to use docker-compose.
- Create dockerfile of each service
- Create a docker-compose.yml file to connect all the dockerfiles
- Run docker-compose up command to start the system
Let me take an example of the sample docker-compose file we saw earlier and show you how the project structure will be created.
my-app
|-----web
|---------Dockerfile
|-----redis
|docker-compose.yml
my-app is my main project directory. This directory has web and Redis service directories and the docker-compose YAML file. Dockerfile of Web service is present in a web directory. Since Redis service is being pulled from docker hub directly, no dockerfile is required in Redis directory. This is how docker-compose workflow looks like.
Containerizing A MEAN Stack Application using Docker Compose
Now that you have understood fundamental concepts. Let me show a demo on how to containerize a MEAN stack application using docker-compose.
MEAN stands for MongoDB, Express, Angular and Node.js. Applications using these services together is also called a MEAN/Full-stack application.
For this demo, we will run three docker containers:
- Container 1 – Angular
- Container 2 – NodeJS and ExpressJS
- Container 3 – MongoDB
Download the complete application here: http://bit.ly/2St7r3A (not tested for production)
This is how my docker-compose.yml file will look like to run these three containers:
version: '3'
services:
angular:
build: angular-client
ports:
- "4200:4200"
volumes:
- ./angular-client/:/var/www/app
express:
build: express-server
ports:
- "3000:3000"
volumes:
- ./express-server/:/var/www/app
links:
- database
database:
image: mongo
ports:
- "27017:27017"
- The first line specifies the docker-compose version being used
- We are running three services – angular, express and database
- Angular service will be built using a dockerfile. It will run on port 4200, and the application volume is /var/www/app
- Express service will be built using a dockerfile. The express server will run at port 3000, and the volume is /var/www/app
- Database service will pull MongoDB image from dockerhub and start it at post 27017
Extract the project in the home directory and go to the angular-client directory.
[email protected]:~$ cd mean
[email protected]:~/mean$ cd angular-client
Run the command below if you don’t have node package manager (npm) installed on your system (ignore if it’s installed).
[email protected]:~/mean/angular-client$ sudo apt install npm
[sudo] password for geekflare:
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following additional packages will be installed:
gyp javascript-common libc-ares2 libhttp-parser2.8 libjs-async libjs-inherits libjs-is-typedarray
libjs-jquery libjs-node-uuid libjs-underscore libssl1.0-dev libuv1 libuv1-dev node-abbrev node-ajv
node-ansi node-ansi-color-table node-ansi-regex node-ansi-styles node-ansistyles node-aproba node-archy
node-are-we-there-yet node-async node-aws-sign2 node-balanced-match node-block-stream node-bluebird
node-boom node-brace-expansion node-builtin-modules node-camelcase node-caseless node-chalk node-cliui
node-clone node-co node-color-convert node-color-name node-combined-stream node-concat-map
node-config-chain node-console-control-strings node-cookie-jar node-copy-concurrently node-core-util-is
node-yallist node-yargs node-yargs-parser nodejs nodejs-dev nodejs-doc
Suggested packages:
apache2 | lighttpd | httpd node-aws-sign node-oauth-sign node-http-signature debhelper
The following NEW packages will be installed:
gyp javascript-common libc-ares2 libhttp-parser2.8 libjs-async libjs-inherits libjs-is-typedarray
libjs-jquery libjs-node-uuid libjs-underscore libssl1.0-dev libuv1 libuv1-dev node-abbrev node-ajv
node-ansi node-ansi-color-table node-ansi-regex node-ansi-styles node-ansistyles node-aproba node-archy
node-are-we-there-yet node-async node-aws-sign2 node-balanced-match node-block-stream node-bluebird
0 upgraded, 212 newly installed, 0 to remove and 233 not upgraded.
Need to get 10.5 MB of archives.
After this operation, 53.6 MB of additional disk space will be used.
Do you want to continue? [Y/n] Y
Get:1 http://us.archive.ubuntu.com/ubuntu cosmic/universe amd64 gyp all 0.1+20180428git4d467626-1 [237 kB]
Get:2 http://us.archive.ubuntu.com/ubuntu cosmic/main amd64 javascript-common all 11 [6,066 B]
Get:3 http://us.archive.ubuntu.com/ubuntu cosmic/main amd64 libhttp-parser2.8 amd64 2.8.1-1 [20.8 kB]
Get:4 http://us.archive.ubuntu.com/ubuntu cosmic/universe amd64 libjs-async all 0.8.0-3 [25.4 kB]
Get:5 http://us.archive.ubuntu.com/ubuntu cosmic/universe amd64 libjs-is-typedarray all 1.0.0-2 [2,934 B]
Get:6 http://us.archive.ubuntu.com/ubuntu cosmic/main amd64 libjs-jquery all 3.2.1-1 [152 kB]
Get:7 http://us.archive.ubuntu.com/ubuntu cosmic/universe amd64 libjs-node-uuid all 1.4.7-5 [11.5 kB]
Get:8 http://us.archive.ubuntu.com/ubuntu cosmic/main amd64 libjs-underscore all 1.8.3~dfsg-1 [59.9 kB]
Get:9 http://us.archive.ubuntu.com/ubuntu cosmic-updates/main amd64 libssl1.0-dev amd64 1.0.2n-1ubuntu6.2 [1,366 kB]
Fetched 10.5 MB in 1min 34s (112 kB/s)
Extracting templates from packages: 100%
Selecting previously unselected package gyp.
(Reading database ... 180130 files and directories currently installed.)
Preparing to unpack .../000-gyp_0.1+20180428git4d467626-1_all.deb ...
Unpacking gyp (0.1+20180428git4d467626-1) ...
Selecting previously unselected package javascript-common.
Preparing to unpack .../001-javascript-common_11_all.deb ...
Unpacking javascript-common (11) ...
Selecting previously unselected package libhttp-parser2.8:amd64.
Preparing to unpack .../002-libhttp-parser2.8_2.8.1-1_amd64.deb ...
Setting up node-fstream-ignore (0.0.6-2) ...
Setting up node-gyp (3.6.2-2) ...
Setting up node-yargs (10.0.3-2) ...
Setting up npm (5.8.0+ds-2) ...
Processing triggers for libc-bin (2.28-0ubuntu1) ...
In angular-client directory and run npm install.
[email protected]:~/mean/angular-client$ npm install
> [email protected] install /home/geekflare/mean/angular-client/node_modules/uws
> node-gyp rebuild > build_log.txt 2>&1 || exit 0
> [email protected] install /home/geekflare/mean/angular-client/node_modules/node-sass
> node scripts/install.js
Downloading binary from https://github.com/sass/node-sass/releases/download/v4.7.2/linux-x64-57_binding.node
Download complete ] - :
Binary saved to /home/geekflare/mean/angular-client/node_modules/node-sass/vendor/linux-x64-57/binding.node
Caching binary to /home/geekflare/.npm/node-sass/4.7.2/linux-x64-57_binding.node
> [email protected] postinstall /home/geekflare/mean/angular-client/node_modules/webpack/node_modules/uglifyjs-webpack-plugin
> node lib/post_install.js
> [email protected] postinstall /home/geekflare/mean/angular-client/node_modules/node-sass
> node scripts/build.js
Binary found at /home/geekflare/mean/angular-client/node_modules/node-sass/vendor/linux-x64-57/binding.node
Testing binary
Binary is fine
added 1457 packages from 1250 contributors in 80.009s
Now go to express directory and run npm install.
[email protected]:~/mean/angular-client$ cd ..
[email protected]:~/mean$ cd express-server/
[email protected]:~/mean/express-server$ npm install
Now that everything is set, its time to run docker-compose.yml file which is going to launch all the docker containers and run the MEAN stack application.
[email protected]:~/mean/express-server$ cd ..
[email protected]:~/mean$ docker-compose up
Creating network "mean_default" with the default driver
Building angular
Step 1/8 : FROM node:8
8: Pulling from library/node
a4d8138d0f6b: Pull complete
dbdc36973392: Pull complete
f59d6d019dd5: Pull complete
aaef3e026258: Pull complete
6e454d3b6c28: Pull complete
c717a7c205aa: Pull complete
37add8e5ac11: Pull complete
0314ab675d31: Pull complete
012886364728: Pull complete
Digest: sha256:310db2abcff097ef44af205d81833282a6d5471002a1b59d7b7459a74152c856
Status: Downloaded newer image for node:8
---> 8e45c884a32e
Step 2/8 : RUN mkdir -p /var/www/app
---> Running in c70a0cab7994
Removing intermediate container c70a0cab7994
---> 001c5e840b24
Step 3/8 : WORKDIR /var/www/app
---> Running in 622ebdc41b2f
Removing intermediate container 622ebdc41b2f
---> baa2e2347259
Step 4/8 : COPY package.json /var/www/app
---> 5b97543befab
Step 5/8 : RUN npm install
---> Running in 73e3d8b7a701
> [email protected] install /var/www/app/node_modules/uws
> node-gyp rebuild > build_log.txt 2>&1 || exit 0
> [email protected] install /var/www/app/node_modules/node-sass
> node scripts/install.js
Downloading binary from https://github.com/sass/node-sass/releases/download/v4.12.0/linux-x64-57_binding.node
Download complete
Binary saved to /var/www/app/node_modules/node-sass/vendor/linux-x64-57/binding.node
Caching binary to /root/.npm/node-sass/4.12.0/linux-x64-57_binding.node
> [email protected] postinstall /var/www/app/node_modules/core-js
> node scripts/postinstall || echo "ignore"
The project needs your help! Please consider supporting of core-js on Open Collective or Patreon:
> https://opencollective.com/core-js
> https://www.patreon.com/zloirock
> [email protected] postinstall /var/www/app/node_modules/webpack/node_modules/uglifyjs-webpack-plugin
> node lib/post_install.js
> [email protected] postinstall /var/www/app/node_modules/node-sass
> node scripts/build.js
Binary found at /var/www/app/node_modules/node-sass/vendor/linux-x64-57/binding.node
Testing binary
Binary is fine
added 1606 packages from 1329 contributors and audited 15092 packages in 112.427s
Removing intermediate container 73e3d8b7a701
---> 55790d2fae93
Step 6/8 : COPY . /var/www/app
---> 61537aa487f4
Step 7/8 : EXPOSE 4200
---> Running in 632eedc35a45
Removing intermediate container 632eedc35a45
---> 51e75b0e2ebe
Step 8/8 : CMD ["npm", "start"]
---> Running in 36bbb12a0d38
Removing intermediate container 36bbb12a0d38
---> 9f8d61db600c
Successfully built 9f8d61db600c
Successfully tagged mean_angular:latest
Pulling database (mongo:)...
latest: Pulling from library/mongo
35b42117c431: Pull complete
ad9c569a8d98: Pull complete
293b44f45162: Pull complete
0c175077525d: Pull complete
4e73525b52ba: Pull complete
a22695a3f5e9: Pull complete
c5175bcf2977: Pull complete
3e320da07793: Pull complete
01c6db6b2b5a: Pull complete
3bd6e9d03e78: Pull complete
e03dcf51513f: Pull complete
c1956a9e136a: Pull complete
4c35cf22b1d5: Pull complete
Building express
Step 1/9 : FROM node:8
---> 8e45c884a32e
Step 2/9 : RUN mkdir -p /var/www/app
---> Using cache
---> 001c5e840b24
Step 3/9 : WORKDIR /var/www/app
---> Using cache
---> baa2e2347259
Step 4/9 : COPY package.json /var/www/app
---> 0232ad53c679
Step 5/9 : RUN npm install
---> Running in c309bf6f218e
added 128 packages from 151 contributors and audited 233 packages in 9.055s
Removing intermediate container c309bf6f218e
---> 49e652884562
Step 6/9 : RUN npm install -g nodemon
---> Running in 0ed5d7f3642b
/usr/local/bin/nodemon -> /usr/local/lib/node_modules/nodemon/bin/nodemon.js
> [email protected] postinstall /usr/local/lib/node_modules/nodemon
> node bin/postinstall || exit 0
Love nodemon? You can now support the project via the open collective:
> https://opencollective.com/nodemon/donate
+ [email protected]
added 221 packages from 128 contributors in 18.856s
Removing intermediate container 0ed5d7f3642b
---> 32c55606f35e
Step 7/9 : COPY . /var/www/app
---> a618b38a2812
Step 8/9 : EXPOSE 3000
---> Running in bea389ab3ef1
Removing intermediate container bea389ab3ef1
---> 684bbfb31371
Step 9/9 : CMD ["npm", "start"]
---> Running in 9aa1b72e4a4e
Removing intermediate container 9aa1b72e4a4e
---> 35dcb3df9806
Successfully built 35dcb3df9806
Successfully tagged mean_express:latest
Creating mean_angular_1_de44b3f5b988Â ... done
Creating mean_database_1_708f8f9c3c33 ... done
Creating mean_express_1_b57a483a72ee ... done
Attaching to mean_angular_1_f257e2233ef1, mean_database_1_ccc5c677e00b, mean_express_1_574f07b045fc
angular_1_f257e2233ef1 |
angular_1_f257e2233ef1 | > [email protected] start /var/www/app
angular_1_f257e2233ef1 | > ng serve -H 0.0.0.0
angular_1_f257e2233ef1 |
database_1_ccc5c677e00b | 2019-07-20T22:33:25.933+0000 I CONTROLÂ [main] Automatically disabling TLS 1.0, to force-enable TLS 1.0 specify --sslDisabledProtocols 'none'
database_1_ccc5c677e00b | 2019-07-20T22:33:25.937+0000 I CONTROLÂ [initandlisten] MongoDB starting : pid=1 port=27017 dbpath=/data/db 64-bit host=f74b56905249
database_1_ccc5c677e00b | 2019-07-20T22:33:25.937+0000 I CONTROLÂ [initandlisten] db version v4.0.10
database_1_ccc5c677e00b | 2019-07-20T22:33:25.937+0000 I CONTROLÂ [initandlisten] git version: c389e7f69f637f7a1ac3cc9fae843b635f20b766
database_1_ccc5c677e00b | 2019-07-20T22:33:25.937+0000 I CONTROL [initandlisten] OpenSSL version: OpenSSL 1.0.2g 1 Mar 2016
database_1_ccc5c677e00b | 2019-07-20T22:33:25.937+0000 I CONTROLÂ [initandlisten] allocator: tcmalloc
database_1_ccc5c677e00b | 2019-07-20T22:33:25.937+0000 I CONTROLÂ [initandlisten] modules: none
database_1_ccc5c677e00b | 2019-07-20T22:33:25.937+0000 I CONTROLÂ [initandlisten] build environment:
database_1_ccc5c677e00b | 2019-07-20T22:33:25.937+0000 I CONTROLÂ [initandlisten]Â Â Â Â distmod: ubuntu1604
database_1_ccc5c677e00b | 2019-07-20T22:33:25.937+0000 I CONTROLÂ [initandlisten]Â Â Â Â distarch: x86_64
database_1_ccc5c677e00b | 2019-07-20T22:33:25.937+0000 I CONTROLÂ [initandlisten]Â Â Â Â target_arch: x86_64
database_1_ccc5c677e00b | 2019-07-20T22:33:25.937+0000 I CONTROLÂ [initandlisten] options: { net: { bindIpAll: true } }
express_1_574f07b045fc |
express_1_574f07b045fc | > [email protected] start /var/www/app
express_1_574f07b045fc | > nodemon ./bin/www
express_1_574f07b045fc |
express_1_574f07b045fc | [nodemon] 1.19.1
express_1_574f07b045fc | [nodemon] to restart at any time, enter `rs`
express_1_574f07b045fc | [nodemon] watching: *.*
express_1_574f07b045fc | [nodemon] starting `node ./bin/www`
database_1_ccc5c677e00b | 2019-07-20T22:33:33.543+0000 I NETWORKÂ [listener] connection accepted from 172.19.0.4:38958 #1 (1 connection now open)
database_1_ccc5c677e00b | 2019-07-20T22:33:33.560+0000 I NETWORKÂ [conn1] received client metadata from 172.19.0.4:38958 conn1: { driver: { name: "nodejs", version: "3.0.1" }, os: { type: "Linux", name: "linux", architecture: "x64", version: "4.18.0-25-generic" }, platform: "Node.js v8.16.0, LE, mongodb-core: 3.0.1" }
express_1_574f07b045fc | mongodb: connected
angular_1_f257e2233ef1 | ** NG Live Development Server is listening on 0.0.0.0:4200, open your browser on http://localhost:4200/ **
angular_1_f257e2233ef1 | Date: 2019-07-21T11:21:03.868Z - Hash: 639d9a968476ed482b5c - Time: 336ms
angular_1_f257e2233ef1 | 4 unchanged chunks
angular_1_f257e2233ef1 | chunk {main} main.bundle.js (main) 19.8 kB [initial] [rendered]
angular_1_f257e2233ef1 |
angular_1_f257e2233ef1 | webpack: Compiled successfully.
angular_1_f257e2233ef1 | webpack: Compiling...
angular_1_f257e2233ef1 | Date: 2019-07-21T11:25:15.661Z - Hash: e5a2b1c1afe0deb396c3 - Time: 251ms
angular_1_f257e2233ef1 | 4 unchanged chunks
angular_1_f257e2233ef1 | chunk {main} main.bundle.js (main) 19.8 kB [initial] [rendered]
angular_1_f257e2233ef1 |
angular_1_f257e2233ef1 | webpack: Compiled successfully.
Go to your browser and check https://localhost:4200, your application will be up and running.
Go to https://localhost:3000 to check if an express server is running.
Also, you can run docker images command to see which all images are present in docker.
[email protected]:~/mean$ docker images
REPOSITORYÂ Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â TAGÂ Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â IMAGE IDÂ Â Â Â Â Â Â Â Â Â Â CREATEDÂ Â Â Â Â Â Â Â Â Â Â Â SIZE
mean_express              latest             35dcb3df9806       14 hours ago       923MB
mean_angular              latest             9f8d61db600c       14 hours ago       1.29GB
node                      8                  8e45c884a32e       9 days ago         895MB
mongo                     latest             785c65f61380       2 weeks ago        412MB
Run the command below to see the containers running inside docker.
[email protected]:~/mean$ docker ps
CONTAINER IDÂ Â Â Â Â Â Â IMAGEÂ Â Â Â Â Â Â Â Â Â Â Â Â Â COMMANDÂ Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â CREATEDÂ Â Â Â Â Â Â Â Â Â Â Â STATUSÂ Â Â Â Â Â Â Â Â Â Â Â Â PORTSÂ Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â NAMES
681c9c34bee2       mean_express       "docker-entrypoint.s…"  14 hours ago       Up 14 hours        0.0.0.0:3000->3000/tcp    mean_express_1_574f07b045fc
f74b56905249       mongo              "docker-entrypoint.s…"  14 hours ago       Up 14 hours        0.0.0.0:27017->27017/tcp  mean_database_1_ccc5c677e00b
260ef1e52dab       mean_angular       "docker-entrypoint.s…"  14 hours ago       Up 14 hours        0.0.0.0:4200->4200/tcp    mean_angular_1_f257e2233ef1
So now, all three docker containers are up and running.
Docker-compose took care of running all the containers with ease. This was a simple example for running three containers; you can imagine how useful it will be if the applications have to be launched on 100s of containers. Go ahead and try out to see how it works.
- Tagged in:
- DevOps
More great readings on Sysadmin
-
Looking For Traceroute on RHEL 8? Try TracepathAbhishek Nair on June 14, 2022
-
6 Best Switch Port Monitoring ToolsDurga Prasad Acharya on June 12, 2022
-
Windows 10/11 Random Shutdown: How to Find the CauseHitesh Sant on May 30, 2022
-
7 Best Server Configuration Monitoring and Auditing ToolsTalha Khalid on May 28, 2022
-
8 Best FTP Server Software for Windows for Secure TransferSatish Shethi on May 24, 2022
-
OSI Model Layers: An Introduction GuideAmrita Pathak on May 13, 2022
Join Geekflare Newsletter
Every week we share trending articles and tools in our newsletter. More than 10,000 people enjoy reading, and you will love it too.