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
    • Invite by email
      Invitee

      This note has no invitees

    • 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
    • Note Insights
    • 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 Versions and GitHub Sync Note Insights Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
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
  • Invite by email
    Invitee

    This note has no invitees

  • 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