狼视 ·

Docker入门:简化Devops

前言

之前只听过其名,没详细看过,趁着这篇文章顺便了解下。老规矩,原文如下:

Getting Started with Docker: Simplifying Devops

文章正文

如果您喜欢鲸鱼,或者您只需要快速,无痛地连续将您的软件交付给生产,那么我邀请您阅读本介绍的Docker教程。一切似乎都表明,软件容器是IT的未来,让我们快速地和Moby DockMolly的容器鲸鱼一起开始吧。

Docker入门:简化Devops

Docker以一个友好的鲸鱼标志为代表,是一个开源的项目,可以方便在软件容器内部署应用程序。其基本功能由Linux内核的资源隔离功能启用,但它在其上提供了一个用户友好的API。第一个版本于2013年发布,从此变得非常受欢迎,被eBay,Spotify,Baidu等许多大厂商广泛使用。在最后一轮融资中,Docker已经投入了9,500万美元

运输货物类比(Transporting Goods Analogy)

Docker背后的理念可以通过以下简单的比喻进行说明。在国际运输业,货物必须以叉车,卡车,火车,起重机和船舶等不同方式运输。这些货物的形状和尺寸不同,存储要求不同:糖,牛奶罐,植物等。从历史上看,每个过境点的装卸依靠手动干预是一个痛苦的过程。

Docker入门:简化Devops

随着多式联运集装箱的采用,这一切都发生了变化。由于它们符合标准尺寸,并以运输为中心制造,所有相关机构都可以设计为以最少的人为干预来处理。密封容器的附加优点是可以保护敏感物品的温度和湿度等内部环境。结果,运输行业可以不再担心货物本身,而是集中精力从A到B。

Docker入门:简化Devops

而这也是Docker所在的地方(感觉可能是说这是Docker与之的相似之处),并为软件行业带来了类似的收益

与虚拟机有何不同?

快速浏览,虚拟机和Docker容器可能看起来一样。但是,当您查看以下图表时,它们的主要区别将变得明显:

Docker入门:简化Devops

运行在虚拟机中的应用程序除了需要虚拟机管理程序外,还需要操作系统和任何支持库的完整实例。另一方面,容器与主机共享操作系统。管理程序与容器引擎(在上图中表示为Docker)相当,因为它管理容器的生命周期。重要的区别是容器内运行的进程与主机上的本机进程一样,不会引入与管理程序执行相关的任何开销。此外,应用程序可以重用库并在容器之间共享数据。

由于两种技术具有不同的优点,通常找到组合虚拟机和容器的系统。一个完美的例子是Docker安装部分中描述的一个名为Boot2Docker的工具。

Docker架构

Docker入门:简化Devops

在架构图的顶部有注册表。默认情况下,主注册表中托管Docker Hub 的公共和官方镜像(official images)。组织机构们如果愿意也可以托管(host )自己的私有注册表( private registries)。

在右边我们有镜像和容器。当启动一个容器时,镜像可以从注册表显式(docker pull imageName)或隐式下载。一旦镜像被下载,它将在本地缓存。

容器是镜像的实例。它们都是有生命的。基于同一个镜像可以运行多个容器。

在中心,Docker daemon的责任是创建、运行和检测容器。它还负责构建和存储镜像。最后,左侧有一个Docker客户端。它通过HTTP与daemon进程通信。在同一台机器上使用Unix套接字,但通过基于HTTP的API可以进行远程管理。

安装Docker

有关最新的说明,请务必参考官方文档

Docker在Linux原生地(natively)运行,所以根据目标distribution可能会很简单sudo apt-get install docker.io。有关详细信息,请参阅文档。通常在Linux中,您可以通过sudo使用Docker命令,但为了清楚起见,我们将在本文中略过它。

由于Docker daemon使用特定于Linux的内核功能,因此无法在Mac OS或Windows中原生地(natively)运行Docker。为了能在其上运行,应该安装一个名为Boot2Docker的应用程序。该应用程序由VirtualBox虚拟机,Docker本身和Boot2Docker管理实用程序(management utilities)组成。您可以按照MacOSWindows的正式安装说明在这些平台上安装Docker。

使用Docker

让我们以简单的例子开始本节:

docker run phusion/baseimage echo "Hello Moby Dock. Hello Molly."

我们应该看到这个输出:

Hello Moby Dock. Hello Molly.

不过,幕后还发生了更多比你想象的要多的事情:

  • 从 Docker Hub下载 ‘phusion/baseimage’镜像(如果尚未在本地缓存中)
  • 一个基于该镜像的容器被启动。
  • 命令echo在容器内执行
  • 当命令被释放时,容器被停止

首次运行时,您可能会在屏幕上打印文字之前注意到延迟。如果镜像已经在本地缓存,一切都将花费几分之一秒。可以通过运行docker ps -l获取最近一个容器的详细信息:

CONTAINER ID		IMAGE					COMMAND				CREATED			STATUS				PORTS	NAMES
af14bec37930		phusion/baseimage:latest		"echo 'Hello Moby Do		2 minutes ago		Exited (0) 3 seconds ago		stoic_bardeen

采取下一个Dive

正如你所知,在Docker中运行一个简单的命令就像在标准终端上直接运行一样简单。为了说明一个更实际的用例,在本文的剩余部分中,我们将看到我们如何利用Docker部署一个简单的Web服务器应用程序。为了保持简单,我们将编写一个Java程序来处理HTTP GET请求‘/ping’以及响应 ‘pong\n’字符串。

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;

public class PingPong {

    public static void main(String[] args) throws Exception {
        HttpServer server = HttpServer.create(new InetSocketAddress(8080), 0);
        server.createContext("/ping", new MyHandler());
        server.setExecutor(null);
        server.start();
    }

    static class MyHandler implements HttpHandler {
        @Override
        public void handle(HttpExchange t) throws IOException {
            String response = "pong\n";
            t.sendResponseHeaders(200, response.length());
            OutputStream os = t.getResponseBody();
            os.write(response.getBytes());
            os.close();
        }
    }
}

Dockerfile

在跳入和构建您自己的Docker映像之前,一个很好的做法是首先检测Docker Hub中或您可以访问的任何私人注册表是否存在一个现有的。例如,我们可以使用官方镜像 java:8,而不是自己安装一个java。

要构建一个镜像,首先我们需要决定一个我们要使用的基本镜像。它由FROM指令表示。在这里,它是来自Docker Hub的Java 8的官方图像。我们将通过发出COPY指令将其复制到我们的Java文件中。接下来,我们将使用RUN编译它EXPOSE指令表示图像将在特定端口上提供服务ENTRYPOINT是一个当基于此镜像的容器启动时我们要执行的指令,CMD指示将要传递给它的默认参数

FROM java:8
COPY PingPong.java /
RUN javac PingPong.java
EXPOSE 8080
ENTRYPOINT ["java"]
CMD ["PingPong"]

在将这些指令保存在名为“Dockerfile”的文件中后,我们可以通过执行以下命令来构建相应的Docker镜像:

docker build -t toptal/pingpong .

Docker的官方文档有一节专门介绍关于编写Dockerfile的最佳做法

运行容器

当镜像建成时,我们可以将其作为容器使用。有几种方法可以运行容器,现在让我们从一个简单的开始:

docker run -d -p 8080:8080 toptal/pingpong

其中-p [port-on-the-host]:[port-in-the-container]分别表示主机和容器上的端口映射。此外,我们通过指定-d告诉Docker在后台作为daemon 程序进程运行容器。您可以通过尝试访问‘http://localhost:8080/ping’来测试Web服务器应用程序是否正在运行。请注意,在使用Boot2docker的平台上,您需要将“localhost”替换为运行Docker的虚拟机的IP地址。

在Linux上:

curl http://localhost:8080/ping

在需要Boot2Docker的平台上:

curl $(boot2docker ip):8080/ping

如果一切顺利,你应该看到回应:

pong

23333,我们的第一个定制Docker容器是活着和游泳( is alive and swimming,应该是想表达容器正常运行了的意思吧)!我们也可以以交互模式启动容器-i -t在我们的例子中,我们将覆盖entrypoint命令,所以我们给了一个bash终端。现在我们可以执行我们想要的任何命令,但退出容器将会停止它:

docker run -i -t --entrypoint="bash" toptal/pingpong

还有更多的选项可用于启动容器。让我们再来一些。例如,如果我们要保留容器外的数据,我们可以使用-v与容器共享主机文件系统。默认情况下,访问模式为读写,但可以通过附加:ro到容器内卷路径来更改为只读模式。当我们需要使用任何安全信息(例如容器中的凭证和私钥)时,卷(Volumes)是特别重要的,不应该存储在镜像上。此外,它还可以防止数据重复,例如通过将本地Maven存储库映射到容器来保存您下载Internet两次。

Docker还具有将容器连接在一起的能力。即使没有端口被暴露,链接的容器也可以相互通信。可以用-link其他容器名称来实现。以下是上述参数组合的示例:

docker run -p 9999:8080 
    --link otherContainerA --link otherContainerB 
    -v /Users/$USER/.m2/repository:/home/user/.m2/repository 
    toptal/pingpong

其他容器和镜像操作

毫不奇怪,可以应用于容器和图像的操作列表相当长。为了简洁起见,我们来看看其中的几个:

  • stop - 停止运行容器。
  • start - 启动一个停止的容器。
  • commit -从容器的更改创建新的镜像。
  • rm - - 删除一个或多个容器。
  • rmi - - 删除一个或多个镜像。
  • ps - 列出容器。
  • images - 列出镜像。
  • exec -在运行容器中运行命令。

最后一个命令可能对于调试目的特别有用,因为它可以连接到运行容器的终端:

docker exec -i -t <container-id> bash

Docker为微服务世界撰写(Docker Compose for the Microservice World)

如果您有不仅仅是几个互连的容器,使用docker-compose这样的工具是有意义的。在配置文件中,您将说明如何启动容器以及如何将它们彼此链接起来。无论涉及的容器数量及其依赖关系如何,您都可以使用一个命令来运行所有容器:docker-compose up

Docker在野外(Docker in the Wild)

我们来看看项目生命周期的三个阶段,看看我们的友好鲸鱼如何能够帮上忙。

开发(Development)

Docker可帮助您保持本地开发环境的清洁。不需要安装多个版本的不同服务,如Java,Kafka,Spark,Cassandra等,您可以在必要时启动和停止所需的容器。您可以进一步了解并且并行运行多个软件堆栈,以避免依赖关系版本的混合。

使用Docker,您可以节省时间,精力和金钱。如果您的项目设置非常复杂,“dockerise”它。经历一次创建Docker镜像的痛苦,从此之后,每个人都可以快速启动一个容器。

您还可以在本地(或CI)上运行“集成环境”,并使用在Docker容器中运行的实际服务替换存根。

测试/持续集成(Testing / Continuous Integration)

使用Dockerfile,很容易实现可重复构建。可以将Jenkins或其他CI解决方案配置为创建Docker镜像用于每个构建。您可以将一些或所有镜像存储在专用Docker注册表中,以备将来参考。

使用Docker,您只需测试需要测试的内容,并将环境排除在等式之外。在运行容器上执行测试可以帮助保持其更加可预测。

拥有软件容器的另一个有趣的特征是,使用相同的开发设置可以轻松地分出子机。它对于集群部署的负载测试尤其有用。

生产(Production)

Docker可以是开发人员和操作人员之间的通用接口,消除了摩擦的根源。它还鼓励在管道的每一步使用相同的镜像/二进制文件。此外,能够部署经过全面测试的容器而无需环境差异,有助于确保在构建过程中不会引入错误。

您可以将应用程序无缝迁移到生产环境中。曾经是一个乏味和片状的过程的东西现在可以简单到:

docker stop container-id; docker run new-image

如果部署新版本出现问题,您可以随时快速回滚或更改为其他容器:

docker stop container-id; docker start other-container-id

..保证不要留下任何混乱或让事情处于不一致的状态。

总结

Docker做的一个很好的总结包括在自己的座右铭中:构建(Build),运输( Ship),运行(Run)

  • Build - Docker允许您从微服务中组合应用程序,而不必担心开发和生产环境之间的不一致,并且不会锁定到任何平台或语言中。
  • Ship - Docker可让您设计整个应用程序开发,测试和分发周期,并通过一致的用户界面进行管理。
  • Run - Docker为您提供在各种平台上安全可靠地部署可伸缩服务的能力。

祝大家与鲸鱼玩的愉快!

这部作品的灵感来自于由Adrian Mouat 使用Docker的优秀作品。

参与评论