Skip to main content

Deploy and Configure the Provided Application Back End with a Provided Custom Docker Image

Hands-On Lab

 

Photo of

Training Architect

Length

01:30:00

Difficulty

Intermediate

The objective of this lab is to deploy and configure the provided application back end with a database and Apache reverse proxy. We need to create a custom image for the provided Python Flask application. Then we will need to create an image of the database which this application will use. After that, we have to configure the Apache web server reverse proxy through which the back-end Python application will be accessible. Lastly, it is required to install and set up a firewall.

What are Hands-On Labs?

Hands-On Labs are scenario-based learning environments where learners can practice without consequences. Don't compromise a system or waste money on expensive downloads. Practice real-world skills without the real-world risk, no assembly required.

Deploy and Configure the Provided Application Back End with a Provided Custom Docker Image

Introduction

The objective of this lab is to deploy and configure the provided application back end with a database and Apache reverse proxy. We need to create a custom image for the provided Python Flask application. Then we will need to create an image of the database which this application will use. After that, we have to configure the Apache web server reverse proxy through which the back-end Python application will be accessible. Lastly, it is required to install and set up a firewall.

Connecting to the Lab

  1. Begin by logging in to the lab server using the credentials provided on the hands-on lab page.

    ssh cloud_user@PUBLIC_IP_ADDRESS

Create an Image for Our Python Flask Back-End Application

  1. Create a Dockerfile.

    vim /home/cloud_user/Dockerfile
  2. Paste the following into the file.

    FROM scratch
    ADD centos-7-x86_64-docker.tar.xz /
    
    LABEL org.label-schema.schema-version="1.0" 
        org.label-schema.name="CentOS Base Image" 
        org.label-schema.vendor="CentOS" 
        org.label-schema.license="GPLv2" 
        org.label-schema.build-date="20191001"
    
    RUN yum -y update
    RUN yum install -y python36 python36-devel
    RUN pip3 install flask flask_cors
    RUN yum install -y mariadb-devel gcc
    RUN pip3 install flask_mysqldb
    RUN pip3 install mysql-connector
    RUN mkdir /app
    
    COPY app.py /app
    WORKDIR /app
    
    ENTRYPOINT ["python3"]
    CMD ["app.py"]
    EXPOSE 65535
  3. Save the changes and exit the editor.

  4. Create the app.py script.

    vim /home/cloud_user/app.py
  5. Paste the following into the file.

    from flask import Flask
    from flask_cors import CORS
    import mysql.connector as mariadb
    
    import random
    import hashlib
    import json
    
    app = Flask(__name__)
    CORS(app)
    
    @app.route("/")
    def initialTest():
            return "TEST"
    
    @app.route("/youtube_video")
    def youtube_video():
            base_url = "https://www.youtube.com/embed/"
            video_ids = [   "h8xYLsmGnEQ",
                            "wZ31Tk2OxyE",
                            "6_IGyMM3QKE",
                            "E7WKVMkF98Q",
                            "g8kJnFTz87M",
                            "ADvYULvHs6Y",
                            "hA-onpcn__8",
                            "WBFb5x6g4dA",
                            "1PPGUOBzzKY",
                            "8xjBwTq2Dss",
                            "iI-cAtKgPXs",
                            "piu-TK00j_c",
                            "7te-pqNAl4o",
                            "s9_L_6r1Eh4",
                            "PZs7MImMOy8",
                            "LJi1FXLINgA",
                            "sGOlcIVd4Dw",
                            "h7a4ATtwkGI",
                            "4bSNfzucG8A"   ]
            return '<iframe src="' + base_url + video_ids[random.randint(0,18)] + '"></iframe>'
    
    @app.route("/random_number")
    def random_number():
            return hashlib.sha224(str(random.randint(1, 10149583095834095834059349)).encode()).hexdigest()
    
    @app.route("/motd")
    def motd():
            mariadb_connection = mariadb.connect(user='chronic', password='Test321', database='MyDB')
            cursor = mariadb_connection.cursor()
            cursor.execute("SELECT msg FROM motd;")
    
            msg = cursor.fetchall()[random.randint(0,8)][0]
            mariadb_connection.commit()
    
            cursor.close()
    
            return str(msg)
    
    @app.route("/set_motd")
    def set_motd():
            msg1 = "Whoever said that the definition of insanity is doing the same thing over and over again and expecting different results has obviously never had to reboot a computer."
            msg2 = "Programmer’s girlfriend: Are you going to sit and type in front of that thing all day or are you going out with me?nProgrammer: Yes."
            msg3 = "What do you call 8 hobbits?nA hobbyte"
            msg4 = "How many programmers does it take to change a light bulb?nNone. It's a hardware problem."
            msg5 = "I broke my finger last week. On the other hand I'm ok."
            msg6 = "What did the computer do at lunchtime?nHad a byte"
            msg7 = "Once a programmer drowned in the sea. Many Marines where at that time on the beach, but the programmer was shouting F1 F1 and nobody understood it."
            msg8 = "Unix is user friendly. It's just very particular about who it's friends are.""
            msg9 = "How many software testers does it take to change a light bulb?nNone. We just recognized darkness, fixing it is someone else's problem."
    
            messages = [msg1, msg2, msg3, msg4, msg5, msg6, msg7, msg8, msg9,]
    
            mariadb_connection = mariadb.connect(user='chronic', password='Test321', database='MyDB')
            cursor = mariadb_connection.cursor()
    
            counter = 0
            for m in messages:
                    cursor.execute("INSERT INTO motd(msg) VALUES(%s);", (messages[counter],))
                    counter += 1
    
            mariadb_connection.commit()
            cursor.close()
    
            return "DONE"
    
    if __name__ == '__main__':
        app.run(debug=True,host='0.0.0.0',port=65535)
  6. Save the changes and exit the editor.

  7. Build the image.

    sudo docker build -t cloud_user/flask-app:v1 .
  8. Verify the presence of the image.

    sudo docker images
  9. Run the container.

    sudo docker run -d --restart=always --network=host -p 65535:65535 cloud_user/flask-app:v1
  1. Verify the container is up and running.

    sudo docker ps

Create an Image for Our Database and Run the Container

  1. Create the database file.

    vim myDB.sh
  2. Paste the following into the file.

    docker container run 
            --name sql-maria 
            -e MYSQL_ROOT_PASSWORD=!!!Test321!! 
            -e MYSQL_USER=chronic 
            -e MYSQL_PASSWORD=Test321 
            -e MYSQL_DATABASE=MyDB 
            -p 3306:3306 
            -d mariadb:10
  3. Save the changes and exit the editor.

  4. Change the permissions on the file so it can be executed.

    chmod 700 myDB.sh
  5. Run the script.

    sudo ./myDB.sh
  6. Verify that the sql-maria container is running.

    sudo docker ps
  7. Create an image from the sql-maria container. Make sure to replace CONTAINER_ID with the CONTAINER ID show in the previous step.

    sudo docker commit -a chronic -m my_sql_img CONTAINER_ID chronic/my_sql_img:v1
  8. Stop the sql-maria container. Make sure to replace CONTAINER_ID with the appropriate value.

    sudo docker stop CONTAINER_ID
  9. Verify that it stopped.

    sudo docker ps
  1. Create a database directory.

    mkdir database
  2. List the images to get the IMAGE ID for the my_sql_img.

    sudo docker images
  3. Start a new container from the image. Make sure to replace IMAGE_ID with the ID from the previous step.

    sudo docker run -p 3306:3306 -v /home/cloud_user/database:/var/lib/mysql/:Z IMAGE_ID
  4. Once a "load completed" message has been displayed, log back into the server in a new terminal.

    ssh cloud_user@PUBLIC_IP_ADDRESS
  5. List the containers.

    sudo docker ps
  6. Stop the recently spun-up container using the CONTAINER ID displayed in the previous step.

    sudo docker stop CONTAINER_ID
  7. Back in the original terminal, rerun the container, but this time in the background. This is the same command as previously used, with the addition of the -d --restart=always flags.

    sudo docker run -d --restart=always -p 3306:3306 -v /home/cloud_user/database:/var/lib/mysql/:Z IMAGE_ID
  8. Verify both containers are up and running.

    sudo docker ps

Install and Configure Apache Web Server Reverse Proxy to Point to Our Back-End App

  1. Install httpd.

    sudo yum install httpd
  2. Start httpd.

    sudo systemctl start httpd
  3. Enable httpd.

    sudo systemctl enable httpd
  4. Confirm it is up and running.

    sudo systemctl status httpd
  5. Create necessary directories.

    sudo mkdir /etc/httpd/sites-enabled
    sudo mkdir /etc/httpd/sites-available
  6. Edit the configuration file.

    sudo vim /etc/httpd/conf/httpd.conf
  7. Find the line IncludeOptional conf.d/*.conf in the file and insert two new lines after it. Then add the following.

    IncludeOptional sites-enabled/*.conf
  8. Save the changes and exit the editor.

  9. Get the public hostname.

    curl -s http://169.254.169.254/latest/meta-data/public-hostname
  1. Copy the public hostname (everything before the [) to the clipboard. This will be referred to as PUBLIC_HOSTNAME through the rest of this lab.

  2. Create a configuration file for the hostname.

    sudo vim /etc/httpd/sites-available/PUBLIC_HOSTNAME.conf
  3. Add the following to the file.

    <VirtualHost *:80>
        ServerName www.PUBLIC_HOSTNAME
        ServerAlias PUBLIC_HOSTNAME
    
        DocumentRoot /var/www/html
    
        ProxyPass          /    http://127.0.0.1:65535/
        ProxyPassReverse   /    http://127.0.0.1:65535/
    
        <Proxy http://127.0.0.1:65535/>
                Require all granted
                Options None
        </Proxy>
    </VirtualHost>
  4. Save the changes and exit the editor.

  5. Link the new configuration.

    sudo ln -s /etc/httpd/sites-available/PUBLIC_HOSTNAME.conf /etc/httpd/sites-enabled/PUBLIC_HOSTNAME.conf
  6. Restart Apache.

    sudo systemctl restart httpd

Configure firewalld

  1. Update the firewall.

    sudo firewall-cmd --add-service=http --permanent
  2. Reload the firewall.

    sudo firewall-cmd --reload
  3. Display the firewall rules and verify the changes.

    sudo firewall-cmd --list-all

Run Tests and Verify It All Works

  1. Open a browser.

  2. Paste PUBLIC_HOSTNAME into the address bar and navigate to that location. If it says the service is unavailable, click refresh. Eventually it should display TEST.

  3. Navigate to PUBLIC_HOSTNAME/random_number and verify the results. Reloading the page should provide a random number.

  4. Navigate to PUBLIC_HOSTNAME/youtube_video and verify the results. Reloading the page should display different videos.

  5. Navigate to PUBLIC_HOSTNAME/set_motd. This might display an error that the table does not exist.

  6. Back in the terminal, install mariadb.

    yum install mariadb
  7. Log into SQL.

    mysql -h 127.0.0.1 -p -u chronic
  8. Show the databases.

    show databases
  9. Set the database.

    use MyDB
  1. Create the table.

    create table motd(msg VARCHAR(200));
  2. Exit.

    exit
  3. Log back into SQL.

    mysql -h 127.0.0.1 -p -u chronic MyDB
  4. Show the tables.

    show tables
  5. Back in the browser, refresh the page. This should no longer produce an error.

  6. Navigate to PUBLIC_HOSTNAME/motd and see the message of the day.

Conclusion

Congratulations, you've completed this hands-on lab!