00.背景
最近学校让一个小组做一个web项目最后部署到linux服务器上,项目本身并不难就是简单的增删改查,但是我想借着这个机会写一个docker部署的模板,方便自己以后用,也希望可以帮助到大家。
01.docker简介
docker可以快捷 轻量 高效 简单的部署服务,docker有两个重要概念 镜像(image)与容器(container) 镜像可以理解为类 容器可以理解为对象,假如我们需要部署一个web项目 这个项目由 vue springboot mysql构成,我们就可以先创造所需的镜像,再创造对应的容器 容器之间进行交互 最终实现这个服务。容器与容器之间是相互隔离的 只有身处同一个网络才能交互,一个镜像产生可以由很多容器。
02.环境整体目录
蓝色节点是目录 红色节点是压缩包 其余是文件。
03.所需材料
这是一个简单的web项目,总共有四大部分,前端vue 后端springboot 数据库mysql 以及nginx服务器。
04.创造镜像
拉取镜像
docker pull nginx
docker pull openjdk:8
docker pull mysql:5.7
这里我们拉取了三个镜像
nginx:用于反向代理 可以简单的理解为 我们前端的请求都会通过nginx进行转发
openjdk:8:jdk8 Java运行环境 我们的springboot项目需要java支持
mysql:5.7 :mysql数据库
除了这三个镜像外我们还需要springboot后端的镜像
05.创造后端镜像
首先我们要用maven打包
我们把打包出来的app.jar放到app目录下
编写dockerfile文件
FROM openjdk:8
EXPOSE 8080
ADD ./app.jar /app.jar
RUN bash -c 'touch /app.jar'
ENTRYPOINT ["java","-jar","/app.jar","--spring.profiles.active=prod"]
dockerfile文件的作用是创造一个镜像,这个镜像创造过程有许多层,例如第一层是FROM openjdk:8 作用就是在openjdk:8环境的基础上搭建镜像,EXPOSE 8080则是这个镜像创造的容器向外暴露的端口
用dockerfile构建后端镜像app
在app目录下构建后端镜像
docker build -f ./dockerfile -t app .
查看现有镜像
docker images
可以看到我们现在有四个镜像,分别是app后端镜像、nginx服务器镜像、mysql镜像、jdk8镜像
06.创造mysql容器
我们首先创造宿主机(本机linux服务器)目录
mkdir -p /mnt/docker/mysql
cd /mnt/docker/mysql
创造mysql容器
docker run -id \
-p 3307:3306 \
--name=mysql \
-v /mnt/docker/mysql/data:/var/lib/mysql \ # 目录挂载
-e MYSQL_ROOT_PASSWORD=root \
mysql:5.7
参数解释
-p 宿主机端口:容器端口,我们后端调用数据库需要调用3307端口 Navicat连接数据库也需要连接3307端口
-v 宿主机mysql目录:容器mysql目录,目录挂载的目的是 把容器与宿主机的目录数据同步,防止因为删除容器而导致数据库中数据丢失
查看容器是否启动
docker ps
可以看到我们启动成功了
07.docker-compose服务编排
服务编排的目的是利用Docker Compose将springboot和nginx容器分批启动
安装Docker Compose
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
# 查看版本信息
docker-compose -version
编写docker-compose.yml文件
进入docker-compose目录 编写docker-compose.yml文件
version: '3'
services:
nginx:
image: nginx
container_name: nginx
ports: #ports:绑定容器的端口到主机的端口,前者为主机端口;expose:将当前容器的端口暴露给link到本容器的容器。
- 80:80
depends_on:
- app
volumes: #将本地目录挂载到容器的目录下,前者为linux的目录,后者为容器目录。(访问容器的目录即可访问到被挂载目录下的所有文件)
- /mnt/docker/docker-compose/nginx/:/etc/nginx/
network_mode: "bridge"
app:
image: app
container_name: app
ports:
- 8080:8080
network_mode: "bridge"
参数解释
version docker-compose版本
services 容器服务
image 容器属于那镜像
container_name 容器名
ports 宿主机端口:容器端口
depends_on 此容器启动所依赖的容器
volumes 挂载到宿主机的哪个目录
network_mode 容器网络,必须处于同一网络下容器才能互相访问
08.nginx相关配置
nginx的作用是反向代理和负载均衡
反向代理:反向代理简单来说就是nginx服务器监听网站请求,并且把这些请求转发到其它服务器处理。反向代理与正向代理相反,正向代理是服务器主动请求,比如我们常用的游戏加速器,比如这个游戏只能在美国玩,此时我们就需要一个美国服务器,此时我们自己的服务器并不会直接连接游戏而且把请求发给美国服务器再由美国服务器请求这个游戏,这个过程就是正向代理。
负载均衡:当我们网站的请求被nginx服务器监听到后 nginx会根据规则把这些请求发送给指定的服务器,比如我们有两个后端服务 一个是java一个是go,我们的其中一部分请求nginx转发给java服务另一部分转发给go服务,通过规则的合理分配以达到最优化资源使用、最大化吞吐率、最小化响应时间、同时避免过载的目的。
nginx相关配置文件编写
在nginx目录下编写nginx.conf
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}
我们可以看到这里面引入了两个文件 /etc/nginx/mime.types;与 /etc/nginx/conf.d/* .conf;
mime.types文件
types {
text/html html htm shtml;
text/css css;
text/xml xml;
image/gif gif;
image/jpeg jpeg jpg;
application/javascript js;
application/atom+xml atom;
application/rss+xml rss;
text/mathml mml;
text/plain txt;
text/vnd.sun.j2me.app-descriptor jad;
text/vnd.wap.wml wml;
text/x-component htc;
image/png png;
image/svg+xml svg svgz;
image/tiff tif tiff;
image/vnd.wap.wbmp wbmp;
image/webp webp;
image/x-icon ico;
image/x-jng jng;
image/x-ms-bmp bmp;
font/woff woff;
font/woff2 woff2;
application/java-archive jar war ear;
application/json json;
application/mac-binhex40 hqx;
application/msword doc;
application/pdf pdf;
application/postscript ps eps ai;
application/rtf rtf;
application/vnd.apple.mpegurl m3u8;
application/vnd.google-earth.kml+xml kml;
application/vnd.google-earth.kmz kmz;
application/vnd.ms-excel xls;
application/vnd.ms-fontobject eot;
application/vnd.ms-powerpoint ppt;
application/vnd.oasis.opendocument.graphics odg;
application/vnd.oasis.opendocument.presentation odp;
application/vnd.oasis.opendocument.spreadsheet ods;
application/vnd.oasis.opendocument.text odt;
application/vnd.openxmlformats-officedocument.presentationml.presentation
pptx;
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
xlsx;
application/vnd.openxmlformats-officedocument.wordprocessingml.document
docx;
application/vnd.wap.wmlc wmlc;
application/x-7z-compressed 7z;
application/x-cocoa cco;
application/x-java-archive-diff jardiff;
application/x-java-jnlp-file jnlp;
application/x-makeself run;
application/x-perl pl pm;
application/x-pilot prc pdb;
application/x-rar-compressed rar;
application/x-redhat-package-manager rpm;
application/x-sea sea;
application/x-shockwave-flash swf;
application/x-stuffit sit;
application/x-tcl tcl tk;
application/x-x509-ca-cert der pem crt;
application/x-xpinstall xpi;
application/xhtml+xml xhtml;
application/xspf+xml xspf;
application/zip zip;
application/octet-stream bin exe dll;
application/octet-stream deb;
application/octet-stream dmg;
application/octet-stream iso img;
application/octet-stream msi msp msm;
audio/midi mid midi kar;
audio/mpeg mp3;
audio/ogg ogg;
audio/x-m4a m4a;
audio/x-realaudio ra;
video/3gpp 3gpp 3gp;
video/mp2t ts;
video/mp4 mp4;
video/mpeg mpeg mpg;
video/quicktime mov;
video/webm webm;
video/x-flv flv;
video/x-m4v m4v;
video/x-mng mng;
video/x-ms-asf asx asf;
video/x-ms-wmv wmv;
video/x-msvideo avi;
}
这个文件的作用是定义用户访问的文件类型
/etc/nginx/conf.d/ .conf;*
这个则是引入了conf.d下的所有文件
这里主要指的是app.conf
gzip_min_length 1k;
gzip_buffers 4 16k;
gzip_comp_level 2;
gzip_vary off;
upstream appstream{
server 私网ip:8080;
}
server {
listen 80;
server_name 公网ip;
error_page 500 502 503 504 /50x.html;
error_page 404 /404.html;
location = /50x.html {
root html;
}
location = /404.html{
root html;
}
location /api/ {
proxy_pass http://appstream/;
}
location / {
root /etc/nginx/html;
index index.html;
}
}
参数解释
upstream appstream 代表上游服务,也就是nginx把请求转发给它,这里指的是本地的8080端口也就是后端服务
server nginx监听的服务
listen 监听的端口 这里是80
server_name 监听的ip
error_page 出现错误指定请求哪个文件
location = /404.html
{root html;} 当请求产生404报错时,nginx展示html目录下404.html
location /api/
{ proxy_pass http://appstream/;}
所有的80端口的请求带/api的都由上游服务处理 这里指的是后端处理,比如我们现在请求
http://公网ip/api/sub/findAccounts 通过 nginx转发就变为了
http://私网ip/sub/findAccounts
location / {
root /etc/nginx/html;
index index.html;
}
同理所以/(根目录)的请求都转发到/etc/nginx/html/index.html
09.前端文件
你们可能发现一个问题前端为什么没有镜像,因为前端只是一堆静态文件,并不需要处理请求,只是用来发送请求接收响应,所以我们只需要把前端放到特点位置,然后我们的nginx根据服务规则 调用需要的前端文件 就像上述app.conf中的location /,http://47.95.49.40/(根请求)就转发到了/etc/nginx/html/index.html 这个指定的前端文件,从而展示前端。
打包前端
我们通过 npm run build 命令打包vue项目 打包完成后会有一个文件一个目录
我们把它们放到html目录下,同时我们可以发现html目录下处理这两个文件 还有一个404.html与50x.html 这两个是我专门写的如果出现错误 指定展示的文件
10 编排启动
我们进入docker-compose 目录下
docker-compose up #直接启动
docker-compose up -d #代表后台启动
docker-compose down #停止并删除容器
docker-compose start #启动已有容器
docker-compose stop #停止运行的容器
我们执行docker-compose up -d 启动 nginx容器与app容器
查看此时的容器
docker ps
我们可以看到我们现在有三个容器 分别是 nginx、app、mysql。
此时我们这个网站就部署成功了
11 整个项目的运行逻辑
首先我们访问 公网ip:80 也就是直接访问公网ip 例如http://47.95.49.40/,此时我们先访问了/(根目录),通过nginx的转发我们知道 展示了/etc/nginx/html/index.html 也就是上述的登录界面,之后我们输入账号密码,发送请求 http://47.95.49.40/api/user/login 我们发现请求是带着/api的 此时我们的nginx转发到我们的后端进行处理 http://私网ipi/user/login 最终完成请求、转发、响应,实现了一个基本的网站。
12 总结
总的来说,我们在用docker部署时要先确定目录结构,之后便是 理清自己的镜像需要哪些依赖从而编写dockerfile文件 ,理清自己需要的容器之间的关系 编写docker-compose.yml文件,理清前后端请求的逻辑编写nginx相关配置。注意要把所需端口放开。
最后 祝各位小伙伴都能部署顺利。