diff --git a/.github/workflows/check_charts.yaml b/.github/workflows/check_charts.yaml index 8fb0cb690..b7bde9ac5 100644 --- a/.github/workflows/check_charts.yaml +++ b/.github/workflows/check_charts.yaml @@ -62,7 +62,7 @@ jobs: # See https://github.com/developmentseed/titiler/discussions/387 platforms: linux/amd64 context: . - file: dockerfiles/Dockerfile.uvicorn + file: dockerfiles/Dockerfile push: false tags: "titiler:dev" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cdce7994d..17269ee89 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -141,20 +141,8 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Docker meta (unicorn) - id: meta-uvicorn - uses: docker/metadata-action@v5 - with: - images: | - ghcr.io/${{ github.repository }}-uvicorn - flavor: | - latest=false - tags: | - type=semver,pattern={{version}} - type=raw,value=latest,enable={{is_default_branch}} - - - name: Docker meta (gunicorn) - id: meta-gunicorn + - name: Docker meta + id: meta uses: docker/metadata-action@v5 with: images: | @@ -165,31 +153,16 @@ jobs: type=semver,pattern={{version}} type=raw,value=latest,enable={{is_default_branch}} - # Uvicorn - - name: Build and push uvicorn - uses: docker/build-push-action@v6 - with: - # TODO: add `linux/arm64 once https://github.com/rasterio/rasterio-wheels/issues/69 is resolved - platforms: linux/amd64 # ,linux/arm64 - context: . - file: dockerfiles/Dockerfile.uvicorn - push: ${{ github.event_name != 'pull_request' }} - tags: ${{ steps.meta-uvicorn.outputs.tags }} - labels: ${{ steps.meta-uvicorn.outputs.labels }} - cache-from: type=gha - cache-to: type=gha,mode=max - - # Gunicorn - name: Build and push uses: docker/build-push-action@v6 with: # TODO: add `linux/arm64 once https://github.com/rasterio/rasterio-wheels/issues/69 is resolved platforms: linux/amd64 # ,linux/arm64 context: . - file: dockerfiles/Dockerfile.gunicorn + file: dockerfiles/Dockerfile push: ${{ github.event_name != 'pull_request' }} - tags: ${{ steps.meta-gunicorn.outputs.tags }} - labels: ${{ steps.meta-gunicorn.outputs.labels }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max diff --git a/CHANGES.md b/CHANGES.md index b51415b86..0ec1267d6 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,43 @@ # Release Notes +## Unreleased + +### Misc + +* Unify Docker images (deprecate `titiler-uvicorn`) + + ``` + # Uvicorn + # before + docker run \ + --platform=linux/amd64 \ + -p 8000:8000 \ + --env PORT=8000 \ + --rm -it ghcr.io/developmentseed/titiler-uvicorn:latest + + # now + docker run \ + --platform=linux/amd64 \ + -p 8000:8000 \ + --rm -it ghcr.io/developmentseed/titiler:latest \ + uvicorn titiler.application.main:app --host 0.0.0.0 --port 8000 --workers 1 + + # Gunicorn + # before + docker run \ + --platform=linux/amd64 \ + -p 8000:8000 \ + --env PORT=8000 \ + --rm -it ghcr.io/developmentseed/titiler:latest + + # now + docker run \ + --platform=linux/amd64 \ + -p 8000:8000 \ + --rm -it ghcr.io/developmentseed/titiler:latest \ + gunicorn -k uvicorn.workers.UvicornWorker titiler.application.main:app --bind 0.0.0.0:8000 --workers 1 + ``` + ## 0.20.1 (2025-01-09) ### titiler.xarray @@ -42,6 +80,13 @@ * Remove `python3.8` support (author @pratapvardhan, https://github.com/developmentseed/titiler/pull/1058) * Add `python3.13` support (author @pratapvardhan, https://github.com/developmentseed/titiler/pull/1058) +## 0.19.3 (2025-01-09) + +### titiler.xarray + +* pin python zarr to >2,<3.0 to avoid zarr 3.0 breaking changes [Backported from 0.20.1] + + ## 0.19.2 (2024-11-28) ### Misc diff --git a/README.md b/README.md index 5ff4ea9d3..ea96ef635 100644 --- a/README.md +++ b/README.md @@ -105,11 +105,11 @@ Ready to use/deploy images can be found on Github registry. - https://github.com/developmentseed/titiler/pkgs/container/titiler ```bash -docker run --name titiler \ +docker run + --platform=linux/amd64 \ -p 8000:8000 \ - --env PORT=8000 \ - --env WORKERS_PER_CORE=1 \ - --rm -it ghcr.io/developmentseed/titiler:latest + --rm -it ghcr.io/developmentseed/titiler:latest \ + uvicorn titiler.application.main:app --host 0.0.0.0 --port 8000 --workers 1 ``` - Built the docker locally @@ -117,11 +117,9 @@ docker run --name titiler \ git clone https://github.com/developmentseed/titiler.git cd titiler -docker compose up --build titiler # or titiler-uvicorn +docker compose up --build titiler ``` -Some options can be set via environment variables, see: https://github.com/tiangolo/uvicorn-gunicorn-docker#advanced-usage - ## Project structure ``` diff --git a/deployment/k8s/charts/Chart.yaml b/deployment/k8s/charts/Chart.yaml index acb0d2a9c..ebec02139 100644 --- a/deployment/k8s/charts/Chart.yaml +++ b/deployment/k8s/charts/Chart.yaml @@ -2,7 +2,7 @@ apiVersion: v1 appVersion: 0.20.1 description: A dynamic Web Map tile server name: titiler -version: 1.1.8 +version: 1.2.0 icon: https://raw.githubusercontent.com/developmentseed/titiler/main/docs/logos/TiTiler_logo_small.png maintainers: - name: emmanuelmathot # Emmanuel Mathot diff --git a/deployment/k8s/charts/templates/deployment.yaml b/deployment/k8s/charts/templates/deployment.yaml index fca1a0b86..ed4582249 100644 --- a/deployment/k8s/charts/templates/deployment.yaml +++ b/deployment/k8s/charts/templates/deployment.yaml @@ -20,6 +20,11 @@ spec: - name: {{ .Chart.Name }} image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.image.pullPolicy }} + command: [ {{ .Values.image.command }} ] + args: [ {{- range $arg := .Values.image.args }} + {{- $arg | quote }}, + {{- end }} + ] securityContext: {{- toYaml .Values.securityContext | nindent 12 }} env: @@ -37,7 +42,7 @@ spec: {{- end }} ports: - name: http - containerPort: {{ .Values.env.PORT }} + containerPort: 80 protocol: TCP livenessProbe: httpGet: diff --git a/deployment/k8s/charts/values-test.yaml b/deployment/k8s/charts/values-test.yaml deleted file mode 100644 index b8865ba9c..000000000 --- a/deployment/k8s/charts/values-test.yaml +++ /dev/null @@ -1,55 +0,0 @@ -# Default values for titiler. -replicaCount: 4 - -ingress: - enabled: true - annotations: {} - # kubernetes.io/ingress.class: nginx - # kubernetes.io/tls-acme: "true" - hosts: - - host: titiler.charter.uat.esaportal.eu - paths: ["/"] - tls: - - secretName: domain-tls - hosts: - - titiler.charter.uat.esaportal.eu - -terminationGracePeriodSeconds: 30 - -extraHostPathMounts: [] - # - name: map-sources - # mountPath: /map-sources/ - # hostPath: /home/ubuntu/map-sources - # readOnly: false - # mountPropagation: HostToContainer # OPTIONAL - -imagePullSecrets: [] - -env: - PORT: 80 - CPL_TMPDIR: /tmp - GDAL_CACHEMAX: 75% - VSI_CACHE: TRUE - VSI_CACHE_SIZE: 1073741824 - GDAL_DISABLE_READDIR_ON_OPEN: EMPTY_DIR - GDAL_HTTP_MERGE_CONSECUTIVE_RANGES: YES - GDAL_HTTP_MULTIPLEX: YES - GDAL_HTTP_VERSION: 2 - PYTHONWARNINGS: ignore - WEB_CONCURRENCY: 2 - -resources: - limits: - cpu: 256m - memory: 1Gi - # ephemeral-storage: 10Gi - requests: - cpu: 256m - memory: 1Gi - # ephemeral-storage: 10Gi - -nodeSelector: {} - -tolerations: [] - -affinity: {} diff --git a/deployment/k8s/charts/values.yaml b/deployment/k8s/charts/values.yaml index ac3a54f6b..2ccf50df0 100644 --- a/deployment/k8s/charts/values.yaml +++ b/deployment/k8s/charts/values.yaml @@ -2,9 +2,18 @@ replicaCount: 1 image: - repository: ghcr.io/developmentseed/titiler-uvicorn + repository: ghcr.io/developmentseed/titiler tag: latest pullPolicy: IfNotPresent + command: "uvicorn" + args: + - "titiler.application.main:app" + - "--host" + - "0.0.0.0" + - "--port" + - "80" + - "--workers" + - "1" nameOverride: "" fullnameOverride: "" @@ -38,7 +47,6 @@ extraHostPathMounts: [] imagePullSecrets: [] env: - PORT: 80 CPL_TMPDIR: /tmp GDAL_CACHEMAX: 200 # 200 mb VSI_CACHE: "TRUE" @@ -48,7 +56,6 @@ env: GDAL_HTTP_MULTIPLEX: "YES" GDAL_HTTP_VERSION: 2 PYTHONWARNINGS: "ignore" - WEB_CONCURRENCY: 2 resources: limits: diff --git a/docker-compose.yml b/docker-compose.yml index ce330ad32..d830839ac 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,62 +5,13 @@ services: platform: linux/amd64 build: context: . - dockerfile: dockerfiles/Dockerfile.gunicorn + dockerfile: dockerfiles/Dockerfile ports: - "8000:8000" + command: ["uvicorn", "titiler.application.main:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "1"] + # Or Using Gunicorn + # command: ["gunicorn", "-k", "uvicorn.workers.UvicornWorker", "titiler.application.main:app", "--bind", "0.0.0.0:8000", "--workers", "1"] environment: - # Application - - HOST=0.0.0.0 - - PORT=8000 - # Gunicorn / Uvicorn - # https://github.com/tiangolo/uvicorn-gunicorn-docker#web_concurrency - - WEB_CONCURRENCY=1 - # https://github.com/tiangolo/uvicorn-gunicorn-docker#workers_per_core - - WORKERS_PER_CORE=1 - # GDAL config - - CPL_TMPDIR=/tmp - - GDAL_CACHEMAX=75% - - GDAL_INGESTED_BYTES_AT_OPEN=32768 - - GDAL_DISABLE_READDIR_ON_OPEN=EMPTY_DIR - - GDAL_HTTP_MERGE_CONSECUTIVE_RANGES=YES - - GDAL_HTTP_MULTIPLEX=YES - - GDAL_HTTP_VERSION=2 - - PYTHONWARNINGS=ignore - - VSI_CACHE=TRUE - - VSI_CACHE_SIZE=536870912 - # GDAL VSI Config - # https://gdal.org/user/virtual_file_systems.html#vsis3-aws-s3-files - # https://gdal.org/user/virtual_file_systems.html#vsigs-google-cloud-storage-files - # https://gdal.org/user/virtual_file_systems.html#vsiaz-microsoft-azure-blob-files - # - AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID} - # - AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY} - # TiTiler config - # - TITILER_API_DISABLE_STAC=TRUE/FALSE - # - TITILER_API_DISABLE_MOSAIC=TRUE/FALSE - # - TITILER_API_DISABLE_COG=TRUE/FALSE - # - TITILER_API_CORS_ORIGIN=url.io,url.xyz - # - TITILER_API_CACHECONTROL=public, max-age=3600 - # - TITILER_API_DEBUG=TRUE/FALSE - # - MOSAIC_CONCURRENCY= # will default to `RIO_TILER_MAX_THREADS` - # rio-tiler config - # - RIO_TILER_MAX_THREADS= - - titiler-uvicorn: - # TODO: remove once https://github.com/rasterio/rasterio-wheels/issues/69 is resolved - # See https://github.com/developmentseed/titiler/discussions/387 - platform: linux/amd64 - build: - context: . - dockerfile: dockerfiles/Dockerfile.uvicorn - ports: - - "8000:8000" - environment: - # Application - - HOST=0.0.0.0 - - PORT=8000 - # Uvicorn - # http://www.uvicorn.org/settings/#production - - WEB_CONCURRENCY=1 # GDAL config - CPL_TMPDIR=/tmp - GDAL_CACHEMAX=75% @@ -91,7 +42,7 @@ services: benchmark: extends: - service: titiler-uvicorn + service: titiler volumes: - ./.github/data:/data diff --git a/dockerfiles/Dockerfile.uvicorn b/dockerfiles/Dockerfile similarity index 54% rename from dockerfiles/Dockerfile.uvicorn rename to dockerfiles/Dockerfile index e0a861133..923512477 100644 --- a/dockerfiles/Dockerfile.uvicorn +++ b/dockerfiles/Dockerfile @@ -1,5 +1,4 @@ -# Dockerfile for running titiler application with uvicorn server -ARG PYTHON_VERSION=3.11 +ARG PYTHON_VERSION=3.12 FROM bitnami/python:${PYTHON_VERSION} RUN apt update && apt upgrade -y \ @@ -12,13 +11,20 @@ RUN mkdir /usr/local/share/ca-certificates/cacert.org RUN cd /usr/local/share/ca-certificates/cacert.org && curl -k -O https://www.cacert.org/certs/root.crt RUN cd /usr/local/share/ca-certificates/cacert.org && curl -k -O https://www.cacert.org/certs/class3.crt RUN update-ca-certificates -ENV CURL_CA_BUNDLE /etc/ssl/certs/ca-certificates.crt +ENV CURL_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt -COPY src/titiler/ /tmp/titiler/ RUN python -m pip install -U pip -RUN python -m pip install /tmp/titiler/core /tmp/titiler/extensions["cogeo,stac"] /tmp/titiler/mosaic /tmp/titiler/application["server"] --no-cache-dir --upgrade +RUN python -m pip install uvicorn uvicorn-worker gunicorn + +COPY src/titiler/ /tmp/titiler/ +RUN python -m pip install /tmp/titiler/core /tmp/titiler/extensions["cogeo,stac"] /tmp/titiler/mosaic /tmp/titiler/application --no-cache-dir --upgrade RUN rm -rf /tmp/titiler -ENV HOST 0.0.0.0 -ENV PORT 80 -CMD uvicorn titiler.application.main:app --host ${HOST} --port ${PORT} +################################################### +# For compatibility (might be removed at one point) +ENV MODULE_NAME=titiler.application.main +ENV VARIABLE_NAME=app +ENV HOST=0.0.0.0 +ENV PORT=80 +ENV WEB_CONCURRENCY=1 +CMD gunicorn -k uvicorn.workers.UvicornWorker ${MODULE_NAME}:${VARIABLE_NAME} --bind ${HOST}:${PORT} --workers ${WEB_CONCURRENCY} diff --git a/dockerfiles/Dockerfile.gunicorn b/dockerfiles/Dockerfile.gunicorn deleted file mode 100644 index 6df319f04..000000000 --- a/dockerfiles/Dockerfile.gunicorn +++ /dev/null @@ -1,21 +0,0 @@ -# Dockerfile for running titiler application with gunicorn server -# Size ~1.4GB -ARG PYTHON_VERSION=3.11 - -FROM ghcr.io/vincentsarago/uvicorn-gunicorn:${PYTHON_VERSION} - -# Ensure root certificates are always updated at evey container build -# and curl is using the latest version of them -RUN mkdir /usr/local/share/ca-certificates/cacert.org -RUN cd /usr/local/share/ca-certificates/cacert.org && curl -k -O https://www.cacert.org/certs/root.crt -RUN cd /usr/local/share/ca-certificates/cacert.org && curl -k -O https://www.cacert.org/certs/class3.crt -RUN update-ca-certificates -ENV CURL_CA_BUNDLE /etc/ssl/certs/ca-certificates.crt - -COPY src/titiler/ /tmp/titiler/ -RUN python -m pip install -U pip -RUN python -m pip install /tmp/titiler/core /tmp/titiler/extensions["cogeo,stac"] /tmp/titiler/mosaic /tmp/titiler/application --no-cache-dir --upgrade -RUN rm -rf /tmp/titiler - -ENV MODULE_NAME titiler.application.main -ENV VARIABLE_NAME app diff --git a/src/titiler/application/pyproject.toml b/src/titiler/application/pyproject.toml index 2bc49ab08..c38699921 100644 --- a/src/titiler/application/pyproject.toml +++ b/src/titiler/application/pyproject.toml @@ -48,7 +48,7 @@ test = [ "boto3", ] server = [ - "uvicorn[standard]>=0.12.0,<0.19.0", + "uvicorn[standard]>=0.12.0", ] [project.urls]