Docker进阶
Docker网络详解
Docker0网络
准备工作:清空所有的容器,清空所有的镜像
docker rm -f $(docker ps -a -q) # 删除所有容器
docker rmi -f $(docker images -qa) # 删除全部镜像
Docker的网络也是十分重要的一个点,希望大家可以认真理解!
本地干净的网络
[root@kuangshenlinux ~]# ip addr
# 本地回环网络
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
# 网卡地址 wifi
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 08:00:27:e0:aa:73 brd ff:ff:ff:ff:ff:ff
inet 192.168.0.111/24 brd 192.168.0.255 scope global noprefixroute enp0s3
valid_lft forever preferred_lft forever
inet6 fe80::3202:526:12cb:70ec/64 scope link noprefixroute
valid_lft forever preferred_lft forever
# docker 0 ,docker创建的网络
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:f8:9d:a8:42 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
1、微服务这么多,访问怎么解决? (容器名)
2、docker每启动一个容器,就会给他分配一个ip。docker0是docker默认给的。我们不指定网络的情况下,创建容器都在docker0中,未来开发,我们要自定义网络。
[root@kuangshenlinux ~]# docker run -itd --name web01 centos
Unable to find image 'centos:latest' locally
latest: Pulling from library/centos
a1d0c7532777: Already exists
Digest: sha256:a27fd8080b517143cbbbab9dfb7c8571c40d67d534bbdee55bd6c473f432b177
Status: Downloaded newer image for centos:latest
53231c3adf0423ed2d0577ead987507c12978416349a51445d663c9536c9b4ff
# docker每启动一个容器,就会给他分配一个ip。这个ip就是归docker0 管理
[root@kuangshenlinux ~]# docker exec -it web01 ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
4: eth0@if5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
# 容器外本地可以ping到容器里面
[root@kuangshenlinux ~]# ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.058 ms
分析原理
1、本来有三个网络,启动容器后,多了一个,这个网络和容器内部的网络是配对的。
# 再次启动一个容器查看
[root@kuangshenlinux ~]# docker exec -it web02 ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
6: eth0@if7: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
[root@kuangshenlinux ~]# ip addr
....
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:f8:9d:a8:42 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
inet6 fe80::42:f8ff:fe9d:a842/64 scope link
valid_lft forever preferred_lft forever
5: veth3b4847e@if4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
link/ether 0e:58:71:93:42:18 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet6 fe80::c58:71ff:fe93:4218/64 scope link
valid_lft forever preferred_lft forever
7: veth13568df@if6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
link/ether 9a:3c:71:70:e2:a0 brd ff:ff:ff:ff:ff:ff link-netnsid 1
inet6 fe80::983c:71ff:fe70:e2a0/64 scope link
valid_lft forever preferred_lft forever
# 总结观察:
1、web1 -- linux 主机 5: veth3b4847e@if4: 4: eth0@if5
2、web2 -- linux 主机 7: veth13568df@if6: 6: eth0@if7
# 只要启动一个容器,默认就会分配一对网卡。
# 虚拟接口 # veth-pair 就是一对的虚拟设备接口,它都是成对出现的。一端连着协议栈,一端彼此相连着。
# 就好比一个桥梁,可以连通容器内外。
# 测试容器之间的访问,ip访问没有问题
[root@kuangshenlinux ~]# docker exec -it web02 ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.058 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.064 ms
^C
--- 172.17.0.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 0.058/0.061/0.064/0.003 ms
[root@kuangshenlinux ~]# docker exec -it web01 ping 172.17.0.3
PING 172.17.0.3 (172.17.0.3) 56(84) bytes of data.
64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=0.043 ms
64 bytes from 172.17.0.3: icmp_seq=2 ttl=64 time=0.071 ms
64 bytes from 172.17.0.3: icmp_seq=3 ttl=64 time=0.092 ms
^C
--- 172.17.0.3 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2005ms
rtt min/avg/max/mdev = 0.043/0.068/0.092/0.022 ms
# 容器删除后再次启动,ip发生了变化怎么办?
小结
Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网关。因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的Container-IP直接通信。
Docker容器网络就很好的利用了Linux虚拟网络技术,在本地主机和容器内分别创建一个虚拟接口,并让他们彼此联通(这样一对接口叫veth pair);
Docker中的网络接口默认都是虚拟的接口。虚拟接口的优势就是转发效率极高(因为Linux是在内核中进行数据的复制来实现虚拟接口之间的数据转发,无需通过外部的网络设备交换),对于本地系统和容器系统来说,虚拟接口跟一个正常的以太网卡相比并没有区别,只是他的速度快很多。
–link
mysql: 服务名地址链接 ip会变化
[root@kuangshenlinux ~]# docker exec -it web02 ping web01
ping: web01: Name or service not known
# 但是可以通过 --link在启动容器的时候连接到另一个容器网络中,可以通过域名ping了
[root@kuangshenlinux ~]# docker run -itd --name web03 --link web02 centos
6f67f9f7407edb8c48ce2d3ca413aef414a2a8628080fd69605e4ce2c3bea6ab
[root@kuangshenlinux ~]# docker exec -it web03 ping web02
PING web02 (172.17.0.3) 56(84) bytes of data.
64 bytes from web02 (172.17.0.3): icmp_seq=1 ttl=64 time=0.062 ms
64 bytes from web02 (172.17.0.3): icmp_seq=2 ttl=64 time=0.064 ms
64 bytes from web02 (172.17.0.3): icmp_seq=3 ttl=64 time=0.064 ms
^C
--- web02 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2005ms
rtt min/avg/max/mdev = 0.062/0.063/0.064/0.006 ms
# 但是反向也ping不通。
[root@kuangshenlinux ~]# docker exec -it web02 ping web03
ping: web03: Name or service not known
# 底层原理
域名:
--link hosts 添加了一条记录
172.17.0.3 web02
[root@kuangshenlinux ~]# docker exec -it web03 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.3 web02 325795bd6df8
172.17.0.4 6f67f9f7407e
[root@kuangshenlinux ~]#
–link是以前的方法,不方便了。
自定义网络
[root@kuangshenlinux ~]# docker network --help
Usage: docker network COMMAND
Manage networks
Commands:
connect Connect a container to a network
create Create a network
disconnect Disconnect a container from a network
inspect Display detailed information on one or more networks
ls List networks
prune Remove all unused networks
rm Remove one or more networks
Run 'docker network COMMAND --help' for more information on a command.
# 查看所有的网络
[root@kuangshenlinux ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
defce6912c4a bridge bridge local
e6e26ff63dfe host host local
8a592709b443 none null local
所有网络模式
网络模式 | 配置 | 说明 |
---|---|---|
bridge模式 | –net=bridge | 默认值,在Docker网桥docker0上为容器创建新的网络栈 |
none模式 | –net=none | 不配置网络,用户可以稍后进入容器,自行配置 |
container模式 | –net=container:name/id | 容器和另外一个容器共享Network namespace。 kubernetes中的pod就是多个容器共享一个Network namespace。 |
host模式 | –net=host | 容器和宿主机共享Network namespace |
用户自定义 | –net=自定义网络 | 用户自己使用network相关命令定义网络,创建容器的时候可以指定为自己定义的网络 |
[root@kuangshenlinux ~]# docker network inspect bridge
[
{
"Name": "bridge",
"Id": "defce6912c4ae8b16d6f02a6eee0650c79c7d39cba26597de32648f936c0cd43",
"Created": "2023-12-12T19:57:25.572880728+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
// 网络配置: config配置,子网网段 255*255. 65534 个地址
"Subnet": "172.17.0.0/16",
// docker0 网关地址
"Gateway": "172.17.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
// 在这个网络下的容器地址。Name就是容器的名字
"Containers": {
"325795bd6df82e6ef18ff027f43a189c4ef886a25b95fdc9c5793bc9d7827179": {
"Name": "web02",
"EndpointID": "9ab43d4cd786b8c79d78fd3bf3f05c6dfbd6f1665ca5bc9e74646f1d6f758508",
"MacAddress": "02:42:ac:11:00:03",
"IPv4Address": "172.17.0.3/16",
"IPv6Address": ""
},
"53231c3adf0423ed2d0577ead987507c12978416349a51445d663c9536c9b4ff": {
"Name": "web01",
"EndpointID": "b891d5b8213b8241b5438c60afc08054c0c4c48490a3715f21fe5591b28b65fc",
"MacAddress": "02:42:ac:11:00:02",
"IPv4Address": "172.17.0.2/16",
"IPv6Address": ""
},
"6f67f9f7407edb8c48ce2d3ca413aef414a2a8628080fd69605e4ce2c3bea6ab": {
"Name": "web03",
"EndpointID": "651e2d1b9dcd72fc7339c687904cf763aaa524bd79cc5945888dfec8829a62b6",
"MacAddress": "02:42:ac:11:00:04",
"IPv4Address": "172.17.0.4/16",
"IPv6Address": ""
}
},
"Options": {
"com.docker.network.bridge.default_bridge": "true",
"com.docker.network.bridge.enable_icc": "true",
"com.docker.network.bridge.enable_ip_masquerade": "true",
"com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
"com.docker.network.bridge.name": "docker0",
"com.docker.network.driver.mtu": "1500"
},
"Labels": {}
}
]
自定义一个网络
[root@kuangshenlinux ~]# docker run -itd --name web01 --net bridge centos
552223f74f163f94238bf536040aa0c683b1ab0fbfbcabdd1ed28644e40f1b9f
# docker0网络的特点
1.它是默认的
2.域名访问不通
3.--link 域名通了,但是删了又不行
create命令创建一个新的网络
[root@kuangshenlinux ~]# docker network create \
--driver bridge \
--subnet 192.169.0.0/16 \
--gateway 192.169.0.1 \
mynet
d37ec2853507c3e6159db06e4c8a33e39a45edff4ac69949c96f981d7aca9a79
[root@kuangshenlinux ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
defce6912c4a bridge bridge local
e6e26ff63dfe host host local
d37ec2853507 mynet bridge local
8a592709b443 none null local
使用的逻辑
# 未来可以通过网络来隔离项目
docker network create \
--driver bridge \
--subnet 192.169.0.0/16 \
--gateway 192.169.0.1 \
kuangstudynet
mysql
redis
web
admin
mq
# 部署集群挽环境,也可以这样定义网络
mysql 3-5个容器
docker network create \
--driver bridge \
--subnet 192.169.0.0/16 \
--gateway 192.169.0.1 \
mysqlnet
--net mysqlnet
# 启动两个服务在自己的网络下。 --net mynet
[root@kuangshenlinux ~]# docker run -itd --name wen01-net --net mynet centos
e16726178e4ee3b61b0dc47f16d112ba0426bcf040b84949811ebc8607d94555
[root@kuangshenlinux ~]# docker run -itd --name wen02-net --net mynet centos
17fae7a2c0bb66c2834ad7d3dc338c0a5707aea5caf4337138f15c6f2079713e
# 测试互相ping,可以使用域名ping通了
[root@kuangshenlinux ~]# docker exec -it wen01-net ping 192.169.0.3
PING 192.169.0.3 (192.169.0.3) 56(84) bytes of data.
64 bytes from 192.169.0.3: icmp_seq=1 ttl=64 time=0.063 ms
64 bytes from 192.169.0.3: icmp_seq=2 ttl=64 time=0.091 ms
64 bytes from 192.169.0.3: icmp_seq=3 ttl=64 time=0.066 ms
^C
--- 192.169.0.3 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2001ms
rtt min/avg/max/mdev = 0.063/0.073/0.091/0.014 ms
[root@kuangshenlinux ~]# docker exec -it wen01-net ping wen02-net
PING wen02-net (192.169.0.3) 56(84) bytes of data.
64 bytes from wen02-net.mynet (192.169.0.3): icmp_seq=1 ttl=64 time=0.041 ms
64 bytes from wen02-net.mynet (192.169.0.3): icmp_seq=2 ttl=64 time=0.064 ms
64 bytes from wen02-net.mynet (192.169.0.3): icmp_seq=3 ttl=64 time=0.106 ms
64 bytes from wen02-net.mynet (192.169.0.3): icmp_seq=4 ttl=64 time=0.088 ms
^C
--- wen02-net ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3007ms
rtt min/avg/max/mdev = 0.041/0.074/0.106/0.026 ms
[root@kuangshenlinux ~]# docker exec -it wen02-net ping wen01-net
PING wen01-net (192.169.0.2) 56(84) bytes of data.
64 bytes from wen01-net.mynet (192.169.0.2): icmp_seq=1 ttl=64 time=0.052 ms
64 bytes from wen01-net.mynet (192.169.0.2): icmp_seq=2 ttl=64 time=0.092 ms
^C
--- wen01-net ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 0.052/0.072/0.092/0.020 ms
# 未来在项目中,直接使用容器名来连接服务,ip无论怎么变,都不会发生变化
docker run -itd --name mysql --net mynet mysql
mysql:3306/rbms
网络连通
由于我们现在是跨网络的,容器之间无法访问
[root@kuangshenlinux ~]# docker exec -it web01 ping wen01-net
ping: wen01-net: Name or service not known
[root@kuangshenlinux ~]# docker exec -it web01 ping 192.169.0.2
docker0和自定义网络肯定不通,我们使用自定义网络的好处就是网络隔离:
大家公司项目部署的业务都非常多,假设我们有一个商城,我们会有订单业务(操作不同数据),会有订单业务购物车业务(操作不同缓存)。如果在一个网络下,有的程序猿的恶意代码就不能防止了,所以我们就在部署的时候网络隔离,创建两个桥接网卡,比如订单业务(里面的数据库,redis,mq,全部业务 都在order-net网络下)其他业务在其他网络。
那关键的问题来了,如何让 web-net-01 访问 web01?
[root@kuangshenlinux ~]# docker network connect --help
Usage: docker network connect [OPTIONS] NETWORK CONTAINER
Connect a container to a network
# 第一个参数 网络
# 第二个参数 容器
[root@kuangshenlinux ~]# docker network connect mynet web01
[root@kuangshenlinux ~]# docker network inspect mynet
[
{
"Name": "mynet",
"Id": "d37ec2853507c3e6159db06e4c8a33e39a45edff4ac69949c96f981d7aca9a79",
"Created": "2023-12-12T20:34:57.1073687+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "192.169.0.0/16",
"Gateway": "192.169.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"17fae7a2c0bb66c2834ad7d3dc338c0a5707aea5caf4337138f15c6f2079713e": {
"Name": "wen02-net",
"EndpointID": "cd4963c8bc9e64182fffc5f7b202495c3c2b28d46da8e17d73d3a94359fd7c1d",
"MacAddress": "02:42:c0:a9:00:03",
"IPv4Address": "192.169.0.3/16",
"IPv6Address": ""
},
# web01 这个容器进入了 mynet 网络
"552223f74f163f94238bf536040aa0c683b1ab0fbfbcabdd1ed28644e40f1b9f": {
"Name": "web01",
"EndpointID": "d684b0ab3142219939957cbbd47a4a254d2459cbcac6fe9f9ae5aed0b7f32370",
"MacAddress": "02:42:c0:a9:00:04",
"IPv4Address": "192.169.0.4/16",
"IPv6Address": ""
},
"e16726178e4ee3b61b0dc47f16d112ba0426bcf040b84949811ebc8607d94555": {
"Name": "wen01-net",
"EndpointID": "574b3b469f3c2f2f5c21725b720adeaa8640a47618f1d7d7ad8f279343f54c2b",
"MacAddress": "02:42:c0:a9:00:02",
"IPv4Address": "192.169.0.2/16",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {}
}
]
[root@kuangshenlinux ~]# docker network inspect bridge
[
{
"Name": "bridge",
"Id": "defce6912c4ae8b16d6f02a6eee0650c79c7d39cba26597de32648f936c0cd43",
"Created": "2023-12-12T19:57:25.572880728+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.17.0.0/16",
"Gateway": "172.17.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"26b67bff513034805ec998da0d36ff3b22eb27d2d5f93709f81adc7cc642d935": {
"Name": "web02",
"EndpointID": "db5229124ae6aee60f2fadd30c59fa0ec38dbde2a6ea325e50a943af9c97618c",
"MacAddress": "02:42:ac:11:00:03",
"IPv4Address": "172.17.0.3/16",
"IPv6Address": ""
},
// web01 依旧存在
"552223f74f163f94238bf536040aa0c683b1ab0fbfbcabdd1ed28644e40f1b9f": {
"Name": "web01",
"EndpointID": "d114e6a65bb580713542121454c5e5c9bb3d1151959cf40ec1e2c80e416240bb",
"MacAddress": "02:42:ac:11:00:02",
"IPv4Address": "172.17.0.2/16",
"IPv6Address": ""
}
},
"Options": {
"com.docker.network.bridge.default_bridge": "true",
"com.docker.network.bridge.enable_icc": "true",
"com.docker.network.bridge.enable_ip_masquerade": "true",
"com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
"com.docker.network.bridge.name": "docker0",
"com.docker.network.driver.mtu": "1500"
},
"Labels": {}
}
]
连接之后,web01这个容器拥有了两个ip。一个容器是可以有多个ip的。
#通过连接之后,网络就完全可以打通了
[root@kuangshenlinux ~]# docker exec -it web01 ping wen02-net
PING wen02-net (192.169.0.3) 56(84) bytes of data.
64 bytes from wen02-net.mynet (192.169.0.3): icmp_seq=1 ttl=64 time=0.047 ms
64 bytes from wen02-net.mynet (192.169.0.3): icmp_seq=2 ttl=64 time=0.064 ms
64 bytes from wen02-net.mynet (192.169.0.3): icmp_seq=3 ttl=64 time=0.140 ms
64 bytes from wen02-net.mynet (192.169.0.3): icmp_seq=4 ttl=64 time=0.069 ms
^C
--- wen02-net ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3014ms
rtt min/avg/max/mdev = 0.047/0.080/0.140/0.035 ms
[root@kuangshenlinux ~]# docker exec -it web02-net ping wen01
Error response from daemon: No such container: web02-net
[root@kuangshenlinux ~]# docker exec -it wen02-net ping web01
PING web01 (192.169.0.4) 56(84) bytes of data.
64 bytes from web01.mynet (192.169.0.4): icmp_seq=1 ttl=64 time=0.031 ms
64 bytes from web01.mynet (192.169.0.4): icmp_seq=2 ttl=64 time=0.063 ms
64 bytes from web01.mynet (192.169.0.4): icmp_seq=3 ttl=64 time=0.092 ms
^C
--- web01 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2001ms
rtt min/avg/max/mdev = 0.031/0.062/0.092/0.024 ms
结论:如果要跨网络操作别人,就需要使用 docker network connect [OPTIONS] NETWORK CONTAINER
连接。
DockerCompose
1、Compose介绍
将单机服务-通过Dockerfile 构建为镜像 -docker run 成为一个服务
user 8080
net 7000
pay 8181
admin 5000
监控
....
docker run 单机版、一个个容器启动和停止
问题:
前面我们使用Docker的时候,定义 Dockerfile 文件,然后使用 docker build、docker run 等命令操作容器,然而微服务架构的应用系统一般包含若干个微服务,每个微服务一般都会部署多个实例,如果每个微服务都要手动启停,那么效率之低,维护量之大可想而之。
使用 Docker Compose 可以轻松,高效的管理容器,它是一个用于定义和运行多容器 Docker 的应用程序工具。
官网文档:https://docs.docker.com/compose
# 容器批量管理
# Compose 定义和运行多个Docker容器,通过Compose, 使用一个yaml文件管理应用服务,通过一个简单的命令,就可以将你的所有服务全部启动
Compose is a tool for defining and running multi-container Docker applications. With Compose, you use a YAML file to configure your application's services. Then, with a single command, you create and start all the services from your configuration.
# 可以在所有环境中使用:开发、生产、ci工作流
Compose works in all environments; production, staging, development, testing, as well as CI workflows. It also has commands for managing the whole lifecycle of your application:
小结
Compose 项目是Docker官方的开源项目,负责实现Docker容器集群的快速编排
开源代码在https://github.com/docker/compose 上
我们知道使用Dockerfile模板文件可以让用户很方便的定义一个单独的应用容器,其实在工作中,经常会碰到需要多个容器相互配合来完成的某项任务情况,例如工作中的web服务容器本身,往往会在后端加上数据库容器,甚至会有负责均衡器,比如LNMP服务
Compose 就是来做这个事情的,它允许用户通过一个单独的docker-compose.yml模板文件(YAML格式)来定义一组相关联的应用容器为一个项目(project)
Compose 中有两个重要的概念:
1、服务(service):一个应用的容器,实际上可以包括若干运行相同镜像的容器实例,很多的镜像启动
- 订单服务 image
- 物流服务 image
- 用户服务 image
- 支付服务 image
- 4个容器后面构成一个服务 service
2、**项目(project):**由一组关联的应用容器组成的一个完整业务单元,在docker-compose.yml中定义。
Compose 项目是由Python编写的,实际上就是调用了Docker服务提供的API来对容器进行管理,因此,只要所在的操作系统的平台支持Docker API,就可以在其上利用Compose来进行编排管理.
2、Docker 安装Compose
1、下载文件安装
- 下载compose文件,授权,就可以启动了
2、yum安装
sudo yum update
sudo yum install docker-compose-plugin
3、一般情况下,linux要安装python环境
yum install python-pip # pip 是 Python 包管理工具
3、尝试使用
https://docs.docker.com/compose/gettingstarted/
Dockerfile;一个镜像的构建自动了
DockerCompose 把一个服务,多个容器自动化来启动和构建。批量管理容器
步骤:
1、编写项目文件
2、编写Dockerfile文件打包项目成为服务镜像
3、通过 Compose.yaml 管理构建所有的服务
services:
# 可以定义多个服务
web:
build: .
ports:
- "8000:5000"
depens_on:
- redis
redis:
image: "redis:alpine"
4、docker compose up 启动所有服务
- 按照 Compose.yaml 定义的来一步步加载
5、会生成镜像
6、查看服务
# 由于是单机版的docker,这个服务无法查看,集群环境中才可以看到。
[root@iZj6c1wvscj5y05fyq1yiqZ ~]# docker service ls
Error response from daemon: This node is not a swarm manager. Use "docker swarm init" or "docker swarm join" to connect this node to swarm and try again.
# 发现一次拉起了两个容器,这个就是 Compose.yaml 定义的服务
# 容器名规律: 项目名-容器服务名-1编号
[root@iZj6c1wvscj5y05fyq1yiqZ ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
292c625ce219 redis:alpine "docker-entrypoint.s…" 6 minutes ago Up 3 minutes 6379/tcp composetest-redis-1
21f4f7a63283 composetest-web "python app.py" 6 minutes ago Up 3 minutes 0.0.0.0:8000->5000/tcp composetest-web-1
#
docker compose 命令需在项目目录下使用
[root@iZj6c1wvscj5y05fyq1yiqZ composetest]# docker compose down
[+] Running 3/2
✔ Container composetest-redis-1 Removed 0.2s
✔ Container composetest-web-1 Removed 0.3s
# compose 会自动创建一个服务的网络
✔ Network composetest_default Removed
4、Compose命令
# Compose 大部分命令的对象即可以是项目的本身,也可以是指定为项目中的服务或者容器
执行docker compose [COMMAND] --help 或者docker compose help [COMMAND]可以查看命令的帮助信息
# 具体的使用格式,一个是启动一个容器,一个是启动多个容器(服务网络问题-自定一个网络。所有服务按照项目名来定义,编号)
docker compose [-f=<arg>...] [options] [COMMAND] [ARGS]
# 参数选项
-f,--file file指定模板文件,默认是docker-compose.yml模板文件,可以多次指定
-p,--project-name name指定项目名称,默认使用所在目录名称作为项目名称
-v,--version 输出版本信息
# Compose所支持的命令
build Build or rebuild services (构建项目中的服务容器)
config Validate and view the Compose file (验证并查看Compose文件)
create Create services (为服务创建容器)
down Stop and remove containers, networks, images, and volumes (停止容器并删除由其创建的容器,网络,卷和图像up)
events Receive real time events from containers (为项目中的每个容器流式传输容器事件)
exec Execute a command in a running container (这相当于docker exec。使用此子命令,您可以在服务中运行任意命令。默认情况下,命令分配TTY,因此您可以使用命令docker compose exec web sh来获取交互式提示。)
help Get help on a command (获得一个命令的帮助)
images List images ()
kill Kill containers (通过发送SIGKILL信号来强制停止服务容器)
logs View output from containers (查看服务容器的输出)
pause Pause services (暂停一个容器)
port Print the public port for a port binding (打印某个容器端口所映射的公共端口)
ps List containers (列出项目中目前所有的容器)
pull Pull service images (拉取服务依赖镜像)
push Push service images (推送服务镜像)
restart Restart services (重启项目中的服务)
rm Remove stopped containers (删除所有停止状态的服务容器)
run Run a one-off command (在指定服务上执行一个命令)
start Start services (启动已存在的服务容器)
stop Stop services (停止已存在的服务容器)
top Display the running processes (显示容器正在运行的进程)
unpause Unpause services (恢复处于暂停状态的容器)
up Create and start containers (自动完成包括构建镜像、创建服务、启动服务并关联服务相关容器的一系列操作)
version Show the Docker-Compose version information (输出版本)
说明:
一个普通的工作流程以docker compose up -d 启动应用程序开始。
docker compose logs和ps命令可以用来验证应用程序的状态,还能帮助调试。
修改代码后,先执行 docker compose build 构建新的镜像,然后执行 docker compose up -d 取代运行中的容器。
注意,Compose会保留原来容器中所有旧的数据卷,这意味着即使容器更新后,数据库和缓存也依旧在容器内(这很可能造成混淆,因此要特别小心)。
如果你修改了Compose的YAML文件,但不需要构建新的镜像,可以通过up -d参数使Compose以新的配置替换容器。
如果想要强制停止Compose并重新创建所有容器,docker compose stop xxxx 和 docker compose rm xxxx
简单使用:
1、执行命令运行容器:docker compose up -d
2、查看镜像:docker images
3、停止和删除容器: docker compose stop xx 和 docker compose rm xxxx
5、Compose.yaml
模板文件是Compose的核心,涉及的指令关键字比较多,但是大部分的指令与docker run相关的参数的含义是类似的
默认的模板名是docker-compose.yml
# 语法-3层
version: "3.8"
services: # 定义很多服务
服务1:
# 当前的服务配置
服务2:
# 当前服务配置
#服务要用的网络、卷、等其他全局规则
volumes:
networks:
configs:
.....
官网链接:https://docs.docker.com/compose/compose-file/#compose-file-structure-and-examples
Compose和Docker兼容性:
Compose 文件格式有3个版本,分别为1, 2.x 和 3.x
目前主流的为 3.x 其支持 docker 1.13.0 及其以上的版本
# 常用参数:
version # 指定 compose 文件的版本
services # 定义所有的 service 信息, services 下面的第一级别的 key 既是一个 service 的名称
服务
build # 指定包含构建上下文的路径, 或作为一个对象,该对象具有 context 和指定的 dockerfile
context # context: 指定 Dockerfile 文件所在的路径
dockerfile # dockerfile: 指定 context 指定的目录下面的 Dockerfile 的名称(默认为 Dockerfile)
args # args: Dockerfile 在 build 过程中需要的参数
command # 覆盖容器启动后默认执行的命令, 支持 shell 格式和 [] 格式
container_name # 指定容器的名称 (等同于 docker run --name 的作用)
deploy # v3 版本以上, 指定与部署和运行服务相关的配置
# deploy 部分是 docker stack 使用的, docker stack 依赖 docker swarm
depends_on # 定义容器启动顺序 (此选项解决了容器之间的依赖关系
dns # 设置 DNS 地址(等同于 docker run --dns 的作用)
entrypoint # 覆盖容器的默认 entrypoint 指令
env_file # 从指定文件中读取变量设置为容器中的环境变量,可以是单个值或者一个文件列表
environment # 设置环境变量, environment 的值可以覆盖 env_file 的值
expose # 暴露端口, 但是不能和宿主机建立映射关系, 类似于 Dockerfile 的 EXPOSE 指令
external_links # 连接不在 docker-compose.yml 中定义的容器或者不在 compose 管理的容器
extra_hosts # 添加 host 记录到容器中的 /etc/hosts 中
healthcheck # v2.1 以上版本, 定义容器健康状态检查
image # 指定 docker 镜像, 可以是远程仓库镜像、本地镜像
labels # 使用 Docker 标签将元数据添加到容器
logging # 设置容器日志服务
network_mode # 指定网络模式 (等同于 docker run --net 的作用, 在使用 swarm 部署时将忽略该选项)
networks # 将容器加入指定网络 (等同于 docker network connect 的作用)
# networks 可以位于 compose 文件顶级键和 services 键的二级键
pid: 'host' # 共享宿主机的 进程空间(PID)
ports # 建立宿主机和容器之间的端口映射关系, ports 支持两种语法格式
- "8000:8000" # 容器的 8000 端口和宿主机的 8000 端口建立映射关系
volumes # 定义容器和宿主机的卷映射关系
- /var/lib/mysql # 映射容器内的 /var/lib/mysql 到宿主机的一个随机目录中
- /opt/data:/var/lib/mysql # 映射容器内的 /var/lib/mysql 到宿主机的 /opt/data
- ./cache:/tmp/cache # 映射容器内的 /var/lib/mysql 到宿主机 compose 文件所在的位置
- ~/configs:/etc/configs/:ro # 映射容器宿主机的目录到容器中去, 权限只读
- datavolume:/var/lib/mysql # datavolume 为 volumes 顶级键定义的目录, 在此处直接调用
.....
# 对于值为时间的可接受的值:
2.5s
10s
1m30s
2h32m
5h34m56s
时间单位: us, ms, s, m, h
# 对于值为大小的可接受的值:
2b
1024kb
2048k
300m
1gb
单位: b, k, m, g 或者 kb, mb, gb
# depends_on示例
version: '3'
services:
web:
build: .
depends_on:
- db
- redis
redis:
image: redis
ports:
- "6379:6379"
environment:
- root_pwd: "123456"
db:
image: postgres
# docker compose up 以依赖顺序启动服务,下面例子中 redis 和 db 服务在 web 启动前启动
# 默认情况下使用 docker compose up web 这样的方式启动 web 服务时,也会启动 redis 和 db 两个服务,因为在配置文件中定义了依赖关系
# network示例
version: '3.7'
services:
test:
image: nginx:1.14-alpine
container_name: mynginx
command: ifconfig
networks:
app_net: # 调用下面 networks 定义的 app_net 网络
ipv4_address: 172.16.238.10
networks:
app_net:
driver: bridge
ipam:
driver: default
config:
- subnet: 172.16.238.0/24
- getaway: 172.16.238.1
小结:
以后我们的微服务项目中,如果有多个微服务,则按照他们的启动顺序,配置对应的规则文件即可!
可以去看看你们的公司项目,有没有 docker-compose.yml 文件,有没有做自动编排!
如果下载的网上开源项目,有dockerfile+docker-compose ,那我们可以一键搞定!
网上的项目拉下来,mysql的sql文件导入数据库。 docker-compose up 即可!
dockerfile+docker-compose。
工程、服务、容器
- Docker Compose 将所管理的容器分为三层,分别是工程(project)、服务(service)、容器(container)
- Docker Compose 运行目录下的所有文件(docker-compose.yml)组成一个工程,一个工程包含多个服务,每个服务中定义了容器运行的镜像、参数、依赖,一个服务可包括多个容器实例!
到此,Dokcer Compose搞定!
6、实战:WordPress
也可以把 WordPress当作一个内容管理系统(CMS)来使用。WordPress是一款个人博客系统
https://github.com/docker/awesome-compose/tree/master/official-documentation-samples/wordpress/
version: '3.8'
services:
db:
image: mysql:5.7
volumes:
- db_data:/var/lib/mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: somewordpress
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: wordpress
wordpress:
depends_on:
- db
image: wordpress:latest
ports:
- "8000:80"
restart: always
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: wordpress
WORDPRESS_DB_NAME: wordpress
volumes:
db_data: {}
docker卷db_data
将WordPress所做的所有更新持久化到数据库。
WordPress Multisite仅适用于port 80
和443
3、docker compose up -d
从您的项目目录运行。
4、测试访问!
未来只需要一键启动就可以安装好环境了!无论多复杂都是一键。
开源项目:常见的环境安装 https://gitee.com/zhengqingya/docker-compose
Docker run 启动一个容器
Docker compse 启动一组容器服务,容器编排