Skip to content
Open
85 changes: 85 additions & 0 deletions release/docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# Copyright 2025 The TensorFlow Quantum Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# =============================================================================

# Summary: build file for making isolated Docker environments for testing.
# This accepts 2 optional build arguments to set the Ubuntu & Python versions.
# Usage example:
#
# docker build --no-cache --build-arg PYTHON_VERSION=3.9 \
# --build-arg UBUNTU_VERSION=24.04 -t my-image:latest .
#
# Note that the name and tag ("my-image" and "latest" in the example above) are
# yours to choose. They're not set using the arguments or linked to their values.

# Default values for build arguments:
ARG PYTHON_VERSION=3.9
ARG UBUNTU_VERSION=22.04

FROM ubuntu:${UBUNTU_VERSION}

# Make the Python version argument visible to the rest of this file after FROM.
ARG PYTHON_VERSION
ENV PYTHON_VERSION=${PYTHON_VERSION}

ENV TZ=UTC
ENV LANG=C.UTF-8
ENV LC_ALL=C.UTF-8
Comment on lines +36 to +38
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: do we really need these ?

ENV DEBIAN_FRONTEND=noninteractive

# Ensure the shell is Bash.
SHELL ["/bin/bash", "-eo", "pipefail", "-c"]

# Tell the Dockerfile linter not to warn about how we use apt.
# hadolint global ignore=DL3008,DL3009

RUN apt-get -q update -q && \
apt-get install -y --no-install-recommends ca-certificates \
pkg-config gnupg curl lsb-release git zip unzip

# We avoid the use of "add-apt-repository" because it is only available from the
# "software-properties-common" package, and installing that package brings in a
# lot of other unrelated unnecessary packages. Instead, we fetch the GPG key for
# the deadsnakes package archive and install it where apt can find it.
ENV ID=0xF23C5A6CF475977595C89F51BA6932366A755776
ENV GPG_FILE="/etc/apt/trusted.gpg.d/deadsnakes.gpg"
RUN curl -sSL "https://keyserver.ubuntu.com/pks/lookup?op=get&search=${ID}" | \
gpg --dearmor -o ${GPG_FILE}

ENV PPA_URL="https://ppa.launchpadcontent.net/deadsnakes/ppa/ubuntu"
ENV APT_FILE="/etc/apt/sources.list.d/deadsnakes.list"
RUN echo "deb [signed-by=${GPG_FILE}] ${PPA_URL} $(lsb_release -cs) main" > "${APT_FILE}"

RUN apt-get -q update -q && \
apt-get install -yq --no-install-recommends make clang g++ zlib1g-dev \
python${PYTHON_VERSION} python${PYTHON_VERSION}-dev \
python${PYTHON_VERSION}-venv python3-pip python-is-python3
Comment on lines +64 to +67
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't python3-pip target the OS default python version. If we are in the process of changing it, I think this could get confused. Might want to instead use a versioned path.


# Use update-alternatives to make the desired version be the default.
# hadolint ignore=SC3010
RUN python_path="" bin="/usr/bin" && \
case "$(lsb_release -rs)" in \
"24.04") python_path="${bin}/python3.12" ;; \
"22.04") python_path="${bin}/python3.10" ;; \
"20.04") python_path="${bin}/python3.8" ;; \
*) python_path=$(readlink -f ${bin}/python3) ;; \
esac && \
update-alternatives --install ${bin}/python3 python3 "${python_path}" 1 && \
update-alternatives --install ${bin}/python3 python3 "${bin}/python${PYTHON_VERSION}" 2

# Clean up before finishing.
# hadolint ignore=DL3027
RUN apt clean

CMD ["/bin/bash"]
31 changes: 31 additions & 0 deletions release/docker/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Docker images for basic testing

This directory contains a [`Dockerfile`](Dockerfile) for creating Ubuntu
containers with Python installed and very little else compared to the stock
Ubuntu images from https://hub.docker.com/_/ubuntu/. These can be used for
testing TensorFlow Quantum builds and tutorials in relatively isolated
environments.

The script [`create_docker_images.sh`](create_docker_images.sh) creates separate
images with a range of Python versions installed in Ubuntu 22.04 and 24.04. The
result is a set of images with names like `ubuntu22-cp39`, `ubuntu22-cp310`,
etc. The script `create_docker_images.sh` is meant to be run simply like this:

```shell
./create_docker_images.sh
```

The configuration in `Dockerfile` runs a Bash shell as the last step if a
container is not started with any other command to run. When combined with
Docker's `-v` argument, you can easily run commands inside the container
environment while accessing your TensorFlow Quantum source files. For example:

```shell
# The next cd command moves to the root of the source tree.
cd $(git rev-parse --show-toplevel)
docker run -it --rm --network host -v .:/tfq ubuntu24-cp312
```

will leave you with a shell prompt inside a basic Ubuntu 24.04 environment with
Python 3.12 preinstalled and your local TensorFlow Quantum source directory
accessible at `/tfq` from inside the container.
68 changes: 68 additions & 0 deletions release/docker/create_docker_images.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#!/bin/bash
# Copyright 2025 The TensorFlow Quantum Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# =============================================================================

# Summary: create a set of Docker images for testing TFQ distributions.
# This loops over a set of Ubuntu versions and Python versions, and builds
# Docker images using the Dockerfile in this directory.
#
# Example of how the resulting images can be run
# docker run -it --rm --network host -v .:/tfq ubuntu22-cp39

set -e

declare -a ubuntu_versions=()
declare -a python_versions=()

ubuntu_versions+=( "22.04" "24.04" )
python_versions+=( "3.9" "3.10" "3.11" "3.12" "3.13" )

usage="Usage: ${0} [OPTIONS]

Build a set of basic Ubuntu Linux x86_64 Docker images with
Python preinstalled.

General options:
-h Show this help message and exit
-v Run Docker build with verbose progress output"

while getopts "hv" opt; do
case "${opt}" in
h) echo "${usage}"; exit 0 ;;
v) export BUILDKIT_PROGRESS=plain ;;
?) echo "${usage}"; exit 1 ;;
esac
done

total_items=$(( ${#ubuntu_versions[@]} * ${#python_versions[@]}))
echo "Building a total of ${total_items} Docker images."

start_time="$(date +"%Y-%m-%d-%H%M")"
for os_version in "${ubuntu_versions[@]}"; do
for py_version in "${python_versions[@]}"; do
echo
echo "~~~~ Python ${py_version} on Ubuntu ${os_version}"
# shellcheck disable=SC2086 # Lack of quotes around vars is ok here.
docker build --no-cache --label "build-datetime=${start_time}" \
--build-arg PYTHON_VERSION="${py_version}" \
--build-arg UBUNTU_VERSION="${os_version}" \
-t ubuntu${os_version%%.*}-cp${py_version//./}:latest .
done
done

echo
echo "~~~~ Done. The following Docker images were created:"
echo
docker images --filter "label=build-datetime=${start_time}"
Loading