Part 3: Docker Compose File: Working with Multiple containers

Till part 2, we have seen how to build containers and mount volumes from local storage alongwith pushing our repository to docker hub.

In this post, we will look at the usage of docker compose file to implement different services in separate containers and to centralize the production level configuration inside a file to be known as docker-compose.yml.

What to achieve ?

We will create two containers:
1. Python engine to host the product details
2. Apache to host the Website

Products   <--->   Website


Solution

1.  Create Directory Structure.

Make two directories for separate containers.
# mkdir website
# mkdir product
$ ls -ltr
total 8
drwxr-xr-x  3 saket1447583  staff  102 Jan 10 13:12 website
drwxr-xr-x  6 saket1447583  staff  204 Jan 10 13:12 product

And a docker compose file to configure it.
# touch docker-compose.yml

After this, build two containers inside these directories and use them to host the service together.
We will see later what to configure inside it.


2. Configure Product container.

$ ls -l product/
total 24
-rw-r--r--  1 saket1447583  staff   66 Jan 10 11:51 Dockerfile
-rw-r--r--  1 saket1447583  staff  342 Jan 10 13:12 api.py
-rw-r--r--  1 saket1447583  staff   33 Jan 10 11:48 requirements.txt

### First we need to create the file say api.py with below content.
### Here we created an array products with a list that we show on website.
### This container service is run on Port 80.

$ cat api.py
# Product Service

from flask import Flask
from flask_restful import Resource, Api

app = Flask(__name__)
api = Api(app)

class Product(Resource):
def get(self):
return {
'products': ['Gajak', 'Moofli', 'Dark Choclate', 'Ice'] }

api.add_resource(Product, '/')

if __name__ == '__main__':
app.run(host='0.0.0.0', port=80, debug=True)
$ 


### In above Python file, we have called Flask library.
### Hence we need Flask and flask-restful to be installed
### By docker during container build.
$ cat requirements.txt 
Flask==0.12
flask-restful==0.3.5
$ 

### Dockerfile contains the image from which we will build the container.
### And what to copy on the default path.
### api.py file to run after container build
$ cat Dockerfile 
FROM python:3-onbuild
COPY . /usr/src/app
CMD ["python","api.py"]
$ 


3. Configure Website Container

### Create a index.php file inside directory
$ cd ../website/
$ ls -ltr
total 8
-rw-r--r--  1 saket1447583  staff  324 Jan 10 13:08 index.php

### put the contents to get the file content.
### "product-service" is the service name defined above.
### docker configures the same name as hostname of that container.
### file_get_contents gets the content of the webpage

$ cat index.php
<html>
<head>
<title>Our Products</title>
</head>
<body>
<h1>Welcome to our products page</h1>
<ul>
<?php $json = file_get_contents('http://product-service');
$obj = json_decode($json);

$products = $obj->products;
foreach ($products as $product) {
echo "<li>$product</li>";
}
?>

</ul>
</body>

</html>
$ 


4. Create docker-compose.yml file.

$ cd ..
$ ls -ltr
total 8
-rw-r--r--  1 saket1447583  staff  275 Jan 10 13:03 docker-compose.yml
drwxr-xr-x  3 saket1447583  staff  102 Jan 10 13:12 website
drwxr-xr-x  6 saket1447583  staff  204 Jan 10 13:12 product

### service name is "product-service"
### build specifies the path is "./product" directory
### volumes mention the local system dir path
### ports map container 80 port to 5000 local system port.
### we can access this service on localhost:5000 port.
### website service defines the image first i.e.
### docker container build configuration
### depends_on specifies the service which
### should be started first for it to work.

$ cat docker-compose.yml 
version: '3'

services:
  product-service:
   build: ./product
   volumes:
     - ./product:/usr/src/app
   ports:
     - 5001:80

  website:
    image: php:apache
    volumes:
      - ./website:/var/www/html
    ports:
      - 5000:80
    depends_on:
     - product-service
$ 


5. Run docker compose file

$ docker-compose up
Pulling website (php:apache)...
apache: Pulling from library/php
177e7ef0df69: Pull complete
9bf89f2eda24: Pull complete
350207dcf1b7: Pull complete
a8a33d96b4e7: Pull complete
c0421d5b63d6: Pull complete
f76e300fbe72: Pull complete
af9ff1b9ce5b: Pull complete
d9f072d61771: Pull complete
4212b7d006e6: Pull complete
1cca8a5e24f8: Pull complete
bd3c820fb415: Pull complete
a2761cbd05fb: Pull complete
91d690c757e8: Pull complete
2c2faa0cad4b: Pull complete
Starting docker_product-service_1 ... done
Creating docker_website_1         ... done
Attaching to docker_product-service_1, docker_website_1
website_1          | AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.18.0.3. Set the 'ServerName' directive globally to suppress this message
website_1          | AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.18.0.3. Set the 'ServerName' directive globally to suppress this message
product-service_1  |  * Running on http://0.0.0.0:80/ (Press CTRL+C to quit)
product-service_1  |  * Restarting with stat
website_1          | [Thu Jan 10 21:05:27.368914 2019] [mpm_prefork:notice] [pid 1] AH00163: Apache/2.4.25 (Debian) PHP/7.3.0 configured -- resuming normal operations
website_1          | [Thu Jan 10 21:05:27.369008 2019] [core:notice] [pid 1] AH00094: Command line: 'apache2 -D FOREGROUND'
product-service_1  |  * Debugger is active!
product-service_1  |  * Debugger PIN: 304-853-752
product-service_1  | 172.18.0.1 - - [10/Jan/2019 21:07:05] "GET / HTTP/1.1" 200 -
product-service_1  | 172.18.0.1 - - [10/Jan/2019 21:07:06] "GET / HTTP/1.1" 200 -
product-service_1  | 172.18.0.1 - - [10/Jan/2019 21:07:06] "GET / HTTP/1.1" 200 -


6. Check the result in browser.

### In product service container:


### In website container:

We will continue to look at docker machine, swarm, and stack in next parts.


References:
1. https://www.youtube.com/watch?v=Qw9zlE3t8Ko
2. And https://docs.docker.com/get-started/part3/

Leave a Reply

Your email address will not be published.