Creating a Hello World Python Docker Container

Introduction

In this tutorial, we'll create a Docker container that runs a simple "Hello World" Python script. This is a fundamental first step in understanding containerization for Python applications, and it's especially useful for JavaScript developers learning Python.

We'll follow George Polya's four-step problem solving method to approach this task systematically:

  1. Understand the Problem: What are we trying to accomplish?
  2. Devise a Plan: How will we approach the solution?
  3. Carry Out the Plan: Implement our solution step by step
  4. Look Back: Review our solution and consider alternatives

Step 1: Understand the Problem

Our task is to create a Docker container that runs a simple "Hello World" Python script. Let's break down what this means:

Expected Input: None (the container will run the script automatically)

Expected Output: "Hello World" printed to the console

Prerequisites:

Analogy: Think of a Docker container like a lightweight, portable virtual machine. It contains everything needed to run your application – in this case, a Python interpreter and your script. It's similar to shipping a product in a self-contained package with batteries included, so it works the same way no matter where it's deployed.

Step 2: Devise a Plan

To create our "Hello World" Python Docker container, we'll follow these steps:

  1. Create a new project directory
  2. Create a simple Python script that prints "Hello World"
  3. Create a Dockerfile that:
    • Uses a Python base image
    • Copies our Python script into the container
    • Specifies the command to run the script
  4. Build the Docker image from our Dockerfile
  5. Run a container based on this image
  6. Verify that "Hello World" is printed to the console

Simplified Whiteboard Plan:

  1. Create project structure:
    hello_world_python/
    ├── hello_world.py   # Python script
    └── Dockerfile       # Instructions for building the image
  2. In hello_world.py: print("Hello World")
  3. In Dockerfile:
    FROM python:3.9-slim
    COPY hello_world.py /app/
    WORKDIR /app
    CMD ["python", "hello_world.py"]
  4. Build image: docker build -t hello-python .
  5. Run container: docker run hello-python

Step 3: Carry Out the Plan

Now, let's implement our plan step by step:

Step 3.1: Create Project Directory

First, let's create a directory for our project:

mkdir hello_world_python
cd hello_world_python

Step 3.2: Create Python Script

Next, create a file named hello_world.py with a simple print statement:

File: hello_world_python/hello_world.py

print("Hello World")

This is the simplest possible Python script that prints "Hello World" to the console. Unlike JavaScript, Python doesn't need semicolons or a function wrapper - just a simple print statement will do.

Step 3.3: Create Dockerfile

Now, create a file named Dockerfile (with no file extension) in the same directory:

File: hello_world_python/Dockerfile

# Use Python 3.9 slim image as the base
FROM python:3.9-slim

# Set the working directory in the container
WORKDIR /app

# Copy the Python script to the container
COPY hello_world.py .

# Command to run when the container starts
CMD ["python", "hello_world.py"]

Let's break down what each line does:

JavaScript vs. Python Container Comparison: If you're coming from Node.js, this is similar to a basic Node.js container. The main differences are:

  • Using python:3.9-slim instead of node:14-slim
  • Running python hello_world.py instead of node server.js
  • No need for package.json or npm install steps (for this simple example)

Step 3.4: Build the Docker Image

Now let's build the Docker image from our Dockerfile:

docker build -t hello-python .

This command tells Docker to:

You should see output showing Docker executing each instruction in your Dockerfile:

Sending build context to Docker daemon  3.072kB
Step 1/4 : FROM python:3.9-slim
 ---> 2b6a279e5279
Step 2/4 : WORKDIR /app
 ---> Running in 6e1c0b0c9491
Removing intermediate container 6e1c0b0c9491
 ---> a7b1e29d1d4f
Step 3/4 : COPY hello_world.py .
 ---> 89b9e963d4b7
Step 4/4 : CMD ["python", "hello_world.py"]
 ---> Running in b7b9fe4cbe68
Removing intermediate container b7b9fe4cbe68
 ---> e567bd177c5e
Successfully built e567bd177c5e
Successfully tagged hello-python:latest

Step 3.5: Run the Container

Finally, let's run a container from our image:

docker run hello-python

This command creates and starts a container based on the "hello-python" image. You should see the output:

Hello World

Congratulations! You've successfully created and run a Docker container with a Python "Hello World" script.

Step 4: Look Back

Now that we've created our solution, let's review what we've accomplished and consider alternatives or improvements:

What We Learned

Alternative Solutions

Alternative 1: Using Alpine Image for Smaller Size

If you want an even smaller container, you can use the Alpine-based Python image:

# Use Alpine-based Python image
FROM python:3.9-alpine

WORKDIR /app
COPY hello_world.py .
CMD ["python", "hello_world.py"]

The Alpine image is significantly smaller (around 45MB compared to 115MB for slim), but it might have compatibility issues with some Python packages that require compilation.

Alternative 2: Using Python One-Liner with Docker Run

For something this simple, you could skip creating a Python file and use Docker's Python image directly:

docker run -it --rm python:3.9-slim python -c "print('Hello World')"

This approach is more concise but less reusable and doesn't teach the process of creating custom images.

Alternative 3: Multi-Stage Build (More Advanced)

For more complex applications, you might use a multi-stage build to reduce image size:

# Build stage
FROM python:3.9 AS builder

WORKDIR /app
COPY requirements.txt .
RUN pip wheel --no-cache-dir --wheel-dir /app/wheels -r requirements.txt

# Final stage
FROM python:3.9-slim

WORKDIR /app
COPY --from=builder /app/wheels /wheels
COPY --from=builder /app/requirements.txt .
RUN pip install --no-cache-dir --no-index --find-links=/wheels -r requirements.txt

COPY hello_world.py .
CMD ["python", "hello_world.py"]

This approach isn't necessary for our simple script but becomes valuable for real-world applications with dependencies.

Considerations and Best Practices

Real-world application: While this example is simple, the same principles apply to containerizing complex Python applications like Flask or Django web servers, data processing pipelines, or machine learning models. Instead of a simple print statement, you might be running a web server or processing data, but the container structure remains similar.

Further Explorations

Now that you've created a basic Python Docker container, here are some ways to extend your learning:

Adding Command-Line Arguments

Modify your Python script to accept a name as an argument and return a personalized greeting:

File: hello_world_python/hello_world.py

import sys

name = "World"
if len(sys.argv) > 1:
    name = sys.argv[1]

print(f"Hello {name}!")

Then modify your Dockerfile's CMD line:

CMD ["python", "hello_world.py", "Docker"]

This will output "Hello Docker!" when you run the container.

Making the Container Interactive

You can modify the script to prompt for input:

File: hello_world_python/hello_world.py

name = input("Enter your name: ")
print(f"Hello {name}!")

And run the container in interactive mode:

docker run -it hello-python

Creating a Web Server

Instead of a simple script, you could create a basic web server that displays "Hello World":

File: hello_world_python/app.py

from http.server import HTTPServer, BaseHTTPRequestHandler

class HelloHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        self.send_response(200)
        self.send_header('Content-type', 'text/html')
        self.end_headers()
        self.wfile.write(b"Hello World from Python HTTP Server!")

server_address = ('', 8000)
httpd = HTTPServer(server_address, HelloHandler)
print("Server running at http://0.0.0.0:8000/")
httpd.serve_forever()

Modified Dockerfile:

FROM python:3.9-slim
WORKDIR /app
COPY app.py .
EXPOSE 8000
CMD ["python", "app.py"]

Build and run with port mapping:

docker build -t hello-python-web .
docker run -p 8000:8000 hello-python-web

Then visit http://localhost:8000 in your browser to see "Hello World from Python HTTP Server!"

Common Issues and Troubleshooting

Issue: "docker: command not found"

Solution: Ensure Docker is installed and in your PATH. See the Docker installation guide.

Issue: Permission denied when running Docker commands

Solution: On Linux, you might need to add your user to the docker group or use sudo:

sudo docker build -t hello-python .
sudo docker run hello-python

Issue: Image builds but container exits immediately

Solution: Ensure your Python script doesn't have errors. You can check the container logs:

docker run hello-python
docker logs [container_id]

Issue: Changes to Python script not reflected when running container

Solution: You need to rebuild the image after changing the script:

docker build -t hello-python .
docker run hello-python

Additional Resources

Conclusion

In this tutorial, we've created a simple Docker container that runs a "Hello World" Python script. We followed George Polya's four-step problem-solving method to approach the problem systematically:

  1. We understood what we needed to accomplish
  2. We devised a plan with clear steps
  3. We carried out the plan, creating a Python script and Dockerfile, building the image, and running the container
  4. We looked back, reviewing our solution and exploring alternatives

This exercise serves as a foundation for more complex containerization scenarios you'll encounter as you develop Python applications. The principles you've learned—creating a Dockerfile, building an image, and running a container—apply to containerizing any Python application, from simple scripts to complex web services.