跳转至主要内容

Python编程

Docker入门指南 – 附带Python示例

Sprite
发表于 2023年12月8日

Docker是什么?

简而言之,Docker是一种容器工具,可以让你将应用程序部署在所谓的容器中,即主机机器上的隔离环境。容器允许你隔离应用程序的所有依赖项,并在不与系统产生冲突的情况下运行它。
Docker引擎容器和虚拟机之间有什么区别?

你可能知道什么是虚拟机(VM)。虚拟机使你能够在托管在另一台机器上的客户操作系统中运行应用程序。例如,如果我想在我的Windows计算机上使用Linux,我可以创建一个Linux虚拟机。

但是虚拟机比较吃资源。这就是为什么开发了容器:为了实现部分类似于虚拟机的隔离,同时不消耗那么多资源。

但是,虚拟机与主机机器完全隔离,而容器不是,因为它们使用主机机器的内核运行。换句话说,Linux机器只能包含Linux容器,而它完全可以包含Windows虚拟机。因此,容器必须遵守主机机器的架构。

Docker引擎

Docker引擎是一个程序,支持Docker容器的运行。对于熟悉虚拟机的人来说,它是一种替代的虚拟机监控程序。

要在一台机器上使用Docker,你只需要Docker引擎。这就是Docker的强大之处,无需任何依赖项来运行你的应用程序,只需Docker引擎。

一个简单的例子

我在Python中创建了一个聊天机器人。显然,我不能在我的电脑上部署这个机器人,因为个人电脑一般不会二十四小时运行。所以我想在我的云服务器上部署它。问题是,由于某种原因,我不想在我的云服务器上安装Python。所以在这种情况下我不能部署聊天机器人吗?

当然可以,我只需要使用一个包含我的应用程序、Python和我所需的所有依赖项(如requests、chat_bot.py等)的容器即可。

我只需要安装Docker引擎这个应用程序,它将允许我运行我的容器。

开始使用Docker


请参考Docker文档中的安装Docker Engine部分。

安装完成后,你可以使用以下命令检查Docker是否正常工作:

docker run hello-worl

正常工作情况下将输出

# Unable to find image 'hello-world:latest' locally# latest: Pulling from library/hello-world# 719385e32844: Pull complete # Digest: sha256:4f53e2564790c8e7856ec08e384732aa38dc43c52f02952483e3f003afbf23db# Status: Downloaded newer image for hello-world:latest# # Hello from Docker!# This message shows that your installation appears to be working correctly.# # To generate this message, Docker took the following steps:#  1. The Docker client contacted the Docker daemon.#  2. The Docker daemon pulled the "hello-world" image from the Docker Hub.#     (amd64)#  3. The Docker daemon created a new container from that image which runs the#     executable that produces the output you are currently reading.#  4. The Docker daemon streamed that output to the Docker client, which sent it#     to your terminal.# # To try something more ambitious, you can run an Ubuntu container with:#  $ docker run -it ubuntu bash# # Share images, automate workflows, and more with a free Docker ID:#  https://hub.docker.com/# # For more examples and ideas, visit:#  https://docs.docker.com/get-started/
Docker镜像是什么?

正如你所看到的,一个容器需要一个镜像来运行。但是什么是镜像?

这是一个简单的文件,包含Docker引擎能够理解的代码,用于创建一个容器。它包含要执行的各种命令和要安装的文件,以便正确运行你的应用程序。

这相当于虚拟机的快照:一个文件,可以让你重新创建整个虚拟机。

我可以在哪里找到Docker镜像?

有几种方法可以找到Docker镜像。首先,你可以在仓库中找到它们。Docker Hub就是这样一个仓库

仓库获取镜像,只需使用 docker pull 。例如,这是一个允许你在容器中使用Firefox的镜像。以下是如何拉取它:

docker pull linuxserver/firefox

另一种获取镜像的方法是自己构建镜像。

创建一个Docker镜像

这是通过使用所谓的Dockerfile完成的。这是一个包含构建Docker镜像的指令的文件。

对于我们的示例,让我们创建一个简单的Python程序的Docker镜像。Docker的优势在于你甚至不需要Python来创建这个镜像。创建文件hello.py:

print("Hello, World!")

然后在同一文件夹中创建一个名为“Dockerfile”的文件

# 使用 base imageFROM python:3.11
# WORKDIR 指定工作目录,RUN, CMD, ENTRYPOINT, COPY 和 ADD 都在该工作目录运行WORKDIR /app
# 复制文件到容器内COPY ./hello.py /app
# 当实例化容器时,运行命令CMD ["python", "hello.py"]

然后,你可以运行以下命令来构建镜像:

docker build -t hello-python .

它创建了一个名为 hello-python 的镜像

行一个容器

现在我们已经有了我们的镜像,我们只需要从中创建一个容器。为了做到这一点,我们使用 docker run

docker run hello-python[sprite@localhost Playground]$ docker run hello-python# Hello, World! 输出内容
持久化数据

当你使用 docker run 时,容器会被创建、执行,然后在其命令执行完成后无痕销毁。这是正常的,因为容器被设计为隔离。

另一方面,容器又可以在隔离环境之外为容器提供文件和文件夹,从而使数据持久化或在主机和容器之间共享文件。

让我们用一个例子来测试一下。创建文件 counter.py:

import os

file_path = "/app/data/count.txt"os.makedirs(os.path.dirname(file_path), exist_ok=True)
count = 0
if os.path.exists(file_path):with open(file_path, "r") as file:count = int(file.read())
count += 1
with open(file_path, "w") as file:file.write(str(count))
print(f"This program has been run {count} times.")

这个程序计算它被运行的次数。然后,更新Dockerfile文件。

FROM python:3.11WORKDIR /app
# Create a directory to store data inside the containerRUN mkdir /app/dataCOPY counter.py /app/CMD ["python", "counter.py"]
创建Docker镜像

docker build -t counter-app .

对于我们的第一次测试,让我们按照之前的方式运行我们的容器:

[sprite@localhost Playground]$ docker run counter-app# 输出 This program has been run 1 times.

如果我们想要再次运行我们的应用程序而不创建另一个容器,我们必须找到容器的ID或名称,并使用 docker start

[sprite@localhost Playground]$ docker ps --all# 输出# CONTAINER ID   IMAGE         COMMAND               CREATED         STATUS                     PORTS     NAMES# 064e0abc0dda   counter-app   "python counter.py"   5 seconds ago   Exited (0) 4 seconds ago             festive_jones

我们使用 docker ps –all 标志来列出所有的容器。

现在,我们只需复制ID并启动容器:

[sprite@localhost Playground]$ docker start 064e0abc0dda064e0abc0dda

这次,我们看不到我们应用程序的输出。这是因为 docker start 的输出不是我们应用程序的输出。我们必须使用 docker container logs 

[sprite@localhost Playground]$ docker container logs 064e0abc0dda# This program has been run 1 times.# This program has been run 2 times.

现在,如果我们重新创建相同的容器,你会发现数据被隔离在容器中,因为它会重置计数器,不使用先前的值:

[sprite@localhost Playground]$ docker run counter-app# This program has been run 1 times.

为了持久化数据,我们可以使用挂载。它们允许将主机机器上的卷映射到容器中的某个位置。以下是一个示例:

[sprite@localhost Playground]$ docker run -v $(pwd)/data:/app/data counter-app# This program has been run 1 times.

我将工作目录中的数据目录映射到容器中的数据目录。如果操作正确,容器应该在我的计算机的工作目录中创建一个文件,最终还会创建一个目录。

[sprite@localhost Playground]$ ls data# count.txt[sprite@localhost Playground]$ cat data/count.txt# 1 

现在,让我们重新启动我们的容器:

[sprite@localhost Playground]$ docker start e0aa18e806cde0aa18e806cd

如果我检查这个文件:

[sprite@localhost Playground]$ cat data/count.txt2

它起作用了,这个文件不再是隔离的,因为容器可以写入它。现在,我删除了我的容器并重新创建它,计数依然会从上一次的值(2)开始

[sprite@localhost Playground]$ docker rm e0aa18e806cd# e0aa18e806cd[sprite@localhost Playground]$ docker run -v $(pwd)/data:/app/data counter-app# This program has been run 3 times.
总结

现在,你应该对Docker有个基础的了解了,可以开始将你的应用程序容器化了。后面我们再出一篇讲解Docker Compose。

写作不易,欢迎关注

分类:

评论已关闭。