Advertisement

Docker 笔记 1:Docker 基础与搭建第一个 Docker 应用栈

阅读量:

源自《Docker 容器与容器云(第2版)》这本书。

如需进一步了解,请访问我的个人博客内容[https://abelsu7.top/2019/08/docker-notes/]。

《Docker 容器与容器云(第2版)》

1. 从容器到容器云

1.1 云计算平台

经典云计算架构 包含 IaaS (Infrastructure as a Service)、PaaS (Platform as a Service)以及 SaaS (Software as a Service)这三个层次的服务。如图所示。

云平台经典架构

1.2 容器技术生态系统

容器技术生态系统

可以看出这一套体系从上到下涵盖了许多关键领域具体来说涉及到了资源调度作业调度以及优化配置管理和优化流程存储网络管理实时监控与日志分析安全防护以及为容器化应用提供完整的支撑平台

  • 持续部署与测试:通过容器技术实现了线上与线下环境的一致性管理,并保证了应用运行环境的一致性和标准化。
  • 跨云平台支持:越来越多的云平台都已经引入了容器技术的支持体系。
  • 环境标准化与版本控制:可采用Git等工具对容器镜像进行版本管理。相较于基于代码的传统版本控制方式,在应用层面实现了更加全面的功能覆盖;一旦出现故障能够快速实现回滚操作;相比传统虚拟机镜像的优势在于压缩备份速度更快且启动效率更高。
  • 资源利用率优化与隔离性提升:相比传统虚拟化方案,在容器架构下没有多余的管理程序开销;能够直接利用底层操作系统资源性能更为卓越;负载压力更低的同时还具备优秀的资源隔离能力;精确分配CPU、内存等关键资源保障各服务组件独立运行。
  • 容器化技术革新:基于传统Linux容器架构的基础上进行了重大创新改进;制定了一套完整统一的标准配置方法;将应用程序及其运行所依赖的系统环境打包成统一形式的镜像文件;显著提升了容器在多平台环境下运行的高度兼容性和灵活性。
  • 易用性提升推动标准化进程:Docker的技术理念源于"集装箱码头工"这一形象比喻;通过这种直观易懂的形象化展示帮助加速了容器化开发实践向产业化的推广进程。
  • 开放共享的应用镜像库:Docker官方发布了一个公共的应用镜像仓库系统;该系统已收集整理了海量的应用级镜像文件库 resources available for public access and download by developers across the board.

1.3 从容器到容器云

基于容器技术的服务架构(Container Service Model)将计算资源划分为独立且可配置的资源划分与管理的核心单元(Resource Partition & Management Core),并整合了完整的软件运行环境(Software Execution Environment),为此类用户提供了一整套开发构建及部署管理功能(Build, Deploy & Manage Functionality)。

  • 当容器云聚焦于共享资源并实现隔离以及组织架构和部署流程时, 它趋向于传统意义上的IaaS架构
    • 当容器云深入应用支撑系统及其运行环境时, 它趋向于传统意义上的PaaS架构

容器云并非仅局限于 Docker, 基于 rkt 容器的 CoreOS 项目同样属于这一范畴.最初发布时,Docker仅作为一个单机应用提供基础功能,后来,Docker推出了 Compose,Machines 和 Swarm 这些编排部署工具,同时收购了 Socketplane 来解决集群化过程中的网络挑战.

除Docker公司外,在云计算领域投入巨额资金进行研发的企业还有很多。例如Fleet、Flynn和Deis等公司均为广为人知的容器云平台,并且它们均基于Docker技术构建,并在该领域占据重要地位;而Kubernetes则成为了行业内的事实主流标准

2. Docker 基础

2.1 Docker 的安装

安装 Docker基本要求 如下:

  • 目前仅兼容 64 位 CPU 架构 的计算机;但现有的设备无法运行该软件。
  • 建议将系统内核版本升级至3.10及其以上版本。
  • 应启用 Linux 内核 中的 cgroupsnamespace 功能;确保系统运行稳定;同时允许资源隔离性分配。

安装步骤说明可供参考访问以下链接地址:CentOS 7 安装 Docker CE

2.2 Docker 操作参数解读

docker命令的执行一般都需要 root 权限 ,因为 Docker 的命令行工具dockerDocker daemon 是同一个二进制文件 ,而 Docker daemon 负责接收并执行来自docker的命令,它的运行需要 root 权限 。同时,从 Docker 0.5.2 版本开始,Docker daemon 默认绑定一个 UNIX Socket 来代替原有的 TCP 端口,该 UNIX Socket 默认是属于 root 用户的。

用户在使用 Docker 时,默认会调用 Docker 行为代理工具(DCAT) 使用其管理功能模块(MAM),而无需手动配置 MAM 配置文件即可实现容器编排功能的开启与关闭操作。此外,在容器编排功能开启的状态下,默认情况下容器会被分配到一个虚拟机上运行;如果需要,则可以根据实际需求选择重新分配到其他虚拟机上运行或者关闭容器服务。
通过调用 docker run -it <container_name> 或者 docker exec -it <container_name>, 用户可以启动或切换到该容器实例进行操作;通过调用 docker ps -a | grep <container_name> 或者 docker logs <container_name>, 用户能够查询到该容器的运行状态信息以及相关日志信息。

复制代码
    > docker
    
    Usage:  docker [OPTIONS] COMMAND
    
    A self-sufficient runtime for containers
    
    Options:
      --config string      Location of client config files (default "/root/.docker")
      -D, --debug              Enable debug mode
      -H, --host list          Daemon socket(s) to connect to
      -l, --log-level string   Set the logging level ("debug"|"info"|"warn"|"error"|"fatal") (default "info")
      --tls                Use TLS; implied by --tlsverify
      --tlscacert string   Trust certs signed only by this CA (default "/root/.docker/ca.pem")
      --tlscert string     Path to TLS certificate file (default "/root/.docker/cert.pem")
      --tlskey string      Path to TLS key file (default "/root/.docker/key.pem")
      --tlsverify          Use TLS and verify the remote
      -v, --version            Print version information and quit
    
    Management Commands:
      config      Manage Docker configs
      container   Manage containers
      image       Manage images
      network     Manage networks
      node        Manage Swarm nodes
      plugin      Manage plugins
      secret      Manage Docker secrets
      service     Manage services
      stack       Manage Docker stacks
      swarm       Manage Swarm
      system      Manage Docker
      trust       Manage trust on Docker images
      volume      Manage volumes

例如可以使用docker start --help命令来获取子命令start的详细信息:

复制代码
    > docker start --help
    
    Usage:  docker start [OPTIONS] CONTAINER [CONTAINER...]
    
    Start one or more stopped containers
    
    Options:
      -a, --attach               Attach STDOUT/STDERR and forward signals
      --detach-keys string   Override the key sequence for detaching a container
      -i, --interactive          Attach container's STDIN

参考链接

根据命令的用途 ,可将 Docker 子命令 进行如下分类

Docker 子命令分类

docker命令的使用 出发,可以梳理出如下的命令结构图

Docker 命令结构图

下面选择每个功能分类中常用的子命令 进行用法和操作参数 的解读。

1. Docker 环境信息

docker info 命令用于检测 Docker 是否正确安装。当 Docker 正确安装时,此命令会输出 Docker 的配置信息

复制代码
    > docker info
    Containers: 33
     Running: 20
     Paused: 0
     Stopped: 13
    Images: 23
    Server Version: 18.06.1-ce
    Storage Driver: overlay2
    ...
    Kernel Version: 4.15.0-38-generic
    Operating System: Ubuntu 18.04.1 LTS
    ...

docker info命令一般结合docker version命令使用,两者结合能够提取到足够详细的 Docker 环境信息

复制代码
    > docker version
    Client:
     Version:           18.06.1-ce
     API version:       1.38
     Go version:        go1.10.3
     Git commit:        e68fc7a
     Built:             Tue Aug 21 17:24:56 2018
     OS/Arch:           linux/amd64
     Experimental:      false
    
    Server:
     Engine:
      Version:          18.06.1-ce
      API version:      1.38 (minimum version 1.12)
      Go version:       go1.10.3
      Git commit:       e68fc7a
      Built:            Tue Aug 21 17:23:21 2018
      OS/Arch:          linux/amd64
      Experimental:     false
2. 容器生命周期管理

容器生命周期管理涉及容器启动、停止等功能。

docker run 命令

docker run命令使用方法如下:

复制代码
    docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

以特定的镜像为基础创建一个容器,并根据选项进行设置和管理

复制代码
    > docker run ubuntu echo "Hello Docker"
    Hello Docker

该命令通过 Ubuntu 镜像开始运行一个新容器,并随后执行 echo 命令输出 Hello Docker 字符串。在完成 echo 命令操作后,系统将会自动终止该容器的运行状态。使用 docker run 命令启动的每个新容器都会被系统自动生成并分配一个独一无二的 CONTAINER ID ,以便于后续对各个独立运行的任务进行管理和监控。

复制代码
    root@ubuntu:~> docker run -i -t --name mytest ubuntu:latest /bin/bash
    root@eb9dda25b0fe:/>

改写说明

  • --name:可以设置启动容器的名称。若无此参数,则Docker系统会为容器随机生成一个名称。
  • -c:用于给运行在容器中的所有进程分配CPU shares值。这是一个相对权重指标,在实际处理中还与宿主机的CPU性能相关联。
  • -m <value>:用于限定为容器中所有进程分配的内存总量。单位可选B、K、M、G。
  • -v <hostDir>/<containerDir><[rw]>:用于挂载 volumes。可以通过多个-v参数同时挂载多个 volumes。
  • -p <hostPort><containerPort>:用于将容器映射到宿主机上的特定端口。常用格式为hostPort:containerPort。
docker start/stop/restart 命令

现有容器实例可以通过docker start/stop/restart命令实现启停操作,在实际应用中通常会通过container ID来唯一标识一个特定的容器;在特殊场景下也可以通过指定container name来进行明确的识别。

在 Docker 中启动时可配置以下参数:首先通过 -i 参数启动交互式模式的同时,并始终保持输入流的开放;其次通过 -a 参数添加标准输入、标准输出以及错误信息;另外,在 Docker Stop 和 Docker Restart 命令中通过 -t 参数设置容器停止前的等待时间

3. Docker registry

Docker registry 作为一个存储着容器镜像的平台,在这个系统中用户可以通过 Docker client 实现了与 Docker registry 的互动。这一功能涵盖了对镜像文件进行搜索、下载以及上传等多种操作。

Docker Hub 由 Docker 公司官方运营,并提供了多样化的镜像存储服务。
这些服务包括公有和私有的存储选项。
作为当前应用最广泛的主要镜像源之一。
此外,用户也可以自行构建私有服务器以满足特定需求。

docker pull 命令

用于从 Docker registry 中拉取 imagerepository

复制代码
    docker pull [OPTIONS] NAME[:TAG @DIGEST]

使用示例如下:

复制代码
    # 从官方 Hub 拉取 ubuntu:latest 镜像
    > docker pull ubuntu
    # 从官方 Hub 拉取指明 "ubuntu 16.04" tag 的镜像
    > docker pull ubuntu:16.04
    # 从特定的仓库拉取 ubuntu 镜像
    > docker pull SEL/ubuntu
    # 从其他服务器拉取镜像
    > docker pull 10.10.103.215:5000/sshd
docker push 命令

用于将本地的 imagerepository 推送到 Docker Hub 的公共或私有镜像存储库及其对应的私有服务器平台

复制代码
    docker push [OPTIONS] NAME[:TAG]

使用示例如下:

复制代码
    > docker push SEL/ubuntu
4. 镜像管理

用户可以在本地保存镜像资源 ,为此 Docker 提供了相应的管理子命令。

docker images 命令

通过 docker images 命令可以 生成主机上的镜像 ,默认情况下只生成顶层镜像。使用 -a 选项可以 展示所有镜像信息

复制代码
    docker images [OPTIONS] [REPOSITORY[:TAG]]

使用示例如下:

复制代码
    > docker images
    REPOSITORY                    TAG                 IMAGE ID            CREATED             SIZE
    ubuntu                        16.04               b0ef3016420a        11 days ago         117MB
    influxdb                      latest              623f651910b3        7 weeks ago         238MB
    memcached                     latest              8230c836a4b3        7 weeks ago         62.2MB
    mongo                         3.2                 fb885d89ea5c        7 weeks ago         300MB
    mist/mailmock                 latest              95c29bda552f        7 weeks ago         299MB
    mist/docker-socat             latest              f00ed0eed13f        7 weeks ago         7.8MB
    mistce/logstash               v3-3-1              0f90a36d12c8        2 months ago        730MB
    mistce/api                    v3-3-1              4a21b676352f        2 months ago        705MB
    mistce/nginx                  v3-3-1              4f55dd9b39e0        2 months ago        109MB
    mistce/gocky                  v3-3-1              ee93caf66f70        2 months ago        440MB
    mistce/elasticsearch-manage   v3-3-1              10a48b9ea0e1        2 months ago        65.8MB
    mistce/ui                     v3-3-1              b8fdbe0ccb23        2 months ago        626MB
    ubuntu-with-vi-dockerfile     latest              74ba87f80b96        2 months ago        169MB
    ubuntu-with-vi                latest              9d2fac08719d        2 months ago        169MB
    ubuntu                        latest              ea4c82dcd15a        2 months ago        85.8MB
    centos                        latest              75835a67d134        3 months ago        200MB
    hello-world                   latest              4ab4c602aa5e        4 months ago        1.84kB
    elasticsearch                 5.6.10              73e6fdf8bd4f        4 months ago        486MB
    mistce/landing                v3-3-1              b0e433749aa9        5 months ago        532MB
    kibana                        5.6.10              bc661616b61c        5 months ago        389MB
    hello-world                   <none>              2cb0d9787c4d        6 months ago        1.85kB
    traefik                       v1.5                fde722950ccf        9 months ago        49.7MB
    mist/swagger-ui               latest              0b5230f1b6c4        10 months ago       24.8MB
    rabbitmq                      3.6.6-management    c74093aa9895        22 months ago       179MB

上例中,通过REPOSITORY属性可以识别出镜像类型属于官方或个人存储空间的镜像类型。

docker rmi/rm 命令

docker rmi 命令用于执行镜像删除操作 ,而 docker rm 命令则用于执行容器删除操作 。这些命令不仅支持批量处理多个镜像或容器的删除操作,并且还提供了基于条件的不同层次化删除功能。

复制代码
    docker rm [OPTIONS] CONTAINER [CONTAINER...]
    docker rmi [OPTIONS] IMAGE [IMAGE...]

通过docker rmi命令来删除镜像时,
若已有基于该镜像运行中的容器存在,
则无法直接执行操作,
必须先清理正在运行的容器。
请注意这些子命令均提供--force选项以强制删除已存在的镜像及其运行中的容器。

5. 容器运维操作

Docker 的核心组成部分包括对 container 的操作和管理。该平台为用户提供了大量用于 container 管理和维护的操作指令。

docker attach 命令

将该命令用于连接至正在运行的容器,并监控该容器的整体状态;同时还可以参与对其主进程的操作。

复制代码
    docker attach [OPTIONS] CONTAINER
docker inspect 命令

docker inspect命令可分析显示镜像及其运行中的容器状态详情 ,此操作默认会列出所有相关信息;若需仅获取特定类型的信息,则可通过指定合适的选项参数来进行过滤处理:

此外用户还可以选择以下几种不同的输出格式以满足不同场景的需求:

  • 基本列表形式
  • 详细日志记录
  • 统计摘要报告
  • 高级定制视图
复制代码
    docker inspect [OPTIONS] CONTAINER|IMAGE [CONTAINER|IMAGE...]

具体示例如下:

复制代码
    > docker inspect --format='{{.NetworkSettings.IPAddress}}' ee36
    172.17.0.8
docker ps 命令

该命令能够以简洁的方式展示与容器相关的详细信息,默认情况下仅列出处于运行状态下的容器数据。具体可获取的信息包括: CONTAINER ID 用于标识当前运行中的虚拟机; NAMES 列出所有已连接到同一宿主机上的容器名称; IMAGE 表示当前运行的镜像文件路径; STATUS 描述容器当前的状态; COMMAND 显示容器内的完整运行指令; CREATED 表明该容器创建的时间戳; PORTS 列出已启用的所有网络端口信息:

复制代码
    docker ps [OPTIONS]

用于查看Docker服务中所有运行状态的命令通常包含--all(-a)和--latest(-l)参数。其中--all参数能够显示所有运行中的容器以及已停止运行的容器;而--latest参数则仅列出最近创建并尚未完成启动的所有新容器。

复制代码
    > docker ps -a
    CONTAINER ID        IMAGE                       COMMAND                 CREATED             STATUS                         PORTS               NAMES
    8befe85aa9b2        ubuntu                      "/bin/bash"             4 minutes ago       Exited (0) 4 minutes ago                           elegant_hawking
    eb9dda25b0fe        ubuntu:latest               "/bin/bash"             About an hour ago   Exited (0) About an hour ago                       mytest
    33be0880de8a        ubuntu                      "echo 'Hello Docker'"   About an hour ago   Exited (0) About an hour ago                       loving_neumann
    9dbd65001cc2        ubuntu                      "echo hello"            About an hour ago   Exited (0) About an hour ago                       zealous_mendeleev
    ee10555e84be        hello-world                 "/hello"                About an hour ago   Exited (0) About an hour ago                       friendly_mestorf
    4219345c98a0        ubuntu-with-vi-dockerfile   "/bin/bash"             2 months ago        Exited (0) 2 months ago                            ecstatic_wilson
    7257b9828da4        centos                      "/bin/bash"             2 months ago        Exited (0) 2 months ago                            hopeful_chaplygin
    26119a6e11bd        centos                      "/bin/bash"             2 months ago        Exited (0) 2 months ago                            brave_khorana
    f48bc1339340        ubuntu-with-vi              "/bin/bash"             2 months ago        Exited (127) 2 months ago                          agitated_hugle
    1abe6e7341ca        ubuntu                      "/bin/bash"             2 months ago        Exited (0) 2 months ago                            laughing_leavitt
    5c5eabb13be4        hello-world                 "/hello"                2 months ago        Exited (0) 2 months ago                            eloquent_wiles
    8f2f6854078c        2cb0d9787c4d                "/hello"                4 months ago        Exited (0) 4 months ago                            goofy_sinoussi
    
    > docker ps -l
    CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                     PORTS               NAMES
    8befe85aa9b2        ubuntu              "/bin/bash"         6 minutes ago       Exited (0) 6 minutes ago                       elegant_hawking
6. 其他子命令
docker commit 命令

docker commit命令可以将一个容器固化为一个新的镜像

复制代码
    docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]

提交保存时, 必须依赖已运行的容器作为基础来生成新镜像 。当构建特定镜像时,默认采用docker commit命令仅作为辅助操作, 不推荐直接调用该命令进行操作。官方指导方针指出, 应通过docker build命令结合 Dockerfile 来创建并管理镜像。

docker events/history/logs 命令

这三个 Docker 命令(包括 docker events、docker history 和 docker logs)被用来获取与 Docker 系统日志相关的详细信息。
使用 docker events 命令可以查看当前系统的实时活动情况。
通过 docker history 命令可以获得指定镜像的历史版本数据,并了解其构建过程中所使用的每一步骤操作。
使用 docker logs 命令可以获取到与当前运行中的容器相关联的所有详细日志记录。

复制代码
    docker events [OPTIONS]
    docker history [OPTIONS] IMAGE
    docker logs [OPTIONS] CONTAINER

2.3 搭建第一个 Docker 应用栈

Docker 核心理念旨在确保每个容器独立执行单一任务。即仅支持单一功能模块的一般情况而言。通过多节点配置实现多样化服务功能,并在之间建立通信连接组织成 Docker 集群结构。

基于 Docker 集群构建的应用称为 Docker App Stack ,即 Docker 应用栈

以下示例将被用来在单一计算设备上通过 Docker 提供的命令行工具构建一个 Docker 应用架构,并通过多容器组合来实现特定功能。

在构建 Docker 应用栈之前, 需要对所涉及的应用栈进行基本的设计与说明: 其中将构建一个包含六个节点的应用栈, 其中包括一个代理节点, 两个 Web 节点, 一个主数据库节点以及两个从数据库节点. 具体架构如图所示: 代理节点负责接收请求并转发给相应的 Web 节点; 每个 Web 节点独立运行并响应客户端请求; 主数据库 node 负责存储核心数据; 各个从数据库 node 分别连接到主数据库 node 并提供数据读取服务.

Docker 应用栈结构图

如图所示,
HAProxy 负载均衡代理节点。
Redis是非关系型数据库,由一个主数据库节点和两个从数据库节点组成。
App是应用,这里将使用Python语言基于Django架构设计一个基础Web应用用于访问数据库。

1. 获取应用栈各节点所需镜像

在构建过程中,可以通过访问 Docker Hub 获得一系列可选镜像,在这些镜像之上运行容器,并根据具体需求进行配置以达成预期目标的功能实现。

复制代码
    > docker pull ubuntu
    > docker pull django
    > docker pull haproxy
    > docker pull redis
    > docker images
    
    REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
    haproxy             latest              d23194a3929a        40 hours ago        72MB
    redis               latest              5d2989ac9711        12 days ago         95MB
    ubuntu              latest              1d9c17228a9e        12 days ago         86.7MB
    django              latest              eb40dcf64078        2 years ago         436MB
2. 应用栈容器节点互联

基于同一主机环境下构建容器应用栈的需求,在于通过完成容器互联任务来实现各容器间的通信目标。可以选择使用docker运行命令中的--link选项来创建各节点之间的互联关系。

复制代码
    > docker run --link redis:redis --name console ubuntu bash

在Ubuntu镜像上将会创建并命名为console的一个新容器,并将其与名称为redis的容器进行连接

采用--link参数配置容器间通信机制时,在确保系统安全性的同时,并非仅止于防护容器对外暴露的IP和端口以规避外网安全风险;即使容器重启导致IP地址变更也可能不会影响服务可用性;其运行机制与DNS服务器如何解析域名与IP地址具有高度相似之处。

回到应用栈的搭建,应用栈各节点的连接信息 如下:

  • 通过启动指定的Redis主节点
  • 在启动阶段需确保两个Redis从节点与主 Redis 节点之间建立通信
  • 为了保证系统的稳定性,在应用部署阶段需将两台应用型容器与主 Redis 节点进行连通设置
  • 当 HAProxy 容器开始运行时,请确认其能够成功与两台应用型容器进行数据交互

综上所述,容器的启动顺序为:

复制代码
    redis-master --> redis-slave --> APP --> HAProxy

此外,为了能够从外网访问应用栈 ,并通过 HAProxy 节点来访问应用栈中的 App ,在启动 HAProxy 容器节点时,需要利用-p参数暴露端口给主机 ,即可从外网访问搭建的应用栈。以下是整个应用栈的搭建流程示例。

3. 应用栈容器节点启动
复制代码
    # 启动 Redis 容器
    > docker run -it --name redis-master redis /bin/bash
    > docker run -it --name redis-slave1 --link redis-master:master redis /bin/bash
    > docker run -it --name redis-slave2 --link redis-master:master redis /bin/bash
    
    # 启动 Django 容器,即应用
    > docker run -it --name APP1 --link redis-master:db -v ~/Projects/Django/App1:/usr/src/app django /bin/bash
    > docker run -it --name APP2 --link redis-master:db -v ~/Projects/Django/App2:/usr/src/app django /bin/bash
    
    # 启动 HAProxy 容器
    > docker run -it --name HAProxy --link APP1:APP1 --link APP2:APP2 -p 6301:6301 -v ~/Projects/HAProxy:/tmp haproxy /bin/bash

启动的容器信息可以通过docker ps命令查看:

复制代码
    > docker ps
    CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
    733e71e16ac5        haproxy             "/docker-entrypoint.…"   30 seconds ago      Up 29 seconds       0.0.0.0:6301->6301/tcp   HAProxy
    3f91ac2a23a6        django              "/bin/bash"              47 seconds ago      Up 46 seconds                                APP2
    e94c7ff2c319        django              "/bin/bash"              3 minutes ago       Up 3 minutes                                 APP1
    5e7994e6ad59        redis               "docker-entrypoint.s…"   5 minutes ago       Up 4 minutes        6379/tcp                 redis-slave2
    6fac6db730c3        redis               "docker-entrypoint.s…"   8 minutes ago       Up 8 minutes        6379/tcp                 redis-slave1
    936c426faa29        redis               "docker-entrypoint.s…"   8 minutes ago       Up 8 minutes        6379/tcp                 redis-master

至此,所有搭建应用栈所需容器的启动工作已经完成。

4. 应用栈容器节点的配置
Redis Master 主数据库容器节点的配置

Redis Master

基于容器架构的轻量化优化,在缺少必要的文本编辑命令工具的情况下,
此时可以通过启动体积挂载命令volume来实现文件的创建。
当容器启动时,
通过指定参数 -v 来挂载体积,
在主机系统与容器之间建立数据共享机制。
因此,在宿主操作系统上即可方便地执行创建与编辑操作。

当使用 Redis 镜像启动一个容器时

复制代码
    > docker inspect --format "{{.Mounts}}" redis-master
    [{volume a77509a99df7d7a9d78313c1a1bb19619bac98fedadd78dbab17f072a49a905c /var/lib/docker/volumes/a77509a99df7d7a9d78313c1a1bb19619bac98fedadd78dbab17f072a49a905c/_data /data local  true }]

可以识别出,在宿主系统中运行的 Docker 容器 volumes 被分配到特定的存储位置 /var/lib/docker/volumes/a77509a99df7d7a9d78313c1a1bb19619bac98fedadd78dbab17f072a49a905c/_data ,而这些数据在容器内部则存储于 /data 目录下。为了方便管理 Redis 数据库的应用程序初始化配置文件,请先访问宿主系统的 volumes 目录并创建相应的启动配置文件。

复制代码
    > cd /var/lib/docker/volumes/a77509a99df7d7a9d78313c1a1bb19619bac98fedadd78dbab17f072a49a905c/_data
    > cp <your-own-redis-dir>/redis.conf redis.conf
    > vim redis.conf

对于 Redis 主数据库 ,需要修改模板文件中的如下几个参数:

复制代码
    daemonize yes
    pidfile /var/run/redis.pid
    protected-mode no # 关闭保护模式

当主机完成启动配置文件的设置后,在容器内切换至 volume 目录,并将 redis.conf 文件复制至 Redis 的工作目录中;随后启动 Redis 服务器

复制代码
    > cd /data
    > cp redis.conf /usr/local/bin/
    > cd /usr/local/bin/
    > redis-server redis.conf
Redis Slave 从数据库容器节点的配置

类似于redis-master容器节点的设置流程,在启动redis-slave容器节点后

复制代码
    daemonize yes
    pidfile /var/run/redis.pid
    protected-mode no # 关闭保护模式
    replicaof master 6379 # 之前是 slaveof

replicaof参数的使用格式replicaof <masterip> <masterport>

在主机上优化完成redis.conf配置文件后,并进入容器进入到指定的/data目录,并将相关配置内容移动至Redis的服务执行工作目录中;随后启动Redis服务:

复制代码
    > cd /data
    > cp redis.conf /usr/local/bin/
    > cd /usr/local/bin/
    > redis-server redis.conf
    594:C 10 Jan 2019 23:10:43.936 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
    594:C 10 Jan 2019 23:10:43.936 # Redis version=5.0.3, bits=64, commit=00000000, modified=0, pid=594, just started
    594:C 10 Jan 2019 23:10:43.936 # Configuration loaded

同理也可实现对另一个Redis_SLAVE容器节点的配置过程。至此已完成所有Redis数据库容器节点的配置工作。

Redis 数据库容器节点的测试

首先配置并运行Redis MasterRedis Slave容器节点参数设置之后,在服务器启动完成之后,则可以通过运行命令redis-cli来进行数据库测试。

首先配置并运行Redis MasterRedis Slave容器节点参数设置之后,在服务器启动完成之后,则可以通过运行命令redis-cli来进行数据库测试。

首先,在redis-master容器内,启动redis-cli,并存储一个数据:

复制代码
    > redis-cli
    127.0.0.1:6379> info replication
    # Replication
    role:master
    connected_slaves:2
    slave0:ip=172.17.0.3,port=6379,state=online,offset=1260,lag=0
    slave1:ip=172.17.0.4,port=6379,state=online,offset=1260,lag=0
    master_replid:295c948cc1bbdf21eb49fdd8417ba5b4b76fc32b
    master_replid2:0000000000000000000000000000000000000000
    master_repl_offset:1260
    second_repl_offset:-1
    repl_backlog_active:1
    repl_backlog_size:1048576
    repl_backlog_first_byte_offset:1
    repl_backlog_histlen:1260
    127.0.0.1:6379> set master 936c
    OK
    127.0.0.1:6379> get master
    "936c"

随后,在Redis集群的两个节点容器`redis-slave1 redis-slave2中依次运行指定的Redis命令行工具(如 redis-cli),并执行以下操作:首先定位到主节点容器中的Redis master实例位置(如 redis-master$),然后检查或检索之前已存入到该数据库中的相关信息或记录

复制代码
    > redis-cli
    127.0.0.1:6379> info replication
    # Replication
    role:slave
    master_host:master
    master_port:6379
    master_link_status:up
    master_last_io_seconds_ago:3
    master_sync_in_progress:0
    slave_repl_offset:1330
    slave_priority:100
    slave_read_only:1
    connected_slaves:0
    master_replid:295c948cc1bbdf21eb49fdd8417ba5b4b76fc32b
    master_replid2:0000000000000000000000000000000000000000
    master_repl_offset:1330
    second_repl_offset:-1
    repl_backlog_active:1
    repl_backlog_size:1048576
    repl_backlog_first_byte_offset:127
    repl_backlog_histlen:1204
    127.0.0.1:6379> get master
    "936c"

我们能够看到redis-master主数据库的数据实现了自动同步到两个从数据库中,并且在应用栈的数据库架构中已完成搭建工作并经过测试验证。

APP 容器节点( Django)的配置

Django 容器启动后,需要利用 Django 框架,开发一个简单的 Web 程序。

为了访问数据库,需要在容器中安装 Python 语言的 Redis 支持包

复制代码
    > pip install redis

安装完成后,验证 Redis 支持包是否安装成功

复制代码
    > python
    Python 3.4.5 (default, Dec 14 2016, 18:54:20) 
    [GCC 4.9.2] on linux
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import redis
    >>> print(redis.__file__)
    /usr/local/lib/python3.4/site-packages/redis/__init__.py

若未出现错误,则表明可以通过Python语言访问Redis数据库。随后启动Web程序。例如,在/volume目录下创建APP:

复制代码
    # 在容器内
    > cd /usr/src/app/
    > mkdir dockerweb
    > cd dockerweb/
    > django-admin.py startproject redisweb
    > ls
    redisweb
    > cd redisweb
    > ls
    manage.py redisweb
    > python manage.py startapp helloworld
    > ls
    helloworld manage.py redisweb

在容器内成功创建APP后,请转至主机指定位置下的~/Projects/Django/App1$目录,并根据需求完成必要的修改以配置APP。

复制代码
    # 在主机内
    > cd ~/Projects/Django/App1
    > ls
    dockerweb

可以看到,在容器内部创建的应用程序文件位于主机下的volume目录中,并且也能够被访问到。之后将helloworld应用的其对应的视图文件views.py进行更新:

复制代码
    > cd dockerweb/redisweb/helloworld
    > ls
    admin.py  __init__.py  models.py  views.py  apps.py   migrations  tests.py
    > vim views.py

为简化设计仅要求完成Redis数据库信息输出以及从Redis数据库中存储和读取数据的结果输出

复制代码
    from django.shortcuts import render
    from django.http import HttpResponse
    
    # Create your views here.
    import redis
    
    def hello(request):
    str = redis.__file__
    str += "<br>"
    r = redis.Redis(host="db", port=6379, db=0)
    info = r.info()
    str += ("Set Hi <br>")
    r.set('Hi', 'HelloWorld-APP1')
    str += ("Get Hi: %s <br>" % r.get('Hi'))
    str += ("Redis Info: <br>")
    str += ("Key: Info Value")
    for key in info:
        str += ("%s: %s <br>" % (key, info[key]))
    return HttpResponse(str)

在完成 views.py 文件的修改之后,在接下来的时间段内会调整 redisweb 项目的配置文件 setting.py。随后会新增一个名为 helloworld 的应用。

复制代码
    > cd ../redisweb/
    > ls
    __init__.py  __pycache__  settings.py  urls.py  wsgi.py
    > vim settings.py

settings.py$...$文件中的...INSTALLED_APPS...变量中新增一个名为helloworld的项,并进一步调整其对应的...ALLOWED_HOSTS...设置。

复制代码
    # SECURITY WARNING: don't run with debug turned on in production!
    DEBUG = True
    
    ALLOWED_HOSTS = ['*']
    
    
    # Application definition
    
    INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'helloworld'
    ]

此处为了演示目的方便起见,默认将ALLOWED_HOSTS配置为支持任意域名访问的情况,在实际开发过程中建议不要采用此配置方式。而在生产环境中则需要关闭调试模式这一选项以确保系统的稳定运行。

最后,在redisweb项目的 URL 模式文件urls.py$中进行更新操作。该模块旨在配置访问应用的 URL 路径设置 ,并为每个 URL 路径建立与相应视图函数之间的明确关联关系。

复制代码
    > vim urls.py

为了在Python文件 urls.py 中导入 helloworld 应用的 hello 视图,并为此处添加一个 urlpatterns 变量以完成 URL 配置,请参考以下代码:

复制代码
    from django.conf.urls import url
    from django.contrib import admin
    from helloworld.views import hello
    
    urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^helloworld$', hello),
    ]

在主机上修改完成后几个文件后,在APP1容器中进行配置,并在目录/usr/src/app/dockerweb/redisweb下启动项目生成流程。

复制代码
    > python manage.py makemigrations
    No changes detected
    > python manage.py migrate
    Operations to perform:
      Apply all migrations: admin, auth, contenttypes, sessions
    Running migrations:
      Applying contenttypes.0001_initial... OK
      Applying auth.0001_initial... OK
      Applying admin.0001_initial... OK
      Applying admin.0002_logentry_remove_auto_add... OK
      Applying contenttypes.0002_remove_content_type_name... OK
      Applying auth.0002_alter_permission_name_max_length... OK
      Applying auth.0003_alter_user_email_max_length... OK
      Applying auth.0004_alter_user_username_opts... OK
      Applying auth.0005_alter_user_last_login_null... OK
      Applying auth.0006_require_contenttypes_0002... OK
      Applying auth.0007_alter_validators_add_error_messages... OK
      Applying auth.0008_alter_user_username_max_length... OK
      Applying sessions.0001_initial... OK
    > python manage.py createsuperuser
    Username (leave blank to use 'root'): admin
    Email address: admin@gmail.com
    Password: 
    Password (again): 
    Superuser created successfully.

旧版本的 Django 依赖于 syncdb 命令来进行数据库同步以及 admin 账户的生成。在新版 Django 中 syncdb 命令已被取代了 ,取而代之的是采用 createsuperuser 命令来生成管理员账户。

至此已完成对APP1$容器的所有配置设置,并对另一个APP2容器进行相同步骤的操作后,则完成了对应用栈 APP 部分的所有配置设置。

在启动 Web 服务器时可以配置服务绑定的网络接口参数。HAProxy容器节点允许所有公网IP访问从而确保资源分配均衡。对于一个应用程序比如APPSpecificName请详细说明启动过程:

复制代码
    > python manage.py runserver 0.0.0.0:8001
    Performing system checks...
    
    System check identified no issues (0 silenced).
    January 11, 2019 - 03:35:58
    Django version 1.10.4, using settings 'redisweb.settings'
    Starting development server at http://0.0.0.0:8001/
    Quit the server with CONTROL-C.
    [11/Jan/2019 03:37:01] "GET /helloworld HTTP/1.1" 200 3999
    [11/Jan/2019 03:37:14] "GET /admin/ HTTP/1.1" 200 2779
    ...
HAProxy 容器节点的配置

在实现了数据库服务及应用程序(APP)应用栈的部署后,在 HAProxy 负载均衡代理容器上实施了后续服务部署。随后,在 HAProxy 负载均衡代理容器上实施了后续服务部署。所有针对应用栈的访问均将通过 HAProxy 实现负载均衡策略。

注:此处为自动填充内容

复制代码
    > cd ~/Projects/HAProxy
    > vim haproxy.cfg

其中,haproxy.cfg配置文件 的内容如下:

复制代码
    global
    log 127.0.0.1  local0  # 日志输入配置,所有日志都记录在本机,通过 local0 输出
    maxconn 4096   # 最大连接数
    chroot /usr/local/sbin # 改变当前工作目录
    daemon         # 以后台形式运行 HAProxy 实例
    nbproc 4       # 启动 4 个 HAProxy 实例
    pidfile /usr/local/sbin/haproxy.pid  # pid 文件位置
    
    defaults
    log      127.0.0.1   local3   # 日志文件的输出定向
    mode     http           # { tcp|http|health } 设定启动实例的协议类型
    option   dontlognull    # 保证 HAProxy 不记录上级负载均衡发送过来的用于检测状态没有数据的心跳包
    option   redispatch     # 当 serverId 对应的服务器挂掉后,强制定向到其他健康>的服务器
    retries  2              # 重试 2 次连接失败就认为服务器不可用,主要通过后面的 check 检查
    maxconn  2000           # 最大连接数
    balance roundrobin      # balance 有两个可用选项:roundrobin 和 source,其中,roundrobin 表示
                            # 轮询,而 source 表示 HAProxy 不采用轮询的策略,而是把来自某个 IP 的请求转发给一个固定 IP 的后端
    timeout connect 5000ms  # 连接超时时间
    timeout client 50000ms  # 客户端连接超时时间
    timeout server 50000ms  # 服务器端连接超时时间
    
    listen redis_proxy 
    bind 0.0.0.0:6301
    stats enable
    stats uri /haproxy-stats
        server APP1 APP1:8001 check inter 2000 rise 2 fall 5  # 你的均衡节点
        server APP2 aPP2:8002 check inter 2000 rise 2 fall 5

随后,在容器的 volume 目录 /tmp 区域内,并将其启动配置文件转移至 HAProxy 的工作目录中:

复制代码
    # 在容器中
    > cd /tmp
    > cp haproxy.cfg /usr/local/sbin/
    > cd /usr/local/sbin/
    > ls
    haproxy  haproxy.cfg

接下来利用该配置文件来启动 HAProxy 代理

复制代码
    > haproxy -f haproxy.cfg

另外,在修改了配置文件内容时

复制代码
    > apt-get update
    > apt-get install procps # ps、pkill
    > apt-get install psmisc # killall
    > killall haproxy

至此已完成针对**HAProxy容器节点**的全面部署,并且同时成功实现了针对整个Docker应用栈的构建工作也已圆满完成。

应用栈访问测试

根据结构图可知

首先,在本地主机上运行测试程序。通过浏览器访问地址 http://172.17.0.7:6301/helloworld ,可以查看来自APP客户端或Web应用的页面内容。系统将根据负载情况将其负载均衡地分配到对应的容器节点上。其中使用的IP地址是 HAProxy容器服务所在IP地址

访问 APP1 容器节点
访问 APP2 容器节点

测试在本地环境顺利通过后,
进而尝试在宿主机的网络邻居节点中选择一个未被占用的端口进行连接,
并使用该宿主机提供的入口容器IP地址以及固定使用的HTTP服务端口6301,
访问该应用栈服务接口的URL http://宿主机IP:6301/helloworld
通过此方式可观察到来自APP1或APP2容器节点发送过来的数据包,
并可查看HAProxy后台运行状态及各项性能统计数据。
其中,
宿主机IP即为本机服务器运行的确切IP地址。

其他主机访问本地主机
HAProxy 后台管理页面

全部评论 (0)

还没有任何评论哟~