Repository: PrefectHQ/prefect

Issue:
Use custom container names when useing docker storage with docker agent
Hi,

I trying to figure out how to set the name for the container that docker agent spans when the flow is deployed from the cloud.

We are using the docker agent running on the local network together with the Prefect Could as an orchestrator. There are multiple jobs that run scheduled to be run by one of the containerized docker agents in a separated container. Our problem with the approach is that every time a new container with the same flow is started it gets an autogenerated name by docker which makes monitoring hard. It would be great if we could use the image name or something similar for the containers. 



Discussion:
It seems to me that when the `create_container` method of the APIClient class the name parameter is not provided [here?](https://github.com/PrefectHQ/prefect/blob/4b6b5253e671291498f62e3ef8af9705fc2c7a88/src/prefect/agent/docker/agent.py#L407)


This is probably something that could be added to the [`DockerRun`](https://docs.prefect.io/api/latest/run_configs.html#dockerrun) as `name` and then the name can be passed to the `create_container` call. @jcrist thoughts on adding this?
Since names have to be unique, we wouldn't want to use `name`, as any pre-named thing could collide if there are multiple concurrent runs. Docker does support labels for containers - we could auto-label all containers with their flow name/slug/something which would group them together. Would also avoid adding another config parameter (too many options can be confusing for users).

Would labeling containers with information on their corresponding flow be sufficient @konczbenedek?

We could also give the container a short name similar to the flow name (with some slugifying/truncating + uuid) to make it easier to tell at a glance what the container is.
@jcrist labeling sounds sufficient. We would need a parameter that is the save over all containers spun for the given flow name / slug so metrics (like average lifetime) would recognize them as one-kinde of entity. 

Resolving patch:
diff --git a/src/prefect/agent/docker/agent.py b/src/prefect/agent/docker/agent.py
--- a/src/prefect/agent/docker/agent.py
+++ b/src/prefect/agent/docker/agent.py
@@ -404,6 +404,12 @@ def deploy_flow(self, flow_run: GraphQLResult) -> str:
                 {self.network: self.docker_client.create_endpoint_config()}
             )
 
+        labels = {
+            "io.prefect.flow-name": flow_run.flow.name,
+            "io.prefect.flow-id": flow_run.flow.id,
+            "io.prefect.flow-run-id": flow_run.id,
+        }
+
         container = self.docker_client.create_container(
             image,
             command=get_flow_run_command(flow_run),
@@ -411,6 +417,7 @@ def deploy_flow(self, flow_run: GraphQLResult) -> str:
             volumes=container_mount_paths,
             host_config=self.docker_client.create_host_config(**host_config),
             networking_config=networking_config,
+            labels=labels,
         )
 
         # Start the container


Test patch:
diff --git a/tests/agent/test_docker_agent.py b/tests/agent/test_docker_agent.py
--- a/tests/agent/test_docker_agent.py
+++ b/tests/agent/test_docker_agent.py
@@ -200,6 +200,7 @@ def test_docker_agent_deploy_flow(core_version, command, api):
                 "flow": GraphQLResult(
                     {
                         "id": "foo",
+                        "name": "flow-name",
                         "storage": Docker(
                             registry_url="test", image_name="name", image_tag="tag"
                         ).serialize(),
@@ -220,6 +221,11 @@ def test_docker_agent_deploy_flow(core_version, command, api):
     assert api.create_host_config.call_args[1]["auto_remove"] is True
     assert api.create_container.call_args[1]["command"] == command
     assert api.create_container.call_args[1]["host_config"]["AutoRemove"] is True
+    assert api.create_container.call_args[1]["labels"] == {
+        "io.prefect.flow-id": "foo",
+        "io.prefect.flow-name": "flow-name",
+        "io.prefect.flow-run-id": "id",
+    }
     assert api.start.call_args[1]["container"] == "container_id"
 
 
@@ -231,6 +237,7 @@ def test_docker_agent_deploy_flow_uses_environment_metadata(api):
                 "flow": GraphQLResult(
                     {
                         "id": "foo",
+                        "name": "flow-name",
                         "storage": Local().serialize(),
                         "environment": LocalEnvironment(
                             metadata={"image": "repo/name:tag"}
@@ -280,6 +287,7 @@ def test_docker_agent_deploy_flow_run_config(api, run_kind, has_docker_storage):
                 "flow": GraphQLResult(
                     {
                         "id": "foo",
+                        "name": "flow-name",
                         "storage": storage.serialize(),
                         "run_config": run.serialize() if run else None,
                         "core_version": "0.13.11",
@@ -313,6 +321,7 @@ def test_docker_agent_deploy_flow_unsupported_run_config(api):
                             "storage": Local().serialize(),
                             "run_config": LocalRun().serialize(),
                             "id": "foo",
+                            "name": "flow-name",
                             "core_version": "0.13.0",
                         }
                     ),
@@ -339,6 +348,7 @@ def test_docker_agent_deploy_flow_storage_raises(monkeypatch, api):
                         {
                             "storage": Local().serialize(),
                             "id": "foo",
+                            "name": "flow-name",
                             "environment": LocalEnvironment().serialize(),
                             "core_version": "0.13.0",
                         }
@@ -361,6 +371,7 @@ def test_docker_agent_deploy_flow_no_pull(api):
                 "flow": GraphQLResult(
                     {
                         "id": "foo",
+                        "name": "flow-name",
                         "storage": Docker(
                             registry_url="test", image_name="name", image_tag="tag"
                         ).serialize(),
@@ -387,6 +398,7 @@ def test_docker_agent_deploy_flow_no_pull_using_environment_metadata(api):
                 "flow": GraphQLResult(
                     {
                         "id": "foo",
+                        "name": "flow-name",
                         "storage": Local().serialize(),
                         "environment": LocalEnvironment(
                             metadata={"image": "name:tag"}
@@ -414,6 +426,7 @@ def test_docker_agent_deploy_flow_reg_allow_list_allowed(api):
                 "flow": GraphQLResult(
                     {
                         "id": "foo",
+                        "name": "flow-name",
                         "storage": Docker(
                             registry_url="test1", image_name="name", image_tag="tag"
                         ).serialize(),
@@ -442,6 +455,7 @@ def test_docker_agent_deploy_flow_reg_allow_list_not_allowed(api):
                     "flow": GraphQLResult(
                         {
                             "id": "foo",
+                            "name": "flow-name",
                             "storage": Docker(
                                 registry_url="test2", image_name="name", image_tag="tag"
                             ).serialize(),
@@ -477,6 +491,7 @@ def test_docker_agent_deploy_flow_show_flow_logs(api, monkeypatch):
                 "flow": GraphQLResult(
                     {
                         "id": "foo",
+                        "name": "flow-name",
                         "storage": Docker(
                             registry_url="test", image_name="name", image_tag="tag"
                         ).serialize(),
@@ -523,6 +538,7 @@ def test_docker_agent_deploy_flow_no_registry_does_not_pull(api):
                 "flow": GraphQLResult(
                     {
                         "id": "foo",
+                        "name": "flow-name",
                         "storage": Docker(
                             registry_url="", image_name="name", image_tag="tag"
                         ).serialize(),
@@ -813,6 +829,7 @@ def test_docker_agent_network(api):
                 "flow": GraphQLResult(
                     {
                         "id": "foo",
+                        "name": "flow-name",
                         "storage": Docker(
                             registry_url="test", image_name="name", image_tag="tag"
                         ).serialize(),
@@ -844,6 +861,7 @@ def test_docker_agent_deploy_with_interface_check_linux(
                 "flow": GraphQLResult(
                     {
                         "id": "foo",
+                        "name": "flow-name",
                         "storage": Docker(
                             registry_url="", image_name="name", image_tag="tag"
                         ).serialize(),
@@ -873,6 +891,7 @@ def test_docker_agent_deploy_with_no_interface_check_linux(
                 "flow": GraphQLResult(
                     {
                         "id": "foo",
+                        "name": "flow-name",
                         "storage": Docker(
                             registry_url="", image_name="name", image_tag="tag"
                         ).serialize(),