Docker入门详解

上一篇 / 目录 / 下一篇

英文原文在这里:https://docs.docker.com/get-started/

Part 1: Docker环境设置

参考Docker安装指南或快速入门手册来安装Docker Desktop。

安装成功后,使用下面的命令来验证Docker的运行状态:
docker --version

docker info 或 docker version 可以查看更加详细的信息:
docker info
docker version

通过下面的命令可以测试一下你的docker安装正确与否:
docker run hello-world
它会下载一个简单的docker镜像,并启动一个容器运行这个镜像。

使用docker image来查看本地的镜像:
docker image ls

使用docker container命令查看本地的容器。例如下面的命令会返回所有正在运行和已经停止的容器:
docker container ls --all

小结

通过Docker,你可以很轻量级的扩展你的程序。而且通过docker镜像发布程序意味着程序的安装将不再需要任何依赖组件(除了Docker Engine)。下面列出了本章节使用到的所有命令,供大家参考。

## List Docker CLI commands
docker
docker container --help
    
## Display Docker version and info
docker --version
docker version
docker info
    
## Execute Docker image
docker run hello-world
    
## List Docker images
docker image ls
    
## List Docker containers (running, all, all in quiet mode)
docker container ls
docker container ls --all
docker container ls -aq

Part 2: 容器

当你按照上述步骤确认了Docker的运行环境正常之后,你可以着手创建自己的容器镜像了。首先创建一个新的目录:

mkdir my-first-container
cd my-first-container

Dockerfile

在此目录中新建一个文本文件,命名为Dockerfile。文件内容如下:

# Use an official Python runtime as a parent image
FROM python:2.7-slim

# Set the working directory to /app
WORKDIR /app

# Copy the current directory contents into the container at /app
COPY . /app

# Install any needed packages specified in requirements.txt
RUN pip install --trusted-host pypi.python.org -r requirements.txt

# Make port 80 available to the world outside this container
EXPOSE 80

# Define environment variable
ENV NAME World

# Run app.py when the container launches
CMD ["python", "app.py"]

Dockerfile 的作用是告诉Docker,按照一定的步骤来构建打包一个镜像。在上述例子中,Docker会依次执行以下步骤来生成新的镜像:首先下载一个名为python:2.7-slim的镜像作为模板,拷贝当前目录下的文件到镜像的/app目录,运行一个pip install命令,对外开放80端口,设置环境变量NAME=World,最后运行一个python程序。

The Python application

Dockerfile 引用了2个文件: requirements.txt 和 app.py. 它们是pip指令和python程序所需的源代码。我们在同一目录下创建这两个文件。

requirements.txt包含下面两行:

Flask
Redis

app.py的内容如下:

from flask import Flask
from redis import Redis, RedisError
import os
import socket

# Connect to Redis
redis = Redis(host="redis", db=0, socket_connect_timeout=2, socket_timeout=2)

app = Flask(__name__)

@app.route("/")
def hello():
    try:
        visits = redis.incr("counter")
    except RedisError:
        visits = "<i>cannot connect to Redis, counter disabled</i>"

    html = "<h3>Hello {name}!</h3>" \
           "<b>Hostname:</b> {hostname}<br/>" \
           "<b>Visits:</b> {visits}"
    return html.format(name=os.getenv("NAME", "world"), hostname=socket.gethostname(), visits=visits)

if __name__ == "__main__":
    app.run(host='0.0.0.0', port=80)

这段代码的逻辑很简单,程序会启动一个web service,监听端口80。返回的html中包含环境变量"NAME"的值(默认为world),以及socket.gethostname()的值(为当前容器的ID)。另外,由于容器中并没有运行Redis,因此程序会打印出错误消息:<i>cannot connect to Redis, counter disabled</i>

编译打包

创建容器镜像的所有文件都准备好了,下面就来编译打包。此时在当前目录中你应该有三个文件:Dockerfile, app.py, requirements.txt。

运行下面的命令来打包生成镜像:
docker build --tag=friendlyhello .

提示:不要忘记命令最末尾的小数点,它表示当前目录。

生成的镜像会保存在本地的Docker镜像注册表中(docker image registry)。运行下面的命令查看所有的本地镜像。

docker image ls
REPOSITORY               TAG                 IMAGE ID            CREATED             SIZE
friendlyhello            latest              17334977b537        13 seconds ago      131MB

在上面的例子中,--tag参数没有指明具体的版本号,因此打包的镜像TAG列默认为latest。如果要指定具体的版本号,可以使用 --tag=friendlyhello:v0.0.1

运行容器

使用命令 docker run来运行一个容器:

docker run -p 4000:80 friendlyhello

参数 -p 4000:80 表明将你的实体机端口4000映射到容器的端口80,因此你可以使用http://localhost:4000 来访问容器中的web service。这个命令会在当前命令行窗口中运行容器,且命令不会返回,直到容器退出。如果要在后台运行容器,请使用参数 -d 开启 detached模式:

docker run -d -p 4000:80 friendlyhello

下面的截图演示了foreground运行和background运行的区别:


foreground
background

使用curl或浏览器来测试这个程序:

curl http://localhost:4000

<h3>Hello World!</h3><b>Hostname:</b> 6be4e1853e71<br/><b>Visits:</b> <i>cannot connect to Redis, counter disabled</i>

停止容器

在容器正在运行的命令行窗口中,点击CTRL+C会退出这个python 程序,但是Windows系统比较特殊,该操作不会停止容器。正确的做法是使用命令docker container stop来停止一个运行的容器。方法是,先执行 docker container ls 找到正在运行的容器ID。

docker container ls
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                  NAMES
6be4e1853e71        friendlyhello       "python app.py"     7 minutes ago       Up 7 minutes        0.0.0.0:4000->80/tcp   infallible_morse

然后执行 docker container stop

docker container stop 6be4e1853e71

发布你的docker镜像

镜像可以发布到Docker公开的镜像仓库(docker hub registry)中,这样任何人都可以在任何机器上下载并运行你的镜像。当然,你也可以把镜像发布到其他第三方维护的Docker注册表,甚至于你可以创建公司内部的私有注册表,不过这不在本指南的讨论范围内。

首先需要登录Docker ID。执行命令 docker login,并按提示输入用户名和密码。

然后给你的镜像设置一个标签。标签是对镜像的唯一标识。完整的标签格式是:<dockerid>/<repository>:<tag>
其中,<dockerid>/<repositroy> 表明镜像会上传到你id中的某个镜像仓库。例如:

docker tag friendlyhello feiandytan/get-started:part2

上述命令为镜像friendlyhello创建了一个新的标签,表明此镜像将上传到我的id feiandytan下的仓库 get-started中,并且将其version记为part2

最后一步就是发布:
docker push <dockerid>/get-started:part

一旦发布成功,你就可以在任意一台安装了Docker的电脑上运行该容器。方法是执行下面的命令:
docker run -p 4000:80 <dockerid>/get-started:part

小结

下面列出本章用到的命令,供大家参考:

docker build -t friendlyhello .  # Create image using this directory's Dockerfile
docker run -p 4000:80 friendlyhello  # Run "friendlyhello" mapping port 4000 to 80
docker run -d -p 4000:80 friendlyhello         # Same thing, but in detached mode
docker container ls                                # List all running containers
docker container ls -a             # List all containers, even those not running
docker container stop <hash>           # Gracefully stop the specified container
docker container kill <hash>         # Force shutdown of the specified container
docker container rm <hash>        # Remove specified container from this machine
docker container rm $(docker container ls -a -q)         # Remove all containers
docker image ls -a                             # List all images on this machine
docker image rm <image id>            # Remove specified image from this machine
docker image rm $(docker image ls -a -q)   # Remove all images from this machine
docker login             # Log in this CLI session using your Docker credentials
docker tag <image> username/repository:tag  # Tag <image> for upload to registry
docker push username/repository:tag            # Upload tagged image to registry
docker run username/repository:tag                   # Run image from a registry

Part 3: 服务(Services)

先来看几个概念。

  • Service:当我们搭建分布式系统时,我们常常希望某一个程序可以同时运行多个副本,它们全部处在一个负载均衡器的后面。在Docker中,这种将一个镜像启动并运行在多个容器副本中的集群,就称为一个服务。描述一个Docker 服务需要指明以下内容:这个服务运行的是哪一个镜像?需要同时运行多少个容器副本?每个容器最大占用多少CPU和内存?是否需要负载均衡等等。这些描述信息都记录在docker-compose.yml文件中。

  • Task: 每一个服务都会运行若干个docker 容器。一个容器就称为这个服务的一个任务。例如,如果一个服务同时运行了5个容器,我们就说这个服务包含5个任务。

docker-compose.yml

我们在任意一个目录中新建文本文件 docker-compose.yml。内容如下:

version: "3"
services:
  web:
    image: <dockerid>/get-started:part2
    deploy:
      replicas: 5
      resources:
        limits:
          cpus: "0.1"
          memory: 50M
      restart_policy:
        condition: on-failure
    ports:
      - "4000:80"
    networks:
      - webnet
networks:
  webnet:

提示:<dockerid>要替换成你的docker id。

上述配置表明:

  1. 服务加载的镜像是<dockerid>/get-started:part2
  2. 启动5个容器实例来组成一个服务。服务的名称为"web"。
  3. 每个容器最多使用一个CPU内核的10%,以及50MB内存。
  4. 容器在失败状态下自动重启。
  5. 映射实体机端口4000到容器的端口80。
  6. 服务使用的网络名为"webnet",并且定义了"webnet"网络为默认配置。

部署运行服务

接下来执行命令(关于swarm会在后面介绍):
docker swarm init

使用docker stack deploy来运行这个stack:
docker stack deploy -c docker-compose.yml getstartedlab

上面的命令将读取服务描述文件docker-compose.yml来部署一个stack,并命名该stack为getstartedlab。

可以访问http://localhost:4000 来观察返回的hostname。每次的结果都不同,说明负载均衡器已经生效。
提示:默认的负载均衡策略是依次循环访问各个容器。

查看服务的状态

使用下面的命令可以查看当前电脑上运行的所有服务:
docker service ls
例如:

C:\Users\i062893\OneDrive\code\docker-workspace\my-first-container>docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE                          PORTS
ypyx4ed2uzur        getstartedlab_web   replicated          0/10                feiandytan/get-started:part2   *:4000->80/tcp

执行命令docker stack services <stack name>查看某个stack的所有服务。例如:

C:\Users\i062893\OneDrive\code\docker-workspace\my-first-container>docker stack services getstartedlab
ID                  NAME                MODE                REPLICAS            IMAGE                          PORTS
ypyx4ed2uzur        getstartedlab_web   replicated          10/10               feiandytan/get-started:part2   *:4000->80/tcp

注意上面服务的命名规则:服务的全称"getstartedlab_web"是由<stack name> + <service name> 组成。

使用下面的命令可以查看某个服务包含哪些任务:
docker service ps getstartedlab_web

使用下面的命令查看某个stack包含哪些任务:
docker stack ps getstartedlab

增加任务数

通过修改文件docker-compose.yml 中的replicas参数,可以很容易的扩展你的服务任务数量。只需要重新运行下面的命令即可:
docker stack deploy -c docker-compose.yml getstartedlab

删除stack和swarm

使用下面的命令删除stack和swarm:

docker stack rm getstartedlab
docker swarm leave --force

小结

下面列出本章使用到的docker命令,供大家参考:

docker swarm init                      # Init this machine as a swarm manager
docker stack ls                                            # List stacks or apps
docker stack deploy -c <composefile> <appname>  # Run the specified Compose file
docker service ls                 # List running services associated with an app
docker service ps <service>                  # List tasks associated with an app
docker inspect <task or container>                   # Inspect task or container
docker container ls -q                                      # List container IDs
docker stack rm <appname>                             # Tear down an application
docker swarm leave --force      # Take down a single node swarm from the manager

Part 4: 蜂窝 (Swarms)

在之前的指南中,已经接触过swarm命令了。Docker可以将多台电脑组合成一个蜂窝集群网络,每一个节点的计算机都可以部署和运行容器,共同来完成分布式计算的任务。Part 3演示了一个仅包含单个节点的蜂窝集群,在其中部署了一个名称为getstartedlab的服务。接下来就演示一下如何将两台电脑连接成一个蜂窝集群。

为了便于理解,首先需要解释一下几个概念,以及蜂窝集群的工作原理。

蜂窝的概念和原理

  • Swarm: 一个蜂窝是一组计算机,它们都运行了Docker Engine并且相互连接组成一个集群。显然,一个蜂窝可以包含多台计算机,而一台计算机只能加入一个蜂窝集群。

  • Swarm manager: 蜂窝经理是Swarm集群中一类特殊的计算机,它们负责执行Docker命令行的命令以及按照一定的策略在各个节点上管理容器。

  • Swarm workers: 蜂窝工人是Swarm集群中的另一类计算机,它们受经理的管理,只负责运行容器,而不能执行Docker命令行的命令。

  • node: 蜂窝集群中的每一个计算机 (经理或工人)都称为一个节点。

  • Ingress routing mesh: 蜂窝利用一种称为Ingress routing mesh的机制来实现负载均衡,其原理如下图所示:


    Ingress routing mesh

在每一个节点上都运行了一个负载均衡器(swarm load balancer),它负责把网络请求分发到各个节点运行的容器中。由上图可以看出,蜂窝集群是一个很复杂的网状结构,每个节点的负载均衡器都与所有节点中的容器相连接。

创建集群

下面以Win10操作系统为例,创建2个虚拟机并将它们组合成一个蜂窝集群。

打开 Hyper-V Manager, 点击右侧的菜单"Virtual Switch Manager…":


Hyper-V Manager

新建一个External类型的virtual switch,取名为"myswitch",勾选"Allow management operating system to share this network adapter"。


Create myswitch

当创建了myswitch虚拟网络交换配置后,虚拟机就可以访问外部网络了。

下面的docker-machine命令可以创建两个虚拟机。
提示:从现在开始,所有的docker-machine命令请在CMD管理员模式下运行。

docker-machine create -d hyperv --hyperv-virtual-switch "myswitch" myvm1
docker-machine create -d hyperv --hyperv-virtual-switch "myswitch" myvm2

使用docker-machine ls命令查看虚拟机列表。你可以从列表中看到虚拟机的IP地址和状态,例如:

C:\Users\i062893\OneDrive\code\docker-workspace\my-first-container>docker-machine ls
NAME    ACTIVE   DRIVER   STATE     URL                        SWARM   DOCKER     ERRORS
myvm1   -        hyperv   Running   tcp://10.58.181.134:2376           v18.09.7
myvm2   -        hyperv   Running   tcp://10.58.180.164:2376           v18.09.7

我们打算让myvm1作为蜂窝集群的经理,因此在myvm1中执行docker swarm init命令。方法如下:

C:\Users\i062893\OneDrive\code\docker-workspace\my-first-container>docker-machine ssh myvm1 "docker swarm init --advertise-addr 10.58.181.134"
Swarm initialized: current node (64ve59yqsdgvcpsphbn59et5v) is now a manager.

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

    docker swarm join --token SWMTKN-1-2zpjxx9ie1a8g8kadizxhy0pygx5sb1lrpjp5wqlu7qxqg2lo6-5h5zw6h0dvq6gf51tly19y9uj 10.58.181.134:2377

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

上述命令将引号中的指令通过ssh连接发送到myvm1虚拟机上并执行。从响应消息中可以看到一个docker swarm join指令,将它拷贝出来,在myvm2上执行,就可以把第二个虚拟机加入同一个蜂窝集群。也可以使用docker swarm join-token worker再次查看具体的docker swarm join 指令,例如:

C:\Users\i062893\OneDrive\code\docker-workspace\my-first-container>docker-machine ssh myvm1 "docker swarm join-token worker"
To add a worker to this swarm, run the following command:

    docker swarm join --token SWMTKN-1-3ych7gmhb6uwven0nn4fo0ft8oe5857vitnlzztofvwia307pn-2vlvn2dng0lr5m87mozo4d5vt 10.59.173.123:2377

我们接着把myvm2加入蜂窝集群:

C:\Users\i062893\OneDrive\code\docker-workspace\my-first-container>docker-machine ssh myvm2 "docker swarm join --token SWMTKN-1-2zpjxx9ie1a8g8kadizxhy0pygx5sb1lrpjp5wqlu7qxqg2lo6-5h5zw6h0dvq6gf51tly19y9uj 10.58.181.134:2377"
This node joined a swarm as a worker.

之后可以使用docker node ls查看蜂窝中的所有节点信息:

C:\Users\i062893\OneDrive\code\docker-workspace\my-first-container>docker-machine ssh myvm1 "docker node ls"
ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS      ENGINE VERSION
64ve59yqsdgvcpsphbn59et5v *   myvm1               Ready               Active              Leader              18.09.7
15dve4fu9wuazzqedtvg40lfe     myvm2               Ready               Active                                  18.09.7

此时,我们已经组建了一个蜂窝集群,包含了两个节点。一个是经理 (myvm1),另一个是工人 (myvm2)。

在蜂窝集群中部署程序

为了方便演示,我们可以把当前的shell窗口直接连到某一个虚拟机上,方法如下:
运行docker-machine env myvm1,例如:

C:\Users\i062893\OneDrive\code\docker-workspace\my-first-container>docker-machine env myvm1
SET DOCKER_TLS_VERIFY=1
SET DOCKER_HOST=tcp://10.58.181.134:2376
SET DOCKER_CERT_PATH=C:\Users\i062893\.docker\machine\machines\myvm1
SET DOCKER_MACHINE_NAME=myvm1
SET COMPOSE_CONVERT_WINDOWS_PATHS=true
REM Run this command to configure your shell:
REM     @FOR /f "tokens=*" %i IN ('docker-machine env myvm1') DO @%i

提示:如果你的Docker配置了代理,那么需要执行命令: docker-machine env --no-proxy myvm1
否则,你会在接下来的运行中遇到Forbidden的错误。

按照响应消息中的提示,再运行最后一行的代码即可:

C:\Users\i062893\OneDrive\code\docker-workspace\my-first-container>@FOR /f "tokens=*" %i IN ('docker-machine env myvm1') DO @%i

这样,当前shell窗口就和myvm1虚拟机建立了连接。所有后续的命令都会直接在myvm1虚拟机上运行。通过查看虚拟机列表,也可以发现myvm1处于ACTIVE状态 (ACTIVE列显示了一个星号):

C:\Users\i062893\OneDrive\code\docker-workspace\my-first-container>docker-machine ls
NAME    ACTIVE   DRIVER   STATE     URL                        SWARM   DOCKER     ERRORS
myvm1   *        hyperv   Running   tcp://10.58.181.134:2376           v18.09.7
myvm2   -        hyperv   Running   tcp://10.58.180.164:2376           v18.09.7

使用Part 3 指南中相同的命令来部署一个服务:

C:\Users\i062893\OneDrive\code\docker-workspace\my-first-container>docker stack deploy -c docker-compose.yml getstartedlab
Creating network getstartedlab_webnet
Creating service getstartedlab_web

这个服务包含5个任务,它们会随机的分布在两个虚拟机中。使用docker stack ps getstartedlab可以查看这些任务的详情。例如,下面的列表显示,1, 3, 5号任务运行在myvm2节点上,而2, 4号任务运行在myvm1节点上。

C:\Users\i062893\OneDrive\code\docker-workspace\my-first-container>docker stack ps getstartedlab
ID                  NAME                  IMAGE                          NODE                DESIRED STATE       CURRENT STATE                    ERROR               PORTS
3nky30x2zeig        getstartedlab_web.1   feiandytan/get-started:part2   myvm2               Running             Running less than a second ago
o6vtrdz6dlvb        getstartedlab_web.2   feiandytan/get-started:part2   myvm1               Running             Running less than a second ago
58xgzjldd6jk        getstartedlab_web.3   feiandytan/get-started:part2   myvm2               Running             Running less than a second ago
uywciema025m        getstartedlab_web.4   feiandytan/get-started:part2   myvm1               Running             Running less than a second ago
xfmjvv0jgvly        getstartedlab_web.5   feiandytan/get-started:part2   myvm2               Running             Running less than a second ago

测试的方式和之前一样,使用curl http://10.58.181.134:4000curl http://10.58.180.164:4000 来访问我们的服务。这里使用的是myvm1或myvm2的IP地址。还记得之前介绍的Ingress routing mesh 机制吗?正是利用了这个机制,使得Docker蜂窝集群的任何一个节点,都可以作为外部web service的访问入口。

清理stack

使用下面的命令删除一个stack:
docker stack rm getstartedlab

使用下面的命令移除一个蜂窝节点:

docker-machine ssh myvm2 "docker swarm leave"
docker-machine ssh myvm1 "docker swarm leave --force"

重启虚拟机

使用docker-machine stop来停止一个虚拟机:
docker-machine stop myvm1

使用docker-machine start启动一个虚拟机:
docker-machine start myvm1

使用docker-machine restart重启虚拟机:
docker-machine restart myvm1

重新生成证书

通常当实体机的网络发生变化时,虚拟机的IP地址也会变化。此时原始的TLS证书就不能使用了。当执行docker-machine ls查看虚拟机状态时,会看到错误提示:Unable to query docker version: Get https://192.168.31.72:2376/v1.15/version: x509: certificate is valid for 10.59.162.174, not 192.168.31.72

解决方法是运行下面的命令重新生成一个虚拟机的证书:
docker-machine regenerate-certs myvm1

小结

下面列出本章中用到的命令,供大家参考:

docker-machine create --driver virtualbox myvm1 # Create a VM (Mac, Win7, Linux)
docker-machine create -d hyperv --hyperv-virtual-switch "myswitch" myvm1 # Win10
docker-machine env myvm1                # View basic information about your node
docker-machine ssh myvm1 "docker node ls"         # List the nodes in your swarm
docker-machine ssh myvm1 "docker node inspect <node ID>"        # Inspect a node
docker-machine ssh myvm1 "docker swarm join-token -q worker"   # View join token
docker-machine ssh myvm1   # Open an SSH session with the VM; type "exit" to end
docker node ls                # View nodes in swarm (while logged on to manager)
docker-machine ssh myvm2 "docker swarm leave"  # Make the worker leave the swarm
docker-machine ssh myvm1 "docker swarm leave -f" # Make master leave, kill swarm
docker-machine ls # list VMs, asterisk shows which VM this shell is talking to
docker-machine start myvm1            # Start a VM that is currently not running
docker-machine env myvm1      # show environment variables and command for myvm1
eval $(docker-machine env myvm1)         # Mac command to connect shell to myvm1
& "C:\Program Files\Docker\Docker\Resources\bin\docker-machine.exe" env myvm1 | Invoke-Expression   # Windows command to connect shell to myvm1
docker stack deploy -c <file> <app>  # Deploy an app; command shell must be set to talk to manager (myvm1), uses local Compose file
docker-machine scp docker-compose.yml myvm1:~ # Copy file to node's home dir (only required if you use ssh to connect to manager and deploy the app)
docker-machine ssh myvm1 "docker stack deploy -c <file> <app>"   # Deploy an app using ssh (you must have first copied the Compose file to myvm1)
eval $(docker-machine env -u)     # Disconnect shell from VMs, use native docker
docker-machine stop $(docker-machine ls -q)               # Stop all running VMs
docker-machine rm $(docker-machine ls -q) # Delete all VMs and their disk images

Part 5: Stacks

在Part 5 指南中,我们一起来了解一下栈的概念。在Docker的世界中,你可以把一组相互关联,共同完成某个程序功能的服务组合成一个栈。在之前的文章中,我们已经使用过栈了:使用docker-compose.yml文件来定义栈,使用docker stack deploy命令来部署一个栈。由此可知,栈是Docker中部署(deploy)的最小单元。即使你的程序只有一个服务,你也必须把它包裹在一个栈中,比如Part 4的示例程序就是一个仅包含一个服务的栈。

在进行下面的练习之前,先确保你的蜂窝集群状态正常。

把当前的shell连接到myvm1, 并运行docker node ls

C:\Users\i062893\OneDrive\code\docker-workspace\my-first-container>docker node ls
ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS      ENGINE VERSION
uneyxvztmsxahbilzoneq76tu *   myvm1               Ready               Active              Leader              18.09.7
gnove3cdyjxfpchn99vc3ff5j     myvm2               Ready               Active                                  18.09.7

确保每个节点的状态都是Ready。否则请参考Part 4搭建蜂窝集群。

增加一个visualizer服务

接下来,我们在之前的getstartedlab的基础上,新增加一个服务。修改docker-compose.yml文件如下:

version: "3"
services:
  web:
    image: <dockerid>/get-started:part2
    deploy:
      replicas: 5
      restart_policy:
        condition: on-failure
      resources:
        limits:
          cpus: "0.1"
          memory: 50M
    ports:
      - "80:80"
    networks:
      - webnet
  visualizer:
    image: dockersamples/visualizer:stable
    ports:
      - "8080:8080"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock"
    deploy:
      placement:
        constraints: [node.role == manager]
    networks:
      - webnet
networks:
  webnet:

我们新增加了一个服务,取名为“visualizer”。它使用了Docker提供的一个标准的镜像:dockersamples/visualizer:stable。这个服务可以在浏览器中显示当前蜂窝集群各个节点的状态。ports属性之前已经介绍过了,即把实体机的端口8080映射到容器的端口8080。volumes属性则是映射磁盘文件,即把实体机的文件"/var/run/docker.sock"映射到容器的文件"/var/run/docker.sock"。而deploy.placement.constraints属性,则意味着该visualizer服务仅能部署到蜂窝经理节点上,即myvm1虚拟机。

运行docker stack deploy来部署新的栈:

docker stack deploy -c docker-compose.yml getstartedlab

部署成功后,我们就可以在浏览器中查看visualizer:


visualizer

再增加一个redis服务

我们重复一遍上述步骤,再新增一个redis服务。在最开始Part 1的python程序中,我们使用到了redis,用来记录当前网站的访问次数。当时由于我们的程序没有包含redis服务,所以返回错误消息。接下来,把redis服务加到docker-compose.yml文件中:

version: "3"
services:
  web:
    image: <dockerid>/get-started:part2
    deploy:
      replicas: 5
      restart_policy:
        condition: on-failure
      resources:
        limits:
          cpus: "0.1"
          memory: 50M
    ports:
      - "80:80"
    networks:
      - webnet
  visualizer:
    image: dockersamples/visualizer:stable
    ports:
      - "8080:8080"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock"
    deploy:
      placement:
        constraints: [node.role == manager]
    networks:
      - webnet
  redis:
    image: redis
    ports:
      - "6379:6379"
    volumes:
      - "/home/docker/data:/data"
    deploy:
      placement:
        constraints: [node.role == manager]
    command: redis-server --appendonly yes
    networks:
      - webnet
networks:
  webnet:

redis服务使用的镜像就是"redis"。并且,redis也和visualizer一样,只运行在经理节点上。

请注意volumes属性,它表明redis服务需要将实体机的文件"/home/docker/data"映射到容器的文件"/data"。因此在部署这个栈之前,我们先在myvm1虚拟机上创建子目录/home/docker/data。方法是运行下面的命令:

docker-machine ssh myvm1 "mkdir ./data"

再次运行docker stack deploy来部署新的栈

docker stack deploy -c docker-compose.yml getstartedlab

成功部署后,在myvm1节点上运行docker service ls查看一下3个服务的状态:

docker service ls
ID                  NAME                       MODE                REPLICAS            IMAGE                             PORTS
xgd8p4k7x5ig        getstartedlab_redis        replicated          1/1                 redis:latest                      *:6379->6379/tcp
t2fhws0yxz49        getstartedlab_visualizer   replicated          1/1                 dockersamples/visualizer:stable   *:8080->8080/tcp
z0wttomwgrbt        getstartedlab_web          replicated          5/5                 feiandytan/get-started:part2      *:80->80/tcp

使用curl 来看看网站的访问计数器:

C:\code\docker-workspace\part5-1>curl http://10.59.173.123
<h3>Hello World!</h3><b>Hostname:</b> 2944f07a164d<br/><b>Visits:</b> 1
C:\code\docker-workspace\part5-1>curl http://10.59.173.123
<h3>Hello World!</h3><b>Hostname:</b> b1b2c6a4fc33<br/><b>Visits:</b> 2
C:\code\docker-workspace\part5-1>curl http://10.59.173.123
<h3>Hello World!</h3><b>Hostname:</b> ce4344324343<br/><b>Visits:</b> 3
C:\code\docker-workspace\part5-1>curl http://10.59.173.123
<h3>Hello World!</h3><b>Hostname:</b> aaf34aec3fa4<br/><b>Visits:</b> 4

最后看一下Visualizer返回的节点状态:


visualizer

至此,我们已经搭建了一个docker集群,并部署了一个容器化的程序。该程序包含1个栈 (3个服务)。其中redis服务和visualizer服务只在经理节点上运行了一个容器;web服务则运行了5个容器,由swarm自动将5个容器分配给集群中的各个节点。Docker会自动维护各个容器的状态,一旦出现异常,容器会自动重启。最重要的是,每个节点对外提供的web service都可以作为该程序的入口地址,Docker的Ingress routing mesh 实现了网络请求的负载均衡。

上一篇 / 目录 / 下一篇

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 161,192评论 4 369
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,186评论 1 303
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 110,844评论 0 252
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,471评论 0 217
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,876评论 3 294
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,891评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,068评论 2 317
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,791评论 0 205
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,539评论 1 249
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,772评论 2 253
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,250评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,577评论 3 260
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,244评论 3 241
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,146评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,949评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,995评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,812评论 2 276

推荐阅读更多精彩内容