第2部分:容器 | Part 2: Containers
开始,第2部分:容器
- 1:概况介绍
- 2:集装箱
- 3:服务
- 4:成群
- 5:堆叠
- 6:部署应用程序
先决条件
- 安装Docker版本1.13或更高版本...
- 阅读第1部分中的方向。
- 给您的环境一个快速测试运行,以确保您已经设置好了:
码头经营哈罗-世界
导言
现在是开始以Docker方式构建应用程序的时候了。我们将从这种应用程序的层次结构的底部开始,该应用程序是一个容器,我们将在此页面上进行介绍。在这个层次上面是一个服务,它定义了容器在生产中的行为方式,在第3部分中进行了讨论。最后,在顶层是堆栈,定义了第5部分中介绍的所有服务的交互。
- 堆叠
- 服务
集装箱
你在这里
您的新开发环境
在过去,如果您要开始编写Python应用程序,您的首要任务就是将Python运行时安装到您的计算机上。但是,这就造成了这样一种情况:为了使应用程序按预期运行,计算机上的环境必须是这样的;运行应用程序的服务器也是如此。
使用Docker,您只需获取一个可移植的Python运行时作为映像,无需安装。然后,您的构建可以将基本Python映像与应用程序代码放在一起,确保应用程序、其依赖项和运行时都能一起运行。
这些便携式图像是由称为a的东西定义的Dockerfile
。
使用Dockerfile
Dockerfile
将定义容器内环境中发生的事情。在这个环境中,对网络接口和磁盘驱动器等资源的访问是虚拟化的,这与系统的其他部分是隔离的,因此您必须将端口映射到外部世界,并具体说明要将哪些文件“复制”到该环境。但是,在这样做之后,您可以预期您的应用程序的构建是在Dockerfile
无论在哪里运行都会表现得完全一样。
Dockerfile
创建一个空目录。将目录(cd
)更改为新目录,创建一个名为的文件Dockerfile
,将以下内容复制并粘贴到该文件中并保存。注意解释新Dockerfile
中每条语句的注释。
# Use an official Python runtime as a parent image
FROM python:2.7-slim
# Set the working directory to /app
WORKDIR /app
# Copy the current directory contents into the container at /app
ADD . /app
# Install any needed packages specified in requirements.txt
RUN pip install -r requirements.txt
# Make port 80 available to the world outside this container
EXPOSE 80
# Define environment variable
ENV NAME World
# Run app.py when the container launches
CMD ["python", "app.py"]
这Dockerfile
指我们还没有创建的几个文件,即app.py
和requirements.txt
让我们创造下一个。
应用程序本身
再创建两个文件,requirements.txt
和app.py
,并将它们放在同一个文件夹中,Dockerfile
这就完成了我们的应用程序,正如您所看到的,这个应用程序非常简单。当以上Dockerfile
被塑造成一幅图像,app.py
和requirements.txt
会因为这个而出现Dockerfile
氏ADD
命令的输出。app.py
可以通过HTTP访问,这要感谢EXPOSE
命令。
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, 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没有运行%28,我们只安装了Python库,而没有安装Redis本身的%29,因此我们应该期望在这里使用它的尝试会失败并产生错误消息。
注
:在容器中检索容器ID时访问主机的名称,这就像正在运行的可执行文件的进程ID一样。
而已!您requirements.txt
的系统中不需要Python或其他任何东西,也不会在您的系统上安装或运行此映像。看起来你并没有真正用Python和Flask建立一个环境,但是你已经拥有了。
构建应用程序
我们已经准备好构建这个应用程序了。确保您仍然处于新目录的顶层。这是什么ls
应显示:
$ ls
Dockerfile app.py requirements.txt
现在运行Build命令。这将创建一个Docker映像,我们将使用它进行标记-t
所以它有个友好的名字。
docker build -t friendlyhello .
你的形象在哪里?它在您机器的本地Docker映像注册表中:
$ docker images
REPOSITORY TAG IMAGE ID
friendlyhello latest 326387cea398
运行应用程序
运行应用程序,使用以下方法将机器的端口4000映射到容器的已发布端口80-p
*
docker run -p 4000:80 friendlyhello
您应该会看到Python正在为您的应用提供服务的通知http://0.0.0.0:80
。但是该消息来自容器内部,它不知道你将该容器的端口80映射到4000,从而制作正确的URL http://localhost:4000
。
转到Web浏览器中的URL,查看网页上的显示内容,包括“HelloWorld”文本、容器ID和Redis错误消息。
您还可以使用curl
命令在shell中查看相同的内容。
$ 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
是为了证明你EXPOSE
在Dockerfile
,还有你publish
使用docker run -p
在后面的步骤中,我们将只将主机上的端口80映射到容器中的端口80,然后使用http://localhost
...
命中CTRL+C
在你的终点站辞职。
现在让我们在后台以分离模式运行该应用程序:
docker run -d -p 4000:80 friendlyhello
你得到你的应用程序的长容器ID,然后被踢回你的终端。您的容器正在后台运行。您还可以看到缩写的容器IDdocker container ls
%28并且在运行命令%29时两者都可以互换工作:
$ docker container ls
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的公共注
册表,仅仅是因为它是免费的和预先配置的,但是有许多公共注
册表可供选择,您甚至可以使用码头受信任登记处...
用您的码头ID登录
如果您没有码头帐户,请在Cloud.docker.com请记下你的用户名。
登录到本地计算机上的Docker公共注册表。
docker login
标记图像
将本地映像与注册表上的存储库关联的符号是username/repository:tag
标记是可选的,但建议使用它,因为它是注册表用于为Docker图像提供一个版本的机制。为上下文提供存储库和标记有意义的名称,如get-started:part1
。这将把图像放在get-started
存储库并将其标记为part1
...
现在,把它放在一起标记图像。跑docker tag image
使用您的用户名、存储库和标签名,以便图像将上载到您想要的目的地。该命令的语法是:
docker tag image username/repository:tag
例如:
docker tag friendlyhello john/get-started:part1
跑码头形象才能看到你的新标记图像。%28你也可以使用docker image ls
.%29
$ 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 run
并使用以下命令在任何机器上运行您的应用程序:
docker run -p 4000:80 username/repository:tag
如果映像在机器上本地不可用,Docker将从存储库中提取它。
docker image rm <image id>
$ 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将使用没有指定%28标记而运行的映像的最后一个版本,而不一定是最近的映像%29。
不管在哪里docker run
执行时,它将提取您的图像以及Python和requirements.txt
运行你的代码。所有这些都是在一个整洁的小包中一起运行的,主机只需要安装Docker就可以运行它了。
第二部分结论
这一页就这么多了。在下一节中,我们将学习如何通过在服务
...
继续第3部分
重述和备忘单%28可选%29
这是本页所涵盖内容的终端记录*
下面列出了这个页面中的基本Docker命令,以及一些相关的命令,如果您想在继续之前进行一番探索的话。
docker build -t friendlyname . # Create image using this directory's Dockerfile
docker run -p 4000:80 friendlyname # Run "friendlyname" mapping port 4000 to 80
docker run -d -p 4000:80 friendlyname # Same thing, but in detached mode
docker container ls # List all running containers
docker container ls -a # List all containers, even those not running
docker container stop <hash> # Gracefully stop the specified container
docker container kill <hash> # Force shutdown of the specified container
docker container rm <hash> # Remove specified container from this machine
docker container rm $(docker container ls -a -q) # Remove all containers
docker image ls -a # List all images on this machine
docker image rm <image id> # Remove specified image from this machine
docker image rm $(docker image ls -a -q) # Remove all images from this machine
docker login # Log in this CLI session using your Docker credentials
docker tag <image> username/repository:tag # Tag <image> for upload to registry
docker push username/repository:tag # Upload tagged image to registry
docker run username/repository:tag # Run image from a registry