环境准备
多台安装了Docker的虚拟机,我使用的是在windows10上安装virtualbox和vagrant来创建多台虚拟机。
关于vagrant和virtualbox的操作以及环境搭建可以看我以前写的这篇文章:使用virtualbox和vagrant搭建Docker环境。
Vagrantfile内容:
# -*- mode: ruby -*-
Vagrant.require_version ">= 1.6.0"
boxes = [
{
:name => "vagrant1",
:eth1 => "192.168.205.10",
:mem => "1024",
:cpu => "1"
},
{
:name => "vagran2",
:eth1 => "192.168.205.11",
:mem => "1024",
:cpu => "1"
},
{
:name => "vagran3",
: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
在vagrantfile中直接引用了安装Docker的setup.sh脚本,setup.sh脚本内容:
#/bin/sh
# install some tools
sudo yum install -y git vim gcc glibc-static telnet bridge-utils
# install docker
curl -fsSL get.docker.com -o get-docker.sh
sh get-docker.sh
# start docker service
sudo groupadd docker
sudo gpasswd -a vagrant docker
sudo systemctl start docker
rm -rf get-docker.sh
Docker swarm是Docker的集群管理工具。
swarm 集群由管理节点(manager)和工作节点(work node)构成 。
swarm mananger:负责整个集群的管理工作包括集群配置、服务管理等所有跟集群有关的工作。
service: Swarm用service管理容器,一个service就是一个容器,使用swarm创建容器的时候,该容器可能会运行在任何一个节点上。
选中manager主机执行:
$ docker swarm init --advertise-addr
docker service create
创建并运行一个service容器:
docker service create --name demo busybox sh -c "while true; do sleep 3600;done"
docker service ls
查看运行中的service:
[vagrant@vagrant1 ~]$ docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
eixl0pvhw572 demo replicated 1/1 busybox:latest
docker service scale
可以横向扩展容器在不同节点的运行数量,在使用docker service ls
发现REPLICAS数量变为了5:
docker service ps
命令可以查看service运行的详情,查看下扩展的demo容器在各个节点的运行详情:
如果删除其中一个节点运行的容器会发生什么呢?
到vagrant1节点,先docker ps
查看下运行中的容器,在使用docker rm -f
强制删除demo1:
在使用docker service ls
会发现还是有5个运行着的service, 这是因为使用scale命令扩展的service,当其中一个停止以后会在新的节点创建并运行相同的service:
docker service rm
可以删除运行着的service(包括所有节点上的):
我们创建service的时候可以指定运行的节点, 比如说我要创建一个nginx指定运行在vagrant3节点上:
给节点打上标签:docker node update --label-add func=nginx vagrant3
, func=nginx
在创建service是指定containt参数
:
docker service create --name vagrant3_nginx --constraint 'node.labels.func == nginx' nginx
不同节点间的网络通信
当使用Swarm创建service集群的时候会分布在不同的节点,那么不同的节点之间如何通信呢?
docker Swarm创建overlay网络会在不同的节点同步该网络。
所以可以使用overlay
网络来连接不同节点间的service:
首先创建一个overlay网络:
docker network create -d overlay my_overlay
在创建service时指定网络为overlay就可以了,比如通过service部署一个wordpress(需要一个mysql容器和wordpress容器):
创建mysql指定网络为overlay, 指定两个环境变量以及挂载。
docker service create --name mysql --network my-overlay --env MYSQL_ROOT_PASSWORD=root --env MYSQL_DATABASE=wordpress --mount type=volume,source=mysql-data,destination=/var/lib/mysql mysql
创建wordpress指定网络为overlay, 指定两个环境变量以及端口映射:
docker service create --name --network my-overlay wordpress -p 80:80 --env WORDPRESS_DB_PASSWORD=root --env WORDPRESS_DB_HOST=mysql wordpress
使用Docker Swarm创建集群的时候默认使用的是overlay网络,在overlay网络上集群上的service之间可以互相通过service name进行通信的,其底层是通过DNS服务实现的。
当我们使用overlay网络创建一个service的时候,docker内置的DNS服务会给该service一个DNS记录,DNS的name是service的name,但是DNS对应的ip是一个虚拟ip并不是该service所在节点的ip(因为节点的ip可以能会改变,如果使用节点ip作为DNS记录会不稳定,使用虚拟ip就不会发生这种情况), 该ip只是为了标记该service所在节点的位置。
下面通过一个实验来验证:
首先确保有一个overlay网络
创建一个service使用overlay网络:
docker service create --name whoami -p 8000:8000 --network my-overlay -d jwilder/whoami
在创建一个service使用overlay网络:
docker service create --name client -d --network my-overlay busybox sh -c "while true; do sleep 3600; done"
在docker manager主机上使用docker service ps client
查看下client service所在的主机,进入client service 的后台,ping whoami service发现ping的ip是10.0.2.2,这个ip就是DNS服务给绑定的虚拟ip:
现在将whoami service扩展到两个,在进入client ping whoami service发现ping的ip还是10.0.2.2:
Routing Mesh的两种体现
Internal——Container和Container之间的访问通过overlay网络(通过VIP虚拟IP)。
Ingress——如果服务有绑定接口,则此服务可以通过任意swarm节点相应接口访问。
当web service使用scale扩展至多个节点时,docker内置的DNS服务也会绑定多个虚拟IP,当我们通过client service去访问web service时,DNS服务会动态的让我们访问不同的节点上的web service,达到服务端负载均衡的目的,当然前提是在同一个overlay网络下。
client service一个具体的请求时通过DNS + VIP + iptable + LVS整个解析路径来达到负载均衡的。
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:
# 使用manager节点
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:
# 使用manager节点
constraints: [node.role == manager]
# 网络不写驱动默认为overlay网络
networks:
frontend:
backend:
volumes:
db-data:
执行deploy命令:
[root@vagrant1 example-vote-app]# docker stack deploy example --compose-file=docker-compose.yml
Docker Secret 用于保存敏感信息。
创建
docker secret create
命令创建,发现可以通过文件或者标准输入创建。
bash-4.2$ docker secret create
"docker secret create" requires at least 1 and at most 2 arguments.
See 'docker secret create --help'.
Usage: docker secret create [OPTIONS] SECRET [file|-]
Create a secret from a file or STDIN as content
通过文件创建:
首先创建一个叫做password的文件,里边写上密码:admin123:
执行docker secret create my-pw password
就可以将password文件下的内容存入Docker节点中:
bash-4.2$ docker secret create my-pw password
mxisg7k2xzzot7pcsv1dl1r4e
存入节点后为了防止密码文件泄漏,此时可以将password文件删除:
bash-4.2$ rm -f password
通过docker secret ls
可以查看当前存入的内容:
bash-4.2$ docker secret ls
ID NAME DRIVER CREATED UPDATED
mxisg7k2xzzot7pcsv1dl1r4e my-pw About a minute ago About a minute ago
通过标准输入:
bash-4.2$ echo "admin123" | docker secret create my-pw2 -
r3ojwxv0289tb4wt4lukxm2yr
使用docker secret ls
此时可以查看到两个:
bash-4.2$ docker secret ls
ID NAME DRIVER CREATED UPDATED
mxisg7k2xzzot7pcsv1dl1r4e my-pw 5 minutes ago 5 minutes ago
r3ojwxv0289tb4wt4lukxm2yr my-pw2 38 seconds ago 38 seconds ago
删除
使用命令docker secret rm
可以删除。
查看详情
docker secret inspect
bash-4.2$ docker secret inspect mxisg7k2xzzot7pcsv1dl1r4e
[
{
"ID": "mxisg7k2xzzot7pcsv1dl1r4e",
"Version": {
"Index": 21
},
"CreatedAt": "2020-10-18T14:43:45.00358644Z",
"UpdatedAt": "2020-10-18T14:43:45.00358644Z",
"Spec": {
"Name": "my-pw",
"Labels": {}
}
}
]
service中使用secret
指定参数--secret
就可以使用:
bash-4.2$ docker service create --name client --secret my-pw busybox sh -c "while true; do sleep 3600; done"
6ublh03hz0806i5l894agfyqh
overall progress: 1 out of 1 tasks
1/1: running
verify: Service converged
进入该service的后台,secret
保存在/run/secrets/
目录下:
bash-4.2$ docker exec -it 05b sh
/ #
/ #
/ # cd /run/secrets/
/run/secrets # ls
my-pw
/run/secrets # cat my-pw
admin123
/run/secrets #
创建一个Mysql的service, root密码从环境变量中读取,而环境变量信息又是从secret中获取:
bash-4.2$ docker service create --name db --secret my-pw -e MYSQL_ROOT_PASSWORD_FILE=/run/secrets/my-pw mysql
zf5v4dulpxygt6lmlto3nda4d
找到该service的结点进入后台使用secret中的密码登录root用户:
在stack 中使用secret
在yum文件中指定secrets, 需要注意的是这里的my-pw是需要提前创建好的:
version: '3'
services:
web:
image: wordpress
ports:
- 8080:80
secrets:
- my-pw
environment:
WORDPRESS_DB_HOST: mysql
WORDPRESS_DB_PASSWORD_FILE: /run/secrets/my-pw
$ docker service create --name db --secret my-pw -e MYSQL_ROOT_PASSWORD_FILE=/run/secrets/my-pw mysql
zf5v4dulpxygt6lmlto3nda4d
找到该service的结点进入后台使用secret中的密码登录root用户:
[外链图片转存中…(img-KcZ0VBvD-1603035582880)]
在stack 中使用secret
在yum文件中指定secrets, 需要注意的是这里的my-pw是需要提前创建好的:
version: '3'
services:
web:
image: wordpress
ports:
- 8080:80
secrets:
- my-pw
environment:
WORDPRESS_DB_HOST: mysql
WORDPRESS_DB_PASSWORD_FILE: /run/secrets/my-pw