Managing Running Container Lifetimes with the Docker Python SDK
Tags: automation, docker, python, containerorchestrati
Published: 2020-12-25 11:13:51

---
title: Managing Running Container Lifetimes with the Docker Python SDK
published: true
date: 2020-11-29 09:10:27 UTC
tags: automation,docker,python,containerorchestrati
canonical_url: https://medium.com/@jmarhee/managing-running-container-lifetimes-with-the-docker-python-sdk-71b58fb05465
---

I began building a service recently that will, upon user request, create a container (to provide said service, not a Container-as-a-Service-style workload), and then after 1–3 hours, terminate the container (taking the user’s session and local data away with it). The process for this required that I:

1. Retrieve the container’s StartedAt timestamp
2. Compare that timestamp to see if it’s been more than however long I’d like to limit a session to.
3. If a container is over that limit, it is queued for being Stopped and then ultimate the image pruned (in a separate task)

The setup for the script looks something like:

```
from datetime import datetime
import docker, dateparser 
```

and then initializing a string for comparison, normalized to look like the Docker API-provided timestamp (these get converted further down, this is just for readability in stdout and, while debugging, I can visually inspect the timestamps):

```
STARTING_TIME = str(datetime.now()).split(" ")[0]+ "T" + str(datetime.now()).split(" ")[1] + "Z"
```

then, before we do anything else, setup the Docker client:

```
client = docker.APIClient(base_url='unix://var/run/docker.sock')
```

In the SDK, stopping a container requires the use of the [Low level API functionality](https://docker-py.readthedocs.io/en/stable/api.html), so unless you require these features, you can leave the client set to docker.from\_env() without any further arguments.

```
def compare_time(run_time,container_started_at):

   dt = dateparser.parse(container_started_at).timestamp()

   mt = dateparser.parse(run_time).timestamp()

   interval = mt - dt

   return interval
```

This function will take two arguments: the STARTING\_TIME above (when the script started running) and the timestamp the container was created, and converts them to seconds, and returns that time in seconds.

```
def eval_interval(interval):

    eval = (interval / 60 ) / 60

    if eval > 2.0:

        return True

    else:

        return False
```

then we are checking if that difference in time exceeds, in this case, 2 hours. If it does, it returns True , which in the next function, indicates a running container is safe to terminate:

```
def check_containers():

    to_delete = []

    for c in client.containers.list():

        start_at = c.attrs['State']['StartedAt']

        interval = compare_time(STARTING_TIME,start_at)

        deleteable = eval_interval(interval)

        print(c.name + " (" + c.id + ") " + str(c.image) + " " + str(deleteable))

        if deleteable == True:

            to_delete.append({"id": c.id, "name": c.name})

        else:

            continue

    return to_delete
```

The to\_delete list this returns is a list of dictionaries that contains the id and name of the containers it detected a deletable value of True , with that in hand, it is handed to a function to delete, or handle:

```
def delete_containers(to_delete):

    failed_deletions = []

    for c in to_delete:

        try:

            running_container = str(c['id'])

            print("Deleting: " + running_container)

 **print(client.stop(container=running\_container))**

        except:

           failed_deletions.append(c)

           print("Failed to delete: " + c.id)
           continue

    return failed_deletions
```

This ingests the list of deletable containers, and then creates its own list of new containers that could not be deleted (and then optionally, I can handle this however I want in retry behavior later, but for now, it just throws an exception before continuing).

All of this is executed via a main function:

```
def main():

    to_delete = check_containers()

    delete_expired = delete_containers(to_delete)

    return delete_expired

if __name__ == " __main__":

    main()
```

For more about the packages I used:

- [dateparser - python parser for human readable dates - DateParser 1.0.0 documentation](https://dateparser.readthedocs.io/en/latest/)
- [Docker SDK for Python](https://docker-py.readthedocs.io/)