Docker容器网络使用

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上已经使用的端口就不能再用了,网络的隔离性不好。

Docker容器网络使用

使用以下命令:

–network host

2、container模式

container模式下,新创建的容器不会创建自己的网卡,配置自己的 IP,而是和一个指定的容器共享 IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过 lo 网卡设备通信。

Docker容器网络使用

使用以下命令:

-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地址和子网掩码,让主机和容器之间可以通过网桥相互通信。

Docker容器网络使用

使用以下命令:

 -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容器网络使用

© 版权声明
THE END
喜欢就支持一下吧
点赞8 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容