Repository: DataDog/dd-trace-py

Issue:
dd-lib-python-init break of change on 1.19 version
<!--
Thanks for taking the time for reporting an issue!

Before reporting an issue on dd-trace-py, please be sure to provide all
necessary information.

If you're hitting a bug, make sure that you're using the latest version of this
library.
-->

### Summary of problem
dd-lib-python-init 1.16 version could be used on non-root-user kubernetes admission controller apm injector
but the 1.19 version has to be run under root user and it will install and build python c libs on the air and set the bin under /.local/bin
this is impossible or too much break of change 
### Which version of dd-trace-py are you using?
1.16.3
### Which version of pip are you using?


### Which libraries and their versions are you using?

<details>
  <summary>`pip freeze`</summary>
  <!-- Paste output of pip freeze here -->
</details>

### How can we reproduce your problem?
create a target app running as non-root user in a kubernetes env, admission controller apm inject it
### What is the result that you get?
installation will require /.local/xx/xx/xx/xx which is impossible for non-root user
### What is the result that you expected?
like 1.16.3 use default user to run it and install it and use the tracer 


Discussion:
Hi @knitehias,

From: https://github.com/DataDog/dd-trace-py/pull/4490
 - "Containers using the root user can be blocked in Kubernetes which makes our lib injection image incompatible with certain Kubernetes configurations. The solution is to simply add and use a non-root user in the image". 

Just to confirm you tried upgrading from ddtrace v1.6.3 to ddtrace v.1.9.3. While v1.6.3 worked as expected, with v1.9.3 you are unable to use library injection with a non-root-user kubernetes admission controller. From your assessment the PR above introduced a breaking change and you would like to option to use the previous behavior. Is this correct?


> Hi @knitehias,
> 
> From: #4490
> 
> * "Containers using the root user can be blocked in Kubernetes which makes our lib injection image incompatible with certain Kubernetes configurations. The solution is to simply add and use a non-root user in the image".
> 
> Just to confirm you tried upgrading from ddtrace v1.6.3 to ddtrace v.1.9.3. While v1.6.3 worked as expected, with v1.9.3 you are unable to use library injection with a non-root-user kubernetes admission controller. From your assessment the PR above introduced a breaking change and you would like to option to use the previous behavior. Is this correct?

Yeah, in 1.6.3 the inject lib will figure it is non root so it will use default user access ( I got it from the logging instead of source code though), we still want to use newer version but as non root :) 
@knitehias 🤔 can you share the logs you mentioned and/or provide a basic repro of the issue? 1.9.3 should not be running as the root (the change introduced in https://github.com/DataDog/dd-trace-py/pull/4490)
Going to close this as we haven't heard back, please let us know if your issue is still present @knitehias and we can re-open and investigate further 🙂 
> Going to close this as we haven't heard back, please let us know if your issue is still present @knitehias and we can re-open and investigate further 🙂



Mar 3, 2023 @ 16:52:59.454 | datadog autoinstrumentation: successfully installed python package
-- | --

  | Mar 3, 2023 @ 16:52:59.454 | datadog autoinstrumentation: installing python package

  | Mar 3, 2023 @ 16:52:58.866 | You should consider upgrading via the '/usr/bin/python -m pip install --upgrade pip' command.

  | Mar 3, 2023 @ 16:52:58.866 | WARNING: You are using pip version 22.0.4; however, version 23.0.1 is available.

  | Mar 3, 2023 @ 16:52:58.639 | Successfully installed attrs-22.2.0 bytecode-0.14.0 cattrs-22.2.0 ddsketch-2.0.4 ddtrace-1.9.0 envier-0.4.0 exceptiongroup-1.1.0 importlib-resources-5.12.0 jsonschema-4.17.3 packaging-23.0 pkgutil-resolve-name-1.3.10 protobuf-4.22.0 pyrsistent-0.19.3 six-1.16.0 tenacity-8.2.2 typing-extensions-4.5.0 xmltodict-0.13.0 zipp-3.15.0

  | Mar 3, 2023 @ 16:52:55.977 | Installing collected packages: zipp, xmltodict, typing-extensions, tenacity, six, pyrsistent, protobuf, pkgutil-resolve-name, packaging, exceptiongroup, envier, attrs, importlib-resources, ddsketch, cattrs, bytecode, jsonschema, ddtrace

  | Mar 3, 2023 @ 16:52:55.374 | Downloading zipp-3.15.0-py3-none-any.whl (6.8 kB)

  | Mar 3, 2023 @ 16:52:55.368 | Collecting zipp>=3.1.0

  | Mar 3, 2023 @ 16:52:55.177 | Downloading importlib_resources-5.12.0-py3-none-any.whl (36 kB)

  | Mar 3, 2023 @ 16:52:55.171 | Collecting importlib-resources>=1.4.0

  | Mar 3, 2023 @ 16:52:54.987 | Downloading pkgutil_resolve_name-1.3.10-py3-none-any.whl (4.7 kB)

  | Mar 3, 2023 @ 16:52:54.982 | Collecting pkgutil-resolve-name>=1.3.10

  | Mar 3, 2023 @ 16:52:54.952 | ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 57.5/57.5 KB 111.0 MB/s eta 0:00:00

  | Mar 3, 2023 @ 16:52:54.947 | Downloading pyrsistent-0.19.3-py3-none-any.whl (57 kB)

  | Mar 3, 2023 @ 16:52:54.942 | Collecting pyrsistent!=0.17.0,!=0.17.1,!=0.17.2,>=0.14.0

  | Mar 3, 2023 @ 16:52:54.666 | Downloading exceptiongroup-1.1.0-py3-none-any.whl (14 kB)

  | Mar 3, 2023 @ 16:52:54.660 | Collecting exceptiongroup

  | Mar 3, 2023 @ 16:52:54.437 | ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 90.4/90.4 KB 143.3 MB/s eta 0:00:00

  | Mar 3, 2023 @ 16:52:54.382 | Downloading jsonschema-4.17.3-py3-none-any.whl (90 kB)

  | Mar 3, 2023 @ 16:52:54.377 | Collecting jsonschema

  | Mar 3, 2023 @ 16:52:54.254 | Downloading cattrs-22.2.0-py3-none-any.whl (35 kB)

  | Mar 3, 2023 @ 16:52:54.248 | Collecting cattrs

  | Mar 3, 2023 @ 16:52:54.177 | Downloading ddsketch-2.0.4-py3-none-any.whl (18 kB)

  | Mar 3, 2023 @ 16:52:54.173 | Collecting ddsketch>=2.0.1

  | Mar 3, 2023 @ 16:52:54.141 | Downloading envier-0.4.0-py3-none-any.whl (10 kB)

  | Mar 3, 2023 @ 16:52:54.136 | Collecting envier

  | Mar 3, 2023 @ 16:52:54.067 | ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 60.0/60.0 KB 125.6 MB/s eta 0:00:00

  | Mar 3, 2023 @ 16:52:54.062 | Downloading attrs-22.2.0-py3-none-any.whl (60 kB)

  | Mar 3, 2023 @ 16:52:54.057 | Collecting attrs>=20

  | Mar 3, 2023 @ 16:52:53.973 | Downloading six-1.16.0-py2.py3-none-any.whl (11 kB)

  | Mar 3, 2023 @ 16:52:53.963 | Collecting six>=1.12.0

  | Mar 3, 2023 @ 16:52:53.902 | Downloading bytecode-0.14.0-py3-none-any.whl (37 kB)

  | Mar 3, 2023 @ 16:52:53.897 | Collecting bytecode

  | Mar 3, 2023 @ 16:52:53.849 | Downloading typing_extensions-4.5.0-py3-none-any.whl (27 kB)

  | Mar 3, 2023 @ 16:52:53.844 | Collecting typing-extensions

  | Mar 3, 2023 @ 16:52:53.758 | ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 302.4/302.4 KB 147.3 MB/s eta 0:00:00

  | Mar 3, 2023 @ 16:52:53.752 | Downloading protobuf-4.22.0-cp37-abi3-manylinux2014_x86_64.whl (302 kB)

  | Mar 3, 2023 @ 16:52:53.747 | Collecting protobuf>=3

  | Mar 3, 2023 @ 16:52:52.500 | Downloading xmltodict-0.13.0-py2.py3-none-any.whl (10.0 kB)

  | Mar 3, 2023 @ 16:52:52.494 | Collecting xmltodict>=0.12

  | Mar 3, 2023 @ 16:52:52.455 | Downloading tenacity-8.2.2-py3-none-any.whl (24 kB)

  | Mar 3, 2023 @ 16:52:52.450 | Collecting tenacity>=5

  | Mar 3, 2023 @ 16:52:52.352 | ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 42.7/42.7 KB 115.8 MB/s eta 0:00:00

  | Mar 3, 2023 @ 16:52:52.347 | Downloading packaging-23.0-py3-none-any.whl (42 kB)

  | Mar 3, 2023 @ 16:52:52.342 | Collecting packaging>=17.1

  | Mar 3, 2023 @ 16:52:52.076 | ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 4.8/4.8 MB 59.7 MB/s eta 0:00:00

  | Mar 3, 2023 @ 16:52:51.991 | Downloading ddtrace-1.9.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (4.8 MB)

  | Mar 3, 2023 @ 16:52:51.963 | Collecting ddtrace

  | Mar 3, 2023 @ 16:52:44.856 | Defaulting to user installation because normal site-packages is not writeable

  | Mar 3, 2023 @ 16:52:44.853 | WARNING: The directory '/.cache/pip' or its parent directory is not owned or is not writable by the current user. The cache has been disabled. Check the permissions and owner of that directory. If executing pip with sudo, you should use sudo's -H flag.

  | Mar 3, 2023 @ 16:26:09.857 | ModuleNotFoundError: No module named 'ddtrace'

  | Mar 3, 2023 @ 16:26:09.857 | Error in sitecustomize; set PYTHONVERBOSE for traceback:

  | Mar 3, 2023 @ 16:26:01.859 | You should consider upgrading via the '/usr/bin/python3 -m pip install --upgrade pip' command.

  | Mar 3, 2023 @ 16:26:01.859 | WARNING: You are using pip version 22.0.4; however, version 23.0.1 is available.

  | Mar 3, 2023 @ 16:26:01.657 | ERROR: Could not install packages due to an OSError: [Errno 30] Read-only file system: '/.local'

  | Mar 3, 2023 @ 16:26:01.656 | Installing collected packages: xmltodict, tenacity, pyrsistent, pkgutil-resolve-name, packaging, exceptiongroup, envier, ddsketch, bytecode, attrs, jsonschema, cattrs, ddtrace

  | Mar 3, 2023 @ 16:26:00.986 | Requirement already satisfied: zipp>=3.1.0 in /app/src/expense_check/docker_image.binary.runfiles/ec_pip_deps_pypi__zipp (from importlib-resources>=1.4.0->jsonschema->ddtrace) (3.10.0)

  | Mar 3, 2023 @ 16:26:00.968 | Requirement already satisfied: importlib-resources>=1.4.0 in /app/src/expense_check/docker_image.binary.runfiles/ec_pip_deps_pypi__importlib_resources (from jsonschema->ddtrace) (5.10.0)

  | Mar 3, 2023 @ 16:26:00.965 | Downloading pkgutil_resolve_name-1.3.10-py3-none-any.whl (4.7 kB)

  | Mar 3, 2023 @ 16:26:00.962 | Collecting pkgutil-resolve-name>=1.3.10

  | Mar 3, 2023 @ 16:26:00.880 | ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 57.5/57.5 KB 240.0 MB/s eta 0:00:00

  | Mar 3, 2023 @ 16:26:00.877 | Downloading pyrsistent-0.19.3-py3-none-any.whl (57 kB)

  | Mar 3, 2023 @ 16:26:00.864 | Collecting pyrsistent!=0.17.0,!=0.17.1,!=0.17.2,>=0.14.0

  | Mar 3, 2023 @ 16:26:00.662 | Downloading exceptiongroup-1.1.0-py3-none-any.whl (14 kB)

  | Mar 3, 2023 @ 16:26:00.656 | Collecting exceptiongroup

  | Mar 3, 2023 @ 16:26:00.463 | Requirement already satisfied: typing-extensions in /app/src/expense_check/docker_image.binary.runfiles/ec_pip_deps_pypi__typing_extensions (from ddtrace) (4.4.0)

  | Mar 3, 2023 @ 16:26:00.462 | ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 42.7/42.7 KB 236.6 MB/s eta 0:00:00

  | Mar 3, 2023 @ 16:26:00.459 | Downloading packaging-23.0-py3-none-any.whl (42 kB)

  | Mar 3, 2023 @ 16:26:00.455 | Collecting packaging>=17.1

  | Mar 3, 2023 @ 16:26:00.296 | Downloading xmltodict-0.13.0-py2.py3-none-any.whl (10.0 kB)

  | Mar 3, 2023 @ 16:26:00.292 | Collecting xmltodict>=0.12

  | Mar 3, 2023 @ 16:26:00.197 | Downloading cattrs-22.2.0-py3-none-any.whl (35 kB)

  | Mar 3, 2023 @ 16:26:00.194 | Collecting cattrs

  | Mar 3, 2023 @ 16:26:00.092 | ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 90.4/90.4 KB 277.1 MB/s eta 0:00:00

  | Mar 3, 2023 @ 16:26:00.089 | Downloading jsonschema-4.17.3-py3-none-any.whl (90 kB)

  | Mar 3, 2023 @ 16:26:00.085 | Collecting jsonschema

  | Mar 3, 2023 @ 16:25:59.897 | ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 60.0/60.0 KB 249.6 MB/s eta 0:00:00

  | Mar 3, 2023 @ 16:25:59.895 | Downloading attrs-22.2.0-py3-none-any.whl (60 kB)

  | Mar 3, 2023 @ 16:25:59.891 | Collecting attrs>=20

  | Mar 3, 2023 @ 16:25:59.785 | Requirement already satisfied: six>=1.12.0 in /app/src/expense_check/docker_image.binary.runfiles/ec_pip_deps_pypi__six (from ddtrace) (1.16.0)

  | Mar 3, 2023 @ 16:25:59.783 | Downloading bytecode-0.14.0-py3-none-any.whl (37 kB)

  | Mar 3, 2023 @ 16:25:59.780 | Collecting bytecode

  | Mar 3, 2023 @ 16:25:59.683 | Downloading envier-0.4.0-py3-none-any.whl (10 kB)

  | Mar 3, 2023 @ 16:25:59.679 | Collecting envier

  | Mar 3, 2023 @ 16:25:59.588 | Downloading tenacity-8.2.2-py3-none-any.whl (24 kB)

  | Mar 3, 2023 @ 16:25:59.584 | Collecting tenacity>=5

  | Mar 3, 2023 @ 16:25:59.478 | Downloading ddsketch-2.0.4-py3-none-any.whl (18 kB)

  | Mar 3, 2023 @ 16:25:59.474 | Collecting ddsketch>=2.0.1

  | Mar 3, 2023 @ 16:25:59.381 | Requirement already satisfied: protobuf>=3 in /app/src/expense_check/docker_image.binary.runfiles/ec_pip_deps_pypi__protobuf (from ddtrace) (3.19.6)

  | Mar 3, 2023 @ 16:25:59.302 | ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 4.8/4.8 MB 215.4 MB/s eta 0:00:00

  | Mar 3, 2023 @ 16:25:59.277 | Downloading ddtrace-1.9.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (4.8 MB)

  | Mar 3, 2023 @ 16:25:59.258 | Collecting ddtrace


@knitehias thanks for getting back to us!

Hmm I'm not seeing anything in the logs that indicates that the install failed. Did the logs get cut off in your reply?

Resolving patch:
diff --git a/lib-injection/dl_megawheel.py b/lib-injection/dl_megawheel.py
new file mode 100755
--- /dev/null
+++ b/lib-injection/dl_megawheel.py
@@ -0,0 +1,116 @@
+#!/usr/bin/env python3
+"""
+Script to download all required wheels (including dependencies) of the ddtrace
+Python package for relevant Python versions (+ abis), C library platforms and
+architectures and merge them into a "megawheel" directory.
+
+This directory provides a portable installation of ddtrace which can be used
+on multiple platforms and architectures.
+
+Currently the only OS supported is Linux.
+
+This script has been tested with 21.0.0 and is confirmed to not work with
+20.0.2.
+
+Usage:
+        ./dl_megawheel.py --help
+
+
+The downloaded wheels can then be installed locally using:
+        pip install --no-index --find-links <dir_of_downloaded_wheels> ddtrace
+"""
+import argparse
+import itertools
+import os
+import subprocess
+import sys
+
+import packaging.version
+
+
+# Do a check on the pip version since older versions are known to be
+# incompatible.
+MIN_PIP_VERSION = packaging.version.parse("21.0")
+cmd = [sys.executable, "-m", "pip", "--version"]
+res = subprocess.run(cmd, capture_output=True)
+out = res.stdout.decode().split(" ")[1]
+pip_version = packaging.version.parse(out)
+if pip_version < MIN_PIP_VERSION:
+    print(
+        "WARNING: using known incompatible version, %r, of pip. The minimum compatible pip version is %r"
+        % (pip_version, MIN_PIP_VERSION)
+    )
+
+
+supported_pythons = ["2.7", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11"]
+supported_arches = ["aarch64", "x86_64", "i686"]
+supported_platforms = ["musllinux_1_1", "manylinux2014"]
+
+parser = argparse.ArgumentParser(description=__doc__)
+parser.add_argument(
+    "--python-version",
+    choices=supported_pythons,
+    action="append",
+    required=True,
+)
+parser.add_argument(
+    "--arch",
+    choices=supported_arches,
+    action="append",
+    required=True,
+)
+parser.add_argument(
+    "--platform",
+    choices=supported_platforms,
+    action="append",
+    required=True,
+)
+parser.add_argument("--ddtrace-version", type=str, required=True)
+parser.add_argument("--output-dir", type=str, required=True)
+parser.add_argument("--dry-run", action="store_true")
+parser.add_argument("--verbose", action="store_true")
+args = parser.parse_args()
+
+dl_dir = args.output_dir
+print("saving wheels to %s" % dl_dir)
+
+for python_version, arch, platform in itertools.product(args.python_version, args.arch, args.platform):
+    print("Downloading %s %s %s wheel" % (python_version, arch, platform))
+    abi = "cp%s" % python_version.replace(".", "")
+    # Have to special-case these versions of Python for some reason.
+    if python_version in ["2.7", "3.5", "3.6", "3.7"]:
+        abi += "m"
+
+    # See the docs for an explanation of all the options used:
+    # https://pip.pypa.io/en/stable/cli/pip_download/
+    #   only-binary=:all: is specified to ensure we get all the dependencies of ddtrace as well.
+    cmd = [
+        sys.executable,
+        "-m",
+        "pip",
+        "download",
+        "ddtrace==%s" % args.ddtrace_version,
+        "--platform",
+        "%s_%s" % (platform, arch),
+        "--python-version",
+        python_version,
+        "--abi",
+        abi,
+        "--only-binary=:all:",
+        "--dest",
+        dl_dir,
+    ]
+    if args.verbose:
+        print(" ".join(cmd))
+
+    if not args.dry_run:
+        subprocess.run(cmd, capture_output=not args.verbose, check=True)
+
+        # Unzip all the wheels into the output directory
+        wheel_files = [f for f in os.listdir(dl_dir) if f.endswith(".whl")]
+        for whl in wheel_files:
+            wheel_file = os.path.join(dl_dir, whl)
+            # -q for quieter output, else we get all of the files being unzipped.
+            subprocess.run(["unzip", "-q", "-o", wheel_file, "-d", dl_dir])
+            # Remove the wheel as it has been unpacked
+            os.remove(wheel_file)
diff --git a/lib-injection/sitecustomize.py b/lib-injection/sitecustomize.py
--- a/lib-injection/sitecustomize.py
+++ b/lib-injection/sitecustomize.py
@@ -1,57 +1,29 @@
 """
-This module when included on the PYTHONPATH will install the ddtrace package from pypi
-for the Python runtime being used.
+When included on the PYTHONPATH this module will initialize the PYTHONPATH to
+include the directory containing the ddtrace package and its dependencies. It
+then imports the ddtrace.bootstrap.sitecustomize module to automatically
+instrument the application.
 """
 import os
 import sys
 
 
-# This special string is to be replaced at container build time so that the
-# version is fixed in the source.
-version = "<DD_TRACE_VERSION_TO_BE_REPLACED>"
-
-
-def _configure_ddtrace():
-    # This import has the same effect as ddtrace-run for the current process.
-    import ddtrace.bootstrap.sitecustomize
-
-    bootstrap_dir = os.path.abspath(os.path.dirname(ddtrace.bootstrap.sitecustomize.__file__))
+def _add_to_pythonpath(path):
+    # type: (str) -> None
+    """Adds a path to the start of PYTHONPATH."""
     prev_python_path = os.getenv("PYTHONPATH", "")
-    os.environ["PYTHONPATH"] = "%s%s%s" % (bootstrap_dir, os.path.pathsep, prev_python_path)
-
-    # Also insert the bootstrap dir in the path of the current python process.
-    sys.path.insert(0, bootstrap_dir)
-    print("datadog autoinstrumentation: successfully configured python package")
-
-
-# Avoid infinite loop when attempting to install ddtrace. This flag is set when
-# the subprocess is launched to perform the installation.
-if "DDTRACE_PYTHON_INSTALL_IN_PROGRESS" not in os.environ:
-    try:
-        import ddtrace  # noqa: F401
-
-    except ImportError:
-        import subprocess
-
-        print("datadog autoinstrumentation: installing python package")
+    os.environ["PYTHONPATH"] = "%s%s%s" % (path, os.pathsep, prev_python_path)
+    sys.path.insert(0, path)
 
-        # Set the flag to avoid an infinite loop.
-        env = os.environ.copy()
-        env["DDTRACE_PYTHON_INSTALL_IN_PROGRESS"] = "true"
 
-        if "git" in version:
-            ddtrace_version = version
-        else:
-            ddtrace_version = "ddtrace==%s" % version
+pkgs_path = os.path.join(os.path.dirname(__file__), "ddtrace_pkgs")
+bootstrap_dir = os.path.join(pkgs_path, "ddtrace", "bootstrap")
+_add_to_pythonpath(pkgs_path)
+_add_to_pythonpath(bootstrap_dir)
 
-        # Execute the installation with the current interpreter
-        try:
-            subprocess.run([sys.executable, "-m", "pip", "install", ddtrace_version], env=env, check=True)
-        except Exception:
-            print("datadog autoinstrumentation: failed to install python package version %r" % ddtrace_version)
-        else:
-            print("datadog autoinstrumentation: successfully installed python package version %r" % ddtrace_version)
-            _configure_ddtrace()
-    else:
-        print("datadog autoinstrumentation: ddtrace already installed, skipping install")
-        _configure_ddtrace()
+try:
+    import ddtrace.bootstrap.sitecustomize  # noqa: F401
+except BaseException as e:
+    print("datadog autoinstrumentation: ddtrace failed to install:\n %s" % str(e))
+else:
+    print("datadog autoinstrumentation: ddtrace successfully installed")


Test patch:
diff --git a/tests/lib-injection/dd-lib-python-init-test-django-gunicorn/Dockerfile b/tests/lib-injection/dd-lib-python-init-test-django-gunicorn/Dockerfile
--- a/tests/lib-injection/dd-lib-python-init-test-django-gunicorn/Dockerfile
+++ b/tests/lib-injection/dd-lib-python-init-test-django-gunicorn/Dockerfile
@@ -1,10 +1,9 @@
-FROM ghcr.io/datadog/dd-trace-py/testrunner:989d6f118d180321399dbc4013467b8eab043396
+FROM python:3.10
 
 ENV PYTHONUNBUFFERED 1
 ENV DJANGO_SETTINGS_MODULE django_app
 WORKDIR /src
 ADD . /src
 EXPOSE 18080
-RUN pyenv global 3.10.3
-RUN python -m pip install django==4.1.3 gunicorn==20.1.0
-CMD /root/.pyenv/versions/3.10.3/bin/gunicorn --bind :18080 django_app:application
+RUN pip install django==4.1.3 gunicorn==20.1.0
+CMD gunicorn --bind :18080 django_app:application
diff --git a/tests/lib-injection/dd-lib-python-init-test-django-uvicorn/Dockerfile b/tests/lib-injection/dd-lib-python-init-test-django-uvicorn/Dockerfile
--- a/tests/lib-injection/dd-lib-python-init-test-django-uvicorn/Dockerfile
+++ b/tests/lib-injection/dd-lib-python-init-test-django-uvicorn/Dockerfile
@@ -1,10 +1,9 @@
-FROM ghcr.io/datadog/dd-trace-py/testrunner:989d6f118d180321399dbc4013467b8eab043396
+FROM python:3.9
 
 ENV PYTHONUNBUFFERED 1
 ENV DJANGO_SETTINGS_MODULE django_app
 WORKDIR /src
 ADD . /src
 EXPOSE 18080
-RUN pyenv global 3.10.3
-RUN python3.10 -m pip install django==4.1.3 uvicorn==0.20.0
-CMD /root/.pyenv/versions/3.10.3/bin/uvicorn --host 0.0.0.0 --port 18080 django_app:application
+RUN pip install django==4.1.3 uvicorn==0.20.0
+CMD uvicorn --host 0.0.0.0 --port 18080 django_app:application
diff --git a/tests/lib-injection/dd-lib-python-init-test-django/Dockerfile b/tests/lib-injection/dd-lib-python-init-test-django/Dockerfile
--- a/tests/lib-injection/dd-lib-python-init-test-django/Dockerfile
+++ b/tests/lib-injection/dd-lib-python-init-test-django/Dockerfile
@@ -1,10 +1,9 @@
-FROM ghcr.io/datadog/dd-trace-py/testrunner:989d6f118d180321399dbc4013467b8eab043396
+FROM python:3.11
 
 ENV PYTHONUNBUFFERED 1
 ENV DJANGO_SETTINGS_MODULE django_app
 WORKDIR /src
 ADD . /src
 EXPOSE 18080
-RUN pyenv global 3.10.3
-RUN python3.10 -m pip install django==4.1.3
-CMD python3.10 -m django runserver 0.0.0.0:18080
+RUN pip install django==4.1.3
+CMD python -m django runserver 0.0.0.0:18080