使用Docker封装java应用

本文详细介绍了如何使用docker封装一个java应用(名字叫cspj,这个java应用涉及数据持久化以及RMI调用),包括:html

  • docker安装
  • 镜像制做
  • 容器运行
  • 数据文件处理
  • 私有仓库
  • swarm集群,包括service、node、stack、task等相关概念
  • 使用docker-machine快速建立docker虚拟机

1. docker介绍

docker是一种容器技术,对操做系统、文件系统、网络等进行了封装,使其中的进程能够完整运行。java

docker和虚拟机是不一样的技术。虚拟机虚拟了一套硬件环境,须要在这个硬件环境之上安装完整的操做系统、jdk等相关软件,才能运行一个java应用,虚拟机和宿主机在操做系统层面就是相互隔离的。而docker则不一样,以Linux下的docker为例,它使用的依旧是宿主机中的Linux内核,只不过在宿主机的用户层上虚拟了一个容器,这个容器中的Linux只是操做系统中的一小部分,使用的依旧是宿主机的Linux内核。好比宿主机是Ubuntu,docker虚拟的操做系统能够是alpine,这只是虚拟了alpine和Ubuntu不一样的部分。node

一个docker容器中通常只运行一个应用,这和虚拟机也是不一样的。好比咱们的一个应用有java应用,有数据库mysql,那么java应用运行在一个容器里,mySql运行在另外一个容器里。他们之间能够经过docker虚拟的网络进行交互。mysql

docker中的容器就是运行中的进程。它是经过镜像进行启动的。docker中的镜像就至关于一个模板,启动一个容器就至关于经过模板建立一个可执行的应用。所以,只要镜像不变,全部经过这个镜像建立的容器都是一摸同样的。又由于docker进行了操做系统、文件系统、网络等方面的封装,因此这个镜像就能够在各类不一样的环境上运行,从而保证一致的执行效果。linux

容器运行以后,在其中会有一个可读写层,这是用来临时保存容器中应用在运行中产生的数据的。当这个容器被销毁以后,所保存的数据也就消失了。使用原有的镜像从新运行一个新的容器,就又是一个全新的应用了。git

因此,若是咱们须要对容器中的数据进行持久化,就须要用到volume或者bind mounts技术。好比咱们的java应用中有一个内置文件数据库Derby,若是须要保留对这个文件数据库的修改,同时又不想改变镜像文件,就能够把这个文件数据库使用volume或bind mounts技术保存到宿主机的文件系统中。这样,即便容器被销毁,容器中所修改的文件数据库也会被保留下来。github

还有一种方法保存容器中的临时数据,就是使用commit命令把容器可读写层中的临时数据也一块儿生成一个新的镜像。之后经过这个新镜像运行的容器,就都保留了这部分数据,这部分数据也就成了新镜像的一层,并且没法被修改。经过这个新镜像运行的容器,会生成一个新的可读写层,用来临时保存这次运行中生成的数据。若是一直使用commit保存数据,新的镜像就会愈来愈大。docker官方不推荐使用这种方法保存数据。sql

在详细说一下docker的镜像。docker的镜像是使用Dockerfile制做的。Dockerfile是一个脚本,docker build命令会读取这个脚本,按照其指令构造镜像。docker的镜像是一层一层的。每个Dockerfile指令,都会生成镜像中的一层。docker

咱们本身制做的docker镜像一般不会从最底层开始构建。好比咱们要制做一个java应用的镜像,咱们就要依赖于openjdk:8-alpine的官方镜像。在这个基础之上,再制做咱们的java应用镜像层。而官方的openjdk:8-alpine则是基于alpine操做系统制做的镜像,在这个操做系统之上,它为咱们设置好了各类环境变量,咱们在这个镜像之上就能够直接制做咱们本身的java应用镜像,而没必要关心jdk的设置了。数据库

aphine 是一个特别简洁的官方的Linux操做系统系统容器镜像,只有5M大小。从中也能够看出docker和虚拟机的区别,虚拟机中运行的操做系统必定是完整的操做系统,一般都会有几个G的大小。

2. 环境准备

实验电脑为Intel-Core-i7 CPU, 安装Windows10操做系统,使用VirtualBox安装了CentOS-7虚拟机。咱们将在CentOS-7虚拟机上安装Docker。关于如何在安装设置虚拟机,请参看这里

若是要执行8.2节中的实例,必须使用VMWare虚拟机安装CentOS-7系统,由于VMWare支持nested vm。还须要设置vmware虚拟机的处理器中,选择“虚拟化Intel VT-x/EPT或AMD-V/RVI(V)。

若是使用AMD处理器,则可使用VirtualBox安装CentOS-7,由于最新的VirtualBox-6支持在AMD系统上打开netstad vm。

VirtualBox中安装的CentOS-7系统的IP地址是192.168.56.104.

3. 安装Docker

Docker分为社区版和企业版,咱们使用社区版便可。

  • 卸载旧docker
$ sudo yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine
  • 安装docker
# 安装依赖
$ sudo yum install -y yum-utils \
  device-mapper-persistent-data \
  lvm2

# 设置国内镜像源
$ sudo yum-config-manager \
    --add-repo \
    https://mirrors.ustc.edu.cn/docker-ce/linux/centos/docker-ce.repo

# 安装最新版本
$ sudo yum install docker-ce docker-ce-cli containerd.io

# 启动
$ sudo systemctl start docker

# 验证,或从docker官方下载hello-world镜像并根据镜像运行容器。这个镜像只有不到2K
$ sudo docker run hello-world

# 把用户添加到docker组中,这样执行docker命令时就没必要使用sudo了
$ sudo usermod -aG docker your-user

设置镜像加速器能够加速从Docker Hub获取镜像的速度。在/etc/docker/daemon.json文件中(如不存在请新建)添加以下内容:

{
  "registry-mirrors": [
    "https://dockerhub.azk8s.cn",
    "https://reg-mirror.qiniu.com"
  ]
}

以后启动服务:

$ sudo systemctl daemon-reload
$ sudo systemctl restart docker

更详细的安装方法请参看Get Docker Engine - Community for CentOS安装 Docker

docker实际上是C/S模式的,咱们在Linux终端输入的docker命令实际上是客户端,后台还有一个服务端在运行。客户端和服务端能够不运行在同一个机器上。

4. 制做镜像

4.1 准备镜像文件

新建一个空目录,把java应用程序放入到这个目录中,并新建Dockerfile文件。这里咱们先不考虑临数据库持久化的问题,直接把全部应用程序进行打包:

[eric@centos7min2 cspj-server]$ ll
total 4
drwxrwxr-x. 2 eric eric 206 Sep 28 21:53 bin
drwxrwxr-x. 2 eric eric 207 Sep 27 16:23 conf
drwxrwxr-x. 4 eric eric  92 Sep 29 14:03 database
-rw-rw-r--. 1 eric eric  93 Sep 29 14:19 Dockerfile
drwxr-xr-x. 3 eric eric 278 Sep 27 16:12 lib

这个java应用程序的启动脚本是bin/startServer.sh,这个脚本中启动命令最后有&符号,须要去掉。由于容器中运行的程序都是在前台运行的,若是加上&符号,这个在前台运行的startServer.sh脚本就执行完毕,这个容器也就当即中止了。

bin/setEnv.sh中设定了一些RMI参数,为了能够进行RMI链接,设置其内容以下:

#!/bin/sh

export IP=`awk 'END{print $1}' /etc/hosts`
echo "$IP cspj-host" >> /etc/hosts
cat /etc/hosts

export JAVA_EXECUTE=java
export CSPJ_LIBPATH=../lib/*.jar
export CSPJ_LIBPATH_OPT=../lib/opt/*.jar
export CSPJ_CLASSPATH=../conf/
export JVM_OPTARGS="-Xmx1024m -Xms1024m"
export CSPJ_OPTARGS="-Dcspj.home=$PWD/../ -Dfile.encoding=UTF-8"
export CSPJ_JMXARGS="-Djava.rmi.server.hostname=cspj-host -Dcom.sun.management.jmxremote.port=9998 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false"

echo $CSPJ_JMXARGS

其中IP是容器运行时动态获取容器的IP地址,把这个地址写入到/etc/hosts中时为了后续进行RMI链接,设置-Djava.rmi.server.hostname=cspj-host也是为了后续的RMI链接

4.2 编写Dockerfile

Dockerfile中内容为:

FROM openjdk:8-alpine
COPY . /cspj-server/
WORKDIR /cspj-server/bin
CMD ["./startServer.sh"]
  • FROM指令表示咱们的镜像所基于的基础镜像。这里咱们使用的是openjdk:8-alpine。官方镜像均可以从docker hub中搜索。好比搜索openjdk,在openjdk界面点击TAGS页面,输入一些过滤信息,就能够找到对应版本。好比咱们还可使用8-jre-alpine进行过滤,只使用jre
  • COPY指令表示把当前目录下的全部文件(Dockerfile除外)复制到镜像中的/cspj-server/目录。注意必定要有最后的“/”符号,表示复制到这个目录中。因为上一条指令咱们基于的基础镜像openjdk:8-alpine就已经包含了一个基础的Linux文件系统,因此执行COPY命令时,就是在镜像中的文件系统中进行操做。COPY命令会自动在这个文件系统中建立不存在的/cspj-server/文件夹
  • WORKDIR指令指定镜像的工做目录。至关于在镜像的文件系统中进入这个目录,并把这个目录设置为工做目录
  • CMD指令指定经过这个镜像启动容器时须要执行什么命令。咱们这里把应用程序的启动脚本做为执行命令

在构建镜像时,docker中每条指令都会构建一层,因此若是有RUN命令时,通常把多个操做都写在一行里。

4.3 构建镜像

在刚才的目录中,执行 docker build -t ws3495/cspj-server:v1.0.0 . 命令,构建镜像。:v1.0.0能够省略,此时默认是:latest。注意不要丢掉最后的“.”,它以宿主机的一个文件夹做为"context",Dockerfile中的指令就是基于这个“context”进行构建的。好比这个docker build命令指定了当前路径(/home/eric/dockertest/forbuildimage/cspj-server)为“context”,那么在Dockerfile中,COPY . /cspj-server/ 指令中的“.”指的就是宿主机的/home/eric/dockertest/forbuildimage/cspj-server目录。关于docker build指令能够参考docker build,关于上下文能够参考这里

经过执行刚才的命令,其执行过程为:

[eric@centos7min2 cspj-server]$ docker build -t ws3495/cspj-server:v1.0.0 .
Sending build context to Docker daemon   32.8MB
Step 1/4 : FROM openjdk:8-alpine
 ---> a3562aa0b991
Step 2/4 : COPY . /cspj-server/
 ---> 27361ab40a65
Step 3/4 : WORKDIR /cspj-server/bin
 ---> Running in aef7152e561a
Removing intermediate container aef7152e561a
 ---> b0fcdabdde69
Step 4/4 : CMD ["./startServer.sh"]
 ---> Running in 7a11c32dccae
Removing intermediate container 7a11c32dccae
 ---> 4e56f3b72f1d
Successfully built 4e56f3b72f1d
Successfully tagged ws3495/cspj-server:v1.0.0

经过这个执行过程当中每一个step,能够看出docker构建镜像时的操做:

  • Sending build context to Docker daemon: docker客户端把“context”发送到docker服务端
  • Step 1/4: 根据基础镜像openjdk:8-alpine构建第一层。若是这是第一次执行,会从docker hub上拉取这个镜像,缓存在本地。之后再次执行这个指令时,就会直接从本地获取这个镜像了。
  • Step 2/4: 构建第2层,把相对“context”路径“.”下全部文件复制到镜像的/cspj-server/文件夹
  • Step 3/4: 构建第3层。先启动一个容器aef7152e561a,执行了所要求的指令,随后删除了这个临时的容器,并把执行结果进行了提交,就生成了镜像的一层。
  • Step 4/4: 设置容器启动命令。
  • 最后打上一个tag

经过执行docker image ls命令,能够看到刚才构建的镜像:

[eric@centos7min2 cspj-server]$ docker image ls
REPOSITORY                TAG                 IMAGE ID            CREATED             SIZE
ws3495/cspj-server        v1.0.0              4e56f3b72f1d        12 minutes ago      137MB
ws3495/cspj-server        v1.0.1              e5868fe7c123        4 hours ago         132MB
openjdk                   8-alpine            a3562aa0b991        4 months ago        105MB
registry                  latest              f32a97de94e1        6 months ago        25.8MB
hello-world               latest              fce289e99eb9        9 months ago        1.84kB
prakhar1989/static-site   latest              f01030e1dcf3        3 years ago         134MB

这个命令输出一个相似表格的结构,第一行是表头。第二行就是咱们刚构建的ws3495/cspj-server:v1.0.0,第3行是咱们从docker hub上拉取的openjdk:8-alpine镜像。

5. 启动应用

5.1 启动容器

执行命令docker run -d -p 27449:27449 -p 27450:27450 ws3495/cspj-server:v1.0.0,依据刚才制做的镜像,启动一个容器:

[eric@centos7min2 cspj-server]$ docker run -d \
>   -p 27449:27449 -p 27450:27450 \
>   ws3495/cspj-server:v1.0.0
47ed8277b0e0bfbb90a798a8b5499a0ee693499fd2342615388248ad72e932ab

命令执行结束后,返给咱们一个字符串,这个串就是这个刚刚启动的容器的ID。因为咱们使用了-d参数,因此这个容器在后台运行。

命令中的-p <host port>:<container port>参数把容器中的端口和宿主机中的端口进行了映射。外部访问host port的链接就会被转发到这个容器的container port上。

使用docker logs id指令能够查看容器的日志,id仅需前几位便可:

[eric@centos7min2 cspj-server]$ docker logs 47ed827
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.2 47ed8277b0e0
172.17.0.2 cspj-host
-Djava.rmi.server.hostname=cspj-host -Dcom.sun.management.jmxremote.port=9998 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false

Starting CSPJ Server...
2019-09-29_10:35:33.263[0000]CSPJ Server Process ID:10
2019-09-29_10:35:33.275[0000]CSPJ Server Version:CSPJ_V1.3.7.1 Build:2019-08-03 10:54:51
2019-09-29_10:35:33.276[0000]系统日志初始化成功[/cspj-server/log/syslog.trace]
2019-09-29_10:35:33.277[0000]平台主目录:/cspj-server
2019-09-29_10:35:33.277[0000]平台配置信息主目录:/cspj-server/conf
...
2019-09-29_10:35:37.587[0000]终端[RMI Registry]监听端口[27449]数据端口[27450]
2019-09-29_10:35:37.587[0000]终端守护进程启动成功
2019-09-29_10:35:37.587[0000]初始化交易主控入口……
2019-09-29_10:35:37.589[0000]交易主控入口初始化成功[DefaultTransactionInvoker]
2019-09-29_10:35:37.589[0000]启动通信口岸……
2019-09-29_10:35:37.599[0000]启动通信口岸:SocketPortal[NIO]
2019-09-29_10:35:37.599[0000]通信口岸启动成功
2019-09-29_10:35:37.649[0000]CSPJ Server 启动成功

使用命令docker ps能够查看正在运行的容器:

[eric@centos7min2 cspj-server]$ docker ps
CONTAINER ID        IMAGE                       COMMAND              CREATED             STATUS              PORTS                                  NAMES
47ed8277b0e0        ws3495/cspj-server:v1.0.0   "./startServer.sh"   53 minutes ago      Up 53 minutes       0.0.0.0:27449-27450->27449-27450/tcp   jolly_shockley

对于这个运行中的容器,可使用命令docker exec -it id sh,进入这个容器进行查看和修改:

[eric@centos7min2 cspj-server]$ docker exec -it 47ed827 sh
/cspj-server/bin # ls
SecInputKey.sh      derby.log           jmxremote.password  serverStatus.sh     startServer.sh      transform.sh
codeinfo.sh         ij.sh               pwdgen.sh           setEnv.sh           stopServer.sh
/cspj-server/bin # cd ../log
/cspj-server/log # ls
error.trace   root.trace    syslog.trace  trace
/cspj-server/bin #

此时就进入到了容器里,在里面对容器中的内容进行修改,就会写入到容器的可读写层(应该是最上层)。以后再执行docker restart <id>时,这个容器的修改不会消失。只有在使用docker rm <id>命令删除这个容器时,全部临时存储的文件就会消失。或者再使用docker run ... ws3495/cspj-server:v1.0.0命令运行一个新容器时,这个容器中所做的修改也不会被新容器知道。

5.2 从外部RMI链接到容器的27449端口

在咱们的windows 10系统上,修改C:\Windows\System32\drivers\etc\hosts文件,添加一行192.168.56.104 cspj-host,其中192.168.56.104是CentOS-7虚拟机的IP。就可使用IDE(RMI链接的客户端工具)链接了:

ide链接cspj-server

其原理是:

如今这个集群共有3个IP地址:

  • IP1: 是windows 10操做系统所在的地址,也是RMI客户端所在的地址
  • IP2: 192.168.56.104,是CentOS-7系统(在win10中运行的VirtualBox虚拟机中)所在的地址
  • IP3: 是docker容器运行的地址,即RMI服务端所在的地址

因为docker启动时设置了-p 27449:27449 -p 27450:27450参数,全部发送到IP2:27449和IP2:27450的信息都会被转发到IP3:27449和IP3:27450。这两个端口是咱们设置的RMI提供服务的端口。

在docker容器中启动的java应用(RMI服务端,IP3)在启动时设置了-Djava.rmi.server.hostname=cspj-host选项,当客户端使用rmi方式链接到docker容器中的进程时,容器中的进程会向客户端返回一个本机的cspj-host参数标定服务端所在的地址(已在docker中的/etc/hosts中设置了IP3 cspj-host(参看5.1节中的docker logs指令的输出结果))。客户端会从本机的hosts文件中查找cspj-host所在的地址。

客户端须要以RMI方式链接到IP3上时,须要经过IP2进行中转,因此在RMI客户端所在的机器上,须要在hosts文件中设置IP2 cspj-host,使客户端去IP2:27449获取RMI服务。又因为IP2会把全部27449端口的数据包都转发到IP3:27449,因此就会最终找到真正的RMI服务。

当有更多的IP对数据包进行转发时,也是同样的,客户端须要设置hosts中cspj-host为IP2所在的地址。

注意:链接过程当中可能会碰到NoSuchObject的异常,须要多试几回。或者在IP2上启动一个cspj,IDE链接上以后,再关闭IP2上的cspj,而后再试

6. 修改数据文件

6.1 使用commit生成新的镜像

经过5.2节图中的界面,咱们能够修改Derby数据库文件。主要修改内容是在容器中开放18000端口,全部向这个端口发送的数据,都会收到一个返回信息,信息中标明这个容器的IP地址。修改以后,使用docker commit <id> ws3495/cspj-server:tmp命令,把这个容器存为一个新镜像ws3495/cspj-server:tmp

[eric@centos7min2 cspj-server]$ docker commit 47ed8277b0e0 ws3495/cspj-server:tmp
sha256:ae4f6b8ecf435b714c331372d93c96bbb56460469bb9dd06e4e0f93faa8659a8
[eric@centos7min2 cspj-server]$ docker image ls
REPOSITORY                TAG                 IMAGE ID            CREATED             SIZE
ws3495/cspj-server        tmp                 ae4f6b8ecf43        9 seconds ago       141MB
ws3495/cspj-server        v1.0.0              4e56f3b72f1d        About an hour ago   137MB
ws3495/cspj-server        v1.0.1              e5868fe7c123        5 hours ago         132MB
openjdk                   8-alpine            a3562aa0b991        4 months ago        105MB
registry                  latest              f32a97de94e1        6 months ago        25.8MB
hello-world               latest              fce289e99eb9        9 months ago        1.84kB
prakhar1989/static-site   latest              f01030e1dcf3        3 years ago         134MB

能够看出,commit生成的镜像tmp比原始镜像v1.0.0镜像大了很多。

使用命令docker stop命令停掉如今这个容器,再使用docker ps -a命令,能够看到其状态为Exited(stop的容器可使用docker start命令再启动,其修改不会丢失):

[eric@centos7min2 cspj-server]$ docker stop 47ed8277b0e0
47ed8277b0e0
[eric@centos7min2 cspj-server]$ docker ps -a
CONTAINER ID        IMAGE                       COMMAND              CREATED             STATUS                        PORTS               NAMES
47ed8277b0e0        ws3495/cspj-server:v1.0.0   "./startServer.sh"   58 minutes ago      Exited (137) 31 seconds ago                       jolly_shockley

咱们根据刚才commit的镜像,启动一个新容器,此次把18000端口也映射到宿主机:

[eric@centos7min2 cspj-server]$ docker run -d \
>   -p 27449:27449 -p 27450:27450 -p 18000:18000 \
>   ws3495/cspj-server:tmp
f211f0844f78dc38460260c34b7e9cb7f9ae8245c7d246e35e7be7cf4d3ba23c

新运行的容器和刚才那个容器的ID是不同的。使用IDE链接到这个新容器上,能够看到刚才在那个容器中所做的修改,这里都存在。

在windows 10上,使用telnet链接到CentOS-7的18000端口,发送一段数据,能够看到返回信息:

response info

其中的ip addr is 172.17.0.2即容器中java应用返回信息。

6.2 更好的方法

v1.0.0镜像启动了一个容器47ed8277b0e0,可不能够在这个运行的容器上再用相似-p的参数映射出一个端口呢?根据How do I assign a port mapping to an existing Docker container?这个答案,须要修改docker守护进程的配置文件,不是一个很好的解决方案。

commit会使镜像不断增大。可使用bind mounts技术,在docker run命令中,使用--mount type=bind,source=<host dir>,target=/cspj-server/database参数,把宿主机上的一个文件夹挂载到容器中。咱们的java应用全部数据库修改都是修改/cspj-server/database目录,这样对数据库的修改就能够保存下来,即便容器被删除了,对数据库的修改也不会消失。不过要注意,<host dir>中因该包含咱们java应用中database目录所需的一些基础文件:

[eric@centos7min2 cspj-server]$ ll database/
total 20
drwxrwxr-x. 2 eric eric   97 Sep 29 14:03 log
-rw-rw-r--. 1 eric eric  608 Sep 29 14:03 README_DO_NOT_TOUCH_FILES.txt
drwxrwxr-x. 2 eric eric 8192 Sep 29 14:03 seg0
-rw-rw-r--. 1 eric eric 1003 Sep 29 14:03 service.properties

或者使用外置的数据库,不要和java应用集成在一块儿。例如链接到外部的oracle数据库;或者启动一个mySQL的docker container,使用docker-compose工具把他们关联到一块儿。详情请参看“容器集群”一节

7. 私有仓库registry

若是没法链接Docker Hub,咱们能够搭建私有仓库。使用官方镜像registry便可搭建:

# 搭建本地的registry,默认在/etc/lib/registry中
[eric@centos7min2 cspj-server]$ docker run -d -p 5000:5000 --restart=always --name registry registry
821497a1688646027389b8c3547ab3e321e8df1c1fa442987506b3b5784de52e

# 查看本地registry上存在的镜像
[eric@centos7min2 cspj-server]$ curl 127.0.0.1:5000/v2/_catalog
{"repositories":[]}

# 使用docker tag标记一个到127.0.0.1:5000的镜像
[eric@centos7min2 cspj-server]$ docker tag ws3495/cspj-server:tmp 127.0.0.1:5000/ws3495/cspj-server:tmp
[eric@centos7min2 cspj-server]$ docker image ls
REPOSITORY                          TAG                 IMAGE ID            CREATED             SIZE
127.0.0.1:5000/ws3495/cspj-server   tmp                 ae4f6b8ecf43        About an hour ago   141MB
ws3495/cspj-server                  tmp                 ae4f6b8ecf43        About an hour ago   141MB
ws3495/cspj-server                  v1.0.0              4e56f3b72f1d        3 hours ago         137MB
ws3495/cspj-server                  v1.0.1              e5868fe7c123        6 hours ago         132MB
openjdk                             8-alpine            a3562aa0b991        4 months ago        105MB
registry                            latest              f32a97de94e1        6 months ago        25.8MB
hello-world                         latest              fce289e99eb9        9 months ago        1.84kB
prakhar1989/static-site             latest              f01030e1dcf3        3 years ago         134MB

# 推送这个镜像
[eric@centos7min2 cspj-server]$ docker push 127.0.0.1:5000/ws3495/cspj-server:tmp
The push refers to repository [127.0.0.1:5000/ws3495/cspj-server]
e907982060bf: Pushed 
4c70c37a74c9: Pushed 
ceaf9e1ebef5: Pushed 
9b9b7f3d56a0: Pushed 
f1b5933fe4b5: Pushed 
tmp: digest: sha256:588c372c92e3909fb280311d273be512dfc5641eb66e0514b9c90c9db314dcb4 size: 1369

# 查看结果
[eric@centos7min2 cspj-server]$ curl 127.0.0.1:5000/v2/_catalog
{"repositories":["ws3495/cspj-server"]}

# 从新pull
[eric@centos7min2 cspj-server]$ docker image rm 127.0.0.1:5000/ws3495/cspj-server:tmp
Untagged: 127.0.0.1:5000/ws3495/cspj-server:tmp
Untagged: 127.0.0.1:5000/ws3495/cspj-server@sha256:588c372c92e3909fb280311d273be512dfc5641eb66e0514b9c90c9db314dcb4

[eric@centos7min2 cspj-server]$ docker pull 127.0.0.1:5000/ws3495/cspj-server:tmp
tmp: Pulling from ws3495/cspj-server
Digest: sha256:588c372c92e3909fb280311d273be512dfc5641eb66e0514b9c90c9db314dcb4
Status: Downloaded newer image for 127.0.0.1:5000/ws3495/cspj-server:tmp
127.0.0.1:5000/ws3495/cspj-server:tmp

[eric@centos7min2 cspj-server]$ docker image ls
REPOSITORY                          TAG                 IMAGE ID            CREATED             SIZE
ws3495/cspj-server                  tmp                 ae4f6b8ecf43        About an hour ago   141MB
127.0.0.1:5000/ws3495/cspj-server   tmp                 ae4f6b8ecf43        About an hour ago   141MB
ws3495/cspj-server                  v1.0.0              4e56f3b72f1d        3 hours ago         137MB
ws3495/cspj-server                  v1.0.1              e5868fe7c123        6 hours ago         132MB
openjdk                             8-alpine            a3562aa0b991        4 months ago        105MB
registry                            latest              f32a97de94e1        6 months ago        25.8MB
hello-world                         latest              fce289e99eb9        9 months ago        1.84kB
prakhar1989/static-site             latest              f01030e1dcf3        3 years ago         134MB

更多搭建私有仓库的方法请参看私有仓库

8. 容器集群

一个container(容器)只作一件事情,一个container中只运行一个程序。若是咱们的应用由好几个部分组成,应该如何把它们组织到一块儿呢?好比一个应用能够分为server(逻辑处理)、db(数据库操做)、monitor(监控)等几部分,通常会把这几部分分别制做成镜像,启动到不一样的container中。怎么把它们组成一个完整的能够对外提供服务的应用呢?若是须要多个应用,如何进行负载均衡呢?

这里就要用到集群管理。Docker自带一个集群管理工具Swarm(蜂群),使用它能够解决咱们刚才提出的问题。

使用Swarm,先要明确与之相关的一些概念:

  • node: swarm集群中每个运行了docker服务的机器(虚拟机或物理机),都被称为node。参看第3节
  • container: 这个咱们已经知道了,就是容器,是经过镜像(image)运行起来的。swarm以外运行的container随时能够加入到swarm中,成为一个task
  • task: 简单来讲,在swarm集群中,每一个运行中的container就是一个task
  • service: 一个应用的不一样部分被称为service。service中能够有多个task正在运行
  • stack: 一些相互关联的service一块儿对外提供服务,就构成了一个stack。例如页面service和数据库service组合在一块儿才能让用户使用,这就是一个stack

docker命令中的nodeservicestack指令,都必须在swarm集群环境下使用。

8.1 负载均衡

咱们前面建立了ws3495/cspj-server:tmp镜像。它对外提供一个服务,对任意发送到18000端口的请求,返回一个容器的IP地址。IDE工具能够用RMI方式链接到这个容器,对容器的数据进行操做。

如今须要实现对这个服务的负载均衡。咱们须要根据这个镜像启动多个容器,让它们共同对外提供更加稳定可靠的服务。

8.1.1 建立compose文件

在任意位置建立一个compose文件 docker-compose.yml:

version: "3"
services:
  server:
    image: ws3495/cspj-server:tmp
    deploy:
      replicas: 2
      resources:
        limits:
          cpus: "0.5"
          memory: 1024M 
      restart_policy:
        condition: on-failure
    ports:
      # <host port> : <container port>
      - "27449:27449"
      - "27450:27450"
      - "18000:18000"
    networks:
      - cspjnet
networks:
  cspjnet:
  • services: services下的每一项都是一个service
  • server: 咱们把cspj程序提供的service叫作server
  • image: 根据哪一个镜像启动容器
  • replicas: 启动2个容器。启动后,每一个容器都是一个task,它们共同组成了一个service(名字叫作server)
  • limits: 限制每一个容器的CPU和内存使用率
  • restart_policy: 失败后当即重启
  • ports: 端口映射,左侧是宿主机的端口,右侧是容器的端口
  • networks: 为这几个容器新建的虚拟网络(默认设置,即load-balanced overlay network)

8.1.2 初始化swarm

swarm中的节点(node)分为manager和worker。咱们须要初始化一个manager,而后把其它节点做为worker加入进来。这里咱们只有一个机器(CentOS-7),因此咱们只建立一个manager节点。

执行命令docker swarm init --advertise-addr 192.168.56.104建立manager节点:

[eric@centos7min2 swarm]$ docker swarm init --advertise-addr 192.168.56.104
Swarm initialized: current node (eby778btfq9hvpzn62gnnv5ux) is now a manager.

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

    docker swarm join --token SWMTKN-1-4famuxyeqheaiiip2rp2vyk7fuq5v4csvn4432w2czbm7ctov2-6yjw4idxlrdy4vjbknd4d1gdg 192.168.56.104:2377

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

这个命令会建立几个network,用于集群管理。ingress和none就是swarm在这个节点上建立的,docker_gwbridge可能也是:

[eric@centos7min2 swarm]$ docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
015532cb540e        bridge              bridge              local
a4025c27d82d        docker_gwbridge     bridge              local
20ce1819213b        host                host                local
5fnz5sfhkka7        ingress             overlay             swarm
ec1e8f535e07        none                null                local

能够执行一些检查,看一看这个节点如今的状态:

# swarm中只有一个节点,而且是manager
[eric@centos7min2 swarm]$ docker node ls
ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS      ENGINE VERSION
eby778btfq9hvpzn62gnnv5ux *   centos7min2         Ready               Active              Leader              19.03.2

# 尚未stack
[eric@centos7min2 swarm]$ docker stack ls
NAME                SERVICES            ORCHESTRATOR

# 也没有service
[eric@centos7min2 swarm]$ docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE               PORTS

8.1.3 部署并启动应用

执行命令docker stack deploy -c docker-compose.yml cspj,swarm就能够根据docker-compose.yml文件中的配置,自动部署并启动应用。咱们给这个stack命名为cspj。

# 部署应用。会根据yml文件中的设置,建立虚拟网络cspj_cspjnet,使用ws3495/cspj-server:tmp镜像启动一个服务cspj_server
[eric@centos7min2 swarm]$ docker stack deploy -c docker-compose.yml cspj
Creating network cspj_cspjnet
Creating service cspj_server

# swarm又新建了一个cspj_cspjnet的虚拟网络
[eric@centos7min2 swarm]$ docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
015532cb540e        bridge              bridge              local
d5a7fdih7h92        cspj_cspjnet        overlay             swarm
a4025c27d82d        docker_gwbridge     bridge              local
20ce1819213b        host                host                local
5fnz5sfhkka7        ingress             overlay             swarm
ec1e8f535e07        none                null                local

# 查看全部stack。如今只有1个,名字叫cspj,里面有1个service
[eric@centos7min2 swarm]$ docker stack ls
NAME                SERVICES            ORCHESTRATOR
cspj                1                   Swarm

# 查看全部service。输出信息代表cspj_server这个service中有两个task(REPLICAS),而且都已经启动了
[eric@centos7min2 swarm]$ docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE                    PORTS
uq82928el14d        cspj_server         replicated          2/2                 ws3495/cspj-server:tmp   *:18000->18000/tcp, *:27449-27450->27449-27450/tcp

# 查看cspj_server这个service中的task。swarm自动为每一个task进行了编号
[eric@centos7min2 swarm]$ docker service ps cspj_server
ID                  NAME                IMAGE                    NODE                DESIRED STATE       CURRENT STATE           ERROR               PORTS
j7kjtj81re1o        cspj_server.1       ws3495/cspj-server:tmp   centos7min2         Running             Running 5 minutes ago                       
1elk64sfezfo        cspj_server.2       ws3495/cspj-server:tmp   centos7min2         Running             Running 5 minutes ago                       

# 按照普通方式查看container,发现ID和service ps中显示的ID不同。为何?
[eric@centos7min2 swarm]$ docker ps 
CONTAINER ID        IMAGE                    COMMAND                  CREATED             STATUS              PORTS                    NAMES
8d9f67c15cb6        ws3495/cspj-server:tmp   "./startServer.sh"       21 minutes ago      Up 21 minutes       27449-27450/tcp          cspj_server.2.1elk64sfezfoql0ex1njwjlnp
dee88b746baf        ws3495/cspj-server:tmp   "./startServer.sh"       21 minutes ago      Up 21 minutes       27449-27450/tcp          cspj_server.1.j7kjtj81re1o1ge5anwnlmzka
821497a16886        registry                 "/entrypoint.sh /etc…"   24 hours ago        Up 24 hours         0.0.0.0:5000->5000/tcp   registry

在Windows 10上,向CentOS-7的18000端口发送数据,能够看到负载均衡的效果:

send message and receive ip

IDE也能够正常链接。

8.1.4 关闭应用并恢复

使用docker stack rm cspj关闭并移除cspj这个task

# 关闭stack
[eric@centos7min2 swarm]$ docker stack rm cspj
Removing service cspj_server
Removing network cspj_cspjnet

# stack已被移除
[eric@centos7min2 swarm]$ docker stack ls
NAME                SERVICES            ORCHESTRATOR

# service已被移除
[eric@centos7min2 swarm]$ docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE               PORTS

# cspj_cspjnet已被移除
[eric@centos7min2 swarm]$ docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
015532cb540e        bridge              bridge              local
a4025c27d82d        docker_gwbridge     bridge              local
20ce1819213b        host                host                local
5fnz5sfhkka7        ingress             overlay             swarm
ec1e8f535e07        none                null                local

# task已被关闭并移除
[eric@centos7min2 swarm]$ docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
821497a16886        registry            "/entrypoint.sh /etc…"   24 hours ago        Up 24 hours         0.0.0.0:5000->5000/tcp   registry

使用命令docker swarm leave --force移除swarm集群(即把最后一个node从swarm集群中移除掉)。以后,docker node, docker stack, docker service这些命令就不可用了:

# 关闭swarm
[eric@centos7min2 compose]$ docker swarm leave --force
Node left the swarm.

8.2 多个node多个servcie

本节使用docker-machine工具建立多个虚拟docker node,并把它们都用swarm组织成一个集群。同时,咱们再在docker-compose.yml文件中添加一个service,使多个service共同工做。操做平台是CentOS-7。docker-machine能够彻底独立使用,没必要同时安装docker,docker-machine建立的虚拟机中就有docker服务。

因为docker-machine建立虚拟机须要先安装virtualbox,而目前版本的virtualbox(6.0)仅能在AMD的CPU上支持嵌套的虚拟机,因此在本节中咱们使用vmware workstation pro 15(有30天免费试用期,或者使用vmware workstation palyer),在这个虚拟机上安装CentOS-7,而后再在CentOS-7上安装docker-machine,docker-machine再建立基于virtualbox的虚拟机。

新搭建的CentOS-7系统的IP地址是192.168.154.100.

8.2.1 安装docker-machine

docker-machine能够快速部署带有docker服务的虚拟机。

在CentOS-7上使用docker-machine须要先安装virtual-box。新建/etc/yum.repos.d/virtualbox.repo文件,内容以下:

[virtualbox]
name=Oracle Linux / RHEL / CentOS-$releasever / $basearch - VirtualBox
baseurl=http://download.virtualbox.org/virtualbox/rpm/el/$releasever/$basearch
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://www.virtualbox.org/download/oracle_vbox.asc

而后执行以下命令安装virtualbox。安装成功以后,执行sudo systemctl status vboxdrv,能够查看virtualbox的状态:

  • sudo yum update,会更新全部软件,能够不执行。若是执行,需在执行后重启系统
  • yum install -y kernel-devel kernel-headers gcc make perl,以后完后可能须要重启系统
  • sudo yum install VirtualBox-6.0
[eric@vmwmin1 ~]$ sudo systemctl status vboxdrv
● vboxdrv.service - VirtualBox Linux kernel module
   Loaded: loaded (/usr/lib/virtualbox/vboxdrv.sh; enabled; vendor preset: disabled)
   Active: active (exited) since Wed 2019-10-02 00:23:22 CST; 23min ago
  Process: 822 ExecStart=/usr/lib/virtualbox/vboxdrv.sh start (code=exited, status=0/SUCCESS)

Oct 02 00:19:51 vmwmin1 systemd[1]: Starting VirtualBox Linux kernel module...
Oct 02 00:19:54 vmwmin1 vboxdrv.sh[822]: vboxdrv.sh: Starting VirtualBox services.
Oct 02 00:19:54 vmwmin1 vboxdrv.sh[855]: Starting VirtualBox services.
Oct 02 00:19:54 vmwmin1 vboxdrv.sh[822]: vboxdrv.sh: Building VirtualBox kernel modules.
Oct 02 00:19:54 vmwmin1 vboxdrv.sh[860]: Building VirtualBox kernel modules.
Oct 02 00:23:22 vmwmin1 systemd[1]: Started VirtualBox Linux kernel module.

安装docker-machine:

$ base=https://github.com/docker/machine/releases/download/v0.16.0 &&
  curl -L $base/docker-machine-$(uname -s)-$(uname -m) >/tmp/docker-machine &&
  sudo mv /tmp/docker-machine /usr/local/bin/docker-machine &&
  chmod +x /usr/local/bin/docker-machine

安装成功后,执行docker-machine ls,能够看到还不存在由docker-machine建立的虚拟机。

8.2.2 建立虚拟机(两个node)

使用docker-machine create --driver virtualbox <vm-name>能够直接建立带有docker服务的虚拟机,没必要事先安装docker。这里咱们建立两个虚拟机,分别为myvm1myvm2:

# 建立myvm1,因为是第一次执行,会从github上下载一些文件
[eric@vmwmin1 ~]$ docker-machine create --driver virtualbox myvm1
Running pre-create checks...
(myvm1) Image cache directory does not exist, creating it at /home/eric/.docker/machine/cache...
(myvm1) No default Boot2Docker ISO found locally, downloading the latest release...
(myvm1) Latest release for github.com/boot2docker/boot2docker is v18.09.9
(myvm1) Downloading /home/eric/.docker/machine/cache/boot2docker.iso from https://github.com/boot2docker/boot2docker/releases/download/v18.09.9/boot2docker.iso...
(myvm1) 0%....10%....20%....30%....40%....50%....60%....70%....80%....90%....100%
Creating machine...
(myvm1) Copying /home/eric/.docker/machine/cache/boot2docker.iso to /home/eric/.docker/machine/machines/myvm1/boot2docker.iso...
(myvm1) Creating VirtualBox VM...
(myvm1) Creating SSH key...
(myvm1) Starting the VM...
(myvm1) Check network to re-create if needed...
(myvm1) Found a new host-only adapter: "vboxnet0"
(myvm1) Waiting for an IP...
Waiting for machine to be running, this may take a few minutes...
Detecting operating system of created instance...
Waiting for SSH to be available...
Detecting the provisioner...
Provisioning with boot2docker...
Copying certs to the local machine directory...
Copying certs to the remote machine...
Setting Docker configuration on the remote daemon...
Checking connection to Docker...
Docker is up and running!
To see how to connect your Docker Client to the Docker Engine running on this virtual machine, run: docker-machine env myvm1

# 建立myvm2,省略了一些输出内容
[eric@vmwmin1 ~]$ docker-machine create --driver virtualbox myvm2
...
Docker is up and running!
To see how to connect your Docker Client to the Docker Engine running on this virtual machine, run: docker-machine env myvm2

# 查看这两个虚拟机
[eric@vmwmin1 ~]$ docker-machine ls
NAME    ACTIVE   DRIVER       STATE     URL                         SWARM   DOCKER     ERRORS
myvm1   -        virtualbox   Running   tcp://192.168.99.100:2376           v18.09.9   
myvm2   -        virtualbox   Running   tcp://192.168.99.101:2376           v18.09.9

8.2.3 配置http方式访问私有仓库

本文开始时咱们使用的CentOS-7系统的地址是192.168.56.104,咱们在这个CentOS-7系统上使用docker搭建个了一个私有仓库。如今咱们又使用vmware新搭建了一个CentOS-7系统,其地址是192.168.154.100,在这个系统上使用docker-machine建立了两个虚拟机myvm1和myvm2。咱们须要使myvm1和myvm2能够访问这个私有仓库,因此须要对myvm1和myvm2进行一些配置,使其能够以不安全的方式访问私有仓库。

经过执行命令docker-machine scp <filename> <your-machine-name>:<path>会把文件拷贝到对应的虚拟机中。

经过执行命令docker-machine ssh <your-machine-name> "<your-docker-command>"能够直接在虚拟机中执行命令。若是省略""中的内容,就能够以ssh方式链接到虚拟机中。

在docker-machine所在的CentOS-7系统上,在任意位置新建一个文件daemon.json,内容为:

{
  "insecure-registries": [
    "192.168.56.104:5000"
  ]
}

192.168.56.104是私有仓库所在的地址。

把这个文件拷贝到myvm1和myvm2的/etc/docker/目录下:

# 拷贝文件
$ docker-machine scp daemon.json myvm1:~
$ docker-machine scp daemon.json myvm2:~
$ docker-machine ssh myvm1 "sudo mv daemon.json /etc/docker/"
$ docker-machine ssh myvm2 "sudo mv daemon.json /etc/docker/"

# 重启
[eric@vmwmin1 ~]$ docker-machine restart myvm1 myvm2
Restarting "myvm2"...
Restarting "myvm1"...
(myvm2) Check network to re-create if needed...
(myvm2) Waiting for an IP...
Waiting for SSH to be available...
(myvm1) Check network to re-create if needed...
(myvm1) Waiting for an IP...
Waiting for SSH to be available...
Detecting the provisioner...
Detecting the provisioner...
Restarted machines may have new IP addresses. You may need to re-run the `docker-machine env` command.

# 查看重启后状态
[eric@vmwmin1 ~]$ docker-machine ls
NAME    ACTIVE   DRIVER       STATE     URL                         SWARM   DOCKER     ERRORS
myvm1   -        virtualbox   Running   tcp://192.168.99.102:2376           v18.09.9   
myvm2   -        virtualbox   Running   tcp://192.168.99.103:2376           v18.09.9

配置好daemon.json以后,myvm1和myvm2就能够以不安全的方式(HTTP)访问私有仓库了。

8.2.4 配置swarm集群

使用swarm命令,把这两个节点加入到swarm集群中:

# 初始化myvm1,会自动设置myvm1为manager
[eric@vmwmin1 ~]$ docker-machine ssh myvm1 "docker swarm init --advertise-addr 192.168.99.102"
Swarm initialized: current node (tjpk0hxlhij9v77yh30ehnzkg) is now a manager.

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

    docker swarm join --token SWMTKN-1-11sad8xx5hp9tyt9oed3gdgzx9ma7lfkk2chm0l8hi3mc0we2s-0bjuixv1bpsvryjsizppfr7bz 192.168.99.102:2377

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

# 根据上一个输出的提示,把myvm2加入到swarm中
[eric@vmwmin1 ~]$ docker-machine ssh myvm2 "docker swarm join --token SWMTKN-1-11sad8xx5hp9tyt9oed3gdgzx9ma7lfkk2chm0l8hi3mc0we2s-0bjuixv1bpsvryjsizppfr7bz 192.168.99.102:2377"
This node joined a swarm as a worker.

# 查看swarm中的节点,*标记的myvm1是manager
[eric@vmwmin1 ~]$ docker-machine ssh myvm1 "docker node ls"
ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS      ENGINE VERSION
tjpk0hxlhij9v77yh30ehnzkg *   myvm1               Ready               Active              Leader              18.09.9
w46api0hvap58ghhe3spdd9i7     myvm2               Ready               Active                                  18.09.9

8.2.5 两个service

新建一个docker-compose2.yml,其内容为:

version: "3"
services:
  server:
    image: 192.168.56.104:5000/ws3495/cspj-server:tmp
    deploy:
      replicas: 2
      resources:
        limits:
          cpus: "0.5"
          memory: 1024M 
      restart_policy:
        condition: on-failure
    ports:
      # <host port> : <container port>
      - "27449:27449"
      - "27450:27450"
      - "18000:18000"
    networks:
      - cspjnet
  visualizer:
    image: 192.168.56.104:5000/dockersamples/visualizer:stable
    ports:
      - "8080:8080"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock"
    deploy:
      placement:
        constraints: [node.role == manager]
    networks:
      - cspjnet
networks:
  cspjnet:

这个compose文件中有两个service,一个是咱们的java应用server;另外一个是visualizer,这是一个能够经过浏览器观察swarm节点状态的镜像。咱们已经提早把它们push到私有仓库了(visualizer镜像也能够直接从Docker Hub中获取)。

把这个compose文件拷贝到myvm1上(必须是manager节点,不能是worker节点),就能够部署了:

# 把docker-compose2.yml拷贝到myvm1的~目录下
[eric@vmwmin1 ~]$ docker-machine scp docker-compose2.yml myvm1:~
docker-compose2.yml                             100%  693   405.5KB/s   00:00    

# 向myvm1虚拟机发送指令,进行service部署
[eric@vmwmin1 ~]$ docker-machine ssh myvm1 "docker stack deploy -c docker-compose2.yml cspj"
Creating network cspj_cspjnet
Creating service cspj_server
Creating service cspj_visualizer

# 查看新部署的stack
[eric@vmwmin1 ~]$ docker-machine ssh myvm1 "docker stack ls"
NAME                SERVICES            ORCHESTRATOR
cspj                2                   Swarm

# 查看新部署的service,能够看到如今是部署并启动了2个service,其中cspj_server启动了2份,cspj_visualizer启动了1份
[eric@vmwmin1 ~]$ docker-machine ssh myvm1 "docker service ls"
ID                  NAME                MODE                REPLICAS            IMAGE                                                 PORTS
lo86uqnj2unu        cspj_server         replicated          2/2                 192.168.56.104:5000/ws3495/cspj-server:tmp            *:18000->18000/tcp, *:27449-27450->27449-27450/tcp
89d5hype8ert        cspj_visualizer     replicated          1/1                 192.168.56.104:5000/dockersamples/visualizer:stable   *:8080->8080/tcp

# CentOS-7系统上(192.168.154.100),全部发送到8080端口的数据包都会被转发到myvm1(192.168.99.102)的8080端口
[eric@vmwmin1 ~]$ sudo firewall-cmd --list-forward-ports
port=8080:proto=tcp:toport=:toaddr=192.168.99.102
port=18000:proto=tcp:toport=:toaddr=192.168.99.102
port=27449:proto=tcp:toport=:toaddr=192.168.99.102
port=27450:proto=tcp:toport=:toaddr=192.168.99.102

使用浏览器链接http://192.168.154.100:8080/,能够看到swarm中节点和service的状态:

visualizer

8.2.6 清理

经过使用命令docker-machine ssh myvm1 "docker stack rm cspj"关闭并删除cspj这个stack,会同时中止并删除server和visualizer这两个service,会同时中止并删除cspj_server.1, cspj_server.2, cspj_visualizer这3个docker容器。

经过使用命令docker-machine stop myvm1 myvm2docker-machine rm myvm1 myvm2中止并删除这两个虚拟机。

8.2.7 简化指令

执行docker-machine env myvm1,按照其输出结果的提示,执行eval $(docker-machine env myvm1),能够把myvm1设置为active。此时能够在CentOS-7系统上直接执行docker命令即会向myvm1发送执行,而没必要经过docker-machine ssh myvm1 "<command>"向myvm1发送指令了。有兴趣能够自行尝试。

9. 总结

docker为应用部署提供了极大方便,镜像设置好以后,能够在任何地方快速部署,保证同样的执行效果。docker的镜像尽可能把每一个功能拆分出来,使多个镜像组成stack共同对外提供服务。若是须要数据持久化,可使用volume功能把数据存储在宿主机上。volume功能也能够在多个service之间共享存储数据。

docker-machine提供了便捷搭建虚拟机,便捷管理虚拟机的能力,使得集群的管理更加方便。

docker中还有不少地方值得探索,好比如何使用config设置配置文件,如何搭建HTTPS方式的私有仓库,kubernetes和swarm的比较,docker的底层工做机制是如何实现的。后续会进一步对这些内容进行分析。

参考文档

相关文章
相关标签/搜索