A beginner’s guide to Docker — how to create a client/server side with docker-compose

A beginner’s guide to Docker — how to create a client/server side with docker-compose

You are a developer and you want to discover docker-compose? This article is made for you.

You are a developer and you want to discover docker-compose? This article is made for you.

After a short introduction on Docker-Compose, you will be able to create your first client/server-side application with Docker.

This article takes into consideration that you know the basics of Docker. If not, don’t panic! I suggest that you read my first article to discover Docker and learn how to create your first application.

A beginner’s guide to Docker — how to create your first Docker application

What is Docker-Compose?

Docker-Compose is a tool provided by Docker. To make it simple, this tool is implemented to solve architectural problems in your projects.

As you may have noticed in my previous article, we created a simple program that displayed “Docker is magic!” when it was launched.

Unfortunately, when you are a developer you rarely create a stand-alone program (a program that does not require any other services to run, such as a database).

However, how do you know if you need Docker-Compose? It’s very simple — if your application requires several services to run, you need this tool. For example, if you create a website that needs to connect to your database to authenticate users (here 2 services, website and database).

Docker-compose offers you the possibility to launch all these services in a single command.

Difference between Docker and Docker-Compose

Docker is used to manage an individual container (service) for your application.

Docker-Compose is used to manage several containers at the same time for the same application. This tool offers the same features as Docker but allows you to have more complex applications.

Docker (individual container) VS Docker-Compose (several containers)

A typical use case

This tool can become very powerful and allow you to deploy applications with complex architectures very quickly. I will give you a concrete case study that will prove that you need it.

Imagine, you are the proud creator of your web software.

Your solution offers two websites. The first allows stores to create their online store in just a few clicks. The second is dedicated to customer support. These two sites interact with the same database.

You are beginning to be successful and your server is no longer sufficient. So, you decide to migrate your entire software to another machine.

Unfortunately, you didn’t use docker-compose. So you’re going to have to migrate and reconfigure your services one after the other, hoping nothing has been forgotten.

If you had used a docker-compose, in only a few commands you would have deployed your entire architecture on your new server. All you have to do now is make a few configurations and load the backup of your database to finalize the migration.

Now let’s create your first client/server-side application with Docker-Compose

Now that you know what docker-compose is going to be used for, it’s time to create your first client/server-side application!

The objective of this tutorial is to create a small website (server) in Python that will contain a sentence. This sentence must be retrieved by a program (client) in Python that will display the sentence.

Note: This tutorial takes into consideration that you have already installed Docker on your computer and that you have the basics. If this is not the case, I invite you to refer to my previous article.#### 1. Create your project

To create your first client/server application, I invite you to create a folder on your computer. It must contain at root the following file and folders:

  • A ‘docker-compose.yml’ file (docker-compose file that will contain the necessary instructions to create the different services).
  • A ‘server’ folder (this folder will contain the files necessary to set up the server).
  • A ‘client’ folder (this folder will contain the files necessary to set up the client).

Normally you should have this folder architecture:

.
├── client/
├── docker-compose.yml
└── server/
2 directories, 1 file

2. Create your server

In order to start with reminders of Docker’s basics, we will start by creating the server.

2a. Create files

Move to your ‘server’ folder and create the following files:

  • A ‘server.py’ file (python file that will contain the server code).
  • An ‘index.html’ file (html file that will contain the sentence to be displayed).
  • A ‘Dockerfile’ file (docker file that will contain the necessary instructions to create the environment of the server).

Normally you should have this folder architecture in the following path ‘server/’:

.
├── Dockerfile
├── index.html
└── server.py
0 directories, 3 files

2b. Edit the Python file

You can add the following code to the ‘server.py’ file:

#!/usr/bin/env python3

# Import of python system libraries.
# These libraries will be used to create the web server.
# You don't have to install anything special, these libraries are installed with Python.
import http.server
import socketserver

# This variable is going to handle the requests of our client on the server.
handler = http.server.SimpleHTTPRequestHandler

# Here we define that we want to start the server on port 1234. 
# Try to remember this information it will be very useful to us later with docker-compose.
with socketserver.TCPServer(("", 1234), handler) as httpd:
    # This instruction will keep the server running, waiting for requests from the client.
    httpd.serve_forever()

This code will allow you to create a simple web server inside this folder. It will retrieve the content of the index.html file to share it on a web page.

2c. Edit the Html file

You can add the following sentence to the ‘index.html’ file:

Docker-Compose is magic!

This file will be shared by the server when it is started and this sentence will be displayed.

2d. Edit the Docker file

Here we will create a basic Dockerfile that will be in charge of executing our Python file. We will use the official image created to execute Python.

#!/usr/bin/env python3

# Import of python system libraries.
# These libraries will be used to create the web server.
# You don't have to install anything special, these libraries are installed with Python.
import http.server
import socketserver

# This variable is going to handle the requests of our client on the server.
handler = http.server.SimpleHTTPRequestHandler

# Here we define that we want to start the server on port 1234. 
# Try to remember this information it will be very useful to us later with docker-compose.
with socketserver.TCPServer(("", 1234), handler) as httpd:
    # This instruction will keep the server running, waiting for requests from the client.
    httpd.serve_forever()

3. Create your client

In order to continue with reminders of Docker’s basics, we will create the client.

3a. Create files

Move to your ‘client’ folder and create the following files:

  • A ‘client.py’ file (python file that will contain the client code).
  • A ‘Dockerfile’ file (docker file that will contain the necessary instructions to create the environment of the client).

Normally you should have this folder architecture in the following path ‘client/’:

.
├── client.py
└── Dockerfile
0 directories, 2 files

3b. Edit the Python file

You can add the following code to the ‘client.py’ file:

#!/usr/bin/env python3

# Import of python system library.
# This library is used to download the 'index.html' from server.
# You don't have to install anything special, this library is installed with Python.
import urllib.request

# This variable contain the request on 'http://localhost:1234/'.
# You must wondering what is 'http://localhost:1234'?
# localhost: This means that the server is local.
# 1234: Remember we define 1234 as the server port.
fp = urllib.request.urlopen("http://localhost:1234/")

# 'encodedContent' correspond to the server response encoded ('index.html').
# 'decodedContent' correspond to the server response decoded (what we want to display).
encodedContent = fp.read()
decodedContent = encodedContent.decode("utf8")

# Display the server file: 'index.html'.
print(decodedContent)

# Close the server connection.
fp.close()

This code will allow you to get the content of the server web page and to display it.

3c. Edit the Docker file

As for the server, we will create a basic Dockerfile that will be in charge of executing our Python file.

# Same thing than the 'server' Dockerfile.
FROM python:latest

# Same thing than the 'server' Dockerfile.
# We import 'client.py' in '/client/' folder.
ADD client.py /client/

# I would like to introduce something new, the 'WORKDIR' command.
# This command changes the base directory of your image.
# Here we define '/client/' as base directory.
WORKDIR /client/

4. Back to Docker-Compose

As you may have noticed, we have created two different projects, the server, and the client, both with a Dockerfile.

So far nothing has changed from the basics you already know.

Now we are going to edit the ‘docker-compose.yml’ at the root of the repository.

Note: Docker-Compose being very complete, this article aims to give you a concrete and typical example. That’s why you won’t see all the keywords.

# A docker-compose must always start by the version tag.
# We use "3" because it's the last version at this time.
version: "3"

# You should know that docker-composes works with services.
# 1 service = 1 container.
# For example, a service maybe, a server, a client, a database...
# We use the keyword 'services' to start to create services.
services:
  # As we said at the beginning, we want to create: a server and a client.
  # That is two services.

  # First service (container): the server.
  # Here you are free to choose the keyword.
  # It will allow you to define what the service corresponds to.
  # We use the keyword 'server' for the server.
  server:
    # The keyword "build" will allow you to define
    # the path to the Dockerfile to use to create the image
    # that will allow you to execute the service.
    # Here 'server/' corresponds to the path to the server folder
    # that contains the Dockerfile to use.
    build: server/

    # The command to execute once the image is created.
    # The following command will execute "python ./server.py".
    command: python ./server.py

    # Remember that we defined in'server/server.py' 1234 as port.
    # If we want to access the server from our computer (outside the container),
    # we must share the content port with our computer's port.
    # To do this, the keyword 'ports' will help us.
    # Its syntax is as follows: [port we want on our machine]:[port we want to retrieve in the container]
    # In our case, we want to use port 1234 on our machine and
    # retrieve port 1234 from the container (because it is on this port that
    # we broadcast the server).
    ports:
      - 1234:1234

  # Second service (container): the client.
  # We use the keyword 'client' for the server.
  client:
    # Here 'client/ corresponds to the path to the client folder
    # that contains the Dockerfile to use.
    build: client/

    # The command to execute once the image is created.
    # The following command will execute "python ./client.py".
    command: python ./client.py

    # The keyword 'network_mode' is used to define the network type.
    # Here we define that the container can access to the 'localhost' of the computer.
    network_mode: host

    # The keyword'depends_on' allows you to define whether the service
    # should wait until other services are ready before launching.
    # Here, we want the 'client' service to wait until the 'server' service is ready.
    depends_on:
      - server

5. Build Docker-Compose

Once the docker-compose is set up, your client/server application need to be built. This step corresponds to the ‘docker build’ command but applied to the different services.

$ docker-compose build

6. Run Docker-Compose

Your docker-compose is built! Now it’s time to start! This step corresponds to the ‘docker run’ command but applied to the different services.

$ docker-compose up

There you go, that’s it. You should normally see “Docker-Compose is magic!” displayed in your terminal.

Note: As indicated in the tutorial, your ‘server’ service uses port 1234 of your computer to distribute its content. If you open the ‘http://localhost:1234/’ page on your computer, you should see ‘Docker-Compose is magic!’.### Code is available

If you want to retrieve the complete code to discover it more simply or to execute it, I have put it at your disposal on my Github.

-> GitHub: Client Server Docker-Compose example

Useful commands for Docker

As usual, I have prepared a list of orders that may be useful to you with docker-compose.

  • Stops containers and removes containers, images… created by ‘docker-compose up’.
$ docker-compose down

  • Displays log output from services (example: ‘docker-compose logs -f client’).
$ docker-compose logs -f [service name]

  • Lists containers.
$ docker-compose ps

  • Executes a command in a running container (example: ‘docker-compose exec server ls’).
$ docker-compose exec [service name] [command]

  • Lists images.
$ docker-compose images

It’s already over…

Thanks for reading !

Mobile App Development Company India | Ecommerce Web Development Company India

Mobile App Development Company India | Ecommerce Web Development Company India

Best Mobile App Development Company India, WebClues Global is one of the leading web and mobile app development company. Our team offers complete IT solutions including Cross-Platform App Development, CMS & E-Commerce, and UI/UX Design.

We are custom eCommerce Development Company working with all types of industry verticals and providing them end-to-end solutions for their eCommerce store development.

Know more about Top E-Commerce Web Development Company

10 docker-compose and docker commands that are useful for active development

10 docker-compose and docker commands that are useful for active development

The following article Lina Rudashevski introduces 10 commands that docker-compose and docker are useful for positive development.

Originally published by Lina Rudashevski at dev.to

Sure you might need other ones but I've found over time that these are the only ones I need or use on a regular basis, and I use Docker and docker-compose regularly for various projects.

1. terminal into the docker container

docker exec -it :container_id bash

You may need to terminal into a container to do things like run tests or apply migrations.

[13:54:41] (master) selfies
🙋 docker ps
CONTAINER ID        IMAGE                  COMMAND                  CREATED             STATUS              PORTS                    NAMES
b5e87b73f6f6        selfies_web            "python manage.py ru…"   2 seconds ago       Up 1 second         0.0.0.0:8000->8000/tcp   selfies_web_1
d8e636ad4805        postgres:10.1-alpine   "docker-entrypoint.s…"   3 seconds ago       Up 2 seconds        0.0.0.0:5432->5432/tcp   selfies_db_1
aeb5cba5a482        redis:latest           "docker-entrypoint.s…"   3 seconds ago       Up 2 seconds        6379/tcp                 selfies_redis_1
[13:54:43] (master) selfies
🙋 docker exec -it b5e87b73f6f6 bash
[email protected]:/selfies# python manage.py makemigrations
No changes detected
[email protected]:/selfies# 

2. run the docker container in debug mode

docker-compose run --service-ports web

If you want to debug your server, this command will let you do it. Otherwise you may get an error if you put a debugger in your code.

[13:56:59] (master) selfies
🙋 docker-compose run --service-ports web
Creating network "selfies_default" with the default driver
Creating selfies_redis_1 ... done
Creating selfies_db_1    ... done
Performing system checks...

System check identified no issues (0 silenced).
July 24, 2019 - 17:57:11
Django version 2.1.7, using settings 'selfies.settings'
Starting ASGI/Channels version 2.2.0 development server at http://0.0.0.0:8000/
Quit the server with CONTROL-C.
Performing system checks...

System check identified no issues (0 silenced).
July 24, 2019 - 18:12:29
Django version 2.1.7, using settings 'selfies.settings'
Starting ASGI/Channels version 2.2.0 development server at http://0.0.0.0:8000/
Quit the server with CONTROL-C.
HTTP OPTIONS /app/users/ 200 [0.01, 172.25.0.1:60046]
> /selfies/app/views/account_views.py(48)post()
-> try:
(Pdb)

3. build the docker container

docker-compose build

This runs everything in the Dockerfile. I usually run this the first time to build the project, and after that only if I add dependencies to my requirements.txt file or change anything within my Dockerfile.

[18:59:42] (master) selfies
// ♥ docker-compose build
db uses an image, skipping
redis uses an image, skipping
Building web
Step 1/7 : FROM python:3.6-stretch
---> 9167692c277e
Step 2/7 : ENV PYTHONUNBUFFERED 1
---> Using cache
---> 0533dfe1c141
Step 3/7 : ENV REDIS_HOST "redis"
---> Using cache
---> c01adb015773
Step 4/7 : RUN mkdir /selfies
---> Using cache
---> e60377d4e9ee
Step 5/7 : WORKDIR /selfies
---> Using cache
---> 9018fb3984b0
Step 6/7 : ADD . /selfies/
---> Using cache
---> 8c6d291d99a7
Step 7/7 : RUN pip install -r requirements.txt
---> Using cache
---> 7caa2f3bf2ac
Successfully built 7caa2f3bf2ac
Successfully tagged selfies_web:latest

4. start the docker container

docker-compose up

This will run your container/s in the terminal and will show the server output

[13:39:32] (master) selfies
🙋 docker-compose up
Creating network "selfies_default" with the default driver
Creating selfies_redis_1 ... done
Creating selfies_db_1 ... done
Creating selfies_web_1 ... done
Attaching to selfies_db_1, selfies_redis_1, selfies_web_1
db_1 | 2019-07-24 17:40:36.069 UTC [1] LOG: listening on IPv4 address "0.0.0.0", port 5432
db_1 | 2019-07-24 17:40:36.069 UTC [1] LOG: listening on IPv6 address "::", port 5432
redis_1 | 1:C 24 Jul 2019 17:40:36.085 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
redis_1 | 1:C 24 Jul 2019 17:40:36.085 # Redis version=5.0.5, bits=64, commit=00000000, modified=0, pid=1, just started
redis_1 | 1:C 24 Jul 2019 17:40:36.085 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
redis_1 | 1:M 24 Jul 2019 17:40:36.086 * Running mode=standalone, port=6379.
redis_1 | 1:M 24 Jul 2019 17:40:36.086 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
redis_1 | 1:M 24 Jul 2019 17:40:36.086 # Server initialized
redis_1 | 1:M 24 Jul 2019 17:40:36.086 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.
redis_1 | 1:M 24 Jul 2019 17:40:36.086 * Ready to accept connections
db_1 | 2019-07-24 17:40:36.072 UTC [1] LOG: listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"
db_1 | 2019-07-24 17:40:36.086 UTC [18] LOG: database system was shut down at 2019-07-24 17:39:28 UTC
db_1 | 2019-07-24 17:40:36.090 UTC [1] LOG: database system is ready to accept connections
web_1 | Performing system checks...
web_1 |
web_1 | System check identified no issues (0 silenced).
web_1 | July 24, 2019 - 17:40:38
web_1 | Django version 2.1.7, using settings 'selfies.settings'
web_1 | Starting ASGI/Channels version 2.2.0 development server at http://0.0.0.0:8000/
web_1 | Quit the server with CONTROL-C.

5. start the docker container in the background

docker-compose up -d

This will run the container but in the background so you can continue to type in the terminal. I usually run it this way if I don't really need to see what the server is returning.

[13:31:03] (master) selfies
🙋 docker-compose up -d
Creating network "selfies_default" with the default driver
Creating selfies_db_1 ... done
Creating selfies_redis_1 ... done
Creating selfies_web_1 ... done

6. see all of the docker containers currently running

List of active docker containers which is useful for the CONTAINER ID and to know what you have running.

docker ps

[13:31:10] (master) selfies
🙋 docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a2b93a900c36 selfies_web "python manage.py ru…" 2 seconds ago Up 1 second 0.0.0.0:8000->8000/tcp selfies_web_1
2d39a1161aa2 postgres:10.1-alpine "docker-entrypoint.s…" 4 seconds ago Up 2 seconds 0.0.0.0:5432->5432/tcp selfies_db_1
62a6f364860e redis:latest "docker-entrypoint.s…" 4 seconds ago Up 2 seconds 6379/tcp selfies_redis_1

7. remove all docker containers in the repository

docker-compose down

I almost always follow this command with docker ps to make sure the containers were successfully removed, out of habit.

[13:37:20] (master) selfies
🙋 docker-compose down
Stopping selfies_web_1 ... done
Stopping selfies_db_1 ... done
Stopping selfies_redis_1 ... done
Removing selfies_web_1 ... done
Removing selfies_db_1 ... done
Removing selfies_redis_1 ... done
Removing network selfies_default

8. remove a specific docker container

docker kill :container_id

The container id is the leftmost column when doing docker ps. I sometimes do this if I need to remove a specific container that I'm not using.

[13:51:43] (master) selfies
🙋 docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
274b1605ca94 selfies_web "python manage.py ru…" 11 minutes ago Up 1 second 0.0.0.0:8000->8000/tcp selfies_web_1
a641f449edfc postgres:10.1-alpine "docker-entrypoint.s…" 11 minutes ago Up 2 seconds 0.0.0.0:5432->5432/tcp selfies_db_1
61b08693e242 redis:latest "docker-entrypoint.s…" 11 minutes ago Up 2 seconds 6379/tcp selfies_redis_1
[13:51:44] (master) selfies
🙋 docker kill 274b1605ca94
274b1605ca94

9. view all of the docker images

You can see all your builds by running this. For me these are either official "images" like redis or python or old builds of my projects. I only occasionally use this, it's not really a part of my daily development.

docker images

[18:28:17] (master) selfies
// ♥ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
selfies_web latest 4869d063569e 7 days ago 1.32GB
python 3.6-stretch 9167692c277e 11 days ago 936MB
redis latest 598a6f110d01 12 days ago 118MB
<none> <none> 9c4676224e86 2 months ago 1e+03MB
<none> <none> 6c925f68c3a9 2 months ago 929MB
<none> <none> b44ef8ff52f4 2 months ago 929MB
<none> <none> 903b976cd478 2 months ago 1.47GB
<none> <none> f7009c6f0868 2 months ago 1.49GB
<none> <none> 52750c0c3926 2 months ago 1.48GB
<none> <none> 1c509a380925 2 months ago 1.44GB

10. clean out any images, builds, etc., that might be hanging

docker system prune

I only occasionally use this, it's not really a part of my daily development.

[18:18:35] (master) selfies
// ♥ docker system prune
WARNING! This will remove:
- all stopped containers
- all networks not used by at least one container
- all dangling images
- all build cache
Are you sure you want to continue? [y/N] y
Deleted Containers:
1f570bbf6828dadfdaa97655165943fd0b93ce6c185df2531f61a82982ec24f2
40f79091bc943c86f5f3ab7bc9d484ac9b576effc686a8a0fdb0031a465b16b4
f3399b0cd4f8c30159b15e1a2027aadeeaf9006efa4b759e4e3586d4589a0004
e0d18cddd40241de3d3b03d695afe667819c884a12fd36465c4c6d584df5aaa6
b7757cef15b49ecfe58ac6a8de3f8fcae91c71d793b7942955ccaf7c266bff92
a8fc94cd1af14f27b0ae22c1728b33fc8cef4090aa7deef1c2549c33755ed114
4de12efd1f88b9ee3541049c9b6fb3df5b1ade3b5787f888f5cf05f2e02c3cec
21d97261412949c06a4fcfb9846a6dee22f92e6a928cd6fb715ee81924917d43
073ca414e8c79e593c82f46f565adbae92a159994699dbbd0fb9df8044b3b1bb
b62f36a4a182479d25c2251e8d90fb7d2b612f31a03e943e83882ab436981879
456510a02d7ad5137dcb907484b2c8d9e07f51946be1103d294e4e253bc0e664
effee0d0a9afa74825f8f820bd363ebe1b7b54948aed38d57e84342482c367fd
5d930ece03ed8a2c2cb9178b81c9b42ef4c7397ef90d29b040ed3b1220f8ba27
a6ccf4f68831a19ab7381354f5643f3afd94cfbe0d066ff9ce4b248b90139a63
1a65f709f9b9c7d9749a04e88d3c4d18539a495160e143337c25025b10f9b24c
e98fbb022cb920dd4550751fdb735c1f73ae1dd6a049b9855bd77db1a2cbb3d1
18cb48bcb6428d4a9d5ca2f4b9c0a2fbedb3ef98c1d1fe6788029d7abea8efe9
97d0ee4625df7d107bc543318b1b45701f17720c41c7bb9614183e2cca0e26c7
5fafd4e2df31a0b84657ce1a0450c9cc8d8caa56ede9b10cddbfa6b6f55f6b50
212dae9eab339a84817b590cceb345d66290fa7f0fd7e347bffda322eb60400e
14cdd7e40ca412e1b091ddf640513ecf3f5f8bfd51cbc826e59b4901b1a0e213
ceeeb46b3aa52660a7080949543654e6436b0c050c865ef6cbed83f43bba8cc3
6c96d28cffed031a8bdd836670401b74eb52fa8f03c1dca83b73b8d0ba8530ec
9c89d36c6ee1f8fbc9d0c542d14d6d5b924817abf47a656941062eed95e607f6
58d212388ac7f15468306e306977661169e8aacdeeaba2fea4fc9cf7ebbb9e46
71963edbfe38d4578ba1338a0d03ed94f81664b202f969acf72d38ceeded5fed
4838aa870e8962e6a1c8c0e679dad8d25f5ad08824bfd45df150d148ae7097ba
abab59a1cd1fcf0a14e1d8f45d03f1787b218233a118af59f604ad890cc64dc1
5375b62e20d2660f8347f5f7355122f9fb528a1b603b1e58ceb7d7b811740410
29d7238e6d81f522f8c98b4d2e478bb304aec7a00892b8339bf1b4a0483e7040

Deleted Networks:
selfiesh_default

Originally published by Lina Rudashevski at dev.to

========================================

Thanks for reading :heart: If you liked this post, share it with all of your programming buddies! Follow me on Facebook | Twitter

Learn More

☞ Docker Mastery: The Complete Toolset From a Docker Captain

☞ Docker and Kubernetes: The Complete Guide

☞ Docker for the Absolute Beginner - Hands On - DevOps

☞ Docker Crash Course for busy DevOps and Developers

☞ The Docker for DevOps course: From development to production

☞ Docker for Node.js Projects From a Docker Captain

☞ Docker Certified Associate 2019

☞ Selenium WebDriver with Docker