diff --git a/Dockerfiles/Dockerfile b/Dockerfiles/Dockerfile index a70f5ae..40fed00 100755 --- a/Dockerfiles/Dockerfile +++ b/Dockerfiles/Dockerfile @@ -1,6 +1,8 @@ ARG INSTALL_OCI_REGISTRY_VER="2.8.2" ARG DOTNET_CONTAINER_VARIANT="6.0-jammy" - +ARG PYPISERVER_PORT=8080 +ARG PYPI_SERVER_VERSION="2.1.1" +ARG OCI_REGISTRY_PORT=5000 FROM mcr.microsoft.com/vscode/devcontainers/dotnet:0-${DOTNET_CONTAINER_VARIANT} AS downloader ARG INSTALL_OCI_REGISTRY_VER="2.8.2" ENV INSTALL_OCI_REGISTRY_VER=${INSTALL_OCI_REGISTRY_VER} @@ -20,10 +22,59 @@ RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ RUN mkdir -p /htpasswd/libs RUN ldd /usr/bin/htpasswd | grep "=> /" | awk '{print $3}' | xargs -I '{}' cp -v '{}' /htpasswd/libs -# FROM mcr.microsoft.com/cbl-mariner/distroless/minimal:2.0 -FROM mcr.microsoft.com/cbl-mariner/distroless/base:2.0 +# Setup PypiServer +FROM mcr.microsoft.com/devcontainers/python:1-3.9 as pypi_builder +ARG PYPI_SERVER_VERSION="2.1.1" +ENV PYPI_SERVER_VERSION=${PYPI_SERVER_VERSION} + +RUN apt-get update && apt-get install -y --no-install-recommends \ + ca-certificates \ + gnupg \ + wget \ + git \ + curl \ + tar \ + libffi-dev \ + tree + +RUN curl --silent --fail --create-dirs --output /code/pypiserver.tar.gz -L https://github.com/pypiserver/pypiserver/archive/refs/tags/v${PYPI_SERVER_VERSION}.tar.gz \ + && tar -xvzf /code/pypiserver.tar.gz -C /code/ + +WORKDIR /code/pypiserver-${PYPI_SERVER_VERSION} + +RUN python -m pip install \ + --no-warn-script-location \ + --prefix=/pypi-server \ + --requirement docker/docker-requirements.txt +RUN python -m pip install \ + --no-warn-script-location \ + --prefix=/pypi-server \ + . + +RUN mkdir -p /code/pypiserver-${PYPI_SERVER_VERSION}/docker/data/packages + +COPY src/gunicorn.conf.py /code/pypiserver-${PYPI_SERVER_VERSION}/docker/data/gunicorn.conf.py + +FROM mcr.microsoft.com/cbl-mariner/base/python:3.9 as final +ARG OCI_REGISTRY_PORT=5000 ARG INSTALL_OCI_REGISTRY_VER="2.8.2" +ARG PYPI_SERVER_VERSION="2.1.1" +ARG PYPISERVER_PORT=8080 + +ENV OCI_REGISTRY_PORT=${OCI_REGISTRY_PORT} +ENV PYPI_SERVER_VERSION=${PYPI_SERVER_VERSION} +ENV PYPISERVER_PORT=${PYPISERVER_PORT} + +# Flush logs immediately to stdout +ENV PYTHONUNBUFFERED=t + +ENV PYTHONPATH=/pypi-server/lib/python3.9/site-packages/ + +RUN ln -s /usr/bin/python3 /usr/bin/python \ + && ln -s /usr/bin/python3 /usr/local/bin/python + +# Copy the registry binaries and the configuration file COPY src/registry-config.yml /etc/docker/registry/config.yml COPY --from=downloader /registry /bin/registry @@ -31,8 +82,18 @@ COPY --from=downloader /registry /bin/registry COPY --from=downloader /usr/bin/htpasswd /usr/bin/htpasswd COPY --from=downloader /htpasswd/libs/* /usr/lib/ +# Copy the built pypi-server files +COPY --from=pypi_builder /pypi-server /pypi-server +COPY --from=pypi_builder /code/pypiserver-${PYPI_SERVER_VERSION}/docker/data /data +COPY --chmod=0755 src/entrypoint.sh /entrypoint.sh + + +VOLUME "/var/lib/registry" +VOLUME "/data/packages" +EXPOSE ${OCI_REGISTRY_PORT} ${PYPISERVER_PORT} + +USER root + +ENTRYPOINT ["/entrypoint.sh"] + -VOLUME ["/var/lib/registry"] -EXPOSE 5000 -ENTRYPOINT ["registry"] -CMD ["serve", "/etc/docker/registry/config.yml"] \ No newline at end of file diff --git a/README.md b/README.md index baa89e6..d282ee3 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![coresvc-registry-build](https://github.com/microsoft/azure-orbital-space-sdk-coresvc-registry/actions/workflows/coresvc-registry-build.yml/badge.svg)](https://github.com/microsoft/azure-orbital-space-sdk-coresvc-registry/actions/workflows/coresvc-registry-build.yml) -Provides an on-vehicle container image repository to use for the Space SDK. This is a fork from https://github.com/distribution/distribution with updates to source images to pullfrom the Microsoft Container Registry. +Provides an on-vehicle container image repository to use for the Space SDK. This is a fork from https://github.com/distribution/distribution with updates to source images to pullfrom the Microsoft Container Registry. It has combined with https://github.com/pypiserver/pypiserver. ## Build diff --git a/src/entrypoint.sh b/src/entrypoint.sh new file mode 100644 index 0000000..87c401a --- /dev/null +++ b/src/entrypoint.sh @@ -0,0 +1,56 @@ +#!/usr/bin/env bash + +# This will start the OCI Registry and the PyPI server in the background and listen for the +# SIGTERM and SIGINT signals to stop the processes gracefully. + +REGISTRY_ENABLED="${REGISTRY_ENABLED:-"true"}" +PYPISERVER_ENABLED="${PYPISERVER_ENABLED:-"true"}" + +# Function to handle termination signal +terminate_processes() { + echo "Termination signal received. Stopping processes..." + if [[ "${REGISTRY_ENABLED}" == "true" ]] && [[ "${PYPISERVER_ENABLED}" == "true" ]]; then + kill $REGISTRY_PID $PYPI_PID + wait $REGISTRY_PID $PYPI_PID + elif [[ "${REGISTRY_ENABLED}" == "true" ]]; then + kill $REGISTRY_PID + wait $REGISTRY_PID + elif [[ "${PYPISERVER_ENABLED}" == "true" ]]; then + kill $PYPI_PID + wait $PYPI_PID + fi + + echo "Processes stopped." + exit 0 +} + +# Trap SIGTERM and SIGINT signals and call the termination function +trap terminate_processes SIGTERM SIGINT + +if [[ "${REGISTRY_ENABLED}" == "true" ]]; then + echo "REGISTRY_ENABLED='true'. Starting the OCI Registry..." + # Run the OCI_Registry in the background + registry serve /etc/docker/registry/config.yml & + REGISTRY_PID=$! + echo "...OCI Registry successfully started." +fi + +if [[ "${PYPISERVER_ENABLED}" == "true" ]]; then + echo "PYPISERVER_ENABLED='true'. Starting the PyPiServer..." + # Run the pypi server in the background + mkdir -p /data/packages + /pypi-server/bin/pypi-server run -p ${PYPISERVER_PORT:-$PORT} --server gunicorn --backend cached-dir /data/packages --verbose --log-file /var/log/pypiserver.log & + PYPI_PID=$! + echo "...PyPiServer started." +fi + + +if [[ "${REGISTRY_ENABLED}" == "true" ]] && [[ "${PYPISERVER_ENABLED}" == "true" ]]; then + # Wait for the background processes to complete + wait $REGISTRY_PID $PYPI_PID +elif [[ "${REGISTRY_ENABLED}" == "true" ]]; then + wait $REGISTRY_PID +elif [[ "${PYPISERVER_ENABLED}" == "true" ]]; then + wait $PYPI_PID +fi + diff --git a/src/gunicorn.conf.py b/src/gunicorn.conf.py new file mode 100644 index 0000000..2253967 --- /dev/null +++ b/src/gunicorn.conf.py @@ -0,0 +1,10 @@ +# Enable to log every request +accesslog = "-" +errorlog = "-" +preload_app = True +workers = 1 +worker_class = "gevent" + +# SSL Certs +keyfile = "/certs/registry.spacefx.local.key" # Path to your private key file +certfile = "/certs/registry.spacefx.local.crt" # Path to your certificate file \ No newline at end of file