玩轉dnmp之埠對映問題解決方案

奕鵬發表於2020-09-18

文章簡介

在上面一篇文章中,分享過如何搭建和使用dnmp,今天分享如何修改dnmp中PHP容器的埠對映功能。

問題歸納

在PHP容器中,安裝了一個swoole擴充套件,啟動了一個server,埠是9501。在安裝dnmp中,docker配置中將9501給暴露出來了,按理來說,啟動服務之後宿主機就可以正常訪問了,但是提示如下資訊。

然後嘗試去telnet埠號,卻發現是測試不通。

 ✘ ert@192  ~  telnet 127.0.0.1 9501
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Connection closed by foreign host.

問題排查

第一步,檢測PHP容器內的9501埠是否正常啟動。發現埠是正常啟動的,接下來,看看是不是對映問題。

/www # netstat -anp | grep 9501
tcp        0      0 0.0.0.0:9501            0.0.0.0:*               LISTEN      69511/tools.Master

第二步,檢視docker的PHP容器埠對映有哪些。

 ✘ ert@192  ~  docker ps                 
CONTAINER ID        IMAGE                COMMAND                  CREATED             STATUS              PORTS                                                      NAMES
68a39b4d38ff        dnmp_php             "docker-php-entrypoi…"   23 hours ago        Up 23 hours         0.0.0.0:9000->9000/tcp, 9501/tcp   php
 ert@192  ~  

發現埠暴露有9000和9501,但是發現9501和9000的卻不一樣。猜想可能是9501沒有給對映出來。接下來,檢視docker-compose.yml的埠設定情況,檢視到如下程式碼:

  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

發現expose設定了9501。於是便檢視了一下docker的expose配置項說明。文件如下:

EXPOSE 指令是宣告執行時容器提供服務埠,這只是一個宣告,在執行時並不會因為這個宣告應用就會開啟這個埠的服務。在 Dockerfile 中寫入這樣的宣告有兩個好處,

a.一個是幫助映象使用者理解這個映象服務的守護埠,以方便配置對映;

b.另一個用處則是在執行時使用隨機埠對映時,也就是 docker run -P 時,會自動隨機對映 EXPOSE 的埠。

要將 EXPOSE 和在執行時使用 -p <宿主埠>:<容器埠> 區分開來。-p,是對映宿主埠和容器埠,換句話說,就是將容器的對應埠服務公開給外界訪問,而 EXPOSE 僅僅是宣告容器打算使用什麼埠而已,並不會自動在宿主進行埠對映。

總結: docker配置檔案中的expose並不是真正的將宿主機的埠和PHP容器的埠做對映。

問題解決

通過上面的分析,發現是實際沒做對映,接下來,我們直接修改一下配置檔案,重新安裝docker容器即可。

第一步:修改如下兩個配置檔案,一個是.env檔案,一個是docker-compose.yml檔案。

// .env
# 這裡就是需要做對映的埠,多配置即可避免後期需要使用。
PHP_HOST_PORT=9000
PHP_HYPERF1_PORT=9501
PHP_HYPERF2_PORT=9502
PHP_HYPERF3_PORT=9503
// docker-compose.yml
  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
    ports:
# 這裡的${xxx}和.env檔案一一對應。
      - "${PHP_HOST_PORT}:9000"
      - "${PHP_HYPERF1_PORT}:9501"
      - "${PHP_HYPERF2_PORT}:9502"
      - "${PHP_HYPERF3_PORT}:9503"
    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

第二步:刪除之前的PHP重啟埠

docker stop 68a39b4d38ff && docker rm 68a39b4d38ff

第三步:重新啟動PHP容器。

docker-compose up php

此時,就重新啟動了一個PHP容器了,並且容器的埠也做好對映了。

 ert@192  ~  docker ps                           
CONTAINER ID        IMAGE                COMMAND                  CREATED             STATUS              PORTS                                                      NAMES
68a39b4d38ff        dnmp_php             "docker-php-entrypoi…"   23 hours ago        Up 23 hours         0.0.0.0:9000->9000/tcp, 0.0.0.0:9501-9503->9501-9503/tcp   php

測試效果

此時,我們啟動PHP容器對應的9501埠服務。訪問,結果如下:

這說明我們的埠對映成功了。接下來,我們進入NGINX容器配置一個反向代理,直接通過域名訪問對應的埠。

upstream travelApi {
    # 這裡的php直接寫PHP容器的名稱即可。
    發現協程127.0.0.1是不行的,因為訪問的是容器內部的埠,
    如果不通過容器訪問,則直接宿主機的IP,但是IP可能會變動,則寫容器名比較合適。
    server php:9501;
}
server {
    listen 80;
    server_name travel_api.com;
    location / {
            proxy_set_header Host $http_host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
               proxy_cookie_path / "/; secure; HttpOnly; SameSite=strict";
            proxy_pass http://travelApi;
    }
}

將對應的域名寫入到宿主機的host檔案,進行訪問,效果如下:

說明我們的反向代理也配置成功了。

問題總結

1.docker中的expose不是做埠對映,而僅僅是宣告埠。

2.容器之間監聽埠,建議使用容器名稱,如NGINX中的反向代理配置。

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章