Saturday, May 13, 2023

How Docker Enhances Modern Development and Offers Advantages Over Running Applications Locally

 Ever pondered the rising popularity of Docker among developers in the contemporary development landscape? In this piece, I will delve into the merits of employing Docker and how it facilitates running any application using a Docker image, as opposed to running the app on a local machine. I will also shed light on a real-life situation where Docker turns out to be invaluable.


Consider a scenario where you are engaged in an image processing project that necessitates the installation of the 'pillow' package on your Windows device. But what if your work laptop's administrative privileges thwart new installations or alterations in the Program Files directory? Docker comes to the rescue in such predicaments.


Docker is especially advantageous for developers immersed in AI/ML projects, as it allows local testing of server applications, even when specific Python packages are not compatible with Windows devices. Docker Desktop paves the way for a consistent environment to create and manage containers, thereby mitigating discrepancies between development, testing, and production environments. It also streamlines the management of application dependencies and configurations within Docker containers.


For a more in-depth comprehension of the distinction between running an application locally and using Docker, let's examine Docker images and Docker containers.


A Docker image is essentially a filesystem snapshot encapsulating the application code, runtime, system tools, libraries, and other necessary elements for running the application. These images are crafted using instructions outlined in a Dockerfile, which serves as the blueprint or template for generating Docker containers.


In contrast, a Docker container is an operational instance of a Docker image. Containers provide lightweight, portable, and isolated environments for running applications along with their dependencies. Operating on the Docker Engine, containers maintain isolation from each other and the host system. Multiple containers can be spawned from a single Docker image, each boasting its own filesystem and secluded runtime environment. Containers can be initiated, halted, or modified without influencing the underlying image or other containers.


To embark on your Docker journey, adhere to these steps:


Establish a project folder comprising a Python file (.py), a Dockerfile (sans extension), and a requirements.txt file. Your Python file houses your code, the Dockerfile includes directives to construct the Docker image, and requirements.txt contains the necessary Python packages for your application.


The Dockerfile is a script composed of a sequence of instructions such as:


FROM: Designates the base image to commence with, like FROM ubuntu:18.04.

RUN: Executes commands within the image during the build phase, for instance, RUN apt-get update && apt-get install -y python3.

COPY: Transfers files and directories from the build context (typically the local filesystem) into the image, such as COPY . /app.

WORKDIR: Designates the working directory for succeeding instructions, like WORKDIR /app.

EXPOSE: Notifies Docker that the container will listen on specified network ports at runtime, for example, EXPOSE 8080.

CMD: Specifies the default command to execute upon container startup, like CMD [“python3”, “app.py”].

Right-click within the project folder and choose Open in Terminal to build a Docker image from a Dockerfile. Utilize the command -


docker build -t <your-image-tag> .


Upon the creation of the Docker image, instantiate a Docker Container within it using the command below -


docker create — name <container_name> <image_name>


Now, initiate/start the container to execute the program.


docker start <container_name>


Head over to the Docker desktop app, click on the container, and then click on the Logs and Files section to verify successful processing.


This process will seamlessly run your program without necessitating installations or local machine modifications.

Acquiring HTTPS status of URL/Endpoint in Python and displaying informative messages based on the received status code

 To be an expert Python and application developer, it is essential to understand and effectively handle HTTPS status codes while working with web applications in Python. These codes are part of the HTTP response and provide valuable information about the outcome of a request made to a specific URL or endpoint. HTTPS status codes are three-digit numbers, where the first digit represents the category of the response. The categories are:


1xx (Informational): The request was received, and the server continues to process it.

2xx (Successful): The request was successfully received, understood, and accepted.

3xx (Redirection): Further action needs to be taken to complete the request.

4xx (Client Error): The request contains bad syntax or cannot be fulfilled by the server.

5xx (Server Error): The server failed to fulfill a valid request.

Understanding these status codes helps developers:


Determine if the request was successful or not.

Handle errors or exceptions that may occur due to issues with the request or server.

Provide informative messages to users based on the outcome of the request.

Implement conditional logic to perform different actions depending on the status code.

Some common HTTPS status codes include:


200 OK: The request was successful, and the server has returned the requested data.

201 Created: The request was successful, and the server has created a new resource as a result (common for successful POST requests).

204 No Content: The request was successful, but there is no data to return (common for DELETE requests).

400 Bad Request: The server could not understand the request due to invalid syntax or missing required data.

401 Unauthorized: The request requires user authentication.

403 Forbidden: The server understood the request but refuses to authorize it.

404 Not Found: The server can’t find the requested resource.

500 Internal Server Error: The server has encountered a situation it doesn’t know how to handle.

You can find a comprehensive list of HTTP status codes on the official website of the Internet Assigned Numbers Authority (IANA): https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml


In Python we have two main libraries requests and http.client for making HTTP requests. Both differ in terms of their features, simplicity, and ease of use.


requests is a popular third-party library that simplifies the process of making HTTP requests in Python. It provides a user-friendly and intuitive interface for working with HTTP requests and responses. http.client is part of the Python standard library and provides a low-level interface for working with HTTP requests and responses. It doesn’t offer as many features as requests, and you’ll need to handle redirects, cookies, and other advanced features manually.


Now let me show some examples for handling HTTPs code in Python. Below is an simple example that uses the Python’s requests library to make an HTTP GET request and print the response code in Python:


import requests


response = requests.get(‘https://www.example.com’)


response_code = response.status_code


print(f’Response code: {response_code}’)


Now let me show you another Python code that will capture the response from URL and print relevant messages based on the status codes.


import requests


response = requests.get(‘https://www.example.com')


# Check the status code

if response.status_code == 200:

print(“Request was successful!”)

# Process the response content

content = response.text

print(content)

elif response.status_code == 404:

print(“The requested resource was not found.”)

else:

print(f”An error occurred. Status code: {response.status_code}”)