Docker 入门 第二部分: 容器

先决条件

  • 安装 Docker 1.13 或更高版本

  • 阅读第一部分

  • 给你的环境做一个快速运行测试,以确保你已经准备好了

    docker run hello-world

介绍

现在到了以docker的方式去构建一个应用了。我们从整个应用的架构的底层开始,这里是一个容器,我们会在本页介绍它。在此层级之上是一个服务,它定义了容器在生产环境中会如何工作,我们会在第三部分介绍。最后,最顶层的是堆栈,定义所有服务的交互行为,我们会在第五部分介绍。

  • Stack 堆栈
  • Services 服务
  • Container 容器 (现在你在这里)

你的新开发环境

在过去,如果你要写一个ptyhon应用,首先你要在你的机器上安装一套ptyhon的运行环境。但是,这就产生了一种情况,为了让你的应用按照预期运行,你机器上的环境需要精确部署,而且还需要和你的生产环境相匹配。

使用Dcoker,你只需要将一个便携的python运行时(就是一套可执行的python)作为镜像,而没有安装的必要。然后,你构建的镜像可以包括基本的Python镜像和你的应用代码。以确保你的应用、应用的依赖和运行环境全部在一起。

这些由某些内容定义的便携的镜像叫做 Dockerfile

使用 Dockerfile 定义一个容器

Dockerfile 定义容器内环境中的内容。对注入网络接口和磁盘驱动的访问都在这个环境中被虚拟化。以和系统的其余部分分离开来,因此你需要将端口映射到外部,并具体指明你想要将什么文件“复制到”该环境。

对诸如网络接口和磁盘驱动器等资源的访问在这个环境中被虚拟化, 这与系统的其余部分隔离开来, 因此您需要将端口映射到外部世界, 并具体要 "复制" 哪些文件到该环境。不管怎样,可以保证在这个 Dockerfile中构建定义的应用可以在任何地方都可以一样的运行。

Dockerfile

创建一个空目录。进入该目录,并创建一个名为 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"]

这个 Dockerfile 文件引用了我们还没有创建的文件,app.pyrequirements.txt。 稍后我们会创建它们。

应用本身

再创建两个文件,app.pyrequirements.txt,并把他们放入和 Dcokerfile 相同的目录里。这样我们就完成了应用,你可以看到,这很简单。当上面的 Dcokerfile 被构建到一个镜像中时,app.pyrequirements.txt 也会存在于这个镜像,这是因为 DockerfileADD 命令,并且因为有 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),正常的话,我们可以看到尝试使用redis失败,产生的错误信息。

注意:当在容器内部检索容器ID时,访问的主机名就像一个正在运行的进程的ID

就是这样,你的系统中不需要 python 或 requirements.txt 中的任何内容,构建和运行这个镜像时也不需要在你的系统上安装它们。看起来你并没有安装Python和Flask的环境,但你已经有了。

构建应用

我们已经准备好了去构建应用。确保你一直都在新建目录的最上级。你可以看到如下内容:

$ ls
Dockerfile app.py requirements.txt

现在运行构建命令,这会创建一个Docker镜像,我们可以使用 -t 参数给它指定一个友好的名字。

docker build -t friendlyhello .

构建的镜像保存在哪里呢?镜像会保存在你机器上本地的Docker镜像registry里:

$ docker image ls

REPOSITORY            TAG                 IMAGE ID
friendlyhello latest 326387cea398

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设置,你可以编辑(或创建)配置文件/etc/docker/daemon.json,设置 dns关键字,内容如下:

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

上面的例子中,列表的第一个元素是DNS服务器的地址,第二个是Google的DNS,当第一个地址无法使用时,会使用第二个。

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

sudo service docker restart

问题修复后,重新尝试build命令

运行应用

运行应用,使用-p参数将你的机器的4000端口映射到容器的发布端口80上。

docker run -p 4000:80 friendlyhello

你会在http://0.0.0.0:80看到一个Pyhton正常为你的应用服务的消息。但是这个消息来自容器内部,它不知道你将该容器的80端口映射到4000端口,需要输入正确的URL http://localhost:4000

在浏览器中访问正确的URL,以查看网页中显示的内容。

注意:如果你在Windows7中使用Docker Toolbox,要使用Docker机器的IP替换localhost。例如,http://192.168.99.100:4000/。使用 docker-machine ip 命令可以找到这个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 演示了和 DockerfiileEXPOSE的不同之处,而且在运行 docker run -p 时设置了发布的值。在后面的步骤中,映射了主机的4000端口到容器的80端口,并使用了 http://localhost

在你的终端中使用 CTRL+C 来退出。

在Windows中,显示的关闭容器

在windows系统,CTRL+C 不会关闭容器。所以,首先输入 CTRL+C 返回提示符(或者新打开一个shell),然后输入 docker container ls 来列出运行中的容器,随后通过 docker container stop <Container NAME or ID>来关闭容器。否则,在稍后的步骤中,当你尝试重新运行容器会得到一个来自守护进程错误的响应。

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

docker run -d -p 4000:80 friendlyhello

你会获得应用容器的长ID并返回终端,容器会在后台运行,你还可以荣国 docker container ls 查看缩写的容器ID()

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

注意 容器IDhttp://localhost:4000上的内容相匹配。

现在使用 docker container stop 指定 容器ID 来结束进程,如下:

docker container stop 1fa4ab2cf395

共享你的镜像

为了证明我们刚刚创建的镜像的可移植性,我们可以上传构建的镜像并在任何地方运行它。毕竟,当你想把容器部署到生产环境中时,你需要知道如何推送到 registries。

一个registry 是一个仓库的集合,一个仓库是一个镜像的集合——类似于GitHub的仓库。只是代码已经构建好了。registry上的一个用户可以创建多个仓库。docker CLI默认使用Docker的公共registry。

注意: 这里我们使用Docker的公共registry是因为它是免费的和预置的,不过我们还是有很多公共的registry可以选择,甚至你可以使用 Docker Trusted Registry来搭建你自己私有的registry。

使用你的docker ID进行登录

如果你没有docker用户,可以在hub.docker.com注册一个。记下你的用户名。在你的本地机器上登录到DOcker公共的registry。

$ docker login

为镜像加标签

关联本地镜像与registry仓库的方法是 username/repository:tag 。标签是可选的,但建议设置上,因为这是registry为docekr镜像提供版本的机制,根据上下文给仓库和标签起一个有意义的名字,例如:get-started:part2。这里我们将镜像放在 get-started仓库,标签名字为 part2

现在,把它们放在一起来标记镜像。使用in的用户名、仓库和标签名来运行 docker tag image,以便将镜像上传到你想要上传的位置,命令语法如下:

docker tag image username/repository:tag

例如:

docker tag friendlyhello gordon/get-started:part2

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

$ docker image ls

REPOSITORY               TAG                 IMAGE ID            CREATED             SIZE
friendlyhello latest d9e555c53008 3 minutes ago 195MB
gordon/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 Hub看到最新的镜像。

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

从现在开始,你可以在在任何机器上使用docker run运行你的应用:

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

如果镜像在本地机器上不可用,Docker会从远程仓库上拉取镜像:

$ docker run -p 4000:80 gordon/get-started:part2
Unable to find image 'gordon/get-started:part2' locally
part2: Pulling from gordon/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 gordon/get-started:part2
* Running on http://0.0.0.0:80/ (Press CTRL+C to quit)

现在无论你在哪里运行docker run,他会拉取镜像,Pyhton、requirements.txt中指定的依赖和你的代码 会在一起运行,他们全部打包在一个小包裹里(镜像),你不需要在你的机器上安装任何东西,Docker 就可以运行它了。

第二部分总结

这就是本页所有内容,下一节,我们会通过在服务中运行这个容器来学习如何扩展我们的应用程序。

回顾和备忘【可选】

官方在这里提供了一段视频,但我这里观看有问题,我就找把视频录制下来放到了B站,地址如下:

官方视频

B站的“分享视频”中给的代码放在博客园无法播放,只能在这里写一个地址了。

下面是本页中关于docker的基本命令列表,以及一些相关的命令,在继续后面的学习前可以研究一下。

docker build -t friendlyhello .  # Create image using this directory's Dockerfile
docker run -p 4000:80 friendlyhello # Run "friendlyname" mapping port 4000 to 80
docker run -d -p 4000:80 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 入门 第二部分: 容器的更多相关文章

  1. Docker学习第二天-容器

    Docker 容器 容器是 Docker 又一核心概念. 简单的说,容器是独立运行的一个或一组应用,以及它们的运行态环境.对应的,虚拟机可以理解为模拟运行的一整套操作系统(提供了运行态环境和其他系统环 ...

  2. 8天入门docker系列 —— 第二天 通过一个aspnetcore程序加深对容器的理解

    我们知道容器是一个打包了应用和相关依赖的盒子,那怎么去操控这个盒子呢? 这一篇我通过一个简单的aspnetcore程序来加深对盒子的理解,使用之前先 安装一下Docker的环境. 一:Docker的安 ...

  3. Docker入门之三容器

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

  4. docker入门——安装(CentOS)、镜像、容器

    Docker简介 什么是docker 官方解释: Docker is the company driving the container movement and the only container ...

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

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

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

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

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

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

  8. Windows10下的docker安装与入门 (三) 创建自己的docker镜像并且在容器中运行它

    Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化.容器是完全使用沙箱机制,相互之间不会有任何 ...

  9. Docker入门 - 004 Docker 容器使用

    Docker 客户端 docker 客户端非常简单 ,我们可以直接输入 docker 命令来查看到 Docker 客户端的所有命令选项. docker 可以通过命令 docker command -- ...

随机推荐

  1. jenkis +sonarqube 对后端代码静态扫描,钉钉群通知执行结果(记录)

    代码提交,触发后端sonar测试,测试完成,jenkins触发依赖任务,执行python脚本,达到预期,调用上线任务模块,进行上线,达不到预期,钉钉群通知. 牵涉到配置: 1.配置sonar测试任务 ...

  2. .netCoreMVC添加数据仓储

    在上一篇关于CodeFirst从零搭建ASP.NETCore2.0中搭建起了完整.netCoreMVC项目,在这一篇中将实现如何注册service服务和Repository数据仓储到web中实现数据的 ...

  3. 一种C#泛型方法在lua中表示的设计

    在进行lua方法注册的时候, 大多数解决方案直接否定了泛型方法, 因为在lua侧难以表达出泛型, 以及lua的函数重载问题, 函数重载问题可以通过一些特殊方法解决, 而泛型问题是主要问题, 以Unit ...

  4. mark一下岗位

    一.中国移动杭州研发中心——测试开发工程师 https://campusresume.zhaopin.com/resume/14375/1   等内推信息 岗位描述:作为产品的质量守护者,在全面理解被 ...

  5. C++:派生类的构造函数和析构函数的调用顺序

    一.派生类 在C++编程中,我们在编写一个基类的派生类时,大致可以分为四步: • 吸收基类的成员:不论是数据成员还是函数成员,派生类吸收除基类的构造函数和析构函数之外的全部成员. • 改造基类函数:在 ...

  6. (第三周)使用visual studio 2015进行单元测试

    Microsoft visual studio是目前最流行的windows平台应用程序的集成开发环境.最新版本为 Visual Studio 2015 .Visual Studio 2015 包含许多 ...

  7. We are a team----sh_6666

    团队宣言:编程,我们是玩命的,玩命,我们是认真的. 团队简介: 团队名称:sh_6666队 团队博客链接:http://www.cnblogs.com/sh-6666/ 人物简介: 剧团导演:吴小勇 ...

  8. 在ubuntu下运行python脚本

    转自http://www.cnblogs.com/hester/p/5575658.html 1. 运行方式一 新建test.py文件: 1 touch test.py 然后vim test.py打开 ...

  9. jQuery~DOM基础操作

    操作DOM 1.什么是DOM:document object model文档对象模型 2.树形结构 3.什么是节点(node):DOM结构中最小单位,元素.文本.属性...创建节点 var $div ...

  10. 【转】maven常用插件介绍

    我们都知道Maven本质上是一个插件框架,它的核心并不执行任何具体的构建任务,所有这些任务都交给插件来完成,例如编译源代码是由maven- compiler-plugin完成的.进一步说,每个任务对应 ...