有時候我們會碰到需要多個服務組件容器共同協作的情況, 這往往需要多個容器之間有能夠相互訪問到對方的服務.
除了通過網絡訪問外, Docker 還提供了兩個很方便的功能來滿足服務訪問的基本需求: 一個是允許映射容器內應用的服務端口到本地宿主主機; 另一個是互聯機制實現多個容器間通過容器名來快速訪問.
端口映射實現訪問容器
1.從外部訪問容器應用
在啟動容器的時候, 如果不指定對應的參數, 在容器外部是無法通過網絡來訪問容器內的網絡應用和服務的.
當容器中運行一些網絡應用, 要讓外部訪問這些應用時, 可以通過 -P
或 -p
參數來指定端口映射. 當使用 -P
(大寫的) 標記時, Docker 會將容器所有暴露的端口隨機映射到宿主主機的 49000~49900 之間的一個端口:
docker run -d -P training/webapp python app.py
此時, 可以使用 docker ps
看到, 本地主機的
docker ps -l
//輸出信息
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6f3bce18f77c training/webapp "python app.py" 14 seconds ago Up 14 seconds 0.0.0.0:32768->5000/tcp blissful_goldberg
-p
(小寫的) 可以指定要映射的端口, 并且, 在一個指定端口上只可以綁定一個容器. 支持的格式有 IP:HostPort:ContainerPort | IP::ContainerPort | HostPort:ContainerPort
2.映射所有接口地址
使用 HostPort:ContainerPort 格式將本地的 5000 端口映射到容器的 5000端口, 可以執行:
docker run -d -p 5000:5000 training/webapp python app.py
多次使用 -p
標記可以綁定多個端口:
docker run -d -p 5000:5000 -p 3000:80 training/webapp python app.py
3.映射到指定地址的指定端口
可以使用 IP:HostPort:ContainerPort 格式指定映射使用一個特定地址, 比如 localhost 地址 127.0.0.1:
docker run -d -p 127.0.0.1:5000:5000 training/webapp python app.py
4.映射到指定地址的任意端口
使用 IP::ContainerPort 綁定 localhost 的任意端口到容器的 5000 端口, 本地主機會自動分配一個端口:
docker run -d -p 127.0.0.1::5000 training/webapp python app.py
還可以使用 udp 標記來指定 udp 端口:
docker run -d -p 127.0.0.1:5000:5000/udp training/webapp python app.py
5.查看映射端口配置
使用 docker port
命令來查看當前映射的端口配置, 也可以查看綁定的地址:
docker port 6f3bce18f77c
//輸出信息
5000/tcp -> 0.0.0.0:32768
也可以查看容器中的服務端口, 被映射到了宿主主機的哪個端口:
docker port 6f3bce18f77c 5000
//輸出信息
0.0.0.0:32768
容器有自己的內部網絡和 IP 地址, 使用
docker inspect
+容器 ID 可以獲取容器的具體信息.
互聯機制實現便捷互訪
容器的互聯是一種讓多個容器中應用進行快速交互的方式. 它會在源和接收容器之間創建連接關系, 接收容器可以通過容器名快速訪問到源容器, 而不用指定具體的 ip 地址.
使用 --link
參數可以讓容器之間安全進行交互.
首先創建一個新的容器:
docker run -d --name db training/postgres
然后創建一個新的 web 容器, 并將它連接到 db 容器:
docker run -d -P --name web --link db:aliasDb training/webapp python app.py
此時, db 容器和 web 容器建立互聯關系.
注意:建立互聯關系的時候, 名字為 db 的容器必須在運行.
--link
參數的格式 --link name:alias
, 其中 name 是要連接的容器名稱, alias 是這個連接的別名.
使用 docker ps
來查看容器的連接, 如下所示:
docker ps --no-trunc
//輸出信息
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
10f712c0adf2887d964fe1eb12fd8b602a78f948817c4d54b7fa3b4f7fef821e training/webapp "python app.py" 47 seconds ago Up 46 seconds 0.0.0.0:32772->5000/tcp web
2c3a75c29c989a66c9c8179a39112328b13eced089af9525edc68a198367ba18 training/postgres "su postgres -c '/usr/lib/postgresql/$PG_VERSION/bin/postgres -D /var/lib/postgresql/$PG_VERSION/main/ -c config_file=/etc/postgresql/$PG_VERSION/main/postgresql.conf'" 54 seconds ago Up 53 seconds 5432/tcp db,web/aliasDb
可以看到自定義命名的容器, db 和 web, db 容器的 names 列有 db 也有 web/aliasDb. 這表示 web 容器連接到 db 容器, 這允許 web 容器訪問 db 容器的信息.
Docker 相當于在兩個互聯的容器之間創建了一個虛擬通道, 而且不用映射它們的端口到宿主主機上. 在啟動 db 容器的時候并沒有私用 -p
和 -P
標記, 從而避免了暴露數據庫服務端口到外部網絡上.
Docker 通過兩種方式為容器公開連接信息:
1.更新環境變量.
2.更新 /etc/hosts
文件.
使用 env
命令來查看 web 容器的環境變量:
docker run --rm --name web5 --link db:aliasDb training/webapp env
//輸出信息
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=cf7de1d9281c
ALIASDB_PORT=tcp://172.17.0.2:5432
ALIASDB_PORT_5432_TCP=tcp://172.17.0.2:5432
ALIASDB_PORT_5432_TCP_ADDR=172.17.0.2
ALIASDB_PORT_5432_TCP_PORT=5432
ALIASDB_PORT_5432_TCP_PROTO=tcp
ALIASDB_NAME=/web5/aliasDb
ALIASDB_ENV_PG_VERSION=9.3
HOME=/root
其中 ALIASDB_
開頭的環境變量是通過 web 容器連接 db 容器使用的, 前綴采用大寫的連接別名.
除了環境變量之外, Docker 還添加 host 信息到父容器的 /etc/hosts
文件. 下面是父容器 web 的 hosts 文件:
root@d28f99ea8427:/opt/webapp# 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.17.0.2 aliasDb 2c3a75c29c98 db
172.17.0.5 d28f99ea8427
這里有兩個 hosts 信息, 第一個是 web 容器, web 容器用自己的 id 作為默認主機名(172.17.0.5 d28f99ea8427
), 第二個是 db 容器的 ip 別名 容器 id 和 主機名(172.17.0.2 aliasDb 2c3a75c29c98 db
).
用 ping 來測試 db 容器, 它會解析成 172.17.0.2
. 用戶可以連接多個子容器到父容器, 比如可以連接多個 web 到同一個 db 容器上.