入门,第 2 部分:容器

先决条件

  • 安装的 Docker 版本是 1.13 及以上。
  • 读完 第一部分
  • 用下面的命令快速测试你的环境是否完备:

    docker run hello-world

概述

现在开始用 Docker 的方式构建应用。我们从这个应用的层次结构底部开始,也就是这里讲的容器。在容器层上面有第三部分讲的 service 层,定义了生产中的容器的行为方式。最顶层的是第五部分讲的 stack 层,定义了所有 service 的交互。

  • Stack
  • Services
  • Container (你在这里)

新的部署环境

过去,如果要写个 Python 应用,首先要在机器上安装 Python 运行时。这就带来了一个问题:要使应用按照预期运行,就需要机器上的环境完美适合应用程序,同时生产环境需要与开发环境完全一致。

通过 Docker,可以将一个可移植的 Python 运行时作为一个 image 镜像获取,无需安装。 然后,构建时可以将基础 Python 镜像与应用程序代码一起包括在内,确保应用程序,依赖项和运行时都一起发布。 通过 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
COPY . /app # Install any needed packages specified in requirements.txt
RUN pip install --trusted-host pypi.python.org -r requirements.txt # Make port available to the world outside this container
EXPOSE # Define environment variable
ENV NAME World # Run app.py when the container launches
CMD ["python", "app.py"]

此 Dockerfile 是指一些尚未创建的文件,即app.pyrequirements.txt。接下来,让我们创建这些。

应用程序本身

再创建两个文件,requirements.txt 和app.py,并将它们与 Dockerfile 放在同一文件夹中。这完成了我们的应用程序,你可以看到这是很简单的。当上述 Dockerfile 内置到映像中时,由于 Dockerfile 的 COPY 命令,app.pyrequirements.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=, socket_connect_timeout=, socket_timeout=) 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=)

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

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

就是这样!您不需要 Python 或任何requirements.txt 在您的系统上,也不构建或运行此映像安装它们在您的系统上。看起来您并没有真正使用 Python 和 Flask 建立了一个环境,但您已经设置了环境。

构建应用

我们准备构建应用程序。请确保您仍在新目录的顶层。以下是 ls 应显示的内容:

$ ls
Dockerfile app.py requirements.txt

现在运行生成命令。这将创建一个 Docker 镜像,我们将使用 --tag 选项命名该镜像。如果要使用较短的选项,请使用 -t。

docker build --tag=friendlyhello .

你的构建镜像在哪里?它位于计算机的本地 Docker 镜像注册表中:

$ docker image ls

REPOSITORY            TAG                 IMAGE ID
friendlyhello latest 326387cea398

请注意标记如何默认为最新标记。标记选项的完整语法类似于

--tag=friendlyhello:v0.0.1.

Linux 用户的故障排除

  • 代理服务器设置

  • 代理服务器可以在 Web 应用启动并运行后阻止其连接到该站点。如果位于代理服务器后面,请向 Dockerfile 添加以下行,使用 ENV 命令指定代理服务器的主机和端口:

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

DNS 设置

DNS 配置错误可能会生成 pip 问题。您需要设置自己的 DNS 服务器地址,以使 pip 正常工作。您可能需要更改 Docker 守护进程程序的 DNS 设置。您可以使用 dns 密钥在 /etc/docker/daeon.json 上编辑(或创建)配置文件,如下所示:

{
"dns": ["your_dns_address", "8.8.8.8"]
}

在上面的示例中,列表的第一个元素是 DNS 服务器的地址。第二个项目是谷歌的DNS,可以使用时,第一个不可用。

在继续之前,请保存daemon.json 并重新启动 docker 服务。

sudo service docker restart

修复后,重试以运行build命令。

运行应用

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

docker run -p : friendlyhello

您应该会看到一条消息,指出 Python 正在http://0.0.0.0:80为你的应用提供服务。但是,该消息来自容器内部,该容器不知道您将该容器的端口 80 映射到 4000,从而正确的 URL 是 http://localhost:4000

转到 Web 浏览器中的该 URL 以查看网页上提供的显示内容。

注意:如果您在 Windows 7 上使用 Docker Toolbox,请使用 Docker machine 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 中的 EXPOSE 与运行 docker run-p 时设置的发布值之间的差异。在后面的步骤中,将主机上的端口 4000 映射到容器中的端口 80 并使用http://localhost

在终端中点击 CTRL+C 以退出。

在 Windows 上,显式停止容器

在 Windows 系统上,CTRL+C 不会停止容器。因此,首先键入 CTRL_C 以返回提示(或打开另一个 shell),然后键入 docker 容器 ls 以列出正在运行的容器,然后键入 docker 容器停止 [容器名称或 ID] 以停止容器。否则,当您尝试在下一步中重新运行容器时,您将从守护进程收到错误响应。

现在,让我们在后台以分离模式运行应用:

docker run -d -p : friendlyhello

您将获得应用的长容器 ID,然后被踢回终端。容器在后台运行。您还可以看到带有 docker container ls 的缩写容器 ID(在运行命令时,两者可互换):

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

请注意,CONTAINER ID 与http://localhost:4000上的内容相匹配。

现在使用 docker container stop 来结束进程,使用 CONTAINER ID,如下所示:

docker container stop 1fa4ab2cf395

分享镜像

为了演示我们刚刚创建的内容的可移植性,让我们上传构建的镜像并将其运行到其他地方。毕竟,您需要知道如何在将容器部署到生产时推送到registries。

一个registry是repositories的集合, repository是镜像的集合— 类似于 GitHub repository,但代码已经生成。一个registry上的帐户可以创建许多repositories。默认情况下,Docker CLI 使用 Docker 的公共registry。

注意:我们在这里使用 Docker 的公共registry,只是因为它是免费的,并且预先配置了,但有许多公共registry可供选择,您甚至可以使用 Docker 可信registry设置您自己的专用registry。

用 Docker ID 登录

如果您没有 Docker 帐户,请hub.docker.com注册。记下您的用户名。

在本地机器上登录 Docker 的公共 registry:

$ docker login

给镜像打标签(Tag)

将一个本地镜像关联到注册处 registry 中的一个仓库的符号是 username/repository:tag。标签是可选的,但是建议使用,因为这是 registry 用来给 Docker 镜像指定版本的机制。给仓库和标签起有意义的名字,例如 get-started:part2。这会把镜像放入 get-started 仓库,并且添加标签 part2。

运行 docker tag image 命令,用自己的 username,repository 和 标签名,这样镜像可以上传到指定的位置。命令的语法是:

docker tag image username/repository:tag

举个例子:

docker tag friendlyhello john/get-started:part2

运行 docker image ls 来查看新打标签的镜像:

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

发布镜像

将标记的镜像上载到repository:

docker push username/repository:tag

上传完成后,这次上传的镜像就可以公开访问了。如果你登录了 Docker Hub,就可以看见这个镜像和对应的 pull 命令。

从远程仓库获取并运行镜像

从现在起,你可以使用 docker run 命令在任何机器上运行你的应用程序:

docker run -p : username/repository:tag

如果镜像不在机器本地上,则 Docker 会从仓库获取镜像。

$ docker run -p : 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)

不管 docker run 在哪里运行,Docker 会获取你的镜像并运行(这里的镜像安装了 Python 和从 requirements.txt 文件指定的依赖,并会运行应用代码)。所有的东西都在一个包里,获取到就可以运行,不需要安装其他东西。

第二部分结论

本页就到此。在下一节中,我们将学习如何通过在service中运行此容器来扩展应用程序。

回顾和备忘单(可选)

下面是此页面中的基本 Docker 命令的列表,如果您想在继续之前先浏览一下,则提供一些相关命令。

docker build -t friendlyhello .  # Create image using this directory's Dockerfile
docker run -p : friendlyhello # Run "friendlyhello" mapping port to
docker run -d -p : friendlyhello # 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

docker 入门2 - 容器 【翻译】的更多相关文章

  1. docker入门——管理容器

    除了交互式的容器(interactive container),我们也可以创建长期运行的容器.守护式容器(daemonized container)没有交互式会话,非常适合运行应用程序和服务.大多数时 ...

  2. Docker入门之三容器

    上一篇博客学习了下镜像,今天来学习容器.容器类似一个手机中的沙盒环境,用来运行app实例.和镜像一样也是对容器的创建.删除.导出等. 由于我买的参考书中的例子好多都是基于linux的,所以我将dock ...

  3. docker入门(二)容器与镜像的理解

    10张图带你深入理解Docker容器和镜像 申明:此篇文章是转载的(原文地址http://dockone.io/article/783),今天意外发现已经有人转载了(复制了),希望大家关注原创 原本打 ...

  4. docker入门(二)容器与镜像的关系

    [编者的话]本文用图文并茂的方式介绍了容器.镜像的区别和Docker每个命令后面的技术细节,能够很好的帮助读者深入理解Docker. 这篇文章希望能够帮助读者深入理解Docker的命令,还有容器(co ...

  5. Docker 入门:容器

    容器看着像机器,实际是进程,是一个运行时程序. 要操作一个 Docker 容器,只需要执行 docker container 命令. 可以通过 help 查看 run 运行容器 基础使用: docke ...

  6. Docker入门(三):容器(Containers)

    这个<Docker入门系列>文档,是根据Docker官网(https://docs.docker.com)的帮助文档大致翻译而成.主要是作为个人学习记录.有错误的地方,Robin欢迎大家指 ...

  7. Docker入门(七):部署app

    这个<Docker入门系列>文档,是根据Docker官网(https://docs.docker.com)的帮助文档大致翻译而成.主要是作为个人学习记录.有错误的地方,Robin欢迎大家指 ...

  8. Docker入门(六):Stacks

    这个<Docker入门系列>文档,是根据Docker官网(https://docs.docker.com)的帮助文档大致翻译而成.主要是作为个人学习记录.有错误的地方,Robin欢迎大家指 ...

  9. Docker入门(五):Swarms

    这个<Docker入门系列>文档,是根据Docker官网(https://docs.docker.com)的帮助文档大致翻译而成.主要是作为个人学习记录.有错误的地方,Robin欢迎大家指 ...

随机推荐

  1. golang中文件以及文件夹路径相关操作

    获取目录中所有文件使用包: io/ioutil 使用方法: ioutil.ReadDir 读取目录 dirmane 中的所有目录和文件(不包括子目录) 返回读取到的文件的信息列表和读取过程中遇到的任何 ...

  2. Java并发指南2:深入理解Java内存模型JMM

    本文转载自互联网,侵删   一:JMM基础与happens-before 并发编程模型的分类 在并发编程中,我们需要处理两个关键问题:线程之间如何通信及线程之间如何同步(这里的线程是指并发执行的活动实 ...

  3. the requested PHP extension dom is missing from your system

    composer  出错 the requested PHP extension dom is missing from your system 解决办法    yum install  php70w ...

  4. Linux下批量ping某个网段的脚本

    比如现在需要对192.168.0.0/24网段的ip进行检查,检查哪些ip现在被占用,哪些ip没有被占用,可以通过ping命令来检查,也可以通过nmap接参数来检查 ping命令脚本如下: [root ...

  5. Socket概述

    Socket套接字概述: 网络上具有唯一标识的IP地址和端口号组合在一起才能构成唯一能识别的标识符套接字. 通信的两端都有Socket. 网络通信其实就是Socket间的通信. 数据在两个Socket ...

  6. Server 2012使用Windows PowerShell cmdlet安装角色和角色服务功能

    Server 2012使用Windows PowerShell cmdlet安装角色和角色服务功能  Windows Server 2012 安装 SQL server 2008 出现了如下错误: 解 ...

  7. 关于CAShapeLayer的一些基本操作

    设置圆形进度条: 实现效果如下: 实现代码如下:(注释很详细啦!!!) UIView *circleView = [[UIView alloc]initWithFrame:CGRectMake(, , ...

  8. mysql访问慢解决

    配置变更思路: 扩大MySQL连接数至2000,同时扩大操作系统最大文件描述符:扩大innodb缓存池 操作步骤: vi /etc/my.cnf max_connections = 2000innod ...

  9. leetcode 将一个二维矩阵进行90度旋转

    import numpy as np import math if __name__ == '__main__': def rotate(matrix): n = len(matrix[0]) for ...

  10. Nginx-windows

    1.下载 http://nginx.org/ 选择最新稳定版本,例如nginx-1.15.5 mainline version has been released. 点击后,跳转页面,选择Stable ...