springboot+vue项目部署全流程(一)

最近有个课程项目,需要部署到服务器上,免费领取了阿里云两个月的云服务器,记录一下部署过程

1.基本环境

Xshell连接到阿里云主机,下载docker

yum install docker-ce

有可能会报错:

Problem: package docker-ce-3:20.10.1-3.el7.x86_64 requires containerd.io >= 1.4.1, but none of the providers can be installed

这是由于需要1.4.1版本以上的containerd.io,默认是安装1.2.0-3.el7版本,需要自己改

yum install https://download.docker.com/linux/centos/8/x86_64/stable/Packages/containerd.io-1.4.3-3.1.el8.x86_64.rpm

安装好了之后重新安装docker,启动docker

systemctl start docker #启动docker
systemctl enable docker #设置开机自启

可以通过vi /etc/docker/daemon.json并添加其他源:

{
    
    
    "registry-mirrors" : [
    "https://registry.docker-cn.com",
    "https://docker.mirrors.ustc.edu.cn",
    "https://cr.console.aliyun.com/"
  ]
}

重启docker服务systemctl restart docker.service,加快docker拉取速度

拉取mysql镜像:docker pull mysql

首先创建数据挂载点:

docker volume create mysql_data

启动数据库容器(这里我把数据库数据放在了自定义目录/root/docker/mysql/data下):

docker run -d --name mysql -p 3306:3306 -v mysql_data:/root/docker/mysql/data -e MYSQL_ROOT_PASSWORD=123456 mysql

docker exec -it mysql bash进入容器
mysql -uroot -p123456 进入mysql
执行GRANT ALL PRIVILEGES ON *.* TO 'root'@'%'WITH GRANT OPTION;
刷新FLUSH PRIVILEGES;

navicat 服务器ip + 3306端口远程连接测试,测试成功即可,有可能这时候会失败,是因为服务器没有开放3306端口

我用的是阿里云,点击安全组,然后配置安全组添加即可

  • 其他容器例如redis:
docker run --name redis -v redis_data:/root/docker/redis/data -d -p 6379:6379 redis redis-server --requirepass "123456" --appendonly yes

其他容器过程类似,此处省略

2.springboot和vue的简单合并

  • 在vue的目录下cmd运行npm run build,打包成dist文件,并将其中的文件复制进springboot的resources中的static文件夹
    在这里插入图片描述
    若仍无法访问,需要设置资源访问规则
@Configuration
public class WebConfig implements WebMvcConfigurer {
    
    
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
    
    
        registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
        WebMvcConfigurer.super.addResourceHandlers(registry);
    }
    @Bean
    public FilterRegistrationBean filterRegistration() {
    
    
        FilterRegistrationBean<RewriteFilter> registration = new FilterRegistrationBean<>();
        //注册rewrite过滤器  
        registration.setFilter(new RewriteFilter());
        registration.addUrlPatterns("/*");
        registration.addInitParameter(RewriteFilter.REWRITE_TO,"/index.html");
        registration.addInitParameter(RewriteFilter.REWRITE_PATTERNS, "/vis/*");
        registration.setName("rewriteFilter");
        registration.setOrder(1);
        return registration;
    }
}
/**
 * 过滤后端请求,不属于后端的请求,交由前端路由处理
 */
public class RewriteFilter implements Filter {
    
    
    /**
     * 需要rewrite到的目的地址
     */
    public static final String REWRITE_TO = "rewriteUrl";

    /**
     * 拦截的url,url通配符之前用英文分号隔开
     */
    public static final String REWRITE_PATTERNS = "urlPatterns";

    /** 配置url通配符 */
    private Set<String> urlPatterns = null;

    private String rewriteTo = null;
    @Override
    public void init(FilterConfig cfg) throws ServletException {
    
    
        //初始化拦截配置
        rewriteTo = cfg.getInitParameter(REWRITE_TO);
        String exceptUrlString = cfg.getInitParameter(REWRITE_PATTERNS);
        if (!StringUtils.isEmpty(exceptUrlString)) {
    
    
            urlPatterns = Collections.unmodifiableSet(
                    new HashSet<>(Arrays.asList(exceptUrlString.split(";", 0))));
        } else {
    
    
            urlPatterns = Collections.emptySet();
        }
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
    
    
        HttpServletRequest request = (HttpServletRequest) req;
        String servletPath = request.getServletPath();
        //匹配到后端路径标识,放行,否则,交给前端路由
        if (isMatches(urlPatterns, servletPath)) {
    
    
            req.getRequestDispatcher(rewriteTo).forward(req, resp);
        }else{
    
    
            chain.doFilter(req, resp);
        }
    }

    @Override
    public void destroy() {
    
    

    }

    /**
     * 匹配返回true,不匹配返回false
     * @param patterns 正则表达式或通配符
     * @param url 请求的url
     * @return
     */
    private boolean isMatches(Set<String> patterns, String url) {
    
    
        if(null == patterns){
    
    
            return false;
        }
        for (String str : patterns) {
    
    
            if (str.endsWith("/*")) {
    
    
                String name = str.substring(0, str.length() - 2);
                if (url.contains(name)) {
    
    
                    return true;
                }
            } else {
    
    
                Pattern pattern = Pattern.compile(str);
                if (pattern.matcher(url).matches()) {
    
    
                    return true;
                }
            }
        }
        return false;
    }
}

本机测试,ip + /index.html,成功访问

这种方法不推荐,推荐使用nginx,前后端分离部署,后续(二)中会提到

3.部署

先clean,再package打包,把生成的jar包和Dockerfile通过xftp发到服务器
在这里插入图片描述
Dockerfile:

FROM openjdk:13-alpine3.9
VOLUME /tmp 
ADD *.jar app.jar
RUN sh -c 'touch /app.jar'
ENV JAVA_OPTS=""
ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar" ]
docker build -t myImage .
  • VOLUME指向了一个/tmp的目录,由于SpringBoot使用内置的Tomcat容器,Tomcat默认使用/tmp作为工作目录。效果就是在主机的/var/lib/docker目录下创建了一个临时文件,并连接到容器的/tmp
  • add将项目的jar文件作为app.jar添加到容器
  • RUN表示在新创建的镜像中执行一些命令,然后把执行的结果提交到当前镜像。这里使用touch命令来改变文件的修改时间,Docker创建的所有容器文件默认状态都是“未修改”。这对于简单应用来说不需要,不过对于一些静态内容(比如:index.html)的文件就需要一个“修改时间”
  • ENTRYPOINT 应用启动命令 参数设定

接着运行容器:

docker run -itd --net=host --name 随意容器名 -p 8088:8088 刚刚创建镜像名

–net=host 告诉 Docker 不要将容器网络放到隔离的名字空间中,即不要容器化容器内的网络。此时容器使用本地主机的网络,它拥有完全的本地主机接口访问权限。容器进程可以跟主机其
它 root 进程一样可以打开低范围的端口,可以访问本地网络服务比如
D-bus,还可以让容器做一些影响整个主机系统的事情,比如重启主机。因此使用这个选项的时候要非常小心。如果进一步的使用
–privileged=true,容器会被允许直接配置主机的网络堆栈

后续将更新结合nginx的前后端分离部署

猜你喜欢

转载自blog.csdn.net/qq_40622253/article/details/111884984