部署流程主要是先在服务器上构建基础环境:Docker, Docker-Compose, Portainer用于后续拉取镜像等。然后还需要在服务器构建应用环境,包括数据库MySQL, 缓存Redis。接下来是在本地把前后端分别打包镜像文件并推送到Docker Hub中由服务器拉取两个镜像完成部署。

1. 服务器环境配置

1.1 Docker安装

更新yum包,安装Doker依赖包

1
2
3
sudo yum update

sudo yum install -y yum-utils device-mapper-persistent-data lvm2

更新doker yum源到阿里云

1
2
sudo yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

查看可以安装的Doker版本并安装指定版本

1
2
yum list docker-ce --showduplicates | sort -r
yum install -y docker-ce-25.0.5 docker-ce-cli-25.0.5 containerd.io

1.2 安装Docker-Compose

从国内镜像地址安装,并设置权限。安装完成后验证一下版本。

1
2
3
4

sudo curl -L https://gitee.com/fustack/docker-compose/releases/download/v2.24.1/docker-compose-linux-x86_64 -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
docker-compose -v

1.3 启动Docker并添加开机自动启动

1
2
sudo systemctl start docker
systemctl enable docker

1.4 设置Docker镜像源

国内现在访问不了Docker Hub,设置一下镜像源就可以成功拉取镜像了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": [
"https://docker.1panel.live",
"https://dc.j8.work",
"https://docker.m.daocloud.io",
"https://dockerproxy.com",
"https://docker.mirrors.ustc.edu.cn",
"https://docker.nju.edu.cn"
]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker

1.5 Portainer

Portainer 是一款用于管理 Docker 环境的图形化工具。它通过提供友好的 Web 界面,使用户可以更方便地管理 Docker 容器、镜像、网络、卷和服务等资源,而无需直接使用命令行操作。

拉取Portainer镜像,并启动Portainer

1
2
docker pull portainer/portainer
docker run -d --restart=always --name portainer -p 9000:9000 -v /var/run/docker.sock:/var/run/docker.sock portainer/portainer

1.6 安装JDK, Maven

本地下载好JDK和Maven tar包,写了一个脚本直接在服务器上安装。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#!/bin/sh
# 定义JDK源文件和目标目录
JDK_SRC="/dev-ops/java/jdk-8u202-linux-x64.tar.gz"
JDK_DST="/usr/local/java"

# 检查JDK源文件是否存在
if [ ! -f "$JDK_SRC" ]; then
    echo "JDK 安装文件不存在: $JDK_SRC"
    exit 1
fi

# 创建目标目录
mkdir -p "$JDK_DST"

# 复制JDK压缩包到目标目录
cp "$JDK_SRC" "$JDK_DST"

# 进入目标目录
cd "$JDK_DST"

# 解压JDK压缩包
tar -zxvf "jdk-8u202-linux-x64.tar.gz"

# 获取解压后的JDK目录名称
JDK_DIR=$(tar -tzf "jdk-8u202-linux-x64.tar.gz" | head -1 | cut -f1 -d"/")
# 配置环境变量
echo "export JAVA_HOME=$JDK_DST/$JDK_DIR" >> /etc/profile
echo "export PATH=\$JAVA_HOME/bin:\$PATH" >> /etc/profile
echo "export CLASSPATH=\$JAVA_HOME/jre/lib/ext:\$JAVA_HOME/lib/tools.jar" >> /etc/profile
# 使环境变量立即生效
source /etc/profile
# 输出安装完成
echo "Java installation completed."
# 输出Java版本
java -version

# 结束脚本
exit 0

2. 服务器应用环境配置

这一部分主要配置微服务所依赖的环境: mySQL, Redis等
使用Docker脚本直接执行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# 命令执行 docker-compose -f docker-compose-environment.yml up -d
version: '3.9'
services:
mysql:
image: mysql:8.0.32
container_name: mysql
command: --default-authentication-plugin=mysql_native_password
restart: always
environment:
TZ: Asia/Shanghai
MYSQL_ROOT_PASSWORD: 123456
networks:
- my-network
depends_on:
- mysql-job-dbdata
ports:
- "13306:3306"
volumes:
- ./mysql/sql:/docker-entrypoint-initdb.d
healthcheck:
test: [ "CMD", "mysqladmin" ,"ping", "-h", "localhost" ]
interval: 5s
timeout: 10s
retries: 10
start_period: 15s
volumes_from:
- mysql-job-dbdata

# 自动加载数据
mysql-job-dbdata:
image: alpine:3.18.2
container_name: mysql-job-dbdata
volumes:
- /var/lib/mysql

# phpmyadmin https://hub.docker.com/_/phpmyadmin
phpmyadmin:
image: phpmyadmin:5.2.1
container_name: phpmyadmin
hostname: phpmyadmin
ports:
- 8899:80
environment:
- PMA_HOST=mysql
- PMA_PORT=3306
- MYSQL_ROOT_PASSWORD=123456
depends_on:
mysql:
condition: service_healthy
networks:
- my-network

# Redis
redis:
image: redis:6.2
container_name: redis
restart: always
hostname: redis
privileged: true
ports:
- 16379:6379
volumes:
- ./redis/redis.conf:/usr/local/etc/redis/redis.conf
command: redis-server /usr/local/etc/redis/redis.conf
networks:
- my-network
healthcheck:
test: [ "CMD", "redis-cli", "ping" ]
interval: 10s
timeout: 5s
retries: 3

# RedisAdmin https://github.com/joeferner/redis-commander
redis-admin:
image: spryker/redis-commander:0.8.0
container_name: redis-admin
hostname: redis-commander
restart: always
ports:
- 8081:8081
environment:
- REDIS_HOSTS=local:redis:6379
- HTTP_USER=admin
- HTTP_PASSWORD=admin
- LANG=C.UTF-8
- LANGUAGE=C.UTF-8
- LC_ALL=C.UTF-8
networks:
- my-network
depends_on:
redis:
condition: service_healthy

networks:
my-network:
driver: bridge

使用Docker-compose 执行该脚本docker-compose -f docker-compose-environment.yml up -d

3. 本地前后端应用推送到Docker-Hub

3.1 前端构建镜像

next.config.ts中新增target: 'server', output: "standalone",用于控制项目的构建和部署行为,特别是构建后如何打包和运行应用

新增Dockerfile用于构建镜像:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
FROM node:18-alpine AS base  

FROM base AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /app

COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./

RUN yarn config set registry 'https://registry.npmmirror.com/'
RUN yarn install

FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .

RUN yarn build

FROM base AS runner
WORKDIR /app

COPY --from=builder /app/public ./public
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
COPY --from=builder /app/.next/server ./.next/server

EXPOSE 3000
ENV PORT 3000
ENV HOSTNAME "0.0.0.0"

CMD ["node", "server.js"]

通过脚本构建镜像: docker build -t priska/big-market-front-app:1.0 .

中间出现很多bug。node.jsreact还是很难用的。比如要让Eslint禁用:

1
2
3
4
5
6
7
8
{  
"extends": ["next/core-web-vitals", "next/typescript"],
"extends": "next",
"rules": {
"react/no-unescaped-entities": "off",
"@next/next/no-page-custom-font": "off"
}
}

更改一些已经编写好的typescript文件

3.2 后端构建镜像

将配置文件从开发配置改成工程配置,在aplication.yml中修改profiles: active: prod

然后修改对应的工程配置,把对应的数据库,缓存等配置成生产环境的, 这里只列出关键信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 应用配置  
app:
config:
#版本,方便通过接口版本升级
api-version: v1
#跨域,开发阶段设置为* 不限制
cross-origin: '*'
# 数据库配置
spring:
datasource:
username: 服务器数据库用户名
password: 服务器数据库密码
#不行的话把mysql改成127.0.0.1
url: jdbc:mysql://127.0.0.1:3306/...
#redis配置
redis:
sdk:
config:
#不行的话就改成ip地址
host: 127.0.0.1
port: 16379

使用dockerfile进行镜像构建:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 基础镜像  
FROM openjdk:8-jre-slim

# 作者
MAINTAINER priska

# 配置
ENV PARAMS=""

# 时区
ENV TZ=PRC
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

# 添加应用
ADD target/big-market-app.jar /big-market-app.jar

ENTRYPOINT ["sh","-c","java -jar $JAVA_OPTS /big-market-app.jar $PARAMS"]

4. 服务器开启服务

将写好的docker-compose-app放到服务器拉取已经上传的前后端镜像:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
version: '3.8'  
# 命令执行 docker-compose -f docker-compose-app.yml up -dservices:
big-market-app:
image: yaqiyu/big-market-app:1.5
container_name: big-market-app
restart: always
ports:
- "8091:8091"
environment:
- TZ=PRC
- SERVER_PORT=8091
- APP_CONFIG_API_VERSION=v1
- APP_CONFIG_CROSS_ORIGIN=*
- SPRING_DATASOURCE_USERNAME=
- SPRING_DATASOURCE_PASSWORD=
- SPRING_DATASOURCE_URL=jdbc:mysql://mysql:3306/big_market?serverTimezone=UTC&characterEncoding=utf8&autoReconnect=true&serverTimezone=Asia/Shanghai
- SPRING_DATASOURCE_DRIVER_CLASS_NAME=com.mysql.cj.jdbc.Driver
- SPRING_HIKARI_POOL_NAME=Retail_HikariCP
- REDIS_SDK_CONFIG_HOST=redis
- REDIS_SDK_CONFIG_PORT=
volumes:
- ./log:/data/log
networks:
- my-network
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
big-market-front-app:
container_name: big-market-front-app
image: yaqiyu/big-market-front-app:1.0
restart: always
networks:
- my-network
ports:
- 3000:3000
environment:
- API_HOST_URL=http://127.0.0.1:8091
- PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
healthcheck:
test: [ "CMD", "wget", "--spider", "-q", "http://0.0.0.0:3000/" ]
interval: 1m
timeout: 10s
retries: 3

networks:
my-network:
driver: bridge