In the previous blog: Docker – Deep Dive, we created a Dockerfile with a set of instructions, started a service and create a container. Actual Projects are usually much more complex and require more than one services at a time running on multiple containers. Docker Compose handles exactly this.
Docker Compose is a tool to configure and run multiple containers that are inter dependent. It uses a YAML file to configure all the services and you can start/stop all of them with these commands:
Start services: docker-compose -f <filename.yaml> up
Stop services: docker-compose -f <filename.yaml> down
Django Application on Docker
As an example I am trying to run on docker, my Twitter Clone App that is built with Django and uses MySQL as the database: https://github.com/shilpavijay/TwitterClone
We will need a Dockerfile and docker-compose.yml file in the project directory.
Dockerfile:
FROM python:3.7-alpine RUN apk update && apk add bash RUN apk add gcc libc-dev linux-headers mariadb-dev RUN pip install django djangorestframework django-rest-swagger PyJWT==1.7.1 gunicorn mysqlclient COPY TwitterClone /app/TwitterClone COPY TUsers /app/TUsers COPY Tweets /app/Tweets COPY manage.py /app WORKDIR /app EXPOSE 8000 CMD ["gunicorn","TwitterClone.wsgi","--bind=0.0.0.0:8000"]
- In the above file, we are using a pre-built light weight image called alpine for python.
- It then install all the required packages. Not specifying the version of the package will install the latest available version.
- Next, all the project files and directories are copied to /app folder on the created container.
- The current directory is changed to /app.
- We also expose the port on which the application will run.
- The last command will start the application.
docker-compose.yaml
version: '3.4'
services:
db:
image: mysql:5.7
ports:
- '3306:3306'
container_name: twitter_db
command: --default-authentication-plugin=mysql_native_password
restart: always
environment:
MYSQL_DATABASE: 'twitterclone'
MYSQL_USER: 'root'
MYSQL_PASSWORD: 'guessme'
MYSQL_ROOT_PASSWORD: 'guessme'
twitterapp:
container_name: twitterclone
build:
context: ./
dockerfile: Dockerfile
restart: always
ports:
- '8080:8000'
volumes:
- .:/code
depends_on:
- db
- We have two services, one is the Django App (twitterapp) and the other is the MySQL DB (db). Ensure the names are always in lowercase.
- The app will be built with the instructions in the Dockerfile.
- MySQL container will be based on the mysql image available on docker hub. (refer previous blogpost)
- The “depends_on” clause tells that the application has a dependency on the database.
- MySQL service takes a while to start. There is usually a lag between the app start and database start time. To ensure a services does not fail if the other has not started yet, “restart: always” is configured.
- Port forwarding is configured in the “ports:” clause. The host port 8080 is mapped to the container post 8000 on which the application is running. Hence, to access the application from the host system, we will be using port 8080.
- We will discuss “volumes” in the subsequent section
Next, update settings.py in the Django Project with the host, port, login details to match that given in the Docker Compose file:
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'twitterclone', 'USER': 'root', 'PASSWORD': 'guessme', 'HOST': 'db', 'PORT': '3306', }, }
Then run, docker-compose -f <filename.yaml> up
When running the application for the first time OR if there are any changes to Django migrations, we need to run this explicitly in order to apply the migrations.
docker exec -it <container-id> python manage.py migrate
Then, execute the following commands to build and run the docker container:
docker-compose up --build
We are Done!!! The application should now be running on localhost:8080.
NOTE: Port already in use error:
If you have a DB running on your local on port 3306, do not forget to stop the service from Windows Services and then try running the docker-compose command. If you have a django app running on one of the ports specified in the docker composer file, you can either change the port number or close the running application
The complete code is here: https://github.com/shilpavijay/TwitterClone
Docker Volumes
Docker volumes are used for data persistence. When a container is stopped and re-run, the database starts all over again and the data stored previously is lost. To make it available even after the container is re-run, Docker volumes are made use of.
Here’s how it works. A directory from the host file system is mapped to a directory of the container file system. So, each time a container is started, the data is replicated into the host directory and when the container is restarted, it gets the data automatically from the directory in the host system.
Docker volumes can be created using the ‘docker run’ command. It can also be configured in the Docker Compose file.
There are 3 different types of docker volumes:
- Host volume: User specifies the host directory where the data is to be replicated.
docker run -v /home/user/dockerdata:/var/lib/mysql/data
- Anonymous volume: User does not specify the host directory. It is automatically taken care of, by docker. Only the directory on the container is specified.
docker run -v /var/lib/mysql/data
- Named volume: User specifies a name but not the path. Path is handled by docker. You can reference the volume by the given name This type is most frequently used.
docker run -v name:/var/lib/mysql/data
Conclusion
In this blogpost series, we have leant the basics required to understand and use Docker. We have seen the Evolution of Docker, the need for docker and also how to setup and run an application on docker. We leant about Docker Compose and Docker Volumes too, in this post. Here are the links to previous posts:
Github link to the project discussed in this blog: https://github.com/shilpavijay/TwitterClone
You can also refer the official documentation page for more information and updates: https://docs.docker.com/get-started/