自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

使用Yarn workspace,TypeScript,esbuild,React和Express構(gòu)建 K8S 云原生應(yīng)用(一)

系統(tǒng) 云計算 云原生
本文將指導(dǎo)您使用 K8S ,Docker,Yarn workspace ,TypeScript,esbuild,Express 和 React 來設(shè)置構(gòu)建一個基本的云原生 Web 應(yīng)用程序。在本教程的最后,您將擁有一個可完全構(gòu)建和部署在 K8S 上的 Web 應(yīng)用程序。

本文將指導(dǎo)您使用 K8S ,Docker,Yarn workspace ,TypeScript,esbuild,Express 和 React 來設(shè)置構(gòu)建一個基本的云原生 Web 應(yīng)用程序。在本教程的最后,您將擁有一個可完全構(gòu)建和部署在 K8S 上的 Web 應(yīng)用程序。

設(shè)置項目

該項目將被構(gòu)造為 monorepo。 monorepo 的目標(biāo)是提高模塊之間共享的代碼量,并更好地預(yù)測這些模塊如何一起通信(例如在微服務(wù)架構(gòu)中)。出于本練習(xí)的目的,我們將使結(jié)構(gòu)保持簡單:

  • app,它將代表我們的 React website。
  • server,它將使用 Express 服務(wù)我們的 app。
  • common,其中一些代碼將在 app 和 server 之間共享。

設(shè)置項目之前的唯一要求是在機器上安裝 yarn。 Yarn 與 npm 一樣,是一個程序包管理器,但性能更好,功能也略多。您可以在官方文檔中閱讀有關(guān)如何安裝它的更多信息。

Workspaces(工作區(qū))

進(jìn)入到要初始化項目的文件夾,然后通過您喜歡的終端執(zhí)行以下步驟:

  1. 使用 mkdir my-app 創(chuàng)建項目的文件夾(可以自由選擇所需的名稱)。
  2. 使用 cd my-app 進(jìn)入文件夾。
  3. 使用 yarn init 初始化它。這將提示您創(chuàng)建初始 package.json 文件的相關(guān)問題(不用擔(dān)心,一旦創(chuàng)建文件,您可以隨時對其進(jìn)行修改)。如果您不想使用 yarn init 命令,則始終可以手動創(chuàng)建文件,并將以下內(nèi)容復(fù)制到其中:
  1.   "name""my-app"
  2.   "version""1.0.0"
  3.   "license""UNLICENSED"
  4.   "private"true // Required for yarn workspace to work 

現(xiàn)在,已經(jīng)創(chuàng)建了 package.json 文件,我們需要為我們的模塊app,common 和 server 創(chuàng)建文件夾。為了方便 yarn workspace 發(fā)現(xiàn)模塊并提高項目的可讀性(readability),我們將模塊嵌套在 packages 文件夾下:

  1. my-app/ 
  2. ├─ packages/ // 我們當(dāng)前和將來的所有模塊都將存在的地方 
  3. │  ├─ app/ 
  4. │  ├─ common/ 
  5. │  ├─ server/ 
  6. ├─ package.json 

我們的每個模塊都將充當(dāng)一個小型且獨立的項目,并且需要其自己的 package.json 來管理依賴項。要設(shè)置它們中的每一個,我們既可以使用 yarn init(在每個文件夾中),也可以手動創(chuàng)建文件(例如,通過 IDE)。

軟件包名稱使用的命名約定是在每個軟件包之前都使用 @my-app/* 作為前綴。這在 NPM 領(lǐng)域中稱為作用域。您不必像這樣給自己加上前綴,但以后會有所幫助。

一旦創(chuàng)建并初始化了所有三個軟件包,您將具有如下所示的相似之處。

app 包:

  1.   "name""@my-app/app"
  2.   "version""0.1.0"
  3.   "license""UNLICENSED"
  4.   "private"true 

common 包:

  1.   "name""@my-app/common"
  2.   "version""0.1.0"
  3.   "license""UNLICENSED"
  4.   "private"true 

server 包:

  1.   "name""@my-app/server"
  2.   "version""0.1.0"
  3.   "license""UNLICENSED"
  4.   "private"true 

最后,我們需要告訴 yarn 在哪里尋找模塊,所以回去編輯項目的 package.json 文件并添加以下 workspaces 屬性(如果您想了解更多有關(guān)詳細(xì)信息,請查看 Yarn 的 workspaces 文檔)。

  1.   "name""my-app"
  2.   "version""1.0"
  3.   "license""UNLICENSED"
  4.   "private"true
  5.   "workspaces": ["packages/*"] // 在這里添加 

您的最終文件夾結(jié)構(gòu)應(yīng)如下所示:

  1. my-app/ 
  2. ├─ packages/ 
  3. │  ├─ app/ 
  4. │  │  ├─ package.json 
  5. │  ├─ common/ 
  6. │  │  ├─ package.json 
  7. │  ├─ server/ 
  8. │  │  ├─ package.json 
  9. ├─ package.json 

現(xiàn)在,您已經(jīng)完成了項目的基礎(chǔ)設(shè)置。

TypeScript

現(xiàn)在,我們將第一個依賴項添加到我們的項目:TypeScript。TypeScript 是 JavaScript 的超集,可在構(gòu)建時實現(xiàn)類型檢查。

通過終端進(jìn)入項目的根目錄,運行 yarn add -D -W typescript。

  • 參數(shù) -D 將 TypeScript 添加到 devDependencies,因為我們僅在開發(fā)和構(gòu)建期間使用它。
  • 參數(shù) -W 允許在工作空間根目錄中安裝一個包,使其在 app、common 和 server 上全局可用。

您的 package.json 應(yīng)該如下所示:

  1.   "name""my-app"
  2.   "version""1.0"
  3.   "license""UNLICENSED"
  4.   "private"true
  5.   "workspaces": ["packages/*"], 
  6.   "devDependencies": { 
  7.     "typescript""^4.2.3" 
  8.   } 

這還將創(chuàng)建一個 yarn.lock 文件(該文件確保在項目的整個生命周期中依賴項的預(yù)期版本保持不變)和一個 node_modules 文件夾,該文件夾保存依賴項的 binaries。

現(xiàn)在我們已經(jīng)安裝了 TypeScript,一個好習(xí)慣是告訴它如何運行。為此,我們將添加一個配置文件,該文件應(yīng)由您的 IDE 拾取(如果使用 VSCode,則會自動獲取)。

在項目的根目錄下創(chuàng)建一個 tsconfig.json 文件,并將以下內(nèi)容復(fù)制到其中:

  1.   "compilerOptions": { 
  2.     /* Basic */ 
  3.     "target""es2017"
  4.     "module""CommonJS"
  5.     "lib": ["ESNext""DOM"], 
  6.  
  7.     /* Modules Resolution */ 
  8.     "moduleResolution""node"
  9.     "esModuleInterop"true
  10.  
  11.     /* Paths Resolution */ 
  12.     "baseUrl""./"
  13.     "paths": { 
  14.       "@flipcards/*": ["packages/*"
  15.     }, 
  16.  
  17.     /* Advanced */ 
  18.     "jsx""react"
  19.     "experimentalDecorators"true
  20.     "resolveJsonModule"true 
  21.   }, 
  22.   "exclude": ["node_modules""**/node_modules/*""dist"

您可以輕松地搜索每個 compileoptions 屬性及其操作,但對我們最有用的是 paths 屬性。例如,這告訴 TypeScript 在 @my-app/server 或 @my-app/app 包中使用 @my-app/common 導(dǎo)入時在哪里查找代碼和 typings。

您當(dāng)前的項目結(jié)構(gòu)現(xiàn)在應(yīng)如下所示:

  1. my-app/ 
  2. ├─ node_modules/ 
  3. ├─ packages/ 
  4. │  ├─ app/ 
  5. │  │  ├─ package.json 
  6. │  ├─ common/ 
  7. │  │  ├─ package.json 
  8. │  ├─ server/ 
  9. │  │  ├─ package.json 
  10. ├─ package.json 
  11. ├─ tsconfig.json 
  12. ├─ yarn.lock 

添加第一個 script

Yarn workspace 允許我們通過 yarn workspace @my-app/* 命令模式訪問任何子包,但是每次鍵入完整的命令將變得非常多余。為此,我們可以創(chuàng)建一些 helper script 方法來提升開發(fā)體驗。打開項目根目錄下的 package.json,并向其添加以下 scripts 屬性。

  1.   "name""my-app"
  2.   "version""1.0"
  3.   "license""UNLICENSED"
  4.   "private"true
  5.   "workspaces": ["packages/*"], 
  6.   "devDependencies": { 
  7.     "typescript""^4.2.3" 
  8.   }, 
  9.   "scripts": { 
  10.     "app""yarn workspace @my-app/app"
  11.     "common""yarn workspace @my-app/common"
  12.     "server""yarn workspace @my-app/server" 
  13.   } 

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

在后續(xù)部分中,我們將開始構(gòu)建前端和后端應(yīng)用程序。

準(zhǔn)備 Git

如果計劃使用 Git 作為版本控制工具,強烈建議忽略生成的文件,例如二進(jìn)制文件或日志。

為此,請在項目的根目錄下創(chuàng)建一個名為 .gitignore 的新文件,并將以下內(nèi)容復(fù)制到其中。這將忽略本教程稍后將生成的一些文件,并避免提交大量不必要的數(shù)據(jù)。

  1. # Logs 
  2. yarn-debug.log* 
  3. yarn-error.log* 
  4.  
  5. # Binaries 
  6. node_modules/ 
  7.  
  8. # Builds 
  9. dist/ 
  10. **/public/script.js 

文件夾結(jié)構(gòu)應(yīng)如下所示:

  1. my-app/ 
  2. ├─ packages/ 
  3. ├─ .gitignore 
  4. ├─ package.json 

添加代碼

這部分將著重于將代碼添加到我們的 common、app 和 server 包中。

Common

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

文件

在本教程中,common 軟件包將非常簡單。首先,從添加新文件夾開始:

src/ 文件夾,包含包的代碼。

創(chuàng)建此文件夾后,將以下文件添加到其中:

src/index.ts

  1. export const APP_TITLE = 'my-app'

現(xiàn)在我們有一些要導(dǎo)出的代碼,我們想告訴 TypeScript 從其他包中導(dǎo)入它時在哪里尋找它。為此,我們將需要更新 package.json 文件:

package.json

  1.   "name""@my-app/common"
  2.   "version""0.1.0"
  3.   "license""UNLICENSED"
  4.   "private"true
  5.   "main""./src/index.ts" // 添加這一行來為 TS 提供入口點 

我們現(xiàn)在已經(jīng)完成了 common 包!

結(jié)構(gòu)提醒:

  1. common/ 
  2. ├─ src/ 
  3. │  ├─ index.ts 
  4. ├─ package.json 

App

依賴項

該 app 包將需要以下依賴項:

  • react
  • react-dom

從項目的根目錄運行:

  • yarn app add react react-dom
  • yarn app add -D @types/react @types/react-dom (為 TypeScript 添加類型typings)

package.json

  1.   "name""@my-app/app"
  2.   "version""0.1.0"
  3.   "license""UNLICENSED"
  4.   "private"true
  5.   "dependencies": { 
  6.     "@my-app/common""^0.1.0", // Notice that we've added this import manually 
  7.     "react""^17.0.1"
  8.     "react-dom""^17.0.1" 
  9.   }, 
  10.   "devDependencies": { 
  11.     "@types/react""^17.0.3"
  12.     "@types/react-dom""^17.0.2" 
  13.   } 

文件

要創(chuàng)建我們的 React 應(yīng)用程序,我們將需要添加兩個新文件夾:

  • 一個 public/ 文件夾,它將保存基本 HTML 頁面和我們的 assets。
  • 一個 src/ 文件夾,其中包含我們應(yīng)用程序的代碼。

一旦創(chuàng)建了這兩個文件夾,我們就可以開始添加 HTML 文件,該文件將成為我們應(yīng)用程序的宿主。

public/index.html

  1. <!DOCTYPE html> 
  2. <html> 
  3.   <head> 
  4.     <title>my-app</title> 
  5.     <meta name="description" content="Welcome on my application!" /> 
  6.   </head> 
  7.   <body> 
  8.     <noscript>You need to enable JavaScript to run this app.</noscript> 
  9.     <!-- 這個 div 是我們將注入 React 應(yīng)用程序的地方 --> 
  10.     <div id="root"></div> 
  11.     <!-- 這是包含我們的應(yīng)用程序的腳本的路徑 --> 
  12.     <script src="script.js"></script> 
  13.   </body> 
  14. </html> 

 現(xiàn)在我們有了要渲染的頁面,我們可以通過添加下面的兩個文件來實現(xiàn)非常基本但功能齊全的 React 應(yīng)用程序。

src/index.tsx

  1. import * as React from 'react'
  2. import * as ReactDOM from 'react-dom'
  3.  
  4. import { App } from './App'
  5.  
  6. ReactDOM.render(<App />, document.getElementById('root')); 

此代碼從我們的 HTML 文件掛接到 root div 中,并將 React組件樹 注入其中。

src/App.tsx

  1. import { APP_TITLE } from '@flipcards/common'
  2. import * as React from 'react'
  3.  
  4. export function App(): React.ReactElement { 
  5.   const [count, setCount] = React.useState(0); 
  6.  
  7.   return ( 
  8.     <div> 
  9.       <h1>Welcome on {APP_TITLE}!</h1> 
  10.       <p> 
  11.         This is the main page of our application where you can confirm that it 
  12.         is dynamic by clicking the button below. 
  13.       </p> 
  14.  
  15.       <p>Current count: {count}</p> 
  16.       <button onClick={() => setCount((prev) => prev + 1)}>Increment</button> 
  17.     </div> 
  18.   ); 

這個簡單的 App 組件將呈現(xiàn)我們的應(yīng)用標(biāo)題和動態(tài)計數(shù)器。這將是我們的 React tree 的入口點。隨意添加您想要的任何代碼。

就是這樣!我們已經(jīng)完成了非?;镜?React 應(yīng)用程序。目前它并沒有太大的作用,但是我們總是可以稍后再使用它并添加更多功能。

結(jié)構(gòu)提醒:

  1. app/ 
  2. ├─ public
  3. │  ├─ index.html 
  4. ├─ src/ 
  5. │  ├─ App.tsx 
  6. │  ├─ index.tsx 
  7. ├─ package.json 

Server

依賴項

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

  • cors
  • express

從項目的根目錄運行:

  • yarn server add cors express
  • yarn server add -D @types/cors @types/express(為 TypeScript 添加類型typings)

package.json

  1.   "name""@my-app/server"
  2.   "version""0.1.0"
  3.   "license""UNLICENSED"
  4.   "private"true
  5.   "dependencies": { 
  6.     "@my-app/common""^0.1.0", // 請注意,我們已手動添加了此導(dǎo)入 
  7.     "cors""^2.8.5"
  8.     "express""^4.17.1" 
  9.   }, 
  10.   "devDependencies": { 
  11.     "@types/cors""^2.8.10"
  12.     "@types/express""^4.17.11" 
  13.   } 

文件

現(xiàn)在我們的 React 應(yīng)用程序已經(jīng)準(zhǔn)備就緒,我們需要的最后一部分是服務(wù)器來為其提供服務(wù)。首先為其創(chuàng)建以下文件夾:

  • 一個 src/ 文件夾,包含我們服務(wù)器的代碼。

接下來,添加 server 的主文件:

src/index.ts

  1. import { APP_TITLE } from '@flipcards/common'
  2. import cors from 'cors'
  3. import express from 'express'
  4. import { join } from 'path'
  5.  
  6. const PORT = 3000; 
  7.  
  8. const app = express(); 
  9. app.use(cors()); 
  10.  
  11. // 服務(wù)來自 "public" 文件夾的靜態(tài)資源(例如:當(dāng)有圖像要顯示時) 
  12. app.use(express.static(join(__dirname, '../../app/public'))); 
  13.  
  14. // 為 HTML 頁面提供服務(wù) 
  15. app.get('*', (req: any, res: any) => { 
  16.   res.sendFile(join(__dirname, '../../app/public''index.html')); 
  17. }); 
  18.  
  19. app.listen(PORT, () => { 
  20.   console.log(`${APP_TITLE}'s server listening at http://localhost:${PORT}`); 
  21. }); 

這是一個非常基本的 Express 應(yīng)用程序,但如果除了單頁應(yīng)用程序之外我們沒有任何其他服務(wù),那么這就足夠了。

結(jié)構(gòu)提醒:

  1. server/ 
  2. ├─ src/ 
  3. │  ├─ index.ts 
  4. ├─ package.json 

構(gòu)建應(yīng)用

Bundlers(打包構(gòu)建捆綁器)

為了將 TypeScript 代碼轉(zhuǎn)換為可解釋的 JavaScript 代碼,并將所有外部庫打包到單個文件中,我們將使用打包工具。JS/TS 生態(tài)系統(tǒng)中有許多捆綁器,如 WebPack、Parcel 或 Rollup,但我們將選擇 esbuild。與其他捆綁器相比,esbuild 自帶了許多默認(rèn)加載的特性(TypeScript, React),并有巨大的性能提升(快了 100 倍)。如果你有興趣了解更多,請花時間閱讀作者的常見問題解答。

這些腳本將需要以下依賴項:

  • esbuild 是我們的捆綁器
  • ts-node 是 TypeScript 的 REPL,我們將使用它來執(zhí)行腳本

從項目的根目錄運行:yarn add -D -W esbuild ts-node。

package.json

  1.   "name""my-app"
  2.   "version""1.0"
  3.   "license""UNLICENSED"
  4.   "private"true
  5.   "workspaces": ["packages/*"], 
  6.   "devDependencies": { 
  7.     "esbuild""^0.9.6"
  8.     "ts-node""^9.1.1"
  9.     "typescript""^4.2.3" 
  10.   }, 
  11.   "scripts": { 
  12.     "app""yarn workspace @my-app/app"
  13.     "common""yarn workspace @my-app/common"
  14.     "server""yarn workspace @my-app/server" 
  15.   } 

Build(編譯構(gòu)建)

現(xiàn)在,我們擁有構(gòu)建應(yīng)用程序所需的所有工具,因此讓我們創(chuàng)建第一個腳本。

首先在項目的根目錄下創(chuàng)建一個名為 scripts/ 的新文件夾。

我們的腳本將用 TypeScript 編寫,并從命令行使用 ts-node 執(zhí)行。盡管存在用于 esbuild 的 CLI,但是如果您要傳遞更復(fù)雜的參數(shù)或?qū)⒍鄠€工作流組合在一起,則可以通過 JS 或 TS 使用該庫,這更加方便。

在 scripts/ 文件夾中創(chuàng)建一個 build.ts 文件,并在下面添加代碼(我將通過注釋解釋代碼的作用):

scripts/build.ts

  1. import { build } from 'esbuild'
  2.  
  3. /** 
  4.  * 在構(gòu)建期間傳遞的通用選項。 
  5.  */ 
  6. interface BuildOptions { 
  7.   env: 'production' | 'development'
  8.  
  9. /** 
  10.  * app 包的一個構(gòu)建器函數(shù)。 
  11.  */ 
  12. export async function buildApp(options: BuildOptions) { 
  13.   const { env } = options; 
  14.  
  15.   await build({ 
  16.     entryPoints: ['packages/app/src/index.tsx'], // 我們從這個入口點讀 React 應(yīng)用程序 
  17.     outfile: 'packages/app/public/script.js', // 我們在 public/ 文件夾中輸出一個文件(請記住,在 HTML 頁面中使用了 "script.js") 
  18.     define: { 
  19.       'process.env.NODE_ENV': `"${env}"`, // 我們需要定義構(gòu)建應(yīng)用程序的 Node.js 環(huán)境 
  20.     }, 
  21.     bundle: true
  22.     minify: env === 'production'
  23.     sourcemap: env === 'development'
  24.   }); 
  25.  
  26. /** 
  27.  * server 軟件包的構(gòu)建器功能。 
  28.  */ 
  29. export async function buildServer(options: BuildOptions) { 
  30.   const { env } = options; 
  31.  
  32.   await build({ 
  33.     entryPoints: ['packages/server/src/index.ts'], 
  34.     outfile: 'packages/server/dist/index.js'
  35.     define: { 
  36.       'process.env.NODE_ENV': `"${env}"`, 
  37.     }, 
  38.     external: ['express'], // 有些庫必須標(biāo)記為外部庫 
  39.     platform: 'node', // 為 Node 構(gòu)建時,我們需要為其設(shè)置環(huán)境 
  40.     target: 'node14.15.5'
  41.     bundle: true
  42.     minify: env === 'production'
  43.     sourcemap: env === 'development'
  44.   }); 
  45.  
  46. /** 
  47.  * 所有軟件包的構(gòu)建器功能。 
  48.  */ 
  49. async function buildAll() { 
  50.   await Promise.all([ 
  51.     buildApp({ 
  52.       env: 'production'
  53.     }), 
  54.     buildServer({ 
  55.       env: 'production'
  56.     }), 
  57.   ]); 
  58.  
  59. // 當(dāng)我們從終端使用 ts-node 運行腳本時,將執(zhí)行此方法 
  60. buildAll(); 

該代碼很容易解釋,但是如果您覺得遺漏了部分,可以查看 esbuild 的 API文檔 以獲取完整的關(guān)鍵字列表。

我們的構(gòu)建腳本現(xiàn)已完成!我們需要做的最后一件事是在我們的 package.json 中添加一個新命令,以方便地運行構(gòu)建操作。

  1.   "name""my-app"
  2.   "version""1.0"
  3.   "license""UNLICENSED"
  4.   "private"true
  5.   "workspaces": ["packages/*"], 
  6.   "devDependencies": { 
  7.     "esbuild""^0.9.6"
  8.     "ts-node""^9.1.1"
  9.     "typescript""^4.2.3" 
  10.   }, 
  11.   "scripts": { 
  12.     "app""yarn workspace @my-app/app"
  13.     "common""yarn workspace @my-app/common"
  14.     "server""yarn workspace @my-app/server"
  15.     "build""ts-node ./scripts/build.ts" // Add this line here 
  16.   } 

現(xiàn)在,您可以在每次對項目進(jìn)行更改時從項目的根文件夾運行 yarn build 來啟動構(gòu)建過程(如何添加hot-reloading,稍后討論)。

結(jié)構(gòu)提醒:

  1. my-app/ 
  2. ├─ packages/ 
  3. ├─ scripts/ 
  4. │  ├─ build.ts 
  5. ├─ package.json 
  6. ├─ tsconfig.json 

Serve(提供服務(wù))

我們的應(yīng)用程序已經(jīng)構(gòu)建好并可以提供給全世界使用,我們只需要向 package.json 添加最后一個命令即可:

  1.   "name""my-app"
  2.   "version""1.0"
  3.   "license""UNLICENSED"
  4.   "private"true
  5.   "workspaces": ["packages/*"], 
  6.   "devDependencies": { 
  7.     "esbuild""^0.9.6"
  8.     "ts-node""^9.1.1"
  9.     "typescript""^4.2.3" 
  10.   }, 
  11.   "scripts": { 
  12.     "app""yarn workspace @my-app/app"
  13.     "common""yarn workspace @my-app/common"
  14.     "server""yarn workspace @my-app/server"
  15.     "build""ts-node ./scripts/build.ts"
  16.     "serve""node ./packages/server/dist/index.js" // Add this line here 
  17.   } 

由于我們現(xiàn)在正在處理純 JavaScript,因此可以使用 node 二進(jìn)制文件啟動服務(wù)器。因此,繼續(xù)運行 yarn serve。

如果您查看控制臺,您將看到服務(wù)器正在成功偵聽。你也可以打開一個瀏覽器,導(dǎo)航到 http://localhost:3000 來顯示你的 React 應(yīng)用🎉!

如果你想在運行時改變端口,你可以用一個環(huán)境變量作為前綴來啟動 serve 命令: PORT=4000 yarn serve。

Docker 🐳

本節(jié)將假定您已經(jīng)熟悉容器的概念。

為了能夠根據(jù)我們的代碼創(chuàng)建鏡像,我們需要在計算機上安裝 Docker。要了解如何基于 OS 進(jìn)行安裝,請花一點時間查看官方文檔 。

Dockerfile

要生成 Docker 鏡像,第一步是在我們項目的根目錄下創(chuàng)建一個 Dockerfile(這些步驟可以完全通過 CLI 來完成,但是使用配置文件是定義構(gòu)建步驟的默認(rèn)方式)。

  1. FROM node:14.15.5-alpine 
  2.  
  3. WORKDIR /usr/src/app 
  4.  
  5. # 盡早安裝依賴項,以便如果我們應(yīng)用程序中的 
  6. # 某些文件發(fā)生更改,Docker無需再次下載依賴項, 
  7. # 而是從下一步(“ COPY ..”)開始。 
  8. COPY ./package.json . 
  9. COPY ./yarn.lock . 
  10. COPY ./packages/app/package.json ./packages/app/ 
  11. COPY ./packages/common/package.json ./packages/common/ 
  12. COPY ./packages/server/package.json ./packages/server/ 
  13. RUN yarn 
  14.  
  15. # 復(fù)制我們應(yīng)用程序的所有文件(.gitignore 中指定的文件除外) 
  16. COPY . . 
  17.  
  18. # 編譯 app 
  19. RUN yarn build 
  20.  
  21. # Port 
  22. EXPOSE 3000 
  23.  
  24. # Serve 
  25. CMD [ "yarn""serve" ] 

我將嘗試盡可能詳細(xì)地說明這里發(fā)生的事情以及這些步驟的順序為什么很重要:

  1. FROM 告訴 Docker 將指定的基礎(chǔ)鏡像用于當(dāng)前上下文。在我們的案例中,我們希望有一個可以運行 Node.js 應(yīng)用程序的環(huán)境。
  2. WORKDIR 設(shè)置容器中的當(dāng)前工作目錄。
  3. COPY 將文件或文件夾從當(dāng)前本地目錄(項目的根目錄)復(fù)制到容器中的工作目錄。如您所見,在此步驟中,我們僅復(fù)制與依賴項相關(guān)的文件。這是因為 Docker 將每個構(gòu)建中的命令的每個結(jié)果緩存為一層。因為我們要優(yōu)化構(gòu)建時間和帶寬,所以我們只想在依賴項發(fā)生更改(通常比文件更改發(fā)生的頻率小)時重新安裝它們。
  4. RUN 在 shell 中執(zhí)行命令。
  5. EXPOSE 是用于容器的內(nèi)部端口(與我們的應(yīng)用程序的 PORT env 無關(guān))。這里的任何值都應(yīng)該很好,但是如果您想了解更多信息,可以查看官方文檔。
  6. CMD 的目的是提供執(zhí)行容器的默認(rèn)值。

如果您想了解更多有關(guān)這些關(guān)鍵字的信息,可以查看 Dockerfile參考。

添加 .dockerignore

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

  • 確保您沒有將垃圾文件復(fù)制到容器中。
  • 使 COPY 命令的使用更加容易。

如果您已經(jīng)熟悉它,它的工作原理就像 .gitignore 文件一樣。您可以將以下內(nèi)容復(fù)制到與 Dockerfile 相同級別的 .dockerignore 文件中,該文件將被自動提取。

  1. README.md 
  2.  
  3. # Git 
  4. .gitignore 
  5.  
  6. # Logs 
  7. yarn-debug.log 
  8. yarn-error.log 
  9.  
  10. # Binaries 
  11. node_modules 
  12. */*/node_modules 
  13.  
  14. # Builds 
  15. */*/build 
  16. */*/dist 
  17. */*/script.js 

隨意添加任何您想忽略的文件,以減輕您的最終鏡像。

構(gòu)建 Docker Image

現(xiàn)在我們的應(yīng)用程序已經(jīng)為 Docker 準(zhǔn)備好了,我們需要一種從 Docker 生成實際鏡像的方法。為此,我們將向根 package.json添加一個新命令:

  1.   "name""my-app"
  2.   "version""1.0.0"
  3.   "license""MIT"
  4.   "private"true
  5.   "workspaces": ["packages/*"], 
  6.   "devDependencies": { 
  7.     "esbuild""^0.9.6"
  8.     "ts-node""^9.1.1"
  9.     "typescript""^4.2.3" 
  10.   }, 
  11.   "scripts": { 
  12.     "app""yarn workspace @my-app/app"
  13.     "common""yarn workspace @my-app/common"
  14.     "server""yarn workspace @my-app/server"
  15.     "build""ts-node ./scripts/build.ts"
  16.     "serve""node ./packages/server/dist/index.js"
  17.     "docker""docker build . -t my-app" // Add this line 
  18.   } 

docker build . -t my-app 命令告訴 docker 使用當(dāng)前目錄(.)查找 Dockerfile,并將生成的鏡像(-t)命名為 my-app。

確保運行了 Docker 守護(hù)進(jìn)程,以便在終端中使用 docker 命令。

現(xiàn)在該命令已經(jīng)在我們項目的腳本中,您可以使用 yarn docker 運行它。

在運行該命令后,您應(yīng)該期望看到以下終端輸出:

  1. Sending build context to Docker daemon  76.16MB 
  2. Step 1/12 : FROM node:14.15.5-alpine 
  3.  ---> c1babb15a629 
  4. Step 2/12 : WORKDIR /usr/src/app 
  5.  ---> b593905aaca7 
  6. Step 3/12 : COPY ./package.json . 
  7.  ---> e0046408059c 
  8. Step 4/12 : COPY ./yarn.lock . 
  9.  ---> a91db028a6f9 
  10. Step 5/12 : COPY ./packages/app/package.json ./packages/app/ 
  11.  ---> 6430ae95a2f8 
  12. Step 6/12 : COPY ./packages/common/package.json ./packages/common/ 
  13.  ---> 75edad061864 
  14. Step 7/12 : COPY ./packages/server/package.json ./packages/server/ 
  15.  ---> e8afa17a7645 
  16. Step 8/12 : RUN yarn 
  17.  ---> 2ca50e44a11a 
  18. Step 9/12 : COPY . . 
  19.  ---> 0642049120cf 
  20. Step 10/12 : RUN yarn build 
  21.  ---> Running in 15b224066078 
  22. yarn run v1.22.5 
  23. $ ts-node ./scripts/build.ts 
  24. Done in 3.51s. 
  25. Removing intermediate container 15b224066078 
  26.  ---> 9dce2d505c62 
  27. Step 11/12 : EXPOSE 3000 
  28.  ---> Running in f363ce55486b 
  29. Removing intermediate container f363ce55486b 
  30.  ---> 961cd1512fcf 
  31. Step 12/12 : CMD [ "yarn""serve" ] 
  32.  ---> Running in 7debd7a72538 
  33. Removing intermediate container 7debd7a72538 
  34.  ---> df3884d6b3d6 
  35. Successfully built df3884d6b3d6 
  36. Successfully tagged my-app:latest 

就是這樣!現(xiàn)在,我們的鏡像已創(chuàng)建并注冊在您的機器上,供 Docker 使用。如果您希望列出可用的 Docker 鏡像,則可以運行 docker image ls 命令:

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

像這樣運行命令

通過命令行運行一個可用的 Docker 鏡像非常簡單:docker run -d -p 3000:3000 my-app

  • -d 以分離模式運行容器(在后臺)。
  • -p 設(shè)置暴露容器的端口(格式為[host port]:[container port])。因此,如果我們想將容器內(nèi)部的端口 3000(還記得 Dockerfile 中的 EXPOSE 參數(shù))暴露到容器外部的端口 8000,我們將把 8000:3000 傳遞給 -p 標(biāo)志。

你可以確認(rèn)你的容器正在運行 docker ps。這將列出所有正在運行的容器:

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

現(xiàn)在,打開瀏覽器并導(dǎo)航到以下URL http://localhost:3000,查看您正在運行的應(yīng)用程序🚀!

 

責(zé)任編輯:姜華 來源: 黑客下午茶
相關(guān)推薦

2024-09-26 09:50:07

2025-01-03 08:08:56

2023-07-26 00:12:04

2021-08-13 07:00:41

云原生k8sspringboot

2021-08-26 07:20:05

云原生K8sSpringboot

2023-03-06 07:19:50

2021-04-25 10:26:58

云計算云原生

2022-04-07 10:17:18

云原生服務(wù)器優(yōu)化

2023-03-03 07:54:21

2022-11-08 08:55:31

2023-03-07 07:56:37

Sqoopk8s底層

2024-06-12 13:21:06

2022-10-14 07:42:50

LuceneHTTPWeb

2020-11-30 23:41:32

K8s容器云計算

2022-08-21 07:25:09

Flink云原生K8S

2023-08-04 08:19:02

2022-11-06 21:31:11

云原生Sentinel集群模式

2022-07-18 18:48:32

Kubernetes云原生

2023-02-08 07:55:33

K8sHPA服務(wù)器

2023-09-06 08:12:04

k8s云原生
點贊
收藏

51CTO技術(shù)棧公眾號