diff --git a/release/docker/Dockerfile b/release/docker/Dockerfile new file mode 100644 index 000000000..f0d803e67 --- /dev/null +++ b/release/docker/Dockerfile @@ -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 +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 + +# 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"] diff --git a/release/docker/README.md b/release/docker/README.md new file mode 100644 index 000000000..3fc2b3793 --- /dev/null +++ b/release/docker/README.md @@ -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. diff --git a/release/docker/create_docker_images.sh b/release/docker/create_docker_images.sh new file mode 100755 index 000000000..4514a66b2 --- /dev/null +++ b/release/docker/create_docker_images.sh @@ -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}"