点击上方 好好学java ,选择 星标 公众号

重磅资讯、干货,第一时间送达

今日推荐:硬刚一周,3W字总结,一年的经验告诉你如何准备校招!

 个人原创100W+访问量博客:点击前往,查看更多

在今年年初的时候,完成了自己的个Fame博客系统的实现,当时也做了一篇博文Spring-boot+Vue = Fame 写blog的一次小结作为记录和介绍。从完成实现到现在,也断断续续的根据实际的使用情况进行更新。

只不过每次上线部署的时候都觉得有些麻烦,因为我的服务器内存太小,每次即使只更新了前台部分(fame-front)的代码,在执行npm build的时候都还必须把我的后端服务(fame-server)的进程关掉,不然会造成服务器卡死(惨啊)。

而且这个项目是前后端分离的,博客前台页面还为了SEO用了Nuxt框架,假如是第一次部署或者要服务器迁移的话,麻烦的要死啊,部署一次的话要以下步骤

  1. 安装mysql,修改相关配置文件,设置编码时区等,然后重启

  2. 下载安装java,配置java环境

  3. 下载安装maven,配置maven环境

  4. 下载安装nginx,修改配置文件,设计反向代理等

  5. 启动spring-boot项目

  6. 打包vue项目,npm install,npm run build

  7. 启动nuxt项目,npm install,npm run start

如果能够顺利的完成这七个步骤算是幸运儿了,假如中间哪个步骤报错出了问题,可能还要回头查找哪个步骤出了问题,然后又重新部署。

我选择死亡

在这些需求面前,Docker就是解决这些问题的大杀器。无论是其虚拟化技术隔离各个容器使其资源互不影响,还是一致的运行环境,以及docker-compose的一键部署,都完美的解决了上述问题。

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

Docker和Docker-compose安装

Docker和Docker-compose的功能和使用可以看线上的一个中文文档Docker — 从入门到实践

下面是Centos7安装和配置Docker以及Docker-compose的shell脚本,其他操作系统可以参考修改来安装。其中Docker版本为docker-ce,Docker-compose版本为1.22.0

#!/bin/sh### 更新 ###
yum -y update### 安装docker ###
# 安装一些必要的系统工具
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并设置为开机启动(centos7)
systemctl  start docker.service
systemctl  enable docker.service
# 替换docker为国内源
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结束 ###

Docker化改造

改造后目录结构

先看一下改造后的项目的结构

├─Fame
│  │  .env                            // docker-compose环境参数配置文件
│  │  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服务器配置文件
│  │  │
│  │  ├─fame-mysql
│  │  │      fame-mysql-Dockerfile    // mysql的Dockerfile文件
│  │  │      mysqld.cnf               // mysql的配置文件mysqld.cnf
│  │  │
│  │  └─fame-nginx
│  │          nginx-Dockerfile        // 整个项目的nginx服务器的Dockerfile文件
│  │          nginx.conf              // 整个项目的nginx的配置文件
│  │
│  ├─fame-admin   // 博客管理后台,基于Vue+elementui
│  ├─fame-front   // 博客前端,基于Nuxt
│  └─fame-server  // 博客服务端,基于spring-boot

为了不破坏原有项目的结构,无论前端还是后端的docker的相关配置文件全部提取出来,单独放在了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项目结构

fame-structure

改造后的docker-compose.yaml文件

version: '3'
services: fame-nginx:container_name: fame-nginxbuild:context: ./dockerfile: ./fame-docker/fame-nginx/nginx-Dockerfileports:- "80:80"volumes:- ./logs/nginx:/var/log/nginxdepends_on:- fame-server- fame-admin- fame-frontfame-mysql:container_name: fame-mysqlbuild: context: ./dockerfile: ./fame-docker/fame-mysql/fame-mysql-Dockerfileenvironment:MYSQL_DATABASE: fameMYSQL_ROOT_PASSWORD: rootMYSQL_ROOT_HOST: '%'TZ: Asia/Shanghaiexpose:- "3306"volumes:- ./mysql/mysql_data:/var/lib/mysqlrestart: alwaysfame-server:container_name: fame-serverrestart: alwaysbuild: context: ./dockerfile: ./fame-docker/fame-server-Dockerfileworking_dir: /appvolumes:- ./fame-server:/app- ~/.m2:/root/.m2- ./logs/fame:/app/logexpose:- "9090"command: mvn clean spring-boot:run -Dspring-boot.run.profiles=docker -Dmaven.test.skip=truedepends_on:- fame-mysqlfame-admin:container_name: fame-adminbuild: context: ./dockerfile: ./fame-docker/fame-admin/fame-admin-Dockerfileargs:BASE_URL: ${BASE_URL}expose:- "3001"fame-front:container_name: fame-frontbuild: context: ./dockerfile: ./fame-docker/fame-front-Dockerfileenvironment:BASE_URL: ${BASE_URL}PROXY_HOST: ${PROXY_HOST}PROXY_PORT: ${PROXY_PORT}expose:- "3000"

docker-compose.yml的结构和刚才目录结构大体类似,也是分以下几个部分

  1. fame-nginx

  2. fame-mysql

  3. fame-server

  4. fame-admin

  5. fame-front

这个docker-compose.yml中有几个要点

  • fame-mysqlfame-serverrestart要设置为always,因为目前Docker-compose是没有一个方案可以解决容器启动的先后的问题的。即使设置了depends_on,那也只是控制容器开始启动的时间,不能控制容器启动完成的时间,所以让fame-mysqlfame-server这两个容器设置restart,防止spring-boot在mysql启动完成之前启动而报错启动失败

  • fame-serverfame-mysqlfame-nginx这三个容器都设置了volumes,把容器里的logs日志文件挂载到宿主机的项目目录里,方便随时看日志文件

  • fame-mysql容器的mysql存储文件也设置了volumes挂载在项目目录里(./mysql/mysql_data:/var/lib/mysql),这个建议大家可以根据实际的情况设置到宿主机的其他目录里,不然不小心删除项目的话那么容器里的数据库数据也都没了

几个镜像的Dockerfile大部分都比较简单,这部分就不全部详细介绍了,可以直接去我项目中了解。

Docker化过程的困难和解决方法

spring-boot双配置切换

为了能够让spring-boot能够在开发环境和Docker环境下快速切换,需要将spring-boot的配置文件进行修改

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

在原有的application.properties基础上增加application-dev.propertiesapplication-docker.properties配置文件,把application.properties里的数据库日志等信息分别放到application-dev.propertiesapplication-docker.properties这两个文件中,实现开发环境和Docker环境的快速切换。

# 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的内容和application-docker.properties文件类似,只是根据自己开发环境的情况修改mysql和log配置。

动态配置axios的baseUrl地址

fame-adminfame-front中用了axios插件,用于发起和获取fame-server服务器的请求。在axios要配置服务器url地址baseUrl,那么通常开发环境和Docker环境以及生产环境的url可能都不一样,每次都去修改有点麻烦。(虽然只需要配置两处,但是代码洁癖不允许我硬编码这个配置)。

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

fame-admin是基于Vue CLI 3搭建的,相对于cli 2.0官方把webpack的一些配置文件都封装起来了,所以没有config和build文件夹。不过对应的官网也给了一些设置更加方便的配置参数。

在官方文档中提到:

只有以 VUE_APP_ 开头的变量会被 webpack.DefinePlugin 静态嵌入到客户端侧的包中。你可以在应用的代码中这样访问它们:

console.log(process.env.VUE_APP_SECRET)

在构建过程中,process.env.VUE_APP_SECRET 将会被相应的值所取代。在 VUE_APP_SECRET=secret 的情况下,它会被替换为 "sercet"

利用这个特性来设置环境变量来动态的设置Docker模式和手动部署模式的baseUrl的值

fame-admin目录下创建文件server-config.js,编写以下内容

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
}

那么只要在环境变量中有VUE_APP_API_URL的值,且NODE_ENV === 'production',baseUrl就等于VUE_APP_API_URL的值,否则就是localhost的值。

接着在axios配置文件中引用该文件设置

// fame-admin/src/plugins/http.js
...
import serverConfig from '../../server-config'const Axios = axios.create({baseURL: serverConfig.api + 'api/',...
})...

现在只要将docker的环境变量设置一个VUE_APP_API_URL的值就行了,只要在对应的Dockerfile中增加一个步骤就可以了。

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

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

同样的,对于用Nuxt搭建fame-front博客前台修改也是类似的思路。

在Nuxt的官方文档中写到:

Nuxt.js 让你可以配置在客户端和服务端共享的环境变量。

例如 (nuxt.config.js):

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

以上配置我们创建了一个 baseUrl 环境变量,如果应用设定了 BASE_URL 环境变量,那么 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以及对应的Dockerfile文件中编写和上面fame-admin部分一样的代码就可以了

现在已经把baseUrl的设置从代码的硬编码中解放出来了,但事实上我们只是把这个参数的编码从代码从转移到Dockerfile文件里了,要是想要修改的话也要去这两个文件里查找然后修改,这样也不方便。后面会解决这个问题把所有环境配置统一起来。

Nuxt在Docker中无法访问到宿主机ip问题

先要说明一点,为什么博客前端要单独去使用的Nuxt而不是和博客后台一样用Vue呢,因为博客前端有SEO的需求的,像Vue这样的对搜索引擎很不友好。

所以Nuxt的页面是服务器端渲染(SSR)的

这样就产生了问题

fame-front的页面在渲染之前必须获取到fame-server服务器中的数据,但是每个docker容器都是互相独立的,其内部想要互相访问只能通过容器名访问。例如容器fame-front想要访问容器fame-server,就设置baseURL = fame-server(fame-server是服务器的容器的container_name)。

这样设置之后打开浏览器输入网址:http://xx.xxx.xxx.xx可以成功...,但是随便点击一个链接,就会看到浏览器提示错误无法访问到地址http://fame-server/...

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

这是必然的结果,在容器里http://fame-server/就是服务器...,但是你本地的浏览器当然是不知道http://fame-server/是个什么鬼...,所以就浏览器就报出无法访问的错误。

什么?可是刚才不是说Nuxt是服务器渲染的页面吗,怎么又让本地浏览器报这个错误了。

原来是因为当通过浏览器链接直接访问的时候,Nuxt的确是从后端渲染了页面再传过来,但是在页面中点击链接的时候是通过Vue-Router跳转的,这时候不在Nuxt的控制范围,而是和Vue一样在浏览器渲染的,这时候就要从浏览器里向服务端获取数据来渲染,浏览器就会报错。

如何解决呢

这个问题开始的时候一直想要尝试配置Docker容器的网络模式来解决,可是都没有解决。直到后面我看axios文档的时候才注意到axios的代理功能,其本质是解决跨域的问题的,因为只要在axios设置了代理,在服务端渲染的时候就会使用代理的地址,同时在浏览器访问的时候会用baseUrl 的地址,这个特点完美解决我的问题啊。

server-config.js文件里增加以下代码(在nuxt.config.js里获取环境变量里的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的环境参数统一设置

在上文解决动态配置axios地址的部分把baseUrl的设置放在了Dockerfile中,现在就再把Dockerfile中的硬编码提取出来,放到统一的配置文件中。

首先在docker-compose.yml文件目录下(即项目跟目录)创建环境文件.env并编写一下内容

BASE_URL=http://xx.xxx.xxx.xxxPROXY_HOST=fame-nginx
PROXY_PORT=80

这个是docker-composeenv_file参数,从文件中获取环境变量,可以为单独的文件路径或列表,如果同目录下有.env文件则会默认读取,也可以自己在docker-compose里设置路径。

已经在.env设置了环境变量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的容器里就有对应的BASE_URL,PROXY_HOST,PROXY_PORT环境变量,Nuxt也能够成功获取并设置。

不过对于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-stageCOPY ./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;"]

这里用了多阶段构建容器,如果直接通过docker-compose设置环境变量只会在后面一个阶段生效,但是npm run build是在第一个阶段执行的,所以环境变量不能应用到Vue当中。为了让环境变量在第一阶段就应用,必须要在构建的时候就把变量从docker-compose传到fame-admin-Dockerfile中,然后在Dockerfile中的第一阶段把这个环境变量应用到容器里。下面修改docker-compose.ymlfame-admin部分:

 fame-admin:...build: context: ./dockerfile: ./fame-docker/fame-admin/fame-admin-Dockerfileargs:BASE_URL: ${BASE_URL} # 这里把环境变量当做ARG传给Dockerfile...

然后在fame-admin-Dockerfile的第一阶段增加步骤

# build stage
FROM node:10.10.0-alpine as build-stageARG BASE_URL # 必须申明这个ARG才能从docker-compose里获取ENV VUE_APP_API_URL $BASE_URL# 以下省略...

这样就可以在构建阶段一镜像的时候就把环境变量传入到阶段一的镜像里,让Vue里的变量生效了。

总结

现在网上很多复杂一点的项目即使用了docker-compose部署,也多少依赖shell脚本来操作,比如复制文件设置环境等,我觉得这样会降低docker-compose的意义。如果都使用了shell脚本,那不如直接不用docker-compose而全用shell来构建和启动镜像。

所以在Docker化的过程中虽然遇到一些坎坷,但坚持实现了只用docker-compose部署,以后上线和下线就及其方便了。也希望我的Docker化思路可以给其他项目做一些参考。

对比以前恐怖的步骤,现在Fame博客的上线和下线只需要两行命令,真的十分的便捷。

docker-compose up
docker-compose down

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

作者:zzzzbw
segmentfault.com/a/1190000016557755
最后,给大家准备了一套算法学习教程,从小白到大神,都是这样走过来的,建议学习一下,拿走不谢!
下载方式1. 首先扫描下方二维码2. 后台回复「A110」即可获取

使用Docker部署SpringBoot+Vue博客系统相关推荐

  1. SpringBoot+Vue博客系统---后端接口开发

    Java后端接口开发 从零开始搭建一个项目骨架,最好选择合适,熟悉的技术,并且在未来易拓展,适合微服务化体系等.所以一般以Springboot作为我们的框架基础,这是离不开的了. 然后数据层,我们常用 ...

  2. 个人博客,懒人终章部署,阿里云Ecs+Jenkins+Gitee自动,一键部署SpringBoot自己博客项目,还在用

    阿里云Ecs+Jenkins+Gitee自动,一键部署SpringBoot自己博客项目: 最近看见网上很多Jenkins的自动部署SpringBoot的Demo,但是都要自己安装JDK,Maven.. ...

  3. Java+MySQL基于springboot校园博客系统#毕业设计

    项目编号:Java+MySQL spring216-基于springboot校园博客系统#毕业设计 开发语言:Java 开发工具:IDEA /Eclipse 数据库:MYSQL5.7 应用服务:Tom ...

  4. 手牵手教Docker部署Springboot+vue ,全过程十分详细,轻松完成项目部署(简单,高效,通用)

    手把手教Docker部署Springboot+vue ,详细全过程,轻松完成项目部署(简单,高效) 上线前准备 腾讯云的服务器,服务器安装好docker 和docker-compose 最好事先了解技 ...

  5. 基于Spring Boot+Vue博客系统的设计与实现(附源码)

    摘要 中文博客第一次映入眼帘是在2002年,那时候的个人终端还是人们眼中的香饽饽,随着科技的不断进步和制造业的蓬勃发展,个人计算机终端开始逐渐变得普及,实现了人手一台电脑,在这种趋势中,博客系统走入了 ...

  6. SpringBoot个人博客系统(含源码+数据库)

    一.作品设计理念 个人博客系统是一个让个人可以通过互联网自由表达.交流和分享的平台,是个人展示自己思想.感受和经验的品牌.设计理念对于任何一个个人博客系统来说都非常重要,它直接影响到用户的使用体验和网 ...

  7. 超详细Docker部署SpringBoot+Vue项目(三更博客项目部署)

    文章目录 1.项目部署规划 2.前置工作 2.1修改后端配置文件ip 2.2修改前端Vue项目运行端口 2.3修改前端对应的服务器ip 2.4后端项目打包 2.4.1解决打包问题 2.4.2项目打包, ...

  8. springboot+vue博客项目(码神之路博客项目)

    写在最前:b站中博客项目除了这个还有一个三更草堂的博客项目也是不错的,三更草堂会比这个完善些,但是码神这个项目也非常好,看完这个再去看三更的,互相补充.(这两个博客项目应该是目前b站最好的了,而且时间 ...

  9. 使用 KubeSphere 部署 Halo 开源博客系统

    Halo 简介 Halo 是一款现代化的开源博客/CMS系统,具有快捷部署和较多漂亮主题模版的特性,深受很多用户喜欢,Halo 还提供了完善的 Content API 和 Admin API,这让用户 ...

最新文章

  1. hilbert变换_希尔伯特变换 matlab实现
  2. ppt转html格式
  3. PHP函数——urlencode() 函数
  4. 土木工程到底有多惨?哭了哭了......
  5. Python使用鼠标滚轮调整tkinter应用程序窗口大小
  6. 占用率_有问有答:任务管理器里面的GPU占用率到底是怎么算的?
  7. 牛客多校第五场 A digits 2 签到
  8. MOQL--操作数(Operand) (二)
  9. 46. 避免 CSS 表达式(7)
  10. jmeter展示内存cpu_Jmeter监控服务器-CPU,Memory,Disk,Network性能指标
  11. 字节码指令之同步控制指令
  12. 米聊PC版体验评测: 简约过头的即时聊天工具
  13. PMP/PRINCE2/IPMP/软考,主流项目管理认证对比
  14. Python 利用pandas 获取Excel重复记录
  15. 2018世界人工智能大会总结
  16. 使用Axure RP8 模拟遮罩层显隐
  17. 视频在html不能播放器,网页无插件直播H265编码视频播放器EasyPlayer网页播放器不能播放怎么处理?...
  18. 删除AppData后出现任务栏图标点击没反应的解决方法
  19. 北方民族大学计算机复试题库,2016年北方民族大学计算机科学与工程学院信号与系统考研复试题库...
  20. 对无人机高度环的思考和第一次炸机体验

热门文章

  1. STM32的启动分析
  2. ESP8266串口处理
  3. R语言:ts() 时间序列的建立
  4. 初等数论--同余--欧拉函数、欧拉定理、费马小定理
  5. 基于SpringBoot和Vue的个人博客系统
  6. 数据结构--双向链表
  7. 738. 单调递增的数字(贪心算法)
  8. unittest单元测试框架—加载测试用例的3种方法以及测试报告存储管理
  9. Boost Part III. 函数对象与高级编程 Library 10. Lambda 用法 switch_statement
  10. APK安装时如何拷贝apk里的文件到sdcard