我有一个 docker-compose 设置,它分三步部署:
dc up -d
(dc
是docker-compose
的别名)dc run web /usr/local/bin/python create_db.py
dc run -d web /usr/local/bin/python -u manage.py populateDB
第 2 步和第 3 步创建新容器(参见前两个):
~/Documents/Project » docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2ead532ea58b myproject_web "/usr/local/bin/pytho" 8 minutes ago Up 8 minutes 8000/tcp myproject_web_run_2
64e1f81ecd1a myproject_web "/usr/local/bin/pytho" 9 minutes ago Restarting (0) About a minute ago 8000/tcp myproject_web_run_1
9f5c670d4d7f myproject_nginx "/usr/sbin/nginx" 40 minutes ago Up 40 minutes 0.0.0.0:80->80/tcp myproject_nginx_1
46d3e8c09c03 myproject_web "/usr/local/bin/gunic" 40 minutes ago Up 40 minutes 8000/tcp myproject_web_1
ea876e68c8c6 postgres:latest "/docker-entrypoint.s" 40 minutes ago Up 40 minutes 0.0.0.0:5432->5432/tcp myproject_postgres_1
这一切都很好,除了他们在他们的工作完成后不退出。
例如,create db 脚本,如您所见,它总是在创建数据库后重新启动。一旦
achromap_web_run_2
完成填充数据库,它将添加每条记录的第二个副本,然后是第三个,等等。永远。
在 github 上,这似乎是 docker 要求的,
docker run --rm
标志处理它。但是--rm
和-d
不相容,我不明白。
你知道如何杀死已经完成其功能的容器吗?具体来说,一旦create_db.py调用
dc run web /usr/local/bin/python create_db.py
,如何让exit()
退出?或者有更好的方法吗?
我想你可能把两件事混为一谈了。
它的存在是为了在容器完成后进行清理,因此它不会在死容器池中徘徊。正如您已经发现的那样,它与
-d
不兼容。但在这种情况下,你根本不需要它。
(也可在 docker-compose 中用作
restart
属性。)
此标志设置重启策略。默认情况下,它设置为
no
,但您可以将其设置为其他一些值,包括 always
。我怀疑你目前将它设置为always
,这将强制容器在每次自行停止时重新启动。
如果您手动停止容器 (
docker stop ...
),那么自动重启将不会启动。但是如果进程自己退出,或者崩溃了,那么容器会被重启。这是可用的,原因很明显,因此如果它崩溃,您的服务将重新启动。
我会说你需要的是使用
exec
而不是 run
来完成这些任务。
首先,正常运行您的容器(即
docker-compose up -d
)。
而不是使用
run
来执行create_db.py
,使用exec
。
docker-compose exec web /usr/local/bin/python create_db.py
这将使用您已经运行的容器,执行一次脚本,当脚本退出时,您就完成了。由于您没有创建新容器(就像
run
所做的那样),因此之后没有清理工作。
请注意,您不需要经常与
-it
一起使用的 docker exec
标志。 docker-compose 默认情况下在 exec
上模拟 tty。
我创建了一个 Python 脚本来停止所有 docker 容器,并在其中一个容器退出时将其删除。至于 docker compose 文件,一旦容器退出,就没有停止容器的标志。您可以按照自己喜欢的方式修改它,例如,除了 docker-compose 之外,您还可以在函数“start_docker_services”和“docker_services_watcher”中使用 docker run 命令。
import os, time, multiprocessing
# Process class
class Process(multiprocessing.Process):
def __init__(self, id):
super(Process, self).__init__()
self.id = id
def run(self):
if self.id == 0:
start_docker_services()
if self.id == 1:
docker_services_watcher()
def start_docker_services():
os.system("docker compose up --build")
def docker_services_watcher():
print("\ndocker services watcher will start in 10 seonds.")
time.sleep(10)
# all containers (reading how many containers are running)
mydata = os.popen("docker compose ps").read()
# print("\n", mydata)
keep_running = True
# as every service run on a port so we are counting the string tcp
total_services_in_start = mydata.count("/tcp")
while keep_running:
current_total_services = os.popen("docker compose ps").read().count("/tcp")
if current_total_services == total_services_in_start:
print(
f"all services are running, total services: \
{current_total_services} / {total_services_in_start}"
)
time.sleep(5) # after every 5 seconds will check again
else:
print("one of the service stopped, closing docker containers...")
keep_running = False
os.system("docker compose down")
if __name__ == '__main__':
p = Process(0)
p.start()
p = Process(1)
p.start()
p.join()