如何为Docker容器分配与主机IP不同的IP地址

123次阅读
没有评论

问题描述

想要为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保持活动状态并将其分配给容器。

正文完