Click here to Skip to main content
16,016,345 members
Articles / Containers / Docker

Dockerize A Simple Web-Application Created By Using Python, Flask and PostgreSQL

Rate me:
Please Sign up or sign in to vote.
5.00/5 (11 votes)
24 Aug 2018CPOL13 min read 22.2K   171   11   1
Create a Python web-app using Flask and PostgreSQL server, and run it in Docker
In this article, we will demonstrate how to create a Python web-application using Flask and PostgreSQL server, and run it in Docker virtualization platform environment

Note: You can evaluate the ready-to-use web-application being discussed in this article by visiting http://ec2-18-191-184-232.us-east-2.compute.amazonaws.com/.

Introduction

In this article, we will demonstrate how using Docker will help us to create and deploy a simple web application, using Python programming language and Flask development framework. The application we’re about to discuss in this article, performs a simple visualization of data, stored in PostgreSQL server database. In particular, as an example, we will create an application designed to perform an indexed search of persons and their phone numbers specific data, by a partial match, stored in the phonebook database. To create the following application, we will use Microsoft Visual Studio 2017 Python development tools. Later on, we will “dockerize” the following web application by running it in the Docker’s virtual environment.

Image 1

Throughout, in this article, we will provide the useful guidelines to setup and configure the Docker’s virtualization platform, and, then, use it to deploy various business-critical applications, providing services for the large number of customers over the Web. In particular, the audience of this article’s readers will find out, specifically, how to deploy an existing web application being created, running it in the Docker’s virtualization platform environment.

What’s Docker…

Docker is a SaaS-oriented operation-system-level virtualization platform, that allows to quickly and easily create and deploy various business web applications without either a deep expertise and knowledge of the virtualization technology (VT), or a large cloud services (CS) deployment experience. According to its architecture, Docker’s virtualization platform allows to deploy and use various applications as separate ‘containers’ running under a single MobyLinuxVM virtual machine instance, inside the Microsoft Hyper-V hardware virtualization platform:

Image 2

The main idea of using containers (e.g., ‘containerization’) is that each service or application deployed in Docker’s virtual environment is running isolated, in its own container.

A ‘container’ is actually a minimalistic virtual machine hosting Windows or Linux operating system, normally used to deploy a particular application or network service, such as HTTP-, FTP-, NTP-, DNS-, database and others. In turn, Docker’s infrastructure provides repositories for creating containers running a specific service or application, from templates, making it possible to deploy those services and applications faster and easily. The using of container templates ensures that we’re deploying a virtual machine host already running a particular application or service without spending time for accomplishing infrastructure-specific maintenance tasks, such as installing host’s operating system, setting up and configuring an application or service daemons, creating virtual networks, monitoring performance, etc. This makes it easy and convenient to deploy various basic and even more advanced services and applications from ‘scratch’.

As we’ve already discussed, by using Docker’s virtualization platform, unlike the other IaaS-based cloud services and platforms such as Amazon EC2, Microsoft Azure, or OpenStack, the developers might no longer take care of accomplishing IaaS-specific application maintenance tasks. In the other words, the entire infrastructure-specific configuration process is very simple, since it’s wrapped up by the Docker’s virtualization platform. Specifically, each container within Docker’s environment is connected to a single network, providing the communication between the containers hosted and running in Docker’s environment. For example, a business application written in Python and running in its own container can access the data in PostgreSQL server database instance, running in the other container, over the Docker’s pre-configured virtual network. Also, while creating Docker’s containers, we no longer need to perform the initial configuration of each container, such as setting up the amounts of virtual system memory used by a virtual machine being created, the number of CPUs, virtual network adapters configuration, etc.

Specifically, in this article, we will learn how to:

  • install and configure Docker’s virtualization platform on a host machine
  • migrate the existing Python web application, introduced in this article, to Docker virtualization environment by creating separate Docker container
  • deploy the other services such as PostgreSQL server instance to Docker from the specific template
  • build the web application created and run it detached, as the Docker’s background service

Finally, we will learn how to deploy Docker virtualization platform environment, hosted by Amazon Linux AMI virtual machine instance, in the Amazon EC2 cloud, to provide a public access to the web application created.

Background

In this section, we will thoroughly discuss the process of dockerizing the indexed search web-application, introduced in this article.

Installing and Configuring Docker Virtualization Platform

The first thing that we have to do, before we deploy web-application to Docker, is to install and configure Docker virtualization platform. In this article, we will harness the capabilities of Amazon EC2 cloud services to install and run Docker hosted by Amazon Linux AMI virtual machine instance.

For that purpose, we must create an Amazon EC2 account and log in to create an instance of Amazon Linux AMI virtual machine, as it’s shown in the figures below:

Image 3

Image 4

During these steps, we must create Amazon EC2 account, log into the AWS Management Console and launch the Amazon Linux AMI instance. To create an instance of Amazon Linux AMI, we must make sure that we pass the following steps:

Step 1: Choosing Amazon Virtual Machine Image

Image 5

Step 2: Choosing an Instance Type and Launch an Instance

Image 6

Image 7

Step 3: Creating an RSA-Key Pair to Establish a Secure SSH-Connection to the Running Instance

Image 8

Image 9

Step 3: Launch Amazon Linux Configured Instance

Image 10

Image 11

Step 4: Configuring the Running Amazon Linux Instance Security Group

To make sure that our web application being deployed accepts traffic by listening on a specific TCP-port, we must properly configure the security group by adding the specific inbound rule (e.g., HTTP-80 port) to the following security group as it's shown in the figures below:

Image 12

Image 13

Image 14

Image 15

Image 16

Step 5: Connecting to the Running Amazon Linux Instance using PuTTY Terminal App

As you can see in the figure shown above, the running instance of Amazon Linux AMI was successfully created and Public DNS (IPv4) hostname has been generated. Later, we will use this hostname to connect to the running instance's SSH-console by using PuTTY terminal application.

To do this, we have to download and install PuTTY and generate a specific *.ppk file from the key-pair *.pem file previously created during the instance configuration phase:

Image 17

For that purpose, we will use PuTTYGen utility as it's shown in the figure above:

Image 18

After we've created and save a new key-pair *.ppk file, let's now make our first connect to the running Amazon Linux instance console by using PuTTY terminal as it's shown below:

Image 19

Image 20

To connect to the running instance of Amazon Linux, we will use the following credentials, for example: hostname: ec2-18-191-184-232.us-east-2.compute.amazonaws.com, and *.ppk key-file previously generated:

Image 21

Step 6: Installing and Configuring Docker

Since we've already launched and configured Amazon Linux AMI virtual machine and connected to its SSH-console, the next step is to deploy Docker's virtualization platform to the running instance of Amazon Linux. To do this, we need to use the following commands in SSH-console.

Before we begin, let's make sure that we're logged onto the SSH-console as a super-user or root. To enable root account, we have to use the following commands such as sudo passwd root and enter a root password. After that, log in to the console as 'root' by entering the following short command: su.

To install Docker, we must enter the following sequence of commands:

[root@ip-172-31-20-4 ec2-user]# yum update -y

[root@ip-172-31-20-4 ec2-user]# yum install -y docker

The entire Docker installation process is illustrated in the figures below:

Image 22

Image 23

After we've successfully installed Docker, we need to make sure that it will be running as services after the next boot. For that purpose, we need to enter the following commands:

[root@ip-172-31-20-4 ec2-user]# chkconfig docker on

[root@ip-172-31-20-4 ec2-user]# service docker start

After that, we must reboot our instance of Amazon Linux AMI to make sure that Docker will run automatically at the next boot. To do this, just type in: shutdown -r now.

Finally, we must ensure that the Docker virtualization environment works as just fine. To do this, we must run a hello-world Docker application from the repository:

[root@ip-172-31-20-4 ec2-user]# docker run hello-world

Image 24

Step 7: Creating PostgreSQL Service Container

To deploy our web-application, the first thing that we must do is create a Docker container of pre-configured instance of PostgreSQL server from a template. To do this, we have to perform the following steps: create a container for PostgreSQL datastore by entering the following command:

docker create -v /var/lib/postgresql/data --name PostgresData alpine 

Next, we have to create a container of pre-configured PostgreSQL server:

docker run -d -p 5432:5432 --restart=always --name postgresql_ec2 
           -e POSTGRES_PASSWORD=12345 -d postgres

As an alternative, we can assign a static IP-address to the running PostgreSQL container by executing the following commands:

To create a custom Docker's virtual network, enter the following command:

docker network create --driver=bridge --subnet=178.17.0.0/24 
                      --gateway=178.17.0.1 postgresql_ec2_nw

To run the PostgreSQL container in the custom virtual network created, use the following command:

docker run -d -p 5432:5432 --name postgresql -it  --network=postgresql_ec2_nw 
--ip=178.17.0.2 --restart always --publish 5432:5432 
--volume /srv/docker/postgresql:/var/lib/postgresql \ 
--env 'PG_TRUST_LOCALNET=true'  --env 'PG_PASSWORD=12345' 
--env 'DB_USER=postgres' --env 'DB_PASS=12345' --env 'DB_NAME=phonebook' postgres

Image 25

Image 26

Finally, to make sure that the PostgreSQL container is running, let's enter the following command:

docker ps -a

Image 27

Step 8: Phonebook PostgreSQL Database Maintenance Steps

After we've successfully setup the PostgreSQL database server container, we must import a ready-to-use database to the PostgreSQL server. To do this, we must additionally install vsftpd ftp-server on the running instance of Amazon Linux. After we've installed the ftp-server, we must copy the files shown in the figure below to the /home/ec2-user directory of our Amazon Linux instance:

Image 28

After that, we must copy the phone_book.sql file to the PostgreSQL container. To do this, we have to use the following command:

docker cp ./phone_book.sql postgresql_ec2:/home/phone_book.sql

After we've successfully copied the following file to the PostgreSQL container, we must import the following dump to the database server and create the phonebook database with data. To do this, we must log into the container console by using the following command:

docker exec -it postgresql_ec2 /bin/bash

To import the existing database, we have to enter the following two commands:

psql -U postgres

, and then type in CREATE DATABASE phonebook; sql-statement, after which the new phonebook database is created.

psql -U postgres -f /home/phone_book.sql phonebook

After entering this command, the phone_book.sql dump file is successfully imported to the newly created phonebook database.

Image 29

Step 9: Building and Running Indexed Search Web Application

After we've successfully maintained the PostgreSQL database server and imported the phonebook database with data, now, let's build and deploy our indexed search web-application. First, what we have to do is create an appropriate Docker file as follows:

FROM python:3

WORKDIR /eg_phonebook

ADD . /eg_phonebook

RUN pip install --trusted-host pypi.python.org -r requirements.txt 
RUN pip install pystrich psycopg2-binary requests

EXPOSE 80

CMD [ "python", "./eg_phonebook.py" ]

In this file, we must specify the repository (e.g., FROM python:3) from which we will be downloading and importing python-packages. Also, we must provide a working dir of our application (e.g., WORKDIR /eg_phonebook) and python main application's filename (ADD . /eg_phonebook). Also, we will be using the RUN wrapper command to execute Python's pip utility that allows us to download and install additional Python-modules:

RUN pip install --trusted-host pypi.python.org -r requirements.txt

RUN pip install pystrich psycopg2-binary requests

Finally, we must provide a TCP-port on which the eg_phonebook app will be listening on. At the bottom of the Docker file, we must execute CMD command that is used to build our Python web-application by building a specific main application's file (e.g., CMD [ "python", "./eg_phonebook.py" ]).

Finally, after the Docker file has been created, we must enter the following commands to build our eg_phonebook web-application:

docker build -t eg_phonebook .

To run the application, we will use the following command:

docker run -d -p 80:80 --restart=always eg_phonebook

After executing this command, the following web-application will run as service at the background and listen on TCP-port 80.

Optionally, we can stop and remove the running containers by using these commands:

docker stop <container-id>

docker rm <container-id>

To verify if the applications works as just fine, let's go to the web-browser and enter the following URL-address:

http://ec2-18-191-184-232.us-east-2.compute.amazonaws.com:80/

Image 30

As you can see in the figure above, the following web application has started and is ready to work.

Using the Code

As an example of the web-application deployed to be run in Docker virtualization environment, we've created an application that performs an indexed search of persons and phone numbers data stored in PostgreSQL database, by a partial match. The following application is intended to visualize the search results organized into a table rendered in the web-application main page.

The application's main web-page HTML-document is listed below. The following HTML-document renders a table of persons and phone number that exactly or partially match the search pattern, and is constructed dynamically by the app's main Python-script. The following HTML-document contains the fragment of JavaScript code that performs HTTP Ajax-requests to the applications web-server and retrieves data on persons and phone numbers based on the query transaction to PostgreSQL server database, performed by the app's main Python-script. The response normally contains the data organized as HTML-table, that, further, is dynamically emplaced and rendered as a portion of application's main web-page. Specifically, in the fragment of JavaScript code, we define doSearch() method inside of which we're performing an Ajax-request by creating XMLHttpRequest() object and defining the callback function to handle onreadystatechange event, fired after the request is completed. Inside the following function, we're obtaining the response text of the Ajax-request, and performing the emplacing of the HTML-table returned by the app's Python-script, to the app's main web-page, after the request has been processed. To send an Ajax-request, we normally construct a URL-string that consists of the application web-server address and a sequence of URL-parameters, such as /search?text=query_string. Specifically query_string value is retrieved from the editable text field by using document.getElementById("query").value property. After the URL-string has been constructed, we're invoking XMLHttpRequest().open method and pass the string being constructed as one of the arguments of this method.

The doSearch method is normally invoked as the result of onload, onkeyup, onclick events being fired by HTML-document's user input controls. For example, if a user starts typing a query string, the onkeyup event is fired and handled by doSeach function, obtaining the string value from the editable text field, sending an Ajax-request to the web-application's main Python-script being executed.

index.html

HTML
<html>
 <head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <script type="text/javascript">
    function doSearch() { 
      var xhttp = new XMLHttpRequest(); 
      xhttp.onreadystatechange = function() { 
        if (this.readyState == 4 && this.status == 200) { 
           document.getElementById("result").innerHTML = xhttp.responseText; 
        } 
      };
     
      xhttp.open("GET", "/search?text=" + document.getElementById("query").value, true); 
      xhttp.send(); 
    } 
  </script>
 </head>
 <body onload="doSearch();">         
   <table border="0">
    <tbody>
     <tr><td align="center"><b>Docker's Indexed Search App v.1.00a</b></td></tr>
     <tr>
      <td>
       <table border="0">
        <tbody>
         <tr>
          <td>Search:</td>
          <td><input id="query" type="text" onkeyup="doSearch();" 
               onpaste="doSearch();"></td>
          <td><input type="submit" onclick="doSearch();"></td> 
         </tr>
        </tbody>
       </table> 
      </td>
     </tr>
     <tr><td><center><p id="result"></p></center></td></tr>
    </tbody>
   </table>
 </body>
</html>

The application's main Python-script is executed every time the HTTP Ajax-request is sent by the specific JavaScript code embedded to the app's main web-page HTTP-document. During the following Python-script execution, we're instantiating the Flask and Redis objects and dispatch the app.run(HOST, PORT) method to launch the web-application on the server-side. While executing the following script, we're perform routing based on HTTP-requests being sent. Specifically, when processing the default route, we're constructing the HTML-document shown above as a string buffer returned by main_empty function. Otherwise, for the /search?text=query_string route, we're establishing connection to PostgreSQL databaser server, constructing and executing the query's SQL-statement such as SELECT person_id, person_name, phone FROM public.persons WHERE \ person_name ILIKE '%""" + search_pattern + """%' OR phone ILIKE '%""" + search_pattern + """%', the execution of which results in obtaining a set of rows that exactly or partially match the given search pattern. If the value of text-parameter of URL-string is empty, then we're executing another SQL-statement, that returns the set of all rows in the persons table.

After we've executed the SQL-statement, we're obtaining the resultant set of rows and generate an HTML-table, each row of which contains data on each particular person and phone number matching the search pattern. The HTML-contents being generated and stored into a string buffer, that, further, will be returned as a response to an Ajax-request being processed.

eg_phonebook.py

Python
"""
This script runs the application using a development server.
It contains the definition of routes and views for the application.
"""

# Importing Flask from flask repository
from flask import Flask
# Importing redis from Redis and RedisError repositories
from redis import Redis, RedisError
# Importing HTTP-requests object from flask repository
from flask import request
# Importing os and socket objects from Python:3.0 repository
import os
import socket
# Importing PostgreSQL client adapter object from Python:3.0 repository
import psycopg2;

# Creating redis data store object
redis = Redis(host="redis", db=0, socket_connect_timeout=2, socket_timeout=2)
# Creating Flask web application framework object
app = Flask(__name__)

# Make the WSGI interface available at the top level so wfastcgi can get it.
wsgi_app = app.wsgi_app

# Performing default routing
@app.route('/')
def main_empty():
    # Returning string buffer containing the applications web-page being generated
    return "<html><head><script type=\"text/javascript\">function doSearch() \
    { var xhttp = new XMLHttpRequest(); xhttp.onreadystatechange = function() \
        { if (this.readyState == 4 && this.status == 200) \
        { document.getElementById(\"result\").innerHTML = xhttp.responseText; } }; \
        xhttp.open(\"GET\", \"/search?text=\" + 
        document.getElementById(\"query\").value, true); \
        xhttp.send(); } </script></head><body onload=\"doSearch();\"> \
        <table border=\"0\"><tr><td align=\"center\"><b>Docker\'s \
        Indexed Search App v.1.00a</b></td></tr><tr><td><table border=\"0\">\
        <tr><td>Search:</td><td> \
        <input id=\"query\" type=\"text\" onkeyup=\"doSearch();\" 
        onpaste=\"doSearch();\"></td>\
        <td><input type=\"submit\" onclick=\"doSearch();\"></td></tr></table> \
        </tr><tr><td><center><p id=\"result\">&nbsp;</p></center>\
        </td></tr></table></body></html>";

# Performing /search routing
@app.route('/search')
def search():
    # Getting value of the /search?text=query_string URL-parameter
    search_pattern = request.args.get("text");

    # Connecting to PostgreSQL database server by using PostgreSQL 
    # Python client adapter object
    conn=psycopg2.connect(database="phonebook", user="postgres", \
                          host="172.17.0.2", password="12345")

    # Getting the initial value of database connection curson
    cursor = conn.cursor()

    pg_query_string = "\0";
    # Performing a check if the search pattern 
    # /search?text=query_string is not equal to an empty string
    if search_pattern != "\0":
        # If not, construct a query string based on SQL statement 
        # performing the conditional query to get a resulting set of rows 
        # that exactly or partially match the given condition
        pg_query_string = """SELECT person_id, person_name, phone \
            FROM public.persons WHERE \
            person_name ILIKE '%""" + search_pattern + """%' \
            OR phone ILIKE '%""" + search_pattern + """%';"""
    # If yes, construct a query string based on SQL statement, 
    # fetching all rows from public.person table
    else: pg_query_string = """SELECT person_id, person_name, \
          phone FROM public.persons;""";

    # Executing SQL statement contained in query_string buffer using curson object
    cursor.execute(pg_query_string)

    # Generating html table and its header as the contents of html string buffer
    html = "<table border=\"0\">";
    html += "<tr><th>#</th><th>Person Name</th><th>Phone</th></tr>"

    # Assigning the initial value of row_id counter variable to 0
    row_id = 0
    # Fetching all rows from the query resultant set and assign the 
    # array of rows to rows variable
    rows = cursor.fetchall()
    # Iterating through the array of rows
    for row in rows:
        # For each row, generating html table row with column values 
        # obtained from the SQL query resultant set
        # Performing a check if the current row_id value is odd (e.g. row_id % 2 != 0)
        # If so, set table row's background style color to `light-grey', 
        # otherwise using `white` color
        html += "<tr style=\"background-color:" + \
            ("#eee" if (row_id % 2) != 0 else "#fff") + "\">";
        html += "<td>" + str(row[0]) + "</td>";
        html += "<td>" + row[1]      + "</td>";
        html += "<td>" + row[2]      + "</td></tr>";
        # Incrementing the value of row_id counter variable
        row_id = row_id + 1;

    # Generating the html table closing tag
    html += "</table>";

    # Returning the html document containing the search results html table
    return html;

if __name__ == '__main__':
    import os
    # Getting the value of hostname (e.g. 0.0.0.0) from the environment
    HOST = os.environ.get('SERVER_HOST', '0.0.0.0')
    try:
        # Getting the value of app's TCP-port equal to 80 from the environment
        PORT = int(os.environ.get('SERVER_PORT', '80'))
    except ValueError:
        PORT = 5555
    # Launching the web-application
    app.run(HOST, PORT)

'phonebook' is a tiny database, containing just one table 'persons', having two fields of 'text' type such as 'person_name' and 'phone'. The SQL-dump of the 'phonebook' database, including constraints and data is listed below:

phone_book.sql

SQL
--
-- PostgreSQL database dump
--

-- Dumped from database version 10.5
-- Dumped by pg_dump version 10.4

-- Started on 2018-08-18 14:20:06

SET statement_timeout = 0;

SET lock_timeout = 0;

SET idle_in_transaction_session_timeout = 0;
SET client_encoding = 'UTF8';

SET standard_conforming_strings = on;

SELECT pg_catalog.set_config('search_path', '', false);

SET check_function_bodies = false;

SET client_min_messages = warning;

SET row_security = off;

DROP DATABASE "phonebook";

--
-- TOC entry 2156 (class 1262 OID 16432)
-- Name: phonebook; Type: DATABASE; Schema: -; Owner: -
--

CREATE DATABASE "phonebook" WITH TEMPLATE = template0 ENCODING = 'UTF8' _
LC_COLLATE = 'Ukrainian_Ukraine.1251' LC_CTYPE = 'Ukrainian_Ukraine.1251';

\connect "phonebook"

SET statement_timeout = 0;

SET lock_timeout = 0;

SET idle_in_transaction_session_timeout = 0;

SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;

SELECT pg_catalog.set_config('search_path', '', false);

SET check_function_bodies = false;

SET client_min_messages = warning;

SET row_security = off;

--
-- TOC entry 2157 (class 0 OID 0)
-- Dependencies: 5
-- Name: SCHEMA "public"; Type: COMMENT; Schema: -; Owner: -
--

COMMENT ON SCHEMA "public" IS 'standard public schema';

--
-- TOC entry 1 (class 3079 OID 12278)
-- Name: plpgsql; Type: EXTENSION; Schema: -; Owner: -
--

CREATE EXTENSION IF NOT EXISTS "plpgsql" WITH SCHEMA "pg_catalog";

--
-- TOC entry 2158 (class 0 OID 0)
-- Dependencies: 1
-- Name: EXTENSION "plpgsql"; Type: COMMENT; Schema: -; Owner: -
--

COMMENT ON EXTENSION "plpgsql" IS 'PL/pgSQL procedural language';

--
-- TOC entry 197 (class 1259 OID 16444)
-- Name: person_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--

CREATE SEQUENCE "public"."person_id_seq"
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;

SET default_with_oids = false;

--
-- TOC entry 196 (class 1259 OID 16436)

-- Name: persons; Type: TABLE; Schema: public; Owner: -
--

CREATE TABLE "public"."persons" (
    "person_id" integer DEFAULT _
    "nextval"('"public"."person_id_seq"'::"regclass") NOT NULL,
    "person_name" "text",
    "phone" "text"
);

--
-- TOC entry 2149 (class 0 OID 16436)
-- Dependencies: 196
-- Data for Name: persons; Type: TABLE DATA; Schema: public; Owner: -
--

INSERT INTO "public"."persons" ("person_id", "person_name", "phone") _
VALUES (1, 'John W. Smith', '+1(719)444-5555');

INSERT INTO "public"."persons" ("person_id", "person_name", "phone") _
VALUES (2, 'Richard Stone', '+1(614)333-2211');

INSERT INTO "public"."persons" ("person_id", "person_name", "phone") _
VALUES (3, 'Jeffry Wilkins', '+1(212)818-2236');
INSERT INTO "public"."persons" ("person_id", "person_name", "phone") _
VALUES (4, 'William Travis', '+1(453)545-0390');

INSERT INTO "public"."persons" ("person_id", "person_name", "phone") _
VALUES (5, 'Tony Creek', '+1(451)452-3311');

INSERT INTO "public"."persons" ("person_id", "person_name", "phone") _
VALUES (6, 'Ronald Steward', '+1(718)959-4310');

INSERT INTO "public"."persons" ("person_id", "person_name", "phone") _
VALUES (7, 'Collin Whitney', '+1(410)541-3456');

INSERT INTO "public"."persons" ("person_id", "person_name", "phone") _
VALUES (8, 'Steven Cromb', '+1(461)553-4312');

INSERT INTO "public"."persons" ("person_id", "person_name", "phone") _
VALUES (9, 'Dave Blackstock', '+1(466)443-2228');

--
-- TOC entry 2159 (class 0 OID 0)

-- Dependencies: 197
-- Name: person_id_seq; Type: SEQUENCE SET; Schema: public; Owner: -
--
SELECT pg_catalog.setval('"public"."person_id_seq"', 9, true);

--
-- TOC entry 2027 (class 2606 OID 16443)
-- Name: persons person_id_pk; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY "public"."persons"
    ADD CONSTRAINT "person_id_pk" PRIMARY KEY ("person_id");

-- Completed on 2018-08-18 14:20:07

--
-- PostgreSQL database dump complete
--

Points of Interest

In this article, we've discussed an approach of creating and dockerizing a simple web-application, that can be also used to deploy the other applications, rather than the one introduced in this article.

History

  • 21st August, 2018 - First version of article published

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) EpsilonDev
Ukraine Ukraine
I’m software developer, system analyst and network engineer, with over 20 years experience, graduated from L’viv State Polytechnic University and earned my computer science and information technology master’s degree in January 2004. My professional career began as a financial and accounting software developer in EpsilonDev company, located at L’viv, Ukraine. My favorite programming languages - C/C++, C#.NET, Java, ASP.NET, Node.js/JavaScript, PHP, Perl, Python, SQL, HTML5, etc. While developing applications, I basically use various of IDE’s and development tools, including Microsoft Visual Studio/Code, Eclipse IDE for Linux, IntelliJ/IDEA for writing code in Java. My professional interests basically include data processing and analysis algorithms, artificial intelligence and data mining, system analysis, modern high-performance computing (HPC), development of client-server web-applications using various of libraries, frameworks and tools. I’m also interested in cloud-computing, system security audit, IoT, networking architecture design, hardware engineering, technical writing, etc. Besides of software development, I also admire to write and compose technical articles, walkthroughs and reviews about the new IT- technological trends and industrial content. I published my first article at CodeProject in June 2015.

Comments and Discussions

 
GeneralKubenetes version of this Simple web-Application. Pin
Member 1190029127-Feb-23 17:36
Member 1190029127-Feb-23 17:36 
I have converted this Dockerize version to the Kubernetes version and here is the step to do so.

----------------------
1. Create a namespace ravi-prac.

2. Set the current context to the namespace ravi-prac.
# kubectl config set-context --current --namespace ravi-prac

3. Create the docker image and push it to the docker hub.
cd IndexedSearchPythonDocker/
docker build -t web-phone-book .
docker images
docker tag web-phone-book:latest tibcoranjan/tibcopublic:web-phone-book
docker login
docker push tibcoranjan/tibcopublic:web-phone-book

4. Create the pgsql deployment with the readiness probe and liveness probe.

a. Create configMap with Database name.
# k create configmap psql-cm --from-literal=POSTGRES_DB=phonebook $do > psql-cm.yaml
b. Create seceret with DB username and password.
# k create secret generic psql-sec --from-literal=POSTGRES_USER=postgres --from-literal=POSTGRES_PASSWORD=12345 $do > psql-sec.yaml
c. Create a serviceaccount for pgsql deployment.
# k create sa pgsql-sa
d. Create pgsql deployment.
# k create deployment psql-deploy --image=postgres:10.1 -r 1 $do > psql-deploy.yaml

e. Add envFrom for configMap and secret and liveness, readiness probe (for tcpSocket port : 5432), rosource limit, serviceaccount in this yaml file.
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: psql-deploy
name: psql-deploy
namespace: ravi-prac
spec:
replicas: 1
selector:
matchLabels:
app: psql-deploy
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: psql-deploy
spec:
serviceAccountName: pgsa
containers:
- image: postgres:10.1
name: postgres
ports:
- containerPort: 5432
readinessProbe:
tcpSocket:
port: 5432
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
tcpSocket:
port: 5432
initialDelaySeconds: 15
periodSeconds: 20
envFrom:
- configMapRef:
name: psql-cm
- secretRef:
name: psql-sec
resources:
requests:
memory: "200Mi"
cpu: "250m"
limits:
memory: "528Mi"
cpu: "500m"
status: {}

f. Run this deployment,
#k apply -f psql-deploy.yaml

g. Expose this deployment for the ClusterIP service with port=5432 and target port=5432
#k expose deploy psql-deploy --type=ClusterIP --name=psql-svc --port=5432 --target-port=5432 $do > psql-svc.yaml
#k create -f psql-svc.yaml

h. Patch this service with the LoadBalancer external IP with one of the worker node IP address.
#k patch svc psql-svc -p '{'spec:'{'externalIP':['192.168.56.102']}}'

5. Create webApp deployment and expose it with the NodePort Service.
#k create deploy web-phone-book --image=tibcoranjan/tibcopublic:web-phone-book -r=1 $do > web-phone-book.yaml
#k expose deploy web-phone-book --name=web-phone-book-svc --type=NodePort --port=80 --target-port=80 $do > web-phone-book-svc.yaml

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.