四: Docker网络
docker network list #查看网络类型
docker inspect ID #查看容器信息
4.1: docker 结合负载实现网站高可用
4.1.1: 整体规划图:
下图为一个小型的网络架构图,其中 nginx 使用 docker 运行
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: 报错如下
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 登录
6.5.3: 创建一个 nginx 项目
与主 harbor 项目名称保持一致
6.5.4:在主 harbor 服务器配置同步测试
6.5.5:点击复制规则
6.5.6:主 harbor 编辑同步策略
6.5.7: 主 harbor 查看镜像同步状态
6.5.8: 从 harbor 查看镜像
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 项目设置为公开
6.5.9.4:设置项目为公开访问
6.5.9.5: docker 客户端下载镜像
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 访问
至此,高可用模式的 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 验证镜像
6.6.7: docker 镜像端测试
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://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 info
command. 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
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
# 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%。
宿主机CPU利用率
将分配给容器的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利用率
基于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
# 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;