saleor-dashboard icon indicating copy to clipboard operation
saleor-dashboard copied to clipboard

Distribute docker images and API_URL replacement in runtime

Open tofran opened this issue 2 years ago • 3 comments

What I'm trying to achieve

Use a distributed, production ready docker images without having to re-build the image from source.

As of right now, saleor-dashboard is not distributed as a Docker image (for example like saleor/saleor). If you are self-hosting, you must re-build an image with the Dockerfile provided in the root of this repository passing --build-arg API_URL="https://your-saleor-api-url.example.com/graphql/".

Unfortunately this is because API_URL is used from process.env and expanded by the bundler to the distribution files.

Having to make builds of third party software just makes users less likely to keep up with updates, and makes management more cumbersome.

Describe a proposed solution

I have been testing with different approaches, some require more effort like global variables in the window. But without making changes to the codebase, it is possible to distribute image with a little script that would replace the env var in the bundle:

./nginx/override-api-url-docker-entrypoint.sh

#!/bin/bash

# Replaces the original API_URL from the bundle files with the one in $API_URL_OVERRIDE
# This avoids having to rebuild the bundle, making it possible to use a distributed Docker image.
# This script is automatically picked up by the nginx entrypoint on startup.

set -e

ORIGINAL_API_URL="http://localhost:8000/graphql/"
BUNDLE_PATH="/app/dashboard"

escape_url() {
    printf '%s\n' "$1" | sed -e 's/[\/&]/\\&/g'
}

if [[ "$API_URL" != "$ORIGINAL_API_URL" ]]; then
    echo "Replacing API_URL with '$API_URL'"

    escaped_original_api_url=$(escape_url "$ORIGINAL_API_URL")
    escaped_api_url=$(escape_url "$API_URL")

    find "$BUNDLE_PATH" \
        -type f \
        -name 'dashboard.*.js' \
        -exec sed -i "s/$escaped_original_api_url/$escaped_api_url/g" {} \;
fi

This would be added in the Dockerfile with: COPY ./nginx/override-api-url-docker-entrypoint.sh /docker-entrypoint.d/50-override-api-url.sh Nginx's image will pick this automatically from their entrypoint script.

With this script, users would be able to run the docker image as distributed with API_URL : docker run --env API_URL="https://your-saleor-api-url.example.com/graphql/" ghcr.io/saleor/saleor-dashboard:3.7.6

(Obviously we can name this differently like API_URL_OVERRIDE if we want to be more conservative. But I feel like API_URL is quite simple and should not cause issues)

I am able to contribute with the script itself, documentation and GitHub actions workflow, following the practices from saleor/saleor/publish-containers.yml to make sure builds are published to the GitHub container registry.

What do you think about this? Does it sound too hacky? Or can I go ahead and open a pull request?

Even if we don't ship this script with the image, It would be really cool, if at least there was a distributed image in the GitHub package registry, like the one for Saleor core, with the hardcoded default API_URL.

tofran avatar Aug 31 '22 17:08 tofran

Hi @tofran, really appreciate your proposed solution! We are discussing it right now. I'll keep you posted.

karolkielecki avatar Sep 02 '22 09:09 karolkielecki

This looking good, I appreciate the effort in preparing such a script. It will do the job, however changing chunk files within runtime is a bit risky - one more word caught by sed and we break the app. Also, we must remember that chunks are being cached by the browser.

I would recommend exploring it, switching an API endpoint shouldn't be a that big deal.

andrzejewsky avatar Sep 02 '22 10:09 andrzejewsky

@karolkielecki @andrzejewsky thank you for your feedback.

Yes I also feel that making a find-and-replace in the bundle is quite clunky. The sed can be controlled to only run for people that really want it, by using the override suggestion I gave above. The caching problem is really relevant, and I did not foresee it. If we were to ship this as suggested, we would clearly have to state that changing the env var would probably not work right away for clients that have visited the app. As the bundle is cached in the client side - only triggering a build changes the hash.

Please have a look into the pull request I have drafted #2281 I would suggest solving this in two steps:

  1. Improve the Dockerfile and add CI to distribute images (done in the pr)
  2. Find a way to dynamically change these values without too much impact on the codebase (right now I suggested that script and PR, but I'm open to try different things until we are satisfied - this can be merged afterwards in another PR)

tofran avatar Sep 02 '22 10:09 tofran

Closed via #2523 Thank you everyone!

tofran avatar Nov 16 '22 16:11 tofran