docker 2:入门,第 2 部分:容器

入门,第 2 部分:容器

预计阅读时间: 5 分钟

先决条件

简介

现在可以开始按照 Docker 方式构建应用。我们将从此类应用的层次结构的底层(即,容器)开始,这是本页面上涵盖的内容。在此级别之上是服务,它定义了容器在生产中的行为方式(请参阅第 3 部分)。最后,处于最高级别的是技术栈,用于定义所有服务的交互(请参阅第 5 部分)。

  • 技术栈
  • 服务
  • 容器(您在此处)

您的新开发环境

过去,如果要开始编写 Python 应用,您的第一项业务是将 Python 运行时安装到机器上。但是,这会导致机器上的环境必须如此,才能使应用按预期运行;对于运行应用的服务器来说,也同样如此。

借助 Docker,您只需将可移植的 Python 运行时抓取为镜像,而无需进行安装。然后,您的构建可以将基本 Python 镜像与应用代码包含在一起,从而确保应用、其依赖项及运行时都一起提供。

这些可移植的镜像由 Dockerfile 定义。

使用 Dockerfile 定义容器

Dockerfile 将在您的容器内定义环境中执行的操作。对网络接口和磁盘驱动器等资源的访问在此环境内实现虚拟化,这将独立于系统的其余部分,因此您必须将端口映射到外部,并具体说明您要“复制”到该环境的文件。但是,在执行此操作后,您可以期望此 Dockerfile 中定义的应用构建的行为在运行时始终相同。

Dockerfile

创建空目录并将名为 Dockerfile 的此文件放入其中。记录说明每个语句的注释。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 将官方 Python 运行时用作父镜像
FROM python:2.7-slim
 
# 将工作目录设置为 /app
WORKDIR /app
 
# 将当前目录内容复制到位于 /app 中的容器中
ADD . /app
 
# 安装 requirements.txt 中指定的任何所需软件包
RUN pip install -r requirements.txt
 
# 使端口 80 可供此容器外的环境使用
EXPOSE 80
 
# 定义环境变量
ENV NAME World
 
# 在容器启动时运行 app.py
CMD ["python", "app.py"]

 

Dockerfile 引用了我们尚未创建的内容,名为 app.pyrequirements.txt。在后续步骤中,我们会准备好这些内容。

备注:中文官网整理时可能粗心了,ADD ./app 中间忘了加空格

应用自身

抓取这两个文件并将其放入 Dockerfile 所在的文件夹。这将完成我们的应用,如您所见它非常简单。将上述 Dockerfile 构建到镜像中时,由于 DockerfileADD 命令而显示 app.pyrequirements.txt,并且借助 EXPOSE 命令,将能够通过 HTTP 访问 app.py 的输出。

requirements.txt

Flask
Redis

app.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from flask import Flask
from redis import Redis, RedisError
import os
import socket
 
# Connect to Redis
redis = Redis(host="redis", db=0, socket_connect_timeout=2, socket_timeout=2)
 
app = Flask(__name__)
 
@app.route("/")
def hello():
    try:
        visits = redis.incr("counter")
    except RedisError:
        visits = "<i>cannot connect to Redis, counter disabled</i>"
 
    html = "<h3>Hello {name}!</h3>" \
           "<b>Hostname:</b> {hostname}<br/>" \
           "<b>Visits:</b> {visits}"
    return html.format(name=os.getenv("NAME", "world"), hostname=socket.gethostname(), visits=visits)
 
if __name__ == "__main__":
    app.run(host='0.0.0.0', port=80)

 

现在,我们可以看到,pip install -r requirements.txt 将安装 Python 的 Flask 和 Redis 库,而此应用将输出环境变量 NAME 以及对 socket.gethostname() 调用的输出。最后,由于 Redis 未在运行(因为我们仅安装了 Python 库,而未安装 Redis 自身),因此我们应期望尝试在此处使用它将失败并生成错误消息。

:在容器内时访问主机的名称将检索容器 ID,这类似于正在运行的可执行文件的进程 ID。

构建应用

好的!您不需要 Python 或系统上 requirements.txt 中的任何内容,也不会构建或运行此镜像来将它们安装在系统上。似乎您尚未真正使用 Python 和 Flask 设置环境,但已进行设置。

以下是 ls 应显示的内容:

$ ls
Dockerfile		app.py			requirements.txt

现在,运行构建命令。这将创建 Docker 镜像,我们将使用 -t 对其进行标记,以使其具有友好名称。

docker build -t friendlyhello .

此时可能会失败 安装pip包的时候超时:ReadTimeoutError: HTTPSConnectionPool(host='pypi.python.org', port=443): Read timed out.
需要FQ 技术应该没有国界,但是却有墙

您已构建的镜像在何处?它位于您的机器上的本地 Docker 镜像库中:

$ docker images

REPOSITORY            TAG                 IMAGE ID
friendlyhello         latest              326387cea398

运行应用

运行应用,使用 -p 参数将机器的 4000 端口映射到容器暴露的 80 端口:

docker run -p 4000:80 friendlyhello

您将看到 Python 正在为应用提供服务(网址为 http://0.0.0.0:80)的通知。但是,该消息来自不知道您已将其 80 端口映射到 4000 端口的容器的内部,因此需要将正确 URL 更改为 http://localhost:4000

在 Web 浏览器中访问该 URL,以查看网页上提供的显示内容,包括“Hello World”文本、容器 ID以及 Redis 错误消息。

浏览器中的 Hello World

您还可以在 shell 中使用 curl 命令查看相同内容。

$ curl http://localhost:4000

<h3>Hello World!</h3><b>Hostname:</b> 8fc990912a14<br/><b>Visits:</b> <i>cannot connect to Redis, counter disabled</i>

:此端口重映射 4000:80 用于说明您在 Dockerfile 中暴露的内容与使用 docker run -p 发布的内容之间的差异。在后续步骤中,我们只需将主机上的 80 端口映射到容器中的 80 端口并使用 http://localhost

在终端上按 CTRL+C 退出。

现在,我们从后台在分离模式下运行应用。

docker run -d -p 4000:80 friendlyhello

您将获得应用的长容器 ID,然后将返回到终端。容器现在在后台运行。您还可以使用 docker ps 查看缩写容器 ID(这两种 ID 可以在运行命令时交换工作):

$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED
1fa4ab2cf395        friendlyhello       "python app.py"     28 seconds ago

您将看到 CONTAINER IDhttp://localhost:4000 上的内容相匹配。

现在,使用 docker stopCONTAINER ID 结束该进程,如下所示:

docker stop 1fa4ab2cf395

共享镜像

为了说明我们刚才创建的可移植性,可以上传已构建的镜像并在其他地方运行它。但是,在您要将容器部署到生产环境中时,需要了解如何推送到镜像库。

镜像库是镜像仓库的集合,而镜像仓库是镜像的集合 - 除了代码已构建之外,类似于 GitHub 镜像仓库。镜像库中的一个帐户可以创建很多镜像仓库。默认情况下,docker CLI 使用 Docker 的公用镜像库。

:我们将在此处使用 Docker 的公用镜像库,仅仅因为它是免费的并且经过预先配置,但有许多公用镜像库可供选择,并且您甚至可以使用 Docker Trusted Registry 设置您自己的专用镜像库。

使用 Docker ID 登录

如果您没有 Docker 帐户,请在 cloud.docker.com 中进行注册。记录您的用户名。

登录本地机器上的 Docker 公用镜像库。

docker login

标记镜像

用于将本地镜像与镜像库中的镜像仓库相关联的表示法为 username/repository:tag。tag 是可选项,但建议使用它,因为这是镜像库用于为 Docker 镜像指定版本的机制。针对上下文为镜像库和 tag 指定有意义的名称,例如 get-started:part1.这会将镜像放入 get-started 镜像仓库并将其标记为 part1

现在,将其合并到一起,以标记镜像。使用您的用户名、镜像仓库和标签名称运行 docker tag image,以便镜像将上传到所需目的地。此命令的语法为:

docker tag image username/repository:tag

例如:

docker tag friendlyhello john/get-started:part1

运行 docker images 以查看新标记的镜像。(您还可以使用 docker image ls。)

$ docker images
REPOSITORY               TAG                 IMAGE ID            CREATED             SIZE
friendlyhello            latest              d9e555c53008        3 minutes ago       195MB
john/get-started         part1               d9e555c53008        3 minutes ago       195MB
python                   2.7-slim            1c7128a655f6        5 days ago          183MB
...

发布镜像

将已标记的镜像上传到镜像仓库:

docker push username/repository:tag

完成后,将公开此上传的结果。如果登录 Docker Hub,可以使用其 pull 命令看到新的镜像。

从远程镜像仓库中拉取并运行镜像

从现在开始,您可以使用 docker run,并且可以使用以下命令在任何机器上运行您的应用:

docker run -p 4000:80 username/repository:tag

如果镜像在机器本地不可用,Docker 将从镜像仓库中拉取它。

$ docker run -p 4000:80 john/get-started:part1
Unable to find image 'john/get-started:part1' locally
part1:Pulling from orangesnap/get-started
10a267c67f42:Already exists
f68a39a6a5e4:Already exists
9beaffc0cf19:Already exists
3c1fe835fb6b:Already exists
4c9f1fa8fcb8:Already exists
ee7d8f576a14:Already exists
fbccdcced46e:Already exists
Digest: sha256:0601c866aab2adcc6498200efd0f754037e909e5fd42069adeff72d1e2439068
Status: Downloaded newer image for john/get-started:part1
 * Running on http://0.0.0.0:80/ (Press CTRL+C to quit)

:如果您未指定这些命令中的 :tag 部分,在进行构建和运行镜像时,将使用标签 :latest 。Docker 将使用在未指定标签的情况下运行的镜像的最新版本(可以不是最新镜像)。

无论 docker run 在何处执行,它将从 requirements.txt 拉取您的镜像及 Python 和所有依赖项,然后运行代码。所有内容都在一个小软件包中提供,并且主机只需安装 Docker 来运行它。

第 2 部分总结

以上是此页面的所有内容。在下一节中,我们学习如何通过在服务中运行此容器来扩展应用。

继续阅读第 3 部分 »

概要和速查表(可选)

以下是关于本页面所涵盖内容的终端记录

以下是此页面上的基本 Docker 命令列表,以及一些相关命令(如果您要在继续之前进行进一步探索)。

docker build -t friendlyname .# 使用此目录的 Dockerfile 创建镜像
docker run -p 4000:80 friendlyname  # 运行端口 4000 到 90 的“友好名称”映射
docker run -d -p 4000:80 friendlyname         # 内容相同,但在分离模式下
docker ps                                 # 查看所有正在运行的容器的列表
docker stop <hash>                     # 平稳地停止指定的容器
docker ps -a           # 查看所有容器的列表,甚至包含未运行的容器
docker kill <hash>                   # 强制关闭指定的容器
docker rm <hash>              # 从此机器中删除指定的容器
docker rm $(docker ps -a -q)           # 从此机器中删除所有容器
docker images -a                               # 显示此机器上的所有镜像
docker rmi <imagename>            # 从此机器中删除指定的镜像
docker rmi $(docker images -q)             # 从此机器中删除所有镜像
docker login             # 使用您的 Docker 凭证登录此 CLI 会话
docker tag <image> username/repository:tag  # 标记 <image> 以上传到镜像库
docker push username/repository:tag            # 将已标记的镜像上传到镜像库
docker run username/repository:tag                   # 运行镜像库中的镜像

容器, python, 代码, 编码, 构建, 推送, 运行

posted @   愤怒的企鹅  阅读(167)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
点击右上角即可分享
微信分享提示