先决条件
- 安装Docker 1.13或更高版本。
- 阅读第1部分的方向。
- 让您的环境快速测试,以确保您全部设置:
docker run hello-world
介绍
现在是开始构建Docker
应用程序的时候了。 我们将从这样一个应用程序的层次结构的底部开始,这是一个容器,我们在这个页面上介绍。 在这个层次之上是一个服务,它定义了容器在生产中的行为方式,涵盖在第3部分中。最后,顶层是堆栈,定义了所有服务的交互,第5部分所述。
- Stack
- Services
- Container (you are here)
您的新开发环境
过去,如果您要开始编写Python应用程序,则您的第一个业务是将Python运行时安装到您的计算机上。 但是,这会造成您的机器上的环境必须如此,以便您的应用程序按预期运行的情况; 同时运行您的应用程序的服务器。
使用Docker,您可以将便携式Python运行时作为图像,无需安装。 然后,您的构建可以将应用程序代码旁边的基本Python图像包含在内,确保您的应用程序,其依赖关系和运行时都一起运行。
这些便携式图像由称为Dockerfile
的东西定义。
定义具有Dockerfile文件的container
Dockerfile将定义容器中环境中的内容。 访问诸如网络接口和磁盘驱动器的资源在此环境中被虚拟化,这与您系统的其他部分是隔离的,因此您必须将端口映射到外部世界,并具体说明要将哪些文件“复制”到 那个环境。 但是,在这样做之后,您可以期望在此Dockerfile中定义的应用程序的构建将在运行的任何地方都运行正常。
Docker文件
创建一个空目录,并将该文件放在其中,名称为Dockerfile
。 注意说明每个陈述的意见。
# 使用官方Python运行时作为基础映像
FROM python:2.7-slim
# 将工作目录设置为/ app
WORKDIR /app
# 将当前目录内容复制到/ app中的容器中
ADD . /app
# 安装require.txt中指定的所需软件包
RUN pip install -r requirements.txt
# 使端口80可用于此容器外的世界
EXPOSE 80
# 定义环境变量
ENV NAME World
# 在容器启动时运行app.py
CMD ["python", "app.py"]
这个Docker文件是指我们还没有创建的几件事,即app.py
和requirements.txt
。 让我们来接下来的那些。
应用程序本身
抓住这两个文件,并将它们放在与Dockerfile
相同的文件夹中。 这完成了我们的应用程序,你可以看到它是非常简单的。 当上述Dockerfile内置到一个图像中时,由于该Dockerfile
的ADD
命令,app.py
和requirements.txt
将会出现,而通过EXPOSE
命令可以通过HTTP
访问来自app.py
的输出。
requirements.txt
Flask
Redis
app.py
from flask import Flask
from redis import Redis, RedisError
import os
import socket
# Connect to Redis
redis = Redis(host="redis", db=0)
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安装require.txt
安装了Python的Flask和Redis库,应用程序会打印出环境变量NAME
以及对socket.gethostname()
的调用输出。 最后,因为Redis没有运行(因为我们只安装了Python库,而不是Redis本身),我们应该期望在这里使用它的尝试将失败并产生错误消息。
注意:在容器内部访问主机的名称将检索容器ID,这与运行的可执行文件的进程ID类似。
构建应用程序
您的系统上的require.txt不需要Python或任何内容,也不构建或运行此映像将其安装在系统上。 你似乎并没有真正使用Python和Flask来设置一个环境,但是你已经有了。
这里是 ls
应该显示:
$ ls
Dockerfile app.py requirements.txt
现在运行build
命令。 这将创建一个Docker映像
,我们将使用-t
进行标记,因此它具有友好的名称。
docker build -t friendlyhello .
你的built image
在哪里? 它在您机器的本地Docker映像注册表中:
$ docker images
REPOSITORY TAG IMAGE ID
friendlyhello latest 326387cea398
运行应用程序
运行应用程序,将您的计算机端口4000映射到容器的EXPOSEd端口80,使用-p
:
docker run -p 4000:80 friendlyhello
您应该看到一个通知,指出Python正在http://0.0.0.0:80
为您的应用程序提供服务。 但是,该消息来自容器内部,这不知道您将该容器的端口80映射到4000,使得正确的URLhttp:// localhost:4000
。 去那里,你会看到“Hello World”文本,容器ID和Redis错误消息。
注意:4000:80的端口重新映射是为了展示Docker文件中EXPOSE之间的区别,以及使用docker run -p发布的内容。 在后面的步骤中,我们将主机上的端口80映射到容器中的端口80,并使用http:// localhost。
在您的终端中点击CTRL + C
退出。
现在让我们在后台运行应用程序,在分离模式下:
docker run -d -p 4000:80 friendlyhello
您的应用程序将获得长容器ID,然后被踢回您的终端。 您的容器在后台运行。 您还可以使用docker ps
查看缩写容器ID(并且在运行命令时可以互换):
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED
1fa4ab2cf395 friendlyhello "python app.py" 28 seconds ago
您会看到CONTAINER ID
与http:// localhost:4000
上的内容相符。
现在使用docker stop
来结束进程,使用CONTAINER ID
,像这样:
docker stop 1fa4ab2cf395
分享您的图像
为了演示我们刚刚创建的可移植性,让我们上传我们的构建并在其他地方运行它。 毕竟,您需要学习如何推动注册管理机构实现集装箱的部署。
注册表是存储库的集合,存储库是图像集合,类似于GitHub存储库,代码已经被构建。 注册表上的帐户可以创建许多存储库。 默认情况下,docker CLI已预先配置为使用Docker的公用注册表。
注意:我们将使用Docker的公共注册表,因为它是免费的和预配置的,但有很多公共选择,您甚至可以使用Docker Trusted Registry设置您自己的私人注册表。
如果您没有Docker帐户,请在cloud.docker.com
注册一个。 记下您的用户名。
登录您的本地机器:
docker login
现在,发布您的图像。 将本地映像与注册表上的存储库关联的符号是 username / repository:tag
。 标签是可选的,但建议; 这是注册表用于给Docker映像一个版本的机制。 所以,把所有的一切,输入你的用户名,和repo和标签名称,所以你现有的图像将上传到您想要的目的地:
docker tag friendlyhello username/repository:tag
上传您的标记图片:
docker push username/repository:tag
一旦完成,此上传的结果是公开的。 从现在开始,您可以使用docker运行并运行您的应用程序在任何机器上使用此命令:
docker run -p 4000:80 username/repository:tag
注意:如果不指定这些命令的
:tag
部分,则在构建和运行映像时,将会假定:latest
的标签。
无论在哪里运行docker,它会将您的图像以及Python以及require.txt中的所有依赖项提取出来,并运行您的代码。 它一起在一个整齐的小包裹,主机不需要安装任何东西,但Docker来运行它。
在下一节中,我们将通过在服务中运行此容器来了解如何扩展应用程序。
docker build -t friendlyname #使用此目录的Dockerfile创建映像
docker run -p 4000:80 friendlyname #运行“friendlyname”映射端口4000到80
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 #从注册表运行映像