编程开源技术交流,分享技术与知识

网站首页 > 开源技术 正文

10年老架构,带你CentOS 7 Docker基本特性入门实践,下篇

wxchong 2024-08-07 01:44:19 开源技术 18 ℃ 0 评论

前言

Docker是一个开源的应用容器引擎,开发人员可以非常容易地打包已经开发好的应用,同时将应用相关的依赖包也打包到这样一个可移植的容器中,然后发布到任意的Linux主机系统上。

Docker是基于Linux Container(LXC)技术实现的一个轻量级虚拟化解决方案,用户可以直接使用容器(Container),来构建自己的应用程序,应用开发人员无需将注意力集中在容器的管理上。Docker的目标是“Build, Ship and Run Any App, Anywhere”,这说明了使用Docker能够实现应用运行的可移植性、便捷性,对开发人员非常友好,只要你的应用是基于Docker进行构建和部署的,在任何时候任何支持Docker的Linux发行版操作系统上都可以运行你的应用程序。

Docker是基于Go语言开发的, 代码开源,可以在Github上查看对应的源码:
https://github.com/docker/docker.git。

Docker网络

Docker支持Container之间通过网络互连,提供了两种网络Driver,分别为Bridge和Overlay,我们也可以实现自己的网络Driver插件来管理我们的Docker Container网络。目前,有很多Docker网络的解决方案,如Flannel、Weave、Pipework、libnetwork等,感兴趣可以深入研究一下。在安装Docker Engine之后,会包含三个默认的网络,可以通过如下命令查看当前所有的网络:

docker network ls

结果如下所示:

NETWORK ID          NAME                DRIVER              SCOPE
b92d9ca4d992        bridge              bridge              local
6d33880bf521        host                host                local
a200b158f39c        none                null                local

名称为host的网络,表示宿主机的网络,如果启动Docker Container指定该网络,则Container与宿主机使用相同的Network Namespace,也就是启动的Container的网络会使用宿主机的网卡、IP、端口。在启动Docker Container时,如果我们没有显示指定网络名称,Docker会使用默认的bridge网络。这种网络模式下,Docker会为Container创建一个独立于宿主机的Network Namespace,并使用独立的IP段,Container连接到一个虚拟网桥上,默认是docker0网桥。虚拟网桥与交换机的工作方式类似,启动的Docker Container连接到虚拟网桥上,这就构成了一个二层网络。为了更加直观说明,我们参考了网上的一个Docker网络的结构图,如下图所示:

下面,通过Docker网络功能,看如何将Container网络连接起来。

  • 创建Docker网络

创建一个Docker网络,名称为my-bridge-network,执行如下命令:

docker network create -d bridge my-bridge-network

创建的结果,输出了新建Docker网络的ID,如下所示:

fc19452525e5d2f5f1fc109656f0385bf2f268b47788353c3d9ee672da31b33a

上面fc19452525e5d2f5f1fc109656f0385bf2f268b47788353c3d9ee672da31b33a就是新创建网络my-bridge-network的ID,可以通过如下命令查看:

docker network ls

当前主机上存在的所有Docker网络信息,如下所示:

NETWORK ID          NAME                DRIVER              SCOPE
b92d9ca4d992        bridge              bridge              local
6d33880bf521        host                host                local
fc19452525e5        my-bridge-network   bridge              local
a200b158f39c        none                null                local
  • 查看一个Docker网络

查看一个Docker网络的详细信息,查看默认的bridge网络,可以执行如下命令:

docker network inspect bridge

执行结果,如下所示:

[
    {
        "Name": "bridge",
        "Id": "2872de41fddddc22420eecad253107e09a305f3512ade31d4172d3b80723d8b6",
        "Created": "2017-03-05T21:46:12.413438219+08:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Containers": {
            "5ab157767bbd991401c351cfb452d663f5cd93dd1edc56767372095a5c2e7f73": {
                "Name": "pgdb",
                "EndpointID": "e0368c3219bcafea7c2839b7ede628fa67ad0a5350d150fdf55a4aa88c01c480",
                "MacAddress": "02:42:ac:11:00:02",
                "IPv4Address": "172.17.0.2/16",
                "IPv6Address": ""
            },
            "da91889d63139019bbdcc6266704fb21e0a1800d0ae63b3448e65d1e17ef7368": {
                "Name": "webappdb",
                "EndpointID": "422ab05dd2cbb55266964b31f0dd9292688f1459e3a687662d1b119875d4ce44",
                "MacAddress": "02:42:ac:11:00:03",
                "IPv4Address": "172.17.0.3/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"
        },
        "Labels": {}
    }
]

通过上面结果信息可以看到,当前bridge网络的ID为2872de41fddddc22420eecad253107e09a305f3512ade31d4172d3b80723d8b6,在该Docker网络内部运行中的Container有2个,分别为pgdb和webapp,他们在Container内部的IP地址分别为172.17.0.2和172.17.0.3,因为在同一个bridge网络中,所以共享相同的IP地址段。或者,我们也可以格式化输出某个Container所在网络的设置,执行如下命令:

docker inspect --format='{{json .NetworkSettings.Networks}}'  pgdb

输出结果如下所示(结果格式化过):

{
    "bridge": {
        "IPAMConfig": null,
        "Links": null,
        "Aliases": null,
        "NetworkID": "2872de41fddddc22420eecad253107e09a305f3512ade31d4172d3b80723d8b6",
        "EndpointID": "e0368c3219bcafea7c2839b7ede628fa67ad0a5350d150fdf55a4aa88c01c480",
        "Gateway": "172.17.0.1",
        "IPAddress": "172.17.0.2",
        "IPPrefixLen": 16,
        "IPv6Gateway": "",
        "GlobalIPv6Address": "",
        "GlobalIPv6PrefixLen": 0,
        "MacAddress": "02:42:ac:11:00:02"
    }
}

可见和上面的命令类似,能输出Docker网络bridge的基本信息。

  • 断开Container网络

可以断开一个Container的网络,来将一个Container从一个Docker网络中移除,只需要指定网络名称和Container名称即可(或者Container的ID),命令如下所示:

docker network disconnect bridge pgdb

docker network disconnect bridge 5ab157767bbd991401c351cfb452d663f5cd93dd1edc56767372095a5c2e7f73

  • 连通处于两个子网中的Docker Container

下面,运行一个Web application,默认使用bridge网络:

docker run -d --name myweb training/webapp python app.py

通过命令:

docker inspect --format='{{json .NetworkSettings.Networks}}'  myweb

可以查看该应用连接网络的状况,如下所示(结果格式化过):

{
    "bridge": {
        "IPAMConfig": null,
        "Links": null,
        "Aliases": null,
        "NetworkID": "2872de41fddddc22420eecad253107e09a305f3512ade31d4172d3b80723d8b6",
        "EndpointID": "a4e66b540e632c346f345c7972617ccdfaa4ef36eefbdc3a298d524b5cf13897",
        "Gateway": "172.17.0.1",
        "IPAddress": "172.17.0.4",
        "IPPrefixLen": 16,
        "IPv6Gateway": "",
        "GlobalIPv6Address": "",
        "GlobalIPv6PrefixLen": 0,
        "MacAddress": "02:42:ac:11:00:04"
    }
}

或者,获取直接Container的IP地址,执行命令:

docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' myweb

结果如下:

172.17.0.4

接着,我们再在my-bridge-network网络中启动一个Container,名称为mydb,执行如下命令:

docker run -d --name mydb --network my-bridge-network training/postgres

查看mydb应用连接网络的状态(结果格式化过):

{
    "my-bridge-network": {
        "IPAMConfig": null,
        "Links": null,
        "Aliases": [
            "fbfbad9e0bd3"
        ],
        "NetworkID": "fc19452525e5d2f5f1fc109656f0385bf2f268b47788353c3d9ee672da31b33a",
        "EndpointID": "49c7afbf24be165b98ea29dbfd7b1e2c0eecd9c1ef16a7efde00ab92d0563985",
        "Gateway": "172.18.0.1",
        "IPAddress": "172.18.0.2",
        "IPPrefixLen": 16,
        "IPv6Gateway": "",
        "GlobalIPv6Address": "",
        "GlobalIPv6PrefixLen": 0,
        "MacAddress": "02:42:ac:12:00:02"
    }
}

应用mydb所在网络为my-bridge-network,IP地址为172.18.0.2。下面,测试从我们的mydb应用所在Container,连接到myweb应用所在的Container(,实际是跨了2个子网,即从my-bridge-network网络连接到bridge网络)。执行如下命令,使得可以在默认的bridge网络中的Container连接到my-bridge-network中的Container,执行如下命令:

docker network connect my-bridge-network myweb

这样,就可以进入到在my-bridge-network网络中的mydb应用所在Container中,通过ping命令,来ping另一个默认bridge网络中myweb应用:

[root@localhost mydockerbuild]# docker exec -it mydb bash
root@fbfbad9e0bd3:/# ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:ac:12:00:02
          inet addr:172.18.0.2  Bcast:0.0.0.0  Mask:255.255.0.0
          inet6 addr: fe80::42:acff:fe12:2/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:36 errors:0 dropped:0 overruns:0 frame:0
          TX packets:14 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:3530 (3.5 KB)  TX bytes:1124 (1.1 KB)
 
lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:26 errors:0 dropped:0 overruns:0 frame:0
          TX packets:26 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1
          RX bytes:2274 (2.2 KB)  TX bytes:2274 (2.2 KB)
root@fbfbad9e0bd3:/# ping myweb
PING myweb (172.18.0.3) 56(84) bytes of data.
64 bytes from myweb.my-bridge-network (172.18.0.3): icmp_seq=1 ttl=64 time=0.318 ms
64 bytes from myweb.my-bridge-network (172.18.0.3): icmp_seq=2 ttl=64 time=2.06 ms
64 bytes from myweb.my-bridge-network (172.18.0.3): icmp_seq=3 ttl=64 time=0.506 ms
64 bytes from myweb.my-bridge-network (172.18.0.3): icmp_seq=4 ttl=64 time=0.404 ms
^C
--- myweb ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3003ms
rtt min/avg/max/mdev = 0.318/0.822/2.061/0.718 ms

可见,在不同Docker网络的两个Container之间的网络是连通的。

Docker Data Volumes

一个Data Volume是在一个或多个Container里面的特定的目录,它能够绕过Union Filesystem,提供持久化或共享数据的特性。添加一个Data Volume,执行如下命令:

docker run -d -P --name vweb -v /webapp training/webapp python app.py

添加一个Data Volume,使用-v选项,目录名为/webapp,该目录是在Container内部的目录,可以通过执行命令docker inspect vweb查看当前Container中对应的信息,如下所示:

[
    {
        "Id": "fcea99542d4d2838102fc4b627c68a201b868d85f229722325d83968b32c8b33",
        "Created": "2017-03-05T16:53:12.614318467Z",
        "Path": "python",
        "Args": [
            "app.py"
        ],
        "State": {
            "Status": "running",
            "Running": true,
            "Paused": false,
            "Restarting": false,
            "OOMKilled": false,
            "Dead": false,
            "Pid": 7555,
            "ExitCode": 0,
            "Error": "",
            "StartedAt": "2017-03-05T16:53:13.380982103Z",
            "FinishedAt": "0001-01-01T00:00:00Z"
        },
        "Image": "sha256:6fae60ef344644649a39240b94d73b8ba9c67f898ede85cf8e947a887b3e6557",
        "ResolvConfPath": "/var/lib/docker/containers/fcea99542d4d2838102fc4b627c68a201b868d85f229722325d83968b32c8b33/resolv.conf",
        "HostnamePath": "/var/lib/docker/containers/fcea99542d4d2838102fc4b627c68a201b868d85f229722325d83968b32c8b33/hostname",
        "HostsPath": "/var/lib/docker/containers/fcea99542d4d2838102fc4b627c68a201b868d85f229722325d83968b32c8b33/hosts",
        "LogPath": "/var/lib/docker/containers/fcea99542d4d2838102fc4b627c68a201b868d85f229722325d83968b32c8b33/fcea99542d4d2838102fc4b627c68a201b868d85f229722325d83968b32c8b33-json.log",
        "Name": "/vweb",
        "RestartCount": 0,
        "Driver": "overlay",
        "MountLabel": "",
        "ProcessLabel": "",
        "AppArmorProfile": "",
        "ExecIDs": null,
        "HostConfig": {
            "Binds": null,
            "ContainerIDFile": "",
            "LogConfig": {
                "Type": "json-file",
                "Config": {}
            },
            "NetworkMode": "default",
            "PortBindings": {},
            "RestartPolicy": {
                "Name": "no",
                "MaximumRetryCount": 0
            },
            "AutoRemove": false,
            "VolumeDriver": "",
            "VolumesFrom": null,
            "CapAdd": null,
            "CapDrop": null,
            "Dns": [],
            "DnsOptions": [],
            "DnsSearch": [],
            "ExtraHosts": null,
            "GroupAdd": null,
            "IpcMode": "",
            "Cgroup": "",
            "Links": null,
            "OomScoreAdj": 0,
            "PidMode": "",
            "Privileged": false,
            "PublishAllPorts": true,
            "ReadonlyRootfs": false,
            "SecurityOpt": null,
            "UTSMode": "",
            "UsernsMode": "",
            "ShmSize": 67108864,
            "Runtime": "runc",
            "ConsoleSize": [
                0,
                0
            ],
            "Isolation": "",
            "CpuShares": 0,
            "Memory": 0,
            "NanoCpus": 0,
            "CgroupParent": "",
            "BlkioWeight": 0,
            "BlkioWeightDevice": null,
            "BlkioDeviceReadBps": null,
            "BlkioDeviceWriteBps": null,
            "BlkioDeviceReadIOps": null,
            "BlkioDeviceWriteIOps": null,
            "CpuPeriod": 0,
            "CpuQuota": 0,
            "CpuRealtimePeriod": 0,
            "CpuRealtimeRuntime": 0,
            "CpusetCpus": "",
            "CpusetMems": "",
            "Devices": [],
            "DiskQuota": 0,
            "KernelMemory": 0,
            "MemoryReservation": 0,
            "MemorySwap": 0,
            "MemorySwappiness": -1,
            "OomKillDisable": false,
            "PidsLimit": 0,
            "Ulimits": null,
            "CpuCount": 0,
            "CpuPercent": 0,
            "IOMaximumIOps": 0,
            "IOMaximumBandwidth": 0
        },
        "GraphDriver": {
            "Name": "overlay",
            "Data": {
                "LowerDir": "/var/lib/docker/overlay/59f20340fa5232f5b13300a715b6d422acc32d21385f48336cead00c3227c63a/root",
                "MergedDir": "/var/lib/docker/overlay/9c602e4263c42984824b7f1e3c62416cb6056332e6447e65c3d08de7c1f50cd6/merged",
                "UpperDir": "/var/lib/docker/overlay/9c602e4263c42984824b7f1e3c62416cb6056332e6447e65c3d08de7c1f50cd6/upper",
                "WorkDir": "/var/lib/docker/overlay/9c602e4263c42984824b7f1e3c62416cb6056332e6447e65c3d08de7c1f50cd6/work"
            }
        },
        "Mounts": [
            {
                "Type": "volume",
                "Name": "228bc2018d65523797450822a068550fb8afbdf6ca2e4010a32cbb36961e3d5f",
                "Source": "/var/lib/docker/volumes/228bc2018d65523797450822a068550fb8afbdf6ca2e4010a32cbb36961e3d5f/_data",
                "Destination": "/webapp",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }
        ],
        "Config": {
            "Hostname": "fcea99542d4d",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "ExposedPorts": {
                "5000/tcp": {}
            },
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
            ],
            "Cmd": [
                "python",
                "app.py"
            ],
            "Image": "training/webapp",
            "Volumes": {
                "/webapp": {}
            },
            "WorkingDir": "/opt/webapp",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": {}
        },
        "NetworkSettings": {
            "Bridge": "",
            "SandboxID": "3f2f86ae96ec76c08e8841c7b8eb75e586000397a8acef9a0098ddf02f2c7da7",
            "HairpinMode": false,
            "LinkLocalIPv6Address": "",
            "LinkLocalIPv6PrefixLen": 0,
            "Ports": {
                "5000/tcp": [
                    {
                        "HostIp": "0.0.0.0",
                        "HostPort": "32768"
                    }
                ]
            },
            "SandboxKey": "/var/run/docker/netns/3f2f86ae96ec",
            "SecondaryIPAddresses": null,
            "SecondaryIPv6Addresses": null,
            "EndpointID": "39693d7b104dab973e7ed27d16bb71b290be39aa83cce5e78f8b80de35309c5a",
            "Gateway": "172.17.0.1",
            "GlobalIPv6Address": "",
            "GlobalIPv6PrefixLen": 0,
            "IPAddress": "172.17.0.5",
            "IPPrefixLen": 16,
            "IPv6Gateway": "",
            "MacAddress": "02:42:ac:11:00:05",
            "Networks": {
                "bridge": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": null,
                    "NetworkID": "2872de41fddddc22420eecad253107e09a305f3512ade31d4172d3b80723d8b6",
                    "EndpointID": "39693d7b104dab973e7ed27d16bb71b290be39aa83cce5e78f8b80de35309c5a",
                    "Gateway": "172.17.0.1",
                    "IPAddress": "172.17.0.5",
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "MacAddress": "02:42:ac:11:00:05"
                }
            }
        }
    }
]

从上面可以看到,在应用vweb所在Container内部的Data Volume为/webapp。也可以mount一个宿主机的目录,作为Docker Container的Data Volume:

docker run -d -P --name vvweb -v /src/webapp:/webapp training/webapp python app.py

上面命令行中,-v选项的值通过冒号分隔,前半部分是宿主机的目录,而后半部分是Container中的相对目录,并且要求宿主机的目录一定包含Container中的Data Volume的路径。Docker的Data Volume默认是read-write模式,可以手动指定为只读模型,执行如下命令:

docker run -d -P --name web -v /src/webapp:/webapp:ro training/webapp python app.py

另外,也可以创建一个用来存储的Data Volume Container,便于多个Container中的应用共享数据。例如创建一个用来存储数据库数据的Data Volume Container,执行如下命令:

docker create -v /dbdata --name dbstore training/postgres /bin/true

创建了一个名称为dbstore的Container。如果其他应用想要共享我们创建的用于存储的Data Volume Container,可以在启动应用Container的时候指定Data Volume,例如启动下面两个Container使用我们创建的dbstore作为共享Data Volume:

docker run -d --volumes-from dbstore --name db1 training/postgres
docker run -d --volumes-from dbstore --name db2 training/postgres

db1和db2这两个Container共享我们创建的dbstore Data Volume Container,查看这两个Container对应的Volume信息,执行如下命令行:

docker inspect db1
docker inspect db2

结果分别取出两个Container的Mounts信息,对比发现内容是相同的,如下所示:

"Mounts": [
            {
                "Name": "741950cc3ef8d901dc6cfdbebf8450082a0d22b07957f43bd0de73d05447b365",
                "Source": "/var/lib/docker/volumes/741950cc3ef8d901dc6cfdbebf8450082a0d22b07957f43bd0de73d05447b365/_data",
                "Destination": "/dbdata",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }
        ]

可见,只能作为Data Volume使用的Container,可以被其他多个应用所共享。

本文作者时延军,原文点击了解更多↓↓↓

感谢大家支持,多多转发关注不迷路~

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表