程式語言初學者 Docker 入門第七章 —— 連接埠對應與容器相連

 需要多個服務元件之容器協作運作的情況。需要多個容器之間能夠彼此存取到對方的服務。

除了網路存取,服務連線基本需求還有:

  1. 允許度應容器內應用程式的監聽埠到本地端 Host 主機
  2. 戶連機制(link)實現多個容器間內過容器名稱來快速連接。

對應連接埠來存取容器

1. 從外部存取容器應用程式

啟動容器時如果不指定連接埠對應參數,在容器外部是無法透過網路來存取容器內的各項網路應用和服務

當容器內執行一些網路應用程式,要讓外部存取這些服務時,可以用 -P-p 參數來指定連接埠對應

  • 不加 -p 參數

    $ docker run -d training/webapp python app.py
    c1a2e0f91b6f593e13e05659dd927b391bac65711fcfd0bbac9443002763c648
    $ docker run -d training/webapp python app.py
    de1cb4fbc539b07741821ffe3d72d7cd436fd8ed052f4d4b987e1750d46252b1
    $ docker run -d training/webapp python app.py
    e252e4aab6b252398d7ccce756c7a020dccdf4bc1faf832e35b9c1bdf1145481
    $ docker run -d training/webapp python app.py
    1058336f9128a18c0663ba270550cd8102e23a4be208143de4bbb56cecf81364$ docker run -d training/webapp python app.py
    
    

    可以連開好幾個都正常

    $ docker ps
    CONTAINER ID   IMAGE             COMMAND           CREATED              STATUS              PORTS      NAMES
    1058336f9128   training/webapp   "python app.py"   About a minute ago   Up About a minute   5000/tcp   nervous_haibt
    e252e4aab6b2   training/webapp   "python app.py"   About a minute ago   Up About a minute   5000/tcp   zealous_pike
    de1cb4fbc539   training/webapp   "python app.py"   About a minute ago   Up About a minute   5000/tcp   tender_einstein1
    c1a2e0f91b6f   training/webapp   "python app.py"   About a minute ago   Up About a minute   5000/tcp   lucid_banzai
    

    ports 都是 5000/tpc 全部 container 都沒有遇到 port 衝突

    從這個實驗結果可以了解 container 具有隔離特性,也就是每個 container 都是獨立的個體,它們各自有屬於自己的 5000/tpc 可以用,因此才不會相衝。

    但這樣無法從外界存取 container,因此要做點手腳才行 port forwarding

    Docker 使用 -p 選項設定 port forwarding

  • -P 隨機對應一個 49000~49900 範圍的連接埠到容器內部有開放的連接埠:

    $ docker run -d -P training/webapp python app.py
    $ docker ps -l
    CONTAINER ID   IMAGE             COMMAND           CREATED              STATUS              PORTS                                         NAMES
    565d7910988d   training/webapp   "python app.py"   About a minute ago   Up About a minute   0.0.0.0:49153->5000/tcp, :::49153->5000/tcp   cranky_ritchie
    

    本機的 TCP:49153 port 被對應到容器的 TCP:5000 port

    存取 Host 主機的 49153 連接埠,即可開啟容器內的 web 應用系統所提供的畫面

    docker logs -f cranky_ritchie 查看容器內應用程式資訊

    $ docker logs -f cranky_ritchie
     * Running on <http://0.0.0.0:5000/> (Press CTRL+C to quit)
    

    在網頁輸入

    <http://0.0.0.0:49153/>
    <http://127.0.0.1:49153/>
    <http://10.1.113.39:49153/>
    

    都可以 work

    但是 log 會不一樣

    172.17.0.1 - - [21/Jun/2021 03:43:39] "GET / HTTP/1.1" 200 -
    172.17.0.1 - - [21/Jun/2021 04:02:47] "GET / HTTP/1.1" 200 -
    10.1.113.39 - - [21/Jun/2021 03:39:18] "GET / HTTP/1.1" 200 -
    

    172.17.0.1 是 docker 的 IP

    10.1.113.39 是本機的 IP

  • -p 可以指定要對應的連接埠,支援三種格式

    • IP:HostPort:ContainerPort
    • IP::ContainerPort
    • HostPort:ContainerPort

2. 對應所有界面位址的特定連接埠

使用 HostPort:ContainerPort 格式將本地的 5000 port 對應到容器的 5000 port

$ docker run -d -p 5000:5000 training/webapp python app.py
$ docker ps
CONTAINER ID   IMAGE             COMMAND           CREATED         STATUS         PORTS                                       NAMES
64a6944ba244   training/webapp   "python app.py"   3 seconds ago   Up 2 seconds   0.0.0.0:5000->5000/tcp, :::5000->5000/tcp   hopeful_rubin
$ docker port hopeful_rubin
5000/tcp -> 0.0.0.0:5000
5000/tcp -> :::5000

網頁輸入:http://10.1.113.39:5000/

此時預設會榜定本機所有界面上的所有位址

多次使用 -p 可以榜定多個連接埠

$ docker run -d -p 5000:5000 -p 3000:80 training/webapp python app.py
$ docker ps
CONTAINER ID   IMAGE             COMMAND           CREATED         STATUS         PORTS                                                                              NAMES
c7f16630b2e2   training/webapp   "python app.py"   3 seconds ago   Up 2 seconds   0.0.0.0:5000->5000/tcp, :::5000->5000/tcp, 0.0.0.0:3000->80/tcp, :::3000->80/tcp   naughty_montalcini
$ docker port naughty_montalcini
5000/tcp -> 0.0.0.0:5000
5000/tcp -> :::5000
80/tcp -> 0.0.0.0:3000
80/tcp -> :::3000

3. 對應到特定位址並指定連接埠

IP:HostPort:ContainerPort 指定對應使用一個特定位址

ex: localhost 位址 127.0.0.1:

$ docker run -d -p 127.0.0.1:5000:5000 training/webapp python app.py
$ docker ps
CONTAINER ID   IMAGE             COMMAND           CREATED         STATUS         PORTS                      NAMES
9c93f7b657f6   training/webapp   "python app.py"   2 seconds ago   Up 2 seconds   127.0.0.1:5000->5000/tcp   loving_bell

網頁輸入:

command line 輸入

curl 127.0.0.1:5000
curl 0.0.0.0:5000

4. 對應到特定位址的任意連接埠

IP::ContainerPort 榜定 localhost 的任意連接埠到容器的 5000 port,本地端主機會自動分配一個連接埠:

$ docker run -d -p 127.0.0.1::5000 training/webapp python app.py
$ docker ps
CONTAINER ID   IMAGE             COMMAND           CREATED         STATUS         PORTS                       NAMES
9441c69e82ce   training/webapp   "python app.py"   2 seconds ago   Up 2 seconds   127.0.0.1:49153->5000/tcp   sad_grothendieck
$ curl 127.0.0.1:49153
Hello world!

用 udp 參數 指定 udp port:

$ docker run -d -p 127.0.0.1:5000:5000/udp training/webapp python app.py
$ docker ps
CONTAINER ID   IMAGE             COMMAND           CREATED         STATUS         PORTS                                NAMES
22f6fc5c70eb   training/webapp   "python app.py"   3 seconds ago   Up 2 seconds   5000/tcp, 127.0.0.1:5000->5000/udp   fervent_cartwright

5. 查看對應連接埠

docker port ContainerName ContainerPort

$ docker port sad_grothendieck
5000/tcp -> 127.0.0.1:49153
$ docker port fervent_cartwright
5000/udp -> 127.0.0.1:5000

容器有自己的內部網路和 IP 位址 docker inspect + 容器 ID 可以顯示容器內部資訊

小補充

$ docker run -d -p 8000:80 httpd
a029cadf17ce6fc837a4977cc4201b5028be4f32a9bd9fbf76c8981215d5f33b
$ curl localhost:8000
<html><body><h1>It works!</h1></body></html>
$ curl <http://localhost:8000>
<html><body><h1>It works!</h1></body></html>

使用 Port forwarding 開放服務 - iT 邦幫忙::一起幫忙解決難題,拯救 IT 人的一天

互連機制來實現快速存取

容器的互聯 linking 機制是一種讓多個容器內應用程式進行快速溝通的方式。

他會在來源與接收容器之間建立連接關係,接收容器可以透過容器名稱快速存取到來源容器,而不用指定具體的 IP 位址

1. 自訂容器命名

docker 互連機制依據容器的名稱來執行,好記的容器名字

  • --name 為容器命名

    docker run -d -P --name web training/webapp python app.py
    
  • docker ps -l 查看 latest container

    docker ps -l
    CONTAINER ID   IMAGE             COMMAND           CREATED         STATUS              PORTS                                         NAMES
    db9353d7441e   training/webapp   "python app.py"   2 minutes ago   Up About a minute   0.0.0.0:55000->5000/tcp, :::55000->5000/tcp   web
    
  • docker inspect 查看容器名稱

    docker inspect -f "{{ .Name}}" db93
    /web
    

2. 容器間互連

使用 --link name:alias

<aside> 💡 name 連接的容器名稱 alias 讓要連接之容器來識別用的別名

</aside>

  1. 建立新的容器資料庫

    docker run -d --name db training/postgres
    
  2. 刪除執行中的 web

    $ docker rm -f web
    web
    
  3. 建立一個新的 web 容器並將它連接到 db 容器

    docker run -d -P --name web --link db:db training/webapp python app.py
    
  4. 查看容器連接

    $ docker ps
    CONTAINER ID   IMAGE                  COMMAND                  CREATED         STATUS         PORTS                                           NAMES
    295aa124ae15   training/webapp        "python app.py"          6 seconds ago   Up 4 seconds   0.0.0.0:55002->5000/tcp, :::55002->5000/tcp     web
    fcb136e458a3   training/postgres      "su postgres -c '/us…"   3 minutes ago   Up 3 minutes   5432/tcp                                        db
    

Docker 相當於在兩個互連的容器之間建立一個虛擬通道,而且不用對應他們的連接埠到 Host 主機上。在啟動 db 容器的時候並沒有使用 -p/-P 標記,進而避免了暴露資料庫連接埠到外部網路上

Docker 透過兩種方式為容器公開連接資訊:

  1. 更新環境變數

    使用 env 命令來查看 web 容器的環境變數

    $ docker run --rm --name web2 --link db:db training/webapp env
    PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
    HOSTNAME=73590563bb9b
    DB_PORT=tcp://172.17.0.2:5432
    DB_PORT_5432_TCP=tcp://172.17.0.2:5432
    DB_PORT_5432_TCP_ADDR=172.17.0.2
    DB_PORT_5432_TCP_PORT=5432
    DB_PORT_5432_TCP_PROTO=tcp
    DB_NAME=/web2/db
    DB_ENV_PG_VERSION=9.3
    HOME=/root
    

    <aside> 💡 DB_ 是提供 web 容器連接 db 容器使用的,前綴字採用大寫的連接之容器別名(db)

    </aside>

  2. 更新 /etc/hosts 檔

    連接 web 的 hosts 檔:

    $ docker run -t -i --rm --link db:db training/webapp /bin/bash
    root@bc8513f69256:/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	db 98a6890f8cc4
    172.17.0.5	bc8513f69256
    

    此處有兩個 hosts 資訊:

    1. web 容器:用自己的容器 ID 做為預設主機名稱

    2. db 容器:IP 和主機名稱,可以在 web 容器中安裝 ping 指令來測試與 db 容器的網路是否相通:

      root@5eca5dbf7b16:/opt/webapp# apt-get install -yqq inetutils-ping
      (Reading database ... 18233 files and directories currently installed.)
      Removing ubuntu-minimal (1.325) ...
      Removing iputils-ping (3:20121221-4ubuntu1.1) ...
      Selecting previously unselected package inetutils-ping.
      (Reading database ... 18221 files and directories currently installed.)
      Preparing to unpack .../inetutils-ping_2%3a1.9.2-1_amd64.deb ...
      Unpacking inetutils-ping (2:1.9.2-1) ...
      Setting up inetutils-ping (2:1.9.2-1) ...
      root@5eca5dbf7b16:/opt/webapp# ping db
      PING db (172.17.0.2): 56 data bytes
      64 bytes from 172.17.0.2: icmp_seq=0 ttl=64 time=2.288 ms
      64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.263 ms
      64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.626 ms
      64 bytes from 172.17.0.2: icmp_seq=3 ttl=64 time=1.207 ms
      64 bytes from 172.17.0.2: icmp_seq=4 ttl=64 time=0.261 ms
      64 bytes from 172.17.0.2: icmp_seq=5 ttl=64 time=0.333 ms
      64 bytes from 172.17.0.2: icmp_seq=6 ttl=64 time=0.167 ms
      

      用 ping 來測試 db 容器,他會解析成 172.17.0.2。使用者可也結合多個連接容器到來源容器,例如可以連接多個 web 容器到同一個 db 容器上

Comments

Popular posts from this blog

《 Imgproxy 使用分析一:圖片下載速度優化分析:Akamai CDN vs Imgproxy 效能比較》

《 Akamai + S3 與 CloudFront + Imgproxy + S3 使用分析二:壓縮圖片設計流程:檔案大小 vs 載入時間的權衡》

程式語言初學者 Docker 入門第二章 —— 安裝與驗證 (Mac)