【Docer篇整理】
=========================
篇一:docker核心概念与常用指令
篇二:镜像与docker数据卷
篇三:dockerfile
篇四:docker网络
Veth是Linux中一种虚拟出来的网络设备,veth设备总是成对出现,所以一般也叫veth-pair。veth模拟了在物理世界里的两块网卡,以及一条网线。通过它可以将两个虚拟的设备连接起来,让他们之间相互通信。
如:v-a和v-b是一对veth设备,v-a收到的数据会从v-b发出。相反,v-b收到的数据会从v-a发出。Veth就像一根网线。
Veth设备的特点:
# 查询ip地址
ip addr
查询宿主机IP地址,可以看到这三个IP:
在宿主机启动一个容器:发现容器启动的时候得到一个eth0@if115 ip地址,这是docker分配的
[root@9527 ~] docker run -d -P --name tomcat01 tomcat
# 查看容器内部的网络地址 ip addr
# 不用进入容器执行,就一句,直接跟后面
[root@9527 ~] docker exec -it tomcat01 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
114: eth0@if115: <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
思考: linux 宿主机能不能ping通这个容器?
[root@9527 ~] 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.077 ms
...
==>linux 可以 ping 通docker容器内部!
原理:
上面容器启动后,ip addr 查看宿主机:发现多了一个网卡vethcf5ccc0,115和114刚好与容器中的114: eth0@if115相对应:
再启动一个容器测试, ip addr 查看宿主机发现又多了一对网卡:
docker run -d -P --name tomcat02 tomcat
这种容器带来的网卡,都是一对一对的,这就是evth-pair技术。
# 我们发现这个容器带来网卡,都是一对对的
# veth-pair 就是一对的虚拟设备接口,他们都是成对出现的,一端连着协议,一端彼此相连
# 正因为有这个特性,veth-pair充当一个桥梁, 连接各种虚拟网络设备
# OpenStac, Docker容器之间的链接,OVS的链接, 都是使用veth-pair技术
测试tomcat01和tomcat02之间是否可以ping通:
docker exec -it tomcat02 ping 172.17.0.2
发现容器和容器之间是可以ping通的,网络模型图如下:
结论:
tomcat01和tomcat02是共用的一个路由器,docker0
所有容器不指定网络的情况下,都是docker0路由的,doucker会给我们的容器分配一个默认的可用IP
这个可用IP的数量:
以255.255.0.1/16为例
00000000.00000000.00000000.00000000 (二进制下)
转十进制则为255.255.255.255
16即二进制下的前16位,即255.255.下是一个网络
===>
可用IP有255 x 255 - 1 - 1 = 655355
第一个1即0.0
第二个1即255.255
---
255.255.0.1/24 即只有最后的一位,255个IP是在这个网络范围的
Docker使用的是Linux的桥接,宿主机中是一个Docker容器的网桥docker0
Docker中的所有的网络接口都是虚拟的,因为虚拟的转发效率高(参考内网传递文件!)
[root@9527 ~] docker exec -it tomcat02 ping tomcat01
ping: tomcat01: Name or service not known
ping IP可以通,ping 容器名却不通,想实现通过容器名来互相访问,可以使用- -link
[root@9527 ~] docker run -d -P --name tomcat03 --link tomcat02 tomcat
3a2bcaba804c5980d94d168457c436fbd139820be2ee77246888f1744e6bb473
[root@9527 ~] docker exec -it tomcat03 ping tomcat02
PING tomcat02 (172.17.0.3) 56(84) bytes of data.
64 bytes from tomcat02 (172.17.0.3): icmp_seq=1 ttl=64 time=0.129 ms
64 bytes from tomcat02 (172.17.0.3): icmp_seq=2 ttl=64 time=0.100 ms
...
反向可以ping通吗?----不能
[root@iZ2zeg4ytp0whqtmxbsqiiZ ~] docker exec -it tomcat02 ping tomcat03
ping: tomcat03: Name or service not known
原因探究:
继续往下看inspect信息:看到docker为每个容器分配的IP地址
这个tomcat03能ping通tomcat02就是–link时在03本地hosts文件配置了tomcat02的IP和名字
[root@9527 ~] docker exec -it tomcat03 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 tomcat02 f22ed47ed1be ## !!!
172.17.0.4 3a2bcaba804c
现在已经不建议使用–link了,往下看自定义网络
查看所有的docker网络
docker network ls
网络模式
bridge: 桥接模式,docker 默认的模式,自己创建的也是用brdge模式
none: 不配置网络
host: 主机模式,即和宿主机共享网络
container:容器网络连通(用的少,局限很大)
# 直接启动的命令默认有一个 --net bridge,而这个就是我们的docker0
docker run -d -P --name tomcat01 tomcat
# 等价于
docker run -d -P --name tomcat01 --net bridge tomcat
docker0特点,默认,容器名不能访问(加 --link可以打通连接,但不建议),基于这个情况,考虑使用自定义网络:
自定义网络
# --driver bridge
# --subnet 192.168.0.0/16 可以支持255*255个网络 192.168.0.2 ~ 192.168.255.254
# --gateway 192.168.0.1
[root@9527 ~] docker network create --driver bridge
--subnet 192.168.0.0/16
--gateway 192.168.0.1 mynet
26a5afdf4805d7ee0a660b82244929a4226470d99a179355558dca35a2b983ec
[root@9527 ~] docker network ls
NETWORK ID NAME DRIVER SCOPE
30d601788862 bridge bridge local
226019b14d91 host host local
26a5afdf4805 mynet bridge local
7496c014f74b none null local
创建成功,查看这个自定义网络的信息:
docker network inspect mynet
[root@9527 ~] docker run -d -P --name tomcat-net-01 --net mynet tomcat
[root@9527 ~] docker run -d -P --name tomcat-net-02 --net mynet tomcat
# ping IP连接和bridge网络下一样
[root@9527~] docker exec -it tomcat-net-01 ping 192.168.0.3
PING 192.168.0.3 (192.168.0.3) 56(84) bytes of data.
....
# 现在不使用 --link,直接可以ping名字
[root@9527~] docker exec -it tomcat-net-01 ping tomcat-net-02
PING tomcat-net-02 (192.168.0.3) 56(84) bytes of data.
...
我们自定义的网络docker都已经帮我们维护好了对应的关系,推荐我们平时这样使用网络。
如此,不同的集群使用不同的网络,保证了集群是安全和健康的。如下图中的redis集群和mysql集群:
两个不同网络下的集群如何连通,看下面。
基于这个指令,测试在docker0和我自定义网络下的两个容器之间的连通:
[root@9527 ~] docker network connect mynet tomcat01
连通之后就是将tomcat01 放到了mynet网络下,简单讲就是一个容器两个ip地址 ,类比阿里云服务器,公网ip,私网ip
[root@9527 ~] docker network inspect mynet
# 查看下mynet网络的变化
# 看到tomcat01直接加入了mynet网络,拥有第二个IP
# 连通ok
[root@9527 ~] docker exec -it tomcat01 ping tomcat-net-01
PING tomcat-net-01 (192.168.0.2) 56(84) bytes of data.
....
# 换tomcat02依旧无法连通,没有connect
[root@iZ2zeg4ytp0whqtmxbsqiiZ ~] docker exec -it tomcat02 ping tomcat-net-01
ping: tomcat-net-01: Name or service not known
结论:假设要跨网络 操作别的容器,就要使用docker network connect连通…!
实验选定 三主三从 的结构,启动六个容器:
docker network create redis --subnet 172.38.0.0/16
接下来使用脚本直接创建六个Redis的配置:
# 通过脚本创建六个redis配置
for port in $(seq 1 6); \
do \
mkdir -p /mydata/redis/node-${port}/conf
touch /mydata/redis/node-${port}/conf/redis.conf
cat << EOF >/mydata/redis/node-${port}/conf/redis.conf
port 6379
bind 0.0.0.0
cluster-enabled yes # 开启集群模式
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-ip 172.38.0.1${port}
cluster-announce-port 6379
cluster-announce-bus-port 16379
appendonly yes
EOF
done
[root@9527 ~] ls /mydata/redis/
node-1 node-2 node-3 node-4 node-5 node-6
启动容器:
# 创建结点1
docker run -p 6371:6379 -p 16371:16379 --name redis-1 \
-v /mydata/redis/node-1/data:/data \
-v /mydata/redis/node-1/conf/redis.conf:/etc/redis/redis.conf \
-d
--net redis
--ip 172.38.0.11
redis:5.0.9-alpine3.11
redis-server /etc/redis/redis.conf
#创建结点2
docker run -p 6372:6379 -p 16372:16379 --name redis-2 \
-v /mydata/redis/node-2/data:/data \
-v /mydata/redis/node-2/conf/redis.conf:/etc/redis/redis.conf \
-d
--net redis
--ip 172.38.0.12
redis:5.0.9-alpine3.11
redis-server /etc/redis/redis.conf
....
3、4、5、6的创建指令一样,改下端口和配置文件、映射目录就行
docker ps 可以看到六个容器启动成功(这里也感受到了容器的轻量级,起六个也没啥)
创建Redis集群:
[root@9527 ~] docker exec -it redis-1 /bin/sh
/data : ls
appendonly.aof nodes.conf
/data : redis-cli --cluster create 172.38.0.11:6379 172.38.0.12:6379 172.38.0.13:6379 172.38.0.14:6379 172.38.0.15:6379 172.38.0.16:6379 --cluster-replicas 1
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
.....
[root@9527 ~] docker exec -it redis-1 /bin/sh
/data : redis-cli - c # 注意加-c,即cluster
127.0.0.1:6379> cluster info
127.0.0.1:6379> cluster nodes
set一个值存入Redis:
127.0.0.1:6379> set a b
-> Redirected to slot located at 172.38.0.13:6379
OK
可以看到是13这台master处理了,此时停掉13,即redis-3容器
[root@9527 ~] docker stop redis-3
模拟主节点挂了以后,此时再get刚存入的值,观察是否从机生效(选举):
127.0.0.1:6379> get a
-> Redirected to slot located at 172.38.0.14:6379
"b"
可以看到14做为13的从机,查数据仍然没问题!!
13failed,14成为master,集群部署成功!
基本步骤是:
创建一个测试demo工程:
并新建一个controller
@RestController
public class HelloController{
@GetMapping("/hello")
public String hello(){
return "hello,9527";
}
}
maven中的package打包:
本地测试jar包可正常启动,且能访问localhost:8080/hello
下载完成后可连接远程仓库:
编写Dockerfile文件
这里先不CI/CD,直接把jar包和Dockerfile文件放到Linux宿主机,执行docker build
[root@9527 ~] mkdir idea
[root@9527 ~] cd idea
[root@9527 idea] docker build -t code9527 .
镜像构建成功后,启动容器:
[root@9527 idea] docker -d -P --name springboot-web code9527
# 启动成功后,docker ps看到随机映射端口是32779
[root@9527 idea] curl localhost:32779/test
hello,9527
[root@9527 idea]
成功!
以后,交付的时候,交付一个镜像即可。部署时docker pull ,运行容器即可!当然实际开发需要CI/CD和K8s对大量容器进行编排。
【Docker篇整理结束 2023/5/6 00:12】