问题描述
想要为Docker容器(Unifi Controller实例)分配一个固定的IP地址。他从Docker Hub上获取了unifi controller的镜像,并将其运行在Synology Docker主机上。如果将容器连接到主机的网络(而不是默认的桥接网络),unifi控制器的容器可以正常运行。然而,这会阻塞他未来需要的其他服务的多个端口。因此,他希望能够为unifi容器分配一个独立的IP地址(192.168.2.2),而不是更改所有端口。
用户在Synology Docker GUI中创建了自己的网络(子网为192.168.2.0/23,网关为192.168.2.1),并将其分配给了一个新的unifi-controller容器实例。GUI建议将主机端口与容器端口映射为“auto”,这让他觉得自己并没有完全理解Docker的网络概念。因为如果他能够设置一个独立的IP,为什么还需要映射主机端口(到容器端口)呢?
解决方案
请注意以下操作注意版本差异及修改前做好备份。
方案1
通过创建macvlan来为容器分配固定IP地址。这将创建一个虚拟适配器,允许它从定义的子网中租用一个IP地址。
1) 激活混杂模式
在网络中启用混杂模式以创建虚拟适配器。对于Unifi控制器,通过SSH连接到网关并设置:
ifconfig [interface] promisc
有些网络网关/控制器默认已经设置了混杂模式。在浪费时间之前,先进行第2步。
2) 创建macvlan
然后可以创建macvlan:
docker network create -d macvlan \
--subnet=192.168.2.0/23 \
--ip-range=192.168.2.5/25 \
--gateway=192.168.2.1 \
--aux-address="my-router=192.168.2.10" \
-o parent=eth0 unifinet
- 使用
--ip-range
来限制可租用的IP范围。 - 使用
--aux-address
标记Synology主机,确保它不会争夺该IP地址(在unifi控制器的DHCP服务中已将其标记为固定IP)。 -o parent
是要附加macvlan的网络接口,例如unifinet
。
使用docker network ls
命令检查macvlan是否已正确创建:
NETWORK ID NAME DRIVER SCOPE
c49094a4c914 bridge bridge local
b2315de1aa7e host host local
c124eda0f9d2 none null local
a60da50f0d12 unifinet macvlan local
3) 启动Docker容器
在定义镜像(--name UnifiController jacobalberty/unifi
)时,将刚创建的macvlan(--network unifinet
)分配给容器(UnifiController)。它将从Docker Hub获取最新的镜像或最新的Unifi Controller版本。
docker run -dit --network unifinet --name UnifiController jacobalberty/unifi
在JSON配置的容器部分验证容器是否已分配到网络中:
sudo docker network inspect unifinet.
[
{
"Name": "unifinet",
"Id": "a60da50f0d1229d1a3c76210141e0c81567c17daf6c2b49d4f1c83d5ec9f02b3",
"Created": "2019-10-04T14:39:37.377311991+02:00",
"Scope": "local",
"Driver": "macvlan",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "192.168.2.0/24",
"Gateway": "192.168.2.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"b819bf1d6f3af459825a1a7b58f9a44e15e6e09489e7bf50653ed8e1e176fd73": {
"Name": "UnifiController",
"EndpointID": "41a048034ad63e48b46b58aed65661c9eaa2bf6937d3eebacefde4478ad26cce",
"MacAddress": "02:42:c0:a8:02:02",
"IPv4Address": "192.168.2.2/24",
"IPv6Address": ""
}
},
"Options": {
"parent": "eth0"
},
"Labels": {}
}
]
IP地址192.168.2.2已分配给容器。容器正常稳定运行。
方案2
当容器由Kubernetes启动时,是否可行?
– @LLlAMnYP 如果你保持macvlan并将其分配给容器,我认为是可行的。我敢打赌它会起作用。但这只是一个假设。请告诉我们结果。
– 好吧,我本来想问的问题更像是“如何在实践中做到这一点”。互联网上通常会模糊回答“使用macvlan cni驱动程序”,但我还没有找到一个合适的详细描述。
– @LLlAMnYP 我明白你的意思。我会在工作中检查一下。我相信迟早会遇到这个问题,然后我会记录下来。因为我坚信为每个服务分配一个IP地址是一种合理的决策。这比仅共享一个IP和端口上的服务更加促进服务的解耦和隔离。当然,这个决策取决于你的网络设置(可用IP地址)、服务数量等因素。
结论
通过创建macvlan,可以为Docker容器分配与主机IP不同的固定IP地址。首先,需要在网络中启用混杂模式,然后创建macvlan。最后,将macvlan分配给容器并启动容器。这样,容器将被分配一个独立的IP地址,并且可以正常工作。
请注意,如果容器由Kubernetes启动,也可以尝试使用macvlan来分配固定IP地址,但需要确保macvlan保持活动状态并将其分配给容器。