Skip to content

Commit

Permalink
Merge pull request #27 from touero/develop
Browse files Browse the repository at this point in the history
Implemented customized deletion of containers
  • Loading branch information
touero authored Dec 4, 2024
2 parents 48d1711 + eede389 commit 8874210
Show file tree
Hide file tree
Showing 17 changed files with 156 additions and 156 deletions.
4 changes: 3 additions & 1 deletion MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,6 @@ exclude dist
exclude build
exclude *.egg-info
exclude tests
exclude .coverage
exclude .coverage
exclude htmlcov
exclude .venv
8 changes: 7 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.PHONY: test clean build upload all
.PHONY: test clean install uninstall build upload all

TWINE_UPLOAD := twine upload --repository pypi --username __token__ --password $(TWINE_API_TOKEN)

Expand All @@ -21,6 +21,12 @@ clean:
rm -rf .coverage
rm -rf htmlcov

install:
pip install -e .

uninstall:
pip uninstall -y easier_docker

build:
python -m build

Expand Down
131 changes: 17 additions & 114 deletions WIKI.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,79 +7,33 @@ pip install easier-docker
```

## Explain
Two params it need now:
Two params it need now, and `network_config` and `extra_config` are kwargs:
> [!Note]
> 1. __container_config__: Necessary, run and manage containers on the server. Run a container. By default, it will wait for the container to finish and return its logs, similar to `docker run`.
> 2. __network_config__: Unnecessary, create and manage networks on the server. For more information about networks, see the [Engine documentation](https://docs.docker.com/network/). Create a network. Similar to the `docker network create`.
> - __container_config__: Necessary, run and manage containers on the server. Run a container. By default, it will wait for the container to finish and return its logs, similar to `docker run`.
> - __network_config__: Unnecessary, create and manage networks on the server. For more information about networks, see the [Engine documentation](https://docs.docker.com/network/). Create a network. Similar to the `docker network create`.
> - __extra_config__: Unnecessary, add extra configurations to the container.Currently used to control whether existing containers will be automatically removed.
Two params config please check:
> [!Important]
> 1. __container_config__: [Docker SDK for Python with Container](https://docker-py.readthedocs.io/en/7.1.0/containers.html)
> 2. __network_config__: [Docker SDK for Python with Network](https://docker-py.readthedocs.io/en/7.1.0/networks.html)
> 3. __extra_config__: Include and default value: `is_remove`, `days_ago_remove`, `remove_now`,
>> `is_remove`: default value is `0`, if it is `1`, enable function that will remove the existing container with the same name.
>> `days_ago_remove`: default value is `3`, it will remove the existing container with the same name if it is older than the specified number of days.
>> `remove_now`: default value is `0`, if it is `1`, `days_ago_remove`will be ineffective, it will remove the existing container with the same name immediately.

## Usage
### Use examples in code
[example.py](https://github.com/touero/easier-docker/blob/master/example/example.py)
```bash
python example.py
```
```python
# example.py
import os

from easierdocker import EasierDocker

if __name__ == '__main__':
parent_dir = os.getcwd()
host_script = os.path.join(parent_dir, 'example')
container_script = '/path/to/container'
container_config = {
'image': 'python:3.9',
'name': 'python_test',
'volumes': {
f'{host_script}': {'bind': container_script, 'mode': 'rw'}
},
'detach': True,
'command': ["sh", "-c", f'cd {container_script} && python docker_example.py'],
}
network_config = {
'name': 'bridge',
'driver': 'bridge',
}
easier_docker = EasierDocker(container_config, network_config)
easier_docker.start()

"""
>>> 2024-02-18 17:02:29,360 - INFO - easier-docker ==> Find docker image: [python:3.9] locally...
>>> 2024-02-18 17:02:29,364 - INFO - easier-docker ==> Image: [python:3.9] is found locally
>>> 2024-02-18 17:02:29,367 - INFO - easier-docker ==> Network id: [13c5a6cb0137], name: [host]
>>> 2024-02-18 17:02:29,368 - INFO - easier-docker ==> Network id: [27d6b39aeef6], name: [none]
>>> 2024-02-18 17:02:29,368 - INFO - easier-docker ==> Network id: [eb71aacede75], name: [bridge]
>>> 2024-02-18 17:02:29,368 - INFO - easier-docker ==> Network: [bridge] is found locally...
>>> 2024-02-18 17:02:29,368 - INFO - easier-docker ==> Find docker container: [python_test] locally...
>>> 2024-02-18 17:02:29,370 - INFO - easier-docker ==> ContainerNotFound: [python_test], it will be created
>>> 2024-02-18 17:02:31,744 - INFO - easier-docker ==> Container name: [python_test] is running
>>> 2024-02-18 17:02:31,744 - INFO - easier-docker ==> Container id: [42f361ef636d] is running
>>> 2024-02-18 17:02:31,744 - INFO - easier-docker ==> Container ip address: [172.17.0.2]
>>> 2024-02-18 17:02:31,744 - INFO - easier-docker ==> Successfully container is running and be created at 2024-02-18T09:02:29.381861Z
"""
```
The content of docker_example.py is
```python
# docker_example.py
def main():
import logging
import time
for i in range(1, 101):
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logging.info(f'sleep 30s, times:{i}')
time.sleep(30)

![code_start](/image/code_start.gif)

if __name__ == '__main__':
main()

```
As mentioned above, it can be executed without `network_config`.
and the docker container logs will be shown in the console.
[docker_example.py](https://github.com/touero/easier-docker/blob/master/example/docker_example.py)
![docker_logs](/image/docker_log.gif)

### Run directly from configuration file
> [!Note]
Expand All @@ -88,56 +42,5 @@ As mentioned above, it can be executed without `network_config`.
```bash
easier-docker -c config.yaml
```
The content of config.yaml is
```yaml
# config.yaml

container:
image: python:3.9
name: python_test
volumes:
D:\code-project\EasierDocker\example:
bind: /path/to/container
mode: rw
detach: true
command:
- sh
- -c
- cd /path/to/container && python docker_example.py

network:
name: bridge
driver: bridge

# >>> 2023-12-29 15:08:58,703 - INFO - easier-docker ==> config =
# >>> {
# >>> "image": "python:3.9",
# >>> "name": "python_test",
# >>> "volumes": {
# >>> "D:\\code-project\\EasierDocker\\example": {
# >>> "bind": "/path/to/container",
# >>> "mode": "rw"
# >>> }
# >>> },
# >>> "detach": true,
# >>> "command": [
# >>> "sh",
# >>> "-c",
# >>> "cd /path/to/container && python docker_example.py"
# >>> ]
# >>> }
# >>> 2023-12-29 15:08:58,707 - INFO - easier-docker ==> Find docker image: [python:3.9] locally...
# >>> 2023-12-29 15:08:58,724 - INFO - easier-docker ==> Image: [python:3.9] is found locally
# >>> 2023-12-29 15:08:58,725 - INFO - easier-docker ==> Find docker container: [python_test] locally...
# >>> 2023-12-29 15:08:58,730 - INFO - easier-docker ==> ContainerNotFound: [python_test], it will be created
# >>> 2023-12-29 15:09:00,989 - INFO - easier-docker ==> Container name: [python_test] is running
# >>> 2023-12-29 15:09:00,990 - INFO - easier-docker ==> Container id: [a9b642f2ddf3] is running
# >>> 2023-12-29 15:09:00,990 - INFO - easier-docker ==> Container ip address: [172.17.0.2]
# >>> 2023-12-29 15:09:00,991 - INFO - easier-docker ==> Successfully container is running and be created at 2023-12-29T07:08:58.738605891Z

```
| |
|------------------------------------------------------------------------------------------------------|
| ![container.png](https://github.com/weiensong/easier-docker/blob/master/image/container.png) |
| ![container_log.png](https://github.com/weiensong/easier-docker/blob/master/image/container_log.png) |

[config.yaml](https://github.com/touero/easier-docker/blob/master/example/config.yaml)
![file](/image/file.gif)
5 changes: 5 additions & 0 deletions example/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,8 @@ container:
network:
name: bridge
driver: bridge

extra:
'is_remove': 1
'days_ago_remove': 7
'remove_now': 0
7 changes: 6 additions & 1 deletion example/example.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,10 @@
'name': 'bridge',
'driver': 'bridge',
}
easier_docker = EasierDocker(container_config, network_config)
extra_config = {
'is_remove': 1,
'days_ago_remove': 3,
'remove_now': 1
}
easier_docker = EasierDocker(container_config, network_config=network_config, extra_config=extra_config)
easier_docker.start()
Binary file added image/code_start.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed image/container.png
Binary file not shown.
Binary file removed image/container_log.png
Binary file not shown.
Binary file added image/docker_log.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added image/file.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 3 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "easier-docker"
version = "2.2.5"
version = "2.2.6"
description = "Configure your container image information more easily in python, allowing the container in docker to execute the configured program you want to execute."
readme = "README.md"
requires-python = ">=3.8"
Expand All @@ -19,7 +19,8 @@ classifiers = [
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12"
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13"
]
dependencies = [
"docker~=7.1.0",
Expand Down
2 changes: 1 addition & 1 deletion src/easierdocker/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
from .log_re import log
from .config import Config

__version__ = '2.2.5'
__version__ = '2.2.6'
5 changes: 3 additions & 2 deletions src/easierdocker/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ def main():
config = Config(config_path).load_file()
log(f"config =\n {json.dumps(config, sort_keys=False, indent=4, separators=(',', ': '))}")
container_config = config['container']
network_config = config.get('network', None)
easier_docker = EasierDocker(container_config, network_config)
network_config = config.get('network', {})
extra_config = config.get('extra', {})
easier_docker = EasierDocker(container_config, network_config=network_config, extra_config=extra_config)
easier_docker.start()


Expand Down
1 change: 1 addition & 0 deletions src/easierdocker/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@
class ContainerStatus(IntEnum):
RUNNING = 1 # running
EXITED = 2 # exited
CREATED = 3 # created
27 changes: 24 additions & 3 deletions src/easierdocker/docker_utils.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,38 @@
import time

from datetime import datetime

from docker.models.containers import Container
from .log_re import log
from .constants import ContainerStatus


def check_container(container: Container) -> ContainerStatus:
for _ in range(60):
def check_container_status(container: Container) -> ContainerStatus:
for index in range(60):
time.sleep(1)
if container.status != ContainerStatus.RUNNING.name.lower():
if container.status == ContainerStatus.CREATED.name.lower():
continue
if container.status != ContainerStatus.RUNNING.name.lower() and index == 0:
container.reload()
continue
elif container.status == ContainerStatus.RUNNING.name.lower():
return ContainerStatus.RUNNING
elif container.status == ContainerStatus.EXITED.name.lower():
log(f'Container name: [{container.name}] is exited')
return ContainerStatus.EXITED


def check_time(target_time_str, days_ago_remove):
"""
Check if the target_time_str is within the last days_ago_remove days
:param target_time_str: timestamp in ISO 8601 format, accurate to nanoseconds.
:param days_ago_remove: how many days old will the container be forcibly removed
:return:
"""
target_time_str = target_time_str[:26] + 'Z'
target_time = datetime.strptime(target_time_str, "%Y-%m-%dT%H:%M:%S.%fZ")
current_time = datetime.utcnow()
time_diff = current_time - target_time
if time_diff.days >= days_ago_remove:
return True
return False
Loading

0 comments on commit 8874210

Please sign in to comment.