[root@vm001 admin]# ifconfig
ens33: flags=4163 mtu 1500
inet 192.168.226.128 netmask 255.255.255.0 broadcast 192.168.226.255
inet6 fe80::8805:f678:285c:a5c0 prefixlen 64 scopeid 0x20
ether 00:0c:29:e7:21:88 txqueuelen 1000 (Ethernet)
RX packets 258 bytes 67570 (65.9 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 140 bytes 16053 (15.6 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73 mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10
loop txqueuelen 1000 (Local Loopback)
RX packets 48 bytes 4080 (3.9 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 48 bytes 4080 (3.9 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
virbr0: flags=4099 mtu 1500
inet 192.168.122.1 netmask 255.255.255.0 broadcast 192.168.122.255
ether 52:54:00:ff:4f:c6 txqueuelen 1000 (Ethernet)
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
yum remove libvirt-libs.x86_64
会产生一个名为docker0的虚拟网桥
## 启动 docker
[root@vm001 admin]# systemctl start docker
[root@vm001 admin]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
orderservice6001 v1.1 f5c5e0bb8815 22 hours ago 685MB
## 查询 ip网络信息
[root@vm001 admin]# ifconfig
docker0: flags=4163 mtu 1500
inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255
inet6 fe80::42:f5ff:fea1:eede prefixlen 64 scopeid 0x20
ether 02:42:f5:a1:ee:de txqueuelen 0 (Ethernet)
RX packets 31 bytes 2658 (2.5 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 52 bytes 18674 (18.2 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
## 其余省略
查看docker网络模式命令:docker network ls
--------- 默认创建三大网络模式
[root@vm001 admin]# docker network ls
NETWORK ID NAME DRIVER SCOPE
3f6c87b881bb bridge bridge local
2e4dd2180dd1 host host local
4fdddc082793 none null local
[root@vm001 admin]#
[root@vm001 admin]# 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.
在4.1.2 中有
创建: docker network create
[root@vm001 admin]# docker network create aa_network
e810395831b1e5069e447c6730df76917dbb981c82e5519970c3d33965f463f3
[root@vm001 admin]# docker network ls
NETWORK ID NAME DRIVER SCOPE
e810395831b1 aa_network bridge local
3f6c87b881bb bridge bridge local
2e4dd2180dd1 host host local
4fdddc082793 none null local
删除: docker network rm
[root@vm001 admin]# docker network rm aa_network
aa_network
[root@vm001 admin]# docker network ls
NETWORK ID NAME DRIVER SCOPE
3f6c87b881bb bridge bridge local
2e4dd2180dd1 host host local
4fdddc082793 none null local
docker network inspect XXX网络名字
如: docker network inspect bridge
显示出来的就是上面看到的 docker0 那个网桥
[root@vm001 admin]# docker network ls
NETWORK ID NAME DRIVER SCOPE
3f6c87b881bb bridge bridge local
2e4dd2180dd1 host host local
4fdddc082793 none null local
[root@vm001 admin]# docker network inspect bridge
[
{
"Name": "bridge",
"Id": "3f6c87b881bbceedca34897b2fa0794a52269d10de7dd0c84ab694a927325c5d",
"Created": "2022-05-09T23:32:21.056937312+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": {
"b014f0b061b4c39c5d13cfdcbc38e4cbb64cbb8c5939ba4fa2385cbd5628165b": {
"Name": "suspicious_keldysh",
"EndpointID": "1677be925e9c7c04a5a1651f48c16f62b7efca13d96c34e6c82c4607c0dd84f7",
"MacAddress": "02:42:ac:11:00:02",
"IPv4Address": "172.17.0.2/16",
"IPv6Address": ""
},
"e2ddfc2abe317482bac74809279e91bbd91a55cbdc2a842720317993d0b1c091": {
"Name": "zk01",
"EndpointID": "304da47bd4bb8e0dafca3ebda522b5587e5d301a30e060dab9ce2c1ab56ab9a7",
"MacAddress": "02:42:ac:11:00:03",
"IPv4Address": "172.17.0.3/16",
"IPv6Address": ""
},
"f27be7bd716acb811fd9d28fa4809e19a60c88db9cceefddafb3eae65a113ee8": {
"Name": "consul",
"EndpointID": "6d3d9798c592807b3c9a9a817d536ce860a28c455e69ccf1340216d0342f461e",
"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": {}
}
]
在单机模式不明显,但是在公司,需要作docker网络管理和容器调用之间的规划。
需要考虑使用常见的网络桥接模式还是其他模式等问题
bridge模式:使用–network bridge指定,默认使用docker0
host模式:使用–network host指定
none模式:使用–network none指定
container模式:使用–network container:NAME或者容器ID指定
[root@vm001 admin]# docker run -it --name ub1 ubuntu bash
# 启动后, 使用 ctrl + p + q 退出,容器仍然运行
root@e46ea4e05596:/# [root@vm001 admin]#
# 启动后, 使用 ctrl + p + q 退出,容器仍然运行
[root@vm001 admin]# docker run -it --name ub2 ubuntu bash
root@67a5ade74ae2:/# [root@vm001 admin]#
[root@vm001 admin]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
67a5ade74ae2 ubuntu "bash" 7 seconds ago Up 5 seconds ub2
e46ea4e05596 ubuntu "bash" 44 seconds ago Up 43 seconds
命令:docker inspect 容器ID or 容器名字
docker inspect ub1 | tail -n 20
docker inspect ub2 | tail -n 20
关闭ub2实例,新建ub3,查看ip变化
所以: docker容器内部的ip是有可能会发生改变的
Docker 服务默认会创建一个 docker0 网桥(其上有一个 docker0 内部接口),该桥接网络的名称为docker0,它在内核层连通了其他的物理或虚拟网卡,这就将所有容器和本地主机都放到同一个物理网络。Docker 默认指定了 docker0 接口 的 IP 地址和子网掩码,让主机和容器之间可以通过网桥相互通信。
# 查看 bridge 网络的详细信息,并通过 grep 获取名称项
# docker network inspect bridge | grep name
[root@vm001 admin]# docker network inspect bridge | grep name
"com.docker.network.bridge.name": "docker0",
# ifconfig
[root@vm001 admin]# ifconfig | grep docker
docker0: flags=4163 mtu 1500
1 Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥(docker0),
Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,
称为Container-IP,同时Docker网桥是每个容器的默认网关。
因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的Container-IP直接通信。
2 docker run 的时候,没有指定network的话默认使用的网桥模式就是bridge,使用的就是docker0。
在宿主机ifconfig,就可以看到docker0和自己create的network(后面讲)eth0,eth1,eth2……代表网卡一,网卡二,网卡三……,
lo代表127.0.0.1,即localhost,inet addr用来表示网卡的IP地址
3 网桥docker0创建一对对等虚拟设备接口一个叫veth,另一个叫eth0,成对匹配。
3.1 整个宿主机的网桥模式都是docker0,类似一个交换机有一堆接口,每个接口叫veth,在本地主机和容器内分别创建一个虚拟接口,并让他们彼此联通(这样一对接口叫veth pair);
3.2 每个容器实例内部也有一块网卡,每个接口叫eth0;
3.3 docker0上面的每个veth匹配某个容器实例内部的eth0,两两配对,一一匹配。
通过上述,将宿主机上的所有容器都连接到这个内部网络上,
两个容器在同一个网络下,会从这个网关下各自拿到分配的ip,
此时两个容器的网络是互通的。
[root@vm001 admin]# docker run -d -p 8081:8080 --name tomcat81 billygoo/tomcat8-jdk8
76e19d0cdaa03641ac807e5d03abcb4424428736a116946bb21aa5d74f55ffd8
[root@vm001 admin]# docker run -d -p 8082:8080 --name tomcat82 billygoo/tomcat8-jdk8
e776f5f5c02c39042c52914a06f8e4db4c8c4e5f44211a2228cc1dc47fb46b2e
[root@vm001 admin]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e776f5f5c02c billygoo/tomcat8-jdk8 "catalina.sh run" 3 seconds ago Up 2 seconds 0.0.0.0:8082->8080/tcp, :::8082->8080/tcp tomcat82
76e19d0cdaa0 billygoo/tomcat8-jdk8 "catalina.sh run" 12 seconds ago Up 11 seconds 0.0.0.0:8081->8080/tcp, :::8081->8080/tcp tomcat81
直接使用宿主机的 IP 地址与外界进行通信,不再需要额外进行NAT 转换。
docker run -d -p 8083:8080 --network host --name tomcat83 billygoo/tomcat8-jdk8
[root@vm001 admin]# docker run -d -p 8083:8080 --network host --name tomcat83 billygoo/tomcat8-jdk8
WARNING: Published ports are discarded when using host network mode
a9fcd26d8aafbb37047b43aee7aaad6a5dfea4cc5fb6a4c7906cf3f90f2a8f8a
[root@vm001 admin]# docker ps
## 能启动,但是没有 port信息
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a9fcd26d8aaf billygoo/tomcat8-jdk8 "catalina.sh run" 47 seconds ago Up 46 seconds tomcat83
问题:
docker 启动时总是遇见标题中的警告
原因:
docker启动时指定--network=host或-net=host,如果还指定了-p映射端口,那这个时候就会有此警告,
并且通过-p设置的参数将不会起到任何作用,端口号会以主机端口号为主,重复时则递增。
解决:
解决的办法就是使用docker的其他网络模式,例如--network=bridge,这样就可以解决问题,或者直接无视。。。
[root@vm001 admin]# docker run -d --network host --name tomcat83 billygoo/tomcat8-jdk8
b037a62b81fe56471e6280ec30e11610a5675fd1495a6a8eb0ef6aaa4305e2ee
[root@vm001 admin]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b037a62b81fe billygoo/tomcat8-jdk8 "catalina.sh run" 3 seconds ago Up 3 seconds tomcat83
此时就不会有容器的配对显示了
## 查看容器实例内部, 可以看到网关和IPAddress 都是空的
[root@vm001 admin]# docker inspect tomcat83 | tail -n 20
"Networks": {
"host": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "2e4dd2180dd1aadc6d206a836e91965a6a6cea23f31d83374e006a414723d96a",
"EndpointID": "fffa8c63bb68c239f94dec596c719a26562e2ad8c24edf05ad5fa9858a99f70b",
"Gateway": "",
"IPAddress": "",
"IPPrefixLen": 0,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "",
"DriverOpts": null
}
}
}
}
]
没有设置-p的端口映射了,如何访问启动的tomcat83呢
在CentOS里面用默认的火狐浏览器访问容器内的tomcat83看到访问成功,因为此时容器的IP借用主机的,
所以容器共享宿主机网络IP,这样的好处是外部主机与容器可以直接通信。
在容器外部访问也成功
在none模式下,并不为Docker容器进行任何网络配置。
也就是说,这个Docker容器没有网卡、IP、路由等信息,只有一个lo
需要我们自己为Docker容器添加网卡、配置IP等。
结果: 禁用网络功能,只有lo标识(就是127.0.0.1表示本地回环)
Networks 为空
[root@vm001 admin]# docker run -d -p 8084:8080 --network none --name tomcat84 billygoo/tomcat8-jdk8
e137ca5aca6647b49537692c492be6d749cf7205b81d9db9196771c36025a126
[root@vm001 admin]# docker inspect tomcat84 |tail -n 20
"Networks": {
## none
"none": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "4fdddc0827933ee2d823ae0dac5ff6af1cc671d0b2790146213ae9d82290c27d",
"EndpointID": "d66ad5e927d8bf1815b944e2ea226ef80ab7f146ccb62e32e607f1a194116da8",
"Gateway": "",
"IPAddress": "",
"IPPrefixLen": 0,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "",
"DriverOpts": null
}
}
}
}
]
且容器内部只有 lo, 即localhost
[root@vm001 admin]# docker exec -it tomcat84 /bin/bash
root@e137ca5aca66:/usr/local/tomcat# ip addr
1: lo: 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
root@e137ca5aca66:/usr/local/tomcat#
container⽹络模式:
新建的容器和已经存在的一个容器共享一个网络ip配置而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。
不适合使用 tomcat进行演示:
docker run -d -p 8085:8080 --name tomcat85 billygoo/tomcat8-jdk8
docker run -d -p 8086:8080 --network container:tomcat85 --name tomcat85 billygoo/tomcat8-jdk8
因为相当于tomcat86和tomcat85公用同一个ip同一个端口,导致tomcat端口冲突
使用Alpine:
Alpine操作系统是一个面向安全的轻型 Linux发行版
docker run -it --name alpine1 alpine /bin/sh
docker run -it --network container:alpine1 --name alpine2 alpine /bin/sh
## 能够看到两个容器的 network是一样的
[root@vm001 admin]# docker exec -it alpine1 /bin/sh
/ # ip addr
1: lo: mtu 65536 qdisc noqueue state UNKNOWN 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
30: eth0@if31: mtu 1500 qdisc noqueue state UP
link/ether 02:42:ac:11:00:04 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.4/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
/ # exit
[root@vm001 admin]# docker exec -it alpine2 /bin/sh
/ # ip addr
1: lo: mtu 65536 qdisc noqueue state UNKNOWN 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
30: eth0@if31: mtu 1500 qdisc noqueue state UP
link/ether 02:42:ac:11:00:04 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.4/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
/ #
此时如果关闭 alpine1, 那么alpine2 只有lo,
30: eth0@if31消失了
/ # ip addr
1: lo: mtu 65536 qdisc noqueue state UNKNOWN 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
利用自定义网络更好地进行网络互联
docker run -d -p 8081:8080 --name tomcat81 billygoo/tomcat8-jdk8
docker run -d -p 8082:8080 --name tomcat82 billygoo/tomcat8-jdk8
上述成功启动并用docker exec进入各自容器实例内部
按照ip 互相ping对方的地址是可以的:
[root@vm001 admin]# docker exec -it tomcat81 /bin/bash
root@76e19d0cdaa0:/usr/local/tomcat# ip addr
1: lo: 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
24: eth0@if25: 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
root@76e19d0cdaa0:/usr/local/tomcat# 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.103 ms
64 bytes from 172.17.0.3: icmp_seq=2 ttl=64 time=0.083 ms
64 bytes from 172.17.0.3: icmp_seq=3 ttl=64 time=0.103 ms
[root@vm001 admin]# docker exec -it tomcat82 /bin/bash
root@e776f5f5c02c:/usr/local/tomcat# ip addr
1: lo: 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
26: eth0@if27: 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@e776f5f5c02c:/usr/local/tomcat# ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.071 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.100 ms
按照服务名ping 会出现问题:
root@76e19d0cdaa0:/usr/local/tomcat# ping tomcat82
ping: tomcat82: Name or service not known
root@e776f5f5c02c:/usr/local/tomcat# ping tomcat81
ping: tomcat81: Name or service not known
自定义桥接网络,自定义网络默认使用的是桥接网络bridge
[root@vm001 admin]# docker network ls
NETWORK ID NAME DRIVER SCOPE
60050306e695 bridge bridge local
2e4dd2180dd1 host host local
4fdddc082793 none null local
[root@vm001 admin]# docker network create cc_network
4d59aa365f0fac6313112676e313de65259ffadd31f46abf86be255440bf8e2d
[root@vm001 admin]# docker network ls
NETWORK ID NAME DRIVER SCOPE
60050306e695 bridge bridge local
4d59aa365f0f cc_network bridge local
2e4dd2180dd1 host host local
4fdddc082793 none null local
[root@vm001 admin]# docker run -d -p 8081:8080 --network cc_network --name tomcat81 billygoo/tomcat8-jdk8
4d56fd03e06047be5ac3135df7cf885c0d3c4df8340b2f1026f4da42ae459d20
[root@vm001 admin]# docker run -d -p 8082:8080 --network cc_network --name tomcat82 billygoo/tomcat8-jdk8
940da1af2795cfb22e2a39300f2740b7faf0ad805d7061c5c23218870865b858
[root@vm001 admin]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
940da1af2795 billygoo/tomcat8-jdk8 "catalina.sh run" 4 seconds ago Up 3 seconds 0.0.0.0:8082->8080/tcp, :::8082->8080/tcp tomcat82
4d56fd03e060 billygoo/tomcat8-jdk8 "catalina.sh run" 11 seconds ago Up 10 seconds 0.0.0.0:8081->8080/tcp, :::8081->8080/tcp tomcat81
[root@vm001 admin]# docker exec -it tomcat81 /bin/bash
#### 81 ping 82
root@4d56fd03e060:/usr/local/tomcat# ping tomcat82
PING tomcat82 (172.18.0.3) 56(84) bytes of data.
64 bytes from tomcat82.cc_network (172.18.0.3): icmp_seq=1 ttl=64 time=0.076 ms
64 bytes from tomcat82.cc_network (172.18.0.3): icmp_seq=2 ttl=64 time=0.110 ms
^C
--- tomcat82 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 0.076/0.093/0.110/0.017 ms
root@4d56fd03e060:/usr/local/tomcat# exit
exit
[root@vm001 admin]# docker exec -it tomcat82 /bin/bash
#### 82 ping 81
root@940da1af2795:/usr/local/tomcat# ping tomcat81
PING tomcat81 (172.18.0.2) 56(84) bytes of data.
64 bytes from tomcat81.cc_network (172.18.0.2): icmp_seq=1 ttl=64 time=0.058 ms
64 bytes from tomcat81.cc_network (172.18.0.2): icmp_seq=2 ttl=64 time=0.068 ms
^C
--- tomcat81 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.058/0.063/0.068/0.005 ms
自定义网络本身就维护好了主机名和ip的对应关系(ip和域名都能通)
自定义网络本身就维护好了主机名和ip的对应关系(ip和域名都能通)
自定义网络本身就维护好了主机名和ip的对应关系(ip和域名都能通)
从其架构和运行流程来看,Docker 是一个 C/S 模式的架构,
后端是一个松耦合架构,众多模块各司其职。
Docker 运行的基本流程为:
1 用户是使用 Docker Client 与 Docker Daemon 建立通信,并发送请求给后者。
2 Docker Daemon 作为 Docker 架构中的主体部分,首先提供 Docker Server
的功能使其可以接受 Docker Client 的请求。
3 Docker Engine 执行 Docker 内部的一系列工作,每一项工作都是以一个 Job
的形式的存在。
4 Job 的运行过程中,当需要容器镜像时,则从 Docker Registry 中下载镜像,
并通过镜像管理驱动 Graph driver将下载镜像以Graph的形式存储。
5 当需要为 Docker 创建网络环境时,通过网络管理驱动 Network driver
创建并配置 Docker 容器网络环境。
6 当需要限制 Docker 容器运行资源或执行用户指令等操作时,
则通过 Execdriver 来完成。
7 Libcontainer是一项独立的容器管理包,Network driver以及Exec driver
都是通过Libcontainer来实现具体对容器进行的操作。
Compose 是 Docker 公司推出的一个工具软件,可以管理多个 Docker 容器组成一个应用。你需要定义一个 YAML 格式的配置文件docker-compose.yml,写好多个容器之间的调用关系。然后,只要一个命令,就能同时启动/关闭这些容器
Docker-Compose是Docker官方的开源项目,负责实现对Docker容器集群的快速编排。
就跟spring的 applicationContext.xml 对bean的管理类似,docker compose实现对容器的管理编排
docker建议我们每一个容器中只运行一个服务,因为docker容器本身占用资源极少,
所以最好是将每个服务单独的分割开来但是这样我们又面临了一个问题?
如果我需要同时部署好多个服务,难道要每个服务单独写Dockerfile然后在构建镜像,
构建容器,这样累都累死了,所以docker官方给我们提供了docker-compose多服务部署
的工具
例如要实现一个Web微服务项目,除了Web服务容器本身,往往还需要再加上后端
的数据库mysql服务容器,redis服务器,注册中心eureka,甚至还包括负载均衡容
器等等。。。。。。
Compose允许用户通过一个单独的docker-compose.yml模板文件(YAML 格式)来
定义一组相关联的应用容器为一个项目(project)。
可以很容易地用一个配置文件定义一个多容器的应用,然后使用一条指令安装这个
应用的所有依赖,完成构建。Docker-Compose 解决了容器与容器之间如何管理
编排的问题。
## 官网:https://docs.docker.com/compose/compose-file/compose-file-v3/
## 官网下载地址:https://docs.docker.com/compose/install/
参考:https://docs.docker.com/compose/install/
apt-get update
apt-get install docker-compose-plugin
或者老师的笔记
yum install docker-compose-plugin
# curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
# chmod +x /usr/local/bin/docker-compose
结果:
[root@vm001 bin]# yum install docker-compose-plugin
已加载插件:fastestmirror, langpacks
Loading mirror speeds from cached hostfile
* base: mirrors.dgut.edu.cn
* extras: mirrors.dgut.edu.cn
* updates: mirrors.dgut.edu.cn
软件包 docker-compose-plugin-2.5.0-3.el7.x86_64 已安装并且是最新版本
无须任何处理
[root@vm001 admin]# docker compose version
Docker Compose version v2.5.0
[root@vm001 admin]# chmod +x /usr/local/bin/docker-compose
命令列表:
[root@vm001 bin]# docker compose --help
Usage: docker compose [OPTIONS] COMMAND
Docker Compose
Options:
--ansi string Control when to print ANSI control characters ("never"|"always"|"auto") (default "auto")
--compatibility Run compose in backward compatibility mode
--env-file string Specify an alternate environment file.
-f, --file stringArray Compose configuration files
--profile stringArray Specify a profile to enable
--project-directory string Specify an alternate working directory
(default: the path of the Compose file)
-p, --project-name string Project name
Commands:
build Build or rebuild services
convert Converts the compose file to platform's canonical format
cp Copy files/folders between a service container and the local filesystem
create Creates containers for a service.
down Stop and remove containers, networks
events Receive real time events from containers.
exec Execute a command in a running container.
images List images used by the created containers
kill Force stop service containers.
logs View output from containers
ls List running compose projects
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 containers
rm Removes stopped service containers
run Run a one-off command on a service.
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
1). 编写Dockerfile定义各个微服务应用并构建出对应的镜像文件
2). 使用 docker-compose.yml 定义一个完整业务单元,安排好整体应用中
的各个容器服务。
3). 最后,执行docker-compose up命令来启动并运行整个应用程序,
完成一键部署上线
docker-compose -h # 查看帮助
docker-compose up # 启动所有docker-compose服务
docker-compose up -d # 启动所有docker-compose服务并后台运行
docker-compose down # 停止并删除容器、网络、卷、镜像。
docker-compose exec yml里面的服务id # 进入容器实例内部 docker-compose exec docker-compose.yml文件中写的服务id /bin/bash
docker-compose ps # 展示当前docker-compose编排过的运行的所有容器
docker-compose top # 展示当前docker-compose编排过的容器进程
docker-compose logs yml里面的服务id # 查看容器输出日志
docker-compose config # 检查配置
docker-compose config -q # 检查配置,有问题才有输出
docker-compose restart # 重启服务
docker-compose start # 启动服务
docker-compose stop # 停止服务
https://blog.csdn.net/BogerPeng/article/details/124601243
create database db2021;
go
use db2021;
CREATE TABLE `t_user` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL DEFAULT '' COMMENT '用户名',
`password` varchar(50) NOT NULL DEFAULT '' COMMENT '密码',
`sex` tinyint(4) NOT NULL DEFAULT '0' COMMENT '性别 0=女 1=男 ',
`deleted` tinyint(4) unsigned NOT NULL DEFAULT '0' COMMENT '删除标志,默认0不删除,1删除',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='用户表'
UTF-8
1.8
1.8
4.12
1.2.17
1.16.18
5.1.47
1.1.16
4.1.5
1.3.0
com.google.guava
guava
23.0
org.redisson
redisson
3.13.4
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-actuator
io.springfox
springfox-swagger2
2.9.2
io.springfox
springfox-swagger-ui
2.9.2
org.springframework.boot
spring-boot-starter-data-redis
org.springframework.boot
spring-boot-starter-cache
org.apache.commons
commons-pool2
redis.clients
jedis
3.1.0
mysql
mysql-connector-java
8.0.19
com.alibaba
druid-spring-boot-starter
1.1.16
com.alibaba
druid
${druid.version}
com.baomidou
mybatis-plus-boot-starter
cn.hutool
hutool-all
5.2.3
junit
junit
${junit.version}
org.springframework.boot
spring-boot-devtools
runtime
true
org.springframework.boot
spring-boot-starter-test
test
log4j
log4j
${log4j.version}
org.projectlombok
lombok
${lombok.version}
true
javax.persistence
persistence-api
1.0.2
org.springframework.boot
spring-boot-maven-plugin
true
repackage
org.apache.maven.plugins
maven-resources-plugin
3.1.0
server:
port: 6001
# ========================alibaba.druid相关配置=====================
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://192.168.226.128:3306/db2021?useUnicode=true&characterEncoding=utf-8&useSSL=false
# jdbc:mysql://192.168.226.129:3306/seata_order?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSL=false
username: root
password: 123456
druid:
test-while-idle: false
# ========================swagger=====================
swagger2:
enabled: true
# ========================redis相关配置=====================
redis:
database: 0
host: 192.168.226.128
port: 6379 # 6381
## redis 密码在 redis.conf 文件中指定
password: 123456
lettuce:
pool:
max-active: 8
max-wait: -1ms
max-idle: 8
min-idle: 0
#cluster:
# nodes: 192.168.226.128:6381,192.168.226.128:6382,192.168.226.128:6383,192.168.226.128:6384,192.168.226.128:6385,192.168.226.128:6386
# ========================mybatis plus相关配置===================
mybatis-plus: #myBatis plus的配置文件位置
mapper-locations: classpath*:mybatis/mapper/*.xml
configuration:
map-underscore-to-camel-case: true
package com.pyh.springcloud;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.pyh.springcloud.dao")
public class DockerBootApplication {
public static void main(String[] args){
SpringApplication.run(DockerBootApplication.class, args);
}
}
RedisConfig:
package com.pyh.springcloud.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.io.Serializable;
@Configuration
@Slf4j
public class RedisConfig {
/**
* @param lettuceConnectionFactory
* @return
*
* redis序列化的工具配置类,下面这个请一定开启配置
* 127.0.0.1:6379> keys *
* 1) "ord:102" 序列化过
* 2) "\xac\xed\x00\x05t\x00\aord:102" 野生,没有序列化过
*/
@Bean
public RedisTemplate<String, Serializable> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory)
{
RedisTemplate<String,Serializable> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(lettuceConnectionFactory);
//设置key序列化方式string
redisTemplate.setKeySerializer(new StringRedisSerializer());
//设置value的序列化方式json
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
SwaggerConfig:
package com.pyh.springcloud.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.text.SimpleDateFormat;
import java.util.Date;
@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Value("${spring.swagger2.enabled}")
private Boolean enabled;
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.enable(enabled)
.select()
.apis(RequestHandlerSelectors.basePackage("com.pyh.springcloud")) //你自己的package
.paths(PathSelectors.any())
.build();
}
public ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("Docker compose example"+"\t"+new SimpleDateFormat("yyyy-MM-dd").format(new Date()))
.description("docker-compose")
.version("1.0")
.termsOfServiceUrl("https://www.xxx.com/")
.build();
}
}
MyDataSourceConfig:
package com.pyh.springcloud.config;
import com.alibaba.druid.pool.DruidDataSource;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import org.mybatis.spring.transaction.SpringManagedTransactionFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import javax.sql.DataSource;
import java.sql.SQLException;
//@Deprecated
@Configuration //引入了druid-spring-boot-starter之后,可以不需要该配置
public class MyDataSourceConfig {
@Value("${mybatis-plus.mapper-locations}")
private String mapperLocations;
// @ConfigurationProperties("spring.datasource")
@ConfigurationProperties(prefix = "spring.datasource") // 与上面相同
@Bean
public DataSource dataSource() throws SQLException {
DruidDataSource druidDataSource = new DruidDataSource();
return druidDataSource;
}
//代理mybaits-plus
@Bean
public MybatisSqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource) throws Exception {
MybatisSqlSessionFactoryBean sqlSessionFactoryBean = new MybatisSqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(mapperLocations));
sqlSessionFactoryBean.setTransactionFactory(new SpringManagedTransactionFactory());
return sqlSessionFactoryBean;
}
}
User:
package com.pyh.springcloud.beans;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import java.util.Date;
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("t_user")
public class User
{
@TableId(type = IdType.AUTO) // id 自增长
private Integer id;
/**
* 用户名
*/
private String username;
/**
* 密码
*/
private String password;
/**
* 性别 0=女 1=男
*/
private Byte sex;
/**
* 删除标志,默认0不删除,1删除
*/
private Byte deleted;
/**
* 更新时间
*/
@Column(name = "update_time")
private Date updateTime;
/**
* 创建时间
*/
@Column(name = "create_time")
private Date createTime;
/**
* @return id
*/
public Integer getId() {
return id;
}
/**
* @param id
*/
public void setId(Integer id) {
this.id = id;
}
/**
* 获取用户名
* @return username - 用户名
*/
public String getUsername() {
return username;
}
/**
* 设置用户名
* @param username 用户名
*/
public void setUsername(String username) {
this.username = username;
}
/**
* 获取密码
* @return password - 密码
*/
public String getPassword() {
return password;
}
/**
* 设置密码
* @param password 密码
*/
public void setPassword(String password) {
this.password = password;
}
/**
* 获取性别 0=女 1=男
* @return sex - 性别 0=女 1=男
*/
public Byte getSex() {
return sex;
}
/**
* 设置性别 0=女 1=男
* @param sex 性别 0=女 1=男
*/
public void setSex(Byte sex) {
this.sex = sex;
}
/**
* 获取删除标志,默认0不删除,1删除
* @return deleted - 删除标志,默认0不删除,1删除
*/
public Byte getDeleted() {
return deleted;
}
/**
* 设置删除标志,默认0不删除,1删除
* @param deleted 删除标志,默认0不删除,1删除
*/
public void setDeleted(Byte deleted) {
this.deleted = deleted;
}
/**
* 获取更新时间
* @return update_time - 更新时间
*/
public Date getUpdateTime() {
return updateTime;
}
/**
* 设置更新时间
* @param updateTime 更新时间
*/
public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime;
}
/**
* 获取创建时间
* @return create_time - 创建时间
*/
public Date getCreateTime() {
return createTime;
}
/**
* 设置创建时间
* @param createTime 创建时间
*/
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
}
UserDTO:
package com.pyh.springcloud.beans;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.Date;
@NoArgsConstructor
@AllArgsConstructor
@Data
@ApiModel(value = "用户信息")
public class UserDTO implements Serializable
{
@ApiModelProperty(value = "用户ID")
private Integer id;
@ApiModelProperty(value = "用户名")
private String username;
@ApiModelProperty(value = "密码")
private String password;
@ApiModelProperty(value = "性别 0=女 1=男 ")
private Byte sex;
@ApiModelProperty(value = "删除标志,默认0不删除,1删除")
private Byte deleted;
@ApiModelProperty(value = "更新时间")
private Date updateTime;
@ApiModelProperty(value = "创建时间")
private Date createTime;
/**
* @return id
*/
public Integer getId() {
return id;
}
/**
* @param id
*/
public void setId(Integer id) {
this.id = id;
}
/**
* 获取用户名
* @return username - 用户名
*/
public String getUsername() {
return username;
}
/**
* 设置用户名
* @param username 用户名
*/
public void setUsername(String username) {
this.username = username;
}
/**
* 获取密码
* @return password - 密码
*/
public String getPassword() {
return password;
}
/**
* 设置密码
* @param password 密码
*/
public void setPassword(String password) {
this.password = password;
}
/**
* 获取性别 0=女 1=男
* @return sex - 性别 0=女 1=男
*/
public Byte getSex() {
return sex;
}
/**
* 设置性别 0=女 1=男
* @param sex 性别 0=女 1=男
*/
public void setSex(Byte sex) {
this.sex = sex;
}
/**
* 获取删除标志,默认0不删除,1删除
* @return deleted - 删除标志,默认0不删除,1删除
*/
public Byte getDeleted() {
return deleted;
}
/**
* 设置删除标志,默认0不删除,1删除
* @param deleted 删除标志,默认0不删除,1删除
*/
public void setDeleted(Byte deleted) {
this.deleted = deleted;
}
/**
* 获取更新时间
* @return update_time - 更新时间
*/
public Date getUpdateTime() {
return updateTime;
}
/**
* 设置更新时间
* @param updateTime 更新时间
*/
public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime;
}
/**
* 获取创建时间
* @return create_time - 创建时间
*/
public Date getCreateTime() {
return createTime;
}
/**
* 设置创建时间
* @param createTime 创建时间
*/
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", sex=" + sex +
'}';
}
}
Mapper:
package com.pyh.springcloud.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.pyh.springcloud.beans.User;
import org.apache.ibatis.annotations.Mapper;
/**
* mybatis plus中,继承BaseMapper,就可以拥有基础的CRUD方法
*/
@Mapper
public interface UserDao extends BaseMapper<User> {
}
UserMapper.xml:
路径:src/main/resources/mybatis/mapper/UserMapper.xml
DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.pyh.springcloud.dao.UserDao">
<resultMap id="BaseResultMap" type="com.pyh.springcloud.beans.User">
<id column="id" jdbcType="INTEGER" property="id" />
<result column="username" jdbcType="VARCHAR" property="username" />
<result column="password" jdbcType="VARCHAR" property="password" />
<result column="sex" jdbcType="TINYINT" property="sex" />
<result column="deleted" jdbcType="TINYINT" property="deleted" />
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
<result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
resultMap>
mapper>
UserService:
package com.pyh.springcloud.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.pyh.springcloud.beans.User;
public interface UserService extends IService<User> {
void addUser(User user);
User findUserById(Integer id);
int updateUser(User user);
void deleteUser(Integer id);
}
UserServiceImpl:
package com.pyh.springcloud.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pyh.springcloud.beans.User;
import com.pyh.springcloud.dao.UserDao;
import com.pyh.springcloud.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserDao, User> implements UserService {
public static final String CACHE_KEY_USER = "user:";
@Resource
private UserDao userMapper;
@Resource
private RedisTemplate redisTemplate;
/**
* addUser
* @param user
*/
public void addUser(User user)
{
//1 先插入mysql并成功
int i = userMapper.insert(user);
if(i > 0)
{
//2 需要再次查询一下mysql将数据捞回来并ok
user = userMapper.selectById(user.getId());
//3 将捞出来的user存进redis,完成新增功能的数据一致性。
String key = CACHE_KEY_USER+user.getId();
redisTemplate.opsForValue().set(key,user);
}
}
/**
* findUserById
* @param id
* @return
*/
public User findUserById(Integer id)
{
User user = null;
String key = CACHE_KEY_USER+id;
//1 先从redis里面查询,如果有直接返回结果,如果没有再去查询mysql
user = (User) redisTemplate.opsForValue().get(key);
if(user == null)
{
//2 redis里面无,继续查询mysql
user = userMapper.selectById(id);
if(user == null)
{
//3.1 redis+mysql 都无数据
//具体细化,防止多次穿透,我们规定,记录下导致穿透的这个key回写redis
return user;
}else{
//3.2 mysql有,需要将数据写回redis,保证下一次的缓存命中率
redisTemplate.opsForValue().set(key,user);
}
}
return user;
}
public int updateUser(User user){
return userMapper.updateById(user);
}
public void deleteUser(Integer id){
userMapper.deleteById(id);
}
}
package com.pyh.springcloud.controller;
import cn.hutool.core.util.IdUtil;
import com.pyh.springcloud.beans.User;
import com.pyh.springcloud.beans.UserDTO;
import com.pyh.springcloud.service.UserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.Random;
@Api("用户User接口")
@RestController
@Slf4j
public class UserController {
@Resource
private UserService userService;
@ApiOperation("数据库新增3条记录")
@RequestMapping(value = "/user/add",method = RequestMethod.POST)
public void addUser()
{
for (int i = 1; i <=3; i++) {
User user = new User();
user.setUsername("pyh"+i);
user.setPassword(IdUtil.simpleUUID().substring(0,6));
user.setSex((byte) new Random().nextInt(2));
userService.addUser(user);
}
}
@ApiOperation("删除1条记录")
@RequestMapping(value = "/user/delete/{id}",method = RequestMethod.POST)
public void deleteUser(@PathVariable Integer id)
{
userService.deleteUser(id);
}
@ApiOperation("修改1条记录")
@RequestMapping(value = "/user/update",method = RequestMethod.POST)
public void updateUser(@RequestBody UserDTO userDTO)
{
User user = new User();
BeanUtils.copyProperties(userDTO,user);
userService.updateUser(user);
}
@ApiOperation("查询1条记录")
@RequestMapping(value = "/user/find/{id}",method = RequestMethod.GET)
public User findUserById(@PathVariable Integer id)
{
return userService.findUserById(id);
}
}
postman add user:
数据库:
浏览器 find user:
post man delete user:
URL: http://localhost:6001/swagger-ui.html
能够成功调用接口
服务编排,一套即可完成
version: "3"
services:
microService:
image: orderservice6001:v1.2
container_name: ms01
ports:
- "6001:6001"
volumes:
- /app/microService:/data
networks:
- cc_network
depends_on:
- redis
- mysql
redis:
# 不带版本号表示最新版本, 如果带版本号也要写上,如 redis:6.0.8
image: redis
ports:
- "6379:6379"
volumes:
- /app/redis/redis.conf:/etc/redis/redis.conf
- /app/redis/data:/data
networks:
- cc_network
command: redis-server /etc/redis/redis.conf
mysql:
image: mysql:8.0.27
environment:
MYSQL_ROOT_PASSWORD: '123456'
MYSQL_ALLOW_EMPTY_PASSWORD: 'no'
MYSQL_DATABASE: 'db2021'
MYSQL_USER: 'pyh'
MYSQL_PASSWORD: 'pyh123'
ports:
- "3306:3306"
volumes:
- /app/mysql/db:/var/lib/mysql
- /app/mysql/conf/my.cnf:/etc/my.cnf
- /app/mysql/init:/docker-entrypoint-initdb.d
networks:
- cc_network
command: --default-authentication-plugin=mysql_native_password #解决外部无法访问
networks:
cc_network:
通过服务名访问,与IP无关
服务名由docker-compose.yaml 文件指定
spring:
datasource:
## url: jdbc:mysql://192.168.226.128:3306/db2021?useUnicode=true&characterEncoding=utf-8&useSSL=false
url: jdbc:mysql://mysql:3306/db2021?useUnicode=true&characterEncoding=utf-8&useSSL=false
redis:
## host: 192.168.226.128
host: redis
参照 docker 进阶三笔记的 4.2 小节,build jar包:
URL: https://blog.csdn.net/BogerPeng/article/details/124601243
## 上传到linux宿主机的相同目录下
[root@vm001 dockertest20220516]# pwd
/dockerfiles/dockertest20220516
[root@vm001 dockertest20220516]# ll
总用量 57172
-rw-r--r--. 1 root root 58534184 5月 16 17:29 docker-boot-1.0-SNAPSHOT.jar
-rw-r--r--. 1 root root 1173 5月 16 17:06 docker-compose.yaml
-rw-r--r--. 1 root root 478 5月 16 15:12 Dockerfile
[root@vm001 dockertest20220516]# docker build -t orderservice6001:v1.2 .
Sending build context to Docker daemon 58.54MB
Step 1/7 : FROM java:8
---> d23bdf5b1b1b
######## 其他日志略--省点文章长度
Step 7/7 : EXPOSE 6001
---> Running in 224851e72012
Removing intermediate container 224851e72012
---> 9b85c31bb9e7
Successfully built 9b85c31bb9e7
Successfully tagged orderservice6001:v1.2
[root@vm001 dockertest20220516]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
orderservice6001 v1.2 9b85c31bb9e7 4 seconds ago 760MB
docker compose up 或者
docker compose up -d (后台运行)
[root@vm001 dockertest20220516]# docker compose up -d
[+] Running 4/4
⠿ Network dockertest20220516_cc_network Created 0.4s
⠿ Container dockertest20220516-mysql-1 Started 0.8s
⠿ Container dockertest20220516-redis-1 Started 0.8s
⠿ Container ms01 Started
[root@vm001 dockertest20220516]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a5a13d9bbe2c orderservice6001:v1.2 "java -jar /OrderSer…" 19 minutes ago Up 19 minutes 0.0.0.0:6001->6001/tcp, :::6001->6001/tcp ms01
466cfff873c6 mysql:8.0.27 "docker-entrypoint.s…" 19 minutes ago Up 19 minutes 0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp dockertest20220516-mysql-1
e12df8432b99 redis "docker-entrypoint.s…" 19 minutes ago Up 19 minutes 0.0.0.0:6379->6379/tcp, :::6379->6379/tcp dockertest20220516-redis-1
参考 5.7.1.2
Compose常用命令
docker-compose -h # 查看帮助
docker-compose up # 启动所有docker-compose服务
docker-compose up -d # 启动所有docker-compose服务并后台运行
docker-compose down # 停止并删除容器、网络、卷、镜像。
docker-compose exec yml里面的服务id # 进入容器实例内部 docker-compose exec docker-compose.yml文件中写的服务id /bin/bash
docker-compose ps # 展示当前docker-compose编排过的运行的所有容器
docker-compose top # 展示当前docker-compose编排过的容器进程
docker-compose logs yml里面的服务id # 查看容器输出日志
dokcer-compose config # 检查配置
dokcer-compose config -q # 检查配置,有问题才有输出
docker-compose restart # 重启服务
docker-compose start # 启动服务
docker-compose stop # 停止服务
docker compose down
[root@vm001 dockertest20220516]# docker compose down
[+] Running 4/4
⠿ Container ms01 Removed 0.5s
⠿ Container dockertest20220516-redis-1 Removed 0.3s
⠿ Container dockertest20220516-mysql-1 Removed 3.5s
⠿ Network dockertest20220516_cc_network Removed 0.3s
[root@vm001 dockertest20220516]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
## 没有运行中的实例