[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"blog-categories":3,"blog-category-devops":78},[4,10,14,19,24,30,36,40,45,51,55,58,62,68,73],{"id":5,"databaseId":6,"name":7,"slug":8,"count":9},"dGVybTo1NQ==",55,"AI","ai",2,{"id":11,"databaseId":12,"name":13,"slug":13,"count":9},"dGVybTo2MQ==",61,"backend",{"id":15,"databaseId":16,"name":17,"slug":18,"count":16},"dGVybToyMA==",20,"Devops","devops",{"id":20,"databaseId":21,"name":22,"slug":22,"count":23},"dGVybToxNQ==",15,"frontend",25,{"id":25,"databaseId":26,"name":27,"slug":28,"count":29},"dGVybTo2MA==",60,"GAS","gas",1,{"id":31,"databaseId":32,"name":33,"slug":34,"count":35},"dGVybTo5",9,"HTML","html",4,{"id":37,"databaseId":38,"name":39,"slug":39,"count":29},"dGVybToyMg==",22,"mac",{"id":41,"databaseId":42,"name":43,"slug":43,"count":44},"dGVybTo2",6,"node",18,{"id":46,"databaseId":47,"name":48,"slug":49,"count":50},"dGVybTo2OQ==",69,"Nuxt","nuxt",3,{"id":52,"databaseId":53,"name":54,"slug":54,"count":50},"dGVybTo1NA==",54,"office",{"id":56,"databaseId":9,"name":57,"slug":57,"count":21},"dGVybToy","omekas",{"id":59,"databaseId":60,"name":61,"slug":61,"count":16},"dGVybToxNg==",16,"vue",{"id":63,"databaseId":64,"name":65,"slug":66,"count":67},"dGVybTo1",5,"WordPress","wordpress",13,{"id":69,"databaseId":29,"name":70,"slug":71,"count":72},"dGVybTox","無","uncategorized",null,{"id":74,"databaseId":75,"name":76,"slug":77,"count":9},"dGVybTo3MA==",70,"生活","life",[79,94,108,121,135,147,158,171,184,196,208,219,232,244,256,268,280,292,303,314],{"id":80,"slug":81,"title":82,"description":83,"content":84,"date":85,"image":86,"imageAlt":82,"author":87,"categories":90,"path":93,"minRead":29},3766,"kinsta-主機的轉移心得","Kinsta 主機的轉移心得","Kinsta 主機的轉移心得 最近幫客戶轉移在 Kinsta上轉移主機，幸運的是從 Kinsta 轉移到 Ki […]","\u003Ch1>Kinsta 主機的轉移心得\u003C\u002Fh1>\n\u003Cp>最近幫客戶轉移在 Kinsta上轉移主機，幸運的是從 Kinsta 轉移到 Kinsta 上XD於是經驗分享與記錄一下過程。\u003C\u002Fp>\n\u003Cp>如果未來要選擇 Kinsta 主機，官方對於轉移有許多方式，可參考\u003Ca href=\"https:\u002F\u002Fkinsta.com\u002Fdocs\u002Fwordpress-hosting\u002Fwordpress-migrations\u002Fmigrating-to-kinsta\u002F\" title=\"文件\">文件\u003C\u002Fa>。\u003C\u002Fp>\n\u003Cp>大致分為：\u003C\u002Fp>\n\u003Col>\n\u003Cli>檔案轉移：使用 SFTP 與 MySQL 搬遷\u003C\u002Fli>\n\u003Cli>外掛轉移：Kinsta 推薦使用 Duplicator 或 Migrate Guru\u003C\u002Fli>\n\u003Cli>從 WordPress.com 轉移\u003C\u002Fli>\n\u003Cli>內部轉移：從 Kinsta 轉移到 Kinsta\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cp>如果購買的方案有Premium Migration，則可以直接請轉移團隊處理，參考此\u003Ca href=\"https:\u002F\u002Fkinsta.com\u002Fdocs\u002Fwordpress-hosting\u002Fwordpress-migrations\u002Fmigrating-to-kinsta\u002F#request-a-premium-migration\" title=\"連結\">連結\u003C\u002Fa>。\u003C\u002Fp>\n\u003Cp>剛好這次是內部轉移，則可以參考此\u003Ca href=\"https:\u002F\u002Fkinsta.com\u002Fdocs\u002Fcompany-settings\u002Ftransfer-ownership\u002F\" title=\"說明\">說明\u003C\u002Fa>。內部轉移實際上只是進行所有權的移轉，因此在 Kinsta 的操作中稱為&quot;tranfer&quot;，參考上述連結進行即可。\u003C\u002Fp>\n\u003Cp>進行移轉(tranfer)需要兩個條件：\u003C\u002Fp>\n\u003Col>\n\u003Cli>必須能操作或請人操作來源主機(MyKinsta)\u003C\u002Fli>\n\u003Cli>必須取得目標主機的 Company ID，並且可以操作 MyKinsta\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cp>流程如下：\u003C\u002Fp>\n\u003Col>\n\u003Cli>取得目標主機的 Company ID\u003C\u002Fli>\n\u003Cli>在來源主機上，進行移轉(tranfer)操作\u003C\u002Fli>\n\u003Cli>輸入 Company ID\u003C\u002Fli>\n\u003Cli>目標主機會出現 tranfer 的請求，選擇確認\u003C\u002Fli>\n\u003Cli>完成\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cp>幾乎是一瞬間完成，會連帶將\u003Cstrong>所有設定\u003C\u002Fstrong>以及\u003Cstrong>備份檔案\u003C\u002Fstrong>、\u003Cstrong>staging主機\u003C\u002Fstrong>和\u003Cstrong>網域設定\u003C\u002Fstrong>都移轉過來。並且不會有主機停機的狀態。另外 Kinsta 的客服回答也很立即，如果有需要的人很推薦試試看。\u003C\u002Fp>\n","2024-06-20T10:04:56","\u002Fapi\u002Fproxy-image?url=https%3A%2F%2Fpost.billxu.net%2Fwp-content%2Fuploads%2F2022%2F12%2FWordPress-logotype-alternative.png",{"name":88,"link":89},"Chih Fan","http:\u002F\u002Fpost.billxu.net",[91,92],{"name":17,"slug":18},{"name":65,"slug":66},"\u002Fblog\u002Fkinsta-主機的轉移心得",{"id":95,"slug":96,"title":97,"description":98,"content":99,"date":100,"image":101,"imageAlt":97,"author":102,"categories":103,"path":107,"minRead":29},3670,"aws-cloudfront-部署靜態網站出現-x-cache-error-from-cloudfront-訊息","AWS Cloudfront 部署靜態網站出現 X-cache: Error from cloudfront 訊息","AWS Cloudfront 部署靜態網站出現 x-cache: Error from cloudfront  […]","\u003Ch1>AWS Cloudfront 部署靜態網站出現 x-cache: Error from cloudfront 訊息\u003C\u002Fh1>\n\u003Cp>相關文章\u003Cbr \u002F>\n\u003Ca href=\"https:\u002F\u002Fstackoverflow.com\u002Fquestions\u002F59160472\u002Fhow-to-solve-x-cache-error-from-cloudfront-on-spa\">https:\u002F\u002Fstackoverflow.com\u002Fquestions\u002F59160472\u002Fhow-to-solve-x-cache-error-from-cloudfront-on-spa\u003C\u002Fa>\u003C\u002Fp>\n\u003Cp>\u003Ca href=\"https:\u002F\u002Fwww.withcoherence.com\u002Fpost\u002Faws-spa-routing-the-bad-the-ugly-and-the-uglier\">https:\u002F\u002Fwww.withcoherence.com\u002Fpost\u002Faws-spa-routing-the-bad-the-ugly-and-the-uglier\u003C\u002Fa>\u003C\u002Fp>\n\u003Cp>這個問題真的是恰巧才發現，也因此意識到不是瀏覽器看起來沒問題就好，網站建好後最好稍微掃一下標頭看看有沒有問題XD\u003C\u002Fp>\n\u003Cp>首先先敘述一下環境好了，這個專案建立在 AWS 上，使用了 S3 + Cloudfront 部署，是一個標準的靜態網站。只是因為業主需求，使用了子資料夾網域(sub-directory)，例如 https:\u002F\u002F\u003Cdoamin>\u002Fhome 。而我最終使用了 Html 5 的 \u003Ca href=\"https:\u002F\u002Fdeveloper.mozilla.org\u002Fdocs\u002FWeb\u002FAPI\u002FHistory?ref=blog.amowu.com\">History API\u003C\u002Fa> 來實作。某天剛好客戶做一些檢查發現跳紅字，就丟給我看，一看上面寫“X-cache: Error from cloudfront”，進而研究了一番。\u003C\u002Fp>\n\u003Ch2>什麼是 X-cache\u003C\u002Fh2>\n\u003Cp>X-cache 通常是 CDN 中會加入的一個標頭資訊，用來辨識你的請求是否由 CDN 傳出，如果成功狀態通常以 Hit 表示。\u003C\u002Fp>\n\u003Ch2>自定義錯誤頁面\u003C\u002Fh2>\n\u003Cp>如果使用過 Cloudfront 應該對這個設定不陌生，剛提到這專案使用了 \u003Ca href=\"https:\u002F\u002Fdeveloper.mozilla.org\u002Fdocs\u002FWeb\u002FAPI\u002FHistory?ref=blog.amowu.com\">History API\u003C\u002Fa> ，也因此要多設定 Cloufront 的自定義錯誤頁面(Custom Error Response)，不然會出現 404 Not Found 。\u003Cbr \u002F>\n設定方式很簡單：\u003C\u002Fp>\n\u003Col>\n\u003Cli>前往 CloudFront Distribution\u003C\u002Fli>\n\u003Cli>選擇 \u003Cstrong>Error Pages\u003C\u002Fstrong> 分頁籤，點選 \u003Cstrong>Create Custom Error Response\u003C\u002Fstrong> 建立自訂的錯誤回應\u003C\u002Fli>\n\u003Cli>HTTP Error Code 選擇 \u003Cstrong>404: Not Found\u003C\u002Fstrong>\u003C\u002Fli>\n\u003Cli>Error Caching Minimum TTL 輸入 \u003Cstrong>0\u003C\u002Fstrong>\u003C\u002Fli>\n\u003Cli>Customize Error Response 選擇 \u003Cstrong>Yes\u003C\u002Fstrong>\u003C\u002Fli>\n\u003Cli>Response Page Path 輸入 \u003Cstrong>\u002Findex.html\u003C\u002Fstrong>\u003C\u002Fli>\n\u003Cli>HTTP Response Code 選擇 \u003Cstrong>200: OK\u003C\u002Fstrong>\u003C\u002Fli>\n\u003Cli>設定完成\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cp>很多教學到這邊，多半以為大功告成了～我在遇到這問題前也以為這樣就好，結果發現“X-cache: Error from cloudfront”，什麼！根據 stackoverflow 中的討論，這訊息表示 CDN 可能是失效，也就是你享受不到 Cloudfront 的快取。透過種種資料，我的理解如下，原因在於當訪問網站 https:\u002F\u002F\u003Cdoamin>時，請求將命中 S3 的 index.html 檔案。因為使用了 History API ，而進入到 https:\u002F\u002F\u003Cdoamin>\u002Fhome 時，則不會有任何後端請求，因此重新載入後，會再次詢問有無 https:\u002F\u002F\u003Cdoamin>\u002Fhome\u002Findex.html 這隻檔案，瀏覽器就會認為有問題，但透過上述方式雖然強制給予 200 狀態，但 S3 會拋回錯誤，導致 Cloudfront 也出現錯誤(Error from cloudfront)。\u003C\u002Fp>\n\u003Ch2>使用 Cloudfront 函數\u003C\u002Fh2>\n\u003Cp>查到的解決做法就是在中介層強制拋回 \u002Findex.html ，實作可以透過 AWS 的 edge lambda function ，但更新的做法為 Cloudfront 自己的函數功能，流程如下：\u003C\u002Fp>\n\u003Col>\n\u003Cli>前往 CloudFront Distribution\u003C\u002Fli>\n\u003Cli>左側進入 函數\u003C\u002Fli>\n\u003Cli>建立新函數，我取名為 SPA-route\u003Cbr \u002F>\n\u003Cimg decoding=\"async\" src=\"\u002Fapi\u002Fproxy-image?url=https%3A%2F%2Fpost.billxu.net%2Fwp-content%2Fuploads%2F2024%2F03%2F%E6%88%AA%E5%9C%96-2024-03-11-%E4%B8%8B%E5%8D%883.37.51.png\" alt=\"\" \u002F>\u003C\u002Fli>\n\u003Cli>使用以下程式碼\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cpre>\u003Ccode class=\"language-jsx\">function handler(event){\n    \u002F\u002F Check if the request is for an internal route (doesn&#039;t have a file extension)\n    if (!event.request.uri.includes(&#039;.&#039;)) {\n        event.request.uri = &#039;\u002Findex.html&#039;; \n       }\n\n    return event.request;\n}\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Col>\n\u003Cli>在發布頁籤中，將要套用的分佈設定在關聯分佈中\u003C\u002Fli>\n\u003Cli>發布完成\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cp>大概幾分鐘後，就能看到”X-cache: Hit from cloudfront ”囉～\u003C\u002Fp>\n","2024-03-19T10:40:48","",{"name":88,"link":89},[104,105,106],{"name":13,"slug":13},{"name":17,"slug":18},{"name":43,"slug":43},"\u002Fblog\u002Faws-cloudfront-部署靜態網站出現-x-cache-error-from-cloudfront-訊息",{"id":109,"slug":110,"title":111,"description":112,"content":113,"date":114,"image":115,"imageAlt":111,"author":116,"categories":117,"path":120,"minRead":29},3642,"aws-cloudfront-計價評估方式","AWS CloudFront 計價評估方式","AWS CloudFront 計價評估方式 剛開始接觸 AWS 時最怕被客戶問到「那這大概要多少錢？」，老實說 […]","\u003Ch1>AWS CloudFront 計價評估方式\u003C\u002Fh1>\n\u003Cp>剛開始接觸 AWS 時最怕被客戶問到「那這大概要多少錢？」，老實說用多少算多少還真的很難講呀，另外就是會被 AWS 複雜的服務架構計價搞得頭昏腦脹。\u003Cbr \u002F>\n以 CloudFront 來說，最近終於找到一篇\u003Ca href=\"https:\u002F\u002Fdocs.aws.amazon.com\u002Fzh_tw\u002FAmazonCloudFront\u002Flatest\u002FDeveloperGuide\u002FCloudFrontPricing.html\" title=\"官方的解釋\">官方的解釋\u003C\u002Fa>讓我很確定價格的算法。就來記錄一下囉。\u003C\u002Fp>\n\u003Cp>先來看這張圖，來自 AWS。\u003Cbr \u002F>\n\u003Cfigure id=\"attachment_3643\" aria-describedby=\"caption-attachment-3643\" style=\"width: 542px\" class=\"wp-caption alignnone\">\u003Cimg loading=\"lazy\" decoding=\"async\" src=\"\u002Fapi\u002Fproxy-image?url=https%3A%2F%2Fpost.billxu.net%2Fwp-content%2Fuploads%2F2024%2F02%2FCharges.png\" alt=\"\" width=\"542\" height=\"498\" class=\"size-full wp-image-3643\" srcset=\"https:\u002F\u002Fpost.billxu.net\u002Fwp-content\u002Fuploads\u002F2024\u002F02\u002FCharges.png 542w, https:\u002F\u002Fpost.billxu.net\u002Fwp-content\u002Fuploads\u002F2024\u002F02\u002FCharges-300x276.png 300w\" sizes=\"auto, (max-width: 542px) 100vw, 542px\" \u002F>\u003Cfigcaption id=\"caption-attachment-3643\" class=\"wp-caption-text\">圖片取自AWS\u003C\u002Ffigcaption>\u003C\u002Ffigure>\u003C\u002Fp>\n\u003Cp>以圖片架構來看，會有三個可能的收費點。\u003C\u002Fp>\n\u003Col>\n\u003Cli>Origin Server：如果是 Amazon S3 服務，那就會有儲存的使用費。\u003C\u002Fli>\n\u003Cli>節點回應物件的請求會產生各種費用，例如流量、請求數等等\u003Cbr \u002F>\n3.如果有一些 POST 請求行為，也會有另外的費用，在文件中有舉例。\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cp>像我使用的架構是 S3 + CloudFront 建立一個靜態網站，那基本上只會產生 1 和 2 的費用，再來就要測試每次一請求花費的流量可能是多少，然後再敲計算機了。有這張圖真的很清楚了解收費點，希望我的理解沒錯XD\u003C\u002Fp>\n","2024-02-04T10:00:50","\u002Fapi\u002Fproxy-image?url=https%3A%2F%2Fpost.billxu.net%2Fwp-content%2Fuploads%2F2024%2F02%2F04be1b7b-b315-402e-8171-eb99a551fc61.jpeg",{"name":88,"link":89},[118,119],{"name":13,"slug":13},{"name":17,"slug":18},"\u002Fblog\u002Faws-cloudfront-計價評估方式",{"id":122,"slug":123,"title":124,"description":125,"content":126,"date":127,"image":128,"imageAlt":124,"author":129,"categories":130,"path":134,"minRead":29},3615,"使用-github-action-部署-github-pages","使用 Github Action 部署 Github Pages","使用 Github Action 部署 Github Pages (node) 記錄一下使用 Github A […]","\u003Ch1>使用 Github Action 部署 Github Pages (node)\u003C\u002Fh1>\n\u003Cp>記錄一下使用 Github Action 部署 Github Pages 的流程\u003Cbr \u002F>\n我這邊需求是 node + vue\u003C\u002Fp>\n\u003Cp>步驟很簡單：\u003C\u002Fp>\n\u003Col>\n\u003Cli>設定個人用的 token\u003C\u002Fli>\n\u003Cli>撰寫 Action 的 yml\u003C\u002Fli>\n\u003Cli>設定 repo\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Ch2>設定個人token\u003C\u002Fh2>\n\u003Cp>記得一兩年前 Github 就棄用輸入密碼的方式允許外部方式連線 repo，都必須要用 token。設定方式如下\u003C\u002Fp>\n\u003Cp>先在大頭像找到 setting\u003Cbr \u002F>\n\u003Cimg decoding=\"async\" src=\"\u002Fapi\u002Fproxy-image?url=https%3A%2F%2Fpost.billxu.net%2Fwp-content%2Fuploads%2F2024%2F01%2F%E6%88%AA%E5%9C%96-2024-01-05-%E4%B8%8A%E5%8D%8811.34.14-694x1024.png\" alt=\"\" \u002F>\u003C\u002Fp>\n\u003Cp>接著在左側欄找到 Developer Settings\u003Cbr \u002F>\n\u003Cimg decoding=\"async\" src=\"\u002Fapi\u002Fproxy-image?url=https%3A%2F%2Fpost.billxu.net%2Fwp-content%2Fuploads%2F2024%2F01%2F%E6%88%AA%E5%9C%96-2024-01-05-%E4%B8%8A%E5%8D%8811.34.34.png\" alt=\"\" \u002F>\u003C\u002Fp>\n\u003Cp>選擇 Token(classic)\u003Cbr \u002F>\n\u003Cimg decoding=\"async\" src=\"\u002Fapi\u002Fproxy-image?url=https%3A%2F%2Fpost.billxu.net%2Fwp-content%2Fuploads%2F2024%2F01%2F%E6%88%AA%E5%9C%96-2024-01-05-%E4%B8%8A%E5%8D%8811.35.09.png\" alt=\"\" \u002F>\u003C\u002Fp>\n\u003Cp>選擇 Generate new token (classic)\u003Cbr \u002F>\n\u003Cimg decoding=\"async\" src=\"\u002Fapi\u002Fproxy-image?url=https%3A%2F%2Fpost.billxu.net%2Fwp-content%2Fuploads%2F2024%2F01%2F%E6%88%AA%E5%9C%96-2024-01-05-%E4%B8%8A%E5%8D%8811.36.11-1024x232.png\" alt=\"\" \u002F>\u003C\u002Fp>\n\u003Cp>scopes 至少要勾以下範圍\u003Cbr \u002F>\n\u003Cimg decoding=\"async\" src=\"\u002Fapi\u002Fproxy-image?url=https%3A%2F%2Fpost.billxu.net%2Fwp-content%2Fuploads%2F2024%2F01%2F%E6%88%AA%E5%9C%96-2024-01-05-%E4%B8%8A%E5%8D%8811.37.21.png\" alt=\"\" \u002F>\u003C\u002Fp>\n\u003Ch2>設定 yml\u003C\u002Fh2>\n\u003Cp>這邊就不解釋 Action 的做法\u003Cbr \u002F>\n請參考 \u003Ca href=\"https:\u002F\u002Fdocs.github.com\u002Fen\u002Factions\" title=\"文件\">文件\u003C\u002Fa>\u003Cbr \u002F>\n我用的是這組 action ：JamesIves\u002Fgithub-pages-deploy-action@4.1.5\u003C\u002Fp>\n\u003Cp>相關參數寫在這邊:\u003Ca href=\"https:\u002F\u002Fgithub.com\u002FJamesIves\u002Fgithub-pages-deploy-action\">https:\u002F\u002Fgithub.com\u002FJamesIves\u002Fgithub-pages-deploy-action\u003C\u002Fa>\u003C\u002Fp>\n\u003Ch3>部署在自己的的專案\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-yaml\">name: Deploy\n\non:\n  push:\n    branches:\n      - main\n\njobs:\n  build-and-deploy:\n    runs-on: ubuntu-latest\n\n    steps:\n    - name: Checkout\n      uses: actions\u002Fcheckout@v2\n\n    - name: Install &amp; Build\n      run: |\n        npm install\n        npm run build \n\n      - name: Deploy\n        uses: JamesIves\u002Fgithub-pages-deploy-action@4.1.5\n        with:\n          branch: gh-pages\n          folder: dist\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>部署到其他專案\u003C\u002Fh3>\n\u003Cp>${{ secrets.ACCESS_TOKEN }} 就是從 ACCESS_TOKEN 的設定取值，不要將 token 暴露在明碼上\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-yaml\">name: Deploy\n\non:\n  push:\n    branches:\n      - main\n\njobs:\n  build-and-deploy:\n    runs-on: ubuntu-latest\n\n    steps:\n    - name: Checkout\n      uses: actions\u002Fcheckout@v2\n\n    - name: Install &amp; Build\n      run: |\n        npm install\n        npm run build \n\n    - name: Deploy Antoher Repo\n      uses: JamesIves\u002Fgithub-pages-deploy-action@4.1.5\n      with:\n        branch: gh-pages\n        folder: dist\n        token: ${{ secrets.ACCESS_TOKEN }}\n        repository-name:  Sakasky\u002FSEZ\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>要另外在專案中設定 token\u003Cbr \u002F>\n\u003Cimg decoding=\"async\" src=\"\u002Fapi\u002Fproxy-image?url=https%3A%2F%2Fpost.billxu.net%2Fwp-content%2Fuploads%2F2024%2F01%2F%E6%88%AA%E5%9C%96-2024-01-05-%E4%B8%8A%E5%8D%8811.42.37.png\" alt=\"\" \u002F>\u003C\u002Fp>\n\u003Cp>\u003Cimg decoding=\"async\" src=\"\u002Fapi\u002Fproxy-image?url=https%3A%2F%2Fpost.billxu.net%2Fwp-content%2Fuploads%2F2024%2F01%2F%E6%88%AA%E5%9C%96-2024-01-05-%E4%B8%8A%E5%8D%8811.42.46-1024x612.png\" alt=\"\" \u002F>\u003C\u002Fp>\n\u003Cp>\u003Cimg decoding=\"async\" src=\"\u002Fapi\u002Fproxy-image?url=https%3A%2F%2Fpost.billxu.net%2Fwp-content%2Fuploads%2F2024%2F01%2F%E6%88%AA%E5%9C%96-2024-01-05-%E4%B8%8A%E5%8D%8811.42.53-1024x478.png\" alt=\"\" \u002F>\u003Cbr \u002F>\n以 yml 為例子\u003Cbr \u002F>\nName就設定 ACCESS_TOKEN\u003Cbr \u002F>\n然後將 token 放到 Secret 裡面\u003C\u002Fp>\n\u003Ch3>打開 Github Pages 設定\u003C\u002Fh3>\n\u003Cp>測試過要先設定或不設定都可以，若不先設定，而直接部署的話也可以\u003Cbr \u002F>\n\u003Cimg decoding=\"async\" src=\"\u002Fapi\u002Fproxy-image?url=https%3A%2F%2Fpost.billxu.net%2Fwp-content%2Fuploads%2F2024%2F01%2F%E6%88%AA%E5%9C%96-2024-01-05-%E4%B8%8A%E5%8D%8811.43.16.png\" alt=\"\" \u002F>\u003C\u002Fp>\n\u003Ch1>完成\u003C\u002Fh1>\n\u003Cp>只要每次 commit \u002F push 完，Action 就會自動幫部署網頁啦，超級方便！\u003C\u002Fp>\n","2024-01-08T10:03:34","\u002Fapi\u002Fproxy-image?url=https%3A%2F%2Fpost.billxu.net%2Fwp-content%2Fuploads%2F2024%2F01%2F7430fe6a-8f97-43ae-89ab-85f8bde95b18.jpeg",{"name":88,"link":89},[131,132,133],{"name":17,"slug":18},{"name":22,"slug":22},{"name":43,"slug":43},"\u002Fblog\u002F使用-github-action-部署-github-pages",{"id":136,"slug":137,"title":138,"description":139,"content":140,"date":141,"image":101,"imageAlt":138,"author":142,"categories":143,"path":146,"minRead":29},3572,"aws-上g3m-4部署-node-nginx","AWS 上使用 EC2 部署 node + Nginx + https","AWS 上使用 EC2 部署 node + Nginx 如果要在 AWS 的 EC2 上部署 node ，多半 […]","\u003Ch1>AWS 上使用 EC2 部署 node + Nginx\u003C\u002Fh1>\n\u003Cp>如果要在 AWS 的 EC2 上部署 node ，多半因為 SSL 關係建議多部署一個 Nginx 作反向代理，這樣就能設定 https 來部署服務。\u003Cbr \u002F>\n大致流程如下：\u003C\u002Fp>\n\u003Col>\n\u003Cli>安裝pm2\u003C\u002Fli>\n\u003Cli>安裝nginx\u003C\u002Fli>\n\u003Cli>設定反向代理\u003C\u002Fli>\n\u003Cli>安裝certbot\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Ch2>安裝pm2\u003C\u002Fh2>\n\u003Cp>pm2是一個可以讓node在背景跑的套件\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-jsx\">sudo npm i pm2 -g\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>安裝完後跑pm2\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-jsx\">pm2 start app \u002F\u002F會去執行app資料夾中的index\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>到這部可以先試試看程式有沒有跑起來，直接看 EC2 執行個體的公開IP就可以囉\u003C\u002Fp>\n\u003Ch2>安裝nginx\u003C\u002Fh2>\n\u003Cpre>\u003Ccode class=\"language-jsx\">$ sudo yum install nginx\n$ sudo systemctl enable nginx &amp;&amp; sudo systemctl start nginx\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>設定反向代理\u003C\u002Fh3>\n\u003Cp>建立設定文件 configuration.conf\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-jsx\">$ sudo vim \u002Fetc\u002Fnginx\u002Fconf.d\u002Fconfiguration.conf\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>輸入以下內容\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-jsx\">server {\nserver_name &lt;你的網域&gt;;\nlocation \u002F {\n        proxy_pass http:\u002F\u002F127.0.0.1:3000; \u002F\u002Fnode使用的port\n      }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>儲存後，重新跑nginx\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-jsx\">$ sudo nginx -t\n$ sudo systemctl restart nginx\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>到這邊可以瀏覽網域(http)看看，如果發現失敗可以先檢查 route 53 或是你的 DNS 有無進行指向設定(A record)。\u003C\u002Fp>\n\u003Ch2>安裝Certbot\u003C\u002Fh2>\n\u003Cp>因為執行 certbot 需要使用 python 所以先處理環境\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-jsx\">$ sudo python3 -m venv \u002Fopt\u002Fcertbot\u002F\n$ sudo \u002Fopt\u002Fcertbot\u002Fbin\u002Fpip install --upgrade pip\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>接著安裝 certbot\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-jsx\">$ sudo \u002Fopt\u002Fcertbot\u002Fbin\u002Fpip install certbot certbot-nginx\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>設定 certbot 為可執行指令\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-jsx\">sudo ln -s \u002Fopt\u002Fcertbot\u002Fbin\u002Fcertbot \u002Fusr\u002Fbin\u002Fcertbot\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>跑看看\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-jsx\">$ sudo certbot --nginx\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>這時會跳出執行詢問，按照詢問填入就可以，若有錯誤則依照錯誤處理。\u003C\u002Fp>\n\u003Cp>最後顯示成功時，輸入你的網域應該就能看到正確的指向了。如果失敗，我自己是忘記設定 EC2 的安全群組，記得要把會用到的 port 都打開。\u003C\u002Fp>\n\u003Ch3>排程處理\u003C\u002Fh3>\n\u003Cp>記得憑證會過期，所以要留下定期處理憑證\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-jsx\">$ echo &quot;0 0,12 * * * root \u002Fopt\u002Fcertbot\u002Fbin\u002Fpython -c &#039;import random; import time; time.sleep(random.random() * 3600)&#039; &amp;&amp; sudo certbot renew -q&quot; | sudo tee -a \u002Fetc\u002Fcrontab &gt; \u002Fdev\u002Fnull\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2>參考資料\u003C\u002Fh2>\n\u003Cp>\u003Ca href=\"https:\u002F\u002Fmedium.com\u002F@chiragmehta900\u002Fdeploy-a-node-js-application-on-aws-ec2-with-nginx-with-ssl-47fb163d0909\">https:\u002F\u002Fmedium.com\u002F@chiragmehta900\u002Fdeploy-a-node-js-application-on-aws-ec2-with-nginx-with-ssl-47fb163d0909\u003C\u002Fa>\u003C\u002Fp>\n\u003Cp>\u003Ca href=\"https:\u002F\u002Fdev.to\u002F0xfedev\u002Fhow-to-install-nginx-as-reverse-proxy-and-configure-certbot-on-amazon-linux-2023-2cc9\">https:\u002F\u002Fdev.to\u002F0xfedev\u002Fhow-to-install-nginx-as-reverse-proxy-and-configure-certbot-on-amazon-linux-2023-2cc9\u003C\u002Fa>\u003C\u002Fp>\n","2023-11-16T10:00:10",{"name":88,"link":89},[144,145],{"name":17,"slug":18},{"name":43,"slug":43},"\u002Fblog\u002Faws-上g3m-4部署-node-nginx",{"id":148,"slug":149,"title":150,"description":151,"content":152,"date":153,"image":101,"imageAlt":150,"author":154,"categories":155,"path":157,"minRead":29},3374,"github提交大型檔案時卡住很久的問題","Github提交大型檔案時卡住很久的問題","Github提交大型檔案時卡住很久的問題 當有大型檔案要丟到Github的repo時，其實有檔案大小限制。從瀏 […]","\u003Ch1>Github提交大型檔案時卡住很久的問題\u003C\u002Fh1>\n\u003Cp>當有大型檔案要丟到Github的repo時，其實有檔案大小限制。從瀏覽器端上傳的話是25MB，如果用desktop或CMD則可以到100MB，也就是單一檔案最大可以到100MB。\u003Cbr \u002F>\n但上傳大一點的檔案時，像我大概約20~30MB，就遇到了提交卡住的狀況。\u003Cbr \u002F>\n狀況類似如此：\u003C\u002Fp>\n\u003Cpre>\u003Ccode>Enumerating objects: 6, done.\nCounting objects: 100% (6\u002F6), done.\nDelta compression using up to 8 threads\nCompressing objects: 100% (4\u002F4), done.\nWriting objects: 100% (4\u002F4), 17.47 MiB | 2.83 MiB\u002Fs, done.\nTotal 4 (delta 1), reused 0 (delta 0), pack-reused 0\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>其實都是正常資訊，但跑到最後卡住了XD會一直等非常久都不會好，或是提交的東西有問題。\u003Cbr \u002F>\n如果使用\u003Ccode>git push --verbose --progress\u003C\u002Fcode> 來進行提交，可以確認有無以下訊息：\u003C\u002Fp>\n\u003Cpre>\u003Ccode>POST git-receive-pack (chunked)\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>如果有的話，主要原因是在透過https 提交，git有個預設的上傳緩衝限制(預設為1MB:1000000 )，如果檔案大小超過這個緩衝上限值時，git 會使用分塊編碼的方式將進行上傳。但這件事可能會出現bug，而導致上述卡住的狀況。我找到的解決辦法是設定一個超大上限值，盡量不讓提交時進行分塊編碼。\u003Cbr \u002F>\n(改為1048MB:1048576000)\u003C\u002Fp>\n\u003Cpre>\u003Ccode>git config http.postBuffer 1048576000\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>這樣應該就可以順利上傳囉！\u003C\u002Fp>\n\u003Cp>\u003Ca href=\"https:\u002F\u002Fstackoverflow.com\u002Fquestions\u002F6842687\u002Fthe-remote-end-hung-up-unexpectedly-while-git-cloning\" title=\"參考資料\">參考資料\u003C\u002Fa>\u003C\u002Fp>\n","2023-03-08T12:10:16",{"name":88,"link":89},[156],{"name":17,"slug":18},"\u002Fblog\u002Fgithub提交大型檔案時卡住很久的問題",{"id":159,"slug":160,"title":161,"description":162,"content":163,"date":164,"image":165,"imageAlt":161,"author":166,"categories":167,"path":170,"minRead":29},3430,"如何與chatgpt合作生產並且部署一個短網址服務","如何與chatGPT合作生產並且部署一個短網址服務","如何與chatGPT合作生產並且部署一個短網址服務 chatGPT問世之後一直想來與chatGPT合作產生一個 […]","\u003Ch1>如何與chatGPT合作生產並且部署一個短網址服務\u003C\u002Fh1>\n\u003Cp>chatGPT問世之後一直想來與chatGPT合作產生一個服務，最近總算花了一點時間完成這個小合作-部署短網址服務，因為設計很多程式碼細節，我在這篇僅紀錄與分享合作過程和遇到的問題。\u003C\u002Fp>\n\u003Ch2>確立目標\u003C\u002Fh2>\n\u003Cp>在開始之前，自己先訂了幾個小目標：\u003C\u002Fp>\n\u003Col>\n\u003Cli>目標是完成短網址服務\u003C\u002Fli>\n\u003Cli>要實際部署\u003C\u002Fli>\n\u003Cli>程式碼盡可能交給chatGPT生產，後來在實際合作過程中，我幾乎都是大膽直接複製貼上去跑服務\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Ch2>運用的環境與工具\u003C\u002Fh2>\n\u003Col>\n\u003Cli>nodeJS + express\u003C\u002Fli>\n\u003Cli>部署在Vercel上\u003C\u002Fli>\n\u003Cli>資料丟給firebase的realtime database\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Ch2>我們開始吧\u003C\u002Fh2>\n\u003Cp>一開始我就很暴力的直接問chatGPT\u003Cbr \u002F>\n\u003Cstrong>「如何使用node打造短網址服務，需要與firebase連結」\u003C\u002Fstrong>\u003Cbr \u002F>\n\u003Cimg decoding=\"async\" src=\"\u002Fapi\u002Fproxy-image?url=https%3A%2F%2Fpost.billxu.net%2Fwp-content%2Fuploads%2F2023%2F02%2F%E6%88%AA%E5%9C%96-2023-02-24-%E4%B8%8B%E5%8D%885.47.57.png\" alt=\"\" \u002F>\u003C\u002Fp>\n\u003Cp>根據chatGPT的回應，我完成了幾個步驟\u003C\u002Fp>\n\u003Col>\n\u003Cli>在firebase設定好環境\u003C\u002Fli>\n\u003Cli>從firebase取得node用的初始化與導入方法\u003C\u002Fli>\n\u003Cli>建立node服務\u003C\u002Fli>\n\u003Cli>完全遵照chatGPT回應貼上啟動服務的程式碼\u003C\u002Fli>\n\u003Cli>分別貼上「處理短網址」和「處理長網址」兩個api的程式碼\u003C\u002Fli>\n\u003Cli>貼上啟動express服務的程式碼\u003C\u002Fli>\n\u003Cli>啟動\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cp>好啦其實我沒有那麼嚴謹，所以某些小細節我覺得怪怪還是有點修改，但基本上沒有太大問題。\u003Cbr \u002F>\n例如，chatGPT提供的作法是用require來引入，因為習慣問題我改成了import。還有chatGPT提供的程式碼是分段敘述，我組合起來時有餐入一點個人習慣，但這問題應該可以透過「請將程式碼組合成index.js」之類的prompt來調整。\u003C\u002Fp>\n\u003Cp>有時我也會問他一些函式寫法問題，像是下圖：\u003Cbr \u002F>\n\u003Cimg decoding=\"async\" src=\"\u002Fapi\u002Fproxy-image?url=https%3A%2F%2Fpost.billxu.net%2Fwp-content%2Fuploads%2F2023%2F02%2F%E6%88%AA%E5%9C%96-2023-02-24-%E4%B8%8B%E5%8D%886.08.47.png\" alt=\"\" \u002F>\u003Cbr \u002F>\n總之有稍微不懂就直接問，問爆XDDD\u003C\u002Fp>\n\u003Ch2>寫完就啟動啦！\u003C\u002Fh2>\n\u003Cp>當然沒那麼順利，剛剛那些步驟做完後，我很開心的輸入\u003C\u002Fp>\n\u003Cpre>\u003Ccode>npm run dev\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>然後就一如往常出現錯誤啦，\u003Cdel>chatGPT跟我的距離也沒多遠嘛\u003C\u002Fdel>。\u003Cbr \u002F>\n當然出現錯誤，我就會敘述清楚回報給chatGPT，像是下圖。\u003Cbr \u002F>\n\u003Cimg decoding=\"async\" src=\"\u002Fapi\u002Fproxy-image?url=https%3A%2F%2Fpost.billxu.net%2Fwp-content%2Fuploads%2F2023%2F02%2F%E6%88%AA%E5%9C%96-2023-02-24-%E4%B8%8B%E5%8D%886.11.51.png\" alt=\"\" \u002F>\u003C\u002Fp>\n\u003Cp>\u003Cstrong>這邊提到一個很有趣的狀況，其實chatGPT會漏給資訊唷\u003C\u002Fstrong>\u003Cbr \u002F>\n在短網址服務中，最重要的環節是將長網址轉換成一個隨機短字串，這邊一開始chatGPT居然只給我一個函式名稱就呼隆過去，我一開始就發現不對勁，果然啟動後發現這邊根本跑不動XDDD\u003Cbr \u002F>\n於是叫他補上，可惡ㄋ，我當免費仔也不能用騙啊。\u003Cbr \u002F>\n\u003Cimg decoding=\"async\" src=\"\u002Fapi\u002Fproxy-image?url=https%3A%2F%2Fpost.billxu.net%2Fwp-content%2Fuploads%2F2023%2F02%2F%E6%88%AA%E5%9C%96-2023-02-24-%E4%B8%8B%E5%8D%886.15.32.png\" alt=\"\" \u002F>\u003C\u002Fp>\n\u003Ch2>看起來順利執行了\u003C\u002Fh2>\n\u003Cp>補上後整體看起來有87像了，但他寫的程式碼他要跟我說怎麼測試啊( 你看使用者真的很懶)，所以就順口問了，啊這段程式碼怎麼測試。\u003Cbr \u002F>\n\u003Cimg decoding=\"async\" src=\"\u002Fapi\u002Fproxy-image?url=https%3A%2F%2Fpost.billxu.net%2Fwp-content%2Fuploads%2F2023%2F02%2F%E6%88%AA%E5%9C%96-2023-02-24-%E4%B8%8B%E5%8D%886.17.50.png\" alt=\"\" \u002F>\u003Cbr \u002F>\n\u003Cimg decoding=\"async\" src=\"\u002Fapi\u002Fproxy-image?url=https%3A%2F%2Fpost.billxu.net%2Fwp-content%2Fuploads%2F2023%2F02%2F%E6%88%AA%E5%9C%96-2023-02-24-%E4%B8%8B%E5%8D%886.18.01.png\" alt=\"\" \u002F>\u003Cbr \u002F>\n這之後開始進入一段時間不短的錯誤與改進攻防戰，因為服務不能正確運作，我就一直把錯誤狀況丟回去給他修改。\u003Cbr \u002F>\n大約來回四五次後提出來的程式碼版本終於能正常使用了，看起來沒啥問題。到這邊其實基本功能已經完成了，只是後來有想到一些防呆與檢查，chatGPT給我的版本處理的不是很好就稍微再修改過，未來有要這樣使用的話記得要提醒他加上檢查判斷。\u003C\u002Fp>\n\u003Cblockquote>\n\u003Cp>但我覺得他已經完成任務！真的強啊！\u003C\u002Fp>\n\u003C\u002Fblockquote>\n\u003Ch2>補上介面\u003C\u002Fh2>\n\u003Cp>剛剛做的只有基本的node api，還沒有加上介面，當然這也得交給chatGPT囉。喂！快工作。\u003Cbr \u002F>\n\u003Cimg decoding=\"async\" src=\"\u002Fapi\u002Fproxy-image?url=https%3A%2F%2Fpost.billxu.net%2Fwp-content%2Fuploads%2F2023%2F02%2F%E6%88%AA%E5%9C%96-2023-02-24-%E4%B8%8B%E5%8D%886.24.36.png\" alt=\"\" \u002F>\u003C\u002Fp>\n\u003Cp>稍微看一下覺得寫得還不錯喔！雖然還是一點錯誤，但那其實是給予的資訊不夠清楚，跟前面一樣開始做一些調整的溝通就弄個差不多了。\u003C\u002Fp>\n\u003Cblockquote>\n\u003Cp>要請他修正最好給予足夠資訊，例如在什麼地方做什麼出現什麼訊息。通常會給很具體的調整方式。\u003C\u002Fp>\n\u003C\u002Fblockquote>\n\u003Cp>最後我嫌介面不好看，還叫他用Alertify.js弄漂亮一點XDDDD像這樣\u003Cbr \u002F>\n\u003Cimg decoding=\"async\" src=\"\u002Fapi\u002Fproxy-image?url=https%3A%2F%2Fpost.billxu.net%2Fwp-content%2Fuploads%2F2023%2F02%2F%E6%88%AA%E5%9C%96-2023-02-24-%E4%B8%8B%E5%8D%886.31.32.png\" alt=\"\" \u002F>\u003C\u002Fp>\n\u003Cp>這時其實已經弄的差不多了，大概花了4小時左右。\u003Cbr \u002F>\n\u003Cimg decoding=\"async\" src=\"\u002Fapi\u002Fproxy-image?url=https%3A%2F%2Fpost.billxu.net%2Fwp-content%2Fuploads%2F2023%2F02%2F%E6%88%AA%E5%9C%96-2023-02-24-%E4%B8%8B%E5%8D%886.30.35.png\" alt=\"\" \u002F>\u003C\u002Fp>\n\u003Ch2>該來部署囉\u003C\u002Fh2>\n\u003Cp>剛剛提到我想部署到Vercel上，這邊犯了一個錯，忘記連部署方法也先叫他提供，導致這邊卡了一段時間，\u003Cbr \u002F>\n問題大意是我要在Vercel部署express服務，但又得提供一個介面，Vercel其實有自己一套做法，但一開始我先從express的設定去調整，造成服務一直部署失敗，Vercel的做法之後會再寫一篇文補上(?\u003Cbr \u002F>\n花了一些時間找錯誤後發現問題在於Vercel的設定，於是重新問問夥伴怎麼寫比較好。\u003Cbr \u002F>\n\u003Cimg decoding=\"async\" src=\"\u002Fapi\u002Fproxy-image?url=https%3A%2F%2Fpost.billxu.net%2Fwp-content%2Fuploads%2F2023%2F02%2F%E6%88%AA%E5%9C%96-2023-02-24-%E4%B8%8B%E5%8D%886.37.44.png\" alt=\"\" \u002F>\u003C\u002Fp>\n\u003Cp>看一看有點不太懂rewrites的一些規則，就乾脆直接問清楚，ㄟ你跟我怎麼設定辣！\u003Cbr \u002F>\n\u003Cimg decoding=\"async\" src=\"\u002Fapi\u002Fproxy-image?url=https%3A%2F%2Fpost.billxu.net%2Fwp-content%2Fuploads%2F2023%2F02%2F%E6%88%AA%E5%9C%96-2023-02-24-%E4%B8%8B%E5%8D%886.38.52.png\" alt=\"\" \u002F>\u003Cbr \u002F>\n我得說這樣問後得到的回答超清楚，比我自己回答還要清楚qq\u003Cbr \u002F>\n就這樣重新問了幾次後，我也搞懂了，然後就部署成功了，哈哈XD\u003Cbr \u002F>\n最後算了一下，從開始到部署完成運作大概花了兩天，中間有些時間是做小調整，熟練後能更快。\u003C\u002Fp>\n\u003Ch2>結論\u003C\u002Fh2>\n\u003Cp>經過這次練習後確認chatGPT真的能有效協助工程師執行專案，尤其面對一些陌生狀況更能快速找到一條處理的道路。說來真感概，幾年前寫論文就是在做人機合作的專家系統，那時就感覺NLP這塊每年技術迭代都在加速，沒想到畢業三年後就看到這麼純熟的人機合作工具，這個時代真棒。\u003C\u002Fp>\n\u003Cp>目前主要問題大概是整合部分，但用的過程也覺得只要給予的條件、目的夠明確，chatGPT回饋的程式碼越具體，所以我想整合能力未來也會突破。\u003C\u002Fp>\n\u003Cp>總之以後不管做工作專案也好、side project也好，有chatGPT真的是幫助不小，這個工具能補足很多欠缺的部分，讓我非常期待可以做更多有趣的東西啦。\u003Cbr \u002F>\n倒不太擔心什麼會被取代之類\u003Cdel>，反正我也沒多強\u003C\u002Fdel>，有這類工具身為創作者才能飛得更遠不是嗎？\u003Cbr \u002F>\n以上就是這個小專案的過程，分享一下，也歡迎留言討論。\u003C\u002Fp>\n\u003Cp>最後這是部署的工具網址\u003Cbr \u002F>\n\u003Ca href=\"https:\u002F\u002Fshort-url-test.vercel.app\u002F\">https:\u002F\u002Fshort-url-test.vercel.app\u002F\u003C\u002Fa>\u003C\u002Fp>\n","2023-02-24T18:49:52","\u002Fapi\u002Fproxy-image?url=https%3A%2F%2Fpost.billxu.net%2Fwp-content%2Fuploads%2F2023%2F02%2FChatGPT_logo.svg.png",{"name":88,"link":89},[168,169],{"name":17,"slug":18},{"name":43,"slug":43},"\u002Fblog\u002F如何與chatgpt合作生產並且部署一個短網址服務",{"id":172,"slug":173,"title":174,"description":175,"content":176,"date":177,"image":178,"imageAlt":174,"author":179,"categories":180,"path":183,"minRead":29},3369,"vercel上的node-canvas部署問題","Vercel上的node-canvas部署問題","Vercel上的node-canvas部署問題 如果要在Vercel上部署有node-canvas的專案，應該 […]","\u003Ch1>Vercel上的node-canvas部署問題\u003C\u002Fh1>\n\u003Cp>如果要在Vercel上部署有node-canvas的專案，應該都會遇到這個問題XD可能會有幾種錯誤訊息，像是\u003Ccode>version &#039;ZLIB_1.2.9&#039; not found\u003C\u002Fcode>或是\u003Ccode>libuuid.so.1: cannot open shared object file:\u003C\u002Fcode>，主因是node-canvas會使用以下幾個函式庫：\u003C\u002Fp>\n\u003Col>\n\u003Cli>libuuid.so\u003C\u002Fli>\n\u003Cli>libmount.so\u003C\u002Fli>\n\u003Cli>libblkid.so\u003Cbr \u002F>\n但Vercel上的serverless環境預設沒有這些函式庫導致部署失敗。\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cp>這邊分享我成功的設定。\u003C\u002Fp>\n\u003Ch2>解決做法\u003C\u002Fh2>\n\u003Cp>關鍵就是package.json上的設定，必須在執行或編譯前，讓Vercel先安裝函式庫。\u003C\u002Fp>\n\u003Cpre>\u003Ccode>  &quot;scripts&quot;: {\n    &quot;now-build&quot;: &quot;yum install libuuid-devel libmount-devel &amp;&amp; cp \u002Flib64\u002F{libuuid,libmount,libblkid}.so.1 node_modules\u002Fcanvas\u002Fbuild\u002FRelease\u002F &amp;&amp; npm run start&quot;\n  },\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>並且我的環境使用的是\u003Ccode>canvas＠2.6.1\u003C\u002Fcode>，有人提到\u003Ccode>canvas＠2.8.0\u003C\u002Fcode>也可以，但我是失敗的，這邊就試試看囉\u003C\u002Fp>\n\u003Cpre>\u003Ccode>&quot;dependencies&quot;: {\n    &quot;canvas&quot;: &quot;2.6.1&quot;,\n  },\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>最後記得Vercel上要將node運作環境改為14。\u003Cbr \u002F>\n真是麻煩的問題，找了整整一天資料才成功部署XD\u003C\u002Fp>\n","2023-02-24T10:30:36","\u002Fapi\u002Fproxy-image?url=https%3A%2F%2Fpost.billxu.net%2Fwp-content%2Fuploads%2F2023%2F01%2F640px-Node.js_logo.svg.png",{"name":88,"link":89},[181,182],{"name":17,"slug":18},{"name":43,"slug":43},"\u002Fblog\u002Fvercel上的node-canvas部署問題",{"id":185,"slug":186,"title":187,"description":188,"content":189,"date":190,"image":178,"imageAlt":187,"author":191,"categories":192,"path":195,"minRead":29},3356,"在vercel上使用puppeteer製作爬蟲","在Vercel上使用puppeteer製作爬蟲","在Vercel上使用puppeteer製作爬蟲 免費仔萬歲！(誤)puppeteer是一個nodeJS的函式庫 […]","\u003Ch1>在Vercel上使用puppeteer製作爬蟲\u003C\u002Fh1>\n\u003Cp>免費仔萬歲！(誤)puppeteer是一個nodeJS的函式庫，可以用來控制 Chrome 或 Chromium 瀏覽器，當然是一個用作爬蟲的好工具。這邊就先跳過puppeteer的使用方式介紹，僅記錄在Vercel上使用puppeteer進行網頁爬蟲遇到的一些問題。\u003Cbr \u002F>\n使用puppeteer可以參考\u003Ca href=\"https:\u002F\u002Fpptr.dev\u002F\" title=\"這邊\">這邊\u003C\u002Fa>\u003C\u002Fp>\n\u003Ch2>使用puppeteer-core\u003C\u002Fh2>\n\u003Cp>由於Vercel上不能直接執行Chromium ，需要透過chrome-aws-lambda來使用Chromium，必須注意chrome-aws-lambda不能執行本機的Chromium，如果要本機測試則需將executablePath改為實體的位置喔。範例大致如下\u003C\u002Fp>\n\u003Cpre>\u003Ccode>import puppeteer from &#039;puppeteer-core&#039;\n\nconst getData = async (url) =&gt; {\n    try {\n        let browser = await puppeteer.launch({\n            args: [...chrome.args, &#039;--hide-scrollbars&#039;, &#039;--disable-web-security&#039;],\n            defaultViewport: chrome.defaultViewport,\n            executablePath: await chrome.executablePath,\n            headless: chrome.headless,\n            ignoreHTTPSErrors: true,\n        });\n        const browser = await puppeteer.launch(options);\n        const page = await browser.newPage();\n        await page.goto(&#039;前往的網頁&#039;, { waitUntil: &#039;networkidle0&#039; });\n        await page.close();\n        await browser.close();\n  } catch (err) {\n      console.error(err);\n      return;\n  }\n}\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2>輕量化爬蟲\u003C\u002Fh2>\n\u003Cp>如果只是要爬取文字資料，那可以關閉圖片、css等請求，將爬蟲輕量化以壓低執行時間。\u003C\u002Fp>\n\u003Cpre>\u003Ccode>\u002F\u002F需要先設定 setRequestInterception 為 true，預設狀況下request 是唯讀的。\nawait page.setRequestInterception(true);\npage.on(&quot;request&quot;, (req) =&gt; {\n  if (\n    req.resourceType() == &quot;stylesheet&quot; ||\n    req.resourceType() == &quot;font&quot; ||\n    req.resourceType() == &quot;image&quot;\n  ) {\n    req.abort();\n  } else {\n    req.continue();\n  }\n});\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2>限制\u003C\u002Fh2>\n\u003Cp>由於Vercel上有部署的套件大小限制50mb，puppeteer-core和chrome-aws-lambda需要使用以下版本，用最新版會超過限制導致無法部署。\u003Cbr \u002F>\nVercel上也需要使用\u003Cstrong>Node14\u003C\u002Fstrong>版本，記得調整唷。\u003Cbr \u002F>\npackeage.json\u003C\u002Fp>\n\u003Cpre>\u003Ccode>  &quot;puppeteer-core&quot;: &quot;10.1.0&quot;,\n  &quot;chrome-aws-lambda&quot;: &quot;10.1.0&quot;,\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>按照上述應該就能部署成功，並且爬取一個網頁內容，在我的專案中爬複數網頁就會超過執行時間而失敗，這邊還是研究如何改進執行效率XD\u003Cbr \u002F>\n如果搭配排程服務，就可以透過免費服務製作一個自動爬蟲工具，免費仔萬歲！\u003C\u002Fp>\n","2023-02-12T10:01:30",{"name":88,"link":89},[193,194],{"name":17,"slug":18},{"name":43,"slug":43},"\u002Fblog\u002F在vercel上使用puppeteer製作爬蟲",{"id":197,"slug":198,"title":199,"description":200,"content":201,"date":202,"image":178,"imageAlt":199,"author":203,"categories":204,"path":207,"minRead":29},3349,"node在vercel上實作低度頻率排程cron-job","[Node]在Vercel上實作低度頻率排程(Cron-Job)","在Vercel上實作低度頻率排程(Cron-Job) 實作了一個放在Vercel的爬蟲，然後定期去執行，這篇記 […]","\u003Ch1>在Vercel上實作低度頻率排程(Cron-Job)\u003C\u002Fh1>\n\u003Cp>實作了一個放在Vercel的爬蟲，然後定期去執行，這篇記錄一下在Vercel上實作排程(cron-job)的過程。\u003Cbr \u002F>\n原本Vercel就有提供排程的作法，官方說明提到如果是低度頻率排程(例如每天)，可以使用GitHub Actions，範例如下：\u003C\u002Fp>\n\u003Cpre>\u003Ccode>name: daily-cron\non:\n  schedule:\n    - cron: &#039;0 1 * * *&#039;\njobs:\n  cron:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Call our API route\n        run: |\n          curl --request POST \\\n          --url &#039;https:\u002F\u002Fyoursite.com\u002Fapi\u002Fcron&#039; \\\n          --header &#039;Authorization: Bearer ${{ secrets.API_SECRET_KEY }}&#039;\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>GitHub Actions的作法在這邊就不提了。\u003C\u002Fp>\n\u003Ch2>概念\u003C\u002Fh2>\n\u003Cp>其實實作概念很簡單，就是多開一個需要驗證的api，然後排時間去觸發api，進而去執行要做的事情。\u003C\u002Fp>\n\u003Ch2>排程失效\u003C\u002Fh2>\n\u003Cp>但我實作完後發現怎樣排程都不會觸發，查了一下找到有個討論說明GitHub Actions的排程其實不穩定，常常會延時或不觸發，\u003Ca href=\"https:\u002F\u002Fupptime.js.org\u002Fblog\u002F2021\u002F01\u002F22\u002Fgithub-actions-schedule-not-working\u002F\" title=\"連結\">連結\u003C\u002Fa>。因此我改用了另外的免費cron服務，這類服務其實滿多的。\u003C\u002Fp>\n\u003Cblockquote>\n\u003Cp>補充：幾天後發現GitHub Actions的排程還是有成功運作，可能是初次觸發會需要一點時間(?，總之相較主打排程的服務，在GitHub Actions使用排程可能會有那麼一點不穩，請注意唷。\u003C\u002Fp>\n\u003C\u002Fblockquote>\n\u003Ch2>Api\u003C\u002Fh2>\n\u003Cp>官方提供的範例如下，需注意要做驗證所以必須準備API_SECRET_KEY，這個可以寫在Vercel的環境變數(Environment Variables)裡面\u003C\u002Fp>\n\u003Cpre>\u003Ccode>export default async function handler(req, res) {\n  if (req.method === &#039;POST&#039;) {\n    try {\n      const { authorization } = req.headers;\n\n      if (authorization === `Bearer ${process.env.API_SECRET_KEY}`) {\n        \u002F\u002F執行需要的事情\n        res.status(200).json({ success: true });\n      } else {\n        res.status(401).json({ success: false });\n      }\n    } catch (err) {\n      res.status(500).json({ statusCode: 500, message: err.message });\n    }\n  } else {\n    res.setHeader(&#039;Allow&#039;, &#039;POST&#039;);\n    res.status(405).end(&#039;Method Not Allowed&#039;);\n  }\n}\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>像我使用express建置，最後用一個route接這隻api就可以。\u003C\u002Fp>\n\u003Cpre>\u003Ccode>app.post(&#039;\u002Fapi\u002Fcron&#039;, async (req, res) =&gt; {\n  handler();\n});\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>剛剛有提到這是低度頻率排程的作法，若是高度頻率官方建議用Upstash QStash 函式庫來實作，這部分就要再研究了XD\u003C\u002Fp>\n","2023-01-27T00:06:38",{"name":88,"link":89},[205,206],{"name":17,"slug":18},{"name":43,"slug":43},"\u002Fblog\u002Fnode在vercel上實作低度頻率排程cron-job",{"id":209,"slug":210,"title":211,"description":212,"content":213,"date":214,"image":101,"imageAlt":211,"author":215,"categories":216,"path":218,"minRead":9},162,"devopsdebian與ubuntu從php7升級到php8","[DevOps]Debian與Ubuntu從php7升級到php8","Debian與Ubuntu從php7升級到php8 因為php7.4將於2022年年底停止安全性更新，因此手上 […]","\u003Ch1>Debian與Ubuntu從php7升級到php8\u003C\u002Fh1>\n\u003Cp>因為php7.4將於2022年年底停止安全性更新，因此手上有些專案必須跟著升級，這邊紀錄升級的過程。主要參考於這篇\u003Ca href=\"https:\u002F\u002Fphp.watch\u002Farticles\u002Fphp-8.0-installation-update-guide-debian-ubuntu\" title=\"文章\">文章\u003C\u002Fa>，我就順便做繁中化整理。若有錯誤請再留言告知。我是使用Debian版本，已經順利完成升級。\u003C\u002Fp>\n\u003Chr \u002F>\n\u003Ch3>How to install\u002Fupdate PHP 8.0 (Debian\u002FUbuntu)\u003C\u002Fh3>\n\u003Ch3>如何安裝\u002F升級PHP 8.0(Debian\u002FUbuntu)\u003C\u002Fh3>\n\u003Ch4>PHP 8.0中的擴充與相依更動\u003C\u002Fh4>\n\u003Col>\n\u003Cli>預設具備JSON擴充，不需要再安裝php-json就可以使用。\u003C\u002Fli>\n\u003Cli>xmlrpc擴充轉移至PECL，PHP8.0中不再具備名為xmlrpc的擴充。\u003C\u002Fli>\n\u003Cli>GD擴充在Windows中從php_gd2.dll更改為php_gd.dll\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Ch4>PHP 8.0中的INI更動。\u003C\u002Fh4>\n\u003Col>\n\u003Cli>\n\u003Cp>Assertions throw exceptions by default - (assert.exception=1)\u003Cbr \u002F>\n預設狀態下斷言會丟出意外判斷。\u003C\u002Fp>\n\u003C\u002Fli>\n\u003Cli>\n\u003Cp>Default error display is set to E_ALL - (error_reporting=-1)\u003Cbr \u002F>\n預設錯誤顯示設定於E_ALL。\u003C\u002Fp>\n\u003C\u002Fli>\n\u003Cli>\n\u003Cp>Startup errors are displayed by default - (display_startup_errors=1)\u003Cbr \u002F>\n預設狀態下，會顯示啟動錯誤。\u003C\u002Fp>\n\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cp>PHP 8.0新的JIT添加了幾個新的 INI 指令。\u003Cbr \u002F>\n\u003Cstrong>zend.exception_string_param_max_len INI \u003C\u002Fstrong>設定用於可設定的異常堆疊(stack)來追蹤字符串長度\u003C\u002Fp>\n\u003Ch4>安裝\u002F升級步驟\u003C\u002Fh4>\n\u003Ch5>1.列出現在的PHP套件(packages)\u003C\u002Fh5>\n\u003Cp>主要是從目前的套件清單直接做參考升級。\u003C\u002Fp>\n\u003Cpre>\u003Ccode>dpkg -l | grep php | tee packages.txt\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch5>2.加入 ondrej\u002Fphp PPA\u003C\u002Fh5>\n\u003Cp>這邊會為PPA新增套件的來源，包含所有PHP套件以及相依項目，例如argon2和libzip。\u003C\u002Fp>\n\u003Cp>Ubuntu\u003C\u002Fp>\n\u003Cpre>\u003Ccode>sudo add-apt-repository ppa:ondrej\u002Fphp # Press enter when prompted.\nsudo apt-get update\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Debian\u003C\u002Fp>\n\u003Cpre>\u003Ccode>sudo apt install apt-transport-https lsb-release ca-certificates wget -y\nsudo wget -O \u002Fetc\u002Fapt\u002Ftrusted.gpg.d\u002Fphp.gpg https:\u002F\u002Fpackages.sury.org\u002Fphp\u002Fapt.gpg \nsudo sh -c &#039;echo &quot;deb https:\u002F\u002Fpackages.sury.org\u002Fphp\u002F $(lsb_release -sc) main&quot; &gt; \u002Fetc\u002Fapt\u002Fsources.list.d\u002Fphp.list&#039;\nsudo apt update\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch5>3.安裝PHP8.0擴充\u003C\u002Fh5>\n\u003Cp>所有PHP8.0的套件都遵循php8.0-NAME 命名模式。這邊將安裝數個根據php8.0-common的擴充以及用於PHP 8.0的CLI。\u003C\u002Fp>\n\u003Cp>使用CLI安装PHP 8.0\u003C\u002Fp>\n\u003Cpre>\u003Ccode>sudo apt install php8.0-common php8.0-cli -y\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>這時可以確認版本，注意，如果是升級的話應該還是原版本\u003C\u002Fp>\n\u003Cpre>\u003Ccode>php -v # Show PHP version.\nphp -m # Show PHP modules loaded.\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch5>其他擴充\u003C\u002Fh5>\n\u003Cp>這時可以安裝其他擴充，但我沒做這段，例如\u003C\u002Fp>\n\u003Cpre>\u003Ccode>sudo apt install php8.0-{bz2,curl,intl,mysql,readline,xml}\nsudo apt install php8.0-pcov # PCOV code coverage tool\nsudo apt install php8.0-xdebug # Xdebug debugger\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch5>安裝伺服器API\u003C\u002Fh5>\n\u003Cp>根據所使用的Web伺服器，需要安裝其他套件與伺服器整合。\u003C\u002Fp>\n\u003Cp>如果是Apache使用mpm_event、Nginx，  Litespeed，可以使用php8.0-fpm \u003C\u002Fp>\n\u003Cpre>\u003Ccode>sudo apt install php8.0-fpm\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>如果是Apache使用 mod_php，則安裝 libapache2-mod-php8.0。\u003C\u002Fp>\n\u003Cpre>\u003Ccode>sudo apt install libapache2-mod-php8.0\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch5>4.測試PHP8.0的安裝\u003C\u002Fh5>\n\u003Cp>測試一下剛剛的安裝結果，如果是升級的話應該還是原版本\u003C\u002Fp>\n\u003Cpre>\u003Ccode>php -v\nphp -m\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cpre>\u003Ccode># php -v\nPHP 8.0.0-dev (cli) (built: Oct 4 2020 14:04:36) ( NTS )\nCopyright (c) The PHP Group\nZend Engine v4.0.0-dev, Copyright (c) Zend Technologies\n\n# php -m\n[PHP Modules]\nCore\nctype\ncurl\n...\n..\n.\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch5>5.清除舊的PHP版本\u003C\u002Fh5>\n\u003Cp>這時可以看看主機內有安裝的PHP環境\u003C\u002Fp>\n\u003Cpre>\u003Ccode>sudo update-alternatives --config php\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cpre>\u003Ccode>There are 2 choices for the alternative php (providing \u002Fusr\u002Fbin\u002Fphp).\nSelection Path Priority Status\n\n------------------------------------------------------------\n\n* 0 \u002Fusr\u002Fbin\u002Fphp8.0 80 auto mode\n1 \u002Fusr\u002Fbin\u002Fphp7.4 74 manual mode\n2 \u002Fusr\u002Fbin\u002Fphp8.0 80 manual mode\n\nPress to keep the current choice[*], or type selection number:\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>如果舊版為PHP7.4\u003C\u002Fp>\n\u003Cpre>\u003Ccode>sudo apt purge &#039;^php7.4.*&#039;\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch5>6.重開機\u003C\u002Fh5>\n\u003Cp>對，記得重開伺服器\u003C\u002Fp>\n\u003Cpre>\u003Ccode>reboot\u003C\u002Fcode>\u003C\u002Fpre>\n","2022-11-04T10:00:43",{"name":88,"link":89},[217],{"name":17,"slug":18},"\u002Fblog\u002Fdevopsdebian與ubuntu從php7升級到php8",{"id":220,"slug":221,"title":222,"description":223,"content":224,"date":225,"image":226,"imageAlt":222,"author":227,"categories":228,"path":231,"minRead":29},118,"omekas實作分散架構的omekas-on-dcoker","[OmekaS]實作分散架構的OmekaS on Dcoker","實作分散架構的omekas on Dcoker 好吧，我不太確定這次標題要怎麼寫XD終於完成了專案的環境轉移， […]","\u003Ch1>實作分散架構的omekas on Dcoker\u003C\u002Fh1>\n\u003Cp>好吧，我不太確定這次標題要怎麼寫XD終於完成了專案的環境轉移，原先我們的OmekaS是建置Vmware上，最近由於辦公室搬遷關係，順便做了系統環境大搬遷(\u003Cdel>才怪\u003C\u002Fdel>)，這邊就分享整個架構的作法與遇到問題。\u003C\u002Fp>\n\u003Ch3>架構說明\u003C\u002Fh3>\n\u003Cp>考慮到一個好系統的三大特性：可靠性 (Reliabilty)、可擴展性 (Scalability)、可維護性 (Maintainability)，毅然決然選定了Docker為基礎來進行轉移，並且一定要實作負載平衡(load balancing)，由於辦公室已經採用proxmox(PVE)環境(上述的Vmware架在別的辦公室)，那就來試試看PVE的LXC(LinuX Containers) + Docker吧！\u003C\u002Fp>\n\u003Cblockquote>\n\u003Cp>也許有人會問用了LXC為什麼還要用Docker？我們的考量點是也許未來不一定還會使用PVE環境，為了最大幅度的可搬遷性決定使用泛用度更高的Docker\u003C\u002Fp>\n\u003C\u002Fblockquote>\n\u003Cp>既然已經選定建置方式了，那接下來就得考慮幾個實務問題：\u003C\u002Fp>\n\u003Col>\n\u003Cli>資料庫放在哪？\u003C\u002Fli>\n\u003Cli>檔案放在哪？\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Ch4>關於資料庫\u003C\u002Fh4>\n\u003Cp>OmekaS使用MySQL，因為分散架構關係，我們將SQL拉出去獨立做一台Docker。\u003C\u002Fp>\n\u003Ch4>關於檔案\u003C\u002Fh4>\n\u003Cp>麻煩的就在於檔案，但還好OmekaS這種典藏系統我們在使用過程中不太常出現大量檔案存取問題，所以考慮「共同存取」特性就好，於是決定使用了NAS來存放系統文件，再使用NFS形式mount在不同台主機中，實作「共同存取」功能。\u003C\u002Fp>\n\u003Cp>根據上述，最後就會產生出幾台Docke in LXC的服務(參考架構圖)\u003Cbr \u002F>\nFrontend(WebServer) \u003Cem> 2\u003Cbr \u002F>\nBackend(SQL) \u003C\u002Fem>1\u003Cbr \u002F>\nNAS * 1 (採用trueNAS建置)\u003C\u002Fp>\n\u003Cp>\u003Cimg decoding=\"async\" src=\"\u002Fapi\u002Fproxy-image?url=https%3A%2F%2Fpost.billxu.net%2Fwp-content%2Fuploads%2F2022%2F08%2FOmekas%E8%99%9B%E6%93%AC%E5%8C%96%E6%9E%B6%E6%A7%8B.drawio.png\" alt=\"架構圖\" \u002F>\u003C\u002Fp>\n\u003Cp>相關文章：\u003Ca href=\"https:\u002F\u002Fpost.billxu.net\u002Farchives\u002F111\" title=\"docker-compose for OmekaS\">docker-compose for OmekaS\u003C\u002Fa>\u003C\u002Fp>\n\u003Ch3>遇到問題\u003C\u002Fh3>\n\u003Cp>一如往常地沒那麼順利，很快就遇到幾個問題XD\u003C\u002Fp>\n\u003Ch4>NAS掛載\u003C\u002Fh4>\n\u003Cp>原本我們打算使用synology的NAS來當作Docker使用的磁碟區，已解決共同使用，但最後發現檔案權限會卡住，以至於OmekaS不能順利取用媒體。最後只好改為在PVE中也建置一台NAS來掛載，原本擔心效能但發現其實還不錯。\u003Cbr \u002F>\n使用NAS掛載要注意幾件事：\u003C\u002Fp>\n\u003Col>\n\u003Cli>我們是用NFS來實作\u003C\u002Fli>\n\u003Cli>注意LSC的特權容器要打開\u003C\u002Fli>\n\u003Cli>docker-compose.yml的特權不一定要開\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Ch4>sendmail\u003C\u002Fh4>\n\u003Cp>OmekaS有些功能會需要寄信，這部分就會需要本機內建smtp，所以要加上兩件事，首先是Dockerfile中要設定安裝與啟動sendmail\u003C\u002Fp>\n\u003Cpre>\u003Ccode>RUN apt-get update &amp;&amp; \\\n    apt-get install -y --no-install-recommends sendmail &amp;&amp; \\\n    rm -rf \u002Fvar\u002Flib\u002Fapt\u002Flists\u002F*\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>再來就是需要賦予FQDN這樣sendmail才能正常運作，須在docker-compose.yml加上\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-yml\">hostname: &lt;your-domain&gt; #need FQDN for mail\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch4>喚醒\u003C\u002Fh4>\n\u003Cp>以下是兩台設定的分享\u003C\u002Fp>\n\u003Ch3>Backend(SQL)\u003C\u002Fh3>\n\u003Ch4>docker-compose.yml\u003C\u002Fh4>\n\u003Cpre>\u003Ccode class=\"language-yaml\">version: &quot;3&quot;\n\nservices:\n  mariadb:\n    image: mariadb:latest\n    restart: always\n    environment:\n      MYSQL_ROOT_PASSWORD: blabla\n      MYSQL_DATABASE: omeka\n      MYSQL_USER: user\n      MYSQL_PASSWORD: password\n    ports:\n      - &quot;3306:3306&quot;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>Frontend\u003C\u002Fh3>\n\u003Ch4>docker-compose.yml\u003C\u002Fh4>\n\u003Cpre>\u003Ccode class=\"language-yaml\">version: &quot;3&quot;\n\nservices:\n  omekas:\n    build: .\n    container_name: omekas\n    hostname: &lt;your-domain&gt; #need FADN for mail\n    restart: always\n    ports:\n      - &quot;80:80&quot;\n    volumes:\n      - html:\u002Fvar\u002Fwww\u002Fhtml\n    privileged: true\n\nvolumes:\n  html:\n    driver_opts:\n      type: &quot;nfs&quot;\n      o: &quot;addr=address&quot;\n      device: &quot;:\u002Ffloder\u002F&quot;\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch4>Dockerfile\u003C\u002Fh4>\n\u003Cpre>\u003Ccode>FROM pudding\u002Fdlll-paas-base-image:php-7.4-apache-20220617-1837\n\nUSER root\nEXPOSE 80\nRUN apt-get update &amp;&amp; \\\n    apt-get install -y --no-install-recommends sendmail &amp;&amp; \\\n    rm -rf \u002Fvar\u002Flib\u002Fapt\u002Flists\u002F*\n\nRUN docker-php-ext-configure gd --with-freetype --with-jpeg --enable-gd\nRUN docker-php-ext-install gd\n\nRUN rm -rf \u002Fvar\u002Fwww\u002Fhtml\nRUN mkdir -p \u002Fvar\u002Fwww\u002Fhtml\n\nWORKDIR \u002Fvar\u002Fwww\u002F\n\nCOPY .\u002Fwait-for-it.sh \u002Fvar\u002Fwww\u002Fwait-for-it.sh\nRUN chmod +x wait-for-it.sh\n\n#start senmail\nRUN sed -i &#039;\u002F#!\\\u002Fbin\\\u002Fsh\u002Faservice sendmail restart&#039; \n\nCMD [&quot;.\u002Fwait-for-it.sh&quot;, &quot;targetHost:port&quot;,&quot;--strict&quot;, &quot;--&quot;, &quot;apache2-foreground&quot;]\n\u003C\u002Fcode>\u003C\u002Fpre>\n","2022-10-27T10:00:50","\u002Fapi\u002Fproxy-image?url=https%3A%2F%2Fpost.billxu.net%2Fwp-content%2Fuploads%2F2022%2F05%2FOmekaBadge.png",{"name":88,"link":89},[229,230],{"name":17,"slug":18},{"name":57,"slug":57},"\u002Fblog\u002Fomekas實作分散架構的omekas-on-dcoker",{"id":233,"slug":234,"title":235,"description":236,"content":237,"date":238,"image":239,"imageAlt":235,"author":240,"categories":241,"path":243,"minRead":29},142,"dockererrorno-matching-manifest-for-linux-arm64-v8-in-the-manifest-list-entries","[docker]Error:no matching manifest for linux\u002Farm64\u002Fv8 in the manifest list entries","Error:no matching manifest for linux\u002Farm64\u002Fv8 in the ma […]","\u003Ch1>Error:no matching manifest for linux\u002Farm64\u002Fv8 in the manifest list entries\u003C\u002Fh1>\n\u003Cp>小筆記一下，一直聽說在mac Ｍ系列(M1、M2)中使用Docker有可能會遇到晶片架構不合的問題，終於在練習某個範例時遇到了，會跳出如標題的訊息。\u003C\u002Fp>\n\u003Cpre>\u003Ccode>no matching manifest for linux\u002Farm64\u002Fv8 in the manifest list entries\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>解決方式就只要在docker-compose.yml中出問題的service加入以下一小行設定就可以囉\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-yml\">platform: linux\u002Famd64\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>例如\u003C\u002Fp>\n\u003Cpre>\u003Ccode>web:\n  image:node:14\n  container_name: web\n  ports:\n  - \"3030:3030\"\n  platform: linux\u002Famd64\n\u003C\u002Fcode>\u003C\u002Fpre>\n","2022-10-11T20:00:59","\u002Fapi\u002Fproxy-image?url=https%3A%2F%2Fpost.billxu.net%2Fwp-content%2Fuploads%2F2022%2F07%2FDocker_Temporary_Image_Google_Blue_1080x1080_v1.webp",{"name":88,"link":89},[242],{"name":17,"slug":18},"\u002Fblog\u002Fdockererrorno-matching-manifest-for-linux-arm64-v8-in-the-manifest-list-entries",{"id":245,"slug":246,"title":247,"description":248,"content":249,"date":250,"image":101,"imageAlt":247,"author":251,"categories":252,"path":255,"minRead":29},138,"cypress如果遇到測試當掉error-code-5","[Cypress]如果遇到測試當掉(error code 5)","如果遇到測試當掉(error code 5) 由於用Cypress跑迴圈測試時遇到此問題，推測可能是記憶體爆掉 […]","\u003Ch1>如果遇到測試當掉(error code 5)\u003C\u002Fh1>\n\u003Cp>由於用Cypress跑迴圈測試時遇到此問題，推測可能是記憶體爆掉了，查了一下可以將Cypress儲存測試結果的快照關閉，請\u003Ca href=\"https:\u002F\u002Fdocs.cypress.io\u002Fguides\u002Freferences\u002Fconfiguration#Global\" title=\"參照\">參照\u003C\u002Fa>中的\u003Cem>numTestsKeptInMemory\u003C\u002Fem>設定。\u003Cbr \u002F>\n有很多人也遇到類似問題，解決方式如下：\u003Cbr \u002F>\n將cypress.json or cypress.config.json中加入”numTestsKeptInMemory”: 0。\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-json\">const { defineConfig } = require(&quot;cypress&quot;);\n\nmodule.exports = defineConfig({\n  e2e: {\n    setupNodeEvents(on, config) {\n      \u002F\u002F implement node event listeners here\n    },\n    &quot;numTestsKeptInMemory&quot;: 0,\n  },\n});\u003C\u002Fcode>\u003C\u002Fpre>\n","2022-10-06T20:00:07",{"name":88,"link":89},[253,254],{"name":17,"slug":18},{"name":43,"slug":43},"\u002Fblog\u002Fcypress如果遇到測試當掉error-code-5",{"id":257,"slug":258,"title":259,"description":260,"content":261,"date":262,"image":101,"imageAlt":259,"author":263,"categories":264,"path":267,"minRead":29},128,"dockerno-jpeg-support-in-this-php-build-in-docker","[Docker]No JPEG support in this PHP build in Docker","No JPEG support in this PHP build in Docker 先前建置完OmekaS […]","\u003Ch1>No JPEG support in this PHP build in Docker\u003C\u002Fh1>\n\u003Cp>先前建置完OmekaS的Docker，運作一段時間後發現圖片出不來的狀況，然後會看到類似的訊息「....No JPEG support in this PHP build.....in GD.....」。\u003C\u002Fp>\n\u003Cp>透過phpinfo()呼叫php訊息會發現GD庫的列表中，獨缺JPEG support選項，表示目前運作的GD庫設定沒有啟用支援JPEG功能，於是得重新呼叫，作法很簡單，只要在Dockerfile中加上以下指令。\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-yml\">...\n.....\nRUN docker-php-ext-configure gd --with-freetype --with-jpeg --enable-gd\nRUN docker-php-ext-install gd\n.....\n...\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>重新build後再up就正常了。\u003C\u002Fp>\n","2022-09-14T10:00:28",{"name":88,"link":89},[265,266],{"name":17,"slug":18},{"name":57,"slug":57},"\u002Fblog\u002Fdockerno-jpeg-support-in-this-php-build-in-docker",{"id":269,"slug":270,"title":271,"description":272,"content":273,"date":274,"image":101,"imageAlt":271,"author":275,"categories":276,"path":279,"minRead":29},111,"omekasomekas的docker設定","[OmekaS]docker-compose for OmekaS","docker-compose for OmekaS 最近寫了一台OmekaS的docker，連結在這。 在這邊 […]","\u003Ch1>docker-compose for OmekaS\u003C\u002Fh1>\n\u003Cp>最近寫了一台OmekaS的docker，\u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fbillxu0521\u002Fomeka-S-docker\" title=\"連結\">連結\u003C\u002Fa>在這。\u003Cbr \u002F>\n在這邊分享與補充說明。\u003C\u002Fp>\n\u003Ch2>說明\u003C\u002Fh2>\n\u003Cp>這是安裝好mariaDB + OmekaS + phpMyadmin的 Docker in LXC 容器\u003Cbr \u002F>\nLXC容器(Linux Container)跟Docker其實有滿大的關係，由於現在工作的環境使用了proxmox，跟同事討論後決定實現了Docker in LXC來擴展各種服務，於是誕生了這個docker。\u003C\u002Fp>\n\u003Cp>雖然說in LXC但稍做修改也可以當作一般Docker使用。(其實也沒啥需要修改)\u003C\u002Fp>\n\u003Cp>希望使用docker能加速OmekaS的推廣，歡迎多多使用囉。\u003C\u002Fp>\n\u003Ch4>重點\u003C\u002Fh4>\n\u003Cul>\n\u003Cli>有設定自動開機，LXC啟動後會開啟docker\u003C\u002Fli>\n\u003Cli>OmekaS尚未設定完成，初次啟動後需要進入OmekaS install程序\u003C\u002Fli>\n\u003Cli>OmekaS版本為3.2.2\u003C\u002Fli>\n\u003Cli>volume掛載lxc容器內\u002Froot中，方便做系統升級\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch2>啟動\u003C\u002Fh2>\n\u003Cpre>\u003Ccode class=\"language-shell\">docker-compose up\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>OmekaS的系統文檔放置在LXC的環境中 若需要更新或放置檔案，開啟ssh使用SFTP傳輸即可\u003C\u002Fp>\n\u003Cp>\u003Cstrong>預設帳號為 admin@test.io \u002F password\u003C\u002Fstrong>\u003C\u002Fp>\n\u003Ch4>docker-compose.yml\u003C\u002Fh4>\n\u003Cul>\n\u003Cli>預設將phpMyadmin的關閉\u003C\u002Fli>\n\u003Cli>記得若修改密碼，須同步修改omeka-s\u002Fconfig\u002Fdatabase.ini\u003C\u002Fli>\n\u003Cli>記得修改hostname，設定hostname是為了確保sendmail正常運作\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch2>放置資料\u003C\u002Fh2>\n\u003Cp>若需要放置模組、主題等檔案 請放置到目錄對應docker-compose.yml中omekas的volume。若使用LXC環境則參考repo內說明。\u003C\u002Fp>\n\u003Ch3>備註\u003C\u002Fh3>\n\u003Cp>Omekas安裝時需注意files的權限，在這個備份範本中已經處理完畢\u003Cbr \u002F>\n另外也要注意config\u002Fdatabase.ini也已經設定完畢，指向到DB。\u003C\u002Fp>\n\u003Ch4>偵測啟動\u003C\u002Fh4>\n\u003Cp>(參考)[\u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fvishnubob\u002Fwait-for-it\">https:\u002F\u002Fgithub.com\u002Fvishnubob\u002Fwait-for-it\u003C\u002Fa>] 預設已經註解掉 參照Dockerfile#detect DB 由於自動開機後要確保DB已經先運作再啟動OmekaS 所以多加了wait-for-it的偵測動作 此bash會先偵測DB是否先啟動，若不啟動則重試直到有偵測到\u003C\u002Fp>\n\u003Cp>記得放置或新增wait-for-it.sh，剩下Dockefile會處理\u003C\u002Fp>\n","2022-09-02T10:00:44",{"name":88,"link":89},[277,278],{"name":17,"slug":18},{"name":57,"slug":57},"\u002Fblog\u002Fomekasomekas的docker設定",{"id":281,"slug":282,"title":283,"description":284,"content":285,"date":286,"image":101,"imageAlt":283,"author":287,"categories":288,"path":291,"minRead":29},107,"omekas筆記-可能為php8影響的問題","[OmekaS]筆記-可能為php8影響的問題","可能為php8影響的問題 筆記一下，最近在製作OmekaS的docker版本，遇到一個錯誤，我們摋用了3.1、 […]","\u003Ch1>可能為php8影響的問題\u003C\u002Fh1>\n\u003Cp>筆記一下，最近在製作OmekaS的docker版本，遇到一個錯誤，我們摋用了3.1、3.2版都遇到此問題。\u003C\u002Fp>\n\u003Cp>當系統安裝完後，建置一個有上傳「媒體」的條目時，會發生錯誤，改為開發者模式查錯誤時會跳出下面訊息。\u003Cbr \u002F>\n查了老半天推斷可能是採用了php8基版的image，降級成7.4後就沒問題了，還不確定到底是什麼原因，有可能為目前OmekaS採用的laminas framework對於php的支援還在7.x。\u003C\u002Fp>\n\u003Cpre>\u003Ccode>Omeka S encountered an error\nLaminas\\Session\\Exception\\InvalidArgumentException\n‘session.name’ is not a valid sessions-related ini setting.\u003C\u002Fcode>\u003C\u002Fpre>\n","2022-08-29T20:00:19",{"name":88,"link":89},[289,290],{"name":17,"slug":18},{"name":57,"slug":57},"\u002Fblog\u002Fomekas筆記-可能為php8影響的問題",{"id":293,"slug":294,"title":295,"description":296,"content":297,"date":298,"image":239,"imageAlt":295,"author":299,"categories":300,"path":302,"minRead":29},97,"dockerdocker掛載nfs系統失敗與解決方式","[Docker]Docker掛載nfs系統失敗與解決方式","Docker掛載nfs系統失敗與解決方式 手上有個舊專案準備要移植到新機器上，考慮到未來維護決定改變架構，預計 […]","\u003Ch1>Docker掛載nfs系統失敗與解決方式\u003C\u002Fh1>\n\u003Cp>手上有個舊專案準備要移植到新機器上，考慮到未來維護決定改變架構，預計要實作LXC 環境中執行docker，並且使用nfs掛載到volume中的架構。\u003Cbr \u002F>\n在建置過程中遇到了一些問題，將於以下說明。\u003C\u002Fp>\n\u003Ch2>LXC 環境\u003C\u002Fh2>\n\u003Cp>這部分就不多贅述，我們的虛擬平台使用proxmox，然後建置了\u003Ca href=\"https:\u002F\u002Fwww.wikiwand.com\u002Fzh-tw\u002FLXC\" title=\"LXC容器\">LXC容器\u003C\u002Fa>，並且在LXC容器中執行docker，到這邊都很順利。\u003C\u002Fp>\n\u003Ch2>舊專案docker化\u003C\u002Fh2>\n\u003Cp>這部分沒什麼大問題，只要將原本專案採用的系統重新用Dockerfile和docker-compose撰寫即可。\u003Cbr \u002F>\n原本的專案是php-SQL常見的網站架構，考慮到維護需求，就改寫成web-SQL分離的docker-compose。\u003C\u002Fp>\n\u003Ch2>實體網站檔案化\u003C\u002Fh2>\n\u003Cp>服務架起來後，因為有分散架構的規劃，我們將web server與真正的web server file拆開來，然後web server file使用NFS來掛載處理，我們的NAS使用synology牌的機器。\u003C\u002Fp>\n\u003Ch2>NFS掛載不上去\u003C\u002Fh2>\n\u003Cp>一開始就遇到NFS掛不上去的狀況，怎麼設定都失敗。都會跑出來權限設定錯誤之類的訊息\u003Cbr \u002F>\n而當遇到掛載不上去時可以先用指令確認NFS server是否存在\u003C\u002Fp>\n\u003Cpre>\u003Ccode>$ showmount -e &lt;NFS server host&gt;\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>若服務有起來，輸入指令後應該能看到一些資訊。\u003Cbr \u002F>\n檢查過後發現synology需要做幾個設定。\u003Cbr \u002F>\n首先是synology的共享資料夾，不只要打開NFS機制，還需要在\u003Cstrong>\u003Cem>共享資料夾&gt;資料夾編輯&gt;NFS權限\u003C\u002Fem>\u003C\u002Fstrong>設定白名單IP，並且設定細節，我們是將權限全開。\u003C\u002Fp>\n\u003Ch2>修改LXC的模式\u003C\u002Fh2>\n\u003Cp>接下來要打開LXC容器的特權模式，建置容器時有個\u003Cstrong>\u003Cem>unprivileged containers\u003C\u002Fem>\u003C\u002Fstrong>選項不能打勾，建置容器完後，\u003Cstrong>\u003Cem>option&gt;featuer\u003C\u002Fem>\u003C\u002Fstrong>這邊要將NFS和FUSE打勾。\u003C\u002Fp>\n\u003Ch2>關閉apparmor\u003C\u002Fh2>\n\u003Cp>透過錯誤訊息發現還要關閉apparmor。\u003Ca href=\"https:\u002F\u002Fwww.linuxcapable.com\u002Fzh-TW\u002Fhow-to-enable-disable-apparmor-on-ubuntu-20-04\u002F\" title=\"apparmor\">apparmor\u003C\u002Fa>是Ubuntu中的一個安全相關模組，需要關閉此模組才能讓NFS掛載成功。\u003C\u002Fp>\n\u003Cpre>\u003Ccode>$ sudo systemctl stop apparmor\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2>掛載完成\u003C\u002Fh2>\n\u003Cp>當docker-compose up後都沒有錯誤訊息後，理論上就順利掛載上囉！我們可以用\u003Cstrong>docker-compose run app bash\u003C\u002Fstrong>來進去docker中檢查是否真的有掛載上。\u003C\u002Fp>\n\u003Cpre>\u003Ccode>$ docker-compose run app bash\u003C\u002Fcode>\u003C\u002Fpre>\n","2022-08-15T10:00:38",{"name":88,"link":89},[301],{"name":17,"slug":18},"\u002Fblog\u002Fdockerdocker掛載nfs系統失敗與解決方式",{"id":304,"slug":305,"title":306,"description":307,"content":308,"date":309,"image":101,"imageAlt":306,"author":310,"categories":311,"path":313,"minRead":29},95,"ubuntu打開root的ssh權限","[Ubuntu]打開root的SSH權限","打開root的SSH權限 只是一個小筆記，通常ubuntu建置完後ssh連線的權限是關閉的，如果真需要打開此權 […]","\u003Ch1>打開root的SSH權限\u003C\u002Fh1>\n\u003Cp>只是一個小筆記，通常ubuntu建置完後ssh連線的權限是關閉的，如果真需要打開此權限，要進行以下步驟。\u003C\u002Fp>\n\u003Ch2>修改sshd_config文件\u003C\u002Fh2>\n\u003Cp>首先編輯\u002Fetc\u002Fssh\u002Fsshd_config這個文件(注意大小寫)\u003C\u002Fp>\n\u003Cp>在裡面可以找到此字串，通常是註解狀態\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-shell\">#Permitrootlogin prohibit-password\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>移除註解並且改為yes\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-shell\">Permitrootlogin yes\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2>ssh需要重開\u003C\u002Fh2>\n\u003Cp>完成以上設定後，再重新啟動ssh服務\u003C\u002Fp>\n\u003Cpre>\u003Ccode>$ \u002Fetc\u002Finit.d\u002Fssh restart\u003C\u002Fcode>\u003C\u002Fpre>\n","2022-08-05T13:00:34",{"name":88,"link":89},[312],{"name":17,"slug":18},"\u002Fblog\u002Fubuntu打開root的ssh權限",{"id":315,"slug":316,"title":317,"description":318,"content":319,"date":320,"image":101,"imageAlt":317,"author":321,"categories":322,"path":324,"minRead":35},85,"ubuntu在vm中擴展ubuntu的磁碟空間lvm","[Ubuntu]在VM中擴展Ubuntu的磁碟空間(LVM)","在VM中擴展Ubuntu的硬碟空間(LVM) 手上管理的專案中有幾台服務是建置在VMware上，最近處理一些事 […]","\u003Ch1>在VM中擴展Ubuntu的硬碟空間(LVM)\u003C\u002Fh1>\n\u003Cp>手上管理的專案中有幾台服務是建置在VMware上，最近處理一些事情發現空間不夠用了，於是參考了\u003Ca href=\"https:\u002F\u002Fblog.ndk.name\u002Fextend-vmware-virtual-machine-lvm-disk\u002F\" title=\"這篇\">這篇\u003C\u002Fa>進行擴展磁碟空間。\u003Cbr \u002F>\nUbuntu版本為16.04.5\u003C\u002Fp>\n\u003Ch2>什麼是LVM\u003C\u002Fh2>\n\u003Cp>LVM (Logical Volume Manager)，可以翻譯成邏輯捲軸管理員吧。LVM的機制目的為『可以彈性調整檔案空間的容量』達到幾個特性：容易利用、管理映碟。\u003Cbr \u002F>\n當空間不足時，則需要使用vg和lv來調整空間，調整時不會影響到原先存放的資料&lt;---重要。\u003Cbr \u002F>\n老實說我也是這次要擴展才去看了一下LVM的機制說明XD\u003C\u002Fp>\n\u003Ch2>作法\u003C\u002Fh2>\n\u003Cp>所以預期我需要做幾件事：\u003C\u002Fp>\n\u003Col>\n\u003Cli>先在VM中配置一組新硬碟\u003C\u002Fli>\n\u003Cli>在Ubuntu中設定LVM擴展空間\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Ch2>VM中配置一組新硬碟\u003C\u002Fh2>\n\u003Cp>在VM介面中新增一顆硬碟，設定為100G，原本只有40G\u003Cbr \u002F>\n\u003Cimg decoding=\"async\" src=\"\u002Fapi\u002Fproxy-image?url=https%3A%2F%2Fpost.billxu.net%2Fwp-content%2Fuploads%2F2022%2F06%2F%E6%88%AA%E5%9C%96-2022-06-29-%E4%B8%8B%E5%8D%881.03.53.png\" alt=\"\" \u002F>\u003C\u002Fp>\n\u003Ch2>Ubuntu中設定LVM擴展空間\u003C\u002Fh2>\n\u003Cp>這邊設定就較為繁瑣，當上一個動作做完後，開啟Ubuntu後應該能看到有顆新硬碟\u002Fdev\u002Fsdb，驗證為100G\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-shell\">root@ubuntu:\u002F# ls \u002Fdev\u002Fsd*\n\u002Fdev\u002Fsda  \u002Fdev\u002Fsda1  \u002Fdev\u002Fsda2  \u002Fdev\u002Fsda5  \u002Fdev\u002Fsdb\n\nroot@ubuntu:\u002F# sudo fdisk -l | grep &quot;Disk \u002Fdev&quot;\nDisk \u002Fdev\u002Fsda: 40 GiB, 42949672960 bytes, 83886080 sectors\nDisk \u002Fdev\u002Fsdb: 100 GiB, 107374182400 bytes, 209715200 sectors\nDisk \u002Fdev\u002Fmapper\u002Fubuntu--vg-root: 38.3 GiB, 41150316544 bytes, 80371712 sectors\nDisk \u002Fdev\u002Fmapper\u002Fubuntu--vg-swap_1: 980 MiB, 1027604480 bytes, 2007040 sectors\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>使用fdisk \u002Fdev\u002Fsdb 作partition，注意Command下的指令\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-shell\">root@ubuntu:\u002F# fdisk \u002Fdev\u002Fsdb\n\nWelcome to fdisk (util-linux 2.27.1).\nChanges will remain in memory only, until you decide to write them.\nBe careful before using the write command.\n\nDevice does not contain a recognized partition table.\nCreated a new DOS disklabel with disk identifier 0x96b1b396.\n\nCommand (m for help): p\nDisk \u002Fdev\u002Fsdb: 100 GiB, 107374182400 bytes, 209715200 sectors\nUnits: sectors of 1 * 512 = 512 bytes\nSector size (logical\u002Fphysical): 512 bytes \u002F 512 bytes\nI\u002FO size (minimum\u002Foptimal): 512 bytes \u002F 512 bytes\nDisklabel type: dos\nDisk identifier: 0x96b1b396\n\nCommand (m for help): n\nPartition type\n   p   primary (0 primary, 0 extended, 4 free)\n   e   extended (container for logical partitions)\nSelect (default p): p\nPartition number (1-4, default 1): 1\nFirst sector (2048-209715199, default 2048):\nLast sector, +sectors or +size{K,M,G,T,P} (2048-209715199, default 209715199):\n\nCreated a new partition 1 of type &#039;Linux&#039; and of size 100 GiB.\n\nCommand (m for help): w\nThe partition table has been altered.\nCalling ioctl() to re-read partition table.\nSyncing disks.\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>將這個partition指定為Linux LVM\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-shell\">root@ubuntu:\u002F# fdisk \u002Fdev\u002Fsdb\n\nWelcome to fdisk (util-linux 2.27.1).\nChanges will remain in memory only, until you decide to write them.\nBe careful before using the write command.\n\nCommand (m for help): t\nSelected partition 1\nPartition type (type L to list all types): 8e\nChanged type of partition &#039;Linux&#039; to &#039;Linux LVM&#039;.\n\nCommand (m for help): w\nThe partition table has been altered.\nCalling ioctl() to re-read partition table.\nSyncing disks.\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>成功的話會看到新增一個\u002Fdev\u002Fsdb1\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-shell\">root@ubuntu:\u002F# ls \u002Fdev\u002Fsd*\n\u002Fdev\u002Fsda  \u002Fdev\u002Fsda1  \u002Fdev\u002Fsda2  \u002Fdev\u002Fsda5  \u002Fdev\u002Fsdb  \u002Fdev\u002Fsdb1\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>在剛剛切割好的磁碟\u002Fdev\u002Fsdb1建立physical volume，並且擴展(extend)到原本的volume group到這個volume。\u003Cbr \u002F>\nvolume group的名稱，可通過vgdisplay的命令查到。\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-shell\">root@ubuntu:\u002F# sudo pvcreate \u002Fdev\u002Fsdb1\n  Physical volume &quot;\u002Fdev\u002Fsdb1&quot; successfully created\nroot@ubuntu:\u002F# sudo vgextend  ubuntu-vg \u002Fdev\u002Fsdb1\n  Volume group &quot;ubuntu-vg&quot; successfully extended\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>使用vgdisplay指令可以看volume group資訊，也確認一下剛剛的操作有沒有成功\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-shell\">  Volume group &quot;ubuntu-vg&quot; successfully extended\nroot@ubuntu:\u002F# sudo vgdisplay\n  --- Volume group ---\n  VG Name               ubuntu-vg\n  System ID\n  Format                lvm2\n  Metadata Areas        2\n  Metadata Sequence No  4\n  VG Access             read\u002Fwrite\n  VG Status             resizable\n  MAX LV                0\n  Cur LV                2\n  Open LV               2\n  Max PV                0\n  Cur PV                2\n  Act PV                2\n  VG Size               139.28 GiB\n  PE Size               4.00 MiB\n  Total PE              35655\n  Alloc PE \u002F Size       10056 \u002F 39.28 GiB\n  Free  PE \u002F Size       25599 \u002F 100.00 GiB\n  VG UUID               Lz4ixT-KeGT-kcDb-lf9N-Tykq-LChm-SGwOlG\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>發現原本40G空間變成了139G！\u003C\u002Fp>\n\u003Cp>接著確認目前的磁區與檔案系統，要將新擴展的空間掛載到根目錄\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-shell\">root@ubuntu:\u002F# df -m\nFilesystem                  1M-blocks  Used Available Use% Mounted on\nudev                              980     0       980   0% \u002Fdev\ntmpfs                             201     6       195   3% \u002Frun\n\u002Fdev\u002Fmapper\u002Fubuntu--vg-root     38500 36046       476  99% \u002F\ntmpfs                            1001     0      1001   0% \u002Fdev\u002Fshm\ntmpfs                               5     0         5   0% \u002Frun\u002Flock\ntmpfs                            1001     0      1001   0% \u002Fsys\u002Ffs\u002Fcgroup\n\u002Fdev\u002Fsda1                         720    58       626   9% \u002Fboot\ntmpfs                             201     0       201   0% \u002Frun\u002Fuser\u002F112\ntmpfs                             201     0       201   0% \u002Frun\u002Fuser\u002F0\nroot@ubuntu:\u002F# df\nFilesystem                  1K-blocks     Used Available Use% Mounted on\nudev                          1003008        0   1003008   0% \u002Fdev\ntmpfs                          204816     6016    198800   3% \u002Frun\n\u002Fdev\u002Fmapper\u002Fubuntu--vg-root  39423400 36910900    486824  99% \u002F\ntmpfs                         1024068        0   1024068   0% \u002Fdev\u002Fshm\ntmpfs                            5120        0      5120   0% \u002Frun\u002Flock\ntmpfs                         1024068        0   1024068   0% \u002Fsys\u002Ffs\u002Fcgroup\n\u002Fdev\u002Fsda1                      736752    59236    640092   9% \u002Fboot\ntmpfs                          204816        0    204816   0% \u002Frun\u002Fuser\u002F112\ntmpfs                          204816        0    204816   0% \u002Frun\u002Fuser\u002F0\nroot@ubuntu:\u002F# sudo lvextend \u002Fdev\u002Fmapper\u002Fubuntu--vg-root dev\u002Fsdb1\n  Size of logical volume ubuntu-vg\u002Froot changed from 38.32 GiB (9811 extents) to 138.32 GiB (35410 extents).\n  Logical volume root successfully resized.\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>最後resize 這個空間為ext4，成功的話就能看到根目錄增加了100G\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-shell\">root@ubuntu:\u002F# sudo resize2fs \u002Fdev\u002F\nDisplay all 199 possibilities? (y or n)\nroot@ubuntu:\u002F# sudo resize2fs \u002Fdev\u002Fubuntu-vg\u002F\nroot    swap_1\nroot@ubuntu:\u002F# sudo resize2fs \u002Fdev\u002Fubuntu-vg\u002Froot\nresize2fs 1.42.13 (17-May-2015)\nFilesystem at \u002Fdev\u002Fubuntu-vg\u002Froot is mounted on \u002F; on-line resizing required\nold_desc_blocks = 3, new_desc_blocks = 9\nThe filesystem on \u002Fdev\u002Fubuntu-vg\u002Froot is now 36259840 (4k) blocks long.\n\nroot@ubuntu:\u002F# df -m\nFilesystem                  1M-blocks  Used Available Use% Mounted on\nudev                              980     0       980   0% \u002Fdev\ntmpfs                             201     6       195   3% \u002Frun\n\u002Fdev\u002Fmapper\u002Fubuntu--vg-root    139289 36058     97160  28% \u002F\ntmpfs                            1001     0      1001   0% \u002Fdev\u002Fshm\ntmpfs                               5     0         5   0% \u002Frun\u002Flock\ntmpfs                            1001     0      1001   0% \u002Fsys\u002Ffs\u002Fcgroup\n\u002Fdev\u002Fsda1                         720    58       626   9% \u002Fboot\ntmpfs                             201     0       201   0% \u002Frun\u002Fuser\u002F112\ntmpfs                             201     0       201   0% \u002Frun\u002Fuser\u002F0\u003C\u002Fcode>\u003C\u002Fpre>\n","2022-07-25T10:20:06",{"name":88,"link":89},[323],{"name":17,"slug":18},"\u002Fblog\u002Fubuntu在vm中擴展ubuntu的磁碟空間lvm"]