Skip to content

Instantly share code, notes, and snippets.

@BillRaymond
Last active October 7, 2025 04:02
Show Gist options
  • Save BillRaymond/b39ae5d862aa81a250b70b812bd5d1cc to your computer and use it in GitHub Desktop.
Save BillRaymond/b39ae5d862aa81a250b70b812bd5d1cc to your computer and use it in GitHub Desktop.
Dockerfile to build a specific version of Python and set it as the default using Deadsnakes
####
# Specify the OS you want to run the Docker container in
# For the latest version of Ubuntu, use:
# FROM ubuntu:latest
# Learn more about this Ubuntu image, and versions (tags):
# https://hub.docker.com/_/ubuntu
####
FROM ubuntu:22.04
#####
# Variables to change before building your image
#
# Define the version of Python to install
# For example "3.11" will get the latest version of 3.11 (ex 3.11.4, 3.11.5, etc)
ARG PYVER="3.11"
# Define the username and email you will use for Git
ARG GITUSERNAME="Your Username"
ARG GITEMAIL="[email protected]"
#####
# These settings prevent a timezone prompt when Python installs
# Use this article to find your time zone (TZ):
# https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
ENV TZ=US/Pacific \
DEBIAN_FRONTEND=noninteractive
# Update the apt repo
RUN apt-get update
# Install Python (software-properties-common), Git, and Python utilities
# Learn about the deadsnakes Personal Package Archives, hosted by Ubuntu:
# https://www.youtube.com/watch?v=Xe40amojaXE
RUN apt-get install -y software-properties-common && \
add-apt-repository -y ppa:deadsnakes/ppa && \
apt-get install -y python$PYVER \
python3-pip \
git-all
# Upgrade packages to the latest version
RUN apt-get -y upgrade
# Update PIP (Python's package manager)
RUN python3 -m pip install --upgrade pip
# Configure git
RUN git config --global user.name "$GITUSERNAME" &&\
git config --global user.email $GITEMAIL &&\
git config --global init.defaultBranch main
# Set PYVER as the default Python interpreter
RUN update-alternatives --install /usr/bin/python3 python /usr/bin/python$PYVER 1
RUN update-alternatives --set python /usr/bin/python$PYVER
RUN update-alternatives --set python /usr/bin/python$PYVER
@AvocadoStyle
Copy link

I just came accross this Dockerfile while I was looking for a Dockerfile reference on google, I have few things to say about this dockerfile:
seems like

# Upgrade packages to the latest version
RUN apt-get -y upgrade

it is not a best practice for Dockerfile builds since it can lead to instability and inconsistent behavior across builds. Use only apt-get update rather than upgrade and install specific versions of critical dependencies when possible.

seems like you forgot to clean the cache and the apt repositories that already installed, take care for that too such as:

apt-get clean && apt-get autoclean && rm -rf /var/cache/apt/archives /var/lib/apt/lists/*

maybe the

/var/cache/apt/archives 

is unecessary because the apt-get autoclean already does that.

@jth0
Copy link

jth0 commented Oct 7, 2025

@AvocadoStyle:

You don't touch on it correctly, since you're swapping update/upgrade without providing further explanation, but apt-get update only grabs the latest apt repository lists/indices. apt-get upgrade installs current/updated packages for all packages installed in your environment. From a security perspective, upgrading any installed packages is strongly preferred. Obviously it's even better to not install a package unless it's necessary, but if it's there, and you can't remove it, upgrade it. If it breaks something, catch it in your testing, and fix your issue.

you forgot to clean the cache

This depends on your tooling/distro. Check /etc/apt/apt.conf.d in your base image. You'll most likely have several files there with a good handful of different configuration options, like which packages to autoremove, instructions to avoid suggesting additional packages, and the autoclean steps taken after each apt/apt-get/dpkg install command. For example:

/etc/apt/apt.conf.d/docker-clean

DPkg::Post-Invoke { "rm -f /var/cache/apt/archives/*.deb /var/cache/apt/archives/partial/*.deb /var/cache/apt/*.bin || true"; };
APT::Update::Post-Invoke { "rm -f /var/cache/apt/archives/*.deb /var/cache/apt/archives/partial/*.deb /var/cache/apt/*.bin || true"; };
Dir::Cache::pkgcache ""; Dir::Cache::srcpkgcache "";

In any case, unless you're really eager to save a few meg, you don't need to rm -rf /var/lib/apt/lists/* -- this folder is less than 100M by quite a bit. I guess it could be bigger in weird cases, but it's not strictly needed. But if you were going to run that, you'd first want to get your RUN apt-get update (and apt-get upgrade) command(s) merged into your install command and append the delete command there to avoid baking the apt cache lists into your image layer.

But if you want to pick at this, I'd get my .config/git/config file straight and just copy that in versus running git config commands in my image build and remove the duplicate update-alternatives command.

@BillRaymond: Cheers, and thanks for sharing!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment