赞
踩
一、Docker Compose
Compose 是一个用于定义和运行多容器 Docker 应用程序的工具。借助 Compose,您可以使用 YAML 文件来配置应用程序的服务。然后,使用单个命令,从配置中创建并启动所有服务。Compose 适用于所有环境:生产、登台、开发、测试以及 CI 工作流。
使用 Compose 基本上是一个三步过程:
Dockerfile
定义你的应用的环境。docker-compose.yml
文件,将你的服务的各个部分组合在一起,以便它们可以在隔离的环境中一起运行。docker compose up
命令启动并运行你的整个应用程序。一个docker-compose.yml
文件,如下:
version: "3.9" # optional since v1.27.0
services:
web:
build: .
ports:
- "5000:5000"
volumes:
- .:/code
- logvolume01:/var/log
links:
- redis
redis:
image: redis
volumes:
logvolume01: {}
Docker Compose的特点
① 国内镜像下载命令
sudo curl -L https://get.daocloud.io/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose
② 因为docker-compose是一个二进制问津,所以我们需要给二进制文件应用可执行权限
sudo chmod +x /usr/local/bin/docker-compose
③ 测试
docker-compose --version
① 卸载
sudo rm /usr/local/bin/docker-compose
下面我们来试一下,使用docker-compose来启动多个服务(镜像)。
我们的体验以官方的一个实例开始:Python+Redis 实现计数器的功能
为项目创建一个目录
mkdir composetest
cd composetest
在当前目录下创建并编写Python应用文件app.py
import time import redis from flask import Flask app = Flask(__name__) cache = redis.Redis(host='redis', port=6379) def get_hit_count(): retries = 5 while True: try: return cache.incr('hits') except redis.exceptions.ConnectionError as exc: if retries == 0: raise exc retries -= 1 time.sleep(0.5) @app.route('/') def hello(): count = get_hit_count() return 'Hello World! I have been seen {} times.\n'.format(count)
在此示例中,redis是应用程序网络上的 redis 容器的主机名。我们使用 Redis 的默认端口6379。
在当前目录下创建并编写requirements.txt
flask
redis
编写一个用于构建 Docker 映像的 Dockerfile。该图像包含 Python 应用程序所需的所有依赖项,包括 Python 本身。
在当前目录下创建并编写Dockerfile
# syntax=docker/dockerfile:1 FROM python:3.7-alpine WORKDIR /code ENV FLASK_APP=app.py ENV FLASK_RUN_HOST=0.0.0.0 RUN apk add --no-cache gcc musl-dev linux-headers COPY requirements.txt requirements.txt RUN pip install -r requirements.txt EXPOSE 5000 COPY . . CMD ["flask", "run"] # 从 Python 3.7 映像开始构建映像。 # 将工作目录设置为/code. # 设置flask命令使用的环境变量。 # 安装 gcc 和其他依赖项 # 复制requirements.txt并安装 Python 依赖项。 # 将元数据添加到图像以描述容器正在侦听端口 5000 # 将.项目中的当前目录复制到.镜像中的workdir 。 # 将容器的默认命令设置为flask run.
在当前目录下创建并编写一个docker-compose.yml
文件
version: "3.9"
services:
web:
build: .
ports:
- "5000:5000"
redis:
image: "redis:alpine"
# 这个 Compose 文件定义了两个服务:web和redis
最后你的当前目录下应该有如下4个文件
在当前目录下。通过docker-compose up
命令(使用该命令前,保证你的docker是启动的)启动并运行你的应用。或者使用docker-compose up -d
后台启动。
注意:如果因为一些依赖或jar包导致项目启动失败,当我们修改之后,重新启动项目可以使用docker-compose up --build
进行重新使用。--build
的目的是重新构建相关的镜像,避免使用原本错误的镜像。
方式1:如果使用的是交互模式启动的项目,那么在项目中使用 Ctrll + C
方式2:如果你是要的是后台启动的项目,在项目目录下使用 docker-compose down
官方文档:https://docs.docker.com/compose/compose-file/
在docker-compose 中有三层的概念,如下
# 第一层:版本
version: "3.9"
# 第二层:服务(核心)
services:
web:
build: .
ports:
- "5000:5000"
redis:
image: "redis:alpine"
# 第三层:其他的一些配置(网络,数据卷...)
官方文档:https://docs.docker.com/compose/compose-file/compose-file-v3/
docker-compose文件的版本和和docker的引擎是有去联系的,其之间需要匹配好。我们的docker是向下兼容的。(说道版本对应,我得说两句,我在学习springcloud的时候,springboot的版本和springcloud的版本可把我害惨了,呜呜呜…)
我的docker引擎的版本是20.10.8
按照上图,我的docker-compose文件的版本应该是3.8以上
compose文件是一个定义了服务、网络和数据卷的YAML(yml / yaml)文件。compose的默认路径是 ./docker-compose.yml
.
官方文档:https://docs.docker.com/compose/compose-file/compose-file-v3/#service-configuration-reference
Volume配置官方文档:https://docs.docker.com/compose/compose-file/compose-file-v3/#volume-configuration-reference
Network配置官方文档:https://docs.docker.com/compose/compose-file/compose-file-v3/#network-configuration-reference
Configs配置官方文档:https://docs.docker.com/compose/compose-file/compose-file-v3/#configs-configuration-reference
Secrets配置官方文档:https://docs.docker.com/compose/compose-file/compose-file-v3/#secrets-configuration-reference
变量替换官方文档:https://docs.docker.com/compose/compose-file/compose-file-v3/#variable-substitution
扩展字段官方文档:https://docs.docker.com/compose/compose-file/compose-file-v3/#extension-fields
我们在初体验的时候体验了一个Python的计数器,现在我们通过springboot实现一个Java+Redis的计数器
① 创建一个springboot项目
application.properties:
application.propertiesserver.port=8080
spring.redis.host=redis
redis是应用程序网络上的 redis 容器的主机名。Redis 的默认端口6379
DemoController:
@RestController
public class DemoController {
@Autowired
private StringRedisTemplate redistemplate;
@RequestMapping("/tiger")
public String demo(){
Long view = redistemplate.opsForValue().increment("view");
return "hello, studioustiger. view:"+view;
}
}
② 编写 Dockerfile
FROM java:8
COPY *.jar /app.jar
CMD ["--server.port:8080"]
ENTRYPOINT ["java","-jar","app.jar"]
③ 编写docker-compose.yml
version: '3.9'
services:
tigerapp:
build: .
image: tigerapp
depends_on:
- redis
ports:
- 8080:8080
redis:
image: "redis:alpine"
④ 将相关文件上传到linux中
我们需要将 docker-compose-0.0.1-SNAPSHOT.jar
、Dockerfile
和docker-compose.yml
上到linux的同一个文件夹中
⑤ 启动项目
在docker-compose.yml
所在目录下使用docker-compose up
命令一键启动项目
二、Docker Swarm
docker-swarm官方文档:https://docs.docker.com/engine/swarm
Swarm 是 Docker 官方提供的一款集群管理工具,其主要作用是把若干台 Docker 主机抽象为一个整体,并且通过一个入口统一管理这些 Docker 主机上的各种 Docker 资源。
运行 Docker 的主机可以主动初始化一个 Swarm 集群或者加入一个已存在的 Swarm 集群,这样这个运行 Docker 的主机就成为一个 Swarm 集群的节点 (node) 。节点分为管理 (manager) 节点和工作 (worker) 节点。
管理节点用于 Swarm 集群的管理,docker swarm 命令基本只能在管理节点执行(节点退出集群命令 docker swarm leave 可以在工作节点执行)。一个 Swarm 集群可以有多个管理节点,但只有一个管理节点可以成为 leader,leader 通过 raft 协议实现。
工作节点是任务执行节点,管理节点将服务 (service) 下发至工作节点执行。管理节点默认也作为工作节点。你也可以通过配置让服务只运行在管理节点。下图展示了集群中管理节点与工作节点的关系。
节点会被配置为管理节点(Manager)或工作节点(Worker)。管理节点负责集群控制面(Control Plane),进行诸如监控集群状态、分发任务至工作节点等操作。工作节点接收来自管理节点的任务并执行。
Swarm 的配置和状态信息保存在一套位于所有管理节点上的分布式 etcd 数据库中。该数据库运行于内存中,并保持数据的最新状态。关于该数据库最棒的是,它几乎不需要任何配置,作为 Swarm 的一部分被安装,无须管理。
关于集群管理,最大的挑战在于保证其安全性。搭建 Swarm 集群时将不可避免地使用 TLS,因为它被 Swarm 紧密集成。
在安全意识日盛的今天,这样的工具值得大力推广。Swarm 使用 TLS 进行通信加密、节点认证和角色授权。自动密钥轮换(Automatic Key Rotation)更是锦上添花!其在后台默默进行,用户甚至感知不到这一功能的存在。
关于应用编排,Swarm 中的最小调度单元是服务。它是随 Swarm 引入的,在 API 中是一个新的对象元素,它基于容器封装了一些高级特性,是一个更高层次的概念。当容器被封装在一个服务中时,我们称之为一个任务或一个副本,服务中增加了诸如扩缩容、滚动升级以及简单回滚等特性。
综上所述,从概括性的视角来看 Swarm,如下图所示。
注意:docker swarm是在docker中集成的,所以你的linux中只要安装了docker即可
我们需要在一个docker中创建一个swarm,并让其他的docker加入创建的swarm,实现swarm集群
我们先来看一下 docker swarm
怎么使用
使用 docker swarm init
创建(初始化)一个swarm。(我们在docker01中创建swarm)
我们可以在swarm的主节点(docker01)使用 docker swarm join-token worker
生成秘钥,在docker02中使用在和秘钥,加入swarm
在docker01中生成worker角色加入swarm的秘钥
docker02加入swarm
我们可以通过 docker node ls
查看swarm中的节点的信息
在docker01中使用docker swarm join-token manager
生成秘钥,在docker03和docker04中使用在和秘钥,加入swarm
生成秘钥(manage)
docker03加入swarm
docker04加入swarm
使用 docker node ls
查看集群中节点的情况
问题:假设一个节点挂了,其他节点是否可用?
Raft协议:保证大多数节点存活;在非集群中存活的节点数需要>1,在集群中存活的节点数需要>3
当 Docker Engine 以 swarm 模式运行时,管理器节点实现 Raft 共识算法来管理全局集群状态,以确保那些负责在集群中的管理和调度任务的所有Manager
节点,都存储相同一致的状态。
在整个集群中具有相同的一致状态意味着在发生故障时,任何 Manager
节点都可以接收任务并将服务恢复到稳定状态。例如,如果集群中负责调度任务的Leader Manager
意外死亡,任何其他 Manager
都可以接手调度的任务并重新平衡任务以匹配所需的状态。
Raft 最多可以允许(N-1)/2
失败,并且需要(N/2)+1
个Manager成员就向集群提出的价值达成一致。这意味着在运行 Raft 的 5 个 Manager 的集群中,如果 3 个节点不可用,系统将无法处理更多请求以安排额外的任务。
在上面的搭建中,我们实现了三个Manager节点,这也就意味着至少有3个[(N+1)/2] Manager节点存活,我们的swarm集群才可以使用。
现在我们关掉一个manager节点试一试。我们使用docker swarn leave --force
使得docker03(manager)退出swarm集群
我来试一试swarm是否还可以使用(如果swarm可以使用,那么在manager节点上使用docker node ls
是可以的)
很明显是可以使用的
现在我们将docker离开,试一下swarm是否还是可以使用
很明显不能使用了,因为manager的个数<2了
因为docker01是leader,所以我们将docker01离开后,整个swarm就崩了,我又重新搭了一个swarm集群,我们看一看当docker01(leader)宕机之后swarm的变化。我们使用systemctl stop docker
模拟宕机
在docker03(manager)通过docker node ls
查看swarm节点的状况。我们发现当原本的leader宕机之后,又出现了新的leader
当docker恢复之后(systemctl start docker
),我们发现docker已经不在是leader,只是普通的manager
上述,我们已经搭建好了一个docker swarm集群,那么我们就可以在集群中部署服务了。大家要注意区分服务和容器的区别(我们使用docker run
启动一个容器;使用docker service
启动一个服务,服务只能在集群中使用)
我们在没有使用docker集群之前,大概是这样的:
我们在使用docker集群之前,大概是这样的:
接下来,我们将通过上面搭建的swarm集群,搭建一个nginx集群,并实现服务弹性。我们来看一下docker service
可以怎么使用
我们先来创建服务,可以使用docker service create --help
看看docker service create
怎么使用。使用docker service create -p 8081:80 --name myNginx nginx
命令创建一个nginx服务。
[root@docker01 ~]# docker service create -p 8081:80 --name myNginx nginx
4ebot7f4xkhzdv7956sm9qbfg
overall progress: 1 out of 1 tasks
1/1: running [==================================================>]
verify: Service converged
通过docker service ps myNginx
命令查看我们创建的服务的进程
我们可以看一下,我们创建的nginx在哪个节点中运行的,发现是在docker03节点
上启动的
我们可以使用docker service update --replicas 4 myNginx
创建myNginx服务的副本/扩缩容(使用docker service update --help
查看其他用法)
我们看一下这4个nginx服务在节点上的分布情况 docker ps
。我们发现是平均分布
我们可以发现不同的节点的访问没有问题,如下:
如果我们在四节点的集群中创建3个nginx的副本,那么肯定有一个节点上时没有nginx服务的,那么该节点是否可以访问nginx服务呢?
使用 docker service update --replicas 3 myNginx
命令创建三个nginx服务
发现在docker02所在节点上没有nginx服务
查看docker02节点的IP
通过docker02 的IP访问nginx服务。很明显,是可以的,这就是集群,这就是高可用!!
我什么我们四个linux上的docker可以进行集群呢?是因为这四个linux在同一个网络中
我们可以使用 docker network ls
查看网络,发现有一个ingress网络(在这里就不展开讲了)
我们可以通过docker network inspect ingress
命令,发现四个docker原来被绑定到同一个网络中了
[root@docker01 ~]# docker network inspect ingress [ { ... "Peers": [ { "Name": "15b9b9d927b5", "IP": "192.168.174.129" }, { "Name": "3043986786d2", "IP": "192.168.174.135" }, { "Name": "1f765c70b2e7", "IP": "192.168.174.134" }, { "Name": "472700543e1c", "IP": "192.168.174.133" } ] } ]
当然,还有很多的细节没有展现,其实其他的细节你可以结合–help慢慢的琢磨,持之以恒,学无止境
例如:我们也可以使用docker service scale myNginx=7
实现动态扩缩容
三、Docker Stack
停更…
四、Docker Secret
停更…
五、Docker Config
停更…
十年饮冰,难凉热血,唯有爱情与科技不可辜负…
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。