Part 2: Containers

司马昭
• 阅读 1354

要求

  • 安装了1.13或者更高版本的Docker

  • 阅读了Part1中的定位(我没写)

介绍

是时候用Docker构建一个app了。我们会从构建这样一个app的最底层开始,容器——我们这节所介绍的内容。在这层之上是服务,服务定义了容器们的在生产中的行为,在第3章介绍。最上层的是堆,定义了服务的交互行为,在第5章介绍。

  • 堆(Stack)

  • 服务(Services)

  • 容器(container)

新开发环境

使用docker,您可以直接获取一个可移植的Python运行时作为映像。然后,您的构建可以在应用程序代码旁边包含基本的Python映像,确保应用程序、它的依赖项和运行时环境一起运行。

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 --trusted-host pypi.python.org -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"]

您是否使用了代理服务器?

代理服务器一旦启动并运行,就可以阻塞连接到您的web应用程序。如果您在代理服务器后面,请在Dockerfile中添加以下几行,使用ENV命令为您的代理服务器指定主机和端口:

# Set proxy server, replace host:port with values for your servers
ENV http_proxy host:port
ENV https_proxy host:port

这个Dockerfile和我们还没有创建的两个文件有联系,即app.py和requirements.txt。接下来让我们创建这些。

应用程序本身

创建两个更多的文件,requirements.txt和app.py,并将它们放在与Dockerfile相同的文件夹中。这就完成了我们的应用程序,正如您所看到的非常简单。当上述Dockerfile被构建成一个Image,由于Dockerfile的ADD命令会添加requirements.txt和app.py,感谢EXPOSE使app.py的输出可以通过HTTP访问。

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没有运行(因为我们只安装了Python库,而不是Redis本身),我们应该期望在这里使用它的尝试会失败并产生错误消息。

注意:当容器内检索容器ID时访问主机名,这就像运行可执行文件的进程ID
就是这样!您不需要Python或requirements.txt中的任何东西在你的系统上,也不会在你的系统上安装或运行这个映像。看起来你并没有真正建立一个包含Python和Flask的环境,但是你有。

构建应用

我们已经准备好构建应用程序,确保您仍然处于新目录的顶层。下面是ls应该展示的:

$ ls
Dockerfile        app.py            requirements.txt

现在运行build命令。这创建了一个Docker映像,我们将使用- t标记它,因此它有一个友好的名称。

docker build -t friendlyhello .

你的构建的Image在哪里?就在你的机器的本地Docker图像注册表中:

$ docker images

REPOSITORY            TAG                 IMAGE ID
friendlyhello         latest              326387cea398

提示:您可以使用命令docker images或较新的docker image ls查看所有的镜像。它们给出相同的输出。

运行应用

运行应用程序,使用-p,将您的机器的端口4000映射到容器已经发布的端口80:

docker run -p 4000:80 friendlyhello

您应该看到一条消息,Python正在以http://0.0.0.0:80为您的应用服务。但是这个消息来自容器内部,它不知道您将该容器的80端口映射到4000,从而使正确的URL http://localhost:4000。
在web浏览器中访问该URL,可以看到web页面上显示的显示内容,包括“Hello World”文本、容器ID和Redis错误消息。

Part 2: Containers

注意:如果您在Windows 7上使用Docker工具,使用Docker机器IP而不是localhost。例如,http://192.168.99.100:4000。要查看IP地址,请使用命令docker -machine IP。

您还可以在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,然后被离开你的终端。您的容器将在后台运行。您还可以看到缩写容器ID通过docker container ls(在运行命令时,这两个工作都可以互换):

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

您将看到匹配http://localhost:4000上的CONTAINER ID

现在使用docker容器停止进程,使用容器ID,例如:

docker container stop 1fa4ab2cf395

分享你的镜像

为了演示我们刚刚创建的可移植性,让我们上传我们构建的映像并在其他地方运行它。毕竟,当您想要将容器部署到生产时,您需要学习如何推动注册。

注册表是存储库的集合,而存储库是镜像的集合——有点像GitHub库,只是代码已经构建好了。注册表上的帐户可以创建许多存储库。docker CLI在默认情况下使用docker的公共注册表。

注意:我们将在这里使用Docker的公共注册表,因为它是免费和预配置的,但是有许多公共注册中心可供选择,而且您甚至可以使用Docker可信注册表建立您自己的私有注册表。

使用您的Docker ID登录

如果你没有Docker帐户,在cloud.docker.com注册一个。记下你的用户名。

登录到本地机器上的Docker公共注册表。

$ docker login

标记镜像

将本地映像与注册表中的存储库关联的符号是username/repository:tag。标签是可选的,但推荐,因为它是注册中心用来给Docker映像提供一个版本的机制。提供存储库并为上下文标记有意义的名称,例如get - started:part2。这将把镜像放到get-started存储库中,并将其标记为part2。

docker tag image username/repository:tag

例如:

docker tag image username/repository:tag

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

$ docker images
REPOSITORY               TAG                 IMAGE ID            CREATED             SIZE
friendlyhello            latest              d9e555c53008        3 minutes ago       195MB
john/get-started         part2               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:part2
Unable to find image 'john/get-started:part2' locally
part2: Pulling from john/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:part2
 * Running on http://0.0.0.0:80/ (Press CTRL+C to quit)

注意:如果您没有指定这些命令的标记部分:tag,那么将会假定您在构建和运行映像时都将使用最新的标记:latest。Docker将使用没有指定标记的图像的最后一个版本(不一定是最近的图像)。

无论docker运行在哪里,它都会拉出您的映像,以及Python以及来自需求的所有依赖项requirements.txt,并运行您的代码。它在一个整洁的小程序包中一起运行,而主机不需要安装任何东西,而是安装Docker来运行它。

点赞
收藏
评论区
推荐文章
liuzhen007 liuzhen007
4年前
如何监控docker的运行状况
目录前言正文查询结果参数解析前言监控docker容器的运行状态是非常普遍的需求,这就是我们今天的讨论内容。正文部署了docker容器之后,我们经常会需要查看容器的运行状态,这里介绍一个非常好用的命令:dockerstats 如果宿主机上有大量的容器在运行,你会看到所有的容器信息,因此我们也可以查看我们关心的某个容器,假如名字为builde
Tommy744 Tommy744
4年前
PaaS失败了吗?让我们看看Cloud Foundry的优势
软件团队常见的行为方式可以总结如下:1.软件部署从Heroku或Firebase开始。2.在应用程序需要快速扩展时,开始使用Docker进行容器化。3.在遇到Docker困境的时候,考虑使用Kubernetes等容器编排工具。(https://cdn.thenewstack.io/media/2020/12/5105a24aimage011.
Tommy744 Tommy744
4年前
你的镜像安全吗?
你的镜像安全吗?与传统的服务器和虚拟机相比,Docker容器为我们工作提供了更安全的环境。容器中可以使我们的应用环境组件实现更小,更轻。每个应用的组件彼此隔离并且大大减少了攻击面。这样即使有人入侵了您的应用,也会最大程度限制被攻击的程度,而且入侵后,利用漏洞传播攻击更难。不过,我们还是需要最大程度了解Docker技术本身的存在的安全隐患,这样
Stella981 Stella981
3年前
Docker 系列:打包新镜像到阿里云镜像仓库
一、.JibJava应用构建容器镜像1.Jib介绍Jib是Google开发的可以直接构建Java应用的Docker和OCI镜像的类库,以 Maven 和 Gradle 插件形式提供。通过Jib,Java开发者可以使用他们熟悉的Java工具来构建容器。Jib是一个快速而简单的容器镜像构建工具,它负责处理
Stella981 Stella981
3年前
Dockerfile 说明
1.基本说明  Dockfile是一个用于编写docker镜像生成过程的文件,其有特定的语法。在一个文件夹中,如果有一个名字为Dockfile的文件,其内容满足语法要求,在这个文件夹路径下执行命令:dockerbuildtagname:tag.,就可以按照描述构建一个镜像了。name是镜像的名称,tag是镜像的版本或者是标签号,
Stella981 Stella981
3年前
Docker Swarm资源管理
DockerSwarmDockerSwarm是Docker官方项目之一,是使用SwarmKit构建的Docker引擎内置的集群管理和编排工具,提供Docker容器集群服务,是Docker官方对容器云生态进行支持的核心方案。使用它,用户可以将多个Docker主机封装为单个大型虚拟Docker主机,快速打造一套容器云平台。节点运
Stella981 Stella981
3年前
Docker数据卷(Volume)
一、将Docker数据挂载到容器  在Docker中,要想实现数据的持久化(所谓Docker的数据持久化即_数据不随着Container的结束而结束_),需要将数据从宿主机挂载到容器中。目前Docker提供了三种不同的方式将数据从宿主机挂载到容器中:  (1)volumes:Docker管理宿主机文件系统的一
Stella981 Stella981
3年前
Docker搭建MySQL服务
Docker开源镜像前面我们已经安装好了Docker,也简单了解了Docker。那么我们可以尝试搭建一个MySQL服务。要搭建服务就要启动服务容器,要创建容易就要有镜像,Docker提供了一个类似Github的开源平台,提供开源镜像,放心可靠。(毕竟大家都看着源码呢)Docker开源镜像传送门(https://www.o
Stella981 Stella981
3年前
Docker 容器介绍
Docker容器介绍_Docker_是一个基于_Go_语言的开源应用容器引擎,它既能实现虚拟化,又可用于将应用服务打包成轻量、可移植的容器,从而可以发布到任何_Linux_平台。除了优秀了沙箱机制外,_Docker_容器的开销也极低。正如其名,_Docker_所做的事情正是以一个集装箱的身份承载应用服务的运行
胖大海 胖大海
2年前
Docker 容器连接
学习docker最好还是整个服务器,买太贵了,建议租一个,我用的是3A服务器!!!前面我们实现了通过网络端口来访问运行在docker容器内的服务。容器中可以运行一些网络应用,要让外部也可以访问这些应用,可以通过 P 或 p 参数
容器、容器云和容器化PaaS平台之间到底是什么关系?
容器是一种操作系统级虚拟化技术,Docker是一种容器引擎。使用Docker来运行操作容器。但从容器自身来说,其提供的是IaaS层能力。Kubernetes提供了容器调度和管理的能力,加上云计算租户功能,实现容器云平台功能。而基于容器技术所构建的应用开发、应用托管和应用运维平台则可以称为容器化PaaS平台,它是一种轻量化PaaS实现。结合日志、监控、认证、权限等基础能力则可以构建企业级的平台和可复用服务,采用微服务架构实现企业技术服务中台能力,支撑企业业务敏捷研发和模式转型。