[关闭]
@yangwenbo 2023-06-27T19:01:56.000000Z 字数 18712 阅读 317

Docker

Docker基础(下)

8. Docker Compose

8.1 介绍

Docker Compose 是 Docker 官⽅编排(Orchestration)项⽬之⼀,负责快速的部署分布式应⽤。其代
码⽬前在https://github.com/docker/compose上开源。Compose 定位是 「定义和运⾏多个 Docker 容器的应⽤(Defining and running multi-container Docker applications)」,其前身是开源项⽬ Fig 。

然⽽,在⽇常⼯作中,经常会碰到需要多个容器相互配合来完成某项任务的情况。例如要实现⼀个 Web 项⽬,除了 Web服务容器本身,往往还需要再加上后端的数据库服务容器或者缓存服务容器,甚⾄还包括负载均衡容器等。Compose 恰好满⾜了这样的需求。它允许⽤户通过⼀个单独的 dockercompose.yml 模板⽂件(YAML 格式)来定义⼀组相关联的应⽤容器为⼀个项⽬(project)。

Compose 中有两个重要的概念:

  • 服务 (service):⼀个应⽤的容器,实际上可以包括若⼲运⾏相同镜像的容器实例。
  • 项⽬ (project):由⼀组关联的应⽤容器组成的⼀个完整业务单元,在 docker-compose.yml ⽂件中定义。

Compose 的默认管理对象是项⽬,通过⼦命令对项⽬中的⼀组容器进⾏便捷地⽣命周期管理。
Compose 项⽬由 Python 编写,实现上调⽤了 Docker 服务提供的 API 来对容器进⾏管理。所以只要所操作的平台⽀持 Docker API,就可以在其上利⽤ Compose 来进⾏编排管理。

8.2 安装

Compose ⽀持 Linux、macOS、Windows 10 三⼤平台。Compose 可以通过 Python 的包管理⼯具 pip 进⾏安装,也可以直接下载编译好的⼆进制⽂件使⽤,甚⾄能够直接在 Docker 容器中运⾏。
前两种⽅式是传统⽅式,适合本地环境下安装使⽤;最后⼀种⽅式则不破坏系统环境,更适合云计算场景。Docker for Mac 、Docker for Windows ⾃带 docker-compose ⼆进制⽂件,安装 Docker 之后可以直接使⽤。

Compose 既然是⼀个 Python 应⽤,⾃然也可以直接⽤容器来执⾏它。

  1. [root@docker ~]# curl -L https://github.com/docker/compose/releases/download/1.8.0/run.sh > /usr/local/bin/docker-compose
  2. [root@docker ~]# chmod +x /usr/local/bin/docker-compose
  3. [root@docker ~]# ll -d /usr/local/bin/docker-compose
  4. -rwxr-xr-x 1 root root 1400 2 4 15:01 /usr/local/bin/docker-compose
  1. 实际上,查看下载的 run.sh 脚本内容,如下:
  2. [root@docker ~]# cat /usr/local/bin/docker-compose
  3. #!/bin/bash
  4. #
  5. # Run docker-compose in a container
  6. #
  7. # This script will attempt to mirror the host paths by using volumes for the
  8. # following paths:
  9. # * $(pwd)
  10. # * $(dirname $COMPOSE_FILE) if it's set
  11. # * $HOME if it's set
  12. #
  13. # You can add additional volumes (or any docker run options) using
  14. # the $COMPOSE_OPTIONS environment variable.
  15. #
  16. set -e
  17. VERSION="1.8.0"
  18. IMAGE="docker/compose:$VERSION"
  19. # Setup options for connecting to docker host
  20. if [ -z "$DOCKER_HOST" ]; then
  21. DOCKER_HOST="/var/run/docker.sock"
  22. fi
  23. if [ -S "$DOCKER_HOST" ]; then
  24. DOCKER_ADDR="-v $DOCKER_HOST:$DOCKER_HOST -e DOCKER_HOST"
  25. else
  26. DOCKER_ADDR="-e DOCKER_HOST -e DOCKER_TLS_VERIFY -e DOCKER_CERT_PATH"
  27. fi
  28. # Setup volume mounts for compose config and context
  29. if [ "$(pwd)" != '/' ]; then
  30. VOLUMES="-v $(pwd):$(pwd)"
  31. fi
  32. if [ -n "$COMPOSE_FILE" ]; then
  33. compose_dir=$(dirname $COMPOSE_FILE)
  34. fi
  35. # TODO: also check --file argument
  36. if [ -n "$compose_dir" ]; then
  37. VOLUMES="$VOLUMES -v $compose_dir:$compose_dir"
  38. fi
  39. if [ -n "$HOME" ]; then
  40. VOLUMES="$VOLUMES -v $HOME:$HOME -v $HOME:/root" # mount $HOME in /root to share docker.config
  41. fi
  42. # Only allocate tty if we detect one
  43. if [ -t 1 ]; then
  44. DOCKER_RUN_OPTIONS="-t"
  45. fi
  46. if [ -t 0 ]; then
  47. DOCKER_RUN_OPTIONS="$DOCKER_RUN_OPTIONS -i"
  48. fi
  49. exec docker run --rm $DOCKER_RUN_OPTIONS $DOCKER_ADDR $COMPOSE_OPTIONS $VOLUMES -w "$(pwd)" $IMAGE "$@"

可以看到,它其实是下载了 docker/compose 镜像并运⾏。

8.3 卸载

如果是⼆进制包⽅式安装的,删除⼆进制⽂件即可。

  1. [root@docker ~]# rm /usr/local/bin/docker-compose

如果是通过 pip 安装的,则执⾏如下命令即可删除。

  1. [root@docker ~]# pip uninstall docker-compose

8.4 使⽤

下⾯我们⽤ Python 来建⽴⼀个能够记录⻚⾯访问次数的 web ⽹站。 新建⽂件夹,在该⽬录中编写 app.py ⽂件

  1. [root@docker ~]# mkdir web
  2. [root@docker ~]# cd web/
  3. [root@docker web]# vim app.py
  4. [root@docker web]# cat app.py
  5. import time
  6. import redis
  7. from flask import Flask
  8. app = Flask(__name__)
  9. cache = redis.Redis(host='redis', port=6379)
  10. def get_hit_count():
  11. retries = 5
  12. while True:
  13. try:
  14. return cache.incr('hits')
  15. except redis.exceptions.ConnectionError as exc:
  16. if retries == 0:
  17. raise exc
  18. retries -= 1
  19. time.sleep(0.5)
  20. @app.route('/')
  21. def hello():
  22. count = get_hit_count()
  23. return 'Hello World! I have been seen {} times.\n'.format(count)
  24. if __name__ == "__main__":
  25. app.run(host="0.0.0.0", debug=True)

接着编写 Dockerfile ⽂件,内容为:

  1. [root@docker web]# vim Dockerfile
  2. [root@docker web]# cat Dockerfile
  3. FROM python:3.6-alpine
  4. ADD . /code
  5. WORKDIR /code
  6. RUN pip install redis flask
  7. CMD ["python", "app.py"]

然后是编写 docker-compose.yml ⽂件,这个是 Compose 使⽤的主模板⽂件。

  1. [root@docker web]# vim docker-compose.yml
  2. [root@docker web]# cat docker-compose.yml
  3. version: '2.0'
  4. services:
  5. web:
  6. build: .
  7. ports:
  8. - "5000:5000"
  9. volumes:
  10. - .:/code
  11. redis:
  12. image: "redis:alpine"

运⾏ compose 项⽬:

  1. [root@docker web]# docker-compose up

image_1etogmo2qu1tvcd18d95cmtne9.png-220.1kB

此时访问本地 5000 端⼝,http://192.168.200.8:5000

image_1etoksdbq11q41ikei58nv9hk9m.png-63.1kB

每次刷新⻚⾯,计数就会加 1。

image_1etokt5uocne8tilndcd8ngq13.png-62.3kB

8.5 Compose 命令

对于 Compose 来说,⼤部分命令的对象既可以是项⽬本身,也可以指定为项⽬中的服务或者容器。如果没有特别的说明,命令对象将是项⽬,这意味着项⽬中所有的服务都会受到命令影响。

执⾏docker-compose [COMMAND] --help或者docker-compose help [COMMAND]可以查看具体某个命令的使⽤格式。

docker-compose 命令的基本的使⽤格式是:docker-compose [-f=<arg>...] [options] [COMMAND] [ARGS...]

命令选项:

  • -f, --file FILE 指定使⽤的 Compose 模板⽂件,默认为 docker-compose.yml,可以多次指定。
  • -p, --project-name NAME 指定项⽬名称,默认将使⽤所在⽬录名称作为项⽬名。
  • --x-networking 使⽤ Docker 的可拔插⽹络后端特性
  • --x-network-driver DRIVER 指定⽹络后端的驱动,默认为 bridge
  • --verbose 输出更多调试信息。
  • -v, --version 打印版本并退出。

build 格式为docker-compose build [options] [SERVICE...]。 构建(重新构建)项⽬中的服务容器。服务容器⼀旦构建后,将会带上⼀个标记名,例如对于 web 项⽬中的⼀个 db 容器,可能是 web_db。可以随时在项⽬⽬录下运⾏ docker-compose build 来重新构建服务。选项包括:

  • --force-rm 删除构建过程中的临时容器。
  • --no-cache 构建镜像过程中不使⽤ cache(这将加⻓构建过程)。
  • --pull 始终尝试通过 pull 来获取更新版本的镜像。

config: 验证 Compose ⽂件格式是否正确,若正确则显示配置,若格式错误显示错误原因。

down:此命令将会停⽌ up 命令所启动的容器,并移除⽹络

exec:进⼊指定的容器。

help:获得⼀个命令的帮助。

images:列出 Compose ⽂件中包含的镜像。

kill:格式为docker-compose kill [options] [SERVICE...]。通过发送 SIGKILL 信号来强制停⽌服务容器。⽀持通过 -s 参数来指定发送的信号,例如通过如下指令发送 SIGINT 信号。

  1. [root@docker ~]# docker-compose kill -s SIGINT

logs:格式为docker-compose logs [options] [SERVICE...],查看服务容器的输出。默认情况下,
docker-compose 将对不同的服务输出使⽤不同的颜⾊来区分。可以通过 --no-color 来关闭颜⾊。该命令在调试问题的时候⼗分有⽤。

pause:格式为docker-compose pause [SERVICE...],暂停⼀个服务容器。

port:格式为docker-compose port [options] SERVICE PRIVATE_PORT,打印某个容器端⼝所映射的公共端⼝。选项:

  • --protocol=proto 指定端⼝协议,tcp(默认值)或者 udp。
  • --index=index 如果同⼀服务存在多个容器,指定命令对象容器的序号(默认为 1)。

ps:格式为docker-compose ps [options] [SERVICE...],列出项⽬中⽬前的所有容器。选项:

  • -q 只打印容器的 ID 信息。

pull:格式为docker-compose pull [options] [SERVICE...] ,拉取服务依赖的镜像。选项:

  • --ignore-pull-failures 忽略拉取镜像过程中的错误。

push:推送服务依赖的镜像到 Docker 镜像仓库。

restart:格式为docker-compose restart [options] [SERVICE...],重启项⽬中的服务。选项:

  • -t, --timeout TIMEOUT 指定重启前停⽌容器的超时(默认为 10 秒)。

rm:格式为docker-compose rm [options] [SERVICE...],删除所有(停⽌状态的)服务容器。推荐先执⾏docker-compose stop 命令来停⽌容器。选项:

  • -f, --force 强制直接删除,包括⾮停⽌状态的容器。⼀般尽量不要使⽤该选项。
  • -v 删除容器所挂载的数据卷。

run:格式为docker-compose run [options] [-p PORT...] [-e KEY=VAL...] SERVICE [COMMAND] [ARGS...],在指定服务上执⾏⼀个命令。例如:

  1. [root@docker ~]# docker-compose run ubuntu ping docker.com

将会启动⼀个 ubuntu 服务容器,并执⾏ ping docker.com命令。默认情况下,如果存在关联,则所有关联的服务将会⾃动被启动,除⾮这些服务已经在运⾏中。

该命令类似启动容器后运⾏指定的命令,相关卷、链接等等都将会按照配置⾃动创建。
给定命令将会覆盖原有的⾃动运⾏命令; 不会⾃动创建端⼝,以避免冲突。

如果不希望⾃动启动关联的容器,可以使⽤ --no-deps 选项,例如:

  1. [root@docker ~]# docker-compose run --no-deps web python manage.py shell

将不会启动 web 容器所关联的其它容器,选项:

  • -d 后台运⾏容器。
  • --name NAME 为容器指定⼀个名字。
  • --entrypoint CMD 覆盖默认的容器启动指令。
  • -e KEY=VAL 设置环境变量值,可多次使⽤选项来设置多个环境变量。
  • -u, --user="" 指定运⾏容器的⽤户名或者 uid。
  • --no-deps 不⾃动启动关联的服务容器。
  • --rm 运⾏命令后⾃动删除容器,d 模式下将忽略。
  • -p, --publish=[] 映射容器端⼝到本地主机。
  • --service-ports 配置服务端⼝并映射到本地主机。
  • -T 不分配伪 tty,意味着依赖 tty 的指令将⽆法运⾏。

scale:格式为docker-compose scale [options] [SERVICE=NUM...],设置指定服务运⾏的容器个数。通过service=num 的参数来设置数量。例如:

  1. [root@docker ~]# docker-compose scale web=3 db=2

将启动 3 个容器运⾏ web 服务,2 个容器运⾏ db 服务。

⼀般的,当指定数⽬多于该服务当前实际运⾏容器,将新创建并启动容器;反之,将停⽌容器。选项:

  • -t, --timeout TIMEOUT 停⽌容器时候的超时(默认为 10 秒)。

start:格式为docker-compose start [SERVICE...],启动已经存在的服务容器。

stop:格式为docker-compose stop [options] [SERVICE...], 停⽌已经处于运⾏状态的容器,但不删除它。通过docker-compose start 可以再次启动这些容器。选项:

  • -t, --timeout TIMEOUT 停⽌容器时候的超时(默认为 10 秒)。

top:查看各个服务容器内运⾏的进程。

unpause:格式为docker-compose unpause [SERVICE...],恢复处于暂停状态中的服务。

up:格式为docker-compose up [options] [SERVICE...],该命令⼗分强⼤,它将尝试⾃动完成包括构建镜像,(重新)创建服务,启动服务,并关联服务相关容器的⼀系列操作。链接的服务都将会被⾃动启动,除⾮已经处于运⾏状态。 可以说,⼤部分时候都可以直接通过该命令来启动⼀个项⽬。

默认情况,docker-compose up 启动的容器都在前台,控制台将会同时打印所有容器的输出信息,可以很⽅便进⾏调试。 当通过 Ctrl-C 停⽌命令时,所有容器将会停⽌。

如果使⽤docker-compose up -d ,将会在后台启动并运⾏所有的容器。⼀般推荐⽣产环境下使⽤该选项。

默认情况,如果服务容器已经存在,docker-compose up 将会尝试停⽌容器,然后重新创建(保持使⽤ volumes-from 挂载的卷),以保证新启动的服务匹配 docker-compose.yml ⽂件的最新内容。如果⽤户不希望容器被停⽌并重新创建,可以使⽤docker-compose up --no-recreate 。这样将只会启动处于停⽌状态的容器,⽽忽略已经运⾏的服务。

如果⽤户只想重新部署某个服务,可以使⽤docker-compose up --no-deps -d <SERVICE_NAME> 来重新创建服务并后台停⽌旧服务,启动新服务,并不会影响到其所依赖的服务。选项:

  • -d 在后台运⾏服务容器。
  • --no-color 不使⽤颜⾊来区分不同的服务的控制台输出。
  • --no-deps 不启动服务所链接的容器。
  • --force-recreate 强制重新创建容器,不能与 --no-recreate 同时使⽤。
  • --no-recreate 如果容器已经存在了,则不重新创建,不能与 --force-recreate 同时使⽤。
  • --no-build 不⾃动构建缺失的服务镜像。
  • -t, --timeout TIMEOUT 停⽌容器时候的超时(默认为 10 秒)。

9. Docker Machine

9.1 介绍

Docker Machine 是 Docker 官⽅编排(Orchestration)项⽬之⼀,负责在多种平台上快速安装 Docker环境。

Docker Machine 项⽬基于 Go 语⾔实现,⽬前在Github上进⾏维护。

Docker Machine 是 Docker 官⽅提供的⼀个⼯具,它可以帮助我们在远程的机器上安装 Docker,或者在虚拟机 host 上直接安装虚拟机并在虚拟机中安装 Docker。我们还可以通过 docker-machine 命令来管理这些虚拟机和 Docker。

9.2 安装

Docker Machine 可以在多种操作系统平台上安装,包括 Linux、macOS,以及 Windows。

在 Linux 上的也安装⼗分简单,从官⽅ GitHub Release处直接下载编译好的⼆进制⽂件即可。 例如,在 Linux 64 位系统上直接下载对应的⼆进制包。

  1. [root@docker ~]# curl -L https://github.com/docker/machine/releases/download/v0.13.0/docker-machine-`uname -s`-`uname -m` > /usr/local/bin/docker-machine
  2. [root@docker ~]# chmod +x /usr/local/bin/docker-machine
  3. [root@docker ~]# ll -d /usr/local/bin/docker-machine
  4. -rwxr-xr-x 1 root root 26574656 2 6 18:58 /usr/local/bin/docker-machine

完成后,查看版本信息。

  1. [root@docker ~]# docker-machine -v
  2. docker-machine version 0.13.0, build 9ba6da9

Docker Machine ⽀持多种后端驱动,包括虚拟机、本地主机和云平台等。

9.3 创建本地主机实例Virtualbox 驱动

使⽤virtualbox类型的驱动,创建⼀台 Docker 主机,命名为 test。

  1. [root@docker ~]# docker-machine create -d virtualbox test

你也可以在创建时加上如下参数,来配置主机或者主机上的 Docker。

  • --engine-opt dns=114.114.114.114配置 Docker 的默认 DNS
  • --engine-registry-mirror https://registry.docker-cn.com配置 Docker 的仓库镜像
  • --virtualbox-memory 2048 配置主机内存
  • --virtualbox-cpu-count 2 配置主机 CPU

更多参数请使⽤ docker-machine create --driver virtualbox --help 命令查看。

  1. [root@docker ~]# docker-machine create -d generic \
  2. --generic-ip-address=192.168.200.6 \
  3. --generic-ssh-user=root \
  4. --generic-ssh-key ~/.ssh/id_rsa \
  5. dev

9.4 使⽤介绍

创建好主机之后,查看主机

  1. [root@docker ~]# docker-machine ls
  2. NAME ACTIVE DRIVER STATE URL SWARM DOCKER
  3. ERRORStest - virtualbox Running tcp://192.168.200.8:2376 v17.1
  4. 0.0-ce

创建主机成功后,可以通过 env 命令来让后续操作对象都是⽬标主机。

  1. [root@docker ~]# docker-machine env test

后续根据提示在命令⾏输⼊命令之后就可以操作 test 主机。也可以通过 SSH 登录到主机。

  1. [root@docker ~]# docker-machine ssh test
  2. docker@test:~$ docker --version
  3. Docker version 17.10.0-ce, build f4ffd25

连接到主机之后你就可以在其上使⽤ Docker 了。

9.5 官⽅⽀持驱动

通过 -d 选项可以选择⽀持的驱动类型:

  • amazonec2
  • azure
  • digitalocean
  • exoscale
  • generic
  • google
  • hyperv
  • none
  • openstack
  • rackspace
  • softlayer
  • virtualbox
  • vmwarevcloudair
  • vmwarefusion
  • vmwarevsphere

9.6 操作命令

  • active 查看活跃的 Docker 主机
  • config 输出连接的配置信息
  • create 创建⼀个 Docker 主机
  • env 显示连接到某个主机需要的环境变量
  • inspect 输出主机更多信息
  • ip 获取主机地址
  • kill 停⽌某个主机
  • ls 列出所有管理的主机
  • provision 重新设置⼀个已存在的主机
  • regenerate-certs 为某个主机重新⽣成 TLS 认证信息
  • restart 重启主机
  • rm 删除某台主机
  • ssh SSH 到主机上执⾏命令
  • scp 在主机之间复制⽂件
  • mount 挂载主机⽬录到本地
  • start 启动⼀个主机
  • status 查看主机状态
  • stop 停⽌⼀个主机
  • upgrade 更新主机 Docker 版本为最新
  • url 获取主机的 URL
  • version 输出 docker-machine 版本信息
  • help 输出帮助信息

每个命令,⼜带有不同的参数,可以通过如下命令来查看具体的⽤法:

  1. [root@docker ~]# docker-machine COMMAND --help

10. Docker Swarm

10.1 基本概念

Swarm 是使⽤SwarmKit构建的 Docker 引擎内置(原⽣)的集群管理和编排⼯具。 Docker Swarm 是Docker 官⽅三剑客项⽬之⼀,提供 Docker 容器集群服务,是 Docker 官⽅对容器云⽣态进⾏⽀持的核⼼⽅案。

使⽤它,⽤户可以将多个 Docker 主机封装为单个⼤型的虚拟 Docker 主机,快速打造⼀套容器云平台。Swarm mode 内置 kv存储功能,提供了众多的新特性,⽐如:具有容错能⼒的去中⼼化设计、内置服务发现、负载均衡、路由⽹格、动态伸缩、滚动更新、安全传输等。使得 Docker 原⽣的 Swarm集群具备与 Mesos 、 Kubernetes 竞争的实⼒。使⽤ Swarm集群之前需要了解以下⼏个概念。

10.2 节点

运⾏ Docker 的主机可以主动初始化⼀个 Swarm 集群或者加⼊⼀个已存在的 Swarm 集群,这样这个运⾏ Docker 的主机就成为⼀个 Swarm 集群的节点 (node) 。节点分为 管理 (manager) 节点和⼯作(worker) 节点 。

管理节点⽤于 Swarm 集群的管理, docker swarm 命令基本只能在管理节点执⾏(节点退出集群命令 docker swarm leave 可以在⼯作节点执⾏)。⼀个 Swarm 集群可以有多个管理节点,但只有⼀个管理节点可以成为 leader ,leader 通过 raft 协议实现。

⼯作节点是任务执⾏节点,管理节点将服务 ( service ) 下发⾄⼯作节点执⾏。管理节点默认也作为⼯作节点。你也可以通过配置让服务只运在管理节点。来⾃ Docker 官⽹的这张图⽚形象的展示了集群中管理节点与⼯作节点的关系。

image_1etre5nm41uvjbre83jinst99.png-1064.7kB

10.3 服务和任务

任务(Task) 是 Swarm 中的最⼩的调度单位,⽬前来说就是⼀个单⼀的容器; 服务(Services) 是指⼀组任务的集合,服务定义了任务的属性。服务有两种模式:

  • replicated services 按照⼀定规则在各个⼯作节点上运⾏指定个数的任务。
  • global services 每个⼯作节点上运⾏⼀个任务

两种模式通过 docker service create 的 --mode 参数指定。来⾃ Docker 官⽹的这张图⽚形象的展示了容器、任务、服务的关系。

image_1etrejn571smjp6d187415dis9dm.png-980.3kB

10.4 初始化集群

我们这⾥利⽤上⼀节的 docker machine 来充当集群的主机,⾸先先创建⼀个 manager 节点,然后在该节点上执⾏初始化集群命令:

  1. [root@docker ~]# docker-machine create -d virtualbox manager

执⾏ docker swarm init 命令的节点⾃动成为管理节点。

10.5 增加⼯作节点

管理节点初始化完成后,然后同样的⽤ docker-machine 创建⼯作节点,然后将其加⼊到管理节点之中去即可:

  1. [root@docker ~]# docker-machine create -d virtualbox worker1

我们可以看到上⾯的提示信息:This node joined a swarm as a worker.,表明节点已经加⼊到 swarm 集群之中了。

10.6 查看集群

经过上边的两步,我们已经拥有了⼀个最⼩的 Swarm 集群,包含⼀个管理节点和两个⼯作节点。

管理节点使⽤ docker node ls 查看集群:

  1. [root@docker ~]# docker node ls
  2. [root@docker ~]# docker service ls
  3. [root@docker ~]# docker-machine ls
  4. [root@docker ~]# docker service ls
  5. [root@docker ~]# docker service ps nginx

使⽤ docker service logs 来查看某个服务的⽇志。

  1. [root@docker ~]# docker service logs nginx

使⽤ docker service rm 来从 Swarm 集群移除某个服务:

  1. [root@docker ~]# docker service rm nginx
  2. nginx

正如之前使⽤ docker-compose.yml 来⼀次配置、启动多个容器,在 Swarm 集群中也可以使⽤ compose ⽂件(docker-compose.yml)来配置、启动多个服务。

上⼀节中,我们使⽤ docker service create ⼀次只能部署⼀个服务,使⽤ docker-compose.yml 我们可以⼀次启动多个关联的服务。

我们以在 Swarm 集群中部署 WordPress 为例进⾏说明:(docker-compose.yml)

  1. version: "3"
  2. services:
  3. wordpress:
  4. image: wordpress
  5. ports:
  6. - 80:80
  7. networks:
  8. - overlay
  9. environment:
  10. WORDPRESS_DB_HOST: db:3306
  11. WORDPRESS_DB_USER: wordpress
  12. WORDPRESS_DB_PASSWORD: wordpress
  13. deploy:
  14. mode: replicated
  15. replicas: 3
  16. db:
  17. image: mysql
  18. networks:
  19. - overlay
  20. volumes:
  21. - db-data:/var/lib/mysql
  22. environment:
  23. MYSQL_ROOT_PASSWORD: somewordpress
  24. MYSQL_DATABASE: wordpress
  25. MYSQL_USER: wordpress
  26. MYSQL_PASSWORD: wordpress
  27. deploy:
  28. placement:
  29. constraints: [node.role == manager]
  30. visualizer:
  31. image: dockersamples/visualizer:stable
  32. ports:
  33. - "8080:8080"
  34. stop_grace_period: 1m30s
  35. volumes:
  36. - "/var/run/docker.sock:/var/run/docker.sock"
  37. deploy:
  38. placement:
  39. constraints: [node.role == manager]
  40. volumes:
  41. db-data:
  42. networks:
  43. overlay:

其中constraints: [node.role == manager]是调度策略,⽂档地址:https://docs.docker.com/swarm/scheduler/filter/

在 Swarm 集群管理节点新建该⽂件,其中的 visualizer 服务提供⼀个可视化⻚⾯,我们可以从浏览器中很直观的查看集群中各个服务的运⾏节点。

在 Swarm 集群中使⽤ docker-compose.yml 我们⽤ docker stack命令,下⾯我们对该命令进⾏详细讲解。

10.7 部署服务

部署服务使⽤ docker stack deploy ,其中 -c 参数指定 compose ⽂件名。

  1. [root@docker ~]# docker stack deploy -c docker-compose.yml wordpres

10.8 查看服务

  1. [root@docker ~]# docker stack ls
  2. NAME SERVICES
  3. wordpress 3

10.9 移除服务

要移除服务,使⽤ docker stack down :

  1. [root@docker ~]# docker stack down wordpress
  2. Removing service wordpress_db
  3. Removing service wordpress_visualizer
  4. Removing service wordpress_wordpress
  5. Removing network wordpress_overlay
  6. Removing network wordpress_default

该命令不会移除服务所使⽤的数据卷 ,如果你想移除数据卷请使⽤docker volume rm

11. 图形化管理和监控

下⾯我们介绍⼏个可以⽤图形化的⽅式来管理 Docker 的⼯具。
Shipyard:https://github.com/shipyard/shipyard(已停⽌维护)

11.1 Portainer

Portainer(基于 Go)是⼀个轻量级的管理界⾯,可让您轻松管理 Docker 主机或 Swarm 集群。
Portainer 的使⽤意图是简单部署。它包含可以在任何 Docker 引擎上运⾏的单个容器(Docker for Linux 和 Docker for Windows)。

Portainer 允许您管理 Docker 容器、image、volume、network 等。 它与独⽴的 Docker 引擎和Docker Swarm 兼容。

Docker 命令安装:

  1. [root@docker ~]# docker volume create portainer_data
  2. portainer_data
  3. [root@docker ~]# docker volume ls
  4. DRIVER VOLUME NAME
  5. local portainer_data
  6. [root@docker ~]# docker run -d -p 9000:9000 -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer
  7. [root@docker ~]# docker images
  8. REPOSITORY TAG IMAGE ID CREATED SIZE
  9. portainer/portainer latest 62771b0b9b09 6 months ago 79.1MB
  10. [root@docker ~]# docker ps -a
  11. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  12. f20b865d83e7 portainer/portainer "/portainer" 25 seconds ago Up 24 seconds 0.0.0.0:9000->9000/tcp hungry_euclid

http://192.168.200.8:9000

image_1ettu1f0l1iar1f5n17jli1h15l61g.png-197.2kB

image_1ettu5h597dgobo1edq2paup42d.png-291.5kB

image_1ettu8l6n7qqa7a169b1p18qe02q.png-388.2kB

11.2 Rancher

Rancher是⼀个开源的企业级容器管理平台。通过Rancher,企业不必⾃⼰使⽤⼀系列的开源软件去从头搭建容器服务平台。Rancher提供了在⽣产环境中使⽤管理DockerKubernetes的全栈化容器部署与管理平台。

image_1ettuiqcb1auk1qfn11ul1mv31ual37.png-1368.3kB

11.3 cAdvisor

cAdvisor 是 Google 开发的容器监控⼯具,我们来看看 cAdvisor 有什么能耐。

  • 监控 Docker Host cAdvisor 会显示当前 host 的资源使⽤情况,包括 CPU、内存、⽹络、⽂件系统等。
  • 监控容器 点击 Docker Containers 链接,显示容器列表。点击某个容器,⽐如 sysdig,进⼊该容器的监控⻚⾯。

以上就是 cAdvisor 的主要功能,总结起来主要两点:

  • 展示 Host 和容器两个层次的监控数据。
  • 展示历史变化数据。

由于 cAdvisor 提供的操作界⾯略显简陋,⽽且需要在不同⻚⾯之间跳转,并且只能监控⼀个 host,这不免会让⼈质疑它的实⽤性。但 cAdvisor 的⼀个亮点是它可以将监控到的数据导出给第三⽅⼯具,由这些⼯具进⼀步加⼯处理。

我们可以把 cAdvisor 定位为⼀个监控数据收集器,收集和导出数据是它的强项,⽽⾮展示数据。cAdvisor ⽀持很多第三⽅⼯具,其中就包括后⾯我们重点要学习的 Prometheus 。

  1. [root@docker ~]# docker run \
  2. --volume=/:/rootfs:ro \
  3. --volume=/var/run:/var/run:rw \
  4. --volume=/sys:/sys:ro \
  5. --volume=/var/lib/docker/:/var/lib/docker:ro \
  6. --volume=/dev/disk/:/dev/disk:ro \
  7. --publish=8080:8080 \
  8. --detach=true \
  9. --name=cadvisor \
  10. google/cadvisor:latest
  1. [root@docker ~]# docker images
  2. REPOSITORY TAG IMAGE ID CREATED SIZE
  3. portainer/portainer latest 62771b0b9b09 6 months ago 79.1MB
  4. google/cadvisor latest eb1210707573 2 years ago 69.6MB
  5. [root@docker ~]# docker ps -a
  6. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  7. 1335debc08cd google/cadvisor:latest "/usr/bin/cadvisor -…" 52 seconds ago Up 51 seconds 0.0.0.0:8080->8080/tcp cadvisor
  8. f20b865d83e7 portainer/portainer "/portainer" 28 minutes ago Up 20 minutes 0.0.0.0:9000->9000/tcp hungry_euclid

通过访问地址:http://192.168.200.8:8080/containers/ 可以查看所有容器信息:

image_1ettv59splm61h861an1a72130u3k.png-332.5kB

除此之外,cAdvisor 还提供了⼀个 Rest
API:https://github.com/google/cadvisor/blob/master/docs/api.md

cAdvisor 通过该 REST API 暴露监控数据,格式如下:
http://<hostname>:<port>/api/<version>/<request>

12. Docker 的多阶段构建

Docker 的⼝号是 Build,Ship,and Run Any App,Anywhere,在我们使⽤ Docker 的⼤部分时候,的确能感觉到其优越性,但是往往在我们 Build ⼀个应⽤的时候,是将我们的源代码也构建进去的,这对于类似于 golang 这样的编译型语⾔肯定是不⾏的,因为实际运⾏的时候我只需要把最终构建的⼆进制包给你就⾏,把源码也⼀起打包在镜像中,需要承担很多⻛险,即使是脚本语⾔,在构的时候也可能需要使⽤到⼀些上线的⼯具,这样⽆疑也增⼤了我们的镜像体积。

12.1 示例

⽐如我们现在有⼀个最简单的 golang 服务,需要构建⼀个最⼩的 Docker 镜像,源码如下:

  1. [root@docker ~]# mkdir web02
  2. [root@docker ~]# cd web02/
  3. [root@docker web02]# vim app-server
  4. [root@docker web02]# cat app-server
  5. package main
  6. import (
  7. "github.com/gin-gonic/gin"
  8. "net/http"
  9. )
  10. func main() {
  11. router := gin.Default()
  12. router.GET("/ping", func(c *gin.Context) {
  13. c.String(http.StatusOK, "PONG")
  14. })
  15. router.Run(":8080")
  16. }

12.2 解决⽅案

我们最终的⽬的都是将最终的可执⾏⽂件放到⼀个最⼩的镜像(⽐如 alpine )中去执⾏,怎样得到最终的编译好的⽂件呢?基于 Docker 的指导思想,我们需要在⼀个标准的容器中编译,⽐如在⼀个
Ubuntu 镜像中先安装编译的环境,然后编译,最后也在该容器中执⾏即可。

但是如果我们想把编译后的⽂件放置到 alpine 镜像中执⾏呢?我们就得通过上⾯的 Ubuntu 镜像将编译完成的⽂件通过 volume挂载到我们的主机上,然后我们再将这个⽂件挂载到 alpine 镜像中去。

这种解决⽅案理论上肯定是可⾏的,但是这样的话在构建镜像的时候我们就得定义两步了,第⼀步是先⽤⼀个通⽤的镜像编译镜像,第⼆步是将编译后的⽂件复制到 alpine 镜像中执⾏,⽽且通⽤镜像编译后的⽂件在 alpine 镜像中不⼀定能执⾏。

定义编译阶段的 Dockerfile :(保存为Dockerfile.build)

  1. [root@docker web02]# vim Dockerfile.build
  2. [root@docker web02]# cat Dockerfile.build
  3. FROM golang
  4. WORKDIR /go/src/app
  5. ADD . /go/src/app
  6. RUN go get -u -v github.com/kardianos/govendor
  7. RUN govendor sync
  8. RUN GOOS=linux GOARCH=386 go build -v -o /go/src/app/app-server

定义 alpine 镜像:(保存为Dockerfile.old)

  1. [root@docker web02]# vim Dockerfile.old
  2. [root@docker web02]# cat Dockerfile.old
  3. FROM alpine:latest
  4. RUN apk add -U tzdata
  5. RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
  6. WORKDIR /root/
  7. COPY app-server .
  8. CMD ["./app-server"]

根据我们的执⾏步骤,我们还可以简单定义成⼀个脚本:(保存为build.sh)

  1. [root@docker web02]# vim build.sh
  2. [root@docker web02]# cat build.sh
  3. #!/bin/sh
  4. echo Building cnych/docker-multi-stage-demo:build
  5. docker build -t cnych/docker-multi-stage-demo:build . -f Dockerfile.build
  6. docker create --name extract cnych/docker-multi-stage-demo:build
  7. docker cp extract:/go/src/app/app-server ./app-server
  8. docker rm -f extract
  9. echo Building cnych/docker-multi-stage-demo:old
  10. docker build --no-cache -t cnych/docker-multi-stage-demo:old . -f Dockerfile.old
  11. rm ./app-server
  1. [root@docker web02]# chmod +x build.sh
  2. [root@docker web02]# ll -d build.sh
  3. -rwxr-xr-x 1 root root 423 2 7 18:17 build.sh
  4. [root@docker web02]# sh build.sh

当我们执⾏完上⾯的构建脚本后,就实现了我们的⽬标。http://192.168.200.8:8080/ping

image_1etu3dkb38snqvese11a162f41.png-291.5kB

12.3 多阶段构建

有没有⼀种更加简单的⽅式来实现上⾯的镜像构建过程呢?Docker 17.05版本以后,官⽅就提供了一个新的特性: Multi-stage builds (多阶段构建)。 使⽤多阶段构建,你可以在⼀个Dockerfile中使⽤多个 FROM 语句。每个 FROM 指令都可以使⽤不同的基础镜像,并表示开始⼀个新的构建阶段。你可以很⽅便的将⼀个阶段的⽂件复制到另外⼀个阶段,在最终的镜像中保留下你需要的内容即可。

我们可以调整前⾯⼀节的 Dockerfile 来使⽤多阶段构建:(保存为Dockerfile)

  1. [root@docker ~]# mkdir web03
  2. [root@docker ~]# cd web03/
  3. [root@docker web03]# vim Dockerfile
  4. [root@docker web03]# cat Dockerfile
  5. FROM golang AS build-env
  6. ADD . /go/src/app
  7. WORKDIR /go/src/app
  8. RUN go get -u -v github.com/kardianos/govendor
  9. RUN govendor sync
  10. RUN GOOS=linux GOARCH=386 go build -v -o /go/src/app/app-server
  11. FROM alpine
  12. RUN apk add -U tzdata
  13. RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
  14. COPY --from=build-env /go/src/app/app-server /usr/local/bin/app-server
  15. EXPOSE 8080
  16. CMD [ "app-server" ]

现在我们只需要⼀个 Dockerfile ⽂件即可,也不需要拆分构建脚本了,只需要执⾏ build 命令即可:

  1. [root@docker web03]# docker build -t cnych/docker-multi-stage-demo:latest .

默认情况下,构建阶段是没有命令的,我们可以通过它们的索引来引⽤它们,第⼀个 FROM 指令从 0 开始,我们也可以⽤ AS 指令为阶段命令,⽐如我们这⾥的将第⼀阶段命名为 build-env ,然后在其他阶段需要引⽤的时候使⽤ --from=build-env 参数即可。

最后我们简单的运⾏下该容器测试:

  1. [root@docker web03]# docker run --rm -p 8080:8080 cnych/docker-multi-stage-demo:latest

运⾏成功后,我们可以在浏览器中打开 http://192.168.200.8:8080/ping 地址,可以看到PONG返回。

image_1eu5krt3m1oui1dqkgpi12q13981p.png-29.6kB

现在我们就把两个镜像的⽂件最终合并到⼀个镜像⾥⾯了。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注