多容器應用程式

到目前為止,您一直在使用單容器應用程式。但是,現在您將嚮應用程式堆疊新增 MySQL。通常會產生以下問題:“MySQL 將在何處執行?在同一個容器中安裝它還是單獨執行它?”一般來說,每個容器應該做好一件事,並且做好它。以下是一些單獨執行容器的原因

  • 您很有可能需要以不同於資料庫的方式擴充套件 API 和前端。
  • 單獨的容器可以讓您獨立地對版本進行版本控制和更新。
  • 雖然您可能在本地使用容器來儲存資料庫,但您可能希望在生產環境中使用託管服務來儲存資料庫。那麼您就不想將資料庫引擎與您的應用程式一起釋出。
  • 執行多個程序將需要一個程序管理器(容器只啟動一個程序),這會增加容器啟動/關閉的複雜性。

還有更多原因。因此,正如以下圖表所示,最好在多個容器中執行您的應用程式。

Todo App connected to MySQL container

容器網路

請記住,容器預設情況下以隔離方式執行,並且不知道同一臺機器上的其他程序或容器。那麼,如何允許一個容器與另一個容器通訊呢?答案是網路。如果您將兩個容器置於同一個網路上,它們就可以相互通訊。

啟動 MySQL

將容器置於網路上主要有兩種方式

  • 在啟動容器時分配網路。
  • 將正在執行的容器連線到網路。

在以下步驟中,您將首先建立網路,然後在啟動時將 MySQL 容器附加到該網路。

  1. 建立網路。

    $ docker network create todo-app
    
  2. 啟動 MySQL 容器並將其附加到網路。您還將定義一些環境變數,資料庫將使用這些環境變數來初始化資料庫。要詳細瞭解 MySQL 環境變數,請參閱 MySQL Docker Hub 列表 中的“環境變數”部分。


    $ docker run -d \
        --network todo-app --network-alias mysql \
        -v todo-mysql-data:/var/lib/mysql \
        -e MYSQL_ROOT_PASSWORD=secret \
        -e MYSQL_DATABASE=todos \
        mysql:8.0
    
    $ docker run -d `
        --network todo-app --network-alias mysql `
        -v todo-mysql-data:/var/lib/mysql `
        -e MYSQL_ROOT_PASSWORD=secret `
        -e MYSQL_DATABASE=todos `
        mysql:8.0
    $ docker run -d ^
        --network todo-app --network-alias mysql ^
        -v todo-mysql-data:/var/lib/mysql ^
        -e MYSQL_ROOT_PASSWORD=secret ^
        -e MYSQL_DATABASE=todos ^
        mysql:8.0
    

    在前面的命令中,您可以看到 `--network-alias` 標誌。在後面的部分中,您將瞭解有關此標誌的更多資訊。

    提示

    您會注意到上述命令中有一個名為 `todo-mysql-data` 的卷,它被掛載到 `\var\lib\mysql`,這是 MySQL 儲存其資料的位置。但是,您從未執行過 `docker volume create` 命令。Docker 識別出您希望使用命名卷,並自動為您建立一個。

  3. 要確認您的資料庫已啟動並執行,請連線到資料庫並驗證它是否已連線。

    $ docker exec -it <mysql-container-id> mysql -u root -p
    

    當出現密碼提示時,請輸入 `secret`。在 MySQL shell 中,列出資料庫並驗證您是否看到 `todos` 資料庫。

    mysql> SHOW DATABASES;
    

    您應該看到類似於以下內容的輸出

    +--------------------+
    | Database           |
    +--------------------+
    | information_schema |
    | mysql              |
    | performance_schema |
    | sys                |
    | todos              |
    +--------------------+
    5 rows in set (0.00 sec)
  4. 退出 MySQL shell 以返回到機器上的 shell。

    mysql> exit
    

    現在您擁有一個 `todos` 資料庫,並且它已準備好供您使用。

連線到 MySQL

既然您知道 MySQL 已啟動並執行,您可以使用它。但是,您如何使用它?如果您在同一個網路上執行另一個容器,您如何找到該容器?請記住,每個容器都有自己的 IP 地址。

為了回答上述問題並更好地理解容器網路,您將使用 nicolaka/netshoot 容器,它附帶了許多用於解決網路問題或除錯網路問題的工具。

  1. 使用 nicolaka/netshoot 映象啟動一個新容器。確保將其連線到同一個網路。

    $ docker run -it --network todo-app nicolaka/netshoot
    
  2. 在容器內部,您將使用 `dig` 命令,這是一個有用的 DNS 工具。您將查詢主機名 `mysql` 的 IP 地址。

    $ dig mysql
    

    您應該獲得類似於以下內容的輸出。

    ; <<>> DiG 9.18.8 <<>> mysql
    ;; global options: +cmd
    ;; Got answer:
    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 32162
    ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
    
    ;; QUESTION SECTION:
    ;mysql.				IN	A
    
    ;; ANSWER SECTION:
    mysql.			600	IN	A	172.23.0.2
    
    ;; Query time: 0 msec
    ;; SERVER: 127.0.0.11#53(127.0.0.11)
    ;; WHEN: Tue Oct 01 23:47:24 UTC 2019
    ;; MSG SIZE  rcvd: 44

    在“ANSWER SECTION”中,您將看到 `mysql` 的 `A` 記錄,它解析為 `172.23.0.2`(您的 IP 地址很可能具有不同的值)。雖然 `mysql` 通常不是有效的主機名,但 Docker 能夠將其解析為具有該網路別名的容器的 IP 地址。請記住,您之前使用了 `--network-alias`。

    這意味著您的應用程式只需連線到名為 `mysql` 的主機,它就會與資料庫進行通訊。

使用 MySQL 執行您的應用程式

todo 應用程式支援設定一些環境變數以指定 MySQL 連線設定。它們是

  • MYSQL_HOST - 執行的 MySQL 伺服器的主機名
  • MYSQL_USER - 用於連線的使用者名稱
  • MYSQL_PASSWORD - 用於連線的密碼
  • MYSQL_DB - 連線後要使用的資料庫

注意

雖然在開發中使用環境變數來設定連線設定是普遍接受的,但在生產環境中執行應用程式時強烈建議不要這樣做。Docker 安全前負責人 Diogo Monica 撰寫了一篇很棒的部落格文章 說明了原因。

一種更安全的機制是使用容器編排框架提供的 secret 支援。在大多數情況下,這些 secret 會作為檔案掛載到正在執行的容器中。您會看到許多應用程式(包括 MySQL 映象和 todo 應用程式)還支援帶有 `_FILE` 字尾的環境變數,以指向包含變數的檔案。

例如,設定 `MYSQL_PASSWORD_FILE` 變數會導致應用程式使用引用檔案的內容作為連線密碼。Docker 不會執行任何操作來支援這些環境變數。您的應用程式需要知道在哪裡查詢變數並獲取檔案內容。

現在您可以啟動開發就緒的容器。

  1. 指定每個先前的環境變數,以及將容器連線到您的應用程式網路。確保在執行此命令時您位於 `getting-started-app` 目錄中。


    $ docker run -dp 127.0.0.1:3000:3000 \
      -w /app -v "$(pwd):/app" \
      --network todo-app \
      -e MYSQL_HOST=mysql \
      -e MYSQL_USER=root \
      -e MYSQL_PASSWORD=secret \
      -e MYSQL_DB=todos \
      node:18-alpine \
      sh -c "yarn install && yarn run dev"
    

    在 Windows 中,在 PowerShell 中執行此命令。

    $ docker run -dp 127.0.0.1:3000:3000 `
      -w /app -v "$(pwd):/app" `
      --network todo-app `
      -e MYSQL_HOST=mysql `
      -e MYSQL_USER=root `
      -e MYSQL_PASSWORD=secret `
      -e MYSQL_DB=todos `
      node:18-alpine `
      sh -c "yarn install && yarn run dev"

    在 Windows 中,在命令提示符中執行此命令。

    $ docker run -dp 127.0.0.1:3000:3000 ^
      -w /app -v "%cd%:/app" ^
      --network todo-app ^
      -e MYSQL_HOST=mysql ^
      -e MYSQL_USER=root ^
      -e MYSQL_PASSWORD=secret ^
      -e MYSQL_DB=todos ^
      node:18-alpine ^
      sh -c "yarn install && yarn run dev"
    
    $ docker run -dp 127.0.0.1:3000:3000 \
      -w //app -v "/$(pwd):/app" \
      --network todo-app \
      -e MYSQL_HOST=mysql \
      -e MYSQL_USER=root \
      -e MYSQL_PASSWORD=secret \
      -e MYSQL_DB=todos \
      node:18-alpine \
      sh -c "yarn install && yarn run dev"
    

  2. 如果您檢視容器的日誌(`docker logs -f `),您應該看到類似於以下內容的訊息,這表明它正在使用 mysql 資料庫。

    $ nodemon src/index.js
    [nodemon] 2.0.20
    [nodemon] to restart at any time, enter `rs`
    [nodemon] watching dir(s): *.*
    [nodemon] starting `node src/index.js`
    Connected to mysql db at host mysql
    Listening on port 3000
    
  3. 在瀏覽器中開啟應用程式,並將一些專案新增到待辦事項列表中。

  4. 連線到 mysql 資料庫並證明專案正在寫入資料庫。請記住,密碼是 `secret`。

    $ docker exec -it <mysql-container-id> mysql -p todos
    

    在 mysql shell 中,執行以下命令

    mysql> select * from todo_items;
    +--------------------------------------+--------------------+-----------+
    | id                                   | name               | completed |
    +--------------------------------------+--------------------+-----------+
    | c906ff08-60e6-44e6-8f49-ed56a0853e85 | Do amazing things! |         0 |
    | 2912a79e-8486-4bc3-a4c5-460793a575ab | Be awesome!        |         0 |
    +--------------------------------------+--------------------+-----------+
    

    您的表格將會有所不同,因為它包含您的專案。但是,您應該看到它們儲存在那裡。

總結

此時,您擁有一個應用程式,該應用程式現在將資料儲存在執行在單獨容器中的外部資料庫中。您瞭解了一些有關容器網路和使用 DNS 的服務發現的知識。

相關資訊

下一步

您很可能開始對啟動此應用程式所需的全部操作感到有點不知所措。您必須建立一個網路,啟動容器,指定所有環境變數,公開埠等等。這些內容需要記住很多,並且確實給其他人傳遞這些資訊帶來了很大困難。

在下一節中,您將瞭解 Docker Compose。使用 Docker Compose,您可以以更簡單的方式共享應用程式堆疊,並讓其他人使用一個簡單的命令啟動它們。