1.Docker网络介绍

  1. Docker是基于Linux KernelnamespaceCGroups,UnionFileSystem等技术封装成的一种自定义容器格式,从而提供了一套虚拟运行环境。

namespace: 用来做隔离的,比如 pid[进程]、net【网络】、mnt【挂载点】

CGroups:Controller Groups 用来做资源限制,比如内存和CPU等

Union File Systems:用来做Image和Container分层

1.1 计算机网络模型

Docker网络官网:https://docs.docker.com/network/。

OSI:开放系统互联参考模型(Open System Interconnect)

TCP/IP:传输控制协议/网际协议(Transmission Control/Internet Protocol),是指能够在多个不同网络间实现信息传输的协议簇。TCP/IP协议不仅仅指的是TCP 和IP两个协议,而是指一个由FTP、SMTP、TCP、UDP、IP等协议构成的协议簇, 只是因为在TCP/IP协议中TCP协议和IP协议最具代表性,所以被称为TCP/IP协议。

分层思想:分层的基本想法是每一层都在它的下层提供的服务基础上提供更高级的增值服务,而最高层提供能运行分布式应用程序的服务

image.png

客户端发送请求:

image.png
服务端接受请求:
image.png

1.2 Liunx中网卡

1.2.1 查看网卡信息

查看网卡的命令

[vagrant@localhost ~]$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 52:54:00:4d:77:d3 brd ff:ff:ff:ff:ff:ff
    inet 10.0.2.15/24 brd 10.0.2.255 scope global noprefixroute dynamic eth0
       valid_lft 85987sec preferred_lft 85987sec
    inet6 fe80::5054:ff:fe4d:77d3/64 scope link 
       valid_lft forever preferred_lft forever
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 08:00:27:6e:31:45 brd ff:ff:ff:ff:ff:ff
    inet 192.168.56.10/24 brd 192.168.56.255 scope global noprefixroute eth1
       valid_lft forever preferred_lft forever
    inet6 fe80::a00:27ff:fe6e:3145/64 scope link 
       valid_lft forever preferred_lft forever
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether 02:42:bf:79:9f:de brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever

通过ip a 可以看到当前的centos中有的4个网卡信息作用分别是

名称 作用
lo 本地网卡【lo 是 loopback 的缩写,也就是环回的意思,linux系统默认会有一块名为 lo 的环回网络接口】
eth0 连接网络的网卡
eth1 和宿主机通信的网卡
docker0 docker的网卡
[vagrant@localhost ~]$ 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
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
    link/ether 52:54:00:4d:77:d3 brd ff:ff:ff:ff:ff:ff
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
    link/ether 08:00:27:6e:31:45 brd ff:ff:ff:ff:ff:ff
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default 
    link/ether 02:42:bf:79:9f:de brd ff:ff:ff:ff:ff:ff

以文件的形式查看网卡:ls /sys/class/net

[vagrant@localhost ~]$ ls /sys/class/net
docker0  eth0  eth1  lo

1.2.2 配置文件

在Linux中网卡对应的其实就是文件,所以找到对应的网卡文件即可,存放的路径

[vagrant@localhost network-scripts]$ cd /etc/sysconfig/network-scripts/
[vagrant@localhost network-scripts]$ ls
ifcfg-eth0   ifdown-eth   ifdown-ppp       ifdown-tunnel  ifup-ippp   ifup-post    ifup-TeamPort      network-functions-ipv6
ifcfg-eth1   ifdown-ippp  ifdown-routes    ifup           ifup-ipv6   ifup-ppp     ifup-tunnel
ifcfg-lo     ifdown-ipv6  ifdown-sit       ifup-aliases   ifup-isdn   ifup-routes  ifup-wireless
ifdown       ifdown-isdn  ifdown-Team      ifup-bnep      ifup-plip   ifup-sit     init.ipv6-global
ifdown-bnep  ifdown-post  ifdown-TeamPort  ifup-eth       ifup-plusb  ifup-Team    network-functions

1.2.3 网卡操作

网卡中增加ip地址

[root@localhost ~]# ip addr add 192.168.100.120/24 dev eth0
[root@localhost ~]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 52:54:00:4d:77:d3 brd ff:ff:ff:ff:ff:ff
    inet 10.0.2.15/24 brd 10.0.2.255 scope global noprefixroute dynamic eth0
       valid_lft 84918sec preferred_lft 84918sec
    inet 192.168.100.120/24 scope global eth0  #### 增加了一个IP地址
       valid_lft forever preferred_lft forever
    inet6 fe80::5054:ff:fe4d:77d3/64 scope link 
       valid_lft forever preferred_lft forever
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 08:00:27:6e:31:45 brd ff:ff:ff:ff:ff:ff
    inet 192.168.56.10/24 brd 192.168.56.255 scope global noprefixroute eth1
       valid_lft forever preferred_lft forever
    inet6 fe80::a00:27ff:fe6e:3145/64 scope link 
       valid_lft forever preferred_lft forever
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether 02:42:bf:79:9f:de brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever

删除IP地址: ip addr delete 192.168.100.120/24 dev eth0

[root@localhost ~]# ip addr delete 192.168.100.120/24 dev eth0
[root@localhost ~]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 52:54:00:4d:77:d3 brd ff:ff:ff:ff:ff:ff
    inet 10.0.2.15/24 brd 10.0.2.255 scope global noprefixroute dynamic eth0
       valid_lft 84847sec preferred_lft 84847sec
    inet6 fe80::5054:ff:fe4d:77d3/64 scope link 
       valid_lft forever preferred_lft forever
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 08:00:27:6e:31:45 brd ff:ff:ff:ff:ff:ff
    inet 192.168.56.10/24 brd 192.168.56.255 scope global noprefixroute eth1
       valid_lft forever preferred_lft forever
    inet6 fe80::a00:27ff:fe6e:3145/64 scope link 
       valid_lft forever preferred_lft forever
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    lik/ether 02:42:bf:79:9f:de brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever

1.2.4 网卡信息解析

状态:UP/DOWN/UNKOWN等
link/ether:MAC地址
inet:绑定的IP地址

1.3 Network Namespace

Network Namespace 是实现网络虚拟化的重要功能,它能创建多个隔离的网络空间,它们有独自的网络栈信息。不管是虚拟机还是容器,运行的时候仿佛自己就在独立的网络中。

1.3.1 Network Namespce 实战

添加一个namespace

ip netns add ns1

查看当前具有的namespace

ip netns list
[root@localhost ~]# ip netns add ns1
[root@localhost ~]# ip netns list
ns1

删除namespace

ip netns delete ns1
[root@localhost ~]# ip netns add ns1
[root@localhost ~]# ip netns list
ns1
[root@localhost ~]# ip netns delete ns1
[root@localhost ~]# ip netns list
[root@localhost ~]#

查看namespace【ns1】的网卡情况

ip netns exec ns1 ip a
[root@localhost ~]# ip netns exec ns1 ip a
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

image.png
启动网络状态

ip netns exec ns1 ifup lo
[root@localhost ~]# 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
[root@localhost ~]# ip netns exec ns1 ifup lo
[root@localhost ~]# ip netns exec ns1 ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
[root@localhost ~]#

关掉网络状态

[root@localhost ~]# ip netns exec ns1 ifdown lo
[root@localhost ~]# ip netns exec ns1 ip a
1: lo: <LOOPBACK> mtu 65536 qdisc noqueue state DOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

还可以通过 link 来设置状态

[root@localhost ~]# ip netns exec ns1 ip link set lo up
[root@localhost ~]# ip netns exec ns1 ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
[root@localhost ~]# ip netns exec ns1 ip link set lo down
[root@localhost ~]# ip netns exec ns1 ip a
1: lo: <LOOPBACK> mtu 65536 qdisc noqueue state DOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
[root@localhost ~]#

再次添加一个namespace【ns2】

[root@localhost ~]# ip netns add ns2
[root@localhost ~]# ip netns list 
ns2
ns1

现在要实现两个namespace的通信

image.png

要实现两个network namespace的通信,我们需要实现到的技术是:

veth pair:Virtual Ethernet Pair,是一个成对的端口,可以实现上述功能

image.png

创建一对link,也就是接下来要通过veth pair连接的link

ip link add veth-ns1 type veth peer name veth-ns2

然后在宿主机中就会多出一对网卡信息

image.png

然后将创建好的 veth-ns1交给namespace1,把veth-ns2交给namespace2

ip link set veth-ns1 netns ns1
ip link set veth-ns2 netns ns2

image.png

再查看ns1和ns2中的link情况

[root@localhost ~]# ip netns exec ns1 ip link
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
6: veth-ns1@if5: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 7e:bb:ee:13:a2:9a brd ff:ff:ff:ff:ff:ff link-netnsid 1
[root@localhost ~]# ip netns exec ns2 ip link
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
5: veth-ns2@if6: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 7e:f8:18:5a:ef:1f brd ff:ff:ff:ff:ff:ff link-netnsid 0

此时veth-ns1和veth-ns2还没有ip地址,显然通信还缺少点条件

ip netns exec ns1 ip addr add 192.168.0.11/24 dev veth-ns1
ip netns exec ns2 ip addr add 192.168.0.12/24 dev veth-ns2

image.png

再次查看,发现state是DOWN.所以我们需要启用对应的网卡

[root@localhost ~]# ip netns exec ns1 ip link set veth-ns1 up
[root@localhost ~]# ip netns exec ns2 ip link set veth-ns2 up

然后查看状态

image.png

然后就可以相互之间ping通了

ip netns exec ns1 ping 192.168.0.12 ip netns exec ns2 ping 192.168.0.11

image.png

1.3.2 Container的NameSpace

按照上面的描述,实际上每个container,都会有自己的network namespace,并且是独立的,我们可以进入到容器中进行验证

创建两个Tomcat容器

docker run -d —name tomcat01 -p 8081:8080 tomcat

docker run -d —name tomcat02 -p 8082:8080 tomcat

进入到两个容器中,查看ip

docker exec -it tomcat01 ip a

docker exec -it tomcat02 ip a

相互ping是可以ping通的

image.png

问题:此时tomcat01和tomcat02属于两个network namespace,是如何能够ping通的? 有些小伙伴可能会想,不就跟上面的namespace实战一样吗?注意这里并没有veth-pair技术

1.4 深入分析container网络-Bridge

1.4.1 Docker默认Bridge

首先我们通过ip a可以查看当前宿主机的网络情况

[root@localhost tomcat]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 52:54:00:4d:77:d3 brd ff:ff:ff:ff:ff:ff
    inet 10.0.2.15/24 brd 10.0.2.255 scope global noprefixroute dynamic eth0
       valid_lft 66199sec preferred_lft 66199sec
    inet6 fe80::5054:ff:fe4d:77d3/64 scope link 
       valid_lft forever preferred_lft forever
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 08:00:27:6e:31:45 brd ff:ff:ff:ff:ff:ff
    inet 192.168.56.10/24 brd 192.168.56.255 scope global noprefixroute eth1
       valid_lft forever preferred_lft forever
    inet6 fe80::a00:27ff:fe6e:3145/64 scope link 
       valid_lft forever preferred_lft forever
4: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:52:d4:0a:9f brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:52ff:fed4:a9f/64 scope link 
       valid_lft forever preferred_lft forever
24: veth78a90d0@if23: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
    link/ether 7e:6b:8c:bf:7e:30 brd ff:ff:ff:ff:ff:ff link-netnsid 2
    inet6 fe80::7c6b:8cff:febf:7e30/64 scope link 
       valid_lft forever preferred_lft forever
26: vetha2bfbf4@if25: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
    link/ether ce:2f:ed:e5:61:32 brd ff:ff:ff:ff:ff:ff link-netnsid 3
    inet6 fe80::cc2f:edff:fee5:6132/64 scope link 
       valid_lft forever preferred_lft forever

然后查看 tomcat01中的网络: docker exec -it tomcat01 ip a可以发现

[root@localhost tomcat]# docker exec -it tomcat01 ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
23: eth0@if24: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever

我们发现在宿主机中是可以ping通Tomcat01的网络的。

[root@localhost tomcat]# ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.038 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.038 ms
^C
--- 172.17.0.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.038/0.038/0.038/0.000 ms

既然可以ping通,而且centos和tomcat01又属于两个不同的NetWork NameSpace,他们是怎么连接的?看图

image.png

其实在tomcat01中有一个eth0和centos的docker0中有一个veth是成对的,类似于之前实战中的veth-ns1和veth-ns2,要确认也很简单

yum install bridge-utils
brctl show

执行

[root@localhost tomcat]# brctl show
bridge name    bridge id        STP enabled    interfaces
docker0        8000.024252d40a9f    no        veth78a90d0
                                        vetha2bfbf4

对比 ip a 情况

image.png

那么画图说明:

image.png

这种网络连接方法我们称之为Bridge,其实也可以通过命令查看docker中的网络模式:docker network ls , bridge也是docker中默认的网络模式

[root@localhost tomcat]# docker network ls 
NETWORK ID     NAME      DRIVER    SCOPE
92242fc0f805   bridge    bridge    local
96b999d7fcc2   host      host      local
17b86f9caa33   none      null      local

不妨检查一下bridge:docker network inspect bridge

"Containers": {
            "4b3500fed6b99c00b3ed1ae46bd6bc33040c77efdab343175363f32fbcf42e63": {
                "Name": "tomcat01",
                "EndpointID": "40fc0925fcb59c9bb002779580107ab9601640188bf157fa57b1c2de9478053a",
                "MacAddress": "02:42:ac:11:00:02",
                "IPv4Address": "172.17.0.2/16",
                "IPv6Address": ""
            },
            "92d2ff3e9be523099ac4b45058c5bf4652a77a27b7053a9115ea565ab43f9ab0": {
                "Name": "tomcat02",
                "EndpointID": "1d6c3bd73e3727dd368edf3cc74d2f01b5c458223f844d6188486cb26ea255bc",
                "MacAddress": "02:42:ac:11:00:03",
                "IPv4Address": "172.17.0.3/16",
                "IPv6Address": ""
            }
        }

在tomcat01容器中是可以访问互联网的,顺便把这张图画一下咯,NAT是通过iptables实现的

image.png

1.4.2 自定义NetWork

创建一个network,类型为 Bridge

docker network create tomcat-net
或者
docker network create tomcat-net --subnet=172.18.0.0/24 tomcat-net

查看已有的NetWork: docker network ls

[root@localhost ~]# docker network create tomcat-net
43915cba1f9204751b48896d7d28b83b4b6cf35f06fac6ff158ced5fb9ddb5b3
[root@localhost ~]# docker network ls
NETWORK ID     NAME         DRIVER    SCOPE
b5c9cfbc0410   bridge       bridge    local
96b999d7fcc2   host         host      local
17b86f9caa33   none         null      local
43915cba1f92   tomcat-net   bridge    local

查看tomcat-net详情信息:docker network inspect tomcat-net

[root@localhost ~]# docker network inspect tomcat-net
[
    {
        "Name": "tomcat-net",
        "Id": "43915cba1f9204751b48896d7d28b83b4b6cf35f06fac6ff158ced5fb9ddb5b3",
        "Created": "2021-10-11T12:10:19.543766962Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.18.0.0/16",
                    "Gateway": "172.18.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {},
        "Options": {},
        "Labels": {}
    }
]

删除network:docker network rm tomcat-net

创建tomcat容器,并指定使用tomcat-net

[root@localhost ~]# docker run -d --name custom-net-tomcat --network tomcat-net tomcat-ip:1.0
264b3901f8f12fd7f4cc69810be6a24de48f82402b1e5b0df364bd1ee72d8f0e

查看custom-net-tomcat的网络信息:截取了关键信息

12: br-43915cba1f92: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:71:a6:67:c7 brd ff:ff:ff:ff:ff:ff
    inet 172.18.0.1/16 brd 172.18.255.255 scope global br-43915cba1f92
       valid_lft forever preferred_lft forever
    inet6 fe80::42:71ff:fea6:67c7/64 scope link 
       valid_lft forever preferred_lft forever
14: veth282a555@if13: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br-43915cba1f92 state UP group default 
    link/ether 3a:3d:83:15:3f:ed brd ff:ff:ff:ff:ff:ff link-netnsid 3
    inet6 fe80::383d:83ff:fe15:3fed/64 scope link 
       valid_lft forever preferred_lft forever

查看网卡接口信息

[root@localhost ~]# brctl show
bridge name                  bridge id        STP   enabled      interfaces
br-43915cba1f92        8000.024271a667c7    no                  veth282a555
docker0                8000.02423964f095    no                  veth4526c0c
                                                          vethaa2f6f4
                                                          vethc6ad4c2

此时在custom-net-tomcat容器中ping一些tomcat01发现是ping不通的

[root@localhost ~]# docker exec -it custom-net-tomcat ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
^C
--- 172.17.0.2 ping statistics ---
3 packets transmitted, 0 received, 100% packet loss, time 2000ms

此时如果tomcat01容器能够连接上tomcat-net上应该就可以了

docker network connect tomcat-net tomcat01
[root@localhost ~]# docker exec -it tomcat01 ping custom-net-tomcat
PING custom-net-tomcat (172.18.0.2) 56(84) bytes of data.
64 bytes from custom-net-tomcat.tomcat-net (172.18.0.2): icmp_seq=1 ttl=64 time=0.138 ms
^C
--- custom-net-tomcat ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.138/0.138/0.138/0.000 ms
[root@localhost ~]# docker exec -it custom-net-tomcat ping tomcat01
PING tomcat01 (172.18.0.3) 56(84) bytes of data.
64 bytes from tomcat01.tomcat-net (172.18.0.3): icmp_seq=1 ttl=64 time=0.031 ms

1.5 深入分析 Container网络-Host&None

1.5.1 Host

 Host模式下,容器将共享主机的网络堆栈,并且主机的所有接口都可供容器使用.容器的主机名将与主机系统上的主机名匹配

创建一个容器,并指定网络为host

docker run -d --name my-tomcat-host --network host tomcat-ip:1.0

查看ip地址

docker exec -it my-tomcat-host ip a

检查host网络

docker network inspect host
"Containers": {
            "f495a6892d422e61daab01e3fcfa4abb515753e5f9390af44c93cae376ca7464": {
                "Name": "my-tomcat-host",
                "EndpointID": "77012b1ac5d15bde3105d2eb2fe0e58a5ef78fb44a88dc8b655d373d36cde5da",
                "MacAddress": "",
                "IPv4Address": "",
                "IPv6Address": ""
            }
        }

1.5.2 None

    None模式不会为容器配置任何IP,也不能访问外部网络以及其他容器.它具有环回地址,可用于运行批处理作业.

创建一个tomcat容器,并指定网络为none

docker run -d --name my-tomcat-none --network none tomcat-ip:1.0

查看ip地址

docker exec -it my-tomcat-none

检查none网络

docker network inspect none
        "Containers": {
            "c957b61dae93fbb9275acf73c370e5df1aaf44a986579ee43ab751f790220807": {
                "Name": "my-tomcat-none",
                "EndpointID": "16bf30fb7328ceb433b55574dc071bf346efa58e2eb92b6f40d7a902ddc94293",
                "MacAddress": "",
                "IPv4Address": "",
                "IPv6Address": ""
            }
        }

1.6 端口映射

创建一个tomcat容器,名称为port-tomcat

docker run -d --name port-tomcat tomcat-ip:1.0

思考如何访问tomcat的服务

docker exec -it port-tomcat bash
curl localhost:8080

如果要载centos7上访问呢

docker exec -it port-tomcat ip a
curl 172.17.0.4:8080

如果我们需要在centos中通过localhost来访问呢?这时我们就需要将port-tomcat中的8080端口映射到centos上了

docker rm -f port-tomcat
docker run -d --name port-tomcat -p 8090:8080 tomcat-ip:1.0
curl localhost:8090

centos7是运行在win10上的虚拟机,如果想要在win10上通过ip:port方式访问呢?

#此时需要centos和win网络在同一个网段,所以在Vagrantfile文件中

#这种方式等同于桥接网络。也可以给该网络指定使用物理机哪一块网卡,比如
#config.vm.network"public_network",:bridge=>'en1: Wi-Fi (AirPort)' 
config.vm.network"public_network"

centos7: ip a    --->192.168.8.118 
win10:浏览器访问        192.168.8.118:9080

image.png

1.7 多机之间通信

具体深入介绍会在 Docker Swarm 中详聊,本节简单介绍。

在同一台centos7机器上,发现无论怎么折腾,我们一定有办法让两个container通信。 那如果是在两台centos7机器上呢?画个图
image.png

VXLAN技术实现:Virtual Extensible LAN(虚拟可扩展局域网)。

image.png

2.Docker实战

2.1 MySQL高可用集群搭建

 MySQL集群搭建在实际项目中还是非常必须的,我们通过PXC【Percona XtraDB Cluster】来实现强一致性数据库集群搭建。

2.1.1 MySQL集群搭建

1> 拉去镜像

docker pull percona/percona-xtradb-cluster:5.7.21

2> 复制pxc镜像【重命名】

docker tag percona/percona-xtradb-cluster:5.7.21 pxc

3>删除原来的镜像

docker rmi percona/percona-xtradb-cluster:5.7.21

4>创建单独的网段,给MySQL数据库集群使用

docker network create --subnet=172.20.0.0/24 pxc-net
docker network inpsect pxc-net # 查看详情
docker network rm pxc-net # 删除网段

5> 创建和删除volume

docker volume create --name v1 # 创建 volume
docker volume rm v1 # 删除volume
docker volume inspect v1 # 查看详情

6> 搭建pxc集群

准备三个数据卷

docker volume create --name v1 
docker volume create --name v2 
docker volume create --name v3

运行3个PXC容器

[CLUSTER_NAME PXC集群名字]

[XTRABACKUP_PASSWORD数据库同步需要用到的密码]

创建第一个节点

docker run -d -p 3301:3306 -v v1:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -e CLUSTER_NAME=PXC -e EXTRABACKUP_PASSWROD=123456 --privileged --name=node1 --net=pxc-net --ip 172.22.0.2 pxc

创建第二个和第三个节点: 注意 -e CLUSTER_JOIN=node1

docker run -d -p 3302:3306 -v v2:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -e CLUSTER_NAME=PXC -e EXTRABACKUP_PASSWROD=123456 -e CLUSTER_JOIN=node1 --privileged --name=node2 --net=pxc-net --ip 172.22.0.3 pxc
docker run -d -p 3303:3306 -v v3:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -e CLUSTER_NAME=PXC -e EXTRABACKUP_PASSWROD=123456 -e CLUSTER_JOIN=node1 --privileged --name=node3 --net=pxc-net --ip 172.22.0.4 pxc

2.1.2 负载均衡服务搭建

image.png

1>拉去镜像

docker pull haproxy

2>创建haproxy的配置文件。

touch /tmp/haproxy/haproxy.cfg

配置文件中的内容

global
    #工作目录,这边要和创建容器指定的目录对应
    # 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:8888
    #访问协议
     mode        http
    #URI相对地址
     stats uri   /dbs_monitor
    #统计报告格式
     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
    server  MySQL_1 172.22.0.2:3306 check weight 1 maxconn 2000  
     server  MySQL_2 172.22.0.3:3306 check weight 1 maxconn 2000  
    server  MySQL_3 172.22.0.4:3306 check weight 1 maxconn 2000 
    #使用keepalive检测死链
     option  tcpka

3>创建haproxy容器

docker run  -d -p 8888:8888 -p 3306:3306 -v /tmp/haproxy:/usr/local/etc/haproxy --name haproxy01 --privileged --net=pxc-net haproxy

4>在MySQL数据库上创建用户,用于心跳检测

CREATE USER 'haproxy'@'%' IDENTIFIED BY '';

5>win浏览器访问

http://centos_ip:8888/dbs_monitor
用户名密码都是:admin

6>客户端连接工具连接

ip:centos_ip
port:3306
user:root
password:123456

2.2 SpringBoot项目部署

咱们一个实际的项目部署情况应该是这样的。

image.png

接下来我们就在MySQL集群环境的基础上来完成一个SpringBoot项目的集群部署操作。网络地址分配为:

image.png

1> 创建对应的网络

docker network create --subnet=172.24.0.0/24 sbm-net

2>创建SpringBoot项目

通过SpringBoot项目整合MyBatis实现CRUD操作,

属性文件中配置的jdbc信息为

# jdbc的相关配置信息
spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://192.168.56.10:3306/haproxy-test?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true
spring.datasource.username=root
spring.datasource.password=123456
# 连接池
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
# mybatis给package设置别名
mybatis.type-aliases-package=com.bobo.pojo
#指定映射文件的位置
mybatis.mapper-locations=classpath:mapper/*.xml

3>对应的项目打成jar包,并上传到centos7中目录放在 /tmp/springboot/ 下 然后创建Dockerfile文件

yum install -y lrzsz
FROM openjdk:8
MAINTAINER bobo
LABEL name="springboot-mybatis" version="1.0" author="bobo"
COPY springboot-mybatis-demo-0.0.1-SNAPSHOT.jar springboot-mybatis.jar
CMD ["java","-jar","springboot-mybatis.jar"]

4>基于Dockerfile构建镜像

    docker build -t sbm-image .

5>基于image创建container

docker run -d --name sb01 -p 8081:8080 --net=sbm-net --ip 172.24.0.11 sbm-image

6>查看启动日志docker logs sb01

7>浏览器访问测试

http://192.168.56.10:8081/user/query

8>创建多个容器

docker run -d --name sb01 -p 8081:8080 --net=pro-net --ip 172.24.0.11 sbm-image
docker run -d --name sb02 -p 8082:8080 --net=pro-net --ip 172.24.0.12 sbm-image
docker run -d --name sb03 -p 8083:8080 --net=pro-net --ip 172.24.0.13 sbm-image

9>Nginx安装

我们通过Nginx来实现负载均衡服务

在centos的/tmp/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.24.0.11:8080;
        server 172.24.0.12:8080;
        server 172.24.0.13:8080;
    }
    include /etc/nginx/conf.d/*.conf;
}

创建容器

docker run -d --name my-nginx -p 80:80 -v /tmp/nginx/nginx.conf:/etc/nginx/nginx.conf --network=pxc-net --ip 172.24.0.10 nginx

3.DockerCompose

3.1 DockerCompose介绍

 Compose 是用于定义和运行多容器 Docker 应用程序的工具。通过 Compose,您可以使用 YML 文件来配置应用程序需要的所有服务。然后,使用一个命令,就可以从 YML 文件配置中创建并启动所有服务。

一键启动所有的服务

DockerCompose的使用步骤

  • 创建对应的DockerFile文件
  • 创建yml文件,在yml文件中编排我们的服务
  • 通过docker-compose up命令 一键运行我们的容器

3.2 Compose安装

官网地址:https://docs.docker.com/compose

sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

速度比较慢的话使用下面的地址:

curl -L https://get.daocloud.io/docker/compose/releases/download/1.25.0/docker-compose-`uname -s`-`uname -m` > /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

3.3 Compose初体验

通过官方案例来演示:https://docs.docker.com/compose/gettingstarted/

创建对应的目录

 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)

在同级目录下创建requirements.txt文件

flask
redis

然后创建对应的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"]

然后创建核心的 yml文件docker-compose.yml

version: "3.9"
services:
  web:
    build: .
    ports:
      - "5000:5000"
  redis:
    image: "redis:alpine"

最终通过docker-compose up命令来启动容器

docker-compose up

如果要退出服务 Ctrl+c 或者 docker-compose down

3.4 Compose配置规则

docker-compse.yml核心

官网地址:https://docs.docker.com/compose/compose-file/compose-file-v3/

version: '' # 版本
servers:  # 服务
  服务1: web
     # 服务的配置
     build
     network
     images
  服务2: redis
  服务3:
  服务4:
  ...
# 其他配置 网络,全局的规则 数据卷
volumes:
configs:
networks:

3.5 Compose一键部署实战

3.5.1 一键部署WP博客

1> 创建my_wordpress目录

mkdir my_wordpress

2>创建yml文件docker-compose.yml

version: "3.9"

services:
  db:
    image: mysql:5.7
    volumes:
      - db_data:/var/lib/mysql
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: somewordpress
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: wordpress

  wordpress:
    depends_on:
      - db
    image: wordpress:latest
    volumes:
      - wordpress_data:/var/www/html
    ports:
      - "8000:80"
    restart: always
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: wordpress
      WORDPRESS_DB_NAME: wordpress
volumes:
  db_data: {}
  wordpress_data: {}

3>通过up命令启动

docker-compose up -d

3.5.2 部署一个SpringBoot项目

我们自己通过Java项目实现访问计数的功能

FROM java:8
COPY my-counter-views-0.0.1-SNAPSHOT.jar app.jar
EXPOSE 8080
CMD ["java","-jar","app.jar"]

yml

version: '3.9'
services:
  myapp:
    build: .
    image: myapp
    depends_on:
      - redis
    ports:
      - "8080:8080"
  redis:
    image: "library/redis:alpine"

3.6 Compose常见操作

(1)查看版本

docker-compose version

(2)根据yml创建service

docker-compose up

指定yaml:docker-compose  up -f xxx.yaml

后台运行:docker-compose up -d

(3)查看启动成功的service

docker-compose ps

也可以使用docker ps

(4)查看images

docker-compose images

(5)停止/启动service

docker-compose stop/start

(6)删除service[同时会删除掉network和volume]

docker-compose down

(7)进入到某个service

docker-compose exec redis sh

3.7 scale扩缩容

docker-compose up --scale web=5 -d

小结:docker-compose

工程—>服务—>容器

version:
services:
  服务1:
  服务2:
  服务3:

4.Harbor

镜像私服仓库

4.1 Docker hub

官网地址:hub.docker.com

(1)在docker机器上登录

docker login

(2)输入用户名和密码

(3)docker push q279583842q/tomcat-ip

[注意镜像名称要和docker id一致,不然push不成功]

(4)给image重命名,并删除掉原来的

docker tag tomcat-ip q279583842q/tomcat-ip

docker rmi -f tomcat-ip

(5)再次推送,刷新hub.docker.com后台,发现成功

(6)别人下载,并且运行

docker pull q279583842q/tomcat-ip

docker run -d —name user01 -p 6661:8080 q279583842q/tomcat-ip

服务上传和下载比较耗时

4.2 阿里云Docker Registry

仓库地址:https://cr.console.aliyun.com/cn-hangzhou/instances/repositories

登录阿里云,进入到镜像服务,创建命名空间
创建镜像仓库
将镜像推送到阿里云镜像仓库

$ docker login --username=dpb2****83842 registry.cn-hangzhou.aliyuncs.com
$ docker tag [ImageId] registry.cn-hangzhou.aliyuncs.com/deng66/dpb-tomcat:[镜像版本号]
$ docker push registry.cn-hangzhou.aliyuncs.com/deng66/dpb-tomcat:[镜像版本号]

我们pull镜像的步骤

$ docker pull registry.cn-hangzhou.aliyuncs.com/deng66/dpb-tomcat:[镜像版本号]

4.3 私服Harbor

4.3.1 Harbor简介

   Docker容器应用的开发和运行离不开可靠的镜像管理,虽然Docker官方也提供了公共的镜像仓库,但是从安全和效率等方面考虑,部署我们私有环境内的Registry也是非常必要的。Harbor是由VMware公司开源的企业级的Docker Registry管理项目,它包括权限管理(RBAC)、LDAP、日志审核、管理界面、自我注册、镜像复制和中文支持等功能。

4.3.2 功能介绍

组件 功能
harbor-adminserver 配置管理中心
harbor-db Mysql数据库
harbor-jobservice 负责镜像复制
harbor-log 记录操作日志
harbor-ui Web管理页面和API
nginx 前端代理,负责前端页面和镜像上传/下载转发
redis 会话
registry 镜像存储

4.3.3 Harbor安装

官网安装教程:https://goharbor.io/docs/2.3.0/install-config/

首先需要下载对于的安装文件:https://github.com/goharbor/harbor/releases

因为比较大,从官网下载很慢,所以会在附近中直接给大家提供,使用最新的2.3.3版本

1> 上传解压安装文件

cd /usr/local/

2>修改配置文件

把 harbor.yml.tmpl 修改为 harbor.yml 文件

hostname: 192.168.56.15
http:
 port: 80
https:
  port: 443
  certificate: /data/cert/192.168.56.15.crt 
  private_key: /data/cert/192.168.56.15.key
external_url: https://192.168.56.15
harbor_admin_password: Harbor12345
database:
  password: root123
  max_idle_conns: 50
  max_open_conns: 100
data_volume: /data/harbor
clair:
  updaters_interval: 12
jobservice:
  max_job_workers: 10
notification:
  webhook_job_max_retry: 10
chart:
  absolute_url: disabled
log:
  level: info
  local:
    rotate_count: 50
    rotate_size: 200M
    location: /data/harbor/logs
_version: 1.10.0
proxy:
  http_proxy:
  https_proxy:
  no_proxy:
  components:
    - core
    - jobservice
    - clair

3>.harbor配置 https 访问

参考文档:

https://goharbor.io/docs/1.10/install-config/configure-https/

https://goharbor.io/docs/1.10/install-config/troubleshoot-installation/#https

    默认情况下,Harbor不附带证书。可以在没有安全性的情况下部署Harbor,以便您可以通过HTTP连接到它。但是,只有在没有外部网络连接的空白测试或开发环境中,才可以使用HTTP。在没有空隙的环境中使用HTTP会使您遭受中间人攻击。在生产环境中,请始终使用HTTPS。如果启用Content Trust with Notary来正确签名所有图像,则必须使用HTTPS。

要配置HTTPS,必须创建SSL证书。您可以使用由受信任的第三方CA签名的证书,也可以使用自签名证书

生成证书颁发机构证书

在生产环境中,您应该从CA获得证书。在测试或开发环境中,您可以生成自己的CA。要生成CA证书,请运行以下命令。

生成CA证书私钥

openssl genrsa -out ca.key 4096

生成CA证书

调整-subj选项中的值以反映您的组织。如果使用FQDN连接Harbor主机,则必须将其指定为通用名称(CN)属性。

openssl req -x509 -new -nodes -sha512 -days 3650 \
 -subj "/C=CN/ST=Beijing/L=Beijing/O=example/OU=Personal/CN=harbor.od.com" \
 -key ca.key \
 -out ca.crt

如果是ip访问, 将 harbor.od.com 改成 ip地址

生成服务器证书

证书通常包含一个.crt文件和一个.key文件

生成私钥

openssl genrsa -out harbor.od.com.key 4096

生成证书签名请求(CSR)

openssl req -sha512 -new \
    -subj "/C=CN/ST=Beijing/L=Beijing/O=example/OU=Personal/CN=harbor.od.com" \
    -key harbor.od.com.key \
    -out harbor.od.com.csr

如果是ip访问, 将 harbor.od.com 改成 ip地址

生成一个x509 v3扩展文件

无论您使用FQDN还是IP地址连接到Harbor主机,都必须创建此文件,以便可以为您的Harbor主机生成符合主题备用名称(SAN)和x509 v3的证书扩展要求。替换DNS条目以反映您的域

cat > v3.ext <<-EOF
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names

[alt_names]
DNS.1=harbor.od.com
DNS.2=harbor.od.com
DNS.3=harbor.od.com
EOF
  • 如果是ip访问
    cat > v3.ext <<-EOF
    authorityKeyIdentifier=keyid,issuer
    basicConstraints=CA:FALSE
    keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
    extendedKeyUsage = serverAuth
    subjectAltName = IP:192.168.56.15
    EOF
    

使用该**v3.ext**文件为您的Harbor主机生成证书

openssl x509 -req -sha512 -days 3650 \
    -extfile v3.ext \
    -CA ca.crt -CAkey ca.key -CAcreateserial \
    -in harbor.od.com.csr \
    -out harbor.od.com.crt

如果是ip访问, 将 harbor.od.com 改成 ip地址

提供证书给Harbor和Docker

生成后ca.crtharbor.od.com.crtharbor.od.com.key文件,必须将它们提供给Harbordocker,重新配置它们

将服务器证书和密钥复制到Harbor主机上的/data/cert/文件夹中

mkdir -p /data/cert/
cp harbor.od.com.crt /data/cert/
cp harbor.od.com.key /data/cert/

转换harbor.od.com.crtharbor.od.com.cert,供Docker使用

openssl x509 -inform PEM -in harbor.od.com.crt -out harbor.od.com.cert

将服务器证书,密钥和CA文件复制到Harbor主机上的Docker证书文件夹中。您必须首先创建适当的文件夹

mkdir -p /etc/docker/certs.d/harbor.od.com/
cp harbor.od.com.cert /etc/docker/certs.d/harbor.od.com/
cp harbor.od.com.key /etc/docker/certs.d/harbor.od.com/
cp ca.crt /etc/docker/certs.d/harbor.od.com/

如果将默认nginx端口443 映射到其他端口,请创建文件夹/etc/docker/certs.d/yourdomain.com:port/etc/docker/certs.d/harbor_IP:port

重新启动Docker Engine

systemctl restart docker

证书目录结构

/etc/docker/certs.d/
└── harbor.od.com
    ├── ca.crt
    ├── harbor.od.com.cert
    └── harbor.od.com.key

Harbor将nginx实例用作所有服务的反向代理。您可以使用prepare脚本来配置nginx为使用HTTPS

./prepare

初始化服务

sh install.sh

停止并删除服务

docker-compose down -v

重启服务

docker-compose up -d

连接验证

docker登录

4.3.4 Harbor部署应用

上传镜像到Harbor服务中

在Web服务中创建项目和用户

创建用户

然后项目分配用户

推送镜像到Harbor仓库中

docker tag redis:latest 192.68.56.10/dpb/redis-dpb:1.0
docker push 192.168.56.10/dpb/redis-dpb:1.0

在Web项目中可以看到上传的镜像
从Harbor镜像仓库拉取镜像
执行拉取命令

5. Swarm

解决集群问题 k8s

官网地址:https://docs.docker.com/engine/swarm/

5.1 Swarm介绍

Swarm是Docker官方提供的一款集群管理工具,其主要作用是把若干台Docker主机抽象为一个整体,并且通过一个入口统一管理这些Docker主机上的各种Docker资源。Swarm和Kubernetes比较类似,但是更加轻,具有的功能也较kubernetes更少一些

管理节点

管理节点处理集群管理任务:

  • 维护集群状态
  • 调度服务
  • 服务群模式HTTP API 端点

    使用`Raft`实现,管理器维护整个 swarm 及其上运行的所有服务的一致内部状态。出于测试目的,可以使用单个管理器运行 swarm。如果单管理器群中的管理器出现故障,您的服务会继续运行,但您需要创建一个新集群来恢复。
    

为了利用 swarm 模式的容错特性,Docker 建议您根据组织的高可用性要求实现奇数个节点。当您有多个管理器时,您可以在不停机的情况下从管理器节点的故障中恢复。

  • 三个管理器的群体最多可以容忍一个管理器的损失。
  • 一个五管理器群可以容忍最大同时丢失两个管理器节点。
  • 一个N管理器集群最多可以容忍管理器的丢失 (N-1)/2
  • Docker 建议一个群最多有七个管理器节点。

工作节点

   工作节点也是 Docker 引擎的实例,其唯一目的是执行容器。Worker 节点不参与 Raft 分布式状态,不做出调度决策,也不为 swarm 模式 HTTP API 提供服务。

您可以创建一个由一个管理器节点组成的群,但是如果没有至少一个管理器节点,您就不能拥有一个工作节点。默认情况下,所有经理也是工人。在单个管理器节点集群中,您可以运行类似命令docker service create,调度程序将所有任务放在本地引擎上。

为防止调度程序将任务放置在多节点群中的管理器节点上,请将管理器节点的可用性设置为Drain。调度器在Drainmode 中优雅地停止节点上的任务并调度Active节点上的任务 。调度程序不会将新任务分配给具有Drain 可用性的节点。

5.2 Swarm集群搭建

环境准备

image.png

准备3个节点,通过vagrant新增加两个节点

需要单独指定hostname

config.vm.hostname="work01-node"

还有就是每个节点需要具备Docker环境

集群环境搭建

1> 创建manager节点

进入manager节点,manager node也可以作为worker node提供服务

docker swarm init -advertise 192.168.56.10

注意观察日志,拿到worker node加入manager node的信息

docker swarm join --token SWMTKN-1-0a5ph4nehwdm9wzcmlbj2ckqqso38pkd238rprzwcoawabxtdq-arcpra6yzltedpafk3qyvv0y3 192.168.56.10:2377

2>进入两个Worker

docker swarm join --token SWMTKN-1-0a5ph4nehwdm9wzcmlbj2ckqqso38pkd238rprzwcoawabxtdq-arcpra6yzltedpafk3qyvv0y3 192.168.56.10:2377

3>进入manager node 查看集群情况

docker node ls

4>node类型转换

可以将worker提升成manager,从而保证manager的高可用

docker node promote worker01-node
docker node promote worker02-node

#降级可以用demote
docker node demote worker01-node

在线Swarm演示:http://labs.play-with-docker.com 通过Dock Hub 的账号密码登录即可,有效会话4个小时

5.3 Raft一致性协议

Raft一致性协议:保证manager节点半数存活集群环境可用

一主两从

还是参考上面的案例直接操作

image.png

我们停掉manager节点,那么整个集群环境是不可用的

image.png

我们将一个work节点提升等级

image.png

二主一从

除了上面的promote提升到 主的案例意外,我们还可用从新来搭集群处理

我们可以在init后直接在 manager节点执行如下命令

docker swarm join-token manager

三主0从

停止其中一个整个集群还是可用

image.png

image.png

但是停止掉两个后就不可用使用了

image.png

image.png
image.png

5.4 Service

(1)创建一个tomcat的service

docker service create --name my-tomcat tomcat

(2)查看当前swarm的service

docker service ls

(3)查看service的启动日志

docker service logs my-tomcat

(4)查看service的详情

docker service inspect my-tomcat

(5)查看my-tomcat运行在哪个node上

docker service ps my-tomcat

日志

ID                  NAME                IMAGE               NODE                DESIRED STATE       CURRENT STATE           ERROR               PORTS
u6o4mz4tj396        my-tomcat.1         tomcat:latest       worker01-node       Running             Running 3 minutes ago

(6)水平扩展service

docker service scale my-tomcat=3
docker service ls
docker service ps my-tomcat

日志:可以发现,其他node上都运行了一个my-tomcat的service

[root@manager-node ~]# docker service ps my-tomcat
ID                  NAME                IMAGE               NODE                DESIRED STATE       CURRENT STATE            ERROR               PORTS
u6o4mz4tj396        my-tomcat.1         tomcat:latest       worker01-node       Running             Running 8 minutes ago                        
v505wdu3fxqo        my-tomcat.2         tomcat:latest       manager-node        Running             Running 46 seconds ago                       
wpbsilp62sc0        my-tomcat.3         tomcat:latest       worker02-node       Running             Running 49 seconds ago

此时到worker01-node上:docker ps,可以发现container的name和service名称不一样,这点要知道

CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
bc4b9bb097b8        tomcat:latest       "catalina.sh run"   10 minutes ago      Up 10 minutes       8080/tcp            my-tomcat.1.u6o4mz4tj3969a1p3mquagxok

(7)如果某个node上的my-tomcat挂掉了,这时候会自动扩展

[worker01-node]
docker rm -f containerid

[manager-node]
docker service ls
docker service ps my-tomcat

(8)删除service

docker service rm my-tomcat

5.5 overlay

   Overlay 在网络技术领域,指的是一种网络架构上叠加的虚拟化技术模式,其大体框架是对基础网络不进行大规模修改的条件下,实现应用在网络上的承载,并能与其它网络业务分离,并且以基于IP的基础网络技术为主

  VXLAN(Virtual eXtensible LAN)技术是当前最为主流的Overlay标准

5.5 WordPress实战

1> 创建MySQL 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

2>创建WordPress的Service

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

3>访问测试

4>查看my-overlay-net