Docker 笔记 1:Docker 基础与搭建第一个 Docker 应用栈
源自《Docker 容器与容器云(第2版)》这本书。
如需进一步了解,请访问我的个人博客内容[https://abelsu7.top/2019/08/docker-notes/]。

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 内核 中的
cgroups和namespace功能;确保系统运行稳定;同时允许资源隔离性分配。
安装步骤说明可供参考访问以下链接地址:CentOS 7 安装 Docker CE
2.2 Docker 操作参数解读
docker命令的执行一般都需要 root 权限 ,因为 Docker 的命令行工具docker与 Docker daemon 是同一个二进制文件 ,而 Docker daemon 负责接收并执行来自docker的命令,它的运行需要 root 权限 。同时,从 Docker0.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命令的使用 出发,可以梳理出如下的命令结构图 :

下面选择每个功能分类中常用的子命令 进行用法和操作参数 的解读。
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 中拉取 image 或 repository :
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 命令
用于将本地的 image 或 repository 推送到 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 并提供数据读取服务.

如图所示,
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 Master和Redis Slave容器节点参数设置之后,在服务器启动完成之后,则可以通过运行命令redis-cli来进行数据库测试。
首先配置并运行Redis Master和Redis 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地址。


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


