How do I set up a Python 2 development environment with Docker in 2026?
I stared at my terminal in disbelief. Python 2.7 was supposed to be dead—like, really dead. End-of-life since January 1, 2020. Yet here I was, six years later, trying to maintain a legacy codebase that absolutely refused to die.
$ python --versionPython 3.11.5
$ python2 --versioncommand not found: python2Great. My modern macOS system doesn’t even recognize Python 2 anymore. And when I tried to install it via Homebrew?
$ brew install python@2Error: python@2 has been disabled because it is past its end-of-life date!Of course it has. But I still needed to run and test this legacy application. Time to figure out how to safely work with Python 2 in 2026 without contaminating my entire system.
The Problem with Python 2 in 2026
Here’s what I learned the hard way: modern operating systems have completely purged Python 2. Package managers don’t include it. Security vulnerabilities are unpatched. Even pip versions have dropped Python 2 support.
But many developers still need Python 2 for:
- Legacy codebases awaiting migration
- Jython projects (Python running on Java)
- Libraries that never made the Python 3 transition
- Testing compatibility before migration
I tried a few approaches before finding the right one.
Approach 1: pyenv (Failed Miserably)
First, I tried installing Python 2 via pyenv on my Mac:
$ pyenv install 2.7.18python-build: use readline from homebrewDownloading Python-2.7.18.tar.xz...-> https://www.python.org/ftp/python/2.7.18/Python-2.7.18.tar.xzInstalling Python-2.7.18...ERROR: The Python ssl extension was not compiled. Missing the OpenSSL lib?After hours of trying to compile OpenSSL 1.1 (also deprecated) and fighting with Xcode command line tools, I gave up. The system dependencies for Python 2 are just too old.
Approach 2: Docker (The Solution!)
Then I remembered: Docker images are frozen in time. I could get a container with Python 2.7 pre-installed and working, without touching my host system.
$ docker pull python:22: Pulling from library/python...Status: Downloaded newer image for python:2docker.io/library/python:2
$ docker run -it python:2 python --versionPython 2.7.18That’s it. Python 2.7.18 running instantly, completely isolated from my host system. No compilation errors, no dependency hell.
Building a Development Environment
A one-off container is fine for quick tests, but I needed a proper development setup. Here’s the Dockerfile I created:
FROM python:2.7.18-slim
ENV PYTHONDONTWRITEBYTECODE=1ENV PYTHONUNBUFFERED=1
WORKDIR /app
RUN pip install --no-cache-dir \ pytest \ mock \ nose \ coverage \ pylint \ flake8 \ "pycodestyle<2.8" \ pydocstyle \ tox \ setuptools \ wheel \ twine \ virtualenv \ "autopep8<1.6" \ yapf
COPY . .
CMD ["python", "app.py"]Notice the version constraints? That bit me hard. I initially tried:
$ pip install pycodestyle autopep8# Later, inside Python 2...ImportError: cannot import name 'SpecifierSet'Turns out, modern versions of these tools dropped Python 2 support. I had to pin to older versions:
pycodestyle<2.8(latest requires Python 3)autopep8<1.6(same story)
The Version Constraint Gotcha
Here’s what happened when I didn’t pin versions:
Collecting pycodestyle Downloading pycodestyle-2.12.1-py2.py3-none-any.whl (42 kB)...Successfully installed pycodestyle-2.12.1
$ pycodestyle --versionTraceback (most recent call last): File "/usr/local/bin/pycodestyle", line 7, in <module> from pycodestyle import _main File "/usr/local/lib/python2.7/site-packages/pycodestyle.py", line 83, in <module> from typing import Optional, SetImportError: No module named typingPython 2 doesn’t have the typing module. The tool installed, but it won’t run. Always check Python 2 compatibility.
Docker Compose for Easier Development
Typing docker build and docker run constantly got tedious. I created a docker-compose.yml:
version: '3.8'
services: app: build: . volumes: - ./src:/app - ./data:/app/data environment: - PYTHONPATH=/app command: python main.py
tools: image: python:3.11-slim volumes: - ./src:/app working_dir: /app command: bashNow I can run my Python 2 app with docker-compose up app, and still have a Python 3 container for modern tooling like black (which doesn’t support Python 2).
CentOS 6 Alternative (Better Tooling)
I discovered another approach on Reddit: using CentOS 6, which has Python 2 as its system Python.
┌─────────────────────────────────────────────────┐│ Container Architecture │├─────────────────────────────────────────────────┤│ ││ ┌─────────────┐ ┌─────────────────────┐ ││ │ CentOS 6 │ │ python:2.7.18-slim │ ││ ├─────────────┤ ├─────────────────────┤ ││ │ Python 2.6 │ │ Python 2.7.18 │ ││ │ (system) │ │ (Debian-based) │ ││ │ │ │ │ ││ │ + yum repos │ │ + pip install │ ││ │ + older pkgs│ │ + smaller image │ ││ └─────────────┘ └─────────────────────┘ ││ ││ Legacy tooling Modern Python 2 setup ││ works better Lightweight & common ││ │└─────────────────────────────────────────────────┘The Dockerfile:
FROM centos:6
RUN yum update -y && \ yum install -y python-pip python-devel && \ yum clean all
WORKDIR /appRUN pip install pytest mock nose coverage pylint
COPY . .CMD ["python", "app.py"]Why CentOS 6? The package repositories still contain Python 2-compatible versions of common tools. Less version pinning needed.
Hybrid Approach: Two Virtual Environments
For my project, I ended up using two virtual environments inside the container:
FROM python:2.7.18-slim
WORKDIR /app
RUN pip install virtualenv
# Application dependencies (Python 2)RUN virtualenv .venv/app
# Modern tools that need Python 3 (black, mypy, etc.)# Run these from host or separate containerThis keeps my application dependencies isolated from development tools:
/app├── .venv/│ ├── app/ # Python 2.7 for legacy app│ └── app_tools/ # Could use Python 3 for modern tooling├── src/│ └── main.py└── requirements.txtCommon Mistakes I Made
Mistake 1: Forgetting to rebuild the image
$ docker run my-python2-appImportError: No module named 'new_dependency'I added a dependency to requirements.txt but forgot to rebuild. Docker doesn’t automatically reinstall.
Mistake 2: Mixing Python 2 and 3 in the same virtualenv
$ virtualenv .venv$ .venv/bin/pip install blackERROR: black requires Python 3.6+Don’t try to force Python 3 tools into a Python 2 environment. Use separate containers or virtualenvs.
Mistake 3: Running Python 2 in production
I was tempted to deploy my Docker container to production. Bad idea. Python 2 hasn’t received security patches since 2020. Development and testing only.
Security Considerations
Let me be clear: Python 2 has known vulnerabilities. The OpenSSL version in the official image is old. No security updates will ever come.
I treat Python 2 containers as disposable:
- Never expose them to the internet
- Never use them in production
- Keep them isolated from my host filesystem
- Delete and recreate containers frequently
┌──────────────────────────────────────────────┐│ Security Boundary ││ ││ ┌────────────────┐ ┌─────────────────┐ ││ │ Host System │ │ Docker Network │ ││ │ (Python 3) │ │ (Isolated) │ ││ │ │ │ │ ││ │ ✓ Secure │ │ ┌───────────┐ │ ││ │ ✓ Patched │ │ │ Python 2 │ │ ││ │ ✓ Modern │ │ │ Container │ │ ││ │ │ │ │ │ │ ││ │ │ │ │ ⚠ Legacy │ │ ││ │ │ │ │ ⚠ Unpatched│ │ ││ └────────────────┘ │ └───────────┘ │ ││ ↑ │ │ ││ │ └─────────────────┘ ││ │ ↑ ││ No direct access │ ││ (use volumes only) Read-only access ││ (if possible) │└──────────────────────────────────────────────┘Quick Reference: Essential Commands
Here’s my cheat sheet for working with Python 2 Docker containers:
# Pull and verifydocker pull python:2docker run -it python:2 python --version
# Interactive developmentdocker run -it -v $(pwd):/app -w /app python:2 bash
# Build and run with Dockerfiledocker build -t py2-project .docker run -it py2-project
# Using docker-composedocker-compose up appdocker-compose exec app bash
# Clean up (do this often)docker container prunedocker image pruneWhy This Matters
Containerizing Python 2 development isn’t just about convenience—it’s about containment (pun intended). By isolating legacy code:
- My host Python 3 environment stays clean
- I can run multiple Python 2 projects with different dependencies
- CI/CD pipelines can test legacy code reproducibly
- Security risks are contained within the Docker sandbox
- Migration becomes a planned project, not an emergency
The alternative—installing Python 2 on my host—would create conflicts, break tools, and leave security holes. Docker gives me a fresh, reproducible environment every time.
What’s Next?
If you’re still maintaining Python 2 code in 2026, you’re not alone. But every hour spent in a Python 2 container should be an hour planning your migration to Python 3. The container is a safety net, not a permanent home.
Start with the basic Dockerfile I shared, add your project’s specific dependencies (with version constraints!), and get that legacy code running in isolation. Then, start planning your Python 3 migration—you’ll thank yourself later.
Final Words + More Resources
My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me
Here are also the most important links from this article along with some further resources that will help you in this scope:
- 👨💻 Python 2.7 on Docker Hub
- 👨💻 Python 2 EOL Announcement
- 👨💻 Docker Documentation
- 👨💻 pyenv GitHub Repository
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!
Comments