Python社区  »  docker

Docker应用详细解析(一) —— 在macOS上使用Docker(一)

不想做iOS了 • 7 月前 • 116 次点击  

版本记录

版本号 时间
V1.0 2018.11.17 星期六

前言

Docker是一个跨平台的轻量级虚拟机,可移植性非常高,一次部署,终生可用。Docker可以在Linux、Windows、MacOS等平台上安装使用。接下来几篇我们就一起看一下Docker相关的内容。

开始

Docker是一种工具,可以轻松地在容器中运行应用程序。 容器提供隔离和安全性,如虚拟机,但它们要小得多,因为它们在主机系统中运行。

作为iOS开发人员,您为什么要使用Docker? 避免版本问题 - 运行操作系统版本,编程语言,数据库应用程序,Web应用程序和Web服务器,机器学习程序 - 所有这些都在隔离的环境中,以避免Mac上安装的任何其他副作用。

在本教程中,您将熟悉Docker词汇表和用于创建,检查和删除容器,网络和数据卷的命令。 您将学习如何在后台或前台运行Docker容器,并在两者之间切换;如何发布端口;如何连接数据库应用程序和在不同容器中运行的Web应用程序;以及如何在容器和Mac之间以及容器之间共享目录。 完成本教程后,您将很快使用Docker ninjadom

注意:这个Docker教程假设您愿意在终端中输入Unix命令。 熟悉Unix命令和文件路径,数据库应用程序和localhost端口会很有帮助。

1. Installing Docker - 安装Docker

Docker最初是为Linux开发的。 在macOS上运行Docker曾经相当复杂,但是2016年7月推出了原生macOS应用程序Docker for Mac,所以现在它变得轻而易举!

通用版Community Edition (CE)是免费下载的,所以download Docker CE for Mac,然后安装并运行该应用程序。 Moby the Whale应出现在Mac的状态栏中:

注意:如果上面的直接下载链接不起作用,请转到Docker’s web page,单击Please Login to Download按钮,创建一个帐户,然后等待激活电子邮件。 在您等待的同时,使用在线Play-With-Docker playground


Docker Terminology & Housekeeping

在本节中,您将学习一些Docker词汇表,并熟悉使用Unix命令行进行基本的housekeeping任务。

注意:本教程中有一个方便的所有命令列表 - 向下滚动到最后。

1. Hello World

打开终端,然后输入此命令以查看Docker是否正常运行:

docker run hello-world

workhorse Docker命令是docker run,这是最简单的docker run命令 - 它指定要运行的Docker镜像。 如果映像不在主机系统上,它会尝试从默认的Docker映像注册表中提取映像。 单词image的含义类似于您下载为.dmg文件的磁盘映像。 Docker镜像是一个应用程序,您可以在你的系统Docker容器中上运行它。

这个命令的输出解释了Docker刚刚做了什么:

Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
d1725b59e92d: Pull complete 
Digest: sha256:0add3ace90ecb4adbf7777e9aacf18357296e799f81cabc9fde470971e499788
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

哇,要学习很多新术语! 从顶部开始:

  • 虽然你只要求了hello-world,但是Docker寻找了hello-world:latest - latest是一个指示版本的标签。 如果您没有要求特定版本,Docker假定您需要最新版本。
  • 由于映像不在您的系统上,因此Docker将其从library/hello-world中拉取 - 它位于默认映像注册表Docker Hub中。 您将在Running a Web App部分中访问此位置。
  • Docker clientDocker daemonDocker Engine的一部分,它是现在在Mac上运行的客户端 - 服务器应用程序。 daemon是服务器,客户端是docker命令行界面(CLI)。 客户端使用引擎的REST APIdaemon发出指令。
Docker engine (image from docs.docker.com)

注意:您将在本教程后面了解Docker的网络和数据量功能。

Docker镜像有很多种类型:

  • OS - 操作系统:主要是Linux风格,如Ubuntu,Alpine等。
  • programming languages - 编程语言Swift,Ruby,PHP,Haskell,Python,Java,Golang等。
  • databases - 数据库MySQL,CouchDB,PostgreSQL,Oracle,IBM Db2等。
  • application frameworks - 应用程序框架Node.js,Flask,Kitura,Tomcat等。
  • Web服务器Nginx,Apache等。
  • 用于机器学习的Web应用程序,包括Python应用程序和Jupyter笔记本

Docker镜像由layers组成 - 较高层(API或应用程序)使用较低层(OS或编程语言)。运行镜像会创建一个容器 - 一个位于镜像只读层顶部的精简读写层。您可以使用非常少的内存在多个容器中运行相同的映像。每个容器只是读写层,系统上只存在一个映像副本。镜像的顶部只读层指定要在容器中运行的命令 - 对于hello-world,此命令只输出Hello from Docker!信息。

Container layer on top of image layers (image from docs.docker.com)

2. Using Docker Commands - 使用Docker命令

现在到housekeeping部分 - 您需要跟踪Docker在您的系统上创建的内容,以便您可以在不再需要时删除内容。

首先,一些关于Docker命令行界面(CLI)语法的一般信息:Docker命令类似于Unix命令,但它们以“docker”开头,如docker run,docker image,docker container,docker network

大多数命令有几个options,许多选项都有简写版本。选项的全名是--something,有两个破折号,如--name--publish。简写版本是-abbrev,带有一个破折号,例如-p用于--publish-v用于--volume。一些选项,如--name,没有简写版本。

大多数选项都需要值,例如-p 8080:8080--name kitura。少数没有值,可以一起运行,比如-it-ti,简称--interactive --tty。您必须在选项名称后面指定选项的值,但选项和选项 - 值对可以按任何顺序出现。

许多选项值将host machine上的某些内容映射到容器中的某些内容。在您的情况下,主机是您的Mac。

您将在本教程中使用所有这些以及更多内容。

首先在终端窗口中输入以下命令:

docker images

输出列出了系统上的Docker镜像,特别是hello-world:Docker提取的最新图像:

REPOSITORY    TAG     IMAGE ID      CREATED       SIZE
hello-world   latest  e38bc07ac18e  2 months ago  1.85kB

注意:您的输出将显示不同的IMAGE IDCREATED值。

正如docker run hello-world的输出所示,Docker daemon从该映像创建了一个容器,以运行生成输出的可执行文件。

运行此命令以显示系统上的所有(-a)Docker容器:

docker ps -a

注意:这与docker container ls -a的功能相同。 对于这两个命令,不使用-a选项仅列出正在运行的容器。

输出只显示一个容器:

CONTAINER ID  IMAGE        COMMAND   CREATED    STATUS  PORTS  NAMES
4ed31ad50912  hello-world  "/hello"  16 sec...  Exited ...     stupefied_gates

Docker为容器创建了一个ID和一个名称 - 您的值将不同。 虽然容器已退出,但它仍在您的系统上。

运行hello-world,然后再次显示所有容器:

docker run hello-world
docker ps -a

注意:使用Up ArrowDown Arrow键浏览您在此终端窗口中运行的Unix命令。

现在有第二个容器,具有不同的ID和名称值:

CONTAINER ID  IMAGE        ...  NAMES
4ed31ad50912  hello-world  ...  stupefied_gates
e5d3669f5ca1  hello-world  ...  flamboyant_zhukovsky

您可以通过指定容器的名称或ID或其ID的前3个字符来删除容器,并且可以在单个命令中删除多个容器,如下所示(您的ID和名称将不同):

docker rm e5d stupefied_gates

输出只是回显容器ID或名称。 确认容器已消失:

docker ps -a

看到Docker提供的名称很有趣,但是当你使用容器一段时间之后,可以方便地为容器提供自己的名字。 输入以下命令:

docker run --name helloWorld hello-world

然后列出容器:

docker ps -a

你已经命名了你的容器:

CONTAINER ID  IMAGE        ...  NAMES
c5f411a593a3  hello-world  ...  helloWorld

再次运行相同的命令:

docker run --name helloWorld hello-world


    

现在您收到一条错误消息,因为该容器名称已被使用:

docker: Error response from daemon: Conflict. The container name "/helloWorld" 
  is already in use by container 
"c5f411a593a341593ff531c444c44f7dd7fd3f1a006395c9c3cbf5ff687838e1". You have to 
  remove (or rename) that container to be able to reuse that name.

接下来,我想向你展示一个很酷的housekeeping技巧,所以运行几次docker run hello-world,以获得混乱你的系统的容器。 然后运行此命令列出它们:

docker ps -a -q -f status=exited

这是您用来显示系统上所有Docker容器的docker ps -a命令,以及两个选项。 选项-q--quiet的缩写,因此该命令仅显示数字ID。 选项-f--filter的缩写,过滤条件是status = exited。 所以输出看起来像这样(你的ID会有所不同):

d8d962602abf
64b2eb1af5da
5fde263a26a0
1659b24f2ce2
ff5e7f6a17b5
ab4bf3b4c32b
0d0e48dfcf32
18d8beb2fe60
c5f411a593a3

现在,不要将每个ID复制粘贴到docker rm命令中,只需将此输出提供给docker rm命令:

docker rm $(docker ps -a -q -f status=exited)

这个命令首先运行$()中的部分,以获取已激活容器的ID列表,然后将它们全部删除 - 非常棒!

既然已经删除了容器,您也可以删除镜像:

docker rmi hello-world

您的输出看起来类似于:

Untagged: hello-world:latest
Untagged: hello-world@sha256:f5233545e43561214ca4891fd1157e1c3c563316ed8e237750d
59bde73361e77
Deleted: sha256:e38bc07ac18ee64e6d59cf2eafcdddf9cec2364dfe129fe0af75f1b0194e0c96
Deleted: sha256:2b8cbd0846c5aeaa7265323e7cf085779eaf244ccbdd982c4931aef9be0d2faf

再次检查镜像

docker images

你的系统现在是干净的了

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE

节省时间提示 - Docker清理终端窗口:将此终端窗口移动到桌面的一角,并仅将其用于运行Docker清理命令。 这样,你想要的命令只会是几个向上箭头击键。 另一个技巧是输入Unix命令history以查找所需命令的编号,然后输入再次运行该命令。 例如,下面是我历史记录中的最后几个命令,因此输入命令!18将删除所有exited的容器。

15  docker run --name helloWorld hello-world
16  docker ps -a
17  docker ps -a -q -f status=exited
18  docker rm $(docker ps -a -q -f status=exited)
19  docker rmi hello-world
20  docker images
21  history

Running a Web App in a Docker Container - 在Docker Container中运行一个Web App

许多iOS应用程序与Web服务器通信,Web服务器也是Web应用程序的后端。 而且您经常希望与iOS应用程序的交互反映在Web应用程序中,反之亦然。 您可以在没有容器的情况下在本地运行Web应用程序,但在容器中运行它可以更容易地单独测试不同的配置,或者测试具有不同权限的用户类型。

要在容器中运行Web应用程序,首先需要了解的是如何在浏览器的localhost中访问容器的端口。 Docker术语是发布端口(publishing ports)。 在本节中,您将了解发布端口,并快速查看默认的Docker镜像注册表Docker Hub

1. Publishing Ports

实际上,你不需要人工智能来找出端口! 语法是--publish后跟两个端口号,用冒号分隔。 诀窍是记住第一个值是主机在这里,第二个值是容器那里 - 你从那里发布一个端口。 对于第一个号码 - 主机的端口 - 您可以指定任何您喜欢的号码,但最简单的选择是使用与容器端口相同的号码。 对于第二个数字,您会遇到容器暴露的任何内容 - 如果您尝试更改它,则会出现错误。 将容器的端口发布到不同的localhost端口的能力使得同时运行多个Web应用程序容器变得容易。

IBM Kitura的一个非常简单的Web应用程序开始。 在浏览器中,在Docker Hub上加载Docker镜像的默认注册表。 在Search框中输入kitura,然后选择第一个返回的项目:

打开一个新的终端窗口 - 这将是您的Docker run终端窗口。 有时,您将在此窗口中的前台运行一个进程,因此您将无法在其中运行任何内务处理命令。 这就是你的Docker cleanup窗口会派上用场的地方!

单击Docker Pull Commandcopy icon,并将其粘贴到Docker run终端窗口中:

docker pull ibmcom/kitura-ubuntu

ibmcom / kitura-ubuntu映像将一个简单的Web应用程序层叠到Kitura应用程序框架上,该框架分层到swift-ubuntu映像上,这是在Ubuntu操作系统之上分层的Swift编程语言。 UbuntuLinux的一个版本。

镜像的Docker Hub页面没有给出任何特定的运行指令,所以请继续尝试:

docker run ibmcom/kitura-ubuntu

注意:您可以刚刚输入命令docker run ibmcom / kitura-ubuntu而不是pull命令,它会在运行之前从Docker Hub中提取镜像。 但有时,您可能只想下载镜像,然后稍后运行 - 也许在设置其他组件之后。

容器启动,包含以下消息:

[2018-10-02T21:53:57.690Z] [WARNING] [ConfigurationManager.swift:261 load(url:
  deserializerName:)] Unable to load data from URL 
  /Kitura-Starter/config/mappings.json
[2018-10-02T21:53:57.698Z] [INFO] [main.swift:28 Kitura_Starter] Server will be 
  started on 'http://localhost:8080'.
[2018-10-02T21:53:57.703Z] [INFO] [HTTPServer.swift:124 listen(on:)] Listening 
  on port 8080

注意:您还可以在docker ps输出的PORTS列中查看容器的端口。

它尝试但未能从JSON文件加载数据,然后开始侦听localhost:8080。 请注意,您没有收到Unix shell提示符 - 此进程正在前台运行,并且尚未退出。

localhost:8080打开浏览器 - 不,“Can’t Connect to the Server”。 发生了什么? 容器在其自己的环境中公开端口8080,但您必须将此端口发布到主机系统上的端口,以查看其中的内容。

首先,摆脱这个试用版容器:在你的Docker cleanup窗口中,运行一个命令来查找容器的ID,停止容器,然后将其删除。 因为只有一个容器在运行,所以您可以使用一个带有两个$()嵌套级别的命令来停止并删除所有正在运行的容器。 在检查下面的解决方案之前,请尝试自己解决此问题。

docker rm (docker stop(docker ps -q))

此命令停止并删除所有正在运行的容器。 如果您有要继续运行的运行容器,请使用docker ps自行查找要停止和删除的正在运行的容器的ID。

返回Docker run终端窗口 - 返回Unix shell提示符。 输入以下命令:

docker run -p 80:8080 --name kitura -d ibmcom/kitura-ubuntu

-p选项 - --publish的缩写,将真正本地的localhost:80映射到容器的8080端口。 --name选项指定容器名称。 -d选项--detach的缩写,在后台运行容器进程,因此您可以立即返回Unix shell提示符。

在浏览器中,打开localhost:80以查看此欢迎页面:

在另一个端口上运行第二个容器:

docker run -p 90:8080 --rm --name kitura2 ibmcom/kitura-ubuntu

在浏览器中,打开localhost:90以查看相同的欢迎页面。

这次,容器在前台运行 - 你没有使用-d选项,所以你没有得到Unix shell提示符。 此外, -- rm选项表示在停止容器时将删除容器。

Docker cleanup窗口中,输入以下命令:

docker stop kitura2

它可能需要几秒钟才能回复kitura2,并且Unix shell提示符会在Docker run窗口中返回。

使用docker ps -a查看没有Exited容器:

CONTAINER ID  IMAGE                .. STATUS       PORTS                  NAMES
f64f7eb69258  ibmcom/kitura-ubuntu .. Up 47 sec..  0.0.0.0:80->8080/tcp   kitura

第一个容器仍在后台运行,因此请输入此命令以停止它:

docker stop kitura

Unix shell提示符返回时,请刷新localhost:80页面 - 它将不会加载,因为您停止了容器进程。

使用docker ps -a检查第一个容器是否仍然存在,然后运行此命令重新启动它:

docker start kitura

刷新localhost:80页 - 这次它有效!

Clean up:关闭浏览器窗口。 停止并取出容器。 请注意,除非使用force,否则无法删除正在运行的容器。


Running a Web App With a Database - 运行使用数据库的Web App

在本节中,您将首先在容器中运行数据库应用程序,由主机系统上运行的Web应用程序访问。 您需要发布数据库应用程序的端口,以便Web应用程序可以访问它。

如果要在多个端口上运行Web应用程序,如果它在容器中运行也会更容易。 但是您必须做一些额外的工作才能让Web应用程序访问数据库应用程序。

1. Running CouchDB in a Docker Container - 在Docker容器中运行CouchDB

Web应用程序通常将数据存储在数据库应用程序中,如PostgreSQLCouchDB。 在Docker容器中运行数据库应用程序可以避免版本问题或测试不同的版本或用户类型。

Docker run窗口中,输入此命令以在Docker容器中运行CouchDB

docker run --name couchdb -p 5984:5984 -d couchdb

CouchDB镜像始终公开端口5984。您可以将其发布到本地主机端口号,以便Web服务器应用程序可以访问它。

注意:要在容器中运行CouchDB时指定用户和密码信息,请使用--env(-e)选项 - 例如:

docker run -e COUCHDB_USER=admin -e COUCHDB_PASSWORD=password --name couchdb -p 5984:5984 -d couchdb

在等待CouchDB时,构建一个使用它的Web服务器应用程序。 别担心 - 这只是几个Unix命令!

打开另一个终端窗口 - 您将在此处输入必须在EmojiJournalServer目录中运行的命令。 在Finder 中,找到下载材料中的EmojiJournalServer文件夹,然后在终端窗口中运行以下命令:

cd <drag the EmojiJournalServer folder from Finder to the terminal window>
swift build 
.build/debug/EmojiJournalServer

注意:随着应用构建,您将收到一些弃用警告。 别理他们。

首先,您切换到EmojiJournalServer目录,该目录包含Package.swift文件。 第二个命令使用此文件构建Web服务器应用程序,第三个命令运行它。 输出如下:

[2018-10-22T14:56:58.919+11:00] [INFO] [Application.swift:45 
  connectionProperties] Running on MacOS - using local database
[2018-10-22T14:56:58.932+11:00] [WARNING] [ConnectionProperties.swift:57 
  init(host:port:secured:username:password:)] Initializing a CouchDB connection 
  without a username or password.
[2018-10-22T14:56:59.018+11:00] [INFO] [Application.swift:94 createNewDatabase()] 
  Database does not exist - creating new database
[2018-10-22T14:56:59.112+11:00] [INFO] [EntryRoutes.swift:43 
  initializeEntryRoutes(app:)] Journal entry routes created
[Mon Oct 22 14:56:59 2018] com.ibm.diagnostics.healthcenter.loader INFO: Swift 
  Application Metrics
[2018-10-22T14:56:59.206+11:00] [INFO] [Metrics.swift:47 
  initializeMetrics(app:)] Initialized metrics.
[2018-10-22T14:56:59.208+11:00] [INFO] [WebClientRoutes.swift:43 
  initializeWebClientRoutes(app:)] Web client routes created
[2018-10-22T14:56:59.218+11:00] [INFO] [HTTPServer.swift:124 listen(on:)] 
  Listening on port 8080

输出的最后一行表示它是“listening on port 8080”,因此在浏览器中打开localhost:8080以查看Kitura欢迎页面。

Journal entry routeclient,因此将/ client添加到位置URL以查看Emoji Journal应用程序: