多容器應用程式

到目前為止,您一直使用單容器應用程式。但是,現在您將把 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 殼層中,列出資料庫並驗證您是否看到 `todos` 資料庫。

    mysql> SHOW DATABASES;
    

    您應該會看到如下所示的輸出

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

    mysql> exit
    

    您現在有一個 `todos` 資料庫,可以開始使用了。

連線到 MySQL

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

為了回答上述問題並更好地瞭解容器網路,您將使用 nicolaka/netshoot

  • 在容器內,您將使用 `dig` 命令,這是一個很有用的 DNS 工具。您將查詢主機名稱 `mysql` 的 IP 位址。

    您應該會得到如下所示的輸出。

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

    這表示您的應用程式只需連線到名為 `mysql` 的主機,即可與資料庫通話。

  • 使用 MySQL 執行您的應用程式

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

    注意

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

    一種更安全的機制是使用您的容器協作框架提供的密鑰支援。在大多數情況下,這些密鑰會作為檔案掛載在執行中的容器中。您會看到許多應用程式(包括 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 <container-id>),您應該會看到類似以下的訊息,表示它正在使用 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,您可以更輕鬆地分享您的應用程式堆疊,並讓其他人使用單一、簡單的命令來啟動它們。