Docker交互模式和执行脚本

xfb7svmp  于 2023-05-06  发布在  Docker
关注(0)|答案(6)|浏览(183)

我在docker容器中有一个Python脚本需要执行,但我还需要在创建容器后(使用/bin/bash)对容器进行交互式访问。
我希望能够创建我的容器,执行我的脚本,并在容器内看到发生的更改/结果(不需要手动执行我的Python脚本)。
我目前面临的问题是,如果我在docker文件中使用CMD或ENTRYPOINT命令,一旦创建了容器,我就无法返回容器。我尝试使用docker start和docker attach,但出现错误:

sudo docker start containerID
sudo docker attach containerID
"You cannot attach to a stepped container, start it first"

理想情况下,接近于此:

sudo docker run -i -t image /bin/bash python myscript.py

假设我的python脚本包含类似这样的内容(它做什么无关紧要,在这种情况下,它只是创建一个带有文本的新文件):

open('newfile.txt','w').write('Created new file with text\n')

当我创建我的容器时,我希望我的脚本能够执行,并且我希望能够看到文件的内容。比如说

root@66bddaa892ed# sudo docker run -i -t image /bin/bash
bash4.1# ls
newfile.txt
bash4.1# cat newfile.txt
Created new file with text
bash4.1# exit
root@66bddaa892ed#

在上面的例子中,我的python脚本将在创建容器时执行,以生成新文件newfile.txt。这就是我需要的

fd3cxomn

fd3cxomn1#

我的做法略有不同,有一些优点。它实际上是多会话服务器而不是脚本,但在某些情况下可能更有用:

# Just create interactive container. No start but named for future reference.
# Use your own image.
docker create -it --name new-container <image>

# Now start it.
docker start new-container

# Now attach bash session.
docker exec -it new-container bash

主要优点是你可以将多个bash会话附加到单个容器。例如,我可以用bash执行一个会话来告诉日志,而在另一个会话中执行实际的命令。
顺便说一句,当你分离最后一个'exec'会话时,你的容器仍然在运行,所以它可以在后台执行操作

aydmsdu9

aydmsdu92#

你可以运行一个docker镜像,执行一个脚本,并使用一个命令进行交互式会话:
sudo docker run -it <image-name> bash -c "<your-script-full-path>; bash"
第二个bash将保持交互式终端会话打开,而不管创建镜像的Dockerfile中的CMD命令如何,因为CMD命令被上面的bash - c命令覆盖。
也不需要在Python脚本中附加像local("/bin/bash")这样的命令(或者在shell脚本中附加bash)。
假设脚本尚未通过ADD Dockerfile命令从Docker主机传输到Docker镜像,我们可以Map卷并从那里运行脚本:sudo docker run -it -v <host-location-of-your-script>:/scripts <image-name> bash -c "/scripts/<your-script-name>; bash"
示例:假设原问题中的python脚本已经在docker镜像上,我们可以省略-v option,命令简单如下:sudo docker run -it image bash -c "python myscript.py; bash"

iqih9akk

iqih9akk3#

为什么不是这个?

docker run --name="scriptPy" -i -t image /bin/bash python myscript.py
docker cp scriptPy:/path/to/newfile.txt /path/to/host
vim /path/to/host

或者你想让它留在集装箱上

docker run --name="scriptPy" -i -t image /bin/bash python myscript.py
docker start scriptPy
docker attach scriptPy

希望对你有帮助。

j2cgzkjk

j2cgzkjk4#

我想这就是你的意思。

**注意:*THis使用Fabric 因为我太懒和/或没有时间去解决如何正确地将stdin/stdout/stderr连接到终端,但你可以花时间直接使用subprocess.Popen *):
输出:

$ docker run -i -t test
Entering bash...
[localhost] local: /bin/bash
root@66bddaa892ed:/usr/src/python# cat hello.txt
Hello World!root@66bddaa892ed:/usr/src/python# exit
Goodbye!

Dockerfile:

# Test Docker Image

FROM python:2

ADD myscript.py /usr/bin/myscript

RUN pip install fabric

CMD ["/usr/bin/myscript"]

myscript.py:

#!/usr/bin/env python

from __future__ import print_function

from fabric.api import local

with open("hello.txt", "w") as f:
    f.write("Hello World!")

print("Entering bash...")
local("/bin/bash")
print("Goodbye!")
dldeef67

dldeef675#

有时,您的Python脚本可能会调用文件夹中的不同文件,如其他Python脚本,CSV文件,JSON文件等。
我认为最好的方法是与您的容器共享目录,这样可以更容易地创建一个可以访问所有所需文件的环境
创建一个文本脚本

sudo nano /usr/local/bin/dock-folder

添加此脚本作为其内容

#!/bin/bash

echo "IMAGE = $1"

## image name is the first param
IMAGE="$1"

## container name is created combining the image and the folder address hash
CONTAINER="${IMAGE}-$(pwd | md5sum | cut -d ' ' -f 1)"
echo "${IMAGE} ${CONTAINER}"

# remove the image from this dir, if exists
## rm                                      remove container command
## pwd | md5                               get the unique code for the current folder
## "${IMAGE}-$(pwd | md5sum)"                   create a unique name for the container based in the folder and image
## --force                                 force the container be stopped and removed
if [[ "$2" == "--reset" || "$3" == "--reset" ]]; then
        echo "## removing previous container ${CONTAINER}"
        docker rm "${CONTAINER}" --force
fi

# create one special container for this folder based in the python image and let this folder mapped
## -it                                     interactive mode
## pwd | md5                               get the unique code for the current folder
## --name="${CONTAINER}"                   create one container with unique name based in the current folder and image
## -v "$(pwd)":/data                       create ad shared volume mapping the current folder to the /data inside your container
## -w /data                                define the /data as the working dir of your container
## -p 80:80                                some port mapping between the container and host ( not required )
## pyt#hon                                  name of the image used as the starting point
echo "## creating container ${CONTAINER} as ${IMAGE} image"
docker create -it --name="${CONTAINER}" -v "$(pwd)":/data -w /data -p 80:80 "${IMAGE}"

# start the container
docker start "${CONTAINER}"

# enter in the container, interactive mode, with the shared folder and running python
docker exec -it "${CONTAINER}" bash

# remove the container after exit
if [[ "$2" == "--remove" || "$3" == "--remove" ]]; then
        echo "## removing container ${CONTAINER}"
        docker rm "${CONTAINER}" --force
fi

增加执行权限

sudo chmod +x /usr/local/bin/dock-folder

然后,您可以调用以下命令将脚本调用到项目文件夹:

# creates if not exists a unique container for this folder and image. Access it using ssh.
dock-folder python

# destroy if the container already exists and replace it
dock-folder python --replace

# destroy the container after closing the interactive mode
dock-folder python --remove

这个调用将创建一个新的python容器来共享你的文件夹。这使得文件夹中的所有文件都可以作为CSV或二进制文件访问。
使用此策略,您可以在容器中快速测试项目,并与容器交互以调试它。
这种方法的一个问题是关于再现性。也就是说,您可以使用运行应用程序所需的shell脚本来安装某些内容。但是,这种变化只是发生在你的容器内。因此,任何试图运行您的代码的人都必须弄清楚您在运行它时做了什么,并做同样的事情。
因此,如果您可以在不安装任何特殊内容的情况下运行项目,那么这种方法可能非常适合您。但是,如果你必须在容器中安装或更改一些东西才能运行你的项目,那么你可能需要创建一个Dockerfile来保存这些命令。这将使从加载容器、进行所需更改到加载文件的所有步骤都易于复制。

dz6r00yl

dz6r00yl6#

有时候不能简单地执行$ docker run -it <image>,因为它可能会运行入口点。在这种情况下,您可以执行以下操作(例如对于image python:3.9-slim):

$ docker run -itd python:3.9-slim
    b6b54c042af2085b0e619c5159fd776875af44351d22096b0c574ac1a7798318

$ docker ps
    CONTAINER ID        IMAGE                      COMMAND                  NAMES
    b6b54c042af2        python:3.9-slim            "python3"                sleepy_davinci

$ docker exec -it b6b54c042af2 bash

我使用docker ps只是为了显示它正在运行以及相应的容器ID。但也可以使用从docker run -itd ...返回的完整容器ID(* b6 b54 c 042 af 2085 b 0 e619 c5159 fd 776875 af 44351 d22096 b 0 c574 ac 1a 7798318 *)

相关问题