1. 使用Docker部署SpringBoot+Vue博客系統(tǒng)

        共 12066字,需瀏覽 25分鐘

         ·

        2020-12-24 20:02

        點擊上方?好好學java?,選擇?星標?公眾號

        重磅資訊、干貨,第一時間送達

        今日推薦:硬剛一周,3W字總結(jié),一年的經(jīng)驗告訴你如何準備校招!

        個人原創(chuàng)100W+訪問量博客:點擊前往,查看更多

        在今年年初的時候,完成了自己的個Fame博客系統(tǒng)的實現(xiàn),當時也做了一篇博文Spring-boot+Vue = Fame 寫blog的一次小結(jié)作為記錄和介紹。從完成實現(xiàn)到現(xiàn)在,也斷斷續(xù)續(xù)的根據(jù)實際的使用情況進行更新。
        只不過每次上線部署的時候都覺得有些麻煩,因為我的服務(wù)器內(nèi)存太小,每次即使只更新了前臺部分(fame-front)的代碼,在執(zhí)行npm build的時候都還必須把我的后端服務(wù)(fame-server)的進程關(guān)掉,不然會造成服務(wù)器卡死(慘啊)。
        而且這個項目是前后端分離的,博客前臺頁面還為了SEO用了Nuxt框架,假如是第一次部署或者要服務(wù)器遷移的話,麻煩的要死啊,部署一次的話要以下步驟
        1. 安裝mysql,修改相關(guān)配置文件,設(shè)置編碼時區(qū)等,然后重啟
        2. 下載安裝java,配置java環(huán)境
        3. 下載安裝maven,配置maven環(huán)境
        4. 下載安裝nginx,修改配置文件,設(shè)計反向代理等
        5. 啟動spring-boot項目
        6. 打包vue項目,npm install,npm run build
        7. 啟動nuxt項目,npm install,npm run start
        如果能夠順利的完成這七個步驟算是幸運兒了,假如中間哪個步驟報錯出了問題,可能還要回頭查找哪個步驟出了問題,然后又重新部署。
        我選擇死亡

        在這些需求面前,Docker就是解決這些問題的大殺器。無論是其虛擬化技術(shù)隔離各個容器使其資源互不影響,還是一致的運行環(huán)境,以及docker-compose的一鍵部署,都完美的解決了上述問題。

        項目地址:https://github.com/zzzzbw/Fame

        Docker和Docker-compose安裝

        Docker和Docker-compose的功能和使用可以看線上的一個中文文檔Docker — 從入門到實踐

        下面是Centos7安裝和配置Docker以及Docker-compose的shell腳本,其他操作系統(tǒng)可以參考修改來安裝。其中Docker版本為docker-ce,Docker-compose版本為1.22.0

        #!/bin/sh

        ###?更新?###
        yum?-y?update

        ###?安裝docker?###
        #?安裝一些必要的系統(tǒng)工具
        sudo?yum?install?-y?yum-utils?device-mapper-persistent-data?lvm2
        #?添加軟件源信息
        sudo?yum-config-manager?--add-repo?http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
        #?更新?yum?緩存
        sudo?yum?makecache?fast
        #?安裝?Docker-ce
        sudo?yum?-y?install?docker-ce
        #?啟動docker并設(shè)置為開機啟動(centos7)
        systemctl??start?docker.service
        systemctl??enable?docker.service
        #?替換docker為國內(nèi)源
        echo?'{"registry-mirrors":?["https://registry.docker-cn.com"],"live-restore":?true}'?>?/etc/docker/daemon.json
        systemctl?restart?docker
        #?安裝dokcer-compose
        sudo?curl?-L?https://github.com/docker/compose/releases/download/1.22.0/docker-compose-`uname?-s`-`uname?-m`?-o?/usr/local/bin/docker-compose
        chmod?+x?/usr/local/bin/docker-compose
        #?安裝命令補全工具
        yum?-y?install?bash-completion
        curl?-L?https://raw.githubusercontent.com/docker/compose/$(docker-compose?version?--short)/contrib/completion/bash/docker-compose?>?/etc/bash_completion.d/docker-compose
        ###?安裝docker結(jié)束?###

        Docker化改造

        改造后目錄結(jié)構(gòu)

        先看一下改造后的項目的結(jié)構(gòu)

        ├─Fame
        │??│??.env????????????????????????????//?docker-compose環(huán)境參數(shù)配置文件
        │??│??docker-compose.yml??????????????//?docker-compose文件
        │??├─fame-docker
        │??│??│??fame-front-Dockerfile????????//?fame-front的Dockerfile文件
        │??│??│??fame-server-Dockerfile???????//?fame-server的Dockerfile文件
        │??│??│??
        │??│??├─fame-admin
        │??│??│??????fame-admin-Dockerfile????//?fame-admin的Dockerfile文件
        │??│??│??????nginx.conf???????????????//?fame-admin的nginx服務(wù)器配置文件
        │??│??│??????
        │??│??├─fame-mysql
        │??│??│??????fame-mysql-Dockerfile????//?mysql的Dockerfile文件
        │??│??│??????mysqld.cnf???????????????//?mysql的配置文件mysqld.cnf
        │??│??│??????
        │??│??└─fame-nginx
        │??│??????????nginx-Dockerfile????????//?整個項目的nginx服務(wù)器的Dockerfile文件
        │??│??????????nginx.conf??????????????//?整個項目的nginx的配置文件
        │??│??????????
        │??├─fame-admin???//?博客管理后臺,基于Vue+elementui
        │??├─fame-front???//?博客前端,基于Nuxt
        │??└─fame-server??//?博客服務(wù)端,基于spring-boot

        為了不破壞原有項目的結(jié)構(gòu),無論前端還是后端的docker的相關(guān)配置文件全部提取出來,單獨放在了fame-docker文件夾中。搜索Java知音公眾號,回復“后端面試“,送你一份Java面試體驗寶典.pdf

        docker-compose.yml放在項目根目錄下,直接在根目錄運行命令:docker-compose up -d

        [root@localhost?Fame]#?docker-compose?up?-d
        Starting?fame-front?...?
        Starting?fame-admin?...?
        Starting?fame-front?...?done
        Starting?fame-admin?...?done
        Starting?fame-nginx?...?done

        就啟動項目了,再也不用重復繁瑣的步驟!

        改造后的docker項目結(jié)構(gòu)

        fame-structure

        改造后的docker-compose.yaml文件

        version:?'3'
        services:?
        ??fame-nginx:
        ????container_name:?fame-nginx
        ????build:
        ?????context:?./
        ?????dockerfile:?./fame-docker/fame-nginx/nginx-Dockerfile
        ????ports:
        ??????-?"80:80"
        ????volumes:
        ?????-?./logs/nginx:/var/log/nginx
        ????depends_on:
        ??????-?fame-server
        ??????-?fame-admin
        ??????-?fame-front
        ??
        ??fame-mysql:
        ???container_name:?fame-mysql
        ???build:?
        ?????context:?./
        ?????dockerfile:?./fame-docker/fame-mysql/fame-mysql-Dockerfile
        ???environment:
        ?????MYSQL_DATABASE:?fame
        ?????MYSQL_ROOT_PASSWORD:?root
        ?????MYSQL_ROOT_HOST:?'%'
        ?????TZ:?Asia/Shanghai
        ???expose:
        ??????-?"3306"
        ???volumes:
        ?????-?./mysql/mysql_data:/var/lib/mysql
        ???restart:?always

        ??fame-server:
        ????container_name:?fame-server
        ????restart:?always
        ????build:?
        ?????context:?./
        ?????dockerfile:?./fame-docker/fame-server-Dockerfile
        ????working_dir:?/app
        ????volumes:
        ??????-?./fame-server:/app
        ??????-?~/.m2:/root/.m2
        ??????-?./logs/fame:/app/log
        ????expose:
        ??????-?"9090"
        ????command:?mvn?clean?spring-boot:run?-Dspring-boot.run.profiles=docker?-Dmaven.test.skip=true
        ????depends_on:
        ??????-?fame-mysql

        ??fame-admin:
        ???container_name:?fame-admin
        ???build:?
        ????context:?./
        ????dockerfile:?./fame-docker/fame-admin/fame-admin-Dockerfile
        ????args:
        ??????BASE_URL:?${BASE_URL}
        ???expose:
        ??????-?"3001"

        ??fame-front:
        ???container_name:?fame-front
        ???build:?
        ????context:?./
        ????dockerfile:?./fame-docker/fame-front-Dockerfile
        ???environment:
        ??????BASE_URL:?${BASE_URL}
        ??????PROXY_HOST:?${PROXY_HOST}
        ??????PROXY_PORT:?${PROXY_PORT}
        ???expose:
        ??????-?"3000"

        docker-compose.yml的結(jié)構(gòu)和剛才目錄結(jié)構(gòu)大體類似,也是分以下幾個部分

        1. fame-nginx

        2. fame-mysql

        3. fame-server

        4. fame-admin

        5. fame-front

        這個docker-compose.yml中有幾個要點

        • fame-mysqlfame-serverrestart要設(shè)置為always,因為目前Docker-compose是沒有一個方案可以解決容器啟動的先后的問題的。即使設(shè)置了depends_on,那也只是控制容器開始啟動的時間,不能控制容器啟動完成的時間,所以讓fame-mysqlfame-server這兩個容器設(shè)置restart,防止spring-boot在mysql啟動完成之前啟動而報錯啟動失敗

        • fame-serverfame-mysql,fame-nginx這三個容器都設(shè)置了volumes,把容器里的logs日志文件掛載到宿主機的項目目錄里,方便隨時看日志文件

        • fame-mysql容器的mysql存儲文件也設(shè)置了volumes掛載在項目目錄里(./mysql/mysql_data:/var/lib/mysql),這個建議大家可以根據(jù)實際的情況設(shè)置到宿主機的其他目錄里,不然不小心刪除項目的話那么容器里的數(shù)據(jù)庫數(shù)據(jù)也都沒了

        幾個鏡像的Dockerfile大部分都比較簡單,這部分就不全部詳細介紹了,可以直接去我項目中了解。

        Docker化過程的困難和解決方法

        spring-boot雙配置切換

        為了能夠讓spring-boot能夠在開發(fā)環(huán)境和Docker環(huán)境下快速切換,需要將spring-boot的配置文件進行修改

        └─fame-server
        ????????...???????????????????
        ????????│??└─resources
        ????????│??????│??application-dev.properties
        ????????│??????│??application-docker.properties
        ????????│??????│??application.properties

        在原有的application.properties基礎(chǔ)上增加application-dev.propertiesapplication-docker.properties配置文件,把application.properties里的數(shù)據(jù)庫日志等信息分別放到application-dev.propertiesapplication-docker.properties這兩個文件中,實現(xiàn)開發(fā)環(huán)境和Docker環(huán)境的快速切換。

        #?application.properties文件
        #端口號
        server.port=9090
        #mybatis
        mybatis.type-aliases-package=com.zbw.fame.Model
        #mapper
        mapper.mappers=com.zbw.fame.util.MyMapper
        mapper.not-empty=false
        mapper.identity=MYSQL

        #mail
        spring.mail.properties.mail.smtp.auth=true
        spring.mail.properties.mail.smtp.starttls.enable=true
        spring.mail.properties.mail.smtp.starttls.required=true

        #默認properties
        spring.profiles.active=dev

        ~

        #?application-docker.properties文件
        #datasource
        spring.datasource.driverClassName=com.mysql.jdbc.Driver
        spring.datasource.url=jdbc:mysql://fame-mysql:3306/fame?useUnicode=true&characterEncoding=utf-8&useSSL=false
        spring.datasource.username=root
        spring.datasource.password=root

        #log
        logging.level.root=INFO
        logging.level.org.springframework.web=INFO
        logging.file=log/fame.log

        application-dev.properties的內(nèi)容和application-docker.properties文件類似,只是根據(jù)自己開發(fā)環(huán)境的情況修改mysql和log配置。

        動態(tài)配置axios的baseUrl地址

        fame-adminfame-front中用了axios插件,用于發(fā)起和獲取fame-server服務(wù)器的請求。在axios要配置服務(wù)器url地址baseUrl,那么通常開發(fā)環(huán)境和Docker環(huán)境以及生產(chǎn)環(huán)境的url可能都不一樣,每次都去修改有點麻煩。(雖然只需要配置兩處,但是代碼潔癖不允許我硬編碼這個配置)。

        1.先修改fame-admin(Vue)使其兼容手動部署模式和Docker模式

        fame-admin是基于Vue CLI 3搭建的,相對于cli 2.0官方把webpack的一些配置文件都封裝起來了,所以沒有config和build文件夾。不過對應(yīng)的官網(wǎng)也給了一些設(shè)置更加方便的配置參數(shù)。

        在官方文檔中提到:

        只有以?VUE_APP_?開頭的變量會被?webpack.DefinePlugin?靜態(tài)嵌入到客戶端側(cè)的包中。你可以在應(yīng)用的代碼中這樣訪問它們:

        console.log(process.env.VUE_APP_SECRET)

        在構(gòu)建過程中,process.env.VUE_APP_SECRET?將會被相應(yīng)的值所取代。在?VUE_APP_SECRET=secret?的情況下,它會被替換為?"sercet"。

        利用這個特性來設(shè)置環(huán)境變量來動態(tài)的設(shè)置Docker模式和手動部署模式的baseUrl的值

        fame-admin目錄下創(chuàng)建文件server-config.js,編寫以下內(nèi)容

        const?isProd?=?process.env.NODE_ENV?===?'production'
        const?localhost?=?'http://127.0.0.1:9090/'
        const?baseUrl?=?process.env.VUE_APP_API_URL?||?localhost
        const?api?=?isProd???baseUrl?:?localhost
        export?default?{
        ??isProd,
        ??api
        }

        那么只要在環(huán)境變量中有VUE_APP_API_URL的值,且NODE_ENV === 'production',baseUrl就等于VUE_APP_API_URL的值,否則就是localhost的值。

        接著在axios配置文件中引用該文件設(shè)置

        //?fame-admin/src/plugins/http.js
        ...
        import?serverConfig?from?'../../server-config'

        const?Axios?=?axios.create({
        ??baseURL:?serverConfig.api?+?'api/',
        ?...
        })
        ????
        ...

        現(xiàn)在只要將docker的環(huán)境變量設(shè)置一個VUE_APP_API_URL的值就行了,只要在對應(yīng)的Dockerfile中增加一個步驟就可以了。

        ENV?VUE_APP_API_URL?http://xx.xxx.xxx.xxx

        2.再修改fame-front(Nuxt)使其兼容手動部署模式和Docker模式

        同樣的,對于用Nuxt搭建fame-front博客前臺修改也是類似的思路。

        在Nuxt的官方文檔中寫到:

        Nuxt.js 讓你可以配置在客戶端和服務(wù)端共享的環(huán)境變量。

        例如 (nuxt.config.js):

        module.exports?=?{
        ??env:?{
        ????baseUrl:?process.env.BASE_URL?||?'http://localhost:3000'
        ??}
        }

        以上配置我們創(chuàng)建了一個?baseUrl?環(huán)境變量,如果應(yīng)用設(shè)定了?BASE_URL?環(huán)境變量,那么?baseUrl?的值等于?BASE_URL?的值,否則其值為?http://localhost:3000。

        所以我們只要和官方文檔說的一樣,在nuxt.config.js文件中增加代碼就可以了

        module.exports?=?{
        ?env:?{
        ???baseUrl:?process.env.BASE_URL?||?'http://localhost:3000'
        ?}
        }

        接著在server-config.js文件和axios的配置文件fame-front/plugins/http.js以及對應(yīng)的Dockerfile文件中編寫和上面fame-admin部分一樣的代碼就可以了

        現(xiàn)在已經(jīng)把baseUrl的設(shè)置從代碼的硬編碼中解放出來了,但事實上我們只是把這個參數(shù)的編碼從代碼從轉(zhuǎn)移到Dockerfile文件里了,要是想要修改的話也要去這兩個文件里查找然后修改,這樣也不方便。后面會解決這個問題把所有環(huán)境配置統(tǒng)一起來。

        Nuxt在Docker中無法訪問到宿主機ip問題

        先要說明一點,為什么博客前端要單獨去使用的Nuxt而不是和博客后臺一樣用Vue呢,因為博客前端有SEO的需求的,像Vue這樣的對搜索引擎很不友好。

        所以Nuxt的頁面是服務(wù)器端渲染(SSR)的

        這樣就產(chǎn)生了問題

        fame-front的頁面在渲染之前必須獲取到fame-server服務(wù)器中的數(shù)據(jù),但是每個docker容器都是互相獨立的,其內(nèi)部想要互相訪問只能通過容器名訪問。例如容器fame-front想要訪問容器fame-server,就設(shè)置baseURL = fame-server(fame-server是服務(wù)器的容器的container_name)。

        這樣設(shè)置之后打開瀏覽器輸入網(wǎng)址:http://xx.xxx.xxx.xx可以成功...,但是隨便點擊一個鏈接,就會看到瀏覽器提示錯誤無法訪問到地址http://fame-server/...

        vendor.e2feb665ef91f298be86.js:2?GET?http://fame-server/api/article/1?net::ERR_CONNECTION_REFUSED

        這是必然的結(jié)果,在容器里http://fame-server/就是服務(wù)器...,但是你本地的瀏覽器當然是不知道http://fame-server/是個什么鬼...,所以就瀏覽器就報出無法訪問的錯誤。

        什么?可是剛才不是說Nuxt是服務(wù)器渲染的頁面嗎,怎么又讓本地瀏覽器報這個錯誤了。

        原來是因為當通過瀏覽器鏈接直接訪問的時候,Nuxt的確是從后端渲染了頁面再傳過來,但是在頁面中點擊鏈接的時候是通過Vue-Router跳轉(zhuǎn)的,這時候不在Nuxt的控制范圍,而是和Vue一樣在瀏覽器渲染的,這時候就要從瀏覽器里向服務(wù)端獲取數(shù)據(jù)來渲染,瀏覽器就會報錯。

        如何解決呢

        這個問題開始的時候一直想要嘗試配置Docker容器的網(wǎng)絡(luò)模式來解決,可是都沒有解決。直到后面我看axios文檔的時候才注意到axios的代理功能,其本質(zhì)是解決跨域的問題的,因為只要在axios設(shè)置了代理,在服務(wù)端渲染的時候就會使用代理的地址,同時在瀏覽器訪問的時候會用baseUrl?的地址,這個特點完美解決我的問題啊。

        server-config.js文件里增加以下代碼(在nuxt.config.js里獲取環(huán)境變量里的proxyHostproxyPort

        ...
        const?localProxy?=?{
        ??host:?'127.0.0.1',
        ??port:?9090
        }
        const?baseProxy?=?{
        ??host:?process.env.proxyHost?||?localProxy.host,
        ??port:?process.env.proxyPort?||?localProxy.port
        }
        exports.baseProxy?=?isProd???baseProxy?:?localProxy
        ...

        然后在axios配置文件里增加代碼

        //?fame-front/plugins/http.js
        const?Axios?=?axios.create({
        ??proxy:?serverConfig.baseProxy
        ?...
        })
        ????
        ...

        就可以完美的解決問題了。

        Dockerfile的環(huán)境參數(shù)統(tǒng)一設(shè)置

        在上文解決動態(tài)配置axios地址的部分把baseUrl的設(shè)置放在了Dockerfile中,現(xiàn)在就再把Dockerfile中的硬編碼提取出來,放到統(tǒng)一的配置文件中。

        首先在docker-compose.yml文件目錄下(即項目跟目錄)創(chuàng)建環(huán)境文件.env并編寫一下內(nèi)容

        BASE_URL=http://xx.xxx.xxx.xxx

        PROXY_HOST=fame-nginx
        PROXY_PORT=80

        這個是docker-composeenv_file參數(shù),從文件中獲取環(huán)境變量,可以為單獨的文件路徑或列表,如果同目錄下有.env文件則會默認讀取,也可以自己在docker-compose里設(shè)置路徑。

        已經(jīng)在.env設(shè)置了環(huán)境變量BASE_URL的值,就能在docker-compose.yml里直接使用了。修改docker-compose.ymlfame-front部分:

        fame-front:
        ?...
        ?environment:
        ??BASE_URL:?${BASE_URL}
        ??PROXY_HOST:?${PROXY_HOST}
        ??PROXY_PORT:?${PROXY_PORT}
        ??...

        這樣在fame-front的容器里就有對應(yīng)的BASE_URL,PROXY_HOST,PROXY_PORT環(huán)境變量,Nuxt也能夠成功獲取并設(shè)置。

        不過對于fame-admin容器來說就要稍微復雜一點點了。先來看一下fame-admin容器的Dockerfile文件fame-admin-Dockerfile

        #?build?stage
        FROM?node:10.10.0-alpine?as?build-stage

        #中間一些操作省略...

        RUN?npm?run?build

        #?production?stage
        FROM?nginx:1.15.3-alpine?as?production-stage

        COPY?./fame-docker/fame-admin/nginx.conf?/etc/nginx/conf.d/default.conf
        COPY?--from=build-stage?/app/dist?/usr/share/nginx/html
        EXPOSE?80
        CMD?["nginx",?"-g",?"daemon?off;"]

        這里用了多階段構(gòu)建容器,如果直接通過docker-compose設(shè)置環(huán)境變量只會在后面一個階段生效,但是npm run build是在第一個階段執(zhí)行的,所以環(huán)境變量不能應(yīng)用到Vue當中。為了讓環(huán)境變量在第一階段就應(yīng)用,必須要在構(gòu)建的時候就把變量從docker-compose傳到fame-admin-Dockerfile中,然后在Dockerfile中的第一階段把這個環(huán)境變量應(yīng)用到容器里。下面修改docker-compose.ymlfame-admin部分:

        ?fame-admin:
        ???...
        ???build:?
        ????context:?./
        ????dockerfile:?./fame-docker/fame-admin/fame-admin-Dockerfile
        ????args:
        ??????BASE_URL:?${BASE_URL}?#?這里把環(huán)境變量當做ARG傳給Dockerfile
        ???...

        然后在fame-admin-Dockerfile的第一階段增加步驟

        #?build?stage
        FROM?node:10.10.0-alpine?as?build-stage

        ARG?BASE_URL?#?必須申明這個ARG才能從docker-compose里獲取

        ENV?VUE_APP_API_URL?$BASE_URL

        #?以下省略...

        這樣就可以在構(gòu)建階段一鏡像的時候就把環(huán)境變量傳入到階段一的鏡像里,讓Vue里的變量生效了。

        總結(jié)

        現(xiàn)在網(wǎng)上很多復雜一點的項目即使用了docker-compose部署,也多少依賴shell腳本來操作,比如復制文件設(shè)置環(huán)境等,我覺得這樣會降低docker-compose的意義。如果都使用了shell腳本,那不如直接不用docker-compose而全用shell來構(gòu)建和啟動鏡像。

        所以在Docker化的過程中雖然遇到一些坎坷,但堅持實現(xiàn)了只用docker-compose部署,以后上線和下線就及其方便了。也希望我的Docker化思路可以給其他項目做一些參考。

        對比以前恐怖的步驟,現(xiàn)在Fame博客的上線和下線只需要兩行命令,真的十分的便捷。

        docker-compose?up
        docker-compose?down

        源碼地址 https://github.com/zzzzbw/Fame

        作者:zzzzbw

        segmentfault.com/a/1190000016557755


        最后,給大家準備了一套算法學習教程,從小白到大神,都是這樣走過來的,建議學習一下,拿走不謝!


        下載方式

        1.?首先掃描下方二維碼

        2.?后臺回復「A110」即可獲取


        瀏覽 43
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
          
          

            1. 三级影片在线观看免费的 | 日韩女优无码 | 蜜桃一区 | 大肉大捧一进一出视频来了 | 大香蕉560 |