Docker 介绍
Docker的特性:
- 文件系统隔离:每个进程容器运行在一个完全独立的根文件系统里。
- 资源隔离:系统资源,像CPU和内存等可以分配到不同的容器中,使用cgroup。
- 网络隔离:每个进程容器运行在自己的网络空间,虚拟接口和IP地址。
- 日志记录:Docker将会收集和记录每个进程容器的标准流(stdout/stderr/stdin),用于实时检索或批量检索。
- 变更管理:容器文件系统的变更可以提交到新的映像中,并可重复使用以创建更多的容器。无需使用模板或手动配置。
- 交互式shell:Docker可以分配一个虚拟终端并关联到任何容器的标准输入上
为啥要用Docker / Docker的优势在哪
Docker提供了一种打包(镜像)标准,一个打好的镜像,可以在任意机器上的任意环境运行,降低了“在我这儿好使啊”这种纷争。
比如我们一个普通的java应用部署, 需要告诉运维机器要安装jdk, 版本要是7+, 要安装tomcat, 版本是7+, 然后才是部署我们的war包。
如果有什么特殊的启动参数, 最后启动的时候还要告诉运维启动命令要加哪些参数。 这样部署起来非常复杂, 以后服务要迁移也很麻烦。
那么Docker怎么解决这个问题?
答案很简单, Docker把所有依赖的环境都封装成一个包, 连启动命令都封装好了!一个镜像的构成如下所示:
docker的镜像跟virtualbox或者vmware的镜像不一样。在虚拟机中,镜像是一个系统的完整体,包括了系统、用户在上面做的操作等等。而在docker中,镜像是一组文件的分层叠加。
Docker安装
版本要求
以Ubuntu系统为例子(其他系统的安装方法见官方文档), 推荐的Ubuntu版本如下:
- Yakkety 16.10
- Xenial 16.04 (LTS)
- Trusty 14.04 (LTS)
当然不是这些版本应该也可以, 根据以往经验, 内核版本在3.10以上的应该都可以(本次未测试)。
安装方式
- 使用docker资源库安装, 这是比较简单也是推荐的方式。
- 下载DEB包, 手动安装
使用Docker资源库安装
-
安装支持资源库的https包(一般默认已经安装了):
sudo apt-get install apt-transport-https ca-certificates
-
安装Docker的GPG key:
curl -fsSL https://yum.dockerproject.org/gpg | sudo apt-key add -
-
添加Docker的stable资源库:
sudo add-apt-repository \ "deb https://apt.dockerproject.org/repo/ \ ubuntu-$(lsb_release -cs) \ main"
-
更新资源库:
sudo apt-get update -y
-
安装Docker Engine:
sudo apt-get install -y docker-engine
-
安装完成后, 验证一下安装:
sudo docker ps adam@adam-host:~$ sudo docker ps [sudo] password for adam: CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
至此, Docker就已经安装成功了.
Docker 简单使用
常见的应用都已经有了docker镜像, 所有的开放镜像都存在于Docker镜像仓库, 可以使用docker快速启动而无需安装, 比如要运行一个redis,
只需要一条命令:
docker run --name redis -d -p 6379:6379 redis
就可以启动redis实例,用telnet
就可以连接上此redis.
搜索镜像
上面说到了Docker的一个镜像仓库, 那么应该怎么使用这个仓库呢? 比如我要看一下Elasticsearch镜像有没有, 怎么搜索?
搜索镜像有两种办法:
-
第一种直接登录Docker镜像仓库网站搜索, 还可以看到镜像的具体使用方法。
-
第二种办法, 使用docker命令搜索:
docker search elasticsearch
输出类似于:
NAME DESCRIPTION STARS OFFICIAL AUTOMATED elasticsearch Elasticsearch is a powerful open source se... 1974 [OK] itzg/elasticsearch Provides an easily configurable Elasticsea... 42 [OK] nshou/elasticsearch-kibana Elasticsearch-5.1.1 Kibana-5.1.1 19 [OK]
有
NAME
镜像名,DESCRIPTION
描述信息,STARS
收藏数,OFFICIAL
是否官方 等信息 .
这里比较推荐第一中方法, 因为单单拿到了镜像可能还不知道怎么使用, 启动镜像需要哪些参数等信息。
Dockerfile
从上面redis的例子可以看出,使用docker非常方便, 无需安装redis只要拉取镜像即可使用。 那么我们如何把自己的程序打成一个镜像呢?
答案就是Dockerfile:
Dockerfile是一个描述镜像如何构建的文本文件, 这个文件里包含了顺序执行的一系列docker命令。Docker可以根据里面的命令自动的去构建一个镜像。
这里先用一个例子简单介绍一下, 可以有个直观的感受:
FROM java:8-jdk
MAINTAINER pengfw.wu@qunar.com
RUN rm /etc/localtime \
&& cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
&& echo "Asia/Shanghai" > /etc/timezone \
&& dpkg-reconfigure -f noninteractive tzdata \
&& mkdir /boot-demo \
&& export LANG=en_US.UTF-8 \
&& export LANGUAGE=en_US:en
WORKDIR /boot-demo
ENV LANG=en_US.UTF-8 LANGUAGE=en_US:en PROFILE=release \
JAVA_OPTS="-Xmx2048m -Xms1024m -XX:+UseConcMarkSweepGC"
EXPOSE 9090
VOLUME /boot-demo/log
COPY ./boot-demo-1.7-SNAPSHOT-boot.jar boot-demo-1.7-SNAPSHOT-boot.jar
ENTRYPOINT java -server -jar -Dspring.profiles.active=$PROFILE $JAVA_OPTS boot-demo-1.7-SNAPSHOT-boot.jar
FROM
关键字用来表示使用哪个父镜像。 前面我们说了镜像中的文件其实是分层组织的。一般应用的镜像都有一个父镜像,是建立在父镜像之上的。 而没有父镜像的被称为基础镜像。
关于基础镜像如何构建这里就不多说了, 感兴趣的可以参考 这篇官方文档
MAINTAINER
用来指明维护人的信息
RUN
关键字用来执行一些shell命令, 此关键字会在新的一层上执行后面的命令, 然后提交结果。 RUN
有两种形式 : RUN <command>
shell形式 以及
RUN ["executable", "param1", "param2"]
。 这里解释一下为什么要把多条命令写在一个RUN
关键字里面, 因为每个RUN命令都会生成一层新的文件, 会增加最终镜像的大小,
所以这么做一是为了减少镜像大小,二是为了可读性可维护性。
WORKDIR
为后面的命令比如RUN
, ENTRYPOINT
, COPY
等命令设置工作目录。 如果此目录不存在, 则会自动创建。
ENV
用于设置环境变量, 后面的命令可以使用$
引用环境变量。 在启动镜像的时候, 可以在命令行设置环境变量的值。
COPY
用于将文件或者目录复制到镜像的文件系统中。
ENTRYPOINT
用于设置镜像的入口, 就是在执行docker run
命令的时候, 实际启动的镜像内部程序的命令.
有了Dockerfile, 我们只需要执行docker build -t <imagename> -f <dockerfile-path>
即可构建镜像.
关于Dockerfile的命令以及详细使用方法参考Dockerfile reference
以及 dockerfile_best-practices。
Container
Container
就是所谓的容器, 它本质上是镜像的运行状态的一个实例。 容器有以下几种常用操作:
启动
使用docker run
命令可以启动一个容器。 类似上面启动的redis
adam@adam-host:~$ docker run --name redis -d -p 6379:6379 redis
dff7830910eb086cb2d29b695bf485189d81e4598d15e13d557f7c6404e5432a
以交互式方式运行容器
adam@adam-host:~$ docker run -it --rm ubuntu /bin/bash
root@7d5eb8f0eb24:/#
root@7d5eb8f0eb24:/# echo hello world
hello world
root@7d5eb8f0eb24:/# exit
查看所有容器
使用docker ps
可以看到正在运行的容器, docker ps -a
可以看到所有的容器.
adam@adam-host:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
dff7830910eb redis "docker-entrypoint..." 36 seconds ago Up 35 seconds 0.0.0.0:6379->6379/tcp redis
停止
使用docker stop <container-name/container-id>
可以停止一个运行的容器
docker stop redis
重启
使用docker restart <container-name/container-id>
可以重启一个容器
docker restart redis
删除
使用docker rm <container-name/container-id>
可以删除一个已经停止的容器
docker rm redis
进入容器内部
使用docker exec
命令可以进入容器的交互式窗口
adam@adam-host:~$ docker exec -it redis /bin/bash
root@dff7830910eb:/data# cat /etc/issue
Debian GNU/Linux 8 \n \l
root@dff7830910eb:/data#
Docker图形化管理工具
shipyard 与 portainer(原dockerui)
以portainer为例:
docker run -d -p 9000:9000 --name dokcerui -v /var/run/docker.sock:/var/run/docker.sock portainer/portainer
访问 localhost:9000
即可。
Swarm && 集群
Swarm是docker的一个集群管理工具, 最开始swarm是单独一个镜像, 现在已经嵌入到了docker-engine里面。 我们简单看一下如何创建docker集群。
要创建一个swarm集群, 我们需要三台机器, 一台做manager管理节点, 另外的做从节点。 当然前提是这三个节点是互通的。这里我使用三个虚拟机adam-host, adam-host1, adam-host2
使用swarm创建集群
-
使用
docker swarm init
可以初始化一个集群。 首先, 登录一台想作为管理节点的机器,这里选择adam-host, 在上面执行:adam@adam-host:~$ docker swarm init Error response from daemon: could not choose an IP address to advertise since this system has multiple addresses on different interfaces (10.0.2.15 on enp0s3 and 192.168.1.4 on enp0s8) - specify one with --advertise-addr
这里报了一个错, 说我们机器上有多个ip, 要手动指定一个作为其他节点连接的ip。
看一下:
adam@adam-host:~$ ip addr 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 inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 link/ether 08:00:27:9c:86:8a brd ff:ff:ff:ff:ff:ff inet 10.0.2.15/8 brd 10.255.255.255 scope global enp0s3 valid_lft forever preferred_lft forever inet6 fe80::a00:27ff:fe9c:868a/64 scope link valid_lft forever preferred_lft forever 3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 link/ether 08:00:27:34:9e:50 brd ff:ff:ff:ff:ff:ff inet 192.168.1.4/24 brd 192.168.1.255 scope global enp0s8 valid_lft forever preferred_lft forever inet6 fe80::a00:27ff:fe34:9e50/64 scope link valid_lft forever preferred_lft forever 4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default link/ether 02:42:0b:af:23:21 brd ff:ff:ff:ff:ff:ff inet 172.17.0.1/16 scope global docker0 valid_lft forever preferred_lft forever inet6 fe80::42:bff:feaf:2321/64 scope link valid_lft forever preferred_lft forever 9: docker_gwbridge: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default link/ether 02:42:c9:7d:07:66 brd ff:ff:ff:ff:ff:ff inet 172.18.0.1/16 scope global docker_gwbridge valid_lft forever preferred_lft forever inet6 fe80::42:c9ff:fe7d:766/64 scope link valid_lft forever preferred_lft forever
这里确实配置了两个IP, 其中192.168.1.4是内网IP, 我们把这个指定为swarm管理节点的IP:
adam@adam-host:~$ docker swarm init --advertise-addr 192.168.1.4 Swarm initialized: current node (qvsktm9hcc59tg66t369wb63r) is now a manager. To add a worker to this swarm, run the following command: docker swarm join \ --token SWMTKN-1-4fmyk4dm7qbnt87bp8gfh3scp1szfyrmm4x3zmb390a3ooh1tp-12mixtt7bpul8l2vjzcbka7u5 \ 192.168.1.4:2377 To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions. adam@adam-host:~$
我们可以看到输出:
docker swarm join \ --token SWMTKN-1-4fmyk4dm7qbnt87bp8gfh3scp1szfyrmm4x3zmb390a3ooh1tp-12mixtt7bpul8l2vjzcbka7u5 \ 192.168.1.4:2377
在剩余的两个节点上面执行这个命令即可加入集群。 在adam-host2上面:adam@adam-host2:~$ docker swarm join \ > --token SWMTKN-1-4fmyk4dm7qbnt87bp8gfh3scp1szfyrmm4x3zmb390a3ooh1tp-12mixtt7bpul8l2vjzcbka7u5 \ > 192.168.1.4:2377 This node joined a swarm as a worker.
最后一台机器adam-host3
adam@adam-host3:~$ docker swarm join \ > --token SWMTKN-1-4fmyk4dm7qbnt87bp8gfh3scp1szfyrmm4x3zmb390a3ooh1tp-12mixtt7bpul8l2vjzcbka7u5 \ > 192.168.1.4:2377 This node joined a swarm as a worker. adam@adam-host3:~$
剩余两个几点成功加入了集群。 现在返回到管理节点adam-host上面, 看一下集群中的节点:
adam@adam-host:~$ docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS n55kjb6mn2u8g2lkcrt03gu0t adam-host2 Ready Active qvsktm9hcc59tg66t369wb63r * adam-host Ready Active Leader zdd201qxmgwnqtrzq60ft6prj adam-host3 Ready Active adam@adam-host:~$
可以看到有三个节点, 其中一个节点正是自己, 是管理节点的角色。
管理集群中的节点:
-
查看集群中的节点, 上面已经说了是
docker node ls
命令:adam@adam-host:~$ docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS n55kjb6mn2u8g2lkcrt03gu0t adam-host2 Ready Active qvsktm9hcc59tg66t369wb63r * adam-host Ready Active Leader zdd201qxmgwnqtrzq60ft6prj adam-host3 Ready Active adam@adam-host:~$
上面的结果中,
AVAILABILITY
共有一下几种取值:Active
表示此节点可以接受分配新任务Pause
表示此节点再接受新任务, 但是已经分配给它的任务会继续执行Drain
表示此节点不再接受新任务, 同时已经分配的任务也不再执行,而是由调度器分发到其他可用的节点上。
MANAGER STATUS
这一列共有以下几种取值:空值
表示此节点不参与swarm的管理Leader
表示此节点是目前的管理节点Reachable
表示此节点备用管理节点, 当Leader
的管理节点失效之后, 此节点可以参与选举, 并可能被选为Leader
节点Unavailable
表示此节点无法与其他管理节点通讯, 这种情况下, 当Leader
节点不可用之后, 需要新加入一个管理节点或者把工作节点提升为管理节点。
-
查看节点详细信息:
docker node inspect
adam@adam-host:~$ docker node inspect adam-host2 [ { "ID": "n55kjb6mn2u8g2lkcrt03gu0t", "Version": { "Index": 15 }, "CreatedAt": "2017-02-04T05:53:51.114898465Z", "UpdatedAt": "2017-02-04T05:53:51.237011222Z", "Spec": { "Role": "worker", "Availability": "active" }, "Description": { "Hostname": "adam-host2", "Platform": { "Architecture": "x86_64", "OS": "linux" }, "Resources": { "NanoCPUs": 1000000000, "MemoryBytes": 2097512448 }, "Engine": { "EngineVersion": "1.13.0", "Plugins": [ { "Type": "Network", "Name": "bridge" }, { "Type": "Network", "Name": "host" }, { "Type": "Network", "Name": "macvlan" }, { "Type": "Network", "Name": "null" }, { "Type": "Network", "Name": "overlay" }, { "Type": "Volume", "Name": "local" } ] } }, "Status": { "State": "ready", "Addr": "192.168.1.5" } } ]
-
更新节点
我们可以更新节点的可用状态、 增加或删除节点的标签数据、 改变节点的角色等操作。
-
修改节点可用状态:
上面我们说了每个节点都有Active
,Pause
,Drain
这三个状态, 我们可以手动修改他们的状态:adam@adam-host:~$ docker node update --availability drain adam-host2 adam-host2 adam@adam-host:~$ docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS n55kjb6mn2u8g2lkcrt03gu0t adam-host2 Ready Drain qvsktm9hcc59tg66t369wb63r * adam-host Ready Active Leader zdd201qxmgwnqtrzq60ft6prj adam-host3 Ready Active
可以看到adam-host2这个节点已经是
Drain
状态了,这样其实就是把此节点下线了, 可以做一些维护操作, 接着把它改回Active
状态:adam@adam-host:~$ docker node update --availability Active adam-host2 adam-host2 adam@adam-host:~$ docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS n55kjb6mn2u8g2lkcrt03gu0t adam-host2 Ready Active qvsktm9hcc59tg66t369wb63r * adam-host Ready Active Leader zdd201qxmgwnqtrzq60ft6prj adam-host3 Ready Active
-
增加或删除标签元信息:
每个node都可以设置一些标签, 标签可以用来管理节点或者限制服务调度。使用
docker node update --label-add
命令可以添加标签,--label-add
支持key
或者key=value
这样的格式。adam@adam-host:~$ docker node update --label-add worker --label-add order=1 adam-host2 adam-host2
我们为adam-host2这个node添加了一个worker标签和order标签, 现在看一下有没有生效:
adam@adam-host:~$ docker node inspect adam-host2 [ { "ID": "n55kjb6mn2u8g2lkcrt03gu0t", "Version": { "Index": 23 }, "CreatedAt": "2017-02-04T05:53:51.114898465Z", "UpdatedAt": "2017-02-04T06:24:42.049105301Z", "Spec": { "Labels": { "order": "1", "worker": "" }, "Role": "worker", "Availability": "active" } ...
可以看到label已经添加上了。
-
将工作节点提升为管理节点:
使用docker node promote
可以提升节点角色, 此命令可以一次性提升多个节点adam@adam-host:~$ docker node promote adam-host2 adam-host3 Node adam-host2 promoted to a manager in the swarm. Node adam-host3 promoted to a manager in the swarm. adam@adam-host:~$ docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS n55kjb6mn2u8g2lkcrt03gu0t adam-host2 Ready Active Reachable qvsktm9hcc59tg66t369wb63r * adam-host Ready Active Leader zdd201qxmgwnqtrzq60ft6prj adam-host3 Ready Active Reachable
可以看到, 目前三个都是管理节点了, 只不过adam-host还是主, 其他的是备用。
-
将管理节点降低为工作节点:
类似的, 使用docker node demote
可以降node的角色:adam@adam-host:~$ docker node demote adam-host2 adam-host3 Manager adam-host2 demoted in the swarm. Manager adam-host3 demoted in the swarm. adam@adam-host:~$ adam@adam-host:~$ adam@adam-host:~$ docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS n55kjb6mn2u8g2lkcrt03gu0t adam-host2 Ready Active qvsktm9hcc59tg66t369wb63r * adam-host Ready Active Leader zdd201qxmgwnqtrzq60ft6prj adam-host3 Ready Active
-
离开集群:
如果node要离开一个swarm集群, 首先要在node节点执行:adam@adam-host2:~$ docker swarm leave Node left the swarm.
然后在manager节点执行 :
adam@adam-host2:~$ docker swarm leave Node left the swarm.
adam-host2节点就已经移除了。
-
在集群中部署服务
-
在集群中部署一个服务, 这里以redis为例:
adam@adam-host:~$ docker service create --name redis -p 6379:6379 --replicas 2 redis kdxwcqo77pnsil9fscliofo6g
上面
--name
指定服务名,--replicas
指定冗余数量,-p
指定端口映射. 更多docker service create
的参数参考docker service create我们在部署一个mysql服务:
adam@adam-host:~$ docker service create --name mysql -p 3306:3306 --env 'MYSQL_ROOT_PASSWORD=123456' --replicas 2 mysql 6oz914dv7ok6oplblqmnuqjpc
-
查看集群中服务:
adam@adam-host:~$ docker service ls ID NAME MODE REPLICAS IMAGE 6oz914dv7ok6 mysql replicated 2/2 mysql:latest kdxwcqo77pns redis replicated 2/2 redis:latest
可以看到,当前集群中有mysql redis 两个服务, 各有两个冗余, 那么这两个服务具体是怎么在节点分布的呢?
adam@adam-host:~$ docker service ps redis ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS t50gm1xp4gui redis.1 redis:latest adam-host2 Running Running 11 minutes ago 9no6uos3yrpu redis.2 redis:latest adam-host Running Running 11 minutes ago adam@adam-host:~$ adam@adam-host:~$ adam@adam-host:~$ adam@adam-host:~$ docker service ps mysql ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS e2a4s3ys0gtc mysql.1 mysql:latest adam-host3 Running Running 56 seconds ago f2majlplcc61 mysql.2 mysql:latest adam-host2 Running Running 56 seconds ago
现在我们停掉其中一个redis,比如是adam-host2上面的, 看swarm会不会再次启动一个:
adam@adam-host2:~$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES aa4b56cafbdc mysql@sha256:5e2ec5964847dd78c83410f228325a462a3bfd796b6133b2bdd590b71721fea6 "docker-entrypoint..." 3 minutes ago Up 3 minutes 3306/tcp mysql.2.f2majlplcc61ux83kc14l2hwm f8ddec77282a redis@sha256:afa4b429ef3ee08c8b198e50d684c5da0ffa43ae58631f61b08829bd6df3c500 "docker-entrypoint..." 13 minutes ago Up 13 minutes 6379/tcp redis.1.t50gm1xp4guiu90hfarcx404e b983c25a66a1 org.singledog.boot-demo "/bin/sh -c 'java ..." 3 hours ago Up 3 hours 0.0.0.0:9091->9090/tcp test adam@adam-host2:~$ docker stop f8ddec77282a f8ddec77282a
再回到管理节点看一看:
adam@adam-host:~$ docker service ls ID NAME MODE REPLICAS IMAGE kdxwcqo77pns redis replicated 2/2 redis:latest u7ckw4btv8p9 mysql replicated 2/2 mysql:latest adam@adam-host:~$ docker service ps redis ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS oit9ge9u67by redis.1 redis:latest adam-host2 Running Running 29 seconds ago t50gm1xp4gui \_ redis.1 redis:latest adam-host2 Shutdown Complete 34 seconds ago 9no6uos3yrpu redis.2 redis:latest adam-host Running Running 15 minutes ago
可以看到, swarm知道其中一个redis停了, 它再次给启动了一个实例以满足指定的2个冗余。
-
服务伸缩
上面我们说到, 可以在创建服务的时候指定服务的冗余数量, 这个数量是可以后期修改的, 就是动态扩容. 比如我们把redis扩展为3个实例:
adam@adam-host:~$ docker service scale redis=3 redis scaled to 3 adam@adam-host:~$ docker service ls ID NAME MODE REPLICAS IMAGE kdxwcqo77pns redis replicated 3/3 redis:latest u7ckw4btv8p9 mysql replicated 2/2 mysql:latest adam@adam-host:~$ docker service ps redis ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS oit9ge9u67by redis.1 redis:latest adam-host2 Running Running 4 minutes ago t50gm1xp4gui \_ redis.1 redis:latest adam-host2 Shutdown Complete 4 minutes ago 9no6uos3yrpu redis.2 redis:latest adam-host Running Running 18 minutes ago f0nbj00l3crw redis.3 redis:latest adam-host3 Running Running 38 seconds ago
可以看到redis已经扩展成了3个。 现在把它降为以1个:
adam@adam-host:~$ docker service scale redis=1 redis scaled to 1 adam@adam-host:~$ docker service ls ID NAME MODE REPLICAS IMAGE kdxwcqo77pns redis replicated 1/1 redis:latest u7ckw4btv8p9 mysql replicated 2/2 mysql:latest adam@adam-host:~$ docker service ps redis ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS 9no6uos3yrpu redis.2 redis:latest adam-host Running Running 20 minutes ago
已经降为了一个实例。
-
删除停止服务
使用
docker service rm
即可删除服务:adam@adam-host:~$ docker service rm redis redis adam@adam-host:~$ docker service ls ID NAME MODE REPLICAS IMAGE u7ckw4btv8p9 mysql replicated 2/2 mysql:latest adam@adam-host:~$ docker service ps redis Error: No such service: redis
不同的容器间通讯 && docker network
docker在多个机器之间通讯一直是一个难题, 在docker network出现之前, 比较普遍的方案是采用docker weave 这个中间件。
不过后来docker自己也意识到这个问题, 所以在docker中集成了network模块用于解决这个问题。
关于network的东西可以另写一篇文章了, 这里先不展开讲, 用一个例子来看一下如何使用overlay网络在不同容器间的通讯。
-
创建overlay 网络
adam@adam-host:~$ docker network create --driver overlay my-net txsfwempwmwc0jzzqgddcwy8i adam@adam-host:~$ docker network ls NETWORK ID NAME DRIVER SCOPE 2df627c1986e bridge bridge local 8edb29069734 docker_gwbridge bridge local 5af457014d24 host host local ay97hon0djy5 ingress overlay swarm txsfwempwmwc my-net overlay swarm 3e2f26ff5cf7 none null local
-
在swarm启动服务, 指定网络为刚刚创建的my-net:
adam@adam-host:~$ docker service create --name redis -p 6379:6379 --replicas 2 --network my-net redis 66hfjyyda36a1sjwu7ry71r4v adam@adam-host:~$ docker service ls ID NAME MODE REPLICAS IMAGE 66hfjyyda36a redis replicated 2/2 redis:latest adam@adam-host:~$ docker service create --name mysql -p 3306:3306 --env 'MYSQL_ROOT_PASSWORD=123456' --replicas 2 --network my-net mysql 3whbbl9p0hzs3bsthfn4e3pcg adam@adam-host:~$ docker service ls ID NAME MODE REPLICAS IMAGE 3whbbl9p0hzs mysql replicated 2/2 mysql:latest 66hfjyyda36a redis replicated 2/2 redis:latest
启动参数都是一样的, 除了多了
--network my-net
. -
进入到任意一个redis容器内, 执行 ping mysql 已经可以ping通了。
adam@adam-host:~$ docker exec -it b129a168cb33 /bin/bash root@b129a168cb33:/data# root@b129a168cb33:/data# ping mysql PING mysql (10.0.0.5): 56 data bytes 64 bytes from 10.0.0.5: icmp_seq=0 ttl=64 time=0.101 ms 64 bytes from 10.0.0.5: icmp_seq=1 ttl=64 time=0.139 ms ^C--- mysql ping statistics --- 2 packets transmitted, 2 packets received, 0% packet loss round-trip min/avg/max/stddev = 0.101/0.120/0.139/0.000 ms root@b129a168cb33:/data#
更多关于docker network的文章, 参考官方文档
原创文章,转载请注明出处。 如发现文章有误, 请联系作者
Q.E.D.