Skip to content

Instantly share code, notes, and snippets.

@arsho
Last active October 16, 2021 23:20
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save arsho/6249e3f0fc1d966d115c34718e1a8a0a to your computer and use it in GitHub Desktop.
Save arsho/6249e3f0fc1d966d115c34718e1a8a0a to your computer and use it in GitHub Desktop.
Step by step installation procedure of Docker in a ubuntu machine. Run Django, Flask, PHP using Docker and Docker compose

Docker

Build image
docker build -t CONTAINER_NAME .
Run container
docker run CONTAINER_NAME -p 3013:3000

Docker Compose

Build services
docker-compose build
Up services
docker-compose up
Up services in daemon mode
docker-compose up -d
Start services
docker-compose start
Stop services
docker-compose stop
Delete every services
docker-compose down

docker-compose.yml

version: '3'

services:
  web:
    build:
      context: .
      dockerfile: Dockerfile
      args:
        migration_flag: 15
    container_name: web_container

Dockerfile

FROM python:3
ENV PYTHONBUFFERED 1
ARG migration_flag
RUN if [ "$migration_flag" -ne 1 ] ; then echo "migration flag is not 1"; fi

Install DOCKER COMPOSE in Ubuntu 16.04

What is Docker Compose?

Compose is a tool for defining and running complex applications with Docker. With Compose, you define a multi-container application in a single file, then spin your application up in a single command which does everything that needs to be done to get it running.

Compose uses a YAML file to configure application's services. Then, with a single command, all the services can be started or stopped from the configuration. Some reasons you might want to use Compose :

  • Multiple isolated environments on a single host
  • Preserve volume data when containers are created
  • Only recreate containers that have changed
  • Variables and moving a composition between environments

Compose works in all environments: production, staging, development, testing as well as CI workflows.

Using Compose is basically a three-step process:

  • Define your app's environment with a Dockerfile so it can be reproduced anywhere.
  • Define the services that make up your app in docker-compose.yml so they can be run together in an isolated environment.
  • Run docker-compose up and Compose will start and run the entire app.

A docker-compose.yml looks like this:

version: '3'
services:
	web:
		build: .
		ports:
		- "5000:5000"
		volumes:
		- .:/code
		- logvolume01:/var/log
		links:
		- redis
	redis:
		image: redis
volumes:
	logvolume01: {}

Environment

  • Operating System : Ubuntu 16.04 LTS (64-bit)

Install Docker Compose in Ubuntu 16.04

Docker Compose relies on Docker Engine. So make sure you have installed Docker Engine before installing Docker Composer. Instructions on installing Docker Engine can be found in: https://gist.github.com/arsho/6249e3f0fc1d966d115c34718e1a8a0a#file-docker_installation_ubuntu_16-04-md

The following steps showed the step by step installation guideline.

Download Latest Version of Docker Compose

Ensure that you have installed curl before running the following command.

sudo curl -L https://github.com/docker/compose/releases/download/1.18.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose

Apply Executable Permissions to the Binary

sudo chmod +x /usr/local/bin/docker-compose

Apply Executable Permissions to the Binary

sudo chmod +x /usr/local/bin/docker-compose

Test the Installation

docker-compose --version

It will output like below:

docker-compose version 1.18.0, build 8dd22a9

References

Run Django (Django REST Framework) & MySQL Application using Docker (Bonus: PHPMyAdmin)

Prerequisite

  • Ensure that you already installed Docker in your machine. To learn more about installation: follow this gist
  • Ensure that you already installed Docker Compose in your machine. To learn more about installation: follow this gist

Environment

  • Operating System : Ubuntu 16.04 LTS (64-bit)

Running Django app with MySQL database inside Docker

The following steps showed the step by step guideline.

Create Project Directory

For separating the application from other projects let's first create a directory and move to that:

mkdir django_mysql
cd django_mysql

Create Dockerfile

Create a Dockerfile inside the project directory and insert the following:

FROM python:3
ENV PYTHONBUFFERED 1
RUN mkdir /code
WORKDIR /code
ADD requirements.txt /code/
RUN pip install -r requirements.txt
ADD . /code/

Create requirements.txt

Create a requirements.txt file inside the project directory and insert the following:

certifi==2017.11.5
chardet==3.0.4
click==6.7
coverage==4.4.2
decorator==4.1.2
Django==2.0
django-ckeditor==5.4.0
django-constance==2.0.0
django-cors-headers==2.1.0
django-countries==5.0
django-js-asset==0.1.1
django-nose==1.4.5
django-picklefield==1.0.0
djangorestframework==3.7.6
geocoder==1.30.1
idna==2.6
mysqlclient==1.3.12
nose==1.3.7
olefile==0.44
Pillow==4.3.0
pytz==2017.3
ratelim==0.1.6
requests==2.18.4
six==1.11.0
urllib3==1.22
Markdown==2.6.11
pytz==2017.3

Create Docker Compose Configuration File

Create a docker-compose.yml inside the project directory and insert the following:

version: '3'

services:
  db:
    image: mysql
    ports:
      - "3307:3306"
    environment:
      MYSQL_ROOT_PASSWORD: mypassword
      MYSQL_USER: root
      MYSQL_DATABASE: django_mysql
  web:
    build: .
    command: python3 manage.py runserver 0.0.0.0:8000
    volumes:
      - .:/code
    ports:
      - "8000:8000"
    depends_on:
      - db
  phpmyadmin:
    image: phpmyadmin/phpmyadmin
    environment:
      - PMA_ARBITRARY=1
    restart: always
    ports:
      - 8082:80
    volumes:
      - /sessions

Build Docker Compose

In this step we are going to build docker compose:

sudo docker-compose build

The execution of the command will take some time based on internet connection speed. If you failed to build everything succesfully retry several times as network connection sometimes cause the error.

Check if the instances are running:

sudo docker-compose up

Press CTRL-C to stop the instances for now.

Create Django Project

To create django project inside the instance:

sudo docker-compose run web django-admin.py startproject composeexample .

In this stage we have the following directory tree:

django_mysql
├── composeexample
│   ├── __init__.py
│   ├── __pycache__
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── db.sqlite3
├── docker-compose.yml
├── Dockerfile
├── manage.py
├── requirements.txt

The files which are created by django-admin are owned by root. Change the ownership of the new files:

sudo chown -R $USER:$USER .

To use Django REST Framwork to create APIs and MySQL as database, we need to change composeexample\settings.py to include:

ALLOWED_HOSTS = ['*']

DJANGO_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

NATIVE_APPS = [
    'ridecoupon',
]

THIRD_PARTY_APPS = [
    'rest_framework',
]

INSTALLED_APPS = DJANGO_APPS + NATIVE_APPS + THIRD_PARTY_APPS

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'django_mysql',
        'USER': 'root',
        'PASSWORD': 'mypassword',
        'HOST': 'db',
        'PORT': '3306',
    },
}

STATIC_URL = '/static/'

STATIC_ROOT = './static'

MEDIA_URL = '/media/'

MEDIA_ROOT = './media'

The ridecoupon is the django app we are going to create.

We also need to update composeexample\urls.py file to add our ridecoupon app:

from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
    path('admin/', admin.site.urls),
    path('ridecoupons/', include('ridecoupon.urls'))
]

if settings.DEBUG:
    urlpatterns = urlpatterns + \
                  static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) + \
                  static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

Run the Instance in Daemon Mode

Run the instance in background using:

sudo docker-compose up -d

Check running processes using:

sudo docker ps

Create New App inside the django project

To run manage.py we need to get logged into the container containing the django app. For this we need to know the container ID of that container. To get the container ID, check the running docker processes using:

sudo docker ps

This will show the container ID of all the containers. We need the container ID that has the django app.

Then, use the container ID to open a bash in that directory of manage.py:

sudo docker exec -t -i 8f88e0935895 bash

Here 8f88e0935895 is container ID of my container. It will be different for your case.

  1. Create an app:
python manage.py startapp ridecoupon
  1. Create models.py, urls.py and other necessary files in ridecoupon. Then makemigrations of newly created model and migrate it:
python manage.py makemigrations ridecoupon
python manage.py migrate
  1. Create super user:
python manage.py createsuperuser
Username: 
Email address:
Password: 
  1. Run the project:
python manage.py runserver

sudo docker-compose build sudo docker-compose up -d sudo docker ps CONTAINER ID IMAGE 8f88e0935895 djangomysql_web sudo docker exec -t -i 8f88e0935895 bash python manage.py makemigrations ridecoupon python manage.py migrate python manage.py createsuperuser

Access the web app

Open http://0.0.0.0:8000/ and see the running web application

(Bonus) Access the phpmyadmin

Open http://0.0.0.0:8082/ and see the running PHPMyAdmin. Use

User: root
Password: mypassword

and keep the host empty.

Referencese

Run Flask Application using Docker

Folder structure:

.
├── backend.py
├── Dockerfile
├── readme.md
└── requirements.txt

requirements.txt:

Flask==1.0.2
Flask-Cors==3.0.7

Dockerfile:

FROM python:3
ENV PYTHONBUFFERED 1
RUN mkdir /code
WORKDIR /code
ADD requirements.txt /code/
RUN pip install -r requirements.txt
ADD . /code/
CMD ["python", "backend.py" ]

Build Docker file:

docker build -t flask-docker .

Run Docker:

docker run -p 5000:5000 flask-docker

* Serving Flask app "backend" (lazy loading)
* Environment: production
  WARNING: Do not use the development server in a production environment.
  Use a production WSGI server instead.
* Debug mode: off
* Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)

Get Docker container ID:

docker ps

CONTAINER ID        IMAGE                   COMMAND                CREATED             STATUS              PORTS                    NAMES
69cb7d5d243a        flask-docker            "python backend.py"    15 minutes ago      Up 15 minutes       0.0.0.0:5000->5000/tcp

Get Docker container IP address:

docker inspect --format '{{ .NetworkSettings.IPAddress }}' 69cb7d5d243a  

172.17.0.2

Use this IP address in AJAX request in HTML file:

<html>
<head>
  <title>Frontend</title>
</head>
<body>
  <div id="data"></div>
  <button type="button" id="btn">Grab data</button>
  <script type="text/javascript">
  document.getElementById("btn").addEventListener('click', add);
  function add()
  {
    const api_url = "http://172.17.0.2:5000/test";
    var xhttp = new XMLHttpRequest();
    xhttp.onreadystatechange = function() {
      if (this.readyState == 4 && this.status == 200) {
        document.getElementById("data").append(this.responseText);
      }
    };
    xhttp.open("GET", api_url, true);
    xhttp.send();
  }
  </script>
</body>
</html>  

backend.py:

from flask import Flask, request, jsonify
from flask_cors import CORS


app = Flask(__name__)
CORS(app)    

@app.route("/test")
def test():
    return "It's working"    

if __name__ == "__main__":
    app.run(host='0.0.0.0', port=5000)

Output:

frontend output

Install DOCKER CE in Ubuntu 16.04

Why Docker?

Docker is a tool for running application in an isolated environment.

Some reasons you might want to use Docker:

  • Same environment: Same environment in developers machines and production servers. Acts the same.
  • Sandbox projects: Eliminates the risk of getting conflicts while working on different projects on same machine.
  • Easy working without setup hussle: Start working directly on others projects without setting all of the environemts.

Container, Image, Dockerfile:

Container is a running instance of an image. An image is a template for creating the environment you want to snapshot out of a system at a particular time. An image includes:

  • Operating system
  • Software
  • Application Code

Images are defined by a Dockerfile. Dockerfile is a text file with the steps to perform to create that image. It includes the following ordered instructions

  • Configure the operating system
  • Install the necessary software
  • Copy the project file in right places

Building the Dockerfile will create the image which is run in the container.

Environment

  • Operating System : Ubuntu 16.04 LTS (64-bit)

Docker Installation Procedure in Ubuntu 16.04

The following steps showed the step by step installation guideline. This instructions shows the way of installing Docker using the Docker repository.

Set up the repository

  1. Update the apt package index:
sudo apt-get update
  1. Install packages to allow apt to use a repository over HTTPS:
sudo apt-get install apt-transport-https ca-certificates curl software-properties-common
  1. Add Docker's official GPG key: GPG is the GNU PGP encryption program. PGP is an identification key system people use to sign files or emails so the receiver can check the authencity of them.
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

Verify that you have the key with the fingerprint 9DC8 5822 9FC7 DD38 854A E2D8 8D81 803C 0EBF CD88 by searching for the last 8 characters of the fingerprint

sudo apt-key fingerprint 0EBFCD88

It should some information about the key file:

pub   4096R/0EBFCD88 2017-02-22
      Key fingerprint = 9DC8 5822 9FC7 DD38 854A  E2D8 8D81 803C 0EBF CD88
uid                  Docker Release (CE deb) <docker@docker.com>
sub   4096R/F273FCD8 2017-02-22
  1. Set up the stable repository.
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

Install Docker Community Edition (CE)

  1. Update the apt package index:
sudo apt-get update
  1. Install the latest version of Docker CE:
sudo apt-get install docker-ce
  1. Verify that Docker CE is installed correctly by running the hello-world image:
sudo docker run hello-world

It downloads a atest image and runs it in a container. When the container runs, it prints informational messages and exits.

Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
ca4f61b1923c: Pull complete 
Digest: sha256:66ef312bbac49c39a89aa9bcc3cb4f3c9e7de3788c944158df3ee0176d32b751
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://cloud.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/engine/userguide/

Post-installation steps for Linux

This section contains optional procedures for configuring Linux hosts to work better with Docker.

Manage Docker as a non-root user

The docker daemon binds to a Unix socket instead of a TCP port. By default that Unix socket is owned by the user root and other users can only access it using sudo. The docker daemon always runs as the root user.

If you don’t want to use sudo when you use the docker command, create a Unix group called docker and add users to it. When the docker daemon starts, it makes the ownership of the Unix socket read/writable by the docker group.

Warning: The docker group grants privileges equivalent to the root user. Create the docker group:

sudo groupadd docker

Add your user to the docker group:

sudo usermod -aG docker $USER

Log out and log back in so that your group membership is re-evaluated.

Verify that you can run docker commands without sudo.

docker run hello-world

This command downloads a test image and runs it in a container. When the container runs, it prints an informational message and exits.

If you get container name conflict

Remove previous container using that name, with the command

docker rm $(docker ps -aq --filter name=CONTAINER_NAME)

References

*. Post installation instructions

Run PHP Application using Docker in Ubuntu 16.04

Prerequisite

To run PHP application ensure that you already installed Docker in your machine. To learn more about installation: follow this gist

Environment

  • Operating System : Ubuntu 16.04 LTS (64-bit)

Running PHP Hello World Application inside Docker

The following steps showed the step by step docker setup guideline for PHP application.

Create the Dockerfile and src folder

  1. For separating the application from other projects let's first create a directory and move to that:
mkdir test_docker_php
cd test_docker_php
  1. In this newly created test_docker_php directory create a file name Dockerfile and a src folder to keep the source code. To make this tutorial simple let's keep only a file called index.php inside the src directory. The directory structure will look like this:
test_docker_php
├── Dockerfile
└── src
    └── index.php

Dockerfile will download the official PHP image, copy the source code to a specific folder and expose port 80 of the container:

FROM php:7.0-apache
COPY src/ /var/www/html
EXPOSE 80

index.php may contain some echo command like:

<?php
	echo "If you can see this message it ensures that Docker container is running successfully";
?>

Build Docker image

In this step we are going to build an image from the above Dockerfile and give it a name, let's say test_docker_php:

sudo docker build -t test_docker_php .

The last . tells that Dockerfile is in the current directory. The execution of the command will take some time based on internet connection speed.

Run Docker image

Let's run this Docker image by providing the port number and path of src directory (absolute path) to reflect dynamic changes in source. To get the present working directory's absolute path:

pwd

For my case it is: /home/..../test_docker_php/ [hide the unnecessary part from here with ....]

Now we can run the image test_docker_php with this absolute path of src folder:

sudo docker run -p 80:80 -v /home/..../test_docker_php/src:/var/www/html test_docker_php

After running the image the executed application can be seen at localhost in web browser.

If you modify the content of index.php just reload the page in the browser and it will be updated instantly.

Run Static Web Application using Docker in Ubuntu 16.04

Prerequisite

To run static web application application ensure that you already installed Docker in your machine. To learn more about installation: follow this gist

Environment

  • Operating System : Ubuntu 16.04 LTS (64-bit)

Running static web application inside Docker

The following steps showed the step by step docker setup guideline for PHP application.

Create the Dockerfile and src folder

  1. For separating the application from other projects let's first create a directory and move to that:
mkdir test_docker_static
cd test_docker_static
  1. In this newly created test_docker_static directory create a file name Dockerfile and a src folder to keep the source code. To make this tutorial simple let's keep only a file called index.html inside the src directory. The directory structure will look like this:
test_docker_static
├── Dockerfile
└── src
    └── index.html

Dockerfile will download the official nginx image, copy the source code to a specific folder and expose port 80 of the container:

FROM nginx:stable
COPY src/ /usr/share/nginx/html
EXPOSE 80

index.html may contain some echo command like:

<html>
  <head>
    <title>Docker static site</title>
  </head>
  <body>
    <h3>Hello from static site (updated again)</h3>
  </body>
</html>

Build Docker image

In this step we are going to build an image from the above Dockerfile and give it a name, let's say test_docker_static:

sudo docker build -t test_docker_static .

The last . tells that Dockerfile is in the current directory. The execution of the command will take some time based on internet connection speed.

Run Docker image

Let's run this Docker image by providing the port number and path of src directory (absolute path) to reflect dynamic changes in source. To get the present working directory's absolute path:

pwd

For my case it is: /home/..../test_docker_static/ [hide the unnecessary part from here with ....]

Now we can run the image test_docker_static with this absolute path of src folder:

sudo docker run -p 80:80 -v /home/..../test_docker_static/src:/usr/share/nginx/html test_docker_static

After running the image the executed application can be seen at localhost in web browser.

If you modify the content of index.html just reload the page in the browser and it will be updated instantly.

@mchesler613
Copy link

Thanks for this wonderful tutorial. When I tried to execute the python manage.py startapp ridecoupon in the django bash, it has errors:

ModuleNotFoundError: No module named 'ridecoupon'

Am I supposed to add this to docker-compose.yml ?

The traceback is as follows:

python manage.py startapp ridecoupon
Traceback (most recent call last):
  File "/code/manage.py", line 15, in <module>
    execute_from_command_line(sys.argv)
  File "/usr/local/lib/python3.9/site-packages/django/core/management/__init__.py", line 371, in execute_from_command_line
    utility.execute()
  File "/usr/local/lib/python3.9/site-packages/django/core/management/__init__.py", line 347, in execute
    django.setup()
  File "/usr/local/lib/python3.9/site-packages/django/__init__.py", line 24, in setup
    apps.populate(settings.INSTALLED_APPS)
  File "/usr/local/lib/python3.9/site-packages/django/apps/registry.py", line 89, in populate
    app_config = AppConfig.create(entry)
  File "/usr/local/lib/python3.9/site-packages/django/apps/config.py", line 90, in create
    module = import_module(entry)
  File "/usr/local/lib/python3.9/importlib/__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1030, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1007, in _find_and_load
  File "<frozen importlib._bootstrap>", line 984, in _find_and_load_unlocked
ModuleNotFoundError: No module named 'ridecoupon'

Thanks again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment