Nighthree
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
      • Invitee
    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Versions and GitHub Sync Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
Invitee
Publish Note

Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

Your note will be visible on your profile and discoverable by anyone.
Your note is now live.
This note is visible on your profile and discoverable online.
Everyone on the web can find and read all notes of this public team.
See published notes
Unpublish note
Please check the box to agree to the Community Guidelines.
View profile
Engagement control
Commenting
Permission
Disabled Forbidden Owners Signed-in users Everyone
Enable
Permission
  • Forbidden
  • Owners
  • Signed-in users
  • Everyone
Suggest edit
Permission
Disabled Forbidden Owners Signed-in users Everyone
Enable
Permission
  • Forbidden
  • Owners
  • Signed-in users
Emoji Reply
Enable
Import from Dropbox Google Drive Gist Clipboard
   owned this note    owned this note      
Published Linked with GitHub
Subscribed
  • Any changes
    Be notified of any changes
  • Mention me
    Be notified of mention me
  • Unsubscribe
Subscribe
# 前端 docker 優雅打包切分環境 ###### tags: `docker` `dockerfile` `frontend` 團隊最近要使用 `GitLab` `CI/CD` 功能了,DevOps 介紹完之後馬上就意識到有個很久的問題必須要解決,之前很菜的時候以及開發流程還沒有很完整的時候還可以手動來決定正式環境還是測試環境 docker 再打包就好,現在需要透過 `Dockerfile` 產生編譯結果以及透過文件指令來區分兩者的差別。 #### 目標: 1. 需要修改的項目越少越好。 2. 最好的狀況是透過設定好的文件和指令互相作用產生不同的編譯結果。 #### 主要步驟: 1. 在 Dockerfile 產生編譯結果 2. 透過打包指令產生正式環境或測試環境 ## 菜雞流程 1. 手動執行 `npm run build` 或 `npm run dev` 2. 打包成 `image` `docker build -t tag_name .` 3. `Dockerfile` 單純只複製 `dist` 內容 ```dockerfile= FROM node:lts-alpine RUN npm install -g http-server RUN mkdir dist COPY ./dist ./dist EXPOSE 8080 CMD [ "http-server", "dist" ] ``` ![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEmNtd95Xk6epc0qou7XkTqnrfaBR6rRBfxH_nIpKHF4lAWp4GDtj7VKUdxcD7Gyrhdr6e_ZQPOeyy2NU7Fe9_OGF_FiaBogBG-gFwVvPvLednJszKIl7nAqFNKlg_kvamN9KDZdzTy265XinEnTrLM2kHR7ONQJhdEmSw8yDCbL0l1YaopFjiayFm/s611/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202022-06-23%20105155.jpg) 這些動作我原本都是透過編輯 sh 檔來完成,不想要正式環境更新就把指令註解起來,~~兩個都不想更新就通通註解起來,~~ 最後我只要下指令`sh maker.sh` 系統就會做完所有事。 ## 在 Dockerfile 產生編譯結果 很多文章分享的大概會是這樣子的 Dockerfile 內容 ```dockerfile= FROM node:lts-alpine RUN npm install -g http-server WORKDIR /app COPY package*.json ./ RUN npm install --production COPY . . RUN npm run build EXPOSE 80 CMD [ "http-server", "dist" ] ``` 如果以官方範例模板來說這段其實沒問題,因為檔案夠小還包得住,但是當專案已經安裝了很多套件或是有點規模時就包不住了,因為 `CPOY . .` 指令,這個指令是把根目錄的所有東西複製到 docker 環境裡,然而 `node_modules` 也一起複製進去了啊啊啊。 神奇的是即便我寫了 `.dockerignore` 忽略 `node_modules` 仍然會失敗(好像和內存有關??),所以我只好把 `npm run build` 的動作從 `Dockerfile` 分離,就產生了前一段的菜雞流程。 我把這個困擾我很久的問題描述給 DevOps,他跟我說 `Dockerfile` 在打包的時候可以多段建構,每一段的建構環境都是乾淨的而且可以互相指向,並給我他使用的 `Dockerfile` 給我當參考。 修改運行成功的結果 Dockerfile : ```dockerfile= # Builder FROM node:14.19 as builder WORKDIR /app COPY . . RUN npm install RUN npm run build # Distribution FROM node:lts-alpine RUN npm install -g http-server RUN mkdir dist COPY --from=builder /app/dist ./dist EXPOSE 8080 CMD [ "http-server", "dist" ] ``` 第一段是在 Docker 進行編譯 `npm run build`,第二段是只將編譯好的結果包起來。 切分建構階段的關鍵是 `FROM` 以及 `as` 指令,我們可以將第一段建構環境使用 `as` 命名,讓第二段建構可以透過 `--from=builder` 指向到第一段環境 `COPY` 出 `dist` 內容,docker 會依照最後建構階段的內容打包成 `image`,並且容量也和菜雞流程包出來的容量一樣小。 [官方文件說明](https://docs.docker.com/develop/develop-images/multistage-build/)、[非官方中文說明](https://yeasy.gitbook.io/docker_practice/image/multistage-builds) 要注意的是如果 `FROM` 一樣的話,那 docker 會自動認為那是同個環境,像是如果我把第二階段改成 `FROM node:14.19` 與第一段相同,那打包出來的容量會超大 XDDD,因為第一段執行過 `npm install` 產生的 `node_modules` 也一起包進去了。 ## 透過打包指令產生正式環境或測試環境 由於前後分離的關係,前端程式碼大多已經是編譯好的結果,不像後端程式碼可以隨時修改環境變數產生變化,也就是所謂的靜態檔案,搜尋了很多如何讓前端程式碼根據指令來替換環境變數,第一時間看到的大多是透過 `shell` 指令來修改關鍵字,但是我覺得那樣太暴力了,應該有更好的方法。 理想的狀況是在 `docker build` 的時候修改 `Dockerfile`,從 `npm run build` 改為 `npm run dev` 指令,但是 `Dockerfile` 所提供的指令 `ENV` `ARG` 偏向修改環境變數,但環境變數已經寫好在專案中的 `.env` 了,所以不符合我的需求。 這問題困擾我很久,弄得我好焦慮 XD,突然間想到 不然輸入 `docker build --help` 看有什麼東西好了。 看到 `Options` 有段描述 ``` -f, --file string Name of the Dockerfile (Default is 'PATH/Dockerfile') ``` 原來 `Dockerfile` 不一定要叫 `Dockerfile` 啊 XDDD,也可以下指令讓 docker 去執行指定檔名,這樣我就可以寫好兩個 `Dockerfile` 然後下 `docker build` 指令時就可以分別使用不同的 `Dockerfile` 產生不同的前端環境。 我在根目錄寫了兩份 `Dockerfile` 分別是 `Dockerfile_dev` `Dockerfile_pro`,差別只有 `npm run dev` 和 `npm run build` 當我要產生測試環境時指令為: ``` docker build -t tag_name_dev -f ./Dockerfile_dev . ``` 正式環境時指令為: ``` docker build -t tag_name_pro -f ./Dockerfile_pro . ``` 這樣 docker 就可以根據我的指令產生不同編譯結果以及不同情境的 image,也達成了 `目標 2. 透過設定好的文件和指令互相作用產生不同的編譯結果`。 ### 檔名 上一段我把 `Dockerfile` 檔名改為 `Dockerfile_dev` 這樣在 VS Code 會失去主題,有夠醜XDD,改成 `dev.Dockerfile` 就會吃到主題, ![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiV0--5LOsAS-LGNEaChQLcZ9WMWXdDZAuJZECw3XxFn6rUVVvhBUYIBjkSEx439-mO6J9K5JiqGaDL0Oz73nMTxNC_9mGHoucMR6ZGKK6yp050DbvwiIgXcI0yYZ9wF4kz85DFokAYLZ4XNsM-THmYvIs0aDi9yGfQU9lkJl3KVeNuqU89YhB2Rui/s385/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202022-06-23%20155559.jpg) 但是 docker 相關的檔案被四散排列有點不好找,我再把檔名改成 `.dDev.Dockerfile`, ![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9kluctEm97mzhrCmeQu6hDInjDg3ghitmFaf2HfCV3i_LhPvaRFVI7zNWdPfUkxi8PO0sDpXRgge4Rbi1hWdWES3723R6tzJij4zMwwLqDzB7T-tJjNYO5pG-gzqxSN9GI4VbW-HDDw2sT2B67FBT4sHA_6AGpi-XxFExK43ppVXewqFAWnBmgpso/s396/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202022-06-23%20155534.jpg) docker 圖案排在一起看起來舒服多了XD,而且指令也能正常發動。 ``` docker build -t tag_name_dev -f ./.dDev.Dockerfile . ``` ## 結語 這次解決了一直以來的問題,更完善了團隊前端 docker 打包流程,現階段我所理解的前端打包部分就到這裡了,如果有新發現再回來修改~

Import from clipboard

Paste your markdown or webpage here...

Advanced permission required

Your current role can only read. Ask the system administrator to acquire write and comment permission.

This team is disabled

Sorry, this team is disabled. You can't edit this note.

This note is locked

Sorry, only owner can edit this note.

Reach the limit

Sorry, you've reached the max length this note can be.
Please reduce the content or divide it to more notes, thank you!

Import from Gist

Import from Snippet

or

Export to Snippet

Are you sure?

Do you really want to delete this note?
All users will lose their connection.

Create a note from template

Create a note from template

Oops...
This template has been removed or transferred.
Upgrade
All
  • All
  • Team
No template.

Create a template

Upgrade

Delete template

Do you really want to delete this template?
Turn this template into a regular note and keep its content, versions, and comments.

This page need refresh

You have an incompatible client version.
Refresh to update.
New version available!
See releases notes here
Refresh to enjoy new features.
Your user state has changed.
Refresh to load new user state.

Sign in

Forgot password

or

By clicking below, you agree to our terms of service.

Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
Wallet ( )
Connect another wallet

New to HackMD? Sign up

Help

  • English
  • 中文
  • Français
  • Deutsch
  • 日本語
  • Español
  • Català
  • Ελληνικά
  • Português
  • italiano
  • Türkçe
  • Русский
  • Nederlands
  • hrvatski jezik
  • język polski
  • Українська
  • हिन्दी
  • svenska
  • Esperanto
  • dansk

Documents

Help & Tutorial

How to use Book mode

Slide Example

API Docs

Edit in VSCode

Install browser extension

Contacts

Feedback

Discord

Send us email

Resources

Releases

Pricing

Blog

Policy

Terms

Privacy

Cheatsheet

Syntax Example Reference
# Header Header 基本排版
- Unordered List
  • Unordered List
1. Ordered List
  1. Ordered List
- [ ] Todo List
  • Todo List
> Blockquote
Blockquote
**Bold font** Bold font
*Italics font* Italics font
~~Strikethrough~~ Strikethrough
19^th^ 19th
H~2~O H2O
++Inserted text++ Inserted text
==Marked text== Marked text
[link text](https:// "title") Link
![image alt](https:// "title") Image
`Code` Code 在筆記中貼入程式碼
```javascript
var i = 0;
```
var i = 0;
:smile: :smile: Emoji list
{%youtube youtube_id %} Externals
$L^aT_eX$ LaTeX
:::info
This is a alert area.
:::

This is a alert area.

Versions and GitHub Sync
Get Full History Access

  • Edit version name
  • Delete

revision author avatar     named on  

More Less

Note content is identical to the latest version.
Compare
    Choose a version
    No search result
    Version not found
Sign in to link this note to GitHub
Learn more
This note is not linked with GitHub
 

Feedback

Submission failed, please try again

Thanks for your support.

On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

Please give us some advice and help us improve HackMD.

 

Thanks for your feedback

Remove version name

Do you want to remove this version name and description?

Transfer ownership

Transfer to
    Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

      Link with GitHub

      Please authorize HackMD on GitHub
      • Please sign in to GitHub and install the HackMD app on your GitHub repo.
      • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
      Learn more  Sign in to GitHub

      Push the note to GitHub Push to GitHub Pull a file from GitHub

        Authorize again
       

      Choose which file to push to

      Select repo
      Refresh Authorize more repos
      Select branch
      Select file
      Select branch
      Choose version(s) to push
      • Save a new version and push
      • Choose from existing versions
      Include title and tags
      Available push count

      Pull from GitHub

       
      File from GitHub
      File from HackMD

      GitHub Link Settings

      File linked

      Linked by
      File path
      Last synced branch
      Available push count

      Danger Zone

      Unlink
      You will no longer receive notification when GitHub file changes after unlink.

      Syncing

      Push failed

      Push successfully