1. 前言
为了加深自己的理解,方便以后针对公司项目提出优化建议,本文将从头开始根据官方文档简要的学习一下Dokcer。
关于Docker的部署安装,本文将直接略过
2. 容器
2.1 定义开发环境
过去,如果你要部署一个python程序,需要将应用copy到服务器上,并且下载源码包,进行编译,pip,运行。
期间可能会遇到各种各样的报错,依赖问题。 而docker的出现,正好解决了这个痛点。我们只需要编写一个Dockerfile即可。
2.2 编写Dockerfile
在本机新建一个空目录,并且CD进去。注意一个Dockerfile尽量单独占用一个目录。
1 | [root@localhost ~] |
- Dockerfile 内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21# Use an official Python runtime as a parent image
# 每个Dockerfile必须已FROM开头作为基础镜像
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所需要文件
requirements.txt
1
2Flask
Redisapp.py
1 | from flask import Flask |
创建Dockerfile
1 | [root@localhost flask]# ls |
2.2 运行容器
1 | docker run -p 4000:80 friendlyhello |

2.3 将容器推送至私有仓库
1 | docker tag a72fbd8c6be9 registry.cn-hangzhou.aliyuncs.com/momom/pythonflask:v0.1 |
3. docker-compose
docker-compose.yml文件是一个YAML文件,它定义了如何Docker容器在生产中应表现。
将此文件保存在docker-compose.yml任意位置。确保已将在第1部分中创建的图像推送到仓库,并通过替换为图像详细信息进行更新。 .yml username/repo:tag
1 | version: "3" |
该docker-compose.yml文件告诉Docker执行以下操作:
- 拉取我们指定仓库的镜像
- 运行该镜像5个实例,每个容器最多使用一个cpu核心时间10%,以及内存50M
- 如果其中一个发生故障,则立即重启
- 将主机上的4000端口映射到容器80
- 指定容器使用的网络
- 创建网络webnet,使用默认的网络模型 及负载均衡
3.1 运行负载均衡
1 | [root@localhost ~]# docker swarm init |
现在运行它。您需要给您的应用命名。在这里,它设置为 getstartedlab:
1 | docker stack deploy -c docker-compose.yml getstartedlab |
获取我们应用程序中一项服务的服务ID:
1 | [root@localhost ~]# docker service ls |
在服务中运行的单个容器称为任务。为任务分配了唯一的ID,这些ID会按数字递增,直到replicas您在中定义 的数量为止docker-compose.yml。列出您的服务任务:
1 | [root@localhost ~]# docker service ps getstartedlab_web |
3.2 验证
此时,我们打开浏览器访问4000端口并且刷新验证,可以清楚的看到Hostname在动态的变化中,这说明我们的负载均衡网络已经起了作用
3.3 缩减集群
您可以通过更改docker-compose.yml中的replicas值,保存更改并重新运行docker stack deploy命令来缩减应用程序:
1 | docker stack deploy -c docker-compose.yml getstartedlab |
Docker执行就会自动更新,无需删除群集或杀死任何容器。
现在,重新运行docker container ls -q 以查看已重新配置已部署的实例。如果按比例扩大副本,则会启动更多任务,从而启动更多容器。
3.4 删除应用和群集
使用 docker stack rm 已关闭容器
1
2
3[root@localhost ~]# docker stack rm getstartedlab
Removing service getstartedlab_web
Removing network getstartedlab_webnet移除swarm
1
docker swarm leave --force
4. docker swarm 群集
swarm是一组运行Docker并加入集群的机器。在发生这种情况之后,您将继续运行您惯用的Docker命令,但是现在它们由集群管理器在集群上执行。群集中的计算机可以是物理的也可以是虚拟的。加入一个群体之后,它们被称为节点。
群管理器可以使用多种策略来运行容器,例如“最空的节点”-用容器填充利用率最低的机器。或“全局”,它可以确保每台机器恰好获得指定容器的一个实例。您可以指示群管理器在Compose文件中使用这些策略,就像您已经在使用的策略一样。
群集管理器是群集中唯一可以执行命令或授权其他计算机作为工作人员加入群集的计算机。工人只是在那里提供能力,而无权告诉其他任何机器它可以做什么和不能做什么。
到目前为止,您一直在本地计算机上以单主机模式使用Docker。但是Docker也可以切换到swarm模式,这就是启用swarms的原因。立即启用群集模式会使当前计算机成为群集管理器。从那时起,Docker将在您管理的集群上运行您执行的命令,而不仅仅是在当前机器上运行。
4.1 设置 swarm 群集
群由多个节点组成,这些节点可以是物理机也可以是虚拟机。基本概念非常简单:运行docker swarm init以启用集群模式,并使当前计算机成为集群管理器,然后docker swarm join在其他计算机上运行 以使它们作为工作组加入集群。在下面选择一个标签,查看在各种情况下如何播放。我们使用虚拟机来快速创建一个两机集群,并将其变成一个集群。
1 | [root@localhost ~]# docker swarm init --advertise-addr 192.168.199.107 |
- 默认监听两个端口,tcp2377端口为集群的管理端口,tcp7946为节点之间的通讯端口
- 默认会创建一个overlay的网络ingress,还会创建一个桥接的网络 docker_gwbridge
- 入口网络默认监听端口为 UDP/4789
4.2 加入群集
1 | [root@localhost ~]# docker swarm join --token SWMTKN-1-3jcpnxc6nb7bmdiitm32pfqmdokhldoduemeh44cxvkymai46m-3mpb6pf2wi1dthd6nrqd97m68 192.168.199.107:2377 |
- 查看集群节点
1 | [root@localhost ~]# docker node ls |
4.3 在管理节点中部署应用
可以使用在第2部分中 docker stack deploy 相同命令部署本地副本,使用其作为集群管理器的功能来部署应用程序docker-compose.yml。此命令可能需要几秒钟才能完成,并且部署需要一些时间才能使用。docker service ps
1 | [root@localhost ~]# docker stack deploy -c docker-compose.yml getstartedlab |
4.4 集群拓扑
如下图拓扑,在swarm前端,集群默认采用负载均衡在分配请求的流量,无论从哪个节点去访问服务,都会转发到后端某一容器中
你不需要关心在集群中你的服务身在何处.

4.5 参考命令
1 | docker-machine create --driver virtualbox myvm1 # Create a VM (Mac, Win7, Linux) |
5. 扩展集群-stack
堆栈是一组共享依赖关系的相互关联的服务,可以一起进行整理和扩展。单个堆栈能够定义和协调整个应用程序的功能(尽管非常复杂的应用程序可能要使用多个堆栈)。
一些好消息是,从第3部分开始,当您创建Compose文件并使用时,从技术上讲您一直在使用堆栈docker stack deploy。但这是在单个主机上运行的单个服务堆栈,通常不会在生产环境中发生。在这里,您可以学到的知识,使多个服务相互关联,然后在多台计算机上运行它们。
5.1 添加服务并重新启动
- docker-compose.yml在编辑器中打开并将其内容替换为以下内容。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29version: "3"
services:
web:
image: registry.cn-hangzhou.aliyuncs.com/momom/pythonflask:v0.1
deploy:
replicas: 5
resources:
limits:
cpus: "0.1"
memory: 50M
restart_policy:
condition: on-failure
ports:
- "4000: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:
唯一增加的服务就是跟 WEB同级的 visualizer,这个是Docker的开源图形化容器,其中比较重要的是,volumes,一定要挂载docker.sock,容器将调用此套接字获取集群的状态
- 在管理器上重新运行命令 docker stack deploy,所有需要更新的服务都会更新:
1 | [root@localhost ~]# docker stack deploy -c docker-compose.yml flask |
- 查看可视器

可视化工具是一项独立的服务,可以在将其包含在堆栈中的任何应用中运行。它不依赖其他任何东西。现在让我们创建一个服务会有依赖性:Redis的服务,提供访客计数器。
5.2 数据持久化
让我们再次经历相同的工作流程,以添加用于存储应用程序数据的Redis数据库。
- 保存此新docker-compose.yml文件,最终添加一个Redis服务。
1 | version: "3" |
要使Redis的数据持久化,首先要保证数据能落地到本地并且保存,所以我们需要在本机挂载data目录,容器来回移动时,存储在本机的数据将会保留,从而实现连续性。
并且我们要保证redis启动和重启必须始终位于相同的节点,否则数据将会不同步,constraints: [node.role == manager]
- 在管理节点创建Redis数据目录
1 | [root@localhost ~] |
重新部署应用
1
2
3
4[root@localhost ~]# docker stack deploy -c docker-compose.yml flask
Updating service flask_visualizer (id: nilgi5vx3dh12kw7q0cwl4chc)
Creating service flask_redis
Updating service flask_web (id: w1p5y92fzz920phb5cwqir2l8)检查service是否正常运行
1
2
3
4
5[root@localhost ~]# docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
mxvddks7lpbc flask_redis replicated 1/1 redis:latest *:6379->6379/tcp
nilgi5vx3dh1 flask_visualizer replicated 1/1 dockersamples/visualizer:stable *:8080->8080/tcp
w1p5y92fzz92 flask_web replicated 5/5 registry.cn-hangzhou.aliyuncs.com/momom/pythonflask:v0.1 *:4000->80/tcp验证计数器是否工作

另外,检查任一节点IP地址上端口8080上的可视化程序,并注意该redis服务与web和visualizer服务一起运行。

6. 结尾
到这里已经简单了解了docker的部署,负载,以及群集的使用,后面将会逐个详细的介绍各组件。