Docker 是 Golang 编写的, 自 2013 年推出以来,受到越来越多的开发者的关注。如今Docker无处不在,这是不争的事实。开发人员都很喜欢它,运维工程师也需要它。他们都需要深入了解如何在关键业务环境中构建和维护符合生产级别要求的容器化应用,那么什么是Docker?运维和开发视角有什么不同?本文将告诉你答案。

本文摘自《深入浅出Docker》,就是那本美亚操作系统排名第一的Docker入门书,被业内誉为:“高中生也能读懂的 Docker入门教程”。

本文从下面两部分内容讲解Docker。

  • 运维(Ops)视角。

  • 开发(Dev)视角。

在运维视角中,主要包括下载镜像、运行新的容器、登录新容器、在容器内运行命令,以及销毁容器。

在开发视角中,更多关注与应用相关的内容。《深入浅出Docker内》会从GitHub拉取一些应用代码,解释其中的Dockerfile,将应用容器化,并在容器中运行它们。

通过上面两部分内容,你可以从整体上理解Docker究竟是什么,以及主要组件之间是如何相互配合的。推荐读者对开发和运维两部分内容都要阅读

1.1 运维视角

当读者安装Docker的时候,会涉及两个主要组件:Docker客户端和Docker daemon(有时也被称为“服务端”或者“引擎”)。

daemon实现了Docker引擎的API。

使用Linux默认安装时,客户端与daemon之间的通信是通过本地IPC/UNIX Socket完成的(/var/run/docker.sock);在Windows上是通过名为npipe:./pipe/docker_engine的管道(pipe)完成的。读者可以使用docker version命令来检测客户端和服务端是否都已经成功运行,并且可以互相通信。

 1> docker version 2Client: 3 Version:       18.01.0-ce 4 API version:   1.35 5 Go version:    go1.9.2 6 Git commit:    03596f5 7 Built: Wed Jan 10 20:11:05 2018 8 OS/Arch:       linux/amd64 9 Experimental:  false10 Orchestrator:  swarm1112Server:13 Engine:14  Version:      18.01.0-ce15  API version:  1.35 (minimum version 1.12)16  Go version:   go1.9.217  Git commit:   03596f518  Built:        Wed Jan 10 20:09:37 201819  OS/Arch:      linux/amd6420  Experimental: false

如果读者能成功获取来自客户端和服务端的响应,那么可以继续后面的操作。如果读者正在使用 Linux,并且服务端返回了异常响应,则可尝试在命令的前面加上 sudo——sudo docker version。如果加上sudo之后命令正常运行,那么读者需要将当前用户加入到docker用户组,或者给本书后面的命令都加上sudo前缀。

1.1.1 镜像

将Docker镜像理解为一个包含了OS文件系统和应用的对象会很有帮助。如果读者实际操作过,就会认为与虚拟机模板类似。虚拟机模板本质上是处于关机状态的虚拟机。在Docker世界中,镜像实际上等价于未运行的容器。如果读者是一名开发者,可以将镜像比作类(Class)。

在Docker主机上运行docker image ls命令。

1$ docker image ls2REPOSITORY    TAG     IMAGE ID     CREATED     SIZE

如果读者运行命令环境是刚完成Docker安装的主机,或者是Play With Docker,那么Docker主机中应当没有任何镜像,命令输出内容会如上所示。

在Docker主机上获取镜像的操作被称为拉取(pulling)。如果使用Linux,那么会拉取ubuntu:latest镜像;如果使用Windows,则会拉取microsoft/powershell:nanoserver镜像。

1latest: Pulling from library/ubuntu250aff78429b1: Pull complete3f6d82e297bce: Pull complete4275abb2c8a6f: Pull complete59f15a39356d6: Pull complete6fc0342a94c89: Pull complete7Digest: sha256:fbaf303...c0ea5d12128Status: Downloaded newer image for ubuntu:latest

再次运行docker image ls命令来查看刚刚拉取的镜像。

1$ docker images2REPOSITORY       TAG      IMAGE ID       CREATED       SIZE3ubuntu           latest   00fd29ccc6f1   3 weeks ago   111MB

关于镜像的存储位置以及镜像内部构成,本书会在后续的章节中详细介绍。现在,读者只需知道镜像包含了基础操作系统,以及应用程序运行所需的代码和依赖包。刚才拉取的ubuntu镜像有一个精简版的Ubuntu Linux文件系统,其中包含部分Ubuntu常用工具。而Windows示例中拉取的microsoft/powershell镜像,则包含了带有PowerShell的Windows Nano Server操作系统。

如果拉取了如nginx或者microsoft/iis这样的应用容器,则读者会得到一个包含操作系统的镜像,并且在镜像中还包括了运行Nginx或IIS所需的代码。

重要的是,Docker的每个镜像都有自己的唯一ID。用户可以通过引用镜像的ID或名称来使用镜像。如果用户选择使用镜像ID,通常只需要输入ID开头的几个字符即可——因为ID是唯一的,Docker知道用户想引用的具体镜像是哪个。

1.1.2 容器

到目前为止,读者已经拥有一个拉取到本地的镜像,可以使用docker container run命令从镜像来启动容器。

在Linux中启动容器的命令如下。

1$ docker container run -it ubuntu:latest /bin/bash2root@6dc20d508db0:/#

在Windows中启动容器的命令如下。

1> docker container run -it microsoft/powershell:nanoserver pwsh.exe23Windows PowerShell4Copyright (C) 2016 Microsoft Corporation. All rights reserved.5PS C:\>

仔细观察上面命令的输出内容,会注意到每个实例中的提示符都发生了变化。这是因为-it参数会将Shell切换到容器终端——现在已经位于容器内部了!

接下来分析一下docker container run命令。docker container run告诉Docker daemon启动新的容器。其中-it参数告诉Docker开启容器的交互模式并将读者当前的Shell连接到容器终端(在容器章节中会详细介绍)。接下来,命令告诉Docker,用户想基于ubuntu:latest镜像启动容器(如果用户使用Windows,则是基于microsoft/powershell:nanoserver镜像)。最后,命令告诉Docker,用户想要在容器内部运行哪个进程。对于Linux示例来说是运行Bash Shell,对于Windows示例来说则是运行PowerShell。

在容器内部运行ps命令查看当前正在运行的全部进程。

Linux示例如下。

1root@6dc20d508db0:/# ps -elf2F S UID    PID  PPID   NI ADDR SZ WCHAN  STIME TTY  TIME CMD34 S root     1     0    0 -  4560 wait   13:38 ?    00:00:00 /bin/bash40 R root     9     1    0 -  8606 -      13:38 ?    00:00:00 ps -elf

Windows示例如下。

 1PS C:\> ps 2 3Handles   NPM(K)   PM(K)   WS(K)   CPU(s)     Id   SI ProcessName 4-------   ------   -----   -----   ------     --   -- ----------- 5      0        5     964    1292     0.00   4716    4 CExecSvc 6      0        5     592     956     0.00   4524    4 csrss 7      0        0       0       4               0    0 Idle 8      0       18    3984    8624     0.13    700    4 lsass 9      0       52   26624   19400     1.64   2100    4 powershell10      0       38   28324   49616     1.69   4464    4 powershell11      0        8    1488    3032     0.06   2488    4 services12      0        2     288     504     0.00   4508    0 smss13      0        8    1600    3004     0.03    908    4 svchost14      0       12    1492    3504     0.06   4572    4 svchost15      0       15   20284   23428     5.64   4628    4 svchost16      0       15    3704    7536     0.09   4688    4 svchost17      0       28    5708    6588     0.45   4712    4 svchost18      0       10    2028    4736     0.03   4840    4 svchost19      0       11    5364    4824     0.08   4928    4 svchost20      0        0     128     136    37.02      4    0 System21      0        7     920    1832     0.02   3752    4 wininit22      0        8    5472   11124     0.77   5568    4 WmiPrvSE

Linux容器中仅包含两个进程。

  • PID 1:代表/bin/bash进程,该进程是通过docker container run命令来通知容器运行的。

  • PID 9:代表ps -elf进程,查看当前运行中进程所使用的命令/程序。

命令输出中展示的ps -elf进程存在一定的误导,因为这个程序在ps命令退出后就结束了。这意味着容器内长期运行的进程其实只有/bin/bash

Windows 容器运行中的进程会更多,这是由 Windows 操作系统工作方式决定的。虽然Windows容器中的进程比Linux容器要多,但与常见的Windows服务器相比,其进程数量却是明显偏少的。

Ctrl-PQ组合键,可以在退出容器的同时还保持容器运行。这样Shell就会返回到Docker主机终端。可以通过查看Shell提示符来确认。

现在读者已经返回到Docker主机的Shell提示符,再次运行ps命令。

Linux示例如下。

1$ ps -elf2F S UID       PID  PPID    NI ADDR SZ WCHAN  TIME CMD34 S root        1     0     0 -  9407 -      00:00:03 /sbin/init41 S root        2     0     0 -     0 -      00:00:00 [kthreadd]51 S root        3     2     0 -     0 -      00:00:00 [ksoftirqd/0]61 S root        5     2     -20     0 -      00:00:00 [kworker/0:0H]71 S root        7     2    -0 -     0 -      00:00:00 [rcu_sched]8<Snip>90 R ubuntu  22783 22475     0 -  9021 -      00:00:00 ps -elf

Windows示例如下。

 1> ps 2Handles   NPM(K)    PM(K)    WS(K)    CPU(s)     Id  SI ProcessName 3-------   ------    -----    -----    ------     --  -- ----------- 4    220       11     7396     7872      0.33   1732   0 amazon-ssm-agen 5     84        5      908     2096      0.00   2428   3 CExecSvc 6     87        5      936     1336      0.00   4716   4 CExecSvc 7    203       13     3600    13132      2.53   3192   2 conhost 8    210       13     3768    22948      0.08   5260   2 conhost 9    257       11     1808      992      0.64    524   0 csrss10    116        8     1348       580     0.08    592   1 csrss11     85        5      532      1136     0.23   2440   3 csrss12    242       11     1848       952     0.42   2708   2 csrss13     95        5      592       980     0.00   4524   4 csrss14    137        9     7784      6776     0.05   5080   2 docker15    401       17    22744     14016    28.59   1748   0 dockerd16    307       18    13344      1628     0.17    936   1 dwm17    <SNIP>18   1888        0      128       136    37.17      4   0 System19    272       15     3372      2452     0.23   3340   2 TabTip20     72        7     1184         8     0.00   3400   2 TabTip3221    244       16     2676      3148     0.06   1880   2 taskhostw22    142        7     6172      6680     0.78   4952   3 WmiPrvSE23    148        8     5620     11028     0.77   5568   4 WmiPrvSE

可以看到与容器相比,Docker主机中运行的进程数要多很多。Windows容器中运行的进程要远少于Windows主机,Linux容器中的进程数也远少于Linux主机。

在之前的步骤当中,是使用Ctrl-PQ组合键来退出容器的。在容器内部使用该操作可以退出当前容器,但不会杀死容器进程。读者可以通过docker container ls命令查看系统内全部处于运行状态的容器。

1$ docker container ls2CONTAINER ID   IMAGE          COMMAND      CREATED  STATUS    NAMES3e2b69eeb55cb   ubuntu:latest  "/bin/bash"  7 mins   Up 7 min  vigilant_borg

上述的输出显示只有一个运行中的容器。这就是前面示例中创建的那个容器。输出中有该容器,证明了容器在退出后依然是运行的。读者可以看到这个进程是7min之前创建的,并且一直在运行。

1.1.3 连接到运行中的容器

执行docker container exec命令,可以将Shell连接到一个运行中的容器终端。因为之前示例中的容器仍在运行,所以下面的示例会创建到该容器的新连接。

Linux示例如下。

1$ docker container exec -it vigilant_borg bash2root@e2b69eeb55cb:/#

示例中的容器名为“vigilant_brog”。读者环境中的容器名称会不同,所以请记得将“vigilant_brog”替换为自己Docker主机上运行中的容器名称或者ID。

Windows示例如下。

1> docker container exec -it pensive_hamilton pwsh.exe23Windows PowerShell4Copyright (C) 2016 Microsoft Corporation. All rights reserved.5PS C:\>

本例中使用的容器为“pensive_hamilton”。同样,读者环境中的容器名称会不同,所以请记得将“pensive_hamilton”替换为自己Docker主机上运行中的容器名称或者ID。

注意,Shell提示符又发生了变化。此时已登录到了容器内部。

docker container exec命令的格式是docker container exec <options><container-name or container-id> <command/app>。在示例中,将本地Shell连接到容器是通过-it参数实现的。本例中使用名称引用容器,并且告诉Docker运行Bash Shell(在Windows示例中是PowerShell)。使用十六进制ID的方式也可以很容易地引用具体容器。

再次使用Ctrl-PQ组合键退出容器。

Shell提示符应当退回到Docker主机中。

再次运行docker container ls命令来确认容器仍处于运行状态。

1$ docker container ls2CONTAINER ID   IMAGE          COMMAND      CREATED  STATUS    NAMES3e2b69eeb55cb   ubuntu:latest  "/bin/bash"  9 mins   Up 9 min  vigilant_borg

通过docker container stopdocker container rm命令来停止并杀死容器。切记需要将示例中的名称/ID替换为读者自己的容器对应的名称和ID。

1$ docker container stop vigilant_borg2vigilant_borg34$ docker container rm vigilant_borg5vigilant_borg

通过运行docker container ls命令,并指定-a参数来确认容器已经被成功删除。添加-a的作用是让Docker列出所有容器,甚至包括那些处于停止状态的。

1$ docker container ls -a2CONTAINER ID    IMAGE    COMMAND    CREATED    STATUS    PORTS    NAMES

1.2 开发视角

容器即应用!

在本节中,会分析一份应用代码中的Dockerfile并将其容器化,最终以容器的方式运行。相关代码可从本书配套资源或我的Github主页中获取。

本节接下来的内容会基于 Linux 示例进行演示。但其实两个示例中都容器化了相同的Web 应用代码,所以步骤也是一样的。

进入到仓库文件目录之下,查看其内容。

 1$ cd psweb 2$ ls -l 3total 28 4-rw-rw-r-- 1 ubuntu ubuntu  341 Sep 29 12:15 app.js 5-rw-rw-r-- 1 ubuntu ubuntu  216 Sep 29 12:15 circle.yml 6-rw-rw-r-- 1 ubuntu ubuntu  338 Sep 29 12:15 Dockerfile 7-rw-rw-r-- 1 ubuntu ubuntu  421 Sep 29 12:15 package.json 8-rw-rw-r-- 1 ubuntu ubuntu  370 Sep 29 12:15 README.md 9drwxrwxr-x 2 ubuntu ubuntu 4096 Sep 29 12:15 test10drwxrwxr-x 2 ubuntu ubuntu 4096 Sep 29 12:15 views

对于Windows示例,读者需要cddotnet-docker-samples\aspnetapp目录当中。

Linux的示例是一个简单的Node.js Web应用。Windows示例是一个简单的ASP.NET Web应用。

每个仓库中都包含一个名为Dockerfile的文件。Dockerfile是一个纯文本文件,其中描述了如何将应用构建到Docker镜像当中。

查看Dockerfile的全部内容。

 1$ cat Dockerfile 2 3FROM alpine 4LABEL maintainer="nigelpoulton@hotmail.com" 5RUN apk add --update nodejs nodejs-npm 6COPY . /src 7WORKDIR /src 8RUN  npm install 9EXPOSE  808010ENTRYPOINT ["node", "./app.js"]

Windows示例中的Dockerfile内容会有所不同。但是,这些区别在现阶段并不重要。关于Dockerfile的更多细节本书会在接下来的章节中进行详细介绍。现在,只需要知道Dockerfile的每一行都代表一个用于构建镜像的指令即可。

使用docker image build命令,根据Dockerfile中的指令来创建新的镜像。示例中新建的Docker镜像名为test:latest

一定要在包含应用代码和Dockerfile的目录下执行这些命令。

 1$ docker image build -t test:latest . 2 3Sending build context to Docker daemon 74.75kB 4Step 1/8 : FROM alpine 5latest: Pulling from library/alpine 688286f41530e: Pull complete 7Digest: sha256:f006ecbb824...0c103f4820a417d 8Status: Downloaded newer image for alpine:latest 9 ---> 76da55c8019d10<Snip>11Successfully built f154cb3ddbd412Successfully tagged test:latest

{注:} 

Windows示例构建可能花费比较长的时间。构建时间长短是由构建过程中要拉取的镜像大小和复杂度决定的。

一旦构建完成,就可以确认主机上是否存在test:latest镜像。

1$ docker image ls2REPO     TAG        IMAGE ID         CREATED         SIZE3Test     latest     f154cb3ddbd4     1 minute ago    55.6MB4...

读者现在已经拥有一个新的Docker镜像,其中包含了应用程序。

从镜像启动容器,并测试应用。

Linux代码如下。

1$ docker container run -d \2  --name web1 \3  --publish 8080:8080 \4  test:latest

打开Web浏览器,在地址栏中输入容器运行所在的Docker主机的DNS名称或者IP地址,并在后面加上端口号8080。然后就能看到图4.1的Web页面。

如果读者使用的是Windows示例或者Mac版Docker,则需要将地址替换为localhost:8080或者127.0.0.1:8080;如果读者使用的是Play with Docker,需要单击终端界面上的8080超链接。


图1.1 Linux系统测试应用Web界面

Windows代码如下。

1> docker container run -d \2  --name web1 \3  --publish 8080:80 \4  test:latest

打开Web浏览器,在地址栏中输入容器运行所在的Docker主机的DNS名称或者IP地址,并在后面加上端口号8080,然后就能看到图4.2的Web页面。


图1.2 Windows系统测试应用Web界面

如果读者使用的是Windows示例或者Mac版Docker,则可参考上面的规则。

读者已经成功将应用代码构建到了Docker镜像当中,然后以容器的方式启动该镜像,这个过程叫作“应用容器化”。

1.3 本文小结

在运维部分,我们下载了Docker镜像,启动容器并且登录到容器内部执行相应的命令,最后停止容器并删除。

在开发部分,我们完成了简单应用的容器化过程:从GitHub拉取应用源代码,并且通过Dockerfile中的指令,将应用代码构建到镜像之中。接着运行了该容器化应用。

深入浅出Docker

【英】Nigel Poulton(奈吉尔 波尔顿)

扫码一键购

在美国亚马逊,有一本书的影响力超高的Docker入门书,在操作系统分类中排行第一,超越了众多实力派Docker书,众多五星好评。也许你有所耳闻,这本书就是《深入浅出Docker》

这是一本关于Docker的图书。这本书的宗旨是从零开始学习Docker,因此你无须任何前置知识储备。如果你对Docker感兴趣,希望了解Docker工作原理以及如何正确使用Docker,则本书适合你。同时本书也可作为Docker认证工程师考试的参考图书。

欢迎留下您对本文的讨论,以及在使用.NET容器化过程中的感悟。评论获点赞最多的前10位读者将获赠《深入浅出Docker》图书一本(包邮)。活动截止时间3.31 23点。

相关文章:

  • ASP.NET Core 借助 K8S 玩转容器编排

  • 如何使用vs将asp.net core项目添加容器支持并发布docker镜像到私有dockerhub和添加k8s/helm管理

.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com

【送书活动】10分钟了解Docker,运维和开发视角有什么不同?相关推荐

  1. 【送书福利】第一次送书活动(总共10本)

    在公众号『程序IT圈』运营以来,终于为各位粉丝争取到了一次十分给力的送书活动,首先大力感谢本次赞助商 电子工业出版社博文视点 提供的10本图书. 好了,下面开始我们的送书活动: 1.先介绍一下本次共有 ...

  2. 【送书活动第二话】:共10本技术书籍送! 送!! 送!!!

    一.本期活动 这次的活动,共赠送10本书籍:抽奖方式见文末. 二.上弹回顾 在上一弹的送书活动中,中三等奖:两本抽奖书籍,中奖的分别是昵称为"醉清风"和"Wy.L&quo ...

  3. 《Python预测之美》送书活动,拿走不谢~

    这是一本什么样的书? - 以Python语言为基础,配合原理.方法.案例进行讲解 - 专注预测专题,体系化介绍预测技术工程实施的必备技能 - 深度剖析预测原理,细致解读数据分析算法 这本书长啥样? P ...

  4. Python查找Word文件中红色和加粗的文字(附元宵节送书活动中奖名单)

    背景知识:docx文件的结构分为三层,1.Docment对象表示整个文档:2.Docment包含了Paragraph对象的列表,每个Paragraph对象用来表示文档中的一个段落:3.一个Paragr ...

  5. 《.NET 性能优化》送书活动结果公布

    截止到9月7日18:00(规则本是12:00,忙的忘记了这事,18点截的图),本次送书活动<.NET 性能优化> 共收到100多位同学参与回复,本次很多同学在看到活动的书 ,自行就到异步社 ...

  6. 《机器学习项目开发实战》送书活动结果公布

    截止到8月8日24:00,本次送书活动 共收到70位同学参与回复,本次很多同学在看到活动的书<机器学习项目开发实践>,自行就到各大网络商店上购买了书,据反馈这个书很不错,小二昨天也收到一本 ...

  7. 挖槽!堪称神级的Java技术手册火了???(文末送书活动)

    前言 本文是为了帮大家快速回顾了Java中知识点,这套面试手册涵盖了诸多Java技术栈的面试题和答案,相信可以帮助大家在最短的时间内用作面试复习,能达到事半功倍效果. 本来想将文件上传到github上 ...

  8. 送书活动还有最后一本书,怎么办呢?

    小灰于12月8日-12月9日举行了送书活动,一共有10位幸运的读者获奖.其中9位读者已经和小灰取得联系,但是还有一位朋友没有联系上,过时不候啦. 12月送书活动 最后这一本书怎么来送给大家呢?靠留言点 ...

  9. 【喜讯】 第1期送书活动获奖名单,看看都是谁!

    微信公众号 关键字全网搜索最新排名 [机器学习算法]:排名第一 [机器学习]:排名第一 [Python]:排名第三 [算法]:排名第四 <机器学习算法与Python学习>的小编于11.10 ...

最新文章

  1. PostgreSQL日期函数备忘
  2. JS获取元素在页面的位置
  3. C# 用IrisSkin4.dll美化你的WinForm
  4. 在阿里工作5年了,斗胆谈谈我认为的高级开发到底应该是怎样的?
  5. Thinkphp 公共函数自动加载
  6. 【先到先得】这款课程版 iPhone XR 免费送给你!
  7. 关于交流电路的谐振等问题
  8. Linux学习笔记9_终端提示符编辑方法(修改颜色,路径,时间)
  9. vue 时间插件_Vue插件丨vxe-table初体验
  10. webview的使用套餐,安卓面试题2021pdf
  11. 动易html在线编辑器,动易系统解决IE8网站后台编辑器无效问题
  12. 【SENCHA TOUCH】datepickerfield将日期改为中文日期或自定义的日期
  13. 线对 Line pairs度量空间频率
  14. wps linux版公式编辑器,linux下的公式编辑器
  15. 一、 Hbase特性 3v特性,Volume(量级) Varity(种类) Velocity(速度)
  16. 多传感器时频信号处理:多通道非平稳数据的分析工具(Matlab代码实现)
  17. Python 爬虫js加密破解(四) 360云盘登录password加密
  18. java 编写线程公共类_Java实现线程间通信方式
  19. CS硕士妹子找工作经历【阿里人搜等互联网公司】
  20. MATLAB复原动态模糊图像

热门文章

  1. wdcp mysql密码_WDCP提示无法连接mysql及创建站点提示mysql密码不正确
  2. 读名老中医之路笔记(二)
  3. jQuery07源码 (3803 , 4299) attr() prop() val() addClass()等 : 对元素属性的操作
  4. php同个用户同时只能登陆一个, 后登陆者踢掉前登陆者
  5. np变题了。但我过了
  6. 如何实现一个线程安全的 ConcurrentHashSet ?
  7. 支付宝 .NET SDK 报错:RSA签名遭遇异常,请检查私钥格式是否正确。
  8. Envoy实现.NET架构的网关(五)集成Redis实现限流
  9. C#多线程开发-处理子线程中的异常
  10. 关于 Azure SQL 数据库你不知道的 5 件事