diff --git a/platypush/install/docker/alpine.Dockerfile b/platypush/install/docker/alpine.Dockerfile index 4f2d0ed09..742614f19 100644 --- a/platypush/install/docker/alpine.Dockerfile +++ b/platypush/install/docker/alpine.Dockerfile @@ -1,8 +1,12 @@ FROM alpine + ADD . /install WORKDIR /var/lib/platypush -RUN DOCKER_CTX=1 /install/platypush/install/scripts/alpine/install.sh +ARG DOCKER_CTX=1 +ENV DOCKER_CTX=1 + +RUN /install/platypush/install/scripts/alpine/install.sh RUN cd /install && pip install -U --no-input --no-cache-dir . RUN rm -rf /install @@ -11,4 +15,7 @@ EXPOSE 8008 VOLUME /etc/platypush VOLUME /var/lib/platypush -CMD /run.sh +CMD platypush \ + --start-redis \ + --config /etc/platypush/config.yaml \ + --workdir /var/lib/platypush diff --git a/platypush/install/docker/debian.Dockerfile b/platypush/install/docker/debian.Dockerfile index 42e8e3242..49e59035c 100644 --- a/platypush/install/docker/debian.Dockerfile +++ b/platypush/install/docker/debian.Dockerfile @@ -1,10 +1,16 @@ FROM debian + ADD . /install WORKDIR /var/lib/platypush +ARG DEBIAN_FRONTEND=noninteractive +ENV DEBIAN_FRONTEND=noninteractive +ARG DOCKER_CTX=1 +ENV DOCKER_CTX=1 + RUN apt update -RUN DOCKER_CTX=1 /install/platypush/install/scripts/debian/install.sh -RUN cd /install && pip install -U --no-input --no-cache-dir . +RUN /install/platypush/install/scripts/debian/install.sh +RUN cd /install && pip install -U --no-input --no-cache-dir . --break-system-packages RUN rm -rf /install RUN apt autoclean -y RUN apt autoremove -y @@ -15,4 +21,7 @@ EXPOSE 8008 VOLUME /etc/platypush VOLUME /var/lib/platypush -CMD /run.sh +CMD platypush \ + --start-redis \ + --config /etc/platypush/config.yaml \ + --workdir /var/lib/platypush diff --git a/platypush/install/docker/ubuntu.Dockerfile b/platypush/install/docker/ubuntu.Dockerfile index 79cbca6e5..14b400802 100644 --- a/platypush/install/docker/ubuntu.Dockerfile +++ b/platypush/install/docker/ubuntu.Dockerfile @@ -1,9 +1,15 @@ FROM ubuntu + ADD . /install WORKDIR /var/lib/platypush +ARG DEBIAN_FRONTEND=noninteractive +ENV DEBIAN_FRONTEND=noninteractive +ARG DOCKER_CTX=1 +ENV DOCKER_CTX=1 + RUN apt update -RUN DOCKER_CTX=1 /install/platypush/install/scripts/debian/install.sh +RUN /install/platypush/install/scripts/debian/install.sh RUN cd /install && pip install -U --no-input --no-cache-dir . RUN rm -rf /install RUN apt autoclean -y @@ -15,4 +21,7 @@ EXPOSE 8008 VOLUME /etc/platypush VOLUME /var/lib/platypush -CMD /run.sh +CMD platypush \ + --start-redis \ + --config /etc/platypush/config.yaml \ + --workdir /var/lib/platypush diff --git a/platypush/install/scripts/debian/PKGCMD b/platypush/install/scripts/debian/PKGCMD index 0b313dee5..333026745 100644 --- a/platypush/install/scripts/debian/PKGCMD +++ b/platypush/install/scripts/debian/PKGCMD @@ -1 +1 @@ -DEBIAN_FRONTEND=noninteractive apt install -y +apt install -y diff --git a/platypush/install/scripts/docker-run.sh b/platypush/install/scripts/docker-run.sh deleted file mode 100755 index 9a0a81b44..000000000 --- a/platypush/install/scripts/docker-run.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -# This script is used as a default entry point for Docker containers - -DOCKER_CTX=1 platypush \ - --start-redis \ - --config /etc/platypush/config.yaml \ - --workdir /var/lib/platypush diff --git a/platypush/install/scripts/install.sh b/platypush/install/scripts/install.sh index 106745a5c..5eb688269 100755 --- a/platypush/install/scripts/install.sh +++ b/platypush/install/scripts/install.sh @@ -14,15 +14,9 @@ CMD="$(cat "${SCRIPT_PATH}/PKGCMD")" REQUIREMENTS="$(cat "${SCRIPT_PATH}/../../requirements/${OS}.txt" | tr '\n' ' ')" SUDO= -# If we are running in a Docker context then we want to copy the docker-run.sh -# script where we can easily find it. -if [ -n "$DOCKER_CTX" ]; then - cp -v /install/platypush/install/scripts/docker-run.sh /run.sh -fi - # If we aren't running in a Docker context, or the user is not root, we should # use sudo to install system packages. -if [[ "$(id -u)" != "0" ]] || [ -z "$DOCKER_CTX" ]; then +if [ $(id -u) -ne 0 ] || [ -z "$DOCKER_CTX" ]; then if ! type sudo >/dev/null; then echo "sudo executable not found, I can't install system packages" >&2 exit 1 diff --git a/platypush/platydock/__init__.py b/platypush/platydock/__init__.py index 084b9956c..86557e445 100755 --- a/platypush/platydock/__init__.py +++ b/platypush/platydock/__init__.py @@ -4,7 +4,6 @@ Dockerfile for Platypush starting from a configuration file. """ import argparse -from enum import Enum import inspect import os import pathlib @@ -12,23 +11,12 @@ import sys from typing import Iterable from platypush.config import Config -from platypush.utils.manifest import Dependencies, InstallContext, PackageManagers - - -class BaseImage(Enum): - """ - Supported base images for Dockerfiles. - """ - - ALPINE = 'alpine' - DEBIAN = 'debian' - UBUNTU = 'ubuntu' - - def __str__(self) -> str: - """ - Explicit __str__ override for argparse purposes. - """ - return self.value +from platypush.utils.manifest import ( + BaseImage, + Dependencies, + InstallContext, + PackageManagers, +) # pylint: disable=too-few-public-methods @@ -67,6 +55,7 @@ class DockerfileGenerator: self.cfgfile, pkg_manager=pkg_manager, install_context=InstallContext.DOCKER, + base_image=self.image, ) is_after_expose_cmd = False @@ -135,7 +124,11 @@ def main(): '-h', '--help', dest='show_usage', action='store_true', help='Show usage' ) parser.add_argument( - 'cfgfile', type=str, nargs='?', help='The path to the configuration file.' + 'cfgfile', + type=str, + nargs='?', + help='The path to the configuration file. If not specified a minimal ' + 'Dockerfile with no extra dependencies will be generated.', ) parser.add_argument( '--image', @@ -154,11 +147,15 @@ def main(): return 0 if not opts.cfgfile: + opts.cfgfile = os.path.join( + str(pathlib.Path(inspect.getfile(Config)).parent), + 'config.auto.yaml', + ) + print( - f'Please specify a configuration file.\nRun {sys.argv[0]} --help to get the available options.', + f'No configuration file specified. Using {opts.cfgfile}.', file=sys.stderr, ) - return 1 dockerfile = DockerfileGenerator(opts.cfgfile, image=opts.image).generate() print(dockerfile) diff --git a/platypush/utils/manifest.py b/platypush/utils/manifest.py index c217c464b..0be831411 100644 --- a/platypush/utils/manifest.py +++ b/platypush/utils/manifest.py @@ -31,6 +31,22 @@ _available_package_manager = None logger = logging.getLogger(__name__) +class BaseImage(Enum): + """ + Supported base images for Dockerfiles. + """ + + ALPINE = 'alpine' + DEBIAN = 'debian' + UBUNTU = 'ubuntu' + + def __str__(self) -> str: + """ + Explicit __str__ override for argparse purposes. + """ + return self.value + + @dataclass class PackageManager: """ @@ -55,7 +71,7 @@ class PackageManagers(Enum): APT = PackageManager( executable='apt', - command=('DEBIAN_FRONTEND=noninteractive', 'apt', 'install', '-y'), + command=('apt', 'install', '-y'), ) PACMAN = PackageManager( @@ -142,6 +158,9 @@ class Dependencies: pkg_manager: Optional[PackageManagers] = None """ Override the default package manager detected on the system. """ install_context: InstallContext = InstallContext.NONE + """ The installation context - Docker, virtual environment or bare metal. """ + base_image: Optional[BaseImage] = None + """ Base image used in case of Docker installations. """ @property def _is_venv(self) -> bool: @@ -154,17 +173,34 @@ class Dependencies: self.install_context == InstallContext.VENV or sys.prefix != sys.base_prefix ) + @property + def _is_docker(self) -> bool: + """ + :return: True if the dependencies scanning logic is running either in a + Docker environment. + """ + return ( + self.install_context == InstallContext.DOCKER + or 'DOCKER_CTX' in os.environ + or os.path.isfile('/.dockerenv') + ) + @classmethod def from_config( cls, conf_file: Optional[str] = None, pkg_manager: Optional[PackageManagers] = None, install_context: InstallContext = InstallContext.NONE, + base_image: Optional[BaseImage] = None, ) -> "Dependencies": """ Parse the required dependencies from a configuration file. """ - deps = cls(pkg_manager=pkg_manager, install_context=install_context) + deps = cls( + pkg_manager=pkg_manager, + install_context=install_context, + base_image=base_image, + ) for manifest in Manifests.by_config(conf_file, pkg_manager=pkg_manager): deps.before += manifest.install.before @@ -179,7 +215,7 @@ class Dependencies: Generates the package manager commands required to install the given dependencies on the system. """ - wants_sudo = self.install_context != InstallContext.DOCKER and os.getuid() != 0 + wants_sudo = not (self._is_docker or os.getuid() == 0) pkg_manager = self.pkg_manager or PackageManagers.scan() if self.packages and pkg_manager: yield ' '.join( @@ -196,8 +232,9 @@ class Dependencies: the system. """ wants_break_system_packages = not ( - # Docker installations shouldn't require --break-system-packages in pip - self.install_context == InstallContext.DOCKER + # Docker installations shouldn't require --break-system-packages in + # pip, except for Debian + (self._is_docker and self.base_image != BaseImage.DEBIAN) # --break-system-packages has been introduced in Python 3.10 or sys.version_info < (3, 11) # If we're in a virtual environment then we don't need