使用 Yarn workspace,TypeScript,esbuild,React 和 Express 構建 K8S 雲原生應用(一)

為少發表於2021-05-26

本文將指導您使用 K8S
DockerYarn workspaceTypeScriptesbuildExpressReact 來設定構建一個基本的雲原生 Web 應用程式。 在本教程的最後,您將擁有一個可完全構建和部署在 K8S 上的 Web 應用程式。

設定專案

該專案將被構造為 monorepomonorepo 的目標是提高模組之間共享的程式碼量,並更好地預測這些模組如何一起通訊(例如在微服務架構中)。出於本練習的目的,我們將使結構保持簡單:

  • app,它將代表我們的 React website
  • server,它將使用 Express 服務我們的 app
  • common,其中一些程式碼將在 appserver 之間共享。

設定專案之前的唯一要求是在機器上安裝 yarnYarnnpm 一樣,是一個程式包管理器,但效能更好,功能也略多。 您可以在官方文件中閱讀有關如何安裝它的更多資訊。

Workspaces(工作區)

進入到要初始化專案的資料夾,然後通過您喜歡的終端執行以下步驟:

  1. 使用 mkdir my-app 建立專案的資料夾(可以自由選擇所需的名稱)。
  2. 使用 cd my-app 進入資料夾。
  3. 使用 yarn init 初始化它。這將提示您建立初始 package.json 檔案的相關問題(不用擔心,一旦建立檔案,您可以隨時對其進行修改)。如果您不想使用 yarn init 命令,則始終可以手動建立檔案,並將以下內容複製到其中:
{
  "name": "my-app",
  "version": "1.0.0",
  "license": "UNLICENSED",
  "private": true // Required for yarn workspace to work
}

現在,已經建立了 package.json 檔案,我們需要為我們的模組appcommonserver 建立資料夾。 為了方便 yarn workspace 發現模組並提高專案的可讀性(readability),我們將模組巢狀在 packages 資料夾下:

my-app/
├─ packages/ // 我們當前和將來的所有模組都將存在的地方
│  ├─ app/
│  ├─ common/
│  ├─ server/
├─ package.json

我們的每個模組都將充當一個小型且獨立的專案,並且需要其自己的 package.json 來管理依賴項。要設定它們中的每一個,我們既可以使用 yarn init(在每個資料夾中),也可以手動建立檔案(例如,通過 IDE)。

軟體包名稱使用的命名約定是在每個軟體包之前都使用 @my-app/* 作為字首。這在 NPM 領域中稱為作用域(您可以在此處閱讀更多內容)。您不必像這樣給自己加上字首,但以後會有所幫助。

一旦建立並初始化了所有三個軟體包,您將具有如下所示的相似之處。

app 包:

{
  "name": "@my-app/app",
  "version": "0.1.0",
  "license": "UNLICENSED",
  "private": true
}

common 包:

{
  "name": "@my-app/common",
  "version": "0.1.0",
  "license": "UNLICENSED",
  "private": true
}

server 包:

{
  "name": "@my-app/server",
  "version": "0.1.0",
  "license": "UNLICENSED",
  "private": true
}

最後,我們需要告訴 yarn 在哪裡尋找模組,所以回去編輯專案的 package.json 檔案並新增以下 workspaces 屬性(如果您想了解更多有關詳細資訊,請檢視 Yarnworkspaces 文件)。

{
  "name": "my-app",
  "version": "1.0",
  "license": "UNLICENSED",
  "private": true,
  "workspaces": ["packages/*"] // 在這裡新增
}

您的最終資料夾結構應如下所示:

my-app/
├─ packages/
│  ├─ app/
│  │  ├─ package.json
│  ├─ common/
│  │  ├─ package.json
│  ├─ server/
│  │  ├─ package.json
├─ package.json

現在,您已經完成了專案的基礎設定。

TypeScript

現在,我們將第一個依賴項新增到我們的專案:TypeScriptTypeScriptJavaScript 的超集,可在構建時實現型別檢查。

通過終端進入專案的根目錄,執行 yarn add -D -W typescript

  • 引數 -DTypeScript 新增到 devDependencies,因為我們僅在開發和構建期間使用它。
  • 引數 -W 允許在工作空間根目錄中安裝一個包,使其在 appcommonserver 上全域性可用。

您的 package.json 應該如下所示:

{
  "name": "my-app",
  "version": "1.0",
  "license": "UNLICENSED",
  "private": true,
  "workspaces": ["packages/*"],
  "devDependencies": {
    "typescript": "^4.2.3"
  }
}

這還將建立一個 yarn.lock 檔案(該檔案確保在專案的整個生命週期中依賴項的預期版本保持不變)和一個 node_modules 資料夾,該資料夾儲存依賴項的 binaries

現在我們已經安裝了 TypeScript,一個好習慣是告訴它如何執行。為此,我們將新增一個配置檔案,該檔案應由您的 IDE 拾取(如果使用 VSCode,則會自動獲取)。

在專案的根目錄下建立一個 tsconfig.json 檔案,並將以下內容複製到其中:

{
  "compilerOptions": {
    /* Basic */
    "target": "es2017",
    "module": "CommonJS",
    "lib": ["ESNext", "DOM"],

    /* Modules Resolution */
    "moduleResolution": "node",
    "esModuleInterop": true,

    /* Paths Resolution */
    "baseUrl": "./",
    "paths": {
      "@flipcards/*": ["packages/*"]
    },

    /* Advanced */
    "jsx": "react",
    "experimentalDecorators": true,
    "resolveJsonModule": true
  },
  "exclude": ["node_modules", "**/node_modules/*", "dist"]
}

您可以輕鬆地搜尋每個 compileoptions 屬性及其操作,但對我們最有用的是 paths 屬性。例如,這告訴 TypeScript@my-app/server@my-app/app 包中使用 @my-app/common 匯入時在哪裡查詢程式碼和 typings

您當前的專案結構現在應如下所示:

my-app/
├─ node_modules/
├─ packages/
│  ├─ app/
│  │  ├─ package.json
│  ├─ common/
│  │  ├─ package.json
│  ├─ server/
│  │  ├─ package.json
├─ package.json
├─ tsconfig.json
├─ yarn.lock

新增第一個 script

Yarn workspace 允許我們通過 yarn workspace @my-app/* 命令模式訪問任何子包,但是每次鍵入完整的命令將變得非常多餘。為此,我們可以建立一些 helper script 方法來提升開發體驗。開啟專案根目錄下的 package.json,並向其新增以下 scripts 屬性。

{
  "name": "my-app",
  "version": "1.0",
  "license": "UNLICENSED",
  "private": true,
  "workspaces": ["packages/*"],
  "devDependencies": {
    "typescript": "^4.2.3"
  },
  "scripts": {
    "app": "yarn workspace @my-app/app",
    "common": "yarn workspace @my-app/common",
    "server": "yarn workspace @my-app/server"
  }
}

現在可以像在子包中一樣執行任何命令。例如,您可以通過鍵入 yarn server add express 來新增一些新的依賴項。這將直接向 server 包新增新的依賴項。

在後續部分中,我們將開始構建前端和後端應用程式。

準備 Git

如果計劃使用 Git 作為版本控制工具,強烈建議忽略生成的檔案,例如二進位制檔案或日誌。

為此,請在專案的根目錄下建立一個名為 .gitignore 的新檔案,並將以下內容複製到其中。這將忽略本教程稍後將生成的一些檔案,並避擴音交大量不必要的資料。

# Logs
yarn-debug.log*
yarn-error.log*

# Binaries
node_modules/

# Builds
dist/
**/public/script.js

資料夾結構應如下所示:

my-app/
├─ packages/
├─ .gitignore
├─ package.json

新增程式碼

這部分將著重於將程式碼新增到我們的 commonappserver 包中。

Common

我們將從 common 開始,因為此包將由 appserver 使用。它的目標是提供共享的邏輯(shared logic)和變數(variables)。

檔案

在本教程中,common 軟體包將非常簡單。首先,從新增新資料夾開始:

  • src/ 資料夾,包含包的程式碼。

建立此資料夾後,將以下檔案新增到其中:

src/index.ts

export const APP_TITLE = 'my-app';

現在我們有一些要匯出的程式碼,我們想告訴 TypeScript 從其他包中匯入它時在哪裡尋找它。為此,我們將需要更新 package.json 檔案:

package.json

{
  "name": "@my-app/common",
  "version": "0.1.0",
  "license": "UNLICENSED",
  "private": true,
  "main": "./src/index.ts" // 新增這一行來為 TS 提供入口點
}

我們現在已經完成了 common 包!

結構提醒:

common/
├─ src/
│  ├─ index.ts
├─ package.json

App

依賴項

app 包將需要以下依賴項:

從專案的根目錄執行:

  • yarn app add react react-dom
  • yarn app add -D @types/react @types/react-dom (為 TypeScript 新增型別typings)

package.json

{
  "name": "@my-app/app",
  "version": "0.1.0",
  "license": "UNLICENSED",
  "private": true,
  "dependencies": {
    "@my-app/common": "^0.1.0", // Notice that we've added this import manually
    "react": "^17.0.1",
    "react-dom": "^17.0.1"
  },
  "devDependencies": {
    "@types/react": "^17.0.3",
    "@types/react-dom": "^17.0.2"
  }
}

檔案

要建立我們的 React 應用程式,我們將需要新增兩個新資料夾:

  • 一個 public/ 資料夾,它將儲存基本 HTML 頁面和我們的 assets
  • 一個 src/ 資料夾,其中包含我們應用程式的程式碼。

一旦建立了這兩個資料夾,我們就可以開始新增 HTML 檔案,該檔案將成為我們應用程式的宿主。

public/index.html

<!DOCTYPE html>
<html>
  <head>
    <title>my-app</title>
    <meta name="description" content="Welcome on my application!" />
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <!-- 這個 div 是我們將注入 React 應用程式的地方 -->
    <div id="root"></div>
    <!-- 這是包含我們的應用程式的指令碼的路徑 -->
    <script src="script.js"></script>
  </body>
</html>

現在我們有了要渲染的頁面,我們可以通過新增下面的兩個檔案來實現非常基本但功能齊全的 React 應用程式。

src/index.tsx

import * as React from 'react';
import * as ReactDOM from 'react-dom';

import { App } from './App';

ReactDOM.render(<App />, document.getElementById('root'));

此程式碼從我們的 HTML 檔案掛接到 root div 中,並將 React元件樹 注入其中。

src/App.tsx

import { APP_TITLE } from '@flipcards/common';
import * as React from 'react';

export function App(): React.ReactElement {
  const [count, setCount] = React.useState(0);

  return (
    <div>
      <h1>Welcome on {APP_TITLE}!</h1>
      <p>
        This is the main page of our application where you can confirm that it
        is dynamic by clicking the button below.
      </p>

      <p>Current count: {count}</p>
      <button onClick={() => setCount((prev) => prev + 1)}>Increment</button>
    </div>
  );
}

這個簡單的 App 元件將呈現我們的應用標題和動態計數器。這將是我們的 React tree 的入口點。隨意新增您想要的任何程式碼。

就是這樣!我們已經完成了非常基本的 React 應用程式。目前它並沒有太大的作用,但是我們總是可以稍後再使用它並新增更多功能。

結構提醒:

app/
├─ public/
│  ├─ index.html
├─ src/
│  ├─ App.tsx
│  ├─ index.tsx
├─ package.json

Server

依賴項

server 軟體包將需要以下依賴項:

從專案的根目錄執行:

  • yarn server add cors express
  • yarn server add -D @types/cors @types/express(為 TypeScript 新增型別typings)

package.json

{
  "name": "@my-app/server",
  "version": "0.1.0",
  "license": "UNLICENSED",
  "private": true,
  "dependencies": {
    "@my-app/common": "^0.1.0", // 請注意,我們已手動新增了此匯入
    "cors": "^2.8.5",
    "express": "^4.17.1"
  },
  "devDependencies": {
    "@types/cors": "^2.8.10",
    "@types/express": "^4.17.11"
  }
}

檔案

現在我們的 React 應用程式已經準備就緒,我們需要的最後一部分是伺服器來為其提供服務。首先為其建立以下資料夾:

  • 一個 src/ 資料夾,包含我們伺服器的程式碼。

接下來,新增 server 的主檔案:

src/index.ts

import { APP_TITLE } from '@flipcards/common';
import cors from 'cors';
import express from 'express';
import { join } from 'path';

const PORT = 3000;

const app = express();
app.use(cors());

// 服務來自 "public" 資料夾的靜態資源(例如:當有影像要顯示時)
app.use(express.static(join(__dirname, '../../app/public')));

// 為 HTML 頁面提供服務
app.get('*', (req: any, res: any) => {
  res.sendFile(join(__dirname, '../../app/public', 'index.html'));
});

app.listen(PORT, () => {
  console.log(`${APP_TITLE}'s server listening at http://localhost:${PORT}`);
});

這是一個非常基本的 Express 應用程式,但如果除了單頁應用程式之外我們沒有任何其他服務,那麼這就足夠了。

結構提醒:

server/
├─ src/
│  ├─ index.ts
├─ package.json

構建應用

Bundlers(打包構建捆綁器)

為了將 TypeScript 程式碼轉換為可解釋的 JavaScript 程式碼,並將所有外部庫打包到單個檔案中,我們將使用打包工具。JS/TS 生態系統中有許多捆綁器,如 WebPackParcelRollup,但我們將選擇 esbuild。與其他捆綁器相比,esbuild 自帶了許多預設載入的特性(TypeScript, React),並有巨大的效能提升(快了 100 倍)。如果你有興趣瞭解更多,請花時間閱讀作者的常見問題解答。

這些指令碼將需要以下依賴項:

  • esbuild 是我們的捆綁器
  • ts-nodeTypeScriptREPL,我們將使用它來執行指令碼

從專案的根目錄執行:yarn add -D -W esbuild ts-node

package.json

{
  "name": "my-app",
  "version": "1.0",
  "license": "UNLICENSED",
  "private": true,
  "workspaces": ["packages/*"],
  "devDependencies": {
    "esbuild": "^0.9.6",
    "ts-node": "^9.1.1",
    "typescript": "^4.2.3"
  },
  "scripts": {
    "app": "yarn workspace @my-app/app",
    "common": "yarn workspace @my-app/common",
    "server": "yarn workspace @my-app/server"
  }
}

Build(編譯構建)

現在,我們擁有構建應用程式所需的所有工具,因此讓我們建立第一個指令碼。

首先在專案的根目錄下建立一個名為 scripts/ 的新資料夾。

我們的指令碼將用 TypeScript 編寫,並從命令列使用 ts-node 執行。儘管存在用於 esbuildCLI,但是如果您要傳遞更復雜的引數或將多個工作流組合在一起,則可以通過 JSTS 使用該庫,這更加方便。

scripts/ 資料夾中建立一個 build.ts 檔案,並在下面新增程式碼(我將通過註釋解釋程式碼的作用):

scripts/build.ts

import { build } from 'esbuild';

/**
 * 在構建期間傳遞的通用選項。
 */
interface BuildOptions {
  env: 'production' | 'development';
}

/**
 * app 包的一個構建器函式。
 */
export async function buildApp(options: BuildOptions) {
  const { env } = options;

  await build({
    entryPoints: ['packages/app/src/index.tsx'], // 我們從這個入口點讀 React 應用程式
    outfile: 'packages/app/public/script.js', // 我們在 public/ 資料夾中輸出一個檔案(請記住,在 HTML 頁面中使用了 "script.js")
    define: {
      'process.env.NODE_ENV': `"${env}"`, // 我們需要定義構建應用程式的 Node.js 環境
    },
    bundle: true,
    minify: env === 'production',
    sourcemap: env === 'development',
  });
}

/**
 * server 軟體包的構建器功能。
 */
export async function buildServer(options: BuildOptions) {
  const { env } = options;

  await build({
    entryPoints: ['packages/server/src/index.ts'],
    outfile: 'packages/server/dist/index.js',
    define: {
      'process.env.NODE_ENV': `"${env}"`,
    },
    external: ['express'], // 有些庫必須標記為外部庫
    platform: 'node', // 為 Node 構建時,我們需要為其設定環境
    target: 'node14.15.5',
    bundle: true,
    minify: env === 'production',
    sourcemap: env === 'development',
  });
}

/**
 * 所有軟體包的構建器功能。
 */
async function buildAll() {
  await Promise.all([
    buildApp({
      env: 'production',
    }),
    buildServer({
      env: 'production',
    }),
  ]);
}

// 當我們從終端使用 ts-node 執行指令碼時,將執行此方法
buildAll();

該程式碼很容易解釋,但是如果您覺得遺漏了部分,可以檢視 esbuildAPI文件 以獲取完整的關鍵字列表。

我們的構建指令碼現已完成! 我們需要做的最後一件事是在我們的 package.json 中新增一個新命令,以方便地執行構建操作。

{
  "name": "my-app",
  "version": "1.0",
  "license": "UNLICENSED",
  "private": true,
  "workspaces": ["packages/*"],
  "devDependencies": {
    "esbuild": "^0.9.6",
    "ts-node": "^9.1.1",
    "typescript": "^4.2.3"
  },
  "scripts": {
    "app": "yarn workspace @my-app/app",
    "common": "yarn workspace @my-app/common",
    "server": "yarn workspace @my-app/server",
    "build": "ts-node ./scripts/build.ts" // Add this line here
  }
}

現在,您可以在每次對專案進行更改時從專案的根資料夾執行 yarn build 來啟動構建過程(如何新增hot-reloading,稍後討論)。

結構提醒:

my-app/
├─ packages/
├─ scripts/
│  ├─ build.ts
├─ package.json
├─ tsconfig.json

Serve(提供服務)

我們的應用程式已經構建好並可以提供給全世界使用,我們只需要向 package.json 新增最後一個命令即可:

{
  "name": "my-app",
  "version": "1.0",
  "license": "UNLICENSED",
  "private": true,
  "workspaces": ["packages/*"],
  "devDependencies": {
    "esbuild": "^0.9.6",
    "ts-node": "^9.1.1",
    "typescript": "^4.2.3"
  },
  "scripts": {
    "app": "yarn workspace @my-app/app",
    "common": "yarn workspace @my-app/common",
    "server": "yarn workspace @my-app/server",
    "build": "ts-node ./scripts/build.ts",
    "serve": "node ./packages/server/dist/index.js" // Add this line here
  }
}

由於我們現在正在處理純 JavaScript,因此可以使用 node 二進位制檔案啟動伺服器。因此,繼續執行 yarn serve

如果您檢視控制檯,您將看到伺服器正在成功偵聽。你也可以開啟一個瀏覽器,導航到 http://localhost:3000 來顯示你的 React 應用?!

如果你想在執行時改變埠,你可以用一個環境變數作為字首來啟動 serve 命令: PORT=4000 yarn serve

Docker ?

本節將假定您已經熟悉容器的概念。

為了能夠根據我們的程式碼建立映象,我們需要在計算機上安裝 Docker。要了解如何基於 OS 進行安裝,請花一點時間檢視官方文件

Dockerfile

要生成 Docker 映象,第一步是在我們專案的根目錄下建立一個 Dockerfile(這些步驟可以完全通過 CLI 來完成,但是使用配置檔案是定義構建步驟的預設方式)。

FROM node:14.15.5-alpine

WORKDIR /usr/src/app

# 儘早安裝依賴項,以便如果我們應用程式中的
# 某些檔案發生更改,Docker無需再次下載依賴項,
# 而是從下一步(“ COPY ..”)開始。
COPY ./package.json .
COPY ./yarn.lock .
COPY ./packages/app/package.json ./packages/app/
COPY ./packages/common/package.json ./packages/common/
COPY ./packages/server/package.json ./packages/server/
RUN yarn

# 複製我們應用程式的所有檔案(.gitignore 中指定的檔案除外)
COPY . .

# 編譯 app
RUN yarn build

# Port
EXPOSE 3000

# Serve
CMD [ "yarn", "serve" ]

我將嘗試儘可能詳細地說明這裡發生的事情以及這些步驟的順序為什麼很重要:

  1. FROM 告訴 Docker 將指定的基礎映象用於當前上下文。在我們的案例中,我們希望有一個可以執行 Node.js 應用程式的環境。
  2. WORKDIR 設定容器中的當前工作目錄。
  3. COPY 將檔案或資料夾從當前本地目錄(專案的根目錄)複製到容器中的工作目錄。如您所見,在此步驟中,我們僅複製與依賴項相關的檔案。這是因為 Docker 將每個構建中的命令的每個結果快取為一層。因為我們要優化構建時間和頻寬,所以我們只想在依賴項發生更改(通常比檔案更改發生的頻率小)時重新安裝它們。
  4. RUNshell 中執行命令。
  5. EXPOSE 是用於容器的內部埠(與我們的應用程式的 PORT env 無關)。 這裡的任何值都應該很好,但是如果您想了解更多資訊,可以檢視官方文件
  6. CMD 的目的是提供執行容器的預設值。

如果您想了解更多有關這些關鍵字的資訊,可以檢視 Dockerfile參考

新增 .dockerignore

使用 .dockerignore 檔案不是強制性的,但強烈建議您使用以下檔案:

  • 確保您沒有將垃圾檔案複製到容器中。
  • 使 COPY 命令的使用更加容易。

如果您已經熟悉它,它的工作原理就像 .gitignore 檔案一樣。您可以將以下內容複製到與 Dockerfile 相同級別的 .dockerignore 檔案中,該檔案將被自動提取。

README.md

# Git
.gitignore

# Logs
yarn-debug.log
yarn-error.log

# Binaries
node_modules
*/*/node_modules

# Builds
*/*/build
*/*/dist
*/*/script.js

隨意新增任何您想忽略的檔案,以減輕您的最終映象。

構建 Docker Image

現在我們的應用程式已經為 Docker 準備好了,我們需要一種從 Docker 生成實際映象的方法。為此,我們將向根 package.json新增一個新命令:

{
  "name": "my-app",
  "version": "1.0.0",
  "license": "MIT",
  "private": true,
  "workspaces": ["packages/*"],
  "devDependencies": {
    "esbuild": "^0.9.6",
    "ts-node": "^9.1.1",
    "typescript": "^4.2.3"
  },
  "scripts": {
    "app": "yarn workspace @my-app/app",
    "common": "yarn workspace @my-app/common",
    "server": "yarn workspace @my-app/server",
    "build": "ts-node ./scripts/build.ts",
    "serve": "node ./packages/server/dist/index.js",
    "docker": "docker build . -t my-app" // Add this line
  }
}

docker build . -t my-app 命令告訴 docker 使用當前目錄(.)查詢 Dockerfile,並將生成的映象(-t)命名為 my-app

確保執行了 Docker 守護程式,以便在終端中使用 docker 命令。

現在該命令已經在我們專案的指令碼中,您可以使用 yarn docker 執行它。

在執行該命令後,您應該期望看到以下終端輸出:

Sending build context to Docker daemon  76.16MB
Step 1/12 : FROM node:14.15.5-alpine
 ---> c1babb15a629
Step 2/12 : WORKDIR /usr/src/app
 ---> b593905aaca7
Step 3/12 : COPY ./package.json .
 ---> e0046408059c
Step 4/12 : COPY ./yarn.lock .
 ---> a91db028a6f9
Step 5/12 : COPY ./packages/app/package.json ./packages/app/
 ---> 6430ae95a2f8
Step 6/12 : COPY ./packages/common/package.json ./packages/common/
 ---> 75edad061864
Step 7/12 : COPY ./packages/server/package.json ./packages/server/
 ---> e8afa17a7645
Step 8/12 : RUN yarn
 ---> 2ca50e44a11a
Step 9/12 : COPY . .
 ---> 0642049120cf
Step 10/12 : RUN yarn build
 ---> Running in 15b224066078
yarn run v1.22.5
$ ts-node ./scripts/build.ts
Done in 3.51s.
Removing intermediate container 15b224066078
 ---> 9dce2d505c62
Step 11/12 : EXPOSE 3000
 ---> Running in f363ce55486b
Removing intermediate container f363ce55486b
 ---> 961cd1512fcf
Step 12/12 : CMD [ "yarn", "serve" ]
 ---> Running in 7debd7a72538
Removing intermediate container 7debd7a72538
 ---> df3884d6b3d6
Successfully built df3884d6b3d6
Successfully tagged my-app:latest

就是這樣!現在,我們的映象已建立並註冊在您的機器上,供 Docker 使用。 如果您希望列出可用的 Docker 映象,則可以執行 docker image ls 命令:

→ docker image ls
REPOSITORY    TAG       IMAGE ID        CREATED          SIZE
my-app        latest    df3884d6b3d6    4 minutes ago    360MB

像這樣執行命令

通過命令列執行一個可用的 Docker 映象非常簡單:docker run -d -p 3000:3000 my-app

  • -d 以分離模式執行容器(在後臺)。
  • -p 設定暴露容器的埠(格式為[host port]:[container port])。因此,如果我們想將容器內部的埠 3000(還記得 Dockerfile 中的 EXPOSE 引數)暴露到容器外部的埠 8000,我們將把 8000:3000 傳遞給 -p 標誌。

你可以確認你的容器正在執行 docker ps。這將列出所有正在執行的容器:

如果您對啟動容器有其他要求和疑問,請在此處找到更多資訊。

→ docker ps
CONTAINER ID    IMAGE     COMMAND                  CREATED          STATUS          PORTS                    NAMES
71465a89b58b    my-app    "docker-entrypoint.s…"   7 seconds ago    Up 6 seconds    0.0.0.0:3000->3000/tcp   determined_shockley

現在,開啟瀏覽器並導航到以下URL http://localhost:3000,檢視您正在執行的應用程式?!

我是為少
微信:uuhells123
公眾號:黑客下午茶
加我微信(互相學習交流),關注公眾號(獲取更多學習資料~)

相關文章