[Docker]Docker1.9后的network

..

声明:

本博客欢迎转发,但请保留原作者信息!

博客地址:http://blog.csdn.net/halcyonbaby

新浪微博:@寻觅神迹

内容系本人学习、研究和总结,如有雷同,实属荣幸!


Docker1.9后的network

介绍与使用

1.9之后,在Docker中network从实验特性转为正式特性发布。

从命令行可以看到新增如下命令:

[[email protected] system]# docker help network

Usage:  docker network [OPTIONS] COMMAND [OPTIONS]

Commands:
  create                   Create a network
  connect                  Connect container to a network
  disconnect               Disconnect container from a network
  inspect                  Display detailed network information
  ls                       List all networks
  rm                       Remove a network

Run ‘docker network COMMAND --help‘ for more information on a command.

  --help=false       Print usage

可以看到Docker daemon启动后默认创建了3个网络:

分别使用了bridge、null、host三种内置network driver。

[[email protected] system]# docker network ls
NETWORK ID          NAME                DRIVER
f280d6a13422        bridge              bridge
f5d11bed22a2        none                null
18642f53648f        host                host

我们来仔细看下三个网络的详细信息:

Name是network的名字,用户可以随意定义。

Id是network内部的uuid,全局唯一。

Scope目前有两个值“local”、“remote”,表示是本机网络还是多机网络。

Driver是指network driver的名字。

IPAM是负责IP管理发放的driver名字与配置信息(我们在bridge网络中可以看到该信息)。

Container内记录了使用这个网络的容器的信息。

Options内记录了driver所需的各种配置信息。

[[email protected] temp]# docker network inspect none
[
    {
        "Name": "none",
        "Id": "1abfa4750ada3be20927c3c168468f9a64efd10705d3be8958ae1eef784b28ef",
        "Scope": "local",
        "Driver": "null",
        "IPAM": {
            "Driver": "default",
            "Config": []
        },
        "Containers": {},
        "Options": {}
    }
]
[[email protected] temp]# docker network inspect host
[
    {
        "Name": "host",
        "Id": "001c9c9047d90efff0b64bf80e49ff7ec33421374b2c895169a0f9e096eb791d",
        "Scope": "local",
        "Driver": "host",
        "IPAM": {
            "Driver": "default",
            "Config": []
        },
        "Containers": {},
        "Options": {}
    }
]
[[email protected] temp]# docker network inspect bridge
[
    {
        "Name": "bridge",
        "Id": "201fbcb64b75977889f5d9c1e88c756308a090eb611397dbd0bb5c824d429276",
        "Scope": "local",
        "Driver": "bridge",
        "IPAM": {
            "Driver": "default",
            "Config": [
                {
                    "Subnet": "172.17.42.1/16",
                    "Gateway": "172.17.42.1"
                }
            ]
        },
        "Containers": {
            "4d4d37853115562080613393c6f605a9ec2b06c3660dfa0ca4e27f2da266773d": {
                "EndpointID": "09e332644c539cec8a9852a11d402893bc76a5559356817192657b5840fe2de3",
                "MacAddress": "02:42:ac:11:00:01",
                "IPv4Address": "172.17.0.1/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"
        }
    }
]

容器网络的各种操作:

-> 创建/添加/解除/删除网络

[[email protected] temp]# docker network create -d bridge --ip-range=192.168.1.0/24 --gateway=192.168.1.1 --subnet=192.168.1.0/24  bridge2
b18f4fb74ebd32b9f67631fd3fd842d09b97c30440efebe254a786d26811cf66
[[email protected] temp]# docker network ls
NETWORK ID          NAME                DRIVER
1abfa4750ada        none                null
001c9c9047d9        host                host
b18f4fb74ebd        bridge2             bridge
201fbcb64b75        bridge              bridge
[[email protected] temp]# docker exec vim ip addr
1: lo: 

driver plugin机制与driver plugin实现

简介

Docker插件一览:

http://docs.docker.com/engine/extend/plugins/

Docker的plugin采用了一种out-of-process的方式。

这样有两个好处,便于扩展、动态增加删除;同时代码上与Docker完全解耦。

Plugin是运行在Docker host上的一个进程,通过将一个文件放在plugin目录来向Docker注册,

从而被docker发现机制发现。

插件名字建议使用比较短的小写单词。插件可以在容器内或者容器外运行,建议在容器外。

插件目录

插件目录下可以放三种文件:


.sock files are UNIX domain sockets.
.spec files are text files containing a URL, such as unix:///other.sock.
.json files are text files containing a full json specification for the plugin.

.sock文件一般放置在/run/docker/plugins下;.spec/.json文件一般放置在/etc/docker/plugins

或者/usr/lib/docker/plugins下。

json文件范例:

{
  "Name": "plugin-example",
  "Addr": "https://example.com/docker/plugin",
  "TLSConfig": {
    "InsecureSkipVerify": false,
    "CAFile": "/usr/shared/docker/certs/example-ca.pem",
    "CertFile": "/usr/shared/docker/certs/example-cert.pem",
    "KeyFile": "/usr/shared/docker/certs/example-key.pem",
  }
}

插件的其他说明

Plugin需要在docker启动前启动;更新plugin时需要先停止docker daemon,更新后再启动docker daemon。

插件在第一次使用时激活。docker会根据指定的插件名字,在插件目录下查找。(感觉docker应该增加一个接口,查询本机插件列表)

Docker与plugin间使用,json格式基于Http的RPC消息,消息类型为post。

握手消息:

/Plugin.Activate
Request: empty body

Response:

{
    "Implements": ["VolumeDriver"]
}

Plugin实现

主要需要实现如下消息:

/Plugin.Activate
/NetworkDriver.GetCapabilities
/NetworkDriver.CreateNetwork
/NetworkDriver.DeleteNetwork
/NetworkDriver.CreateEndpoint
/NetworkDriver.EndpointOperInfo
/NetworkDriver.DeleteEndpoint
/NetworkDriver.Join
/NetworkDriver.Leave
/NetworkDriver.DiscoverNew
/NetworkDriver.DiscoverDelete

详细参考:

https://github.com/docker/libnetwork/blob/master/docs/remote.md

libnetwork与docker

调用关系:

docker daemon—->libnetwork—–>network plugin

CNM介绍

https://github.com/docker/libnetwork/blob/master/docs/design.md

CNM全称Container Network Model。主要对libnetwork的网络模型进行了定义。

主要有三个概念:
  • network

    一组可以直接互相通信的endpoint构成。通常的实现手段linux bridge/ovs等。

  • sandbox

    sandbox包含了一个容器的网络栈。一般包含interface/route/dns设置等。一般通过namespace实现。

    一个sandbox可以包含多个属于不同network的endpoint。

  • endpoint

    endpoint将一个sandbox与一个网络连通。

    通常可以使用linux bridge的veth pair或者ovs的internal port等技术。

CNM的主要对象有
  • NetworkController

    主要负责管理driver,提供创建network接口。

  • Driver

    提供network/sandbox/endpoint的实现。

  • Network
  • Endpoint
  • Sandbox

代码分析

Docker daemon
  • 在daemon初始化时创建了三个网络

    daemon.go 函数NewDaemon:

func NewDaemon(config *Config, registryService *registry.Service) (daemon *Daemon, err error) {
...
d.netController, err = d.initNetworkController(config)
    if err != nil {
        return nil, fmt.Errorf("Error initializing network controller: %v", err)
    }
...
}
  • initNetworkController函数在daemon_unix.go/daemon_windows.go中,以unix为例:

    主要做了以下几件事情:

    初始化controller, 初始化null/host/bridge三个内置网络。


func (daemon *Daemon) initNetworkController(config *Config) (libnetwork.NetworkController, error) {
    netOptions, err := daemon.networkOptions(config)
    if err != nil {
        return nil, err
    }

    controller, err := libnetwork.New(netOptions...)
    if err != nil {
        return nil, fmt.Errorf("error obtaining controller instance: %v", err)
    }

    // Initialize default network on "null"
    if _, err := controller.NewNetwork("null", "none", libnetwork.NetworkOptionPersist(false)); err != nil {
        return nil, fmt.Errorf("Error creating default \"null\" network: %v", err)
    }

    // Initialize default network on "host"
    if _, err := controller.NewNetwork("host", "host", libnetwork.NetworkOptionPersist(false)); err != nil {
        return nil, fmt.Errorf("Error creating default \"host\" network: %v", err)
    }

    if !config.DisableBridge {
        // Initialize default driver "bridge"
        if err := initBridgeDriver(controller, config); err != nil {
            return nil, err
        }
    }

    return controller, nil
}
  • 启动容器时创建网络

api/server/router/container/container.go
local.NewPostRoute("/containers/{name:.*}/start", r.postContainersStart),
postContainersStart中调用了containerStart函数
daemon/start.go
func (daemon *Daemon) containerStart(container *Container) (err error) {
    ...
    if err := daemon.initializeNetworking(container); err != nil {
        return err
    }
        ...
}
daemon/container_unix.go
func (daemon *Daemon) initializeNetworking(container *Container) error {
...
    if err := daemon.allocateNetwork(container); err != nil {
        return err
    }
...
}
func (daemon *Daemon) allocateNetwork(container *Container) error {
...
    for n := range container.NetworkSettings.Networks {
        if err := daemon.connectToNetwork(container, n, updateSettings); err != nil {
            return err
        }
    }
...
}
func (daemon *Daemon) connectToNetwork(container *Container, idOrName string, updateSettings bool) (err error) {
...
// 创建endpoint
ep, err = n.CreateEndpoint(endpointName, createOptions...)
...
// 获得sandbox
sb := daemon.getNetworkSandbox(container)
...
// 接入sandbox
    if err := ep.Join(sb); err != nil {
        return err
    }
...
}
  • 创建Network

    实际上是调用libnetwork的NewNetwork接口。

    network的所有API,都会被路由到daemon/network.go中的函数上


daemon/network.go
// CreateNetwork creates a network with the given name, driver and other optional parameters
func (daemon *Daemon) CreateNetwork(name, driver string, ipam network.IPAM, options map[string]string) (libnetwork.Network, error) {
    c := daemon.netController
    if driver == "" {
        driver = c.Config().Daemon.DefaultDriver
    }

    nwOptions := []libnetwork.NetworkOption{}

    v4Conf, v6Conf, err := getIpamConfig(ipam.Config)
    if err != nil {
        return nil, err
    }

    nwOptions = append(nwOptions, libnetwork.NetworkOptionIpam(ipam.Driver, "", v4Conf, v6Conf))
    nwOptions = append(nwOptions, libnetwork.NetworkOptionDriverOpts(options))
    return c.NewNetwork(driver, name, nwOptions...)
}
  • Connect容器到Network

    我们再看看connect容器到Network。

    可以看到最后也是调用了libnetwork的接口。

    创建EP,加入sandbox。


// ConnectContainerToNetwork connects the given container to the given
// network. If either cannot be found, an err is returned. If the
// network cannot be set up, an err is returned.
func (daemon *Daemon) ConnectContainerToNetwork(containerName, networkName string) error {
    container, err := daemon.Get(containerName)
    if err != nil {
        return err
    }
    return daemon.ConnectToNetwork(container, networkName)
}
// ConnectToNetwork connects a container to a network
func (daemon *Daemon) ConnectToNetwork(container *Container, idOrName string) error {
    if !container.Running {
        return derr.ErrorCodeNotRunning.WithArgs(container.ID)
    }
    if err := daemon.connectToNetwork(container, idOrName, true); err != nil {
        return err
    }
    if err := container.toDiskLocking(); err != nil {
        return fmt.Errorf("Error saving container to disk: %v", err)
    }
    return nil
}
func (daemon *Daemon) connectToNetwork(container *Container, idOrName string, updateSettings bool) (err error) {
    if container.hostConfig.NetworkMode.IsContainer() {
        return runconfig.ErrConflictSharedNetwork
    }

    if runconfig.NetworkMode(idOrName).IsBridge() &&
        daemon.configStore.DisableBridge {
        container.Config.NetworkDisabled = true
        return nil
    }

    controller := daemon.netController

    n, err := daemon.FindNetwork(idOrName)
    if err != nil {
        return err
    }

    if updateSettings {
        if err := daemon.updateNetworkSettings(container, n); err != nil {
            return err
        }
    }

    ep, err := container.getEndpointInNetwork(n)
    if err == nil {
        return fmt.Errorf("container already connected to network %s", idOrName)
    }

    if _, ok := err.(libnetwork.ErrNoSuchEndpoint); !ok {
        return err
    }

    createOptions, err := container.buildCreateEndpointOptions(n)
    if err != nil {
        return err
    }

    endpointName := strings.TrimPrefix(container.Name, "/")
    ep, err = n.CreateEndpoint(endpointName, createOptions...)
    if err != nil {
        return err
    }
    defer func() {
        if err != nil {
            if e := ep.Delete(); e != nil {
                logrus.Warnf("Could not rollback container connection to network %s", idOrName)
            }
        }
    }()

    if err := daemon.updateEndpointNetworkSettings(container, n, ep); err != nil {
        return err
    }

    sb := daemon.getNetworkSandbox(container)
    if sb == nil {
        options, err := daemon.buildSandboxOptions(container, n)
        if err != nil {
            return err
        }
        sb, err = controller.NewSandbox(container.ID, options...)
        if err != nil {
            return err
        }

        container.updateSandboxNetworkSettings(sb)
    }

    if err := ep.Join(sb); err != nil {
        return err
    }

    if err := container.updateJoinInfo(n, ep); err != nil {
        return derr.ErrorCodeJoinInfo.WithArgs(err)
    }

    return nil
}

其他功能和上述分析类似。

libnetwork

Libnetwork代码中内置了若干个driver,分别是(bridge,null,host,overlay,remote,windows),其中bridge,null,host是常用的local driver。

overlay是docker新发布的multi-host network方案。remote则可以与第三方定制的driver plugin通信。

参考libnetwork/dirvers/remote/driver.go的函数,最后是发送rest消息与plugin通信。

...
func (d *driver) CreateNetwork(id string, options map[string]interface{}, ipV4Data, ipV6Data []driverapi.IPAMData) error {
    create := &api.CreateNetworkRequest{
        NetworkID: id,
        Options:   options,
        IPv4Data:  ipV4Data,
        IPv6Data:  ipV6Data,
    }
    return d.call("CreateNetwork", create, &api.CreateNetworkResponse{})
}

func (d *driver) DeleteNetwork(nid string) error {
    delete := &api.DeleteNetworkRequest{NetworkID: nid}
    return d.call("DeleteNetwork", delete, &api.DeleteNetworkResponse{})
}
...
时间: 2024-12-23 06:37:17

[Docker]Docker1.9后的network的相关文章

docker1.13新功能network关注点

网络 允许 docker run 连入指定的 swarm mode 的网络 https://github.com/docker/docker/pull/25962 在 Docker 1.12 发布新的 Swarm Mode 之后,很多人都问过这样的问题,怎么才能让 docker run 的容器连入 Swarm Mode 服务的 overlay 网络中去?答案是不可以,因为 swarm 的 overlay 网络是为了 swarm mode service 准备的,相对更健壮,而直接使用 docke

Docker windows 容器启动失败 network not found

前几天由于重启了服务器,docker配置的网络出了些问题导致在docker容器中安装的mysql识别用户权限时发生错误.(从宿主机A以user身份 登入到容器B中安装的Mysql时,用户竟然不是[email protected] 导致没有表的写权限.) 在网上查找解决方法的时候手贱运行了 1 docker network prune 结果把容器正在使用的网络给删除了...-_-|| 导致再运行 docker start 启动容器的时候报错:Error response from daemon:

docker export import后,导入镜像,启动时的错误,Error response from daemon: No command specified

Docker的流行与它对容器的易分享和易移植密不可分,用户不仅可以把容器提交到公共服务器上,还可以把容器导出到本地文件系统中.同样,我们也可以把导出的容器重新导入到Docker运行环境中.Docker的容器导入导出分别用import和export命令完成. 1.导出容器export 注意:export导出的是容器,不是镜像. [plain] view plain copy docker export <CONTAINER ID > > my_container.tar docker ex

docker被入侵后.............

服务器上线后,怎么发现总有个 xmrig 的容器在跑,删了还出来 那么恭喜你!!你的服务器已经被入侵了!! $ docker ps IMAGE               COMMAND                  CREATED           STATUS                           PORTS    NAMES linuxrun/cpu2    "./xmrig --algo=cr...."    4 hours ago     Exited (

docker 安装好后启动异常解决

一个月前在虚拟机中根据视频教程安装了docker 启动docker后执行 systemctl status docker 出现了异常,具体如下: [[email protected] ~]# systemctl status docker.service ● docker.service - Docker Application Container Engine Loaded: loaded (/usr/lib/systemd/system/docker.service; enabled; ve

docker容器运行后退出,怎么才能一直运行?【转】

现象 启动docker容器 docker run –name [CONTAINER_NAME] [CONTAINER_ID] 查看容器运行状态 docker ps -a 发现刚刚启动的mydocker容器已经退出 原因 docker容器的主线程(dockfile中CMD执行的命令)结束,容器会退出 办法 可以使用交互式启动 docker run -i [CONTAINER_NAME or CONTAINER_ID] 上面的不太友好,建议使用后台模式和tty选项 docker run -dit [

Weex playground手机扫描二维码后显示network error解决

首先可以参考下面的博客 Weex playground 手机扫描二维码报错network error解决办法 1.手机和电脑是否在同一局域网: 2.第一步确认没问题后,还是报network error,确认下PC上wifi的连接策略是否为专用: 3.在npm start之前,手动再运行npm install 安装一次 若还未解决,可以尝试禁用虚拟网卡,如下图: 原文地址:https://www.cnblogs.com/ZYTZ/p/12113725.html

docker 关闭镜像后,容器无法启动---Conflict. The container nam

当执行关闭某个镜像: 执行关闭:  docker stop fa671dd6bdfb docker ps 重启某个容器: docker run --name itbilu-mysql -e MYSQL_ROOT_PASSWORD=my-pass -d mysql:5.7 报异常: 删除对应的容器: docker rm itbilu-mysql 重启对应的容器命令 原文地址:http://blog.51cto.com/4925054/2097498

Docker进入容器后使用ifconfig等命令“command not found”解决办法

当进入一个容器后,使用ifconfig.ip addr等命令时,出现如下“command not found”:   解决办法: yum update yum -y install net-tools 原文地址:https://www.cnblogs.com/lemon-le/p/9788955.html