Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,称为容器IP,同时Docker网桥是每个容器的默认网关。因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器IP直接通信。但是Docker容器每次重启后容器IP是会发生变化的。这也意味着如果容器间使用IP地址来进行通信的话,一旦有容器重启,重启的容器将不再能被访问到。而Docker网络就能够解决这个问题。
Docker 网络主要有以下两个作用:
-
容器间的互联和通信以及端口映射
-
容器IP变动时候可以通过服务名直接网络通信而不受到影响
因此只要是处于同一个Docker网络下的容器就可以使用服务名进行直接访问,而无需担心重启。
容器网络模式
Docker的4种网络模式:
-
host:容器和宿主机共享网络命名空间,直接使用宿主机的IP和端口
-
container:指定新容器和其他已经存在的容器共享一个网络命名空间,不是和宿主机共享。
-
none:容器有独立的网络命名空间,但没有任何网络设置,比如网桥连接、ip配置等
-
bridge:docker默认的网络模式
1、host模式
相当于VMware中的桥接模式,与宿主机在同一个网络中,但没有独立的IP地址。就是容器和宿主机共享网络命名空间,直接使用宿主机的ip和端口。host最大的优势就是网络性能比较好,但是docker host上已经使用的端口就不能再用了,网络的隔离性不好。
使用以下命令:
–network host
2、container模式
container模式下,新创建的容器不会创建自己的网卡,配置自己的 IP,而是和一个指定的容器共享 IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过 lo 网卡设备通信。
使用以下命令:
-network container:[容器名或容器ID]
3、none模式
使用none模式,Docker容器拥有自己的网络命名空间,但是,并不为Docker容器进行任何网络配置。也就是说,这个Docker容器没有网卡、IP、路由等信息。需要我们自己为Docker容器添加网卡、配置IP等。这种网络模式下容器只有lo回环网络,没有其他网卡。none模式可以在容器创建时通过–network none来指定。这种类型的网络没有办法联网,封闭的网络能很好的保证容器的安全性。
–network none
4、bridge模式
Docker服务启动 时,默认会创建一个名称为 docker0 网桥(其上有一个名称为 docker0 内部接口)。该桥接网络的名称为docker0,它在内核层连通了其他的物理或虚拟网卡,这就将所有容器和本地主机都放到同一个物理网络。Docker会 默认指定docker0 的 ip地址和子网掩码,让主机和容器之间可以通过网桥相互通信。
使用以下命令:
-network bridge
新建容器网络
使用docker network create新建网络
[root@localhost ~]# docker network create elk-net
查看容器网络
使用docker network ls命令查看网络
[root@localhost ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
0096358b96d7 bridge bridge local
807589f4bc25 host host local
ef44e8ad99ed none null local
附带参数:
-
–no-trunc:显示完整的网络ID
[root@localhost ~]# docker network ls --no-trunc
NETWORK ID NAME DRIVER SCOPE
222c8b1d0161a2061426526af1ec9666c221dd967f1fae7fff45ce2072af4b7b bridge bridge local
38d8c167b6ae287c2af51703c6406fa6823807902c34c524ed40d338cc1edb19 dnmp_default bridge local
e4f4510292a8a0f4e1a78c661e9c5101e638f16fdec7198777f47425c8da7dce elk-net bridge local
9487f7012971de0eef2d7cf11b212bcfca0e55211800c3cec89c657afab75d01 halo-net bridge local
44f802f342cd12c70381d19055a67877068192310470d5a57e9a8c92d418e992 host host local
fc8aa2f868d909da7448d937ab56a39b74525c27c7aec25b8cbb46a95b8fc801 none null local
8c9ed32f625962fd019aa1cbd1e609e48f56d7ca6df20ec7fa9774e392db1593 redis_default bridge local -
driver:驱动程序过滤器根据驱动程序匹配网络
[root@localhost ~]# docker network ls --filter driver=bridge
NETWORK ID NAME DRIVER SCOPE
222c8b1d0161 bridge bridge local
38d8c167b6ae dnmp_default bridge local
e4f4510292a8 elk-net bridge local
9487f7012971 halo-net bridge local
8c9ed32f6259 redis_default bridge local -
id:匹配网络ID的全部或部分
[root@localhost ~]# docker network ls --filter id=38d8c167b6ae287c2af51703c6406fa6823807902c34c524ed40d338cc1edb19
NETWORK ID NAME DRIVER SCOPE
38d8c167b6ae dnmp_default bridge local -
format :里使用不带标题的模板,并输出用冒号分隔所有网络的ID和驱动程序条目
[root@localhost ~]# docker network ls --format "{{.ID}}: {{.Driver}}"
222c8b1d0161: bridge
38d8c167b6ae: bridge
e4f4510292a8: bridge
9487f7012971: bridge
44f802f342cd: host
fc8aa2f868d9: null
8c9ed32f6259: bridge
查看docker network inspect网络数据源
[root@localhost ~]# docker network inspect bridge
[
{
"Name": "bridge",
"Id": "222c8b1d0161a2061426526af1ec9666c221dd967f1fae7fff45ce2072af4b7b",
"Created": "2023-01-19T01:06:50.223891493+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,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {},
"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": {}
}
]
删除容器网络
使用docker network rm命令
[root@localhost ~]# docker network rm elk-net
删除所有不在用的网络
[root@localhost ~]# docker network prune
WARNING! This will remove all custom networks not used by at least one container.
Are you sure you want to continue? [y/N] y
容器连接网络
容器连接到网络的三种方式:
-
容器启动时:
[root@localhost ~]# docker run -itd --network=redis_default redis
-
容器运行时:
[root@localhost ~]# docker network connect redis_default redis
-
指定容器IP地址:
[root@localhost ~]# docker network connect --ip 10.10.10.10 redis_default redis
容器挂载网络
一般来说docker-compose命令编排的一组容器时会默认创建一个网络,并且这组容器全部都会加入到网络当中。容器之间可以直接使用服务名去直接通信的原因。有如下docker-compose.yml文件参考:
version: "3"
services:
nginx:
build:
context: ./services/nginx
args:
NGINX_VERSION: nginx:${NGINX_VERSION}
CONTAINER_PACKAGE_URL: ${CONTAINER_PACKAGE_URL}
NGINX_INSTALL_APPS: ${NGINX_INSTALL_APPS}
container_name: nginx
ports:
- "${NGINX_HTTP_HOST_PORT}:80"
- "${NGINX_HTTPS_HOST_PORT}:443"
- "${NGINX_API_HOST_PORT}:56668"
volumes:
- ${SOURCE_DIR}:/www/:rw
- ${NGINX_SSL_CERTIFICATE_DIR}:/ssl:rw
- ${NGINX_CONFD_DIR}:/etc/nginx/conf.d/:rw
- ${NGINX_CONF_FILE}:/etc/nginx/nginx.conf:ro
- ${NGINX_FASTCGI_PHP_CONF}:/etc/nginx/fastcgi-php.conf:ro
- ${NGINX_FASTCGI_PARAMS}:/etc/nginx/fastcgi_params:ro
- ${NGINX_LOG_DIR}:/var/log/nginx/:rw
environment:
TZ: "$TZ"
restart: always
networks:
- default
# 可以把-default 改成下列配置,以固定容器IP
#default:
# ipv4_address: 10.0.0.10
php:
build:
context: ./services/php
args:
PHP_VERSION: php:${PHP_VERSION}-fpm-alpine
CONTAINER_PACKAGE_URL: ${CONTAINER_PACKAGE_URL}
PHP_EXTENSIONS: ${PHP_EXTENSIONS}
TZ: "$TZ"
container_name: php
expose:
- 9501
extra_hosts:
- "www.site1.com:172.17.0.1"
volumes:
- ${SOURCE_DIR}:/www/:rw
- ${PHP_PHP_CONF_FILE}:/usr/local/etc/php/php.ini:ro
- ${PHP_FPM_CONF_FILE}:/usr/local/etc/php-fpm.d/www.conf:rw
- ${PHP_LOG_DIR}:/var/log/php
- ${DATA_DIR}/composer:/tmp/composer
restart: always
cap_add:
- SYS_PTRACE
networks:
- default
mysql:
image: mysql/mysql-server:${MYSQL_VERSION}
container_name: mysql
ports:
- "${MYSQL_HOST_PORT}:3306"
volumes:
- ${MYSQL_CONF_FILE}:/etc/mysql/conf.d/mysql.cnf:ro
- ${DATA_DIR}/mysql:/var/lib/mysql/:rw
- ${MYSQL_LOG_DIR}:/var/log/mysql/:rw
restart: always
networks:
- default
environment:
MYSQL_ROOT_PASSWORD: "${MYSQL_ROOT_PASSWORD}"
MYSQL_ROOT_HOST: "${MYSQL_ROOT_HOST}"
TZ: "$TZ"
mysql5:
image: mysql/mysql-server:${MYSQL5_VERSION}
container_name: mysql5
ports:
- "${MYSQL5_HOST_PORT}:3306"
volumes:
- ${MYSQL5_CONF_FILE}:/etc/mysql/conf.d/mysql.cnf:ro
- ${DATA_DIR}/mysql5:/var/lib/mysql/:rw
- ${MYSQL5_LOG_DIR}:/var/log/mysql/:rw
restart: always
networks:
- default
environment:
MYSQL_ROOT_PASSWORD: "${MYSQL5_ROOT_PASSWORD}"
MYSQL_ROOT_HOST: "${MYSQL5_ROOT_HOST}"
TZ: "$TZ"
networks:
default:
driver: bridge
ipam:
driver: default
# 解除下面的注释可以设置网段,用于nginx等容器固定容器IP
#config:
# - subnet: 10.0.0.0/24
这样容器编排时,所有容器都会加入到default这个自定义网络当中。在使用以下命令构建容器时默认创建网络:
[root@localhost dnmp]#docker-compose up -d
查看容器网络
[root@localhost ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
38d8c167b6ae dnmp_default bridge local
断开容器网络
使用docker network disconnect命令
[root@localhost ~]# docker network disconnect redis_default redis
网络端口映射
容器中可以运行一些网络应用,要让外部也可以访问这些应用,可以通过 -P 或 -p 参数来指定端口映射。
-p -P常见的五种使用方式
-
-p(小写)常用方式,多用于生产环境,格式:主机端口:容器端口
-
-P(大写)随机分配端口映射,多用于测试,宿主机会随机映射一个 49000~49900 的端口到映射容器内部的端口。
1、宿主机随机端口映射容器所有端口
此处的所有端口,指的是自动匹配容器的内部端口。比如启动的是redis自动匹配6379,映射到6379端口。
#sleep参数30s后,容器通过--rm自行销毁
[root@localhost ~]# docker run -d --name redis --rm -P redis sleep 30
264d978dcd43cbfd974f00879086e1e08964178b0402824b1441c5e1f252fe85
#查看端口自动分配情况
[root@localhost ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
264d978dcd43 redis "docker-entrypoint.s…" 5 seconds ago Up 4 seconds 0.0.0.0:49154->6379/tcp, :::49154->6379/tcp redis
2、宿主机随机端口映射容器的指定端口
[root@localhost ~]# docker run -d --name redis --rm -p 6379 redis sleep 30
ed8e4aa0239b43b35dc54a7a260af6b3fad8eec1f45e3a11ac5085234299d634
[root@localhost ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ed8e4aa0239b redis "docker-entrypoint.s…" 4 seconds ago Up 3 seconds 0.0.0.0:49155->6379/tcp, :::49155->6379/tcp redis
3、宿主机指定端口映射容器指定端口(常用)
[root@localhost ~]# docker run -d --name redis --rm -p 6379:6379 redis sleep 30
3537f3b2ef8afe055591b96ad98721f2f3a3c90f63c5e706adc81a0872a2180c
[root@localhost ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3537f3b2ef8a redis "docker-entrypoint.s…" 5 seconds ago Up 5 seconds 0.0.0.0:6379->6379/tcp, :::6379->6379/tcp redis
4、宿主机指定IP+端口、映射容器指定端口
[root@localhost ~]# docker run -d --name redis --rm -p 192.168.0.128:6379:6379 redis sleep 30
ca50338b5f5babab6d566ec9a0eca526b1901b7eb6955c4ee2c786560ef712b5
[root@localhost ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ca50338b5f5b redis "docker-entrypoint.s…" 5 seconds ago Up 4 seconds 192.168.0.128:6379->6379/tcp redis
5、宿主机指定IP+随机端口,映射容器指定端口
[root@localhost ~]# docker run -d --name redis --rm -p 192.168.0.128::6379 redis sleep 30
3974036eb2e1101d5488b11c26489667010d4376dd846e484fe8b9f019b0590f
[root@localhost ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3974036eb2e1 redis "docker-entrypoint.s…" 4 seconds ago Up 3 seconds 192.168.0.128:49153->6379/tcp redis
容器互联
端口映射并不是唯一把 docker 连接到另一个容器的方法。docker 有一个连接系统允许将多个容器连接在一起,共享连接信息。docker 连接会创建一个父子关系,其中父容器可以看到子容器的信息。
1、创建网络
创建一个新的Docker 网络
[root@localhost ~]# docker network create -d bridge test-net
15e5b0597983455401b6794e8a4beace5ba07e02bc0d95e05040084f1fd7e35f
[root@localhost ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
0096358b96d7 bridge bridge local
2bac3098a618 dnmp_default bridge local
807589f4bc25 host host local
ef44e8ad99ed none null local
15e5b0597983 test-net bridge local
参数说明:
-
-d:参数指定 Docker 网络类型,有 bridge、overlay。其中 overlay 网络类型用于 Swarm mode。
2、连接容器
运行一个容器并连接到新建的 test-net 网络:
[root@localhost ~]# docker run -itd --name test1 --network test-net ubuntu /bin/bash
Unable to find image 'ubuntu:latest' locally
latest: Pulling from library/ubuntu
7b1a6ab2e44d: Pull complete
Digest: sha256:626ffe58f6e7566e00254b638eb7e0f3b11d4da9675088f4781a50ae288f3322
Status: Downloaded newer image for ubuntu:latest
9c234242f80e518b9f29d2264dd74da7e34af1ea128fb172e8e810ed28533046
打开新的终端,再运行一个容器并加入到 test-net 网络:
[root@localhost ~]# docker run -itd --name test2 --network test-net ubuntu /bin/bash
17a9c422766c8b852623c65a29277cfb9ee3b288d649926ab1bb925a655ec880
查看容器
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
17a9c422766c ubuntu "/bin/bash" 14 seconds ago Up 13 seconds test2
9c234242f80e ubuntu "/bin/bash" 39 seconds ago Up 38 seconds test1
3、验证容器互联
容器内安装ping命令
apt-get update
apt install iputils-ping
在 test1 容器输入以下命令:
[root@localhost ~]# docker exec -it test1 /bin/sh
# apt-get update
# apt install iputils-ping
# ping test2
PING test2 (172.19.0.3) 56(84) bytes of data.
64 bytes from test2.test-net (172.19.0.3): icmp_seq=1 ttl=64 time=0.098 ms
64 bytes from test2.test-net (172.19.0.3): icmp_seq=2 ttl=64 time=0.072 ms
64 bytes from test2.test-net (172.19.0.3): icmp_seq=3 ttl=64 time=0.073 ms
64 bytes from test2.test-net (172.19.0.3): icmp_seq=4 ttl=64 time=0.181 ms
64 bytes from test2.test-net (172.19.0.3): icmp_seq=5 ttl=64 time=0.079 ms
64 bytes from test2.test-net (172.19.0.3): icmp_seq=6 ttl=64 time=0.074 ms
同理在 test2 容器也会成功连接到:
[root@localhost ~]# docker exec -it test2 /bin/sh
# apt-get update
# apt install iputils-ping
# ping test1
PING test1 (172.19.0.2) 56(84) bytes of data.
64 bytes from test1.test-net (172.19.0.2): icmp_seq=1 ttl=64 time=0.055 ms
64 bytes from test1.test-net (172.19.0.2): icmp_seq=2 ttl=64 time=0.091 ms
64 bytes from test1.test-net (172.19.0.2): icmp_seq=3 ttl=64 time=0.078 ms
64 bytes from test1.test-net (172.19.0.2): icmp_seq=4 ttl=64 time=0.071 ms
64 bytes from test1.test-net (172.19.0.2): icmp_seq=5 ttl=64 time=0.085 ms
64 bytes from test1.test-net (172.19.0.2): icmp_seq=6 ttl=64 time=0.081 ms
这样,test1 容器和 test2 容器建立了互联关系。如果你有多个容器之间需要互相连接,推荐使用 Docker Compose,也就是上面提到容器挂载网络。
原文始发于微信公众号(面试技术):Docker容器网络使用
暂无评论内容