介绍
Docker 是一个强大的工具,用于容器化(containerizing)应用程序,这使得开发、部署和管理软件变得更容易。在本教程中,我们将探讨如何在 Docker 容器启动时运行 Python 脚本。这种方法允许你自动化应用程序的部署并简化你的开发工作流程。在本实验(Lab)结束时,你将能够创建一个 Docker 容器,该容器会在启动时自动执行你的 Python 脚本。
Docker 是一个强大的工具,用于容器化(containerizing)应用程序,这使得开发、部署和管理软件变得更容易。在本教程中,我们将探讨如何在 Docker 容器启动时运行 Python 脚本。这种方法允许你自动化应用程序的部署并简化你的开发工作流程。在本实验(Lab)结束时,你将能够创建一个 Docker 容器,该容器会在启动时自动执行你的 Python 脚本。
在第一步中,我们将创建一个简单的 Python 脚本,该脚本将在我们的 Docker 容器启动时执行。此脚本将打印一条消息以及当前的日期和时间。
让我们首先为我们的项目创建一个新目录:
mkdir -p ~/project/python-docker
cd ~/project/python-docker
现在,让我们使用 nano 文本编辑器创建一个名为 app.py 的简单 Python 脚本:
nano app.py
在 nano 编辑器中,添加以下 Python 代码:
import datetime
import time
print("Hello from the Docker container!")
print(f"Current date and time: {datetime.datetime.now()}")
## Keep the container running to demonstrate it's working
print("Container is running...")
while True:
print("Container still running... Press Ctrl+C to stop.")
time.sleep(10)
通过按 Ctrl+O,然后 Enter 来保存文件,并通过按 Ctrl+X 退出 nano。
此脚本将:
让我们测试我们的 Python 脚本,以确保它正常工作:
python3 app.py
你应该看到类似于以下的输出:
Hello from the Docker container!
Current date and time: 2023-10-12 14:30:45.123456
Container is running...
Container still running... Press Ctrl+C to stop.
按 Ctrl+C 停止脚本。
现在我们有了一个可运行的 Python 脚本,我们可以继续创建一个 Docker 容器,该容器将在启动时运行此脚本。
现在我们已经准备好了 Python 脚本,让我们创建一个 Dockerfile 来定义应该如何构建我们的 Docker 容器。
Dockerfile 是一个文本文件,其中包含构建 Docker 镜像所需的所有命令。此镜像将包含我们的 Python 脚本和所有必要的依赖项。
在同一目录 (~/project/python-docker) 中,创建一个名为 Dockerfile 的新文件:
nano Dockerfile
将以下内容添加到 Dockerfile 中:
## Use the official Python image as base
FROM python:3.9-slim
## Set working directory
WORKDIR /app
## Copy the Python script to the container
COPY app.py .
## Command to run when the container starts
CMD ["python", "app.py"]
通过按 Ctrl+O,然后 Enter,再按 Ctrl+X 来保存并退出 nano。
让我们了解 Dockerfile 中的每一行都做了什么:
FROM python:3.9-slim:这指定要使用的基础镜像。我们使用官方的 Python 3.9 镜像,并使用 slim 变体来保持较小的体积。
WORKDIR /app:这会将容器内的工作目录设置为 /app。
COPY app.py .:这会将我们的 Python 脚本从宿主机复制到容器中的当前工作目录(即 /app)。
CMD ["python", "app.py"]:这指定了容器启动时要运行的命令。在这种情况下,它将运行我们的 Python 脚本。
现在,让我们使用此 Dockerfile 构建我们的 Docker 镜像:
docker build -t python-app .
此命令从当前目录 (.) 中的 Dockerfile 构建一个 Docker 镜像,并使用名称 python-app 进行标记(-t 代表 tag)。
你应该看到类似于以下的输出:
Sending build context to Docker daemon 3.072kB
Step 1/4 : FROM python:3.9-slim
---> 1bc6a8a2a52f
Step 2/4 : WORKDIR /app
---> Using cache
---> 2a3b7a28c9e5
Step 3/4 : COPY app.py .
---> Using cache
---> 9a0b7a1c8c2d
Step 4/4 : CMD ["python", "app.py"]
---> Using cache
---> 3b0c7a2d9f1e
Successfully built 3b0c7a2d9f1e
Successfully tagged python-app:latest
输出可能有所不同,但如果一切顺利,你应该看到 "Successfully built" 和 "Successfully tagged" 消息。
你现在已经成功创建了一个 Docker 镜像,其中包含你的 Python 脚本,并且当从该镜像启动容器时,它将运行该脚本。
现在我们已经构建了 Docker 镜像,我们可以基于此镜像运行一个容器。容器将在启动时自动执行我们的 Python 脚本。
要从我们的镜像运行容器,请使用以下命令:
docker run --name python-container python-app
此命令从我们在上一步中创建的 python-app 镜像启动一个名为 python-container 的新容器。
你应该看到类似于以下的输出:
Hello from the Docker container!
Current date and time: 2023-10-12 15:45:30.123456
Container is running...
Container still running... Press Ctrl+C to stop.
Container still running... Press Ctrl+C to stop.
容器现在正在运行并执行我们的 Python 脚本。该脚本旨在无限期运行,每 10 秒打印一条消息。
按 Ctrl+C 停止查看日志,但请注意,容器仍在后台运行。
要验证容器是否正在运行,请使用以下命令:
docker ps
你应该在正在运行的容器列表中看到你的容器:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1a2b3c4d5e6f python-app "python app.py" 1 minute ago Up 1 minute python-container
要停止容器,请使用以下命令:
docker stop python-container
要再次启动容器,请使用:
docker start python-container
要查看正在运行的容器的日志:
docker logs python-container
这将显示我们 Python 脚本的输出。你可以按 Ctrl+C 退出日志视图。
当你完成时,要删除容器,首先停止它(如果它正在运行),然后删除它:
docker stop python-container
docker rm python-container
你现在已经成功创建并运行了一个 Docker 容器,该容器在启动时执行一个 Python 脚本。
环境变量是配置你的应用程序而无需更改代码的好方法。在这一步中,我们将修改我们的 Python 脚本以使用环境变量,并更新我们的 Dockerfile 以提供这些变量。
首先,让我们更新我们的 Python 脚本以读取一个环境变量:
nano app.py
修改脚本以包含环境变量支持:
import datetime
import time
import os
## Get the environment variable with a default value if not set
user_name = os.environ.get('USER_NAME', 'Guest')
print(f"Hello, {user_name}, from the Docker container!")
print(f"Current date and time: {datetime.datetime.now()}")
## Keep the container running to demonstrate it's working
print("Container is running...")
while True:
print("Container still running... Press Ctrl+C to stop.")
time.sleep(10)
通过按 Ctrl+O,然后 Enter,再按 Ctrl+X 来保存并退出 nano。
现在,让我们更新我们的 Dockerfile 以包含一个环境变量:
nano Dockerfile
更新 Dockerfile 以包含环境变量:
## Use the official Python image as base
FROM python:3.9-slim
## Set working directory
WORKDIR /app
## Set environment variable
ENV USER_NAME="Docker User"
## Copy the Python script to the container
COPY app.py .
## Command to run when the container starts
CMD ["python", "app.py"]
保存并退出 nano,然后重建 Docker 镜像:
docker build -t python-app-env .
现在,使用默认环境变量运行一个容器:
docker run --name python-env-container python-app-env
你应该在输出中看到带有 "Docker User" 的问候语:
Hello, Docker User, from the Docker container!
Current date and time: 2023-10-12 16:30:45.123456
Container is running...
按 Ctrl+C 停止查看日志。
停止并删除容器:
docker stop python-env-container
docker rm python-env-container
你也可以在运行容器时覆盖环境变量:
docker run --name python-env-container -e USER_NAME="LabEx Student" python-app-env
这次,你应该在问候语中看到你的自定义名称:
Hello, LabEx Student, from the Docker container!
Current date and time: 2023-10-12 16:35:15.789012
Container is running...
按 Ctrl+C 停止查看日志。
停止并删除容器:
docker stop python-env-container
docker rm python-env-container
在 Docker 中使用环境变量是一种常见的做法,可以使你的容器更具可配置性,而无需为小的更改而重建镜像。
在 Docker 中,有两个指令用于指定容器启动时应该运行的命令:CMD 和 ENTRYPOINT。它们具有不同的用途和行为,理解它们之间的区别对于容器管理至关重要。
ENTRYPOINT:定义容器启动时将运行的可执行文件。它在运行时更难被覆盖。CMD:为 ENTRYPOINT 提供默认参数,或者在未使用的 ENTRYPOINT 时指定整个命令。它在运行时很容易被覆盖。让我们通过创建两个不同的 Dockerfile 来探索区别。
首先,创建一个新的 Python 脚本,该脚本接受命令行参数:
nano greeting.py
添加以下代码:
import sys
print("Script started!")
if len(sys.argv) > 1:
print(f"Arguments provided: {sys.argv[1:]}")
for arg in sys.argv[1:]:
print(f"- {arg}")
else:
print("No arguments provided.")
print("Script finished!")
保存并退出 nano。
现在,让我们创建一个使用 CMD 的 Dockerfile:
nano Dockerfile.cmd
添加以下内容:
FROM python:3.9-slim
WORKDIR /app
COPY greeting.py .
CMD ["python", "greeting.py", "default", "arguments"]
保存并退出 nano。
构建镜像:
docker build -t python-cmd -f Dockerfile.cmd .
现在,创建另一个使用 ENTRYPOINT 的 Dockerfile:
nano Dockerfile.entrypoint
添加以下内容:
FROM python:3.9-slim
WORKDIR /app
COPY greeting.py .
ENTRYPOINT ["python", "greeting.py"]
CMD ["default", "arguments"]
保存并退出 nano。
构建镜像:
docker build -t python-entrypoint -f Dockerfile.entrypoint .
让我们从这两个镜像运行容器并观察差异。
首先,在没有额外参数的情况下,使用 CMD 镜像运行一个容器:
docker run --name cmd-container python-cmd
输出应该类似于:
Script started!
Arguments provided: ['default', 'arguments']
- default
- arguments
Script finished!
现在,使用 CMD 镜像运行一个容器,但提供自定义参数:
docker run --name cmd-container-custom python-cmd hello world
输出:
Script started!
No arguments provided.
Script finished!
请注意,整个命令被替换为 hello world,它们没有作为参数传递给我们的脚本。
现在,让我们在没有额外参数的情况下,使用 ENTRYPOINT 镜像运行一个容器:
docker run --name entrypoint-container python-entrypoint
输出:
Script started!
Arguments provided: ['default', 'arguments']
- default
- arguments
Script finished!
最后,使用 ENTRYPOINT 镜像运行一个容器并提供自定义参数:
docker run --name entrypoint-container-custom python-entrypoint hello world
输出:
Script started!
Arguments provided: ['hello', 'world']
- hello
- world
Script finished!
这次,我们的参数被正确地传递给 Python 脚本,因为 ENTRYPOINT 定义了可执行文件,并且提供给 docker run 的任何额外参数都会传递给该可执行文件。
ENTRYPOINTCMD 提供可以轻松覆盖的默认参数ENTRYPOINT 作为命令和 CMD 作为默认参数来组合两者清理容器:
docker rm cmd-container cmd-container-custom entrypoint-container entrypoint-container-custom
你现在已经了解了 Docker 中 CMD 和 ENTRYPOINT 之间的区别,这对于控制你的 Python 脚本在容器启动时的运行方式至关重要。
在这个实验中,你已经学习了如何在 Docker 容器启动时运行 Python 脚本。以下是你已经完成的内容:
这些技能是容器化 Python 应用程序并自动化其部署的基础。你现在可以:
有了这些知识,你可以构建更复杂的 Docker 应用程序,这些应用程序在启动时自动运行 Python 脚本,从而使你的部署过程更高效、更可靠。