Skip to content

♻️ connecting docker-api-proxy to services which require docker swarm socket - #8773

Open
GitHK wants to merge 30 commits into
ITISFoundation:masterfrom
GitHK:pr-osparc-use-docker-subnet2
Open

♻️ connecting docker-api-proxy to services which require docker swarm socket#8773
GitHK wants to merge 30 commits into
ITISFoundation:masterfrom
GitHK:pr-osparc-use-docker-subnet2

Conversation

@GitHK

@GitHK GitHK commented Jan 26, 2026

Copy link
Copy Markdown
Contributor

What do these changes do?

NOTE I have recreated the PR since the previous one was way out of scope. (@pcrespov @sanderegg please bare with me and review it one more time 🙏 )

This PR is very noisy and it replaces the local docker client, used to access the swarm API in the with the docker-api-proxy service in the following services:

  • autoscaling (optional when the image is started inside the computational cluster)
  • director (mandatory)
  • director-v2 (mandatory)

Related issue/s

How to test

Dev-ops

@GitHK GitHK self-assigned this Jan 26, 2026
@GitHK GitHK added this to the Unicorns milestone Jan 26, 2026
@GitHK GitHK changed the title ♻️ take 2 ♻️ take 2 connecting docker-api-proxy to services which require docker swarm socket Jan 26, 2026
@GitHK GitHK changed the title ♻️ take 2 connecting docker-api-proxy to services which require docker swarm socket ♻️ connecting docker-api-proxy to services which require docker swarm socket Jan 26, 2026
@codecov

codecov Bot commented Jan 26, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 92.64706% with 10 lines in your changes missing coverage. Please review.
✅ Project coverage is 89.06%. Comparing base (92a290c) to head (455355f).
⚠️ Report is 366 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #8773      +/-   ##
==========================================
- Coverage   89.30%   89.06%   -0.24%     
==========================================
  Files        1823     1783      -40     
  Lines       72257    69679    -2578     
  Branches      911      911              
==========================================
- Hits        64526    62058    -2468     
+ Misses       7503     7394     -109     
+ Partials      228      227       -1     
Flag Coverage Δ
integrationtests 63.66% <80.88%> (-0.08%) ⬇️
unittests 87.79% <85.29%> (-0.28%) ⬇️
Components Coverage Δ
pkg_aws_library 95.28% <ø> (ø)
pkg_celery_library 75.90% <ø> (ø)
pkg_dask_task_models_library 79.37% <ø> (ø)
pkg_models_library 92.98% <ø> (ø)
pkg_notifications_library 77.28% <ø> (ø)
pkg_postgres_database 88.09% <ø> (ø)
pkg_service_integration 72.86% <ø> (ø)
pkg_service_library ∅ <ø> (∅)
pkg_settings_library 90.58% <ø> (ø)
pkg_simcore_sdk 85.41% <ø> (+0.16%) ⬆️
agent 92.93% <ø> (ø)
api_server 91.37% <ø> (ø)
autoscaling ∅ <ø> (∅)
catalog 92.10% <ø> (ø)
clusters_keeper 99.03% <ø> (ø)
dask_sidecar 91.73% <ø> (ø)
datcore_adapter 97.95% <ø> (ø)
director ∅ <ø> (∅)
director_v2 91.37% <92.64%> (-0.10%) ⬇️
dynamic_scheduler 96.53% <ø> (ø)
dynamic_sidecar 88.58% <ø> (ø)
efs_guardian 89.85% <ø> (ø)
invitations 90.90% <ø> (ø)
payments 92.55% <ø> (ø)
resource_usage_tracker 90.78% <ø> (-0.43%) ⬇️
storage 86.22% <ø> (+0.20%) ⬆️
webclient ∅ <ø> (∅)
webserver 86.54% <ø> (+<0.01%) ⬆️

Continue to review full report in Codecov by Harness.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 92a290c...455355f. Read the comment docs.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@mergify

mergify Bot commented Jan 26, 2026

Copy link
Copy Markdown
Contributor

🧪 CI Insights

Here's what we observed from your CI run for 455355f.

❌ Job Failures

Pipeline Job Health on master Retries 🔍 CI Insights 📄 Logs
CI unit-tests Broken 0 View View

@GitHK
GitHK marked this pull request as ready for review January 28, 2026 13:42
@mrnicegyu11

Copy link
Copy Markdown
Member

@GitHK since this is a critical security issue, I'd like to check this actually. But as you said the PR is very noisy. Can you maybe point me to the key changes? or explain them, w.r.t. the implications for the mounted docker socket, admin rights etc. thanks

@GitHK

GitHK commented Jan 28, 2026

Copy link
Copy Markdown
Contributor Author

@GitHK since this is a critical security issue, I'd like to check this actually. But as you said the PR is very noisy. Can you maybe point me to the key changes? or explain them, w.r.t. the implications for the mounted docker socket, admin rights etc. thanks

@mrnicegyu11

This is a followup of the two following PRs:

From a security point of view it's a "drop-in" replacement of the docker socket, with an HTTP authentication layer so that not all services can access it.

The PR simply replaces the docker socket with the docker-api-proxy endpoint (which requires credentials by default). The replacement is done only for osparc services that require swarm level access (typically create and remove services and overlay networks).

Comment thread services/docker-compose.yml

@sanderegg sanderegg left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Much better thanks for the new changes. Nevertheless I am still not ok with the changes in the autoscaling and give you the following proposal (which we can discuss tomorrow):

  • instead of calling this a remote docker client -> setup_docker_client
  • then if there is no settings, then initiate the docker client as usual, so that it is not necessary to have that additional moving piece for unit tests
  • then it also becomes get_docker_client instead of get_remote_docker_client
  • Also change DockerApiProxySettings to DockerClientSettings
  • also I do not think yo need mock_setup_remote_docker_client all over the place since these can just be None while testing, which will simplify the testing even more, unless you specifically want to test it (which I would recommend to do in service lib and not in every single service)

Comment thread packages/pytest-simcore/src/pytest_simcore/docker_api_proxy.py Outdated
exit_stack = AsyncExitStack()

async def on_startup() -> None:
app.state.remote_docker_client = await exit_stack.enter_async_context(aiodocker.Docker())

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

1 question: did you check what happens if the connection to the docker engine is broken. does this client reconnects?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It's based on HTTP not TCP, so there is no such issue. If the connection comes back this will work as expcted

yield {}


def setup_remote_docker_client(app: FastAPI, settings: DockerApiProxysettings) -> None:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

should this not be using the new lifespan mechanisms?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

this should not be a "remote_docker_client" but the "docker_client".
and if there is no settings it should create the default client with the unix socket.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

There is a lifespan, for services which use it. In this situation it is required since not all of them use it

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The intent of the name is to avoid any possible confusion that this is a docker client that uses the local docker socket.
I want to keep this very obvious since mixing them is bad. Especially since we only have 1 machine for development and not multiple node machines.

This is client is intended to use docker swarm API and runs only on maser nodes.

If you are on a worker and need to list the containers, this will not work, since the connection will point to a docker master.

If you don't like the name, I suggest to make it even more obvious. Something like swarm_master_node_docker_client. It has to be obvious.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

For the reasons above, this should never user the local docker socket

Comment thread services/autoscaling/tests/unit/test_api_health.py Outdated
Comment thread services/director-v2/tests/integration/01/test_computation_api.py Outdated
Comment thread services/director-v2/tests/integration/01/test_computation_api.py Outdated

@pytest.fixture()
def mock_env(
mock_setup_remote_docker_client: Callable[[str], None],

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I do not think this is necessary for unit tests. this should just be disabled.

@pcrespov pcrespov left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

thx. left some comments.


# pylint: disable=too-many-branches
async def _create_docker_service_params(
async def _create_docker_service_params( # noqa: C901, PLR0912, PLR0913, PLR0915

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Those are lint rule suppressions (typically for flake8 / Ruff):

  • C901Function is too complex (cyclomatic complexity too high)
  • PLR0912Too many branches in a function
  • PLR0913Too many arguments in a function/method
  • PLR0915Too many statements in a function

So:

# noqa: C901, PLR0912, PLR0913, PLR0915

tells the linter to ignore complexity-related warnings for that line or function — basically “yes, this >function is big/complex, and that’s intentional.”

I think we should be careful ignoring these!! IMO now the RoI is even greater provided that we can pair-program with copilot on these issues

Comment thread services/director/src/simcore_service_director/producer.py
Comment thread services/director/src/simcore_service_director/producer.py
async def on_shutdown() -> None:
await exit_stack.aclose()

app.add_event_handler("startup", on_startup)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

why not using lifespan events in the fast app instead of these deprecate events https://fastapi.tiangolo.com/advanced/events/

if new code keeps the deprecated events ... we will never get the code up to date. Right now we have a nasty melange of all of these events :-(

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Because not all services support them. And we cannot mix them easily. Either the entire service is lifespan based or setup based.

Comment thread packages/service-library/src/servicelib/fastapi/docker.py


async def update_scheduler_data_label(scheduler_data: SchedulerData) -> None:
client = get_remote_docker_client(app)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

THOUGHT: Basically, the new proxy client only requires replacing

async with docker_client() as client:
    #
    client.services.  # same Docker client API
    #

with

client = get_remote_docker_client(app)
#
client.services.  # same Docker client API
#

I’m wondering whether using a context manager instead of a simple getter (get_remote_docker_client) would have kept the calling code almost unchanged while also making the client’s usage scope explicit. That scope information could then be used for logging start/stop events, timing, or other cross-cutting concerns, e.g.

async with remote_docker_client_ctx(app) as client:
    #
    client.services.  # same Docker client API
    #

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

We have a mix of styles with this client. And I only wanted to do one. Since a single instance apparently works well. I wanted to unify the pattern and avid client creation on the fly.

@GitHK GitHK modified the milestones: Unicorns, Fuerstenberg Feb 11, 2026
@sonarqubecloud

Copy link
Copy Markdown

@matusdrobuliak66 matusdrobuliak66 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants