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:
- Understand the Problem: What are we trying to accomplish?
- Devise a Plan: How will we approach the solution?
- Carry Out the Plan: Implement our solution step by step
- 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:
- We need to create a Python script that prints "Hello World" to the console
- We need to package this script in a Docker container
- When the container runs, it should execute the script and display the message
Expected Input: None (the container will run the script automatically)
Expected Output: "Hello World" printed to the console
Prerequisites:
- Docker installed on your machine
- Basic knowledge of Python syntax
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:
- Create a new project directory
- Create a simple Python script that prints "Hello World"
- Create a Dockerfile that:
- Uses a Python base image
- Copies our Python script into the container
- Specifies the command to run the script
- Build the Docker image from our Dockerfile
- Run a container based on this image
- Verify that "Hello World" is printed to the console
Simplified Whiteboard Plan:
- Create project structure:
hello_world_python/ ├── hello_world.py # Python script └── Dockerfile # Instructions for building the image
- In hello_world.py:
print("Hello World") - In Dockerfile:
FROM python:3.9-slim COPY hello_world.py /app/ WORKDIR /app CMD ["python", "hello_world.py"]
- Build image:
docker build -t hello-python . - 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:
FROM python:3.9-slim: Specifies the base image to use - in this case, a lightweight version of Python 3.9WORKDIR /app: Sets the working directory inside the container to /appCOPY hello_world.py .: Copies our Python script from the host into the container's working directoryCMD ["python", "hello_world.py"]: Specifies the command to run when the container starts
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-sliminstead ofnode:14-slim - Running
python hello_world.pyinstead ofnode 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:
build: Build a new image-t hello-python: Tag (name) the image as "hello-python".: Use the current directory as the build context
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
- How to create a simple Python script
- How to write a basic Dockerfile for Python applications
- How to build a Docker image from a Dockerfile
- How to run a container from the image
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
- Base image selection: Choose the appropriate base image based on your needs (full, slim, or alpine)
- Security: For production applications, consider running as a non-root user
- Image size: Keep images as small as possible by removing unnecessary files
- Layer caching: Structure your Dockerfile to make the most of Docker's layer caching
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
- Docker Python Guide - Official Docker documentation for Python
- Dockerfile Best Practices - Guidelines for creating efficient Dockerfiles
- Choosing the Right Python Base Image - Detailed comparison of Python base images
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:
- We understood what we needed to accomplish
- We devised a plan with clear steps
- We carried out the plan, creating a Python script and Dockerfile, building the image, and running the container
- 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.