Docker起步,第二部分:容器

原文链接:Get Started,Part 2:Containers
预计阅读时间:14分钟

先决条件(Prerequisites)

docker run hello-world

介绍(Introduction)

是时候开始用Docker的方式来创建一个应用了。我们从一个应用层级的底部开始创建,这是一个容器(container),我们将在整个页面介绍它。在这个层级之上就是服务,它定义了容器在产品中的表现,将在第三部分中介绍。最后,最顶层的是stack,它定义了services之间的交互,将在第五部分讲到。

  • Stack
  • 服务
  • 容器(你在这里)

你的新开发环境(Your new development environment)

在过去,如果你想开发一个Python应用,第一步要做的就是在你的机器上安装Python环境。但是这造成了一种情况,你的环境需要完美支持运行你的应用,同时也要匹配你的生产环境。
用Docker,你不必安装Python,只需要带一个便携的Python运行时镜像就可以了。然后,在构建代码时,你的Python镜像就会在一旁,确保你的应用、依赖和运行时一直都在一起。
这些便携的镜像通通用一个叫Dockerfile的东西来定义。

Dockerfile来定义一个容器(Define a container with Dockerfile

Dockerfile定义了容器中的环境里要做什么。对资源的访问如网络接口和硬盘驱动都是虚拟的存在于这个环境中的,而且是与其他系统隔离的,所以你需要配置对外暴露的端口并且明确哪些文件是要“拷贝”到这个环境中。在做完这些操作之后,你可以认为在Dockerfile中构建的项目在任何地方都可以有相同的表现。

Dockerfile

创建一个空的目录并切换目录(cd)到这个新的目录下,创建一个叫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,让我们接下来创建这些文件。

应用本身(The app itself)

在创建两个叫requirements.txtapp.py的文件,并把它们放在和Dockerfile相同的目录下。这完成了我们的应用,你可以看到它很简单。当上述的Dockerfile文件被构建到一个image中时,app.pyrequirements.txt将因为Dockerfile中的ADD指令发挥作用,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=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的Python库,这个Python应用打印了环境变量Name,和调用socket.gethostname()的输出一样。最后,因为Redis并没有运行(我们只安装了Python的Redis库,并不是Redis),这里我们想要看到的是试图使用Redis但是失败并展现的错误信息。

注意:在容器中检索容器ID时访问主机名,就像正在运行程序的进程ID一样(Accessing the name of the host when inside a container retrieves the container ID, which is like the process ID for a running executable. 机翻 不知道怎么翻)

完成了,并不需要在你的系统安装Python和requirements.txt中的任何东西,也不需要构建运行或者安装这些镜像到你的系统中。看起来你的确没有安装Python环境和Flask框架,但事实上你已经拥有了这些环境。

构建应用(Build the app)

我们已经准备好构建应用了。确认一下你仍在新目录的最顶部。使用ls命令应该看到以下文件:

Dockerfile      app.py          requirements.txt

现在运行构建命令。下面的命令将会创建Docker镜像,使用-ttag可以让我们自己给镜像起名

docker build -t friendlyhello .

你刚刚构建的镜像在哪儿呢?它已经在你本地的Docker镜像注册中心:

REPOSITORY              TAG                 IMAGE ID            CREATED             SIZE
friendlyhello           latest              cab62a96dfbe        44 hours ago        132MB

运行你的应用(Run the app)

运行应用,使用-ptag来将容器中暴露的80端口映射到本机的4000端口

docker run -p 4000:80 friendlyhello

你应该能看到Python已经启动了你的服务http://0.0.0.0:80。但这些信息是来自于容器内部的,它并不知道你已经将它的80端口映射到机器的4000端口,使用正确的URL来访问
http://localhost:4000
通过浏览器来访问URL就能看到服务信息显示在网页上了

注意:如果你在Windows 7上使用Docker Toolbox,请使用Docker Machine IP来替代localhost。比如: http://192.168.99.100:4000/。可以使用docker-machine ip来查看上述的IP地址。

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

docker run -d -p 4000:80 friendlyhello

之后你会得到一个container ID并被踢回终端界面。你的容器正在后台,但你仍可以使用docker container ls来查看缩略的container ID(并且在运行命令时两者都可以互换???and both work interchangeably when running commands)

localhost:myContainer yichen$ docker container ls
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                  NAMES
3a51a998eed6        friendlyhello       "python app.py"     6 seconds ago       Up 6 seconds        0.0.0.0:4000->80/tcp   angry_bartik

注意这个CONTAINER IDhttp://localhost:4000上显示的一样。
现在使用docker container stopCONTAINER ID来结束进程,如下:

docker container stop 3a51a998eed6

分享你的镜像(Share your image)

让我们把刚刚上传刚刚构建的镜像并在其他地方运行一下来证明刚刚创建的东西是编写的。毕竟当你想要将容器部署到生产环境时需要知道如何将其推到registries。

上面提到的registry是一个仓库的集合,而仓库又是镜像的集合--类似于GitHub,只是代码需要编译一下。一个账号在registry可以创建多个仓库。docker 客户端使用Docker的默认registry。

注意:我们使用Docker公共的registry因为他是免费且是预先配置好的,但还有很多公共的registry可供选择,或者你可以用Docker Trusted Registry
创建自己私有的registry。

使用Docker ID登录(Log in with your Docker ID)

如果你还没有Docker账户,可以去 hub.docker.com
注册一个并记下你的用户名。
在你的本地登录Docker公共registry

docker login

给镜像加一个标签(Tag the image)

username/repository:tag是一个关联本地镜像和registry中仓库的标记。标签(tag)是可选但推荐使用的,因为这是registry记录Dcoker镜像版本的一个机制。为了更好的理解,请给仓库和标签起一个有意义的名字,比如get-started:part2。这样就会将镜像放到get-started仓库并用part2将其标记。

现在讲这些放在一起来标记镜像(tag the image)。执行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
...

发布镜像(Publish the image)

将被标记的镜像上传到仓库:

docker push username/repository:tag

一旦成功,上传的镜像即可被大众使用。如果你登录了Docker Hub,就能看到带有pull命令的新镜像。

从远程仓库拉取并运行镜像(Pull and run the image from the remote repository)

从现在开始,你可以用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在哪里执行,他都会将你的镜像拉取下来,下载的还有Python,requirements.txt中的依赖并运行你的代码。这些都会囊括在这个小巧的保重,你并不用为Docker运行你的镜像安装任何东西。

总了个结(Conclusion of part two)

本部分到这里就结束了。在下一个部分,我们将container运行在service中,以此来学习如何所扩容你的应用。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,383评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,522评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,852评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,621评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,741评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,929评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,076评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,803评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,265评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,582评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,716评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,395评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,039评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,027评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,488评论 2 361
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,612评论 2 350

推荐阅读更多精彩内容