Skip to content

feat: Introduce a new Docker environment for development #5355

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 8 commits into
base: main
Choose a base branch
from

Conversation

emyller
Copy link
Contributor

@emyller emyller commented Apr 17, 2025

  • I have added information to docs/ if required so people know about the feature!
  • I have filled in the "Changes" section below?
  • I have filled in the "How did you test this code" section below?
  • I have used a Conventional Commit title for this Pull Request

Changes

Introduce a new Docker environment, initially aimed at the local environment.
The design is intended to allow developers to run the code as easily as possible.
In the future, this format might contribute to remote environments as well (needs discussion).

How did you test this code?

  1. Install [and run] Docker, or Orbstack, or your favorite container tool.
  2. ./api/run — gets the application running in one command.
  3. ./api/run pytest --sw --pdb api/tests/ — or run any other command.
  4. cd api; ./run pytest -x tests/ — current directory is passed to the container.

Ideally any command should work just by prefixing it with ./api/run.

@emyller emyller requested a review from a team as a code owner April 17, 2025 19:13
@emyller emyller requested review from matthewelwell and removed request for a team April 17, 2025 19:13
Copy link

vercel bot commented Apr 17, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

3 Skipped Deployments
Name Status Preview Comments Updated (UTC)
docs ⬜️ Ignored (Inspect) Visit Preview May 13, 2025 11:01pm
flagsmith-frontend-preview ⬜️ Ignored (Inspect) Visit Preview May 13, 2025 11:01pm
flagsmith-frontend-staging ⬜️ Ignored (Inspect) Visit Preview May 13, 2025 11:01pm

@github-actions github-actions bot added api Issue related to the REST API feature New feature or request labels Apr 17, 2025
Copy link
Contributor

github-actions bot commented Apr 17, 2025

Docker builds report

Image Build Status Security report
ghcr.io/flagsmith/flagsmith-api-test:pr-5355 Finished ✅ Skipped
ghcr.io/flagsmith/flagsmith-e2e:pr-5355 Finished ✅ Skipped
ghcr.io/flagsmith/flagsmith-api:pr-5355 Finished ✅ Results
ghcr.io/flagsmith/flagsmith-frontend:pr-5355 Finished ✅ Results
ghcr.io/flagsmith/flagsmith:pr-5355 Finished ✅ Results
ghcr.io/flagsmith/flagsmith-private-cloud:pr-5355 Finished ✅ Results

Copy link
Contributor

github-actions bot commented Apr 17, 2025

Uffizzi Ephemeral Environment Deploying

☁️ https://app.uffizzi.com/github.com/Flagsmith/flagsmith/pull/5355

⚙️ Updating now by workflow run 15008393060.

What is Uffizzi? Learn more!

@emyller emyller force-pushed the feat/dockerized-local-env branch from 2947c16 to 51120a3 Compare April 17, 2025 19:33
@github-actions github-actions bot added feature New feature or request and removed feature New feature or request labels Apr 17, 2025
Copy link

codecov bot commented Apr 17, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 97.63%. Comparing base (4aa9e1b) to head (eb3b37d).
Report is 3 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #5355   +/-   ##
=======================================
  Coverage   97.63%   97.63%           
=======================================
  Files        1234     1234           
  Lines       42992    42992           
=======================================
  Hits        41974    41974           
  Misses       1018     1018           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions github-actions bot added feature New feature or request and removed feature New feature or request labels Apr 17, 2025
Copy link
Member

@khvn26 khvn26 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I approve the general idea of making life easier for contributors preferring Docker-based development environments.

That said, I'm not happy at all being faced with a prospect of maintaining:

  • A new Dockerfile, completely independent from the current one, making the build toolchain for backend un-DRY again.
  • A new task runner separate from the existing Makefile — confusing to contributors and probably redundant.
  • A yet another Docker Compose file (though I appreciate it's probably intended to replace one or more of the existing ones).

Overall, I feel that, at this moment, this PR introduces more new boilerplate aimed to solve one specific use case than I can tolerate.

I suggest we take a step back and align ourselves on the initial intent. I'm curious to learn about every roadblock you've encountered when setting up your local dev env, and how they are solved by throwing Docker into the equation.

If we decide that the use case warrants adding new tooling, I will insist on keeping our build toolchain as DRY and as standardised as possible — i.e., introducing a new target stage into the original Dockerfile, integrating Compose with our Make targets, exploring established solutions like devcontainers, devenv.sh, etc. etc.

api/Dockerfile Outdated
Comment on lines 1 to 3
# NOTE: Why not Alpine? Because Alpine demands installation of OS software
# prior to running app code, which leads to maintenance work and a larger image
# size compared to Debian — considering Debian layers are shared across images.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand how having to maintain a new Dockerfile is a viable trade-off here. I'll prefer a unified build toolchain to a neater dev container image; I'd rather this file be a new target stage in the existing root Dockerfile.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed! For now this Dockerfile is only experimental. It aligns nicely with the proposal but it would have a long way to go before becoming an actual thing.

api/Dockerfile Outdated
# Install Python packages
WORKDIR /tmp
ARG POETRY_VERSION_CONSTRAINT
ARG INSTALL_DEV_DEPENDENCIES
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why would we want to not install dev dependencies in a development container?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question! The ability to not install dev dependencies allows us to reuse the image setup in other contexts, e.g. production. But then again, this Dockerfile is only experimental.

api/Dockerfile Outdated
# NOTE: Forcefully delete optional private dependencies for now since
# Poetry needs to fetch them in order to calculate the dependency tree. See
# https://github.com/python-poetry/poetry/issues/4562
# TODO: Improve management of enterprise features
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is, at least in part, being tracked in #4764 (comment).

api/Dockerfile Outdated
Comment on lines 18 to 37
COPY api/pyproject.toml api/poetry.lock ./
RUN \
pip install -q poetry${POETRY_VERSION_CONSTRAINT:-} &&\
poetry config virtualenvs.create false &&\
poetry config cache-dir /var/cache/pypoetry &&\
###
# NOTE: Forcefully delete optional private dependencies for now since
# Poetry needs to fetch them in order to calculate the dependency tree. See
# https://github.com/python-poetry/poetry/issues/4562
# TODO: Improve management of enterprise features
sed -ie '/tool.poetry.group.auth-controller/,+1d' pyproject.toml &&\
sed -ie '/tool.poetry.group.saml/,+1d' pyproject.toml &&\
sed -ie '/tool.poetry.group.ldap/,+1d' pyproject.toml &&\
sed -ie '/tool.poetry.group.workflows/,+1d' pyproject.toml &&\
sed -ie '/tool.poetry.group.licensing/,+1d' pyproject.toml &&\
poetry lock &&\
###
poetry install --no-root $([ "$INSTALL_DEV_DEPENDENCIES" != "true" ] && echo "--without dev") &&\
rm -rf /var/cache/pypoetry &&\
rm -rf /tmp/*
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Private dependency problem aside (which, IMO, should not be solved here), why isn't this make install with POETRY_CACHE_DIR set to a mounted path?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I'd rather use #4764 to improve private dependency management. This sed trickery only exists to favor this PoC.

why isn't this make install with POETRY_CACHE_DIR set to a mounted path?

Another good question. I can list a few reasons why not to use make install within the Docker build:

  • IMO make is better suited for persons interacting with the shell directly. Especially, assuming make commands are going to run Docker underneath [if we eventually decide in favor of it], I'd rather not introduce inconsistency by having some commands that are intended to run from within a container instead of from the outside.
  • Currently make install will: 1. install pip, 2. install Poetry in a venv, then finally 3. install Python packages.
    • pip is already available in the Python Docker image, there's no need to reinstall.
    • The Poetry install script will setup a venv and install Poetry. A Docker env has no benefit out of Python virtualenvs, or really anything else this script does besides finally pip install poetry.
    • Though currently a necessary step to setup the local env, make install could be disregarded entirely thanks to ./run — or Docker Compose, really.
  • Finally, RUN --mount to improve build efficiency sounds like a great idea! We'd have to explore that.

context: ../../
dockerfile: api/Dockerfile
args:
POETRY_VERSION_CONSTRAINT: ==2.1.2
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather pin to a specific version (see Makefile).

api/poetry.lock Outdated
@@ -1,4 +1,4 @@
# This file is automatically @generated by Poetry 2.1.1 and should not be changed by hand.
# This file is automatically @generated by Poetry 2.1.2 and should not be changed by hand.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makefile POETRY_VERSION is still 2.1.1

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for catching the inconsistency. I tend to upgrade patch versions if they're harmless, but I shouldn't upgrade this yet, not in this PR.

@Zaimwa9 Zaimwa9 assigned Zaimwa9 and unassigned Zaimwa9 Apr 21, 2025
@emyller emyller marked this pull request as draft April 21, 2025 14:04
@github-actions github-actions bot added feature New feature or request and removed feature New feature or request labels Apr 21, 2025
@emyller
Copy link
Contributor Author

emyller commented Apr 21, 2025

@khvn26 I agree with every comment. The shape of this PR right now is more of a foundation to discuss, rather than an actual patch to merge. I’ve updated the status to Draft accordingly.

I’ve introduced a [tiny] new boilerplate as the shortest possible path to validate the PoC as an end. And only if we decide to pursue it to the benefit of users, then most definitely we’ll have to look into the means. This patch barely scratches the surface of the ultimate intent, which is a combination of long-term benefits:

  1. Having a single Docker image serving both local and remote environments consistently.
  2. Improve and simplify ECR/ECS rollouts, also allowing for better IaC.
  3. Allowing developers to effortlessly run the code with only one command.

For now, looking at the local environment, the run script tries to translate a Docker-based experience to native idiom, by providing an entrypoint for developers to run any command right after cloning the repo — seamlessly Dockerized. Instead of opposing it to the existing toolchain, make commands could actually benefit from it while aiming towards standardization of maintenance tasks, e.g.

serve:
    ./run

# Encourage developers to name migrations
MIGRATION_NAME ?= $(shell read -p 'Migration name (snake_case): ' name; echo $$name)
migration:
    ./run python manage.py makemigrations -n $(MIGRATION_NAME)

docs:
...

While make commands continue to shine, developers can also easily run arbitrary commands from within an ephemeral container, e.g. ./run pytest —pdb tests/test_myfeature.py, much similar to how they'd go without Docker.

I hope that makes sense! Please let me know your thoughts. I will add to the other comments shortly.

@emyller
Copy link
Contributor Author

emyller commented Apr 21, 2025

If the team decides this is worth pursuing, I'd love to write an RFC and publish it eventually. Likely it would be a WIP lasting as long as it takes until I learn all the ins and outs of the product, unless it gets help from other folks who'd like to join an adventure when the time is right.

For now this PR is really nothing but a PoC to discuss the idea of Dockerizing the product from local to production.

@github-actions github-actions bot added feature New feature or request and removed feature New feature or request labels Apr 21, 2025
@github-actions github-actions bot added feature New feature or request and removed feature New feature or request labels May 13, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api Issue related to the REST API feature New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants