5种Docker日志最佳实践

作者 |Jeffrey Walker

翻译|Vincent

来源| CSDN

原文|http://geek.csdn.net/news/detail/232608

在过去的几年中,容器已经成为IT领域的一个重要话题,尤其是在DevOps领域。简单地说,当从一个环境迁移到另一个环境时,容器提供了一种简单且可扩展的方法可以运行软件。

容器是通过在一个包中提供完整的运行环境实现的,其中就包括了应用程序,所有的依赖项,库,其它二进制文件以及运行时所需的配置文件。

与容器紧密结合的是微服务,它代表了开发应用程序的一种更灵活的方式。微服务体系结构将应用程序构建为一组松耦合的服务,这些服务通过处理离散业务功能的API连接起来。微服务主要为应用程序开发提供了一种“分而治之”的方法,而不是一个大型的单一代码库。

Docker在容器的基础架构领域是处于世界领先地位的,它是一个部署容器级软件应用的平台。容器的真正价值在于它们允许团队动态地启动一个完整的运行环境。Docker可以说是让企业采用微服务的最具影响力的平台。

类似于虚拟机通过向来自一个服务器的终端用户提供一个操作系统的多个实例来简化软件开发和测试,容器在应用程序和主机操作系统之间添加了一个额外的抽象层。最大的不同是,容器不需要管理程序,只运行操作系统的一个实例;总的来说,这等同于内存更少,运行时间更快。

与开发任何应用程序一样,日志记录是过程的中心部分,在出现问题时尤其有用。但是,在集装箱化应用程序的世界里,与传统应用程序相比,它是不同的。日志Docker实际上意味着不仅记录应用程序和应用程序主机操作系统,以及Docker服务。在处理多码应用程序时,有许多日志记录技术和方法可以记住。我们将在下面详细介绍前五种最佳实践。

基于应用程序的日志记录

在基于应用程序的方法中,容器内的应用程序使用日志框架来处理日志记录过程。例如,某个Java应用程序可能会使用Log4j 2来对日志文件格式化,然后发送到远程服务器,并完全绕过Docker环境和操作系统。

虽然基于应用程序的日志记录使开发人员对日志事件有了最大的控制权,但是这种方法也会在应用程序过程中产生大量的消耗。这种方法对于那些工作在传统应用程序环境中的人来说可能是有用的,因为它允许开发人员继续使用应用程序的日志框架(例如Log4j 2)而不需要向主机添加日志功能。

Logging Docker实际上意味着不仅需要记录应用程序和主机操作系统,还包括了Docker服务。

使用数据卷

容器本质上是临时的,这意味着如果容器关闭了,那么容器内的任何文件最终都会丢失。相反,容器必须将日志事件转发到集中式日志记录服务(比如Loggly),或者将日志事件存储在数据卷中。数据卷的定义为“容器内的一个标记目录,该目录用来保存持久或共享的数据”。

使用数据卷来记录事件的好处是,由于它们链接到主机上的一个目录,所以日志数据仍然存在,并且可以与其它容器共享。这种方法的优点是它减少了在容器失败或关闭时丢失数据的可能性。在这里可以找到关于在Ubuntu中设置Docker数据卷的说明。

Docker日志驱动

在Docker中进行日志记录的第三种方法是使用平台的日志驱动程序将日志事件转发给在主机上运行的syslog实例。Docker日志驱动程序直接从容器的stdout和stderr输出里面读取日志事件;这就消除了从日志文件中读取和写入的需要,最终也会稍微改善性能。

然而,使用Docker日志驱动程序也有一些缺点:

  1. 它不允许进行日志解析,只允许进行日志转发。

  2. Docker日志命令只与日志驱动程序JSON文件一起工作。

  3. 当TCP服务器不可访问时,容器就会终止。

这里可以找到为Docker配置默认日志驱动程序的说明。

容器专用日志

这种方法的主要优点是允许在Docker环境中完全地管理日志事件。由于专用的日志容器可以从其他容器收集日志事件,聚合它们,然后将事件存储或转发到第三方服务,这种方法消除了对主机的依赖。

专用日志容器的其它优点是:

  1. 自动收集、监视和分析日志事件。

  2. 在没有配置的情况下自动缩放日志事件。

  3. 通过多个日志事件、stats和Docker API数据流来检索日志。

Sidecar方法

Sidecars已经成为管理微服务架构的流行方法。Sidecar的想法来自于类似摩托车的sidecar是如何附着在摩托车上的。引用一个消息源,“Sidecar作为第二个过程在你的服务旁边运行,并通过类似于HTTP上的REST-like API 这样一个同类接口提供了’平台基础设施’的特性。”

从日志记录的角度来看,Sidecar方法的优点是每个容器都与它自己的日志容器有关(应用程序容器保存日志事件和日志容器标记,然后像Loggly那样将它们转发到日志管理系统)。

5种Docker日志最佳实践

Sidecar方法对于大型部署来说尤其有用,因为这些部署需要有更专门的日志信息和自定义标记。不过,建立Sidecar非常复杂,而且难度也很大。

【基础教程】Docker基础及应用

0x00什么是Docker?

Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。

一个完整的Docker有以下几个部分组成:

dockerClient客户端

Docker Daemon守护进程

Docker Image镜像

DockerContainer容器

知乎上有人回答说:Docker(码头工人)的思想来自于集装箱,集装箱解决了什么问题?在一艘大船上,可以把货物规整的摆放起来。并且各种各样的货物被集装箱标准化了,集装箱和集装箱之间不会互相影响。那么我就不需要专门运送水果的船和专门运送化学品的船了。只要这些货物在集装箱里封装的好好的,那我就可以用一艘大船把他们都运走。这里可以看docker的logo来理解,鲸鱼拖着许多集装箱。

这就解释了另外一个应用场景:应用的分离化,假如搭建一个Web网站需要CentOS+Apache+PHP+MySQL,我们即可利用CentOS的集装箱,Apache的集装箱和PHP,MySQL的集装箱来通信实现Web应用,集装箱之间除了交换数据并没有多余的联系。

0x01Docker相关的几个概念

1. 仓库(Repositories)

docker提供一个公共仓库,可以用dockersearch 命令去查找所需要的镜像,用docker pull 命令从仓库中拉取需要的镜像到本地。

https://hub.docker.com/explore/

【基础教程】Docker基础及应用

2.镜像(Images)

Docker的镜像类似虚拟机的快照,但更轻量,非常非常轻量。

创建Docker镜像有几种方式,多数是在一个现有镜像基础上创建新镜像,因为几乎你需要的任何东西都有了公共镜像,包括所有主流Linux发行版,你应该不会找不到你需要的镜像。不过,就算你想从头构建一个镜像,也有好几种方法。

要创建一个镜像,你可以拿一个镜像,对它进行修改来创建它的子镜像。实现前述目的的方式有两种:在一个文件中指定一个基础镜像及需要完成的修改;或通过“运行”一个镜像,对其进行修改并提交。不同方式各有优点,不过一般会使用文件来指定所做的变化。

镜像拥有唯一ID,以及一个供人阅读的名字和标签对。镜像可以命名为类似ubuntu:latest、ubuntu:precise、django:1.6、django:1.7等等。

用docker images 列出本地的镜像,dpcler search查找镜像列表。

【基础教程】Docker基础及应用

3.容器(Container)

你可以从镜像中创建容器,这等同于从快照中创建虚拟机,不过更轻量。应用是由容器运行的。

举个例子,你可以下载一个Ubuntu的镜像(有个叫docker registry的镜像公共仓库),通过安装Gunicorn和Django应用及其依赖项来完成对它的修改,然后从该镜像中创建一个容器,在它启动后运行你的应用。

容器与虚拟机一样,是隔离的。它们也拥有一个唯一ID和唯一的供人阅读的名字。容器对外公开服务是必要的,因此Docker允许公开容器的特定端口。

【基础教程】Docker基础及应用

与虚拟机相比,容器有一个很大的差异,它们被设计用来运行单进程,无法很好地模拟一个完整的环境Docker。容器和虚拟机的第二个巨大差异是:当你停止一个虚拟机时,可能除了一些临时文件,没有文件会被删除;当你停止一个Docker容器,对初始状态(创建容器所用的镜像的状态)做的所有变化都会丢失。

容器是设计来运行一个应用的,而非一台机器。你可能会把容器当虚拟机用,但如我们所见,你将失去很多的灵活性,因为Docker提供了用于分离应用与数据的工具,使得你可以快捷地更新运行中的代码/系统,而不影响数据。

仓库、镜像、容器的关系

【基础教程】Docker基础及应用

4.数据卷

数据卷让你可以不受容器生命周期影响进行数据持久化。它们表现为容器内的空间,但实际保存在容器之外,从而允许你在不影响数据的情况下销毁、重建、修改、丢弃容器。Docker允许你定义应用部分和数据部分,并提供工具让你可以将它们分开。使用Docker时必须做出的最大思维变化之一就是:容器应该是短暂和一次性的。

卷是针对容器的,你可以使用同一个镜像创建多个容器并定义不同的卷。卷保存在运行Docker的宿主文件系统上,你可以指定卷存放的目录,或让Docker保存在默认位置。保存在其他类型文件系统上的都不是一个卷。

【基础教程】Docker基础及应用

5.链接

链接是Docker的另一个重要部分。

容器启动时,将被分配一个随机的私有IP,其它容器可以使用这个IP地址与其进行通讯。这点非常重要,原因有二:一是它提供了容器间相互通信的渠道,二是容器将共享一个本地网络。在同一台机器上为两个客户启动两个elasticsearch容器,但保留集群名称为默认设置,结果这两台elasticsearch服务器立马变成了一个自主集群。注:限制容器间通讯是可行的,请阅读Docker的高级网络文档做进一步了解。

要开启容器间通讯,Docker允许你在创建一个新容器时引用其它现存容器,在你刚创建的容器里被引用的容器将获得一个(你指定的)别名。我们就说,这两个容器链接在了一起。

因此,如果DB容器已经在运行,我可以创建web服务器容器,并在创建时引用这个DB容器,给它一个别名,比如dbapp。在这个新建的web服务器容器里,我可以在任何时候使用主机名dbapp与DB容器进行通讯。

Docker更进一步,要求你声明容器在被链接时要开放哪些端口给其他容器,否则将没有端口可用。

0x02Docker的应用场景

关于docker的应用场景,http://dockone.io/article/126给出了详细的介绍。

【基础教程】Docker基础及应用

1. 简化配置

虚拟机的最大好处是能在你的硬件设施上运行各种配置不一样的平台(软件、系统),Docker在降低额外开销的情况下提供了同样的功能。它能让你将运行环境和配置放在代码中然后部署,同一个Docker的配置可以在不同的环境中使用,这样就降低了硬件要求和应用环境之间耦合度。

2. 代码流水线(Code Pipeline)管理

前一个场景对于管理代码的流水线起到了很大的帮助。代码从开发者的机器到最终在生产环境上的部署,需要经过很多的中间环境。而每一个中间环境都有自己微小的差别,Docker给应用提供了一个从开发到上线均一致的环境,让代码的流水线变得简单不少。

3. 提高开发效率

不同的开发环境中,我们都想把两件事做好。一是我们想让开发环境尽量贴近生产环境,二是我们想快速搭建开发环境。

理想状态中,要达到第一个目标,我们需要将每一个服务都跑在独立的虚拟机中以便监控生产环境中服务的运行状态。然而,我们却不想每次都需要网络连接,每次重新编译的时候远程连接上去特别麻烦。这就是Docker做的特别好的地方,开发环境的机器通常内存比较小,之前使用虚拟的时候,我们经常需要为开发环境的机器加内存,而现在Docker可以轻易的让几十个服务在Docker中跑起来。

4. 隔离应用

有很多种原因会让你选择在一个机器上运行不同的应用,比如之前提到的提高开发效率的场景等。

我们经常需要考虑两点,一是因为要降低成本而进行服务器整合,二是将一个整体式的应用拆分成松耦合的单个服务。

5. 整合服务器

正如通过虚拟机来整合多个应用,Docker隔离应用的能力使得Docker可以整合多个服务器以降低成本。由于没有多个操作系统的内存占用,以及能在多个实例之间共享没有使用的内存,Docker可以比虚拟机提供更好的服务器整合解决方案。

6. 调试能力

Docker提供了很多的工具,这些工具不一定只是针对容器,但是却适用于容器。它们提供了很多的功能,包括可以为容器设置检查点、设置版本和查看两个容器之间的差别,这些特性可以帮助调试Bug。

7. 多租户环境

另外一个Docker有意思的使用场景是在多租户的应用中,它可以避免关键应用的重写。这种多租户的基本代码非常复杂,很难处理,重新规划这样一个应用不但消耗时间,也浪费金钱。

使用Docker,可以为每一个租户的应用层的多个实例创建隔离的环境,这不仅简单而且成本低廉,当然这一切得益于Docker环境的启动速度和其高效的diff命令。

8. 快速部署

在虚拟机之前,引入新的硬件资源需要消耗几天的时间。虚拟化技术(Virtualization)将这个时间缩短到了分钟级别。而Docker通过为进程仅仅创建一个容器而无需启动一个操作系统,再次将这个过程缩短到了秒级。

你可以在数据中心创建销毁资源而无需担心重新启动带来的开销。通常数据中心的资源利用率只有30%,通过使用Docker并进行有效的资源分配可以提高资源的利用率。

0x03安全人员的常用场景

快速搭建各种漏洞环境

实例1:快速搭建webgoat环境

docker pull webgoat/webgoat-8.0docker run -p 8080:8080 -itwebgoat/webgoat-8.0 /home/webgoat/start.sh

【基础教程】Docker基础及应用

访问网址:http://IP:8080/WebGoat/login.mvc即可。

DVWA等开源漏洞平台也可以如上步骤轻松搭建。

实例2:搭建Zabbix漏洞环境

在平时的工作和学习中经常会遇到需要本地复现某个漏洞的情况,很多时候,搭建漏洞环境就会耗去我们较长的时间,其间可能会遇到各种各样的问题,要去修改、调试,直至真正搭建成功,过程还是比较崎岖的。docker完美的解决了这一问题。

以 Zabbix v2.2.x, 3.0.0-3.0.3 jsrpc 参数 profileIdx2 SQL 注入漏洞为例:

可以先使用docker search zabbix命令查找仓库中有哪些zabbix镜像,在镜像列表中选择一个 拉取到本地。

【基础教程】Docker基础及应用

Step1、拉取镜像到本地

docker pull medicean/vulapps:z_zabbix_1

Step2、启动环境

docker run -d -p 8888:80medicean/vulapps:z_zabbix_1

-p 8888:80 前面的 8888代表物理机的端口,可随意指定。

如果获取速度慢,推荐使用 中科大 Docker Mirrors

【基础教程】Docker基础及应用

在同网段访问该主机的8888端口即可看到zabbix服务已经成功启动

【基础教程】Docker基础及应用

如果不适用docker呢?

通常情况下,我们如果选择在一台centos7上安装zabbix,会经历以下过程

Step1.安装依赖包

yum -y install wget net-snmp-devel OpenIPMI-devel httpdopenssl-devel java lrzsz fping-devel libcurl-devel perl-DBI pcre-devel libxml2libxml2-devel mysql-devel gcc php php-bcmath php-gd php-xml php-mbstringphp-ldap php-mysql.x86_64 php-pear php-xmlrpc net-tools wget vim-enhanced

经历了大约10分钟的等待,依赖包全部安装完成。期间可能会出现

Cannot find a valid baseurl for repo:base/7/x86_64的报错信息,可以通过修改DNS来解决,不赘述。

Step2.关闭防火墙

systemctl stop firewalld.servicesystemctl disable firewalld.service

关闭selinux

vi /etc/selinux/config

修改SELINUX选项为disabled

重启x系统 reboot

等待ing…..

Step3. 搭建zabbix所需要的lamp环境

下载最新的yum源,

wget -P/etc/yum.repos.d http://mirrors.aliyun.com/repo/Centos-7.repo

【基础教程】Docker基础及应用

开始安装lamp环境

yum -y install mariadbmariadb-server php php-mysql httpd

【基础教程】Docker基础及应用

配置mysql数据库

systemctl enable mariadb.servicesystemctl start mariadb.service

【基础教程】Docker基础及应用

初始化mysql数据库,并配置root用户密码mysql_secure_installation

【基础教程】Docker基础及应用

【基础教程】Docker基础及应用

Enter current passwdord for root处,直接敲回车键即可

为root用户配置密码,并刷新相关权限。(密码设为123456,只为实验用,生产环境自定义)

Remove anonymous users? 删除匿名用户?

Disallow root login remotely? 禁止root远程登陆

Remove test database and access to it? 删除测试数据库并且和访问它

Reload privilege tables now? 重新载入特权表

0x04Docker的安装

由于Docker是一门较新的技术,所以对系统的要求也是比较新的,Docker需要在内核版本至少在3.0以后的版本中运行。

笔者环境是系统环境为CentOS Linux release 7.3.1611(Core) 内核版本3.10.0-514.el7.x86_64

centos7安装docker

1、Docker 软件包已经包括在默认的 CentOS-Extras 软件源里。因此想要安装 docker,只需要运行下面的 yum 命令:

yum install docker

2、安装完成后,使用下面的命令来启动docker 服务,并将其设置为开机启动:

service docker startchkconfig docker on

4、下载官方的 CentOS 镜像到本地

docker pull centos

5、确认 CentOS 镜像已经被获取:

docker images centos

6、运行一个 Docker 容器:

docker run -it centos /bin/bash

0x05Docker常用命令

基础命令

启动docker服务service docker start

设置开机自动启动 chkconfig docker on

docker服务对应版本查看docker version

Docker环境查看docker info

查看docker的所有命令docker

Docker命令帮助docker <command> –help 查看docker命令的帮助信息

查看docker状态ps -ef | grep docker

镜像

查找镜像 docker search <image name >

查看镜像列表 docker images

查看镜像的历史版本 docker history <image name>

 

创建镜像 docker pull <image name>

删除一个或多个镜像docker rmi <image name>

 

保存镜像docker save image name > /tmp/image.tar

加载镜像 docker load < /tmp/image/image.tar

 

容器

新建容器 docker create container name

交互式启动容器 docker run -it < containername> /bin/bash

 

显示容器状态 docker stats < container name/id>

启动容器 docker start <container name/id>

重启容器 docker restart < container name/id>

停止容器 docker stop < container name/id >

杀死容器 docker kill < container name/id>

删除容器 docker rm < container name/id>

重命名容器 docker rename < container name/id>

备份容器docker commit< container name/id > pro_test1

列出所有容器docker ps -a

列出最近一次启动的容器docker ps -l

列出所有当前正在运行的容器docker ps

0x06Dockerfile

Docker 可以通过 Dockerfile 的内容来自动构建镜像。

Dockerfile一般包含下面几个部分:

基础镜像:以哪个镜像作为基础进行制作,用法是FROM 基础镜像名称

维护者信息:需要写下该Dockerfile编写人的姓名或邮箱,用法是MANITAINER 名字/邮箱

镜像操作命令:对基础镜像要进行的改造命令,比如安装新的软件,进行哪些特殊配置等,常见的是RUN 命令

容器启动命令:当基于该镜像的容器启动时需要执行哪些命令,常见的是CMD 命令或ENTRYPOINT

Dockerfile 的基本语法结构

Dockerfile 是一个包含创建镜像所有命令的文本文件,通过docker build命令可以根据 Dockerfile 的内容构建镜像,先介绍下 Dockerfile 的基本语法结构。

Dockerfile 有以下指令选项:

  • FROM
  • MAINTAINER
  • RUN
  • CMD
  • EXPOSE
  • ENV
  • ADD
  • COPY
  • ENTRYPOINT
  • VOLUME
  • USER
  • WORKDIR
  • ONBUILD

1.FROM

用法:FROM <image>

  • FROM指定构建镜像的基础源镜像,如果本地没有指定的镜像,则会自动从 Docker 的公共库 pull 镜像下来。
  • FROM必须是 Dockerfile 中非注释行的第一个指令,即一个 Dockerfile 从FROM语句开始。
  • FROM可以在一个 Dockerfile 中出现多次,如果有需求在一个 Dockerfile 中创建多个镜像。
  • 如果FROM语句没有指定镜像标签,则默认使用latest标签。

2 MAINTAINER

指定创建镜像的用户。用法:MAINTAINER <name>

3.RUN

RUN命令将在当前image中执行任意合法命令并提交执行结果。命令执行提交后,就会自动执行Dockerfile中的下一个指令。有两种使用方式:

  • RUN
  • RUN “executable”, “param1”, “param2”

每条RUN指令将在当前镜像基础上执行指定命令,并提交为新的镜像,后续的RUN都在之前RUN提交后的镜像为基础,镜像是分层的,可以通过一个镜像的任何一个历史提交点来创建,类似源码的版本控制。

exec 方式会被解析为一个 JSON 数组,所以必须使用双引号而不是单引号。exec 方式不会调用一个命令 shell,所以也就不会继承相应的变量,如:

RUN [ "echo", "$HOME" ]

这种方式是不会达到输出 HOME 变量的,正确的方式应该是这样的

RUN [ "sh", "-c", "echo", "$HOME" ]

RUN产生的缓存在下一次构建的时候是不会失效的,会被重用,可以使用–no-cache选项,即docker build –no-cache,如此便不会缓存。

4 CMD

CMD有三种使用方式:

  • CMD “executable”,”param1″,”param2″
  • CMD “param1″,”param2”
  • CMD command param1 param2 (shell form)

CMD指定在 Dockerfile 中只能使用一次,如果有多个,则只有最后一个会生效。

CMD的目的是为了在启动容器时提供一个默认的命令执行选项。如果用户启动容器时指定了运行的命令,则会覆盖掉CMD指定的命令。

CMD会在启动容器的时候执行,build 时不执行,而RUN只是在构建镜像的时候执行,后续镜像构建完成之后,启动容器就与RUN无关了。

5 EXPOSE

用法:EXPOSE <port> [<port>…]

告诉 Docker 服务端容器对外映射的本地端口,需要在 docker run 的时候使用-p或者-P选项生效。

6 ENV

ENV <key> <value> # 只能设置一个变量

ENV <key>=<value> …# 允许一次设置多个变量

指定一个环境变量,会被后续RUN指令使用,并在容器运行时保留。

例子:

ENV myName="John Doe" myDog=Rex The Dog   myCat=fluffy

等同于

ENV myName John DoeENV myDog Rex The DogENV myCat fluffy

ENV设置的环境变量,可以使用 docker inspect命令来查看。同时还可以使用docker run –env <key>=<value>来修改环境变量

7 ADD

用法:ADD <src>… <dest>

ADD 将文件从路径 <src> 复制添加到容器内部路径 <dest>。

<src> 必须是想对于源文件夹的一个文件或目录,也可以是一个远程的url,<dest> 是目标容器中的绝对路径。

所有的新文件和文件夹都会创建UID 和 GID。事实上如果<src> 是一个远程文件URL,那么目标文件的权限将会是600。

支持通过Go的正则模糊匹配,具体规则可参见 Go filepath.Match

ADD hom* /mydir/    # adds all files starting with "hom"ADD hom?.txt /mydir/  # ? is replaced with any single character

路径必须是绝对路径,如果不存在,会自动创建对应目录;路径必须是 Dockerfile 所在路径的相对路径,如果是一个目录,只会复制目录下的内容,而目录本身则不会被复制。

8 COPY

用法:COPY <src><dest>

COPY 将文件从路径 <src> 复制添加到容器内部路径 <dest>。

COPY复制新文件或者目录从 并且添加到容器指定路径中 。用法同ADD,唯一的不同是不能指定远程文件 URLS。

9 ENTRYPOINT

  • ENTRYPOINT “executable”, “param1″,”param2”
  • ENTRYPOINT command param1 param2 (shell form)

配置容器启动后执行的命令,并且不可被 docker run 提供的参数覆盖,而CMD是可以被覆盖的。如果需要覆盖,则可以使用docker run –entrypoint选项。

每个 Dockerfile 中只能有一个ENTRYPOINT,当指定多个时,只有最后一个生效。

Exec form ENTRYPOINT 例子

通过ENTRYPOINT使用 exec form 方式设置稳定的默认命令和选项,而使用CMD添加默认之外经常被改动的选项。

FROM ubuntuENTRYPOINT ["top", "-b"]CMD ["-c"]

通过 Dockerfile 使用ENTRYPOINT展示前台运行 Apache 服务

FROM debian:stableRUN apt-get update && apt-get install -y --force-yes apache2EXPOSE 80 443VOLUME ["/var/www", "/var/log/apache2", "/etc/apache2"]ENTRYPOINT ["/usr/sbin/apache2ctl", "-D", "FOREGROUND"]

Shell form ENTRYPOINT 例子

这种方式会在/bin/sh -c中执行,会忽略任何CMD或者docker run命令行选项,为了确保docker stop能够停止长时间运行ENTRYPOINT的容器,确保执行的时候使用exec选项。

FROM ubuntuENTRYPOINT exec top -b

如果在ENTRYPOINT忘记使用exec选项,则可以使用CMD补上:

FROM ubuntuENTRYPOINT top -bCMD --ignored-param1 # --ignored-param2 ... --ignored-param3 ... 依此类推

10 VOLUME

用法:VOLUME [“/data”]

创建一个可以从本地主机或其他容器挂载的挂载点,一般用来存放数据库和需要保持的数据等。

11 USER

USER daemon

USER 用来切换运行属主身份的。Docker 默认是使用 root,但若不需要,建议切换使用者身分,毕竟 root 权限太大了,使用上有安全的风险,后续的RUN、CMD、ENTRYPOINT也会使用指定用户。

12 WORKDIR

用法:WORKDIR /path/to/workdir

WORKDIR 用来切换工作目录的。Docker 默认的工作目录是/,只有 RUN 能执行cd命令切换目录,而且还只作用在当下下的 RUN,也就是说每一个 RUN 都是独立进行的。如果想让其他指令在指定的目录下执行,就得靠 WORKDIR。WORKDIR 动作的目录改变是持久的,不用每个指令前都使用一次。

为后续的RUN、CMD、ENTRYPOINT指令配置工作目录。可以使用多个WORKDIR指令,后续命令如果参数是相对路径,则会基于之前命令指定的路径。

WORKDIR。

WORKDIR /a

WORKDIR b

WORKDIR c

RUN pwd

最终路径是/a/b/c。

WORKDIR指令可以在ENV设置变量之后调用环境变量:

ENV DIRPATH /path

WORKDIR $DIRPATH/$DIRNAME

最终路径则为 /path/$DIRNAME。

13 ONBUILD

用法:ONBUILD [INSTRUCTION]

ONBUILD 的作用就是让指令延迟執行,延迟到下一个使用 FROM 的 Dockerfile 在建立 image 时执行,只限延迟一次。

ONBUILD 的使用情景是在建立镜像时取得最新的源码 (搭配 RUN) 与限定系统框架。

例如,Dockerfile 使用如下的内容创建了镜像 image-A:

[...]ONBUILD ADD . /app/srcONBUILD RUN /usr/local/bin/python-build --dir /app/src[...]

如果基于 image-A 创建新的镜像时,新的 Dockerfile 中使用 FROM image-A 指定基础镜像时,会自动执行 ONBUILD 指令内容,等价于在后面添加了两条指令。

# Automatically run the followingADD . /app/srcRUN /usr/local/bin/python-build --dir /app/src

使用ONBUILD指令的镜像,推荐在标签中注明,例如 ruby:1.9-onbuild。

创建dockerfile文件实例

【基础教程】Docker基础及应用

vim编辑Dockerfile文件

【基础教程】Docker基础及应用

上面的Dockerfile非常简单,创建了一个包含apache的镜像。

FROM指定基础镜像,如果镜像名称中没有制定TAG,默认为latest。

MAINTAINER写明了作者信息

RUN命令默认使用/bin/sh Shell执行,默认为root权限。如果命令过长需要换行,需要在行末尾加。

CMD命令也是默认在/bin/sh中执行,并且默认只能有一条,如果是多条CMD命令则只有最后一条执行。用户也可以在docker run命令创建容器时指定新的CMD命令来覆盖Dockerfile里的CMD。

这个Dockerfile已经可以使用docker build创建新镜像了,先构建一个版本yishuyu:1:

【基础教程】Docker基础及应用

使用docker images命令查看镜像

【基础教程】Docker基础及应用

使用该镜像创建容器web1,将容器中的端口80映射到本地80端口:

【基础教程】Docker基础及应用

查看最近启动的容器

【基础教程】Docker基础及应用

访问该台机器8080端口,即可看到apache首页

【基础教程】Docker基础及应用

CMD如果只有一个命令,那如果我们需要运行多个服务怎么办呢?最好的办法是分别在不同的容器中运行,通过link进行连接。如果一定要在一个容器中运行多个服务可以考虑用Supervisord来进行进程管理,方式就是将多个启动命令放入到一个启动脚本中。

首先安装Supervisord,添加下面内容到Dockerfile:

RUN easy_install supervisorRUN mkdir -p /var/log/supervisor

拷贝配置文件到指定的目录:

COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf

其中supervisord.conf文件需要放在/home/yishuyu/yishuyu下,文件内容如下:

[supervisord]nodaemon=true[program:apache2]command=/bin/bash -c "source /etc/apache2/envvars && exec /usr/sbin/apache2ctl -D FOREGROUND"

如果有多个服务需要启动可以在文件后继续添加[program:xxx],比如如果有ssh服务,可以增加[program:ssh]。

修改CMD命令,启动Supervisord:

CMD ["/usr/bin/supervisord"]

在上述基本的架构下,我们根据需求可以增加新的内容到Dockerfile中。后续的扩展操作都需要放置在Dockerfile的镜像操作部分。

# Version 0.2FROM centosMAINTAINER yishuyu@163.com  #作者信息RUN yum -y install apache2   #安装apacheRUN easy_install supervisor  #安装SupervisordRUN mkdir -p /var/log/supervisor  #建立supervisor目录VOLUME ["/var/log/apche2"]  #将apache访问的日志数据存储到宿主机可以访问的数据卷中ADD html.tar /var/www  #向镜像中增加文件COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf  #拷贝配置文件到指定的目录WORKDIR /var/www/html  #指定后续命令的执行目录ENV HOSTNAME shiyanloutest  #使用ENV设置一些apache启动的环境变量ENV APACHE_RUN_USER www-dataENV APACHE_RUN_GROUP www-dataENV APACHE_LOG_DIR /var/log/apche2ENV APACHE_PID_FILE /var/run/apache2.pidENV APACHE_RUN_DIR /var/run/apache2ENV APACHE_LOCK_DIR /var/lock/apche2EXPOSE 80  #设置对外连接端口号CMD ["/usr/bin/supervisord"]  #启动Supervisord

 

0x06参考链接

http://dockone.io/article/126

https://lug.ustc.edu.cn/wiki/mirrors/help/docker

https://github.com/Medicean/VulApps/tree/master/z/zabbix/1

http://www.jkeabc.com/176978.html

http://www.linuxidc.com/Linux/2014-12/110034.htm

【基础教程】Docker基础及应用

 

Docker实战命令

输入docker –help可以查看Docker的子命令。

总结一下常用命令:

其中< >括起来的参数为必选,[]括起来为可选。

·docker version查看docker的版本号,包括客户端、服务端、依赖的Go等

·docker info查看系统(docker)层面信息,包括管理的images, containers数等

·docker search <image>在docker index中搜索image

·docker pull <image>从docker registry server中下拉image

·docker push <image|repository>推送一个image或repository到registry

·docker push <image|repository>:TAG同上,指定tag

·docker inspect <image|container>查看image或container的底层信息

·docker imagesTODOfilter out the intermediate image layers (intermediate image layers 是什么)

·docker images -a列出所有的images

·docker ps默认显示正在运行中的container

·docker ps -l显示最后一次创建的container,包括未运行的

Docker实战命令

·docker ps -a显示所有的container,包括未运行的

·docker logs <container>查看container的日志,也就是执行命令的一些输出

·docker rm <container…>删除一个或多个container

·docker rm `docker ps -a -q` 删除所有的container

·docker ps -a -q | xargsdocker rm同上, 删除所有的container

·docker rmi <image…>删除一个或多个image

·docker start/stop/restart <container>开启/停止/重启container

·docker start -i <container>启动一个container并进入交互模式

·docker attach <container>attach一个运行中的container

·docker run <image> <command>使用image创建container并执行相应命令,然后停止

·docker run -i -t <image> /bin/bash使用image创建container并进入交互模式, login shell是/bin/bash

·docker run -i -t -p <host_port:contain_port>将container的端口映射到宿主机的端口

·docker commit <container> [repo:tag]将一个container固化为一个新的image,后面的repo:tag可选

·docker build <path>寻找path路径下名为的Dockerfile的配置文件,使用此配置生成新的image

·docker build -t repo[:tag]同上,可以指定repo和可选的tag

·docker build – < <dockerfile>使用指定的dockerfile配置文件,docker以stdin方式获取内容,使用此配置生成新的image

·docker port <container> <container port>查看本地哪个端口映射到container的指定端口,或者用docker ps也可以看到。

 

Docker 入门教程

2013年发布至今,Docker一直广受瞩目,被认为可能会改变软件行业。

但是,许多人并不清楚 Docker 到底是什么,要解决什么问题,好处又在哪里?本文就来详细解释,帮助大家理解它,还带有简单易懂的实例,教你如何将它用于日常开发。

Docker 入门教程

一、环境配置的难题

软件开发最大的麻烦事之一,就是环境配置。用户计算机的环境都不相同,你怎么知道自家的软件,能在那些机器跑起来?

用户必须保证两件事:操作系统的设置,各种库和组件的安装。只有它们都正确,软件才能运行。举例来说,安装一个 Python 应用,计算机必须有 Python 引擎,还必须有各种依赖,可能还要配置环境变量。

如果某些老旧的模块与当前环境不兼容,那就麻烦了。开发者常常会说:”它在我的机器可以跑了”(It works on my machine),言下之意就是,其他机器很可能跑不了。

环境配置如此麻烦,换一台机器,就要重来一次,旷日费时。很多人想到,能不能从根本上解决问题,软件可以带环境安装?也就是说,安装的时候,把原始环境一模一样地复制过来。

二、虚拟机

虚拟机(virtual machine)就是带环境安装的一种解决方案。它可以在一种操作系统里面运行另一种操作系统,比如在 Windows 系统里面运行 Linux 系统。应用程序对此毫无感知,因为虚拟机看上去跟真实系统一模一样,而对于底层系统来说,虚拟机就是一个普通文件,不需要了就删掉,对其他部分毫无影响。

虽然用户可以通过虚拟机还原软件的原始环境。但是,这个方案有几个缺点。

(1)资源占用多

虚拟机会独占一部分内存和硬盘空间。它运行的时候,其他程序就不能使用这些资源了。哪怕虚拟机里面的应用程序,真正使用的内存只有 1MB,虚拟机依然需要几百 MB 的内存才能运行。

(2)冗余步骤多

虚拟机是完整的操作系统,一些系统级别的操作步骤,往往无法跳过,比如用户登录。

(3)启动慢

启动操作系统需要多久,启动虚拟机就需要多久。可能要等几分钟,应用程序才能真正运行。

三、Linux 容器

由于虚拟机存在这些缺点,Linux 发展出了另一种虚拟化技术:Linux 容器(Linux Containers,缩写为 LXC)。

Linux 容器不是模拟一个完整的操作系统,而是对进程进行隔离。或者说,在正常进程的外面套了一个保护层。对于容器里面的进程来说,它接触到的各种资源都是虚拟的,从而实现与底层系统的隔离。

由于容器是进程级别的,相比虚拟机有很多优势。

(1)启动快

容器里面的应用,直接就是底层系统的一个进程,而不是虚拟机内部的进程。所以,启动容器相当于启动本机的一个进程,而不是启动一个操作系统,速度就快很多。

(2)资源占用少

容器只占用需要的资源,不占用那些没有用到的资源;虚拟机由于是完整的操作系统,不可避免要占用所有资源。另外,多个容器可以共享资源,虚拟机都是独享资源。

(3)体积小

容器只要包含用到的组件即可,而虚拟机是整个操作系统的打包,所以容器文件比虚拟机文件要小很多。

总之,容器有点像轻量级的虚拟机,能够提供虚拟化的环境,但是成本开销小得多。

四、Docker 是什么?

Docker 属于 Linux 容器的一种封装,提供简单易用的容器使用接口。它是目前最流行的 Linux 容器解决方案。

Docker 将应用程序与该程序的依赖,打包在一个文件里面。运行这个文件,就会生成一个虚拟容器。程序在这个虚拟容器里运行,就好像在真实的物理机上运行一样。有了 Docker,就不用担心环境问题。

总体来说,Docker 的接口相当简单,用户可以方便地创建和使用容器,把自己的应用放入容器。容器还可以进行版本管理、复制、分享、修改,就像管理普通的代码一样。

五、Docker 的用途

Docker 的主要用途,目前有三大类。

(1)提供一次性的环境。比如,本地测试他人的软件、持续集成的时候提供单元测试和构建的环境。

(2)提供弹性的云服务。因为 Docker 容器可以随开随关,很适合动态扩容和缩容。

(3)组建微服务架构。通过多个容器,一台机器可以跑多个服务,因此在本机就可以模拟出微服务架构。

六、Docker 的安装

Docker 是一个开源的商业产品,有两个版本:社区版(Community Edition,缩写为 CE)和企业版(Enterprise Edition,缩写为 EE)。企业版包含了一些收费服务,个人开发者一般用不到。下面的介绍都针对社区版。

Docker CE 的安装请参考官方文档:https://docs.docker.com/install/。

  • Mac

  • Windows

  • Ubuntu

  • Debian

  • CentOS

  • Fedora

  • 其他 Linux 发行版

安装完成后,运行下面的命令,验证是否安装成功。

$ docker version# 或者$ docker info

Docker 需要用户具有 sudo 权限,为了避免每次命令都输入sudo,可以把用户加入 Docker 用户组(官方文档)。

$ sudo usermod -aG docker $USER

Docker 是服务器—-客户端架构。命令行运行 docker 命令的时候,需要本机有 Docker 服务。如果这项服务没有启动,可以用下面的命令启动(官方文档)。

# service 命令的用法$ sudo service docker start# systemctl 命令的用法$ sudo systemctl start docker

七、image 文件

Docker 把应用程序及其依赖,打包在 image 文件里面。只有通过这个文件,才能生成 Docker 容器。image 文件可以看作是容器的模板。Docker 根据 image 文件生成容器的实例。同一个 image 文件,可以生成多个同时运行的容器实例。

image 是二进制文件。实际开发中,一个 image 文件往往通过继承另一个 image 文件,加上一些个性化设置而生成。举例来说,你可以在 Ubuntu 的 image 基础上,往里面加入 Apache 服务器,形成你的 image。

# 列出本机的所有 image 文件。$ docker image ls# 删除 image 文件$ docker image rm [imageName]

image 文件是通用的,一台机器的 image 文件拷贝到另一台机器,照样可以使用。一般来说,为了节省时间,我们应该尽量使用别人制作好的 image 文件,而不是自己制作。即使要定制,也应该基于别人的 image 文件进行加工,而不是从零开始制作。

为了方便共享,image 文件制作完成后,可以上传到网上的仓库。Docker 的官方仓库Docker Hub是最重要、最常用的 image 仓库。此外,出售自己制作的 image 文件也是可以的。

八、实例:hello world

下面,我们通过最简单的 image 文件 “hello world”,感受一下 Docker。

首先,运行下面的命令,将 image 文件从仓库抓取到本地。

$ docker image pull library/hello-world

上面代码中,docker image pull 是抓取 image 文件的命令。library/hello-world 是 image 文件在仓库里面的位置,其中 library 是 image 文件所在的组,hello-world 是 image 文件的名字。

由于 Docker 官方提供的 image 文件,都放在 library 组里面,所以它的是默认组,可以省略。因此,上面的命令可以写成下面这样。

$ docker image pull hello-world

抓取成功以后,就可以在本机看到这个 image 文件了。

$ docker image ls

现在,运行这个 image 文件。

$ docker container run hello-world

docker container run 命令会从 image 文件,生成一个正在运行的容器实例。

注意,docker container run 命令具有自动抓取 image 文件的功能。如果发现本地没有指定的 image 文件,就会从仓库自动抓取。因此,前面的 docker image pull 命令并不是必需的步骤。

如果运行成功,你会在屏幕上读到下面的输出。

$ docker container run hello-world

Hello from Docker!

This message shows that your installation appears to be working correctly

…. …

输出这段提示以后,hello world 就会停止运行,容器自动终止。

有些容器不会自动终止,因为提供的是服务。比如,安装运行 Ubuntu 的 image,就可以在命令行体验 Ubuntu 系统。

$ docker container run -it ubuntu bash

对于那些不会自动终止的容器,必须使用 docker container kill 命令手动终止。

$ docker container kill [containID]

九、容器文件

image 文件生成的容器实例,本身也是一个文件,称为容器文件。也就是说,一旦容器生成,就会同时存在两个文件: image 文件和容器文件。而且关闭容器并不会删除容器文件,只是容器停止运行而已。

# 列出本机正在运行的容器$ docker container ls -l# 列出本机所有容器,包括终止运行的容器$ docker container ls --all

上面命令的输出结果之中,包括容器的 ID。很多地方都需要提供这个 ID,比如上一节终止容器运行的 docker container kill 命令。

终止运行的容器文件,依然会占据硬盘空间,可以使用 docker container rm 命令删除。

$ docker container rm [containerID]

运行上面的命令之后,再使用 docker container ls –all 命令,就会发现被删除的容器文件已经消失了。

十、Dockerfile 文件

学会使用 image 文件以后,接下来的问题就是,如何可以生成 image 文件?如果你要推广自己的软件,势必要自己制作 image 文件。

这就需要用到 Dockerfile 文件。它是一个文本文件,用来配置 image。Docker 根据该文件生成二进制的 image 文件。

下面通过一个实例,演示如何编写 Dockerfile 文件。

十一、实例:制作自己的 Docker 容器

下面我以koa-demos项目为例,介绍怎么写 Dockerfile 文件,实现让用户在 Docker 容器里面运行 Koa 框架。

作为准备工作,请先下载源码。

$ git clone https://github.com/ruanyf/koa-demos.git

$ cd koa-demos

11.1 编写 Dockerfile 文件

首先,在项目的根目录下,新建一个文本文件.dockerignore,写入下面的内容。

.git node_modules npm-debug.log

上面代码表示,这三个路径要排除,不要打包进入 image 文件。如果你没有路径要排除,这个文件可以不新建。

然后,在项目的根目录下,新建一个文本文件 Dockerfile,写入下面的内容。

FROM node:8.4

COPY . /app

WORKDIR /app

RUN npm install –registry=https://registry.npm.taobao.org

EXPOSE 3000

上面代码一共五行,含义如下。

  • FROM node:8.4:该 image 文件继承官方的 node image,冒号表示标签,这里标签是8.4,即8.4版本的 node。

  • COPY . /app:将当前目录下的所有文件(除了.dockerignore排除的路径),都拷贝进入 image 文件的/app目录。

  • WORKDIR /app:指定接下来的工作路径为/app。

  • RUN npm install:在/app目录下,运行npm install命令安装依赖。注意,安装后所有的依赖,都将打包进入 image 文件。

  • EXPOSE 3000:将容器 3000 端口暴露出来, 允许外部连接这个端口。

11.2 创建 image 文件

有了 Dockerfile 文件以后,就可以使用 docker image build 命令创建 image 文件了。

$ docker image build -t koa-demo .

# 或者

$ docker image build -t koa-demo:0.0.1 .

上面代码中,-t 参数用来指定 image 文件的名字,后面还可以用冒号指定标签。如果不指定,默认的标签就是 latest。最后的那个点表示 Dockerfile 文件所在的路径,上例是当前路径,所以是一个点。

如果运行成功,就可以看到新生成的 image 文件 koa-demo 了。

$ docker image ls

11.3 生成容器

docker container run 命令会从 image 文件生成容器。

$ docker container run -p 8000:3000 -it koa-demo /bin/bash

# 或者

$ docker container run -p 8000:3000 -it koa-demo:0.0.1 /bin/bash

上面命令的各个参数含义如下:

  • -p参数:容器的 3000 端口映射到本机的 8000 端口。

  • -it参数:容器的 Shell 映射到当前的 Shell,然后你在本机窗口输入的命令,就会传入容器。

  • koa-demo:0.0.1:image 文件的名字(如果有标签,还需要提供标签,默认是 latest 标签)。

  • /bin/bash:容器启动以后,内部第一个执行的命令。这里是启动 Bash,保证用户可以使用 Shell。

如果一切正常,运行上面的命令以后,就会返回一个命令行提示符。

root@66d80f4aaf1e:/app#

这表示你已经在容器里面了,返回的提示符就是容器内部的 Shell 提示符。执行下面的命令。

root@66d80f4aaf1e:/app# node demos/01.js

这时,Koa 框架已经运行起来了。打开本机的浏览器,访问 http://127.0.0.1:8000,网页显示”Not Found”,这是因为这个demo没有写路由。

这个例子中,Node 进程运行在 Docker 容器的虚拟环境里面,进程接触到的文件系统和网络接口都是虚拟的,与本机的文件系统和网络接口是隔离的,因此需要定义容器与物理机的端口映射(map)。

现在,在容器的命令行,按下 Ctrl + c 停止 Node 进程,然后按下 Ctrl + d (或者输入 exit)退出容器。此外,也可以用 docker container kill 终止容器运行。

# 在本机的另一个终端窗口,查出容器的 ID

$ docker container ls

# 停止指定的容器运行

$ docker container kill [containerID]

容器停止运行之后,并不会消失,用下面的命令删除容器文件。

# 查出容器的 ID$ docker container ls --all# 删除指定的容器文件$ docker container rm [containerID]

也可以使用 docker container run 命令的 –rm 参数,在容器终止运行后自动删除容器文件。

$ docker container run –rm -p 8000:3000 -it koa-demo /bin/bash

11.4 CMD 命令

上一节的例子里面,容器启动以后,需要手动输入命令 node demos/01.js。我们可以把这个命令写在 Dockerfile 里面,这样容器启动以后,这个命令就已经执行了,不用再手动输入了。

FROM node:8.4

COPY . /app

WORKDIR /app

RUN npm install –registry=https://registry.npm.taobao.org

EXPOSE 3000

CMD node demos/01.js

上面的 Dockerfile 里面,多了最后一行 CMD node demos/01.js,它表示容器启动后自动执行 node demos/01.js。

你可能会问,RUN 命令与 CMD 命令的区别在哪里?简单说,RUN 命令在 image 文件的构建阶段执行,执行结果都会打包进入 image 文件;CMD 命令则是在容器启动后执行。另外,一个 Dockerfile 可以包含多个 RUN 命令,但是只能有一个 CMD 命令。

注意,指定了 CMD 命令以后,docker container run 命令就不能附加命令了(比如前面的 /bin/bash),否则它会覆盖 CMD 命令。现在,启动容器可以使用下面的命令。

$ docker container run –rm -p 8000:3000 -it koa-demo:0.0.1

11.5 发布 image 文件

容器运行成功后,就确认了 image 文件的有效性。这时,我们就可以考虑把 image 文件分享到网上,让其他人使用。

首先,去hub.docker.com或cloud.docker.com注册一个账户。然后,用下面的命令登录。

$ docker login

接着,为本地的 image 标注用户名和版本。

$ docker image tag [imageName] [username]/[repository]:[tag]

# 实例

$ docker image tag koa-demos:0.0.1 ruanyf/koa-demos:0.0.1

也可以不标注用户名,重新构建一下 image 文件。

$ docker image build -t [username]/[repository]:[tag] .

最后,发布 image 文件。

$ docker image push [username]/[repository]:[tag]

发布成功以后,登录 hub.docker.com,就可以看到已经发布的 image 文件。

十二、其他有用的命令

docker 的主要用法就是上面这些,此外还有几个命令,也非常有用。

(1)docker container start

前面的 docker container run 命令是新建容器,每运行一次,就会新建一个容器。同样的命令运行两次,就会生成两个一模一样的容器文件。如果希望重复使用容器,就要使用 docker container start 命令,它用来启动已经生成、已经停止运行的容器文件。

$ docker container start [containerID]

(2)docker container stop

前面的 docker container kill 命令终止容器运行,相当于向容器里面的主进程发出 SIGKILL 信号。而 docker container stop 命令也是用来终止容器运行,相当于向容器里面的主进程发出 SIGTERM 信号,然后过一段时间再发出 SIGKILL 信号。

$ docker container stop [containerID]

这两个信号的差别是,应用程序收到 SIGTERM 信号以后,可以自行进行收尾清理工作,但也可以不理会这个信号。如果收到 SIGKILL 信号,就会强行立即终止,那些正在进行中的操作会全部丢失。

(3)docker container logs

docker container logs 命令用来查看 docker 容器的输出,即容器里面 Shell 的标准输出。如果 docker run 命令运行容器的时候,没有使用 -it 参数,就要用这个命令查看输出。

$ docker container logs [containerID]

(4)docker container exec

docker container exec 命令用于进入一个正在运行的 docker 容器。如果 docker run 命令运行容器的时候,没有使用 -it 参数,就要用这个命令进入容器。一旦进入了容器,就可以在容器的 Shell 执行命令了。

$ docker container exec -it [containerID] /bin/bash

(5)docker container cp

docker container cp 命令用于从正在运行的 Docker 容器里面,将文件拷贝到本机。下面是拷贝到当前目录的写法。

$ docker container cp [containID]:[/path/to/file] .

  • 来源:阮一峰的网络日志

  • 原文:http://t.cn/RRhT0D2

  • 题图:来自谷歌图片搜索

  • 版权:本文版权归原作者所有

Docker 入门教程

今日思想

Knowledge will give you power, but character respect.

知识给你力量,品格给你别人的尊敬。

——李小龙

Docker 入门教程

更多精彩热文:

Docker 入门教程

Docker 入门教程

Docker 入门教程

docker概述与原理

 

Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中。谢谢刘磊为我们准备了这一系列的内容,非常赞!

 

 

Docker是一个开源的引擎,可以轻松而又快速的为任何应用创建一个轻量级的、可移植的、自给自足的容器。开发者在笔记本上编译测试通过的容器可以批量地在生产环境中部署,包括VMs(虚拟机)、baremetal、OpenStack集群和其他的基础应用平台。

1
Docker系统有两个程序:服务端和客户端

其中docker服务端是一个服务进程,管理着所有的容器。docker客户端则扮演着docker服务端的远程控制器,可以用来控制docker的服务端进程。大部分情况下,docker服务端和客户端运行在一台机器上。

2
Docker通常适用如下场景:

·web应用的自动化打包和发布;

·自动化测试和持续集成、发布;

·在服务型环境中部署和调整数据库或其他的后台应用;

·从头编译或者扩展现有的OpenShift或CloudFoundry平台来搭建自己的PaaS环境。

3
查看docker版本

docker概述与原理

4
Dockr架构

docker概述与原理

Docker采用Client/Server架构模式。DockerDaemon是docker的核心守护进程,也就是Server端,Server端可以部署在远程,也可以部署在本地,客户端向服务器发送请求,服务端负责构建、运行和分发容器。客户端和服务器可以运行在同一个Host上,客户端可以通过socket或RESTAPI与远程的服务器通信.

dockerCLI实现容器和镜像的管理,为用户提供统一的操作界面,这个客户端提供一个只读的镜像,然后通过镜像可以创建一个或者多个容器(container),这些容器可以只是一个RFS(RootFileSystem),也可以是一个包含了用户应用的RFS。容器在dockerClient中只是一个进程,两个进程是互不可见的,从而实现容器之间的个隔离。

用户不能与server直接交互,但可以通过与容器这个桥梁来交互,由于是操作系统级别的虚拟技术,中间的损耗几乎可以不计。

docker概述与原理

5
docker容器和虚拟化实现原理

docker概述与原理

左图是虚拟机的工作原理图,着重体现在硬件层面进行虚拟化,实现对硬件资源进行抽象,对性能的损耗比较大,而且还会占用大量的内存资源

有图是Docker的工作原理图,属于OS级别的虚拟化,kernel通过创建多个镜像来隔离不同的app进程,由于kernel是是共享,本身linuximage也不大,性能损耗几乎可以不计,而且内存占用也不大,大大节约了设备成本

 

docker集群管理之swarm mode

序言

当有多台物理机的时候,就要考虑使用集群的模式了,那么docker如何来使用集群来进行管理呢?在这里主要使用的是docker自带的swarm mode,也就是docker集群的管理和编排。所谓的编排就是指多台集群的管理,主机的配置,容器的调度等。

swarm mode是docker engine中自带的一种模式,很容易使用,并且无须安装其他的软件。

swarm mode的使用

在使用swarm mode的时候,几台主机上都要先安装好docker,架构如下所示:

docker集群管理之swarm mode

将主机名为docker-ce的机器作为manager节点,也就是管理节点,而docker1和docker2作为工作节点。

1、 创建swarm集群

[root@docker-ce swarm]# docker swarm init –advertise-addr 192.168.1.222 (初始化集群,节点之间相互通信的ip地址为192.168.1.222,默认端口为2377

Swarm initialized: current node (pk4p936t4e03cpse3izuws07s) is now a manager.

To add a worker to this swarm, run the following command:

docker swarm join –token SWMTKN-1-60h71geyd7z297jfy2icektmq3ha3n5nego2znytgrzqix768e-f36psbhrnrdn9h0bop6np22xm 192.168.1.222:2377

To add a manager to this swarm, run ‘docker swarm join-token manager’ and follow the instructions.

[root@docker-ce swarm]# docker info|grep -i swarm(swarm模式已经激活

Swarm: active

[root@docker-ce swarm]# netstat -tnlp|grep docker(默认监听两个端口,tcp2377端口为集群的管理端口,tcp7946为节点之间的通讯端口

tcp6 0 0 :::2377 :::* LISTEN 66488/dockerd

tcp6 0 0 :::7946 :::* LISTEN 66488/dockerd

[root@docker-ce swarm]# docker network ls(默认会创建一个overlay的网络ingress,还会创建一个桥接的网络docker_gwbridge

NETWORK ID NAME DRIVER SCOPE

641eeb86f6a4 bridge bridge local

c23afa61afaa docker_gwbridge bridge local

65f6eed9f144 host host local

n8i6cpizzlww ingress overlay swarm

b4d6492a85d5 none null local

[root@docker-ce swarm]# docker node ls(查看集群中的节点,当有多个manager节点的时候,是通过raft协议来选取主节点,也就是leader节点

ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS

pk4p936t4e03cpse3izuws07s * docker-ce Ready Active Leader

[root@docker-ce swarm]# ls -l(swarm的配置文件都在/var/lib/docker/swarm目录中,会有相关的证书和manager的配置文件,使用的是raft协议

total 8

drwxr-xr-x. 2 root root 75 Jan 26 10:13 certificates(使用的tls来进行安全通信

-rw——-. 1 root root 151 Jan 26 10:13 docker-state.json(用来记录通信的地址和端口,也会记录本地的地址和端口

drwx——. 4 root root 55 Jan 26 10:13 raft(raft协议

-rw——-. 1 root root 69 Jan 26 10:13 state.json(manager的ip和端口

drwxr-xr-x. 2 root root 22 Jan 26 10:13 worker(记录工作节点下发的任务信息

[root@docker2 ~]# docker swarm join –token SWMTKN-1-60h71geyd7z297jfy2icektmq3ha3n5nego2znytgrzqix768e-f36psbhrnrdn9h0bop6np22xm 192.168.1.222:2377(其他的机器加入swarm集群

This node joined a swarm as a worker.

当忘记了加入集群的token的时候,可以使用如下的指令找到token,然后在node节点上直接执行,就可以加入worker节点或者是manager节点。

docker集群管理之swarm mode

查看集群如下:

docker集群管理之swarm mode

节点之间的角色可以随时进行变换(使用update进行更新):

docker集群管理之swarm mode

2、 开放防火墙

在各个节点进行通信的时候,必须开放相关的防火墙策略,其中包括通信的tcp的2377端口,tcp和udp的7946端口,还有网络overlay的udp端口4789端口。

[root@docker-ce ~]# firewall-cmd –add-port tcp/2377 –permanent

[root@docker-ce ~]# firewall-cmd –add-port tcp/7946 –permanent

[root@docker-ce ~]# firewall-cmd –add-port udp/7946 –permanent

[root@docker-ce ~]# firewall-cmd –add-port udp/4789–permanent

[root@docker-ce ~]# systemctl restart firewalld

3、 运行服务

服务为service,也就是一组task的集合,而一个task则表示为一个容器,从基本概念来说,运行一个service,可能有几个task,例如运行几个nginx的服务,从而会拆解为几个nginx的容器在各个节点上进行运行。

[root@docker-ce ~]# docker service create –name web nginx(create表示创建一个服务,名称为web,镜像为nginx

oy2y8sb31c2jpn9owk6gdt7nk

overall progress: 1 out of 1 tasks

1/1: running [==================================================>]

verify: Service converged

[root@docker-ce ~]# docker service create –name frontweb –mode global nginx(创建一个名称问frontweb的服务,模式为global,镜像为nginx

ld835zsd9x1x4rdaj6u1i1rfy

overall progress: 3 out of 3 tasks

pk4p936t4e03: running [==================================================>]

xvkxa7z22v75: running [==================================================>]

6xum2o1iqmya: running [==================================================>]

verify: Service converged

[root@docker-ce ~]# docker service ls(查看运行的服务

ID NAME MODE REPLICAS IMAGE PORTS

ld835zsd9x1x frontweb global 3/3 nginx:latest

oy2y8sb31c2j web replicated 1/1 nginx:latest

[root@docker-ce ~]# docker service ps web(查看运行的详细信息,默认情况下manager节点也可以运行容器

ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS

li2bfdt1dfjs web.1 nginx:latest docker-ce Running Running 13 minutes ago

[root@docker-ce ~]# docker service ps frontweb(查看运行的详细信息

ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS

s96twac1s4av frontweb.6xum2o1iqmyaun2khb4b5z57h nginx:latest docker2 Running Running 34 seconds ago

qtr35ehwuu26 frontweb.xvkxa7z22v757jnptndvtcc4t nginx:latest docker1 Running Running 37 seconds ago

jujtu01q49o2 frontweb.pk4p936t4e03cpse3izuws07s nginx:latest docker-ce Running Running 55 seconds ago

在创建服务的时候,会经过几个状态,一个是prepared,表示准备,主要是从仓库拉取镜像,然后启动容器,也就是starting,最后会进行验证容器状态,从而最后变成running状态。

在查看服务的时候,会出现一个mode,也就是服务的类型,可以分为两种,一种replicated,表示副本,默认情况下是使用replicated模式,并且默认情况只会创建一个副本,主要使用的目的是为了高可用;另外一种为global,也就是必须在每个机器上运行一个task也就是容器,可以看到在使用global的模式的时候创建了三个容器。

docker集群管理之swarm mode

4、服务的扩缩容

在使用服务的时候,由于是集群,那么就必然会涉及到高可用,从而会有服务的扩容和缩容,在swarm中还是很容易的。

[root@docker-ce ~]# docker service scale web=3(扩容为3,也就是运行三个容器

web scaled to 3

overall progress: 3 out of 3 tasks

1/3: running [==================================================>]

2/3: running [==================================================>]

3/3: running [==================================================>]

verify: Service converged

[root@docker-ce ~]# docker service ls(查看服务,可以看到replicas副本数量为3个

ID NAME MODE REPLICAS IMAGE PORTS

oy2y8sb31c2j web replicated 3/3 nginx:latest

[root@docker-ce ~]# docker service ps web(可以看到三个节点上都运行了每个都各运行了一个容器task

ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS

li2bfdt1dfjs web.1 nginx:latest docker-ce Running Running 25 minutes ago

8dsrshssyd6t web.2 nginx:latest docker2 Running Running 46 seconds ago

4i7vgzspdpts web.3 nginx:latest docker1 Running Running 46 seconds ago

在默认情况下,管理的机器也是可以运行容器的,从而在manager节点上也运行一个容器。

[root@docker-ce ~]# docker service scale web=2(将web服务缩容为2个

web scaled to 2

overall progress: 2 out of 2 tasks

1/2: running [==================================================>]

2/2: running [==================================================>]

verify: Service converged

[root@docker-ce ~]# docker service ps web(查看运行的容器

ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS

4i7vgzspdpts web.3 nginx:latest docker1 Running Running 9 minutes ago

56s441jtydq4 web.5 nginx:latest docker-ce Running Running about a minute ago

当要让swarm的manager节点不运行容器的时候,只要更改节点的状态,从Active变成Drain即可,如果在manager上运行容器,那么当manager宕机的时候,如果不是多节点的manager,会导致此服务无法进行调度。

[root@docker-ce ~]# docker node update –availability drain docker-ce(将manager节点的状态修改为drain状态,从而不会执行相关的task任务

docker-ce

[root@docker-ce ~]# docker node ls(查看节点的状态从active变成drain

ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS

xvkxa7z22v757jnptndvtcc4t docker1 Ready Active

6xum2o1iqmyaun2khb4b5z57h docker2 Ready Active

pk4p936t4e03cpse3izuws07s * docker-ce Ready Drain Leader

[root@docker-ce ~]# docker service ps web(本来运行在docker-ce上的容器会被关闭,然后自动迁移到其他的worker节点上

ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS

4i7vgzspdpts web.3 nginx:latest docker1 Running Running 12 minutes ago

x2w8qdxuv2y5 web.5 nginx:latest docker2 Running Running about a minute ago

56s441jtydq4 _ web.5 nginx:latest docker-ce Shutdown Shutdownabout a minute ago

5、 自动故障转移

在集群中,当有机器发生宕机了咋办,swarm可以做到自动迁移,但是在生产环境中需要考虑的一个问题就是,如果出现了自动的failover,那么其他的机器是否有足够的资源来创建这些容器,所以,在进行运行容器的时候,就要考虑剩余资源的问题,例如cpu和内存。

[root@docker-ce ~]# docker service ps web(查看服务的分布

ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS

nrkfvb2js6p1 web.1 nginx:latest docker1 Running Running 10 seconds ago

q17kbbwd3ewr web.2 nginx:latest docker2 Running Running 10 seconds ago

yvpijmfr4qrm web.3 nginx:latest docker2 Running Running 10 seconds ago

[root@docker2 ~]# systemctl stop docker(关闭docker服务,模拟机器宕机

[root@docker-ce ~]# docker node ls(查看node的信息,发现docker2主机标记为down,也就是主机宕机

ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS

xvkxa7z22v757jnptndvtcc4t docker1 Ready Active

6xum2o1iqmyaun2khb4b5z57h docker2 Down Active

pk4p936t4e03cpse3izuws07s * docker-ce Ready Drain Leader

[root@docker-ce ~]# docker service ps web(查看自动迁移后的服务,会将宕机的服务全部标记为shutdown关闭

ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS

nrkfvb2js6p1 web.1 nginx:latest docker1 Running Running about a minute ago

i76d3p7bmdht web.2 nginx:latest docker1 Running Running 28 seconds ago

q17kbbwd3ewr _ web.2 nginx:latest docker2 Shutdown Running 50 seconds ago

ohg093dh9zvt web.3 nginx:latest docker1 Running Running 28 seconds ago

yvpijmfr4qrm _ web.3 nginx:latest docker2 Shutdown Running 50 seconds ago

[root@docker2 ~]# systemctl start docker(将主机进行上线

[root@docker-ce ~]# docker node ls(主机状态变成ready,表示可运行task任务

ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS

xvkxa7z22v757jnptndvtcc4t docker1 Ready Active

6xum2o1iqmyaun2khb4b5z57h docker2 Ready Active

pk4p936t4e03cpse3izuws07s * docker-ce Ready Drain Leader

[root@docker-ce ~]# docker service ps web(再次查看服务的分布,服务不会再次进行迁移到不同的机器上,维持原状

ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS

nrkfvb2js6p1 web.1 nginx:latest docker1 Running Running 5 minutes ago

i76d3p7bmdht web.2 nginx:latest docker1 Running Running 4 minutes ago

q17kbbwd3ewr _ web.2 nginx:latest docker2 Shutdown Shutdown about a minute ago

ohg093dh9zvt web.3 nginx:latest docker1 Running Running 4 minutes ago

yvpijmfr4qrm _ web.3 nginx:latest docker2 Shutdown Shutdown about a minute ago

6、 访问服务

访问服务的时候,主要分为两种,一种是内部访问的服务,也就是不对外开放端口,一种是对外的服务,会向外开放端口,也就是主机映射端口。

[root@docker-ce ~]# docker service create –name web –replicas=2 httpd(创建副本为2的httpd服务

60c9i7de4mu4x9n3ia03nrh52

overall progress: 2 out of 2 tasks

1/2: running [==================================================>]

2/2: running [==================================================>]

verify: Service converged

[root@docker-ce ~]# docker service ps web(查看运行容器的主机

ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS

wb56gj6zbtlw web.1 httpd:latest docker2 Running Running 18 seconds ago

n6hupzwlchss web.2 httpd:latest docker1 Running Running 18 seconds ago

[root@docker1 ~]# docker ps (登录本地主机,查看运行的容器

CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

19a6ed6ec945 httpd:latest “httpd-foreground” 23 seconds ago Up 22 seconds 80/tcp web.2.n6hupzwlchss01fbcec6jsp27

[root@docker1 ~]# docker exec 19a6ed6ec945 ip addr show(查看运行容器的ip地址

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1

link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

inet 127.0.0.1/8 scope host lo

valid_lft forever preferred_lft forever

201: eth0@if202: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default

link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff

inet172.17.0.2/16 brd 172.17.255.255 scope global eth0

valid_lft forever preferred_lft forever

[root@docker1 ~]# curl 172.17.0.2(根据ip地址访问,只能在本节点上进行访问,属于内部网络,也就是docker_gwbrige网络

<html><body><h1>It works!</h1></body></html>

[root@docker-ce ~]# docker service update –publish-add 8000:80 web

web(添加主机映射端口,从而将服务对外放开,从而外部能访问此服务

overall progress: 2 out of 2 tasks

1/2: running [==================================================>]

2/2: running [==================================================>]

verify: Service converged

[root@docker-ce ~]# docker service ps web(将原来的容器关闭,重新运行容器

ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS

pktheo7u3178 web.1 httpd:latest docker2 Running Running 11 seconds ago

wb56gj6zbtlw _ web.1 httpd:latest docker2 Shutdown Shutdown 13 seconds ago

j5mrcqlozlhz web.2 httpd:latest docker1 Running Running 16 seconds ago

n6hupzwlchss _ web.2 httpd:latest docker1 Shutdown Shutdown 20 seconds ago

[root@docker-ce ~]# curl 192.168.1.222:8000(无论是manager节点还是worker节点,均监听了8000端口,均可以访问

<html><body><h1>It works!</h1></body></html>

[root@docker-ce ~]# curl 192.168.1.32:8000

<html><body><h1>It works!</h1></body></html>

[root@docker-ce ~]# curl 192.168.1.33:8000

<html><body><h1>It works!</h1></body></html>

[root@docker-ce ~]# netstat -ntlp|grep 8000(集群中的每个机器都会监听8000端口,无论是否运行了这个容器

tcp6 0 0 :::8000 :::* LISTEN 66488/dockerd

在这里主要使用了routing mesh的功能,在swarm内部实现了负载均衡,使用的网络为swarm自动创建的overlay网络。

当使用publish端口的时候,最大的坏处就是对外暴露了端口号,而且在使用的时候,如果进行了故障转移,那么多个服务运行在同一个主机上面,会造成端口占用冲突。

7、 服务发现

在使用集群的时候,如果进行了自动转移,那么ip地址会发生变化,如果指定了ip地址,那么就会影响其他服务的使用,从而需要服务发现的功能,也就是自动将服务进行dns的解析,然后负载到正确的服务中。

[root@docker-ce ~]# docker network create –driver overlay kel(创建overlay网络,默认的ingress网络未实现服务发现的功能)

nomp3f50to1s4gn6ke4zpxn8n

[root@docker-ce ~]# docker service create –name web –replicas=2 –network=kel nginx(将服务挂载到自创建的overlay网络中,从而能实现名称解析

uo5kuxad0wojn5j24moudi4l5

overall progress: 2 out of 2 tasks

1/2: running [==================================================>]

2/2: running [==================================================>]

verify: Service converged

[root@docker-ce ~]# docker service create –name ds –network=kel busybox sleep 100000(创建另外一个服务依赖于其他的服务

hwcn4esjpgqyae7r9bqcn8a9m

overall progress: 1 out of 1 tasks

1/1: running [==================================================>]

verify: Service converged

[root@docker-ce ~]# docker service ps ds(查看运行的服务

ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS

7gknpd69eti1 ds.1 busybox:latest docker2 Running Running 12 seconds ago

[root@docker2 ~]# docker exec 66ece5551fc5 ping -c 2 web(自动实现了dns的解析功能

PING web (10.0.0.5): 56 data bytes

64 bytes from 10.0.0.5: seq=0 ttl=64 time=0.833 ms

64 bytes from 10.0.0.5: seq=1 ttl=64 time=0.323 ms

— web ping statistics —

2 packets transmitted, 2 packets received, 0% packet loss

round-trip min/avg/max = 0.323/0.578/0.833 ms

[root@docker2 ~]# docker exec 66ece5551fc5 nslookup web(查看vip地址

Server: 127.0.0.11

Address 1: 127.0.0.11

Name: web

Address 1: 10.0.0.5

[root@docker2 ~]# docker exec 66ece5551fc5 nslookup tasks.web(查看各个主机的ip地址

Server: 127.0.0.11

Address 1: 127.0.0.11

Name: tasks.web

Address 1: 10.0.0.7 b2f14e41a97a.kel

Address 2: 10.0.0.6 web.1.78a2eugjholl3c35xa361kdaj.kel

8、滚动更新rolling update

当需要进行更新的时候,swarm可以设定相应的策略来进行更新,例如并行更新多少个容器,更新之间的间隔时间等。

[root@docker-ce ~]# docker service update –image nginx:1.10 web(更新web的镜像

web

overall progress: 2 out of 2 tasks

1/2: running [==================================================>]

2/2: running [==================================================>]

verify: Service converged

[root@docker-ce ~]# docker service ps web(更新的时候先关闭,然后再更新

ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS

512sgoen7yu9 web.1 nginx:1.10 docker1 Running Running 6 minutes ago

rz9thj8s1iv6 _ web.1 nginx:1.9 docker1 Shutdown Shutdown 6 minutes ago

5hsl7q2486iz web.2 nginx:1.10 docker2 Running Running 6 minutes ago

czgdnq3lmhgu _ web.2 nginx:1.9 docker2 Shutdown Shutdown 7 minutes ago

[root@docker-ce ~]# docker service update –image nginx:1.11 web

web

overall progress: 2 out of 2 tasks

1/2: running [==================================================>]

2/2: running [==================================================>]

verify: Service converged

[root@docker-ce ~]# docker service update –update-parallelism 2 –update-delay 1m web(更新的时候,设定更新的并发数和更新的间隔时间

web

overall progress: 2 out of 2 tasks

1/2: running [==================================================>]

2/2: running [==================================================>]

verify: Service converged

[root@docker-ce ~]# docker service inspect web –pretty(查看具体的信息,可以看到更新的一些参数配置

ID: cxsk18saisqsycc9bn1m768xx

Name: web

Service Mode: Replicated

Replicas: 2

Placement:

UpdateConfig:

Parallelism: 2

Delay: 1m0s

On failure: pause

Monitoring Period: 5s

Max failure ratio: 0

Update order: stop-first

RollbackConfig:

Parallelism: 1

On failure: pause

Monitoring Period: 5s

Max failure ratio: 0

Rollback order: stop-first

ContainerSpec:

Image: nginx:1.11@sha256:e6693c20186f837fc393390135d8a598a96a833917917789d63766cab6c59582

Resources:

Endpoint Mode: vip

9、label控制service运行的节点

主要是用来控制每个task运行的节点,从而可以为每个节点设置属性label,然后根据label来指定task运行的位置(生产环境中可能要手动将容器分布在不同的机器上,从而达到高可用的目的)。

[root@docker-ce ~]# docker node update –label-add ncname=docker1 docker1(更新节点的属性,为节点添加标签

docker1

[root@docker-ce ~]# docker node update –label-add ncname=docker2 docker2(更新节点的属性,为节点添加标签

docker2

[root@docker-ce ~]# docker node inspect docker1 –pretty(查看设置的属性

ID: xvkxa7z22v757jnptndvtcc4t

Labels:

– ncname=docker1

[root@docker-ce ~]# docker service create –name web –constraint node.labels.ncname==docker1 –replicas 2 nginx(指定机器来运行相关的任务,主要是根据label的值

m0126tvjof5owsn9crke00w63

overall progress: 2 out of 2 tasks

1/2: running [==================================================>]

2/2: running [==================================================>]

verify: Service converged

[root@docker-ce ~]# docker service ps web(运行在指定的机器上

ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS

igfs9wrv2j0w web.1 nginx:latest docker1 Running Running 55 seconds ago

ibcdq1i6hjkx web.2 nginx:latest docker1 Running Running 55 seconds ago

[root@docker-ce ~]# docker service update –constraint-rm node.labels.ncname==docker1 web(去掉指定的标签

web

overall progress: 2 out of 2 tasks

1/2: running [==================================================>]

2/2: running [==================================================>]

verify: Service converged

[root@docker-ce ~]# docker service update –constraint-add node.labels.ncname==docker2 web(服务迁移到另外一台主机上

web

overall progress: 2 out of 2 tasks

1/2: running [==================================================>]

2/2: running [==================================================>]

verify: Service converged

[root@docker-ce ~]# docker service ps web(查看结果,这种修改也是可以回滚的,也就是使用rollback进行回滚

ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS

0uhx5oewt7tp web.1 nginx:latest docker2 Running Running 9 seconds ago

ykykhvuydnmu _ web.1 nginx:latest docker1 Shutdown Shutdown 11 seconds ago

igfs9wrv2j0w _ web.1 nginx:latest docker1 Shutdown Shutdown 43 seconds ago

r2t52s9py825 web.2 nginx:latest docker2 Running Running 13 seconds ago

vssp6qqc5eez _ web.2 nginx:latest docker2 Shutdown Shutdown 15 seconds ago

ibcdq1i6hjkx _ web.2 nginx:latest docker1 Shutdown Shutdown 47 seconds ago

10、 健康检查

如何来进行业务层面的健康检查呢,容器的状态是不可以的。在运行服务的时候,也是可以设定相关参数的,具体的参数如下:

使用dockerfile的参数:

  • –interval=DURATION(default:30s)

  • –timeout=DURATION(default:30s)

  • –start-period=DURATION(default:0s)

  • –retries=N(default:3)

    使用docker service create的参数:

–health-cmd string Command to run to check health

–health-interval duration Time between running the check (ms|s|m|h)

–health-retries int Consecutive failures needed to report unhealthy

–health-start-period duration Start period for the container to initializebefore counting retries towards unstable (ms|s|m|h)

–health-timeout duration Maximum time to allow one check to run (ms|s|m|h)

使用dockerfile的例子如下:

[root@docker-ce kel]# cat dockerfile (在dockerfile里面进行健康检查进行设置

FROM redis

RUN echo ‘/usr/local/bin/redis-cli info |grep “role:master”‘>/usr/local/bin/kel

RUN chmod u+x /usr/local/bin/kel

HEALTHCHECK CMD kel

[root@docker-ce kel]# docker service ps kel(查看服务信息

ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS

k2ewbrauv0dv kel.1 kellyseeme/redishealthcheck:latest docker2 Running Running about a minute ago

yzadjp443091 kel.2 kellyseeme/redishealthcheck:latest docker1 Running Running about a minute ago

[root@docker1 ~]# docker inspect f4759f2dcfbc(查看健康检查的配置和相关的日志

“Health”: {

“Status”: “healthy”,

“FailingStreak”: 0,

“Log”: [

{

“Start”: “2018-01-27T16:51:44.945773759+08:00”,

“End”: “2018-01-27T16:51:45.633754663+08:00”,

“ExitCode”: 0,

“Output”: “role:masterrn”

“Healthcheck”: {

“Test”: [

“CMD-SHELL”,

“kel”