通过 Docker 实现前后端的容器化部署
写在前面
在传统的部署方式上,我们需要自己在服务器一个个安装并配置需要的环境,非常麻烦,主要核心体现在三点:命令太多了,记不住、软件安装包名字复杂,不知道去哪里找、安装和部署步骤复杂,容易出错。
而Docker就能很好的解决这个问题,即便你对Linux不熟悉,你也能轻松部署各种常见软件、Java项目。
如果你需要查看Docker的基础知识,可以访问后端开发入门Docker:从基础到实践 | Panda)
如果你需要我使用的终端工具,可用访问Tabby:一款出色的开源终端工具
这里使用我的大二课程作业给大家在 CentOS 7 下演示通过 Docker 实现前后端的容器化部署,同时开启Nginx
、MySQL
、Redis
等服务
如果不使用 Redis 可以省略对应的步骤,并且注意在 Compose 文件中去掉 Redis 的配置
Linux系统中创建目录
在root目录下创建文件夹,用于本地目录挂载
- 创建maiba文件夹(自定义名称,这里使用项目名),用于存放所有文件
- 在
maiba
文件夹中创建三个文件夹nginx
、mysql
、redis
- 其他文件等我们配置好,在后面的步骤再单独放入
前端构建
打开你的 Vue 项目,在终端中输入npm run build
命令,直到看见Build complete.
说明打包完成
打包完成后你会在目录中看见一个dist
文件夹,里面会有index.html
文件和css
、img
、js
等文件夹
将dist
文件夹名改为自定义名称(这里使用 maiba ),放入创建好的nginx
文件夹中的html
文件夹中
Nginx基本配置
准备nginx.conf
文件,设置与本地部署基本一致,但是需要注意:
-
网站根目录设置需要设置你的文件夹名,且路径是Docker容器中的路径(已挂载到本地
html
文件夹) -
服务器名称和后端的服务地址不再使用
IP
,而是使用Docker中自定义桥接网络的名称(这里使用maiba
)
worker_processes 1; # 定义工作进程数量
events {
worker_connections 1024; # 定义每个工作进程的最大连接数
}
http {
include mime.types; # 包含文件类型定义
default_type application/octet-stream; # 默认文件类型
sendfile on; # 开启高效文件传输模式
keepalive_timeout 65; # 连接保持超时时间
server {
listen 80; # 监听端口号
server_name maiba; # 服务器名称
location / {
root /usr/share/nginx/html/maiba; # 网站根目录
index index.html index.htm; # 默认首页文件
}
error_page 500 502 503 504 /50x.html; # 错误页面配置
location = /50x.html {
root html; # 错误页面根目录
}
location /api/ {
proxy_pass http://maiba:8080; # 后端服务地址
proxy_set_header Host $host; # 设置请求头Host
proxy_set_header X-Real-IP $remote_addr; # 设置请求头X-Real-IP
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 设置请求头X-Forwarded-For
proxy_set_header X-Forwarded-Proto $scheme; # 设置请求头X-Forwarded-Proto
}
}
}
可以看到,所有的
ip / localhost
已经替换为了maiba
(Docker中自定义桥接网络的名称)
将准备好的nginx.conf
文件放入nginx
文件夹,与html
文件夹并列
后端打包
- 在项目
pom.xml
文件中修改配置,避免出现no main manifest attribute
错误,找到<plugin>
下的<configuration>
标签
<configuration>
<mainClass>com.xxx.SpringbootMaibaApplication</mainClass>
<!-- <skip>true</skip> -->
<!-- 将上面skip标签注释掉或删掉,添加如下includeSystemScope标签 -->
<includeSystemScope>true</includeSystemScope>
</configuration>
- 检查确保在
application.properties
或application.yml
中关于MySQL和Redis的配置正确- 使用我们设置的自定义的桥接网络名(这里用maiba)代替
localhost
- 使用
redis
作为 redis 的 host (在后面的 Docker Compose 文件中,Redis 服务的名称是redis
)
- 使用我们设置的自定义的桥接网络名(这里用maiba)代替
- 在IDEA右侧的Maven工具栏中点击
package
打包,这时候会在target
文件夹中看到一个jar
包
- 复制
jar
包,修改成自定义名字(这里使用 maiba ),将其发送到Linux中的maiba
根目录下
准备 Dockerfile
- 准备
Dockerfile
文件,将其中的jar
包名修改成自己的(这里为maiba)
# 基础镜像
FROM openjdk:11.0-jre-buster
# 设定时区
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# 拷贝jar包
COPY maiba.jar /app.jar
# 入口
ENTRYPOINT ["java", "-jar", "/app.jar"]
- 确保
Dockerfile
被放在你的项目根目录下(这里为maiba),与jar
包要在一个目录,因为Dockerfile文件中使用了相对路径
放入MySQL和Redis的初始化文件
- 在MySQL文件夹中创建两个文件夹
init
和conf
- 在
init
文件夹中放入你的sql
文件,这样在MySQL容器创建的时候,你的数据库就创建好了 - 在
conf
文件夹中放入一个简单的maiba.cnf
文件(名字自定义,这里叫 maiba ),简单设置一下字符集
[client]
default_character_set=utf8mb4
[mysql]
default_character_set=utf8mb4
[mysqld]
character_set_server=utf8mb4
collation_server=utf8mb4_unicode_ci
init_connect='SET NAMES utf8mb4'
- 确保 mysql 文件夹中的两个文件夹中文件都正确放置
5. 在redis
文件夹中放入准备好的dump.rdb
文件和redis.conf
文件
-
前者为你需要初始化的的Redis数据,由Redis生成,找到复制过来即可
-
后者为redis的配置文件,注意需要设置
daemonize
为no
,否则会出现redis
启动后又正常退出的问题
在 Docker 容器中运行 Redis 时,不需要设置
daemonize
为yes
。原因是 Docker 容器本身就是一个单独的进程,如果 Redis 容器以守护进程模式运行,会导致容器立即退出。
- 守护进程模式:当
daemonize yes
时,Redis 会在后台运行,并且主进程会退出。而在 Docker 中,主进程的退出意味着容器的退出。- 前台运行:Docker 容器的最佳实践是让主进程在前台运行,以便 Docker 可以管理进程生命周期。
- 确保redis文件夹中的两文件都正确放置
创建 Docker Compose 文件
- 创建
docker-compose.yml
文件,输入下面内容
version: "3.8"
services:
mysql:
image: mysql
container_name: mysql
ports:
- "3306:3306"
environment:
TZ: Asia/Shanghai
MYSQL_ROOT_PASSWORD: 123456
volumes:
- "./mysql/conf:/etc/mysql/conf.d"
- "./mysql/data:/var/lib/mysql"
- "./mysql/init:/docker-entrypoint-initdb.d"
networks:
- new
maiba:
build:
context: .
dockerfile: Dockerfile
container_name: maiba
ports:
- "8080:8080"
networks:
- new
depends_on:
- mysql
nginx:
image: nginx
container_name: nginx
ports:
- "80:80"
volumes:
- "./nginx/nginx.conf:/etc/nginx/nginx.conf"
- "./nginx/html:/usr/share/nginx/html"
depends_on:
- maiba
networks:
- new
redis:
image: redis
container_name: redis
volumes:
- ./redis/dump.rdb:/data/dump.rdb
- ./redis/redis.conf:/usr/local/etc/redis/redis.conf
command: ["redis-server", "/usr/local/etc/redis/redis.conf"]
ports:
- "6379:6379"
networks:
- new
networks:
new:
name: maiba
我们四个容器都使用了自定义桥接网络
maiba
,所以在之前的Nginx配置文件和后端连接MySQL的配置中我们都使用了maiba
代替需要注意密码等设置要和自己在后端的Properties中配置的一致,端口也根据需要进行设置
并且我们都对容器挂载了本地目录,可以实现数据的永久保存
- 确保
docker-compose.yml
被放在你的项目根目录下(这里为maiba)
构建和启动 Docker 容器
前面的步骤做完,确保好文件都放置正确了,我们终于可以一键构建容器并运行了
- 在终端中使用
cd ~
回到 root 目录,运行cd maiba
进入项目文件夹,运行docker compose up -d
,完成所有的容器创建
- 第一次运行,会根据 Dockerfile 文件生成 maiba 后端容器镜像(蓝色部分),其他镜像如果曾经
docker pull
过,则无需下载,省时 - 然后就会依次创建所有容器,并挂载到我们指定的目录,并加入相同的网络(与Nginx中配置的和后端配置的相同)
2. 执行docker ps
查看到所有容器都启动成功并且显示端口,证明正常创建
- 执行
docker network inspect maiba
,查看该maiba
网络,可以看到四个容器都添加到了同一网络中
如果遇到了失败的情况,可以执行
docker logs container_name
查看具体错误并解决它即可
部署与测试
所有容器正常启动,在浏览器中输入Linux系统的 IP 地址或云服务器的地址访问,能看到前端页面和请求状态码200说明成功了**(注意开放常用的端口,)**
Navicat中也可以访问MySQL和Redis中的数据,说明数据根据sql
和rdb
文件也初始化成功(需开放服务器的MySQL和Redis端口,才能远程访问)