docker-compose設置靜態ip和link與depends_on的區別

 
 

在容器中設置靜態ip,這似乎又是一個過時的老話題,但是在討論羣中仍然有朋友爲此感到困惑。我致力於解決這些小問題和在使用中容器落地的問題。爲此,我又寫了這篇文章來描述容器中使用靜態ip,和不使用靜態ip link的技巧。

在正式配置docker-compose之前,我們需要先了解link,因爲在我看來在容器中使用固定ip是件沒有必要的事情,使用ip只是我們腦中長久的一個使用習慣。而在docker中link已經幫我們解決了這個麻煩事,並提供了更簡單的方式。

那麼,通常來講,在這個問題上產生疑問的,必然是在使用兩個以上的容器。那就有必要了解depends_on。在使用link的同時,我當然也會敘述另外一個常用的選項depends_on,它非常有用。並且我會做簡單的比較。

閱讀本篇文章,你將瞭解,docker-compose中3版本的使用,以及link使用方式和depends_on的技巧。

I. 容器間互聯

儘管,我們要解決的是單機網絡,也不妨先簡單介紹下跨主機和不跨主機容器間互聯的區別

不跨主機互聯可以採用默認的bridge網絡,docker0橋在物理機上,而後創建的容器,容器內有eth0,另外一側在物理機的docker0,而docker0可以理解成一個虛擬交換機。這樣同一個交換機內的容器就可以直接進行互聯。

除此之外,還可以使用host網絡模式,共用宿主機網絡,這樣一來容器和宿主機使用同一個網絡,不隔離網絡名稱空間,網卡信息,就不存在網絡上的問題。

最後還可以採用聯盟式容器解決網絡問題

容器跨主機訪問實際上是做了DNAT,將容器發佈出去,這些規則在iptables中可以看到

Chain DOCKER (3 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 ACCEPT     tcp  --  !br-77c0aabda308 br-77c0aabda308  0.0.0.0/0            172.18.0.2           tcp dpt:26379
    0     0 ACCEPT     tcp  --  !br-77c0aabda308 br-77c0aabda308  0.0.0.0/0            172.18.0.2           tcp dpt:6379
    0     0 ACCEPT     tcp  --  !br-77c0aabda308 br-77c0aabda308  0.0.0.0/0            172.18.0.3           tcp dpt:1194
    0     0 ACCEPT     tcp  --  !br-77c0aabda308 br-77c0aabda308  0.0.0.0/0            172.18.0.3           tcp dpt:443

而對於互相雙方來講,是看不到後面的容器的,訪問的是通過端口轉發到真正的容器端口上。如果你要跨主機訪問,就不能使用容器的ip,只能使用宿主機的ip和容器映射的端口通過iptables轉發訪問。

[[email protected] ~]# telnet 172.25.50.250 6379
Trying 172.25.50.250...
Connected to 172.25.50.250.
Escape character is '^]'.

當然,也有例外,如果是疊加的方式就不需要在物理機做端口映射,直接通過隧道訪問對端ip和端口

II. link連接

我們瞭解到在容器網絡中的分配ip是不固定的,倘若我在第一次使用的ip地址在後面使用中發生了改變,那可能不無法正常使用了!這顯然並不是我們想要的。link就解決了這個問題。links似乎將會被棄用,因爲它並不重要(不使用link仍然可以通過容器名稱訪問),我們主要來看這裏的別名操作

docker-compose如下:

version: '3'
services:
  redis:
    image: marksugar/redis:5.0.0
    container_name: redis
    restart: always
    privileged: true
    environment:
      - REDIS_CONF=on
      - REQUIRE_PASS=OTdmOWI4ZTM4NTY1M2M4OTZh
      - MASTER_AUTH=OTdmOWI4ZTM4NTY1M2M4OTZh
      - MAXCLIENTS_NUM=600
      - MAXMEMORY_SIZE=4096M
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /data/redis-data:/data/redis:Z
      - /data/logs:/data/logs
    ports:
      - '6379:6379'
      - '26379:26379'

  softether:
    image: marksugar/softether:4.27
    links:
      - "redis:redisdb"
    container_name: softether4.27
    restart: always
    ports:
      - '443:443'
      - '1194:1194'

請注意,其中

    links:
      - "redis:redisdb"

softether和redis的容器ip地址分別是172.18.0.2和172.25.8.0.3,假設此時我們並不知道ip

這裏在softether中鏈接了redis,並設置了別名,redisdb。那也就是說我們可以使用redisdb來訪問redis本身。

[[email protected] /opt/2019/net]# docker exec -it softether4.27 sh
/ # apk update
fetch http://dl-cdn.alpinelinux.org/alpine/v3.8/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.8/community/x86_64/APKINDEX.tar.gz
v3.8.2-56-g4d33ed061d [http://dl-cdn.alpinelinux.org/alpine/v3.8/main]
v3.8.2-53-g53558ad6fc [http://dl-cdn.alpinelinux.org/alpine/v3.8/community]
OK: 9559 distinct packages available
/ # apk add redis
(1/1) Installing redis (4.0.11-r0)
Executing redis-4.0.11-r0.pre-install
Executing redis-4.0.11-r0.post-install
Executing busybox-1.28.4-r0.trigger
OK: 68 MiB in 35 packages
/ # redis-cli -a OTdmOWI4ZTM4NTY1M2M4OTZh -h redisdb info
Warning: Using a password with '-a' option on the command line interface may not be safe.
# Server
redis_version:5.0.0
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:a7a8d032c5a69a3f
redis_mode:standalone
os:Linux 4.18.12-1.el7.elrepo.x86_64 x86_64
arch_bits:64
multiplexing_api:epoll
atomicvar_api:atomic-builtin
gcc_version:6.4.0
process_id:10
run_id:c6162ba2b02d70c1defda6073f863af1ccb207a6
tcp_port:6379
uptime_in_seconds:263
uptime_in_days:0
hz:10
configured_hz:10
lru_clock:7302247

這說明了什麼?

我們完全可以使用容器的名稱來進行訪問,並不需要使用ip地址來指定。因爲ip會變,名稱卻不會變,這是因爲容器的hosts

/ # cat /etc/hosts
127.0.0.1   localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.18.0.3  d374cbffc3b0

在hosts中,已經寫了ip和容器id的對應關係。你完全可以使用容器名稱來進行訪問。

tips

你可以不使用別名,直接使用容器名稱進行訪問,你會看到redis容器的ip地址

/ # ping redis
PING redis (172.18.0.2): 56 data bytes
64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.093 ms
64 bytes from 172.18.0.2: seq=1 ttl=64 time=0.143 ms
64 bytes from 172.18.0.2: seq=2 ttl=64 time=0.106 ms
64 bytes from 172.18.0.2: seq=3 ttl=64 time=0.152 ms

因爲在同一個網絡內。

III. depends_on

我們在看另外一個場景,假如此刻softether依賴於redis,在啓動的時候就需要讀取redis或者寫入,通常情況下,redis必然要先啓動,redis啓動,softether在啓動。這纔是正確的方式,如果softether先啓動,而redis還沒有就緒,程序必然會報錯,甚至崩潰。此時depends_on就有了用武之地

如上場景中那般,配置如下:

redis:
    image: marksugar/redis:5.0.0
    ...
    
softether:
    image: marksugar/softether:4.27
    ...
    depends_on:
      - redis

這樣,softether會在redis啓動之後啓動。

如果你有多個依賴,就可以按照順序往後寫,比如mysql

redis:
    image: marksugar/redis:5.0.0
    ...
mysql:
    image:
    ...
softether:
    image: marksugar/softether:4.27
    ...
    depends_on:
      - redis
      - mysql

這樣的順序就是,softether會等待,先啓動redis,在啓動mysql,依次啓動纔到softether。由此可見,depends_on和links完全是兩個不同的東西。

  • tips:

我非常有必要提醒,啓動和準備就緒是兩個概念 ,啓動並不意味着一定就啓動完成,就像點擊開機並不意味着馬上就進入桌面。其中的就緒狀態則是另外的問題。請參閱啓動順序策略

IV. docker-compose 靜態ip

默認情況下,docker會爲容器分配隨機(某種......)IP地址。通過使用鏈接,您可以將條目添加到容器的hosts文件中,並使用其IP地址映射另一個容器的名稱。這樣您就不需要知道其IP地址,只需使用其名稱即可通過網絡訪問它。這種通過容器的hosts文件繼而使用容器名稱進行訪問,這似乎已經解決了一大半人的問題。

但是,我們仍然可以使用靜態ip。上面我提到,網絡是會發生改變的,爲了徹底解決這一點,我們將網關,子網都設置好。

在上面的默認網絡中使用的ip是172.18.0.0網段。現在,我們修改它

version: '3.7'
services:
  redis:
    networks:
      linuxea:
        ipv4_address: 172.2.0.10
...        
  softether:
    networks:
      linuxea:
        ipv4_address: 172.2.0.11
...
networks:
  linuxea:
    ipam:
     driver: default
     config:
       - subnet: 172.2.0.0/24

docker-compose如下

[[email protected] /opt/2019/net]# cat docker-compose.yaml 
version: '3.7'
services:
  redis:
    image: marksugar/redis:5.0.0
    container_name: redis
    restart: always
    privileged: true
    environment:
      - REDIS_CONF=on
      - REQUIRE_PASS=OTdmOWI4ZTM4NTY1M2M4OTZh
      - MASTER_AUTH=OTdmOWI4ZTM4NTY1M2M4OTZh
      - MAXCLIENTS_NUM=600
      - MAXMEMORY_SIZE=4096M
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /data/redis-data:/data/redis:Z
      - /data/logs:/data/logs
    ports:
      - '6379:6379'
      - '26379:26379'
    networks:
      linuxea:
        ipv4_address: 172.2.0.10
  softether:
    image: marksugar/softether:4.27
    links:
      - "redis:redisdb"
    container_name: softether4.27
    restart: always
    ports:
      - '443:443'
      - '1194:1194'
    networks:
      linuxea:
        ipv4_address: 172.2.0.11
networks:
  linuxea:
    ipam:
     driver: default
     config:
       - subnet: 172.2.0.0/24

現在,你就可以使用靜態的ip進行訪問

[[email protected] /opt/2019/net]# docker-compose -f ./docker-compose.yaml up -d
Creating redis ... done
Creating softether4.27 ... done
[[email protected] /opt/2019/net]# docker exec -it softether4.27 sh
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
293: eth0@if294: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP 
    link/ether 02:42:ac:02:00:0b brd ff:ff:ff:ff:ff:ff
    inet 172.2.0.11/24 brd 172.2.0.255 scope global eth0
       valid_lft forever preferred_lft forever

安裝redis-client

/ # apk update
fetch http://dl-cdn.alpinelinux.org/alpine/v3.8/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.8/community/x86_64/APKINDEX.tar.gz
v3.8.2-56-g4d33ed061d [http://dl-cdn.alpinelinux.org/alpine/v3.8/main]
v3.8.2-53-g53558ad6fc [http://dl-cdn.alpinelinux.org/alpine/v3.8/community]
OK: 9559 distinct packages available
/ # apk add redis
(1/1) Installing redis (4.0.11-r0)
Executing redis-4.0.11-r0.pre-install
Executing redis-4.0.11-r0.post-install
Executing busybox-1.28.4-r0.trigger
OK: 68 MiB in 35 packages

通過靜態ip鏈接

/ # redis-cli -a OTdmOWI4ZTM4NTY1M2M4OTZh -h 172.2.0.10
Warning: Using a password with '-a' option on the command line interface may not be safe.
172.2.0.10:6379> info
# Server
redis_version:5.0.0
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:a7a8d032c5a69a3f
redis_mode:standalone
os:Linux 4.18.12-1.el7.elrepo.x86_64 x86_64
arch_bits:64
multiplexing_api:epoll
atomicvar_api:atomic-builtin
gcc_version:6.4.0
process_id:10
run_id:cbf1e8eacc74da75c3dfcf797d104a8a2f95076e

使用ipam可以爲新網絡定義特定的CIDR塊,然後將每個容器連接到該網絡,可以在該範圍上指定其IP地址。

現在,redis始終使用IP地址172.2.0.10運行,softether運行172.2.0.11,並且我能夠在配置文件中對這些地址進行硬編碼。

V. 延伸閱讀

linuxea:白話容器之虛擬化網絡與容器網絡(8)

linuxea:白話容器之docker網絡(9)

VI. 學習更多

學習如何使用Docker CLI命令,Dockerfile命令,使用這些命令可以幫助你更有效地使用Docker應用程序。查看Docker文檔和我的其他帖子以瞭解更多信息。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章