七、网络
1.在 centos创建network namespace
(1) 创建ns1
# 创建network namespace,添加网络命名空间名称为 ns1
ip netns add ns1
# 查看网络命名空间名称
ip netns list
# 查看添加的网络命名空间
ip netns exec ns1 ip link show
# 显示以下内容
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
# 启动该网络命名空间
ip netns exec ns1 ifup lo
# 再次查看
ip netns exec ns1 ip link show
# 显示一下内容
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
# 查看物理主机
ip link show
# 显示以下其中一条内容
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
# 发现添加的网络命名空间和物理主机的网络命名空间都为 UNKNOWN
(2)按照以上步骤创建ns2
ip netns add ns2
# 查看网络命名空间名称
ip netns list
# 查看添加的网络命名空间
ip netns exec ns2 ip link show
# 显示以下内容
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
# 启动该网络命名空间
ip netns exec ns2 ifup lo
接下来使这两个网络命名空间进行通信
2.veth pair:Virtual Ethernet Pair
成对出现的网卡,创建出来是默认能够联通的,也就是使ns1和ns2联通
(1)创建veth网卡
# 创建两个网卡并使它们连接
ip link add veth-ns1 type veth peer name veth-ns2
# 再次查看
ip link show
# 发现它们两个已经连上了
52: veth-ns2@veth-ns1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 7a:70:ac:99:cc:60 brd ff:ff:ff:ff:ff:ff
53: veth-ns1@veth-ns2: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether fe:5d:55:36:01:94 brd ff:ff:ff:ff:ff:ff
(2)把这两个派给ns1和ns2这两个网络命名空间
# 把网卡veth-ns1派给网络命名空间ns1
ip link set veth-ns1 netns ns1
# 派送完成之后通过 ip link show再次查看已经看不到veth-ns1这个网卡了
# 再次查看ns1这个网络命名空间
ip netns exec ns1 ip link show
# 显示一下内容,说明veth-ns1这个网卡已经被派送过来了
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
53: veth-ns1@if52: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether fe:5d:55:36:01:94 brd ff:ff:ff:ff:ff:ff link-netnsid 0
# 同样给ns2派送网卡veth-ns2
ip link set veth-ns2 netns ns2
# 再次查看ns2这个网络命名空间
ip netns exec ns2 ip link show
# 显示一下内容表示派送成功
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
52: veth-ns2@if53: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 7a:70:ac:99:cc:60 brd ff:ff:ff:ff:ff:ff link-netnsid 0
(3)给这两个网卡添加ip地址
# 给ns1这个网络命名空间的veth-ns1网卡添加ip为192.168.0.11,子网掩码为24,
ip netns exec ns1 ip addr add 192.168.0.11/24 dev veth-ns1
# 启动该网络命名空间
ip netns exec ns1 ip link set veth-ns1 up
# 再次查看
ip netns exec ns1 ip a
# 操作ns2这个网络命名空间
ip netns exec ns2 ip addr add 192.168.0.12/24 dev veth-ns2
# 启动该网络命名空间
ip netns exec ns2 ip link set veth-ns2 up
# 查看该网络命名空间
ip netns exec ns2 ip a
(4)验证两个网络命名空间是否互通
# 在ns1上面去ping ns2
ip netns exec ns1 ping 192.168.0.12
# 在ns2上面去ping ns1
ip netns exec ns2 ping 192.168.0.11
看到以下表示ping通
(5)启动两个tomcat容器,并进入容器进行查看ip去验证是否能互相ping通
ip a查看网络,如果报bash: ip: command not found错误,使用以下命令安装ip命令
apt update && apt install -y iproute2
进入其中一个,然后ping另外一个的ip,如果ping命令失败,使用以下命令安装ping命令
# 更新
apt-get update
# 安装
apt install iputils-ping
3.安装查看网桥工具
(1)安装
yum install bridge-utils
# 查看
brctl show
# 会显示以下内容
bridge name bridge id STP enabled interfaces
br-57f9401a93d6 8000.0242814bbbac no
docker0 8000.0242603a900c no veth57d3d66
veth6f9793a
veth7f8cf69
vethd979e57
(2)在centos通过ip a再次查看网络,可以找到 brctl show
命令出现的docker0的网卡信息
41: veth57d3d66@if40: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
link/ether 92:8c:21:a1:c4:ea brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet6 fe80::908c:21ff:fea1:c4ea/64 scope link
valid_lft forever preferred_lft forever
43: veth7f8cf69@if42: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
link/ether 96:5c:08:88:07:82 brd ff:ff:ff:ff:ff:ff link-netnsid 1
inet6 fe80::945c:8ff:fe88:782/64 scope link
valid_lft forever preferred_lft forever
47: veth6f9793a@if46: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
link/ether 7a:05:4e:b2:7b:a6 brd ff:ff:ff:ff:ff:ff link-netnsid 2
inet6 fe80::7805:4eff:feb2:7ba6/64 scope link
valid_lft forever preferred_lft forever
49: vethd979e57@if48: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
link/ether ce:0a:83:9c:a3:ef brd ff:ff:ff:ff:ff:ff link-netnsid 3
inet6 fe80::cc0a:83ff:fe9c:a3ef/64 scope link
valid_lft forever preferred_lft forever
(3)原理图
4.网络类型
(1)查看docker网络类型
# 查看
docekr network ls
# 显示一下内容
57f9401a93d6 harbor_harbor bridge local
6b5feb06c2bf host host local
cd6aba8f33fa none null local
# docker中创建的任何容器都是基于bridge网络类型的,
# host是和宿主主机一样的网络
# 查看bridge类型的
docker network inspect bridge
(2)给docker 创建网络
# 创建一个网络,默认为bridge类型的
docker network create tomcat-net
# 再次查看已经出现了
docker network ls
# 查看创建出来的tomcat-net网络信息,它的网段已经不是172.17了,而是172.19或者其他递增的
docker network inspect tomcat-net
# 创建网络并指定网段
docker network create --subnet=172.19.0.0/24 tomcat-net
# 删除网络
docker network rm tomcat-net
(3)创建容器并指定网络
docker run -d --name custom-net-tomcat --network tomcat-net tomcat
# 再来查看该容器的网络
docker exec -it custom-net-tomcat ip a
# 可以发现它就是刚刚创建的172.19开头的网段了
# 这时候用创建出来的网络去ping之前的tomcat是ping不同的
docker exec -it custom-net-tomcat ping 172.17.0.2
# 因为现在的custom-net-tomcat这个容器是新的网络,跟之前docker默认的不一样
用下面一张图来理解
接下来把tomcat01添加到tomcat-net里面
docker network connect tomcat-net tomcat01
# 添加完再次查看
docker network inspect tomcat-net
# 此时已经能看到tomcat01被添加到tomcat-net这个网络里面了
# 再去查看tomcat01这个容器的网络
docker inspect tomcat01
# 此时也能看到tomcat-net这个网络了
这时候进入custom-tomcat-net这个容器里面去ping一下tomcat01这个容器,此时已经可以ping通了。
docker exec -it custom-tomcat-net /bin/bash
ping 172.17.0.2
用下面一张图来理解一下
5.用容器名称对外提供连接
直接使用容器名称去ping两个容器的话是ping不同的,分别给他们指定网络之后可以ping通。
(1)指定网络可以ping通
创建两个tomcat容器,并分别指定网络为上面创建的tomcat-net,此时再去根据容器名称ping的话是可以ping通的。
# 这这两个容器都指定网络为tomcat-net
docker network connect tomcat-net tomcat01
docker network connect tomcat-net tomcat02
# 再去ping
docker exec -it tomcat01 ping tomcat02
(2)通过 --link
参数
# 指定tomcat01容器连接到tomcat02上面,通过dns连接
docker run -d --name tomcat01 --link tomcat02 tomcat:8
# 再次去ping可以ping通
docker exec -it tomcat01 ping tomcat02
生产中推荐使用自定义网络来进行连接。
6.解决多机网络通信问题
overlay网络模式,实现的是vxlan
八、Docker数据持久化
1.Volume
# 查看所有的volume
docker volume ls
# 查看某一个volume详情
docker volume inspect VOLUMENAME
# 删除某一个volume
docker vlume rm VOLUMENAME
(1)以mysql为例来说明
# 拉取mysql镜像
docker pull mysql
# 创建mysql01容器
docker run -d --name mysql01 -e MYSQL_ROOT_PASSWORD=123456 mysql
# 进入到mysql01容器
docker exec -it mysql01 /bin/bash
# 在容器里面进入到/var/lib/mysql目录
cd /var/lib/mysql
# 可以看到有以下文件
'#ib_16384_0.dblwr' '#innodb_temp' binlog.000001 binlog.index ca.pem client-key.pem ib_logfile0 ibdata1 mysql performance_schema public_key.pem server-key.pem undo_001
'#ib_16384_1.dblwr' auto.cnf binlog.000002 ca-key.pem client-cert.pem ib_buffer_pool ib_logfile1 ibtmp1 mysql.ibd private_key.pem server-cert.pem sys undo_002
# 退出容器,在centos里面查看数据持久化
# 首选查看刚创建出来的msql01的VOLUME NAME
docker volume ls
# 然后根据VOLUME NAME的值查看该volume数据存储的位置
docker volume inspect 6a19afe432358b32607297e828150308440976509b0e19b48616a60cdfd7ab7e
# 可以看到该容器的数据是存储在/var/lib/docker/volumes下面的,
[
{
"CreatedAt": "2022-05-18T01:18:31Z",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/6a19afe432358b32607297e828150308440976509b0e19b48616a60cdfd7ab7e/_data",
"Name": "6a19afe432358b32607297e828150308440976509b0e19b48616a60cdfd7ab7e",
"Options": null,
"Scope": "local"
}
]
# 进入到该完整目录里面,可以看到有以下文件,和在容器中查看的一样
auto.cnf binlog.000002 ca-key.pem client-cert.pem #ib_16384_0.dblwr ib_buffer_pool ib_logfile0 ibtmp1 mysql performance_schema public_key.pem server-key.pem undo_001
binlog.000001 binlog.index ca.pem client-key.pem #ib_16384_1.dblwr ibdata1 ib_logfile1 #innodb_temp mysql.ibd private_key.pem server-cert.pem sys undo_002
# 每次创建容器都会在centos的机器上面生成一个文件夹,用来保存数据
(2)给创建的容器指定volume名称
# 指定volume名称,并指定容器内存储数据目录
docker run -d --name mysql02 -v mysql02_volume:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 mysql
# 再次查看
docker volume ls
# 就显示我们指定的
local mysql02_volume
# 删除容器之后,centos查看volume还会存在,也就是容器被删除之后,可以恢复数据,除非把centos的volume给删除了那就无法恢复
# 在mysql02这个容器中的数据存储目录里面创建一个文件,centos也会同步显示
docker exec -it mysql02 /bin/bash
cd /var/lib/mysql
touch test.txt
# 查看已经能显示了
ls
# 退出容器
exit
# 在centos查看该容器对应的volume所在的路径
docker volume inspect mysql02_volume
# 查看该volume所在的路径,也已经能看到 test.txt 文件了
ls /var/lib/docker/volumes/mysql02_volume/_data
(3)删除mysql02容器,并进行恢复
# 首先在该容器创建一个数据库
create database tqz_test;
# 查看该数据库已经被创建出来了
show databases;
# 删除
docker rm -f mysql02
# 再重新创建一个容器,并指定volume
docker run -d --name mysql02 -v mysql02_valume:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 mysql
# 进入到该容器查看
docker exec -it test-mysql /bin/bash
mysql -u root -p
show databases;
# 可以发现上面创建的tqz_test数据库还存在
2.Bind mounts
# 在centos创建一个文件夹
mkdir /usr/local/malls
# 编辑一个html页面
vi test.html
# 随便写上一段内容
Hello Bind mounts!
# 创建一个tomcat01的容器,并且指定挂载centos的项目,也就是上面我们创建的页面挂载上去
docker run -d --name tomcat01 -p 9090:8080 -v /usr/local/malls/:/usr/local/tomcat/webapps/malls tomcat
# 进入容器中里面,可以在tomcat的webapps目录下面看到该项目
docker exec -it tomcat01 /bin/bash
# 浏览器访问可以看到我们test.html页面的内容
http://192.168.0.136:9090/malls/test.html
九、搭建mysql高可用集群
1.Percona Xtradb Cluster 搭建集群
hub.docker.com搜索:percona/percona-xtradb-cluster
# 拉取pxc镜像
docker pull percona/percona-xtradb-cluster:5.7.21
# 由于镜像名称太长,给其打个tag重新起个名字
docker tag percona/percona-xtradb-cluster:5.7.21 pxc
# 删除之前的镜像
docker rmi percona/percona-xtradb-cluster:5.7.21
创建pxc-net网络
# 创建网络并指定网段
docker network create --subnet=172.20.0.0/24 pxc-net
# 查看网络详情
docker network inspect pxc-net
创建三个volume,分别给三个mysql容器使用
docker volume create --name v1
docker volume create --name v2
docker volume create --name v3
创建三个mysql容器
# 创建mysql01容器,映射到centos端口为3301,指定volume为v1,在容器中的存储路径为/var/lib/mysql,mysql密码为123456,集群名称为PXC,集群之间同步数据的密码为123456,指定容器的网络为pxc-net,指定ip为172.20.0.2
docker run -d --name=mysql01 -p 3301:3306 -v v1:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=123456 --privileged --net=pxc-net --ip 172.20.0.2 pxc
# 创建mysql02容器,映射到centos端口为3302,指定volume为v2,加入到mysql01里面组成集群,指定ip为172.20.0.3
docker run -d --name=mysql02 -p 3302:3306 -v v2:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=123456 -e CLUSTER_JOIN=mysql01 --privileged --net=pxc-net --ip 172.20.0.3 pxc
# 创建mysql03容器,映射到centos端口为3303,指定volume为v3,加入到mysql01里面组成集群,指定ip为172.20.0.4
docker run -d --name=mysql03 -p 3303:3306 -v v3:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=123456 -e CLUSTER_JOIN=mysql01 --privileged --net=pxc-net --ip 172.20.0.4 pxc
通过客户端工具分别连接到三个mysql,在其中一个mysql里面创建数据库,然后创建一张表并添加数据,其他两个mysql里面也能同步到数据。
2.Haproxy 负载均衡
# 拉取haproxy镜像
docker pull haproxy
# 在centos机器创建一个文件夹
mkdir -p /usr/local/haproxy
# 在上面的目录下创建一个haproxy.cfg配置文件
touch /usr/local/haproxy.haproxy.cfg
以下为 haproxy.cfg
配置文件内容
global
#工作目录,这边要和创建容器指定的目录对应,haproxy容器的目录默认在该路径
# chroot /usr/local/etc/haproxy
#日志文件
log 127.0.0.1 local5 info
#守护进程运行
daemon
defaults
log global
mode http
#日志格式
option httplog
#日志中不记录负载均衡的心跳检测记录
option dontlognull
#连接超时(毫秒)
timeout connect 5000
#客户端超时(毫秒)
timeout client 50000
#服务器超时(毫秒)
timeout server 50000
#监控界面
listen admin_stats
#监控界面的访问的IP和端口
bind 0.0.0.0:8123
#访问协议
mode http
#控制台URI相对地址
stats uri /haproxy
#统计报告格式
stats realm Global\ statistics
#控制台登陆帐户信息
stats auth admin:admin
#数据库负载均衡
listen proxy-mysql
#访问的IP和端口,haproxy开发的端口为3306
#假如有人访问haproxy的3306端口,则将请求转发给下面的数据库实例
bind 0.0.0.0:3306
#网络协议
mode tcp
#负载均衡算法(轮询算法)
#轮询算法:roundrobin
#权重算法:static-rr
#最少连接算法:leastconn
#请求源IP算法:source
balance roundrobin
#日志格式
option tcplog
#在MySQL中创建一个没有权限的haproxy用户,密码为空。
#Haproxy使用这个账户对MySQL数据库心跳检测
option mysql-check user haproxy
#以下为三台mysql容器ip和端口号
server MySQL_1 172.20.0.2:3306 check weight 1 maxconn 2000
server MySQL_2 172.20.0.3:3306 check weight 1 maxconn 2000
server MySQL_3 172.20.0.4:3306 check weight 1 maxconn 2000
#使用keepalive检测死链
option tcpka
创建haproxy容器
docker run -it -d -p 8123:8123 -p 3306:3306 -v /usr/local/haproxy/:/usr/local/etc/haproxy --name haproxy --privileged --net=pxc-net haproxy
启动完之后浏览器访问
# centos的ip加映射到centos的端口号,后面的uri就是我们再haproxy.cfg配置的stats uri
# 账户和密码使我们在haproxy.cfg配置的stats auth后面的参数
http://192.168.0.136:8123/haproxy
navicat连接数据库,需要创建一个haproxy用户,在mysql01的容器上面执行以下命令
# 进入mysql01容器
docker exec -it mysql01 /bin/bash
# 进入mysql,并输入密码
mysql -u root -p
# 首选执行该命令,正常情况都可以成功
CREATE USER 'haproxy'@'%' IDENTIFIED BY '';
# 如果创建失败,可以先输入一下命令
drop user 'haproxy'@'%';
flush privileges;
CREATE USER 'haproxy'@'%' IDENTIFIED BY '';
3.springboot项目连接高可用数据库
网络还是使用上面mysql高可用集群和haproxy的网络 pxc-net
上传springboot-mybatis.jar包
注意配置文件
# 数据源
spring:
datasource:
# 这里先使用haproxy容器的ip
url: jdbc:mysql://172.20.0.2:3306/sbm-ds?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
# mybatis托管mapper文件
mybatis:
mapper-locations: classpath:mapper/*.xml
接口
@RestController
@RequestMapping(value = "/user")
public class UserController {
@Autowired
private UserService userService;
private AtomicInteger value = new AtomicInteger(0);
// 查询所有用户接口
@RequestMapping("/getList")
public R<List<User>> getList(HttpServletRequest request) {
String msg = "第 " + value.incrementAndGet() + " 次调用...";
System.out.println(msg);
List<User> users = userService.getList();
return new R<>(200, msg, users);
}
// 添加用户接口
@RequestMapping(value = "/add", method = RequestMethod.POST)
public String add(User user) {
int result = userService.insertUser(user);
if (result >= 1) {
return "添加成功";
} else {
return "添加失败";
}
}
}
编写 Dockerfile
文件
FROM openjdk:8-jre-alpine
MAINTAINER tianqingzhao
LABEL name="springboot-mybatis" version="1.0" author="tianqingzhao"
COPY springboot-mybatis-0.0.1-SNAPSHOT.jar springboot-mybatis.jar
CMD ["java","-jar","springboot-mybatis.jar"]
基于springboot的jar包和 Dockerfile
文件构建 springboot-mybatis-image
镜像
docker build -t springboot-mybatis-image .
基于image创建容器
# 映射到centos端口号为8811,使用pxc-net的网络,容器的ip使用172.20.0.11
docker run -d --name sbm01 -p 8811:8080 --net=pxc-net --ip 172.20.0.11 springboot-mybatis-image
访问接口
# centos通过curl命令
curl http://localhost:8811/user/getList
4.通过nginx负载均衡访问项目,数据库访问haproxy容器名称
整体流程:用户请求 —》 nginx —》springboot-mybatis容器项目
先删除之前的springboot-mybatis-image镜像和启动的sbm01容器
# 删除镜像
docker rmi springboot-mybatis-image:latest
# 删除容器
docker rm -f sbm01
修改配置文件数据库url连接
# 数据源
spring:
datasource:
### 在同一个网络中,bridge pxc-net 容器之间不仅可以通过ip访问,而且可以通过名称
url: jdbc:mysql://haproxy/sbm-ds?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
# mybatis托管mapper文件
mybatis:
mapper-locations: classpath:mapper/*.xml
打包上传重新构建image,上传之前,先删掉之前传的jar包。基于新上传的jar包重新构建镜像,Dockerfile
文件不用修改。
# 构建新的镜像
docker build -t springboot-mybatis-image .
# 重新构建之后的镜像目前已推送到hub.docker.com仓库,通过以下命令可拉取
docker pull tianqingzhao/springboot-mybatis:v1.0
基于springboot-mybatis-image镜像启动三个容器
# 启动sbm01容器
docker run -d --name sbm01 -p 8811:8080 --net=pxc-net --ip 172.20.0.11 springboot-mybatis-image
# 启动sbm02容器,注意修改容器名称、端口号、ip
docker run -d --name sbm02 -p 8822:8080 --net=pxc-net --ip 172.20.0.12 springboot-mybatis-image
# 启动sbm03容器,注意修改容器名称、端口号、ip
docker run -d --name sbm03 -p 8833:8080 --net=pxc-net --ip 172.20.0.13 springboot-mybatis-image
拉取nginx镜像
docker pull nginx
编写 nginx.conf
配置文件
user nginx;
worker_processes 1;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
# 访问路径为根路径
location / {
proxy_pass http://balance;
}
}
upstream balance{
server 172.18.0.20:8080;
server 172.18.0.20:8080;
server 172.18.0.20:8080;
}
include /etc/nginx/conf.d/*.conf;
}
创建nginx容器
# 容器名称为nginx,映射到centos端口号为80,把centos机器的nginx.conf挂载到容器的/etc/nginx/nginx.conf目录里面
# 使用pxc-net这个网络,ip为172.20.0.10
docker run -d --name nginx -p 80:80 -v /usr/local/nginx-image/nginx.conf:/etc/nginx/nginx.conf --network=pxc-net --ip 172.20.0.10 nginx
浏览器访问
# 该ip为centosip,由于nginx配置的为根路径,,端口号监听的80,所以直接访问ip加接口即可
http://192.168.0.136/user/getList
# 可以通过docker logs 容器名称 命令查看每个容器输出情况来验证是否做到了负载均衡
十、Docker-compose
1.基于Dockerfile启动一个python应用
在centos机器上面创建一个文件夹,用于存放Dockerfile和python应用的代码
# 创建文件夹
mkdir -p /usr/local/python
# 进入到该文件夹
cd /usr/local/python
接下来在上面创建的文件夹写一个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)
继续在上面的文件夹创建 requirements.txt
文件,该文件用于标识python应用的依赖包
flask
redis
编写 Dockerfile
文件
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
COPY . .
CMD ["flask", "run"]
根据上面的 Dockefile
文件生成镜像
docker build -t python-app-image .
拉取一个轻量级的redis镜像
docker pull redis:alpine
创建网络
# 指定网段为172.17.21.0,名称为python-net
docker network create --subnet=172.21.0.0/24 python-net
基于上面构建的镜像创建容器
docker run -d --name python-app -p 5000:5000 --network python-net python-app-image
基于redis镜像创建容器
docker run -d --name redis -p 6379:6379 --network python-net redis:alpine
浏览器访问
# centos的ip加python应用的端口号
http://192.168.0.136:5000/
# 可以看到有输出,每次访问都会递增1
Hello World! I have been seen 1 times.
2.docker-compose实现上面python应用
删除上面的容器、镜像、网络
docker rm -f python-app
docker rmi -f python-app-image
docker rm -f redis
docker rmi -f redis:alpine
docker network rm python-net
docker-compose是在单机上面进行多个容器的管理部署
首先安装docker-compose
# 下载 Docker-Compose版本,使用daocloud下载
curl -L https://get.daocloud.io/docker/compose/releases/download/1.25.1/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
# 使用官方的地址
curl -L https://github.com/docker/compose/releases/download/1.25.1/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
# 将可执行权限应用于二进制文件:
chmod +x /usr/local/bin/docker-compose
# 创建软链
ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
# 验证是否安装成功
docker-compose --version
编写 docker-compose.yaml
文件
version: '1'
services: # 表示定义一些容器,下面每一个service就是docker中容器的名称
python-app: # 容器名称
build: . # 从当前目录的Dockerfile进行构建
ports:
- "5000:5000" # 端口的映射,和 -p 命令一样
networks:
- python-net # 使用这个网络
redis:
image: "redis:alpine" # 从该镜像构建一个容器
networks:
- python-net
networks: # docker network create --name python-net
python-net:
driver: bridge # 创建一个python-net的网络,并指定为bridge类型的
使用 docker-compose.yaml
创建容器
# up表示启动 -d表示后台启动
# 如果有指定docker-compose.yaml文件,使用-f命令指定
docker-compose up -d
docker-compose文件详解
# service表示一个容器
# ports表示映射的端口号,相当于-p
# build表示要根据Dockerfile文件构建镜像
# networks表示创建网络,service下面指定networks参数表示使用该网络
# images表示指定从指定镜像创建service
# volumes表示指定数据卷,相当于-v v1:/var/lib/mysql
# enviornment表示参数,相当于-e
docker-compose常见操作
# 查看版本
docker-compose version
# 根据yml创建service
docker-compose up
# 指定yaml:docker-compose up -f xxx.yaml
# 后台运行:docker-compose up
#查看启动成功的service
docker-compose ps
# 也可以使用docker ps
# 查看images
docker-compose images
#停止/启动service
docker-compose stop/start
# 删除service[同时会删除掉network和volume]
docker-compose down
# 进入到某个service
docker-compose exec redis sh
十一、docker-swarm
docker-swarm是为了解决在多机部署容器
manager-node:2200
work01-node:2201
work02-node:2202
1.安装docker-swarm
进入manager
docker swarm init --advertise-addr=192.168.0.11
显示以下内容,复制圈住的内容
在其他两个worker节点执行该命令
docker swarm join --token SWMTKN-1-12nfretcz1e6jgguiifz5by9ntb2tuzdtjbc8znw9465n8nir6-93l1j9flq85rhxgvyf62ym0q7 192.168.0.11:2377
查看集群状态
docker node ls
可以看到manager-node节点的MANAGER STATUS为Leader
node类型的转换,可以将worker提升成manager,从而保证manager的高可用
# 提成节点为候选的
docker node promote worker01-node
docker node promote worker02-node
#降级可以用demote
docker node demote worker01-node
2.docker-swarm基本操作
创建一个service
docker service create --name tomcat01 tomcat
查看当前swarm的service
docker service ls
查看日志详情
docker service logs tomcat01
查看service的详情
docker service inspect tomcat01
查看容器运行在哪个节点上面
docker service ps tomcat01
# 输出以下内容,随机运行在某一个节点上面
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
pawlnlhurroa tomcat01.1 tomcat:latest worker01-node Running Running 6 hours ago
水平扩容service
docker service scale tomcat01=3
# 查看列表
docker service ls
# 查看详情
docker service ps my-tomcat
# 输出一下内容
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
pawlnlhurroa tomcat01.1 tomcat:latest worker01-node Running Running 7 hours ago
xg6yne73yug2 tomcat01.2 tomcat:latest manager-node Running Running 12 minutes ago
xig0y6lgaoiy tomcat01.3 tomcat:latest worker02-node Running Preparing 12 minutes ago
此时到worker01-node上:docker ps,可以发现container的name和service名称不一样
docker ps
# 显示一下内容
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f8fa8f859a1f tomcat:latest "catalina.sh run" 7 hours ago Up 7 hours 8080/tcp tomcat01.1.pawlnlhurroa78izqtc21zyjm
如果某个node上的my-tomcat挂掉了,这时候会自动扩展
# [worker01-node]
docker rm -f containerid
# [manager-node]
docker service ls
docker service ps my-tomcat
删除service
docker service rm my-tomcat
3.Swarm中部署一个个人博客
(1)创建一个overlay网络,用于docker swarm中多机通信
# manager节点执行
docker network create -d overlay my-overlay-net
# 此时worker node查看不到
docker network ls
(2)创建mysql的service
# manager节点创建service
docker service create --name mysql --mount type=volume,source=v1,destination=/var/lib/mysql --env MYSQL_ROOT_PASSWORD=examplepass --env MYSQL_DATABASE=db_wordpress --network my-overlay-net mysql:5.6
#查看service
docker service ls
docker service ps mysql
(3)创建wordpress的service
# 创建service [注意之所以下面可以通过mysql名字访问,也是因为有DNS解析]
docker service create --name wordpress --env WORDPRESS_DB_USER=root --env WORDPRESS_DB_PASSWORD=examplepass --env WORDPRESS_DB_HOST=mysql:3306 --env WORDPRESS_DB_NAME=db_wordpress -p 8080:80 --network my-overlay-net wordpress
# 查看service
docker service ls
docker service ps mysql
# 此时mysql和wordpress的service运行在哪个node上,这时候就能看到my-overlay-net的网络
(4)测试
win浏览器访问ip[manager/worker01/worker02]:8080都能访问成功
(5)查看my-overlay-net
docker network inspect my-overlay-net
(6)为什么没有用etcd?docker swarm中有自己的分布式存储机制
4. Routing Mesh
(1) Ingress
docker service create --name tomcat -p 8080:8080 --network my-overlay-net tomcat
记得使用一个自定义的overlay类型的网络
--network my-overlay-net
查看service情况
docker service ls
docker service ps tomcat
访问3台机器的ip:8080测试,发现都能够访问到tomcat的欢迎页
(2) Internal
之前在实战wordpress+mysql的时候,发现wordpress中可以直接通过mysql名称访问
这样可以说明两点,第一是其中一定有dns解析,第二是两个service的ip是能够ping通的
再创建一个service,也同样使用上述tomcat的overlay网络,然后来实验
docker service create --name whoami -p 8000:8000 --network my-overlay-net -d jwilder/whoami
查看whoami的情况
docker service ps whoami
在各自容器中互相ping一下彼此,也就是容器间的通信
#tomcat容器中ping whoami
docker exec -it 9d7d4c2b1b80 ping whoami
64 bytes from bogon (10.0.0.8): icmp_seq=1 ttl=64 time=0.050 ms
64 bytes from bogon (10.0.0.8): icmp_seq=2 ttl=64 time=0.080 ms
#whoami容器中ping tomcat
docker exec -it 5c4fe39e7f60 ping tomcat
64 bytes from bogon (10.0.0.18): icmp_seq=1 ttl=64 time=0.050 ms
64 bytes from bogon (10.0.0.18): icmp_seq=2 ttl=64 time=0.080 ms
将whoami进行扩容
docker service scale whoami=3
docker service ps whoami #manager,worker01,worker02
此时再ping whoami service,并且访问whoami服务
#ping
docker exec -it 9d7d4c2b1b80 ping whoami
64 bytes from bogon (10.0.0.8): icmp_seq=1 ttl=64 time=0.055 ms
64 bytes from bogon (10.0.0.8): icmp_seq=2 ttl=64 time=0.084 ms
#访问
docker exec -it 9d7d4c2b1b80 curl whoami:8000 [多访问几次]
I'm 09f4158c81ae
I'm aebc574dc990
I'm 7755bc7da921
whoami服务对其他服务暴露的ip是不变的,但是通过whoami名称访问8000端口,确实访问到的是不同的service。
也就是说whoami service对其他服务提供了一个统一的VIP入口,别的服务访问时会做负载均衡。
(3) Stack
docker stack deploy:https://docs.docker.com/engine/reference/commandline/stack_deploy/
compose-file:https://docs.docker.com/compose/compose-file/
docker swarm中的Stack,我们直接通过前面的wordpress+mysql案例看看怎么使用咯。
新建service.yml文件
version: '3'
services:
wordpress:
image: wordpress
ports:
- 8080:80
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: exampleuser
WORDPRESS_DB_PASSWORD: examplepass
WORDPRESS_DB_NAME: exampledb
networks:
- ol-net
volumes:
- wordpress:/var/www/html
deploy:
mode: replicated
replicas: 3
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
update_config:
parallelism: 1
delay: 10s
db:
image: mysql:5.7
environment:
MYSQL_DATABASE: exampledb
MYSQL_USER: exampleuser
MYSQL_PASSWORD: examplepass
MYSQL_RANDOM_ROOT_PASSWORD: '1'
volumes:
- db:/var/lib/mysql
networks:
- ol-net
deploy:
mode: global
placement:
constraints:
- node.role == manager
volumes:
wordpress:
db:
networks:
ol-net:
driver: overlay
根据service.yml创建service
docker stack deploy -c service.yml my-service
常见操作
# 查看stack具体信息
docker stack ls
NAME SERVICES ORCHESTRATOR
my-service 2 Swarm
#查看具体的service
docker stack services my-service
ID NAME MODE REPLICAS IMAGE PORTS
icraimlesu61 my-service_db global 1/1 mysql:5.7
iud2g140za5c my-service_wordpress replicated 3/3 wordpress:latest *:8080->80/tcp
# 查看某个service
docker service inspect my-service-db
"Endpoint": {
"Spec": {
"Mode": "vip"
},
"VirtualIPs": [
{
"NetworkID": "kz1reu3yxxpwp1lvnrraw0uq6",
"Addr": "10.0.1.5/24"
}
]
}
(4)访问测试
win浏览器ip[manager,worker01,worker02]:8080