Docker篇之docker容器之间的通信

问题描述
docker使用时,通过默认镜像地址检索或者拉取镜像时,仓库下载速度较慢,时常报错“net/http: TLS handshake timeout”。
解决问题的核心策略是,将拉取地址改为国内镜像仓库即可。

方法一
修改/etc/docker/daemon.json,多加几个可靠的地址,如下:

{
“registry-mirrors”: [“https://registry.docker-cn.com”,“http://hub-mirror.c.163.com”,“http://f1361db2.m.daocloud.io”,“https://mirror.ccs.tencentyun.com”]
}

自从Docker容器工具诞生以来,当我们在正式线上环境进行容器部署以及容器管理任务时,通常容器之间是需要进行数据通信的,来支撑正常业务运转。因此容器间的通信也随之成为热点,也是生产环境中的重中之重。

容器间的网络通信可分为两大方面:单主机容器上的相互通信,跨主机的容器相互通信。

一、Docker单主机容器通信

1、假设通过容器ip访问 【不可行】
由于docker容器每次在重启后,其IP会发生变化。因此通过容器ip访问不可行。
2、假设通过宿主机的ip:port访问 【不可行】
通过宿主机的ip:port访问,只能依靠监听在暴露出的端口的进程来进行有限的通信,过于狭隘,不可行

单主机容器通信最佳选择:
通过docker network建立桥接网络。User-defined networks
实现步骤:
1、首先通过docker network来创建一个桥接网络,在docker run的时候将容器指定到新创建的桥接网络中,这样同一桥接网络中的容器就可以通过互相访问。
创建网络

docker network create test-network

  
  
    
    
    
    
  • 1

2、启动容器时,加入创建的网络

docker run -it --network test-network --network-alias mysql -e MYSQL-ROOT_PASSWORD=123 mysql:5.7

  
  
    
    
    
    
  • 1

3、启动被链接的容器

docker run -it --network test-network --network-alias centos  centos /bin/bash

  
  
    
    
    
    
  • 1

可通过如下指令进入被链接容器test-centos,查看是否能够进行容器间通信
docker exec -it test-centos /bin/bash
输入指令mysql -h test-mysql -uroot -p123
Docker篇之docker容器之间的通信_第1张图片
如此,便说明容器间通信成功建立!

二、容器网络模式总结

按照docker官方说法,docker容器的网络有五种模式:
1、bridge模式,–net=bridge(默认)
这是docker网络的默认设置,为容器创建独立的网络命令空间,容器具有独立的网卡等所有单独的网络栈,是最常用的使用方式。
在进行docker run启动容器的时候,如果不加–net参数,就默认采用这种网络模式。
安装完docker,系统会自动添加一个供docker使用的网桥docker0,我们创建一个新的容器时,容器通过DHCP获取一个与docker0同网段的IP地址,并默认连接到docker0网桥,以此实现容器与宿主机的网络互通。

2、host模式,–net=host
这个模式创建出来的容器,直接使用容器宿主机的网络命名空间,将不拥有自己独立的Network Namespace,即没有独立的网络环境。它使用的是宿主机的ip和端口。

3、none模式,–net=none
为容器创建独立网络命名空间,但不为它做任何网络配置,容器中只有lo,用户可以在此基础上,对容器网络做任意定制。这种模式下,docker不为容器进行任何网络配置,需要我们自己为容器添加网卡,配置IP。
因此,如果要使用pipework配置docker容器的ip地址,必须要在none模式下才可以。

4、其他容器模式(即container模式,join模式),–net=container:NAME_or_ID
与host模式类似,只是容器将与指定的容器共享网络命名空间。这个模式就是指定一个已有的容器,共享该容器的IP和端口。
注意:除了网络方面两个容器共享,其他的如文件系统,进程等还是隔离开的。

这些网络模式在相互通信下的对比如下:
Docker篇之docker容器之间的通信_第2张图片
注:南北向通信指的是容器与宿主机外界的访问机制
东西向通信指的是同一宿主机上,与其他容器相互访问的机制

可通过docker network ls查看容器的网络模式:
在本机中,如下图,
Docker篇之docker容器之间的通信_第3张图片

三、吃个栗子
举例nginx与php两个容器之间通信:

1、启动php容器

[root@docker ~]# docker run -d --name=php -v /www:/usr/local/nginx/html php

  
  
    
    
    
    
  • 1

2、启动nginx容器

[root@docker ~]# docker run -d --name=nginx --link=php:php -v /www:/usr/local/nginx/html -p 81:80 nginx

  
  
    
    
    
    
  • 1

3、通过docker ps -a 查看容器状态
[root@docker ~]# docker ps -a

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                NAMES
58280fe851f9        nginx               "/usr/local/nginx/..."   15 seconds ago      Up 14 seconds       0.0.0.0:81->80/tcp   nginx
9ea150c35587        php                 "/usr/local/php/sb..."   36 seconds ago      Up 35 seconds       9000/tcp             php

  
  
    
    
    
    
  • 1
  • 2
  • 3

通过容器间的选项–link指定容器名称进行不同容器间的通信(–link container_name或者将container_name取一个别名)

现在使用另外一种方式替代–link来达到容器间的通信:docker network

查看local的网络信息:
docker network ls

[root@docker ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
5133ec415c3c        bridge              bridge              local
f359ca4e2d39        host                host                local
8d68673c045c        none                null                local

  
  
    
    
    
    
  • 1
  • 2
  • 3
  • 4
  • 5

4、现在开始创建网络名,名为test_net且driver为bridge的网络:(默认创建的就是bridge)

[root@docker ~]# docker network create test_net
67e29f0e4a77c79144efc337a081a889188b5b8e289968f22be6e4ddd9b80610
[root@docker ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
5133ec415c3c        bridge              bridge              local
f359ca4e2d39        host                host                local
67e29f0e4a77        my_net              bridge              local
8d68673c045c        none                null                local

  
  
    
    
    
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

5、利用–network启动容器提供服务

[root@docker ~]# docker run -d --name=php --network test_net --network-alias php -v /www:/usr/local/nginx/html php
6b493cbe8207dee4cb4d5945cfce305dba96914083bd7f46841b0b42376bcb99
[root@docker ~]# docker run -d --name=nginx --network test_net --network-alias nginx -v /www:/usr/local/nginx/html -p 80:80 nginx
5ab220196b52bb768bef508433f0b920eecee70c3ee47880ebc5e2a74b5ee254

  
  
    
    
    
    
  • 1
  • 2
  • 3
  • 4

注意:可通过–network-alias 给网络命名取别名,方便区分

6、至此,便可以进行测试

[root@docker ~]# docker exec -it nginx ping php
PING php (172.18.0.2) 56(84) bytes of data.
64 bytes from php.my_net (172.18.0.2): icmp_seq=1 ttl=64 time=0.079 ms
64 bytes from php.my_net (172.18.0.2): icmp_seq=2 ttl=64 time=0.090 ms

  
  
    
    
    
    
  • 1
  • 2
  • 3
  • 4

两个容器之间可以ping通,说明两个容器在同一个网络test_net内,而nginx里面的ping的php是容器名(管理的是容器级别)

因为nginx是可以ping通php的,所以在nginx配置中:

server {
    listen   80;
    root /usr/local/nginx/html;
    index index.htm index.html index.php;
    location ~ \.php$ {
        root /usr/local/nginx/html;
        fastcgi_pass php:9000;
        fastcgi_index index.php;
        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        include fastcgi_params;
    } 
}

  
  
    
    
    
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

配置文件中的php不会导致nginx启动失败,可通过network的driver bridge实现容器间的访问

在此,查看容器之间是否共用同一个网络:
可通过查询compose配置文件。
上面在容器启动的时候使用的是选项–network,而在compose的配置文件中则是networks,现在通过配置文件来进行阐述该参数的作用:

[root@docker lnmp]# cat lnmp.yml 
version: '3'
services:
  nginx:
    image: nginx
    container_name: lnmp-nginx
    depends_on:
      - php
    ports:
      - "80:80"
    networks:
      - "net1"
    volumes:
      - "/www:/usr/local/nginx/html"
  php:
    image: php
    container_name: lnmp-php
    expose: 
      - "9000"
    networks:
      - "net1"
    volumes:
      - "/www:/usr/local/nginx/html"

networks:
net1:
driver: bridge

由上述文件中可以看出networks定义了一个名称为net1的网络,由于networks是top-level(顶层级别,所以需要在顶层设置),而在创建网络时候需要指定driver(单一网络使用bridge,swarm集群使用overlay),而且driver内容不能省略,
在nginx和php两个service中使用了同一网络net1,现在将服务启动:

[root@docker lnmp]# docker-compose -f lnmp.yml up
Creating network "lnmp_net1" with driver "bridge"
Creating lnmp-php ... 
Creating lnmp-php ... done
Creating lnmp-nginx ... 
Creating lnmp-nginx ... done
Attaching to lnmp-php, lnmp-nginx

 
 
   
   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

可看出在启动服务的时候创建了服务级别的网络lnmp_net1

[root@docker lnmp]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
5133ec415c3c        bridge              bridge              local
f359ca4e2d39        host                host                local
29d798852b52        lnmp_net1           bridge              local
67e29f0e4a77        my_net              bridge              local
8d68673c045c        none                null                local

 
 
   
   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

服务nginx和php在网络lnmp_net1中实现了互联通信

[root@docker lnmp]# docker-compose -f lnmp.yml exec nginx ping php
PING php (172.19.0.2) 56(84) bytes of data.
64 bytes from lnmp-php.lnmp_net1 (172.19.0.2): icmp_seq=1 ttl=64 time=0.060 ms

 
 
   
   
   
   
  • 1
  • 2
  • 3

在nginx服务中能够访问php的服务,在compose编排中级别的访问是对service级别的访问,所以在nginx服务配置文件中对应的php能够实现,不会导致nginx启动失败。

好了,至此,nginx与php之间的网络通信就已经实现。
休息,tired。

你可能感兴趣的:(杂记,docker,容器,运维)