Chrome Pointer

2023年12月20日 星期三

Docker-compose和mysql 映像和容器的使用教學,及Docker network網路講解

參考文章

💓Docker常用指令介紹


Q:我的node.js在本地安裝跑,可是我的mysql想用docker來裝,有辦法讓這兩個東西連接在一起嗎?

A:可以,但你要讓node.js和mysql連結在同一個網路之中(--network),要在同個網路下面才可以進行通訊。


方法1: mysql和node.js個別run起來

把mysql給run起來

docker run --network=mynetwork --name=mysql-container -e MYSQL_ROOT_PASSWORD=root -d mysql:8.2-oraclelinux8

把node.js的Dockerfile給build起來

docker build -t my-express-app .
把node.js給run起來
docker run --name my-node-app --rm -v D:/mysql:/app --network=mynetwork -p 3000:3000 -d node:14 node /app/server.js

方法1缺點>>

雖然您可以個別使用 docker run 命令來運行單個容器,但在開發和生產環境中,通常會涉及到多個容器相互協作的情況,例如應用程式需要與資料庫服務、消息佇列服務等進行通訊。

方法2: Docker Compose來run起來

這時使用 Docker Compose 可以帶來以下幾個優點:

1. 方便管理多個容器:透過一個配置檔案 (docker-compose.yml),您可以定義並管理多個容器,包括它們的屬性、依賴關係、網路設定等,這樣可以更有效地管理和運行整個應用程式的相關容器。

2. 簡化部署:使用 Docker Compose 可以使應用程式的部署變得更容易,只需在部署環境中運行一個指令 (docker-compose up),即可自動啟動並連接多個容器,而不需要手動運行多個 docker run 命令。

3. 提供環境一致性:使用 Docker Compose 可以確保開發、測試和生產環境之間的一致性,因為您可以在不同環境中使用相同的配置檔案來啟動和管理容器。

雖然可以個別運行容器,但使用 Docker Compose 通常是管理多個相互關聯的容器更簡便和方便的方式。這對於開發、測試和部署複雜的應用程式尤其有益。


👿困難點::

Q: 使用Dockerfile build成一個image後,是不是我的檔案就不能更改了QQ?

A: 需要使用volumes,將本地程式碼目錄掛載到容器內。

services:
  my-node-app:
    volumes:
      - .:/usr/src/app  # 將本地程式碼目錄掛載到容器內
  mysql-container:
    volumes:
      - ./mysql-data:/var/lib/mysql

如果你沒有用volumes來掛載,當stop container後,你之後在start container時,就會發現你在裡面做的更動都不見囉~~

我之前mysql沒有掛載,我進去mysql container裡面創建了DB和Table,但只要我重啟了container後,我新增的東西就會不見。

如果有用volumes,你做的更動會存在本地的./mysql-data資料夾裡面,也就是說就算container重啟,你有進行掛載的資料都還會在唷!!


Q: 為什麼我的server.js跑不出來??? 一直卡住?

CMD ["npm", "start"]到底在幹嘛?

A: npm start 是 Node.js 中的一個預設 script,它用於啟動應用程式。當您在命令列執行 npm start 時,Node.js 會查找 package.json 檔案中的 "scripts" 部分,並找到名為 "start" 的指令。

"scripts": {
  "start": "node server.js"
}

即使在 package.json 文件中沒有明確定義 "start" script,npm start 也能運行成功。這是因為 npm 有一個預設行為:如果沒有定義 "start" script,它會嘗試運行一個叫做 server.js 的文件。

當您運行 npm start 時,npm 會檢查當前目錄下是否有 server.js 文件,如果有的話,它會試圖使用 node server.js 來啟動應用程式。

所以如果你的server取很特別的名字,像是server_wei.js,你就需要加上scripts >> start進去了!!

{
  "dependencies": {
    "express": "^4.17.1",
    "mysql": "^2.18.1",
    "mysql2": "^3.6.5"
  },
  "scripts": {
    "start": "node server_wei.js"
  }
}


🙆尚未建立網路,可以使用以下命令建立一個自定義的 Docker 網路:

docker network create mynetwork

🙆可以使用以下命令來列出 Docker 中目前存在的網絡
docker network ls

如果您的 Docker Compose 專案名為 my_project,

my_project_default 是 Docker Compose 預設為專案建立的網路名稱。

本專案的project名稱為mysql_DockerCopmpose,因此網路名稱為mysql_dockercopmpose_default  。

574b5af1e1a8   mysql_dockercopmpose_default   bridge    local


🙆啟動 MySQL 容器時,使用 --network 參數將容器連接到您剛剛建立的網路中。

docker run --network=mynetwork --name=mysql-container -e MYSQL_ROOT_PASSWORD=root -d mysql:8.2-oraclelinux8

這條指令是用於在 Docker 中啟動名為 mysql-container 的 MySQL 容器,並將其連接到名為 mynetwork 的自定義網路中。該容器使用了 mysql:8.2-oraclelinux8 這個映像。已經正確設置了 root 用戶的密碼為 root。

fdf11af7e81d3d50d4846ebe8dde3a76e83d52ea8113704711bac098db28bffd是所建立的 MySQL 容器的 ID。這個 ID 是容器的唯一標識符。

該容器已以後台(detached)模式運行,MySQL 容器的名稱為 mysql-container,並已加入了名為 mynetwork 的自定義網路。這表示其他容器也可以透過該網路與該 MySQL 容器進行通訊。

🙆列出所有的 Docker 容器,包括運作中的和已經停止的。
docker ps -a


🙆用於在運行中的 MySQL 容器中啟動一個互動式的 Bash 終端。它允許您在容器內部執行命令或進行操作
docker exec -it mysql-container bash

bash-4.4#

mysql -u root -p

Enter password: 輸入root

Welcome to the MySQL monitor.  Commands end with ; or \g.

Your MySQL connection id is 8 ...


🙆或者可以直接把mysql -u root -p加在最後面,可以少打一行。

docker exec -it mysql-container mysql -u root -p


🙆創建DB

create database qq;

Query OK, 1 row affected (0.01 sec)


🙆使用DB

use qq;

Database changed


🙆創建Table

CREATE TABLE q_table (
    id INT, -- 整数类型
    text TEXT -- 文本类型
);
CREATE TABLE messages (
    id INT AUTO_INCREMENT PRIMARY KEY,
    text TEXT
);

Query OK, 0 rows affected (0.02 sec)


🙆插入內容

INSERT INTO q_table (id, text) VALUES (1, 'Some text');
INSERT INTO messages (text) VALUES ('Hello, this is a new message!');
Query OK, 1 row affected (0.01 sec)

🙆Select裡面的資料

SELECT * FROM q_table;

+------+-----------+

| id   | text      |

+------+-----------+

|    1 | Some text |

+------+-----------+

1 row in set (0.00 sec)

SELECT * FROM messages;


🙆Dockerfile

# 使用官方 Node.js 映像作為基礎映像
FROM node:14

# 設定工作目錄
WORKDIR /usr/src/app

# 複製 package.json 和 package-lock.json(如果有的話)
COPY package*.json ./

# 安裝相依套件
RUN npm install

# 複製應用程式代碼到容器中
COPY . .

# 開放應用程式使用的端口
EXPOSE 3000

# 定義啟動應用程式的指令
CMD ["npm", "start"]

👉FROM node:14:

FROM 指令指定了這個 Dockerfile 使用的基礎映像。在這裡,它使用官方的 Node.js 映像作為基礎,版本是 14。這表示您的應用程式將建立在 Node.js 14 的運行環境之上。

👉WORKDIR /usr/src/app:

WORKDIR 指令用於設定容器中的工作目錄。在這裡,它設置工作目錄為 /usr/src/app,這將是您應用程式代碼的主要位置。

👉COPY package*.json ./:

COPY 指令將主機中的 package.json 和 package-lock.json 檔案複製到容器中的工作目錄。這麼做是為了讓 Docker 在建構映像時安裝您應用程式所需的相依套件。

👉RUN npm install:

RUN 指令用於在容器內執行命令。在這裡,它執行 npm install 命令,安裝了在剛才複製進來的 package.json 中定義的相依套件。這個步驟將會在建立映像時執行。

👉COPY . .:

COPY 指令將目前目錄下的所有檔案複製到容器的工作目錄中。這個步驟將會把整個應用程式的代碼複製進容器中。

👉EXPOSE 3000:

EXPOSE 指令定義了容器執行的應用程式使用的端口號。在這裡,它設置容器內部使用的端口號為 3000,但這僅僅是一種宣告,並不會實際打開該端口。

👉CMD ["npm", "start"]:

CMD 指令定義了容器啟動時要運行的預設命令。在這裡,它設置容器啟動後要執行的指令是 npm start,這將啟動您的 Node.js 應用程式。

🙆是一個用於建構 Docker 映像的命令。

docker build -t my-express-app .

docker build: 這是 Docker 命令的一部分,用於建置 Docker 映像。

-t my-express-app: -t 參數用於為您建立的鏡像指定名稱(my-express-app)。


🙆運行名為 my-express-app 的鏡像作為一個容器,並且指定了一些參數:

docker run -d --name my-express-app --network mynetwork -p 3000:3000 my-express-app

-d: 表示以背景模式運行容器。

--name my-express-app: 為容器指定名稱為 my-express-app。

--network mynetwork: 將容器連接到指定的網路,網路名稱為 mynetwork。

-p 3000:3000: 將容器的 3000 端口映射到主機的 3000 端口,這樣您可以通過瀏覽器訪問主機的 3000 端口來訪問容器中運行的應用程式。

my-express-app: 這是要運行的 Docker 映像的名稱。


🙆運行 Docker 容器並執行 Node:14 的映像

docker run --name my-node-app -it --rm --network=mynetwork -v D:/mysql:/app node:14

docker run: 啟動一個新的容器

--name my-node-app: 為容器指定名稱為 my-node-app

-it: 分別代表使用互動式(interactive)的模式運行容器,通常用於在容器內部進行命令行操作

--rm: 當容器停止運行時自動刪除容器

--network=mynetwork: 將容器連接到名為 mynetwork 的網路

-v D:/mysql:/app: 將本機的 D:/mysql 掛載到容器的 /app 目錄,這樣容器內的 /app 目錄將與本機的 D:/mysql 目錄進行資料共享

node:14: 使用的 Docker 映像為 Node.js 的版本 14


🙆運行 Docker 容器並執行 Node:14 的映像+執行node.js伺服器

在這個指令中,-p 3000:3000 表示將容器的 3000 連接埠對應到宿主機器的 3000 連接埠。這樣,您可以在本機瀏覽器中透過 http://127.0.0.1:3000/ 或 http://localhost:3000/ 存取您的 Node.js 伺服器。

docker run --name my-node-app --rm -v D:/mysql:/app --network=mynetwork -p 3000:3000 -d node:14 node /app/server.js

docker run: 啟動一個新的容器

--name my-node-app: 為容器指定名稱為 my-node-app

--rm: 當容器停止運行時自動刪除容器

-v D:/mysql:/app: 將本機的 D:/mysql 掛載到容器的 /app 目錄,這樣容器內的 /app 目錄將與本機的 D:/mysql 目錄進行資料共享

--network=mynetwork: 將容器連接到名為 mynetwork 的網路

-p 3000:3000: 將容器的 3000 端口映射到主機的 3000 端口,使得可以通過訪問主機的 3000 端口來訪問容器中運行的應用程式

-d: 表示以背景模式運行容器

node:14: 使用的 Docker 映像為 Node.js 的版本 14

node /app/server.js: 在容器內運行指令 node /app/server.js,這會執行容器中的 /app/server.js 檔案,開啟一個 Node.js 伺服器。



docker-compose up
docker-compose down

💫💫💫
/mysqld.sock'  port: 3306  MySQL Community Server - GPL.
my-node-app      | Server is running on port 3000
my-node-app      | Error connecting to database: Error: ER_NOT_SUPPORTED_AUTH_MODE: Client does not support authentication protocol requested by server; consider upgrading MySQL client
my-node-app      |     at Handshake.Sequence._packetToError (/usr/src/app/node_modules/mysql/lib/protocol/sequences/Sequence.js:47:14)
my-node-app      |     at Handshake.ErrorPacket (/usr/src/app/node_modules/mysql/lib/protocol/sequences/Handshake.js:123:18)
my-node-app      |     at Protocol._parsePacket (/usr/src/app/node_modules/mysql/lib/protocol/Protocol.js:291:23)
my-node-app      |     at Parser._parsePacket (/usr/src/app/node_modules/mysql/lib/protocol/Parser.js:433:10)
my-node-app      |     at Parser.write (/usr/src/app/node_modules/mysql/lib/protocol/Parser.js:43:10)
my-node-app      |     at Protocol.write (/usr/src/app/node_modules/mysql/lib/protocol/Protocol.js:38:16)
my-node-app      |     at Socket.<anonymous> (/usr/src/app/node_modules/mysql/lib/Connection.js:88:28)
my-node-app      |     at Socket.<anonymous> (/usr/src/app/node_modules/mysql/lib/Connection.js:526:10)
my-node-app      |     at Socket.emit (events.js:400:28)
my-node-app      |     at addChunk (internal/streams/readable.js:293:12)
my-node-app      |     --------------------
my-node-app      |     at Protocol._enqueue (/usr/src/app/node_modules/mysql/lib/protocol/Protocol.js:144:48)
my-node-app      |     at Protocol.handshake (/usr/src/app/node_modules/mysql/lib/protocol/Protocol.js:51:23)
my-node-app      |     at Connection.connect (/usr/src/app/node_modules/mysql/lib/Connection.js:116:18)
my-node-app      |     at Object.<anonymous> (/usr/src/app/server.js:17:12)
my-node-app      |     at Module._compile (internal/modules/cjs/loader.js:1114:14)
my-node-app      |     at Object.Module._extensions..js (internal/modules/cjs/loader.js:1143:10)
my-node-app      |     at Module.load (internal/modules/cjs/loader.js:979:32)
my-node-app      |     at Function.Module._load (internal/modules/cjs/loader.js:819:12)
my-node-app      |     at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:75:12)
my-node-app      |     at internal/main/run_main_module.js:17:47 {
my-node-app      |   code: 'ER_NOT_SUPPORTED_AUTH_MODE',
my-node-app      |   errno: 1251,
my-node-app      |   sqlMessage: 'Client does not support authentication protocol requested by server; consider upgrading MySQL client',
my-node-app      |   sqlState: '08004',
my-node-app      |   fatal: true
my-node-app      | }

這個錯誤表示 MySQL 用戶端不支援 MySQL 伺服器所要求的身份驗證協定。這通常是由於 MySQL 伺服器使用了新的身份驗證插件,而舊版的 MySQL 用戶端不支援這種插件造成的。

解決方法1: 使用mysql2,不要使用mysql

const mysql = require('mysql2');

改成使用mysql2,就成功了!!


解決方法2:使用 npm 命令更新 MySQL 模块

更新前和更新後版本都一樣,即使更新到最新的mysql,也只有2.18.1版本~


D:\mysql>npm show mysql version
2.18.1

D:\mysql>npm install mysql@latest

up to date, audited 86 packages in 4s

11 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

D:\mysql>
D:\mysql>npm show mysql version
2.18.1

因此還是必須要使用mysql2才能成功使用。



👿遇到問題!!
docker failed to solve: Canceled: context canceled

PS D:\mysql_DockerCopmpose> docker-compose up
[+] Building 3.2s (5/9)                                                                                                                  docker:default
 => [my-node-app internal] load .dockerignore                                                                                                      0.0s
 => => transferring context: 81B                                                                                                                   0.0s
 => [my-node-app internal] load build definition from Dockerfile                                                                                   0.0s
 => => transferring dockerfile: 443B                                                                                                               0.0s
 => [my-node-app internal] load metadata for docker.io/library/node:14                                                                             3.0s
 => [my-node-app 1/5] FROM docker.io/library/node:14@sha256:a158d3b9b4e3fa813fa6c8c590b8f0a860e015ad4e59bbce5744d2f6fd8461aa                       0.0s
 => CANCELED [my-node-app internal] load build context                                                                                             0.2s
 => => transferring context: 6.27MB                                                                                                                0.2s
failed to solve: Canceled: context canceled

我把mysql 的volume裡面內容刪除就可以跑了,
總之出現這個訊息可以試著清空/mysql-data~
(mysql-data~刪除後,需要再次創DB、table等內容)

mysql-container:
    volumes:
      - ./mysql-data:/var/lib/mysql


🙆.gitignore
.gitignore 是一個用來指示 Git 忽略哪些檔案或目錄的配置文件。它通常用於排除不應該被版本控制的檔案或目錄,例如暫存檔案、編譯生成的檔案、臨時檔案、敏感資訊等。

👉暫存檔案:通常由編輯器或 IDE 產生的暫存檔案,如 .DS_Store(Mac 系統的暫存檔)、Thumbs.db(Windows 系統的暫存檔)等。

👉編譯生成的檔案:例如編譯後的程式碼、執行檔、程式庫檔案、log 檔案等,這些通常是由編譯器、建置工具或執行程式生成的。

👉臨時檔案:臨時性的檔案或目錄,例如暫時性的下載檔案、快取檔案等。

👉資料夾:排除整個資料夾的路徑,特別是包含大量檔案或敏感資訊的資料夾。

👉敏感資訊:如密碼、私鑰、API 金鑰等應該保密的資訊檔案。

👉自動生成的檔案:由程式自動生成的檔案,如日誌檔案、測試報告等。

👉特定程式語言或框架生成的檔案:某些程式語言或框架會生成特定的檔案或資料夾,可能需要被忽略。

# 忽略暫存檔案 .DS_Store Thumbs.db # 忽略編譯生成的檔案 /dist /build *.log # 忽略臨時檔案 .temp/ .tmp/



沒有留言:

張貼留言

喜歡我的文章嗎? 喜歡的話可以留言回應我喔! ^^