第六课 Docker践行DevOps理念-docker-swarm
tags:
- Docker
- 慕课网
categories:
- docker-swarm
文章目录
第一节 docker-swarm介绍
1.1 多容器的问题
- 怎么去管理这么多容器?
- 怎么能方便的横向扩展?
- 如果容器down了,怎么能自动恢复?
- 如何去更新容器而不影响业务?
- 如何去监控追踪这些容器?
- 怎么去调度容器的创建?
- 保护隐私数据?
1.2 docker-swarm
- 它是docker内置的容器编排工具。当然还有其他的编排工具(比如:k8s)
- Docker Swarm Mode Architecture
- 一种角色叫Manager(避免单点故障,需要数据库来同步)
- 另一种角色叫worker
- Service和Replicas
- 服务创建和调度
1.3 实验环境-swarm cluster
- Vagrant + Virtualbox
- Docker Machine + Virtualbox
- Paly with docker https://labs.play-with-docker.com/
# -*- mode: ruby -*-
# vi: set ft=ruby :
Vagrant.require_version ">= 1.6.0"
boxes = [
{
:name => "swarm-manager",
:eth1 => "192.168.205.10",
:mem => "1024",
:cpu => "1"
},
{
:name => "swarm-worker1",
:eth1 => "192.168.205.11",
:mem => "1024",
:cpu => "1"
},
{
:name => "swarm-worker2",
:eth1 => "192.168.205.12",
:mem => "1024",
:cpu => "1"
}
]
Vagrant.configure(2) do |config|
config.vm.box = "centos/7"
boxes.each do |opts|
config.vm.define opts[:name] do |config|
config.vm.hostname = opts[:name]
config.vm.provider "vmware_fusion" do |v|
v.vmx["memsize"] = opts[:mem]
v.vmx["numvcpus"] = opts[:cpu]
end
config.vm.provider "virtualbox" do |v|
v.customize ["modifyvm", :id, "--memory", opts[:mem]]
v.customize ["modifyvm", :id, "--cpus", opts[:cpu]]
end
config.vm.network :private_network, ip: opts[:eth1]
end
end
#config.vm.synced_folder "./labs", "/home/vagrant/labs"
config.vm.provision "shell", privileged: true, path: "./setup.sh"
end
# 配置阿里镜像
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://eyzd1v97.mirror.aliyuncs.com"]
}
EOF
# 更新源
sudo yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
sudo yum clean all
sudo yum makecache fast
sudo yum update
# 安装依赖包和docker
sudo yum install -y yum-utils device-mapper-persistent-data lvm2 git vim gcc glibc-static telnet bridge-utils net-tools
sudo yum install docker-ce-17.12.0.ce -y
sudo systemctl enable docker
sudo systemctl daemon-reload
sudo systemctl restart docker
# 添加vagrant到docker组中
sudo gpasswd -a vagrant docker # 把当前用户添加到docker组中
sudo systemctl restart docker.service # 重启docker服务
1.4 创建三节点的swarm集群
- 进入swarm-manager节点
- vagrant ssh swarm-manager
- 初始化管理节点:docker swarm init --advertise-addr=192.168.205.10
- 看输出有Token,进入另外两台worker添加子节点节点:docker swarm join --token SWMTKN-1-4efgmfq2ktp7kse85hph2url6hb1lx7z0bpj58zfrq8tuu7k8o-d7oua9xqykog02vicrydepm11 192.168.205.10:2377
- 在swarm-manager节点中查看当前swarm集群中的节点:docker node ls
第二节 docker-swarm中的service
2.1 Service的创建维护和水平扩展
- docker service create --help
- 在swarm中我们就不要用docker run 啦,docker run只能创建运行在本地节点的容器。docker service 可以随机在swarm集群中创建容器。
- 服务水平拓展docker service scale demo=5
- 分母表示要求的拓展数目 5
- 分子表示Ready,准备好了5个
- 查看服务的具体信息:docker service ps demo
- 如果我们到一台机器上强制删除一个容器, swarm会发现容器失效,会自动重新启动一台容器以达到swarm的scale=5的设置修补。
# 在swarm节点中创建busybox服务
docker service create --name demo busybox sh -c "while true;do sleep 3600;done"
# 查看创建的service服务
docker service ls
# 查看服务的具体信息 比如在那台机器上
docker service ps demo
# demo使我们service的名字 而不是我们创建的容器的名字 服务创建的容器名为:demo.1.3y15hagxrtnsggtdi4lct7mkc
docker ps -a
# 服务水平拓展
docker service scale demo=5
# 如果我们到一台机器上强制删除一个容器
docker rm -f c96cd4209efc
# 如果手速快 可以看到 4个变成5个的过程
docker service ls
docker service ls
# 删除服务 默认把所有节点的service产生的容器删除
docker service rm demo
2.2 swarm集群里通过service部署wordpress
- 先创建一个overlay的网络,这样不管,这两个容器是否在同一个机器上都可以相互通信。
- docker network create -d overlay demo
# 创建一个overlay的网络
docker network create -d overlay demo
# 创建mysql 服务
docker service create --name mysql --env MYSQL_ROOT_PASSWORD=root --env MYSQL_DATABASE=wordpress --network demo --mount type=volume,source=mysq1-data,destination=/var/lib/mysql mysql:5.7
# 查看服务在个机器上
docker service ps mysql
# 创建wordpress服务
docker service create --name wordpress -p 80:80 --env WORDPRESS_DB_PASSWORD=root --env WORDPRESS_DB_HOST=mysql --network demo wordpress
# 发现wordpress服务在work2上 在work2上观察网络发现demo
docker network ls
# 输入下面三个ip的地址 都可以访问 wordpress服务
192.168.205.10
192.168.205.11
192.168.205.12
- swarm内部维护了一个网络机制会同步网络的创建,不需要我们手动使用etcd等key value数据库来同步。
2.3 集群服务间通信之Routing Mesh体现-Internal
- swarm有内置的DNS服务发现功能
- 为连到overlay上的所有的sevice增加一条DNS的记录
- Service的DNS的名字是sevice名字name
- 但是DNS对应的ip并不是对应机器上的容器的ip,而是一个vip(虚拟IP)。这其实很好理解,因为它要拓展和自我恢复,容器的ip很不稳定容易改变。(虚拟ip和实际ip有个映射关系)
- 它技术是通过LVS(Linux Virtual Server)实现的。 www.linuxvirtualserver.org
- nslookup命令介绍。查询DNS用的。例子: nslookup www.imooc.com 可以看到域名对应的ip地址
# 启动一个whoam服务 网络连到demo上
docker service create --name whoami -p 8000:8000 --network demo -d jwilder/whoami
docker service ps whoami
# 访问它会返回hostname
curl 127.0.0.1:8000
# 启动一个busybox服务 网络连到demo上
docker service create --name client -d --network demo busybox sh -c "while true;do sleep 3600;done"
# 实验开始 进入client的容器中
docker exec -it c925c4dc5eb4 /bin/sh
# ping whoami服务名 可以ping通发现虚拟IP vip 10.0.0.10
ping whoami
# 拓展whoami 看下ping的地址会不会变 肯定不变呀 虚拟ip呀 vip 10.0.0.10
docker service scale whoami=3
ping whoami
# 在client容器中使用 nslookup查询 返回vip 10.0.0.10
nslookup whoami
# 在client容器中使用nslookup查询tasks.whoami可以看到容器ip
nslookup tasks.whoami
# client容器访问whoami服务 发现提供服务的是随机一台虚机 自动负载均衡
wget whoami:8000
more index.html
- LVS(Linux Virtual Server)技术介绍。
- www.linuxvirtualserver.org 用于实现操作系统级别的Node Banlance
- 这个技术由国人 章文松 实现。从阿里调到滴滴
- 感兴趣可以实现:Ivs+keepalived配置高可用负载均衡集群。
- Internal: Container和Container之间的访问通过overlay网络(vxlan技术)通信,服务和服务之间通过VIP(LVS技术)虚拟IP通信 ,它会自动帮我们做负载均衡
2.4 集群服务间通信之Routing Mesh体现-Ingress
- Ingress Network如果服务有绑定接口,则此服务可以通过任意swarm节点的相应接口访问。
- 就是说任意节点都可以通过8080端口访问到我们的wordpress服务的技术就是Ingress Network
- 外部访问的负载均衡
- 服务端口被暴露到各个swarm节点
- 内部通过IPVS进行负载均衡
# 继续上面的实验环境
# 拓展whoami 3个变2个
docker service scale whoami=2
# 它会在两个节点上负载均衡
curl 127.0.0.1:8000
curl 127.0.0.1:8000
curl 127.0.0.1:8000
# 我们到没有容器的 work1上执行 发现可以访问 这就是Ingress Network的作用
curl 127.0.0.1:8000
# 通过命令查看网络转发的过程
sudo iptables -nL -t nat
# 查看work1网络 发现docker_gwbridge的地址和DOCKER-INGRESS网络在同一个网段上(那肯定有关系呀)
ip a
# 继续 发现 DOCKER-INGRESS 就连在docker_gwbridge上
# 那就是说我们访问本地8000 这个请求转发到172.18.0.2:8000上
# 172.18.0.2:8000就是我们的ingress-sbox 它是一个network namespace
brctl show
docker network inspect docker_gwbridge
2. 我们访问本地8000 这个请求转发到172.18.0.2:8000上,172.18.0.2:8000就是我们的ingress-sbox 它是一个network namespace。
3. 继续试验。观察数据包走向
# 安装ipvsadm ipvs管理工具
sudo yum install ipvsadm
# 进入ingress sbox中 它是一个network namespace
sudo nsenter --net=/var/run/docker/netns/ingress_sbox
iptables -nL -t mangle
# 查看负载均衡
ipvsadm -l
第三节 Docker Stack部署Wordpress
3.1 swarm中docker-compose定义
- 我们知道本地开发工具docker-compose可以在本机上(单节点)部署应用。那么在docker swarm的集群中如何构建我们定义的应用呢。
- 通过docker-compose定义应用,部署不用docker-compose而直接使用docker命令docker stack。
- docker-compose定义(version 3.3), 主要增加depoy命令:https://docs.docker.com/compose/compose-file/#replicas
- 字段endpoint_mode :
- vip(默认使用): 虚拟ip,service互相访问时,底层通过vip负载均衡成具体ip。
- dnssr: 通过dns访问不通过vip,robin是负载均衡的策略,循环访问服务。
- 字段labels : 帮助描述的信息。
- 字段mode:
- global: service不能通过scale做拓展。
- replicated(默认): 可以进行横向拓展
- 字段placement:主要设置限制条件。
- 字段placemen下字段preferences 优先喜欢的设置。
- constraints: node.role == manager 限制只运行在manager节点
- 字段replicas: 一开始部署时就部署6个service.
- 字段resources: 设置资源的限制。如:内存、cpu
- 字段restart_policy: 重启的策略。如:尝试重启的次数
- 字段update_config:
- 字段update_config下parallelism字段: 同时更新的replicas个数
- 字段update_config下delay字段: 更新间隔时间。
- 字段endpoint_mode :
3.2 Wordpress部署案例
- 设置mysql不能拓展,只能在主节点上。
- wordpress可拓展, 设置拓展数为3。配置重启策略。。。
- 通过docker stack --help 命令部署。deploy、ls、ps、rm、services
- docker stack deploy wordpress --compose-file=docker-compose. yml
- 执行发现服务上会加上 wordpress的 前缀名
# 通过docker stack在docker swarm cluster上部署应用
docker stack deploy wordpress --compose-file=docker-compose.yml
# 查看应用的信息
docker stack ps wordpress
# 删除应用 包括网络
docker stack rm wordpress
version: '3'
services:
web:
image: wordpress
ports:
- 8080:80
environment:
WORDPRESS_DB_HOST: mysql
WORDPRESS_DB_PASSWORD: root
networks:
- my-network
depends_on:
- mysql
deploy:
mode: replicated
replicas: 3
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
update_config:
parallelism: 1
delay: 10s
mysql:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: wordpress
volumes:
- mysql-data:/var/lib/mysql
networks:
- my-network
deploy:
mode: global
placement:
constraints:
- node.role == manager
volumes:
mysql-data:
networks:
my-network:
driver: overlay
3.3 部署投票应用案例
- swarm模式下,docker-compose.yml网络类型默认是overlay类型。
- 这个例子和上面例子不同的是,镜像需要拉取,而不是构建。
- visualizer可视化工具: image: dockersamples/visualizer:stable
docker stack deploy example --compose-file=docker-compose.yml
docker stack services example
# 拓展vote service为三个 前面要加stack名字example
docker service scale example_vote=3
version: "3"
services:
redis:
image: redis:alpine
ports:
- "6379"
networks:
- frontend
deploy:
replicas: 2
update_config:
parallelism: 2
delay: 10s
restart_policy:
condition: on-failure
db:
image: postgres:9.4
volumes:
- db-data:/var/lib/postgresql/data
networks:
- backend
deploy:
placement:
constraints: [node.role == manager]
vote:
image: dockersamples/examplevotingapp_vote:before
ports:
- 5000:80
networks:
- frontend
depends_on:
- redis
deploy:
replicas: 2
update_config:
parallelism: 2
restart_policy:
condition: on-failure
result:
image: dockersamples/examplevotingapp_result:before
ports:
- 5001:80
networks:
- backend
depends_on:
- db
deploy:
replicas: 1
update_config:
parallelism: 2
delay: 10s
restart_policy:
condition: on-failure
worker:
image: dockersamples/examplevotingapp_worker
networks:
- frontend
- backend
deploy:
mode: replicated
replicas: 1
labels: [APP=VOTING]
restart_policy:
condition: on-failure
delay: 10s
max_attempts: 3
window: 120s
placement:
constraints: [node.role == manager]
visualizer:
image: dockersamples/visualizer:stable
ports:
- "8080:8080"
stop_grace_period: 1m30s
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
deploy:
placement:
constraints: [node.role == manager]
networks:
frontend:
backend:
volumes:
db-data:
第四节 Docker Secret管理和使用
4.1 Docker Secret介绍和创建
- 什么是Secret
- 用户名密码
- SSH Key
- TLS认证
- 任何不想让别人看到的数据
- 密码管理,比如上面的wordpress,密码明文写在docker-compose.yml文件中。这肯定不安全呀
- 那怎么安全储存密码同时让service安全访问密码呢。
- Docker Swarm Mode Architecture(docker swarm架构图如下)
- Secret Management
- 存在Swarm Manager节点Raft database里。(加密的)
- Secret可以assign给一个service ,这个service就能看到这个secret
- 在container内部Secret看起来像文件,但是实际是在内存中
- docker secret create 创建密码
- 方式一:从文件中创建密码 docker secret create my-pw password
- 方式二:从标准输入创建密码: echo “adminadmin” | docker secret create my-pw2 -
- 如何使用创建的密码呢? 指定关键字 --secret my-pw。 这里可以传入多个。。。
- 上边的是传入一个 如果需要传入多个的话,就需要加入 --secret 名称1 --secret 名称2
# 写入密码admin123
vi password
# 从文件中创建密码
docker secret create my-pw password
# 创建完密码 可以删除文件啦 防止别人看到密码
rm -rf password
# 通过下面命令 查看存储在Swarm Manager节点数据库中的密码数据
docker secret ls
# 从标准输入创建密码 最后有一个 - 符号别忘了
echo "adminadmin" | docker secret create my-pw2 -
docker secret ls
# 删除一个密码
docker secret rm my-pw2
docker secret ls
# 创建一个 可以访问到 my-pwd 的服务
docker service create --name client --secret my-pw busybox sh -c "while true; do sleep 3600; done"
# 进入到创建好的容器中
docker ps
docker exec -it ccee sh
# 进入容器文件夹 查看内容 发现自己创建的密码原文
cd /run/secrets/
cat my-pw
# 把密码传进来 当作mysql的root密码使用
docker service create --name db --secret my-pw -e MYSQL_ROOT_PASSWORD_FILE=/run/secrets/my-pw mysql
# 进入容器验证root密码
docker exec -it 6dc34 sh
mysql -uroot -p
4.2 Docker Secret在docker-compose.yml中使用
- docker stack deploy wordpress -c=docker-compose.yml
- 在这个docker-compose最下面有个有三行注释,如果放开的话这是引用了外部密码文件的形式创建docker secret,这种方式虽然省事了,但是有安全隐患,里面多了个passwd文件,最好的方式还是通过docker secret create的方式。
- 如果报错: secrets Additional property secrets is not allowed 可能两个原因
- Docker Engine<1.13.1
- docker-compose.yml文件的版本号<“3.1”.
- 修改docker版本号,以及docker-compose.yml的版本号为3.4
version: '3.4'
services:
web:
image: wordpress
ports:
- 8080:80
secrets:
- my-pw
environment:
WORDPRESS_DB_HOST: mysql
WORDPRESS_DB_PASSWORD_FILE: /run/secrets/my-pw
networks:
- my-network
depends_on:
- mysql
deploy:
mode: replicated
replicas: 3
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
update_config:
parallelism: 1
delay: 10s
mysql:
image: mysql
secrets:
- my-pw
environment:
MYSQL_ROOT_PASSWORD_FILE: /run/secrets/my-pw
MYSQL_DATABASE: wordpress
volumes:
- mysql-data:/var/lib/mysql
networks:
- my-network
deploy:
mode: global
placement:
constraints:
- node.role == manager
volumes:
mysql-data:
networks:
my-network:
driver: overlay
secrets:
my-pw:
file: ./password
第五节 service更新
- 对运行中的service进行更新。
- swarm一般用于生产环境,我们不希望中断业务(不宕机)进行service更新。实际要比我们现在的演示要复杂的多。
- 更新命令:docker service update --help
- 可以更新密码、发布端口、image等。
- docker stack没有–update。docker-compose.yml中有一些更新的配置。
- 如果是docker-compose.yml文件通过docker stack部署的service,对它更新时。直接修改docker-compose.yum文件, 然后docker stack deploy执行。它会自动分辨和上次的差别进行更新。
docker network ls
docker network create -d overlay demo
# 创建一个服务 tag是1.0版本
docker service create --name web --publish 8080:5000 --network demo xiaopeng163/python-flask-demo:1.0
# 更新过程
# 第一步 拓展成两个以上节点 这样一个更新 另外一个仍可以跑业务。等跟新完在更新另一个
docker service scale web=2
curl 127.0.0.1:8080 # hello docker, version 1
# 在swarm-worker1上一直访问 业务 模拟真实环境
sh -c "while true; do curl 192.168.205.10:8080&&sleep 1; done"
# 第二步 更新容器到2.0
docker service update --image xiaopeng163/python-flask-demo:2.0 web
# 发现有一段时间 是1.0和2.0版本共存的时刻。这个在实际业务中也是不允许的,可以思考一下怎么解决。
# 再做一次端口的更新 端口的中断一定业务会中断的(因为访问是通过vip+端口实现的)
docker service update --publish-rm 8080:5000 --publish-add 8088:5000 web
docker service ls
# 如果是docker-compose.yum文件通过docker stack部署的service,对它更新时。直接修改docker-compose.yum文件, 然后docker stack deploy执行。它会自动分辨和上次的差别进行更新。