Skip to content

agents/docker: Refactor Docker agent.#1119

Draft
nrybowski wants to merge 9 commits into
INGInious:mainfrom
nrybowski:refactor_docker_agent
Draft

agents/docker: Refactor Docker agent.#1119
nrybowski wants to merge 9 commits into
INGInious:mainfrom
nrybowski:refactor_docker_agent

Conversation

@nrybowski

@nrybowski nrybowski commented Jul 9, 2026

Copy link
Copy Markdown
Member

This PR is a major refactor of the Docker agent which focuses on two main points: (i) deprecating the kata-runtime as it is unused and adds a lot of unnecessary complexity and, (ii) implementing a robust communication scheme between the agent, the grading containers and the student containers.

Regarding to the first point, we experimented a few years ago with launching custom kernels within student container (#949). This is a solid alternative to the kata-runtime for running student code as root, e.g., for networking exercises, without compromising INGInious security. This feature has been blocked since then because of the way the Docker agent exposes its capabilities, which in turns impacts the way jobs are distributed among available agents.

Regarding to the second point, the Docker agent communicates with grading and student containers through their std{in,out} interfaces which is quite fragile and blocks a current effort of removing the Docker dependency (see #1115, #1116) in favor of generic OCI compatibility. Also, when the kata-runtime is used, the Docker agent serves as a proxy between the grading and student containers while they can communicate directly when both of them run on the same kernel. This is not required by #949.
The Docker agent also relies on the ZMQ framework for communications. This is an heavy framework whose advanced features are not used. We deprecate it in favor of a simpler and lower level approach based on simple bytestreams over TCP and Unix sockets which is already in use in the existing code. By leveraging the Transport and Protocol features of the asyncio framework, we also can get rid of the custom buffering that has been implemented. The goal here is to mainly rely on features of the standard python library and simplify the code base.
Furthermore, the messages sent between each element are not formally described and are encoded with dictionaries built-on the fly. This approach is not reliable and makes the messages hard to correctly extend.

The kata-runtime is so intermingled with the Docker agent I/O that it is nearly impossible to deprecate it without refactoring the whole Docker agent I/O.
This PR is an effort in the continuity of #1115 and #1116, and should be a cleaner basis for #949.
It implements on the following changes:

  • Docker agent.
    • Formalizing messages exchanged with the grading containers.
    • Refactoring the I/O loop.
      • Exposing TCP endpoint for communication rather than containers std{in,out}.
      • Leveraging formalized messages.
      • Deprecating kata-runtime related code.
      • Deprecate ZMQ.
    • Refactor the Docker interface to reflect the communication changes.
      • Remove Unix socket mount point.
      • Enable authenticated IPC sharing between grading and students containers.
  • Base container.
    • Formalizing messages exchanged with the student containers.
    • Leveraging formalized messages.
    • Deprecate ZMQ.
    • Proxying student container messages to the Agent through the grading container.
    • Sending container errors directly to the Agent to facilitate the debugging process.
    • Deprecating kata-runtime related code.
  • Student container.
    • Deprecating kata-runtime related code.
    • Leveraging formalized messages.
    • Deprecate ZMQ.
  • Add tests.
    • Grading container integration tests.
      • Add Docker agent mock.
      • Test simple successful grading run.
      • Test simple successful run_student.
      • Test failed run_student spawn.
    • Agent unit tests.
      • Grading container spawn.
      • Student container spawn.
  • Document the Docker agent internals.

Note: This PR is WIP, the git history will be squashed and rewritten before opening it for merge request.

@nrybowski nrybowski changed the title Refactor Docker agent. agents/docker: Refactor Docker agent. Jul 9, 2026
@codacy-production

codacy-production Bot commented Jul 9, 2026

Copy link
Copy Markdown

Not up to standards ⛔

🔴 Issues 1 critical · 20 high · 6 medium · 1 minor

Alerts:
⚠ 28 issues (≤ 0 issues of at least minor severity)

Results:
28 new issues

Category Results
BestPractice 1 minor
ErrorProne 1 critical
1 high
Security 2 medium
19 high
Complexity 4 medium

View in Codacy

🟢 Metrics 148 complexity · 0 duplication

Metric Results
Complexity 148
Duplication 0

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

@nrybowski nrybowski requested a review from anthonygego July 9, 2026 13:16
Comment on lines +690 to +697
attrs = self._docker.sync._docker.containers.get(info.container_id).attrs
try:
reader_stream, write_stream = await asyncio.open_connection(sock=sock._sock)
ip = attrs['NetworkSettings']['Networks']['bridge']['IPAddress']
except KeyError:
self._logger.exception("Failed to fetch grading container IP from container attributes.")
return None
try:
reader_stream, write_stream = await asyncio.open_connection(ip, GRADING_CONTAINER_TCP_PORT)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Replace with TCP server instead, grading containers will connect to the agent when they are ready.

# ==== Common types ====

class MsgType(IntEnum):
AgentInitMsg = 1

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Rename in AgentInitGrading

@staticmethod
def from_dict(o: dict):
if (msg_type := o.get('type')) is not None:
if msg_type == MsgType.AgentInitMsg:

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Bis.

elif msg_type == MsgType.GradingError:
return GradingError(**o)
else:
raise ValueError

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Add explicit error message.

else:
raise ValueError
else:
raise KeyError

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Bis.

def deserialize(o: bytes):
o = msgpack.loads(o)
if not isinstance(o, dict):
raise TypeError

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Ter.

envtypes: dict
run_cmd: str
run_as_root: bool = False
shared_kernel: bool = True

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

To deprecate.

nrybowski added 3 commits July 9, 2026 15:38
- Deprecate kata-runtime related code, i.e., shared_kernel and both_docker switches.
- Leverage formalized Agent messages when proxied through the grading container.
- Deprecate kata-runtime related code.
- Connect to Agent TCP server.
- Leverage formalized Agent messages.
…iner.

This commit adds a mock of the Docker agent to test the behavior of the grading / students
container w.r.t. the new I/O scheme, as well as some simple test cases.
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.

1 participant