提示:本次部署采用centos7服务器,使用nginx进行反向代理,运行docker容器完成上线。小白看完这篇都会了! 补充说明:未经本人同意禁止转载!本文的shell代码及dockerfile代码请在linux环境下使用vim复制粘贴运行,不然会出现乱码!本文也提供了这些文件的下载地址,详情查看文末! 一、环境提前准备工作。 1.centos云服务器 国内比较出名的云服务器属阿里云、腾讯云、百度云,三家各有优劣,自行了解比较,并选择自己适合的购买就行,新用户有很大的优惠。 阿里云服务器新用户链接:https://www.aliyun.com/product/ecs?userCode=m3bbolgr 腾讯云服务器新老用户活动链接:https://cloud.tencent.com/act/cvmgift?hash=I7h4cIANzuM0Vd0J&fromSource=gwzcw.1293314.1293314.1293314&cps_key=98e3b13dc4a1659435daf62289161ee5 百度云服务器新用户链接:https://cloud.baidu.com/campaign/2021autdiscount/index.html?track=cp:nsem 2.服务器安装Docker如何部署请参考下面: # step 1: 安装必要的一些系统工具 sudo yum install -y yum-utils device-mapper-persistent-data lvm2 # Step 2: 添加软件源信息 sudo yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo # Step 3 sudo sed -i 's+download.docker.com+mirrors.aliyun.com/docker-ce+' /etc/yum.repos.d/docker-ce.repo # Step 4: 更新并安装Docker-CE sudo yum -y install docker-ce # Step 4: 开启Docker服务 sudo service docker start # 注意: # 官方软件源默认启用了最新的软件,您可以通过编辑软件源的方式获取各个版本的软件包。例如官方并没有将测试版本的软件源置为可用,您可以通过以下方式开启。同理可以开启各种测试版本等。 # vim /etc/yum.repos.d/docker-ce.repo # 将[docker-ce-test]下方的enabled=0修改为enabled=1 # # 安装指定版本的Docker-CE: # Step 1: 查找Docker-CE的版本: # yum list docker-ce.x86_64 --showduplicates | sort -r # Loading mirror speeds from cached hostfile # Loaded plugins: branch, fastestmirror, langpacks # docker-ce.x86_64 17.03.1.ce-1.el7.centos docker-ce-stable # docker-ce.x86_64 17.03.1.ce-1.el7.centos @docker-ce-stable # docker-ce.x86_64 17.03.0.ce-1.el7.centos docker-ce-stable # Available Packages # Step2: 安装指定版本的Docker-CE: (VERSION例如上面的17.03.0.ce.1-1.el7.centos) # sudo yum -y install docker-ce-[VERSION]强烈推荐配置!不然好多镜像从官方仓库拉不下来! 剩下的具体配置,这个页面也教你怎么配了,不多说。 3.编写dockerfile,创建project容器。包含前后端打包的环境,将项目放进去,包含git可以及时更新项目 # projcet_dockerfile FROM centos:7 MAINTAINER luoqianyi<3228077562@qq.com> RUN yum -y update \ #安装vim编辑器 && yum -y install vim \ #安装git,方便代码同步 && yum -y install git \ #安装wget,方便进入容器下载其它资源 && yum -y install wget \ #安装jdk && yum -y install java-1.8.0-openjdk-devel.x86_64 \ #配置maven源和运行环境,用于后端项目打包和导入依赖 && yum-config-manager --add-repo \ && yum-config-manager --enable epel-apache-maven\ && yum install -y apache-maven \ && mkdir ~/.m2 RUN echo '<?xml version="1.0" encoding="UTF-8"?><settings xmlns="" xmlns:xsi="" xsi:schemaLocation=" "><mirrors><mirror><id>nexus-aliyun</id><mirrorOf>*</mirrorOf><name>Nexus aliyun</name><url></url></mirror></mirrors></settings>' > ~/.m2/settings.xml #安装并配置nvm环境 RUN wget https://nodejs.org/dist/v14.17.5/node-v14.17.5-linux-x64.tar.xz \ && tar xf node-v14.17.5-linux-x64.tar.xz \ && mv node-v14.17.5-linux-x64 /usr/local ENV PATH $PATH:/usr/local/node-v14.17.5-linux-x64/bin #安装yarn,解决npm install卡住的情况 RUN npm install yarn -g CMD echo "finish---------------------------->success!"创建完这个project_dockerfile后,进行build生成新镜像,我这里将部署用到的dockerfile放到宿主机下自己创建的dockerfiles文件夹下。那么我需要在这个文件夹下进行build的命令就是docker build -f /dockerfiles/project_dockerfile -t luoqianyi/project . 完成构建的截图如下: 等待构建的过程中可以喝杯茶放松一下。 4.宿主机创建项目文件夹,给luoqianyi/project创建数据卷容器将容器里的项目与宿主机挂载,通过xftp工具方便查看代码并进行一些快捷的操作,减少繁复操作。 #本地 mkdir /datavolumes mkdir /datavolumes/project #创建容器,进入bash docker run -it -v /datavolumes/project:/project --name pro luoqianyi/project bash #进入到容器里面后,进入/project目录下 cd /project #git克隆远程仓库代码到/project目录下,克隆链接使用http,如果提示输入邮箱密码,自己输错了,可以按ctrl+退格键进行删除 git clone https://xxxx.xxxx.git #进入拉取的项目里面设置用户信息 git config --global user.email "you@example.com" git config --global user.name "Your Name" #然后就可以根据项目的变化情况进行同步了,git操作这里就不多说了,不会的可以先去学一下。 #--------------------------------------------------------------------- #这里可以对前后端项目直接进行打包,方便其它服务性质的容器直接运行 #进入前端项目目录 npm install #如果卡住使用 yarn install npm run build #生成的dist目录,这是我们接着后面部署需要的 #进入后端项目目录,后端我这里用maven进行管理的 mvn clean install #这时候也可直接运行mvn spring-boot:run启动后端项目了 二、具体流程 1.编写拉取镜像的后端脚本,例如mysql镜像等此操作简化操作,省去一个一个的自己去搜去拉,这里拉取的都是官方的镜像,可以指定版本信息。 注意:如果你买的服务器配置较高,那么连mysql的时候可以连8.0版本以上,不然还是拉取5.x版本的吧,版本太高,mysql都可以拿你服务器的cpu烤肉了。如果是5.x版本的mysql,记得看一下后端连的mysql是啥版本,需不需要进行更换。 #!/bin/bash #OR #!/bin/sh #Scriptname:pull_images.sh #Author:luoqianyi #本脚本提供的默认后端环境镜像 DEFAULT_IMAGES=('mysql' 'redis' 'tomcat' 'rabbitmq' 'zookeeper' 'nginx') echo -e "\e[1;33m 开始进行镜像的拉取,你只需要输入镜像的名字或版本号即可,不输入直接回车代表默认拉取最新版本镜像!\e[0m" for image in ${DEFAULT_IMAGES[@]} do echo -e "\e[1;31m=============开始拉取 ${image} ============================ \e[0m" read -p "请输入版本号:" answer if [ "${answer}" == "" ] then docker pull ${image} else docker pull "${image}:${answer}" fi echo -e "\e[1;32m拉取${image}:${answer}完毕!\e[0m" done read -p "本脚本默认镜像已拉取完毕,是否获取其它镜像,[y/n]?" res if [ "${res}" == "" -o "${res}" == "y" -o "${res}" == "Y" ] then while [ "${yn}" == "" -o "${yn}" == "y" -o "${yn}" == "Y" ] do echo -e "\e[1;31m请输入拉取的镜像及版本,输入参考\e[0m \e[1;33m mysql:5.7\e[0m " read img echo -e "\e[1;31m=============开始拉取 ${img} ============================\e[0m" docker pull "${img}" echo -e "\e[1;32m自定义拉取${img}完毕!\e[0m" read -p "是否继续拉取镜像?[y/n]: " yn done echo "脚本运行结束!" exit 1 else echo "脚本运行结束!" exit 1 fi这个脚本你可以放在服务器的某个目录下,然后在该目录下通过bash pull_images.sh或sh pull_images.sh可以运行此脚本,运行过程中提供了6个后端常用的镜像,根据脚本运行的提示来就行。这个只是减轻我们重复pull的过程,简化一下操作。如果你只需要安装一个两个镜像,那么大可不必使用此脚本,直接用命令一个一个拉就行。 脚本执行界面如下: 设置相关服务密码,确定项目中是否用到中文字体,路径中是否存在中文,更改数据库版本问题等等。。。 这里说明一下我部署中出现的一些问题,供大家解决参考: 2.1.1编码问题:路径中是否包含中文由于是在linux服务器上运行,可能存在中文乱码的情况,前台上传文件到服务器后,服务器返回给前台的文件列表中出现中文乱码,所有的中文文件名全部变成?,英文文件名则正常显示。 由于我们项目运行是在docker里的,我们可以更改docker容器的编码即可,这样解决了编码乱码的问题。 查看docker容器编码格式:执行locale命令;可以看到当前编码格式为POSIX,而这种编码格式不支持中文: 那么我们可以先看一下容器已经有的所有语言,执行locale -a ok,有en_US.utf8编码(如果切换后仍然乱码,建议参考这篇文章安装中文语言包Linux中的系统语言包及UTF-8、en_US.UTF-8和zh_CN.UTF-8的区别),我们进行切换: LANG=en_US.UTF-8 (如果有zh_CN.UTF-8,建议切换为这个) source /etc/profile这样一来,当前容器的编码就可以兼容中文编码了。 2.1.2.字体问题:new Font()找不到字体
解决方法1: 项目static静态资源目录下加个fonts文件夹,项目需要的字体放到这个文件夹下,new Font()的时候指定从哪里找字体文件即可,这需要改一下代码即可,然后git进行同步一下即可。
解决方法2: 上面那种方法可能有点麻烦,这里推荐第二种方法: #步骤1:以windows为例子:进入自己电脑的控制面板,找到 字体 ,搜索需要的字体(以宋体为例),右键复制 #步骤2:通过xftp将字体复制到/usr/share/ 下 #步骤3:执行命令 docker cp /usr/share/fonts/SIMSUN.TTC pro:/usr/share/fonts/ #完毕! 2.1.3.时区问题:应用时间和系统时间不匹配由于服务器上的时区默认是UTC的,不是北京时间,所以后端项目启动类上需要改一下代码,以springboot项目为例: 在启动类main方法里加上即可 TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai"));但是这不是根本解决办法,因为还有其它的情况,比如mysql时区设置,难道我们也要一点一点去改吗?当然duck不必!其实根本的解决办法就是: 启动容器的时候挂载宿主机服务器的/etc/localtime与容器的/etc/localtime,以及/etc/timezone,举个栗子: docker run -it -v /datavolumes/project:/project -v /etc/localtime:/etc/localtime -v /etc/timezone:/etc/timezone --name pro luoqianyi/project bash 2.1.4.其它问题仔细检查,细心推敲,不断尝试,多查百度! 2.2.后端相关容器服务启动 2.2.1.在宿主机下建立一个网桥就Docker而言,网桥网络使用软件网桥,该软件网桥允许连接到同一网桥网络的容器进行通信,同时提供与未连接到该网桥网络的容器的隔离,所以这里就很建议使用网桥了。 docker network create project-net 2.2.2.根据镜像脚本编写启动容器的脚本 #!/bin/bash #OR #!/bin/sh #Scriptname:run_container.sh #Author:luoqianyi #脚本提供的默认后端环境镜像最新版,以此为基础拓展run,比如elasticsearch等 DEFAULT_IMAGES=('mysql' 'redis' 'rabbitmq:management' 'nginx') echo -e "\e[1;33m 开始运行容器,本脚本全自动化,如果需要个性化定制,可自行修改相关代码!\e[0m" #建立数据卷的宿主机目录 ROOT_DIR=/datavolumes/docker #常用容器的配置挂载 #mysql MYSQL_CONF=/datavolumes/docker/mysql/conf MYSQL_DATA=/datavolumes/docker/mysql/data MYSQL_LOGS=/datavolumes/docker/mysql/logs #redis REDIS_DATA=/datavolumes/docker/redis/data REDIS_CONF=/datavolumes/docker/redis/redis.conf #nginx NGINX_CONF=/datavolumes/docker/nginx/conf NGINX_LOGS=/datavolumes/docker/nginx/logs #强烈建议给每个服务加密码,不然极其不安全,服务器被攻击的现象太常见了,加个密起码安全一点 # mysql默认密码 MYSQL_ROOT_PASSWORD=123456 # redis 默认密码 REDIS_DEFAULT_PASS=123456 # rabbitmq 默认虚拟机和用户账号 RABBITMQ_DEFAULT_VHOST=my-rabbit RABBITMQ_DEFAULT_USER=guest RABBITMQ_DEFAULT_PASS=guest #杀死占用容器端口的进程 kill_ports(){ echo "$1端口占用情况如下:" lsof -i:$1 echo "清理占用端口中..." sudo kill -9 $(lsof -i:$1 -t) echo "清理完毕,检查是否还有端口占用!" lsof -i:$1 } run_mysql(){ echo -e "\e[1;31m=============开始启动 mysql ============================ \e[0m" sudo killall mysqld docker rm -f pro_mysql mkdir $ROOT_DIR/mysql docker run -d --name pro_mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=$MYSQL_ROOT_PASSWORD -v $MYSQL_CONF:/etc/mysql/conf.d -v $MYSQL_DATA:/var/lib/mysql -v $MYSQL_LOGS:/var/log mysql echo -e "\e[1;32m mysql容器启动结束!\e[0m" } run_redis(){ echo -e "\e[1;31m=============开始启动 redis ============================ \e[0m" mkdir $ROOT_DIR/redis touch $REDIS_CONF cat>$REDIS_CONF <<END #注释掉这部分,这是限制redis只能本地访问 #bind 127.0.0.1 #默认yes,开启保护模式,限制为本地访问 protected-mode no #默认no,意为是否以守护进程方式启动,可后台运行,不要改为yes 否则可能redis会启动失败 daemonize no #redis持久化(可选) appendonly yes #设置redis密码 requirepass $REDIS_DEFAULT_PASS END port=6379 kill_ports $port docker rm -f pro_redis docker run -p 6379:6379 --name pro_redis -v $REDIS_CONF:/etc/redis/redis.conf -v $REDIS_DATA:/data -d redis redis-server /etc/redis/redis.conf --appendonly yes echo -e "\e[1;32m redis容器启动结束!\e[0m" } run_rabbitmq(){ echo -e "\e[1;31m=============开始启动 rabbitmq:management ============================ \e[0m" #5672是rabbitmq的端口,15672是管理界面的端口。 #启动后在浏览器中输入虚拟机地址:15672来访问管理界面,默认登录用户名和密码都是guest port1=5672 kill_ports $port1 port2=15672 kill_ports $port2 docker rm -f pro_rabbit docker run -d --hostname $RABBITMQ_DEFAULT_VHOST --name pro_rabbit -e RABBITMQ_DEFAULT_USER=$RABBITMQ_DEFAULT_USER -e RABBITMQ_DEFAULT_PASS=$RABBITMQ_DEFAULT_PASS -p 15672:15672 -p 5672:5672 rabbitmq:management echo -e "\e[1;32m rabbitmq:management容器启动结束!\e[0m" } run_nginx(){ echo -e "\e[1;31m=============开始启动 nginx ============================ \e[0m" mkdir $ROOT_DIR/nginx docker rm -f pro_nginx #共享宿主机端口,动态映射式运行nginx容器,容器挂载生成一个conf文件夹 docker run --net host -v $NGINX_CONF:/conf -v $NGINX_LOGS:/var/log/nginx -v /datavolumes/project:/var/www/html --name pro_nginx -d nginx #容器与宿主机交互,宿主机目录在容器目录下有快捷方式,而容器目录在宿主机目录也有快捷方式,方便维护 #step1:conf.d文件夹如果没有可以在容器里建一个 docker exec -it pro_nginx mkdir /etc/nginx/conf.d #step2:将conf.d移到/conf下 docker exec -it pro_nginx mv /etc/nginx/conf.d /conf #step3:建立/nginx_conf/conf.d 与 /etc/nginx的软连接 docker exec -it pro_nginx ln -s /conf/conf.d /etc/nginx #step4:将nginx.conf移到conf下,方便在宿主机查看 docker exec -it pro_nginx mv /etc/nginx/nginx.conf /conf #step5:建立/etc/nginx/nginx.conf与/conf的软连接 docker exec -it pro_nginx ln -s /conf/nginx.conf /etc/nginx #检查是否有误 docker exec -it pro_nginx nginx -t #重新启动容器服务 docker exec -it pro_nginx nginx -s reload docker restart pro_nginx echo -e "\e[1;32m rabbitmq:management容器启动结束!\e[0m" } mkdir $ROOT_DIR #启动mysql run_mysql #启动redis run_redis #启动rabbitmq run_rabbitmq #启动nginx run_nginx echo -e "\e[1;33m 本脚本默认容器已启动完成!\e[0m" docker ps exit 1脚本运行完成的截图如下: 上面有些容器即使启动了,但是在提供服务的时候可能还有点问题,比如说数据库的密码更改等,这时候进入容器bash,连接mysql: # 修改数据库 ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'root'; # 重新修改密码 alter user 'root'@'%' identified by '123456'; #刷新数据库 mysql> flush privileges;不同的容器运行遇到的情况也不一样,所以还是按照上述其它问题的解决方式来解决即可。 2.3.启动前后端服务 2.3.1.服务器防火墙相关设置我们在前面的操作中,开启的服务端口只是在服务器内开放,但是如果想让我们通过本地去访问服务器ip获取服务,还需要在云服务器控制台那里把对应端口的防火墙打开,不然访问不到,还有一件事,服务器的防火墙与控制台的防火墙不是一回事,如果控制台那里的端口开放了,但是仍然访问不到,那么就极其可能是服务器主机防火墙没有关闭!执行命令:
重启失效,仅服务器运行时有效:service iptables stop
永久关闭服务器防火墙,开放所有端口:systemctl disable firewalld 2.3.2.打包运行前后端项目在准备工作阶段,我们将我们的项目放在了pro容器里,那里有我们前后端项目打包运行的环境,我们有两种选择了:
第一种方式: 根据luoqianyi/project镜像运行一个专门的后端项目容器和一个专门的前端项目容器,这样似乎更符合前后端分离的思想,大型项目优选这种方案。 但是我这里推荐
第二种方式: 前后端在一个容器里,一起部署,前端打包成静态文件后,我们通过nginx进行代理这些静态资源可以访问到,而后端只需要打包后运行打的包即可,然后nginx代理请求访问docker网桥里的服务即可,前端访问请求也就不存在跨域问题了,axios代理可以由nginx替代。普通项目优选这种方案。 以springboot项目为例运行后端项目: ######################如果是maven进行管理的,进入后端项目文件夹下,可直接运行启动,下面命令会自动导入依赖,不必打成jar包######################### docker exec -it pro bash cd /project/[后端项目目录] mvn spring-boot:run #启动后如果出现started字样,就代表启动成功了,这时候我们直接不中断式退出容器,按下 ctrl+p+q 即可 #重新进入容器查看进程 docker exec -it pro ps -ef #如果出现两个与java相关的进程,那就代表后端项目确实启动了,如果想停止,直接执行 docker exec -it pro kill -9 [带java的进程号] #重新启动服务的话按照上面几个步骤来即可。 ###############如果不是maven进行管理的或者有打成jar包的需求,那么请先在本地借助某些工具或通过命令打包成一个可运行的jar包########################### docker exec -it pro bash #执行这条命令可以运行打包好的jar包,并生成start.log日志文件 nohup java -server -XX:-DisableExplicitGC -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -jar [jar包所在的位置] > start.log 2>&1 & #如果结果返回一个进程号,那么代表启动成功了 #如果想停止,直接执行 kill -9 [进程号]以vue项目为例运行前端项目: #准备工作中我们已经对前端项目进行打包了,我们只需要找到知道dist目录下的index.html在哪即可,在宿主机/conf.d/default.conf配置文件中进行配置即可 2.3.3.服务器端同步代码的时候自动打包运行的脚本每次想同步部署到服务器上,难道我还要重新打包再运行吗?不用怕,我这里编写了一个自动化打包运行的脚本(本来想包含git拉取代码的操作的,但是问题可能会有点多,比如说版本回退不成功等问题),可以参考使用: #!/bin/bash #OR #!/bin/sh #Scriptname:package_run.sh #Author:luoqianyi #本脚本在git操作完成后执行,建议放在/datavolumes/project下 echo -e "\e[1;33m 开始自动打包运行...\e[0m" #前台项目路径,没有的话就不用动 FRONT_PRO="/project/luoqianyi_blog/blog-vue" #后台项目路径,没有的话就不用动 ADMIN_PRO="/project/luoqianyi_blog/blog-admin" #后端项目路径,没有的话就不用动 SERVER_PRO="/project/luoqianyi_blog/blog-java" #前端打包 pack_front(){ if [ $FRONT_PRO!="" ] then cd $FRONT_PRO yarn install yarn run build echo -e "\e[1;32m front packaged! \e[0m" fi } pack_admin(){ if [ $ADMIN_PRO!="" ] then cd $ADMIN_PRO yarn install yarn run build echo -e "\e[1;32m admin packaged! \e[0m" fi } #后端打包,maven环境下 pack_server(){ if [ $SERVER_PRO!="" ] then cd $SERVER_PRO mvn clean package echo -e "\e[1;32m server packaged! \e[0m" fi } #后端运行 run_server(){ if [ $SERVER_PRO!="" ] then cd $SERVER_PRO ps -ef | grep java | grep -v grep | awk '{print $2}' | xargs kill -9 nohup mvn spring-boot:run > start.log 2>&1 & fi } pack_front pack_admin pack_server run_server echo -e "\e[1;33m Script Finished!!\e[0m" exit 1进入pro容器里下的/project/,执行bash ./package_run.sh即可。 3.nginx反向代理服务我们在前面启动容器的时候,准备工作都已经做好了,至于为什么启动nginx的时候需要建立软链接,详情查看这篇博客: https://blog.csdn.net/qq_42937522/article/details/108179441。 我们只需要在宿主机修改default.conf文件即可,这里根据本文部署方案提供一种配置: #上游服务地址,查看docker网桥里项目运行的容器的ip,指定端口,服务名为myserver upstream myserver{ server 172.17.0.4:8000; } server{ listen 80; #域名,根据实际情况修改[]的内容 #server_name xxxx; client_max_body_size 20m; access_log /var/log/nginx/host.access.log main; #前台,根据实际情况修改[]的内容 location /portal { alias /var/www/html/[项目前台目录]/dist; try_files $uri $uri/ /index.html?s=$uri&$args; index index.html index.htm index.php; } #后台,根据实际情况修改[]的内容 location / { root /var/www/html/[项目后台目录]/dist; try_files $uri $uri/ /index.html?s=$uri&$args; index index.html index.htm index.php; } #后端 location /api { proxy_pass ; index index.html index.htm; } location /swagger-ui.html { proxy_pass ; index index.html index.htm; } location /webjars { proxy_pass ; index index.html index.htm; } location /swagger-resources { proxy_pass ; index index.html index.htm; } location /v2 { proxy_pass ; index index.html index.htm; } #后端静态资源获取 location /[资源所在的目录名]{ alias /var/www/html/[项目后端目录]/src/main/resources/static/[资源所在的目录名]; } } 三、本文总结经过一番折腾,想必终于可以理顺docker整个构建的过程了吧,其实还蛮简单,但最重要的是脚本了,这可是一劳永逸的事情。希望大家不断完善哦! 四、学习参考 1.Docker学习 2.docker 构建git+maven+jdk8的centos7环境,实现轻量级的springboot项目的自动化部署 3.docker安装启动redis、nginx、mysql8详解 4.Shell 教程 | 菜鸟教程 (runoob.com) 五、资源下载觉得好用欢迎一键三连哦!~ (责任编辑:) |