美文网首页
39-docker(三)

39-docker(三)

作者: Liang_JC | 来源:发表于2020-07-23 16:58 被阅读0次

    四: Docker网络

    docker network list     #查看网络类型
    docker inspect ID           #查看容器信息
    

    4.1: docker 结合负载实现网站高可用

    4.1.1: 整体规划图:
    下图为一个小型的网络架构图,其中 nginx 使用 docker 运行

    image.png

    4.1.2:安装并配置 keepalived

    4.1.2.1: Server1 安装并配置

    [root@docker-server1 ~]# yum install keepalived –y
    [root@docker-server1 ~]# cat /etc/keepalived/keepalived.conf
    vrrp_instance MAKE_VIP_INT {
        state MASTER
        interface eth0
        virtual_router_id 1
        priority 100
        advert_int 1
        unicast_src_ip 192.168.10.205
        unicast_peer {
            192.168.10.206
        }
        authentication {
            auth_type PASS
            auth_pass 1111
        }
        virtual_ipaddress {
            192.168.10.100/24 dev eth0 label eth0:1
        }
    }
    [root@docker-server1~]# systemctl restart keepalived && systemctl enable keepalived
    

    4.1.2.2: Server2 安装并配置

    [root@docker-server2 ~]# yum install keepalived –y
    [root@docker-server2 ~]# cat /etc/keepalived/keepalived.conf
        vrrp_instance MAKE_VIP_INT {
        state BACKUP
        interface eth0
        virtual_router_id 1
        priority 50
        advert_int 1
        unicast_src_ip 192.168.10.206
        unicast_peer {
            192.168.10.205
        }
        authentication {
            auth_type PASS
            auth_pass 1111
        }
        virtual_ipaddress {
            192.168.10.100/24 dev eth0 label eth0:1
        }
    }
    [root@docker-server2 ~]# systemctl restart keepalived && systemctl enable keepalived
    

    4.1.3: 安装并配置 haproxy

    4.1.3.1.:各服务器配置内核参数

    [root@docker-server1 ~]# sysctl -w net.ipv4.ip_nonlocal_bind=1
    [root@docker-server2 ~]# sysctl -w net.ipv4.ip_nonlocal_bind=1
    

    4.1.3.2: Server1 安装并配置 haproxy

    [root@docker-server1 ~]# yum install haproxy –y
    [root@docker-server1 ~]# cat /etc/haproxy/haproxy.cfg
     global
     maxconn 100000
     uid 99
     gid 99
     daemon
     nbproc 1
     log 127.0.0.1 local0 info
     
     defaults
     option http-keep-alive
     #option forwardfor
     maxconn 100000
     mode tcp
     timeout connect 500000ms
     timeout client 500000ms
     timeout server 500000ms
     
     listen stats
     mode http
     bind 0.0.0.0:9999
     stats enable
     log global
     stats uri /haproxy-status
     stats auth haadmin:q1w2e3r4ys
    
    #================================================================
    frontend docker_nginx_web
        bind 192.168.10.100:80
        mode http
        default_backend docker_nginx_hosts
    
    backend docker_nginx_hosts
        mode http
        #balance source
        balance roundrobin
        server 192.168.10.205 192.168.10.205:81 check inter 2000 fall 3 rise 5
        server 192.168.10.206 192.168.10.206:81 check inter 2000 fall 3 rise 5
    

    4.1.3.3: Server2 安装并配置 haproxy

    [root@docker-server2 ~]# yum install haproxy –y
    [root@docker-server2 ~]# cat /etc/haproxy/haproxy.cfg
     global
     maxconn 100000
     uid 99
     gid 99
     daemon
     nbproc 1
     log 127.0.0.1 local0 info
     
     defaults
     option http-keep-alive
     #option forwardfor
     maxconn 100000
     mode tcp
     timeout connect 500000ms
     timeout client 500000ms
     timeout server 500000ms
     
     listen stats
     mode http
     bind 0.0.0.0:9999
     stats enable
     log global
     stats uri /haproxy-status
     stats auth haadmin:q1w2e3r4ys
    
    #================================================================
    frontend docker_nginx_web
        bind 192.168.10.100:80
        mode http
        default_backend docker_nginx_hosts
    
    backend docker_nginx_hosts
        mode http
        #balance source
        balance roundrobin
        server 192.168.10.205 192.168.10.205:81 check inter 2000 fall 3 rise 5
        server 192.168.10.206 192.168.10.206:81 check inter 2000 fall 3 rise 5
    

    4.1.3.4: 各服务器别分启动 haproxy

    [root@docker-server1 ~]# systemctl enable haproxy
    Created symlink from /etc/systemd/system/multi-user.target.wants/haproxy.service
    to /usr/lib/systemd/system/haproxy.service.
    [root@docker-server1 ~]# systemctl restart haproxy
    
    [root@docker-server2 ~]# systemctl enable haproxy
    Created symlink from /etc/systemd/system/multi-user.target.wants/haproxy.service
    to /usr/lib/systemd/system/haproxy.service.
    [root@docker-server2 ~]# systemctl restart haproxy
    

    4.2: 容器之间的互联

    4.2.1: 通过容器名称互联

    即在同一个宿主机上的容器之间可以通过自定义的容器名称相互访问,比如一个业务前端静态页面是使用 nginx,动态页面使用的是 tomcat, 由于容器在启动的时候其内部 IP 地址是 DHCP 随机分配的,所以如果通过内部访问的话,自定义名称是相对比较固定的,因此比较适用于此场景。

    此方式最少需要两个容器之间操作

    4.2.1.1: 先创建第一个容器,后续会使用到这个容器的名称

    # docker run -it -d --name tomcat-web1 -p 8801:8080 tomcat-web:app1
    96fd3426c786b032f252b709d4bb483590de8e57a99f401821634e4bd0045577
    

    4.2.1.2: 查看当前 hosts 文件内容

    # docker exec -it 96fd3426c786 bash
    [root@96fd3426c786 /]# cat /etc/hosts
    127.0.0.1 localhost
    ::1 localhost ip6-localhost ip6-loopback
    fe00::0 ip6-localnet
    ff00::0 ip6-mcastprefix
    ff02::1 ip6-allnodes
    ff02::2 ip6-allrouters
    172.17.0.2 96fd3426c786
    1.1.1.1 abc.test.com
    

    4.2.1.3: 创建第二个容器

    # docker run -it -d -p 80:80 --name magedu-nginx-web1 --link tomcat-web1
    magedu-nginx:v1
    e7796ad98c84d7e6148fd25e10c7026bdbe9a21fd5699995912340ab8906b9fc
    

    4.2.1.4: 查看第二个容器的 hosts 文件内容

    # docker exec -it e7796ad98c84 bash
    [root@e7796ad98c84 /]# cat /etc/hosts
    127.0.0.1 localhost
    ::1 localhost ip6-localhost ip6-loopback
    fe00::0 ip6-localnet
    ff00::0 ip6-mcastprefix
    ff02::1 ip6-allnodes
    ff02::2 ip6-allrouters
    172.17.0.2 tomcat-web1 96fd3426c786 #连接的对方容器的 ID 和容器名称
    172.17.0.3 e7796ad98c84
    

    4.2.1.5: 检测通信

    ping tomcat-web1

    ping 96fd3426c786

    4.2.2: 通过自定义容器别名互联

    上一步骤中,自定义的容器名称可能后期会发生变化, 那么一旦名称发生变化,程序之间也要随之发生变化,比如程序通过容器名称进行服务调用, 但是容器名称发生变化之后再使用之前的名称肯定是无法成功调用, 每次都进行更改的话又比较麻烦, 因此可以使用自定义别名的方式解决,即容器名称可以随意更,只要不更改别名即可,具体如下:
    命令格式:
    docker run -d --name 新容器名称 --link 目标容器名称:自定义的名称 -p 本
    地端口:容器端口 镜像名称 shell 命令

    4.2.2.1: 启动第三个容器

    # docker run -it -d -p 81:80 --name magedu-nginx-web2 --link tomcatweb1:java_server magedu-nginx:v1
    6acb8a2b366ec31045b19f9c5a00bd7e811d95c5c46202aec09f140bf3420508
    

    4.2.2.2:查看当前容器的 hosts 文件

    root@docker-server1:~# docker exec -it 6acb8a2b366e bash
    [root@6acb8a2b366e /]# cat /etc/hosts
    127.0.0.1 localhost
    ::1 localhost ip6-localhost ip6-loopback
    fe00::0 ip6-localnet
    ff00::0 ip6-mcastprefix
    ff02::1 ip6-allnodes
    ff02::2 ip6-allrouters
    172.17.0.2 java_server 96fd3426c786 tomcat-web1
    172.17.0.4 6acb8a2b366
    

    4.2.2.3: 检查自定义别名通信

    ping java_server

    4.2.3.1: docker 网络类型

    Docker 的网络使用 docker network ls 命令看到有三种类型,下面将介绍每一种类
    型的具体工作方式:
    Bridge 模式, 使用参数 –net=bridge 指定, 不指定默认就是 bridge 模式。
    查看当前 docke 的网卡信息:

    root@docker-server1:~# docker network list
    NETWORK ID      NAME    DRIVER  SCOPE
    96b8c5310386    bridge  bridge  local
    06be5dcfad98    host    host    local
    9374ba0c4a30    none    null    local
    
    Bridge: #桥接,使用自定义 IP
    Host: #不获取 IP 直接使用物理机 IP, 并监听物理机 IP 监听端口
    None: #没有网络
    

    4.2.3.1.1: Host 模式

    Host 模式,使用参数 –net=host 指定。
    启动的容器如果指定了使用 host 模式,那么新创建的容器不会创建自己的虚拟
    网卡,而是直接使用宿主机的网卡和 IP 地址, 因此在容器里面查看到的 IP 信息
    就是宿主机的信息,访问容器的时候直接使用宿主机 IP+容器端口即可,不过容
    器的其他资源们必须文件系统、 系统进程等还是和宿主机保持隔离。

    此模式的网络性能最高,但是各容器之间端口不能相同, 适用于运行容器端口比较固定的业务。

    为避免端口冲突, 先删除所有的容器

    启动一个新容器,并指定网络模式为 host

    # docker run -d --name net_host --net=host magedu-nginx:v1
    7d65d6106ca87d41b6c62677740a1cdd14a870234f7c15d0beac6b306583cff8
    

    验证网络信息

    docker exec -it 7d65d6106ca8 bash
    ifconfig
    

    访问宿主机验证

    192.168.7.101/magedu

    Host 模式不支持端口映射, 当指定端口映射的时候会提示如下警告信息:
    使用主机网络模式时,将丢弃已指定的端口:

    # docker run -it -d --name net_host -p 80:80 --net=host magedu-nginx:v1
    /apps/nginx/sbin/nginx
    WARNING: Published ports are discarded when using host network mode
    025ff64d057f095032ac6c271d5275d81cea1f73645e93877c3d696cb2280020
    

    4.2.3.1.2: none 模式

    None 模式,使用参数 –net=none 指定在使用 none 模式后, Docker 容器不会进行任何网络配置,其没有网卡、没有 IP
    也没有路由,因此默认无法与外界通信, 需要手动添加网卡配置 IP 等,所以极少使用

    命令使用方式

    # docker run -it -d --name net_none -p 80:80 --net=none magedu-nginx:v1
    /apps/nginx/sbin/nginx
    7d7125a2a53e0af9718e6f7b3407b093a1367499188d5493b8c4b4a56dfff584
    

    4.2.3.1.3: Container 模式

    Container 模式,使用参数 –net=container:名称或 ID 指定。
    使用此模式创建的容器需指定和一个已经存在的容器共享一个网络,而不是和宿主机共享网,新创建的容器不会创建自己的网卡也不会配置自己的 IP,而是和一个已经存在的被指定的容器东西 IP 和端口范围,因此这个容器的端口不能和被指定的端口冲突, 除了网络之外的文件系统、进程信息等仍然保持相互隔离,两个容器的进程可以通过 lo 网卡及容器 IP 进行通信。

    # docker rm -fv `docker ps -a -q`
    
    # docker run -it -d --name nginx-web1 -p 80:80 --net=bridge magedu-nginx:v1
    /apps/nginx/sbin/nginx
    8d6950bcf89f7744b2cc3d53733b4561f4c9e2ec2fb735f75972bedb0a4eb79a
    
    # docker run -it -d --name tomcat-web1 --net=container:nginx-web1 tomcatweb:app1 #直接使用对方的网络,此方式较少使用
    bf77a272fe2b88b1888b321c96c95d6a27da8d5297366d6965ac1e3e26560083
    

    4.2.3.1.4: bridge 模式

    docker 的默认模式即不指定任何模式就是 bridge 模式, 也是使用比较多的模式,此模式创建的容器会为每一个容器分配自己的网络 IP 等信息,并将容器连接到一个虚拟网桥与外界通信。

    [root@docker-server1 ~]# docker network inspect bridge
    # docker rm -fv `docker ps -a -q`
    # docker run -it -d --name nginx-web1 -p 80:80 --net=bridge magedu-nginx:v1
    /apps/nginx/sbin/nginx
    0dfe5a96ef1b7c8f0af820a097a4b140aed8809a787562c694d4982d8f0037b9
    

    4.2.3.2: docker 夸主机互联之简单实现

    夸主机互联是说 A 宿主机的容器可以访问 B 主机上的容器,但是前提是保证各
    宿主机之间的网络是可以相互通信的, 然后各容器才可以通过宿主机访问到对方
    的容器, 实现原理是在宿主机做一个网络路由就可以实现 A 宿主机的容器访问 B
    主机的容器的目的, 复杂的网络或者大型的网络可以使用 google 开源的 k8s 进
    行互联。

    4.2.3.2.1: 修改各宿主机网段

    Docker 的默认网段是 172.17.0.x/24,而且每个宿主机都是一样的,因此要做路由
    的前提就是各个主机的网络不能一致,具体如下:
    问避免影响, 先在各服务器删除之前创建的所有容器。

    # docker rm -f `docker ps -a -q`
    

    4.2.3.2.2: 服务器 A 更改网段

    # vim /lib/systemd/system/docker.service
    ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --bip=10.10.0.1/24
    

    4.2.3.2.3:重启 docker 服务并验证网卡

    root@docker-server1:~# systemctl daemon-reload
    root@docker-server1:~# systemctl restart docker
    root@docker-server1:~# ifconfig
    

    4.2.3.2.4: 服务器 B 更改网段并验证网卡

    # vim /lib/systemd/system/docker.service
    --bip=10.20.0.1/24
    # systemctl daemon-reload
    # systemctl restart docker
    ifconfig
    

    4.2.3.3: 在两个宿主机分别启动一个容器

    #Server1:
    root@docker-server1:~# docker run -it -p 8080:8080 tomcat-web:app1 bash
    [root@781e7f053c20 /]# ifconfig
    eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
        inet 10.10.0.2 netmask 255.255.255.0 broadcast 10.10.0.255
        ether 02:42:0a:0a:00:02 txqueuelen 0 (Ethernet)
        RX packets 8 bytes 696 (696.0 B)
        RX errors 0 dropped 0 overruns 0 frame 0
        TX packets 0 bytes 0 (0.0 B)
        TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
    
    lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
        inet 127.0.0.1 netmask 255.0.0.0
        loop txqueuelen 1000 (Local Loopback)
        RX packets 0 bytes 0 (0.0 B)
        RX errors 0 dropped 0 overruns 0 frame 0
        TX packets 0 bytes 0 (0.0 B)
        TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
    
    #Server2:
    root@docker-node2:~# docker run -it -p 8080:8080 tomcat-web:app2 bash
    [root@1ee02ccc1810 /]# ifconfig
    eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
        inet 10.20.0.2 netmask 255.255.255.0 broadcast 10.20.0.255
        ether 02:42:0a:14:00:02 txqueuelen 0 (Ethernet)
        RX packets 8 bytes 696 (696.0 B)
        RX errors 0 dropped 0 overruns 0 frame 0
        TX packets 0 bytes 0 (0.0 B)
        TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
    
    lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
        inet 127.0.0.1 netmask 255.0.0.0
        loop txqueuelen 1000 (Local Loopback)
        RX packets 0 bytes 0 (0.0 B)
        RX errors 0 dropped 0 overruns 0 frame 0
        TX packets 0 bytes 0 (0.0 B)
        TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
    

    4.2.3.4: 添加静态路由

    在各宿主机添加静态路由,网关指向对方的 IP

    4.2.3.4.1: Server1 添加静态路由

    # route add -net 10.20.0.0/24 gw 192.168.7.102
    # iptables -A FORWARD -s 192.168.0.0/21 -j ACCEPT
    

    4.2.3.4.2: server2 添加静态路由

    [root@docker-server2 ~]# route add -net 10.10.0.0/24 gw 192.168.10.205
    [root@docker-server2 ~]# iptables -A FORWARD -s 192.168.0.0/21 -j ACCEPT
    

    4.2.3.5:测试容器间互联

    4.2.3.5.1: 宿主机 A 到宿主机 B 容器测试

    ping 10.20.0.2

    4.2.3.5.2: 宿主机 B 到宿主机 A 容器测试

    ping 10.10.0.2

    4.3: 创建自定义网络

    可以基于 docker 命令创建自定义网络,自定义网络可以自定义 IP 地范围和网关等信息。

    4.3.1:创建自定义 docker 网络
    # docker network create –help
    # docker network create -d bridge --subnet 10.100.0.0/24 --gateway 10.100.0.1
    magedu-net #创建自定义网络 magedu-net
    954c8bda9a8c35cd8e9e76159ef04f29f89f054e72f29e92cc5fc4a7be1cf6da
    
    验证网络:
    # docker network list
    NETWORK ID NAME DRIVER SCOPE
    78b0503ddcf3 bridge bridge local
    06be5dcfad98 host host local
    954c8bda9a8c magedu-net bridge local
    9374ba0c4a30 none null local
    
    4.3.2: 创建不同网络的容器测试通信

    4.3.2.1: 使用自定义网络创建容器

    root@docker-server1:~# docker run -it -p 8080:8080 --name magedu-net-test --
    net=magedu-net tomcat-web:app1 bash
    [root@42dba1061dd1 /]# ifconfig
    eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
    inet 10.100.0.2 netmask 255.255.255.0 broadcast 10.100.0.255
    ether 02:42:0a:64:00:02 txqueuelen 0 (Ethernet)
    RX packets 8 bytes 696 (696.0 B)
    RX errors 0 dropped 0 overruns 0 frame 0
    TX packets 0 bytes 0 (0.0 B)
    TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
    
    lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
    inet 127.0.0.1 netmask 255.0.0.0
    loop txqueuelen 1000 (Local Loopback)
    RX packets 0 bytes 0 (0.0 B)
    RX errors 0 dropped 0 overruns 0 frame 0
    TX packets 0 bytes 0 (0.0 B)
    TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
    
    [root@42dba1061dd1 /]# ping www.magedu.com
    PING www.magedu.com (101.200.188.230) 56(84) bytes of data.
    64 bytes from 101.200.188.230 (101.200.188.230): icmp_seq=1 ttl=127 time=5.62ms
    64 bytes from 101.200.188.230 (101.200.188.230): icmp_seq=2 ttl=127 time=4.91ms
    

    4.3.2.2: 创建默认网络容器

    root@node1:~# docker run -it --name bridge-container-test -p 8081:8080 tomcatweb:app1 bash
    [root@ed06c2785c92 /]# ifconfig
    eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
        inet 10.10.0.2 netmask 255.255.255.0 broadcast 10.10.0.255
        ether 02:42:0a:0a:00:02 txqueuelen 0 (Ethernet)
        RX packets 8 bytes 696 (696.0 B)
        RX errors 0 dropped 0 overruns 0 frame 0
        TX packets 0 bytes 0 (0.0 B)
        TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
    
    lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
        inet 127.0.0.1 netmask 255.0.0.0
        loop txqueuelen 1000 (Local Loopback)
        RX packets 0 bytes 0 (0.0 B)
        RX errors 0 dropped 0 overruns 0 frame 0
        TX packets 0 bytes 0 (0.0 B)
        TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
    
    [root@ed06c2785c92 /]# ping www.magedu.com
    PING www.magedu.com (101.200.188.230) 56(84) bytes of data.
    64 bytes from 101.200.188.230 (101.200.188.230): icmp_seq=1 ttl=127 time=5.40ms
    64 bytes from 101.200.188.230 (101.200.188.230): icmp_seq=2 ttl=127 time=5.47ms
    
    4.3.3: 当前 iptables 规则
    iptables -t nat -vnL
    iptables -vnL
    
    4.3.4: 如何与使用默认网络的容器通信

    现在有一个 docker0(10.10.0.0/24)网络一个自定义的 magedu-net(10.100.0.0/24)网络, 每个网络上分别运行了不同数量的容器,那么怎么才能让位于不同网络的容器可以相互通信呢?

    #保存iptables规则
    # iptables-save > iptables.sh
    #-A DOCKER-ISOLATION-STAGE-2 -o ... -j DROP         #注释掉
    #-A DOCKER-ISOLATION-STAGE-2 -o docker0 -j DROP     #注释掉
    
    4.3.5: 重新导入 iptables 并验证通信
    #重新导入 iptables 规则:
    # iptables-restore < iptables.sh
    

    五: Docker 仓库之单机 Docker Registry

    Docker Registry 作为 Docker 的核心组件之一负责镜像内容的存储与分发, 客户
    端的 docker pull 以及 push 命令都将直接与 registry 进行交互,最初版本的 registry
    由 Python实现,由于设计初期在安全性,性能以及 API 的设计上有着诸多的缺陷,
    该版本在 0.9 之后停止了开发,由新的项目 distribution(新的 docker register 被
    称为 Distribution)来重新设计并开发下一代 registry,新的项目由 go 语言开发,
    所有的 API, 底层存储方式, 系统架构都进行了全面的重新设计已解决上一代
    registry 中存在的问题, 2016 年 4 月份 rgistry 2.0 正式发布, docker 1.6 版本开始
    支持 registry 2.0,而八月份随着 docker 1.8 发布, docker hub 正式启用 2.1 版本
    registry 全面替代之前版本 registry,新版 registry 对镜像存储格式进行了重新设
    计并和旧版不兼容, docker 1.5 和之前的版本无法读取 2.0 的镜像, 另外, Registry
    2.4 版本之后支持了回收站机制,也就是可以删除镜像了,在 2.4 版本之前是无
    法支持删除镜像的,所以如果你要使用最好是大于 Registry 2.4 版本的,目前最新版本为 2.7.x。
    官方文档地址: https://docs.docker.com/registry/
    官方 github 地址: https://github.com/docker/distribution

    本部分将介绍通过官方提供的 docker registry 镜像来简单搭建一套本地私有仓库环境。

    5.1: 下载 docker registry 镜像

    [root@docker-server1 ~]# docker pull registry
    

    5.2: 搭建单机仓库

    5.2.1: 创建授权使用目录
    [root@docker-server1 ~]# mkdir /docker/auth #创建一个授权使用目录
    
    5.2.2: 创建用户
    [root@docker-server1 ~]# cd /docker
    [root@docker-server1 docker]# docker run --entrypoint htpasswd registry -Bbn jack 123456 > auth/htpasswd #创建一个用户并生成密码
    
    5.2.3: 验证用户名密码
    [root@docker-server1 docker]# cat auth/htpasswd
    jack:$2y$05$8W2aO/2RXMrMzw/0M5pig..QXwUh/m/XPoW5H/XxloLLRDTepVGP6
    
    5.2.4: 启动 docker registry
    [root@docker-server1 docker]# docker run -d -p 5000:5000 --restart=always --name registry1 -v /docker/auth:/auth -e "REGISTRY_AUTH=htpasswd" -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd registry
    ce659e85018bea3342045f839c43b66de1237ce5413c0b6b72c0887bece5325a
    
    5.2.5: 验证端口和容器
    docker ps
    ss -ntl
    
    5.2.6:测试登录仓库

    编辑各 docker 服务器/etc/sysconfig/docker 配置文件如下

    5.2.6.1: 报错如下

    image.png

    5.2.6.2: 解决方法

    [root@docker-server1 ~]# vim /etc/sysconfig/docker
    4 OPTIONS='--selinux-enabled --log-driver=journald'
    9 ADD_REGISTRY='--add-registry 192.168.10.205:5000'
    10 INSECURE_REGISTRY='--insecure-registry 192.168.10.205:5000'
    [root@docker-server1 ~]# systemctl restart docker
    
    [root@docker-server2 ~]# vim /etc/sysconfig/docker
    4 OPTIONS='--selinux-enabled --log-driver=journald'
    5 if [ -z "${DOCKER_CERT_PATH}" ]; then
    6 DOCKER_CERT_PATH=/etc/docker
    7 fi
    8
    9 ADD_REGISTRY='--add-registry 192.168.10.205:5000'
    10 INSECURE_REGISTRY='--insecure-registry 192.168.10.205:5000'
    
    [root@docker-server2 ~]# systemctl restart docker
    
    #小笔记:启动文件
    vim /usr/lib/systemd/system/docker.service
        Execstart=... --insecure-registry 192.168.10.205:5000
    systemctl daemon-reload
    systemctl restart docker
    

    5.2.6.3: 验证各 docker 服务器登录

    docker login 192.168.10.205:5000

    5.2.7: 在 Server1 登录后上传镜像

    5.2.7.1: 镜像打 tag:

    [root@docker-server1 ~]# docker tag jack/nginx-1.16.1-alpine
    192.168.10.205:5000/jack/nginx-1.16.1-alpine
    

    5.2.7.2:上传镜像

    docker push 192.168.10.205:5000/jack/nginx-1.16.1-alpine
    
    5.2.8: Server 2 下载镜像并启动容器

    5.2.8.1:登录并从 docker registry 下载镜像

    [root@docker-server2 ~]# docker images
    REPOSITORY TAG MAGE ID CREATED
    SIZE
    [root@docker-server2 ~]# docker login 192.168.10.205:5000
    Username (jack): jack
    Password:
    Login Succeeded
    [root@docker-server2 ~]# docker pull 192.168.10.205:5000/jack/nginx-1.16.1-alpine
    

    5.2.8.2: 从下载的镜像启动容器

    192.168.10.205:5000/jack/nginx-1.16.1-alpine nginx
    2ba24f28362e1b039fbebda94a332111c2882aa06987463ae033c630f5c9927c
    
    小笔记
    #新建2台server
    
    yum install -y yum-utils device-mapper-persistent-data lvm2
    yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
    yum makecache fast
    yum -y install docker-ce-18.09.9-3.el7 docker-ce-cli-18.09.9-3.el7
    systemctl start docker
    vim /usr/lib/systemd/system/docker.service
        Execstart=... --insecure-registry 192.168.37.27:5000
    systemctl daemon-reload
    systemctl restart docker
    docker login 192.168.37.27:5000
    docker pull 192.168.37.27:5000/linux39/haproxy:2.0.13-centos
    

    六: Docker 仓库之分布式 Harbor

    Harbor是一个用于存储和分发 Docker镜像的企业级 Registry 服务器,由 vmware
    开源,其通过添加一些企业必需的功能特性,例如安全、标识和管理等,扩展了
    开源 Docker Distribution。作为一个企业级私有 Registry 服务器, Harbor 提供了更
    好的性能和安全。提升用户使用 Registry 构建和运行环境传输镜像的效率。Harbor
    支持安装在多个 Registry 节点的镜像资源复制,镜像全部保存在私有 Registry 中,
    确保数据和知识产权在公司内部网络中管控, 另外, Harbor 也提供了高级的安全
    特性,诸如用户管理,访问控制和活动审计等。
    vmware 官方开源服务列表地址: https://vmware.github.io/harbor/cn/
    harbor 官方 github 地址: https://github.com/vmware/harbor
    harbor 官方网址: https://goharbor.io/

    6.1: Harbor 功能官方介绍:

    基于角色的访问控制:用户与 Docker 镜像仓库通过“项目”进行组织管理,一个用户可以对多个镜像仓库在同一命名空间(project)里有不同的权限。
    镜像复制:镜像可以在多个 Registry 实例中复制(同步)。尤其适合于负载均衡,高可用,混合云和多云的场景。
    图形化用户界面:用户可以通过浏览器来浏览,检索当前 Docker 镜像仓库,管理项目和命名空间。
    AD/LDAP 支: Harbor 可以集成企业内部已有的 AD/LDAP,用于鉴权认证管理。
    审计管理:所有针对镜像仓库的操作都可以被记录追溯,用于审计管理。
    国际化:已拥有英文、中文、德文、日文和俄文的本地化版本。更多的语言将会添加进来。
    RESTful API - RESTful API :提供给管理员对于 Harbor 更多的操控, 使得与其它管理软件集成变得更容易。
    部署简单:提供在线和离线两种安装工具, 也可以安装到 vSphere 平台(OVA 方式)虚拟设备。

    nginx: harbor 的一个反向代理组件,代理 registry、 ui、 token 等服务。这个代理会转发 harbor web 和 docker client 的各种请求到后端服务上。
    harbor-adminserver: harbor 系统管理接口,可以修改系统配置以及获取系统信息。
    harbor-db:存储项目的元数据、用户、规则、复制策略等信息。
    harbor-jobservice: harbor 里面主要是为了镜像仓库之前同步使用的。
    harbor-log:收集其他 harbor 的日志信息。
    harbor-ui:一个用户界面模块,用来管理 registry。
    registry:存储 docker images 的服务,并且提供 pull/push 服务。
    redis:存储缓存信息
    webhook: 当 registry 中的 image 状态发生变化的时候去记录更新日志、复制等操作。
    token service:在 docker client 进行 pull/push 的时候负责 token 的发放。
    

    6.2: 安装 Harbor

    下载地址: https://github.com/vmware/harbor/releases
    安装文档:https://github.com/vmware/harbor/blob/master/docs/installation_guide.md

    6.2.1: 服务器 1 安装 docker

    本次使用当前 harbor 最新的稳定版本 1.7.5 离线安装包,具体名称为 harbor-offline-installer-v1.7.5.tgz

    [root@docker-server1 ~]# yum install docker -y
    [root@docker-server1 ~]# systemctl satrt docker
    [root@docker-server1 ~]# systemctl enable docker
    Created symlink from /etc/systemd/system/multi-user.target.wants/docker.service to
    /usr/lib/systemd/system/docker.service
    
    6.2.2: 服务器 2 安装 docker
    [root@docker-server2 ~]# yum install docker -y
    [root@docker-server2 ~]# systemctl start docker
    [root@docker-server2 ~]# systemctl enable docker
    Created symlink from /etc/systemd/system/multi-user.target.wants/docker.service to
    /usr/lib/systemd/system/docker.service.
    
    6.2.3: 下载 Harbor 安装包

    6.2.3.1: 下载离线完整安装包

    推荐使用离线完整安装包

    [root@docker-server2 ~]# cd /usr/local/src/
    [root@docker-server2 src]# wget
    https://github.com/vmware/harbor/releases/download/v1.7.5/harbor-offlineinstaller-v1.7.5.tgz
    

    6.2.3.2: 下载在线安装包

    不是很推荐此方式

    [root@docker-server2 src]# wget
    https://github.com/vmware/harbor/releases/download/v1.7.5/harbor-onlineinstaller-v1.7.5.tgz
    

    6.3: 配置 Harbor

    6.3.1: 解压并编辑 harbor.cfg
    [root@docker-server1 src]# tar xvf harbor-offline-installer-v1.7.5.tgz
    [root@docker-server1 src]# ln -sv /usr/local/src/harbor /usr/local/
    ‘/usr/local/harbor’ -> ‘/usr/local/src/harbor’
    [root@docker-server1 harbor]# cd /usr/local/harbor/
    
    [root@docker-server1 harbor]# yum install python-pip –y
    [root@docker-server1 harbor]# docker-compose start
    [root@docker-server1 harbor]# vim harbor.cfg
    
    [root@docker-server1 harbor]# grep "^[a-Z]" harbor.cfg
    hostname = 192.168.10.205
    ui_url_protocol = http
    db_password = root123
    max_job_workers = 3
    customize_crt = on
    ssl_cert = /data/cert/server.crt
    ssl_cert_key = /data/cert/server.key
    secretkey_path = /data
    admiral_url = NA
    clair_db_password = password
    email_identity = harbor
    email_server = smtp.163.com
    email_server_port = 25
    email_username = rooroot@163.com
    email_password = zhang@123
    email_from = admin <rooroot@163.com>
    email_ssl = false
    harbor_admin_password = zhang@123
    auth_mode = db_auth
    ldap_url = ldaps://ldap.mydomain.com
    ldap_basedn = ou=people,dc=mydomain,dc=com
    ldap_uid = uid
    ldap_scope = 3
    ldap_timeout = 5
    self_registration = on
    token_expiration = 30
    project_creation_restriction = everyone
    verify_remote_cert = on
    
    6.3.2: 更新 harbor 配置

    6.3.2.1: 首次部署 harbor 更新

    [root@docker-server1 harbor]# pwd
    /usr/local/harbor #在 harbor 当前目录执行
    [root@docker-server1 harbor]# ./prepare #更新配置
    

    执行完毕后会在当前目录生成一个 docker-compose.yml 文件,用于配置数据目录等配置信息

    6.3.2.2: 后期修改配置

    如果 harbor 运行一段时间之后需要更改配置,则步骤如下

    6.3.2.2.1:停止 harbor

    [root@docker-server1 harbor]# pwd
    /usr/local/harbor #harbor 的当前目录
    [root@docker-server1 harbor]# docker-compose stop
    

    6.3.2.2.2: 编辑 harbor.cfg 进行相关配置

    [root@docker-server1 harbor]# vim harbor.cfg
    

    6.3.2.2.3:更新配置

    [root@docker-server1 harbor]# ./prepare
    

    6.3.2.2.4:启动 harbor 服务

    [root@docker-server1 harbor]# docker-compose start
    
    6.3.3: 官方方式启动 Harbor

    6.3.3.1: 官方方式安装并启动 harbor

    [root@docker-server1 harbor]# yum install python-pip
    [root@docker-server1 harbor]# pip install --upgrade pip
    [root@docker-server1 harbor]# pip install docker-compose
    [root@docker-server1 harbor]# ./install.sh #官方构建 harbor 和启动方式,推荐此方法, 会下载官方的 docker 镜像:
    

    6.3.3.2: web 访问 Harbor 管理界面

    http://192.168.10.205

    6.3.4: 非官方方式启动

    6.3.4.1: 非官方方式启动 harbor

    [root@docker-server2 harbor]# ./prepare
    [root@docker-server2 harbor]# yum install python-pip -y
    [root@docker-server2 harbor]# pip install --upgrade pip #升级 pip 为最新版本
    [root@docker-server2 harbor]# pip install docker-compose #安装 docker-compose命令
    

    6.3.4.2:启动 harbor

    [root@docker-server2 harbor]# docker-compose up –d #非官方方式构建容器,此步骤会从官网下载镜像,需要相当长的时间
    

    6.4: 配置 docker 使用 harbor 仓库上传下载镜像

    6.4.1:编辑 docker 配置文件

    注意:如果我们配置的是 https 的话,本地 docker 就不需要有任何操作就可以访问 harbor 了

    [root@docker-server1 ~]# vim /etc/sysconfig/docker
    4 OPTIONS='--selinux-enabled --log-driver=journald --insecure-registry 192.168.10.205'
    #其中 192.168.10.205 是我们部署 Harbor 的地址,即 hostname 配置项值。配置完后需要重启 docker 服务。
    
    6.4.2: 重启 docker 服务
    [root@docker-server1 ~]# systemctl stop docker
    [root@docker-server1 ~]# systemctl start docker
    
    6.4.3: 验证能否登录 harbor
    [root@docker-server1 harbor]# docker login 192.168.10.205
    
    6.4.4:测试上传和下载镜像

    将之前单机仓库构构建的 Nginx 镜像上传到 harbor 服务器用于测试

    6.4.4.1:导入镜像

    [root@docker-server1 harbor]# docker load < /opt/nginx-1.10.3_docker.tar.gz  
    

    6.4.4.2:验证镜像导入成功

    docker images
    

    6.4.4.3:镜像打 tag

    修改 images 的名称,不修改成指定格式无法将镜像上传到 harbor 仓库,格式为: Harbor IP/项目名/image 名字:版本号

    [root@docker-server1 harbor]# docker tag 192.168.10.205:5000/jack/nginx-1.10.3:v1 192.168.10.205/nginx/nginx_1.10.3:v1
    [root@docker-server1 harbor]# docker images
    
    6.4.5: 验证从 harbor 服务器下载镜像并启动容器

    6.4.5.1:更改 docker 配置文件:
    目前凡是需要从 harbor 镜像服务器下载 image 的 docker 服务都要更改,不更改的话无法下载

    [root@docker-server2 ~]# vim /etc/sysconfig/docker
    4 OPTIONS='--selinux-enabled --log-driver=journald --insecure-registry 192.168.10.205'
    

    6.4.5.2: 重启 docker

    [root@docker-server2 ~]# systemctl stop docker
    [root@docker-server2 ~]# systemctl start docker
    

    6.4.5.3: 验证从 harbor 下载镜像

    6.4.5.5.1: 查看下载命令:
    harbor 上的每个镜像里面自带 pull 命令

    6.4.5.5.2: 执行下载

    [root@docker-server2 ~]# docker pull 192.168.10.205/nginx/nginx_1.10.3:v1
    
    6.4.6: 从镜像启动容器并验证

    6.4.6.1: 启动容器

    [root@docker-server2 ~]# docker run -d -p 80:80 -p 443:443 192.168.10.205/nginx/nginx_1.10.3:v1 nginx
    89901f9badf74809f6abccc352fc7479f1490f0ebe6d6e3b36d689e73c3f9027
    
    小笔记:harbor
    #harbor1.7及之前版本配置都一样,1.8以后不兼容1.7及以下的
    
    #1.10版本
    cd /usr/local/src
    tar -xf harbor-offline-installer-v1.10.1.tgz
    cd harbor
    vim harbor.yml
    hostname = 192.168.37.37
    ...
    #https
      #port: 443
    harbor_admin_password: 123456
    ...
    
    yum install python-pip –y
    pip install docker-compose
    ./install.sh
    
    #client
    http://192.168.37.37
    admin
    123456
    
    vim /usr/lib/systemd/system/docker.service
        Execstart=... --insecure-registry 192.168.37.37
    docker login 192.168.37.37
    docker tag nginx-1.16.1-alpine 192.168.37.37/linux39/nginx-1.16.1-alpine
    docker push 192.168.37.37/linux39/nginx-1.16.1-alpine
    
    #1.7.6版本
    yum install -y yum-utils device-mapper-persistent-data lvm2
    yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
    yum makecache fast
    yum -y install docker-ce-18.09.9-3.el7 docker-ce-cli-18.09.9-3.el7
    cd /usr/local/src
    tar xf harbor-offline-installer-v1.7.6.tgz
    cd harbor
    vim harbor.cfg
        hostname = 192.168.37.37
        ui_url_protocol = http
        #ssl_cert = /data/cert/server.crt
        #ssl_cert_key = /data/cert/server.key
        ...
        email_identity = harbor
        email_server = smtp.163.com
        email_server_port = 25
        email_username = rooroot@163.com
        email_password = abc@123                #邮箱密码
        email_from = admin <rooroot@163.com>
        email_ssl = false
        harbor_admin_password = 123456
    yum install python-pip –y
    pip install docker-compose
    ./install.sh
    

    6.5: 实现 harbor 高可用

    Harbor 支持基于策略的 Docker 镜像复制功能,这类似于 MySQL 的主从同步,其可以实现不同的数据中心、 不同的运行环境之间同步镜像, 并提供友好的管理界面,大大简化了实际运维中的镜像管理工作,已经有用很多互联网公司使用harbor 搭建内网 docker 仓库的案例,并且还有实现了双向复制的案列,本文将实现单向复制的部署

    6.5.1: 新部署一台 harbor 服务器
    [root@docker-server2 ~]# cd /usr/local/src/
    [root@docker-server2 src]# tar xf harbor-offline-installer-v1.7.5.tgz
    [root@docker-server2 src]# ln -sv /usr/local/src/harbor /usr/local/
    ‘/usr/local/harbor’ -> ‘/usr/local/src/harbor’
    [root@docker-server2 src]# cd /usr/local/harbor/
    [root@docker-server2 harbor]# grep "^[a-Z]" harbor.cfg
    hostname = 192.168.10.206
    ui_url_protocol = http
    db_password = root123
    max_job_workers = 3
    customize_crt = on
    ssl_cert = /data/cert/server.crt
    ssl_cert_key = /data/cert/server.key
    secretkey_path = /data
    admiral_url = NA
    clair_db_password = password
    email_identity = harbor-1.7.5
    email_server = smtp.163.com
    email_server_port = 25
    email_username = rooroot@163.com
    email_password = zhang@123
    email_from = admin <rooroot@163.com>
    email_ssl = false
    harbor_admin_password = zhang@123
    auth_mode = db_auth
    ldap_url = ldaps://ldap.mydomain.com
    ldap_basedn = ou=people,dc=mydomain,dc=com
    ldap_uid = uid
    ldap_scope = 3
    ldap_timeout = 5
    self_registration = on
    token_expiration = 30
    project_creation_restriction = everyone
    verify_remote_cert = on
    [root@docker-server2 harbor]# yum install python-pip -y
    [root@docker-server2 harbor]# pip install --upgrade pip
    [root@docker-server2 harbor]# pip install docker-compose
    [root@docker-server2 harbor]# ./install.sh
    
    6.5.2: 验证从 harbor 登录
    image.png
    6.5.3: 创建一个 nginx 项目

    与主 harbor 项目名称保持一致

    image.png
    6.5.4:在主 harbor 服务器配置同步测试
    image.png
    6.5.5:点击复制规则
    image.png
    6.5.6:主 harbor 编辑同步策略
    image.png
    6.5.7: 主 harbor 查看镜像同步状态
    image.png
    6.5.8: 从 harbor 查看镜像
    image.png
    6.5.9:测试从 harbor 镜像下载和容器启动

    6.5.9.1: docker 客户端配置使用 harbor

    本次新部署了一台 docker 客户端, IP 地址为 192.168.10.207

    [root@docker-server3 ~]# vim /etc/sysconfig/docker
    4 OPTIONS='--selinux-enabled --log-driver=journald --insecure-registry 192.168.10.206'
    

    6.5.9.2: 重启 docker 服务

    [root@docker-server3 ~]# systemctl restart docker
    

    6.5.9.3:从 harbor 项目设置为公开

    image.png

    6.5.9.4:设置项目为公开访问

    image.png

    6.5.9.5: docker 客户端下载镜像

    image.png

    6.5.9.6: docker 客户端从镜像启动容器

    [root@docker-server3 ~]# docker run -d -p 80:80 -p443:443 192.168.10.206/nginx/nginx_1.10.3:v1 nginx
    0b496bc81035291b80062d1fba7d4065079ab911c2a550417cf9e593d353c20b
    

    6.5.9.7: 验证 web 访问

    image.png

    至此,高可用模式的 harbor 仓库部署完毕

    6.6.: 实现 harbor 双向同步

    6.6.1: 在 docker 客户端导入 centos 基础镜像
    [root@docker-server3 ~]# docker load -i /opt/centos.tar.gz
    [root@docker-server3 ~]# vim /etc/sysconfig/docker
    4 OPTIONS='--selinux-enabled --log-driver=journald --insecure-registry 192.168.10.206'
    
    6.6.2:镜像打 tag
    [root@docker-server3 ~]# docker tag docker.io/centos 192.168.10.206/nginx/centos_base
    
    6.6.3:上传到从 harbor
    [root@docker-server3 ~]# docker push 192.168.10.206/nginx/centos_base
    
    6.6.4:从 harbor 界面验证

    http://192.168.10.206

    6.6.5:从 harbor 创建同步规则

    规则方式与主 harbor 相同, 写对方的 IP+用户名密码,然后点测试连接,确认可以测试连接通过。

    6.6.6: 到主 harbor 验证镜像
    image.png
    6.6.7: docker 镜像端测试
    image.png

    6.6.7.1:下载 centos 基础镜像

    [root@docker-server1 harbor]# docker pull 192.168.10.205/nginx/centos_base
    Using default tag: latest
    Trying to pull repository 192.168.10.205/nginx/centos_base ...
    sha256:822de5245dc5b659df56dd32795b08ae42db4cc901f3462fc509e91e97132dc0: Pulling from 192.168.10.205/nginx/centos_base
    
    Digest:
    sha256:822de5245dc5b659df56dd32795b08ae42db4cc901f3462fc509e91e97132dc0
    

    6.6.7.2: 从镜像启动容器

    [root@docker-server1 ~]# docker run -it --name centos_base
    192.168.10.205/nginx/centos_base bash
    [root@771f5aa0d089 /]#
    

    6.7: harbor https 配置

    # openssl genrsa -out /usr/local/src/harbor/certs/harbor-ca.key 2048
    # openssl req -x509 -new -nodes -key /usr/local/src/harbor/certs/harbor-ca.key -
    subj "/CN=harbor.magedu.net" -days 7120 -out /usr/local/src/harbor/certs/harborca.crt
    
    # vim harbor.cfg
        hostname = harbor.magedu.net
        ui_url_protocol = https
        ssl_cert = /usr/local/src/harbor/certs/harbor-ca.crt
        ssl_cert_key = /usr/local/src/harbor/certs/harbor-ca.key
        harbor_admin_password = 123456
    # ./install.sh
    
    # yum install docker-ce-18.06.3.ce-3.el7.x86_64.rpm
    # yum install docker-compose
    # mkdir /etc/docker/certs.d/harbor.magedu.net -p
    # cp certs/harbor-ca.crt /etc/docker/certs.d/harbor.magedu.net/
    # docker login harbor.magedu.net
    

    七: 单机编排之 Docker Compose

    当在宿主机启动较多的容器时候,如果都是手动操作会觉得比较麻烦而且容器
    出错,这个时候推荐使用 docker 单机编排工具 docker-compose, docker-compose
    是 docker 容器的一种单机编排服务, docker-compose 是一个管理多个容器的工
    具,比如可以解决容器之间的依赖关系, 就像启动一个 nginx 前端服务的时候会
    调用后端的 tomcat,那就得先启动 tomcat,但是启动 tomcat 容器还需要依赖数
    据库, 那就还得先启动数据库, docker-compose 就可以解决这样的嵌套依赖关系,
    其完全可以替代 docker run 对容器进行创建、 启动和停止。

    docker-compose 项目是 Docker 官方的开源项目,负责实现对 Docker 容器集群
    的快速编排, docker-compose 将所管理的容器分为三层,分别是工程(project),
    服务(service)以及容器(container)。

    github 地址 https://github.com/docker/compose

    # cat docker-compose.yml
    version: '3'
    services:
      nginx:
        image: nginx
        container_name: nginx-web1
        expose:
          - 80
          - 443
        ports:
          - "80:80"
          - "443:443
    
    小笔记:portainer,web管理docker

    https://www.portainer.io/

    https://github.com/portainer/portainer

    https://quchao.net/Portainer-CN.html #中文

    #安装
    mkdir /portainer
    docker run -d -p 8000:8000 -p 9000:9000 --name=portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v /portainer:/data portainer/portainer
    
    #登录
    http://192.168.37.7:9000
    user:admin
    pass:第一次需要设置密码
    
    #中文
    mkdir /data/docker_cn
    wget https://dl.quchao.net/Soft/Portainer-CN.zip
    docker run -d -p 9000:9000 -v /var/run/docker.sock:/var/run/docker.sock -v /portainer:/data -v /data/docker_cn:/public portainer/portainer
    
    #docker监听端口
    vim /usr/lib/systemd/system/docker.service
    execstart=... -H tcp://0.0.0.0:2375
    

    7.1: 基础环境准备

    7.1.1: 安装 python-pip 软件包

    python-pip 包将安装一个 pip 的命令, pip 命令是一个 pyhton 安装包的安装工
    具, 其类似于 ubuntu 的 apt 或者 redhat 的 yum, 但是 pip 只安装 python 相关的
    安装包,可以在多种操作系统安装和使用 pip。

    Ubuntu:
    # apt update
    # apt install -y python-pip
    
    Centos:
    # yum install epel-release
    # yum install -y python-pip
    # pip install --upgrade pip
    

    注:官方二进制下载地址: https://github.com/docker/compose/releases

    v1.25.x最后支持python2.7版本

    7.1.2: 安装 docker compose
    # pip install docker-compose
    
    7.1.3:验证 docker-compose 版本
    # docker-compose version
    docker-compose version 1.25.0, build b42d419
    docker-py version: 4.1.0
    CPython version: 2.7.15+
    OpenSSL version: OpenSSL 1.1.1 11 Sep 2018
    
    7.1.4: 查看 docker-compose 帮助
    https://docs.docker.com/compose/reference/ #官方文档
    
    [root@docker-server3 ~]# docker-compose --help
    Usage:
    docker-compose [-f <arg>...] [options] [COMMAND] [ARGS...]
    docker-compose -h|--help
    选项如下:
    -f, –file FILE #指定 Compose 模板文件,默认为 docker-compose.yml。
    -p, –project-name NAME #指定项目名称,默认将使用当前所在目录名称作为项目名。
    --verbose #显示更多输出信息
    --log-level LEVEL #定义日志级别 (DEBUG, INFO, WARNING, ERROR, CRITICAL)
    --no-ansi #不显示 ANSI 控制字符
    -v, --version #显示版本
    #命令选项,需要在 docker-compose.yml 文件目录执行
    #build #通过 docker-compose 构建镜像
    #bundle #从当前 docker compose 文件生成一个以当前目录为名称的从 Compose文件生成一个分布式应用程序捆绑包(DAB)。
    
    config -q #查看当前配置, 没有错误不输出任何信息
    
    #create #创建服务
    down #停止和删除所有容器、网络、镜像和卷
    
    #events #从容器接收实时事件, 可以指定 json 日志格式,如:docker-compose events --json
    
    #exec #进入指定容器进行操作
    help #显示帮助细信息
    #images #显示当前服务器的 docker 镜像信息
    kill #强制终止运行中的容器
    logs #查看容器的日志
    #pause #暂停服务
    #port #查看端口
        # docker-compose port --protocol=tcp nginx 80
    ps #列出容器
    pull #重新拉取镜像
    #push #上传镜像
    #restart #重启服务
    rm #删除已经停止的服务
    run #一次性运行容器,等于 docker run --rm
    scale #设置指定服务运行的容器个数
        docker-compose scale nginx=2
    start #启动服务
    stop #停止服务
    top #显示容器运行状态
    unpause #取消暂定
    up #创建并启动容器
    version #显示 docker-compose 版本信息
    

    7.2: 从 docker compose 启动单个容器

    目录可以在任意目录, 推荐放在有意义的位置。

    # cd /opt/
    # mkdir magedu
    # cd magedu/
    
    7.2.1: 单个容器的 docker compose 文件

    编写一个 yml 格式的配置 docker-compose 文件, 启动一个 nginx 服务, 由于格式为 yml 格式, 因此要注意前后的缩进及上下行的等级关系。

    # pwd
    /opt/magedu
    
    # cat docker-compose.yml
    service-nginx-web:
      image: 192.168.7.103/linux37/ubuntu-nginx:1.16.1
      expose:
        - 80
        - 443
      ports:
        - "80:80"
        - "443:443"
    
    7.2.2: 启动容器

    必须要在 docker compose 文件所在的目录执行

    # pwd
    /opt/magedu
    
    # docker-compose up -d #不加是 d 前台启动
    
    7.2.3:启动完成

    镜像下载完成后将容器创建完成并成功运行

    7.2.4: web 访问测试

    http://192.168.7.105

    7.2.5: 后台启动服务

    容器的在启动的时候, 会给容器自定义一个名称, 在 service name 后面加_1。

    # docker-compose up -d
    # docker-compose ps
    Name Command State Ports
    ---------------------------------------------------------------------
    magedu_service-nginx-web_1 nginx Up 0.0.0.0:443->443/tcp, 0.0.0.0:80->80/tcp
    
    7.2.6:自定义容器名称
    # cat docker-compose.yml
    service-nginx-web:
      image: 192.168.7.103/linux37/ubuntu-nginx:1.16.1
      container_name: nginx-web1
      expose:
        - 80
        - 443
      ports:
        - "80:80"
        - "443:443"
        
    # docker-compose up -d
    Recreating magedu_service-nginx-web_1 ... done
    # docker-compose ps
    Name Command State Ports
    -----------------------------------------------------------------------
    nginx-web1 nginx Up 0.0.0.0:443->443/tcp, 0.0.0.0:80->80/tcp    
    
    7.2.7:验证容器
    docker ps
    
    7.2.8: 查看容器进程
    [root@docker-server3 docker-compose]# docker-compose ps
    
    小笔记:编写单个docker compose
    mkdir /opt/linux39
    cd /opt/linux39
    vim docker-compose.yml
    version: "3.7"
    services:
      redis:
        image: redis:latest
        deploy:
          replicas: 1   #容器个数
        #expose:
          #- 80
          #- 443
        #ports:
          #- "80:80"
          #- "443:443"
    

    7.3:从 docker compose 启动多个容器

    7.3.1: 编辑 docker-compose 文件
    # pwd
    /opt/magedu
    # cat docker-compose.yml
    service-nginx-web:
      image: 192.168.7.103/linux37/ubuntu-nginx:1.16.1
      container_name: nginx-web1
      expose:
        - 80
        - 443
      ports:
        - "80:80"
        - "443:443"
        
    service-tomcat-app1:
      image: 192.168.7.103/linux37/linux37-tomcat:app1
      container_name: tomcat-app1
      expose:
        - 8080
      ports:
        - "8080:8080"
    
    7.3.2:重新启动容器
    # pwd
    /opt/magedu
    
    # docker-compose stop
    # docker-compose up -d
    
    小笔记:docker-compose启动多个容器
    vim docker-compose.yml
    service-haproxy:
      image: 192.168.37.37/linux39/haproxy:2.0.13-centos
      container_name: haproxy
      expose:
        - 80
        - 9999
      ports:
        - "80:80"
        - "9999:9999"
      links:
      - service-nginx-web
    
    service-nginx-web:
      image: 192.168.37.37/linux39/nginx:1.16.1-alpine
      container_name: nginx-web1
      #expose:
      #  - 81
      #  - 443
      #ports:
      #  - "81:80"
      #  - "443:443"
      links:
        - service-tomcat-app1
        - service-tomcat-app2
    
    service-tomcat-app1:
      image: 192.168.37.37/linux39/tomcat-linux39:app1
      container_name: tomcat-app1
      #expose:
      #  - 8081
      #ports:
      #  - "8081:8080" 
    
    service-tomcat-app2:
      image: 192.168.37.37/linux39/tomcat-linux39:app2
      container_name: tomcat-app2
      #expose:
      #  - 8080
      #ports:
      #  - "8080:8080"   
    
    docker exec -it haproxy_id bash
    vim /etc/haproxy/haproxy.cfg
     server web1 service-nginx-web:80 check inter 3000 fall 2 rise 5
    
    docker-compose up -d        #启动容器
    docker-compose down         #关闭容器
    docker-compose pull         #下载容器,镜像更新用
    
    #上传到harbor
    vim /usr/lib/systemd/system/docker.service
        Execstart=... --insecure-registry 192.168.37.37
    docker login 192.168.37.37
    docker tag tomcat-linux39:app2 192.168.37.37/linux39/tomcat-linux39:app2
    docker push 192.168.37.37/linux39/tomcat-linux39:app2
    

    7.4: 定义数据卷挂载

    7.4.1: 创建数据目录和文件
    # mkdir -p /data/nginx/magedu
    # echo "magedu test page" > /data/nginx/magedu/index.html
    
    7.4.2: 编辑 compose 配置文件
    # cat docker-compose.yml
    service-nginx-web:
      image: 192.168.7.103/linux37/ubuntu-nginx:1.16.1
      container_name: nginx-web1
      volumes:
        - /data/nginx/magedu:/apps/nginx/html
      expose:
        - 80
        - 443
      ports:
        - "80:80"
        - "443:443"
      # links:
        # - nginx-web1
        
    service-tomcat-app1:
      image: 192.168.7.103/linux37/linux37-tomcat:app1
      container_name: tomcat-app1
      expose:
        - 8080
      ports:
        - "8080:8080"
    
    7.4.3: 重启容器
    # docker-compose stop
    # docker-compose up –d
    # docker-compose up -d
    tomcat-app1 is up-to-date
    Recreating nginx-web1 ... done
    
    7.4.4: 其他常用命令

    7.4.4.1: 重启单个指定容器

    # docker-compose restart service-nginx-web #写容器的 service 名称
    Restarting nginx-web1 ... done
    

    7.4.4.2: 重启所以容器

    # docker-compose restart
    

    7.4.4.3:停止和启动单个容器

    # docker-compose stop service-tomcat-app1
    # docker-compose start service-tomcat-app1
    

    7.4.4.4: 停止和启动所有容器

    # docker-compose stop
    # docker-compose start
    
    小笔记:docker-compose 定义卷挂载
    #主页面目录挂载
    vim docker-compose.yml
    ...
    service-tomcat-app1:
      image: 192.168.37.37/linux39/tomcat-linux39:app1
      container_name: tomcat-app1
      volumes:      #卷挂载
        - /opt/linux39/app1:/data/tomcat/webapps/linux39
    
    service-tomcat-app2:
      image: 192.168.37.37/linux39/tomcat-linux39:app2
      container_name: tomcat-app2
      volumes:
        - /opt/linux39/app2:/data/tomcat/webapps/linux39
      
    mkdir /opt/linux39/app{1,2}
    docker-compose up –d
    

    7.5: 实现单机版的 Nginx+Tomcat

    编写 docker-compose.yml 文件,实现单机版本的 nginx+tomcat 的动静分离 web
    站点, 要求从 nginx 作为访问入口,当访问指定 URL 的时候转发至 tomcat 服务
    器响应。

    7.5.1: 制作 Haproxy 镜像

    当前目录文件

    # pwd
    /opt/dockerfile/web/linux37/haproxy
    
    # tree
    .
    ├── build-command.sh
    ├── dockerfile
    ├── haproxy-2.0.5.tar.gz
    ├── haproxy.cfg
    └── run_haproxy.sh
    
    0 directories, 5 files
    

    7.5.1.1: dockerfile 文件

    # cat dockerfile
    FROM linux37-centos-base:7.6.1810
    
    maintainer zhangshijie "2973707860@qq.com"
    
    RUN yum install -y yum install gcc gcc-c++ glibc glibc-devel pcre pcre-devel openssl
    openssl-devel systemd-devel net-tools vim iotop bc zip unzip zlib-devel lrzsz tree
    screen lsof tcpdump wget ntpdate
    ADD haproxy-2.0.5.tar.gz /usr/local/src
    
    RUN cd /usr/local/src/haproxy-2.0.5 && make ARCH=x86_64 TARGET=linuxglibc USE_PCRE=1 USE_OPENSSL=1 USE_ZLIB=1 USE_SYSTEMD=1
    USE_CPU_AFFINITY=1 PREFIX=/usr/local/hap
    roxy && make install PREFIX=/usr/local/haproxy && cp haproxy /usr/sbin/ &&
    mkdir /usr/local/haproxy/run
    ADD haproxy.cfg /etc/haproxy/
    
    ADD run_haproxy.sh /usr/bin
    EXPOSE 80 9999
    CMD ["/usr/bin/run_haproxy.sh"]
    

    7.5.1.2: haprox.cfg 配置文件

    # cat haproxy.cfg
    # cat haproxy.cfg
    global
    chroot /usr/local/haproxy
    #stats socket /var/lib/haproxy/haproxy.sock mode 600 level admin
    uid 99
    gid 99
    daemon
    nbproc 1
    pidfile /usr/local/haproxy/run/haproxy.pid
    log 127.0.0.1 local3 info
    
    defaults
    option http-keep-alive
    option forwardfor
    mode http
    timeout connect 300000ms
    timeout client 300000ms
    timeout server 300000ms
    
    listen stats
     mode http
     bind 0.0.0.0:9999
     stats enable
     log global
     stats uri /haproxy-status
     stats auth haadmin:123456
    
    listen web_port_80
     bind 0.0.0.0:80
     mode http
     log global
     balance roundrobin
     server web1 127.0.0.1:8800 check inter 3000 fall 2 rise 5
    
    listen web_port_443
     bind 0.0.0.0:443
     mode http
     log global
     balance roundrobin
     server web1 127.0.0.1:8843 check inter 3000 fall 2 rise 5
    

    7.5.1.3: haproxy 运行脚本

    # cat run_haproxy.sh
    #!/bin/bash
    
    haproxy -f /etc/haproxy/haproxy.cfg
    tail -f /etc/hosts
    

    7.5.1.4: build-command 脚本

    # cat build-command.sh
    #!/bin/bash
    docker build -t 192.168.7.103/linux37/linux37-centos-haproxy:2.0.5 .
    docker push 192.168.7.103/linux37/linux37-centos-haproxy:2.0.5
    

    7.5.1.5: 执行镜像构建

    # bash build-command.sh
    
    7.5.2: 准备 nginx 镜像

    参考步骤 2.3 2.6 及 2.7

    7.5.3: 准备 tomcat 镜像

    参考步骤 2.4

    7.5.4: 编辑 docker compose 文件及环境准备

    7.5.4.1: 编辑 docker compose 文件

    # pwd
    /opt/maged
    
    # cat docker-compose.yml
    service-haproxy:
      image: 192.168.7.103/linux37/linux37-centos-haproxy:2.0.5
      container_name: haproxy
      expose:
        - 80
        - 443
        - 9999
      ports:
        - "80:80"
        - "443:443"
        - "9999:9999"
      links:
        service-nginx-web
        
    service-nginx-web:
      image: 192.168.7.103/linux37/ubuntu-nginx:1.16.1
      container_name: nginx-web1
      volumes:
        - /data/nginx/magedu:/apps/nginx/html/magedu
        - /data/nginx/static:/apps/nginx/html/static
      expose:
        - 80
        - 443
      # ports:
        # - "8800:80"
        # - "8443:443"
      links:
        - service-tomcat-app1
        - service-tomcat-app2    
        
    service-tomcat-app1:
      image: 192.168.7.103/linux37/linux37-tomcat:app1
      container_name: tomcat-app1
      volumes:
        - /data/tomcat/webapps/magedu/:/data/tomcat/webapps/app/magedu
      expose:
        - 8080
      # ports:
        # - "8801:8080" 
        
    service-tomcat-app2:
      image: 192.168.7.103/linux37/linux37-tomcat:app2
      container_name: tomcat-app2
      volumes:
        - /data/tomcat/webapps/magedu/:/data/tomcat/webapps/app/magedu
      expose:
        - 8080   
      # ports:
      # - "8802:8080"
    

    7.5.4.2:准备 nginx 静态文件

    # mkdir /data/nginx/static
    # echo "Nginx static page" > /data/nginx/static/index.html
    上传宿主机图片到静态文件路径
    
    # tree /data/nginx/static/
    /data/nginx/static/
    ├── 1.jpeg
    └── index.html
    
    0 directories, 2 files
    

    7.5.4.3:准备 nginx.conf 配置文件

    在 nginx 配置文件中,将用户访问 app 目录的请求通过 upstream 服务器组转发至后端 tomcat 容器。

    # pwd
    /opt/dockerfile/system/ubuntu
    
    # grep -v "#" nginx.conf | grep -v "^$"
    user nginx;
    worker_processes 1;
    daemon off;
    events {
        worker_connections 1024;
    }
    http {
        include mime.types;
        default_type application/octet-stream;
        sendfile on;
        keepalive_timeout 65;
        upstream tomcat_webserver {
            server service-tomcat-app1:8080;
            server service-tomcat-app2:8080;
        }
        server {
            listen 80;
            server_name localhost;
            location / {
                root html;
                index index.html index.htm;
            }
            location /linux37 {
                root /data/nginx/html;
                index index.html;
            }
            location /app {
                proxy_pass http://tomcat_webserver;
                proxy_set_header Host $host;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Real-IP $remote_addr;
            }
            error_page 500 502 503 504 /50x.html;
            location = /50x.html {
                root html;
            }
        }
    }
    

    7.5.4.4:准备 tomcat 页面文件

    # mkdir /data/tomcat/webapps/magedu –p
    # cat /data/tomcat/webapps/magedu/showhost.jsp
    <%@page import="java.util.Enumeration"%>
    <br />
    host:
    <%try{out.println(""+java.net.InetAddress.getLocalHost().getHostName());}catch(Exc
    eption e){}%>
    <br />
    remoteAddr: <%=request.getRemoteAddr()%>
    <br />
    remoteHost: <%=request.getRemoteHost()%>
    <br />
    sessionId: <%=request.getSession().getId()%>
    <br />
    serverName:<%=request.getServerName()%>
    <br />
    scheme:<%=request.getScheme()%>
    <br />
    <%request.getSession().setAttribute("t1","t2");%>
    <%
        Enumeration en = request.getHeaderNames();
        while(en.hasMoreElements()){
        String hd = en.nextElement().toString();
            out.println(hd+" : "+request.getHeader(hd));
            out.println("<br />");
        }
    %>
    
    7.5.5: 启动容器
    # pwd
    /opt/magedu
    
    # docker-compose up -d
    
    7.5.6: 验证容器启动成功
    docker-compose ps
    
    7.5.7: 查看启动日志
    [root@docker-server3 docker-compose]# docker-compose logs -f
    
    7.5.8: 访问 haroxy 管理界面

    http://192.168.7.105:9999/haproxy-status

    小笔记:定义tomcat动态页面
    cd /opt/linux39/app1
    vim showhost.jsp
    <%@page import="java.util.Enumeration"%>
    <br />
    host:
    <%try{out.println(""+java.net.InetAddress.getLocalHost().getHostName());}catch(Exc
    eption e){}%>
    <br />
    remoteAddr: <%=request.getRemoteAddr()%>
    <br />
    remoteHost: <%=request.getRemoteHost()%>
    <br />
    sessionId: <%=request.getSession().getId()%>
    <br />
    serverName:<%=request.getServerName()%>
    <br />
    scheme:<%=request.getScheme()%>
    <br />
    <%request.getSession().setAttribute("t1","t2");%>
    <%
        Enumeration en = request.getHeaderNames();
        while(en.hasMoreElements()){
        String hd = en.nextElement().toString();
            out.println(hd+" : "+request.getHeader(hd));
            out.println("<br />");
        }
    %>
    cp showhost.jsp ../app2
    vim docker-compose.yml
    ...
    service-tomcat-app1:
      image: 192.168.37.37/linux39/tomcat-linux39:app1
      container_name: tomcat-app1
      volumes:      #卷挂载
        - /opt/linux39/app1:/data/tomcat/webapps/linux39
        - /opt/linux39/tomcat-catalina/catalina.sh:/apps/tomcat/bin/catalina.sh     #映射启动脚本
    
    service-tomcat-app2:
      image: 192.168.37.37/linux39/tomcat-linux39:app2
      container_name: tomcat-app2
      volumes:
        - /opt/linux39/app2:/data/tomcat/webapps/linux39
        - /opt/linux39/tomcat-catalina/catalina.sh:/apps/tomcat/bin/catalina.sh
        
    docker-compose down
    docker-compose up -d
    

    八:补充-资源限制

    官方文档

    https://docs.docker.com/config/containers/resource_constraints/

    By default, a container has no resource constraints and can use as much of a given resource as the host’s kernel scheduler allows. Docker provides ways to control how much memory, or CPU a container can use, setting runtime configuration flags of the docker run command. This section provides details on when you should set such limits and the possible implications of setting them.

    Many of these features require your kernel to support Linux capabilities. To check for support, you can use the docker infocommand. If a capability is disabled in your kernel, you may see a warning at the end of the output like the following:

    默认情况下,容器没有资源限制,可以使用系统所有资源。docker 通过 docker run 配置容器的内存,cpu, 磁盘io使用量。

    其中许多功能都要求您的内核支持Linux功能。 要检查支持,可以使用docker info命令。 如果内核中禁用了某项功能,您可能会在输出结尾处看到警告,如下所示:

    WARNING: No swap limit support

    小笔记
    #解决以上警告
    vim /etc/default/grub
    GRUB_CMDLINE_LINUX="net.ifnames=0 biosdevname=0 cgroup_enable=memory"
    

    https://docs.docker.com/config/containers/resource_constraints/

    内存限制

    对于Linux 主机,如果没有足够的内容来执行重要的系统任务,将会抛出 OOM 或者 Out of Memory Exception(内存溢出、内存泄漏、内存异常), 随后系统会开始杀死进程以释放内存。每个进程都有可能被 kill,包括Dockerd和其它的应用程序。如果重要的系统进程被Kill,会导致整个系统宕机。

    产生 OOM 异常时,Docker尝试通过调整Docker守护程序上的OOM优先级来减轻这些风险,以便它比系统上的其他进程更不可能被杀死。 容器上的OOM优先级未调整,这使得单个容器被杀死的可能性比Docker守护程序或其他系统进程被杀死的可能性更大,不推荐通过在守护程序或容器上手动设置--oom-score-adj为极端负数,或通过在容器上设置--oom-kill-disable来绕过这些安全措施。

    小笔记:OOM优先级

    linux会为每个进程算一个分数,最终他会将分数最高的进程kill掉。

    /proc/PID/omm_score_adj     #范围为-1000到1000,值越大越容易被宿主机kill掉,如果将该值设置为-1000,则进程永远不会被宿主机kernel kill掉。
    /proc/PID/omm_adj           #范围为-17到+15,值越大越容易被干掉,如果是-17,则表示不能被kill,该设置参数的存在时为了和旧版本的linux内核兼容。
    /proc/PID/omm_score         #该值为系统综合进程的内存消耗量、CPU时间(utime+stime)、存活时间(uptime-start time)和oom_adj计算出的进程得分,消耗内存越多得分越高,越容易被宿主机kernel强制kill掉。
    
    限制容器对内存的访问

    Docker 可以强制执行硬性内存限制,即只允许容器使用给定的内存大小。

    Docker 也可以执行非硬性内存限制,即容器可以使用尽可能多的内存,除非内核检测到主机上的内存不够用了。

    Most of these options take a positive integer, followed by a suffix of b, k, m, g, to indicate bytes, kilobytes, megabytes, or gigabytes.

    内存限制参数
    -m or --memory=  :容器可以使用的最大内存量,如果您设置此选项,则允许的最小值为4m (4兆字节)。
    
    --memory-swap * :容器可以使用的交换分区大小,要在设置物理内存限制的前提才能设置交换分区的限制
    
    --memory-swappiness :设置容器使用交换分区的倾向性,值越高表示越倾向于使用swap分区,范围为0-100,0为能不用就不用,100为能用就用
    
    --kernel-memory :容器可以使用的最大内核内存量,最小为4m,由于内核内存与用户空间内存隔离,因此无法与用户空间内存直接交换,因此内核内存不足的容器可能会阻塞宿主主机资源,这会对主机和其他容器产生副作用。
    
    --memory-reservation :允许您指定小于--memory的软限制,当Docker检测到主机上的争用或内存不足时会激活该限制,如果使用--memory-reservation,则必须将其设置为低于--memory才能使其优先。 因为它是软限制,所以不能保证容器不超过限制。
    
    --kernel-memory :
    
    --oom-kill-disable:默认情况下,发生OOM时,kernel会杀死容器内进程,但是可以使用--oom-kill-disable参数,可以禁止oom发生在指定的容器上,即 仅在已设置-m / - memory选项的容器上禁用OOM,如果-m 参数未配置,产生OOM时,主机为了释放内存还会杀死系统进程
    
    swap限制

    swap限制参数--memory-swap 只有在设置了 --memory 后才会有意义。使用Swap,可以让容器将超出限制部分的内存置换到磁盘上。WARNING:经常将内存交换到磁盘的应用程序会降低性能

    不同的设置会产生不同的效果:

    --memory-swap:值为正数, 那么--memory和--memory-swap都必须要设置,--memory-swap表示你能使用的内存和swap分区大小的总和,例如: --memory=300m, --memory-swap=1g, 那么该容器能够使用 300m 内存和 700m swap,即--memory是实际物理内存大小值不变,而实际的计算方式为(--memory-swap)-(--memory)=容器可用swap
    
    --memory-swap:如果设置为0,则忽略该设置,并将该值视为未设置,即未设置交换分区。
    
    --memory-swap:如果等于--memory的值,并且--memory设置为正整数,容器无权访问swap即也没有设置交换分区
    
    --memory-swap:如果设置为unset,如果宿主机开启了swap,则实际容器的swap值为2x( --memory),即两倍于物理内存大小,但是并不准确。
    
    --memory-swap:如果设置为-1,如果宿主机开启了swap,则容器可以使用主机上swap的最大空间。
    
    小笔记:内存限制验证
    docker pull lorel/docker-stress-ng      #测试镜像
    docker run -it --rm lorel/docker-stress-ng --help
     docker run -it --rm  lorel/docker-stress-ng -m 1024M --vm 2 --vm-bytes 256M    
    
    未做内存限制

    未作限制可以利用到系统内存最大空间

    root@docker-node2:~# docker run -it --rm  lorel/docker-stress-ng --vm 2 --vm-bytes 256M
    root@docker-node2:~# docker stats
    
    容器内存软限制
    #docker run -it --rm  --oom-kill-disable --memory 128m --memory-reservation 64m  lorel/docker-stress-ng --vm 2 --vm-bytes 256M
    # cat /sys/fs/cgroup/memory/docker/f容器ID/memory.soft_limit_in_bytes
    67108864 #返回的限制结果
    
    内存硬限制
    root@docker-node2:~# docker run -it --rm  -m 128m   lorel/docker-stress-ng --vm 2 --vm-bytes 256M
    
    # cat /sys/fs/cgroup/   /docker/容器ID/memory.limit_in_bytes
    134217728 #返回的限制结果
    

    注:通过echo命令可以改内存限制的值,但是可以在原基础之上增大内存限制,缩小内存限制会报错write error: Device or resource busy

    交换分区限制
    # docker run -it --rm  --oom-kill-disable --memory 128m  --memory-swap 192m  centos bash
    # cat /sys/fs/cgroup/memory/docker/容器ID/memory.memsw.limit_in_bytes
    201326592 #返回值
    
    关闭oom限制
    # docker run -it --rm  -m 256m --oom-kill-disable --name magedu-c1 lorel/docker-stress-ng --vm 2 --vm-bytes 256M
    cat /sys/fs/cgroup/memory/docker/容器ID/memory.oom_control
    oom_kill_disable 1  #1为关闭
    under_oom 0
    oom_kill 0
    
    K8s 1.8.3更新日志

    https://github.com/kubernetes/kubernetes/blob/release-1.8/CHANGELOG-1.8.md

    image.png

    CPU

    一个宿主机,有几十个核心的CPU,CPU为可压缩资源,但是有成百上千的进程,那么这么多进程怎么执行的?

    实时优先级:0-99

    非实时优先级(nice):-20-19,对应100-139的进程优先级

    Linux kernel进程的调度基于CFS(Completely Fair Scheduler),完全公平调度

    CPU密集型的场景:优先级越低越好,计算密集型任务的特点是要进行大量的计算,消耗CPU资源,比如计算圆周率、对视频进行高清解码等等,全靠CPU的运算能力

    IO密集型的场景:优先级值高点,涉及到网络、磁盘IO的任务都是IO密集型任务,这类任务的特点是CPU消耗很少,任务的大部分时间都在等待IO操作完成(因为IO的速度远远低于CPU和内存的速度),比如Web应用,高并发,数据量大的动态网站来说,数据库应该为IO密集型。

    磁盘调度算法
    root@docker-node2:~# cat /sys/block/sda/queue/scheduler
    noop deadline [cfq]
    

    默认情况下,每个容器对主机CPU周期的访问权限是不受限制的,但是我们可以设置各种约束来限制给定容器访问主机的CPU周期,大多数用户使用的是默认的CFS调度方式,在Docker 1.13及更高版本中,还可以配置实时优先级。

    参数:

    --cpus= 指定容器可以使用多少可用CPU资源。例如,如果主机有两个CPU,并且您设置了--cpus =“1.5”,那么该容器将保证最多可以访问一个半的CPU。这相当于设置--cpu-period =“100000”和--cpu-quota =“150000”。在Docker 1.13和更高版本中可用。
    
    --cpu-period :设置CPU CFS调度程序周期,它与--cpu-quota一起使用,,默认为100微妙,范围从 100ms~1s,即[1000, 1000000]
    --cpu-quota :在容器上添加CPU CFS配额,也就是cpu-quota / cpu-period的值,通常使用--cpus设置此值
    
    --cpuset-cpus  主要用于指定容器运行的CPU编号,也就是我们所谓的绑核。
    root@docker-node2:~#  cat /sys/fs/cgroup/cpuset/docker/4ec68c6eb4db89d4d2907c5ea38941945c75d8431d8960855e026d3b26091641/cpuset.cpus 
    0-1
    
    --cpuset-mem  设置使用哪个cpu的内存,仅对 非统一内存访问(NUMA)架构有效
    --cpu-shares   主要用于cfs中调度的相对权重,,cpushare值越高的,将会分得更多的时间片,默认的时间片1024,最大262144
    
    测试CPU限制

    未限制容器CPU

    对于一台四核的服务器,如果不做限制,容器会把宿主机的CPU全部占完

    root@docker-node2:~# docker run -it --rm    lorel/docker-stress-ng  --cpu 4 --vm 4
    
    image.png
    # cat /sys/fs/cgroup/cpuset/docker/**容器ID/cpuset.cpus
    0-3 #**返回值**
    

    限制容器CPU

    root@docker-node2:~# docker run -it --rm  --cpus 2  lorel/docker-stress-ng  --cpu 4 --vm 4
    
    #宿主机cgroup验证
    cat /sys/fs/cgroup/cpu,cpuacct/docker/容器ID/cpu.cfs-quota_us
    200000  #每核心CPU会按照1000为单位转换成百分比进行资源划分,2个核心的CPU就是200000/1000=200%。
    
    image.png

    宿主机CPU利用率

    image.png

    将分配给容器的2核心分配到了每一核心宿主机CPU上,也就是进程可以利用任意一核心的宿主机CPU

    将容器运行到指定的CPU上

    # docker run -it --rm  --cpus 2  --cpuset-cpus  1,3 lorel/docker-stress-ng  --cpu 4 --vm 4
    # cat /sys/fs/cgroup/cpuset/docker/容器ID /cpuset.cpus 
    1,3
    
    

    宿主机CPU利用率

    image.png

    基于cpu—shares对CPU进行切分

    启动两个容器,一个--cpu-shares为1000,一个为500,观察最终效果,基本上shares值500的容器对CPU的利用率是shares值为1000容器的一半:

    root@docker-node2:~# docker run -it --rm  --cpu-shares 1000  lorel/docker-stress-ng  --cpu 4 --vm 4
    root@docker-node2:~# docker run -it --rm  --cpu-shares  500   lorel/docker-stress-ng  --cpu 4 --vm 4
    
    image.png
    # cat /sys/fs/cgroup/cpu/docker/容器ID/cpu.shares 
    1000
    # cat /sys/fs/cgroup/cpu/docker/容器PID/cpu.shares 
    500
    

    动态修改CPU shares值

    root@docker-node2:~# echo 1000 >  /sys/fs/cgroup/cpu/docker/f容器ID/cpu.shares 
    root@docker-node2:~# echo 2000 >  /sys/fs/cgroup/cpu/docker/f容器ID/cpu.shares
    
    root@docker-node1:~# cat aa.sh 
    #!/bin/bash
    x=0
    while [ True ];do
    x=$x+1
    done;
    
    

    相关文章

      网友评论

          本文标题:39-docker(三)

          本文链接:https://www.haomeiwen.com/subject/gycdqktx.html