云服务器-Docker容器-系统搭建部署

一、引言

        最近公司在海外上云服务器,作者自己也搞了云服务器去搭建部署系统,方便了解整体架构和系统的生命周期,排查解决问题可以从原理侧进行分析实验。虽然用的云不是同一个,但是原理都是相通的。

二、选型

        作者选用的是腾讯云,没别的原因,就是便宜加牌子大。

        阿里云肯定是更好一些的,不管是服务售后还是服务器内核和操作系统都是比较活跃的,毕竟作者以前公司用的就是阿里云,了解一些。

        不过以前都是和运维沟通排查问题,作者自己只能看到一些服务器监控和运维的截图,这对于了解整个云服务架构体系的生命流程是不太友好的。

        操作系统选择了CentOS7.6-Docker20,毕竟linux的底层是必须的,目前的容器环境也是服务的基础。

        基本参数如下,没必要太好

  • CPU - 2核 内存 - 4GB
  • 系统盘 - SSD云硬盘 60GB管理快照
  • 流量包 - 500GB/月(带宽:5Mbps)

三、系统搭建部署

        作者准备把springboot用Maven打包,jar包拿到docker容器运行

3.1、后端

        后端是SpringBoot,SSM框架,代码就不贴了,作者写了个小程序给家里人用的。

3.2、打包

        这一步很麻烦,打出来的包很小,作者当时还没意识到问题,本地java -jar运行一下,报错了。显示no main manifest attribute, in /**.jar,问了一下chatGpt,这就很扯,做了这么久的SpringBoot,他里面的application怎么可能不是字段设置为主类的呢。

17ce6df27b104a96b5382aafb3c999ce.png

        作者有找了网上的一些文章,有的说是打包的时候没有设置入口类,pom的build重新设置一下。

<build>
        <plugins>
            <!-- maven-compiler-plugin 插件配置 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>

            <!-- maven-jar-plugin 插件配置 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>3.2.0</version>
                <configuration>
                    <archive>
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <mainClass>**.Application</mainClass>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>

            <!-- 其他插件... -->
        </plugins>
    </build>

        然后出现了新的错误:Caused by: java.lang.ClassNotFoundException: org.springframework.boot.SpringApplication
at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:355)
at java.lang.ClassLoader.loadClass(ClassLoader.java:351)

        跟chatgpt拉扯了许久,还是没找到正确的pom,又找了朋友看以前做的项目,其实很简单的po,完全依赖spring自动打包发现

<build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

        打包之后有60几M大小,之前只有几百k,所以很明显了,再次本地运行java -jar,显示成功,通过Localhost也可以访问里面的接口

d1d0931761fe47d880c8ebe02fd1de4f.png

 3.3 部署

        部署系统jar之前,需要先把数据库部署好,不然根本运行不起来。

1、部署mysql

        这里安装的的是mysql5.7,习惯了这个版本

        下载MySQL 5.7的Docker镜像:docker pull mysql:5.7
        下载完成后,可以运行以下命令来创建并运行MySQL容器:docker run --name mysql -e MYSQL_ROOT_PASSWORD=<password> -p 3306:3306 -d mysql:5.7
        创建一个名为`mysql`的容器,并将MySQL的默认端口3306映射到主机的3306端口。将`<password>`替换密码。
        检查MySQL容器是否正在运行:docker ps -a
        如果看到`mysql`容器正在运行,说明MySQL已经成功安装并运行在Docker中。

        如果MySQL容器未运行,启动它:docker start mysql

        登录到MySQL:docker exec -it mysql mysql -u root -p

        检查MySQL服务器的运行状态:service mysql status
        启动它:service mysql start

        作者在这中间还走了一些弯路,一开始不想设置用户名密码,结果导致他自动生成了一串,作者还不知道密码是什么,又进去修改密码,最后还生成了两个root账号,一个权限是*一个是localhost,导致后面jar运行出了问题。

2、部署服务

        腾讯云界面上有个SFTP的文件可视化,作者一开始不知道,还准备搞市面上的一些文件传输软件,毕竟jar包需要传输到远程服务器。

        首先要创建一个Dockerfile,这个文件没有后缀的,在服务器窗口建好文件夹之后

        输入:vi Dockerfile

        从vi界面搭建i编辑,自动创建文件,写完内容之后点击esc退出编辑状态,再点击:wq退出文件并且保存。

        Dockerfile里面内容:

# 基础镜像使用java
FROM openjdk:8-jdk-alpine
# VOLUME 指定了临时文件目录为/tmp。
# 其效果是在主机 /var/lib/docker 目录下创建了一个临时文件,并链接到容器的/tmp
VOLUME /tmp
ADD test-provider-service-0.0.1.jar /test-provider-service.jar
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/test-provider-service.jar"]

1. `FROM openjdk:8-jdk-alpine`:指定使用OpenJDK 8的Alpine Linux作为基础镜像。

2. `VOLUME /tmp`:指定将主机的`/var/lib/docker`目录与容器的`/tmp`目录进行挂载,用作临时文件目录。

3. `ADD test-provider-service-0.0.1.jar /test-provider-service.jar`:将当前目录下的`test-provider-service-0.0.1.jar`文件复制到容器的根目录,并将其重命名为`test-provider-service.jar`。

4. `ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/test-provider-service.jar"]`:指定容器启动时要执行的命令。这里是运行Java应用程序的命令,使用`java`命令执行`test-provider-service.jar`文件。

        然后把jar传入服务器,jar要和Dockerfile在一个文件夹里面。

        创建docker镜像:docker build -t ** .

        这个.是指使用当前文件夹,所以要先cd到jar所在的文件夹,**就是指容器的名字。

        运行容器:docker run -d -p 5006:5006**

        用的是宿主机5006端口,容器的5006也是作者springboot用的端口,默认springboot是用8080的,这个要在配置文件设一下

3、问题排查解决

3.1、root拒绝

        docker ps -a看一下容器状态,诶嘿,退出来了exit,说明jar有问题,但是docker logs ** 有看不到日志,那就加个日志打印。

public class Application {

    public static void main(String[] args) {
        try{
            SpringApplication.run(Application.class, args);
        } catch (Throwable t) {
            System.out.println(t);
            throw t;
        }
    }
}

       先得把之前的容器和镜像删除,然后重新生成,删除容器需要用容器id或者名称,在docker ps -a中可以看到:docker rm **

        删除镜像:docker rmi **        

        爆出来的是:access denied for user 'root'@'ip' (using password: YES)  

        一开始还以为是配置错了账号密码,在本地又跑了一下,但是很明显没有问题,

        看了一下mysql,在MySQL的user表中,每个用户都有一个唯一的组合键,由用户名(User)和主机名(Host)组成。这意味着即使用户名相同,只要主机名不同,就会被视为不同的用户。我猜测的是root这个%会拦截所有的root访问,因为在本地用workBench去链接显示的也是拒绝。但是%的root不是我设置的密码,所以得加一个新的用户密码。

root | localhost
root | %

        创建一个具有相同权限的新用户,但允许从任何主机访问MySQL服务器:

        CREATE USER 'new_user'@'%' IDENTIFIED BY 'password';GRANT ALL PRIVILEGES ON *.* TO 'new_user'@'%' WITH GRANT OPTION;

3.2、链接mysql失败

        再次运行镜像爆出了不一样的错误:

Unsatisfied dependency expressed through bean property 'sqlSessionFactory'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'sqlSessionFactory' defined in class path resource [org/mybatis/spring/boot/autoconfigure/MybatisAutoConfiguration.class]: Unsatisfied dependency expressed through method 'sqlSessionFactory' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in class path resource [com/alibaba/druid/spring/boot/autoconfigure/DruidDataSourceAutoConfigure.class]: Invocation of init method failed; nested exception is com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure

        很明显是mysql的链接问题,但是为什么会出现这种问题,问一下chatgot

6883d3fd87fc499e849f7e84baf011e6.png

         说的很官方,没有什么实际作用,但是原理是相同的,要么是驱动程序问题,要么是网络问题,如果是驱动程序应该不可能出现本地运行成功,服务器失败。

        那么就要思考服务器的docker容器和本地运行到底有什么区别,作者想到的是mysql和服务jar运行在两个容器当中,本地访问服务器的mysql是通过公网ip,那么在服务器jar里面的配置是使用127.0.0.1(localhost)去链接mysql,那么是不是不能直接使用localhost去链接。

        因为云服务器的容器不一定在同一个宿主机上面,即使在同一个宿主机,分配端口维度也可能是容器,这个就看每个云厂商怎么设置的规则了。

        带着这样的猜测,作者把配置文件改为使用内网ip,结果成功了。

b9a4c6e1f75844a7a9a5602ec06bde93.png

 四、总结

        通过自己安装部署云服务器上的系统,作者对于整个系统架构有了更多了解,实践出真知,对于技术工具实验和底层原理排查都有帮助。

猜你喜欢

转载自blog.csdn.net/m0_69270256/article/details/132311966