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.py 和 requirements.txt。 稍后我们会创建它们。

应用本身

再创建两个文件,app.py 和 requirements.txt,并把他们放入和 Dcokerfile 相同的目录里。这样我们就完成了应用,你可以看到,这很简单。当上面的 Dcokerfile 被构建到一个镜像中时,app.py 和 requirements.txt 也会存在于这个镜像,这是因为 Dockerfile 有 ADD 命令,并且因为有 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 演示了和 Dockerfiile 中EXPOSE的不同之处,而且在运行 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

注意 容器ID 与 http://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. JVM源码---教你傻瓜式编译openjdk7(JAVA虚拟机爱好者必看)

    LZ经过一个星期断断续续的研究,终于成功的搞定了JDK的成功编译与调试.尽管网络上的教程也有不少,包括源码中也有自带的编译步骤说明,但真正自己动手的话,还是会遇到不少意料之外的错误. 为了方便各位猿友 ...

  2. linux重启tomcat的shell脚本

    基本思路: 先检查待重启的tomcat的进程是否存在 存在则执行shutdown. 然后再次检查进程是否还存在,不存在则执行kill 然后删除工作空间及10天前的日志. 最后执行启动. #!/bin/ ...

  3. opencv core组件进阶

    1.图像在内存中存储方式,图像矩阵的大小取决于颜色模型,取决于所有的通道数:还有重要的颜色空间缩减的概念:因为如果是RGB的话,使用uchar的话,就有256^3的结合方法.所以要用到颜色缩减的方法, ...

  4. page = new String(request.getQueryString().getBytes("ISO-8859-1"),"GBK");解决前台传后台乱码问题

    page = new String(request.getQueryString().getBytes("ISO-8859-1"),"GBK");解决前台传后台 ...

  5. offices 激活

    http://www.xitongcheng.com/jiaocheng/dnrj_article_44577.html  破解工具见cnblos文件中 : https://blog.csdn.net ...

  6. powershell远程管理服务器磁盘空间的实现代码

    一.启用远程管理 1.将管理服务器的trusthost列表改为* 运行Set-item wsman:localhostclienttrustedhosts ?value * 2.在远程服务器上运行En ...

  7. shell脚本实现多台服务器自动巡检

    shell脚本实现多台服务器自动巡检 摘要:         运维服务一个项目二十多台(或者多台)服务器,每天要做服务器的性能巡检工作是查看服务器的CPU.内存.磁盘空间是否在正常值范围内.像这样每天 ...

  8. 在vue中使用weixin-js-sdk自定义微信分享效果

    在做微信分享的时候,产品要求分享效果要有文字和图片,使用weixin-js-sdk解决了, 原始的分享效果: 使用微信JS-SDK的分享效果: 首先需要引入weixin-js-sdk npm inst ...

  9. sqlserver 比较两个表的列

    一.问题 给了两个各有四五十个列的表,找出他们相同的列和不同的列 二.查询两个表的列,存在临时表 --#a ,#b都是临时表,当前连接断开后自动删除--RANK() OVER (ORDER BY sy ...

  10. BZOJ2728 HNOI2012与非(并查集+数位dp)

    容易发现x nand x=not x.并且使用这个性质有x and y=not(x nand y)=(x nand y)nand(x nand y).也就是说nand运算可以作为not和and运算使用 ...