如今Docker的使用已经非常普遍,特别在一线互联网公司。使用Docker技术可以帮助企业快速水平扩展服务,从而到达弹性部署业务的能力。在云服务概念兴起之后,Docker的使用场景和范围进一步发展。今天,就让我们来看看关于Docker的深度问答。
Q:vethxxxx 这种虚拟网卡和容器的对应关系从哪里看?
A:
使用如下命令:
$ docker network ls
注意这里的 br-56f04389b8f0 以及 br-094fcb269385,br- 后面的是上面的网络id,由此可以看出 veth 和 Docker 网络的对应关系,而容器都是连接到了某个Docker网络上的,从而就有了容器和 veth 的对应关系。对于某个网络出现了多个veth 的情况,可以观察veth22996d2@if11 后面的 if11 这部分,和容器内的 ip addr 的结果,一般奇-偶是一对。
Q:如何让一个容器连接两个网络?
A:
如果是使用 docker run,那很不幸,一次只可以连接一个网络,因为 docker run 的 --network 参数只可以出现一次(如果出现多次,最后的会覆盖之前的)。不过容器运行后,可以用命令 docker network connect 连接多个网络。假设我们创建了两个网络:
Q:Docker 多宿主网络怎么配置
A:
Docker 跨节点容器网络互联,最通用的是使用 overlay 网络。
一代 Swarm 已经不再使用,它要求使用 overlay 网络前先准备好分布式键值库,比如 etcd, consul 或 zookeeper。然后在每个节点的 Docker 引擎中,配置 --cluster-store 和 --cluster-advertise 参数。这样才可以互连。可以参考我写的 LNMP 容器互联例子中的 run1.sh 这个脚本,这个脚本是利用 docker-machine自动建立 Swarm 并且配置好 overlay 的脚本,可以分析其流程。
现在都在使用二代 Swarm,也就是 Docker Swarm Mode,非常简单,只要 docker swarm init 建立集群,其它节点 docker swarm join 加入集群后,集群内的服务就自动建立了 overlay 网络互联能力。
需要注意的是,如果是多网卡环境,无论是 docker swarm init 还是 docker swarm join,都不要忘记使用参数 --advertise-addr 指定宣告地址,否则自动选择的地址很可能不是你期望的,从而导致集群互联失败。格式为 --advertise-addr <地址>:<端口>,地址可以是 IP 地址,也可以是网卡接口,比如 eth0。端口默认为 2377,如果不改动可以忽略。
此外,这是供服务使用的 overlay,因此所有 docker service create 的服务容器可以使用该网络,而 docker run 不可以使用该网络,除非明确该网络为 --attachable。
Q:明明 docker network ls 中看到了建立的 overlay 网络,怎么docker run 还说网络不存在啊?
A:
如果在 docker network ls 中看到了如下的 overlay 网络:
报错说mynet 网络找不到。其实如果仔细观察,会看到这个名为mynet 的网络,驱动是 overlay没有错,但它的Scope 是swarm。这个意思是说这个网络是在二代Swarm环境中建立的overlay网络,因此只可以由Swarm环境下的服务容器才可以使用。而docker run所运行的只是零散的容器,并非Service,因此自然在零散容器所能使用的网络中,不存在叫mynet网络。
docker run可以使用的overlay网络是Scope为global的overlay网络,也就是使用外置键值库所建立的overlay网络,比如一代Swarm的overlay网络。这点在 1.13 后稍有变化。如果是 1.13 以后的系统,会看到这样的信息:
Q:容器怎么取宿主机 IP 啊?
A:单机环境
如果是单机环境,很简单,不必琢磨怎么突破命名空间限制,直接用环境变量送进去即可。
然后容器内直接读取 HOST_IP 环境变量即可。
集群环境相对比较复杂,docker service create 中的 -e 以及 --env-file是在服务创建时指定、读取环境变量内容,而不是运行时,因此对于每个节点都是一样的。而且目前不存在 dockerd -e 选项,所以直接使用这些选项达不到我们想要的效果。不过有变通的办法,可以在宿主上建立一个 /etc/variables 文件(名字随意,这里用这个文件举例)。其内容为:
其中 1.2.3.4 是这个节点的宿主 IP,因此每个节点的 /etc/variables 的内容不同。
而在启动服务时,指定挂载这个服务端本地文件:
docker service create --name app \
--mount type=bind,source=/etc/variables,target=/etc/variables:ro \
myapp
由于 --mount 是发生于容器运行时,因此所加载的是所运行的服务器的 /etc/variables,里面所包含的也是该服务器的 IP 地址。在 myapp 这个镜像的入口脚本加入加载该环境变量文件的命令:
这样app这个服务容器就会拥有 HOST_IP 环境变量,其值为所运行的宿主 IP。
小伙伴们冲鸭,后台留言区等着你!
关于Docker,今天你学到了什么?还有哪些不懂的?除此还对哪些话题感兴趣?
快来留言区打卡啦!留言方式:打开第XX天,答:……
同时欢迎大家搜集更多问题,投稿给我们!
风里雨里留言区里等你~
1、
扫描添加小编微信,备注“
姓名+公司职位
”,加入【
云计算学习交流群
】,和志同道合的朋友们共同打卡学习!
2、
公众号后台回复:
白皮书
,获取
IDC最新数据白皮书
整理资料!
推荐阅读:
喜欢就点击“好看”吧
理解
Docker
网络
(
Docker
0)
我们每启动
一个
docker
容器
,
docker
就会给
docker
容器
分配
一个
ip
,我们只要安装了
docker
,就会有
一个
网卡
docker
0,用的是桥接模式,使用的技术是evth-pair技术。
evth-pair 就是一对的虚拟设备接口,他们都是成对出现的,一端连着协议,一端彼此相连,实现通信。正因为有这个特性,evth-pair 充当
一个
桥梁,
连接
各种虚拟
网络
设备
如下图:
容器
1和
容器
2是共用的
一个
路由器
docker
0,所有的
容器
在不指定
网络
的情况下,都是dock
你也许已经知道了,
Docker
容器
技术是现有的成熟虚拟化技术的
一个
替代方案。它被企业应用在越来越多的领域中,比如快速部署环境、简化基础设施的配置流程、多客户环境间的互相隔离等等。当你开始在真实的生产环境使用
Docker
容器
去部署应用沙箱时,你可能需要用到多个
容器
部署一套复杂的多层应用系统,其中每个
容器
负责
一个
特定的功能(例如负载均衡、LAMP 栈、数据库、UI 等)。
那么问题来了:有多台
ip
link add br0 type bridge #
ip
link delete br0
ip
link set br0 up #
ip
link set br0 down
ip
link set eth0 master br0 #
ip
link set eth0 nomaster
overlay
网络
驱动程序在多个
Docker
守护进程主机之间创建
一个
分布式
网络
。这个
网络
在允许
容器
连接
并进行安全通信的主机专用
网络
之上(overlay 覆盖在上面)。
Docker
透明地处理每个
Docker
守护进程与目标
容器
之间的数据包的路由。
当初始化 swarm 集群或将
一个
Docker
主机加入已经存在的 swarm 集群时,
Docker
主机上会创建
两个
新
网络
: ...
[root@iZ2ze4zc54bfy36wjglfqsZ /]#
docker
network ls
NETWORK ID NAME DRIVER SCOPE
bac2fa49ec66 bridge bridge local
064163...
2.通过命令排查
docker
inspect b5be1d9e71de
"Error": "Could not attach to network fabric-tbc20200721: rpc error: code = PermissionDenied desc = network fabric-tbc20200721 not manually attachable",
3.原因分析
fabric- 是使用命令 dock.
### 如何使
一个
Docker
容器
连接
到另
一个
容器
中的 MySQL 数据库
为了实现
两个
Docker
容器
之间的通信,特别是当目标是从
一个
应用
容器
连接
至另一
容器
内的 MySQL 数据库时,有几种方法可供采用。
#### 利用自定义桥接
网络
推荐的方式是利用
Docker
的用户定义桥接
网络
。这种方式允许不同
容器
间通过服务名称互相发现并建立
连接
,而无需依赖于
IP
地址或端口映射。创建
一个
新的桥接
网络
,并确保应用程序
容器
和 MySQL
容器
都加入此同一
网络
[^1]。
```bash
docker
network create mynetwork
启动 MySQL
容器
时指定新创建的
网络
:
```bash
docker
run -d --network=mynetwork \
-e MYSQL_ROOT_PASSWORD=my-secret-pw mysql:tag
接着,在启动其他需要访问 MySQL 的应用
容器
时同样指明相同的
网络
名以及设置环境变量来配置数据库
连接
参数:
```bash
docker
run -d --name=app-container --network=mynetwork \
-e DB_HOST=mysql-container \
-e DB_USER=root \
-e DB_PASS=my-secret-pw \
my-app-image
这里 `DB_HOST` 被设为 `mysql-container`,即 MySQL
容器
的名字;这使得应用能够解析出正确的主机地址用于建立 TCP/
IP
连接
[^2]。
#### 使用链接特性(已弃用)
虽然旧版本中可以通过 `--link` 参数直接关联
两个
容器
,但这已被官方标记为过时的功能,建议优先考虑上述基于
网络
的方法。
#### 处理常见错误
有时可能会遇到类似于 `pymysql.err.OperationalError: (2003, "Can't connect to MySQL server on 'localhost'")` 错误消息的情况。这类问题通常是因为尝试使用 `'localhost'` 或者 `127.0.0.1` 来作为数据库服务器的位置所致——这些指向的是调用者的 localhost 接口而不是远程的服务实例。因此应当始终依据实际部署情况调整相应的配置文件或是命令行选项以匹配真实的主机位置[^3]。