Docker前后端项目摆设(完备篇)

南七星之家  金牌会员 | 2024-6-23 19:48:22 | 来自手机 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 665|帖子 665|积分 1997

本文详细讲解了怎样利用 Docker 构建镜像并摆设前后端项目,包罗怎样编写 Dockerfile 和启动容器的方式。在实践过程中,作者发现了一些常见问题,并提供相识决方案,例如怎样解决无法毗连数据库的问题、怎样配置 nginx 代理等。本文将对想要深入相识 Docker 镜像摆设前后端项目的读者提供帮助。
目次
安装docker
开始前
摆设mysql8
生成挂载目次和配置
创建容器
 一些问题
摆设后端项目
构建镜像
启动容器
一些问题
Nginx摆设前端项目
构建nginx镜像
启动容器
摆设多个网站(扩展)
善后工作

Docker-Compose实现


安装docker

此时你有一台服务器,首先安排上docker
  1. # 检查是否安装
  2. yum list installed | grep docker
  3. # 在线安装docker必备依赖包
  4. yum install -y yum-utils device-mapper-persistent-data lvm2
  5. # 添加阿里云有关 Docker 的软件源(即Docker的存储库)
  6. yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
  7. # 安装docker
  8. yum install -y docker-ce docker-ce-cli containerd.io
  9. # docker默认配置文件中设置阿里云的镜像地址,更多配置参考 https://www.cnblogs.com/yakniu/p/16329611.html
  10. vi /etc/docker/daemon.json
  11. {"registry-mirrors": ["https://gg3gwnry.mirror.aliyuncs.com"]}
复制代码
开始前

为本项目创建一个假造网络network,用于多个容器间通讯如毗连数据库等
docker network create --driver=bridge --gateway=192.168.0.0 --subnet=192.168.0.0/16  mynet-1
创建工作目次
mkdir /mydata
cd /mydata

摆设mysql8

生成挂载目次和配置

mkdir  mysql mysql/conf mysql/data mysql/mysql-files
vi mysql/conf/cus-docker.cnf
  1. [mysqld]
  2. wait_timeout=31536000
  3. interactive_timeout=31536000
  4. # 数据库忽略大小写
  5. lower_case_table_names = 1
  6. #免密登录,如果忘记密码启用这个配置
  7. #skip-grant-tables
  8. # mysql8 换了密码加密方式,要让数据库使用旧的密码加密方式 , 身份插件mysql_native_password 本地密码
  9. authentication_policy=mysql_native_password
  10. #密码失效时间-永不过期
  11. default_password_lifetime=0
  12. # 127.0.0.1只能本地访问,0.0.0.0接收任何来源ip的连接访问
  13. bind-address = 0.0.0.0
  14. # 最大连接数
  15. max_connections = 2000
  16. # 设置数据库时区为正8区
  17. default-time_zone = '+8:00'
复制代码
启动容器

docker pull mysql:8.0.31
挂载的卷


  • /etc/mysql/conf.d 
mysql的配置文件my.cnf位于/etc/my.cnf,my.cnf会优先导入/etc/mysql/conf.d目次下的所有扩展名为cnf的配置文件


  • /var/lib/mysql/ 
mysql的日记、数据存放目次,如导入一个数据库surveyking.sql就会增加一个surveyking的目次
docker run --name cus-mysql --network mynet-1 --ip 192.168.0.2 --restart=always --privileged=true -v /mydata/mysql/conf:/etc/mysql/conf.d -v /mydata/mysql/data:/var/lib/mysql/ -v /mydata/mysql/mysql-files:/var/lib/mysql-files/ -p 3306:3306  -e  MYSQL_ROOT_PASSWORD=123456 -e LANG=zh_CN.utf8 -e LANGUAGE=zh_CN.utf8  -d mysql:8.0.31
mysql容器初始化
宿主机拷贝后端项目数据库到mysql容器中
新增后端项目数据库所需的用户和暗码,并赋予该数据库所有的权限
  1. docker cp /mydata/db/surveyking.sql cus-mysql:/tmp;
  2. docker exec -it cus-mysql mysql -u root -p
  3. create database surveyking;
  4. use surveyking;
  5. source /tmp/surveyking.sql;
  6. flush privileges;
  7. alter user 'hao'@'%' identified by 'lihao@123456' password expire never;
  8. alter user'hao'@'%' identified with mysql_native_password by 'lihao@123456';
  9. grant all privileges on surveyking.* to 'hao'@'%';
  10. flush privileges;
复制代码
 一些问题

       mysql8容器启动后如果一直登录不上(暗码错误),Access denied for user 'root'@'localhost' (use Password Yes) 可以开启免密登录,初始化完成再关闭免密登录
  因为mysql8更改了登录方式利用暗码加密(明文和密文打八辈子也不等好吧)
  
      如果容器内可以正常进入mysql,其它容器或者我们的navicat远程工具无法连上mysql,需要查抄登录的用户是否是答应的主机地址,select user,host from mysql.user;
  如果host是%即答应任何主机地址,那么不可远程毗连很有可能是配置文件bind-address设置了localhost或者127.0.0.1(我遇到的问题),改为0.0.0.0即可
  
      将主机目次下的文件夹挂载到容器的文件夹后,进入到docker容器内对应的挂载目次中,运行下令ls后提示
ls: cannot open directory .: Permission denied
  原因是CentOS7中的安全模块selinux把权限禁掉了,解决方法容器启动时--privileged=true
  
摆设后端项目

拷贝后端jar包到工作目次 /mydata
构建镜像

/mydata/surveyking-dockerfile文件如下
  1. FROM openjdk:8  
  2. RUN mkdir -p /home/app
  3. # 设置工作目录
  4. WORKDIR /mydata
  5. # apt-get update && apt-get install -y iputils-ping;
  6. COPY surveyking-v1.5.1.jar /home/app/surveyking-v1.5.1.jar
  7. EXPOSE 8080
  8. # 设置容器启动时运行的命令
  9. CMD ["java", "-jar","/home/app/surveyking-v1.5.1.jar"]
复制代码
docker build -f surveyking-dockerfile -t surveyking-image:1.5.1 .
启动容器

docker run -p 8080:8080 --name surveyking-server --network mynet-1 --ip 192.168.0.3 -d surveyking-image:1.5.1

一些问题

   docker ps -a 发现如果启动容器后自动退出,即项目运行出现异常
  docker logs surveyking-server 查抄启动日记
  
  按网上的资料说同一个自定义network下的多个容器间可以 ping 容器名,但是一直测试报错ping的容器名是未知的地址,原因未遂,最后还是决定利用固定ip即--ip的参数在容器run的时候指定
  后端项目容器毗连数据库的容器的url:
  jdbc:mysql://192.168.0.2:3306/surveyking?characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true&useUnicode=true
  
   项目启动没有问题,但是一旦访问到数据库响应异常docker logs surveyking-server检察后端项目日记,访问数据库报错如下
com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure
The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
  网上各种答案都说是url没有useSSL=false,各种答案都试过都没得,困扰我灰常的久。尝试将这个jar包运行在主机电脑毗连远程服务器容器的数据库,居然数据库访问就正常了。
  解决尝试:navicat试连,用户要有权限,最重要url上的mysql地址在jar包运行的容器中能ping通 (利用自定义的network,能ping通后访问就解决了)
  ⭐⭐注意,mysql在初始化完后一定要关闭免密登录,否则也会导致上面的问题
  
Nginx摆设前端项目

创建挂载卷目次(/mydata工作目次)
1. mkdir nginx nginx/conf /nginx/html /nginx/logs
2. 拷贝前端打包项目到/nginx/html下
3. vi nginx/conf/nginx.conf
  1. #定义Nginx运行的用户和用户组
  2. #user  nobody;
  3. #开启的线程数(默认为1),一般跟逻辑CPU核数一致
  4. worker_processes  1;
  5. #制定日志路径,级别。这个设置可以放入全局块,http块,server块,级别以此为:debug | info | notice | warn | error | crit | alert | emerg
  6. #error_log  logs/error.log;
  7. #error_log  logs/error.log  notice;
  8. #error_log  logs/error.log  info;
  9. #指定nginx进程运行文件存放地址
  10. #pid        logs/nginx.pid;
  11. events {
  12.     accept_mutex on;   #设置网路连接序列化,防止惊群现象发生,默认为on
  13.     multi_accept on;  #设置一个进程是否同时接受多个网络连接,默认为off
  14.     use epoll;      #事件驱动模型,select|poll|kqueue|epoll|resig|/dev/poll|eventport
  15.     #单个进程最大连接数(最大连接数=连接数*进程数)
  16.     #根据硬件调整,和前面工作进程配合起来用,尽量大,但是别把cpu跑到100%就行。每个进程允许的最多连接数,理论上每台nginx服务器的最大连接数为。
  17.     worker_connections  1024;
  18. }
  19. http {
  20.     #文件扩展名与文件类型映射表
  21.     include       mime.types;
  22.         #默认文件类型
  23.     default_type  application/octet-stream;
  24.    
  25.     #access_log off; #取消服务日志
  26.     #引用日志main
  27.     #access_log  logs/access.log  main;
  28.        
  29.     #下面代码为日志格式的设定,main为日志格式的名称,可自行设置,后面引用
  30.     #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
  31.     #                  '$status $body_bytes_sent "$http_referer" '
  32.     #                  '"$http_user_agent" "$http_x_forwarded_for"';
  33.    
  34.     #开启高效文件传输模式,sendfile指令指定nginx是否调用sendfile函数来输出文件,对于普通应用设为 on,如果用来进行下载等应用磁盘IO重负载应用,可设置为off,以平衡磁盘与网络I/O处理速度,降低系统的负载。注意:如果图片显示不正常把这个改成off。
  35.     #sendfile指令指定 nginx 是否调用sendfile 函数(zero copy 方式)来输出文件,对于普通应用,必须设为on。如果用来进行下载等应用磁盘IO重负载应用,可设置为off,以平衡磁盘与网络IO处理速度,降低系统uptime。
  36.     sendfile        on;
  37.     # 当使用sendfile 函数,tcp_nopush 才起作用,是tcp协议栈中的知识点
  38.     # 当tcp_nopush = on 时,会调用tcp_cork 方法,是默认的,就是收到的数据报不会立即发送出去,而是等到数据报最大时,一次性传输出去,有利于解决网络堵塞。
  39.     #tcp_nopush     on;
  40.     # 客户端连接超时时间
  41.     # = 0 : 表示禁用长连接。
  42.     # = x :表示长连接timeout
  43.     #keepalive_timeout  0;
  44.     keepalive_timeout  65;
  45.     #HttpGZip模块配置
  46.     #开启gzip压缩
  47.     #gzip  on;
  48.     #设置允许压缩的页面最小字节数
  49.     #gzip_min_length 1k;
  50.     #申请4个单位为16K的内存作为压缩结果流缓存
  51.     #gzip_buffers 4 16k;
  52.     #设置识别http协议的版本,默认为1.1
  53.     #gzip_http_version 1.1;
  54.     #指定gzip压缩比,1-9数字越小,压缩比越小,速度越快
  55.     #gzip_comp_level 2;
  56.     #指定压缩的类型
  57.     #gzip_types text/plain application/x-javascript text/css application/xml;
  58.     #让前端的缓存服务器进过gzip压缩的页面
  59.     #gzip_vary on;
  60.        
  61.     server {
  62.         listen       80;
  63.         server_name  localhost;
  64.         #charset koi8-r;
  65.         #access_log  logs/host.access.log  main;
  66.         location / {
  67.                 # 设置虚拟主机的网站根目录
  68.             root   html/website-surveyking;
  69.                 # history 模式下需要加上这一行,防止刷新页面时404
  70.                 try_files $uri $uri/ /index.html;                        
  71.             #设置虚拟主机默认访问的网页
  72.             index  index.html index.htm;
  73.         }
  74.         #对 / 启用反向代理
  75.         #location /sk-api {
  76.             #proxy_pass  http://127.0.0.1:8080;
  77.             #以下是一些反向代理的配置可删除
  78.             #proxy_redirect off;
  79.             #rewrite "^/sk-api/(.*)$" /$1 break ; # 最终url中去掉/api前缀
  80.             #后端的Web服务器可以通过X-Forwarded-For获取用户真实IP
  81.             #proxy_set_header Host $host;
  82.             #proxy_set_header X-Real-IP $remote_addr;
  83.             #proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  84.             #client_max_body_size       10m;   #允许客户端请求的最大单文件字节数
  85.             #client_body_buffer_size    128k;  #缓冲区代理缓冲用户端请求的最大字节数
  86.             #proxy_connect_timeout      300;   #nginx跟后端服务器连接超时时间(代理连接超时)
  87.             #proxy_send_timeout         300;   #后端服务器数据回传时间(代理发送超时)
  88.             #proxy_read_timeout         300;   #连接成功后,后端服务器响应时间(代理接收超时)
  89.             #proxy_buffer_size          4k;    #设置代理服务器(nginx)保存用户头信息的缓冲区大小
  90.             #proxy_buffers              4 32k; #proxy_buffers缓冲区,网页平均在32k以下的话,这样设置
  91.             #proxy_busy_buffers_size    64k;   #高负荷下缓冲大小(proxy_buffers*2)
  92.             #proxy_temp_file_write_size 64k;   #设定缓存文件夹大小,大于这个值,将从upstream服务器传
  93.         #}
  94.         #error_page  404              /404.html;
  95.         # redirect server error pages to the static page /50x.html
  96.         #
  97.         error_page   500 502 503 504  /50x.html;
  98.         location = /50x.html {
  99.             root   html;
  100.         }
  101.         # proxy the PHP scripts to Apache listening on 127.0.0.1:80
  102.         #
  103.         #location ~ \.php$ {
  104.         #    proxy_pass   http://127.0.0.1;
  105.         #}
  106.         # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
  107.         #
  108.         #location ~ \.php$ {
  109.         #    root           html;
  110.         #    fastcgi_pass   127.0.0.1:9000;
  111.         #    fastcgi_index  index.php;
  112.         #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
  113.         #    include        fastcgi_params;
  114.         #}
  115.         # deny access to .htaccess files, if Apache's document root
  116.         # concurs with nginx's one
  117.         #
  118.         #location ~ /\.ht {
  119.         #    deny  all;
  120.         #}
  121.     }
  122.     # another virtual host using mix of IP-, name-, and port-based configuration
  123.     #
  124.     #server {
  125.     #    listen       8000;
  126.     #    listen       somename:8080;
  127.     #    server_name  somename  alias  another.alias;
  128.     #    location / {
  129.     #        root   html;
  130.     #        index  index.html index.htm;
  131.     #    }
  132.     #}
  133.     # HTTPS server
  134.     #
  135.     #server {
  136.     #    listen       443 ssl;
  137.     #    server_name  localhost;
  138.     #    ssl_certificate      cert.pem;
  139.     #    ssl_certificate_key  cert.key;
  140.     #    ssl_session_cache    shared:SSL:1m;
  141.     #    ssl_session_timeout  5m;
  142.     #    ssl_ciphers  HIGH:!aNULL:!MD5;
  143.     #    ssl_prefer_server_ciphers  on;
  144.     #    location / {
  145.     #        root   html;
  146.     #        index  index.html index.htm;
  147.     #    }
  148.     #}
  149. }
复制代码
构建nginx镜像

/mydata/nginx-dockerfile文件如下
  1. FROM centos:7
  2. #给基础镜像centos安装必备的环境
  3. # 加上“rpm --rebuilddb &&”是为了防止数据库损坏而影响yum安装。
  4. # 注意,比较保险的做法是有多少个yum命令,就加多少个“rpm --rebuilddb &&”在yum前面。
  5. # 另外yum install一定要安装的是pcre,zlib,net-tools,make,gcc,wget,tar及其相关内容
  6. RUN rpm --rebuilddb && yum install -y autoconf automake make wget proc-devel net-tools zlib zlib-devel make gcc  g++ openssl-devel pcre pcre-devel tar
  7. # 在线获取nginx压缩包(也可以在本地系统(centos)里先下载压缩包,再ADD命令将包加入到基础镜像/usr/src目录中)
  8. RUN wget http://nginx.org/download/nginx-1.17.1.tar.gz
  9. # 解压到当前目录
  10. RUN tar -zxvf nginx-1.17.1.tar.gz
  11. # 设置环境
  12. WORKDIR nginx-1.17.1
  13. # 配置nginx
  14. RUN ./configure --prefix=/usr/local/nginx && make && make install
  15. # RUN rm -rf /usr/src/nginx
  16. ENV TimeZone=Asia/Shanghai
  17. # 拷贝前端打包资源到nginx容器中
  18. # COPY /mydata/website-surveyking /usr/local/nginx/html  
  19. #开启 80 和 443 端口
  20. EXPOSE 80      
  21. #https
  22. EXPOSE 443  
  23. #不能直接nginx,可能环境变量没有配置
  24. CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off;"]
复制代码
docker build -f nginx-dockerfile -t cus-nginx-image:1.7 .
启动容器

因为上面镜像的dockerfile文件中指定了编译安装nginx的路径为/usr/local/nginx
挂载的卷


  • /usr/local/nginx/conf/nginx.conf:挂载nginx配置文件到宿主机中
  • /usr/local/nginx/html:nginx的网站根目次
  • /usr/local/nginx/logs:nginx的运行、错误等日记
docker run -p 81:80 --name cus-nginx --network mynet-1 --ip 192.168.0.4 --restart=always --privileged=true -v /mydata/nginx/conf/nginx.conf:/usr/local/nginx/conf/nginx.conf -v /mydata/nginx/logs:/usr/local/nginx/logs -v /mydata/nginx/html:/usr/local/nginx/html -d cus-nginx-image:1.7
到此项目摆设完毕

摆设多个网站(扩展)

   nginx的配置基础
  
  root和alias都是用于指定哀求的静态文件的根目次
root:当Nginx接收到哀求时,会将location后面的路径与root拼接起来作为文件的实际路径。这意味着,实际文件路径为root路径/location后面的路径。
  例如 location /surveyking { root: html/p1; }
  哀求: /surveyking/index.html    实际:/surveyking/p1/surveyking/index.html 
alias:alias在构建文件路径时会直接利用location后面的路径匹配哀求之后哀求的剩余路径。这意味着,实际文件路径为alias路径/哀求路径 - location后面的路径。
  例如 location /surveyking { alias: html/p1; }
  哀求: /surveyking/project/index.html    实际:/surveyking/p1/project/index.html
  
  反向代理
  nginx反向代理可以实现每个api前缀的代理映射到不同的服务器端口举行处理
  反向代理主要是解决后端服务器负载均衡和保证安全性,而哀求转发则是实现服务器哀求处理的调度和功能灵活性
location /sk-api {  proxy_pass  http://192.168.0.3:8080; }
  需求:比如我想一个nginx摆设多个网站项目,而不是根路径/直接映射到root指向的项目路径,而导致其它网站的location地址没有意义了
首先nginx.conf需要修改
location /surveyking {
     root   html/website-surveyking;
     try_files $uri $uri/ /surveyking/index.html;             
     index  index.html index.htm;
}
修改后就可以了吗,会报错
已拦截加载自“http://xx.xx.xx.x:81/assets/index.6e0363b3.js”的模块,它利用了不答应的 MIME 范例(“text/html”)。
来源为“http://xx.xx.xx.x:81/assets/index.6e0363b3.js”的模块加载失败。
因为vue工程打包后目次结构为
- assets  
    -xxx.js
- index.html
index.html对所有资源assets内的访问路径为http://xxx.xxx.xx.x/assets/xxx.js
需要给所有资源的访问路径拼接surveyking前缀,让nginx能够匹配location
vue项目中利用vite打包的话,增加配置即可
vite.conf.js
  1. export default defineConfig(({ command, mode }) => {
  2.    const env = loadEnv(mode, process.cwd(), '')
  3.    let base;
  4.    if (command.indexOf('build')!==1) {
  5.       base = '/surveyking'
  6.    } else {
  7.       base = '/'
  8.    }
  9.    return{
  10.     base,
  11.            {option..}
  12.    }
  13. }
复制代码
到这问题还没结束,index.html页面可以正常加载css、js等静态资源渲染表现了
但是如果vue中点击就了路由跳转,利用了history的地址栏是不是surveyking前缀又没了,如果此时刷新,nginx将该刷新哀求分析为/路由地址而不是使try_files $uri $uri/ /surveyking/index.html生效的/surveyking/路由地址
最后,将路由前缀也添加上即可解决,vue3 + vue-router解决方案
const router = createRouter({
    history: createWebHistory("/surveyking"),
    routes: constantRoutes
});

善后工作

如果是1核1G三个容器跑起来,慢慢地越来越卡,一直到步伐瓦解,检察服务器的仪表盘,发现磁盘读流量异常的高,总是忽然飙升,而cpu利用率则并没有太大的动静。
这里应该考虑服务器为容器调整合适的配置参数,如mysql中的InnoDB缓冲池巨细、InnoDB日记文件巨细、查询缓存巨细等参,后端项目运行日记存储策略等
通过不断的探索改造,可算得出以下的较为合适的配置
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

南七星之家

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表