Docker之进阶

七、网络

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值